Explorar el Código

Merge branch '1.0.0_online' of http://192.168.1.41:3000/SmartCost/ConstructionOperation into 1.0.0_online

TonyKang hace 6 años
padre
commit
eadbd45716

+ 74 - 0
modules/all_models/config_material_list.js

@@ -0,0 +1,74 @@
+/**
+ * Created by zhang on 2019/9/6.
+ */
+/**
+ * Created by zhang on 2019/3/18.
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let evaluateSchema = {
+    ID:{type:String,  index: true},
+    projectID: {type:Number,index: true},
+    is_related:{type: Number, default: 0},//关联,1关,0不关
+    projectGLJID:Number,//关联工料机ID
+    seq:String,//序号
+    code:String,
+    name:String,
+    specs:String,
+    unit:String,
+    type:Number,
+    market_price:String,
+    quantity:String,
+    locked:{type: Number, default: 0},//锁定,1锁,0不锁
+    remark:String,
+    originPlace:String,//产地
+    vender:String //厂家
+};
+mongoose.model("evaluate_list", new Schema(evaluateSchema, {versionKey: false, collection: "evaluate_list"}));
+
+let bidEvaluationSchema = {
+    ID:{type:String,  index: true},
+    projectID: {type:Number,index: true},
+    is_related:{type: Number, default: 0},//关联,1关,0不关
+    projectGLJID:Number,//关联工料机ID
+    seq:String,//序号
+    code:String,
+    name:String,
+    specs:String,
+    unit:String,
+    type:Number,
+    market_price:String,
+    quantity:String,
+    remark:String,
+    originPlace:String,//产地
+    vender:String //厂家
+};
+
+mongoose.model("bid_evaluation_list", new Schema(bidEvaluationSchema, {versionKey: false, collection: "bid_evaluation_list"}));
+
+
+let contractorSchema = {
+    ID:{type:String,  index: true},
+    projectID: {type:Number,index: true},
+    is_related:{type: Number, default: 0},//关联,1关,0不关
+    projectGLJID:Number,//关联工料机ID
+    seq:String,//序号
+    code:String,
+    name:String,
+    specs:String,
+    unit:String,
+    type:Number,
+    riskCoe:String,//风险系数
+    standardPrice:String,//基准单价
+    FO:String,//基本价格指数
+    FI:String,//现行价格指数
+    market_price:String,
+    quantity:String,
+    remark:String,
+    supply: {type: Number, default: 0},
+    originPlace:String,//产地
+    vender:String //厂家
+};
+
+mongoose.model("contractor_list", new Schema(contractorSchema, {versionKey: false, collection: "contractor_list"}));

+ 12 - 0
modules/bills_lib/controllers/bills_lib_controllers.js

@@ -9,6 +9,18 @@ let callback = function(req, res, err, message, data){
 let logger = require('../../../logs/log_helper').logger;
 
 module.exports = {
+    copyStdBillsLib: async function (req, res) {
+        try {
+            const data = JSON.parse(req.body.data);
+            const userName = req.session.managerData.username;
+            const libName = data.libName;
+            const libId = data.libId;
+            const newLibData = await billsLibDao.copyLib(userName, libName, libId);
+            callback(req, res, 0, 'copyLib success', [newLibData]);
+        } catch (err) {
+            callback(req, res, 1, 'copyLib fail', null);
+        }
+    },
     getMaxNumber: function(req, res){
         let data = JSON.parse(req.body.data);
         billsLibDao.getMaxNumber(data, function(err, message, maxNumber){

+ 3 - 0
modules/bills_lib/controllers/stdBillsLib_permissionController.js

@@ -40,6 +40,9 @@ class billsLibPermContr extends baseController{
     createStdBillsLib(req, res){
         billsController.createStdBillsLib(req, res);
     }
+    copyStdBillsLib(req, res) {
+        billsController.copyStdBillsLib(req, res);
+    }
     deleteStdBillsLib(req, res){
         billsController.deleteStdBillsLib(req, res);
     }

+ 36 - 12
modules/bills_lib/models/bills_lib_interfaces.js

@@ -14,40 +14,40 @@ const engLibModel = mongoose.model('engineering_lib');
 let uuid = require('uuid');
 let billsLibDao = function(){};
 
-billsLibDao.prototype.copyLib = async function (fromLib, toLib) {
-    console.log('entner---------------------');
+billsLibDao.prototype.copyLib = async function (userName, libName, fromLibId) {
+    const libData = await this.createStdBillsLibSync(userName, libName);
+    const newLibId = libData.billsLibId;
     //插入工作内容
-    let orgJobs = await JobContent.find({billsLibId: fromLib});
-    console.log(fromLib);
+    let orgJobs = await JobContent.find({billsLibId: fromLibId}).lean();
     let jobCounter = await counter.counterDAO.getIDAfterCount(counter.moduleName.billsLib_jobs, orgJobs.length);
     let maxJobId = jobCounter.sequence_value;
     let jobTask = [],
         orgNewJobMapping = {};
     for (let i = 0; i < orgJobs.length; i++) {
-        let jobData = orgJobs[i]._doc;
+        let jobData = orgJobs[i];
         delete jobData._id;
         let newID = (maxJobId - (orgJobs.length - 1) + i);
         orgNewJobMapping[jobData.id] = newID;
         jobData.id = newID;
-        jobData.billsLibId = toLib;
+        jobData.billsLibId = newLibId;
         jobTask.push({insertOne: {document: jobData}});
     }
     if (jobTask.length > 0) {
         await JobContent.bulkWrite(jobTask);
     }
     //插入项目特征
-    let orgItems = await ItemCharacter.find({billsLibId: fromLib});
+    let orgItems = await ItemCharacter.find({billsLibId: fromLibId}).lean();
     let itemCounter = await counter.counterDAO.getIDAfterCount(counter.moduleName.billsLib_items, orgItems.length);
     let maxItemId = itemCounter.sequence_value;
     let itemTask = [],
         orgNewItemMapping = {};
     for (let i = 0; i < orgItems.length; i++) {
-        let itemData = orgItems[i]._doc;
+        let itemData = orgItems[i];
         delete itemData._id;
         let newID = (maxItemId - (orgItems.length - 1) + i);
         orgNewItemMapping[itemData.id] = newID;
         itemData.id = newID;
-        itemData.billsLibId = toLib;
+        itemData.billsLibId = newLibId;
         itemTask.push({insertOne: {document: itemData}});
     }
     if (itemTask.length > 0) {
@@ -55,13 +55,13 @@ billsLibDao.prototype.copyLib = async function (fromLib, toLib) {
     }
     //插入清单
     let billsTask = [];
-    let bills = await Bills.find({billsLibId: fromLib});
+    let bills = await Bills.find({billsLibId: fromLibId}).lean();
     let IDMapping = {},
         billsDatas = [];
     for (let b of bills) {
-        let bData = b._doc;
+        let bData = b;
         delete bData._id;
-        bData.billsLibId = toLib;
+        bData.billsLibId = newLibId;
         billsDatas.push(bData);
         IDMapping[bData.ID] = uuid.v1();
     }
@@ -73,6 +73,15 @@ billsLibDao.prototype.copyLib = async function (fromLib, toLib) {
         if (IDMapping[bD.ParentID]) {
             bD.ParentID = IDMapping[bD.ParentID];
         }
+        // 更新sectionInfo数据
+        if (bD.sectionInfo) {
+            const first = IDMapping[bD.sectionInfo.first];
+            const second = IDMapping[bD.sectionInfo.second];
+            const third = IDMapping[bD.sectionInfo.third];
+            bD.sectionInfo.first = first || null;
+            bD.sectionInfo.second = second || null;
+            bD.sectionInfo.third = third || null;
+        }
         for (let subJob of bD.jobs) {
             if (orgNewJobMapping[subJob.id]) {
                 subJob.id = orgNewJobMapping[subJob.id];
@@ -88,6 +97,7 @@ billsLibDao.prototype.copyLib = async function (fromLib, toLib) {
     if (billsTask.length > 0) {
         await Bills.bulkWrite(billsTask);
     }
+    return libData;
 };
 
 billsLibDao.prototype.getMaxNumber = function(gData, callback){
@@ -140,6 +150,20 @@ billsLibDao.prototype.getStdBillsLib = function(callback){
     });
 };
 
+billsLibDao.prototype.createStdBillsLibSync = async function (userName, libName) {
+    const counterRst = await counter.counterDAO.getIDAfterCount(counter.moduleName.billsLib, 1);
+    const dateStr = moment().format('YYYY-MM-DD HH:mm:ss');
+    const libData = {
+        creator: userName,
+        createDate: dateStr,
+        recentOpr: [{operator: userName, operateDate: dateStr}],
+        billsLibId: counterRst.sequence_value,
+        billsLibName: libName,
+        deleted: false
+    };
+    await StdBillsLib.create(libData);
+    return libData;
+};
 
 billsLibDao.prototype.createStdBillsLib = function(clibData, callback){
     counter.counterDAO.getIDAfterCount(counter.moduleName.billsLib, 1, function(err, result){

+ 1 - 0
modules/bills_lib/routes/bills_lib_routes.js

@@ -26,6 +26,7 @@ module.exports =function (app) {
     billsRouter.post('/getABillsLib', billsLibContr.auth, billsLibContr.init, billsLibContr.getABillsLib);
     billsRouter.post("/getStdBillsLib", billsLibContr.auth, billsLibContr.init, billsLibContr.getStdBillsLib);
     billsRouter.post("/createStdBillsLib", billsLibContr.auth, billsLibContr.init, billsLibContr.createStdBillsLib);
+    billsRouter.post("/copyStdBillsLib", billsLibContr.auth, billsLibContr.init, billsLibContr.copyStdBillsLib);
     billsRouter.post("/deleteStdBillsLib", billsLibContr.auth, billsLibContr.init, billsLibContr.deleteStdBillsLib);
     billsRouter.post("/renameStdBillsLib", billsLibContr.auth, billsLibContr.init, billsLibContr.renameStdBillsLib);
     billsRouter.post("/getStdBillsLibName", billsLibContr.auth, billsLibContr.init, billsLibContr.getStdBillsLibName);

+ 5 - 1
modules/common/const/bills_fixed.js

@@ -66,7 +66,10 @@ const fixedFlag = {
     //住宅工程质量分户验收费
     HOUSE_QUALITY_ACCEPT_FEE:31,
     //组织措施费
-    ORGANIZATION:32
+    ORGANIZATION:32,
+    //其他措施费
+    OTHER_MEASURE_FEE:33
+
 };
 const fixedFlagList = [
     {name: "分部分项工程", value: fixedFlag.SUB_ENGINERRING},
@@ -101,6 +104,7 @@ const fixedFlagList = [
     {name: '建设工程竣工档案编制费', value: fixedFlag.PROJECT_COMPLETE_ARCH_FEE},
     {name: '住宅工程质量分户验收费', value: fixedFlag.HOUSE_QUALITY_ACCEPT_FEE},
     {name: '组织措施费', value: fixedFlag.ORGANIZATION},
+    {name: '其他措施费', value: fixedFlag.OTHER_MEASURE_FEE}
 ];
 
 export {fixedFlag as default, fixedFlagList as List};

+ 39 - 10
modules/ration_repository/models/ration_item.js

@@ -10,6 +10,7 @@ let rationRepositoryDao = require('./repository_map');
 const scMathUtil = require('../../../public/scMathUtil').getUtil();
 const rationItemModel = mongoose.model('std_ration_lib_ration_items');
 const stdRationLibModel = mongoose.model('std_ration_lib_map');
+const stdRationSectionModel = mongoose.model('std_ration_lib_ration_chapter_trees');
 const compleRationModel = mongoose.model('complementary_ration_items');
 import STDGLJListModel from '../../std_glj_lib/models/gljModel';
 
@@ -939,17 +940,20 @@ rationItemDAO.prototype.exportExcelData = async function(rationRepId) {
     const condition = {
         rationRepId: rationRepId
     };
-    // @todo 限制导出的数量以防内存溢出
-    const rationDataList = await this.getRationItemByCondition(condition, ['name', 'code', 'ID', 'sectionId', 'feeType', 'caption', 'basePrice']);
+    const rationDataList = await this.getRationItemByCondition(condition, ['name', 'code', 'ID', 'sectionId', 'feeType', 'caption', 'basePrice', 'jobContent', 'annotation']);
 
     // 整理数据
     let rationData = [];
     for (const tmp of rationDataList) {
         const sectionId = tmp.sectionId <= 0 || tmp.sectionId === undefined ? null : tmp.sectionId;
         const feeType = tmp.feeType === '' || tmp.feeType === undefined ? null : tmp.feeType;
-        const ration = [sectionId, feeType, tmp.ID, tmp.code, tmp.name, tmp.caption, tmp.basePrice];
+        const ration = [sectionId, feeType, tmp.ID, tmp.code, tmp.name, tmp.caption, tmp.basePrice, tmp.jobContent, tmp.annotation];
         rationData.push(ration);
     }
+    const excelData = [['树ID', '取费专业', '定额ID', '定额编码', '定额名', '定额显示名称', '基价', '工作内容', '附注']];
+    excelData.push.apply(excelData, rationData);
+
+    return excelData;
     //根据编号排序,优先级:number-number-..., number, Anumber....
     /*let regConnector = /-/g,
         regLetter = /[a-z,A-Z]/g,
@@ -1013,10 +1017,10 @@ rationItemDAO.prototype.exportExcelData = async function(rationRepId) {
         }
         return rst;
     });*/
