Files
senmesh-zc/frontend/src/components/ExcelPreview.tsx

110 lines
3.1 KiB
TypeScript
Raw Normal View History

import { useState, useEffect } from "react";
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
import * as XLSX from "xlsx";
type Props = {
url?: string;
};
export function ExcelPreview({ url }: Props) {
const [sheets, setSheets] = useState<{ name: string; data: any[][] }[]>([]);
const [activeSheet, setActiveSheet] = useState(0);
const { data, isLoading, error, isError } = useQuery({
queryKey: ["excel", url],
queryFn: () => axios.get(url!, { responseType: "arraybuffer" }),
enabled: !!url,
});
useEffect(() => {
if (data?.data) {
try {
const workbook = XLSX.read(data.data, { type: "array" });
const sheetData = workbook.SheetNames.map((name) => {
const worksheet = workbook.Sheets[name];
const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
return { name, data: jsonData as any[][] };
});
setSheets(sheetData);
} catch (err) {
}
}
}, [data]);
if (!url) {
return (
<div className="w-full h-full flex items-center justify-center text-muted-foreground">
Excel 文件地址无效
</div>
);
}
if (isLoading) {
return (
<div className="flex items-center justify-center h-full">
<div>加载中...</div>
</div>
);
}
if (isError) {
return (
<div className="flex items-center justify-center h-full text-red-500">
{error?.message || "加载失败"}
</div>
);
}
if (sheets.length === 0) {
return (
<div className="flex items-center justify-center h-full text-muted-foreground">
Excel 文件为空或格式不正确
</div>
);
}
const currentSheet = sheets[activeSheet];
return (
<div className="h-full flex flex-col">
{sheets.length > 1 && (
<div className="flex-none border-b bg-slate-50 dark:bg-slate-900 p-2 flex gap-2 overflow-x-auto">
{sheets.map((sheet, index) => (
<button
key={index}
onClick={() => setActiveSheet(index)}
className={`px-4 py-2 rounded text-sm whitespace-nowrap transition-colors ${
activeSheet === index
? "bg-primary text-primary-foreground"
: "bg-white dark:bg-slate-800 hover:bg-slate-100 dark:hover:bg-slate-700"
}`}
>
{sheet.name}
</button>
))}
</div>
)}
<div className="flex-auto overflow-auto">
<table className="w-full border-collapse text-sm">
<tbody>
{currentSheet.data.map((row, rowIndex) => (
<tr key={rowIndex} className="border-b">
{row.map((cell, cellIndex) => (
<td
key={cellIndex}
className="border-r px-3 py-2 whitespace-nowrap"
>
{cell !== null && cell !== undefined ? String(cell) : ""}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}