53 lines
1.3 KiB
TypeScript
53 lines
1.3 KiB
TypeScript
import { Download } from "lucide-react";
|
|
import { Button } from "@/components/ui/button";
|
|
import type { Column } from "./DataGrid";
|
|
|
|
function cellValue<T extends object>(row: T, col: Column<T>): string | number {
|
|
const raw = row[col.key];
|
|
if (col.format) return col.format(raw, row);
|
|
return (raw as string | number) ?? "";
|
|
}
|
|
|
|
/** 按表格列定义导出 xlsx;xlsx 按需加载,避免进入首屏包。 */
|
|
export async function exportToXlsx<T extends object>(
|
|
rows: T[],
|
|
columns: Column<T>[],
|
|
filename: string,
|
|
sheetName = "明细",
|
|
): Promise<void> {
|
|
const { buildJsonSheet, writeWorkbook } = await import("../../../shared/xlsx");
|
|
const sheet = buildJsonSheet(
|
|
rows.map((row) =>
|
|
Object.fromEntries(columns.map((col) => [col.label, cellValue(row, col)])),
|
|
),
|
|
);
|
|
writeWorkbook([{ name: sheetName, sheet }], filename);
|
|
}
|
|
|
|
export function ExportButton<T extends object>({
|
|
rows,
|
|
columns,
|
|
filename,
|
|
sheetName,
|
|
label = "导出",
|
|
}: {
|
|
rows: T[];
|
|
columns: Column<T>[];
|
|
filename: string;
|
|
sheetName?: string;
|
|
label?: string;
|
|
}) {
|
|
return (
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
className="min-h-9 w-fit md:min-h-7"
|
|
disabled={!rows.length}
|
|
onClick={() => void exportToXlsx(rows, columns, filename, sheetName)}
|
|
>
|
|
<Download data-icon="inline-start" />
|
|
{label}
|
|
</Button>
|
|
);
|
|
}
|