175 lines
4.6 KiB
TypeScript
175 lines
4.6 KiB
TypeScript
|
||
|
||
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 { 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<object>;
|
||
xlsxMap: Array<MapItem>;
|
||
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<object>, keyMap: Array<MapItem>) {
|
||
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)
|
||
.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<object>, 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);
|
||
};
|