-    const excelData = [['树ID', '取费专业', '定额ID', '定额编码', '定额名', '定额显示名称', '基价']];
+    /*const excelData = [['树ID', '取费专业', '定额ID', '定额编码', '定额名', '定额显示名称', '基价']];
     excelData.push.apply(excelData, rationData);
 
-    return excelData;
+    return excelData;*/
 };
 
 /**
@@ -1030,12 +1034,17 @@ rationItemDAO.prototype.batchUpdateSectionIdFromExcel = async function(data) {
         return false;
     }
     // 批量执行update
-    let bulkOprs = [];
+    let bulkOprs = [],
+        sectionIDs = [];
     for (const tmp of data) {
         let rationId = parseInt(tmp[2]);
         rationId = isNaN(rationId) || rationId <= 0 ? 0 : rationId;
         let sectionId = parseInt(tmp[0]);
         sectionId = isNaN(sectionId) || sectionId <= 0 ? 0 : sectionId;
+        if (sectionId <= 0 || rationId <= 0) {
+            continue;
+        }
+        sectionIDs.push(sectionId);
         // 取费专业
         let feeType = tmp[1] ? parseInt(tmp[1]) : null;
         feeType = isNaN(feeType) || feeType <= 0 ? null : feeType;
@@ -1043,15 +1052,35 @@ rationItemDAO.prototype.batchUpdateSectionIdFromExcel = async function(data) {
         name = name ? name : '';
         let caption = tmp[5];
         caption = caption ? caption : '';
-        if (sectionId <= 0 || rationId <= 0) {
-            continue;
-        }
-        bulkOprs.push({updateOne: {filter: {ID: rationId}, update: {$set: {sectionId: sectionId, feeType: feeType, name: name, caption: caption}}}});
+        let jobContent = tmp[7] ? tmp[7] : '';
+        let annotation = tmp[8] ? tmp[8] : '';
+        bulkOprs.push({updateOne: {
+            filter: {ID: rationId},
+            update: {$set: {
+                sectionId,
+                feeType,
+                name,
+                caption,
+                jobContent,
+                annotation
+            }}}
+        });
     }
     if(bulkOprs.length <= 0){
         throw '无有效数据(树ID、定额ID不为空、且为数值)';
     }
     await rationItemModel.bulkWrite(bulkOprs);
+    // 更新章节树工作内容、附注节点选项(全设置为ALL)
+    sectionIDs = Array.from(new Set(sectionIDs));
+    if (sectionIDs.length) {
+        await stdRationSectionModel.updateMany(
+            {ID: {$in: sectionIDs}},
+            {$set: {
+                jobContentSituation: 'ALL',
+                annotationSituation: 'ALL'
+            }}
+        )
+    }
 };
 
 module.exports = new rationItemDAO();

+ 54 - 0
modules/std_glj_lib/controllers/gljController.js

@@ -255,6 +255,60 @@ class GljController extends BaseController{
             }
         });
     }
+
+    async importComponents(request, response) {
+        let responseData = {
+            err: 0,
+            msg: ''
+        };
+        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(request, async function(err, fields, files) {
+            try{
+                const gljLibId = fields.gljLibId !== undefined && fields.gljLibId.length > 0 ?
+                    fields.gljLibId[0] : 0;
+                if (gljLibId <= 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 '不支持该类型';
+                }
+                // 重命名文件名
+                uploadFullName = uploadOption.uploadDir + '/' + file.originalFilename;
+                fs.renameSync(file.path, uploadFullName);
+
+                const sheet = excel.parse(uploadFullName);
+                if (sheet[0] === undefined || sheet[0].data === undefined || sheet[0].data.length <= 0) {
+                    throw 'excel没有对应数据';
+                }
+                // 更新组成物
+                await gljDao.importComponents(gljLibId, sheet[0].data);
+                // 删除文件
+                if(uploadFullName && fs.existsSync(uploadFullName)){
+                    fs.unlink(uploadFullName);
+                }
+                response.json(responseData);
+            }
+            catch (error){
+                console.log(error);
+                if(uploadFullName && fs.existsSync(uploadFullName)){
+                    fs.unlink(uploadFullName);
+                }
+                responseData.err = 1;
+                responseData.msg = error;
+                response.json(responseData);
+            }
+        });
+    }
 }
 
 export default GljController;

+ 162 - 29
modules/std_glj_lib/models/gljModel.js

@@ -48,34 +48,57 @@ class GljDao  extends OprDao{
     async getGljItemsByRep(repositoryId,callback = null){
         try {
             let rst = await gljModel.find({repositoryId: repositoryId}).lean();
+            // test-- 删除重复编码数据
+            /*const map = {};
+            rst.forEach(glj => {
+                if (glj.code === '016100400') {
+                    console.log(glj);
+                }
+                const obj = {code: glj.code, ID: glj.ID};
+                if (!map[glj.code]) {
+                    map[glj.code] = [obj];
+                } else {
+                    map[glj.code].push(obj);
+                }
+            });
+            const IDs = [];
+            for (let code in map) {
+                if (map[code].length > 1) {
+                    map[code].sort((a, b) => a.ID - b.ID);
+                    console.log(map[code]);
+                    let hasUsed = false;
+                    const removeIDs = [];
+                    const tempIDs = [];
+                    for (let i = 0; i < map[code].length; i++) {
+                        const glj = map[code][i];
+                        if (i !== 0) {
+                            tempIDs.push(glj.ID);
+                        }
+                        const isUsed = await rationModel.findOne({'rationGljList.gljId': glj.ID});
+                        if (isUsed) {
+                            hasUsed = true;
+                        } else {
+                            removeIDs.push(glj.ID);
+                        }
+                    }
+                    if (hasUsed) {
+                        IDs.push(...removeIDs);
+                    } else {
+                        IDs.push(...tempIDs);
+                    }
+                    //console.log(map[code]);
+                }
+            }
+            if (IDs.length) {
+                await gljModel.deleteMany({ID: {$in: IDs}});
+            }
+            console.log(IDs);*/
+            // test--
             this.sortToNumber(rst);
             callback(0, rst);
         } catch (err) {
             callback(1, null);
         }
