封装 xlsx.ts 文件
npm i xlsx element-plus
import * as XLSX from "xlsx";
import { ElMessageBox, ElMessage } from "element-plus";
export const exportExcel = (tableRef: any = null,fileName = "export.xlsx",options: any = {}
) => {let headers = options.headers || [];let data = options.data || [];if (tableRef) {if (tableRef.$options.name === "VxeTable") {headers =headers.length > 0? headers: tableRef.getColumns().map((col: any) => col.title);data = data.length > 0 ? data : tableRef.getTableData().fullData;} else if (tableRef.$options.name === "ElTable") {headers =headers.length > 0? headers: tableRef.columns.map((col: any) => col.label);data = data.length > 0 ? data : tableRef.data;} else {throw new Error("不支持的表格组件类型");}if (options.dataKeys) {data = data.map((item: any) =>options.dataKeys.reduce((obj: any, key: any) => ({ ...obj, [key]: item[key] }),{}));}}if (!headers.length) {throw new Error("缺少必要的表头");}const worksheetData = [headers, ...data.map((item: any) =>headers.map((header: any) => {const key = Object.keys(item).find((k) => k.toLowerCase() === header.toLowerCase());return key ? item[key] : "";})),];const workbook = XLSX.utils.book_new();const worksheet = XLSX.utils.aoa_to_sheet(worksheetData);worksheet["!cols"] = headers.map(() => ({ wch: 10 })); XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");XLSX.writeFile(workbook, fileName);
};
export const importExcel = (tableRef: any = null,requiredFields: string[] = []
) => {return new Promise((resolve, reject) => {const input = document.createElement("input");input.setAttribute("type", "file");input.setAttribute("accept", ".xlsx"); input.click();input.onchange = (e: any) => {const files = e.target.files;if (!files.length) {reject(new Error("没有选择文件"));return;}const file = files[0];if (!file.name.endsWith(".xlsx")) {reject(new Error("只能导入 .xlsx 文件"));return;}const reader = new FileReader();reader.onload = (event: any) => {try {const data = new Uint8Array(event.target.result);const workbook = XLSX.read(data, { type: "array" });const firstSheetName = workbook.SheetNames[0];const worksheet = workbook.Sheets[firstSheetName];const headerData: any = XLSX.utils.sheet_to_json(worksheet, {header: 1,})[0]; if (!requiredFields.every((field) => headerData.includes(field))) {reject(new Error("导入的表格表头与要求不符,请使用正确的模板!"));return;}const newData = XLSX.utils.sheet_to_json(worksheet, {defval: "", });if (requiredFields.length > 0) {const missingFieldsMap = new Map(); newData.forEach((row: any, index: number) => {requiredFields.forEach((field) => {const fieldValue = row[field]; if (fieldValue === "" ||fieldValue === null ||fieldValue === undefined) {const rowNumber = index + 2;if (!missingFieldsMap.has(rowNumber)) {missingFieldsMap.set(rowNumber, []);}missingFieldsMap.get(rowNumber).push(field);}});});if (missingFieldsMap.size > 0) {let errorMessage = "以下行的必填字段缺失:<br>"; missingFieldsMap.forEach((fields, rowNumber) => {errorMessage += `第 ${rowNumber} 行缺失字段:${fields.join(", ")}<br>`; });reject(new Error(errorMessage)); return;}}if (tableRef) {let existingData;if (tableRef.$options.name === "VxeTable") {existingData = tableRef.getTableData().fullData;} else if (tableRef.$options.name === "ElTable") {existingData = tableRef.data;}const combinedData = [...existingData, ...newData];if (tableRef.$options.name === "VxeTable") {tableRef.loadData(combinedData);} else if (tableRef.$options.name === "ElTable") {tableRef.data = combinedData;}}resolve(newData); } catch (error) {reject(error);}};reader.onerror = () => reject(new Error("读取文件时出错"));reader.readAsArrayBuffer(file);};});
};
export const importAndInsertData = async (data: any[],insertApi: (item: any) => Promise<any>,refreshTable: () => void,setLoading: (isLoading: boolean) => void
) => {try {setLoading(true);const insertPromises = data.map((item) =>insertApi(item).catch((error) => {return { item, error };}));const results = await Promise.all(insertPromises);const failedItems = results.filter((result) => result && result.error);if (failedItems.length > 0) {let errorMessage = "以下数据插入失败:<br>";failedItems.forEach(({ item, error }) => {errorMessage += `数据:${JSON.stringify(item)},错误:${error.message}<br>`;});ElMessageBox.alert(errorMessage, "导入失败", {confirmButtonText: "确定",dangerouslyUseHTMLString: true,});} else {ElMessage.success("导入成功");refreshTable();}} catch (error: any) {ElMessageBox.alert(`导入过程中发生错误:${error.message}`, "导入失败", {confirmButtonText: "确定",});} finally {setLoading(false); }
};