|  | @@ -1081,4 +1081,305 @@ $(document).ready(() => {
 | 
	
		
			
				|  |  |          ledgerSpread.refresh();
 | 
	
		
			
				|  |  |          materialSpread.refresh();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 导入功能
 | 
	
		
			
				|  |  | +    // 上传图片
 | 
	
		
			
				|  |  | +    $('#upload-list').click(function () {
 | 
	
		
			
				|  |  | +        // if (materialChecklistData.length === 0) {
 | 
	
		
			
				|  |  | +        //     toastr.error('请选择调差清单再导入。');
 | 
	
		
			
				|  |  | +        //     return
 | 
	
		
			
				|  |  | +        // }
 | 
	
		
			
				|  |  | +        $(this).siblings('input').trigger('click');
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +    $('#upload-list-file').change(function () {
 | 
	
		
			
				|  |  | +        const file = this.files[0];
 | 
	
		
			
				|  |  | +        const ext = file.name.toLowerCase().split('.').splice(-1)[0];
 | 
	
		
			
				|  |  | +        const imgStr = /(xls|xlsx|json|XLS|XLSX|JSON)$/;
 | 
	
		
			
				|  |  | +        if (!imgStr.test(ext)) {
 | 
	
		
			
				|  |  | +            toastr.error('请导入正确格式的json或excel文件。');
 | 
	
		
			
				|  |  | +            return
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        const fileReader = new FileReader();
 | 
	
		
			
				|  |  | +        fileReader.onload = async function(ev) {
 | 
	
		
			
				|  |  | +            try{
 | 
	
		
			
				|  |  | +                const data = ev.target.result;
 | 
	
		
			
				|  |  | +                let tree = [];
 | 
	
		
			
				|  |  | +                resetExport();
 | 
	
		
			
				|  |  | +                $('#okedit').modal('show');
 | 
	
		
			
				|  |  | +                setProgress($('#export-progress'), 30);
 | 
	
		
			
				|  |  | +                if (/(xls|xlsx|XLS|XLSX)$/.test(ext)) {
 | 
	
		
			
				|  |  | +                    const workbook = XLSX.read(data, {type: 'binary'}); // 以二进制流方式读取得到整份excel表格对象
 | 
	
		
			
				|  |  | +                    const jsonData = transExcel(XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], { defval: null }));
 | 
	
		
			
				|  |  | +                    if (!(jsonData[0] && jsonData[0].code !== undefined && jsonData[0].code !== null &&
 | 
	
		
			
				|  |  | +                        jsonData[0].b_code !== undefined && jsonData[0].name !== undefined &&
 | 
	
		
			
				|  |  | +                        jsonData[0].unit !== undefined && jsonData[0].unit_price !== undefined)) {
 | 
	
		
			
				|  |  | +                        throw 'excel必须按指定格式内容上传';
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    tree = _.filter(jsonData, function (item) {
 | 
	
		
			
				|  |  | +                        return item.code !== null;
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  | +                    for (const [i,t] of tree.entries()) {
 | 
	
		
			
				|  |  | +                        const jIndex1 = _.findIndex(jsonData, { code: t.code, name: t.name, unit: t.unit, unit_price: t.unit_price });
 | 
	
		
			
				|  |  | +                        if (i + 1 < tree.length) {
 | 
	
		
			
				|  |  | +                            const jIndex2 = _.findIndex(jsonData, { code: tree[i+1].code, name: tree[i+1].name, unit: tree[i+1].unit, unit_price: tree[i+1].unit_price });
 | 
	
		
			
				|  |  | +                            t.children = jsonData.slice(jIndex1 + 1, jIndex2);
 | 
	
		
			
				|  |  | +                        } else {
 | 
	
		
			
				|  |  | +                            t.children = jsonData.slice(jIndex1 + 1);
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                } else {
 | 
	
		
			
				|  |  | +                    const ascii = jschardet.detect(data.substring(0, 10000));
 | 
	
		
			
				|  |  | +                    iconv.skipDecodeWarning = true
 | 
	
		
			
				|  |  | +                    tree = JSON.parse(iconv.decode(data, ascii.encoding));// 需要转码,否则前端处理中文会出现乱码
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                stopProgress($('#export-progress'));
 | 
	
		
			
				|  |  | +                $('#bill-detail').show();
 | 
	
		
			
				|  |  | +                setProgress($('#bill-progress'), 30);
 | 
	
		
			
				|  |  | +                // 导入先生成materialCheckList,再生成materialBillsData,最后生成materialListData
 | 
	
		
			
				|  |  | +                console.log(tree, gclGatherData, materialChecklistData, materialBillsData);
 | 
	
		
			
				|  |  | +                const pushChecklist = [];
 | 
	
		
			
				|  |  | +                const pushBillsData = [];
 | 
	
		
			
				|  |  | +                const needPushTree = [];
 | 
	
		
			
				|  |  | +                // 分析materialCheckList和tree,找出相同的清单并插入对应不存在的工料
 | 
	
		
			
				|  |  | +                for (const t of tree) {
 | 
	
		
			
				|  |  | +                    const order = _.findIndex(gclGatherData, { b_code: t.code, name: t.name, unit: t.unit, unit_price: t.unit_price ? parseFloat(t.unit_price) : null });
 | 
	
		
			
				|  |  | +                    const mlOrder = _.findIndex(materialChecklistData, { b_code: t.code, name: t.name, unit: t.unit, unit_price: t.unit_price ? parseFloat(t.unit_price) : null });
 | 
	
		
			
				|  |  | +                    if (mlOrder === -1 && order !== -1 && _.findIndex(pushChecklist, { b_code: t.code, name: t.name, unit: t.unit, unit_price: t.unit_price ? parseFloat(t.unit_price) : null}) === -1) {
 | 
	
		
			
				|  |  | +                        pushChecklist.push({
 | 
	
		
			
				|  |  | +                            b_code: gclGatherData[order].b_code,
 | 
	
		
			
				|  |  | +                            name: gclGatherData[order].name,
 | 
	
		
			
				|  |  | +                            unit: gclGatherData[order].unit,
 | 
	
		
			
				|  |  | +                            unit_price: gclGatherData[order].unit_price,
 | 
	
		
			
				|  |  | +                            quantity: gclGatherData[order].quantity ? gclGatherData[order].quantity : null,
 | 
	
		
			
				|  |  | +                            total_price: gclGatherData[order].total_price ? gclGatherData[order].total_price : null,
 | 
	
		
			
				|  |  | +                            had_bills: 0,
 | 
	
		
			
				|  |  | +                        });
 | 
	
		
			
				|  |  | +                    } else if (mlOrder === -1 && order === -1) {
 | 
	
		
			
				|  |  | +                        continue;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    needPushTree.push(t);
 | 
	
		
			
				|  |  | +                    for (const c of t.children) {
 | 
	
		
			
				|  |  | +                        const mbOrder = _.findIndex(materialBillsData, { code: c.b_code, name: c.name, unit: c.unit });
 | 
	
		
			
				|  |  | +                        if (c.b_code !== null && mbOrder === -1 && _.findIndex(pushBillsData, { code: c.b_code, name: c.name, unit: c.unit }) === -1) {
 | 
	
		
			
				|  |  | +                            pushBillsData.push({
 | 
	
		
			
				|  |  | +                                code: c.b_code,
 | 
	
		
			
				|  |  | +                                name: c.name,
 | 
	
		
			
				|  |  | +                                unit: c.unit
 | 
	
		
			
				|  |  | +                            })
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                console.log(pushChecklist, pushBillsData);
 | 
	
		
			
				|  |  | +                // stopProgress($('#bill-progress'));
 | 
	
		
			
				|  |  | +                // await pushListData(needPushTree);
 | 
	
		
			
				|  |  | +                // 先上传需要生成的清单及工料
 | 
	
		
			
				|  |  | +                if (pushChecklist.length > 0 || pushBillsData.length > 0) {
 | 
	
		
			
				|  |  | +                    postData(window.location.pathname + '/save', { type:'exportCB', addChecklist: pushChecklist, addBillsList: pushBillsData }, async function (result) {
 | 
	
		
			
				|  |  | +                        // materialListData = result;
 | 
	
		
			
				|  |  | +                        materialChecklistData = result.materialChecklistData;
 | 
	
		
			
				|  |  | +                        materialBillsData = result.materialBillsData;
 | 
	
		
			
				|  |  | +                        materialStageBillsData = result.materialStageBillsData;
 | 
	
		
			
				|  |  | +                        stopProgress($('#bill-progress'));
 | 
	
		
			
				|  |  | +                        await pushListData(needPushTree);
 | 
	
		
			
				|  |  | +                    }, function () {
 | 
	
		
			
				|  |  | +                        stop = true;
 | 
	
		
			
				|  |  | +                        clearInterval(interval);
 | 
	
		
			
				|  |  | +                        setTimeout(function () { $('#okedit').modal('hide') }, 1000);
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  | +                } else {
 | 
	
		
			
				|  |  | +                    stopProgress($('#bill-progress'));
 | 
	
		
			
				|  |  | +                    await pushListData(needPushTree);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            } catch (error) {
 | 
	
		
			
				|  |  | +                console.log(error);
 | 
	
		
			
				|  |  | +                toastr.error(error);
 | 
	
		
			
				|  |  | +                stop = true;
 | 
	
		
			
				|  |  | +                clearInterval(interval);
 | 
	
		
			
				|  |  | +                setTimeout(function () { $('#okedit').modal('hide') }, 1000);
 | 
	
		
			
				|  |  | +                return
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // 分析jsondata,得出每个清单间工料数量,生成新的树结构数组
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // let persons = []; // 存储获取到的数据
 | 
	
		
			
				|  |  | +            // // 表格的表格范围,可用于判断表头是否数量是否正确
 | 
	
		
			
				|  |  | +            // let fromTo = '';
 | 
	
		
			
				|  |  | +            // // 遍历每张表读取
 | 
	
		
			
				|  |  | +            // for (const sheet in workbook.Sheets) {
 | 
	
		
			
				|  |  | +            //     if (workbook.Sheets.hasOwnProperty(sheet)) {
 | 
	
		
			
				|  |  | +            //         fromTo = workbook.Sheets[sheet]['!ref'];
 | 
	
		
			
				|  |  | +            //         console.log(fromTo);
 | 
	
		
			
				|  |  | +            //         persons = persons.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheet]));
 | 
	
		
			
				|  |  | +            //         // break; // 如果只取第一张表,就取消注释这行
 | 
	
		
			
				|  |  | +            //     }
 | 
	
		
			
				|  |  | +            // }
 | 
	
		
			
				|  |  | +            // console.log(persons);
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 以二进制方式打开文件
 | 
	
		
			
				|  |  | +        fileReader.readAsBinaryString(file);
 | 
	
		
			
				|  |  | +        $('#upload-list-file').val('');
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    function sleep(millisecond) {
 | 
	
		
			
				|  |  | +        return new Promise(resolve => {
 | 
	
		
			
				|  |  | +            setTimeout(() => {
 | 
	
		
			
				|  |  | +                resolve()
 | 
	
		
			
				|  |  | +            }, millisecond)
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let value = 0;
 | 
	
		
			
				|  |  | +    let interval;
 | 
	
		
			
				|  |  | +    let stop = false;
 | 
	
		
			
				|  |  | +    function setProgress(_this, time = 50) {
 | 
	
		
			
				|  |  | +        interval = setInterval(function () {
 | 
	
		
			
				|  |  | +            if (value < 100) {
 | 
	
		
			
				|  |  | +                value = parseInt(value) + 1;
 | 
	
		
			
				|  |  | +                _this.css("width", value + "%").text(value + "%");
 | 
	
		
			
				|  |  | +            } else if (value === 100) {
 | 
	
		
			
				|  |  | +                value = parseInt(value) + 1;
 | 
	
		
			
				|  |  | +                value = 30;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }, time);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    function resetExport() {
 | 
	
		
			
				|  |  | +        resetProgress($('#export-progress'));
 | 
	
		
			
				|  |  | +        $('#bill-detail').hide();
 | 
	
		
			
				|  |  | +        resetProgress($('#bill-progress'));
 | 
	
		
			
				|  |  | +        $('#list-detail').hide();
 | 
	
		
			
				|  |  | +        resetProgress($('#list-progress'));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    function resetProgress(_this) {
 | 
	
		
			
				|  |  | +        _this.removeClass('bg-success');
 | 
	
		
			
				|  |  | +        _this.css("width", "0%").text("0%").attr('aria-valuenow', '0');
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    function stopProgress(_this) {
 | 
	
		
			
				|  |  | +        if (interval) {
 | 
	
		
			
				|  |  | +            _this.addClass('bg-success');
 | 
	
		
			
				|  |  | +            _this.css("width", "100%").text("100%");
 | 
	
		
			
				|  |  | +            value = 0;
 | 
	
		
			
				|  |  | +            stop = true;
 | 
	
		
			
				|  |  | +            clearInterval(interval);
 | 
	
		
			
				|  |  | +            interval = 0;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    async function pushListData(tree = []) {
 | 
	
		
			
				|  |  | +        console.log(tree);
 | 
	
		
			
				|  |  | +        if (tree.length > 0) {
 | 
	
		
			
				|  |  | +            for (const [i,t] of tree.entries()) {
 | 
	
		
			
				|  |  | +                $('#list-detail').find('b').text(t.code);
 | 
	
		
			
				|  |  | +                resetProgress($('#list-progress'));
 | 
	
		
			
				|  |  | +                if (!interval) {
 | 
	
		
			
				|  |  | +                    $('#list-detail').show();
 | 
	
		
			
				|  |  | +                    setProgress($('#list-progress'), 30);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                const mbList = [];
 | 
	
		
			
				|  |  | +                for (const mb of t.children) {
 | 
	
		
			
				|  |  | +                    const mbInfo = _.find(materialBillsData, { code: mb.b_code, name: mb.name, unit: mb.unit });
 | 
	
		
			
				|  |  | +                    if (mbInfo) {
 | 
	
		
			
				|  |  | +                        const num = parseFloat(mb.quantity);
 | 
	
		
			
				|  |  | +                        if (num < 0 || !/^\d+(\.\d{1,6})?$/.test(num)) {
 | 
	
		
			
				|  |  | +                            // toastr.warning('已保留6位小数');
 | 
	
		
			
				|  |  | +                            mb.quantity = ZhCalc.round(num, 6);
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                        mbList.push({ id: mbInfo.id, quantity: mb.quantity });
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                const gclIndex = _.findIndex(gclGatherData, { b_code: t.code, name: t.name, unit: t.unit, unit_price: t.unit_price ? parseFloat(t.unit_price) : null });
 | 
	
		
			
				|  |  | +                const gcl = gclGatherData[gclIndex].leafXmjs;
 | 
	
		
			
				|  |  | +                const ms_id = isStageSelf ? materialStageData[0].id : null;
 | 
	
		
			
				|  |  | +                // const index = materialChecklistData.indexOf(select);
 | 
	
		
			
				|  |  | +                const datas = [];
 | 
	
		
			
				|  |  | +                for (const xmj of gcl) {
 | 
	
		
			
				|  |  | +                    const notx = findNotJoinLeafXmj(xmj);
 | 
	
		
			
				|  |  | +                    const data = {
 | 
	
		
			
				|  |  | +                        xmj_id: xmj.id,
 | 
	
		
			
				|  |  | +                        gcl_id: xmj.gcl_id,
 | 
	
		
			
				|  |  | +                        mx_id: xmj.mx_id !== undefined ? xmj.mx_id : '',
 | 
	
		
			
				|  |  | +                        gather_qty: xmj.gather_qty,
 | 
	
		
			
				|  |  | +                        is_join: notx === undefined ? 1 : 0,
 | 
	
		
			
				|  |  | +                    };
 | 
	
		
			
				|  |  | +                    if (ms_id) data.ms_id = ms_id;
 | 
	
		
			
				|  |  | +                    datas.push(data);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                if (isStageSelf) {
 | 
	
		
			
				|  |  | +                    // 取所有的gclGatherData才行,然后获取下的值
 | 
	
		
			
				|  |  | +                    const gclData = gclGatherData[gclIndex];
 | 
	
		
			
				|  |  | +                    for (const [index, ms] of materialStageData.entries()) {
 | 
	
		
			
				|  |  | +                        if (ms.id !== ms_id) {
 | 
	
		
			
				|  |  | +                            const gclOther = _.find(gclGatherListData[index], { b_code: gclData.b_code, name: gclData.name, unit: gclData.unit, unit_price: gclData.unit_price });
 | 
	
		
			
				|  |  | +                            if (gclOther) {
 | 
	
		
			
				|  |  | +                                const leafXmjs = gclOther.leafXmjs.filter(item => item.gather_qty !== null && item.gather_qty !== undefined);
 | 
	
		
			
				|  |  | +                                for (const xmj of leafXmjs) {
 | 
	
		
			
				|  |  | +                                    const notx = findNotJoinLeafXmj(xmj);
 | 
	
		
			
				|  |  | +                                    const data = {
 | 
	
		
			
				|  |  | +                                        xmj_id: xmj.id,
 | 
	
		
			
				|  |  | +                                        gcl_id: xmj.gcl_id,
 | 
	
		
			
				|  |  | +                                        mx_id: xmj.mx_id ? xmj.mx_id : '',
 | 
	
		
			
				|  |  | +                                        gather_qty: xmj.gather_qty,
 | 
	
		
			
				|  |  | +                                        is_join: notx === undefined ? 1 : 0,
 | 
	
		
			
				|  |  | +                                        ms_id: ms.id,
 | 
	
		
			
				|  |  | +                                    };
 | 
	
		
			
				|  |  | +                                    datas.push(data);
 | 
	
		
			
				|  |  | +                                }
 | 
	
		
			
				|  |  | +                            }
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                // 上传到数据库
 | 
	
		
			
				|  |  | +                const select = _.find(materialChecklistData, { b_code: t.code, name: t.name, unit: t.unit, unit_price: t.unit_price ? parseFloat(t.unit_price) : null });
 | 
	
		
			
				|  |  | +                console.log(select, datas, mbList);
 | 
	
		
			
				|  |  | +                if (select) {
 | 
	
		
			
				|  |  | +                    await postData(window.location.pathname + '/save', {type: 'adds', checklist: { id: select.id, had_bills: 1 }, postData: {xmjs: datas, mbIds: mbList, export: true}}, function (result) {
 | 
	
		
			
				|  |  | +                        // materialListData = result;
 | 
	
		
			
				|  |  | +                        select.had_bills = 1;
 | 
	
		
			
				|  |  | +                        gclList = result;
 | 
	
		
			
				|  |  | +                        stopProgress($('#list-progress'));
 | 
	
		
			
				|  |  | +                        if (i+1 === tree.length) {
 | 
	
		
			
				|  |  | +                            toastr.success('导入成功');
 | 
	
		
			
				|  |  | +                            setTimeout(function () { $('#okedit').modal('hide') }, 2000);
 | 
	
		
			
				|  |  | +                            showSjsData();
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    }, function () {
 | 
	
		
			
				|  |  | +                        stop = true;
 | 
	
		
			
				|  |  | +                        clearInterval(interval);
 | 
	
		
			
				|  |  | +                        setTimeout(function () { $('#okedit').modal('hide') }, 1000);
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  | +                } else {
 | 
	
		
			
				|  |  | +                    stopProgress($('#list-progress'));
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    function transExcel(results) {
 | 
	
		
			
				|  |  | +        const mapInfo = {
 | 
	
		
			
				|  |  | +            '清单编号': 'code',
 | 
	
		
			
				|  |  | +            '工料编号': 'b_code',
 | 
	
		
			
				|  |  | +            '名称': 'name',
 | 
	
		
			
				|  |  | +            '单位': 'unit',
 | 
	
		
			
				|  |  | +            '单价': 'unit_price',
 | 
	
		
			
				|  |  | +            '单位耗量': 'quantity',
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +        return results.map(zhObj => {
 | 
	
		
			
				|  |  | +            const enObj = {}
 | 
	
		
			
				|  |  | +            const zhKeys = Object.keys(zhObj);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            zhKeys.forEach(zhKey => {
 | 
	
		
			
				|  |  | +                const enKey = mapInfo[zhKey];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                enObj[enKey] = zhObj[zhKey];
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return enObj
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  });
 |