-        /*//批量获取异步
-        let functions = [];
-        let count = await gljModel.find({repositoryId: repositoryId, $or: [{deleted: null}, {deleted: false}]}).count();
-        let findCount = Math.ceil(count/500);
-        for(let i = 0, len = findCount; i < len; i++){
-            functions.push((function(flag) {
-                return function (cb) {
-                    gljModel.find({repositoryId: repositoryId, deleted: null}, cb).skip(flag).sort({ID: 1}).limit(500);
-                }
-            })(i*500));
-        }
-        async.parallel(functions,  function (err, results) {
-            if(err){
-                callback(err, null);
-            }
-            else{
-                for(let stdGljs of results){
-                    rst = rst.concat(stdGljs);
-                }
-                me.sortToNumber(rst);
-                callback(0, rst);
-            }
-        });*/
     }
 
     getGljItemByType (repositoryId, type, callback){
@@ -246,11 +269,63 @@ class GljDao  extends OprDao{
 
     static addGljItems (repId, lastOpr, items, callback) {
         if (items && items.length > 0) {
-            counter.counterDAO.getIDAfterCount(counter.moduleName.GLJ, items.length, function(err, result){
-                var maxId = result.sequence_value;
-                var arr = [];
-                for (var i = 0; i < items.length; i++) {
-                    var obj = new gljModel(items[i]);
+            const codes = [];
+            items.forEach(item => codes.push(item.code));
+            gljModel.find({repositoryId: repId, code: {$in: codes}}, '-_id code', {lean: true}, (err, codeData) => {
+                if (err) {
+                    callback(true, '判断编码唯一性失败', false);
+                    return;
+                }
+                const insertData = [];
+                const failCode = [];
+                items.forEach(item => {
+                    const matchData = codeData.find(codeItem => codeItem.code === item.code);
+                    if (!matchData) {
+                        insertData.push(item);
+                    } else {
+                        failCode.push(item.code);
+                    }
+                });
+                if (!insertData.length) {
+                    callback(false, 'empty data', {insertData, failCode});
+                    return;
+                }
+                counter.counterDAO.getIDAfterCount(counter.moduleName.GLJ, items.length, (counterErr, counterData) => {
+                    if (counterErr) {
+                        callback(true, '获取人材机ID失败', false);
+                        return;
+                    }
+                    const maxId = counterData.sequence_value;
+                    for (let i = 0; i < insertData.length; i++) {
+                        insertData[i].ID = (maxId - (insertData.length - 1) + i);
+                        insertData[i].repositoryId = repId;
+                    }
+                    const task = [];
+                    insertData.forEach(item => {
+                       task.push({
+                           insertOne: {document: item}
+                       });
+                    });
+                    gljModel.bulkWrite(task, (insertErr, rst) => {
+                        if (insertErr) {
+                            callback(true, '新增数据失败', false);
+                            return;
+                        }
+                        GljDao.updateOprArr({ID: repId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
+                            if(err){
+                                callback(true, "Fail to update Operator", false);
+                            } else{
+                                callback(false, "Add successfully", {insertData, failCode});
+                            }
+                        });
+                    });
+                });
+            });
+            /*counter.counterDAO.getIDAfterCount(counter.moduleName.GLJ, items.length, function(err, result){
+                const maxId = result.sequence_value;
+                const arr = [];
+                for (let i = 0; i < items.length; i++) {
+                    const obj = new gljModel(items[i]);
                     obj.ID = (maxId - (items.length - 1) + i);
                     obj.repositoryId = repId;
                     arr.push(obj);
@@ -269,7 +344,7 @@ class GljDao  extends OprDao{
                         });
                     }
                 })
-            });
+            });*/
         } else {
             callback(true, "No source", false);
         }
@@ -586,6 +661,64 @@ class GljDao  extends OprDao{
         }
 
     }
+
+    async importComponents(gljLibId, sheetData) {
+        const gljLib = await gljMapModel.findOne({ID: gljLibId});
+        if (!gljLib) {
+            throw '不存在此人材机库';
+        }
+        const compilation = await compilationModel.findOne({_id: mongoose.Types.ObjectId(gljLib.compilationId)});
+        if (!compilation) {
+            throw '不存在此费用定额';
+        }
+        // 将所有人材机进行编码映射
+        const allGLJs = await gljModel.find({repositoryId: gljLibId}, {ID: true, code: true}).lean();
+        const codeMapping = {};
+        allGLJs.forEach(glj => codeMapping[glj.code] = glj);
+        // excel表格列号与字段的映射
+        const colMapping = {
+            // 材料编码
+            code: 0,
+            // 组成物编码
+            componentCode: 1,
+            // 组成物消耗量
+            consumeAmt: 2
+        };
+        // 跳过列头
+        for (let row = 1; row < sheetData.length; row++) {
+            const rowData = sheetData[row];
+            const code = rowData[colMapping.code];
+            const componentCode = rowData[colMapping.componentCode];
+            const consumeAmt = +rowData[colMapping.consumeAmt];
+            const glj = codeMapping[code];
+            const component = codeMapping[componentCode];
+            if (!glj || !component) {
+                continue;
+            }
+            if (!glj.component) {
+                glj.component = [];
+            }
+            glj.component.push({
+                ID: component.ID,
+                consumeAmt: consumeAmt
+            });
+        }
+        // 更新数据
+        const tasks = [];
+        allGLJs.filter(glj => glj.component && glj.component.length).forEach(glj => {
+            tasks.push({
+                updateOne: {
+                    filter: {
+                        ID: glj.ID
+                    },
+                    update: {$set: {component: glj.component}}
+                }
+            });
+        });
+        if (tasks.length) {
+            await gljModel.bulkWrite(tasks);
+        }
+    }
 }
 
 export default GljDao;

+ 1 - 0
modules/std_glj_lib/routes/routes.js

@@ -43,6 +43,7 @@ module.exports = function (app) {
     router.post("/getGljItemsOccupied",gljController.auth, gljController.init, gljController.getGljItemsOccupied);
     router.post("/isUsed",gljController.auth, gljController.init, gljController.isUsed);//工料机是否被引用
     router.post('/importPrice', gljController.auth, gljController.init, gljController.importPrice);
+    router.post('/importComponents', gljController.auth, gljController.init, gljController.importComponents);
 
 
     app.use("/stdGljRepository/api", router);

+ 17 - 1
modules/sys_tools/models/sys_model.js

@@ -22,7 +22,7 @@ const rationGljModel = mongoose.model('ration_glj');
 const rationCoeMolde = mongoose.model('ration_coe');
 const installationModel = mongoose.model('installation_fee');
 const rationInstallationModel = mongoose.model('ration_installation');
-const rationTemplateModel  = mongoose.model('ration_template')
+const rationTemplateModel  = mongoose.model('ration_template');
 const quantityDetailModel = mongoose.model('quantity_detail');
 const unitPriceFileModel = mongoose.model('unit_price_file');
 const unitPriceModel = mongoose.model('unit_price');
@@ -30,6 +30,10 @@ const mixRatioModel = mongoose.model('mix_ratio');
 const feeRateFileModel = mongoose.model('fee_rate_file');
 const feeRateModel = mongoose.model('fee_rates');
 const compleRationSection = mongoose.model('complementary_ration_section_tree');
+const evaluateListModel = mongoose.model("evaluate_list");
+const bidListModel = mongoose.model("bid_evaluation_list");
+const contractorListModel = mongoose.model("contractor_list");
+
 
 //删除垃圾数据
 async function clearJunkData(callback){
@@ -89,6 +93,18 @@ async function clearJunkData(callback){
         functions.push(function(cb){
             quantityDetailModel.remove({projectID: {$in: junkProjIds}}, cb);
         });
+        //清除暂估材料
+        functions.push(function(cb){
+            evaluateListModel.remove({projectID: {$in: junkProjIds}}, cb);
+        });
+        //清除评标材料
+        functions.push(function(cb){
+            bidListModel.remove({projectID: {$in: junkProjIds}}, cb);
+        });
+        //清除承包材料
+        functions.push(function(cb){
+            contractorListModel.remove({projectID: {$in: junkProjIds}}, cb);
+        });
     }
     //彻底删除了的单价文件
     let junkUFs = await unitPriceFileModel.find({'deleteInfo.deleted': true, 'deleteInfo.completeDeleted': true});

+ 49 - 4
web/maintain/bills_lib/html/main.html

@@ -32,11 +32,16 @@
                   <div class="col-md-8">
                     <div class="warp-p2 mt-3">
                       <table class="table table-hover table-bordered">
-                        <thead><tr><th>清单规则名称</th><th width="160">添加时间</th><th width="90">操作</th><th width="90">导入</th></tr></thead>
+                        <thead>
+                            <tr>
+                                <th>清单规则名称</th>
+                                <th width="160">添加时间</th>
+                                <th width="60">操作</th>
+                                <th width="90">导入</th>
+                                <th width="90">复制</th>
+                            </tr>
+                        </thead>
                         <tbody id="showArea">
-                          <!--<tr><td><a href="qingdan.html">XX清单规则</a></td><td>2017-01-01 </td><td><a href="javacript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a> <a href="javacript:void(0);" data-toggle="modal" data-target="#del" class="text-danger" title="删除"><i class="fa fa-remove"></i></a></td></tr>
-                          <tr><td><a href="qingdan.html">XX清单规则</a></td><td>2017-01-01 </td><td><a href="javacript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a> <a href="javacript:void(0);" data-toggle="modal" data-target="#del" class="text-danger" title="删除"><i class="fa fa-remove"></i></a></td></tr>
-                          <tr><td><a href="qingdan.html">XX清单规则</a></td><td>2017-01-01 </td><td><a href="javacript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a> <a href="javacript:void(0);" data-toggle="modal" data-target="#del" class="text-danger" title="删除"><i class="fa fa-remove"></i></a></td></tr>-->
                         </tbody>
                       </table>
                     </div>
@@ -144,6 +149,31 @@
             </div>
         </div>
     </div>
+    <!--弹出复制库-->
+    <div class="modal fade" id="copy" data-backdrop="static" aria-hidden="true">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">复制清单规则</h5>
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">×</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <form>
+                        <div class="form-group">
+                            <label>清单规则名称</label>
+                            <input id="copyName" class="form-control" autofocus placeholder="输入清单规则名称" type="text">
+                        </div>
+                    </form>
+                </div>
+                <div class="modal-footer">
+                    <a id="copyA"  href="javascript:void(0);" class="btn btn-primary">确定</a>
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                </div>
+            </div>
+        </div>
+    </div>
     <!-- JS. -->
     <script src="/lib/jquery/jquery.min.js"></script>
     <script src="/lib/tether/tether.min.js"></script>
@@ -318,6 +348,21 @@
                 $.bootstrapLoading.end();
             }
         });
+        // 复制库
+        $("#showArea").on("click", ".copy-data", function () {
+            let id = $(this).data("id");
+            id = parseInt(id);
+            if (isNaN(id) || id <= 0) {
+                return false;
+            }
+            selLibId = id;
+            $("#copy").modal("show");
+        });
+        $('#copyA').click(function () {
+            const libId = selLibId;
+            const libName = $('#copyName').val();
+            mainAjax.copyBillsLib(libId, libName);
+        });
     });
 </script>
 

+ 57 - 27
web/maintain/bills_lib/scripts/bills_lib_ajax.js

@@ -50,34 +50,45 @@ var mainAjax = {
             }
         });
     },
