Переглянути джерело

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

chenshilong 6 роки тому
батько
коміт
ff7078fe60

+ 1 - 0
modules/main/controllers/project_controller.js

@@ -39,6 +39,7 @@ module.exports = {
         // Project.getFilterData(data.project_id, ['bills', 'projectGLJ'], function (err, result) {
         //     console.log(result);
         // });
+        project_facade.getIndexReportData(data.project_id,['ProjectInfoFields','ProjectFeatureFields','ProjectQtyFields','ProjectLabMaterialFields','ProjectEcoFields','ProjectCostFields']);
         Project.getData(data.project_id, function (err, message, result) {
             if (!err) {
                 callback(req, res, err, message, result);

+ 103 - 3
modules/main/facade/project_facade.js

@@ -12,7 +12,8 @@ module.exports = {
     markProjectsToChange:markProjectsToChange,
     getSEIProjects:getSEIProjects,
     loadSEIProjectData:loadSEIProjectData,
-    setSEILibData:setSEILibData
+    setSEILibData:setSEILibData,
+    getIndexReportData:getIndexReportData
 };
 
 let mongoose = require('mongoose');
@@ -37,8 +38,8 @@ let engineerFeatureLib = mongoose.model('std_engineer_feature_lib');
 let engineerInfoLib = mongoose.model('std_engineer_info_lib');
 let mainQuantityLib = mongoose.model('std_main_quantity_lib');
 let materialLib = mongoose.model('std_material_lib');
-
-
+import fixedFlag from '../../common/const/bills_fixed';
+const scMathUtil = require('../../../public/scMathUtil').getUtil();
 
 async function calcInstallationFee(data) {
     let result={};
@@ -381,4 +382,103 @@ async function setSEILibData(property){
         let economic = await economicLib.findOne({'ID':property.economicLibID});
         if(economic) property.economics = economic.index;
     }
+}
+
+async function getIndexReportData(projectID,keyArr) {
+    let project = await projectsModel.findOne({ID:projectID});
+    let bills = await bill_model.getDataSync(projectID);
+    let result = {};
+
+     for(let key of keyArr){
+         switch (key) {
+             case 'ProjectCostFields':
+                 result[key] =getEngineerCostData(project.property,bills);
+                 break;
+             case 'ProjectEcoFields':
+                 result[key] = getEconomicDatas(project.property,bills);
+                 break;
+             case 'ProjectLabMaterialFields':
+                 result[key] = await getMainMaterialDatas(projectID,project.property);
+                 break;
+             case 'ProjectQtyFields':
+                 result[key] = await getQuantityDatas(project.property,bills);
+                 break;
+             case 'ProjectInfoFields':
+                 result[key] = getEngineerInfoData(project.property.engineerInfos);
+                 break;
+             case 'ProjectFeatureFields':
+                 result[key] = getEngineerFeaturesDatas(project.property.engineerFeatures);
+                 break;
+         }
+     }
+    return result
+}
+
+
+
+
+function getEngineerInfoData(engineerInfos) {
+    let datas = [];
+    for(let info of engineerInfos){
+        let d = {
+            name:info.dispName,
+            value:info.value
+        };
+        datas.push(d);
+    }
+    return datas;
+}
+
+function getEngineerFeaturesDatas(engineerFeatures) {
+    let datas = [];
+    for(let f of engineerFeatures){
+        let tem = {
+            ID:f.ID,
+            name:f.name,
+            value:f.value,
+            ParentID:f.ParentID
+        }
+        datas.push(tem);
+    }
+    return datas;
+}
+
+function getQuantityDatas(property,bills) {
+     return gljUtil.getQuantityDatas(property.engineerFeatures,property.mainQuantities,bills,fixedFlag,_,scMathUtil,property.decimal)
+}
+
+function getEconomicDatas(property,bills) {
+   return gljUtil.getEconomicDatas(property.engineerFeatures,property.economics,bills,fixedFlag,_,scMathUtil,property.decimal)
+}
+
+
+function getEngineerCostData(property,bills){
+    let datas = [];
+    let priceIndex = gljUtil.getEngineerCostData(property,bills,fixedFlag,scMathUtil);
+    for(let c of priceIndex.children){
+        let tem = {
+            name:c.name,
+            cost:parseFloat(c.attrs[0].value),
+            unitCost:parseFloat(c.attrs[1].value),
+            per:parseFloat(c.attrs[2].value)
+        };
+        datas.push(tem);
+    }
+    return datas;
+}
+
+async function getMainMaterialDatas(projectID,property) {
+    let gljListModel = new GLJListModel();
+    let [gljList, mixRatioConnectData,mixRatioMap,unitPriceMap] = await gljListModel.getListByProjectId(projectID, property.unitPriceFile?property.unitPriceFile.id:null);
+    gljList = JSON.parse(JSON.stringify(gljList));
+    await calcProjectGLJQuantity(projectID,{gljList:gljList,mixRatioMap:mixRatioMap},property);
+    return gljUtil.getMainMaterialDatas(property.engineerFeatures,property.materials,{gljList:gljList},property.calcOptions,property.decimal,false,_,scMathUtil)
+
+}
+
+async function calcProjectGLJQuantity(projectID,projectGLJDatas,property){
+    let q_decimal = property.decimal.glj.quantity;
+    let rationGLJDatas = await ration_glj_model.find({'projectID':projectID});
+    let rationDatas = await ration_model.model.find({'projectID':projectID});
+    gljUtil.calcProjectGLJQuantity(projectGLJDatas,rationGLJDatas,rationDatas,[],q_decimal)
 }

+ 6 - 4
modules/main/models/project_consts.js

@@ -50,10 +50,12 @@ let summaryConstList = [
 ];
 
 let projectFieldConstList = [
-    `ProjectCostFields`,
-    `ProjectEcoFields`,
-    `ProjectLabMaterialFields`,
-    `ProjectQtyFields`
+    `ProjectInfoFields`,        //工程信息指标
+    `ProjectFeatureFields`,     //工程特征指标
+    `ProjectCostFields`,        //工程造价指标
+    `ProjectEcoFields`,         //工程(主要)经济指标
+    `ProjectLabMaterialFields`, //主要工料指标
+    `ProjectQtyFields`          //主要工程量指标
 ];
 
 let commonConst = {

+ 7 - 0
modules/pm/facade/pm_facade.js

@@ -14,6 +14,7 @@ module.exports={
     copyExample: copyExample,
     getSummaryInfo: getSummaryInfo,
     getSummaryInfoByTender: getSummaryInfoByTender,
+    getIndexReportData: getIndexReportData,
     getTendersFeeInfo: getTendersFeeInfo,
     getConstructionProject: getConstructionProject,
     getFullPath: getFullPath,
@@ -703,6 +704,12 @@ function getBuildingArea(projFeature){
     return null;
 }
 
+//根据单位工程ID获取经济指标信息
+//@param {Number}prj_id @return {Object}
+async function getIndexReportData(prj_id, filters) {
+    return await project_facade.getIndexReportData(prj_id, filters);
+}
+
 //根据单位工程ID获取汇总信息
 //@param {Number}tenderID {String}summaryType @return {Object}
 async function getSummaryInfoByTender(tenderID, summaryType) {

+ 12 - 351
modules/reports/controllers/rpt_controller.js

@@ -11,347 +11,6 @@ let Template = mongoose.model('rpt_templates');
 let rptTplDataFacade = require("../facade/rpt_tpl_data_facade");
 let fsUtil = require("../../../public/fsUtil");
 let pm_facade = require('../../../modules/pm/facade/pm_facade');
-let dummyDataObj = {
-    ProjectCostFields: [{
-        "name": "分部分项工程费",
-        "cost": 728819,
-        "unitCost": 728819,
-        "per": 70.08
-    }, {
-        "name": "技术措施费",
-        "cost": 36807.79,
-        "unitCost": 36807.79,
-        "per": 3.54
-    }, {
-        "name": "安全文明施工费",
-        "cost": 62312.37,
-        "unitCost": 62312.37,
-        "per": 5.99
-    }, {
-        "name": "建设工程竣工档案编制费",
-        "cost": 6867.95,
-        "unitCost": 6867.95,
-        "per": 0.66
-    }, {
-        "name": "其他组织措施费",
-        "cost": 36056.75,
-        "unitCost": 36056.75,
-        "per": 3.47
-    }, {
-        "name": "暂列金额",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }, {
-        "name": "专业工程暂估价",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }, {
-        "name": "计日工",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }, {
-        "name": "总承包服务费",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }, {
-        "name": "索赔与现场签证",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }, {
-        "name": "规费",
-        "cost": 64387.06,
-        "unitCost": 64387.06,
-        "per": 6.19
-    }, {
-        "name": "税金",
-        "cost": 104748.1,
-        "unitCost": 104748.1,
-        "per": 10.07
-    }, {
-        "name": "工程造价",
-        "cost": 1039999.02,
-        "unitCost": 1039999.02,
-        "per": 100
-    }
-    ],
-    ProjectEcoFields: [{
-        "name": "土石方工程",
-        "cost": 31477.97,
-        "unitCost": 29.338,
-        "per": 0.84
-    }, {
-        "name": "地基处理与边坡支护工程",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }, {
-        "name": "桩基工程",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }, {
-        "name": "砌筑工程",
-        "cost": 312217.05,
-        "unitCost": 290.995,
-        "per": 8.32
-    }, {
-        "name": "混凝土及钢筋混凝土工程",
-        "cost": 2301974.32,
-        "unitCost": 2145.503,
-        "per": 61.34
-    }, {
-        "name": "金属结构工程",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }, {
-        "name": "木结构工程",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }, {
-        "name": "门窗工程",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }, {
-        "name": "屋面及防水工程",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }, {
-        "name": "保温、防腐、隔热工程",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }, {
-        "name": "楼地面装饰工程",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }, {
-        "name": "其他工程",
-        "cost": 0,
-        "unitCost": 0,
-        "per": 0
-    }
-    ],
-    ProjectLabMaterialFields: [{
-        "name": "综合用工",
-        "unit": "工日",
-        "unitPrice": 118.62,
-        "quantity": 5248.2,
-        "unitIndex": 489.147
-    }, {
-        "name": "土石方用工",
-        "unit": "工日",
-        "unitPrice": 100,
-        "quantity": 176.71,
-        "unitIndex": 16.47
-    }, {
-        "name": "钢材",
-        "unit": "t",
-        "unitPrice": 3079.64,
-        "quantity": 1.68,
-        "unitIndex": 0.157
-    }, {
-        "name": "水泥",
-        "unit": "t",
-        "unitPrice": 0,
-        "quantity": 0,
-        "unitIndex": 0
-    }, {
-        "name": "商品混凝土",
-        "unit": "m3",
-        "unitPrice": 403,
-        "quantity": 484.59,
-        "unitIndex": 45.165
-    }, {
-        "name": "锯材",
-        "unit": "m3",
-        "unitPrice": 0,
-        "quantity": 0,
-        "unitIndex": 0
-    }, {
-        "name": "砂",
-        "unit": "t",
-        "unitPrice": 0,
-        "quantity": 0,
-        "unitIndex": 0
-    }, {
-        "name": "石子",
-        "unit": "t",
-        "unitPrice": 0,
-        "quantity": 0,
-        "unitIndex": 0
-    }, {
-        "name": "标砖",
-        "unit": "千块",
-        "unitPrice": 4,
-        "quantity": 11.06,
-        "unitIndex": 1.031
-    }, {
-        "name": "砌块",
-        "unit": "m3",
-        "unitPrice": 0,
-        "quantity": 0,
-        "unitIndex": 0
-    }, {
-        "name": "门",
-        "unit": "m2",
-        "unitPrice": 0,
-        "quantity": 0,
-        "unitIndex": 0
-    }, {
-        "name": "窗",
-        "unit": "m2",
-        "unitPrice": 0,
-        "quantity": 0,
-        "unitIndex": 0
-    }, {
-        "name": "保温材料",
-        "unit": "",
-        "unitPrice": 0,
-        "quantity": 0,
-        "unitIndex": 0
-    }, {
-        "name": "防水材料",
-        "unit": "",
-        "unitPrice": 0,
-        "quantity": 0,
-        "unitIndex": 0
-    }, {
-        "name": "其它材料",
-        "unit": "",
-        "unitPrice": 0,
-        "quantity": 0,
-        "unitIndex": 0
-    }
-    ],
-    ProjectQtyFields: [{
-        "name": "挖土石方量",
-        "quantityIndexUnit": "m3",
-        "quantity": 0
-    }, {
-        "name": "基础混凝土",
-        "quantityIndexUnit": "m3",
-        "quantity": 0
-    }, {
-        "name": "混凝土桩",
-        "quantityIndexUnit": "m3",
-        "quantity": 0
-    }, {
-        "name": "混凝土柱",
-        "quantityIndexUnit": "m3",
-        "quantity": 0
-    }, {
-        "name": "混凝土梁",
-        "quantityIndexUnit": "m3",
-        "quantity": 0
-    }, {
-        "name": "混凝土有梁板",
-        "quantityIndexUnit": "m3",
-        "quantity": 0
-    }, {
-        "name": "混凝土平板",
-        "quantityIndexUnit": "m3",
-        "quantity": 0
-    }, {
-        "name": "混凝土楼梯",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "混凝土墙",
-        "quantityIndexUnit": "m3",
-        "quantity": 0
-    }, {
-        "name": "屋架",
-        "quantityIndexUnit": "m3",
-        "quantity": 0
-    }, {
-        "name": "砌体",
-        "quantityIndexUnit": "m3",
-        "quantity": 0
-    }, {
-        "name": "楼地面",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "隔热、保温",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "天棚装饰",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "内墙装饰",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "外墙装饰",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "防水",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "门",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "窗",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "钢材",
-        "quantityIndexUnit": "t",
-        "quantity": 0
-    }, {
-        "name": "阳台雨蓬挑檐",
-        "quantityIndexUnit": "m3",
-        "quantity": 0
-    }, {
-        "name": "屋面防水",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "基础模板",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "梁模板",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "柱模板",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "墙模板",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "平板模板",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "楼梯模板",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }, {
-        "name": "其他模板",
-        "quantityIndexUnit": "m2",
-        "quantity": 0
-    }
-    ]
-};
 
 import rptTplFacade from "../facade/rpt_template_facade";
 import demoTemplateFacade from "../facade/rpt_tpl_data_demo_facade";
@@ -563,9 +222,7 @@ function setupCustomizeCfg(customizeCfg, rptTpl, defProperties) {
         }
     }
 }
-function getEcoFieldsData() {
-    return dummyDataObj;
-}
+
 function getAllPagesCommon(user_id, prj_id, rpt_id, pageSize, orientation, customizeCfg, option, outputType, cb) {
     let rptTpl = null;
     rptTplFacade.getRptTemplate(rpt_id).then(function(rst) {
@@ -585,7 +242,7 @@ function getAllPagesCommon(user_id, prj_id, rpt_id, pageSize, orientation, custo
                 }
             }
             if (economicRst.length > 0) {
-                promiseArr[2] = getEcoFieldsData();
+                promiseArr[2] = pm_facade.getIndexReportData(prj_id, economicRst);
             }
             rptTplDataFacade.prepareProjectData(user_id, prj_id, filter, function (err, msg, rawDataObj) {
                 if (!err) {
@@ -644,13 +301,17 @@ function getAllPagesCommon(user_id, prj_id, rpt_id, pageSize, orientation, custo
                         });
                     } else {
                         if (promiseArr[2] !== null) {
-                            //暂时这样测试
-                            rawDataObj.prjData.push({moduleName: 'ProjectCostFields', data: promiseArr[2].ProjectCostFields});
-                            rawDataObj.prjData.push({moduleName: 'ProjectEcoFields', data: promiseArr[2].ProjectEcoFields});
-                            rawDataObj.prjData.push({moduleName: 'ProjectLabMaterialFields', data: promiseArr[2].ProjectLabMaterialFields});
-                            rawDataObj.prjData.push({moduleName: 'ProjectQtyFields', data: promiseArr[2].ProjectQtyFields});
+                            promiseArr[2].then(function (rst) {
+                                let ecoFieldsRst = (rst._doc)?rst._doc:rst;
+                                rawDataObj.prjData.push({moduleName: 'ProjectCostFields', data: ecoFieldsRst.ProjectCostFields});
+                                rawDataObj.prjData.push({moduleName: 'ProjectEcoFields', data: ecoFieldsRst.ProjectEcoFields});
+                                rawDataObj.prjData.push({moduleName: 'ProjectLabMaterialFields', data: ecoFieldsRst.ProjectLabMaterialFields});
+                                rawDataObj.prjData.push({moduleName: 'ProjectQtyFields', data: ecoFieldsRst.ProjectQtyFields});
+                                buildPageData(rawDataObj, rptDataUtil, rptTpl);
+                            });
+                        } else {
+                            buildPageData(rawDataObj, rptDataUtil, rptTpl);
                         }
-                        buildPageData(rawDataObj, rptDataUtil, rptTpl);
                     }
                     /*/
                     let tplData = rptDataUtil.assembleData(rawDataObj);

+ 66 - 4
modules/reports/rpt_component/jpc_flow_tab.js

@@ -821,6 +821,10 @@ JpcFlowTabSrv.prototype.createNew = function(){
     };
     JpcFlowTabResult.combinePageCells = function (rstPageCells, verticalCombinePos, horizonCombinePos) {
         // let me = this;
+        //备注:纵向合并要考虑以下因素:
+        //     如果有多个column纵向合并,需要总体考虑分割,
+        //     假如:第一列的前3个数据(1、2、3)是相同的,第二列中第2、3、4行数据相同,那么第二列只能合并2、3行的数据,不能合并到第四行
+        //     同理如此类推第三列...n列
         if (verticalCombinePos.length > 0 || horizonCombinePos.length > 1) {
             let cacheObj = {vCache:{}, hCache: {}, hCacheStr: []};
             let removeCellIds = [];
@@ -848,19 +852,56 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 }
             }
             if (verticalCombinePos.length > 0) {
-                for (let vPosArr of verticalCombinePos) {
+                let preColMergePosArr = []; //见上面备注描述,纪录当前列的分割坐标集合情况
+                let private_chk_in_pre_merge = function (preIdx, newCell) {
+                    let rst = true;
+                    if (preIdx >= 0 && preIdx < preColMergePosArr.length) {
+                        for (let mergeArea of preColMergePosArr[preIdx]) {
+                            if (newCell[JV.PROP_AREA][JV.PROP_TOP] >= mergeArea[0] && newCell[JV.PROP_AREA][JV.PROP_TOP] < mergeArea[1]) {
+                                rst = (newCell[JV.PROP_AREA][JV.PROP_BOTTOM] <= mergeArea[1]);
+                                break;
+                            }
+                        }
+                    }
+                    return rst;
+                };
+                for (let vidx = 0; vidx < verticalCombinePos.length; vidx++) {
+                    let vPosArr = verticalCombinePos[vidx];
                     let pStr = "_" + vPosArr[0] + "_" + vPosArr[1];
                     //rstPageCells的结果已经是按顺序排列了,这里不用再排序
                     if (cacheObj.vCache[pStr] && cacheObj.vCache[pStr].length > 0) {
                         let preCell = rstPageCells[cacheObj.vCache[pStr][0]];
+                        if (vidx === 0) {
+                            //这里要处理下
+                            let minY = 10000, maxY = 0;
+                            for (let preCIdx = 0; preCIdx < cacheObj.vCache[pStr].length; preCIdx++) {
+                                if (minY > rstPageCells[cacheObj.vCache[pStr][preCIdx]][JV.PROP_AREA][JV.PROP_TOP]) minY = rstPageCells[cacheObj.vCache[pStr][preCIdx]][JV.PROP_AREA][JV.PROP_TOP];
+                                if (maxY < rstPageCells[cacheObj.vCache[pStr][preCIdx]][JV.PROP_AREA][JV.PROP_BOTTOM]) maxY = rstPageCells[cacheObj.vCache[pStr][preCIdx]][JV.PROP_AREA][JV.PROP_BOTTOM];
+                            }
+                            preColMergePosArr.push([[minY, maxY]]);
+                        }
+                        let dtlColMergePosArr = [];
+                        preColMergePosArr.push(dtlColMergePosArr);
                         for (let cIdx = 1; cIdx < cacheObj.vCache[pStr].length; cIdx++) {
                             if (preCell.Value === "") {
+                                dtlColMergePosArr.push([preCell[JV.PROP_AREA][JV.PROP_TOP], preCell[JV.PROP_AREA][JV.PROP_BOTTOM]]);
                                 preCell = rstPageCells[cacheObj.vCache[pStr][cIdx]];
                             } else {
                                 if (preCell.Value === rstPageCells[cacheObj.vCache[pStr][cIdx]].Value) {
+                                    let bkBottom = preCell[JV.PROP_AREA][JV.PROP_BOTTOM];
                                     preCell[JV.PROP_AREA][JV.PROP_BOTTOM] = rstPageCells[cacheObj.vCache[pStr][cIdx]][JV.PROP_AREA][JV.PROP_BOTTOM];
-                                    removeCellIds.push(cacheObj.vCache[pStr][cIdx]);
+                                    if (private_chk_in_pre_merge(vidx, preCell)) {
+                                        removeCellIds.push(cacheObj.vCache[pStr][cIdx]);
+                                        if (cIdx === cacheObj.vCache[pStr].length - 1) {
+                                            dtlColMergePosArr.push([preCell[JV.PROP_AREA][JV.PROP_TOP], preCell[JV.PROP_AREA][JV.PROP_BOTTOM]]);
+                                        }
+                                    } else {
+                                        preCell[JV.PROP_AREA][JV.PROP_BOTTOM] = bkBottom;
+                                        dtlColMergePosArr.push([preCell[JV.PROP_AREA][JV.PROP_TOP], preCell[JV.PROP_AREA][JV.PROP_BOTTOM]]);
+                                        preCell = rstPageCells[cacheObj.vCache[pStr][cIdx]];
+                                    }
                                 } else {
+                                    dtlColMergePosArr.push([preCell[JV.PROP_AREA][JV.PROP_TOP], preCell[JV.PROP_AREA][JV.PROP_BOTTOM]]);
                                     preCell = rstPageCells[cacheObj.vCache[pStr][cIdx]];
                                 }
                             }
@@ -892,8 +933,10 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 }
             }
             if (removeCellIds.length > 0) {
-                //这次真的要排序了
-                removeCellIds.sort(); //默认方式即可
+                //排序,保证一定的顺序,不能用默认的方式(默认方式是针对字符串的简单排序)
+                removeCellIds.sort(function (idx1, idx2) {
+                    return parseInt(idx1) - parseInt(idx2);
+                });
                 for (let idx = removeCellIds.length - 1; idx >= 0; idx--) {
                     rstPageCells.splice(removeCellIds[idx], 1);
                 }
@@ -1099,9 +1142,28 @@ JpcFlowTabSrv.prototype.createNew = function(){
         for (let idIdx = eliminateCells.length - 1; idIdx >= 0; idIdx--) {
             rst.splice(eliminateCells[idIdx], 1);
         }
+        me.checkCombineEvent(JV.RUN_TYPE_BEFORE_COMBINE, verticalCombinePos, horizonCombinePos, rst, $CURRENT_RPT);
         me.combinePageCells(rst, verticalCombinePos, horizonCombinePos);
+        me.checkCombineEvent(JV.RUN_TYPE_AFTER_COMBINE, verticalCombinePos, horizonCombinePos, rst, $CURRENT_RPT);
         return rst;
     };
+    JpcFlowTabResult.checkCombineEvent = function ($RUN_TYPE, $VER_COMB_ARRAY, $HOR_COMB_ARRAY, $CURRENT_CELL_ITEMS, $CURRENT_RPT) {
+        if ($CURRENT_RPT.formulas) {
+            for (let execFmlIdx = 0; execFmlIdx < $CURRENT_RPT.formulas.length; execFmlIdx++) {
+                if ($CURRENT_RPT.formulas[execFmlIdx][JV.PROP_RUN_TYPE] === $RUN_TYPE) {
+                    let expression = $CURRENT_RPT.formulas[execFmlIdx][JV.PROP_EXPRESSION];
+                    if (expression) {
+                        let $ME = $CURRENT_RPT.formulas[execFmlIdx];
+                        try {
+                            eval(expression);
+                        } catch (ex) {
+                            console.log(ex);
+                        }
+                    }
+                }
+            }
+        }
+    };
     JpcFlowTabResult.outputColumn = function (rptTpl, dataObj, page, segIdx, bands, unitFactor, multiColIdx) {
         let me = this, rst = [];
         let FLOW_NODE_STR = me.isEx?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;

+ 3 - 0
modules/users/models/user_model.js

@@ -176,10 +176,13 @@ class UserModel extends BaseModel {
                 latest_login:userData.latest_login,
                 isUserActive: userData.isUserActive,
             };
+            console.log("updateUser 开始 -------------------------------");
             let updateResult = await this.updateUser(condition,UpdateData);
+            console.log("updateUser 完成 -------------------------------");
             if (updateResult.ok === 1) {
                 let logModel = new LogModel();
                 result = await logModel.addLoginLog(userDataFromDb._id, request);
+                console.log("addLoginLog 完成 -------------------------------");
             }
         }
         request.session.sessionUser.id = userDataFromDb._id;

+ 21 - 1
public/gljUtil.js

@@ -17,7 +17,11 @@ module.exports = {
     getBasePrice:getBasePrice,
     getAdjustPrice:getAdjustPrice,
     getGljTypeSeq:getGljTypeSeq,
-    sortRationGLJ:sortRationGLJ
+    sortRationGLJ:sortRationGLJ,
+    getEngineerCostData:getEngineerCostData,
+    getEconomicDatas:getEconomicDatas,
+    getMainMaterialDatas:getMainMaterialDatas,
+    getQuantityDatas:getQuantityDatas
 };
 
 function calcProjectGLJQuantity(projectGLJDatas,rationGLJDatas,rationDatas,billsDatas,q_decimal) {
@@ -50,4 +54,20 @@ function getGljTypeSeq() {
 
 function sortRationGLJ(list,std) {
     return gljNodeUtil.sortRationGLJ(list,std);
+}
+
+function getEngineerCostData(property,bills,fixedFlag,scMathUtil) {
+    return gljNodeUtil.getEngineerCostData(property,bills,fixedFlag,scMathUtil);
+}
+
+function getEconomicDatas(engineerFeatures,economics,bills,fixedFlag,_,scMathUtil,decimal) {
+    return gljNodeUtil.getEconomicDatas(engineerFeatures,economics,bills,fixedFlag,_,scMathUtil,decimal);
+}
+
+function getMainMaterialDatas(engineerFeatures,materials,projectGLJData,calcOptions,decimalObj,isRadio,_,scMathUtil) {
+    return gljNodeUtil.getMainMaterialDatas(engineerFeatures,materials,projectGLJData,calcOptions,decimalObj,isRadio,_,scMathUtil);
+}
+
+function getQuantityDatas(engineerFeatures,mainQuantities,billsList,fixedFlag,_,scMathUtil,decimal) {
+    return gljNodeUtil.getQuantityDatas(engineerFeatures,mainQuantities,billsList,fixedFlag,_,scMathUtil,decimal);
 }

+ 232 - 0
public/web/gljUtil.js

@@ -319,6 +319,238 @@ let gljUtil = {
             return scMathUtil.roundToString(quantity * glj.quantity, gd);
         }
     },
+    getEngineerCostData:function(property,bills,fixedFlag,scMathUtil){
+        let priceIndex = {
+            name:"工程造价指标",
+            attrs:[],
+            children:[],
+        };
+        let fixMap = {};
+        let buildingArea = this.getBuildArea(property.engineerFeatures); //tender.property.projectFeature?getItemValueBykey(tender.property.projectFeature,"buildingArea"):1;//建筑面积
+
+        for(let b of bills){
+            if(b.flags && b.flags.length > 0){
+                let f = _.find(b.flags,{"fieldName":"fixed"});
+                if(f) fixMap[f.flag] = this.getTotalFee(b,scMathUtil,property.decimal);
+            }
+        }
+        //计算其他组织措施费 = 施工组织措施项目下的子项,除了  安全文明施工费、建设工程竣工档案编制费以外的项
+        let CONSTRUCTION_ORGANIZATION = fixMap[fixedFlag.CONSTRUCTION_ORGANIZATION]?fixMap[fixedFlag.CONSTRUCTION_ORGANIZATION]:0;
+        let SAFETY_CONSTRUCTION =  fixMap[fixedFlag.SAFETY_CONSTRUCTION]?fixMap[fixedFlag.SAFETY_CONSTRUCTION]:0;
+        let PROJECT_COMPLETE_ARCH_FEE =  fixMap[fixedFlag.PROJECT_COMPLETE_ARCH_FEE]? fixMap[fixedFlag.PROJECT_COMPLETE_ARCH_FEE]:0;
+        let other_org_fee = CONSTRUCTION_ORGANIZATION - SAFETY_CONSTRUCTION - PROJECT_COMPLETE_ARCH_FEE;
+        other_org_fee = other_org_fee >0 ?other_org_fee:0;
+        let engineerCost = fixMap[fixedFlag.ENGINEERINGCOST]?fixMap[fixedFlag.ENGINEERINGCOST]:1;
+        priceIndex.children.push(this.getEngineerFlag("分部分项工程费",fixMap[fixedFlag.SUB_ENGINERRING],engineerCost,buildingArea,scMathUtil));
+        priceIndex.children.push(this.getEngineerFlag("技术措施费",fixMap[fixedFlag.CONSTRUCTION_TECH],engineerCost,buildingArea,scMathUtil));
+        priceIndex.children.push(this.getEngineerFlag("安全文明施工费",fixMap[fixedFlag.SAFETY_CONSTRUCTION],engineerCost,buildingArea,scMathUtil));
+        priceIndex.children.push(this.getEngineerFlag("建设工程竣工档案编制费",fixMap[fixedFlag.PROJECT_COMPLETE_ARCH_FEE],engineerCost,buildingArea,scMathUtil));
+        priceIndex.children.push(this.getEngineerFlag("其他组织措施费",other_org_fee,engineerCost,buildingArea,scMathUtil));
+        priceIndex.children.push(this.getEngineerFlag("暂列金额",fixMap[fixedFlag.PROVISIONAL],engineerCost,buildingArea,scMathUtil));
+        priceIndex.children.push(this.getEngineerFlag("专业工程暂估价",fixMap[fixedFlag.ENGINEERING_ESITIMATE],engineerCost,buildingArea,scMathUtil));
+        priceIndex.children.push(this.getEngineerFlag("计日工",fixMap[fixedFlag.DAYWORK],engineerCost,buildingArea,scMathUtil));
+        priceIndex.children.push(this.getEngineerFlag("总承包服务费",fixMap[fixedFlag.TURN_KEY_CONTRACT],engineerCost,buildingArea,scMathUtil));
+        priceIndex.children.push(this.getEngineerFlag("索赔与现场签证",fixMap[fixedFlag.CLAIM_VISA],engineerCost,buildingArea,scMathUtil));
+        priceIndex.children.push(this.getEngineerFlag("规费",fixMap[fixedFlag.CHARGE],engineerCost,buildingArea,scMathUtil));
+        priceIndex.children.push(this.getEngineerFlag("税金",fixMap[fixedFlag.TAX],engineerCost,buildingArea,scMathUtil));
+        priceIndex.children.push(this.getEngineerFlag("工程造价",fixMap[fixedFlag.ENGINEERINGCOST],engineerCost,buildingArea,scMathUtil));
+        return priceIndex;
+    },
+    getBuildArea:function (features) {
+        if(features){
+            let areas = [];
+            for(let f of features){
+                if(f.index == true && f.value && f.value !=="" && this.IsNumber(f.value)) areas.push(f.value);
+            }
+            return areas.length==0?1:areas;
+        }
+        return 1
+    },
+    getEngineerFlag: function (name,totalCost,engineerCost,buildingArea,scMathUtil) {
+        totalCost = totalCost?totalCost:0;
+        let flag = {
+            name:name,
+            attrs:[
+                {name: "金额", value: scMathUtil.roundToString(totalCost,3)},
+                {name: "单方造价", value: scMathUtil.roundToString(this.calcUnitB(totalCost,buildingArea,scMathUtil),2)},
+                {name: "占造价比例", value: scMathUtil.roundToString(totalCost/engineerCost * 100,2)},
+            ],
+        };
+        return flag;
+    },
+    getTotalFee:function (b,scMathUtil,decimal) {
+        let total = 0;
+        if(b.fees && b.fees.length > 0){
+            for(let f of b.fees){
+                if(f.fieldName == "common"){
+                    total = scMathUtil.roundForObj(f.totalFee,decimal?decimal.bills.totalPrice:getDecimal("bills.totalPrice"));
+                }
+            }
+        }
+        return total;
+    },
+     IsNumber : function(pstrVal){
+        let dblNo = Number.NaN;
+        dblNo = new Number(pstrVal);
+        if (isNaN(dblNo)) return false;
+        return true;
+     },
+    calcUnitB:function (total,building,scMathUtil,coe,decimal = 3) {
+        if(Array.isArray(building)){
+            for(let b of building){
+                total = scMathUtil.roundForObj(total/b,6);
+            }
+        }else {
+            total = scMathUtil.roundForObj(total/building,6);
+        }
+        coe = gljUtil.isDef(coe)?coe:1;
+        return scMathUtil.roundForObj(total*coe,decimal);
+    },
+    getEconomicDatas:function(engineerFeatures,economics,billsList,fixedFlag,_,scMathUtil,decimal){
+        let datas = [];
+        let [bills,totalFee] = gljUtil.getIndexBills(billsList,fixedFlag,_,scMathUtil,decimal);
+        let billsGroup = _.groupBy(bills,'economicType');
+        if(!economics) return datas;
+        for(let e of economics){
+            let tem = {
+                name:e.name,
+                cost:0,
+                unitCost:0,
+                per:0
+            };
+            if(billsGroup[e.name]) setEconomics(billsGroup[e.name],totalFee,tem);
+            datas.push(tem);
+        }
+        function setEconomics(items,engineerCost,data) {
+            let cost = 0;
+            let priceDe = decimal?decimal.bills.totalPrice:getDecimal("bills.totalPrice");//getDecimal("bills.totalPrice");
+            for(let i of items){
+                i.totalFee =  scMathUtil.roundForObj(i.totalFee,priceDe);
+                cost = scMathUtil.roundForObj(cost + i.totalFee,decimal?decimal.process:getDecimal("process"))//getDecimal("process");
+            }
+            data.cost = scMathUtil.roundForObj(cost,priceDe,_);
+            data.unitCost = gljUtil.calUnitWidthCoe(data.cost,true,engineerFeatures,_,scMathUtil);//noNeedCoe = true 这里不需要乘以系数
+            data.per = engineerCost?scMathUtil.roundForObj(data.cost/engineerCost * 100,2):0;
+        }
+
+        return datas;
+    },
+    calUnitWidthCoe:function (total,noNeedCoe,engineerFeatures,_,scMathUtil) {
+        let areas = gljUtil.getBuildArea(engineerFeatures);
+        let f = _.find(engineerFeatures,{index:true});
+        return f && noNeedCoe!==true?gljUtil.calcUnitB(total,areas,scMathUtil,f.coe):gljUtil.calcUnitB(total,areas,scMathUtil);
+    },
+    getIndexBills:function (bills,fixedFlag,_,scMathUtil,decimal) {
+        let parentMap = {},datas = [],totalCost = 0;
+        let FBFX_b = null,teh_b = null,costNode=null;
+        for(let b of bills) {
+            parentMap[b.ParentID] ? parentMap[b.ParentID].push(b) : parentMap[b.ParentID] = [b];//有添加,无则生成
+            if(b.flags && b.flags.length > 0){
+                let f = _.find(b.flags,{"fieldName":"fixed"});
+                if(!f) continue;
+                if(f.flag == fixedFlag.SUB_ENGINERRING) FBFX_b = b;//过滤出分部分项工程;
+                if(f.flag == fixedFlag.CONSTRUCTION_TECH) teh_b = b;//过滤出技术措施项目;
+                if(f.flag == fixedFlag.ENGINEERINGCOST) costNode = b;//过滤出工程造价项目;
+            }
+        }
+        if(FBFX_b) getChildren(FBFX_b,parentMap,datas);
+        if(teh_b) getChildren(teh_b,parentMap,datas);
+        if(costNode) totalCost = gljUtil.getTotalFee(costNode,scMathUtil,decimal);
+
+        for(let td of datas){
+            if(parentMap[td.ID]){
+                td.economicType = "";
+                td.quantityIndexType = "";
+                td.quantityIndexUnit = "";
+                td.quantityIndexCoe = "";
+            }
+        }
+        return [datas,totalCost];
+
+        function getChildren(d,map,arr) {
+            let tem = {
+                ID:d.ID,
+                ParentID:d.ParentID,
+                code:d.code,
+                name:d.name,
+                unit:d.unit,
+                quantity:d.quantity,
+                totalFee:gljUtil.getTotalFee(d,scMathUtil,decimal),
+                economicType:d.economicType,
+                quantityIndexType:d.quantityIndexType,
+                quantityIndexUnit:d.quantityIndexUnit,
+                quantityIndexCoe:d.quantityIndexCoe,
+            };
+            arr.push(tem);
+            if(map[d.ID]){
+                for(let s of map[d.ID]){
+                    getChildren(s,map,arr)
+                }
+            }
+        }
+    },
+    getMainMaterialDatas:function (engineerFeatures,materials,projectGLJData,calcOptions,decimalObj,isRadio,_,scMathUtil) {
+        let datas = [];
+        let materialGroup = _.groupBy(projectGLJData.gljList,'materialIndexType');
+        if(!materials) return datas;
+        for(let m of materials){
+            let tem = {
+                name:m.name,
+                unit:m.unit,
+                unitPrice:0,
+                quantity:0,
+                unitIndex:0
+            };
+            if(materialGroup[m.name]) setMainMaterial(materialGroup[m.name],tem);
+            datas.push(tem);
+        }
+
+        function setMainMaterial(gljs,data) {
+            let quantity = 0 ,unitPrice=0;
+            for(let g of gljs){
+                if(!g.quantity || g.quantity=="") continue;
+                let marketPrice = gljUtil.getMarketPrice(g,projectGLJData,calcOptions,decimalObj,false,_,scMathUtil); // gljOprObj.setGLJPrice(tem,g);
+                let materialIndexCoe = g.materialIndexCoe?scMathUtil.roundForObj(g.materialIndexCoe,decimalObj.process):0;
+                let t_quantity = scMathUtil.roundForObj(g.quantity * materialIndexCoe,decimalObj.process);
+                quantity = scMathUtil.roundForObj(t_quantity + quantity,decimalObj.process);
+                let temPrice = scMathUtil.roundForObj(g.quantity * marketPrice,decimalObj.process);
+                unitPrice = scMathUtil.roundForObj(temPrice + unitPrice,decimalObj.process);
+            }
+            data.quantity = scMathUtil.roundForObj(quantity,2);
+            if(data.quantity) data.unitPrice = scMathUtil.roundForObj(unitPrice/data.quantity,2);
+            data.unitIndex = gljUtil.calUnitWidthCoe(data.quantity,false,engineerFeatures,_,scMathUtil);
+        }
+
+        return datas;
+    },
+    getQuantityDatas:function (engineerFeatures,mainQuantities,billsList,fixedFlag,_,scMathUtil,decimal) {//主要工程量指标
+        let datas = [];
+        let [bills,totalFee] = gljUtil.getIndexBills(billsList,fixedFlag,_,scMathUtil,decimal);//bills,fixedFlag,_,scMathUtil
+        let billsGroup = _.groupBy(bills,'quantityIndexType');
+        if(!mainQuantities) return datas;
+        for(let m of mainQuantities){
+            let tem = {
+                name : m.name,
+                quantityIndexUnit:m.unit,
+                quantity:0
+            };
+            if(billsGroup[m.name]) setQuantities(billsGroup[m.name],tem);
+
+            datas.push(tem);
+        }
+
+        function setQuantities(items,data) {
+            let quantity = 0;
+            for (let i of items){
+                let coe = i.quantityIndexCoe && i.quantityIndexCoe!=""?parseFloat(i.quantityIndexCoe):0;
+                i.quantity = scMathUtil.roundForObj(parseFloat(i.quantity)*coe,decimal.process);
+                quantity = scMathUtil.roundForObj(quantity +  i.quantity,decimal.process);
+            }
+            data.quantity = gljUtil.calUnitWidthCoe(quantity,false,engineerFeatures,_,scMathUtil);
+        }
+
+        return datas;
+    },
     fixedFlag : {
         // 分部分项工程
         SUB_ENGINERRING: 1,

+ 2 - 0
public/web/rpt_value_define.js

@@ -207,6 +207,8 @@ const JV = {
     RUN_TYPE_BEFORE_ANALYZING: "before_analyzing",
     RUN_TYPE_BEFORE_PAGING: "before_paging",
     RUN_TYPE_BEFORE_OUTPUT: "before_output",
+    RUN_TYPE_BEFORE_COMBINE: "before_combine",
+    RUN_TYPE_AFTER_COMBINE: "after_combine",
 
     PAGE_STATUS: ["EveryPage","FirstPage", "LastPage", "SegmentStart", "SegmentEnd", "Group", "CrossRowEnd", "CrossColEnd"],
 

+ 1 - 1
test/unit/reports/test_rpt_test_template.js

@@ -67,7 +67,7 @@ let userId_me = "5b6a60b1c4ba33000dd417c0"; //我的
 // demoPrjId = 2260; //QA:
 // demoPrjId = 5029; //
 // demoPrjId = 5029; //项目名称过长
-demoPrjId = 8464; //
+demoPrjId = 8522; //
 // demoPrjId = 4107; //UAT:
 //*/
 let userId_Dft = userId_Leng;

+ 5 - 5
web/building_saas/main/html/main.html

@@ -166,7 +166,7 @@
                               <a class="nav-link px-3 right-nav-link"  href="javascript:void(0)" id = 'locateTab' relaPanel="#locate">查找定位</a>
                           </li>-->
                           <li class="nav-item">
-                              <a class="nav-link px-1 right-nav-link" href="javascript:void(0)" id = 'stdBillsGuidanceTab' relaPanel="#zy">标准清单</a>
+                              <a class="nav-link px-1 right-nav-link" href="javascript:void(0)" id = 'stdBillsGuidanceTab' relaPanel="#zy">清单</a>
                           </li>
                          <!-- <li class="nav-item">
                               <a class="nav-link px-3" href="javascript:void(0)" id = 'stdBillsTab' relaPanel="#qd">清单规则</a>
@@ -204,7 +204,7 @@
                           <div class="bottom-content" id="bottom_div">
                               <ul class="nav nav-tabs" role="tablist" id="bottom_div_ul">
                                   <li class="nav-item" id="QDJL_div">
-                                      <a class="nav-link sub-item" id="linkQDJL" data-toggle="tab" href="#subSpread" role="tab">清单精灵</a>
+                                      <a class="nav-link sub-item" id="linkQDJL" data-toggle="tab" href="#subSpread" role="tab">清单</a>
                                   </li>
                                   <li class="nav-item" id="GLJ_div">
                                       <a class="nav-link sub-item active" id="linkGLJ" data-toggle="tab" href="#subSpread" role="tab">人材机</a>
@@ -288,7 +288,7 @@
                                                           <li class="nav-item" data-toggle="tooltip" data-placement="left" title="项目特征">
                                                               <a data-toggle="tab" id="xm-nav" href="#rnc-xm" role="tab" class="zmhs-link nav-link">特征<!--<i class="fa fa-info-circle"></i>--></a>
                                                           </li>
-                                                          <li class="nav-item" data-toggle="tooltip" data-placement="left" title="附注条件"><a data-toggle="tab" href="#rnc-zm" role="tab"class="zmhs-link nav-link">换算<!--<i class="fa fa-check-circle-o"></i>--></a></li>
+                                                          <li class="nav-item" data-toggle="tooltip" data-placement="left" title="附注条件"><a data-toggle="tab" id="hs-nav" href="#rnc-zm" role="tab"class="zmhs-link nav-link">换算<!--<i class="fa fa-check-circle-o"></i>--></a></li>
                                                           <li class="nav-item" data-toggle="tooltip" data-placement="left" title="自定义系数"><a data-toggle="tab" href="#rnc-cus" role="tab"class="zmhs-link nav-link">系数<!--<i class="fa fa-wrench"></i>--></a></li>
                                      <!--                     <li class="nav-item" data-toggle="tooltip" data-placement="left" title="增减换算"><a data-toggle="tab" href="#rnc-fz" role="tab"class="zmhs-link nav-link "><i class="fa fa-plus"></i></a></li>-->
                                                         <!--  <li class="nav-item"><a data-toggle="tab" href="#rnc-xm" role="tab"  class="nav-link">项目特征</a></li>
@@ -458,7 +458,7 @@
                                                       <a id="elfInsertRation" href="javascript:void(0);" class="btn btn-sm btn-primary px-1 ml-1">应用选项</a>
                                                       <a id="elfInsertSingle" href="javascript:void(0)" class="btn btn-sm btn-primary px-1 ml-1">应用单条</a>
                                                   </div>
-                                                  <div class="ovf-hidden" id="elfItems">
+                                                  <div class="ovf-hidden" id="billsSubItems">
                                                   </div>
                                               </div>
                                           </div>
@@ -1633,7 +1633,7 @@
                         </label>
                     </div>
                     <div class="form-check">
-                        <input class="form-check-input zlfb-check" type="checkbox" checked id="bill_recode"  >
+                        <input class="form-check-input zlfb-check" type="checkbox" id="bill_recode"  >
                         <label class="form-check-label">
                             清单重新编码
                         </label>

+ 8 - 119
web/building_saas/main/js/models/exportSEIInterface.js

@@ -4,136 +4,25 @@
 
 let exportUtil = {
     setEngineerPriceIndex:function (tender,projectData) {
-        let priceIndex = {
-            name:"工程造价指标",
-            attrs:[],
-            children:[],
-        };
-        let fixMap = {};
-        let buildingArea = this.getBuildArea(tender.property.engineerFeatures); //tender.property.projectFeature?getItemValueBykey(tender.property.projectFeature,"buildingArea"):1;//建筑面积
-
-        for(let b of projectData.bills){
-            if(b.flags && b.flags.length > 0){
-                let f = _.find(b.flags,{"fieldName":"fixed"});
-                if(f) fixMap[f.flag] = this.getTotalFee(b);
-            }
-        }
-        //计算其他组织措施费 = 施工组织措施项目下的子项,除了  安全文明施工费、建设工程竣工档案编制费以外的项
-        let CONSTRUCTION_ORGANIZATION = fixMap[fixedFlag.CONSTRUCTION_ORGANIZATION]?fixMap[fixedFlag.CONSTRUCTION_ORGANIZATION]:0;
-        let SAFETY_CONSTRUCTION =  fixMap[fixedFlag.SAFETY_CONSTRUCTION]?fixMap[fixedFlag.SAFETY_CONSTRUCTION]:0;
-        let PROJECT_COMPLETE_ARCH_FEE =  fixMap[fixedFlag.PROJECT_COMPLETE_ARCH_FEE]? fixMap[fixedFlag.PROJECT_COMPLETE_ARCH_FEE]:0;
-        let other_org_fee = CONSTRUCTION_ORGANIZATION - SAFETY_CONSTRUCTION - PROJECT_COMPLETE_ARCH_FEE;
-        other_org_fee = other_org_fee >0 ?other_org_fee:0;
-        let engineerCost = fixMap[fixedFlag.ENGINEERINGCOST]?fixMap[fixedFlag.ENGINEERINGCOST]:1;
-        priceIndex.children.push(this.getFlag("分部分项工程费",fixMap[fixedFlag.SUB_ENGINERRING],engineerCost,buildingArea));
-        priceIndex.children.push(this.getFlag("技术措施费",fixMap[fixedFlag.CONSTRUCTION_TECH],engineerCost,buildingArea));
-        priceIndex.children.push(this.getFlag("安全文明施工费",fixMap[fixedFlag.SAFETY_CONSTRUCTION],engineerCost,buildingArea));
-        priceIndex.children.push(this.getFlag("建设工程竣工档案编制费",fixMap[fixedFlag.PROJECT_COMPLETE_ARCH_FEE],engineerCost,buildingArea));
-        priceIndex.children.push(this.getFlag("其他组织措施费",other_org_fee,engineerCost,buildingArea));
-        priceIndex.children.push(this.getFlag("暂列金额",fixMap[fixedFlag.PROVISIONAL],engineerCost,buildingArea));
-        priceIndex.children.push(this.getFlag("专业工程暂估价",fixMap[fixedFlag.ENGINEERING_ESITIMATE],engineerCost,buildingArea));
-        priceIndex.children.push(this.getFlag("计日工",fixMap[fixedFlag.DAYWORK],engineerCost,buildingArea));
-        priceIndex.children.push(this.getFlag("总承包服务费",fixMap[fixedFlag.TURN_KEY_CONTRACT],engineerCost,buildingArea));
-        priceIndex.children.push(this.getFlag("索赔与现场签证",fixMap[fixedFlag.CLAIM_VISA],engineerCost,buildingArea));
-        priceIndex.children.push(this.getFlag("规费",fixMap[fixedFlag.CHARGE],engineerCost,buildingArea));
-        priceIndex.children.push(this.getFlag("税金",fixMap[fixedFlag.TAX],engineerCost,buildingArea));
-        priceIndex.children.push(this.getFlag("工程造价",fixMap[fixedFlag.ENGINEERINGCOST],engineerCost,buildingArea));
-        return priceIndex;
+       return gljUtil.getEngineerCostData(tender.property,projectData.bills,fixedFlag,scMathUtil);
     },
     getTotalFee:function (b) {
-        let total = 0;
-        if(b.fees && b.fees.length > 0){
-            let common = _.find(b.fees,{"fieldName":"common"});
-            if(common) total = scMathUtil.roundForObj(common.totalFee,getDecimal("bills.totalPrice"))
-        }
-        return total;
+        return gljUtil.getTotalFee(b,scMathUtil);
     },
     getFlag: function (name,totalCost,engineerCost,buildingArea) {
-        totalCost = totalCost?totalCost:0;
-        let flag = {
-            name:name,
-            attrs:[
-                {name: "金额", value: scMathUtil.roundToString(totalCost,3)},
-                {name: "单方造价", value: scMathUtil.roundToString(exportUtil.calcUnitB(totalCost,buildingArea),2)},
-                {name: "占造价比例", value: scMathUtil.roundToString(totalCost/engineerCost * 100,2)},
-            ],
-        };
-        return flag;
+        return gljUtil.getEngineerFlag(name,totalCost,engineerCost,buildingArea);
     },
     getBuildArea:function (features) {
-        if(features){
-            let areas = [];
-            for(let f of features){
-                if(f.index == true && f.value && f.value !=="" && IsNumber(f.value)) areas.push(f.value);
-            }
-            return _.isEmpty(areas)?1:areas;
-        }
-        return 1
+        return gljUtil.getBuildArea(features)
     },
-    calcUnitB:function (total,building,coe,decimal = 3) {
-        if(Array.isArray(building)){
-            for(let b of building){
-                total = scMathUtil.roundForObj(total/b,6);
-            }
-        }else {
-            total = scMathUtil.roundForObj(total/building,6);
-        }
-        coe = gljUtil.isDef(coe)?coe:1;
-        return scMathUtil.roundForObj(total*coe,decimal);
+    calcUnitB:function (total,building,scMathUtil,coe,decimal = 3) {
+        return gljUtil.calcUnitB(total,building,scMathUtil,coe,decimal)
     },
     calUnitWidthCoe:function (total,noNeedCoe) {
-        let areas = exportUtil.getBuildArea(projectObj.project.property.engineerFeatures);
-        let f = _.find(projectObj.project.property.engineerFeatures,{index:true});
-        return f && noNeedCoe!==true?exportUtil.calcUnitB(total,areas,f.coe):exportUtil.calcUnitB(total,areas);
+        return gljUtil.calUnitWidthCoe(total,noNeedCoe,projectObj.project.property.engineerFeatures,_,scMathUtil);
     },
     getIndexBills:function (bills) {
-        let parentMap = {},datas = [],totalCost = 0;
-        let FBFX_b = null,teh_b = null,costNode=null;
-        for(let b of bills) {
-            parentMap[b.ParentID] ? parentMap[b.ParentID].push(b) : parentMap[b.ParentID] = [b];//有添加,无则生成
-            if(b.flags && b.flags.length > 0){
-                let f = _.find(b.flags,{"fieldName":"fixed"});
-                if(!f) continue;
-                if(f.flag == fixedFlag.SUB_ENGINERRING) FBFX_b = b;//过滤出分部分项工程;
-                if(f.flag == fixedFlag.CONSTRUCTION_TECH) teh_b = b;//过滤出技术措施项目;
-                if(f.flag == fixedFlag.ENGINEERINGCOST) costNode = b;//过滤出工程造价项目;
-            }
-        }
-        if(FBFX_b) getChildren(FBFX_b,parentMap,datas);
-        if(teh_b) getChildren(teh_b,parentMap,datas);
-        if(costNode) totalCost = exportUtil.getTotalFee(costNode);
-
-        for(let td of datas){
-            if(parentMap[td.ID]){
-                td.economicType = "";
-                td.quantityIndexType = "";
-                td.quantityIndexUnit = "";
-                td.quantityIndexCoe = "";
-            }
-        }
-        return [datas,totalCost];
-
-        function getChildren(d,map,arr) {
-            let tem = {
-                ID:d.ID,
-                ParentID:d.ParentID,
-                code:d.code,
-                name:d.name,
-                unit:d.unit,
-                quantity:d.quantity,
-                totalFee:exportUtil.getTotalFee(d),
-                economicType:d.economicType,
-                quantityIndexType:d.quantityIndexType,
-                quantityIndexUnit:d.quantityIndexUnit,
-                quantityIndexCoe:d.quantityIndexCoe,
-            };
-            arr.push(tem);
-            if(map[d.ID]){
-                for(let s of map[d.ID]){
-                    getChildren(s,map,arr)
-                }
-            }
-        }
+        return gljUtil.getIndexBills(bills,fixedFlag,_,scMathUtil);
     }
 };
 

+ 3 - 2
web/building_saas/main/js/models/exportStandardInterface.js

@@ -691,7 +691,7 @@ const XMLStandard = (function () {
                 {name: '计算基础', value: exportKind === _config.EXPORT_KIND.Tender ? source.calcBaseValue : '', type: _config.TYPE.DECIMAL, required: true},
                 {name: '服务内容', value: source.serviceContent, maxLen: 255, required: true,
                     failHint: `第${source.row}行承包服务费清单-“服务内容”`},
-                {name: '费率', value: exportKind === _config.EXPORT_KIND.Tender ? source.feeRate : '100', type: _config.TYPE.DECIMAL, required: true},
+                {name: '费率', value: exportKind === _config.EXPORT_KIND.Tender ? source.feeRate : '0', type: _config.TYPE.DECIMAL, required: true},
                 {name: '金额', value: exportKind === _config.EXPORT_KIND.Tender ? _util.getFee(source.fees, 'common.totalFee') : '0', type: _config.TYPE.NUM2, required: true},
                 {name: '备注', value: source.remark}
             ];
@@ -951,6 +951,8 @@ const XMLStandard = (function () {
         //@param {Number}tenderID(当前界面的单位工程ID,后台根据这个单位工程,去找其建设项目下所有数据)
         //@return {Object}(eleObj)
         async function loadProject(projectData) {
+            // 标记自检提示的开始(一次性多出多个文件类型,会导出多次)
+            _failList.push(_config.HINT_START);
             console.log(projectData);
             //标段
             let project = new Project({
@@ -1735,7 +1737,6 @@ const XMLStandard = (function () {
                         if (hasBillsClass) {
                             _failList.push(`第${source.row}行清单应是清单分类,其下必须有清单项目。<span style="color: red">(错误清单结构)</span>`);
                         }
-                        debugger;
                         parent.children.push(new TurnKeyContractItem(source));
                     }
                 }

+ 60 - 3
web/building_saas/main/js/models/exportStdInterfaceBase.js

@@ -8,7 +8,8 @@
  * @version
  */
 const XML_EXPORT_BASE = (() => {
-
+    // 自检提示的开始记号,区分提示属于哪一部分的类型(eg: 招标、控制价),便于后续做提示的合并去重
+    const HINT_START = '--start--';
     // 属性类型
     const TYPE = {
         DATE: 1,        //日期类型YYYY-MM-DD
@@ -40,7 +41,7 @@ const XML_EXPORT_BASE = (() => {
         coe: 'priceCoe' // 价格指数调整法
     };
     // 加载数据间隔,减少服务器压力
-    const TIMEOUT_TIME = 500;
+    const TIMEOUT_TIME = 200;
     // 导出粒度
     const GRANULARITY = {
         PROJECT: 1,         //导出建设项目
@@ -55,6 +56,7 @@ const XML_EXPORT_BASE = (() => {
     };
     // 配置项
     const CONFIG = Object.freeze({
+        HINT_START,
         TYPE,
         WHITE_SPACE,
         TAX_TYPE,
@@ -164,7 +166,7 @@ const XML_EXPORT_BASE = (() => {
         let dateReg = /([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))/;
         for (let data of datas) {
             // 值统一转换成String
-            data.value = !isDef(data.value)
+            data.value = !hasValue(data.value)
                 ? DEFAULT_VALUE[data.type]
                     ? DEFAULT_VALUE[data.type]
                     : ''
@@ -238,6 +240,60 @@ const XML_EXPORT_BASE = (() => {
         }
         return rst;
     }
+    // 提取各导出类型的自检数据
+    function _extractHintParts(failList) {
+        let rst = [],
+            curPart;
+        for (let hint of failList) {
+            if (hint === HINT_START) {
+                curPart = [];
+                rst.push(curPart);
+                continue;
+            }
+            curPart.push(hint);
+        }
+        return rst;
+    }
+    // 自检提示去重
+    function deWeightHints(failList) {
+        let rst = [];
+        let hintParts = _extractHintParts(failList);
+        // 建设项目提示文本
+        let rootHints = [],
+            // 单位工程提示文本映射
+            tenderMap = {},
+            reg = /^<span style="font-weight: bold">单位工程/;
+        for (let hintPart of hintParts) {
+            // 单位工程xxx提示
+            let curTenderHint;
+            // 提取建设项目提示、各自单位工程提示
+            for (let hint of hintPart) {
+                if (reg.test(hint)) {
+                    curTenderHint = hint;
+                    if (!tenderMap[curTenderHint]) {
+                        tenderMap[curTenderHint] = [];
+                    }
+                    continue;
+                }
+                if (curTenderHint) {
+                    tenderMap[curTenderHint].push(hint);
+                } else {
+                    rootHints.push(hint);
+                }
+            }
+        }
+        // 建设项目提示去重,放入结果中
+        rootHints = [...new Set(rootHints)];
+        rst.push(...rootHints);
+        // 单位工程提示放入结果中
+        for (let tenderHint in tenderMap) {
+            rst.push(tenderHint);
+            // 单位工程提示去重
+            let tenderHints = [...new Set(tenderMap[tenderHint])];
+            rst.push(...tenderHints);
+        }
+        return rst;
+    }
     // 等待一段时间
     function setTimeoutSync(handle, time) {
         return new Promise((resolve, reject) => {
@@ -609,6 +665,7 @@ const XML_EXPORT_BASE = (() => {
     }
 
     const UTIL = Object.freeze({
+        deWeightHints,
         isDef,
         hasValue,
         setTimeoutSync,

+ 154 - 62
web/building_saas/main/js/views/billsElf.js

@@ -9,20 +9,21 @@
  */
 
 /*
-* 造价书下方清单精灵
+* 造价书下方清单精灵、清单指引
 * */
 //选项单选多选状态(按住alt为多选) 单选:0 多选:1
 let billsGuidanceSelMode = 0;
 
-const BillsElf = (function() {
-    //清单精灵树挂载的地方,selected:当前选中的清单,mapping:以前九位清单编码为索引, 'xxx' : {elf: {datas, tree, controller}}
+const BillsSub = (function() {
+    //清单树挂载的地方,selected:当前选中的清单,mapping:以前九位清单编码为索引, 'xxx' : {sub: {datas, tree, controller}}
     let bills = {selected: null, mapping: {}};
     const itemType = {
         job: 0,
         ration: 1
     };
+    // 清单精灵
     const elfItem = {
-        dom: $('#elfItems'),
+        dom: $('#billsSubItems'),
         workBook: null,
         tree: null,
         controller: null,
@@ -92,6 +93,88 @@ const BillsElf = (function() {
             }
         }
     };
+    // 清单指引
+    const guideItem = {
+        dom: $('#billsSubItems'),
+        workBook: null,
+        tree: null,
+        controller: null,
+        treeSetting: {
+            treeCol: 1,
+            emptyRows: 0,
+            headRows: 1,
+            headRowHeight: [40],
+            defaultRowHeight: 21,
+            cols: [
+                {
+                    width: 420,
+                    readOnly: false,
+                    head: {
+                        titleNames: ["项目指引"],
+                        spanCols: [1],
+                        spanRows: [1],
+                        vAlign: [1],
+                        hAlign: [1],
+                        font: ["Arial"]
+                    },
+                    data: {
+                        field: "name",
+                        vAlign: 1,
+                        hAlign: 0,
+                        font: "Arial"
+                    }
+                },
+                {
+                    width: 35,
+                    readOnly: false,
+                    head: {
+                        titleNames: ["选择"],
+                        spanCols: [1],
+                        spanRows: [1],
+                        vAlign: [1],
+                        hAlign: [1],
+                        font: ["Arial"]
+                    },
+                    data: {
+                        field: "select",
+                        vAlign: 1,
+                        hAlign: 1,
+                        font: "Arial"
+                    }
+                }
+            ]
+        },
+        headers: [
+            {name: '项目指引', dataCode: 'name', width: 300, vAlign: 'center', hAlign: 'left', formatter: '@'},
+            {name: '选择', dataCode: 'select', width: 35, vAlign: 'center', hAlign: 'center', formatter: '@'},
+        ],
+        rowHeaderWidth:25,
+        events: {
+            /*EditStarting: function (sender, args) {
+                if(!bills.tree || guideItem.headers[args.col]['dataCode'] === 'name'){
+                    args.cancel = true;
+                }
+            },*/
+            ButtonClicked: function (sender, args) {
+                if(args.sheet.isEditing()){
+                    args.sheet.endEdit(true);
+                }
+                //refreshInsertRation();
+            },
+        }
+    };
+
+    // 目前的模块:清单精灵或清单指引,默认是清单指引
+    let curModule = guideItem;
+    // 切换目前的模块
+    // 1:清单指引 2:清单精灵
+    function switchModule(type) {
+        curModule = elfItem;
+       /* curModule = type === 1
+            ? guideItem
+            : elfItem;*/
+    }
+
     const options = {
         workBook: {
             tabStripVisible:  false,
@@ -193,20 +276,20 @@ const BillsElf = (function() {
     //建表
     //@param {Object}module @return {void}
     function buildSheet() {
-        if(!elfItem.workBook){
-            elfItem.workBook = new GC.Spread.Sheets.Workbook(elfItem.dom[0], {sheetCount: 1});
-            sheetCommonObj.spreadDefaultStyle(elfItem.workBook);
-            let sheet = elfItem.workBook.getActiveSheet();
-            sheet.options.isProtected = true;
+        console.log(curModule);
+        if(!curModule.workBook){
+            curModule.workBook = new GC.Spread.Sheets.Workbook(curModule.dom[0], {sheetCount: 1});
+            sheetCommonObj.spreadDefaultStyle(curModule.workBook);
+            let sheet = curModule.workBook.getActiveSheet();
+            /*sheet.options.isProtected = true;
             sheet.getRange(-1, 0, -1, 1).locked(true);
-            sheet.getRange(-1, 1, -1, 1).locked(false);
-            if(elfItem.rowHeaderWidth) {
-                sheet.setColumnWidth(0, elfItem.rowHeaderWidth, GC.Spread.Sheets.SheetArea.rowHeader);
+            sheet.getRange(-1, 1, -1, 1).locked(false);*/
+            if(curModule.rowHeaderWidth) {
+                sheet.setColumnWidth(0, curModule.rowHeaderWidth, GC.Spread.Sheets.SheetArea.rowHeader);
             }
-            setOptions(elfItem.workBook, options);
-            buildHeader(elfItem.workBook.getActiveSheet(), elfItem.headers);
-            //setColumnWidthByRate(elfItem.workBook, $('#elfItems').width(), elfItem.headers);
-            bindEvent(elfItem.workBook, elfItem.events);
+            setOptions(curModule.workBook, options);
+            buildHeader(curModule.workBook.getActiveSheet(), curModule.headers);
+            bindEvent(curModule.workBook, curModule.events);
         }
     }
     //刷新表
@@ -216,9 +299,9 @@ const BillsElf = (function() {
         if ($('#qdjl').is(':visible')) {
             let totalHeight = $('#qdjl').height(),
                 elfToolsHeight = $('#qdjlTools').height();
-            $('#elfItems').height(totalHeight - elfToolsHeight);
-            if (elfItem.workBook) {
-                elfItem.workBook.refresh();
+            $('#billsSubItems').height(totalHeight - elfToolsHeight);
+            if (curModule.workBook) {
+                curModule.workBook.refresh();
             }
         }
     }
@@ -247,32 +330,35 @@ const BillsElf = (function() {
     function elfItemInitSel(row){
         let billsNode = bills.selected;
         let node = null;
-        if(billsNode && billsNode.elf.tree){
-            node = billsNode.elf.tree.items[row];
+        if(billsNode && billsNode.sub.tree){
+            node = billsNode.sub.tree.items[row];
             if(node){
-                billsNode.elf.tree.selected = node;
+                billsNode.sub.tree.selected = node;
             }
         }
     }
-    //清单焦点变换-清单精灵操作,获取清单前九位编码的标准清单清单精灵选项
+    //清单焦点变换-清单子界面操作,获取清单前九位编码的标准清单清单精灵选项 或 清单指引数据
     //@param {String}code @return {void}
-    function billsSelElf(code) {
-        let elfSheet = elfItem.workBook.getActiveSheet();
-        cleanData(elfSheet, elfItem.headers, -1);
+    function billsSelSub(code) {
+        console.log(bills);
+        let sheet = curModule.workBook.getActiveSheet();
+        cleanData(sheet, curModule.headers, -1);
         if (!code || code === '') {
             return;
         }
         let nineCode = code.substr(0, 9);
         //查看此清单映射是否存在此编码映射数据,不存在,则新建映射
         if (!bills.mapping[nineCode]) {
-            bills.mapping[nineCode] = {elf: {datas: [], tree: null, controller: null}};
+            bills.mapping[nineCode] = {sub: {datas: [], tree: null, controller: null}};
         }
         let node = bills.mapping[nineCode];
         bills.selected = node;
-        if(!node.elf.tree){
+        if(!node.sub.tree){
             let guidanceLibID;
             if (projectObj.project.projectInfo.engineeringInfo && projectObj.project.projectInfo.engineeringInfo.billsGuidance_lib) {
-                guidanceLibID = projectObj.project.projectInfo.engineeringInfo.billsGuidance_lib[0] ? projectObj.project.projectInfo.engineeringInfo.billsGuidance_lib[0].id : null;
+                guidanceLibID = projectObj.project.projectInfo.engineeringInfo.billsGuidance_lib[0]
+                    ? projectObj.project.projectInfo.engineeringInfo.billsGuidance_lib[0].id
+                    : null;
             }
             CommonAjax.post('/billsGuidance/api/getItemsByCode', {guidanceLibID: guidanceLibID, code: nineCode}, function (rstData) {
                 //定额数据删除编号信息,(编码后+空格才会去除编码)
@@ -285,7 +371,7 @@ const BillsElf = (function() {
                         }
                     }
                 }
-                node.elf.datas = rstData;
+                node.sub.datas = rstData;
                 //第一层节点数据
                 let firstLevelDatas = _.filter(rstData, function (data) {
                     return data.ParentID == -1;
@@ -298,11 +384,11 @@ const BillsElf = (function() {
                     fData.optionsData = options && options.length > 0 ? _.cloneDeep(options) : [];
                     fData.optionChecked = options && options.length > 0 ? [_.cloneDeep(options[0])] : [];
                 }
-                renderSheetFunc(elfSheet, function () {
-                    initTree(node.elf, elfSheet, elfItem.treeSetting, firstLevelDatas);
+                renderSheetFunc(sheet, function () {
+                    initTree(node.sub, sheet, elfItem.treeSetting, firstLevelDatas);
                     //初始选择选项
                     let initOptsOpr = [];
-                    for(let elfNode of node.elf.tree.items){
+                    for(let elfNode of node.sub.tree.items){
                         if(elfNode.data.optionsData.length > 0){
                             initOptsOpr.push({node: elfNode, data: elfNode.data.optionsData[0]});
                         }
@@ -310,19 +396,18 @@ const BillsElf = (function() {
                     for(let opr of initOptsOpr){
                         insertNodeByData(opr.node, opr.data);
                     }
-                    TREE_SHEET_HELPER.refreshTreeNodeData(elfItem.treeSetting, elfSheet, node.elf.tree.items, false);
-                    setOptionsCellType(node.elf.tree.items);
+                    TREE_SHEET_HELPER.refreshTreeNodeData(elfItem.treeSetting, sheet, node.sub.tree.items, false);
+                    setOptionsCellType(node.sub.tree.items);
                     //项目指引初始焦点
-                    elfItemInitSel(elfSheet.getActiveRowIndex() ? elfSheet.getActiveRowIndex() : 0);
+                    elfItemInitSel(sheet.getActiveRowIndex() ? sheet.getActiveRowIndex() : 0);
                 });
             });
-        }
-        else{
-            renderSheetFunc(elfSheet, function () {
-                node.elf.controller.showTreeData();
-                setOptionsCellType(node.elf.tree.items);
+        } else{
+            renderSheetFunc(sheet, function () {
+                node.sub.controller.showTreeData();
+                setOptionsCellType(node.sub.tree.items);
                 //项目指引初始焦点
-                elfItemInitSel(elfSheet.getActiveRowIndex() ? elfSheet.getActiveRowIndex() : 0);
+                elfItemInitSel(sheet.getActiveRowIndex() ? sheet.getActiveRowIndex() : 0);
             });
         }
     }
@@ -412,9 +497,9 @@ const BillsElf = (function() {
         let insertNextSiblingID = -1,
             insertParentID = node.data.ID;
         //当前操作节点的选项
-        let nodeOpts = getOptions(node.data, bills.selected.elf.datas);
-        let subOpts = getOptions(data, bills.selected.elf.datas);
-        let dataDepth = getOptionDepth(data, bills.selected.elf.datas);
+        let nodeOpts = getOptions(node.data, bills.selected.sub.datas);
+        let subOpts = getOptions(data, bills.selected.sub.datas);
+        let dataDepth = getOptionDepth(data, bills.selected.sub.datas);
         if(subOpts.length >0 && subOpts[0].type !== itemType.ration){
             if((dataDepth + 1) % 2 === 0){
                 //排序后的数据
@@ -423,9 +508,9 @@ const BillsElf = (function() {
                 for(let subOpt of subOpts){
                     for(let subNode of sameDepthNodes){
                         //同层节点原本选项数据
-                        let subNodeOptData = _.find(bills.selected.elf.datas, {ID: subNode.data.ID});
+                        let subNodeOptData = _.find(bills.selected.sub.datas, {ID: subNode.data.ID});
                         //同层节点原本父选项数据
-                        let subNodeOptParent = _.find(bills.selected.elf.datas, {ID: subNodeOptData.ParentID});
+                        let subNodeOptParent = _.find(bills.selected.sub.datas, {ID: subNodeOptData.ParentID});
                         let subNodeOptParentWithRank = _.find(nodeOpts, {ID: subNodeOptParent.ID});
                         //父项顺序决定插入位置
                         if(dataWithRank.rank < subNodeOptParentWithRank.rank){
@@ -440,7 +525,7 @@ const BillsElf = (function() {
                             }
                         }
                     }
-                    let sub2Opts = getOptions(subOpt, bills.selected.elf.datas);
+                    let sub2Opts = getOptions(subOpt, bills.selected.sub.datas);
                     subOpt.options = sub2Opts.length > 0 ? sub2Opts[0].name : '';
                     let cloneOpt = _.cloneDeep(subOpt);//不改变原本的数据,比如ParentID
                     cloneOpt.optionChecked = sub2Opts.length > 0 ? [_.cloneDeep(sub2Opts[0])] : [];
@@ -473,7 +558,7 @@ const BillsElf = (function() {
                 return '';
             }
             let height = cellRect.height;
-            let options = getOptions(node.data, bills.selected.elf.datas);
+            let options = getOptions(node.data, bills.selected.sub.datas);
             top = options.length > 6 ? top - 6 * height : top - options.length * height;
             let $editInput = $(`<div style="height: ${height}px; background: ${cellStyle.backColor};overflow: hidden; white-space: nowrap; text-overflow: ellipsis">${node.data.options}</div>`),
                 $optDiv = $(`<div style="position: fixed; width: ${cellRect.width}px; top: ${top}px;background: ${cellStyle.backColor};border: 1px solid; overflow: auto; height: ${options.length > 6 ? height*6+5 : height*options.length+5}px; font-size: 0.9rem;"></div>`);
@@ -510,7 +595,7 @@ const BillsElf = (function() {
             let checkedNameArr = [],
                 optionChecked= [];
             for(let checkSel of checkedSels){
-                let opt = _.cloneDeep(_.find(bills.selected.elf.datas, {ID: $(checkSel).val()}));
+                let opt = _.cloneDeep(_.find(bills.selected.sub.datas, {ID: $(checkSel).val()}));
                 opt.rank = $(checkSel).attr('rank');
                 checkedNameArr.push(opt.name);
                 optionChecked.push(opt);
@@ -527,7 +612,7 @@ const BillsElf = (function() {
             //插入节点
             for(let perCheked of optionChecked){
                 let exist = false;
-                let subOpts = getOptions(perCheked, bills.selected.elf.datas);
+                let subOpts = getOptions(perCheked, bills.selected.sub.datas);
                 for(let subNode of node.children){
                     for(let subOpt of subOpts){
                         if(subNode.data.ID === subOpt.ID){
@@ -550,7 +635,7 @@ const BillsElf = (function() {
             for(let subNode of node.children){
                 let exist = false;
                 for(let perChecked of optionChecked){
-                    let subOpts = getOptions(perChecked, bills.selected.elf.datas);
+                    let subOpts = getOptions(perChecked, bills.selected.sub.datas);
                     for(let subOpt of subOpts){
                         if(subNode.data.ID === subOpt.ID){
                             exist = true;
@@ -579,7 +664,7 @@ const BillsElf = (function() {
                 $editor.attr("gcUIElement", "gcEditingInput");
                 //编辑文本框距离浏览器的top
                 let top = $('.header').height() + $('#zaojiashu').find('.toolsbar').height() + $('#top_div').height() + $('#bottom_div_ul').height() + $('#qdjlTools').height() + $('.resize-y').height();
-                let node = bills.selected.elf.tree.items[elfSheet.getActiveRowIndex()];
+                let node = bills.selected.sub.tree.items[elfSheet.getActiveRowIndex()];
                 setOptionsDiv($editor, node, cellRect, cellStyle, top + cellRect.y);
                 this.isEscKey = false;
             }
@@ -592,7 +677,7 @@ const BillsElf = (function() {
         };
         OptionsCellType.prototype.getEditorValue = function (editor, context) {
             let me = this;
-            let node = bills.selected.elf.tree.items[elfSheet.getActiveRowIndex()];
+            let node = bills.selected.sub.tree.items[elfSheet.getActiveRowIndex()];
             if(this.isEscKey !=true){
                 renderSheetFunc(elfSheet, function () {
                     doAfterSel.call(me, node);
@@ -649,10 +734,10 @@ const BillsElf = (function() {
     //@return {Array}
     function getInsertElfRationData(){
         let rst = [];
-        if(!bills.selected || !bills.selected.elf){
+        if(!bills.selected || !bills.selected.sub){
             return rst;
         }
-        let tree = bills.selected.elf.tree;
+        let tree = bills.selected.sub.tree;
         if(!tree){
             return rst;
         }
@@ -676,7 +761,7 @@ const BillsElf = (function() {
                 }
                 //选项下子选项是定额
                 else {
-                    let rationOpts = getOptions(perChecked, bills.selected.elf.datas);
+                    let rationOpts = getOptions(perChecked, bills.selected.sub.datas);
                     for(let ration of rationOpts){
                         if(ration.type === itemType.ration && !existTheRation(ration.rationID)){
                             rst.push({itemQuery: {userID: userID, ID: ration.rationID}, rationType: rationType.ration});
@@ -691,10 +776,10 @@ const BillsElf = (function() {
     //@return {Array}
     function getInsertElfSingleRation() {
         let rst = [];
-        if (!bills.selected || !bills.selected.elf) {
+        if (!bills.selected || !bills.selected.sub) {
             return rst;
         }
-        let tree = bills.selected.elf.tree;
+        let tree = bills.selected.sub.tree;
         if (!tree) {
             return rst;
         }
@@ -718,7 +803,7 @@ const BillsElf = (function() {
         if (firstOptionChecked.type === itemType.ration && !existTheRation(firstOptionChecked.rationID)) {
             rst.push({itemQuery: {userID: userID, ID: firstOptionChecked.rationID}, rationType: rationType.ration});
         } else {
-            let rationOpts = getOptions(firstOptionChecked, bills.selected.elf.datas);
+            let rationOpts = getOptions(firstOptionChecked, bills.selected.sub.datas);
             for(let ration of rationOpts){
                 if(ration.type === itemType.ration && !existTheRation(ration.rationID)){
                     rst.push({itemQuery: {userID: userID, ID: ration.rationID}, rationType: rationType.ration});
@@ -757,9 +842,16 @@ const BillsElf = (function() {
             insertRations(addRationDatas);
         });
     }
-    return {buildSheet, refreshWorkBook, billsSelElf, setColumnWidthByRate, bindListener};
+    return {
+        switchModule,
+        buildSheet,
+        refreshWorkBook,
+        billsSelSub,
+        setColumnWidthByRate,
+        bindListener
+    };
 })();
 
 $(document).ready(function () {
-    BillsElf.bindListener();
+    BillsSub.bindListener();
 });

+ 4 - 3
web/building_saas/main/js/views/export_view.js

@@ -10,7 +10,8 @@
 //导出接口相关
 const ExportView = (() => {
     let _base = XML_EXPORT_BASE,
-        _cache = _base.CACHE;
+        _cache = _base.CACHE,
+        _util = _base.UTIL;
     // 导出数据缓存
     let _exportCache = [];
     //设置工程编号表格数据设置
@@ -82,7 +83,7 @@ const ExportView = (() => {
                         _exportCache.push(...exportData);
                     }
                 }
-                failList = [...new Set(failList)];
+                failList = _util.deWeightHints(failList);
                 //设置提示弹窗
                 if (failList.length * 20 > 400) {
                     $('#hintBox_caption').addClass('export-check');
@@ -126,7 +127,7 @@ const ExportView = (() => {
                     }
                     pr.end();
                 }
-                failList = [...new Set(failList)];
+                failList = _util.deWeightHints(failList);
                 //错误-设置提示弹窗
                 if (failList.length * 20 > 400) {
                     $('#hintBox_caption').addClass('export-check');

+ 6 - 62
web/building_saas/main/js/views/index_view.js

@@ -259,7 +259,7 @@ let indexObj= {
                     cost:parseFloat(c.attrs[0].value),
                     unitCost:parseFloat(c.attrs[1].value),
                     per:parseFloat(c.attrs[2].value)
-                }
+                };
                 datas.push(tem);
             }
             return datas;
@@ -288,7 +288,8 @@ let indexObj= {
         sheet.setRowCount(quantityDatas.length);
     },
     getQuantityDatas:function (mainQuantities,billsList) {
-        let datas = [];
+        return gljUtil.getQuantityDatas(projectObj.project.property.engineerFeatures,mainQuantities,billsList,fixedFlag,_,scMathUtil,projectObj.project.property.decimal)
+       /* let datas = [];
         let [bills,totalFee] = exportUtil.getIndexBills(billsList);
         let billsGroup = _.groupBy(bills,'quantityIndexType');
         if(!mainQuantities) return datas;
@@ -313,71 +314,14 @@ let indexObj= {
             data.quantity = exportUtil.calUnitWidthCoe(quantity);
         }     
         
-        return datas;
+        return datas;*/
     },
     getEconomicDatas:function (economics,billsList) {
-        let datas = [];
-        let [bills,totalFee] = exportUtil.getIndexBills(billsList);
-        let billsGroup = _.groupBy(bills,'economicType');
-        if(!economics) return datas;
-        for(let e of economics){
-            let tem = {
-                name:e.name,
-                cost:0,
-                unitCost:0,
-                per:0
-            };
-            if(billsGroup[e.name]) setEconomics(billsGroup[e.name],totalFee,tem);
-            datas.push(tem);
-        }
-        function setEconomics(items,engineerCost,data) {
-            let cost = 0;
-            let priceDe = getDecimal("bills.totalPrice");
-            for(let i of items){
-                i.totalFee =  scMathUtil.roundForObj(i.totalFee,priceDe);
-                cost = scMathUtil.roundForObj(cost + i.totalFee,getDecimal("process"));
-            }
-            data.cost = scMathUtil.roundForObj(cost,priceDe);
-            data.unitCost = exportUtil.calUnitWidthCoe(data.cost,true);//noNeedCoe = true 这里不需要乘以系数
-            data.per = engineerCost?scMathUtil.roundForObj(data.cost/engineerCost * 100,2):0;
-        }
-
-        return datas;
+        return gljUtil.getEconomicDatas(projectObj.project.property.engineerFeatures,economics,billsList,fixedFlag,_,scMathUtil);
     },
 
     getMainMaterialDatas:function (materials,projectGLJData,calcOptions,decimalObj,isRadio,_,scMathUtil) {
-        let datas = [];
-        let materialGroup = _.groupBy(projectGLJData.gljList,'materialIndexType');
-        if(!materials) return datas;
-        for(let m of materials){
-            let tem = {
-                name:m.name,
-                unit:m.unit,
-                unitPrice:0,
-                quantity:0,
-                unitIndex:0
-            };
-            if(materialGroup[m.name]) setMainMaterial(materialGroup[m.name],tem);
-            datas.push(tem);
-        }
-
-        function setMainMaterial(gljs,data) {
-            let quantity = 0 ,unitPrice=0;
-            for(let g of gljs){
-                if(!g.quantity || g.quantity=="") continue;
-                let marketPrice = gljUtil.getMarketPrice(g,projectGLJData,calcOptions,decimalObj,false,_,scMathUtil); // gljOprObj.setGLJPrice(tem,g);
-                let materialIndexCoe = g.materialIndexCoe?scMathUtil.roundForObj(g.materialIndexCoe,getDecimal("process")):0;
-                let t_quantity = scMathUtil.roundForObj(g.quantity * materialIndexCoe,getDecimal("process"));
-                quantity = scMathUtil.roundForObj(t_quantity + quantity,getDecimal("process"));
-                let temPrice = scMathUtil.roundForObj(g.quantity * marketPrice,getDecimal("process"));
-                unitPrice = scMathUtil.roundForObj(temPrice + unitPrice,getDecimal("process"));
-            }
-            data.quantity = scMathUtil.roundForObj(quantity,2);
-            if(data.quantity) data.unitPrice = scMathUtil.roundForObj(unitPrice/data.quantity,2);
-            data.unitIndex = exportUtil.calUnitWidthCoe(data.quantity);
-        }
-
-        return datas;
+        return gljUtil.getMainMaterialDatas(projectObj.project.property.engineerFeatures,materials,projectGLJData,calcOptions,decimalObj,isRadio,_,scMathUtil);
     },
     showEcoQuantity:function () {
         let parentMap = {};

+ 8 - 0
web/building_saas/main/js/views/project_info.js

@@ -33,6 +33,14 @@ var projectInfoObj = {
         if (data) {
             if(!data.engineeringInfo.billsGuidance_lib || data.engineeringInfo.billsGuidance_lib.length === 0){
                 $('#stdBillsGuidanceTab').addClass('disabled');
+            } else {
+                let billsGuidanceLib = data.engineeringInfo.billsGuidance_lib[0],
+                    libText = billsGuidanceLib.type === 1
+                        ? '清单精灵'
+                        : '清单精灵';
+                $('#stdBillsGuidanceTab').text(libText);
+                $('#linkQDJL').text(libText);
+                BillsSub.switchModule(billsGuidanceLib.type);
             }
             //init decimal
             setDecimal(decimalObj, data.property.decimal);

+ 13 - 10
web/building_saas/main/js/views/project_view.js

@@ -291,7 +291,7 @@ var projectObj = {
         let stdMatchCode, formatCode, matchs;
         let searchStdBillsAndUpdate = function (stdCode, formatCode) {
             let orgCode = node.data.code?node.data.code.substr(0, 9):"";
-            if (projectObj.project.projectInfo.engineeringInfo.bill_lib.length === 0) {
+            if (projectObj.project.projectInfo.engineeringInfo.bill_lib.length === 0 || updateCodeCheck(value,stdCode === orgCode)) {
                 normalUpdate(node,value,stdCode === orgCode);
             } else if (projectObj.project.projectInfo.engineeringInfo.bill_lib.length > 0) {
                 let libId = projectObj.project.projectInfo.engineeringInfo.bill_lib[0].id;
@@ -333,13 +333,13 @@ var projectObj = {
                                 data.unit = existB.unit;
                                 project.Bills.replaceBills(node.source, data, formatCode);
                                 projectObj.mainController.refreshTreeNode([node], false);
-                                BillsElf.billsSelElf(node.data.code);
+                                BillsSub.billsSelSub(node.data.code);
                             } else {
                                 ConfirmModal.stdBillsUnit.check(data, function (std) {
                                     updateBeforeInsert(node, data);
                                     project.Bills.replaceBills(node.source, std, formatCode);
                                     projectObj.mainController.refreshTreeNode([node], false);
-                                    BillsElf.billsSelElf(node.data.code);
+                                    BillsSub.billsSelSub(node.data.code);
                                 }, function () {
                                     projectObj.mainController.refreshTreeNode([node], false);
                                 });
@@ -348,14 +348,14 @@ var projectObj = {
                             updateBeforeInsert(node, data);
                             project.Bills.replaceBills(node.source, data, formatCode);
                             projectObj.mainController.refreshTreeNode([node], false);
-                            BillsElf.billsSelElf(node.data.code);
+                            BillsSub.billsSelSub(node.data.code);
                         }
                     } else {
                         normalUpdate(node,value);
                     }
                 });
             }
-        }
+        };
         //分部分项、措施项目才匹配
         let withinValidFixed = false;
         let matchFixedFlags = [fixedFlag.SUB_ENGINERRING, fixedFlag.MEASURE];
@@ -387,16 +387,19 @@ var projectObj = {
         }
         normalUpdate(node,value);
 
-
-        function normalUpdate(billnode,codeValue,onNeedCheck) {//在标准库中没有找到清单时改分项为补项再更新
+        function normalUpdate(billnode,codeValue,no_Need_Check) {//在标准库中没有找到清单时改分项为补项再更新
             let toBX = false;
-            if(onNeedCheck!==true && billnode.data.type == billType.FX){
+            if(no_Need_Check!==true && billnode.data.type == billType.FX){
                 billnode.data.type = billType.BX;
                  toBX = true;
             }
             project.Bills.updateField(billnode.source, 'code', codeValue, toBX);
             me.mainController.refreshTreeNode([billnode], false);
         }
+
+        function updateCodeCheck(value,sameStdCode) {//如果前9位相同,只改前三位,则只更新编号就行了,不用做其它处理
+            return sameStdCode && value && value.length == 12
+        }
     },
     updateRationCode: function (node, value) {
         if(!isDef(node.data.code) && (!isDef(value) || value.toString().trim() == '')){
@@ -1322,7 +1325,7 @@ var projectObj = {
                         return !project.Ration.canAdd(project.mainTree.selected);
                     },
                     callback: function (key, opt) {
-                        project.Ration.addNewRation(null,rationType.ration,projectObj.selectColAndFocus,true);
+                        project.Ration.addNewRation(null,rationType.ration,projectObj.selectColAndFocus,false);
                        // ProjectController.addRation(project, controller, rationType.ration);
                     }/*,
                     visible: function(key, opt){
@@ -1953,7 +1956,7 @@ var projectObj = {
         TREE_SHEET_HELPER.massOperationSheet(sheet, function () {
             for(let node of nodes){
                 if(node && node.serialNo()!= -1){
-                    sheet.getRange(node.serialNo(), -1, 1, -1).backColor(me.getNodeColorStyle(sheet, node,tree).backColor);
+                    sheet.getRange(node.serialNo(), -1, 1, -1).backColor(me.getNodeColorStyle(sheet, node,tree)?me.getNodeColorStyle(sheet, node,tree).backColor:null);
                 }
             }
         });

+ 0 - 2
web/building_saas/main/js/views/side_tools.js

@@ -9,7 +9,6 @@ $(window).resize(function() {
     billsGuidance.setColumnWidthByRate(billsGuidance.elfItem.workBook, $('#zy').width(), billsGuidance.elfItem.headers);
     billsGuidance.refreshWorkBook();
     rationLibObj.refreshSpread();
-    //BillsElf.setColumnWidthByRate();
     loadSideToolsHeight();
     //刷新主界面与各库中间的拖动条宽度:始终保持为一个宽度(在小窗口打开一个库,再放大窗口后,该拖动条宽度会变大)
     SlideResize.setResizeWidth($('#sideResize'));
@@ -36,7 +35,6 @@ SlideResize.horizontalSlide(sideResizeEles.eleObj, sideResizeEles.limit, functio
     subObj.initGljSubTab();
     subObj.initQDSubTab();
     pageCCOprObj.resizeWidth();
-    //BillsElf.setColumnWidthByRate();
     projectObj.refreshMainSpread();
     refreshSubSpread();
     if (sideResizeEles.eleObj.module === 'stdBillsGuidanceTab') {//清单精灵(规则)

+ 1 - 1
web/building_saas/main/js/views/std_billsGuidance_lib.js

@@ -666,8 +666,8 @@ const billsGuidance = (function () {
                 elfItem.workBook = null;
             }
             initViews();
-            initTree(bills, bills.workBook.getActiveSheet(), bills.treeSetting, rstData.bills);
             let callback = function () {
+                initTree(bills, bills.workBook.getActiveSheet(), bills.treeSetting, rstData.bills);
                 if(doAfterLoadGuidance){
                     doAfterLoadGuidance();
                 }

+ 10 - 6
web/building_saas/main/js/views/sub_view.js

@@ -13,9 +13,10 @@ let subObj = {
     TZJNRrePercent:null,
     showGljSubTab:false,
     showQDSubTab:false,
+    firstOpen:true,
     initSubSpread:function () {
-        //清单精灵
-        BillsElf.buildSheet();
+        //清单子界面
+        BillsSub.buildSheet();
         contentOprObj.buildSheet($("#jobSpread")[0]);
         //sheetCommonObj.bindEscKey(contentOprObj.workBook, [{sheet: contentOprObj.workBook.getSheet(0), editStarting: contentOprObj.onEditStart, editEnded: contentOprObj.onEditEnded}]);
         sheetCommonObj.spreadDefaultStyle(contentOprObj.workBook);
@@ -198,6 +199,10 @@ let subObj = {
         if (gljOprObj.activeTab !== gljOprObj.preActiveTab) {   //提高焦点变换性能 2019年4月12日
             refreshSubSpread();
         }
+        if(this.firstOpen == true){
+            $("#zmhs_toogle").click();
+            this.firstOpen = false;
+        }
     },
     showQDSubTabData:function () {
         this.initQDSubTab();
@@ -366,10 +371,9 @@ $('#linkQDJL').click(function () {
     $("#xmtzTextDiv").show();
     $("#tzItemTab").show();
     let selectedNode = projectObj.mainController.tree.selected;
-    BillsElf.billsSelElf(selectedNode.data.code);
+    BillsSub.billsSelSub(selectedNode.data.code);
     //refreshSubSpread();      //提升焦点变换性能 2019年4月12日
     gljOprObj.setNodeShowTab();
-    //BillsElf.refreshWorkBook();   //提升焦点变换性能 2019年4月12日
 
 });
 //特征及内容
@@ -720,7 +724,7 @@ function refreshSubSpread(){
         if(subSpread) subSpread.refresh();
         if(MaterialController.spread) MaterialController.spread.refresh();
     }
-    BillsElf.refreshWorkBook();
+    BillsSub.refreshWorkBook();
     //if($('#linkZMHS').hasClass('active')) zmhs_obj.refresh();
     if($('#rnc-zm').is(':visible')|| $('#rnc-fz').is(':visible') || $('#rnc-cus')) zmhs_obj.refresh();
     if($('#linkMBZM').hasClass('active')) mbzm_obj.refresh();
@@ -815,7 +819,7 @@ $('#linkAZZJF').on('shown.bs.tab', function () {
 $('#zmhs_toogle').bind('click',function (){
    $("#zmhs_nav").show();
    if(subObj.showGljSubTab == false){
-       subObj.activeGLJItemTab?$(subObj.activeGLJItemTab).click():$("#xm-nav").click();
+       subObj.activeGLJItemTab?$(subObj.activeGLJItemTab).click():$("#hs-nav").click();
    }
     $("#zmhs_toogle").hide();
 });

+ 1 - 1
web/building_saas/main/js/views/zmhs_view.js

@@ -263,7 +263,7 @@ let zmhs_obj = {
         $('#assSpread').is(':visible')&&this.assSpread?this.assSpread.refresh():'';
     },
     showDatas:function () {
-        if($('#itemCharacterText').is(':visible'))MaterialController.showItemCharacterText()
+        if($('#itemCharacterText').is(':visible'))MaterialController.showItemCharacterText();
         if($('#coeSpread').is(':visible')) this.showCoeData();
         if($('#cusSpread').is(':visible')) this.showCusData();
         if($('#assSpread').is(':visible')) this.showAssData();

+ 3 - 3
web/users/js/login.js

@@ -312,18 +312,18 @@ function login(captchaObj) {
                 }
             } else if(response.error === 2) {
                 // $('#phonepass').modal('hide');
-                captchaObj.reset();
+                // captchaObj.reset();
                 $('#check_ssoId').val(response.ssoId);
                 $('#phone').modal('show');
             } else if(response.error === 3) {
-                captchaObj.reset();
+                // captchaObj.reset();
                 $('#phonepass').modal('show');
                 $('#mobileLogin').val(response.data);
             } else {
                 // $('#phonepass').modal('hide');
                 let msg = response.msg !== undefined ? response.msg : '未知错误';
                 showError(msg, $("input"));
-                captchaObj.reset();
+                // captchaObj.reset();
             }
         },
         error: function (result) {