feat: add A-card operations frontend and backend foundation
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
export type ExcelValue = string | number | boolean | Date | null | undefined;
|
||||
|
||||
export type ExcelExportOptions = {
|
||||
fileName: string;
|
||||
sheetName: string;
|
||||
headers: string[];
|
||||
rows: ExcelValue[][];
|
||||
};
|
||||
|
||||
function safeFileName(value: string): string {
|
||||
return value.replace(/[\\/:*?"<>|]/g, "_").replace(/\.xlsx$/i, "");
|
||||
}
|
||||
|
||||
function safeSheetName(value: string): string {
|
||||
return value.replace(/[\\/*?:\[\]]/g, "_").slice(0, 31) || "Sheet1";
|
||||
}
|
||||
|
||||
export async function exportRowsToExcel({ fileName, sheetName, headers, rows }: ExcelExportOptions): Promise<void> {
|
||||
const { default: writeExcelFile } = await import("write-excel-file/browser");
|
||||
const headerRow = headers.map((value) => ({
|
||||
value,
|
||||
fontWeight: "bold" as const,
|
||||
backgroundColor: "#EDF6FF",
|
||||
align: "center" as const,
|
||||
}));
|
||||
const columns = headers.map((header, index) => {
|
||||
const maxLength = Math.max(header.length * 2, ...rows.map((row) => String(row[index] ?? "").length));
|
||||
return { width: Math.min(42, Math.max(12, maxLength + 3)) };
|
||||
});
|
||||
await writeExcelFile([headerRow, ...rows], {
|
||||
sheet: safeSheetName(sheetName),
|
||||
stickyRowsCount: 1,
|
||||
columns,
|
||||
}).toFile(`${safeFileName(fileName)}.xlsx`);
|
||||
}
|
||||
Reference in New Issue
Block a user