<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="less">
@import "./app-data-upload.less";
</style>