+    getLibsHtml: function (data) {
+        const libHtml = data.reduce((acc, libData) => {
+            const id = libData.billsLibId;
+            const billsLibName = libData.billsLibName;
+            const createDateFmt = new Date(libData.createDate).format("yyyy-MM-dd");
+            const html = 
+                `<tr id="${id}">
+                    <td><a href="/stdBills?billsLibId=${id}">${billsLibName}</a></td>
+                    <td>${createDateFmt}</td>
+                    <td>
+                        <a href="javascript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a>
+                        <a href="javascript:void(0);" class="text-danger" data-toggle="modal" data-target="#del" title="删除"><i class="fa fa-remove"></i></a>
+                    </td>
+                    <td>
+                        <a href="javascript:void(0);" class="btn btn-secondary btn-sm import-data" data-id="${id}" title="导入数据"><i class="fa fa-sign-in fa-rotate-90"></i>导入</a>
+                    </td>
+                    <td>
+                        <a href="javascript:void(0);" class="btn btn-secondary btn-sm copy-data" data-id="${id}" title="复制数据"><i class="fa fa-clone"></i>复制</a>
+                    </td>
+                 </tr>`;
+            return acc += html;
+        }, '');
+        return libHtml;
+    },
     getStdBillsLib: function(){
+        const me = this;
         $.ajax({
             type: "post",
             url: "/stdBillsEditor/getStdBillsLib",
             dataType: "json",
             success: function(result){
                 if(result.data){
-                    for(var i=0; i<result.data.length; i++){
-                        var id = result.data[i].billsLibId;
-                        var billsLibName = result.data[i].billsLibName;
-                        var createDate = result.data[i].createDate;
-                        var createDateFmt = new Date(createDate).format("yyyy-MM-dd");
-                        $("#showArea").append(
-                            "<tr id='"+id+"'>" +
-                            "<td><a href='stdBills?billsLibId="+id+"'>"+billsLibName+"</a></td>" +
-                            "<td>"+createDateFmt+" </td>" +
-                            "<td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
-                            "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
-                            "<i class='fa fa-remove'></i></a></td>" +
-                            "<td><a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>"+
-                            "</tr>");
-                    }
+                    $('#showArea').append(me.getLibsHtml(result.data));
                 }
-
             }
         });
     },
     createStdBillsLib: function(userAccount, billsLibName){
+        const me = this;
         $.ajax({
             type: "POST",
             url: "/stdBillsEditor/createStdBillsLib",
@@ -85,18 +96,31 @@ var mainAjax = {
             dataType: "json",
             success: function(result){
                 if(!result.error){
-                    var id = result.data[0].billsLibId;
-                    var createDate = result.data[0].createDate;
-                    var createDateFmt = new Date(createDate).format("yyyy-MM-dd");
-                    $("#showArea").append(
-                        "<tr id='"+id+"'><td><a href='stdBills?billsLibId="+id+"'>"+billsLibName+"</a></td><td>"+createDateFmt+" </td><td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
-                        "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
-                        "<i class='fa fa-remove'></i></a></td>" +
-                        "<td><a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
-                        "</tr>"
-                    );
-                    $('#cancelBtn').click();
+                    $('#showArea').append(me.getLibsHtml(result.data));
+                    $('#add').modal('hide');
+                }
+            }
+        });
+    },
+    copyBillsLib: function (libId, libName) {
+        const me = this;
+        $.ajax({
+            type: 'post',
+            url: '/stdBillsEditor/copyStdBillsLib',
+            data: {data: JSON.stringify({libId, libName})},
+            dataType: 'json',
+            timeout: 150000,
+            beforeSend: function () {
+                $('#copy').modal('hide');
+                $.bootstrapLoading.start();
+            },
+            success: function (result) {
+                if (!result.error) {
+                    $('#showArea').append(me.getLibsHtml(result.data));
                 }
+            },
+            complete: function () {
+                $.bootstrapLoading.end();
             }
         });
     },
@@ -164,12 +188,18 @@ var billsAjax = {
             url: "/stdBillsEditor/getBills",
             data: {data: JSON.stringify({billsLibId: billsLibId})},
             dataType: "json",
+            beforeSend: function () {
+                $.bootstrapLoading.start();
+            },
             success: function(result){
                 if(!result.error){
                     if(callback) {
                         callback(result.data);
                     }
                 }
+            },
+            complete: function () {
+                $.bootstrapLoading.end();
             }
         });
     },

