import { utils, write } from 'xlsx'; import { dateUtil } from '/nerv-lib/util/date-util'; import { NsMessage } from '/nerv-lib/component/message'; import axios from 'axios'; import { createVNode, h, render as vueRender } from 'vue'; import { Cookies } from '/nerv-lib/util/cookie'; import { NsXlsxImport } from '/nerv-lib/component/xlsx'; import { NsModal } from '/nerv-lib/component/modal'; interface MapItem { title: string; dataIndex: string; format?: Function; } type objProps = { [name: string]: any; }; type argType = { data: Array; xlsxMap: Array; xlsxName: string; limit?: number; }; const DATE_FORMAT = 'YYYY-MM-DD '; const MODAL_INFO = { title: '警告', okText: '确认', cancelText: '取消', }; const errorTable = [ { title: '行数', dataIndex: 'row', }, { title: '错误内容', dataIndex: 'reason', }, ]; const sheet2blob = (sheet: any, sheetName = 'sheet1') => { sheetName = sheetName || 'sheet1'; const workbook = { SheetNames: [sheetName], Sheets: {}, }; workbook['Sheets'][sheetName] = sheet; // 生成excel的配置项 const wbout = write(workbook, { bookType: 'xlsx', // 要生成的文件类型 bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性 type: 'binary', }); const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' }); // 字符串转ArrayBuffer function s2ab(s: any) { const buf = new ArrayBuffer(s.length); const view = new Uint8Array(buf); for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff; return buf; } return blob; }; function openDownloadDialog(url: string | Blob | MediaSource, saveName: string) { if (typeof url == 'object' && url instanceof Blob) { url = URL.createObjectURL(url); // 创建blob地址 } const aLink = document.createElement('a'); aLink.href = url; aLink.download = saveName || ''; document.body.appendChild(aLink); aLink.click(); document.body.removeChild(aLink); } function download(table: unknown[][], name: string, config: any) { let isHandle; if (config && config['isHandle']) { isHandle = config['isHandle']; } let sheet; //isHandle 表示自己处理表格样式和数据,不需要再做处理 isHandle ? (sheet = table) : (sheet = utils.aoa_to_sheet(table)); openDownloadDialog(sheet2blob(sheet), `${name}.xlsx`); } function DataHandler(data: Array, keyMap: Array) { const tableHeader: string[] = []; // 表头 const tableHeaderKeyMap: objProps = {}; // 表头索引map keyMap?.map((item: MapItem) => { tableHeader.push(item['title']); tableHeaderKeyMap[item['title']] = item['dataIndex']; }); const table = [tableHeader]; data.forEach((item: object) => { const rowData: any[] = []; tableHeader.forEach((th: string, index: number) => { let temp = item[tableHeaderKeyMap[th]]; const format = keyMap[index].format; if (format) temp = format(temp, item); rowData.push(temp); }); table.push(rowData); }); return table; } export const importFile = ( { api, params }: any, reload: Function, event: any, successBack?: Function, errorBack?: Function, ) => { const formData = new FormData(); params && Object.keys(params).map((item) => { formData.append(item, params[item]); }); formData.append('file', event); axios .post(api, formData, { headers: { token: Cookies.get(`${import.meta.env.VITE_PUBLIC_PATH}-nervsid`) }, }) .then((res) => { if (res) { NsMessage.success('导入成功', 1, () => { reload && reload(); successBack && successBack(res); }); } }) .catch((err) => { if (errorBack) { errorBack(err); } else { NsMessage.error(err.response?.data?.msg || '导入失败'); const error = err.response?.data?.data; if (error) xlsxExport({ data: error, xlsxMap: errorTable, xlsxName: '导入数据不规范说明YYYY-MM-DD', }); } }); }; const checkLimit = (data: Array, limit?: number) => { if (limit && data.length > limit) { NsModal.confirm({ ...MODAL_INFO, content: `本次数据下载超过${limit}条,请重新选择数据!`, }); return false; } return true; }; export const xlsxExport = ({ data, xlsxMap, xlsxName, limit }: argType) => { if (!checkLimit(data, limit)) return; const name = dateUtil(new Date()).format(xlsxName); download(DataHandler(data, xlsxMap), `${name}`, ''); }; export const xlsxImport = (data: any) => { const div = document.createElement('div'); const vm = h(NsXlsxImport, { ...data }, ''); vueRender(vm, div); };