| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773 | /** * Created by jimiz on 2017/4/7. */let mongoose = require('mongoose');var billsData = require('../models/bills');let ration_model = require('../models/ration');let ProjectsData = require('../../pm/models/project_model').project;let logger = require("../../../logs/log_helper").logger;let quantity_detail = require("../facade/quantity_detail_facade");let bill_facade = require("../facade/bill_facade");let ration_glj = mongoose.model('ration_glj');let ration_coe = mongoose.model('ration_coe');let rationInstallationModel = mongoose.model('ration_installation');let stdBillsModel = mongoose.model('std_bills_lib_bills');let stdBillJobsModel = mongoose.model('std_bills_lib_jobContent');let stdBillCharacterModel = mongoose.model('std_bills_lib_itemCharacter');import fixedFlag from  '../../common/const/bills_fixed';const uuidV1 = require('uuid/v1');const billType ={    DXFY:1,//大项费用    FB:2,//分部    FX:3,//分项    BILL:4,//清单    BX:5//补项};//上传的09表、广联达表const uploadType = {lj: 'lj', gld: 'gld'};// 上传控件const multiparty = require("multiparty");const fs = require("fs");// excel解析const excel = require("node-xlsx");//统一回调函数var callback = function(req, res, err, message, data){    res.json({error: err, message: message, data: data});};module.exports = {    getData: function(req, res){        var data = JSON.parse(req.body.data);        billsData.getData(data.projectId, function(err, message, billsList){            if (err === 0) {                callback(req, res, err, message, billsList);            } else {                callback(req, res, err, message, null);            }        });    },    getItemTemplate: function(req, res){        //var data = JSON.parse(req.body.data);        billsData.getItemTemplate(function(err, message, billsItem){            if (billsItem) {                callback(req, res, err, message, billsItem);            } else {                callback(req, res, err, message, null);            }        });    },    allocIDs: function(req, res){        billsData.allocIDs(function(err, message, data){            if (err) {                callback(req, res, err, message, data);            } else {                callback(req, res, err, message, null);            }        });    },    //zhong 2017-9-1    updateCharacterContent: function (req, res) {        let data = JSON.parse(req.body.data);        let findSet = data.findSet,            updateObj = data.updateObj,            txtObj = data.txtObj;        billsData.updateCharacterContent(findSet, updateObj, txtObj, function (err, message) {            callback(req, res, err, message, null);        });    },    updateBill: async function(request, response) {        const data = JSON.parse(request.body.data);        const findSet = data.findSet;        const updateData = data.updateData;        let settingData = {};        // 筛选出要保存在项目属性的设置        for (const index in updateData) {            if (updateData[index].field === 'addRule') {                settingData = updateData[index].value;                delete updateData[index];            }        }       /* // 更新项目属性        const propertyUpdateData = {            property: 'addRule',            data: settingData        };*/        //const projectResult = await ProjectsData.updateProjectProperty(findSet.projectID, propertyUpdateData);        const result = await billsData.updateBill(findSet, updateData);        const message = !result ? '修改失败' : '修改成功';        const err = !result ? 1 : 0;        callback(request, response, err, message, null);    },    singleDelete:async function(req, res){        let result={            error:0        }        try {            let data = req.body.data;            data = JSON.parse(data);            let tasks = generateSingleDeleteTasks(data);            let resultData= await billsData.model.bulkWrite(tasks);            //删除工程量明细            await quantity_detail.deleteByQuery({projectID: data.projectID, billID: data.ID}) ;            result.data=resultData;        }catch (err){            logger.err(err);            result.error=1;            result.message = err.message;        }        res.json(result);    },    multiDelete:async function(req, res){        let result={            error:0        };        try {            let data = req.body.data;            data = JSON.parse(data);            result.data=await doBillsOrRationsDelete(data);        }catch (err){            logger.err(err);            result.error=1;            result.message = err.message;        }        res.json(result);    },    getSectionInfo:async function(req, res){        let result={            error:0        }        try {            let data = req.body.data;            data = JSON.parse(data);            let sectionInfo= await bill_facade.getSectionInfo(data);            result.data=sectionInfo;        }catch (err){            logger.err(err);            result.error=1;            result.message = err.message;        }        res.json(result);    },    reorganizeFBFX:async function(req,res){        let result={            error:0        }        try {            let data = req.body.data;            data = JSON.parse(data);            let reorganizeResult= await bill_facade.reorganizeFBFX(data);            result.data=reorganizeResult;        }catch (err){            logger.err(err);            result.error=1;            result.message = err.message;        }        res.json(result);    },    pasteBlock:async function(req,res){        let result={            error:0        };        try {            let data = req.body.data;            data = JSON.parse(data);            let pasteResult = await bill_facade.pasteBlock(data);            result.data = pasteResult;        }catch (err){            logger.err(err);            result.error=1;            result.message = err.message;        }        res.json(result);    },    //下载导入清单示例    downloadExample: async function(request, response) {        try {            const filePath = './public/static/uploadExample.xlsx';            const stats = fs.statSync(filePath);            // 下载相关header            response.set({                'Content-Type': 'application/octet-stream',                'Content-Disposition': 'attachment; filename=uploadExample.xlsx',                'Content-Length': stats.size            });            fs.createReadStream(filePath).pipe(response);        } catch (error) {            response.end(error);        }    },    //导入清单    upload: async function(req, res){        let responseData = {            err: 0,            msg: '',            data: []        };        const allowHeader = ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];        const uploadOption = {            uploadDir: './public'        };        const form = new multiparty.Form(uploadOption);        let uploadFullName;        form.parse(req, async function(err, fields, files) {            try{                const projectID = fields.projectID !== undefined && fields.projectID.length > 0 ?                    parseInt(fields.projectID[0]) : 0;                if (projectID <= 0) {                    throw '参数错误';                }                const file = files.file !== undefined ? files.file[0] : null;                if (err || file === null) {                    throw '上传失败';                }                // 判断类型                if (file.headers['content-type'] === undefined || allowHeader.indexOf(file.headers['content-type']) < 0) {                    throw '不支持该类型';                }                //导入表类型(09表lj、广联达gld)                const fileType = fields.fileType !== undefined && fields.fileType.length > 0 ? fields.fileType[0] : uploadType.lj;                // 重命名文件名                uploadFullName = uploadOption.uploadDir + '/' + file.originalFilename;                fs.renameSync(file.path, uploadFullName);                const sheets = excel.parse(uploadFullName);                if (sheets[0] === undefined || sheets[0].data === undefined) {                    throw 'excel没有对应数据';                }                //出现错误的表表名,前端提示用                let invalidSheets = [];                let validSheets = {fbfx: [], jscsxm: [], zzcsxm: []};                //获得选择的导入的表及导入位置                const uploadWorkBook = fields.uploadWorkBook !== undefined && fields.uploadWorkBook.length > 0 ? JSON.parse(fields.uploadWorkBook[0]) : [];                //识别非法和合法表,sheetInfo存储前端勾选的表的位置索引以及选择的导入位置                for(let sheetInfo of uploadWorkBook){                    let sheet = sheets[sheetInfo.sheetIdx];                    if(sheet.data === undefined){                        invalidSheets.push(sheet.name);                        continue;                    }                    //获取表的列设置确定导入的格式是否合法(09、广联达)                    let colMapping = getColMapping(sheet.data);                    if(!isValidSheet(colMapping, fileType)){                        invalidSheets.push(sheet.name);                        continue;                    }                    //合法的表                    sheet.colMapping = colMapping;                    //将合法的表按导入位置分类当做一个表来处理                    if(validSheets[sheetInfo.position] !== undefined){                        validSheets[sheetInfo.position].push(sheet)                    }                }                //合并同类表并提取表的有效数据                let toImportSheets = [];                for(let uploadPosition in validSheets){                    let validExcelData = [];                    for(let uSheet of validSheets[uploadPosition]){                        validExcelData = validExcelData.concat(getValidImportData(uSheet.colMapping, uSheet.data))                    }                    if(validSheets[uploadPosition].length > 0){                        toImportSheets.push({position: uploadPosition, colMapping: validSheets[uploadPosition][0].colMapping, validExcelData: validExcelData});                    }                }                //匹配的清单库                const billsLibId = fields.billsLibId !== undefined && fields.billsLibId.length > 0 && fields.billsLibId[0]? parseInt(fields.billsLibId[0]) : null;                let stdBills = [], stdJobs = [], stdCharacters = [];                if(billsLibId){                    stdBills = await stdBillsModel.find({billsLibId: billsLibId, deleted: false}, '-_id code jobs items engineering billsLibId');                    stdJobs = await stdBillJobsModel.find({billsLibId: billsLibId, deleted: false});                    stdCharacters = await stdBillCharacterModel.find({billsLibId: billsLibId, deleted: false});                }                let stdData = {stdBills: stdBills, stdJobs: stdJobs, stdCharacters: stdCharacters};                //导入表                for(let importData of toImportSheets){                    let updateFrontData = await importSheet(importData, req.session.sessionUser.id, projectID, stdData);                    if(updateFrontData){                        responseData.data.push(updateFrontData);                    }                }                if(responseData.data.length === 0){                    throw 'excel无有效数据';                }                if(invalidSheets.length > 0){                    let msg = invalidSheets.join('、');                    responseData.msg = `${msg},导入失败`;                }                //删除暂存文件                fs.unlink(uploadFullName);                res.json(responseData);            }            catch (error){                if(fs.existsSync(uploadFullName)){                    fs.unlink(uploadFullName);                }                responseData.err = 1;                console.log(error);                responseData.msg = typeof error === 'object' ? '上传失败' : error;                res.json(responseData);            }        });    }};//async function importSheet(importData, userID, projectID, stdData){        //导入位置的有固定行        let flag = getImportFlag(importData.position);        if(!flag){            throw 'excel数据错误';        }        let fixedBill = await billsData.model.findOne({projectID: projectID, 'flags.flag': flag, deleteInfo: null});        let insertFixedBill = null;        //导入xx措施项目,若不存在此固定清单,则先插入相关固定清单        if(!fixedBill){            //分部分项工程(不可删除)应存在            if(flag === fixedFlag.SUB_ENGINERRING){                throw '项目不存在分部分项工程'            }            //措施项目是否存在            let csxm = await billsData.model.findOne({projectID: projectID, 'flags.flag': fixedFlag.MEASURE, deleteInfo: null});            if(!csxm){                throw '项目不存在措施项目'            }            //插入清单固定行(施工技术措施项目、施工组织措施项目可删除)            insertFixedBill = {projectID: projectID, name: flag === fixedFlag.CONSTRUCTION_TECH ? '施工技术措施项目' : '施工组织措施项目', code: '1',                ID: uuidV1(), NextSiblingID: -1, ParentID: csxm.ID, flags: [{fieldName: 'fixed', flag: flag}], type: billType.BILL};            //更新前节点            let preDatas = await billsData.model.find({projectID: projectID, ParentID: csxm.ID, deleteInfo: null});            for(let preData of preDatas){                if(preData.NextSiblingID == -1){                    await billsData.model.update({ID: preData.ID}, {$set: {NextSiblingID: insertFixedBill.ID}});                    break;                }            }            await billsData.model.create(insertFixedBill);            fixedBill = insertFixedBill;        }        //将excel数据转换成清单树结构数据        let insertDatas = parseToBillData(importData.validExcelData, importData.colMapping, fixedBill, projectID, stdData);        /*if(insertDatas.length === 0){            throw 'excel无有效数据';        }*/        if(insertDatas.length === 0){            return null;        }        //删除相关数据        let deleteDatas = await billsData.deepDeleteBill([fixedBill], userID);        //新增清单数据        await billsData.importBills(insertDatas);        //返回数据以更新前端        if(insertFixedBill){            insertDatas.push(insertFixedBill);        }        return {fixedBill: fixedBill, insert: {bill: insertDatas, ration: []}, remove: {bill: deleteDatas.bill, ration: deleteDatas.ration}};}//是否是有效的表头列格式,只要含有各表需要的列就行,不严格控制多少列function isValidSheet(colMapping, fileType){    function hasField(field, all){        for(let i of all){            if(field === i){                return true;            }        }        return false;    }    let needFields;    if(fileType === uploadType.lj){        //09表:序号、项目编码、项目名称、项目特征、计量单位、工程量、金额        needFields = ['serialNo', 'code', 'name', 'money'];    }    else {        //广联达表:序号、项目编码、项目名称、项目特征、计量单位、工程量、工程量明细、费用明细        needFields = ['serialNo', 'code', 'name', 'itemCharacterText', 'unit', 'quantity', 'quantityDetail', 'feeDetail'];    }    let hasFieldCount = 0;    for(let attr in colMapping){        if(hasField(attr, needFields)){            hasFieldCount++;        }    }    return hasFieldCount === needFields.length;}//提取excel表头列对应数据function getColMapping(sheetData){    //获取表头    function getHeadRow(sheetData){        for(let rData of sheetData) {            //寻找含有序号的行,认作表头行            for(let cData of rData){                if (cData && cData.toString().replace(/\s/g, '') === '序号') {                    headRow = rData;                    return rData;                }            }        }        return [];    }    //获取需要的表头列与列号对应关系    let colMapping = {};    let headRow = getHeadRow(sheetData);    for(let c = 0; c < headRow.length; c++){        if(headRow[c]){            headRow[c] = headRow[c].toString().replace(/\s/g, '');            //重复的,只取第一个            console.log(headRow[c]);            if(headRow[c] === '序号' && colMapping.serialNo === undefined){                colMapping.serialNo = c;            }            else if((headRow[c] === '编码' || headRow[c] === '项目编码') && colMapping.code === undefined){                colMapping.code = c;            }            else if((headRow[c] === '名称' || headRow[c] === '项目名称') && colMapping.name === undefined){                colMapping.name = c;            }            else if((headRow[c] === '特征' || headRow[c] === '项目特征') && colMapping.itemCharacterText === undefined){                colMapping.itemCharacterText = c;            }            else if((headRow[c] === '单位' || headRow[c] === '计量单位') && colMapping.unit === undefined){                colMapping.unit = c;            }            else if((headRow[c] === '工程量' || headRow[c] === '项目工程量') && colMapping.quantity === undefined){                colMapping.quantity = c;            }            else if(headRow[c].includes('金额') && colMapping.money === undefined){                colMapping.money = c;            }            else if(headRow[c] === '工程量明细' && colMapping.quantityDetail === undefined){                colMapping.quantityDetail = c;            }            else if(headRow[c] === '费用明细' && colMapping.feeDetail === undefined){                colMapping.feeDetail = c;            }        }    }    return colMapping;}function rowExistData(rowData){    for(let cData of rowData){        if(cData !== undefined && cData !== ''){            return true;        }    }    return false;}//提取excel表数据中的有效数据(去表头表尾,提取其中的excel数据)(根据fixedBill获取栏头占行数)function getValidImportData(colMapping, sheetData){    let withingD = false;    let validData = [];    function isHead(rData){        return rData[colMapping.serialNo] && rData[colMapping.serialNo].toString().replace(/\s/g, '') === '序号';    }    function isTail(rData){        for(let cData of rData){            if(cData){                let trimCData = cData.toString().replace(/\s/g, '');                if(trimCData === '本页小计' || trimCData === '本页小计'){                    return true;                }            }        }        return false;    }    for(let r = 0; r < sheetData.length; r++){        let rData = sheetData[r];        if(isHead(rData)){            withingD = true;          /*  if(fixedBill.name !== '施工组织措施项目'){                r++;            }*/            continue;        }        else if(isTail(rData)){            withingD = false;        }        if(withingD && rowExistData(rData)){            validData.push(rData);        }        /*if(rData[0]){            //首列去空格            rData[0] = rData[0].toString().replace(/\s/g, '');            //表头            if(rData[0] === '序号'){                withingD = true;                if(fixedBill.name !== '施工组织措施项目'){                    r++;                }                continue;            }            //表尾            else if(rData[0] === '本页小计' || rData[0] === '合计'){                withingD = false;            }        }        if(withingD && rowExistData(rData)){            validData.push(rData);        }*/    }    return validData;}function getImportFlag(position){    const fixedItem = {'fbfx': fixedFlag.SUB_ENGINERRING, 'jscsxm': fixedFlag.CONSTRUCTION_TECH, 'zzcsxm': fixedFlag.CONSTRUCTION_ORGANIZATION};    return fixedItem[position] ? fixedItem[position] : null;}function isDef(data){    return typeof data !== 'undefined' && data !== null && data !== '';}//excel数据转换成清单数据function parseToBillData(validData, colMapping, fixedBill, projectID, stdData){    let rst = [];    let billIdx = {};    let preRootID = -1,        preLeafID = -1,        preID = -1;    //去除转义字符    function removeESC(data){        return isDef(data) ? data.toString().replace(/[\r,\n,\s,\t]/g, '') : data;    }    //父节点:1.无序号 2有编码    function isRoot(rData){        //序号和编码去除转义字符(有的表格单元格看起来是没数据,实际含有\r,\n等数据)        let serialNo = removeESC(rData[colMapping.serialNo]);        let code = removeESC(rData[colMapping.code]);        return !isDef(serialNo) && isDef(code);    }    //子节点:有序号    function isLeaf(rData){        let serialNo = removeESC(rData[colMapping.serialNo]);        return isDef(serialNo);    }    //续数据:1. 前数据有效 2.无序号 3.无编码 4.有名称或特征    function isExtend(preData, rData){        let serialNo = removeESC(rData[colMapping.serialNo]);        let code = removeESC(rData[colMapping.code]);        let name = rData[colMapping.name];        let itemCharacterText = rData[colMapping.itemCharacterText];        return isDef(preData) && (isRoot(preData) || isLeaf(preData)) && !isDef(serialNo) && !isDef(code) && (isDef(name) || isDef(itemCharacterText));    }    function getBillType(rData, flag){        if(flag === fixedFlag.CONSTRUCTION_TECH || flag === fixedFlag.CONSTRUCTION_ORGANIZATION){            return billType.BILL;        }        else if(flag === fixedFlag.SUB_ENGINERRING){            return isLeaf(rData) ? billType.FX : billType.FB;        }        return null;    }    //excel数据与标准库数据匹配,根据清单前九位编码匹配,匹配成功则获取标准清单对应的工程专业、特征及内容    function matchStdBill(excelBill, stdData){        let isMatch = false;        let regExp = /^\d{12}$/g;        if(regExp.test(excelBill.code)){            let nineCode = excelBill.code.substr(0, 9);            for(let stdBill of stdData.stdBills){                //set programID                if(nineCode == stdBill.code){                    isMatch = true;                    excelBill.programID = stdBill.engineering ? stdBill.engineering : null;                    excelBill.billsLibId = stdBill.billsLibId ? stdBill.billsLibId : null;                    //set jobContent and itemCharacter                    let tempJob = [], tempCharacter = [];                    for(let billJob of stdBill.jobs){                        for(let stdJob of stdData.stdJobs) {                            if (billJob.id == stdJob.id) {                                tempJob.push({isChecked: false, serialNo: billJob.serialNo, content: stdJob.content});                            }                        }                    }                    for(let billCharacter of stdBill.items){                        for(let stdCharacter of stdData.stdCharacters){                            if(billCharacter.id == stdCharacter.id){                                let eigenvalue = [];                                for(let eValue of stdCharacter.itemValue){                                    eigenvalue.push({isSelected: false, value: eValue.value});                                }                                tempCharacter.push({isChecked: false, serialNo: billCharacter.serialNo, character: stdCharacter.content, eigenvalue: eigenvalue});                            }                        }                    }                    excelBill.jobContent = tempJob;                    excelBill.itemCharacter = tempCharacter;                }            }        }        if(!isMatch && excelBill.type === billType.FX){//分项不为空,同时在标准清单中不匹配,则识别为补项                excelBill.type = billType.BX;        }    }    for(let r = 0; r < validData.length; r++){       /* //序号和编码去除转义字符(有的表格单元格看起来是没数据,实际含有\r,\n等数据)        let serialNo = validData[r][colMapping.serialNo];        let code = validData[r][colMapping.code];        if(isDef(serialNo)){            serialNo = removeESC(serialNo);        }        if(isDef(code)){            code = removeESC(code);        }*/        let preData = validData[r-1],            rData = validData[r];        if(fixedBill.flags[0].flag == fixedFlag.CONSTRUCTION_TECH && rData[colMapping.name] === '施工技术措施项目'            || fixedBill.flags[0].flag == fixedFlag.CONSTRUCTION_ORGANIZATION && rData[colMapping.name] === '施工组织措施项目'){            continue;        }        //过滤无效数据        if(!isRoot(rData) && !isLeaf(rData) && !isExtend(preData, rData)){            continue;        }        if(isExtend(preData, rData)){            let preBill = billIdx[preID];            //合并续数据            if(preBill){                preBill.code += rData[colMapping.code] ? rData[colMapping.code] : '';                preBill.name += rData[colMapping.name] ? rData[colMapping.name] : '';                preBill.itemCharacterText += rData[colMapping.itemCharacterText] ? rData[colMapping.itemCharacterText] : '';                preBill.unit += rData[colMapping.unit] ? rData[colMapping.unit] : '';                preBill.quantity += rData[colMapping.quantity] ? rData[colMapping.quantity] : '';            }        }        else {            let newID = uuidV1();            let pID = -1;            let preBill = null;            if(isRoot(rData)){                pID = fixedBill.ID;                preBill = billIdx[preRootID];            }            else if(isLeaf(rData)){                pID = preRootID !== -1 ? preRootID : fixedBill.ID;                preBill = billIdx[preLeafID];            }            //set bill data            billIdx[newID] = {                ID: newID, ParentID: pID, NextSiblingID: -1,                code: rData[colMapping.code] ? removeESC(rData[colMapping.code]) : '',                name: rData[colMapping.name] ? removeESC(rData[colMapping.name]) : '',                itemCharacterText: rData[colMapping.itemCharacterText] ? rData[colMapping.itemCharacterText] : '',                itemCharacter: [],                jobContentText: '',                jobContent: [],                programID: null,                unit: rData[colMapping.unit] ? rData[colMapping.unit] : '',                quantity: rData[colMapping.quantity] ? rData[colMapping.quantity] : '',                //安全文明                flags: fixedBill.flags[0].flag === fixedFlag.CONSTRUCTION_ORGANIZATION && (rData[colMapping.name] === '安全文明施工专项费用' || rData[colMapping.name] === '安全文明施工费') ?                    [{fieldName: 'fixed', flag: fixedFlag.SAFETY_CONSTRUCTION}] : [],                fees: [],                projectID: projectID,                type: getBillType(rData, fixedBill.flags[0].flag)};            //match stdBill and reset programID、jobContent、itemCharacter            matchStdBill(billIdx[newID], stdData);            //update preBill NextSibling            if(preBill){                preBill.NextSiblingID = newID;            }            //set new preID            preID = newID;            preRootID = isRoot(rData) ? newID : preRootID;            preLeafID = isLeaf(rData) ? newID : preLeafID;        }    }    for(let i in billIdx){        rst.push(billIdx[i]);    }    return rst;}async function doBillsOrRationsDelete(data) {    let billTask = [];    let deleteBillIDs = [];    let rationTask=[];    let deleteRationIDs=[];    let qd_query=null;    let sub_query=null;    if(data['bills']){        billTask = generateUpdateTasks(data['bills'],data.projectID,data.user_id);        for(let b_key in data['bills']){            if(data['bills'][b_key]===true){                deleteBillIDs.push(b_key+'');            }        }        if(deleteBillIDs.length>0){            qd_query={projectID: data.projectID, billID: {"$in": deleteBillIDs}};        }    }    if(data['ration']){        rationTask = generateUpdateTasks(data['ration'],data.projectID,data.user_id);        for(let r_key in data['ration']){            if(data['ration'][r_key]===true){                deleteRationIDs.push(r_key+'');            }        }        if(deleteRationIDs.length>0){            if(qd_query==null){//说明没删除清单                qd_query={projectID: data.projectID, rationID: {"$in": deleteRationIDs}};            }else {                qd_query={                    "$or":[                        {projectID: data.projectID, billID: {"$in": deleteBillIDs}},                        {projectID: data.projectID, rationID: {"$in": deleteRationIDs}}                    ]                }            }            sub_query={projectID: data.projectID, rationID: {"$in": deleteRationIDs}};        }    }    //先删除工程量明细    if(qd_query!=null){        await quantity_detail.deleteByQuery(qd_query) ;    }    if(sub_query!=null){        await ration_coe.deleteMany(sub_query);//删除附注条件        await ration_glj.deleteMany(sub_query);//删除定额工料机        await rationInstallationModel.deleteMany(sub_query);//删除安装增加费    }    if(rationTask.length>0){        await ration_model.model.bulkWrite(rationTask);//删除定额    }    if(billTask.length>0){        await billsData.model.bulkWrite(billTask);//删除清单    }    return 'success';}function  generateSingleDeleteTasks(data) {    let updateData = data.updateData;    updateData[data.ID]=true;    let tasks = generateUpdateTasks(updateData,data.projectID,data.user_id);    return tasks;}function  generateUpdateTasks(data,projectID,user_id) {    let tasks=[];    let updateData = data;    let deleteInfo={deleted: true, deleteDateTime: new Date(), deleteBy: user_id};    for(let key in updateData){        let task={            updateOne:{                filter:{                    ID:key,                    projectID:projectID                }            }        };        if(updateData[key]===true){            task.updateOne.update={                deleteInfo:deleteInfo            };        }else {            task.updateOne.update=updateData[key];        }        tasks.push(task);    }    return tasks;}
 |