+ 1 - 4
web/maintain/std_glj_lib/html/main.html

@@ -33,11 +33,8 @@
                   <div class="col-md-8">
                     <div class="warp-p2 mt-3">
                       <table class="table table-hover table-bordered">
-                        <thead><tr><th>人材机库名称</th><th>费用定额</th><th>定额库</th><th width="160">添加时间</th><th width="90">操作</th><th width="90">价格数据</th><th width="90">补充模板</th></tr></thead>
+                        <thead><tr><th>人材机库名称</th><th>费用定额</th><th>定额库</th><th width="160">添加时间</th><th width="90">操作</th><th width="90">价格数据</th><th width="100">组成物数据</th><th width="90">补充模板</th></tr></thead>
                         <tbody id="showArea">
-                      <!--    <tr><td><a href="gongliao.html">XX工料机库</a></td><td>重庆2018</td><td>XXX定额库(重庆2018)</td><td>2017-01-01 </td><td><a href="javacript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a> <a href="javacript:void(0);" data-toggle="modal" data-target="#del" class="text-danger" title="删除"><i class="fa fa-remove"></i></a></td></tr>
-                          <tr><td><a href="gongliao.html">XX工料机库</a></td><td>重庆2018</td><td></td><td>2017-01-01 </td><td><a href="javacript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a> <a href="javacript:void(0);" data-toggle="modal" data-target="#del" class="text-danger" title="删除"><i class="fa fa-remove"></i></a></td></tr>
-                          <tr><td><a href="gongliao.html">XX工料机库</a></td><td>重庆2018</td><td></td><td>2017-01-01 </td><td><a href="javacript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a> <a href="javacript:void(0);" data-toggle="modal" data-target="#del" class="text-danger" title="删除"><i class="fa fa-remove"></i></a></td></tr>-->
                         </tbody>
                       </table>
                     </div>

