Browse Source

Merge branch 'master' into 定额优化

zhangweicheng 5 năm trước cách đây
mục cha
commit
6ff6a721a6
44 tập tin đã thay đổi với 540 bổ sung697 xóa
  1. 2 1
      logs/log4js.json
  2. 10 0
      modules/bills_lib/controllers/bills_lib_controllers.js
  3. 3 0
      modules/bills_lib/controllers/bills_permissionController.js
  4. 9 0
      modules/bills_lib/models/bills_lib_interfaces.js
  5. 1 0
      modules/bills_lib/routes/bills_lib_routes.js
  6. 0 82
      modules/common/const/bills_fixed.js
  7. 1 1
      modules/main/controllers/bills_controller.js
  8. 3 0
      modules/main/controllers/installation_controller.js
  9. 2 1
      modules/main/controllers/project_controller.js
  10. 2 2
      modules/main/facade/project_facade.js
  11. 1 1
      modules/main/models/bills.js
  12. 2 2
      modules/main/models/project.js
  13. 20 8
      modules/pm/controllers/pm_controller.js
  14. 81 30
      modules/pm/facade/pm_facade.js
  15. 56 61
      modules/pm/models/project_model.js
  16. 5 3
      modules/ration_glj/facade/ration_glj_facade.js
  17. 5 1
      modules/reports/util/rpt_construct_data_util.js
  18. 2 2
      package.json
  19. 12 0
      pm2_import.json
  20. 9 0
      pm2_server.json
  21. 9 3
      public/common_constants.js
  22. 2 1
      public/web/gljUtil.js
  23. 28 25
      public/web/sheet/sheet_common.js
  24. 4 0
      web/building_saas/css/main.css
  25. 1 1
      web/building_saas/main/html/main.html
  26. 0 399
      web/building_saas/main/js/calc/bills_calc.js
  27. 1 0
      web/building_saas/main/js/models/calc_base.js
  28. 29 25
      web/building_saas/main/js/models/calc_program.js
  29. 26 1
      web/building_saas/main/js/models/installation_fee.js
  30. 24 3
      web/building_saas/main/js/models/overHeight.js
  31. 16 3
      web/building_saas/main/js/models/ration_glj.js
  32. 6 1
      web/building_saas/main/js/views/calc_program_manage.js
  33. 1 1
      web/building_saas/main/js/views/glj_col.js
  34. 2 2
      web/building_saas/main/js/views/glj_view.js
  35. 21 3
      web/building_saas/main/js/views/project_info.js
  36. 3 3
      web/building_saas/main/js/views/project_view.js
  37. 5 0
      web/building_saas/main/js/views/tender_price_view.js
  38. 1 0
      web/building_saas/pm/js/pm_newMain.js
  39. 25 0
      web/common/components/share/index.js
  40. 1 1
      web/common/html/header.html
  41. 1 1
      web/over_write/js/chongqing_2018.js
  42. 42 12
      web/over_write/js/guangdong_2018.js
  43. 56 15
      web/over_write/js/guangdong_2018_export.js
  44. 10 2
      web/over_write/js/guangdong_2018_import.js

+ 2 - 1
logs/log4js.json

@@ -1,4 +1,5 @@
-{
+{        
+  "disableClustering": true, 
   "customBaseDir" :"../logs/ConstructionCost/",
   "customDefaultAtt" :{
     "type": "dateFile",

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

@@ -245,6 +245,16 @@ module.exports = {
         billsLibDao.getStdBillsByCode(data, function (err, message, data) {
             callback(req, res, err, message, data)
         });
+    },
+    getBillsByQueries: async function (req, res) {
+        try {
+            const { queries, occupancy } = JSON.parse(req.body.data);
+            const data = await billsLibDao.getBillsByQueries(queries, occupancy);
+            callback(req, res, 0, 'success', data);
+        } catch (err) {
+            callback(req, res, 1, String(err), null);
+        }
+        
     }
 }
 

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

@@ -56,6 +56,9 @@ class billsPermContr extends baseController{
     getStdBillsByCode(req, res) {
         billsController.getStdBillsByCode(req, res);
     }
+    getBillsByQueries(req, res) {
+        billsController.getBillsByQueries(req, res);
+    }
 
 }
 

+ 9 - 0
modules/bills_lib/models/bills_lib_interfaces.js

@@ -3215,5 +3215,14 @@ billsLibDao.prototype.getStdBillsByCodet = function (data, callback) {
     });
 };
 
+billsLibDao.prototype.getBillsByQueries = async function (queries, occupancy) {
+    const task = queries.map(query => Bills.find(query, occupancy));
+    const results = await Promise.all(task);
+    const rst = results.reduce((acc, result) => {
+        acc.push(...result);
+        return acc;
+    }, []);
+    return rst;
+}
 
 module.exports = new billsLibDao();

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

@@ -66,6 +66,7 @@ module.exports =function (app) {
     billsRouter.post("/edUpdateItem", itemsContr.init, itemsContr.edUpdateItem);
 
     billsRouter.post('/getStdBillsByCode', billsContr.init, billsContr.getStdBillsByCode);
+    billsRouter.post('/getBillsByQueries', billsContr.init, billsContr.getBillsByQueries);
 
     app.use("/stdBillsEditor", billsRouter);
 

+ 0 - 82
modules/common/const/bills_fixed.js

@@ -1,82 +0,0 @@
-/**
- * Created by Zhong on 2017/12/18.
- */
-const fixedFlag = {
-    // 分部分项工程
-    SUB_ENGINERRING: 1,
-    // 措施项目
-    MEASURE: 2,
-    // 施工技术措施项目
-    CONSTRUCTION_TECH: 3,
-    // 安全文明施工按实计算费用
-    SAFETY_CONSTRUCTION_ACTUAL: 4,
-    // 施工组织措施专项费用
-    CONSTRUCTION_ORGANIZATION: 5,
-    // 安全文明施工专项费用
-    SAFETY_CONSTRUCTION: 6,
-    // 其他项目
-    OTHER: 7,
-    // 暂列金额
-    PROVISIONAL: 8,
-    // 暂估价
-    ESTIMATE: 9,
-    // 材料(工程设备)暂估价
-    MATERIAL_PROVISIONAL: 10,
-    // 专业工程暂估价
-    ENGINEERING_ESITIMATE: 11,
-    // 计日工
-    DAYWORK: 12,
-    // 总承包服务费
-    TURN_KEY_CONTRACT: 13,
-    // 索赔与现场签证
-    CLAIM_VISA: 14,
-    // 规费
-    CHARGE: 15,
-    // 社会保险费及住房公积金 Social insurance fee and housing accumulation fund
-    SOCIAL_INSURANCE_HOUSING_FUND: 16,
-    // 工程排污费 charges for disposing pollutants
-    POLLUTANTS: 17,
-    // 税金
-    TAX: 18,
-    //工程造价
-    ENGINEERINGCOST: 19,
-    //增值税
-    ADDED_VALUE_TAX: 20,
-    //专项技术措施暂估价
-    SPECIAL_TECH_PROVISIONAL: 21,
-    //专业发包工程管理费
-    LET_CONTRACT_MANAGEMENT: 22,
-    //人工
-    LABOUR: 23,
-    //材料
-    MATERIAL: 24,
-    //施工机械
-    MACHINE: 25,
-    //索赔
-    CLAIM: 26,
-    //现场签证
-    VISA: 27,
-    ADDITIONAL_TAX: 28,
-    //环境保护税
-    ENVIRONMENTAL_PROTECTION_TAX: 29,
-    //建设工程竣工档案编制费
-    PROJECT_COMPLETE_ARCH_FEE:30,
-    //住宅工程质量分户验收费
-    HOUSE_QUALITY_ACCEPT_FEE:31,
-    //组织措施费
-    ORGANIZATION:32,
-    //其他措施费
-    OTHER_MEASURE_FEE:33,
-    // 绿色施工安全防护措施费
-    GREEN_MEASURE_FEE: 34,
-    // 预算包干费
-    BUDGET_INCLUDE_WORK_FEE: 35,
-    // 工程优质费
-    PROJECT_HIGH_QUALITY_FEE: 36,
-    // 概算幅度差
-    BUDGET_ESTIMATE_DIFF: 37,
-    // 其他费用(与其他项目不同,参考广东的用法)
-    OTHER_FEE: 38
-};
-
-export default fixedFlag;

+ 1 - 1
modules/main/controllers/bills_controller.js

@@ -12,7 +12,7 @@ let raiton_facade = require("../facade/ration_facade");
 let stdBillsModel = mongoose.model('std_bills_lib_bills');
 let stdBillJobsModel = mongoose.model('std_bills_lib_jobContent');
 let stdBillCharacterModel = mongoose.model('std_bills_lib_itemCharacter');
-import fixedFlag from  '../../common/const/bills_fixed';
+const { fixedFlag } = require('../../../public/common_constants');
 let LZString = require('lz-string');
 const uuidV1 = require('uuid/v1');
 const billType ={

+ 3 - 0
modules/main/controllers/installation_controller.js

@@ -74,6 +74,9 @@ async function  resetToDefault(req, res) {
         let data = req.body.data;
         data = JSON.parse(data);
         let returnData= await installation_facade.resetToDefault(data.projectID,data.installFees);
+        if(data.rationInstallations && data.rationInstallations.length > 0){
+          await ration_installation_facade.updateFromInstallationFee(data.projectID,data.rationInstallations);
+        }
         result.data=returnData;
     }catch (err){
         logger.err(err);

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

@@ -42,13 +42,14 @@ module.exports = {
         // Project.getFilterData(data.project_id, ['bills', 'projectGLJ'], function (err, result) {
         //     console.log(result);
         // });
+        const isReport = false;
         Project.getData(data.project_id, function (err, message, result) {
             if (!err) {
                 callback(req, res, err, message, result);
             } else {
                 callback(req, res, err, message, null);
             }
-        });
+        }, isReport, req.session.sessionUser.id);
     },
     getDataForInterface: async function (req, res) {
         const data = JSON.parse(req.body.data);

+ 2 - 2
modules/main/facade/project_facade.js

@@ -41,7 +41,7 @@ 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 { fixedFlag } = require('../../../public/common_constants');
 const scMathUtil = require('../../../public/scMathUtil').getUtil();
 const billsLibDao = require("../../bills_lib/models/bills_lib_interfaces");
 
@@ -531,7 +531,7 @@ async function setDefaultInfo(rootProjectID,engineerInfos){
             if(attrs.indexOf(en.dispName) != -1){
                 let key = en.dispName;
                 if(key == "工程地点") key = "工程所在地";
-                en.value = baseMap[key].value;
+                en.value = baseMap[key] && baseMap[key].value || '';
             }
         }
     }

+ 1 - 1
modules/main/models/bills.js

@@ -14,7 +14,7 @@ let rationGljModel = mongoose.model('ration_glj');
 let rationCoeModel = mongoose.model('ration_coe');
 let rationInstModel = mongoose.model('ration_installation');
 let quantityDelModel = mongoose.model('quantity_detail');
-const fixedFlag = require('../../common/const/bills_fixed');
+const { fixedFlag } = require('../../../public/common_constants');
 
 let bills = mongoose.model("bills");
 let baseModel = require('./base_model');

+ 2 - 2
modules/main/models/project.js

@@ -102,7 +102,7 @@ Project.prototype.save = function(datas, callback){
     me.datas = [];
 };
 
-Project.prototype.getData = function(projectID, callback){
+Project.prototype.getData = function(projectID, callback, isReport, userID){
     var functions = [];
     var itemName;
     let firstTime = +new Date();
@@ -114,7 +114,7 @@ Project.prototype.getData = function(projectID, callback){
                     let endTime = +new Date();
                     console.log(moduleName+'---------------'+(endTime - startTime));
                     cb(err, {moduleName: moduleName, data: data})
-                })
+                }, isReport, userID)
             }
         })(itemName))
     }

+ 20 - 8
modules/pm/controllers/pm_controller.js

@@ -87,13 +87,17 @@ module.exports = {
     },
     updateProjects: async function (req, res) {
         let data = JSON.parse(req.body.data);
-        await ProjectsData.updateUserProjects(req.session.sessionUser.id, req.session.sessionCompilation._id, req.session.sessionCompilation.name, req.session.sessionCompilation.overWriteUrl, data.updateData, function (err, message, data) {
-            if (err === 0) {
-                callback(req, res, err, message, data);
-            } else {
-                callback(req, res, err, message, null);
-            }
-        });
+        try {
+            await ProjectsData.updateUserProjects(req.session.sessionUser.id, req.session.sessionCompilation._id, req.session.sessionCompilation.name, req.session.sessionCompilation.overWriteUrl, data.updateData, function (err, message, data) {
+                if (err === 0) {
+                    callback(req, res, err, message, data);
+                } else {
+                    callback(req, res, 1, message, null);
+                }
+            });
+        } catch (err) {
+            callback(req, res, 1, String(err), null);
+        }
     },
     // CSL, 2017-12-14 该方法用于项目属性:提交保存混合型数据,这些数据来自不同的表,包括projects.property、ration、bills、labour_coes.
     updateMixDatas: async function (req, res) {
@@ -207,7 +211,7 @@ module.exports = {
         });
     },
     //project getData接口
