<template> <div class="app-data-upload-view" v-loading.fullscreen="isUploading" element-loading-background="rgba(57, 57, 57, 0.2)"> <input ref="inputUpLoad" type="file" style="display: none" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" @change="importFile" /> <div class="main-content"> <div v-if="importDataArray.length === 0 && !isUploading && uploadProgress !== 100" class="upload-container" @click="handleUpLoad"> <img class="icon-import" src="@/assets/img/icon-import.svg" /> <span class="select-file-text">{{ $t("components.appDataUploadView.selectfile") }}</span> </div> <div class="data-info-container" v-if="importDataArray.length > 0 || isUploading || uploadProgress == 100"> <el-progress class="progress" v-show="isUploading" :text-inside="true" :stroke-width="14" :percentage="uploadProgress"></el-progress> <div class="message-container"> <div class="result-list"> <template v-if="(errorInfos.length === 0)"> <span>{{ promptInfo }}</span> </template> <template v-else> <span>导入错误信息</span> <ui> <li class="error-item" v-for="(item, index) in errorInfos" :key="index"> <span v-if="item.index">{{ $t('components.appDataUploadView.start') }} {{item.index}} {{ $t('components.appDataUploadView.row') }}:</span><span v-html="item.info"></span> </li> </ui> </template> </div> </div> </div> </div> <div class="second-content"> <div class="import-template-message">{{ $t('components.appDataUploadView.datatemplatemessage') }}</div> <div class="import-template"> <img class="icon-link" src="@/assets/img/icon-link.svg" /> <span style="cursor: pointer;" @click="downloadTemp">{{ $t('components.appDataUploadView.datatemplate') }}</span> </div> </div> <el-row class="button-container"> <el-button type="primary" @click="handleCancel">{{ $t("components.appDataUploadView.cancel") }}</el-button> <el-button :disabled="importDataArray.length === 0" :loading="isUploading" type="primary" class="primary-button" @click="uploadServer">{{ $t("components.appDataUploadView.uploadserver") }}</el-button> </el-row> </div> </template> <script lang="ts"> import XLSX from "xlsx"; import CodeListService from "@/codelist/codelist-service"; import { Vue, Component, Prop, Watch } from "vue-property-decorator"; import { Environment } from "@/environments/environment"; import moment from "moment"; import { Util } from "@/utils"; @Component({}) export default class AppDataUploadView extends Vue { /** * 传入视图上下文 * * @type {string} * @memberof AppDataUploadView */ @Prop() protected viewdata!: string; /** * 传入视图参数 * * @type {string} * @memberof AppDataUploadView */ @Prop() protected viewparam!: string; /** * 代码表服务对象 * * @type {CodeListService} * @memberof AppDataUploadView */ public codeListService: CodeListService = new CodeListService({ $store: this.$store }); /** * 实体服务对象 * * @protected * @type {EntityService} * @memberof AppDataUploadView */ protected entityService: any; /** * 视图参数 * * @type {*} * @memberof AppDataUploadView */ protected viewparams: any = {}; /** * 导入数据模型 * * @type {Array<*>} * @memberof AppDataUploadView */ protected importDataModel: Array<any> = []; /** * 导入数据集合 * * @type {Array<*>} * @memberof AppDataUploadView */ public importDataArray: Array<any> = []; /** * 导入标识 * * @type {string} * @memberof AppDataUploadView */ protected importId: string = ""; /** * 是否已有导入数据 * * @type {boolean} * @memberof AppDataUploadView */ public hasImported: boolean = false; /** * 导入数据识别项属性 * * @type {string} * @memberof AppDataUploadView */ public importUniqueItem: string = ""; /** * 提示信息 * * @type {string} * @memberof AppDataUploadView */ public promptInfo: string = ""; /** * 导入状态 * * @type {boolean} * @memberof AppDataUploadView */ public isUploading: boolean = false; /** * 导入失败数据 * * @type {string} * @memberof AppDataUploadView */ public importErrorData: Array<any> = []; /** * 读取完成的数据 * * @type {*} * @memberof AppDataUploadView */ public workBookData: any; /** * 所有的代码表 * * @type {*} * @memberof AppDataUploadView */ public allCodeList: any; /** * 属性Map(用作属性转化) * * @type {*} * @memberof AppDataUploadView */ public allFieldMap: Map<string, any> = new Map(); /** * 上传服务器数据切片数 * * @type {number} * @memberof AppDataUploadView */ public sliceUploadCnt: number = Environment.sliceUploadCnt; /** * 上传服务器进度条百分比 * * @type {number} * @memberof AppDataUploadView */ public uploadProgress: number = 0; /** * 是否忽略导入错误 * * @type {boolean} * @memberof AppDataUploadView */ public ignoreError: boolean = false; /** * 错误消息集合 * * @type {any[]} * @memberof AppDataUploadView */ public errorInfos: any[] = []; /** * 导入成功计数 * * @type {number} * @memberof AppDataUploadView */ public successCount: number = 0; /** * 视图参数变化 * * @param {*} newVal * @param {*} oldVal * @memberof AppDataUploadView */ @Watch("viewparam", { immediate: true, deep: true }) onParamData(newVal: any, oldVal: any) { if (newVal) { Object.assign(this.viewparams, JSON.parse(this.viewparam)); this.initBasic(); } } /** * 初始化基础数据 * * @memberof AppDataUploadView */ public async initBasic() { if (this.viewparams.importId) { this.importId = this.viewparams.importId; } if (this.viewparams.importData) { this.importDataModel = Object.values(this.viewparams.importData); this.bubbleSort(this.importDataModel, this.importDataModel.length); } this.importDataModel.forEach((item: any) => { if (item.isuniqueitem) { this.importUniqueItem = item.headername; } this.allFieldMap.set(item.headername, item); }); if (this.viewparams.serviceName) { this.entityService = await window.entityServiceRegister.getService(this.viewparams.serviceName.toLowerCase()); } this.ignoreError = this.viewparams.ignoreError === true || this.viewparams.ignoreError === 'true' ? true : false; //获取代码表值 this.allCodeList = await this.getChartAllCodeList(); } /** * 冒泡排序 * * @param {*} newVal * @param {*} oldVal * @memberof AppDataUploadView */ public bubbleSort(array: Array<any>, length: number) { for (let i = 0; i < length; i++) { for (let j = 0; j < length - i - 1; j++) { if (array[j].order > array[j + 1].order) { let temp: any; temp = array[j + 1]; array[j + 1] = array[j]; array[j] = temp; } } } } /** * 下载导入数据模板 * * @memberof AppDataUploadView */ public downloadTemp() { this.importExcel(this.viewparams.appDeLogicName + this.$t("components.appDataUploadView.datatemplate"), []); } /** * 选择文件 * * @memberof AppDataUploadView */ public handleUpLoad() { (this.$refs.inputUpLoad as any).click(); } /** * 上传服务器 * * @memberof AppDataUploadView */ public uploadServer() { if (this.importDataArray.length == 0 || !this.entityService) { return; } let tempDataArray: Array<any> = []; this.transformData(this.importDataArray, tempDataArray); this.hasImported = true; this.isUploading = true; this.uploadProgress = 0; this.successCount = 0; this.importDataArray = []; this.sliceUploadService(tempDataArray, 0); } /** * 数据切片上传 * * @memberof AppDataUploadView */ public sliceUploadService(dataArray: Array<any>, cnt: number) { if (cnt >= dataArray.length) { this.isUploading = false; this.uploadProgress = 100; this.$Notice.success({ desc: this.$t("components.appDataUploadView.completed") as string }); this.promptInfo = `${this.$t('components.appDataUploadView.completed')}, ${this.$t('components.appDataUploadView.totaldata')} ${this.successCount} ${this.$t('components.appDataUploadView.total')}`; return; } let sliceArray: Array<any> = []; if (dataArray) { sliceArray = dataArray.slice(cnt, cnt + this.sliceUploadCnt); } try { this.entityService .ImportData(this.viewdata, { name: this.importId, importData: sliceArray, ignoreError: this.ignoreError }) .then((res: any) => { const result: any = res.data; this.successCount += result.success; if (result.total !== result.success) { this.handleErrorInfo(result.errorinfo, cnt); if (!this.ignoreError) { this.isUploading = false; return; } } this.uploadProgress = Number(((cnt / dataArray.length) * 100).toFixed(2)); this.sliceUploadService(dataArray, cnt + this.sliceUploadCnt); }) .catch((error: any) => { this.isUploading = false; this.promptInfo = this.$t("components.appDataUploadView.importfailed") as string; }); } catch (error: any) { this.handleErrorInfo(error.errorinfo, cnt); if (!this.ignoreError) { this.isUploading = false; return; } this.uploadProgress = Number(((cnt / dataArray.length) * 100).toFixed(2)); this.sliceUploadService(dataArray, cnt + this.sliceUploadCnt); } } /** * 处理错误信息 * * @memberof AppDataUploadView */ public handleErrorInfo(infos: any[], cnt: number) { if (infos && infos.length) { infos.forEach((item: any) => { this.errorInfos.push(Object.assign({ index: cnt + item.row }, item)); }) } } /** * 取消 * * @memberof AppDataUploadView */ public handleCancel() { this.$emit("close", this.successCount > 0 ? [{ count: this.successCount }] : []); } /** * 导出excel * * @memberof AppDataUploadView */ public async importExcel(filename: string, _data: any) { const tHeader: Array<any> = []; this.importDataModel.forEach((item: any) => { tHeader.push(item.headername); }); this.$export.exportExcel().then((excel: any) => { excel.export_json_to_excel({ header: tHeader, //表头 必填 data: [], //具体数据 必填 filename: filename, //非必填 autoWidth: true, //非必填 bookType: "xlsx", //非必填 }); }); } /** * 确认 * * @memberof AppDataUploadView */ public handleOK() { this.$emit("close", this.successCount > 0 ? [{ count: this.successCount }] : []); } /** * 导入Excel * * @memberof AppDataUploadView */ public importFile($event: any) { let obj = $event.target || $event.srcElement; if (!obj.files) { return; } let f = obj.files[0]; let reader = new FileReader(); reader.onload = (e: any) => { let data = e.target.result; this.workBookData = XLSX.read(data, { type: "binary", cellDates: true }); let xlsxData = XLSX.utils.sheet_to_json(this.workBookData.Sheets[this.workBookData.SheetNames[0]]); let list1 = this.getFirstRow(this.workBookData); xlsxData = this.addXlsxData(xlsxData, list1); this.importDataArray = Util.deepCopy(xlsxData); this.promptInfo = this.$t('components.appDataUploadView.read') as string; (this.$refs.inputUpLoad as any).value = ""; }; reader.readAsBinaryString(f); } /** * 获取excel第一行的内容 * * @memberof AppDataUploadView */ public getFirstRow(wb: any) { //// 读取的excel单元格内容 let wbData = wb.Sheets[wb.SheetNames[0]]; // 匹配excel第一行的内容 let re = /^[A-Z]1$/; let temparr = []; // excel第一行内容赋值给数组 for (let key in wbData) { if (wbData.hasOwnProperty(key)) { if (re.test(key)) { temparr.push(wbData[key].h); } } } return temparr; } /** * 增加对应字段空白内容 * * @memberof AppDataUploadView */ public addXlsxData(xlsxData: any, list1: any) { // 空白字段替换值 let addData = null; for (let i = 0; i < xlsxData.length; i++) { // 要被JSON的数组 for (let j = 0; j < list1.length; j++) { // excel第一行内容 if (!xlsxData[i][list1[j]]) { xlsxData[i][list1[j]] = addData; } } } return xlsxData; } /** * 获取图表所需代码表 * * @memberof AppDataUploadView */ public async getChartAllCodeList() { let codeListMap: Map<string, any> = new Map(); if (Object.values(this.importDataModel).length > 0) { await Object.values(this.importDataModel).forEach(async (singleDataModel: any) => { if (singleDataModel.codelist) { let tempCodeListMap: Map<any, any> = new Map(); let res: any = await this.getCodeList(singleDataModel.codelist); if (res && res.length > 0) { res.forEach((codeListItem: any) => { tempCodeListMap.set(codeListItem.value, codeListItem.text); }); } codeListMap.set(singleDataModel.codelist.tag, tempCodeListMap); } }); } return codeListMap; } /** * 获取代码表 * * @returns {Promise<any>} * @memberof AppDataUploadView */ public getCodeList(codeListObject: any): Promise<any> { return new Promise((resolve: any, reject: any) => { if (codeListObject.tag && Object.is(codeListObject.type, "STATIC")) { const codelist = this.$store.getters.getCodeList(codeListObject.tag); if (codelist) { resolve([...JSON.parse(JSON.stringify(codelist.items))]); } else { console.log(`----${codeListObject.tag}----${this.$t("app.commonWords.codeNotExist") as string}`); } } else if (codeListObject.tag && Object.is(codeListObject.type, "DYNAMIC")) { this.codeListService .getItems(codeListObject.tag) .then((res: any) => { resolve(res); }) .catch((error: any) => { console.log( `----${codeListObject.tag}----${this.$t("app.commonWords.codeNotExist") as string}` ); }); } }); } /** * 转化数据 * * @memberof AppDataUploadView */ public transformData(data: Array<any>, result: Array<any>) { data.forEach((item: any) => { let curObject: any = {}; Object.keys(item).forEach((ele: any) => { // todo XLSX读取时间为国际时间(东8区)+8H转为标准时间 if (item[ele] instanceof Date) { const tempDate: Date = item[ele]; item[ele] = moment(tempDate) .add(8, "h") .format("YYYY-MM-DD HH:mm:ss"); } if (this.allFieldMap.get(ele).codelist) { let codelistTag: string = this.allFieldMap.get(ele).codelist.tag; let codelistIsNumber: boolean = this.allFieldMap.get(ele).codelist.isnumber; let curCodeList: any = this.transCodeList(codelistTag, codelistIsNumber, true); Object.defineProperty(curObject, this.allFieldMap.get(ele).name, { value: curCodeList.get(item[ele]), writable: true, enumerable: true, configurable: true, }); } else { Object.defineProperty(curObject, this.allFieldMap.get(ele).name, { value: item[ele], writable: true, enumerable: true, configurable: true, }); } }); result.push(curObject); }); } /** * 翻译代码表 * * @memberof AppDataUploadView */ public transCodeList(codeListTag: string, codelistIsNumber: boolean, isTransform: boolean) { let curCodeList: any = this.allCodeList.get(codeListTag); if (isTransform) { let tempCodelist: Map<string, string> = new Map(); curCodeList.forEach((item: string, key: string) => { let value: any = codelistIsNumber ? Number(key) : key; tempCodelist.set(item, value); }); curCodeList = tempCodelist; } return curCodeList; } } </script> <style lang="scss"> @import "./app-data-upload.scss"; </style>