Files
tms-erp-web/src/utils/import-excel.js
b2894lxlx c339852e04 1、基础数据修复bug
2、客商模块修复bug
2026-08-06 02:57:55 +08:00

121 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { importBlob } from '@/api/common';
import { downloadXls } from '@/utils/util';
import { ElLoading } from 'element-plus';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
const excelPattern = /\.(xls|xlsx)$/;
const isExcelResponse = res => {
const contentType = res.headers['content-type'] || res.data.type || '';
return contentType.includes('application/vnd.ms-excel');
};
const parseBlobJson = async blob => {
const text = await blob.text();
return text ? JSON.parse(text) : {};
};
/**
* 加工后端返回的导入失败明细 Excel。
* 若传入 failDetailDecorator函数则动态加载 exceljs 读取 blob 流,
* 交由 decorator 完成改写原因列、调整列宽等加工,再导出新的 blob
* 否则原样返回 blob保持旧行为不影响未使用 decorator 的模块)。
* @param {Blob} blob 后端返回的失败明细 Excel 流
* @param {String} businessName 业务名称(如「货物类型」)
* @param {Function} [failDetailDecorator] async (workbook, { businessName }) => void
* @returns {Promise<Blob>}
*/
const decorateFailExcel = async (blob, businessName, failDetailDecorator) => {
if (typeof failDetailDecorator !== 'function') return blob;
const ExcelJS = await import('exceljs');
const buf = await blob.arrayBuffer();
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.load(buf);
await failDetailDecorator(workbook, { businessName });
const out = await workbook.xlsx.writeBuffer();
return new Blob([out], { type: 'application/vnd.ms-excel' });
};
/**
* 打开导入弹窗
* @param {Object} vm 组件实例
* @param {String} businessName 业务名称,用于失败明细文件命名
* @param {Function} [onSuccess] 导入成功回调
* @param {Object} [options] 扩展项
* @param {Function} [options.failDetailDecorator] 失败明细加工函数,用于对后端返回的失败 Excel 标红/改写原因
*/
export const openImportDialog = (vm, businessName, onSuccess, options = {}) => {
const { failDetailDecorator } = options;
const excelOption = vm.excelOption || vm.excelOptionConfig;
const column = vm.findColumn(excelOption?.column || [], 'excelFile');
if (!column) {
vm.$message.error('导入配置异常,请稍后重试');
return;
}
column.httpRequest = (option, uploadColumn) =>
handleImportExcel(vm, option, uploadColumn, businessName, onSuccess, { failDetailDecorator });
vm.excelBox = true;
};
export const handleImportExcel = async (vm, option, column, businessName, onSuccess, options = {}) => {
const { failDetailDecorator } = options;
const file = option.file;
const fileName = file && file.name ? file.name.toLowerCase() : '';
if (!excelPattern.test(fileName)) {
vm.$message.error('请上传 .xls,.xlsx 标准格式文件');
if (typeof option.onError === 'function') {
option.onError(new Error('请上传 .xls,.xlsx 标准格式文件'));
}
return;
}
NProgress.start();
const loading = ElLoading.service({
lock: true,
text: '导入中',
background: 'rgba(255, 255, 255, 0.7)',
});
try {
const res = await importBlob(column.action, file);
if (isExcelResponse(res)) {
const decorated = await decorateFailExcel(res.data, businessName, failDetailDecorator);
downloadXls(
decorated,
`${businessName}导入失败明细${vm.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`
);
vm.$message.warning('部分数据导入失败,已下载失败明细');
} else {
const result = await parseBlobJson(res.data);
if (result.code !== 200) {
vm.$message.error(result.msg || '导入失败');
if (typeof option.onError === 'function') {
option.onError(new Error(result.msg || '导入失败'));
}
return;
}
vm.$message.success('导入完成');
}
vm.excelBox = false;
vm.excelForm = {};
if (typeof onSuccess === 'function') {
onSuccess();
} else if (typeof vm.onLoad === 'function') {
vm.onLoad(vm.page, vm.query);
} else if (typeof vm.initTree === 'function') {
vm.initTree();
}
if (typeof option.onSuccess === 'function') {
option.onSuccess(res);
}
} catch (error) {
vm.$message.error(error.message || '导入失败');
if (typeof option.onError === 'function') {
option.onError(error);
}
} finally {
loading.close();
NProgress.done();
}
};