-    getData: function (projectID, callback) {
+    getData: function (projectID, callback, isReport, userID) {
         projectModel.findOne({ $or: [{ deleteInfo: null }, { 'deleteInfo.deleted': false }], ID: projectID }, '-_id').then(async function (project) {
             if (!project) {
                 callback('', consts.projectConst.PROJECT_INFO, {});
@@ -247,6 +251,14 @@ module.exports = {
             //获取单位工程完整目录结构
             let fullPath = await pm_facade.getFullPath(projectID);
             projInfo.fullPath = fullPath;
+            // 获取分享的tip
+            projInfo.shareTip = await pm_facade.getShareTip(projectID, 2);
+            // 获取分享状态
+            if (typeof userID === 'string') {
+                projInfo.shareState = await pm_facade.getShareState(projectID, userID);
+            }
+            // 获取项目所属用户
+            projInfo.owner = await userModel.findOne({_id: mongoose.Types.ObjectId(project.userID)}, 'real_name');
             callback('', consts.projectConst.PROJECT_INFO, project);
         }, function (err) {
             callback(err, consts.projectConst.PROJECT_INFO, {});

+ 81 - 30
modules/pm/facade/pm_facade.js

@@ -17,6 +17,8 @@ module.exports={
     getShareInfoMap,
     getRecentShareList,
     getProjectShareList,
+    getShareTip,
+    getShareState,
     moveProject:moveProject,
     accessToCopyProject,
     copyProject:copyProject,
@@ -105,7 +107,7 @@ import SectionTreeDao from '../../complementary_ration_lib/models/sectionTreeMod
 let sectionTreeDao = new SectionTreeDao();
 import CounterModel from "../../glj/models/counter_model";
 import moment from 'moment-timezone';
-import billsFlags from '../../common/const/bills_fixed';
+const { fixedFlag } = require('../../../public/common_constants');
 const notDeleted = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
 import {
     defaultDecimal,
@@ -268,26 +270,65 @@ async function getRecentShareList(userID, count) {
 }
 
 // 获取某项目的分享记录
-async function getProjectShareList(projectID) {
-    const sharedList = await shareListModel.find({ projectID }).lean();
+async function getProjectShareList(projectID, limit = null) {
+    const sharedList = limit 
+        ? await shareListModel.find({ projectID }).lean().sort({ shareDate: -1 }).limit(limit)
+        : await shareListModel.find({ projectID }).lean().sort({ shareDate: -1 });
     const userIDs = [];
     const userMap = {};
-    sharedList.forEach(item => {
+    sharedList.forEach((item, index) => {
         userIDs.push(item.receiver);
         userMap[item.receiver] = item;
+        userMap[item.receiver].index = index;
     });
     const userObjectIDs = userIDs.map(userID => mongoose.Types.ObjectId(userID));
     const users = await userModel.find({_id: {$in: userObjectIDs}}, 'real_name mobile company').lean();
     users.forEach(user => {
         const matched = userMap[user._id];
         if (matched) {
+            user.index = matched.index;
             user.allowCopy = matched.allowCopy;
             user.allowCooperate = matched.allowCooperate;
         }
     });
+    users.sort((a, b) => a.index - b.index);
     return users;
 }
 
+// 获取分享的提示(造价书分享按钮tooltip使用)
+async function getShareTip(projectID, limit) {
+    const task = [
+        getProjectShareList(projectID, limit),
+        shareListModel.count({ projectID })
+    ];
+    const [users, count] = await Promise.all(task);
+    return users.reduce((acc, user, index) => {
+        if (index === 0) {
+            acc += '已分享给';
+            acc += user.real_name;
+        } else {
+            acc += ` ${user.real_name}`;
+        }
+        if (index === users.length - 1 && count > limit) {
+            acc += `等${count}人`;
+        }
+        return acc;
+    }, '');
+}
+
+// 获取项目的分享状态
+// 分享项目的拷贝和编辑性,需要参考父项
+// 以项目链上最新更新的分享数据为准
+async function getShareState(projectID, receiver) {
+    const projectIDs = await getUpChainIDs(projectID);
+    const shareList = await shareListModel.find({ projectID: { $in: projectIDs }, receiver }).lean();
+    shareList.sort((a, b) => Date.parse(b.updateDate) - Date.parse(a.updateDate));
+    return {
+        allowCopy: shareList[0] && shareList[0].allowCopy || false,
+        allowCooperate: shareList[0] && shareList[0].allowCooperate || false
+    };
+}
+
 //拷贝例题项目
 //@param {String}userID {Array}projIDs拷贝的例题项目ID(建设项目、文件夹)@return {Boolean}
 async function copyExample(userID, compilation, projIDs){
@@ -1046,13 +1087,13 @@ async function getTendersFeeInfo(tenders) {
     let IDMapping = {};
     //固定清单类别与汇总金额字段映射
     let flagFieldMapping = {};
-    flagFieldMapping[billsFlags.ENGINEERINGCOST] = 'engineeringCost';
-    flagFieldMapping[billsFlags.SUB_ENGINERRING] = 'subEngineering';
-    flagFieldMapping[billsFlags.MEASURE] = 'measure';
-    flagFieldMapping[billsFlags.SAFETY_CONSTRUCTION] = 'safetyConstruction';
-    flagFieldMapping[billsFlags.OTHER] = 'other';
-    flagFieldMapping[billsFlags.CHARGE] = 'charge';
-    flagFieldMapping[billsFlags.TAX] = 'tax';
+    flagFieldMapping[fixedFlag.ENGINEERINGCOST] = 'engineeringCost';
+    flagFieldMapping[fixedFlag.SUB_ENGINERRING] = 'subEngineering';
+    flagFieldMapping[fixedFlag.MEASURE] = 'measure';
+    flagFieldMapping[fixedFlag.SAFETY_CONSTRUCTION] = 'safetyConstruction';
+    flagFieldMapping[fixedFlag.OTHER] = 'other';
+    flagFieldMapping[fixedFlag.CHARGE] = 'charge';
+    flagFieldMapping[fixedFlag.TAX] = 'tax';
     let tenderIDs = [];
     if(tenders.length > 0){
         for(let tender of tenders){
@@ -1061,8 +1102,8 @@ async function getTendersFeeInfo(tenders) {
             IDMapping[tender.ID]['buildingArea'] = '';
         }
         //需要获取的清单固定类别综合合价:工程造价、分部分项、措施项目、安全文明施工专项、规费、其他项目、税金
-        let needFlags = [billsFlags.ENGINEERINGCOST, billsFlags.SUB_ENGINERRING, billsFlags.MEASURE,
-            billsFlags.SAFETY_CONSTRUCTION, billsFlags.CHARGE, billsFlags.OTHER, billsFlags.TAX];
+        let needFlags = [fixedFlag.ENGINEERINGCOST, fixedFlag.SUB_ENGINERRING, fixedFlag.MEASURE,
+            fixedFlag.SAFETY_CONSTRUCTION, fixedFlag.CHARGE, fixedFlag.OTHER, fixedFlag.TAX];
         //获取单位工程汇总金额需要用到的所有清单
         let allBills = await billsModel.find({projectID: {$in: tenderIDs}, 'flags.flag': {$in: needFlags}, $or: notDeleted},
             '-_id projectID fees flags');
@@ -1072,7 +1113,7 @@ async function getTendersFeeInfo(tenders) {
             let costField = flagFieldMapping[billsFlag];
             IDMapping[bills.projectID][costField] = getTotalFee(bills, 'common');
             //暂估合价(工程造价暂估合价)
-            if (billsFlag === billsFlags.ENGINEERINGCOST){
+            if (billsFlag === fixedFlag.ENGINEERINGCOST){
                 IDMapping[bills.projectID]['estimate'] = getTotalFee(bills, 'estimate');
             }
         }
@@ -1088,28 +1129,28 @@ async function getTendersFeeInfo(tenders) {
 }
 
 const defaultSummaryField = {
-    [billsFlags.ENGINEERINGCOST]: {
+    [fixedFlag.ENGINEERINGCOST]: {
         items: [
             { name: 'engineeringCost', feeName: 'common' },
             { name: 'estimate', feeName: 'estimate' }
         ]
     },
-    [billsFlags.SUB_ENGINERRING]: {
+    [fixedFlag.SUB_ENGINERRING]: {
         items: [{ name: 'subEngineering', feeName: 'common' }]
     },
-    [billsFlags.MEASURE]: {
+    [fixedFlag.MEASURE]: {
         items: [{ name: 'measure', feeName: 'common' }]
     },
-    [billsFlags.SAFETY_CONSTRUCTION]: {
+    [fixedFlag.SAFETY_CONSTRUCTION]: {
         items: [{ name: 'safetyConstruction', feeName: 'common' }]
     },
-    [billsFlags.OTHER]: {
+    [fixedFlag.OTHER]: {
         items: [{ name: 'other', feeName: 'common' }]
     },
-    [billsFlags.CHARGE]: {
+    [fixedFlag.CHARGE]: {
         items: [{ name: 'charge', feeName: 'common' }]
     },
-    [billsFlags.TAX]: {
+    [fixedFlag.TAX]: {
         items: [{ name: 'tax', feeName: 'common' }]
     }
 };
@@ -1260,13 +1301,13 @@ async function getSummaryInfo(projectIDs, summaryField = defaultSummaryField){
     }
     if (!feeFields) {
         feeFields = [
-            {k: billsFlags.ENGINEERINGCOST, v: 'engineeringCost'},
-            {k: billsFlags.SUB_ENGINERRING, v: 'subEngineering'},
-            {k: billsFlags.MEASURE, v: 'measure'},
-            {k: billsFlags.SAFETY_CONSTRUCTION, v: 'safetyConstruction'},
-            {k: billsFlags.OTHER, v: 'other'},
-            {k: billsFlags.CHARGE, v: 'charge'},
-            {k: billsFlags.TAX, v: 'tax'}
+            {k: fixedFlag.ENGINEERINGCOST, v: 'engineeringCost'},
+            {k: fixedFlag.SUB_ENGINERRING, v: 'subEngineering'},
+            {k: fixedFlag.MEASURE, v: 'measure'},
+            {k: fixedFlag.SAFETY_CONSTRUCTION, v: 'safetyConstruction'},
+            {k: fixedFlag.OTHER, v: 'other'},
+            {k: fixedFlag.CHARGE, v: 'charge'},
+            {k: fixedFlag.TAX, v: 'tax'}
         ];
     }
     // 项目总造价的各个费用,k为汇总的字段,v为工程造价的费用字段
@@ -1336,7 +1377,7 @@ async function getSummaryInfo(projectIDs, summaryField = defaultSummaryField){
             let costField = flagFieldMapping[billsFlag];
             IDMapping[bills.projectID][costField] = getTotalFee(bills, 'common');
             // 工程造价各费用
-            if (billsFlag === billsFlags.ENGINEERINGCOST){
+            if (billsFlag === fixedFlag.ENGINEERINGCOST){
                 engineeringCostFields.forEach(({k, v}) => {
                     IDMapping[bills.projectID][k] = getTotalFee(bills, v);
                 });
@@ -2402,10 +2443,19 @@ async function importProjects(data,req,updateData) {
 
 
 async function handleEachProject(data,projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap){
-    let bills = [],rations = [],projectGLJs = [],rationGLJs=[],rationCoes=[],quantityDetails=[],rationInstallations=[],rationTemplates=[],evaluateList=[],bidList=[],contractorList=[];
+    let bills = [],rations = [],projectGLJs = [],installationFees=[],rationGLJs=[],rationCoes=[],quantityDetails=[],rationInstallations=[],rationTemplates=[],evaluateList=[],bidList=[],contractorList=[];
     let newProjectSetting =null,newCalcProgramsFile = null,newLabourCoe = null;
     let billsIDMap = {},projectGLJIDMap={},rationIDMap = {};
     let newProjectID = projectIDMap[data.projSetting.projectID];
+    //生成安装增加费设置
+    if(data.installationFees && data.installationFees.length > 0){
+        for(let ins of data.installationFees){
+          delete ins._id;
+          ins.ID = uuidV1();
+          ins.projectID = newProjectID;
+          installationFees.push(ins);
+        }
+    }
     //生成新的清单;
     if(data.bills && data.bills.length > 0){
         for(let b of data.bills){
@@ -2479,6 +2529,7 @@ async function handleEachProject(data,projectIDMap,labourCoeFileIDMap,calcProgra
     if(newProjectSetting) await projectSettingModel.create(newProjectSetting);
     if(bills.length > 0) await insertMany(bills,billsModel);
     if(rations.length > 0) await insertMany(rations,rationModel);
+    if(installationFees.length > 0) await insertMany(installationFees,installationFeeModel);
     if(projectGLJs.length > 0) await insertMany(projectGLJs,gljListModel);
     if(rationGLJs.length > 0) await insertMany(rationGLJs,rationGLJModel);
     if(rationCoes.length > 0) await insertMany(rationCoes,rationCoeModel);

+ 56 - 61
modules/pm/models/project_model.js

@@ -32,7 +32,7 @@ import {
     G_FILE_VER
 } from './project_property_template';
 import optionSetting from '../../options/models/optionTypes';
-import fixedFlag from '../../common/const/bills_fixed';
+const { fixedFlag } = require('../../../public/common_constants');
 let FeeRateFiles = mongoose.model('fee_rate_file');
 let counter = require("../../../public/counter/counter.js");
 
@@ -236,75 +236,70 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                 data.updateData['deleteInfo'] = deleteInfo;
                 //Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll);
                 //update
-                try {
-                    if (data.updateData.projType === projectType.project) {
-                        let engineerings = await Projects.find({userID: userId, ParentID: data.updateData.ID});
-                        let isExist = false;
-                        if (engineerings.length > 0) {
-                            for (let j = 0, jLen = engineerings.length; j < jLen; j++) {
-                                let e_tenders = await Projects.find({userID: userId, ParentID: engineerings[j].ID});
-                                if (e_tenders.length > 0) {
-                                    isExist = true;
-                                    break;
-                                }
+                if (data.updateData.projType === projectType.project) {
+                    let engineerings = await Projects.find({ userID: userId, ParentID: data.updateData.ID });
+                    let isExist = false;
+                    if (engineerings.length > 0) {
+                        for (let j = 0, jLen = engineerings.length; j < jLen; j++) {
+                            let e_tenders = await Projects.find({ userID: userId, ParentID: engineerings[j].ID });
+                            if (e_tenders.length > 0) {
+                                isExist = true;
+                                break;
                             }
                         }
-                        if (isExist) {//fake
-                            await UnitPriceFiles.update({
-                                user_id: userId,
-                                root_project_id: data.updateData.ID
-                            }, {$set: {deleteInfo: deleteInfo}}, {multi: true});
-                            await FeeRateFiles.update({
-                                userID: userId,
-                                rootProjectID: data.updateData.ID
-                            }, {$set: {deleteInfo: deleteInfo}}, {multi: true});
-                            await Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll);
-                        }
-                        else {//true
-                            await UnitPriceFiles.remove({user_id: userId, root_project_id: data.updateData.ID});
-                            await FeeRateFiles.remove({userID: userId, rootProjectID: data.updateData.ID});
-                            //await Projects.update({userID: userId, NextSiblingID: data.updateData.ID, deleteInfo: null}, {$set: {NextSiblingID: data.NextSiblingID}});
-                            await Projects.remove({userID: userId, ID: data.updateData.ID}, updateAll);
-                        }
                     }
-                    else if (data.updateData.projType === projectType.engineering) {
-                        let tenders = await Projects.find({userID: userId, ParentID: data.updateData.ID});
-                        if (tenders.length > 0) {//fake
-                            await Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll);
+                    if (isExist) {//fake
+                        await UnitPriceFiles.update({
+                            user_id: userId,
+                            root_project_id: data.updateData.ID
+                        }, { $set: { deleteInfo: deleteInfo } }, { multi: true });
+                        await FeeRateFiles.update({
+                            userID: userId,
+                            rootProjectID: data.updateData.ID
+                        }, { $set: { deleteInfo: deleteInfo } }, { multi: true });
+                        await Projects.update({ userID: userId, ID: data.updateData.ID }, data.updateData, updateAll);
+                    }
+                    else {//true
+                        await UnitPriceFiles.remove({ user_id: userId, root_project_id: data.updateData.ID });
+                        await FeeRateFiles.remove({ userID: userId, rootProjectID: data.updateData.ID });
+                        //await Projects.update({userID: userId, NextSiblingID: data.updateData.ID, deleteInfo: null}, {$set: {NextSiblingID: data.NextSiblingID}});
+                        await Projects.remove({ userID: userId, ID: data.updateData.ID }, updateAll);
+                    }
+                }
+                else if (data.updateData.projType === projectType.engineering) {
+                    let tenders = await Projects.find({ userID: userId, ParentID: data.updateData.ID });
+                    if (tenders.length > 0) {//fake
+                        await Projects.update({ userID: userId, ID: data.updateData.ID }, data.updateData, updateAll);
+                    }
+                    else {//true
+                        //await Projects.update({userID: userId, NextSiblingID: data.updateData.ID, deleteInfo: null}, {$set: {NextSiblingID: data.NextSiblingID}});
+                        await Projects.remove({ userID: userId, ID: data.updateData.ID }, updateAll);
+                    }
+                }
+                else if (data.updateData.projType === projectType.tender) {//fake
+                    let delTender = await Projects.findOne({ userID: userId, ID: data.updateData.ID });
+                    //如果这个单位工程用到的费率文件、单价文件,没有被其他的单位工程使用,则应该一起跟随删除
+                    if (delTender) {
+                        let unitPriceFile = delTender.property.unitPriceFile;
+                        let feeRateFile = delTender.property.feeFile;
+                        let usedUFTenders = await Projects.find(
+                            { userID: userId, $or: [{ deleteInfo: null }, { 'deleteInfo.deleted': false }], 'property.unitPriceFile.id': unitPriceFile.id });
+                        if (usedUFTenders.length === 1) {
+                            await UnitPriceFiles.update({ id: unitPriceFile.id }, { $set: { deleteInfo: deleteInfo } });
                         }
-                        else {//true
-                            //await Projects.update({userID: userId, NextSiblingID: data.updateData.ID, deleteInfo: null}, {$set: {NextSiblingID: data.NextSiblingID}});
-                            await Projects.remove({userID: userId, ID: data.updateData.ID}, updateAll);
+                        let usedFRTenders = await Projects.find(
+                            { userID: userId, $or: [{ deleteInfo: null }, { 'deleteInfo.deleted': false }], 'property.feeFile.id': feeRateFile.id });
+                        if (usedFRTenders.length === 1) {
+                            await FeeRateFiles.update({ ID: feeRateFile.id }, { $set: { deleteInfo: deleteInfo } });
                         }
+                        await Projects.update({ userID: userId, ID: data.updateData.ID }, data.updateData, updateAll);
                     }
-                    else if (data.updateData.projType === projectType.tender) {//fake
-                        let delTender = await Projects.findOne({userID: userId, ID: data.updateData.ID});
-                        //如果这个单位工程用到的费率文件、单价文件,没有被其他的单位工程使用,则应该一起跟随删除
-                        if(delTender){
-                            let unitPriceFile = delTender.property.unitPriceFile;
-                            let feeRateFile = delTender.property.feeFile;
-                            let usedUFTenders = await Projects.find(
-                                {userID: userId, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], 'property.unitPriceFile.id': unitPriceFile.id});
-                            if(usedUFTenders.length === 1){
-                                await UnitPriceFiles.update({id: unitPriceFile.id}, {$set: {deleteInfo: deleteInfo}});
-                            }
-                            let usedFRTenders = await Projects.find(
-                                {userID: userId, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], 'property.feeFile.id': feeRateFile.id});
-                            if(usedFRTenders.length === 1){
-                                await FeeRateFiles.update({ID: feeRateFile.id}, {$set: {deleteInfo: deleteInfo}});
-                            }
-                            await Projects.update({userID: userId, ID: data.updateData.ID}, data.updateData, updateAll);
-                        }
 
-                    }
-                    else if (data.updateData.projType === projectType.folder) {//true
-                        await Projects.remove({userID: userId, ID: data.updateData.ID}, updateAll);
-                    }
-                    else throw '未知文件类型,删除失败!';
                 }
-                catch (error) {
-                    callback(1, error, null);
+                else if (data.updateData.projType === projectType.folder) {//true
+                    await Projects.remove({ userID: userId, ID: data.updateData.ID }, updateAll);
                 }
+                else throw '未知文件类型,删除失败!';
             }
             else {
                 hasError = true;

+ 5 - 3
modules/ration_glj/facade/ration_glj_facade.js

@@ -920,7 +920,7 @@ function getData(projectID, callback, isReport) {
         let ration = rations.find(function getElement(element) {
             return element.ID == ID;
         });
-        return ration._doc;
+        return ration && ration._doc;
     };
 
     ration_glj.find({'projectID': projectID}, (err, datas) => {
@@ -940,12 +940,14 @@ function getData(projectID, callback, isReport) {
                                         if (ration.quantityCoe._doc.labour)
                                             coe = ration.quantityCoe._doc.labour;
                                     }
-                                    else if ([gljType.GENERAL_MATERIAL,
+                                    else if (
+                                        [gljType.GENERAL_MATERIAL,
                                         gljType.CONCRETE,
                                         gljType.MORTAR,
                                         gljType.MIX_RATIO,
                                         gljType.COMMERCIAL_CONCRETE,
-                                        gljType.COMMERCIAL_MORTAR].includes(glj.type)){
+                                        gljType.COMMERCIAL_MORTAR,
+                                        gljType.OTHER_MATERIAL].includes(glj.type)){
                                         if (ration.quantityCoe._doc.material)
                                             coe = ration.quantityCoe._doc.material;
                                     }

+ 5 - 1
modules/reports/util/rpt_construct_data_util.js

@@ -1430,7 +1430,11 @@ function ext_getCalcProperty(templateIDs, calcItemKey, calcItemKeyVal, calcItemR
         if (calcTplObj) {
             for (let calcItem of calcTplObj.calcItems) {
                 if (calcItem[calcItemKey] === calcItemKeyVal) {
-                    rst.push(calcItem[calcItemRstKey]);
+                    if (calcItem[calcItemRstKey] !== undefined && calcItem[calcItemRstKey] !== null) {
+                        rst.push(calcItem[calcItemRstKey]);
+                    } else {
+                        rst.push(calcItem['feeRate']); //业务特点,如果上述key没有值的话,直接取‘feeRate’的value,省的去改指标定义了
+                    }
                     break;
                 }
             }

+ 2 - 2
package.json

@@ -63,9 +63,9 @@
   },
   "scripts": {
     "start": "C:\\Users\\mai\\AppData\\Roaming\\npm\\babel-node.cmd server.js",
-    "server": "node --max-old-space-size=2048 server.js",
+    "server": "pm2-docker pm2_server.json",
     "socket": "node socket.js",
-    "import": "node --max-old-space-size=2048 importserver.js",
+    "import": "pm2-docker pm2_import.json",
     "dev_server": "SET NODE_ENV=qa&& babel-node server.js",
     "dev_socket": "SET NODE_ENV=qa&& babel-node socket.js",
     "dev_import": "SET NODE_ENV=qa&& babel-node importserver.js"

+ 12 - 0
pm2_import.json

@@ -0,0 +1,12 @@
+{
+  "apps": {
+      "name": "constructionimport",
+      "script": "importserver.js",
+      "output": "/home/logs/out.log",
+      "error": "/home/logs/err.log",
+      "log_date_format": "YYYY-MM-DD HH:mm Z",
+      "exec_mode": "cluster_mode",                
+      "instances": 3, 
+      "merge_logs": true
+    }
+}

+ 9 - 0
pm2_server.json

@@ -0,0 +1,9 @@
+{
+  "apps": {
+      "name": "constructionimport",
+      "script": "server.js",
+      "node_args":"--max-old-space-size=2048",
+      "exec_mode": "cluster_mode",                
+      "instances": 3
+    }
+}

+ 9 - 3
public/common_constants.js

@@ -1,6 +1,12 @@
 // 部分数据从main_consts.js中抽出来,因为除了造价书界面,有一些页面也需要用到其中的变量
 // 但是其他页面直接引入整个main_consts.js不合理,且会报错(main_consts.js正常运行依赖main.html的一些内容)
-const commonConstants = (() => {
+((factory) => {
+    if (typeof module !== 'undefined') {
+        module.exports = factory();
+    } else {
+        window.commonConstants = factory();
+    }
+})(() => {
     // 清单固定行
     const fixedFlag = {
         // 分部分项工程
@@ -142,5 +148,5 @@ const commonConstants = (() => {
         supplyType,
         supplyText,
         SourceType,
-    }
-})();
+    };
+});

+ 2 - 1
public/web/gljUtil.js

@@ -120,8 +120,9 @@ let gljUtil = {
         let typeString = ration_glj.type +"";
         let coeField = "";
         for(let key in coeMap){
-            if(typeString.indexOf(key)!= -1){
+            if(typeString.indexOf(key) == 0){
               coeField = coeMap[key];
+              break;
             }
         }
         let coe = 1;

+ 28 - 25
public/web/sheet/sheet_common.js

@@ -292,13 +292,14 @@ var sheetCommonObj = {
             if (setting.header[col].formatter) {
                 sheet.setFormatter(-1, col, setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
             }
-            if(setting.headRows != 2 &&  setting.header[col].cellType === "checkBox"||setting.header[col].cellType === "button"){//clear and reset   2019 - 11- 11 加入了多行列头的判断情况,排除多行列头时清空操作,先试运行看是否有问题
+            /* 直接在showrowdata时当val为null时返回一个text类型的单元格 
+              if(setting.headRows != 2 &&  setting.header[col].cellType === "checkBox"||setting.header[col].cellType === "button"){//clear and reset   2019 - 11- 11 加入了多行列头的判断情况,排除多行列头时清空操作,先试运行看是否有问题
                 var me = this, header = GC.Spread.Sheets.SheetArea.colHeader;
                 sheet.deleteColumns(col,1);
                 sheet.addColumns(col, 1);
                 sheet.setValue(0, col, setting.header[col].headerName, header);
                 sheet.setColumnWidth(col, setting.header[col].headerWidth?setting.header[col].headerWidth:100);
-            }
+            } */
             if(setting.header[col].visible!==null&&setting.header[col].visible!==undefined){
                 sheet.setColumnVisible(col,setting.header[col].visible);
             }
@@ -350,7 +351,7 @@ var sheetCommonObj = {
                     val =val+'';
                 }
             }
-            if(val!=null&&setting.header[col].cellType === "checkBox"){
+            if(setting.header[col].cellType === "checkBox"){
                 this.setCheckBoxCell(row,col,sheet,val)
             }
             if(setting.header[col].cellType === "comboBox"){
@@ -483,7 +484,7 @@ var sheetCommonObj = {
         }
     },
     setCheckBoxCell(row,col,sheet,val){
-        var c = this.getCheckBox();
+        var c = val==null?new GC.Spread.Sheets.CellTypes.Text():this.getCheckBox();
         sheet.setCellType(row, col,c,GC.Spread.Sheets.SheetArea.viewport);
         sheet.getCell(row, col).value(val);
         sheet.getCell(row, col).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
@@ -682,46 +683,48 @@ var sheetCommonObj = {
         //sheet.setCellType(row, col,this.getSelectButton(header.headerWidth),GC.Spread.Sheets.SheetArea.viewport);
     },
 
-    getCusButtonCellType:function (callback,readOnly=false,ostyle) {
+    getCusButtonCellType: function (callback, readOnly = false, ostyle) {
         var ns = GC.Spread.Sheets;
+
         function CusButtonCellType() {
         }
+
         CusButtonCellType.prototype = new ns.CellTypes.Text();
         CusButtonCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
-            if(!readOnly){
-                if(options.sheet.getActiveRowIndex()==options.row&&options.sheet.getActiveColumnIndex()==options.col){
-                    var image = document.getElementById('f_btn'),imageMagin = 3;
+            if (!readOnly) {
+                if (options.sheet.getActiveRowIndex() == options.row && options.sheet.getActiveColumnIndex() == options.col) {
+                    var image = document.getElementById('f_btn'), imageMagin = 3;
                     var imageHeight = 15;
                     var imageWidth = 25;
-                    var imageX = x + w - imageWidth- imageMagin, imageY = y + h / 2 - imageHeight / 2;
+                    var imageX = x + w - imageWidth - imageMagin, imageY = y + h / 2 - imageHeight / 2;
                     ctx.save();
-                    if(style.backColor){
+                    if (style.backColor) {
                         ctx.fillStyle = style.backColor;
-                        ctx.fillRect(x,y,w,h);
+                        ctx.fillRect(x, y, w, h);
                     }
-                    ctx.drawImage(image, imageX, imageY,imageWidth,imageHeight);
+                    ctx.drawImage(image, imageX, imageY, imageWidth, imageHeight);
                     ctx.beginPath();
-                    ctx.arc(imageX+imageWidth/2,imageY+imageHeight/2,1,0,360,false);
-                    ctx.arc(imageX+imageWidth/2-4,imageY+imageHeight/2,1,0,360,false);
-                    ctx.arc(imageX+imageWidth/2+4,imageY+imageHeight/2,1,0,360,false);
-                    ctx.fillStyle="black";//填充颜色,默认是黑色
+                    ctx.arc(imageX + imageWidth / 2, imageY + imageHeight / 2, 1, 0, 360, false);
+                    ctx.arc(imageX + imageWidth / 2 - 4, imageY + imageHeight / 2, 1, 0, 360, false);
+                    ctx.arc(imageX + imageWidth / 2 + 4, imageY + imageHeight / 2, 1, 0, 360, false);
+                    ctx.fillStyle = "black";//填充颜色,默认是黑色
                     ctx.fill();//画实心圆
                     ctx.closePath();
                     ctx.restore();
                     w = w - imageWidth - imageMagin;
                     //这里的左对齐的,当显示的字长度超过空白地方时,要改成右对齐
-                    if(style.hAlign == 0){
-                        if(value){
+                    if (style.hAlign == 0) {
+                        if (value) {
                             let textWidth = ctx.measureText(value).width;
                             let spaceWidth = w;
-                            if(spaceWidth<textWidth){
+                            if (spaceWidth < textWidth) {
                                 style.hAlign = 2;
                             }
                         }
                     }
                 }
             }
-            if(ostyle)  gljUtil.setProperty(style,ostyle);
+            if (ostyle) gljUtil.setProperty(style, ostyle);
             GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
         };
         CusButtonCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
@@ -737,12 +740,12 @@ var sheetCommonObj = {
         };
 
         CusButtonCellType.prototype.processMouseDown = function (hitinfo) {
-            if(hitinfo.sheet.getActiveRowIndex()==hitinfo.row&&hitinfo.sheet.getActiveColumnIndex()==hitinfo.col){
-                var offset=hitinfo.cellRect.x+hitinfo.cellRect.width-6;
+            if (hitinfo.sheet.getActiveRowIndex() == hitinfo.row && hitinfo.sheet.getActiveColumnIndex() == hitinfo.col) {
+                var offset = hitinfo.cellRect.x + hitinfo.cellRect.width - 6;
                 var imageWidth = 25;
-                if(hitinfo.x<offset&&hitinfo.x>offset-imageWidth){
-                    if(!readOnly){
-                        if(callback) callback(hitinfo)
+                if (hitinfo.x < offset && hitinfo.x > offset - imageWidth) {
+                    if (!readOnly) {
+                        if (callback) callback(hitinfo)
                     }
                 }
             }

+ 4 - 0
web/building_saas/css/main.css

@@ -56,6 +56,10 @@ font-size: .875rem;
 height: calc(1.5em + .5rem + 2px);
 font-size: .875rem;
 }
+.btn-xs{
+  padding:0rem .5rem;
+  font-size:.875rem;
+}
 /*自定义css*/
 .login-body,.login-html{
 height:100%;

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

@@ -945,7 +945,7 @@
                                                     子目单价取费(正算):清单综合合价=∑子目综合合价
                                                 </label>
                                             </div>
-                                            <div class="form-check">
+                                            <div class="form-check" style="display:none">
                                                 <label class="form-check-label">
                                                     <input class="form-check-input" name="calcFlag" id="billsPrice" value="3" type="radio">
                                                     清单单价取费

+ 0 - 399
web/building_saas/main/js/calc/bills_calc.js

@@ -1,399 +0,0 @@
-/**
- * Created by Mai on 2017/7/5.
- */
-
-// const rationContent = 0, rationPrice = 1, rationPriceConverse = 2, billsPrice = 3;
-
-// sumTotalFeeFlag: sum(child.totalFee), totalFeeFlag: bills.quantity × bills.unitFee
-// const sumTotalFeeFlag = 0, totalFeeFlag = 1;
-// rationContentUnitFeeFlag: sum(child.unitFee * child.quantity / bills.quantity)
-// averageQtyUnitFeeFlag: sum(child.totalFee/bills.quantity)
-// billsPriceUnitFeeFlag: 根据定额计算程序
-// converseUnitFeeFalg: bills.totalFee / bills.quantity
-// const rationContentUnitFeeFlag = 0, averageQtyUnitFeeFlag = 1, billsPriceUnitFeeFlag = 2, converseUnitFeeFlag = 3;
-
-/*let rationContentCalcFields = [
-    {'type': 'common', 'unitFeeFlag': rationContentUnitFeeFlag, 'totalFeeFlag': totalFeeFlag},
-    {'type': 'labour', 'unitFeeFlag': rationContentUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag},
-    {'type': 'material', 'unitFeeFlag': rationContentUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag},
-    {'type': 'machine', 'unitFeeFlag': rationContentUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag}
-];
-let rationPriceCalcFields = [
-    {'type': 'common', 'unitFeeFlag': averageQtyUnitFeeFlag, 'totalFeeFlag': totalFeeFlag},
-    {'type': 'labour', 'unitFeeFlag': averageQtyUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag},
-    {'type': 'material', 'unitFeeFlag': averageQtyUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag},
-    {'type': 'machine', 'unitFeeFlag': averageQtyUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag}
-];
-let rationPriceConverseCalcFields = [
-    {'type': 'common', 'unitFeeFlag': averageQtyUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag},
-    {'type': 'labour', 'unitFeeFlag': averageQtyUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag},
-    {'type': 'material', 'unitFeeFlag': averageQtyUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag},
-    {'type': 'machine', 'unitFeeFlag': averageQtyUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag}
-];
-let billsPriceCalcFields = [
-    {'type': 'common', 'unitFeeFlag': billsPriceUnitFeeFlag, 'totalFeeFlag': totalFeeFlag},
-    {'type': 'labour', 'unitFeeFlag': billsPriceUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag},
-    {'type': 'material', 'unitFeeFlag': billsPriceUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag},
-    {'type': 'machine', 'unitFeeFlag': billsPriceUnitFeeFlag, 'totalFeeFlag': sumTotalFeeFlag}
-];*/
-
-/*let nodeCalcObj = {
-    node: null,
-    digit: 2,
-    field: null,
-    getFee: calcFees.getFee,
-    sumTotalFee: function() {
-        let result = 0, child;
-        for (child of this.node.children) {
-            let value = this.getFee(child.data, this.field.totalFee);
-            if (Object.prototype.toString.apply(value) === "[object String]") {
-                value = parseFloat(value);
-            }
-            result += value;
-        }
-        return result;
-    },
-    averageQty: function() {
-        let result = 0, child, qty;
-        result = this.sumTotalFee(this.field);
-        qty = this.getFee(this.node.data, 'quantity');
-        if (Object.prototype.toString.apply(qty) === "[object String]") {
-            qty = parseFloat(qty);
-        }
-        if (qty !== 0) {
-            result = result / qty;
-        }
-        return result;
-    },
-    totalFee: function () {
-        return this.getFee(this.node.data, this.field.unitFee) * this.getFee(this.node.data, 'quantity');
-    },
-    rationContentUnitFee: function () {
-        let result = 0, child, qty = this.getFee(this.node.data, 'quantity');
-        if (Object.prototype.toString.apply(qty) === "[object String]") {
-            qty = parseFloat(qty);
-        }
-        if (qty === 0) {
-            qty = 1;
-        }
-        for (child of this.node.children) {
-            let childUnitFee = this.getFee(child.data, this.field.unitFee);
-            if (Object.prototype.toString.apply(childUnitFee) === "[object String]") {
-                childUnitFee = parseFloat(childUnitFee);
-            }
-            let childQuantity = this.getFee(child.data, 'quantity');
-            if (Object.prototype.toString.apply(childQuantity) === "[object String]") {
-                childQuantity = parseFloat(childQuantity);
-            }
-            result += (childUnitFee * childQuantity / qty).toDecimal(this.digit);
-        }
-        return result;
-    },
-    converseUnitFee: function (digit) {
-        let totalFee = this.sumTotalFee().toDecimal(digit);
-        let qty = this.getFee(this.node.data, 'quantity');
-        if (qty !== 0){
-            return totalFee / qty;
-        } else {
-            return 0;
-        }
-    }
-};*/
-
-/*let baseCalcField = [
-    {
-        ID: 1,
-        // 序号
-        serialNo: '一',
-        // 费用代号
-        code: "A",
-        // 名称
-        name: "定额直接费",
-        // 计算基数
-        dispExpr: "A1+A2+A3",
-        // 基数说明
-        statement: "人工费+材料费+机械费",
-        // 费率
-        feeRate: null,
-        // 费用类别
-        type: 'RationDirect',
-        // 备注
-        memo: ''
-    }, {
-        ID: 2,
-        // 序号
-        serialNo: '1',
-        // 费用代号
-        code: "A1",
-        // 名称
-        name: "人工费",
-        // 计算基数
-        dispExpr: "H_J",
-        // 基数说明
-        statement: "合计",
-        // 费率
-        feeRate: 0,
-        // 费用类别
-        type: 'labour',
-        // 备注
-        memo: ''
-    }, {
-        ID: 3,
-        // 序号
-        serialNo: '2',
-        // 费用代号
-        code: "A2",
-        // 名称
-        name: "材料费",
-        // 计算基数
-        dispExpr: "H_J",
-        // 基数说明
-        statement: "合计",
-        // 费率
-        feeRate: 100,
-        // 费用类别
-        type: 'material',
-        // 备注
-        memo: ''
-    }, {
-        ID: 4,
-        // 序号
-        serialNo: '3',
-        // 费用代号
-        code: "A3",
-        // 名称
-        name: "机械费",
-        // 计算基数
-        dispExpr: "H_J",
-        // 基数说明
-        statement: "合计",
-        // 费率
-        feeRate: 0,
-        // 费用类别
-        type: 'machine',
-        // 备注
-        memo: ''
-    }, {
-        ID: 5,
-        // 序号
-        serialNo: '二',
-        // 费用代号
-        code: "A4",
-        // 名称
-        name: "管理费",
-        // 计算基数
-        dispExpr: "A",
-        // 基数说明
-        statement: "定额直接费",
-        // 费率
-        feeRate: 0,
-        // 费用类别
-        type: 'management',
-        // 备注
-        memo: ''
-    }, {
-        ID: 6,
-        // 序号
-        serialNo: '三',
-        // 费用代号
-        code: "B",
-        // 名称
-        name: "利润",
-        // 计算基数
-        dispExpr: "A",
-        // 基数说明
-        statement: "定额直接费",
-        // 费率
-        feeRate: 0,
-        // 费用类别
-        type: 'profit',
-        // 备注
-        memo: ''
-    }, {
-        ID: 7,
-        // 序号
-        serialNo: '四',
-        // 费用代号
-        code: "C",
-        // 名称
-        name: "风险费用",
-        // 计算基数
-        dispExpr: "",
-        // 基数说明
-        statement: "",
-        // 费率
-        feeRate: null,
-        // 费用类别
-        type: 'risk',
-        // 备注
-        memo: ''
-    }, {
-        ID: 8,
-        // 序号
-        serialNo: '',
-        // 费用代号
-        code: "",
-        // 名称
-        name: "综合单价",
-        // 计算基数
-        dispExpr: "A+B",
-        // 基数说明
-        statement: "定额直接费+利润",
-        // 费率
-        feeRate: NaN,
-        // 费用类别
-        type: 'common',
-        // 备注
-        memo: ''
-    }
-];*/
-
-/*class BillsCalcHelper {
-    constructor (project, calcFlag) {
-        this.project = project;
-        this.InitFields(project.calcFields);
-    };
-    getBillsGLjs (node) {
-        let rations = this.project.Ration.getBillsSortRation(node.source.getID());
-        let gljs = this.project.ration_glj.getGatherGljArrByRations(rations);
-        for (let glj of gljs) {
-            glj.quantity = (glj.quantity / calcFees.getFee(node.data, 'quantity')).toDecimal(4);
-        }
-        return gljs;
-    };
-    calcRationLeaf (node, fields, isIncre) {
-        nodeCalcObj.node = node;
-        nodeCalcObj.digit = this.project.Decimal.common.unitFee;
-        calcFees.checkFields(node.data, fields);
-        let nodeCalc = nodeCalcObj, virData= null, decimal = this.project.Decimal;
-
-        // 清单单价:套用定额计算程序
-        // if (this.project.projSetting.billsCalcMode === billsPrice) {
-/!*        if (this.project.property.billsCalcMode === leafBillGetFeeType.billsPrice) {
-            rationCalcObj.calcGljs = this.getBillsGLjs(node);
-            console.log(rationCalcObj.calcGljs);
-            rationCalcObj.calcFields = rationCalcFields;
-            virData = rationCalcObj.calculate();
-        }*!/
-
-        for (let field of fields) {
-            nodeCalcObj.field = field;
-            switch (field.unitFeeFlag) {
-                case rationContentUnitFeeFlag:
-                    node.data.feesIndex[field.type].unitFee = nodeCalcObj.rationContentUnitFee().toDecimal(decimal.common.unitFee);
-                    break;
-                case averageQtyUnitFeeFlag:
-                    node.data.feesIndex[field.type].unitFee = nodeCalcObj.averageQty().toDecimal(decimal.common.unitFee);
-                    break;
-                case billsPriceUnitFeeFlag:
-                    node.data.feesIndex[field.type].unitFee = virData[field.type];
-                    break;
-                case converseUnitFeeFlag:
-                    node.data.feesIndex[field.type].unitFee = nodeCalcObj.converseUnitFee(decimal.common.totalFee).toDecimal(decimal.common.unitFee);
-                    break;
-                default:
-                    node.data.feesIndex[field.type].unitFee = 0;
-            }
-            let value = 0;
-            switch (field.totalFeeFlag) {
-                case sumTotalFeeFlag:
-                    value = nodeCalcObj.sumTotalFee().toDecimal(decimal.common.totalFee);
-                    break;
-                case totalFeeFlag:
-                    value = nodeCalcObj.totalFee().toDecimal(decimal.common.totalFee);
-                    break;
-                default:
-                    value = 0;
-            }
-            this.setTotalFee(node, field, value, isIncre);
-        }
-    };
-    calcVolumePriceLeaf (node, fields, isIncre) {
-        let total = 0;
-        for (let child of node.children) {
-            total += calcFees.getFee(child.data, 'feesIndex.common.totalFee');
-        }
-    };
-    calcParent (node, fields, isIncre) {
-        nodeCalcObj.node = node;
-        calcFees.checkFields(node.data, fields);
-        for (let field of fields) {
-            nodeCalcObj.field = field;
-            let value = nodeCalcObj.sumTotalFee().toDecimal(this.project.Decimal.common.totalFee);
-            this.setTotalFee(node, field, value, isIncre);
-        }
-    };
-    clearFeeFields(node, fields, isIncre) {
-        for (let field of fields) {
-            node.data.feesIndex[field.type].unitFee = 0;
-            this.setTotalFee(node, field, 0, isIncre);
-        }
-    }
-    calcNode(node, isIncre) {
-        if (node.source.children.length > 0) {
-            this.calcParent(node, this.project.calcFields, isIncre);
-        } else {
-            if (node.children.length > 0) {
-                if (node.firstChild().sourceType === this.project.Ration.getSourceType()) {
-                    this.calcRationLeaf(node, this.project.calcFields, isIncre);
-                } else {
-                    this.calcVolumePriceLeaf(node, this.project.calcFields, isIncre);
-                }
-            } else {
-                this.clearFeeFields(node, this.project.calcFields, isIncre);
-            }
-        }
-    };
-    calcNodes (nodes) {
-        for (let node of nodes) {
-            if (node.sourceType !== this.project.Bills.getSourceType()) {
-                return;
-            }
-            if (node.source.children.length > 0) {
-                this.calcNodes(node.children);
-            }
-            this.calcNode(node);
-        }
-    };
-    updateParent (parent, field, Incre) {
-        if (parent && parent.sourceType === this.project.Bills.getSourceType()) {
-            calcFees.checkFields(parent.data, [field]);
-            parent.data.feesIndex[field.type].totalFee = (parent.data.feesIndex[field.type].totalFee + Incre).toDecimal(this.project.Decimal.common.totalFee);
-            parent.data.feesIndex[field.type].unitFee = 0;   // AAAAA 临时补上,使存储 unitFee.toFixed(2) 时不出错
-            this.updateParent(parent.parent, field, Incre);
-        }
-    };
-    setTotalFee (node, field, value, isIncre) {
-        if (isIncre) {
-            let incre = value - node.data.feesIndex[field.type].totalFee;
-            node.data.feesIndex[field.type].totalFee = value;
-            node.data.feesIndex[field.type].unitFee = 0; // AAAAA 临时补上,使存储 unitFee.toFixed(2) 时不出错
-            this.updateParent(node.parent, field, incre);
-        } else {
-            node.data.feesIndex[field.type].totalFee = value;
-            node.data.feesIndex[field.type].unitFee = 0; // AAAAA 临时补上,使存储 unitFee.toFixed(2) 时不出错
-        }
-    };
-    converseCalc (node) {
-        if (node && node.sourceType === this.project.Bills.getSourceType()) {
-            this.calcNode(node);
-            this.converseCalc(node.parent);
-        }
-    };
-    calcAll () {
-        this.calcNodes(this.project.mainTree.roots);
-    };
-    InitFields (fields) {
-        for (let field of fields) {
-            if (field.unitFee) return;
-            field.unitFee = 'feesIndex.' + field.type + '.unitFee';
-            field.unitFeeSplit = field.unitFee.split('.');
-            field.totalFee = 'feesIndex.' + field.type + '.totalFee';
-            field.totalFeeSplit = field.totalFee.split('.');
-            field.tenderUnitFee = 'feesIndex.'+ field.type + '.tenderUnitFee';
-            field.tenderUnitFeeSplit = field.tenderUnitFee.split('.');
-            field.tenderTotalFee = 'feesIndex.' + field.type + '.tenderTotalFee';
-            field.tenderTotalFeeSplit = field.tenderTotalFee.split('.');
-        }
-    };
-}*/

+ 1 - 0
web/building_saas/main/js/models/calc_base.js

@@ -771,6 +771,7 @@ let baseFigureTemplate = {
         return rst;
     },
     'JGZCF': function (tender) {//甲供主材费
+        debugger;
         let rst = 0;
         let projGljs = calcBase.project.projectGLJ.datas.gljList;
         for(let glj of projGljs){

+ 29 - 25
web/building_saas/main/js/models/calc_program.js

@@ -204,20 +204,23 @@ let calcTools = {
         };
         return nodes;
     },
+
+    /* 重要说明:
+    此时得到的GLJList,每条glj都有tenderQuantity = glj的quantity * 定额的quantity * glj的消耗量调整系数coe。
+    与定额的tenderQuantity无关,与定额的子目工程量调整系数coe无关。例如:
+    例:定额AB0003,工程量5,下含工料机“建筑综合工”,消耗量0.202。调价:人材机单价系数4,人工系数3,子目工程量系数2。
+    则GLJList中的建筑综合工:quantity 1.01, tenderQuantity 3.03。marketPrice 115, tenderPrice 460。
+    */
     getGLJList: function (treeNode, needOneBill) {
         delete treeNode.data.gljList;
+
         if (this.isRationCategory(treeNode)) {
             if (!calcTools.isVP_or_GLJR(treeNode)){
                 treeNode.data.gljList = projectObj.project.calcProgram.getGljArrByRation(treeNode.data);
             }
         }
         else if (this.isBill(treeNode)){
-            let nodeQ = this.uiNodeQty(treeNode);
-            let q = nodeQ ? nodeQ : 1;
-            let allNodes = projectObj.project.Ration.getRationNodes(treeNode);
-            let rNodes = allNodes.filter(function (node) {return calcTools.isRationItem(node)});
-            let rations = rNodes.map(function (node) {return node.data});
-            treeNode.data.gljList = projectObj.project.ration_glj.getGatherGljArrByRations(rations, needOneBill, q);
+            treeNode.data.gljList = projectObj.project.ration_glj.getGljArrByBill(treeNode, needOneBill);
         };
     },
     getLeafBills: function (treeNode){
@@ -894,7 +897,7 @@ let calcTools = {
     },
 
     // 在项目工料机里检查该工料机是否参与调价
-    isTenderGLJ: function (glj){
+    isTenderProjectGLJ: function (glj){
         let projGLJ = this.getProjectGLJ(glj);
         return !(projGLJ && projGLJ.is_adjust_price == 1);
     },
@@ -918,6 +921,7 @@ let calcTools = {
     tenderCoe_GLJQty: function (treeNode, glj){
         let coe = 1;
         if (!treeNode.data.quantityCoe) return coe;
+        if (!calcTools.isTenderProjectGLJ(glj)) return coe;
 
         if (gljType.LABOUR == glj.type){
             if (treeNode.data.quantityCoe.labour)
@@ -980,7 +984,7 @@ let calcTools = {
         }
         else{
             let coe = 1;
-            if (this.isTenderGLJ(glj))
+            if (this.isTenderProjectGLJ(glj))
                 coe = this.tenderCoe_GLJQty(treeNode, glj);
             glj.tenderQuantity = (glj.quantity * coe).toDecimal(decimalObj.glj.quantity);
         }
@@ -1629,7 +1633,7 @@ class CalcProgram {
         me.compiledFeeTypeMaps = {};
         me.compiledFeeTypeNames = [];
         me.compiledCalcBases = {};
-        me.saveForReports = [];
+        // me.saveForReports = [];
 
         me.feeRates = this.project.FeeRate.datas.rates;
         me.labourCoes = this.project.labourCoe.datas.coes;
@@ -1647,16 +1651,16 @@ class CalcProgram {
 
 
         // 存储费率临时数据,报表用。
-        if (isInit && me.saveForReports.length > 0){
-            let saveDatas = {};
-            saveDatas.projectID = projectObj.project.projectInfo.ID;
-            saveDatas.calcItems = me.saveForReports;
-            CommonAjax.post('/calcProgram/saveCalcItems', saveDatas, function (result) {
-                if (result){
-                    me.saveForReports = [];
-                };
-            });
-        };
+        // if (isInit && me.saveForReports.length > 0){
+        //     let saveDatas = {};
+        //     saveDatas.projectID = projectObj.project.projectInfo.ID;
+        //     saveDatas.calcItems = me.saveForReports;
+        //     CommonAjax.post('/calcProgram/saveCalcItems', saveDatas, function (result) {
+        //         if (result){
+        //             me.saveForReports = [];
+        //         };
+        //     });
+        // };
     };
 
     compilePublics(){
@@ -1756,9 +1760,9 @@ class CalcProgram {
                     let cfr = me.compiledFeeRates[item.feeRateID];
                     item.feeRate = cfr ? cfr.rate : 100;
 
-                    if (!orgFeeRate || (orgFeeRate && orgFeeRate != item.feeRate)){
-                        me.saveForReports.push({templatesID: template.ID, calcItem: item});
-                    }
+                    // if (!orgFeeRate || (orgFeeRate && orgFeeRate != item.feeRate)){
+                    //     me.saveForReports.push({templatesID: template.ID, calcItem: item});
+                    // }
                 };
 
                 // 字段名映射
@@ -1836,7 +1840,7 @@ class CalcProgram {
             };
         };
 
-        // 父清单汇总子项(子清单或定额)的费用类别
+        // 叶子清单汇总定额、父清单汇总子清单的费用类别
         if (treeNode.calcType == treeNodeCalcType.ctGatherBillsFees || treeNode.calcType == treeNodeCalcType.ctGatherRationsFees){
             treeNode.data.programID = null;
             calcTools.initFees(treeNode);
@@ -2456,7 +2460,7 @@ class CalcProgram {
                 // 先把会破坏金额比例关系的孩子排除:1.有目标金额的 2.满载的(孙子全满,没有分摊空间,所以实质上该孩子的金额已被锁死无法分摊)
                 for (let i = 0; i < treeNode.children.length; i++) {
                     let child = treeNode.children[i];
-                    if (!child.data.feesIndex['common']) continue;     // 无计算金额的(如空清单)当它不存在
+                    if (!child.data.feesIndex || !child.data.feesIndex['common']) continue;   // 空白行清单、定额
 
                     child.data.tender_activeTotal = child.data.feesIndex['common'].totalFee;
 
@@ -2474,7 +2478,7 @@ class CalcProgram {
 
                     for (let i = 0; i < treeNode.children.length; i++) {
                         let child = treeNode.children[i];
-                        if (!child.data.feesIndex['common']) continue;
+                        if (!child.data.feesIndex || !child.data.feesIndex['common']) continue;   // 空白行清单、定额
                         if (!calcTools.hasTargetTotalFee(child)){
                             child.data.tender_activeTarget = (coe * child.data.tender_activeTotal).toDecimal(decimalObj.decimal('totalPrice', treeNode));
                             child.data.targetTotalFee = child.data.tender_activeTarget;

+ 26 - 1
web/building_saas/main/js/models/installation_fee.js

@@ -742,6 +742,17 @@ var installation_fee = {
             });
         };
 
+        installation_fee.prototype.setRationInstallToDefual = function(){
+           let ration_install=projectObj.project.ration_installation;
+           let rationInstallations = [];
+           for(let ri of ration_install.datas){
+              if(ri.unifiedSetting == 0 || ri.ruleId!==""){
+                rationInstallations.push({ID:ri.ID,doc:{'ruleId':"",unifiedSetting:1}});
+              }
+           } 
+           return rationInstallations;
+        }
+
         installation_fee.prototype.resetToDefault = function (callback) {
             let me = this;
             let installFees = [];
@@ -753,10 +764,24 @@ var installation_fee = {
                 installFees.push(ins);
             }
             //data.projectID,data.installFees
+            let rationInstallations = me.setRationInstallToDefual();
+
+
             $.bootstrapLoading.start();
-            CommonAjax.post("/installation/resetToDefault",{projectID:project.ID(),installFees:installFees},function (result) {
+            CommonAjax.post("/installation/resetToDefault",{projectID:project.ID(),installFees:installFees,rationInstallations:rationInstallations},function (result) {
                 console.log(result)
                 me.datas = result;
+                 //更新定额安装费的缓存
+                 if(rationInstallations.length > 0){
+                  for(let ri of rationInstallations){
+                      let c_ri = project.ration_installation.getByID(ri.ID);
+                      if(c_ri){
+                          for(let rkey in ri.doc){
+                              c_ri[rkey] = ri.doc[rkey];
+                          }
+                      }
+                  }
+                }
                 if(callback){
                     callback();
                 }

+ 24 - 3
web/building_saas/main/js/models/overHeight.js

@@ -217,9 +217,12 @@ const OVER_HEIGHT = (() => {
     }
 
     // 超高降效列的控制,右键计取触发
-    function switchVisible() {
+    function switchVisible(visible) {
         const curVisible = colSettingObj.getVisible('overHeight');
-        colSettingObj.setVisible('overHeight', !curVisible);
+        if (curVisible === visible) {
+            return;
+        }
+        colSettingObj.setVisible('overHeight', visible);
         colSettingObj.updateColSetting(true);
     }
 
@@ -812,6 +815,7 @@ const OVER_HEIGHT = (() => {
         // 取消计取费用,只删除超高子目
         if (isCancelCalc) {
             postData.deleteData = getDeleteData();
+            postData.updateData = getUpdateData();
             return postData;
         }
         // 没有新的选项行为,获取当前项目的选项行为
@@ -1016,8 +1020,25 @@ const OVER_HEIGHT = (() => {
         TREE_SHEET_HELPER.massOperationSheet(sheet, func);
     }
 
+    // 请空所有清单和定额的超高文本
+    function clearOverHeightText() {
+        const sheet = projectObj.mainController.sheet;
+        const func = () => {
+            const nodes = projectObj.project.mainTree.items;
+            const overHeightCol = getOverHeightCol();
+            nodes.forEach((node, index) => {
+                if (node.data.overHeight) {
+                    sheet.setText(index, overHeightCol, '');
+                }
+            });
+        };
+        TREE_SHEET_HELPER.massOperationSheet(sheet, func);
+    }
+
     // 取消超高降效,删除所有超高子目
     function cancelCalc() {
+        switchVisible(false);
+        clearOverHeightText();
         handleConfirmed(true);
     }
 
@@ -1094,7 +1115,7 @@ const OVER_HEIGHT = (() => {
             return;
         }
         // 存在不同,重算
-       await handleConfirmed();
+        await handleConfirmed();
     }
 
     // 事件监听

+ 16 - 3
web/building_saas/main/js/models/ration_glj.js

@@ -45,7 +45,7 @@ let ration_glj = {
         };
 
 
-        ration_glj.prototype.getGatherGljArrByRations = function (rations, needOneBill, billQuantity) {
+        ration_glj.prototype.getGljArrByBill = function (treeNode, needOneBill) {
             let result = [];
             let clone = function (obj) {
                 if (obj === null) return null;
@@ -63,6 +63,13 @@ let ration_glj = {
                 }
                 return null;
             }
+
+            let nodeQ = calcTools.uiNodeQty(treeNode);
+            let q = nodeQ ? nodeQ : 1;
+            let allNodes = projectObj.project.Ration.getRationNodes(treeNode);
+            let rNodes = allNodes.filter(function (node) {return calcTools.isRationItem(node)});
+            let rations = rNodes.map(function (node) {return node.data});
+
             for (let ration of rations) {
                 if (ration.type == rationType.volumePrice || ration.type == rationType.gljRation){
                     let glj = JSON.parse(JSON.stringify(ration));
@@ -77,12 +84,18 @@ let ration_glj = {
                     let rationGljs = projectObj.project.calcProgram.getGljArrByRation(ration);
                     for (let glj of rationGljs) {
                         let sameGlj = findGlj(glj, result);
+                        let coe = calcTools.tenderCoe_GLJQty(treeNode, glj);
                         if (!sameGlj) {
                             sameGlj = clone(glj);
                             sameGlj.quantity = (sameGlj.quantity * ration.quantity).toDecimal(4);
+                            // glj的 tenderQuantity = glj的quantity * 定额的quantity * glj的消耗量调整系数coe。
+                            // 与定额的tenderQuantity无关,与定额的子目工程量调整系数coe无关。下面这里直接取数量即可,因为它在上一句已经乘过定额数量了。
+                            sameGlj.tenderQuantity = (sameGlj.quantity * coe).toDecimal(4);
                             result.push(sameGlj);
                         } else {
                             sameGlj.quantity = sameGlj.quantity + (glj.quantity * ration.quantity).toDecimal(4);
+                            sameGlj.tenderQuantity = sameGlj.tenderQuantity + (glj.quantity * coe).toDecimal(4);
+
                             sameGlj.totalQuantity = (parseFloat(sameGlj.totalQuantity) + parseFloat(glj.totalQuantity)).toDecimal(4);
                         }
                     }
@@ -107,8 +120,8 @@ let ration_glj = {
                     glj.type = glj.subType;
                 };
 
-                // glj.quantity = (glj.quantity / billQuantity).toDecimal(decimalObj.glj.quantity);
-                glj.quantity = (glj.quantity / billQuantity).toDecimal(decimalObj.process);  // 广联达这里没有取舍
+                glj.quantity = (glj.quantity / q).toDecimal(decimalObj.process);  // 广联达这里没有取舍
+                glj.tenderQuantity = (glj.tenderQuantity / q).toDecimal(decimalObj.process);
             };
             return oneBill;
         }

+ 6 - 1
web/building_saas/main/js/views/calc_program_manage.js

@@ -79,6 +79,7 @@ let calcProgramManage = {
         me.detailSheet.bind(GC.Spread.Sheets.Events.EnterCell, me.onDetailEnterCell);
         me.detailSheet.bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
         sheetCommonObj.showData(me.mainSheet, me.mainSetting, me.datas);
+        me.mainSheet.setRowCount(me.datas.length);
 
         me.detailSheet.name('calc_detail');
         feeRateObject.setFeeRateCellCol(me.detailSheet, _.findIndex(me.detailSetting.header,{'dataCode':'feeRate'}));
@@ -232,6 +233,8 @@ let calcProgramManage = {
         }
     },
     onDetailEnterCell: function (sender, args) {
+        // if (args.col == 2)    // 加这句,切换单元格后,原单元格的三点图片不会消失。
+            calcProgramManage.detailSheet.repaint();   // 这句是为了触发sheetCommonObj → getCusButtonCellType → CusButtonCellType → paint方法。
         // for test.
         // let t = calcProgramManage.getSelectionInfo().template;
         // let c = calcProgramManage.getSelectionInfo().calcItem;
@@ -550,7 +553,9 @@ $(document).ready(function(){
             calcProgramManage.buildSheet()
         else
             calcProgramManage.mainSpread.refresh();
-        calcProgramManage.detailSheet.setRowCount(calcProgramManage.datas[0].calcItems.length, GC.Spread.Sheets.SheetArea.viewport);
+
+        let count = calcProgramManage.datas[calcProgramManage.mainSheet.getActiveRowIndex()].calcItems.length;
+        calcProgramManage.detailSheet.setRowCount(count, GC.Spread.Sheets.SheetArea.viewport);
     });
 
     $("#calcProgramFileSelect").change(function() {

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

@@ -62,7 +62,7 @@ let gljCol = {
             {headerName: "质量等级", headerWidth: 80, dataCode: "qualityGrace", hAlign: "left", dataType: "String",spanRows: [2]},
             {headerName: "品牌", headerWidth: 80, dataCode: "brand", hAlign: "left", dataType: "String",spanRows: [2]},
             {headerName: "备注", headerWidth: 100, dataCode: "remark", hAlign: "left", dataType: "String",spanRows: [2]},
-            {headerName: "不调价", headerWidth: 55, dataCode: "is_adjust_price", dataType: "String",cellType: "checkBox",spanRows: [2]},
+            {headerName: "不调价", headerWidth: 55, dataCode: "is_adjust_price", dataType: "String",cellType: "checkBox",spanRows: [2], visible: false},
             {headerName: ["调价后","市场价"], headerWidth: 75, dataCode: "tenderPrice", hAlign: "right", dataType: "Number",validator:"number",spanCols: [2,1], visible: false},
             {headerName: ["","总消耗量"], headerWidth: 90, dataCode: "tenderQuantity", hAlign: "right", dataType: "Number",decimalField:'glj.quantity',spanCols: [0,1], visible: false}
         ],

+ 2 - 2
web/building_saas/main/js/views/glj_view.js

@@ -791,9 +791,9 @@ var gljOprObj = {
         let calcOptions=projectObj.project.projectInfo.property.calcOptions;
         let decimalObj = projectObj.project.projectInfo.property.decimal;
         let labourCoeDatas =  projectObj.project.labourCoe.datas;
-        let tenderCoe = projectObj.project.projectGLJ.getTenderPriceCoe(glj);
         glj = glj?glj:_.find(proGLJ.datas.gljList, {'id': data.projectGLJID});
         if(glj){
+            let tenderCoe = projectObj.project.projectGLJ.getTenderPriceCoe(glj);
             let result = gljUtil.getGLJPrice(glj,proGLJ.datas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil,tenderCoe);
             data.marketPrice = result.marketPrice;
             data.tenderPrice = result.tenderPrice;
@@ -1017,7 +1017,7 @@ var gljOprObj = {
       let [marketPrice,basePrice] = this.getParentPrice(subList,0,ratio,"delete");
       try {
         $.bootstrapLoading.start()
-        projectData = await ajaxPost('/glj/updateRatio', {id: ratio.mixRatioId,type:'delete',pid:ratio.parentGLJ.id,market_price: marketPrice,base_price: basePrice});
+        projectData = await ajaxPost('/glj/updateRatio', {id: ratio.mixRatioId,type:'delete',pid:ratio.parentGLJ.unit_price.id,market_price: marketPrice,base_price: basePrice});
 
         //更新缓存
         let pk = gljUtil.getIndex(ratio.parentGLJ);

+ 21 - 3
web/building_saas/main/js/views/project_info.js

@@ -3,6 +3,21 @@
  */
 
 var projectInfoObj = {
+    getSubShareInfo: function (proj) {
+        const { allowCopy, allowCooperate } = proj.shareState;
+        let str = '(';
+        if (allowCopy) {
+            str += '可拷贝 ';
+        }
+        if (allowCooperate) {
+            if (allowCopy) {
+                str += ' ';
+            }
+            str += '可编辑';
+        }
+        str += ')';
+        return str === '()' ? '' : str;
+    },
     getFullPathHtml: function (proj) {
         let fullPath = [], i, pm = '<span class="text-truncate"><a href="/pm">项目管理</a></span>', angleRight = '<span class="text-truncate"><i class="fa fa-angle-right fa-fw"></i></span>';
         if (proj) {
@@ -10,6 +25,8 @@ var projectInfoObj = {
             let engName = pathArr[pathArr.length - 2] || '',
                 projectName = pathArr[pathArr.length - 3] || '',
                 folderName = pathArr[pathArr.length - 4] || '';
+            const subShareInfo = projectInfoObj.getSubShareInfo(proj);
+            const receiveTip = `<span class="alert alert-success py-0 px-2 m-0" id="share-info"><i class="fa fa-share-alt"></i>来自 ${proj.owner && proj.owner.real_name || ''} 的分享${subShareInfo}</span>`;
             let newHtml = `   <span data-toggle="tooltip" data-placement="bottom" data-original-title="${folderName}"><i class="fa fa-folder-open-o"></i>...</span>
                 <span class="text-muted px-1">\</span>
                 <span data-toggle="tooltip" data-placement="bottom" data-original-title="${projectName}"><i class="fa fa-cubes"></i>...</span>
@@ -18,15 +35,16 @@ var projectInfoObj = {
                 <span class="text-muted px-1">\</span>
                  <span><i class="fa fa-sticky-note-o"></i></span>
                 <span class="text-truncate"  data-toggle="tooltip" data-placement="bottom" data-original-title="${proj.name}">&nbsp;${proj.name}</span>
-                ${projectReadOnly ?
+                ${projectReadOnly || projectCooperate ? receiveTip : `<span id="share-tip" class="ml-2" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="${proj.shareTip}"><a id="init-share" href="javascript:;" class="btn btn-xs btn-primary"><i class="fa fa-share-alt"></i> 分享</a></span>`}
+                `;
+            /* ${projectReadOnly ?
                     '<span data-toggle="tooltip" data-placement="bottom" data-original-title="当前的工程状态为“只读”,如果要进行编辑,请在项目管理-分享界面,使用“拷贝工程”功能。">(只读)</span>'
                     : ''}
                 ${projectCooperate ?
                     '<span data-toggle="tooltip" data-placement="bottom" data-original-title="当前的工程状态为“协作”,可直接编辑分享人的原始数据。">(协作)</span>'
                     : ''}
                 
-                ${projectReadOnly || projectCooperate ? '' : '<span><a id="init-share" class="pl-2" href="javascript:;"><i class="fa fa-share-alt" aria-hidden="true"></i> 分享</a></span>'}
-                `;
+                ${projectReadOnly || projectCooperate ? '' : `<span id="share-tip" class="ml-2" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="${proj.shareTip}"><a id="init-share" href="javascript:;" class="btn btn-xs btn-primary"><i class="fa fa-share-alt"></i> 分享</a></span>`} */
             fullPath.push(newHtml);
             fullPath.push(`<input id="rootProjectName" value="${projectName}" type="hidden">`);
 

+ 3 - 3
web/building_saas/main/js/views/project_view.js

@@ -1466,7 +1466,7 @@ var projectObj = {
                                 return projectReadOnly;
                             },
                             callback: function (key, opt) {
-                                OVER_HEIGHT.switchVisible();
+                                OVER_HEIGHT.switchVisible(true);
                             }
                         },
                         'setOption': {
@@ -2482,8 +2482,8 @@ $('#poj-set').on('show.bs.modal', function () {
     }
     if (projectObj.project) {
         //江西重定义了leafBillGetFeeType的内容
-        let ft = projectObj.project.property.billsCalcMode !== undefined &&
-                 projectObj.project.property.billsCalcMode !== null ? projectObj.project.property.billsCalcMode : leafBillGetFeeType.rationContent;
+        let ft = (projectObj.project.property.billsCalcMode !== undefined && projectObj.project.property.billsCalcMode !== null) ?
+            projectObj.project.property.billsCalcMode : leafBillGetFeeType.rationContent;   // 广东默认取1不是0,但这里不动,防止这种情况:旧项目默认无值,按取0算的,你改成1了,计算结果会变。
         let zg = projectObj.project.property.zanguCalcMode !== undefined &&
                  projectObj.project.property.zanguCalcMode !== null ? projectObj.project.property.zanguCalcMode : zanguCalcType.common;
         setCalcFlag($('#rationContent'), leafBillGetFeeType.rationContent, ft);

+ 5 - 0
web/building_saas/main/js/views/tender_price_view.js

@@ -500,6 +500,11 @@ $(function () {
             }
             tender_obj.showTenderData();
             projectObj.project.projectGLJ.calcQuantity();
+            // 刷新造价书界面的相关显示。刷新放在这里是为了切换UI时体验更流畅。
+            if($('#linkJSCX').hasClass('active'))
+                calcProgramObj.refreshCalcProgram(projectObj.project.mainTree.selected, 2)
+            if($('#linkGLJ').hasClass('active'))
+                gljOprObj.refreshView();
         };
         projectObj.project.calcProgram.doTenderCalc(callback);
     });

+ 1 - 0
web/building_saas/pm/js/pm_newMain.js

@@ -940,6 +940,7 @@ const projTreeObj = {
             return lineNum * defaultHeight;
         };
         TreeNodeCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
+            if(style.backColor == undefined) style.backColor = "white"  
             if (style.backColor) {
                 ctx.save();
                 ctx.fillStyle = style.backColor;

+ 25 - 0
web/common/components/share/index.js

@@ -261,6 +261,7 @@ const SHARE_TO = (() => {
                     initContactsView(rst.contacts)
                 }
                 initSharedView(curSharedUsers);
+                refreshShareTip(curSharedUsers);
                 refreshTreeView();
             }
         } catch (err) {
@@ -285,6 +286,30 @@ const SHARE_TO = (() => {
         }
     }
 
+    // 刷新造价书的分享按钮tooltip提示
+    function refreshShareTip(sharedUsers) {
+        const $shareTip = $('#share-tip');
+        if (!$shareTip) {
+            return;
+        }
+        const limit = 2;
+        const count = sharedUsers.length;
+        const users = sharedUsers.slice(0, 2);
+        const tip = users.reduce((acc, user, index) => {
+            if (index === 0) {
+                acc += '已分享给';
+                acc += user.real_name;
+            } else {
+                acc += ` ${user.real_name}`;
+            }
+            if (index === users.length - 1 && count > limit) {
+                acc += `等${count}人`;
+            }
+            return acc;
+        }, '');
+        $shareTip.attr('data-original-title', tip);
+    }
+
     // 初始化分享给的页面
     async function initModal(projectID) {
         try {

+ 1 - 1
web/common/html/header.html

@@ -4,7 +4,7 @@
     <% if(controller === 'boot' || controller === 'pm'){ %>
     <!--<a style="text-decoration: none" href="javascript:void(0);" class="header-logo">-->
     <% }else { %>
-    <div class="mx-2"><a href="/pm" class="btn btn-sm text-white" data-toggle="tooltip" title="返回项目管理"><i class="fa fa-angle-left" style="font-size:24px"></i></a></div>
+    <div class="mx-2"><a href="/pm" class="btn btn-sm" data-toggle="tooltip" title="返回项目管理"><i class="fa fa-angle-left" style="font-size:24px"></i></a></div>
         <!--<a style="text-decoration: none" href="/pm" class="header-logo">-->
     <% } %>
     <div class="header-logo">

+ 1 - 1
web/over_write/js/chongqing_2018.js

@@ -51,7 +51,7 @@ let isCQ2018 = true;
 
 if(typeof baseMaterialTypes !== 'undefined'){
     baseMaterialTypes.push(gljType.OTHER_MATERIAL);
-    allMaterialTypes.delete(gljType.EQUIPMENT);
+    // allMaterialTypes.delete(gljType.EQUIPMENT);  新规定里重庆材料类型里需要包含设备费。
     baseMachineTypes.delete(gljType.MACHINE_COMPOSITION);
     baseMachineTypes.push(gljType.INSTRUMENT, gljType.FUEL_POWER_FEE, gljType.DEPRECIATION_FEE,
         gljType.INSPECTION_FEE, gljType.MAINTENANCE, gljType.DISMANTLING_FREIGHT_FEE,

+ 42 - 12
web/over_write/js/guangdong_2018.js

@@ -18,7 +18,7 @@ function overwriteRationCalcBases (){
     rationCalcBases['材料费'] = function (node, isTender) {
         return calcTools.rationBaseFee(node, baseMaterialTypes, priceTypes.ptMarketPrice, isTender);
     };
-    rationCalcBases['施工机具费'] = function (node, isTender) {
+    rationCalcBases['机具费'] = function (node, isTender) {
         return calcTools.rationBaseFee(node, baseMachineTypes, priceTypes.ptMarketPrice, isTender);
     };
     rationCalcBases['主材费'] = function (node, isTender) {
@@ -31,7 +31,7 @@ function overwriteRationCalcBases (){
     rationCalcBases['管理费'] = function (node, isTender) {
         let rst = 0;
         if (calcTools.isRationItem(node) && node.data.gljList && node.data.manageFeeRate) {
-            rst = (rationCalcBases['人工费'](node, isTender) + rationCalcBases['施工机具费'](node, isTender)) * node.data.manageFeeRate * 0.01;
+            rst = (rationCalcBases['人工费'](node, isTender) + rationCalcBases['机具费'](node, isTender)) * node.data.manageFeeRate * 0.01;
             rst = rst.toDecimal(decimalObj.ration.unitPrice);
         };
         return rst;
@@ -45,7 +45,7 @@ function overwriteRationCalcBases (){
     rationCalcBases['甲供材料费'] = function (node, isTender) {
         return calcTools.partASupplyFee(node, '甲供材料费', isTender, false);
     };
-    rationCalcBases['甲供施工机具费'] = function (node, isTender) {
+    rationCalcBases['甲供机具费'] = function (node, isTender) {
         return calcTools.partASupplyFee(node, '甲供机械费', isTender, false);
     };
     rationCalcBases['甲供主材费'] = function (node, isTender) {
@@ -60,7 +60,7 @@ function overwriteRationCalcBases (){
     rationCalcBases['甲定材料费'] = function (node, isTender) {
         return calcTools.partASupplyFee(node, '甲定材料费', isTender, false);
     };
-    rationCalcBases['甲定施工机具费'] = function (node, isTender) {
+    rationCalcBases['甲定机具费'] = function (node, isTender) {
         return calcTools.partASupplyFee(node, '甲定机械费', isTender, false);
     };
     rationCalcBases['甲定主材费'] = function (node, isTender) {
@@ -79,7 +79,7 @@ function overwriteRationCalcBases (){
     cpFeeTypes = [
         {type: 'labour', name: '人工费'},
         {type: 'material', name: '材料费'},
-        {type: 'machine', name: '机费'},
+        {type: 'machine', name: '机费'},
         {type: 'mainMaterial', name: '主材费'},
         {type: 'equipment', name: '设备费'},
         {type: 'direct', name: '直接费'},
@@ -106,7 +106,7 @@ if (typeof module !== 'undefined') {
             '分部分项工程费': {base: 'FBFXGCF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
             '分部分项人工费': {base: 'FBFXDEJJRGF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
             '分部分项材料费': {base: 'FBFXDEJJCLF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
-            '分部分项施工机具费': {base: 'FBFXDEJJJXF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
+            '分部分项机具费': {base: 'FBFXDEJJJXF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
             '分部分项主材费': {base: 'FBFXZCF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
             '分部分项设备费': {base: 'FBFXSBF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
             '分部分项人工工日': {base: 'FBFXRGGR', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
@@ -115,16 +115,29 @@ if (typeof module !== 'undefined') {
             '其他项目费': {base: 'QTXMF',  fixedFlag: fixedFlag.OTHER, class: 'QTXM'},
             '甲供人工费': {base: 'JGDEJJRGF', class: 'RCJ'},
             '甲供材料费': {base: 'JGDEJJCLF', class: 'RCJ'},
-            '甲供施工机具费': {base: 'JGDEJJJXF', class: 'RCJ'},
+            '甲供机具费': {base: 'JGDEJJJXF', class: 'RCJ'},
+            '甲供主材费': {base: 'JGZCF', class: 'RCJ'},
+            '甲供设备费': {base: 'JGSBF', class: 'RCJ'},
             '甲定人工费': {base: 'JDDEJJRGF', class: 'RCJ'},
             '甲定材料费': {base: 'JDDEJJCLF', class: 'RCJ'},
-            '甲定施工机具费': {base: 'JDDEJJJXF', class: 'RCJ'},
+            '甲定机具费': {base: 'JDDEJJJXF', class: 'RCJ'},
             '甲定主材费': {base: 'JDZCF', class: 'RCJ'},
             '甲定设备费': {base: 'JDSBF', class: 'RCJ'},
             '暂估材料费(从子目汇总)': {base: 'ZGCLFFZM', class: 'RCJ'},
             '税金': {base: 'SJ', fixedFlag: fixedFlag.TAX, class: 'SJ'}
         };
     }
+    if(typeof baseFigureTemplate !== 'undefined'){
+        baseFigureTemplate['ZGCLFFZM'] = function (tender) { //暂估材料费(从子目汇总)
+            const feeField = 'estimate';
+            const subFeeField = tender ? 'tenderTotalFee' : 'totalFee';
+            // 分部分项暂估合价
+            const subEngineeringFee = cbTools.getBillsFee(fixedFlag.SUB_ENGINERRING, feeField, subFeeField);
+            // 措施项目暂估合价
+            let measureFee = cbTools.getBillsFee(fixedFlag.MEASURE, feeField, subFeeField);
+            return (subEngineeringFee + measureFee).toDecimal(decimalObj.bills.totalPrice);
+        };
+    }
 }
 
 if(typeof gljCol !== 'undefined'){
@@ -170,7 +183,7 @@ if (typeof commonConstants !== 'undefined') {
         // 其他项目
         [commonConstants.fixedFlag.OTHER]: 'QTF',
         // 措施项目的子项
-        [commonConstants.fixedFlag.GREEN_MEASURE_FEE]: 'AQWMSGF', // 绿色施工安全防护措施费
+        [commonConstants.fixedFlag.SAFETY_CONSTRUCTION]: 'AQWMSGF', // 绿色施工安全防护措施费
         [commonConstants.fixedFlag.OTHER_MEASURE_FEE]: 'QTCSF', // 其他措施费
         // 其他项目的子项
         [commonConstants.fixedFlag.PROVISIONAL]: 'ZLF', // 暂列金额
@@ -196,7 +209,7 @@ if (typeof commonConstants !== 'undefined') {
         '{分部分项工程费}': 'QDF',
         '{分部分项人工费}': 'QRG',
         '{分部分项材料费}': 'QCL',
-        '{分部分项施工机具费}': 'QJX',
+        '{分部分项机具费}': 'QJX',
         '{分部分项主材费}': 'QZCF',
         '{分部分项设备费}': 'QSBF',
         '{分部分项人工工日}': 'FBFXRGGR', // 标准没有,自增
@@ -205,13 +218,30 @@ if (typeof commonConstants !== 'undefined') {
         '{其他项目费}': 'QTF',
         '{甲供人工费}': 'JGRGF', // 自增
         '{甲供材料费}': 'JGC',
-        '{甲供施工机具费}': 'JGSGJJF', // 自增
+        '{甲供机具费}': 'JGJJF', // 自增
+        '{甲供主材费}': 'JGZCF', // 自增
+        '{甲供设备费}': 'JGSBF', // 自增
         '{甲定人工费}': 'JDRGF', // 自增
         '{甲定材料费}': 'JDCLF', // 自增
-        '{甲定施工机具费}': 'JDSGJJF', // 自增
+        '{甲定机具费}': 'JDJJF', // 自增
         '{甲定主材费}': 'JDZCF', // 自增
         '{甲定设备费}': 'JDSBF', // 自增
         '{暂估材料费(从子目汇总)}': 'ZGCLFCZMHZ', // 自增
         '{税金}': 'SJ',
     };
+}
+
+if(typeof module !== 'undefined'){
+    module.exports = {
+        getBillsCalcMode: getBillsCalcMode,
+        getAreaName: getAreaName
+    };
+}
+
+function getBillsCalcMode() {
+    return 1
+}
+
+function getAreaName() {
+    return 'guangdong_2018'
 }

+ 56 - 15
web/over_write/js/guangdong_2018_export.js

@@ -108,7 +108,7 @@ const XMLStandard = (function () {
         '直接费': 'RGF+CLF+JXF+ZCF+SBF+GLF',
         '人工费': 'RGF',
         '材料费': 'CLF',
-        '施工机具费': 'JXF',
+        '机具费': 'JXF',
         '主材费': 'ZCF',
         '设备费': 'SBF',
         '管理费': 'GLF',
@@ -120,7 +120,7 @@ const XMLStandard = (function () {
         '直接费': 'ZJF',
         '人工费': 'RGF',
         '材料费': 'CLF',
-        '施工机具费': 'JXF',
+        '机具费': 'JXF',
         '主材费': 'ZCF',
         '设备费': 'SBF',
         '管理费': 'GLF',
@@ -235,7 +235,7 @@ const XMLStandard = (function () {
                 { name: 'measureProfit', feeName: 'profit' }
             ]
         },
-        [fixedFlag.GREEN_MEASURE_FEE]: {
+        [fixedFlag.SAFETY_CONSTRUCTION]: {
             items: [{ name: 'greenMeasureFee', feeName: 'common' }]
         },
         [fixedFlag.OTHER_MEASURE_FEE]: {
@@ -433,7 +433,7 @@ const XMLStandard = (function () {
             const attrs = [
                 // 项目编号
                 {
-                    name: 'Number', dName: '项目编号', required: true,
+                    name: 'Number', dName: '工程编号', required: true, minLen: 1,
                     value: _util.getValueByKey(basicInformation, 'projNum')
                 },
                 // 项目名称
@@ -483,7 +483,7 @@ const XMLStandard = (function () {
                 },
                 // 建设单位
                 {
-                    name: 'BulidUnit', dName: '建设单位', required: true,
+                    name: 'BulidUnit', dName: '建设单位', required: true, minLen: 1,
                     value: _util.getValueByKey(basicInformation, 'constructingUnits')
                 },
                 // 建设单位法定代表人或其授权人
@@ -513,7 +513,7 @@ const XMLStandard = (function () {
                 },
                 // 建设规模单位
                 {
-                    name: 'Unit', dName: '建设规模单位', required: true,
+                    name: 'Unit', dName: '建设规模单位', required: true, minLen: 1,
                     value: _util.getValueByKey(basicInformation, 'unit')
                 },
                 // 技术经济指标(元) 取单方造价
@@ -1081,7 +1081,7 @@ const XMLStandard = (function () {
                 },
                 // 工程类型
                 {
-                    name: 'ProjectType', dName: '工程类型', required: true,
+                    name: 'ProjectType', dName: '工程类型', required: true, minLen: 1,
                     value: _util.getValueByKey(projectFeature, 'projType')
                 },
                 // 计价模式
@@ -1126,7 +1126,7 @@ const XMLStandard = (function () {
                 },
                 // 建设规模单位 取单位工程-工程特征-建设规模单位
                 {
-                    name: 'Unit', dName: '建设规模单位', required: true,
+                    name: 'Unit', dName: '建设规模单位', required: true, minLen: 1,
                     value: _util.getValueByKey(projectFeature, 'buildScaleUnit')
                 },
                 // 占总投资比例(%)
@@ -1362,7 +1362,7 @@ const XMLStandard = (function () {
                 // 绿色施工安全防护措施费
                 {
                     name: 'CostForHSE', type: _type.DECIMAL,
-                    value: node.isBelongToFlags([fixedFlag.GREEN_MEASURE_FEE]) ? _util.getFeeByFlag(items, fixedFlag.GREEN_MEASURE_FEE, 'common.totalFee') : '0'
+                    value: node.isBelongToFlags([fixedFlag.SAFETY_CONSTRUCTION]) ? _util.getFeeByFlag(items, fixedFlag.SAFETY_CONSTRUCTION, 'common.totalFee') : '0'
                 },
                 // 其他项目费
                 {
@@ -1431,9 +1431,10 @@ const XMLStandard = (function () {
             _base.Element.call(this, 'DivisionalWorks', attrs, '分部工程');
         }
         // 清单项目
-        function WorkElement(node, kind, specialty) {
+        function WorkElement(node, kind) {
             const bills = node.data;
             const row = node.serialNo() + 1;
+            const programID = getBillsProgramID(bills);
             const attrs = [
                 // 项目编码
                 { name: 'Number', dName: '项目编码', required: true, value: bills.code || '', minLen: 1, failHint: `第${row}行清单-“项目编码”` },
@@ -1472,7 +1473,7 @@ const XMLStandard = (function () {
                 // 计算方式
                 { name: 'CalcType', dName: '计算方式', type: _type.INT, required: true, value: '1' },
                 // 专业类型
-                { name: 'Specialty', type: _type.INT, value: specialty },
+                { name: 'Specialty', type: _type.INT, value: programID },
                 // 清单标识
                 { name: 'ListingIdentity', value: 'GB50500-2013 1 GD' },
                 // 费用代号
@@ -2265,6 +2266,7 @@ const XMLStandard = (function () {
          * @return {Array}
          * */
         let tenderDetail = null;
+        let usedStdBills = []; // 造价书里使用到的清单库里的标准清单
         async function loadTenders(summaryInfoMap, tenderData, isPlain) {
             const unitWorks = [];
             for (const tData of tenderData) {
@@ -2304,8 +2306,11 @@ const XMLStandard = (function () {
                 // 先计算人材机总消耗量,以供后面需要
                 gljUtil.calcProjectGLJQuantity(tenderDetail.projectGLJ.datas,
                     tenderDetail.ration_glj.datas, tenderDetail.Ration.datas, tenderDetail.Bills.datas, Decimal.GLJ, _, scMathUtil); */
+                
                 // 单位工程费用汇总
                 const unitWorksSummary = loadUnitWorksSummary(tenderDetail);
+                // 获取标准清单编码-取费类别映射表
+                usedStdBills = await getUsedStdBills(tenderDetail.Bills.datas);
                 // 分部分项工程
                 const divisionalElements = loadDivisionalAndElementalWorks();
                 // 措施项目
@@ -2342,6 +2347,43 @@ const XMLStandard = (function () {
             return unitWorks;
         }
 
+        // 获取清单的取费类别,对应的是标准清单的工程专业
+        function getBillsProgramID(bills) {
+            if (bills.programID) {
+                return bills.programID;
+            }
+            const defaultProgramID = 1;
+            const reg = /^\d{12}$/;
+            if (!bills.billsLibId || !reg.test(bills.code)) {
+                return defaultProgramID;
+            } else {
+                const nineCode = bills.code.substr(0, 9);
+                const matched = usedStdBills.find(stdItem => stdItem.code === nineCode && stdItem.billsLibId === bills.billsLibId);
+                return matched && matched.engineering || defaultProgramID;
+            }
+        }
+
+        // 获取造价书中使用到的标准清单
+        async function getUsedStdBills(allBills) {
+            // 标准清单添加到造价书后应该是12位编码
+            const reg = /^\d{12}$/;
+            const map = allBills
+                .filter(bills => !bills.programID && bills.billsLibId && reg.test(bills.code))
+                .reduce((acc, bills) => {
+                    if (!acc[bills.billsLibId]) {
+                        acc[bills.billsLibId] = [];
+                    }
+                    const nineCode = bills.code.substr(0, 9);
+                    acc[bills.billsLibId].push(nineCode);
+                    return acc;
+                }, {});
+            const queries = Object
+                .entries(map)
+                .map(([billsLibId, codes]) => ({ billsLibId, code: { $in: codes } }));
+            const occupancy = 'code engineering billsLibId'
+            return await ajaxPost('/stdBillsEditor/getBillsByQueries', { queries, occupancy });
+        }
+
         // 加载工程特征信息
         // attrList 单位工程的工程特征,来自property.projectFeature
         function loadAttrInfo(attrList) {
@@ -2390,7 +2432,7 @@ const XMLStandard = (function () {
             const csxmGroup = new UnitWorksSummaryGroup(csxm.data);
             // 措施项目的子项,“绿色施工安全防护措施费”、“其他措施费”
             const csxmChildren = csxm.getPosterity()
-                .filter(node => [fixedFlag.GREEN_MEASURE_FEE, fixedFlag.OTHER_MEASURE_FEE].includes(node.getFlag()))
+                .filter(node => [fixedFlag.SAFETY_CONSTRUCTION, fixedFlag.OTHER_MEASURE_FEE].includes(node.getFlag()))
                 .map(node => new UnitWorksSummaryItem(node));
             csxmGroup.children.push(...csxmChildren);
             // 其他项目
@@ -2467,8 +2509,7 @@ const XMLStandard = (function () {
 
         // 加载清单
         function loadBills(node, kind) {
-            const specialty = Specialty[tenderDetail.projectInfo.property.engineeringName]; // 工程专业
-            const workElement = new WorkElement(node, kind, specialty);
+            const workElement = new WorkElement(node, kind);
             // 合计费用
             const summaryCost = new SummaryOfBasicCost(tenderDetail.mainTree.items, node);
             workElement.children.push(summaryCost);
@@ -2537,7 +2578,7 @@ const XMLStandard = (function () {
                     return parsedTotalQuantity;
                 })
                 .map(rGLJ => {
-                    const totalQuantity = gljUtil.getTotalQuantity(rGLJ, node.data, Decimal.QUANTITY, Decimal.GLJ);
+                    //const totalQuantity = gljUtil.getTotalQuantity(rGLJ, node.data, Decimal.QUANTITY, Decimal.GLJ);
                     const noCost = getNoCost(projectGLJCodeMap, rGLJ.code);
                     return new LabourMaterialsEquipmentsMachinesElement(rGLJ, rGLJ.quantity, noCost);
                 });

+ 10 - 2
web/over_write/js/guangdong_2018_import.js

@@ -45,7 +45,7 @@ const importXML = (() => {
         '4': '四类地区',
     }
     // 一些数据是需要从后端获取自增数字后赋值的,这里是记录,用完会在extractProject清空
-    const countData = {
+    let countData = {
         projectCount: 0,    //项目数量
         projectGLJCount: 0,  //项目人材机数量
         ratioCount: 0,      //组成物数量
@@ -319,6 +319,14 @@ const importXML = (() => {
             feeCode: getValue(divisionalSrc, ['_Code']),
             remark: getValue(divisionalSrc, ['_Remark']),
         };
+        // 特殊处理措施项目的费用代号(广联达这两条数据没有导出费用代号,跟我们的清单模板不匹配,从而导致从合并变成了新增),详看mergeBills中的mergeitems放啊
+        if (type === billType.BILL) {
+            if (item.code === 'AQFHWMSG') {
+                item.feeCode = FlagFeeCodeMap[fixedFlag.SAFETY_CONSTRUCTION];
+            } else if (item.code === 'QTCSF') {
+                item.feeCode = FlagFeeCodeMap[fixedFlag.OTHER_MEASURE_FEE];
+            }
+        }
         if (importFileKind === FileKind.tender) {
             const summaryFees = getFeesFromBasicCost(divisionalSrc);
             const fees = [{ fieldName: 'common', totalFee: getValue(divisionalSrc, ['_Total']), unitFee: getValue(divisionalSrc, ['_TechnicalAndEconomicIndex']) }];
@@ -712,7 +720,7 @@ const importXML = (() => {
         }
         // 根据计税方式获取价格,一般计税对应不含税,简易对应含税
         function getPriceByTaxType(gljSrc, taxType) {
-            return taxType === TaxType.NORMAL
+            return +taxType === TaxType.NORMAL
                 ? {
                     base_price: getValue(gljSrc, ['_NoTaxOrgPrice']),
                     market_price: getValue(gljSrc, ['_NoTaxPrice'])