import React, { useCallback, useId, useRef, useState } from "react"; import { FileSpreadsheet, Upload, X } from "lucide-react"; import { Button } from "../ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "../ui/dialog"; import { Label } from "../ui/label"; import { cn } from "../ui/utils"; import { toast } from "sonner"; import { ApiError } from "../../lib/apiClient"; export type BatchImportDialogProps = { open: boolean; onOpenChange: (open: boolean) => void; title: string; description?: string; /** 弹框底部「下载模板」 */ onDownloadTemplate: () => void | Promise; /** 选择文件后点击 Import 上传 */ onImportFile: (file: File) => Promise<{ successCount: number; failCount: number }>; downloadingTemplate?: boolean; }; const ACCEPT = ".xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; function formatFileSize(bytes: number): string { if (!Number.isFinite(bytes) || bytes < 0) return ""; if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; } function pickFile(list: FileList | null): File | null { const f = list?.[0]; if (!f) return null; const name = f.name.toLowerCase(); if (!name.endsWith(".xlsx")) { return null; } return f; } export function BatchImportDialog({ open, onOpenChange, title, description, onDownloadTemplate, onImportFile, downloadingTemplate = false, }: BatchImportDialogProps) { const fileInputId = useId(); const inputRef = useRef(null); const [file, setFile] = useState(null); const [busy, setBusy] = useState(false); const [dragActive, setDragActive] = useState(false); const reset = () => { setFile(null); setDragActive(false); if (inputRef.current) inputRef.current.value = ""; }; const clearSelectedFile = () => { setFile(null); if (inputRef.current) inputRef.current.value = ""; }; const applyFiles = useCallback((list: FileList | null) => { const f = pickFile(list); if (list?.length && !f) { toast.error("Invalid file", { description: "Please choose an .xlsx file." }); return; } setFile(f); }, []); /** 延迟触发:避免嵌在 Radix Dialog 内时,同步 click() 导致部分浏览器不触发 change */ const openPicker = () => { window.setTimeout(() => { const el = inputRef.current; if (!el) return; el.value = ""; el.click(); }, 0); }; return ( { if (!v) reset(); onOpenChange(v); }} > {title} {description ? ( {description} ) : null}
applyFiles(e.target.files)} /> {file ? (
Selected file
{file.name}
{formatFileSize(file.size) ? (
{formatFileSize(file.size)}
) : null}
) : (
No file selected yet — use Browse or drag an .xlsx above
)}

After a file is selected, click Import to upload it to the server.

); }