|
@@ -1,390 +1,460 @@
|
|
|
-// import XLSX from 'xlsx'
|
|
|
-// import _ from 'lodash'
|
|
|
-// // import ExcelImportDialog from "./renderers/excelImportDialog";
|
|
|
-// import * as path from "path";
|
|
|
-// // import {clearLoading, loading} from "./renderers";
|
|
|
-// // @ts-ignore
|
|
|
-// // import XLSX_EXPORT from 'xlsx_export';
|
|
|
-// // @ts-ignore
|
|
|
-// const XLSX_EXPORT = window.LAY_EXCEL
|
|
|
-//
|
|
|
-// export {XLSX};
|
|
|
-// export {XLSX_EXPORT}
|
|
|
-//
|
|
|
-// export function readExcel(file: File): Promise<any> {
|
|
|
-// return new Promise((resolve, reject) => {
|
|
|
-// var reader = new FileReader();
|
|
|
-// reader.onload = function (e) {
|
|
|
-// if (e.target) {
|
|
|
-// const data = e.target.result;
|
|
|
-// const workbook = XLSX.read(data, {type: 'binary'});
|
|
|
-// resolve(workbook);
|
|
|
-// } else {
|
|
|
-// reject("文件读取失败!!!")
|
|
|
-// }
|
|
|
-// };
|
|
|
-// try {
|
|
|
-// reader.readAsBinaryString(file);
|
|
|
-// } catch (e) {
|
|
|
-// reject(e)
|
|
|
-// }
|
|
|
-// })
|
|
|
-// }
|
|
|
-//
|
|
|
-// export declare interface ErrorMsgDataItem {
|
|
|
-// /** 错误id 由allData 的__importID__字段值 + "_" + field的值 表示哪一行的哪一列出错,行校验错误时候直接为allData 的__importID__ + "" */
|
|
|
-// errorId: string
|
|
|
-// /** 对应数据行 allData 的__importID__字段值 */
|
|
|
-// importID: number
|
|
|
-// /** 字段 */
|
|
|
-// field: string
|
|
|
-// /** 字段值 */
|
|
|
-// title: string
|
|
|
-// /** 字段值 */
|
|
|
-// value: string
|
|
|
-// /** 错误信息 */
|
|
|
-// errormessage: string
|
|
|
-// }
|
|
|
-//
|
|
|
-// export declare interface ImportResult {
|
|
|
-// /** 所有导入的数据,如果有字典会格式化到字典,格式化错误的保持原始值 */
|
|
|
-// allData: any[]
|
|
|
-// /** 导入正确的数据 */
|
|
|
-// okData: any[]
|
|
|
-// /** 导入错误的数据 */
|
|
|
-// errorData: any[]
|
|
|
-// /** 导入错误数据的错误明细 */
|
|
|
-// errorMsgData: ErrorMsgDataItem[]
|
|
|
-// }
|
|
|
-//
|
|
|
-// /** 定义参数列 */
|
|
|
-// export declare interface Field {
|
|
|
-// /** 字段 */
|
|
|
-// dataIndex: string
|
|
|
-// /** 字段名 */
|
|
|
-// header: string
|
|
|
-// /** 校验方法,校验通过返回true, 否则返回错误信息 会记录到错误列表里面 errorMsgData */
|
|
|
-// validate?: ((v: ValidateObject) => true | string) | string
|
|
|
-// /** 格式化,表格显示 兼容默认弹出框表格的formatter */
|
|
|
-// fix?: ((v: any) => any) | string
|
|
|
-// /** 导入格式化 返回null或者undefined 表示格式化错误,会记录到错误列表里面 errorMsgData */
|
|
|
-// importFormatter?: ((v: ValidateObject) => null | undefined | string | number) | string
|
|
|
-// /** 字典, 参与数据校验和表格显示格式化, 校验不通过的,会记录到错误列表里面 errorMsgData 同时兼容默认弹出框表格的字典 */
|
|
|
-// data?: any | { id: string | number, text: string }
|
|
|
-// }
|
|
|
-//
|
|
|
-// /** 格式化及校验的参数 */
|
|
|
-// export declare interface ValidateObject {
|
|
|
-// field: Field
|
|
|
-// ov: any,
|
|
|
-// nv: any,
|
|
|
-// rowIndex: number,
|
|
|
-// data: any,
|
|
|
-// rowDatas: any[],
|
|
|
-// }
|
|
|
-//
|
|
|
-// /** 行数据校验的参数 */
|
|
|
-// export declare interface RowValidateObject {
|
|
|
-// fields: Field[],
|
|
|
-// data: any,
|
|
|
-// rowIndex: number,
|
|
|
-// rowDatas: any[]
|
|
|
-// }
|
|
|
-//
|
|
|
-// /**
|
|
|
-// * 定义切口,可以在外部修改数据
|
|
|
-// */
|
|
|
-// export declare type AfterClientValidate =
|
|
|
-// ((importResult: ImportResult, resolve: (value?: (ImportResult | PromiseLike<ImportResult> | undefined)) => void) => ImportResult)
|
|
|
-// | undefined
|
|
|
-//
|
|
|
-// export function readExcelWithFieldSet(file: File,
|
|
|
-// fieldSet: any[],
|
|
|
-// dataStartRow: number = 2,
|
|
|
-// titleRowNumber: number = 1,
|
|
|
-// rowValidate: ((rv: RowValidateObject) => true | string) | undefined = undefined,
|
|
|
-// otherValidate: AfterClientValidate = undefined,
|
|
|
-// fieldValidate: ((fields: Field[], columnTitles: string[]) => boolean) | undefined = undefined): Promise<ImportResult> {
|
|
|
-// return new Promise<ImportResult>((resolve, reject) => {
|
|
|
-// setTimeout(()=>{
|
|
|
-// readExcel(file).then(workbook => {
|
|
|
-// const sheetNames = workbook.SheetNames; // 工作表名称集合
|
|
|
-// const worksheet = workbook.Sheets[sheetNames[0]]; // 这里我们只读取第一张sheet
|
|
|
-// const titleRowValue: any[] = [];
|
|
|
-// const titleRowKey: any[] = [];
|
|
|
-// let needLoop: boolean = false; // 是否需要迭代
|
|
|
-// let fields: any[] = [];
|
|
|
-// if (worksheet && worksheet["!ref"]) {
|
|
|
-// const t = worksheet["!ref"];
|
|
|
-// const tempArr = t.split(':');
|
|
|
-// if (tempArr.length >= 2) {
|
|
|
-// let firstRowNumber = tempArr[0].replace(/[^0-9]/ig, "");
|
|
|
-//
|
|
|
-// // 选取title的行,删除之前的行
|
|
|
-// if (titleRowNumber > firstRowNumber) {
|
|
|
-// for (let i = firstRowNumber; i < titleRowNumber; i++) {
|
|
|
-// for (const key in worksheet) {
|
|
|
-// if (key.endsWith(i) && key.replace(/[^0-9]/ig, "") === i) {
|
|
|
-// delete worksheet[key];
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// const fc = tempArr[0].replace(/[^a-z]/ig, "");
|
|
|
-// firstRowNumber = titleRowNumber + '';
|
|
|
-// worksheet["!ref"] = fc+firstRowNumber + ":" + tempArr[1]
|
|
|
-// }
|
|
|
-// const lastRowNumber = tempArr[1].replace(/[^0-9]/ig, "");
|
|
|
-// // const firstColNumber = tempArr[0].split(''+firstRowNumber)[0];
|
|
|
-// // const lastColNumber = tempArr[1].split(''+lastRowNumber)[0];
|
|
|
-// for (const key in worksheet) {
|
|
|
-// if (key.endsWith(firstRowNumber) && key.replace(/[^0-9]/ig, "") === firstRowNumber) {
|
|
|
-// titleRowKey.push(key)
|
|
|
-// titleRowValue.push(worksheet[key].v)
|
|
|
-// }
|
|
|
-// }
|
|
|
-// if (fieldSet && fieldSet.length > 0) {
|
|
|
-// let length = fieldSet.length;
|
|
|
-// length = length <= titleRowKey.length ? length : titleRowKey.length;
|
|
|
-// for (let i = 0; i < length; i++) {
|
|
|
-// const vk = titleRowKey[i];
|
|
|
-// const item = fieldSet[i];
|
|
|
-// const field: any = {}
|
|
|
-// if (typeof item === 'string') {
|
|
|
-// field.field = item;
|
|
|
-// field.title = worksheet[vk].v;
|
|
|
-// worksheet[vk] = {t: "s", v: item, h: item, w: item}
|
|
|
-// } else if (typeof item.field === "string") {
|
|
|
-// field.field = item.field;
|
|
|
-// field.title = worksheet[vk].v;
|
|
|
-// worksheet[vk] = {t: "s", v: item.field, h: item.field, w: item.field};
|
|
|
-// if (typeof item.validate === "function") {
|
|
|
-// field.validate = item.validate
|
|
|
-// needLoop = true;
|
|
|
-// }
|
|
|
-// if (typeof item.importFormatter === "function") {
|
|
|
-// field.importFormatter = item.importFormatter
|
|
|
-// needLoop = true;
|
|
|
-// }
|
|
|
-// if ((item.data instanceof Array && item.data.length > 0)
|
|
|
-// || _.isPlainObject(item.data) && Object.keys(item.data).length > 0) {
|
|
|
-// field.data = item.data
|
|
|
-// needLoop = true;
|
|
|
-// }
|
|
|
-// }
|
|
|
-// fields.push(field)
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-//
|
|
|
-// if (fieldValidate && typeof fieldValidate === "function") {
|
|
|
-// if (fieldValidate(fields, titleRowValue) !== true) {
|
|
|
-// reject("fields validate error");
|
|
|
-// return
|
|
|
-// }
|
|
|
-// }
|
|
|
-//
|
|
|
-// const allData = XLSX.utils.sheet_to_json(worksheet);
|
|
|
-// let okData: any[] = [], errorData: any[] = [], errorMsgData: ErrorMsgDataItem[] = [];
|
|
|
-// const needItemLoop = needLoop;
|
|
|
-// if (rowValidate && typeof rowValidate === "function") {
|
|
|
-// needLoop = true;
|
|
|
-// }
|
|
|
-// if (needLoop === true) {
|
|
|
-// for (let index = 0; index < allData.length; index++) {
|
|
|
-// const row: any = allData[index];
|
|
|
-// const rowNumber = dataStartRow + index;
|
|
|
-// row.__importID__ = rowNumber
|
|
|
-// let isRowOk: boolean = true;
|
|
|
-// if (needItemLoop) {
|
|
|
-// for (let num = 0; num < fields.length; num++) {
|
|
|
-// const field = fields[num];
|
|
|
-// const ov = row[field.field];
|
|
|
-// let nv: any = ov;
|
|
|
-//
|
|
|
-// let hasError: boolean = false;
|
|
|
-// const rowNumber = dataStartRow + index;
|
|
|
-// const ei: ErrorMsgDataItem = {
|
|
|
-// errorId: rowNumber + '_' + field.field,
|
|
|
-// importID: rowNumber,
|
|
|
-// field: field.field,
|
|
|
-// title: field.title,
|
|
|
-// value: ov,
|
|
|
-// errormessage: ""
|
|
|
-// }
|
|
|
-//
|
|
|
-// // 格式化
|
|
|
-// if (field.data instanceof Array) {
|
|
|
-// nv = undefined;
|
|
|
-// ei.errormessage = "字典匹配失败"
|
|
|
-// _.forEach(field.data, (v, index) => {
|
|
|
-// if (v.text === ov) {
|
|
|
-// nv = v.id;
|
|
|
-// return
|
|
|
-// }
|
|
|
-// })
|
|
|
-// } else if (_.isPlainObject(field.data)) {
|
|
|
-// nv = undefined;
|
|
|
-// ei.errormessage = "字典匹配失败"
|
|
|
-// _.forEach(field.data, (value, key) => {
|
|
|
-// if (value === ov) {
|
|
|
-// nv = key;
|
|
|
-// return
|
|
|
-// }
|
|
|
-// })
|
|
|
-// }
|
|
|
-//
|
|
|
-// if (field.importFormatter) {
|
|
|
-// const vdata: ValidateObject = {
|
|
|
-// field,
|
|
|
-// ov,
|
|
|
-// nv,
|
|
|
-// rowIndex: index,
|
|
|
-// data: row,
|
|
|
-// rowDatas: allData
|
|
|
-// }
|
|
|
-// nv = undefined;
|
|
|
-// ei.errormessage = "格式化失败";
|
|
|
-// nv = field.importFormatter(vdata)
|
|
|
-// }
|
|
|
-//
|
|
|
-// if (nv === undefined || nv === null) {
|
|
|
-// hasError = true;
|
|
|
-// } else {
|
|
|
-// row[field.field] = nv;
|
|
|
-// ei.errormessage = "";
|
|
|
-// }
|
|
|
-//
|
|
|
-// // 校验
|
|
|
-// if (field.validate) {
|
|
|
-// const vdata: ValidateObject = {
|
|
|
-// field,
|
|
|
-// ov,
|
|
|
-// nv,
|
|
|
-// rowIndex: index,
|
|
|
-// data: row,
|
|
|
-// rowDatas: allData
|
|
|
-// }
|
|
|
-// const errormessage: true | string = field.validate(vdata);
|
|
|
-// if (errormessage === true) {
|
|
|
-//
|
|
|
-// } else {
|
|
|
-// hasError = true;
|
|
|
-// ei.errormessage = ei.errormessage + "/" + errormessage;
|
|
|
-// }
|
|
|
-// }
|
|
|
-// if (hasError === true) {
|
|
|
-// isRowOk = false;
|
|
|
-// errorMsgData.push(ei);
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// if (rowValidate && typeof rowValidate === "function") {
|
|
|
-// const errormessage: true | string = rowValidate({
|
|
|
-// fields,
|
|
|
-// data: row,
|
|
|
-// rowIndex: index,
|
|
|
-// rowDatas: allData
|
|
|
-// })
|
|
|
-// if (errormessage === true) {
|
|
|
-//
|
|
|
-// } else {
|
|
|
-// isRowOk = false;
|
|
|
-//
|
|
|
-// const ei: ErrorMsgDataItem = {
|
|
|
-// errorId: rowNumber + '',
|
|
|
-// field: "row",
|
|
|
-// title: "数据行",
|
|
|
-// value: "当前行的数据",
|
|
|
-// importID: rowNumber,
|
|
|
-// errormessage
|
|
|
-// }
|
|
|
-// errorMsgData.push(ei);
|
|
|
-// }
|
|
|
-// }
|
|
|
-// row.__hasError__ = !isRowOk
|
|
|
-// if (isRowOk === true) {
|
|
|
-// okData.push(row)
|
|
|
-// } else {
|
|
|
-// errorData.push(row)
|
|
|
-// }
|
|
|
-// }
|
|
|
-//
|
|
|
-// } else {
|
|
|
-// // 添加数据的唯一标识
|
|
|
-// for (let index = 0; index < allData.length; index++) {
|
|
|
-// const row: any = allData[index];
|
|
|
-// const rowNumber = dataStartRow + index;
|
|
|
-// row.__importID__ = rowNumber;
|
|
|
-// row.__hasError__ = false
|
|
|
-// }
|
|
|
-// okData = allData;
|
|
|
-// }
|
|
|
-// if (otherValidate && typeof otherValidate === "function") {
|
|
|
-// otherValidate({allData, okData, errorData, errorMsgData}, resolve);
|
|
|
-// } else {
|
|
|
-// resolve({allData, okData, errorData, errorMsgData});
|
|
|
-// }
|
|
|
-// // clearLoading()
|
|
|
-// })
|
|
|
-// }, 50);
|
|
|
-// })
|
|
|
-// }
|
|
|
-//
|
|
|
-// export declare interface ImportExcelOption {
|
|
|
-// // 字段设置
|
|
|
-// fields: Field[],
|
|
|
-// // 字段校验方法
|
|
|
-// fieldValidate?: ((fields: Field[], columnTitles: string[]) => boolean) | undefined,
|
|
|
-// // 数据行校验方法
|
|
|
-// rowValidate?: ((rv: RowValidateObject) => true | string) | undefined,
|
|
|
-// // 客户端校验完成后调用
|
|
|
-// afterClientValidate?: AfterClientValidate,
|
|
|
-// // Excel起始数据行的的行号 默认给定为2
|
|
|
-// dataStartRow?: number,
|
|
|
-// // Excel标题行的的行号 默认给定为1
|
|
|
-// titleRowNumber?: number,
|
|
|
-// // 导入完成后调用 回传结果数据
|
|
|
-// onImportAfter?: (result: ImportResult) => {}
|
|
|
-// // 隐藏所有数据表格, 默认false
|
|
|
-// hidAllDataGrid?: boolean,
|
|
|
-// // 隐藏正确数据表格 默认 false
|
|
|
-// hidOKDataGrid?: boolean,
|
|
|
-// // 隐藏错误数据的表格 默认false
|
|
|
-// hidErrorDataGrid?: boolean,
|
|
|
-// // 隐藏错误信息表格 默认false
|
|
|
-// hidErrorMsgGrid?: boolean,
|
|
|
-// // 所有数据表格的分页大小, 0 为不分页
|
|
|
-// dataGridPageSize?: 0 | 10 | 20 | 50 | 100 | 200 | 500 | 1000,
|
|
|
-// // 错误信息表格的分页大小, 0 为不分页
|
|
|
-// errorMsgGridPageSize?: 0 | 10 | 20 | 50 | 100 | 200 | 500 | 1000,
|
|
|
-// // 导入模版的名称
|
|
|
-// templateName?: string,
|
|
|
-// // 导入模板下载地址
|
|
|
-// dowLoadUrl?: string,
|
|
|
-// // 标题
|
|
|
-// title?: string,
|
|
|
-// // 弹窗高
|
|
|
-// height?: string,
|
|
|
-// // 弹窗宽
|
|
|
-// width?: string,
|
|
|
-// // 默认显示的表格
|
|
|
-// defaultShowData?: "allData" | "okData" | "errorData",
|
|
|
-// // 自定义错误信息表格的列宽
|
|
|
-// errMsgGridColWidths?: number[],
|
|
|
-// // 外部定义的控件
|
|
|
-// toolBar?: any[],
|
|
|
-// // 关闭回调
|
|
|
-// onClose?: string | (() => void)
|
|
|
-// }
|
|
|
-//
|
|
|
-// /**
|
|
|
-// * 打开excel导入的方法
|
|
|
-// * @param option 参数配置
|
|
|
-// * @param sender
|
|
|
-// */
|
|
|
-// export function importExcel(option: ImportExcelOption, sender: any): ExcelImportDialog {
|
|
|
-// const dialog = new ExcelImportDialog({option})
|
|
|
-// dialog.showDialog(sender);
|
|
|
-// return dialog
|
|
|
-// }
|
|
|
+import XLSX from 'xlsx'
|
|
|
+import _ from 'lodash'
|
|
|
+import {ExcelImportDialog} from "./ExcelImportDialog";
|
|
|
+import * as path from "path";
|
|
|
+import {lookupFn} from "./lib/lib";
|
|
|
+import {Scope} from "./Scope";
|
|
|
+// import {clearLoading, loading} from "./renderers";
|
|
|
+// @ts-ignore
|
|
|
+// import XLSX_EXPORT from 'xlsx_export';
|
|
|
+// @ts-ignore
|
|
|
+const XLSX_EXPORT = window.LAY_EXCEL
|
|
|
+
|
|
|
+export {XLSX};
|
|
|
+export {XLSX_EXPORT}
|
|
|
+
|
|
|
+export function readExcel(file: File): Promise<any> {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ if (!file) {
|
|
|
+ reject("文件读取失败!!!")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var reader = new FileReader();
|
|
|
+ reader.onload = function (e) {
|
|
|
+ if (e.target) {
|
|
|
+ const data = e.target.result;
|
|
|
+ const workbook = XLSX.read(data, {type: 'binary'});
|
|
|
+ resolve(workbook);
|
|
|
+ } else {
|
|
|
+ reject("文件读取失败!!!")
|
|
|
+ }
|
|
|
+ };
|
|
|
+ try {
|
|
|
+ reader.readAsBinaryString(file);
|
|
|
+ } catch (e) {
|
|
|
+ reject(e)
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+export declare interface ErrorMsgDataItem {
|
|
|
+ /** 错误id 由allData 的__importID__字段值 + "_" + field的值 表示哪一行的哪一列出错,行校验错误时候直接为allData 的__importID__ + "" */
|
|
|
+ errorId: string
|
|
|
+ /** 对应数据行 allData 的__importID__字段值 */
|
|
|
+ importID: number
|
|
|
+ /** 字段 */
|
|
|
+ dataIndex: string
|
|
|
+ /** 字段值 */
|
|
|
+ header: string
|
|
|
+ /** 字段值 */
|
|
|
+ value: string
|
|
|
+ /** 错误信息 */
|
|
|
+ errormessage: string
|
|
|
+}
|
|
|
+
|
|
|
+export declare interface ImportResult {
|
|
|
+ /** 所有导入的数据,如果有字典会格式化到字典,格式化错误的保持原始值 */
|
|
|
+ allData: any[]
|
|
|
+ /** 导入正确的数据 */
|
|
|
+ okData: any[]
|
|
|
+ /** 导入错误的数据 */
|
|
|
+ errorData: any[]
|
|
|
+ /** 导入错误数据的错误明细 */
|
|
|
+ errorMsgData: ErrorMsgDataItem[]
|
|
|
+}
|
|
|
+
|
|
|
+/** 定义参数列 */
|
|
|
+export declare interface Column {
|
|
|
+ /** 字段 */
|
|
|
+ dataIndex: string
|
|
|
+ /** 字段名 */
|
|
|
+ header: string
|
|
|
+ /** 校验方法,校验通过返回true, 否则返回错误信息 会记录到错误列表里面 errorMsgData */
|
|
|
+ validate?: ((v: ValidateObject) => true | string) | string
|
|
|
+ /** 格式化,表格显示 兼容默认弹出框表格的formatter */
|
|
|
+ fix?: ((v: any) => any) | string
|
|
|
+ /** 导入格式化 返回null或者undefined 表示格式化错误,会记录到错误列表里面 errorMsgData */
|
|
|
+ importFormatter?: ((v: ValidateObject) => null | undefined | string | number) | string
|
|
|
+ /** 字典, 参与数据校验和表格显示格式化, 校验不通过的,会记录到错误列表里面 errorMsgData 同时兼容默认弹出框表格的字典 */
|
|
|
+ data?: any | { id: string | number, text: string }
|
|
|
+}
|
|
|
+
|
|
|
+/** 格式化及校验的参数 */
|
|
|
+export declare interface ValidateObject {
|
|
|
+ column: Column
|
|
|
+ ov: any,
|
|
|
+ nv: any,
|
|
|
+ rowIndex: number,
|
|
|
+ data: any,
|
|
|
+ rowDatas: any[],
|
|
|
+}
|
|
|
+
|
|
|
+/** 行数据校验的参数 */
|
|
|
+export declare interface RowValidateObject {
|
|
|
+ columns: Column[],
|
|
|
+ data: any,
|
|
|
+ rowIndex: number,
|
|
|
+ rowDatas: any[]
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 定义切口,可以在外部修改数据
|
|
|
+ */
|
|
|
+export declare type AfterClientValidate =
|
|
|
+ ((importResult: ImportResult, resolve: (value?: (ImportResult | PromiseLike<ImportResult> | undefined)) => void) => ImportResult)
|
|
|
+ | undefined
|
|
|
+
|
|
|
+export function readExcelWithColumnsSet(topScope: Scope,
|
|
|
+ file: File,
|
|
|
+ columnsSet: any[],
|
|
|
+ dataStartRow: number = 2,
|
|
|
+ titleRowNumber: number = 1,
|
|
|
+ rowValidate: ((rv: RowValidateObject) => true | string) | undefined = undefined,
|
|
|
+ otherValidate: AfterClientValidate = undefined,
|
|
|
+ fieldValidate: ((columns: Column[], columnTitles: string[]) => boolean) | undefined = undefined): Promise<ImportResult> {
|
|
|
+ return new Promise<ImportResult>((resolve, reject) => {
|
|
|
+
|
|
|
+ const promiseArr = []
|
|
|
+ for (let i = 0; i < columnsSet.length; i++) {
|
|
|
+ const fix = columnsSet[i].fix;
|
|
|
+ if (_.isArray(fix) && fix.length > 0) {
|
|
|
+ const ss = fix[0].toLowerCase()
|
|
|
+ if (ss.indexOf("date") > -1 || ss.indexOf("time") > -1) {
|
|
|
+ columnsSet[i].importFormatter = function (vdata: ValidateObject) {
|
|
|
+ // @ts-ignore
|
|
|
+ return window.moment(vdata.ov)-0
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const fn = lookupFn(topScope, fix[0])
|
|
|
+ promiseArr.push(fn(null, columnsSet[i]))
|
|
|
+ delete columnsSet[i].fix
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if (_.isString(fix)) {
|
|
|
+ const ss = fix.toLowerCase()
|
|
|
+ if (ss.indexOf("date") > -1 || ss.indexOf("time") > -1) {
|
|
|
+ columnsSet[i].importFormatter = function (vdata: ValidateObject) {
|
|
|
+ // @ts-ignore
|
|
|
+ return window.moment(vdata.ov)-0
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const fn = lookupFn(topScope, fix)
|
|
|
+ promiseArr.push(fn(null, columnsSet[i]))
|
|
|
+ delete columnsSet[i].fix
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ const read = ()=>{
|
|
|
+ readExcel(file).then(workbook => {
|
|
|
+ const sheetNames = workbook.SheetNames; // 工作表名称集合
|
|
|
+ const worksheet = workbook.Sheets[sheetNames[0]]; // 这里我们只读取第一张sheet
|
|
|
+ const titleRowValue: any[] = [];
|
|
|
+ const titleRowKey: any[] = [];
|
|
|
+ let needLoop: boolean = false; // 是否需要迭代
|
|
|
+ let columns: Column[] = [];
|
|
|
+ if (worksheet && worksheet["!ref"]) {
|
|
|
+ const t = worksheet["!ref"];
|
|
|
+ const tempArr = t.split(':');
|
|
|
+ if (tempArr.length >= 2) {
|
|
|
+ let firstRowNumber = tempArr[0].replace(/[^0-9]/ig, "");
|
|
|
+
|
|
|
+ // 选取title的行,删除之前的行
|
|
|
+ if (titleRowNumber > firstRowNumber) {
|
|
|
+ for (let i = firstRowNumber; i < titleRowNumber; i++) {
|
|
|
+ for (const key in worksheet) {
|
|
|
+ if (key.endsWith(i) && key.replace(/[^0-9]/ig, "") === i) {
|
|
|
+ delete worksheet[key];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const fc = tempArr[0].replace(/[^a-z]/ig, "");
|
|
|
+ firstRowNumber = titleRowNumber + '';
|
|
|
+ worksheet["!ref"] = fc+firstRowNumber + ":" + tempArr[1]
|
|
|
+ }
|
|
|
+ const lastRowNumber = tempArr[1].replace(/[^0-9]/ig, "");
|
|
|
+ // const firstColNumber = tempArr[0].split(''+firstRowNumber)[0];
|
|
|
+ // const lastColNumber = tempArr[1].split(''+lastRowNumber)[0];
|
|
|
+ for (const key in worksheet) {
|
|
|
+ if (key.endsWith(firstRowNumber) && key.replace(/[^0-9]/ig, "") === firstRowNumber) {
|
|
|
+ titleRowKey.push(key)
|
|
|
+ titleRowValue.push(worksheet[key].v)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (columnsSet && columnsSet.length > 0) {
|
|
|
+ let length = columnsSet.length;
|
|
|
+ length = length <= titleRowKey.length ? length : titleRowKey.length;
|
|
|
+ for (let i = 0; i < length; i++) {
|
|
|
+ const vk = titleRowKey[i];
|
|
|
+ const item = columnsSet[i];
|
|
|
+ const column: any = {}
|
|
|
+ if (typeof item === 'string') {
|
|
|
+ column.dataIndex = item;
|
|
|
+ column.header = worksheet[vk].v;
|
|
|
+ worksheet[vk] = {t: "s", v: item, h: item, w: item}
|
|
|
+ } else if (typeof item.dataIndex === "string") {
|
|
|
+ column.dataIndex = item.dataIndex;
|
|
|
+ column.header = worksheet[vk].v;
|
|
|
+ worksheet[vk] = {t: "s", v: item.dataIndex, h: item.dataIndex, w: item.dataIndex};
|
|
|
+ if (typeof item.validate === "function") {
|
|
|
+ column.validate = item.validate
|
|
|
+ needLoop = true;
|
|
|
+ }
|
|
|
+ if (typeof item.importFormatter === "function") {
|
|
|
+ column.importFormatter = item.importFormatter
|
|
|
+ needLoop = true;
|
|
|
+ }
|
|
|
+ if ((item.data instanceof Array && item.data.length > 0)
|
|
|
+ || _.isPlainObject(item.data) && Object.keys(item.data).length > 0) {
|
|
|
+ column.data = item.data
|
|
|
+ needLoop = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ columns.push(column)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fieldValidate && typeof fieldValidate === "function") {
|
|
|
+ if (fieldValidate(columns, titleRowValue) !== true) {
|
|
|
+ reject("fields validate error");
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const allData = XLSX.utils.sheet_to_json(worksheet);
|
|
|
+ let okData: any[] = [], errorData: any[] = [], errorMsgData: ErrorMsgDataItem[] = [];
|
|
|
+ const needItemLoop = needLoop;
|
|
|
+ if (rowValidate && typeof rowValidate === "function") {
|
|
|
+ needLoop = true;
|
|
|
+ }
|
|
|
+ if (needLoop === true) {
|
|
|
+ for (let index = 0; index < allData.length; index++) {
|
|
|
+ const row: any = allData[index];
|
|
|
+ const rowNumber = dataStartRow + index;
|
|
|
+ row.__importID__ = rowNumber
|
|
|
+ let isRowOk: boolean = true;
|
|
|
+ if (needItemLoop) {
|
|
|
+ for (let num = 0; num < columns.length; num++) {
|
|
|
+ const column = columns[num];
|
|
|
+ const ov = row[column.dataIndex];
|
|
|
+ let nv: any = ov;
|
|
|
+
|
|
|
+ let hasError: boolean = false;
|
|
|
+ const rowNumber = dataStartRow + index;
|
|
|
+ const ei: ErrorMsgDataItem = {
|
|
|
+ errorId: rowNumber + '_' + column.dataIndex,
|
|
|
+ importID: rowNumber,
|
|
|
+ dataIndex: column.dataIndex,
|
|
|
+ header: column.header,
|
|
|
+ value: ov,
|
|
|
+ errormessage: ""
|
|
|
+ }
|
|
|
+
|
|
|
+ // 格式化
|
|
|
+ if (column.data instanceof Array) {
|
|
|
+ nv = undefined;
|
|
|
+ ei.errormessage = "字典匹配失败"
|
|
|
+ _.forEach(column.data, (v, index) => {
|
|
|
+ if (v.text === ov) {
|
|
|
+ nv = v.id;
|
|
|
+ return
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else if (_.isPlainObject(column.data)) {
|
|
|
+ nv = undefined;
|
|
|
+ ei.errormessage = "字典匹配失败"
|
|
|
+ _.forEach(column.data, (value, key) => {
|
|
|
+ if (value === ov) {
|
|
|
+ nv = key;
|
|
|
+ return
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( typeof column.importFormatter === 'function') {
|
|
|
+ const vdata: ValidateObject = {
|
|
|
+ column,
|
|
|
+ ov,
|
|
|
+ nv,
|
|
|
+ rowIndex: index,
|
|
|
+ data: row,
|
|
|
+ rowDatas: allData
|
|
|
+ }
|
|
|
+ nv = undefined;
|
|
|
+ ei.errormessage = "格式化失败";
|
|
|
+ nv = column.importFormatter(vdata)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!nv) {
|
|
|
+ hasError = true;
|
|
|
+ } else {
|
|
|
+ row[column.dataIndex] = nv;
|
|
|
+ ei.errormessage = "";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 校验
|
|
|
+ if (typeof column.validate === 'function') {
|
|
|
+ const vdata: ValidateObject = {
|
|
|
+ column,
|
|
|
+ ov,
|
|
|
+ nv,
|
|
|
+ rowIndex: index,
|
|
|
+ data: row,
|
|
|
+ rowDatas: allData
|
|
|
+ }
|
|
|
+ const errormessage: true | string = column.validate(vdata);
|
|
|
+ if (errormessage === true) {
|
|
|
+
|
|
|
+ } else {
|
|
|
+ hasError = true;
|
|
|
+ ei.errormessage = ei.errormessage + "/" + errormessage;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (hasError === true) {
|
|
|
+ isRowOk = false;
|
|
|
+ errorMsgData.push(ei);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (rowValidate && typeof rowValidate === "function") {
|
|
|
+ const errormessage: true | string = rowValidate({
|
|
|
+ columns,
|
|
|
+ data: row,
|
|
|
+ rowIndex: index,
|
|
|
+ rowDatas: allData
|
|
|
+ })
|
|
|
+ if (errormessage === true) {
|
|
|
+
|
|
|
+ } else {
|
|
|
+ isRowOk = false;
|
|
|
+
|
|
|
+ const ei: ErrorMsgDataItem = {
|
|
|
+ errorId: rowNumber + '',
|
|
|
+ dataIndex: "row",
|
|
|
+ header: "数据行",
|
|
|
+ value: "当前行的数据",
|
|
|
+ importID: rowNumber,
|
|
|
+ errormessage
|
|
|
+ }
|
|
|
+ errorMsgData.push(ei);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ row.__hasError__ = !isRowOk
|
|
|
+ if (isRowOk === true) {
|
|
|
+ okData.push(row)
|
|
|
+ } else {
|
|
|
+ errorData.push(row)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // 添加数据的唯一标识
|
|
|
+ for (let index = 0; index < allData.length; index++) {
|
|
|
+ const row: any = allData[index];
|
|
|
+ const rowNumber = dataStartRow + index;
|
|
|
+ row.__importID__ = rowNumber;
|
|
|
+ row.__hasError__ = false
|
|
|
+ }
|
|
|
+ okData = allData;
|
|
|
+ }
|
|
|
+ if (otherValidate && typeof otherValidate === "function") {
|
|
|
+ otherValidate({allData, okData, errorData, errorMsgData}, resolve);
|
|
|
+ } else {
|
|
|
+ resolve({allData, okData, errorData, errorMsgData});
|
|
|
+ }
|
|
|
+ // clearLoading()
|
|
|
+ }).catch(e=>{
|
|
|
+ reject(e)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ if (promiseArr.length > 0) {
|
|
|
+ Promise.all(promiseArr).then(resArr=>{
|
|
|
+ for (let i = 0; i < resArr.length; i++) {
|
|
|
+ const tmp = resArr[i]
|
|
|
+ tmp.config.data = []
|
|
|
+ if (tmp && tmp.r && Array.isArray(tmp.r.field) && Array.isArray(tmp.r.data)) {
|
|
|
+ if (tmp.r.field.length > 1) {
|
|
|
+ const keyKey = tmp.r.field[0]
|
|
|
+ const valueKey = tmp.r.field[1]
|
|
|
+ for (let j = 0; j < tmp.r.data.length; j++) {
|
|
|
+ const it = tmp.r.data[j]
|
|
|
+ const newIt: any = {}
|
|
|
+ newIt.id = it[keyKey]
|
|
|
+ newIt.text = it[valueKey]
|
|
|
+ tmp.config.data.push(newIt)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ read()
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ setTimeout(read, 50);
|
|
|
+ }
|
|
|
+
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+export declare interface ImportExcelOption {
|
|
|
+ // 字段设置
|
|
|
+ columns: Column[],
|
|
|
+ // 字段校验方法
|
|
|
+ fieldValidate?: ((columns: Column[], columnTitles: string[]) => boolean) | string | undefined,
|
|
|
+ // 数据行校验方法
|
|
|
+ rowValidate?: ((rv: RowValidateObject) => true | string) | string |undefined,
|
|
|
+ // 客户端校验完成后调用
|
|
|
+ afterClientValidate?: AfterClientValidate | string,
|
|
|
+ // Excel起始数据行的的行号 默认给定为2
|
|
|
+ dataStartRow?: number,
|
|
|
+ // Excel标题行的的行号 默认给定为1
|
|
|
+ titleRowNumber?: number,
|
|
|
+ // 导入完成后调用 回传结果数据
|
|
|
+ onImportAfter?: ((result: ImportResult) => {}) | string | undefined
|
|
|
+ // 隐藏所有数据表格, 默认false
|
|
|
+ hidAllDataGrid?: boolean,
|
|
|
+ // 隐藏正确数据表格 默认 false
|
|
|
+ hidOKDataGrid?: boolean,
|
|
|
+ // 隐藏错误数据的表格 默认false
|
|
|
+ hidErrorDataGrid?: boolean,
|
|
|
+ // 隐藏错误信息表格 默认false
|
|
|
+ hidErrorMsgGrid?: boolean,
|
|
|
+ // 所有数据表格的分页大小, 0 为不分页
|
|
|
+ dataGridPageSize?: 0 | 10 | 20 | 50 | 100 | 200 | 500 | 1000,
|
|
|
+ // 错误信息表格的分页大小, 0 为不分页
|
|
|
+ errorMsgGridPageSize?: 0 | 10 | 20 | 50 | 100 | 200 | 500 | 1000,
|
|
|
+ // 导入模版的名称
|
|
|
+ templateName?: string,
|
|
|
+ // 导入模板下载地址
|
|
|
+ dowLoadUrl?: string,
|
|
|
+ // 标题
|
|
|
+ title?: string,
|
|
|
+ // 弹窗高
|
|
|
+ height?: string,
|
|
|
+ // 弹窗宽
|
|
|
+ width?: string,
|
|
|
+ // 默认显示的表格
|
|
|
+ defaultShowData?: "allData" | "okData" | "errorData",
|
|
|
+ // 自定义错误信息表格的列宽
|
|
|
+ errMsgGridColWidths?: number[],
|
|
|
+ // 外部定义的控件
|
|
|
+ toolBar?: any[],
|
|
|
+ // 关闭回调
|
|
|
+ onClose?: string | (() => void),
|
|
|
+ // 提取数据按钮的名称
|
|
|
+ tQButtonText?: string | null | undefined
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 打开excel导入的方法
|
|
|
+ * @param option 参数配置
|
|
|
+ * @param sender
|
|
|
+ */
|
|
|
+export function importExcel(option: ImportExcelOption, sender: any): ExcelImportDialog {
|
|
|
+ const dialog = new ExcelImportDialog(option)
|
|
|
+ dialog.showDialog(sender,{}, {});
|
|
|
+ return dialog
|
|
|
+}
|