+ 61 - 7
web/maintain/std_glj_lib/js/glj.js

@@ -386,6 +386,19 @@ let repositoryGljObj = {
             success:function(result){
                 if(!result.error) {
                     me.gljList = result.data;
+                    // test
+                    /*const temp = [];
+                    const map = {};
+                    me.gljList.forEach(glj => {
+                        if (!map[glj.code]) {
+                            map[glj.code] = 1;
+                        } else {
+                            temp.push(glj);
+                        }
+                    });
+                    temp.sort((a, b) => b.ID - a.ID);
+                    console.log(temp);*/
+                    // test
                     me.workBook.getSheet(0).setRowCount(result.data.length);
                     me.sortGlj();
                     me.currentGlj = me.gljList.length > 0 ? me.gljList[0] : null;//初始
@@ -1557,6 +1570,15 @@ let repositoryGljObj = {
             me.saveInString(updateArr)
         }
         if(addArr.length > 0){
+            const codeMap = {};
+            const uniqueCodeAddArr =[];
+            addArr.forEach(item => {
+                if (!codeMap[item.code]) {
+                    codeMap[item.code] = 1;
+                    uniqueCodeAddArr.push(item);
+                }
+            });
+            addArr = uniqueCodeAddArr;
             me.saveInString(addArr);
         }
         $.ajax({
@@ -1570,7 +1592,17 @@ let repositoryGljObj = {
                 if (result.error) {
                     alert(result.message);
                 } else {
-                    me.updateCache(addArr, updateArr, removeIds, result);
+                    const failCodes = result.data.failCode;
+                    if (failCodes && failCodes.length) {
+                        let failText = '';
+                        failCodes.forEach(code => {
+                            failText += `<p>编码“${code}”已存在</p>`;
+                        });
+                        $('#alertText').html(failText);
+                        $('#codeAlert').modal('show');
+                    }
+                    const insertData = result.data.insertData;
+                    me.updateCache(insertData, updateArr, removeIds);
                     //me.sortGlj();
                     if(me.currentOprParent === 1){
                         me.currentCache = me.getParentCache(me.parentNodeIds["_pNodeId_" + me.gljCurTypeId]);
@@ -1642,10 +1674,10 @@ let repositoryGljObj = {
         }
         return rst;
     },
-    updateCache: function(addArr, updateArr, removeIds, result) {
+    updateCache: function(insertData, updateArr, removeIds) {
         let me = this, cacheSection = me.gljList;
-        if (addArr.length > 0) {
-            me.gljList = me.gljList.concat(addArr);
+        if (insertData && insertData.length > 0) {
+            me.gljList = me.gljList.concat(insertData);
             cacheSection = me.gljList;
         }
         for (let i = removeIds.length - 1; i >= 0; i--) {
@@ -1655,7 +1687,7 @@ let repositoryGljObj = {
                 }
             }
         }
-        if (result && result.data && result.data.ops && result.data.ops.length > 0) {
+        /*if (result && result.data && result.data.ops && result.data.ops.length > 0) {
             for (let i = 0; i < result.data.ops.length; i++) {
                 for (let j = 0; j < cacheSection.length; j++) {
                     if (cacheSection[j]['code'] == result.data.ops[i]['code']) {
@@ -1663,7 +1695,7 @@ let repositoryGljObj = {
                     }
                 }
             }
-        }
+        }*/
         for (let i = 0; i < updateArr.length; i++) {
             for (let j = 0; j < cacheSection.length; j++) {
                 if (updateArr[i]["ID"] && cacheSection[j]["ID"]) {
@@ -1917,4 +1949,26 @@ let gljTypeTreeOprObj = {
         $("#addBtn_"+treeNode.tId).unbind().remove();
     }
 
-};
+};
+const setTimeoutSync = (handle, time) => {
+    return new Promise((resolve, reject) => {
+        setTimeout(() => {
+            try {
+                if (handle && typeof handle === 'function') {
+                    handle();
+                }
+                resolve();
+            } catch (err) {
+                reject(err);
+            }
+        }, time);
+    });
+};
+setTimeoutSync(() => {
+    //throw new Error('a');
+}).then(v => {
+    setTimeoutSync(() => {
+        //Promise.reject(new Error('b'))
+        //throw new Error('b');
+    });
+}).catch(err => console.log(err));

+ 30 - 3
web/maintain/std_glj_lib/js/main.js

@@ -122,7 +122,13 @@ $(function () {
         });
     });
     let selLibId = -1;
+    const importType = {
+        price: 1,
+        component: 2
+    };
+    let importAction;
     $("#showArea").on("click", ".import-data", function () {
+        importAction = importType.price;
         let id = $(this).data("id");
         id = parseInt(id);
         if (isNaN(id) || id <= 0) {
@@ -131,10 +137,20 @@ $(function () {
         selLibId = id;
         $("#import").modal("show");
     });
-    //导入单价数据
-    $("#data-import").click(function() {
+    $("#showArea").on("click", ".import-components", function () {
+        importAction = importType.component;
+        let id = $(this).data("id");
+        id = parseInt(id);
+        if (isNaN(id) || id <= 0) {
+            return false;
+        }
+        selLibId = id;
+        $("#import").modal("show");
+    });
+    function importExcel(url) {
         $.bootstrapLoading.start();
         const self = $(this);
+        console.log(self);
         try {
             let formData = new FormData();
             let file = $("input[name='import_data']")[0];
@@ -148,7 +164,7 @@ $(function () {
             }
             formData.append('gljLibId', selLibId);
             $.ajax({
-                url: 'api/importPrice',
+                url: url,
                 type: 'POST',
                 data: formData,
                 cache: false,
@@ -186,6 +202,15 @@ $(function () {
             alert(error);
             $.bootstrapLoading.end();
         }
+    }
+    $("#data-import").click(function () {
+        // 导入单价
+        if (importAction === importType.price) {
+            importExcel.call(this, '/stdGljRepository/api/importPrice');
+        } else {
+            // 导入组成物
+            importExcel.call(this, '/stdGljRepository/api/importComponents');
+        }
     });
     //设置补充人材机库分类树模板
     $("#showArea").on("click", ".set-comple", function () {
@@ -260,6 +285,7 @@ function getAllGljLib(callback){
                         "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
                         "<i class='fa fa-remove'></i></a></td>" +
                         "<td><a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
+                        "<td><a class='btn btn-secondary btn-sm import-components' href='javacript:void(0);' data-id='"+ id +"' title='导入组成物'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
                         "<td><a class='btn btn-secondary btn-sm set-comple' href='javacript:void(0);' data-id='"+ id +"' title='将分类树设为补充模板数据'><i class='fa fa-sign-in fa-rotate-90'></i>设置</a></td>" +
                         "</tr>");
                 }
@@ -310,6 +336,7 @@ function createGljLib(gljLibObj, dispNamesArr, usedCom){
                     "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
                     "<i class='fa fa-remove'></i></a></td>" +
                     "<td><a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
+                    "<td><a class='btn btn-secondary btn-sm import-components' href='javacript:void(0);' data-id='"+ id +"' title='导入组成物'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
                     "<td><a class='btn btn-secondary btn-sm set-comple' href='javacript:void(0);' data-id='"+ id +"' title='将分类树设为补充模板数据'><i class='fa fa-sign-in fa-rotate-90'></i>设置</a></td>" +
                     "</tr>");
             }