Prechádzať zdrojové kódy

Merge branch 'master' of http://192.168.1.41:3000/SmartCost/ConstructionCost

TonyKang 5 rokov pred
rodič
commit
1753e81409
48 zmenil súbory, kde vykonal 1873 pridanie a 1008 odobranie
  1. 3 0
      config/gulpConfig.js
  2. 1 1
      gulpfile.js
  3. 2 0
      modules/all_models/bills.js
  4. 4 0
      modules/all_models/engineering_lib.js
  5. 1 1
      modules/all_models/projects.js
  6. 2 0
      modules/all_models/ration.js
  7. 26 0
      modules/all_models/share_list.js
  8. 9 0
      modules/all_models/user.js
  9. 11 1
      modules/common/const/bills_fixed.js
  10. 26 3
      modules/main/facade/project_facade.js
  11. 4 1
      modules/main/facade/ration_facade.js
  12. 2 2
      modules/main/routes/main_route.js
  13. 102 38
      modules/pm/controllers/pm_controller.js
  14. 163 31
      modules/pm/facade/pm_facade.js
  15. 12 1
      modules/pm/models/project_model.js
  16. 1 0
      modules/pm/routes/pm_route.js
  17. 37 5
      modules/ration_glj/facade/glj_calculate_facade.js
  18. 2 1
      modules/templates/controllers/bills_template_controller.js
  19. 4 2
      modules/templates/models/bills_template.js
  20. 2 0
      modules/users/controllers/login_controller.js
  21. 32 0
      modules/users/models/user_model.js
  22. 3 0
      public/web/gljUtil.js
  23. 12 0
      public/web/id_tree.js
  24. 5 0
      public/web/number_util.js
  25. 10 3
      public/web/sheet/sheet_common.js
  26. 2 2
      public/web/slideResize.js
  27. 438 535
      web/building_saas/css/main.css
  28. 3 15
      web/building_saas/main/html/calc_program_manage.html
  29. 60 0
      web/building_saas/main/html/main.html
  30. 12 0
      web/building_saas/main/js/models/bills.js
  31. 12 0
      web/building_saas/main/js/models/cache_tree.js
  32. 20 2
      web/building_saas/main/js/models/calc_program.js
  33. 3 3
      web/building_saas/main/js/models/exportSEIInterface.js
  34. 270 265
      web/building_saas/main/js/models/exportStdInterface_gd18.js
  35. 11 1
      web/building_saas/main/js/models/main_consts.js
  36. 19 12
      web/building_saas/main/js/models/overHeight.js
  37. 28 1
      web/building_saas/main/js/models/project.js
  38. 143 0
      web/building_saas/main/js/views/area_increase_fee_view.js
  39. 1 0
      web/building_saas/main/js/views/calc_program_manage.js
  40. 1 10
      web/building_saas/main/js/views/index_view.js
  41. 99 0
      web/building_saas/main/js/views/item_increase_fee_view.js
  42. 18 15
      web/building_saas/main/js/views/main_tree_col.js
  43. 65 2
      web/building_saas/main/js/views/project_view.js
  44. 40 5
      web/building_saas/pm/html/project-management.html
  45. 2 0
      web/building_saas/pm/js/pm_import.js
  46. 139 42
      web/building_saas/pm/js/pm_newMain.js
  47. 2 8
      web/building_saas/pm/js/pm_share.js
  48. 9 0
      web/over_write/js/guangdong_2018.js

+ 3 - 0
config/gulpConfig.js

@@ -42,6 +42,7 @@ module.exports = {
     pm_jspaths:[
         'public/web/uuid.js',
         'public/web/date_util.js',
+        'public/web/upload_cdn.js',
         'public/web/id_tree.js',
         'public/web/tree_sheet/tree_sheet_helper.js',
         'public/web/sheet/sheet_data_helper.js',
@@ -151,6 +152,8 @@ module.exports = {
         'web/building_saas/main/js/views/confirm_modal.js',
         'web/building_saas/main/js/views/zlfb_view.js',
         'web/building_saas/main/js/views/installation_fee_view.js',
+        'web/building_saas/main/js/views/area_increase_fee_view.js',
+        'web/building_saas/main/js/views/item_increase_fee_view.js',
         'web/building_saas/main/js/views/material_adjust_view.js',
         'web/building_saas/main/js/views/config_material_view.js',
         'web/building_saas/main/js/views/index_view.js',

+ 1 - 1
gulpfile.js

@@ -186,7 +186,7 @@ function css(options) {
     if(options.csspaths){
         return gulp.src(options.csspaths)
             .pipe($.plumber())
-            .pipe($.cssnano())
+            .pipe($.cssnano({reduceIdents: false}))
             .pipe($.concat(options.concatName+"."+version+".css"))
             .pipe(gulp.dest(cssDest));
     }

+ 2 - 0
modules/all_models/bills.js

@@ -65,6 +65,8 @@ let billsSchema = new Schema({
     deleteInfo: deleteSchema,
     isEstimate:{type: Number,default:0},       // 1 true 0 false 是否暂估
     mainBills:{type:Schema.Types.Mixed,default:false},//true 是,false否,null 不确定,三个状态
+    //是否记取面积增加费
+    areaIncreaseFee:{type:Schema.Types.Mixed,default:false},//true 是,false否,null 不确定,三个状态
     outPutMaxPrice:{type:Schema.Types.Mixed,default:false},//输出最高限价 true 是,false否,null 不确定,三个状态
     maxPrice:String,//最高限价
     remark:String,

+ 4 - 0
modules/all_models/engineering_lib.js

@@ -107,6 +107,10 @@ let modelSchema = {
     engineering:Number,
     //是否计算安装增加费
     isInstall:{type: Boolean, default: false},
+    //是否计算子目增加费
+    isItemIncrease:{type: Boolean, default: false},
+    //是否计算面积增加费
+    isAreaIncrease:{type: Boolean, default: false},
     indexName:String,//指标专业名称
     seq:Number//序列号
 };

+ 1 - 1
modules/all_models/projects.js

@@ -26,7 +26,7 @@ const ProjectSchema = new Schema({
     "compilation": String,
     "deleteInfo": deleteSchema,
     'fullFolder': Array,
-    "shareInfo": [shareSchema],
+    //"shareInfo": [shareSchema],
     "property": {
         type: Schema.Types.Mixed,
         default: {}

+ 2 - 0
modules/all_models/ration.js

@@ -76,6 +76,8 @@ let rationSchema = new Schema({
     // 工作内容 (选择自清单)
     jobContentText: String,
     manageFeeRate:String,//管理费率
+    //是否记取面积增加费
+    areaIncreaseFee:{type:Schema.Types.Mixed,default:false},//true 是,false否,null 不确定,三个状态
 
     //工料机特有属性
     projectGLJID:Number,  //项目工料机ID

+ 26 - 0
modules/all_models/share_list.js

@@ -0,0 +1,26 @@
+/*
+ * @Descripttion: 分享列表
+ * @Author: Zhong
+ * @Date: 2020-01-10 10:51:35
+ */
+
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const shareSchema = new Schema({
+    ID: String,
+    projectID: Number,
+    owner: String, // 项目拥有者ID
+    receiver: String, // 接收者ID
+    allowCopy: {
+        type: Boolean,
+        default: false
+    },
+    allowCooperate: {
+        type: Boolean,
+        default: false
+    },
+    shareDate: String,
+    updateDate: String
+}, {versionKey: false});
+
+mongoose.model('share_list', shareSchema, 'share_list');

+ 9 - 0
modules/all_models/user.js

@@ -42,6 +42,10 @@ let schema = {
     username: String,
     email: String,
     mobile: String,
+    qq: {
+        type: String,
+        default: ''
+    },
     real_name: {
         type: String,
         default: ''
@@ -84,6 +88,11 @@ let schema = {
         type: [userdList],
         default: []
     },
+    // 联系人
+    contacts: {
+        type: Array,
+        default: []
+    },
     // 是否邮箱已通过验证
     isUserActive: Number,
     // 是否只允许短信登录

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

@@ -66,7 +66,17 @@ const fixedFlag = {
     //组织措施费
     ORGANIZATION:32,
     //其他措施费
-    OTHER_MEASURE_FEE:33
+    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;

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

@@ -14,7 +14,8 @@ module.exports = {
     getSEIProjects:getSEIProjects,
     loadSEIProjectData:loadSEIProjectData,
     setSEILibData:setSEILibData,
-    getIndexReportData:getIndexReportData
+    getIndexReportData:getIndexReportData,
+    setDefaultItemIncrease:setDefaultItemIncrease
 };
 
 let mongoose = require('mongoose');
@@ -30,6 +31,7 @@ let ration_glj_model = mongoose.model('ration_glj');
 let rationTemplateModel = mongoose.model('ration_template');
 let project_glj_model = mongoose.model('glj_list');
 let ration_glj_facade = require("../../ration_glj/facade/ration_glj_facade");
+let glj_calculate_facade = require("../../ration_glj/facade/glj_calculate_facade");
 const uuidV1 = require('uuid/v1');
 const gljUtil = require('../../../public/gljUtil');
 let stdColSettingModel = mongoose.model('std_main_col_lib');
@@ -50,7 +52,6 @@ async function calcInstallationFee(data) {
     if(billTasks.length>0){
         await bill_model.model.bulkWrite(billTasks);
     }
-    console.log(rationTasks);
     if(rationTasks.length>0){
         await ration_model.model.bulkWrite(rationTasks);
     }
@@ -281,6 +282,17 @@ async function updateNodes(datas){
             if(type == projectConsts.BILLS){
                 billTasks.push(getTask(node));
             }else if(type == projectConsts.RATION){
+                //处理面积增加费的数据
+                if(node.data.hasOwnProperty("areaIncreaseFee")){
+                    let areaSetting = null;
+                    if(nodeGroups[projectConsts.PROJECT]){
+                        for(let pn of nodeGroups[projectConsts.PROJECT]){
+                            if(pn.data['property.areaSetting']) areaSetting = pn.data['property.areaSetting'];
+                        }
+                    }
+                    let t = await glj_calculate_facade.calculateQuantity({rationID:node.data.ID},true,false,node.data.areaIncreaseFee,areaSetting);
+                    node.data.adjustState = t.adjustState;
+                }
                 rationTasks.push(getTask(node));
             }else if(type == projectConsts.RATION_GLJ){
                 rationGLJTasks.push(getTask(node));
@@ -317,7 +329,9 @@ async function updateNodes(datas){
     projectGLJTasks.length>0?asyncTasks.push(project_glj_model.bulkWrite(projectGLJTasks)):"";
     projectTasks.length>0?asyncTasks.push(projectsModel.bulkWrite(projectTasks)):"";
     rationTemplateTasks.length>0?asyncTasks.push(rationTemplateModel.bulkWrite(rationTemplateTasks)):"";
-    return  asyncTasks.length>0?await Promise.all(asyncTasks):"";
+    asyncTasks.length>0?await Promise.all(asyncTasks):"";
+    return datas;
+
 
     function getTask(node,idFiled = 'ID') {
 
@@ -542,6 +556,15 @@ async function setSEILibData(property){
     }
 }
 
+function setDefaultItemIncrease(property) {
+    property.itemIncreaseSetting = [
+        {"name":"在生产车间边生产边施工","base":"人工费","coe":10,"scope":{}},
+        {"name":"在有害身体健康的场所内施工","base":"人工费","coe":10,"scope":{}},
+        {"name":"在洞内、地下室内、库内或暗室内进行施工","base":"人工费","coe":40,"scope":{}},
+        {"name":"在洞内、地下室内、库内或暗室内进行施工(模板拆除)","base":"人工费","coe":10,"scope":{}}
+    ]
+}
+
 async function getIndexReportData(projectID,keyArr) {
     let project = await projectsModel.findOne({ID:projectID});
     let bills = await bill_model.getDataSync(projectID);

+ 4 - 1
modules/main/facade/ration_facade.js

@@ -228,6 +228,9 @@ async function addRationSubList(stdRation,newRation,needInstall,compilation,clea
         console.log("添加定额install时间-----"+(addRationInstallFeeTime - addRationCoeTime));
         //添加定额模板子目
         ration_template = await addRationTemplate(stdRation,newRation);
+    }else if(newRation.areaIncreaseFee == true){//清空子目换算时,如果有面积增加费,子目调整状态要生成
+        let t = await glj_calculate_facade.calculateQuantity({rationID:newRation.ID},true);
+        newRation.adjustState = t.adjustState;
     }
     return {ration:newRation,ration_gljs:ration_gljs,ration_coes:ration_coes,ration_installations:ration_installations,ration_templates:ration_template?[ration_template]:[]};
 }
@@ -577,7 +580,7 @@ async function  updateRation(std,defaultLibID,rationID,billsItemID,projectID,cal
          "marketUnitFee":1,
          'marketTotalFee':1,
          "maskName":1
-     }
+     };
     let newRation = await ration_model.model.findOneAndUpdate({ID:rationID,projectID:projectID},{"$set":ration,"$unset":unsetObject},{new: true});//;
     return newRation;
 }

+ 2 - 2
modules/main/routes/main_route.js

@@ -14,14 +14,14 @@ module.exports =function (app) {
     app.get('/main', baseController.init, function(req, res) {
         let pm = require('../../pm/controllers/pm_controller');
 
-        pm.checkProjectRight(req.session.sessionUser.id, req.query.project, async function (hasRight, projectData, shareInfo) {
+        pm.checkProjectRight(req.session.sessionUser.id, req.query.project, async function (hasRight, projectData, allowCooperate) {
             if (hasRight) {
                 //分享的项目,只读、协作(允许编辑)
                 let projectReadOnly = false,
                     projectCooperate = false;
                 if(req.session.sessionUser.id !== projectData.userID){
                     projectData._doc.readOnly = true;
-                    projectCooperate = !!shareInfo.allowCooperate;
+                    projectCooperate = allowCooperate;
                     //允许协作的项目允许编辑,非只读
                     projectReadOnly = !projectCooperate;
                 }

+ 102 - 38
modules/pm/controllers/pm_controller.js

@@ -4,6 +4,8 @@
 import UnitPriceFileModel from "../../glj/models/unit_price_file_model";
 import moment from 'moment';
 import CompilationModel from "../../users/models/compilation_model";
+import UserModel from "../../users/models/user_model";
+const userModelObj = new UserModel();
 let mongoose = require('mongoose');
 let ProjectsData = require('../models/project_model').project;
 let labourCoe = require('../../main/facade/labour_coe_facade');
@@ -26,6 +28,7 @@ const stdBillsGuidanceLibModel = mongoose.model('std_billsGuidance_lib');
 const fs = require('fs');
 const _ = require('lodash');
 import SectionTreeDao from '../../complementary_ration_lib/models/sectionTreeModel';
+const uuidV1 = require('uuid/v1');
 let sectionTreeDao = new SectionTreeDao();
 let consts = require('../../main/models/project_consts');
 const rationLibModel = mongoose.model('std_ration_lib_map');
@@ -59,10 +62,11 @@ module.exports = {
             let shareInfo = null;
             //判断是否是打开分享的项目,分享项目shareInfo不为null
             if(userId !== result.userID){
-                shareInfo = await pm_facade.getShareInfo(userId, result);
+                shareInfo = await pm_facade.getShareInfo(userId, result.ID);
             }
             if ((userId === result.userID || shareInfo) && result._doc.projType === projType.tender) {
-                callback(true, result, shareInfo);
+                const allowCooperate = (shareInfo || {}).allowCooperate;
+                callback(true, result, allowCooperate);
             } else {
                 callback(false);
             }
@@ -71,7 +75,8 @@ module.exports = {
         });
     },
     getProjects: async function(req, res){
-         await ProjectsData.getUserProjects(req.session.sessionUser.id, req.session.sessionCompilation._id, function(err, message, projects){
+        await ProjectsData.getUserProjects(req.session.sessionUser.id, req.session.sessionCompilation._id, function(err, message, projects){
+            console.log(err);
             if (projects) {
                 callback(req, res, err, message, projects);
             } else {
@@ -296,6 +301,8 @@ module.exports = {
     },
     // 项目管理首页
     index: async function(request, response) {
+        // TODO 上线后删除,处理旧的分享数据
+        await pm_facade.prepareShareList();
         // 获取编办信息
         let sessionCompilation = request.session.sessionCompilation;
         if (sessionCompilation === undefined ||sessionCompilation ===null) {
@@ -564,37 +571,86 @@ module.exports = {
     },
     projectShareInfo: async function(req, res){
         try{
-            let data = JSON.parse(req.body.data);
-            let shareInfo = await projectModel.findOne({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, '-_id shareInfo');
+            const data = JSON.parse(req.body.data);
+            const shareList = await pm_facade.getShareList({projectID: data.projectID});
+            const shareInfoMap = await pm_facade.getShareInfoMap(null, shareList);
+            const shareInfo = shareInfoMap[data.projectID] || [];
+            //let shareInfo = await projectModel.findOne({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, '-_id shareInfo');
             callback(req, res, 0, 'success', shareInfo);
         }
         catch (err){
             callback(req, res, 1, err, null);
         }
     },
+    getRecentShareInfo: async function (req, res) {
+        try {
+            const { count } = JSON.parse(req.body.data);
+            const userID = req.session.sessionUser.id;
+            const recentUsers = await pm_facade.getRecentShareList(userID, count);
+            const contacts = await userModelObj.getContacts(userID);
+            callback(req, res, 0, 'success', { recentUsers, contacts });
+        } catch (err) {
+            console.log(err);
+            callback(req, res, 1, err.message, null);
+        }
+    },
     share: async function(req, res){
         try{
-            let data = JSON.parse(req.body.data);
-            let shareDate = moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'),
-                shareUserIDs = [];
-            for (let data of data.shareData) {
-                shareUserIDs.push(data.userID);
-                data.shareDate = shareDate;
-            }
-            //添加分享
-            if(data.type === 'create'){
-                //新增
-                for (let sData of data.shareData) {
-                    await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$addToSet: {shareInfo: sData}});
+            const data = JSON.parse(req.body.data);
+            const { type, shareData, projectID } = data;
+            const userID = req.session.sessionUser.id;
+            const shareDate = moment(Date.now()).format('YYYY-MM-DD HH:mm:ss');
+            shareData.forEach(item => item.shareDate = shareDate);
+            const task = [];
+            if (type === 'create') {
+                // 生成分享记录
+                const docs = shareData.map(item => ({
+                    ID: uuidV1(),
+                    projectID,
+                    owner: userID,
+                    receiver: item.userID,
+                    allowCooperate: item.allowCooperate,
+                    allowCopy: item.allowCopy,
+                    shareDate: item.shareDate,
+                    updateDate: item.shareDate
+                }));
+                task.push(pm_facade.addShareList(docs));
+                // 分享即互相添加为联系人
+                task.push(userModelObj.addContact(docs[0].owner, docs[0].receiver));
+            } else if (type === 'update') {
+                // 取消分享(项目管理界面可一次进行更新和取消)
+                const cancelReceivers = shareData
+                    .filter(item => item.isCancel)
+                    .map(item => item.userID);
+                if (cancelReceivers.length) {
+                    task.push(pm_facade.deleteShareList({projectID, receiver: {$in: cancelReceivers}}));
                 }
-            } else if (data.type === 'update') {
-                await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$set: {shareInfo: data.shareData}});
-            }
-            //取消分享
-            else {
-                await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$pull: {shareInfo: {userID: {$in: shareUserIDs}}}});
+                // 更新分享选项
+                const updateData = shareData
+                    .filter(item => !item.isCancel)
+                    .map(item => (
+                        {
+                            query: {
+                                projectID,
+                                receiver: item.userID
+                            },
+                            update: {
+                                allowCopy: item.allowCopy,
+                                allowCooperate: item.allowCooperate,
+                                updateDate: shareDate
+                            }
+                        }
+                    ));
+                if (updateData.length) {
+                    task.push(pm_facade.updateShareList(updateData))
+                }
+            } else { // 取消分享
+                const cancelReceivers = shareData.map(item => item.userID);
+                task.push(pm_facade.deleteShareList({projectID, receiver: {$in: cancelReceivers}}));
             }
-            callback(req, res, 0, 'success', data.shareData);
+            await Promise.all(task);
+            const rstData = shareData.filter(item => !item.isCancel);
+            callback(req, res, 0, 'success', rstData);
         }
         catch (err){
             callback(req, res, 1, err, null);
@@ -604,20 +660,24 @@ module.exports = {
         try {
             let rst = {grouped: [], ungrouped: [], summaryInfo: null};
             let userID = req.session.sessionUser.id;
-            let receiveProjects = await projectModel.find({
-                $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], compilation: req.session.sessionCompilation._id, 'shareInfo.userID': userID}, '-_id');
+            const shareList = await pm_facade.getShareList({ receiver: userID });
+            const receiveProjectIDs = shareList.map(item => item.projectID);
+            const compilation = req.session.sessionCompilation._id;
+            const notDeleted = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
+            const receiveProjects = await projectModel.find({ID: {$in: receiveProjectIDs}, compilation, $or: notDeleted}, '-_id').lean();
             //设置原项目用户信息
+            const shareInfoMap = await pm_facade.getShareInfoMap(null, shareList);
             if(receiveProjects.length > 0){
                 let orgUserIDs = [];
                 for(let proj of receiveProjects){
                     orgUserIDs.push(proj.userID);
                     if (proj.projType === projType.tender) {
                         //设置工程专业
-                        proj._doc.feeStandardName = proj.property.feeStandardName || '';
+                        proj.feeStandardName = proj.property.feeStandardName || '';
                         //设置计税方法
-                        proj._doc.taxType = proj.property.taxType;
+                        proj.taxType = proj.property.taxType;
                     }
-                    delete proj._doc.property;
+                    delete proj.property;
                 }
                 orgUserIDs = Array.from(new Set(orgUserIDs));
                 let userObjIDs = [];
@@ -629,28 +689,32 @@ module.exports = {
                 let consProjIDs = [],
                     ungroupedTenders = [];
                 for(let proj of receiveProjects){
+                    // 设置分享信息
+                    proj.shareInfo = shareInfoMap[proj.ID] || [];
                     if (proj.projType === projType.project) {
                         consProjIDs.push(proj.ID);
                     }
                     //获取分享项目子项
                     if (proj.projType !== projType.tender) {
-                        proj._doc.children = await pm_facade.getPosterityProjects([proj.ID]);
-                        for (let projC of proj._doc.children) {
+                        proj.children = await pm_facade.getPosterityProjects([proj.ID]);
+                        for (let projC of proj.children) {
+                            // 设置分享信息
+                            projC.shareInfo = shareInfoMap[projC.ID] || [];
                             if (projC.projType === projType.project) {
                                 consProjIDs.push(projC.ID);
                             } else if (projC.projType === projType.tender) {
                                 //设置工程专业
-                                projC._doc.feeStandardName = projC.property.feeStandardName || '';
+                                projC.feeStandardName = projC.property.feeStandardName || '';
                                 //设置计税方法
-                                projC._doc.taxType = projC.property.taxType;
+                                projC.taxType = projC.property.taxType;
                                 if (proj.projType === projType.engineering) {
-                                    ungroupedTenders.push(projC._doc);
+                                    ungroupedTenders.push(projC);
                                 }
                             }
-                            delete projC._doc.property;
+                            delete projC.property;
                         }
                     } else {//未分类的单位工程不进行汇总,只取价格信息
-                        ungroupedTenders.push(proj._doc);
+                        ungroupedTenders.push(proj);
                     }
                     //设置分组,单位工程及单项工程分到未分组那
                     if (proj.projType === projType.tender || proj.projType === projType.engineering) {
@@ -659,11 +723,11 @@ module.exports = {
                         rst.grouped.push(proj);
                     }
                     //设置项目类型为来自别人分享
-                    proj._doc.shareType = 'receive';
+                    proj.shareType = 'receive';
                     for(let userData of orgUsersInfo){
                         if(proj.userID == userData._id.toString()){
                             let userInfo = {name: userData.real_name, mobile: userData.mobile, company: userData.company, email: userData.email};
-                            proj._doc.userInfo = userInfo;
+                            proj.userInfo = userInfo;
                         }
                     }
                 }

+ 163 - 31
modules/pm/facade/pm_facade.js

@@ -9,6 +9,13 @@ const projectType = {
 };
 //先导出后require可以解决循环引用问题
 module.exports={
+    prepareShareList,
+    getShareList,
+    addShareList,
+    updateShareList,
+    deleteShareList,
+    getShareInfoMap,
+    getRecentShareList,
     moveProject:moveProject,
     copyProject:copyProject,
     copyExample: copyExample,
@@ -84,6 +91,7 @@ let contractorListModel = mongoose.model("contractor_list");
 let featureLibModel =  mongoose.model("std_project_feature_lib");
 let importLogsModel = mongoose.model("import_logs");
 const overHeightLibModel = mongoose.model('std_over_height_lib');
+const shareListModel = mongoose.model('share_list');
 let scMathUtil = require('../../../public/scMathUtil').getUtil();
 let counter = require('../../../public/counter/counter');
 import SectionTreeDao from '../../complementary_ration_lib/models/sectionTreeModel';
@@ -120,6 +128,138 @@ let qiniu_config = {
 };
 let mac = new qiniu.auth.digest.Mac(qiniu_config.AccessKey, qiniu_config.SecretKey);
 
+// 重构了分享的数据结构,原本存在projects表的shareInfo数组中
+// 为了更好地适应新功能及以后拓展功能,现将分享信息存放在单独的share_list表中
+// 为了适应旧数据,需要在share_list没有数据的时候,将原本的分享信息复制到share_list中,同时生成联系人
+// TODO: 上线后这个方法执行过后,应该删除此方法
+async function prepareShareList() {
+    const shareListCount = await shareListModel.count({});
+    console.log(shareListCount);
+    if (shareListCount) {
+        return;
+    }
+    logger.info('================================enterPrepareShareList================================================');
+    // 将项目的shareInfo数据复制到share_list表中
+    const projects = await projectModel.find({'shareInfo.0': {$exists: true}}, '-_id ID userID shareInfo').lean();
+    if (!projects.length) {
+        return;
+    }
+    const shareList = [];
+    const userMap = {}; // 给生成联系人做准备
+    projects.forEach(project => {
+        const ownerContacts = userMap[project.userID] || (userMap[project.userID] = []);
+        project.shareInfo.forEach(shareItem => {
+            if (!shareItem.shareDate) {
+                return;
+            }
+            const receiverContacts = userMap[shareItem.userID] || (userMap[shareItem.userID] = []);
+            receiverContacts.push(project.userID);
+            const newItem = {
+                ID: uuidV1(),
+                projectID: project.ID,
+                owner: project.userID,
+                receiver: shareItem.userID,
+                allowCopy: shareItem.allowCopy,
+                allowCooperate: shareItem.allowCooperate,
+                shareDate: shareItem.shareDate,
+                updateDate: shareItem.shareDate
+            };
+            ownerContacts.push(shareItem.userID);
+            shareList.push(newItem);
+        });
+    });
+    // 插入分享信息
+    const shareListPromise = shareListModel.insertMany(shareList);
+    const tasks = [shareListPromise];
+    // 更新用户信息
+    const userTasks = [];
+    Object.entries(userMap).forEach(([userID, contacts]) => {
+        contacts = [...new Set(contacts)]
+            .map(user => ({ userID: user }));
+        const task = {
+            updateOne: {
+                filter: {
+                    _id: mongoose.Types.ObjectId(userID)
+                },
+                update: {
+                    contacts
+                }
+            }
+        };
+        userTasks.push(task);
+    });
+    if (userTasks.length) {
+        tasks.push(userModel.bulkWrite(userTasks));
+    }
+    await Promise.all(tasks);
+}
+
+
+// 获取分享列表
+async function getShareList(query) {
+    return await shareListModel.find(query, '-_id').lean();
+}
+
+async function addShareList(docs) {
+    await shareListModel.insertMany(docs);
+}
+
+async function deleteShareList(query) {
+    await shareListModel.deleteMany(query);
+}
+
+async function updateShareList(updateData) {
+    const bulks = updateData.map(item => (
+        {
+            updateOne: {
+                filter: item.query,
+                update: item.update
+            }
+        }
+    ));
+    if (bulks.length) {
+        await shareListModel.bulkWrite(bulks);
+    }
+}
+
+// 根据项目ID获取项目shareInfo字段的数据映射(前端旧逻辑依赖项目本身的shareInfo字段)
+async function getShareInfoMap(projectIDs, shareList = null) {
+    if (!shareList) {
+        shareList = await getShareList({projectID: {$in: projectIDs}});
+    }
+    // 将相同项目的分享信息进行映射
+    const map = {};
+    shareList.forEach(item => {
+        const shareInfo = map[item.projectID] || (map[item.projectID] = []);
+        shareInfo.push({
+            userID: item.receiver,
+            shareDate: item.shareDate,
+            updateDate: item.updateDate,
+            allowCopy: item.allowCopy,
+            allowCooperate: item.allowCooperate
+        });
+    });
+    return map;
+}
+
+// 获取最近分享(只算分享出去的记录)
+async function getRecentShareList(userID, count) {
+    const shareList = await getShareList({owner: userID});
+    shareList.sort((a, b) => Date.parse(b.shareDate) - Date.parse(a.shareDate));
+    const set = new Set();
+    for(const item of shareList) {
+        if (set.size === count) {
+            break;
+        }
+        set.add(item.receiver);
+    }
+    const sortedIDList = [...set];
+    const userIDList = sortedIDList.map(userID => mongoose.Types.ObjectId(userID));
+    const users = await userModel.find({_id: {$in: userIDList}}, 'real_name mobile company').lean();
+    users.sort((a, b) => sortedIDList.indexOf(a._id.toString()) - sortedIDList.indexOf(b._id.toString()));
+    return users;
+}
+
 //拷贝例题项目
 //@param {String}userID {Array}projIDs拷贝的例题项目ID(建设项目、文件夹)@return {Boolean}
 async function copyExample(userID, compilation, projIDs){
@@ -127,7 +267,7 @@ async function copyExample(userID, compilation, projIDs){
         IDMapping = {},
         projMapping = {};
     //例题项目不可为单项工程、单位工程、只能是建设项目、文件夹,否则不自动新建例题项目(这里不报错,让用户没有感觉)
-    let parentExample = await projectModel.find({ID: {$in: projIDs}, $or: notDeleted});
+    let parentExample = await projectModel.find({ID: {$in: projIDs}, $or: notDeleted}).lean();
     if (parentExample.length === 0) {
         return false;
     }
@@ -168,7 +308,7 @@ async function copyExample(userID, compilation, projIDs){
         data.compilation = compilation;
         data.shareInfo = [];
         if (data.projType !== projectType.tender) {
-            let newData = _.cloneDeep(data._doc);
+            let newData = _.cloneDeep(data);
             delete newData._id;
           //  await projectModel.create(newData);
             parentBulks.push({insertOne: {document: newData}});
@@ -1066,13 +1206,24 @@ async function getFullPath(projectID) {
     }
 }
 
+// 获取项目链上,自身、父项、爷爷项...的ID
+async function getUpChainIDs(projectID) {
+    const rst = [];
+    while (projectID != -1) {
+        rst.push(projectID);
+        const project = await projectModel.findOne({ ID: projectID }, '-_id ParentID').lean();
+        projectID = project ? project.ParentID : -1;
+    }
+    return rst;
+}
+
 //获取projectIDs文件下所有子项目(不包括projectIDs本身)
 async function getPosterityProjects(projectIDs) {
     let rst = [];
     async function getProjects(parentIDs) {
         if (parentIDs.length > 0) {
             let newIDs = [];
-            let projs = await projectModel.find({ParentID: {$in: parentIDs}, $or: notDeleted}, '-_id');
+            let projs = await projectModel.find({ParentID: {$in: parentIDs}, $or: notDeleted}, '-_id').lean();
             for (let proj of projs) {
                 // 兼容旧的错误数据,可能ParentID和ID相同
                 if (parentIDs.includes(proj.ID)) {
@@ -1089,31 +1240,13 @@ async function getPosterityProjects(projectIDs) {
 }
 
 //根据项目获得分享信息(分享层级不一定在项目级)(以最新为准)
-//@param {String}userId {Object}tender @return {Object} || {null}
-async function getShareInfo(userId, project) {
-    //与该用户相关的分享
-    let shareList = [];
-    while (project) {
-        for(let shareData of project.shareInfo){
-            if(shareData.userID === userId){
-                shareList.push(shareData);
-                break;
-            }
-        }
-        project = await projectModel.findOne({ID: project.ParentID}, '-_id shareInfo ID ParentID');
-    }
-    //获取最新分享
-    shareList.sort(function (a, b) {
-        let aV = Date.parse(a.shareDate),
-            bV = Date.parse(b.shareDate);
-        if (aV > bV) {
-            return -1;
-        } else if (aV < bV) {
-            return 1;
-        }
-        return 0;
-    });
-    return shareList[0] || null;
+async function getShareInfo(userID, projectID) {
+    // 接受到的分享项目
+    const upChainIDs = await getUpChainIDs(projectID);
+    const shareList = await getShareList({receiver: userID, projectID: {$in: upChainIDs}});
+    // 返回最新的分享
+    //return shareList.sort((a, b) => Date.parse(b.shareDate) - Date.parse(a.shareDate))[0];
+    return shareList.sort((a, b) => Date.parse(b.updateDate) - Date.parse(a.updateDate))[0];
 }
 
 //打开的单位工程是否是被分享的.
@@ -2175,11 +2308,10 @@ async function isTenderOverrun(tenderCount, session) {
     const userID = session.sessionUser.id;
     const compilation = session.sessionCompilation._id;
     const compilationVersion = session.compilationVersion || '免费';
-    let systemSetting = session.systemSetting;
+    let systemSetting = session.systemSetting || (session.systemSetting = await systemSettingMiddleware.getSystemSetting());
     // 这种情况只有在刚上线此功能时会出现,不考虑时间差
     if (!systemSetting) {
-        systemSetting = await systemSettingMiddleware.getSystemSetting();
-        session.systemSetting = systemSetting;
+        return false;
     }
     const type = compilationVersion.includes('免费') ? 'normal' : 'professional';
     const limit = systemSetting[type].project;

+ 12 - 1
modules/pm/models/project_model.js

@@ -69,13 +69,20 @@ ProjectsDAO.prototype.getUserProjects = async function (userId, compilation, cal
             }, {'userID': userId, 'compilation': compilation, 'deleteInfo.deleted': {'$in': [null, false]}}]
         }, '-_id', {lean: true});
         let projIDs= [];
+        const allIDs = [];
         for(let project of projects){
+            allIDs.push(project.ID);
             if(project.projType === projectType.project){
                 projIDs.push(project.ID);
             }
         }
+        // 设置分享信息 
+        const shareMap = await pmFacade.getShareInfoMap(allIDs);
+        projects.forEach(project => {
+            project.shareInfo = shareMap[project.ID] || [];
+        });
+        // 设置汇总字段
         let summaryInfo = await pmFacade.getSummaryInfo(projIDs);
-        //设置汇总字段
         for(let proj of projects){
             let summaryProj = summaryInfo[proj.ID];
             if(summaryProj){
@@ -185,6 +192,10 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     if(data.updateData.property.isInstall == true || data.updateData.property.isInstall=='true'){//判断是否安装工程
                         await installationFacade.copyInstallationFeeFromLib(data.updateData.ID,data.updateData.property.engineering_id);
                     }
+                    //子目增加费
+                    if(data.updateData.property.isItemIncrease == true || data.updateData.property.isItemIncrease=='true'){//判断是否需计算子目增加费
+                        projectFacade.setDefaultItemIncrease(data.updateData.property);
+                    }
                     //锁定清单
                     data.updateData.property.lockBills = false;
                     //工料机单价调整系数

+ 1 - 0
modules/pm/routes/pm_route.js

@@ -59,6 +59,7 @@ module.exports = function (app) {
     pmRouter.post('/delGC', pmController.delGC);
     //share
     pmRouter.post('/getProjectShareInfo', pmController.projectShareInfo);
+    pmRouter.post('/getRecentShareInfo', pmController.getRecentShareInfo);
     pmRouter.post('/share', pmController.share);
     pmRouter.post('/receiveProjects', pmController.receiveProjects);
     pmRouter.post('/changeFile', pmController.changeFile);

+ 37 - 5
modules/ration_glj/facade/glj_calculate_facade.js

@@ -10,6 +10,7 @@ let ration = mongoose.model('ration');
 let ration_coe = mongoose.model('ration_coe');
 let std_ration_lib_ration_items = mongoose.model('std_ration_lib_ration_items');
 let std_glj_lib_gljList_model = mongoose.model('std_glj_lib_gljList');
+let project_model = mongoose.model('projects');
 let glj_type_util = require('../../../public/cache/std_glj_type_util');
 const scMathUtil = require('../../../public/scMathUtil').getUtil();
 let decimal_facade = require('../../main/facade/decimal_facade');
@@ -19,7 +20,7 @@ module.exports={
     calculateQuantity:calculateQuantity,
     getGLJTypeByID:getGLJTypeByID
 }
-//辅助定额调整、替换工料机、标准附注条件调整、添加工料机、自定义消耗量(包括删除工料机)、自定义乘系数、市场单价调整
+//辅助定额调整、替换工料机、标准附注条件调整、添加工料机、自定义消耗量(包括删除工料机)、自定义乘系数、面积增加、市场单价调整
 let stateSeq ={
     ass:1,
     replace:2,
@@ -27,7 +28,8 @@ let stateSeq ={
     add:4,
     cusQuantity:5,
     cusCoe:6,
-    adjMak:7
+    area:7,
+    adjMak:8
 };
 //自定义乘系数与定额工料机类型映射表
 let coeTypeMap = {
@@ -40,7 +42,7 @@ let coeTypeMap = {
 };
 
 
-async function calculateQuantity(query,noNeedCal,refreshRationName = false){
+async function calculateQuantity(query,noNeedCal,refreshRationName = false,areaIncreaseFee,areaSetting){
     try {
          let  result ={
              glj_result:[],
@@ -55,6 +57,7 @@ async function calculateQuantity(query,noNeedCal,refreshRationName = false){
          if(!impactRation){//如果定额不存在或者已删除,返回空
              return null;
          }
+        if(areaIncreaseFee !== null && areaIncreaseFee !== undefined) impactRation.areaIncreaseFee = areaIncreaseFee;
          if(impactRation._doc.hasOwnProperty("rationAssList")&&impactRation.rationAssList.length>0){
              let temTimes = [];
              let thirdRationCodes=[];
@@ -89,6 +92,8 @@ async function calculateQuantity(query,noNeedCal,refreshRationName = false){
          if(noNeedCal==null && result.glj_result.length > 0){
             await ration_glj.bulkWrite(generateUpdateTasks(result.glj_result));
          }
+         if(impactRation.areaIncreaseFee == true) await setAreaAdjustState(impactRation.projectID,adjustState,areaSetting);
+
          adjustState= _.sortByOrder(adjustState, ['index'], ['asc']);
          adjustState=_.map(adjustState, _.property('content'));
          let adjustStateString = adjustState.join(';');
@@ -98,7 +103,8 @@ async function calculateQuantity(query,noNeedCal,refreshRationName = false){
              setData.name = newName;
              result.rationName = newName;
          }
-         await ration.update({ID:query.rationID},setData);
+         //如果uareaIncreaseFee有值说明是从其它更新定额的地方进来的,后面会一起更新
+         if(areaIncreaseFee === null || areaIncreaseFee === undefined) await ration.update({ID:query.rationID},setData);
          result.adjustState=adjustStateString;
          return result;
     }catch (err){
@@ -107,6 +113,31 @@ async function calculateQuantity(query,noNeedCal,refreshRationName = false){
     }
 }
 
+async function setAreaAdjustState(projectID,adjustState,areaSetting){
+    if(!areaSetting){
+        let project =  await project_model.findOne({ID:projectID},'property.areaSetting');
+        areaSetting = project.property.areaSetting;
+    }
+    if(areaSetting){
+        let stringArr = [];
+        let labour = getStr(areaSetting.labour);
+        let material = getStr(areaSetting.material);
+        let machine  = getStr(areaSetting.machine);
+        if(labour !="") stringArr.push(`人工*${labour}`);
+        if(material !="") stringArr.push(`材料*${material}`);
+        if(machine !="") stringArr.push(`机械*${machine}`);
+        if(stringArr.length > 0){
+            adjustState.push({index:stateSeq.area,content:`面积:${stringArr.join(',')}`});//面积:人工*1.1,材料*1.015”。
+        }
+    }
+
+    function getStr(num) {
+        if(num != 0) return 1 + num/100;
+        return "";
+    }
+
+}
+
 function quantityUpdateCheck(glj,r) {//检查,有改变的才更新
     for(let key in r.doc){
         if(glj._doc[key] != r.doc[key]) return true
@@ -259,7 +290,8 @@ function generateAdjustState(glj,coeList,adjustState,gljList,quantity) {
         for(let i=0;i<coeList.length;i++){
             if(coeList[i].isAdjust==1){
                 if(i==coeList.length-1){
-                    adjustState.push({index:stateSeq.cusCoe,content:getContent(coeList[i].coes)});//自定义乘系数要去掉倍数为1的
+                    let cus_content = getContent(coeList[i].coes);
+                    if(cus_content !="") adjustState.push({index:stateSeq.cusCoe,content:cus_content});//自定义乘系数要去掉倍数为1的
                 }else {
                     if(coeList[i].select_code && coeList[i].select_code!=""){
                         _.remove(adjustState,{'content':coeList[i].original_code+'换'+coeList[i].select_code});//去掉替换工料机自动生成的调整状态

+ 2 - 1
modules/templates/controllers/bills_template_controller.js

@@ -51,7 +51,8 @@ module.exports = {
             callback(req, res, 0, 'succes', mapping);
         } catch (err) {
             console.log(err);
-            callback(req, res, 1, err, null);
+            const msg = err.message || err;
+            callback(req, res, 1, msg, null);
         }
     }
 }

+ 4 - 2
modules/templates/models/bills_template.js

@@ -103,7 +103,8 @@ function setSeqByNext(billsData) {
         sameDepthDatas[data.ParentID].push(data);
     }
     //设置同层节点的序号
-    for (let sameDepth of Object.values(sameDepthDatas)) {
+    for (let attr in sameDepthDatas) {
+        let sameDepth = sameDepthDatas[attr];
         let sortedData = getDataBySorted(sameDepth),
             seq = 1;
         sortedData.forEach((data => data.seq = seq++));
@@ -136,7 +137,8 @@ function sortSeqToNextSibling(needfulData) {
         }
         sameDepthDatas[data.ParentID].push(data);
     }
-    for (let sameDepth of Object.values(sameDepthDatas)) {
+    for (let attr in sameDepthDatas) {
+        let sameDepth = sameDepthDatas[attr];
         sameDepth.sort((a, b) => a.seq - b.seq);
         for (let i = 0; i < sameDepth.length; i++) {
             let cur = sameDepth[i],

+ 2 - 0
modules/users/controllers/login_controller.js

@@ -71,6 +71,7 @@ class LoginController {
                     username: userData.username,
                     email: userData.useremail,
                     mobile: userData.mobile,
+                    qq: userData.qq,
                     isUserActive: userData.isUserActive,
                 };
 
@@ -252,6 +253,7 @@ class LoginController {
                 username: userData.username,
                 email: userData.useremail,
                 mobile: userData.mobile,
+                qq: userData.qq,
                 isUserActive: userData.isUserActive,
             };
 

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

@@ -173,6 +173,7 @@ class UserModel extends BaseModel {
                 email : userData.email,
                 mobile : userData.mobile,
                 ssoId : userData.ssoId,
+                qq: userData.qq,
                 latest_login:userData.latest_login,
                 isUserActive: userData.isUserActive,
             };
@@ -355,6 +356,37 @@ class UserModel extends BaseModel {
         }
         return free
     }
+
+    /*
+    * 添加联系人,互相添加
+    */
+    async addContact(userID, contactID) {
+        const data = [
+            { user: userID, contact: contactID },
+            { user: contactID, contact: userID }
+        ];
+        const task = [];
+        for (const { user, contact } of data) {
+            const hasThisContact = await this.model.count({_id: mongoose.Types.ObjectId(user), 'contacts.userID': contact});
+            // 没有则添加
+            if (!hasThisContact) {
+                task.push(this.model.update({_id: mongoose.Types.ObjectId(user)}, {$push: {contacts: {userID: contact}}}));
+            }
+        }
+        if (task.length) {
+            await Promise.all(task);
+        }
+    }
+
+    async getContacts(userID) {
+        const user = await this.model.findOne({_id: mongoose.Types.ObjectId(userID)}, 'contacts').lean();
+        if (!user) {
+            return [];
+        }
+        const userIDList = user.contacts.map(item => mongoose.Types.ObjectId(item.userID));
+        const users = await this.model.find({_id: {$in: userIDList}}, 'real_name mobile company');
+        return users;
+    }
 }
 
 export default UserModel;

+ 3 - 0
public/web/gljUtil.js

@@ -432,6 +432,7 @@ let gljUtil = {
         for(let e of economics){
             let tem = {
                 name:e.name,
+                exportName:e.exportName,
                 cost:0,
                 unitCost:0,
                 per:0
@@ -515,6 +516,7 @@ let gljUtil = {
             let tem = {
                 name:m.name,
                 unit:m.unit,
+                exportName:m.exportName,
                 unitPrice:0,
                 quantity:0,
                 unitIndex:0
@@ -550,6 +552,7 @@ let gljUtil = {
             let tem = {
                 name : m.name,
                 quantityIndexUnit:m.unit,
+                exportName:m.exportName,
                 quantity:0
             };
             if(billsGroup[m.name]) setQuantities(billsGroup[m.name],tem);

+ 12 - 0
public/web/id_tree.js

@@ -410,6 +410,18 @@ var idTree = {
             }
             return null;
         };
+        // 节点是否属于某些固定ID,会一直向上找,直到找到或到达顶层
+        Node.prototype.isBelongToFlags = function (flags) {
+            let node = this;
+            while (node) {
+                const flag = node.getFlag();
+                if (flags.includes(flag)) {
+                    return true;
+                }
+                node = node.parent;
+            }
+            return false;
+        }
         // 获取节点所有后代节点
         Node.prototype.getPosterity = function() {
             let posterity = [];

+ 5 - 0
public/web/number_util.js

@@ -33,5 +33,10 @@ var  number_util = {
             value = scMathUtil.roundTo(Number(obj),-decimal);
         }
         return value.toFixed(decimal);
+    },
+    isNum(thisValue){
+        var regPos = /^\d+(\.\d+)?$/; //非负浮点数
+        var regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; //负浮点数
+        return (regPos.test(thisValue) || regNeg.test(thisValue));
     }
 }

+ 10 - 3
public/web/sheet/sheet_common.js

@@ -379,7 +379,7 @@ var sheetCommonObj = {
             }
             sheet.setValue(row, col, val, ch);
             if(data[row].foreColor && data[row].styleCol == col){
-                sheet.setStyle(row, col, {foreColor: "#ff2a23"});
+                sheet.setStyle(row, col, {foreColor: data[row].foreColor});
             }
         }
         this.setRowStyle(row,sheet,data[row].bgColour);
@@ -1353,8 +1353,7 @@ var sheetCommonObj = {
     //设置默认样式
     spreadDefaultStyle: function (workBook) {
         let defaultStyle = new GC.Spread.Sheets.Style();
-        defaultStyle.font = '14px Calibri';
-        let sheetCount = workBook.getSheetCount();
+        defaultStyle.font = '14px Calibri';let sheetCount = workBook.getSheetCount();
         for(let i = 0; i < sheetCount; i++){
             let sheet = workBook.getSheet(i);
             sheet.setDefaultStyle(defaultStyle, GC.Spread.Sheets.SheetArea.viewport);
@@ -1477,5 +1476,13 @@ var sheetCommonObj = {
         if (workbook) {
             setTimeout(() => workbook.refresh(), time);
         }
+    },
+    setRowsAutoFit(sheet, rows, col, wordWrap) {
+        console.time('rowFit');
+        rows.forEach(row => {
+            sheet.getCell(row, col).wordWrap(wordWrap);
+            sheet.autoFitRow(row);
+        });
+        console.timeEnd('rowFit');
     }
 }

+ 2 - 2
public/web/slideResize.js

@@ -207,8 +207,8 @@ const SlideResize = (function() {
         let topHeight = getLocalCache(`${module}${eleObj.top.attr('id')}Height`),
             bottomHeight = getLocalCache(`${module}${eleObj.bottom.attr('id')}Height`);
         //默认上下比例
-        const topProp = 5;
-        const bottomProp = 2;
+        const topProp = 2;
+        const bottomProp = 1;
         let topProportion = topProp / (topProp + bottomProp);
         if (topHeight !== null && bottomHeight !== null) {
             topHeight = parseFloat(topHeight);

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 438 - 535
web/building_saas/css/main.css


+ 3 - 15
web/building_saas/main/html/calc_program_manage.html

@@ -9,26 +9,14 @@
 </head>
 
 <body>
-    <div style="">
-    </div>
-    <div class="toolsbar px-1" />
+    <div class="toolsbar px-1" style="height:30px;width:100%;line-height:30px;font-size:15px;">总计算程序-设置</div>
     <div class="container-fluid">
-        <div style="height:35px;width:100%;line-height:35px;font-size:15px;">总计算程序-设置</div>
         <div class="row">
             <div class="col-lg-2 p-0">
-<!--                <div id="divSelect" style="text-align:left;height:45px;line-height:45px;">
-                    &lt;!&ndash;<label>计算程序文件:</label>&ndash;&gt;
-                    <select id='calcProgramFileSelect' style="width:98%;height:30px;">
-                        <option value="none">无</option>
-                        <option value="1" selected>计算程序2013标准</option>
-                        <option value="2">计算程序2018标准</option>
-                    </select>
-                </div>-->
-                <div class="main-data-not" id="mainSpread"></div>
+                <div class="grid main-data-full" id="mainSpread"></div>
             </div>
             <div class="col-lg-10 p-0">
-                <div class="main-data-not" id="detailSpread">
-                </div>
+                <div class="grid main-data-full" id="detailSpread"></div>
             </div>
         </div>
     </div>

+ 60 - 0
web/building_saas/main/html/main.html

@@ -2278,6 +2278,64 @@
     </div>
 </div>
 
+
+<!--弹出 面积增加费窗口-->
+<div class="modal fade" id="areaIncreaseFeeDiv" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">建筑面积500m2以下的调整</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <fieldset class="form-group"  style="border:1px solid #b3b3b3;padding: 15px">
+                    <legend class="legend" style="font-size:16px">设置系数</legend>
+                    <div style="margin-top:-20px">请输入调整的百分比比例,0代表不调整,负数表示下调(不小于-100)</div>
+                    <br>
+                    <div class="form-group">
+                        <label >人工(%)</label>
+                        <input class="form-control" id="areaIncreaseFee_labour" value="">
+                        <label >材料(%)</label>
+                        <input class="form-control" id="areaIncreaseFee_material" value="">
+                        <label >机械(%)</label>
+                        <input class="form-control" id="areaIncreaseFee_machine" value="">
+                    </div>
+                </fieldset>
+
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-primary" id="areaIncreaseFeeConfirm">确定</button>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+<!--弹出 子目增加费窗口-->
+<div class="modal fade" id="itemIncreaseFeeDiv" data-backdrop="static">
+    <div class="modal-dialog " style="max-width:600px" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">统一设置子目增加费</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body" style="height: 200px;padding: 0px">
+                <div class="ovf-hidden full-h" id="itemIncreaseFee_sheet"></div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-primary" data-dismiss="modal" id="itemIncreaseFeeConfirm">确定</button>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+
+
     <img src="/web/dest/css/img/folder_open.png" id="folder_open_pic" style="display: none">
     <img src="/web/dest/css/img/folder_close.png" id="folder_close_pic" style="display: none">
     <img src="/web/dest/css/img/project.png" id="proj_pic" style="display: none">
@@ -2409,6 +2467,8 @@
     <script type="text/javascript" src='/web/building_saas/main/js/views/confirm_modal.js'></script>
     <script type="text/javascript" src='/web/building_saas/main/js/views/zlfb_view.js'></script>
     <script type="text/javascript" src='/web/building_saas/main/js/views/installation_fee_view.js'></script>
+    <script type="text/javascript" src='/web/building_saas/main/js/views/area_increase_fee_view.js'></script>
+    <script type="text/javascript" src='/web/building_saas/main/js/views/item_increase_fee_view.js'></script>
     <script type="text/javascript" src='/web/building_saas/main/js/views/material_adjust_view.js'></script>
     <script type="text/javascript" src='/web/building_saas/main/js/views/config_material_view.js'></script>
     <script type="text/javascript" src='/web/building_saas/main/js/views/index_view.js'></script>

+ 12 - 0
web/building_saas/main/js/models/bills.js

@@ -623,6 +623,18 @@ var Bills = {
             }
             return techMeasureCheck(node);
         };
+        // 相关固定类别清单部分,【不】允许清单自身计算得到合价: “数量 * 单价 = 合价”
+        // 删除【不】允许通过自身数据计算的清单的定额时,该清单价格【会清空】
+        // 这种清单的单价和合价都是只读的
+        bills.prototype.cantCalcToTalFeeByOwn = function (node) {
+            const flags = [
+                fixedFlag.SUB_ENGINERRING,
+                fixedFlag.CONSTRUCTION_TECH,
+                fixedFlag.GREEN_MEASURE_FEE,
+                fixedFlag.OTHER_MEASURE_FEE,
+            ];
+            return node.isBelongToFlags(flags);
+        };
 
         bills.prototype.isEngineeringCost = function (node) {//判断这个节点是否是工程造价节点
             if(isFlag(node.data)&&node.data.flagsIndex.fixed.flag==fixedFlag.ENGINEERINGCOST){

+ 12 - 0
web/building_saas/main/js/models/cache_tree.js

@@ -312,6 +312,18 @@ var cacheTree = {
             }
             return null;
         };
+        // 节点是否属于某些固定ID,会一直向上找,直到找到或到达顶层
+        Node.prototype.isBelongToFlags = function (flags) {
+            let node = this;
+            while (node) {
+                const flag = node.getFlag();
+                if (flags.includes(flag)) {
+                    return true;
+                }
+                node = node.parent;
+            }
+            return false;
+        }
         // 获取节点所有后代节点
         Node.prototype.getPosterity = function() {
             let posterity = [];

+ 20 - 2
web/building_saas/main/js/models/calc_program.js

@@ -179,7 +179,10 @@ let calcTools = {
         return projectObj.project.Bills.isFBFX(treeNode);
     },
     isTechMeasure:function(treeNode){
-       return projectObj.project.Bills.isTechMeasure(treeNode)
+        return projectObj.project.Bills.isTechMeasure(treeNode)
+    },
+    canCalcToTalFeeByOwn: function (treeNode) {
+        return !projectObj.project.Bills.cantCalcToTalFeeByOwn(treeNode);
     },
     getChildrenFormulaNodes: function (self, allFormulaNodesArr, parentNodes){       // 获取结点parentNodes下有公式的子结点
         let nodes = [];
@@ -406,6 +409,17 @@ let calcTools = {
                         if (priceType == priceTypes.ptBasePrice){ price = me.uiGLJPrice(glj["basePrice"], glj);}
                         else if (priceType == priceTypes.ptAdjustPrice){price = aprice;}
                         else if (priceType == priceTypes.ptMarketPrice){price = mprice;}
+                        if (projectObj.project.property.areaSetting && treeNode.data.areaIncreaseFee){
+                            let p;
+                            if ([gljType.LABOUR].includes(glj.type))
+                                p = projectObj.project.property.areaSetting.labour
+                            else if (baseMaterialTypes.includes(glj.type))
+                                p = projectObj.project.property.areaSetting.material
+                            else if ([gljType.GENERAL_MACHINE].includes(glj.type))
+                                p = projectObj.project.property.areaSetting.machine;
+                            qty = qty * (1 + p * 0.01).toDecimal(decimalObj.process);
+                        }
+
                         temp = (qty * price).toDecimal(decimalObj.process);
                         result = (result + temp).toDecimal(decimalObj.process);
                     };
@@ -1851,12 +1865,16 @@ class CalcProgram {
 
             // 第1、2部分以外的叶子清单在没有公式的情况下可以手工修改综合单价并参与计算。
             // 2017-09-27 需求改了,除了第 1 、 2.2部分以外,都可以手工修改综合单价、综合合价并参与计算
-            if(!calcTools.isFBFX(treeNode) && !calcTools.isTechMeasure(treeNode)){ // if(!calcTools.isInheritFrom(treeNode, [fixedFlag.SUB_ENGINERRING, fixedFlag.MEASURE]))
+            //if(!calcTools.isFBFX(treeNode) && !calcTools.isTechMeasure(treeNode)){ // if(!calcTools.isInheritFrom(treeNode, [fixedFlag.SUB_ENGINERRING, fixedFlag.MEASURE]))
+            // 在没有公式的情况下可以手工修改综合单价并参与计算
+            if(calcTools.canCalcToTalFeeByOwn(treeNode)){
                 if (treeNode.data.feesIndex && treeNode.data.feesIndex.common){
                     let ftObj = {};
                     ftObj.fieldName = 'common';
                     ftObj.unitFee = parseFloatPlus(treeNode.data.feesIndex.common.unitFee);
                     ftObj.totalFee = (ftObj.unitFee * nQ).toDecimal(decimalObj.bills.totalPrice);
+                    ftObj.tenderUnitFee = ftObj.unitFee;
+                    ftObj.tenderTotalFee = (ftObj.tenderUnitFee * nTQ).toDecimal(decimalObj.bills.totalPrice);
                     calcTools.checkFeeField(treeNode, ftObj);
                 }
             } else{

+ 3 - 3
web/building_saas/main/js/models/exportSEIInterface.js

@@ -36,11 +36,11 @@ async function exportSEI(projectID) {
     let project = getProject(result);
     await prepareTenderDatas(tenderProjects,project);
 
-
     if(!_.isEmpty(errorMap)){
         showError(errorMap);
         return pr.end();
     }
+
     toXml(project);
 
     pr.end();
@@ -112,7 +112,7 @@ async function exportSEI(projectID) {
             valuationType:source.property.valuationType,
             taxType:source.property.taxType,
             property:source.property,
-            name:source.name
+            projectName:source.name
         };
         return tender;
     }
@@ -315,7 +315,7 @@ async function exportSEI(projectID) {
     function setEngineerInfo(tender) {//设置工程信息
         let infos = tender.property.engineerInfos?tender.property.engineerInfos:[];
         let errors =  infoRequireChecking(infos);
-        if(errors.length > 0) errorMap[tender.name] = errors;
+        if(errors.length > 0) errorMap[tender.projectName] = errors;
         let info = {
             name:"工程信息",
             attrs:[

+ 270 - 265
web/building_saas/main/js/models/exportStdInterface_gd18.js

@@ -148,7 +148,7 @@ const XMLStandard = (function () {
     const GLJKind = {
     };
     // 供料方式
-    const Provider ={
+    const Provider = {
     }
 
     // 通用设置和工具
@@ -171,47 +171,52 @@ const XMLStandard = (function () {
         function ConstructionProject(src) {
             const attrs = [
                 // 项目编号
-                {name: 'Number', dName: '项目编号', value: '', required: true},
+                { name: 'Number', dName: '项目编号', value: '', required: true },
                 // 项目名称
-                {name: 'Name', dName: '项目名称', value: src.name, required: true},
+                { name: 'Name', dName: '项目名称', value: src.name, required: true },
                 // 工程类别
-                {name: 'ProjectCategory', dName: '工程类别', value: _util.getValueByKey(src.basicInformation, 'projectCategory'), required: true},
+                { name: 'ProjectCategory', dName: '工程类别', value: _util.getValueByKey(src.basicInformation, 'projectCategory'), required: true },
                 // 工程类型
-                {name: 'ProjectType', dName: '工程类型', value: src.projectType, required: true},
+                { name: 'ProjectType', dName: '工程类型', value: src.projectType, required: true },
                 // 建设性质
-                {name: 'ConstructionType', value: ConstructionType[_util.getValueByKey(src.basicInformation, 'projectCategory')], type: _type.INT,
-                 enumeration: Object.keys(ConstructionType)
+                {
+                    name: 'ConstructionType', value: ConstructionType[_util.getValueByKey(src.basicInformation, 'projectCategory')], type: _type.INT,
+                    enumeration: Object.keys(ConstructionType)
                 },
                 // 文件类型 todo
-                {name: 'FileKind', dName: '造价类型', value: CostType[_util.getValueByKey(src.basicInformation, 'costType')], type: _type.INT, required: true,
-                 enumeration: Object.keys(CostType)},
+                {
+                    name: 'FileKind', dName: '造价类型', value: CostType[_util.getValueByKey(src.basicInformation, 'costType')], type: _type.INT, required: true,
+                    enumeration: Object.keys(CostType)
+                },
                 // 计价模式
-                {name: 'ValuationModel', dName: '计价模式', value: ValuationModel.bill, type: _type.INT, required: true},
+                { name: 'ValuationModel', dName: '计价模式', value: ValuationModel.bill, type: _type.INT, required: true },
                 // 计税模式
-                {name: 'TaxModel', dName: '计税模式', value: src.taxType, type: _type.INT, required: true},
+                { name: 'TaxModel', dName: '计税模式', value: src.taxType, type: _type.INT, required: true },
                 // 地区类别 todo
-                {name: 'AreaKind', dName: '地区类别', value: AreaKind[_util.getValueByKey(src.basicInformation, 'areaKind')], type: _type.INT, required: true,
-                 enumeration: Object.keys(AreaKind)},
+                {
+                    name: 'AreaKind', dName: '地区类别', value: AreaKind[_util.getValueByKey(src.basicInformation, 'areaKind')], type: _type.INT, required: true,
+                    enumeration: Object.keys(AreaKind)
+                },
                 // 工程地点
-                {name: 'ProjectSite', value: _util.getValueByKey(src.basicInformation, '"projLocation"')},
+                { name: 'ProjectSite', value: _util.getValueByKey(src.basicInformation, '"projLocation"') },
                 // 建设单位
-                {name: 'BuildUnit', dName: '建设单位', value: _util.getValueByKey(src.basicInformation, 'constructionUnit'), required: true},
+                { name: 'BuildUnit', dName: '建设单位', value: _util.getValueByKey(src.basicInformation, 'constructionUnit'), required: true },
                 // 建设单位法定代表人或其授权人 todo
-                {name: 'BulidAuthorizer', value: _util.getValueByKey(src.basicInformation, 'todo')},
+                { name: 'BulidAuthorizer', value: _util.getValueByKey(src.basicInformation, 'todo') },
                 // 数据交换标准名称
-                {name: 'StandardName', value: '建设工程政府投资项目造价数据标准', required: true},
+                { name: 'StandardName', value: '建设工程政府投资项目造价数据标准', required: true },
                 // 数据交换标准编号
-                {name: 'StandardNumber', value: 'DBJ/T XX-XX-2018', required: true},
+                { name: 'StandardNumber', value: 'DBJ/T XX-XX-2018', required: true },
                 // 建设(编制)范围 todo
-                {name: 'RangeOfCompilation', value: ''},
+                { name: 'RangeOfCompilation', value: '' },
                 // 建设规模
-                {name: 'Scale', dName: '工程规模', value: _util.getValueByKey(src.basicInformation, 'projectScale'), type: _type.DECIMAL, required: true},
+                { name: 'Scale', dName: '工程规模', value: _util.getValueByKey(src.basicInformation, 'projectScale'), type: _type.DECIMAL, required: true },
                 // 建设规模单位 todo add key
-                {name: 'Unit', dName: '建设规模单位', value: _util.getValueByKey(src.basicInformation, 'unit'), required: true},
+                { name: 'Unit', dName: '建设规模单位', value: _util.getValueByKey(src.basicInformation, 'unit'), required: true },
                 // 技术经济指标(元) todo
-                {name: 'TechnicalAndEconomicIndex', value: '0', type: _type.DECIMAL},
+                { name: 'TechnicalAndEconomicIndex', value: '0', type: _type.DECIMAL },
                 // 总说明
-                {name: 'Explains', value: _util.getValueByKey(src.basicInformation, 'todo')}
+                { name: 'Explains', value: _util.getValueByKey(src.basicInformation, 'todo') }
             ];
             _base.Element.call(this, 'ConstructionProject', attrs);
         }
@@ -219,11 +224,11 @@ const XMLStandard = (function () {
         function SystemInfo(src) {
             const attrs = [
                 // 编制软件信息
-                {name: 'ID1', value: src.softInfo},
+                { name: 'ID1', value: src.softInfo },
                 // 编制机器硬件信息,不输出
-                {name: 'ID2', value: _util.generateHardwareId()},
+                { name: 'ID2', value: _util.generateHardwareId() },
                 // 文件生成时间
-                {name: 'MakeDate', dName: '文件生成时间', value: src.generatedTime, type: _type.DATE_TIME, required: true}
+                { name: 'MakeDate', dName: '文件生成时间', value: src.generatedTime, type: _type.DATE_TIME, required: true }
             ];
             _base.Element.call(this, 'SystemInfo', attrs);
         }
@@ -235,13 +240,13 @@ const XMLStandard = (function () {
         function Option() {
             const attrs = [
                 // 工料机消耗量、含量、用量类小数精度
-                {name: 'ResPrecision', value: 4, type: _type.INT, required: true},
+                { name: 'ResPrecision', value: 4, type: _type.INT, required: true },
                 // 工程量、数量类小数精度
-                {name: 'QuantityPrecision', value: 3, type: _type.INT, required: true},
+                { name: 'QuantityPrecision', value: 3, type: _type.INT, required: true },
                 // 金额、合价、费用类小数精度
-                {name: 'CostPrecision', value: 2, type: _type.INT, required: true},
+                { name: 'CostPrecision', value: 2, type: _type.INT, required: true },
                 // 费率、指数、比例(%)类小数精度
-                {name: 'RatePrecision', value: 3, type: _type.INT, required: true}
+                { name: 'RatePrecision', value: 3, type: _type.INT, required: true }
             ];
             _base.Element.call(this, 'Option', attrs);
         }
@@ -249,33 +254,33 @@ const XMLStandard = (function () {
         function ProjectInfo(src) {
             const attrs = [
                 // 设计单位
-                {name: 'Designer', value: _util.getValueByKey(src.basicInformation, 'designUnit')},
+                { name: 'Designer', value: _util.getValueByKey(src.basicInformation, 'designUnit') },
                 // 承包单位
-                {name: 'Contractor', value: _util.getValueByKey(src.basicInformation, 'buildingUnit')},
+                { name: 'Contractor', value: _util.getValueByKey(src.basicInformation, 'buildingUnit') },
                 // 编制单位
-                {name: 'CompileCompany', dName: '编制单位', value: _util.getValueByKey(src.basicInformation, 'establishUnit') || '无', required: true},
+                { name: 'CompileCompany', dName: '编制单位', value: _util.getValueByKey(src.basicInformation, 'establishUnit') || '无', required: true },
                 // 编制单位法定代表人或其授权人 todo
-                {name: 'Authorizer', value: _util.getValueByKey(src.basicInformation, 'Authorizer')},
+                { name: 'Authorizer', value: _util.getValueByKey(src.basicInformation, 'Authorizer') },
                 // 编制人
-                {name: 'Compiler', value: _util.getValueByKey(src.basicInformation, 'establishUnitAuthor')},
+                { name: 'Compiler', value: _util.getValueByKey(src.basicInformation, 'establishUnitAuthor') },
                 // 编制人资格证书编号 todo
-                {name: 'CompilerCertNo', value: _util.getValueByKey(src.basicInformation, 'CompilerCertNo')},
+                { name: 'CompilerCertNo', value: _util.getValueByKey(src.basicInformation, 'CompilerCertNo') },
                 // 编制时间
-                {name: 'CompileDate', dName: '编制时间', value: _util.getValueByKey(src.basicInformation, 'establishDate'), required: true},
+                { name: 'CompileDate', dName: '编制时间', value: _util.getValueByKey(src.basicInformation, 'establishDate'), required: true },
                 // 审核人
-                {name: 'Examiner', value: _util.getValueByKey(src.basicInformation, 'auditUnitAuditor')},
+                { name: 'Examiner', value: _util.getValueByKey(src.basicInformation, 'auditUnitAuditor') },
                 // 审核人资格证书编号 todo
-                {name: 'ExaminerCertNo', value: _util.getValueByKey(src.basicInformation, 'ExaminerCertNo')},
+                { name: 'ExaminerCertNo', value: _util.getValueByKey(src.basicInformation, 'ExaminerCertNo') },
                 // 审核时间
-                {name: 'ExamineDate', value: _util.getValueByKey(src.basicInformation, 'auditDate')},
+                { name: 'ExamineDate', value: _util.getValueByKey(src.basicInformation, 'auditDate') },
                 // 审定人 todo
-                {name: 'Approver', value: _util.getValueByKey(src.basicInformation, 'Approver')},
+                { name: 'Approver', value: _util.getValueByKey(src.basicInformation, 'Approver') },
                 // 审定人资格证书编号 todo
-                {name: 'ApproverCertNo', value: _util.getValueByKey(src.basicInformation, 'ApproverCertNo')},
+                { name: 'ApproverCertNo', value: _util.getValueByKey(src.basicInformation, 'ApproverCertNo') },
                 // 审定时间 todo
-                {name: 'ApproverDate', value: _util.getValueByKey(src.basicInformation, 'ApproverDate')},
+                { name: 'ApproverDate', value: _util.getValueByKey(src.basicInformation, 'ApproverDate') },
                 // 工程总价(元)
-                {name: 'Total', dName: '工程总价', value: src.summaryInfo.engineeringCost || '0', type: _type.DECIMAL, required: true}
+                { name: 'Total', dName: '工程总价', value: src.summaryInfo.engineeringCost || '0', type: _type.DECIMAL, required: true }
             ];
             _base.Element.call(this, 'ProjectInfo', attrs);
         }
@@ -283,77 +288,77 @@ const XMLStandard = (function () {
         function TendereeInfo(info) {
             const attrs = [
                 // 招标人
-                {name: 'TendereeName', dName: '招标人', value: _util.getValueByKey(info, 'bidInviter'), required: true},
+                { name: 'TendereeName', dName: '招标人', value: _util.getValueByKey(info, 'bidInviter'), required: true },
                 // 招标单位法定代表人或其授权人
-                {name: 'TenderAuthorizer', value: _util.getValueByKey(info, 'tenderRepresentative')},
+                { name: 'TenderAuthorizer', value: _util.getValueByKey(info, 'tenderRepresentative') },
                 // 招标单位编制人
-                {name: 'TenderCompiler', value: _util.getValueByKey(info, 'TenderCompiler')},
+                { name: 'TenderCompiler', value: _util.getValueByKey(info, 'TenderCompiler') },
                 // 招标单位编制人资格证书编号
-                {name: 'TenderCompilerCertNo', value: _util.getValueByKey(info, 'TenderCompilerCertNo')},
+                { name: 'TenderCompilerCertNo', value: _util.getValueByKey(info, 'TenderCompilerCertNo') },
                 // 招标单位编制时间
-                {name: 'TenderCompileDate', value: _util.getValueByKey(info, 'TenderCompileDate')},
+                { name: 'TenderCompileDate', value: _util.getValueByKey(info, 'TenderCompileDate') },
                 // 招标单位审核人
-                {name: 'TenderExaminer', value: _util.getValueByKey(info, 'TenderExaminer')},
+                { name: 'TenderExaminer', value: _util.getValueByKey(info, 'TenderExaminer') },
                 // 招标单位审核人资格证书编号
-                {name: 'TenderExaminerCertNo', value: _util.getValueByKey(info, 'TenderExaminerCertNo')},
+                { name: 'TenderExaminerCertNo', value: _util.getValueByKey(info, 'TenderExaminerCertNo') },
                 // 招标单位审核时间
-                {name: 'TenderExamineDate', value: _util.getValueByKey(info, 'TenderExamineDate')},
+                { name: 'TenderExamineDate', value: _util.getValueByKey(info, 'TenderExamineDate') },
                 // 招标单位审定人
-                {name: 'TenderApprover', value: _util.getValueByKey(info, 'TenderApprover')},
+                { name: 'TenderApprover', value: _util.getValueByKey(info, 'TenderApprover') },
                 // 招标单位审定人资格证书编号
-                {name: 'TenderApproverCertNo', value: _util.getValueByKey(info, 'TenderApproverCertNo')},
+                { name: 'TenderApproverCertNo', value: _util.getValueByKey(info, 'TenderApproverCertNo') },
                 // 招标单位审定时间
-                {name: 'TenderApproveDate', value: _util.getValueByKey(info, 'TenderApproveDate')},
+                { name: 'TenderApproveDate', value: _util.getValueByKey(info, 'TenderApproveDate') },
                 // 招标代理 不得为空,如无招标代理,则应填写“无”。
-                {name: 'Proxy', dName: '招标代理', value: _util.getValueByKey(info, 'Proxy'), required: true},
+                { name: 'Proxy', dName: '招标代理', value: _util.getValueByKey(info, 'Proxy'), required: true },
                 // 招标代理资质证书编号
-                {name: 'ProxyCertNo', value: _util.getValueByKey(info, 'ProxyCertNo')},
+                { name: 'ProxyCertNo', value: _util.getValueByKey(info, 'ProxyCertNo') },
                 // 招标代理法定代表人或其授权人
-                {name: 'ProxyAuthorizer', value: _util.getValueByKey(info, 'ProxyAuthorizer')},
+                { name: 'ProxyAuthorizer', value: _util.getValueByKey(info, 'ProxyAuthorizer') },
                 // 招标代理编制人员
-                {name: 'ProxyCompiler', value: _util.getValueByKey(info, 'ProxyCompiler')},
+                { name: 'ProxyCompiler', value: _util.getValueByKey(info, 'ProxyCompiler') },
                 // 招标代理编制人员资格证书编号
-                {name: 'ProxyCompilerCertNo', value: _util.getValueByKey(info, 'ProxyCompilerCertNo')},
+                { name: 'ProxyCompilerCertNo', value: _util.getValueByKey(info, 'ProxyCompilerCertNo') },
                 // 招标代理编制时间
-                {name: 'ProxyCompileDate', value: _util.getValueByKey(info, 'ProxyCompileDate')},
+                { name: 'ProxyCompileDate', value: _util.getValueByKey(info, 'ProxyCompileDate') },
                 // 招标代理审核人
-                {name: 'ProxyExaminer', value: _util.getValueByKey(info, 'ProxyExaminer')},
+                { name: 'ProxyExaminer', value: _util.getValueByKey(info, 'ProxyExaminer') },
                 // 招标代理审核人资格证书编号
-                {name: 'ProxyExaminerCertNo', value: _util.getValueByKey(info, 'ProxyExaminerCertNo')},
+                { name: 'ProxyExaminerCertNo', value: _util.getValueByKey(info, 'ProxyExaminerCertNo') },
                 // 招标代理审核时间
-                {name: 'ProxyExamineDate', value: _util.getValueByKey(info, 'ProxyExamineDate')},
+                { name: 'ProxyExamineDate', value: _util.getValueByKey(info, 'ProxyExamineDate') },
                 // 招标代理审定人
-                {name: 'ProxyApprover', value: _util.getValueByKey(info, 'ProxyApprover')},
+                { name: 'ProxyApprover', value: _util.getValueByKey(info, 'ProxyApprover') },
                 // 招标代理审定人资格证书编号
-                {name: 'ProxyApproverCertNo', value: _util.getValueByKey(info, 'ProxyApproverCertNo')},
+                { name: 'ProxyApproverCertNo', value: _util.getValueByKey(info, 'ProxyApproverCertNo') },
                 // 招标代理审定时间
-                {name: 'ProxyApproveDate', value: _util.getValueByKey(info, 'ProxyApproveDate')},
+                { name: 'ProxyApproveDate', value: _util.getValueByKey(info, 'ProxyApproveDate') },
                 // 造价咨询 、Consultant(造价咨询):不得为空,如无则应填写“无”。
-                {name: 'Consultant', dName: '造价咨询', value: _util.getValueByKey(info, 'Consultant'), required: true},
+                { name: 'Consultant', dName: '造价咨询', value: _util.getValueByKey(info, 'Consultant'), required: true },
                 // 造价咨询资质证书编号
-                {name: 'ConsultantCertNo', value: _util.getValueByKey(info, 'ConsultantCertNo')},
+                { name: 'ConsultantCertNo', value: _util.getValueByKey(info, 'ConsultantCertNo') },
                 // 造价咨询法定代表人或其授权人
-                {name: 'ConsultantAuthorizer', value: _util.getValueByKey(info, 'ConsultantAuthorizer')},
+                { name: 'ConsultantAuthorizer', value: _util.getValueByKey(info, 'ConsultantAuthorizer') },
                 // 造价咨询编制人
-                {name: 'ConsultantCompiler', value: _util.getValueByKey(info, 'ConsultantCompiler')},
+                { name: 'ConsultantCompiler', value: _util.getValueByKey(info, 'ConsultantCompiler') },
                 // 造价咨询编制人资格证书
-                {name: 'ConsultantCompilerCertNo', value: _util.getValueByKey(info, 'ConsultantCompilerCertNo')},
+                { name: 'ConsultantCompilerCertNo', value: _util.getValueByKey(info, 'ConsultantCompilerCertNo') },
                 // 造价咨询编制时间
-                {name: 'ConsultantCompileDate', value: _util.getValueByKey(info, 'ConsultantCompileDate')},
+                { name: 'ConsultantCompileDate', value: _util.getValueByKey(info, 'ConsultantCompileDate') },
                 // 造价咨询审核人
-                {name: 'ConsultantExaminer', value: _util.getValueByKey(info, 'ConsultantExaminer')},
+                { name: 'ConsultantExaminer', value: _util.getValueByKey(info, 'ConsultantExaminer') },
                 // 造价咨询审核人资格证书编号
-                {name: 'ConsultantExaminerCertNo', value: _util.getValueByKey(info, 'ConsultantExaminerCertNo')},
+                { name: 'ConsultantExaminerCertNo', value: _util.getValueByKey(info, 'ConsultantExaminerCertNo') },
                 // 造价咨询审核时间
-                {name: 'ConsultantExamineDate', value: _util.getValueByKey(info, 'ConsultantExamineDate')},
+                { name: 'ConsultantExamineDate', value: _util.getValueByKey(info, 'ConsultantExamineDate') },
                 // 造价咨询审定人
-                {name: 'ConsultantApprover', value: _util.getValueByKey(info, 'ConsultantApprover')},
+                { name: 'ConsultantApprover', value: _util.getValueByKey(info, 'ConsultantApprover') },
                 // 造价咨询审定人资格证书编号
-                {name: 'ConsultantApproverCertNo', value: _util.getValueByKey(info, 'ConsultantApproverCertNo')},
+                { name: 'ConsultantApproverCertNo', value: _util.getValueByKey(info, 'ConsultantApproverCertNo') },
                 // 造价咨询审定时间
-                {name: 'ConsultantApproveDate', value: _util.getValueByKey(info, 'ConsultantApproveDate')},
+                { name: 'ConsultantApproveDate', value: _util.getValueByKey(info, 'ConsultantApproveDate') },
                 // 招标控制价(元)
-                {name: 'TenderSumLimit', dName: '招标控制价', value: 'todo', type: _type.DECIMAL, required: true}
+                { name: 'TenderSumLimit', dName: '招标控制价', value: 'todo', type: _type.DECIMAL, required: true }
             ];
             _base.Element.call(this, 'TendereeInfo', attrs);
         }
@@ -361,29 +366,29 @@ const XMLStandard = (function () {
         function BidderInfo(src) {
             const attrs = [
                 // 投标人
-                {name: 'BidName', dName: '投标人', value: _util.getValueByKey(src.basicInformation, 'bidName'), required: true},
+                { name: 'BidName', dName: '投标人', value: _util.getValueByKey(src.basicInformation, 'bidName'), required: true },
                 // 投标单位法定代表人或其授权人
-                {name: 'BidAuthorizer', value: _util.getValueByKey(src.basicInformation, 'bidAuthorizer')},
+                { name: 'BidAuthorizer', value: _util.getValueByKey(src.basicInformation, 'bidAuthorizer') },
                 // 投标总价(元)
-                {name: 'BidAuthorizer', dName: '投标总价', value: src.summaryInfo.engineeringCost, type: _type.DECIMAL, required: true},
+                { name: 'BidAuthorizer', dName: '投标总价', value: src.summaryInfo.engineeringCost, type: _type.DECIMAL, required: true },
                 // 投标单位编制人
-                {name: 'BidCompiler', value: _util.getValueByKey(src.basicInformation, 'bidCompiler')},
+                { name: 'BidCompiler', value: _util.getValueByKey(src.basicInformation, 'bidCompiler') },
                 // 投标单位编制人资格证书编号
-                {name: 'BidCompilerCertNo', value: _util.getValueByKey(src.basicInformation, 'BidCompilerCertNo')},
+                { name: 'BidCompilerCertNo', value: _util.getValueByKey(src.basicInformation, 'BidCompilerCertNo') },
                 // 投标单位编制时间
-                {name: 'BidCompileDate', value: _util.getValueByKey(src.basicInformation, 'bidCompileDate')},
+                { name: 'BidCompileDate', value: _util.getValueByKey(src.basicInformation, 'bidCompileDate') },
                 // 投标单位审核人
-                {name: 'BidExaminer', value: _util.getValueByKey(src.basicInformation, 'bidExaminer')},
+                { name: 'BidExaminer', value: _util.getValueByKey(src.basicInformation, 'bidExaminer') },
                 // 投标单位审核人资格证书编号
-                {name: 'BidExaminerCertNo', value: _util.getValueByKey(src.basicInformation, 'bidExaminerCertNo')},
+                { name: 'BidExaminerCertNo', value: _util.getValueByKey(src.basicInformation, 'bidExaminerCertNo') },
                 // 投标单位审核时间
-                {name: 'BidExamineDate', value: _util.getValueByKey(src.basicInformation, 'bidExamineDate')},
+                { name: 'BidExamineDate', value: _util.getValueByKey(src.basicInformation, 'bidExamineDate') },
                 // 投标单位审定人
-                {name: 'BidApprover', value: _util.getValueByKey(src.basicInformation, 'bidApprover')},
+                { name: 'BidApprover', value: _util.getValueByKey(src.basicInformation, 'bidApprover') },
                 // 投标单位审定人资格证书
-                {name: 'BidApproverCertNo', value: _util.getValueByKey(src.basicInformation, 'bidApproverCertNo')},
+                { name: 'BidApproverCertNo', value: _util.getValueByKey(src.basicInformation, 'bidApproverCertNo') },
                 // 投标单位审定时间
-                {name: 'BidApproveDate', value: _util.getValueByKey(src.basicInformation, 'BidApproveDate')}
+                { name: 'BidApproveDate', value: _util.getValueByKey(src.basicInformation, 'BidApproveDate') }
             ];
             _base.Element.call(this, 'BidderInfo', attrs);
         }
@@ -391,55 +396,55 @@ const XMLStandard = (function () {
         function SummaryOfCost(summaryInfo) {
             const attrs = [
                 // 工程造价(元)
-                {name: 'Total', value: summaryInfo.engineeringCost, type: _type.DECIMAL},
+                { name: 'Total', value: summaryInfo.engineeringCost, type: _type.DECIMAL },
                 // 建筑工程费
-                {name: 'Construction', value: '0', type: _type.DECIMAL},
+                { name: 'Construction', value: '0', type: _type.DECIMAL },
                 // 安装工程费
-                {name: 'Installation', value: '0', type: _type.DECIMAL},
+                { name: 'Installation', value: '0', type: _type.DECIMAL },
                 // 分部分项工程费
-                {name: 'DivisionalAndElementalWorks', value: summaryInfo.subEngineering, type: _type.DECIMAL},
+                { name: 'DivisionalAndElementalWorks', value: summaryInfo.subEngineering, type: _type.DECIMAL },
                 // 措施项目费
-                {name: 'Preliminaries', value: summaryInfo.measure, type: _type.DECIMAL},
+                { name: 'Preliminaries', value: summaryInfo.measure, type: _type.DECIMAL },
                 // 安全文明施工费
-                {name: 'CostForHSE', value: summaryInfo.safetyConstruction, type: _type.DECIMAL},
+                { name: 'CostForHSE', value: summaryInfo.safetyConstruction, type: _type.DECIMAL },
                 // 其他措施费
-                {name: 'OtherPreliminaries', value: 'todo', type: _type.DECIMAL},
+                { name: 'OtherPreliminaries', value: 'todo', type: _type.DECIMAL },
                 // 其他项目费
-                {name: 'SundryCosts', value: summaryInfo.other, type: _type.DECIMAL},
+                { name: 'SundryCosts', value: summaryInfo.other, type: _type.DECIMAL },
                 // 暂列金额
-                {name: 'ProvisionalSums', value: summaryInfo.provisional, type: _type.DECIMAL},
+                { name: 'ProvisionalSums', value: summaryInfo.provisional, type: _type.DECIMAL },
                 // 暂估价材料
-                {name: 'ProvisionalMaterial', value: summaryInfo.materialProvisional, type: _type.DECIMAL},
+                { name: 'ProvisionalMaterial', value: summaryInfo.materialProvisional, type: _type.DECIMAL },
                 // 专业工程暂估价
-                {name: 'SpecialtyProvisionalPrice', value: summaryInfo.engineeringEstimate, type: _type.DECIMAL},
+                { name: 'SpecialtyProvisionalPrice', value: summaryInfo.engineeringEstimate, type: _type.DECIMAL },
                 // 计日工费用
-                {name: 'DayWorkRate', value: summaryInfo.daywork, type: _type.DECIMAL},
+                { name: 'DayWorkRate', value: summaryInfo.daywork, type: _type.DECIMAL },
                 // 总承包服务费
-                {name: 'MainContractorAttendance', value: summaryInfo.turnKeyContract, type: _type.DECIMAL},
+                { name: 'MainContractorAttendance', value: summaryInfo.turnKeyContract, type: _type.DECIMAL },
                 // 索赔费用
-                {name: 'ClaimForLossAndExpenses', value: 'todo', type: _type.DECIMAL},
+                { name: 'ClaimForLossAndExpenses', value: 'todo', type: _type.DECIMAL },
                 // 现场签证费用
-                {name: 'SiteInstruction', value: 'todo', type: _type.DECIMAL},
+                { name: 'SiteInstruction', value: 'todo', type: _type.DECIMAL },
                 // 规费
-                {name: 'StatutoryFees', value: summaryInfo.charge, type: _type.DECIMAL},
+                { name: 'StatutoryFees', value: summaryInfo.charge, type: _type.DECIMAL },
                 // 税金
-                {name: 'Tax', value: summaryInfo.tax, type: _type.DECIMAL},
+                { name: 'Tax', value: summaryInfo.tax, type: _type.DECIMAL },
                 // 人工费
-                {name: 'Labor', value: 'todo', type: _type.DECIMAL},
+                { name: 'Labor', value: 'todo', type: _type.DECIMAL },
                 // 材料费
-                {name: 'Material', value: 'todo', type: _type.DECIMAL},
+                { name: 'Material', value: 'todo', type: _type.DECIMAL },
                 // 主材设备费
-                {name: 'MainMaterialEquipment', value: 'todo', type: _type.DECIMAL},
+                { name: 'MainMaterialEquipment', value: 'todo', type: _type.DECIMAL },
                 // 主材费
-                {name: 'MainMaterial', value: 'todo', type: _type.DECIMAL},
+                { name: 'MainMaterial', value: 'todo', type: _type.DECIMAL },
                 // 机械费
-                {name: 'Machine', value: 'todo', type: _type.DECIMAL},
+                { name: 'Machine', value: 'todo', type: _type.DECIMAL },
                 // 管理费
-                {name: 'Overhead', value: 'todo', type: _type.DECIMAL},
+                { name: 'Overhead', value: 'todo', type: _type.DECIMAL },
                 // 利润
-                {name: 'Profit', value: 'todo', type: _type.DECIMAL},
+                { name: 'Profit', value: 'todo', type: _type.DECIMAL },
                 // 设备费
-                {name: 'Equipment', value: 'todo', type: _type.DECIMAL},
+                { name: 'Equipment', value: 'todo', type: _type.DECIMAL },
                 // 其中:引进部分(美元)
                 //{name: 'ForeignCurrency', value: '0', type: _type.DECIMAL},
                 // 折合人民币
@@ -451,27 +456,27 @@ const XMLStandard = (function () {
         function ProjectInstallationWorkCost(src) {
             const attrs = [
                 // 工程编号
-                {name: 'Number', value: ''},
+                { name: 'Number', value: '' },
                 // 工程名称
-                {name: 'Name', value: src.name, required: true},
+                { name: 'Name', value: src.name, required: true },
                 // 金额 (元)
-                {name: 'Total', value: src.summaryInfo.engineeringCost, type: _type.DECIMAL},
+                { name: 'Total', value: src.summaryInfo.engineeringCost, type: _type.DECIMAL },
                 // 其中:引进部分(美元)
-                {name: 'ForeignCurrency', value: 'todo', type: _type.DECIMAL},
+                { name: 'ForeignCurrency', value: 'todo', type: _type.DECIMAL },
                 // 折合人民币
-                {name: 'ConvertedIntoRMB', value: 'todo', type: _type.DECIMAL},
+                { name: 'ConvertedIntoRMB', value: 'todo', type: _type.DECIMAL },
                 // 建设规模
-                {name: 'Scale', value: _util.getValueByKey(src.basicInformation, 'projectScale'), type: _type.DECIMAL, required: true},
+                { name: 'Scale', value: _util.getValueByKey(src.basicInformation, 'projectScale'), type: _type.DECIMAL, required: true },
                 // 建设规模单位 todo add key
-                {name: 'Unit', value: _util.getValueByKey(src.basicInformation, 'unit'), required: true},
+                { name: 'Unit', value: _util.getValueByKey(src.basicInformation, 'unit'), required: true },
                 // 技术经济指标(元)
-                {name: 'TechnicalAndEconomicIndex', value: 'todo', type: _type.DECIMAL},
+                { name: 'TechnicalAndEconomicIndex', value: 'todo', type: _type.DECIMAL },
                 // 占总比例(%)
-                {name: 'Ratios', value: '100', type: _type.DECIMAL},
+                { name: 'Ratios', value: '100', type: _type.DECIMAL },
                 // 费用代号
-                {name: 'Code', value: 'todo'},
+                { name: 'Code', value: 'todo' },
                 // 备注
-                {name: 'Remark', value: src.remark}
+                { name: 'Remark', value: src.remark }
             ];
             _base.Element.call(this, 'ProjectInstallationWorkCost', attrs);
         }
@@ -479,25 +484,25 @@ const XMLStandard = (function () {
         function SectionWorks(src) {
             const attrs = [
                 // 工程编号
-                {name: 'Number', value: ''},
+                { name: 'Number', value: '' },
                 // 工程名称
-                {name: 'Name', value: src.name, required: true},
+                { name: 'Name', value: src.name, required: true },
                 // 标段
-                {name: 'Segment', value: src.segment},
+                { name: 'Segment', value: src.segment },
                 // 金额
-                {name: 'Total', value: src.summaryInfo.engineeringCost, type: _type.DECIMAL},
+                { name: 'Total', value: src.summaryInfo.engineeringCost, type: _type.DECIMAL },
                 // 建设规模
-                {name: 'Scale', value: 'todo', type: _type.DECIMAL, required: true},
+                { name: 'Scale', value: 'todo', type: _type.DECIMAL, required: true },
                 // 建设规模单位
-                {name: 'Unit', value: 'todo', required: true},
+                { name: 'Unit', value: 'todo', required: true },
                 // 技术经济指标
-                {name: 'TechnicalAndEconomicIndex', value: 'todo', type: _type.DECIMAL},
+                { name: 'TechnicalAndEconomicIndex', value: 'todo', type: _type.DECIMAL },
                 // 占总投资比例(%)
-                {name: 'Ratios', value: src.summaryInfo.rate, type: _type.DECIMAL},
+                { name: 'Ratios', value: src.summaryInfo.rate, type: _type.DECIMAL },
                 // 费用代号
-                {name: 'Code', value: 'todo', type: _type.DECIMAL},
+                { name: 'Code', value: 'todo', type: _type.DECIMAL },
                 // 备注
-                {name: 'Remark', value: 'todo'}
+                { name: 'Remark', value: 'todo' }
             ];
             _base.Element.call(this, 'SectionWorks', attrs);
         }
@@ -505,55 +510,55 @@ const XMLStandard = (function () {
         function UnitWorks(src) {
             const attrs = [
                 // 工程编号
-                {name: 'Number', value: '', required: true},
+                { name: 'Number', value: '', required: true },
                 // 工程名称
-                {name: 'Name', value: src.name, required: true},
+                { name: 'Name', value: src.name, required: true },
                 // 标段
-                {name: 'Segment', value: src.segment},
+                { name: 'Segment', value: src.segment },
                 // 工程类别
-                {name: 'ProjectCategory', value: 'todo', required: true},
+                { name: 'ProjectCategory', value: 'todo', required: true },
                 // 工程类型
-                {name: 'ProjectType', value: 'todo', required: true},
+                { name: 'ProjectType', value: 'todo', required: true },
                 // 计价模式
-                {name: 'ValuationModel', value: VALUATION_MODEL.bill, type: _type.INT, required: true},
+                { name: 'ValuationModel', value: VALUATION_MODEL.bill, type: _type.INT, required: true },
                 // 计税模式
-                {name: 'TaxModel', value: src.taxType, type: _type.INT, required: true},
+                { name: 'TaxModel', value: src.taxType, type: _type.INT, required: true },
                 // 地区类别
-                {name: 'AreaKind', value: 'todo', type: _type.INT, required: true},
+                { name: 'AreaKind', value: 'todo', type: _type.INT, required: true },
                 // 金额
-                {name: 'Total', value: src.summaryInfo.engineeringCost, type: _type.DECIMAL},
+                { name: 'Total', value: src.summaryInfo.engineeringCost, type: _type.DECIMAL },
                 // 专业类别
-                {name: 'Specialty', value: src.summaryInfo.engineeringCost, type: _type.INT},
+                { name: 'Specialty', value: src.summaryInfo.engineeringCost, type: _type.INT },
                 // 工程用途
-                {name: 'Purposes', value: 'todo'},
+                { name: 'Purposes', value: 'todo' },
                 //建设(编制)范围
-                {name: 'RangeOfCompilation', value: 'todo'},
+                { name: 'RangeOfCompilation', value: 'todo' },
                 // 建设规模
-                {name: 'Scale', value: 'todo', type: _type.DECIMAL, required: true},
+                { name: 'Scale', value: 'todo', type: _type.DECIMAL, required: true },
                 // 建设规模单位
-                {name: 'Unit', value: 'todo', required: true},
+                { name: 'Unit', value: 'todo', required: true },
                 // 技术经济指标(元)
-                {name: 'TechnicalAndEconomicIndex', value: 'todo', type: _type.DECIMAL},
+                { name: 'TechnicalAndEconomicIndex', value: 'todo', type: _type.DECIMAL },
                 // 占总投资比例(%)
-                {name: 'Ratios', value: src.summaryInfo.rate, type: _type.DECIMAL},
+                { name: 'Ratios', value: src.summaryInfo.rate, type: _type.DECIMAL },
                 // 费用代号
-                {name: 'Code', value: 'todo'},
+                { name: 'Code', value: 'todo' },
                 // 清单数据库,没有则填写 “无”
-                {name: 'BillDataBase', value: 'todo', required: true},
+                { name: 'BillDataBase', value: 'todo', required: true },
                 // 定额数据库,没有则填写 “无”
-                {name: 'NormDataBase', value: 'todo', required: true},
+                { name: 'NormDataBase', value: 'todo', required: true },
                 // 人工材料设备价格文件,没有则填写 “无”
-                {name: 'ResInfoPricingFile', value: 'todo', required: true},
+                { name: 'ResInfoPricingFile', value: 'todo', required: true },
                 // 执行费率文件
-                {name: 'AppliedRateFile', value: 'todo'},
+                { name: 'AppliedRateFile', value: 'todo' },
                 // 其他计价依据文件
-                {name: 'OtherRelatedFile', value: 'todo'},
+                { name: 'OtherRelatedFile', value: 'todo' },
                 // 总说明
-                {name: 'Explains', value: 'todo'},
+                { name: 'Explains', value: 'todo' },
                 // 导出XML文件名,工程编号+工程名称.xml
-                {name: 'FileName', value: 'todo'},
+                { name: 'FileName', value: 'todo' },
                 // 备注
-                {name: 'Remark', value: 'todo'},
+                { name: 'Remark', value: 'todo' },
             ];
             _base.Element.call(this, 'UnitWorks', attrs);
         }
@@ -564,10 +569,10 @@ const XMLStandard = (function () {
         // 工程特征信息明细 AttrInfoItem, 补充信息明细AddiInfoItem
         function InfoItem(eleName, src) {
             const attrs = [
-                {name: 'Name', value: src.name, required: true},
-                {name: 'Value', value: src.value},
-                {name: 'Code', value: src.code},
-                {name: 'Remark', value: src.remark}
+                { name: 'Name', value: src.name, required: true },
+                { name: 'Value', value: src.value },
+                { name: 'Code', value: src.code },
+                { name: 'Remark', value: src.remark }
             ];
             _base.Element.call(this, eleName, attrs);
         }
@@ -579,54 +584,54 @@ const XMLStandard = (function () {
         function UnitWorksSummaryGroup(src) {
             const attrs = [
                 // 费用编号
-                {name: 'Number', value: src.code},
+                { name: 'Number', value: src.code },
                 // 费用名称
-                {name: 'Name', value: src.name, required: true},
+                { name: 'Name', value: src.name, required: true },
                 // 单位
-                {name: 'Unit', value: src.unit},
+                { name: 'Unit', value: src.unit },
                 // 工程量
-                {name: 'Quantity', value: src.quantity, type: _type.DECIMAL},
+                { name: 'Quantity', value: src.quantity, type: _type.DECIMAL },
                 // 金额
-                {name: 'Total', value: _util.getFee(src.fees, 'common.totalFee'), type: _type.DECIMAL},
+                { name: 'Total', value: _util.getFee(src.fees, 'common.totalFee'), type: _type.DECIMAL },
                 // 技术经济指标(元)
-                {name: 'TechnicalAndEconomicIndex', value: 'todo', type: _type.DECIMAL},
+                { name: 'TechnicalAndEconomicIndex', value: 'todo', type: _type.DECIMAL },
                 // 占比(%)
-                {name: 'Ratios', value: src.summaryInfo.engineeringCost, type: _type.DECIMAL},
+                { name: 'Ratios', value: src.summaryInfo.engineeringCost, type: _type.DECIMAL },
                 //章节类型
-                {name: 'ChapterKind', value: 'todo', type: _type.INT, required: true},
+                { name: 'ChapterKind', value: 'todo', type: _type.INT, required: true },
                 // 费用代号
-                {name: 'Code', value: 'todo', type: _type.INT, required: true},
+                { name: 'Code', value: 'todo', type: _type.INT, required: true },
                 // 汇总类型
-                {name: 'Kind', value: 'todo', type: _type.INT, required: true},
+                { name: 'Kind', value: 'todo', type: _type.INT, required: true },
                 // 备注
-                {name: 'Remark', value: src.remark}
+                { name: 'Remark', value: src.remark }
             ];
             _base.Element.call(this, 'UnitWorksSummaryGroup', attrs);
         }
         // 单位工程费汇总明细
         function UnitWorksSummaryItem(src) {
             const attrs = [
-                {name: 'Number', value: src.code},
-                {name: 'Name', value: src.name, required: true},
-                {name: 'Unit', value: src.unit},
-                {name: 'Quantity', value: src.quantity, type: _type.DECIMAL},
+                { name: 'Number', value: src.code },
+                { name: 'Name', value: src.name, required: true },
+                { name: 'Unit', value: src.unit },
+                { name: 'Quantity', value: src.quantity, type: _type.DECIMAL },
                 // 计算基数:可由费用代号、数字、四则运算符号、小括号组成
-                {name: 'QtyFormula', value: src.calcBase, type: _type.DECIMAL},
+                { name: 'QtyFormula', value: src.calcBase, type: _type.DECIMAL },
                 // 费率
-                {name: 'Rate', value: src.feeRate, type: _type.DECIMAL},
-                {name: 'Total', value: _util.getFee(src.fees, 'common.totalFee'), type: _type.DECIMAL},
+                { name: 'Rate', value: src.feeRate, type: _type.DECIMAL },
+                { name: 'Total', value: _util.getFee(src.fees, 'common.totalFee'), type: _type.DECIMAL },
                 // 技术经济指标(元)
-                {name: 'TechnicalAndEconomicIndex', value: 'todo', type: _type.DECIMAL},
+                { name: 'TechnicalAndEconomicIndex', value: 'todo', type: _type.DECIMAL },
                 // 占比(%)
-                {name: 'Ratios', value: src.summaryInfo.engineeringCost, type: _type.DECIMAL},
+                { name: 'Ratios', value: src.summaryInfo.engineeringCost, type: _type.DECIMAL },
                 //章节类型
-                {name: 'ChapterKind', value: 'todo', type: _type.INT, required: true},
+                { name: 'ChapterKind', value: 'todo', type: _type.INT, required: true },
                 // 费用代号
-                {name: 'Code', value: 'todo', type: _type.INT, required: true},
+                { name: 'Code', value: 'todo', type: _type.INT, required: true },
                 // 汇总类型
-                {name: 'Kind', value: 'todo', type: _type.INT, required: true},
+                { name: 'Kind', value: 'todo', type: _type.INT, required: true },
                 // 备注
-                {name: 'Remark', value: src.remark}
+                { name: 'Remark', value: src.remark }
             ];
             _base.Element.call(this, 'UnitWorksSummaryItem', attrs);
         }
@@ -638,23 +643,23 @@ const XMLStandard = (function () {
         function SummaryOfBasicCost() {
             // 省略了一些
             const attrs = [
-                {name: 'Labor', value: 'todo', type: _type.DECIMAL},
-                {name: 'Material', value: 'todo', type: _type.DECIMAL},
-                {name: 'Material', value: 'todo', type: _type.DECIMAL},
-                {name: 'MainMaterial', value: 'todo', type: _type.DECIMAL},
-                {name: 'Equipment', value: 'todo', type: _type.DECIMAL},
-                {name: 'MainMaterialEquipment', value: 'todo', type: _type.DECIMAL},
-                {name: 'Machine', value: 'todo', type: _type.DECIMAL},
+                { name: 'Labor', value: 'todo', type: _type.DECIMAL },
+                { name: 'Material', value: 'todo', type: _type.DECIMAL },
+                { name: 'Material', value: 'todo', type: _type.DECIMAL },
+                { name: 'MainMaterial', value: 'todo', type: _type.DECIMAL },
+                { name: 'Equipment', value: 'todo', type: _type.DECIMAL },
+                { name: 'MainMaterialEquipment', value: 'todo', type: _type.DECIMAL },
+                { name: 'Machine', value: 'todo', type: _type.DECIMAL },
                 // 管理费
-                {name: 'Overhead', value: 'todo', type: _type.DECIMAL},
+                { name: 'Overhead', value: 'todo', type: _type.DECIMAL },
                 // 规费
-                {name: 'StatutoryFees', value: 'todo', type: _type.DECIMAL},
+                { name: 'StatutoryFees', value: 'todo', type: _type.DECIMAL },
                 // 税金
-                {name: 'Tax', value: 'todo', type: _type.DECIMAL},
+                { name: 'Tax', value: 'todo', type: _type.DECIMAL },
                 // 利润
-                {name: 'Profit', value: 'todo', type: _type.DECIMAL},
+                { name: 'Profit', value: 'todo', type: _type.DECIMAL },
                 // 暂估价
-                {name: 'Appraisal', value: 'todo', type: _type.DECIMAL}
+                { name: 'Appraisal', value: 'todo', type: _type.DECIMAL }
             ];
             _base.Element.call(this, 'SummaryOfBasicCost', attrs);
         }
@@ -662,17 +667,17 @@ const XMLStandard = (function () {
         function DivisionalWorks(src) {
             const attrs = [
                 // 编码
-                {name: 'Number', value: src.code},
-                {name: 'Name', value: src.name, required: true},
+                { name: 'Number', value: src.code },
+                { name: 'Name', value: src.name, required: true },
                 // 特征
-                {name: 'Attr', value: 'todo'},
-                {name: 'Unit', value: src.unit},
-                {name: 'Quantity', value: src.quantity, type: _type.DECIMAL},
-                {name: 'Total', value: _util.getFee(src.fees, 'common.totalFee'), type: _type.DECIMAL},
-                {name: 'TechnicalAndEconomicIndex', value: 'todo', type: _type.DECIMAL},
-                {name: 'ChapterKind', value: 'todo', type: _type.INT, required: true},
-                {name: 'Code', value: 'todo', type: _type.INT},
-                {name: 'Remark', value: src.remark}
+                { name: 'Attr', value: 'todo' },
+                { name: 'Unit', value: src.unit },
+                { name: 'Quantity', value: src.quantity, type: _type.DECIMAL },
+                { name: 'Total', value: _util.getFee(src.fees, 'common.totalFee'), type: _type.DECIMAL },
+                { name: 'TechnicalAndEconomicIndex', value: 'todo', type: _type.DECIMAL },
+                { name: 'ChapterKind', value: 'todo', type: _type.INT, required: true },
+                { name: 'Code', value: 'todo', type: _type.INT },
+                { name: 'Remark', value: src.remark }
             ];
             _base.Element.call(this, 'DivisionalWorks', attrs);
         }
@@ -680,48 +685,48 @@ const XMLStandard = (function () {
         function WorkElement(src) {
             const attrs = [
                 // 项目编码
-                {name: 'Number', value: src.code, required: true},
+                { name: 'Number', value: src.code, required: true },
                 // 项目名称
-                {name: 'Name', value: src.name, required: true},
+                { name: 'Name', value: src.name, required: true },
                 // 项目特征
-                {name: 'Attr', value: 'todo'},
+                { name: 'Attr', value: 'todo' },
                 // 工作内容
-                {name: 'WorkContent', value: 'todo'},
+                { name: 'WorkContent', value: 'todo' },
                 // 计量单位
-                {name: 'Unit', value: src.unit, required: true},
+                { name: 'Unit', value: src.unit, required: true },
                 // 工程量
-                {name: 'Quantity', value: src.quantity, type: _type.DECIMAL},
+                { name: 'Quantity', value: src.quantity, type: _type.DECIMAL },
                 // 计算基数
-                {name: 'QtyFormula', value: src.calcBase, type: _type.DECIMAL},
+                { name: 'QtyFormula', value: src.calcBase, type: _type.DECIMAL },
                 // 单价(元)
-                {name: 'Price', value: _util.getFee(src.fees, 'common.unitFee'), type: _type.DECIMAL},
+                { name: 'Price', value: _util.getFee(src.fees, 'common.unitFee'), type: _type.DECIMAL },
                 // 设备单价(元)指清单项目所采用设备的综合单价
-                {name: 'EquipmentPrice', value: 'todo', type: _type.DECIMAL},
+                { name: 'EquipmentPrice', value: 'todo', type: _type.DECIMAL },
                 // 最低限价(元)
-                {name: 'PriceLow', value: 'todo', type: _type.DECIMAL},
+                { name: 'PriceLow', value: 'todo', type: _type.DECIMAL },
                 // 最高限价(元)
-                {name: 'PriceHigh', value: src.maxPrice, type: _type.DECIMAL},
+                { name: 'PriceHigh', value: src.maxPrice, type: _type.DECIMAL },
                 // 费率(%)
-                {name: 'Rate', value: src.feeRate, type: _type.DECIMAL},
+                { name: 'Rate', value: src.feeRate, type: _type.DECIMAL },
                 // 合价(元)
-                {name: 'Total', value: _util.getFee(src.fees, 'common.totalFee'), type: _type.DECIMAL},
+                { name: 'Total', value: _util.getFee(src.fees, 'common.totalFee'), type: _type.DECIMAL },
                 // 主要清单
-                {name: 'Total', value: !!src.mainBills, type: _type.BOOL},
+                { name: 'Total', value: !!src.mainBills, type: _type.BOOL },
                 // 子目类型
-                {name: 'Kind', value: 'todo', type: _type.INT, required: true},
+                { name: 'Kind', value: 'todo', type: _type.INT, required: true },
                 // 取费类型
-                {name: 'CalculationKind', value: 'todo', type: _type.INT, required: true},
+                { name: 'CalculationKind', value: 'todo', type: _type.INT, required: true },
                 // 费用归属
-                {name: 'CostKind', value: 'todo', type: _type.INT, required: true},
+                { name: 'CostKind', value: 'todo', type: _type.INT, required: true },
                 // 计算方式
-                {name: 'CalcType', value: 'todo', type: _type.INT, required: true},
+                { name: 'CalcType', value: 'todo', type: _type.INT, required: true },
                 // 专业类型
-                {name: 'Specialty', value: 'todo', type: _type.INT},
+                { name: 'Specialty', value: 'todo', type: _type.INT },
                 // 清单标识
-                {name: 'ListingIdentity', value: 'todo'},
+                { name: 'ListingIdentity', value: 'todo' },
                 // 费用代号
-                {name: 'Code', value: 'todo'},
-                {name: 'Remark', value: src.remark}
+                { name: 'Code', value: 'todo' },
+                { name: 'Remark', value: src.remark }
             ];
             _base.Element.call(this, 'WorkElement', attrs);
         }
@@ -729,23 +734,23 @@ const XMLStandard = (function () {
         function ExpressElement(src) {
             const attrs = [
                 // 序号
-                {name: 'OrderNumber', value: 'todo', required: true},
+                { name: 'OrderNumber', value: 'todo', required: true },
                 // 工程量计算式
-                {name: 'Express', value: 'todo', required: true},
+                { name: 'Express', value: 'todo', required: true },
                 // 工程量
-                {name: 'Quantity', value: 'todo', required: true},
+                { name: 'Quantity', value: 'todo', required: true },
                 // 汇总类型
-                {name: 'Kind', value: 'todo', type: _type.INT, required: true},
-                {name: 'Remark', value: src.remark}
+                { name: 'Kind', value: 'todo', type: _type.INT, required: true },
+                { name: 'Remark', value: src.remark }
             ];
             _base.Element.call(this, 'ExpressElement', attrs);
         }
         // 工序内容
         function WorkContent(src) {
             const attrs = [
-                {name: 'Name', value: src.name, required: true},
-                {name: 'Total', value: _util.getFee(src.fees, 'common.totalFee'), type: _type.DECIMAL},
-                {name: 'Remark', value: ''}
+                { name: 'Name', value: src.name, required: true },
+                { name: 'Total', value: _util.getFee(src.fees, 'common.totalFee'), type: _type.DECIMAL },
+                { name: 'Remark', value: '' }
             ];
             _base.Element.call(this, 'WorkContent', attrs);
         }
@@ -753,45 +758,45 @@ const XMLStandard = (function () {
         function Norm(src) {
             const attrs = [
                 // 定额编码
-                {name: 'Number', value: src.code, required: true},
-                {name: 'Name', value: src.name, required: true},
-                {name: 'Unit', value: src.unit, required: true},
-                {name: 'Quantity', value: src.quantity, type: _type.DECIMAL},
+                { name: 'Number', value: src.code, required: true },
+                { name: 'Name', value: src.name, required: true },
+                { name: 'Unit', value: src.unit, required: true },
+                { name: 'Quantity', value: src.quantity, type: _type.DECIMAL },
                 // 单价
-                {name: 'Price', value: _util.getFee(src.fees, 'common.unitFee'), type: _type.DECIMAL},
+                { name: 'Price', value: _util.getFee(src.fees, 'common.unitFee'), type: _type.DECIMAL },
                 // 设备单价
-                {name: 'EquipmentPrice', value: _util.getFee(src.fees, 'todo'), type: _type.DECIMAL},
+                { name: 'EquipmentPrice', value: _util.getFee(src.fees, 'todo'), type: _type.DECIMAL },
                 // 合价
-                {name: 'Total', value: _util.getFee(src.fees, 'common.totalFee'), type: _type.DECIMAL},
+                { name: 'Total', value: _util.getFee(src.fees, 'common.totalFee'), type: _type.DECIMAL },
                 // 设备合价
-                {name: 'EquipmentTotal', value: _util.getFee(src.fees, 'todo'), type: _type.DECIMAL},
+                { name: 'EquipmentTotal', value: _util.getFee(src.fees, 'todo'), type: _type.DECIMAL },
                 // 其中:引进部分(美元)
-                {name: 'ForeignCurrency', value: _util.getFee(src.fees, 'todo'), type: _type.DECIMAL},
+                { name: 'ForeignCurrency', value: _util.getFee(src.fees, 'todo'), type: _type.DECIMAL },
                 // 折合人民币(元)
-                {name: 'ConvertedIntoRMB', value: _util.getFee(src.fees, 'todo'), type: _type.DECIMAL},
+                { name: 'ConvertedIntoRMB', value: _util.getFee(src.fees, 'todo'), type: _type.DECIMAL },
                 // 是否定额
-                {name: 'IsNorm', value: _util.getFee(src.fees, 'todo'), type: _type.Bool, required: true},
+                { name: 'IsNorm', value: _util.getFee(src.fees, 'todo'), type: _type.Bool, required: true },
                 // 子目类型
-                {name: 'Kind', value: 'todo', type: _type.INT, required: true},
+                { name: 'Kind', value: 'todo', type: _type.INT, required: true },
                 // 取费类型
-                {name: 'CalculationKind', value: 'todo', type: _type.INT, required: true},
+                { name: 'CalculationKind', value: 'todo', type: _type.INT, required: true },
                 // 费用归属
-                {name: 'CostKind', value: 'todo', type: _type.INT, required: true},
+                { name: 'CostKind', value: 'todo', type: _type.INT, required: true },
                 // 降效类型
-                {name: 'EfficiencyKind', value: 'todo', type: _type.INT},
+                { name: 'EfficiencyKind', value: 'todo', type: _type.INT },
                 // 子目增加费类型
-                {name: 'IncFeeKind', value: 'todo', type: _type.INT},
+                { name: 'IncFeeKind', value: 'todo', type: _type.INT },
                 // 换算说明
-                {name: 'Conversion', value: 'todo'},
+                { name: 'Conversion', value: 'todo' },
                 // 专业类别
-                {name: 'Specialty', value: 'todo', type: _type.INT},
+                { name: 'Specialty', value: 'todo', type: _type.INT },
                 //定额标识
-                {name: 'NormIdentity', value: 'todo'},
+                { name: 'NormIdentity', value: 'todo' },
                 // 册 定额书没有分册填写0,有分册的按册号填写
-                {name: 'Volume', value: 'todo', type: _type.INT},
+                { name: 'Volume', value: 'todo', type: _type.INT },
                 // 章
-                {name: 'Chapter', value: 'todo', type: _type.INT},
-                {name: 'Remark', value: src.remark}
+                { name: 'Chapter', value: 'todo', type: _type.INT },
+                { name: 'Remark', value: src.remark }
             ];
             _base.Element.call(this, 'Norm', attrs);
         }

+ 11 - 1
web/building_saas/main/js/models/main_consts.js

@@ -276,7 +276,17 @@ const fixedFlag = {
     //组织措施费
     ORGANIZATION:32,
     //其他措施费
-    OTHER_MEASURE_FEE:33
+    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
 };
 // 只读的固定类别(工程量、单价、综合合价只读,相当于是标题)
 const titleFlags = [

+ 19 - 12
web/building_saas/main/js/models/overHeight.js

@@ -286,10 +286,10 @@ const OVER_HEIGHT = (() => {
         TREE_SHEET_HELPER.massOperationSheet(sheet, func);
     }
 
-    // 获取措施技术项目底下固定的节点(011704001...): 选项二时
-    function getTechFixedNode() {
-        const measureNode = projectObj.project.mainTree.items.find(node => node.getFlag() === fixedFlag.CONSTRUCTION_TECH);
-        const measureChildren = measureNode.getPosterity();
+    // 获取其他措施费项目底下固定的节点(011704001...): 选项二时
+    function getMeasureFixedNode() {
+        const otherMeasureNode = projectObj.project.mainTree.items.find(node => node.getFlag() === fixedFlag.OTHER_MEASURE_FEE);
+        const measureChildren = otherMeasureNode.getPosterity();
         return measureChildren.find(node => node.data.code && fixedCodeReg.test(node.data.code));
     }
 
@@ -306,7 +306,7 @@ const OVER_HEIGHT = (() => {
         if (option === Option.SEPARATION) {
             return true;
         } else if (option === Option.MEASURE) {
-            const isValid = !!getTechFixedNode();
+            const isValid = !!getMeasureFixedNode();
             if (!isValid) {
                 $('#overHeightMeasure').modal('show');
             }
@@ -564,16 +564,17 @@ const OVER_HEIGHT = (() => {
         const { option, specificID } = action;
         // 生成清单数据
         function initMountedBills() {
-            // 生成的清单位置为施工技术措施项目的最末子项
-            const measureNode = projectObj.project.mainTree.items.find(node => node.getFlag() === fixedFlag.CONSTRUCTION_TECH);
-            const parent = measureNode.children[measureNode.children.length - 1];
+            // 生成的清单位置为其他措施项目的首项
+            const measureNode = projectObj.project.mainTree.items.find(node => node.getFlag() === fixedFlag.OTHER_MEASURE_FEE);
+            const firstNode = measureNode.children[0];
+            //const parent = measureNode.children[measureNode.children.length - 1];
             // 具体完整数据需要在后端跟标准数据对比完善
             return {
                 projectID: projectObj.project.ID(),
                 billsLibId: +projectObj.project.projectInfo.engineeringInfo.bill_lib[0].id,
                 ID: uuid.v1(),
-                ParentID: parent.data.ID,
-                NextSiblingID: -1,
+                ParentID: measureNode.data.ID,
+                NextSiblingID: firstNode ? firstNode.data.ID : -1,
                 type: billType.BILL,
                 code: fixedCode,
                 name: '超高施工增加',
@@ -588,7 +589,7 @@ const OVER_HEIGHT = (() => {
                 bills: null,
             };
         } else if (option === Option.MEASURE) {   // 选项二且造价书没有相关清单,需要插入清单
-            const fixedNode = getTechFixedNode();
+            const fixedNode = getMeasureFixedNode();
             return {
                 isNew: !fixedNode,
                 bills: fixedNode ? fixedNode.data : initMountedBills(),
@@ -876,6 +877,7 @@ const OVER_HEIGHT = (() => {
             // 重算相关节点
             projectObj.project.calcProgram.calcNodesAndSave(reCalcNodes);
         } catch (err) {
+            alert(err);
             console.log(err);
             recoverCellsText();
             $.bootstrapLoading.end();
@@ -947,6 +949,11 @@ const OVER_HEIGHT = (() => {
             if (project) {
                 const property = projectObj.project.projectInfo.property;
                 Object.assign(property, project);
+                // 更新节点(控制基数只读性,指定清单基数列只读)
+                const specificNode = getSpecificNode(property.overHeightSpecificID);
+                if (specificNode) {
+                    TREE_SHEET_HELPER.refreshTreeNodeData(projectObj.mainController.setting, projectObj.mainController.sheet, [specificNode], false);
+                }
             }
             const mainTree = projectObj.project.mainTree;
             // 更新节点超高降效
@@ -1129,7 +1136,7 @@ const OVER_HEIGHT = (() => {
                     handleConfirmed(false, { option, specificID: null });
                     break;
                 case Option.MEASURE:
-                    const fixedNode = getTechFixedNode();
+                    const fixedNode = getMeasureFixedNode();
                     // 造价书不存在相关清单,提示是否新增清单,由提示窗口进行后续操作
                     if (!fixedNode) {
                         $('#overHeightMeasure').modal('show');

+ 28 - 1
web/building_saas/main/js/models/project.js

@@ -410,6 +410,20 @@ var PROJECT = {
             }
             return true;
         };
+        project.prototype.updateProjectProperty = function(datas,field,callback){
+            let pfield = "property."+field;
+            let tem ={
+                type:'project',
+                data:{ID:projectObj.project.ID()}
+            };
+            tem.data[pfield] = datas;
+
+            projectObj.project.updateNodes([tem],function () {
+                projectObj.project.property[field] = datas;
+                if(callback) callback();
+            })
+
+        };
         project.prototype.updateCasCadeBills = function(node,newval,fieldName){
             let datas = [];
             let data =  {
@@ -474,7 +488,6 @@ var PROJECT = {
                 data[fieldName] = avalue;
                 if(fieldName == "outPutMaxPrice") data.maxPrice = null;
             }
-
         };
         project.prototype.updateNodesAndRefresh=function (datas,callback) {
             let me = this;
@@ -484,6 +497,18 @@ var PROJECT = {
             })
         };
 
+        project.prototype.syncUpdateNodesAndRefresh =async function (datas) {
+            let me = this;
+            return new Promise(function (resolve, reject) {
+                me.updateNodes(datas,function (result) {
+                    let nodes = me.updateNodesCache(result);
+                    projectObj.mainController.refreshTreeNode(nodes);
+                    resolve(nodes);
+                });
+            });
+        };
+
+
         project.prototype.updateNodes = function (datas,callback) {
           /*  let datas = [
                 {
@@ -522,6 +547,8 @@ var PROJECT = {
                         temObj = temNode.data;
                         refreshNode.push(temNode);
                     }
+                }else if(d.type == ModuleNames.project){
+                    temObj = this;
                 }else {//其它类型,更新datas
                     temObj = _.find(this[d.type].datas,{"ID":d.data.ID});
                 }

+ 143 - 0
web/building_saas/main/js/views/area_increase_fee_view.js

@@ -0,0 +1,143 @@
+/**
+ * Created by zhang on 2020/1/10.
+ */
+let areaIncreaseFeeObj = {
+    setDefaultSetting:function () {
+        if(!gljUtil.isDef(projectObj.project.property.areaSetting)){
+            let data={
+                labour:10,
+                material:1.5,
+                machine:0,
+            };
+            projectObj.project.updateProjectProperty(data,"areaSetting")
+        }
+
+    },
+    casCadeUpdate:async function (node,newval,fieldName) {
+        let datas = [];
+        let data =  {
+            type:node.sourceType,
+            data:{ID:node.data.ID}
+        };
+        setData(data.data,newval,fieldName);
+        datas.push(data);
+        setChildren(node,newval,datas);//同步设置所有子项
+        let nodes = await projectObj.project.syncUpdateNodesAndRefresh(datas);
+        projectObj.project.calcProgram.calcNodesAndSave(nodes,function () {
+            OVER_HEIGHT.reCalcOverHeightFee();
+        });
+
+
+        function setChildren(pnode,newValue,datas) {//同步设置所有子项
+            if(pnode.children.length > 0 && (pnode.children[0].sourceType == ModuleNames.bills || pnode.children[0].sourceType == ModuleNames.ration)){//设置子项
+                for(let c of pnode.children){
+                    let data =  {
+                        type:c.sourceType,
+                        data:{ID:c.data.ID}
+                    };
+                    setData(data.data,newval,fieldName);
+                    datas.push(data);
+                    setChildren(c,newValue,datas)
+                }
+            }
+        }
+        function setData(data,avalue,fieldName) {
+            data[fieldName] = avalue;
+            if(fieldName == "outPutMaxPrice") data.maxPrice = null;
+        }
+    },
+    confirmAreaIncreaseFeeSetting:async function () {
+        let labour = $("#areaIncreaseFee_labour").val();
+        let material = $("#areaIncreaseFee_material").val();
+        let machine = $("#areaIncreaseFee_machine").val();
+        if(!settingNumCheck(labour,"人工")) return;
+        if(!settingNumCheck(material,"材料")) return;
+        if(!settingNumCheck(machine,"机械")) return;
+
+        let areaSetting = {
+            labour:scMathUtil.roundForObj(labour,2),
+            material:scMathUtil.roundForObj(material,2),
+            machine:scMathUtil.roundForObj(machine,2)
+        };
+        let tem ={
+            type:'project',
+            data:{ID:projectObj.project.ID(),"property.areaSetting":areaSetting}
+        };
+        $('#areaIncreaseFeeDiv').modal('hide');
+        let needUpdate = false;
+        for(let key in areaSetting){
+            if(areaSetting[key] != projectObj.project.property.areaSetting[key]){
+                needUpdate = true;
+                break;
+            }
+        }
+        if(needUpdate){
+            let datas = this.getAreaIncreaseDatas();
+            datas.push(tem);
+            let nodes = await projectObj.project.syncUpdateNodesAndRefresh(datas);
+            projectObj.project.calcProgram.calcNodesAndSave(nodes);
+        }
+
+        function settingNumCheck(value,type) {
+            if(!number_util.isNum(value)){
+                alert("输入的"+type+"数据类型不对,请重新输入!");
+                return   false;
+            }
+            if(parseFloat(value) < -100){
+                alert("输入的"+type+"不能小于负100,请重新输入!");
+                return false
+            }
+            return true;
+        }
+    },
+     getAreaIncreaseDatas:function (withBills = false) {
+        let datas = [];
+        let rations = projectObj.project.Ration.datas;
+        for(let r of rations){
+            if(r.areaIncreaseFee == true){
+                datas.push({type:"ration",data:{ID:r.ID,areaIncreaseFee:true}})
+            }
+        }
+        if(withBills == true){
+            let bills = projectObj.project.Bills.datas;
+            for(let b of bills){
+                if(b.areaIncreaseFee == true){
+                    datas.push({type:"bills",data:{ID:b.ID,areaIncreaseFee:true}})
+                }
+            }
+        }
+        return datas;
+     },
+    cancelAreaIncreaseFee:async function () {
+        let datas = this.getAreaIncreaseDatas(true);
+        //将值设置为false
+        for(let d of datas){
+            d.data.areaIncreaseFee = false;
+        }
+        let nodes = await projectObj.project.syncUpdateNodesAndRefresh(datas);
+        projectObj.project.calcProgram.calcNodesAndSave(nodes,function () {
+            OVER_HEIGHT.reCalcOverHeightFee();
+        });
+    }
+    
+};
+
+
+
+$(function () {
+    $("#areaIncreaseFeeConfirm").on("click",async function(e){
+        areaIncreaseFeeObj.confirmAreaIncreaseFeeSetting();
+    });
+
+    $('#areaIncreaseFeeDiv').on('show.bs.modal', function (e) {
+        let areaSetting = {
+            labour:10,
+            material:1.5,
+            machine:0,
+        };
+        if(gljUtil.isDef(projectObj.project.property.areaSetting)) areaSetting = projectObj.project.property.areaSetting;
+        $("#areaIncreaseFee_labour").val(areaSetting.labour);
+        $("#areaIncreaseFee_material").val(areaSetting.material);
+        $("#areaIncreaseFee_machine").val(areaSetting.machine);
+    });
+});

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

@@ -550,6 +550,7 @@ $(document).ready(function(){
             calcProgramManage.buildSheet()
         else
             calcProgramManage.mainSpread.refresh();
+        calcProgramManage.detailSheet.setRowCount(calcProgramManage.datas[0].calcItems.length, GC.Spread.Sheets.SheetArea.viewport);
     });
 
     $("#calcProgramFileSelect").change(function() {

+ 1 - 10
web/building_saas/main/js/views/index_view.js

@@ -509,18 +509,9 @@ let indexObj= {
 
     },
     updateProjectProperty: function(datas,field){
-        let pfield = "property."+field;
-        let tem ={
-            type:'project',
-            data:{ID:projectObj.project.ID()}
-        };
-        tem.data[pfield] = datas;    
-             
-        projectObj.project.updateNodes([tem],function () {
-            projectObj.project.property[field] = datas;
+        projectObj.project.updateProjectProperty(datas,field,function () {
             indexObj.showDatas();
         })
-
     },
     getNewPropertyData:function (datas,property) {
         if(!property) return null;

+ 99 - 0
web/building_saas/main/js/views/item_increase_fee_view.js

@@ -0,0 +1,99 @@
+/**
+ * Created by zhang on 2020/1/17.
+ */
+let itemBaseOptions = ["人工费","材料费","机械费","人工费+材料费","人工费+机械费","人工费+材料费","材料费+机械费","人工费+材料费+机械费"];
+let itemIncreaseFeeObj = {
+    settingSpread:null,
+    itemSetting:{
+        header:[
+            {headerName: "名称", headerWidth: 270, dataCode: "name", dataType: "String"},
+            {headerName: "范围", headerWidth: 70, dataCode: "displayScope",hAlign: "center",dataType: "String"},
+            {headerName: "取费基数", headerWidth: 150, dataCode: "base",  hAlign: "center", dataType: "String",cellType:'comboBox',options:itemBaseOptions},
+            {headerName: "系数(%)", headerWidth: 55, dataCode: "coe", hAlign: "center", dataType: "Number",validator:"number"}
+        ],
+        view: {
+            lockColumns: ["code","specs"],
+            rowHeaderWidth:25,
+            colHeaderHeight:36
+        },
+        autoFit:true,
+        fitRow:['name']
+    },
+    settingDatas:[],
+    initSpread:function () {
+        if(this.settingSpread) return this.settingSpread.refresh();
+        this.settingSpread = SheetDataHelper.createNewSpread($("#itemIncreaseFee_sheet")[0]);
+        sheetCommonObj.spreadDefaultStyle(this.settingSpread);
+        this.settingSheet = this.settingSpread.getSheet(0);
+        sheetCommonObj.initSheet(this.settingSheet, this.itemSetting, 4);
+        this.settingSheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onItemSelectionChange);
+        this.settingSheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onItemValueChange);
+    /*   ;
+
+        this.settingSheet.bind(GC.Spread.Sheets.Events.EditStarting,this.onElectrovalenceEditStarting);*/
+        /*
+         ;*/
+        this.settingSheet.name('itemIncreaseFee_sheet');
+        if(projectReadOnly){
+            disableSpread(this.settingSpread);
+        }
+    },
+    onItemSelectionChange:function (sender,args) {
+        args.sheet.repaint();
+    },
+    showDatas:function(datas){
+        let sel = this.settingSheet.getSelections()[0];
+        let oldData = sel.row<this.settingDatas.length?this.settingDatas[sel.row]:"";
+        this.settingSheet.setRowCount(0);
+        this.settingDatas = datas?datas:this.getItemSettingDatas();
+        sheetCommonObj.showData(this.settingSheet, this.itemSetting,this.settingDatas);
+        this.settingSheet.setRowCount(this.settingDatas.length);
+        sel.row =  oldData?_.findIndex(this.settingDatas,{'name':oldData.name}):sel.row ;
+        this.settingSheet.setSelection(sel.row==-1?0:sel.row,sel.col,sel.rowCount,sel.colCount);
+    },
+    getItemSettingDatas:function () {
+        let datas = [];
+        if(projectObj.project.property.itemIncreaseSetting){
+            for(let i of projectObj.project.property.itemIncreaseSetting){
+                let d = {name:i.name,displayScope:"范围",scope:i.scope,base:i.base,coe:i.coe};
+                if(_.isEmpty(d.scope)){
+                    d.foreColor = "#ff2a23";
+                    d.styleCol = 1;
+                }
+                datas.push(d);
+            }
+        }
+        return datas;
+    },
+    onItemValueChange:function (sender,args) {
+        let me = itemIncreaseFeeObj;
+        let dataCode = me.itemSetting.header[args.col].dataCode;
+        let value = args.newValue;
+        let tem = me.settingDatas[args.row];
+        if (value&&!sheetCommonObj.checkData(args.col,me.itemSetting,value)) {
+            alert('输入的数据类型不对,请重新输入!');
+            return  me.showDatas(me.settingDatas);
+        }
+        if(dataCode == 'coe') {
+            if (value) value = scMathUtil.roundForObj(value, 2);
+        }
+        tem[dataCode] = value;
+        me.showDatas(me.settingDatas);
+    }
+};
+
+
+
+
+
+
+$(function () {
+   /* $("#areaIncreaseFeeConfirm").on("click",async function(e){
+        areaIncreaseFeeObj.confirmAreaIncreaseFeeSetting();
+    });*/
+
+    $('#itemIncreaseFeeDiv').on('shown.bs.modal', function (e) {
+        itemIncreaseFeeObj.initSpread();
+        itemIncreaseFeeObj.showDatas();
+    });
+});

+ 18 - 15
web/building_saas/main/js/views/main_tree_col.js

@@ -117,8 +117,10 @@ let MainTreeCol = {
                 if (calcTools.isTitleBills(node)) {
                     return true;
                 }
-                // 当前属于分部分项、施工技术措施项目,综合单价只读。
-                if(Bills.isFBFX(node)||Bills.isTechMeasure(node)) return true;
+                // 当前属于不可通过自身数据计算合价的部分,单价只读
+                if (Bills.cantCalcToTalFeeByOwn(node)) {
+                    return true;
+                }
                 // 不属于分部分项、施工技术措施项目的部分,如果不是叶子清单,或有基数计算/定额/量价/人材机 只读
                 if(!calcTools.isLeafBill(node)||calcTools.isCalcBaseBill(node)||node.children.length > 0)return true;
             }
@@ -134,8 +136,8 @@ let MainTreeCol = {
             }
             // 09-29 zhang
             let Bills =projectObj.project.Bills;
-            // 当前属于分部分项、施工技术措施项目,综合单价只读。
-            if(Bills.isFBFX(node)||Bills.isTechMeasure(node)){
+            // 当前属于不可通过自身数据计算合价的部分,合价只读
+            if (Bills.cantCalcToTalFeeByOwn(node)) {
                 return true;
             }
             // 不属于分部分项、施工技术措施项目的部分,如果不是叶子清单,或有基数计算/定额/量价/人材机 只读
@@ -146,28 +148,24 @@ let MainTreeCol = {
         },
         //根据节点、父节点类型判断是否可用计算基数
         calcBaseType: function (node) {
-            function isDef(v) {
-                return v !== undefined && v !== null;
-            }
-
             function isFlag(v) {
                 return this.isDef(v.flagsIndex) && this.isDef(v.flagsIndex.fixed);
             }
-
+            // 如果清单为超高子目指定清单,则只读
+            if (node.data.ID === projectObj.project.projectInfo.property.overHeightSpecificID) {
+                return true;
+            }
             let calcBase = projectObj.project.calcBase;
             let parent = node.parent;
             if (isFlag(node.data) && (node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.SUB_ENGINERRING
                 || node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CONSTRUCTION_TECH)) {
                 return true;
-            }
-            else if (isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION) {
+            } else if (isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION) {
                 return false;
-            }
-            else {
+            } else {
                 if (!parent) {
                     return false;
-                }
-                else {
+                } else {
                     return this.calcBaseType(parent);
                 }
             }
@@ -420,6 +418,10 @@ let MainTreeCol = {
         mainBills:function (node) {
             if(MainTreeCol.mainBillsEnable(node)) return sheetCommonObj.getCheckBox(true);
         },
+        mainNodeCheckBox:function (node) {//分部分项、措施项目下的清单、定额
+            let Bills = projectObj.project.Bills;
+            if((Bills.isFBFX(node)||Bills.isMeasure(node)) && node.sourceType != ModuleNames.ration_glj) return sheetCommonObj.getCheckBox(false);
+        },
         outPutMaxPrice:function (node) {
             if(MainTreeCol.mainBillsEnable(node)) {
                 // 投标项目,复选框不可改变
@@ -689,6 +691,7 @@ let colSettingObj = {
         for(let i = 0; i < cols.length; i++){
             let colSetting = cols[i];
             if(colSetting.data.field === field){
+                
                 return i;
             }
         }

+ 65 - 2
web/building_saas/main/js/views/project_view.js

@@ -1504,6 +1504,65 @@ var projectObj = {
                         return false;
                     },
                 },
+                "areaIncreaseFee":{
+                    name:"面积增加费",
+                    icon: 'fa-sign-in',
+                    visible:function () {
+                        return  projectObj.project.property.isAreaIncrease == true;
+                    },
+                    items:{
+                        "calcAreaIncreaseFee":{
+                            name:"计取面积增加费",
+                            icon: 'fa-sign-in',
+                            callback:function () {
+                                areaIncreaseFeeObj.setDefaultSetting();
+                                colSettingObj.setVisible('areaIncreaseFee', true);
+                                colSettingObj.updateColSetting(true);
+                            }
+                        },
+                        "setArea":{
+                            name:"设置调整系数",
+                            icon: 'fa-sign-in',
+                            callback:function(){
+                                $("#areaIncreaseFeeDiv").modal('show');
+                            }
+                        },
+                        "cancelAreaIncreaseFee":{
+                            name:"取消面积增加费",
+                            icon: 'fa-sign-in',
+                            callback:function(){
+                                colSettingObj.setVisible('areaIncreaseFee', false);
+                                colSettingObj.updateColSetting(true);
+                                areaIncreaseFeeObj.cancelAreaIncreaseFee();
+                            }
+                        }
+                    }
+                },
+                "itemIncreaseFee":{
+                    name:"子目增加费",
+                    icon: 'fa-sign-in',
+                    visible:function () {
+                        return  projectObj.project.property.isItemIncrease == true;
+                    },
+                    items:{
+                        "setItem":{
+                            name:"设置范围",
+                            icon: 'fa-sign-in',
+                            callback:function(){
+                                $("#itemIncreaseFeeDiv").modal('show');
+                            }
+                        },
+                        "cancelAreaIncreaseFee":{
+                            name:"取消子目增加费",
+                            icon: 'fa-sign-in',
+                            callback:function(){
+                                /*colSettingObj.setVisible('areaIncreaseFee', false);
+                                colSettingObj.updateColSetting(true);
+                                areaIncreaseFeeObj.cancelAreaIncreaseFee();*/
+                            }
+                        }
+                    }
+                },
                 "setBookMark": {
                     name: '设置书签批注',
                     icon: 'fa-flag',
@@ -1890,7 +1949,7 @@ var projectObj = {
             projectObj.onIsEstimateClick(node,info);
         }else if(fieldName == "evaluationProject"){
             projectObj.onEvaluationProjectClic(node,info);
-        }else if(fieldName == "mainBills"||fieldName == "outPutMaxPrice"){
+        }else if(fieldName == "mainBills"||fieldName == "outPutMaxPrice"||fieldName=="areaIncreaseFee"){
             projectObj.onCasCadeButtonClick(node,info,fieldName);
         }
     },
@@ -1940,7 +1999,11 @@ var projectObj = {
         } else {
             newval = true;
         }
-        projectObj.project.updateCasCadeBills(node,newval,fieldName);
+        if(fieldName == "areaIncreaseFee"){
+            areaIncreaseFeeObj.casCadeUpdate(node,newval,fieldName);
+        }else {
+            projectObj.project.updateCasCadeBills(node,newval,fieldName);
+        }
     },
     onSubcontractClick:function (node) {//点击分包费checkbox
         if (node.data.isSubcontract) node.data.isSubcontract = false;

+ 40 - 5
web/building_saas/pm/html/project-management.html

@@ -667,7 +667,7 @@
                                 <select class="form-control" id="otherFileOptions">
                                     <option>10.9建筑例题内测单价文件</option><!--建设项目下单价文件-->
                                 </select>
-                                <span class="form-text text-muted">你选择的文件将复制一份至新项目,不会影响原建设项目的文件。</span>
+                                <span class="form-text text-muted">您选择的文件将复制一份至当前项目,不会影响原建设项目的文件。。</span>
                             </div>
                         </div>
 
@@ -718,15 +718,50 @@
                 <div class="form-group">
                     <div class="input-group input-group-sm">
                         <input id="sharePhone" type="text" class="form-control" placeholder="输入 手机号 添加分享" autofocus="autofocus">
-                       <!-- <div class="input-group-append">
-                            <button class="btn btn-primary" type="button" id="button-addon2">添加分享</button>
-                        </div>-->
+                        <div class="input-group-append">
+                            <a class="btn btn-outline-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuBook">
+                              最新分享
+                            </a>
+                            <div id="shareSubMenu" class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuBook" style="width: 250px;">
+                              <div class="">
+                                  <ul class="nav nav-tabs nav-fill mx-1">
+                                      <li class="nav-item">
+                                          <a class="nav-link active" id="zuijin-tab" data-toggle="tab" href="#zuijin" role="tab" aria-controls="zuijin" aria-selected="true">最近分享</a>
+                                        </li>
+                                        <li class="nav-item">
+                                          <a class="nav-link" id="lianxi-tab" data-toggle="tab" href="#lianxi" role="tab" aria-controls="lianxi" aria-selected="false">联系人</a>
+                                        </li>
+                                  </ul>
+                                  <div class="tab-content" id="myTabContent">
+                                    <div class="tab-pane fade show active" id="zuijin" role="tabpanel" aria-labelledby="zuijin-tab">
+                                      <!--最近分享5个人-->
+                                      <ul class="book-list" id="recentList">
+                                      </ul>
+                                    </div>
+                                    <div class="tab-pane fade" id="lianxi" role="tabpanel" aria-labelledby="lianxi-tab">
+                                        <ul class="book-list" id="contactsList">
+                                      </ul>
+                                    </div>
+                                  </div>
+                              </div>
+                            </div>
+                      </div>
                     </div>
                 </div>
                 <table class="table table-sm" id="shareFindDiv">
                     <tbody style="display: block">
                     <tr><th style="width: 112px;">姓名</th><th style="width: 165px;">公司</th><th style="width: 136px;">手机</th><th style="width: 160px;">邮箱</th><th style="width: 90px;">允许拷贝</th><th style="width: 90px;">允许编辑</th><th style="width: 90px;">添加分享</th></tr>
-                    <tr><td id="user_name">张三</td><td id="user_company">XX公司</td><td id="user_mobile">12345678900</td><td id="user_email"></td><td><input id="allowCopy" type="checkbox"></td><td><input id="allowCooperate" type="checkbox"></td><td><a id="share-confirm" href="javascript:void(0)" class="btn btn-sm btn-primary">添加分享</a></td></tr>
+                    <tr>
+                        <td id="user_name"></td>
+                        <td id="user_company"></td>
+                        <td id="user_mobile"></td>
+                        <td id="user_email"></td>
+                        <td><input id="allowCopy" type="checkbox"></td>
+                        <td><input id="allowCooperate" type="checkbox"></td>
+                        <td>
+                            <a id="share-confirm" href="javascript:void(0)" class="btn btn-sm btn-primary">添加分享</a>
+                        </td>
+                    </tr>
                     </tbody>
                 </table>
                 <p id="share-info" class="text-danger">不存在手机号 15812777651 的用户</p>

+ 2 - 0
web/building_saas/pm/js/pm_import.js

@@ -257,6 +257,8 @@ const importView = (() => {
             engineeringName: curEngineering.lib.name,
             taxType: parseInt(tbcObj.taxType),    //计税方法
             isInstall: !!curEngineering.lib.isInstall,  //是安装工程?
+            isItemIncrease: !!curEngineering.lib.isItemIncrease,  //是否子目增加费?
+            isAreaIncrease: !!curEngineering.lib.isAreaIncrease,  //是否子目增加费?
             feeStandardName: curEngineering.lib.feeName,    //费用标准
             engineering: curEngineering.lib.engineering,    //定额取费专业
             projectEngineering: curEngineering.lib.projectEngineering,  //单位工程取费专业

+ 139 - 42
web/building_saas/pm/js/pm_newMain.js

@@ -52,7 +52,6 @@ let regions = [];
 function isDef(v) {
     return typeof v !== 'undefined' && v !== null;
 }
-
 let keyupTime = 0,
     delayTime = 500;
 function delayKeyup(callback) {
@@ -425,7 +424,7 @@ const projTreeObj = {
             }
         },
         refreshSummary: {
-            name: "刷新当前项目造价",
+            name: "刷新项目造价",
             icon: 'fa-refresh',
             disabled: function () {
                 let selectedItem = projTreeObj.tree.selected;
@@ -1176,7 +1175,9 @@ const projTreeObj = {
             sheet.setRowCount(nodes.length);
             let treeNodeCell = me.getTreeNodeCell(tree);
             sheet.getRange(-1, 0, -1, 1).cellType(treeNodeCell);
+            const rows = [];
             for(let i = 0; i < nodes.length; i++){
+                rows.push(i);
                 for(let j = 0; j < headers.length; j++){
                     sheet.getRange(-1, j, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[j]['hAlign']]);
                     sheet.getRange(-1, j, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[j]['vAlign']]);
@@ -1192,6 +1193,7 @@ const projTreeObj = {
                     sheet.setRowVisible(nodes[i].serialNo(), nodes[i].visible);
                 }
             }
+            //sheetCommonObj.setRowsAutoFit(sheet, rows, 0, true);
         };
         me.renderSheetFuc(sheet, fuc);
     },
@@ -1698,7 +1700,90 @@ function setupRequiredWarn(compilation) {
         map[compilation.name] ? $warn.html(map[compilation.name]) : $warn.html('');
     }
 }
+
+// 显示最近分享信息
+function showRecentShareInfo() {
+    function getBookListHtml(users) {
+        return users.reduce((acc, user) => {
+            const mobile = user.mobile || '';
+            const realName = user.real_name || '';
+            const company = user.company || '';
+            // 手机最后一位
+            const lastMobileNumer = mobile.substring(mobile.length - 1);
+            // 显示名称为真实名称后两位
+            const nickName = realName.substring(realName.length - 2);
+            return acc +
+            `<li>
+                <span class="avatar bg-${lastMobileNumer}">${nickName}</span>
+                <div class="book-body">
+                    <h5 class="mt-0" title="${company}">${realName}</h5>
+                    <span class="mobile-info">${mobile}</span>
+                </div>
+            </li>`;
+        }, '');
+        
+    }
+    $.bootstrapLoading.start();
+    CommonAjax.post('/pm/api/getRecentShareInfo', {user_id: userID, count: 5}, (data) => {
+        const recentHtml = getBookListHtml(data.recentUsers);
+        // 联系人按拼英首字母降序排序
+        data.contacts.sort((a, b) => {
+            const realNameA = a.real_name || '';
+            const realNameB = b.real_name || '';
+            return realNameA.localeCompare(realNameB, 'zh-Hans-CN', {sensitivity: 'accent'})
+        });
+        const contactsHtml = getBookListHtml(data.contacts);
+        $('#recentList').html(recentHtml);
+        $('#contactsList').html(contactsHtml);
+        $('#myTabContent ul li').click(function () {
+            const mobile = $(this).find('.mobile-info')[0].textContent;
+            $('#sharePhone').val(mobile);
+            shareTender();
+            const $subMenu = $('#shareSubMenu');
+            const subMenu = $subMenu[0];
+            $(subMenu.parentElement).removeClass('show');
+            $subMenu.removeClass('show');
+        });
+        $.bootstrapLoading.end();
+    }, () => {
+        $.bootstrapLoading.end();
+    });
+}
+
 $(document).ready(function() {
+    // 最近分享、联系人列表相关
+    $('body').click(function (e) {
+        const body = $(this)[0];
+        const $subMenu = $('#shareSubMenu');
+        const subMenu = $subMenu[0];
+        const menuBook = $('#dropdownMenuBook')[0]
+        if (!$subMenu.is(':visible')) {
+            return;
+        }
+        let target = e.target;
+        while (target !== body) {
+            if ([subMenu, menuBook].includes(target)) {
+                return;
+            }
+            target = target.parentElement;
+        }
+        $(subMenu.parentElement).removeClass('show');
+        $subMenu.removeClass('show');
+    });
+    // 最近分享、联系人列表相关
+    $('#dropdownMenuBook').click(function () {
+        const $subMenu = $('#shareSubMenu');
+        const visible = $subMenu.is(':visible');
+        if (visible) {
+            $(this).parent().removeClass('show');
+            $subMenu.removeClass('show');
+        } else {
+            $(this).parent().addClass('show');
+            $subMenu.addClass('show');
+            showRecentShareInfo();
+        }
+    });
+
     // 单位工程超限提示后,弹出客服列表
     $('#hintBox_form').on('hide.bs.modal', function () {
         const text = $('#hintBox_caption').text();
@@ -2865,6 +2950,7 @@ function initProjects(callback) {
             projTreeObj.sumEngineeringCost();
             initNodesVisibility(projTreeObj.tree.items, false);
             projTreeObj.showTreeData(projTreeObj.tree.items, projTreeObj.setting, sheet);
+            const rows = projTreeObj.tree.items.map((item, index) => index);
             //初始选择
             const initSel = sheet.getSelections()[0] ? sheet.getSelections()[0] : { row: 0, rowCount: 1 };
             projTreeObj.initSelection(initSel, null, sheet);
@@ -3101,7 +3187,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
                 projID, {updateType: 'new', projectType: projectType.project});
             let updateEng = {updateType: 'new', updateData: {ID: engID, ParentID: projID, NextSiblingID: -1, name: engName, projType: projectType.engineering}};
             property.rootProjectID = projID;
-            let updateTender = {updateType: 'new', updateData: {ID: tenderID, ParentID: engID, NextSiblingID: -1, shareInfo: [], name: tenderName, projType: projectType.tender, property: property}};
+            let updateTender = {updateType: 'new', updateData: {ID: tenderID, ParentID: engID, NextSiblingID: -1, name: tenderName, projType: projectType.tender, property: property}};
             updateDatas = updateDatas.concat(updateProjs);
             updateDatas.push(updateEng);
             updateDatas.push(updateTender);
@@ -3109,6 +3195,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
                 let projData, engData, tenderData;
                 datas.forEach(function (data) {
                     if (data.updateType === 'new') {
+                        data.updateData.shareInfo = [];
                         setInitSummaryData(data.updateData);
                         if(data.updateData.projType === projectType.project){
                             projData = data.updateData;
@@ -3124,7 +3211,9 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
                 });
                 let pojNode = projTreeObj.insert(projData, parent, next);
                 let engNode = projTreeObj.insert(engData, pojNode, null);
-                projTreeObj.insert(tenderData, engNode, null);
+                let tenderNode = projTreeObj.insert(tenderData, engNode, null);
+                /* const rows = [pojNode.serialNo(), engNode.serialNo(), tenderNode.serialNo()];
+                sheetCommonObj.setRowsAutoFit(projTreeObj.workBook.getSheet(0), rows, 0, true) */
                 callback();
             }, errCB);
         }, errCB);
@@ -3136,7 +3225,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
             let next = null;
             let updateEng = {updateType: 'new', updateData: {ID: engID, ParentID: tempProj.data.ID, NextSiblingID: -1, name: engName, projType: projectType.engineering}};
             property.rootProjectID = tempProj.data.ID;
-            let updateTender = {updateType: 'new', updateData: {ID: tenderID, ParentID: engID, NextSiblingID: -1,  shareInfo: [], name: tenderName, projType: projectType.tender, property: property}};
+            let updateTender = {updateType: 'new', updateData: {ID: tenderID, ParentID: engID, NextSiblingID: -1, name: tenderName, projType: projectType.tender, property: property}};
             if(selected && selected.data.projType === projectType.engineering && selected.parent === tempProj){
                 pre = selected;
                 next = selected.nextSibling;
@@ -3151,6 +3240,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
                 let engData, tenderData;
                 datas.forEach(function (data) {
                     if (data.updateType === 'new') {
+                        data.updateData.shareInfo = [];
                         setInitSummaryData(data.updateData);
                         if(data.updateData.projType === projectType.engineering){
                             engData = data.updateData;
@@ -3162,7 +3252,9 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
                     }
                 });
                 let engNode = projTreeObj.insert(engData, tempProj, next);
-                projTreeObj.insert(tenderData, engNode, null);
+                let tenderNode = projTreeObj.insert(tenderData, engNode, null);
+                /* const rows = [engNode.serialNo(), tenderNode.serialNo()];
+                sheetCommonObj.setRowsAutoFit(projTreeObj.workBook.getSheet(0), rows, 0, true); */
                 callback();
             }, errCB);
         }, errCB);
@@ -3172,7 +3264,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
             let tenderID = IDs.lowID;
             let pre = tempEng.lastChild();
             property.rootProjectID = tempProj.data.ID;
-            let updateTender = {updateType: 'new', updateData: {ID: tenderID, ParentID: tempEng.id(), NextSiblingID: -1,  shareInfo: [], name: tenderName, projType: projectType.tender, property: property}};
+            let updateTender = {updateType: 'new', updateData: {ID: tenderID, ParentID: tempEng.id(), NextSiblingID: -1, name: tenderName, projType: projectType.tender, property: property}};
             updateDatas.push(updateTender);
             if(pre){
                 updateDatas.push({updateType: 'update', updateData: {ID: pre.id(), NextSiblingID: tenderID}});
@@ -3180,9 +3272,12 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
             UpdateProjectData(updateDatas, function (datas) {
                 datas.forEach(function (data) {
                     if(data.updateType === 'new') {
+                        data.updateData.shareInfo = [];
                         setInitSummaryData(data.updateData);
                         data.updateData.feeStandardName = data.updateData.property.feeStandardName || '';
-                        projTreeObj.insert(data.updateData, tempEng, null);
+                        let tenderNode = projTreeObj.insert(data.updateData, tempEng, null);
+                        /* const rows = [tenderNode.serialNo()];
+                        sheetCommonObj.setRowsAutoFit(projTreeObj.workBook.getSheet(0), rows, 0, true); */
                     }
                 });
                 callback();
@@ -3220,8 +3315,10 @@ function AddChildrenItem(selected, name, property, type, existCallback, sucCallb
             UpdateProjectData(updateData, function(datas){
                 datas.forEach(function (data) {
                     if (data.updateType === 'new') {
+                        data.updateData.shareInfo = [];
                         setInitSummaryData(data.updateData);
-                        projTreeObj.insert(data.updateData, parent, null);
+                        let node = projTreeObj.insert(data.updateData, parent, null);
+                        //sheetCommonObj.setRowsAutoFit(projTreeObj.workBook.getSheet(0), [node.serialNo()], 0, true);
                     }
                 });
                 sucCallback();
@@ -3258,8 +3355,10 @@ function AddSiblingsItem(selected, name, property, type, existCallback, sucCallb
             UpdateProjectData(updateData, function(datas){
                 datas.forEach(function (data) {
                     if (data.updateType === 'new') {
+                        data.updateData.shareInfo = [];
                         setInitSummaryData(data.updateData);
-                        projTreeObj.insert(data.updateData, parent, next);
+                        const node = projTreeObj.insert(data.updateData, parent, next);
+                        //sheetCommonObj.setRowsAutoFit(projTreeObj.workBook.getSheet(0), [node.serialNo()], 0, true)
                     }
                 });
                 sucCallback();
@@ -3770,6 +3869,8 @@ function AddTender() {
             valuationType: valuationType,
             valuationName: valuationName,
             isInstall: libs.isInstall !== undefined ? libs.isInstall : false,
+            isItemIncrease: !!libs.isItemIncrease,
+            isAreaIncrease: !!libs.isAreaIncrease,
             engineering: libs.engineering,//定额默认取费专业
             projectEngineering:libs.projectEngineering,//单位工程默认取费专业(造价书中插入量价、工料机时用)
             engineering_id: libs._id,
@@ -4606,8 +4707,8 @@ function shareTender(){
             coopInput.prop('checked', false);
             userInfo.show();
             //判断项目是否已经分享
-            CommonAjax.post('/pm/api/getProjectShareInfo', {user_id: userID, projectID: shareSeleted.data.ID}, function (rstData) {
-                for(let shareData of rstData.shareInfo){
+            CommonAjax.post('/pm/api/getProjectShareInfo', {user_id: userID, projectID: shareSeleted.data.ID}, function (shareInfo) {
+                for(let shareData of shareInfo){
                     if(shareData.userID === userData._id){
                         setDangerInfo(hintInfo, '已与该用户分享。', true);
                         return;
@@ -4649,7 +4750,7 @@ $('#share-confirm').click(function(){
                         <td style="width: 90px;"><input value="allowCopy" ${allowCopy ? 'checked' : ''} type="checkbox"></td>
                         <td style="width: 90px;"><input value="allowCooperate" ${allowCoop ? 'checked' : ''} type="checkbox"></td>
                         <td style="width: 90px;"><input value="cancelShare" type="checkbox"></td>
-                     </tr>`);
+                    </tr>`);
         let tbodyTotalHeight = $('#shareToInfo').height() + perHeight > 200 ? 200 : $('#shareToInfo').height() + perHeight;
         $('#shareToInfo').height(tbodyTotalHeight);
         $('#shareToInfo').append($tr);
@@ -4807,28 +4908,28 @@ function setShareToModal(selected){
         let infoArr = [];
         //居中style="width: 90px;text-align: center"
         let theadHtml = `<tr>
-                                          <th style="width: 112px;">姓名</th>
-                                          <th style="width: 165px;">公司</th>
-                                          <th style="width: 136px;">手机</th>
-                                          <th style="width: 136px;">邮箱</th>
-                                          <th style="width: 90px;">允许拷贝</th>
-                                          <th style="width: 90px;">允许编辑</th>
-                                          <th style="width: 90px;">取消分享</th>
-                               </tr>`;
+                            <th style="width: 112px;">姓名</th>
+                            <th style="width: 165px;">公司</th>
+                            <th style="width: 136px;">手机</th>
+                            <th style="width: 136px;">邮箱</th>
+                            <th style="width: 90px;">允许拷贝</th>
+                            <th style="width: 90px;">允许编辑</th>
+                            <th style="width: 90px;">取消分享</th>
+                        </tr>`;
         infoArr.push(theadHtml);
         for(let user of selected.data.shareInfo){
             if (!user.exist) {
                 continue;
             }
             let infoHtml = `<tr>
-                                          <td style="width: 112px;">${user.name}</td>
-                                          <td style="width: 165px;">${user.company}</td>
-                                          <td style="width: 136px;">${user.mobile}</td>
-                                          <td style="width: 160px;">${user.email}</td>
-                                          <td style="width: 90px;"><input value="allowCopy" ${user.allowCopy ? 'checked' : ''} type="checkbox"></td>
-                                          <td style="width: 90px;"><input value="allowCooperate" ${user.allowCooperate ? 'checked' : ''} type="checkbox"></td>
-                                          <td style="width: 90px;"><input value="cancelShare" type="checkbox"></td>
-                               </tr>`;
+                                <td style="width: 112px;">${user.name}</td>
+                                <td style="width: 165px;">${user.company}</td>
+                                <td style="width: 136px;">${user.mobile}</td>
+                                <td style="width: 160px;">${user.email}</td>
+                                <td style="width: 90px;"><input value="allowCopy" ${user.allowCopy ? 'checked' : ''} type="checkbox"></td>
+                                <td style="width: 90px;"><input value="allowCooperate" ${user.allowCooperate ? 'checked' : ''} type="checkbox"></td>
+                                <td style="width: 90px;"><input value="cancelShare" type="checkbox"></td>
+                            </tr>`;
             infoArr.push(infoHtml);
         }
         let tbodyTotalHeight = infoArr.length * perHeight + 5 > 200 ? 200 : infoArr.length * perHeight + 5;
@@ -4871,6 +4972,7 @@ function updateShareInfo(selected){
     }
     let newShareInfo = [],
         orgShareInfo = [];
+    const postData = [];
     //数据不同才提交
     for (let shareData of selected.data.shareInfo) {
         orgShareInfo.push({userID: shareData.userID, allowCopy: shareData.allowCopy, allowCooperate: shareData.allowCooperate})
@@ -4882,15 +4984,19 @@ function updateShareInfo(selected){
         let cancelShare = $(userTr).find('input:eq(2)').prop('checked');
         selected.data.shareInfo[i].allowCopy = allowCopy;
         selected.data.shareInfo[i].allowCooperate = allowCoop;
-        if(!cancelShare){
-            //newShareInfo.push(selected.data.shareInfo[i]);
-            newShareInfo.push({userID: selected.data.shareInfo[i].userID, allowCopy: allowCopy, allowCooperate: allowCoop});
+        let shareItem;
+        if(cancelShare){
+            shareItem = {userID: selected.data.shareInfo[i].userID, isCancel: true};
+        } else {
+            shareItem = {userID: selected.data.shareInfo[i].userID, allowCopy: allowCopy, allowCooperate: allowCoop};
+            newShareInfo.push(shareItem);
         }
+        postData.push(shareItem);
     }
     if (_.isEqual(newShareInfo, orgShareInfo)) {
         return;
     }
-    CommonAjax.post('/pm/api/share', {user_id: userID, type: 'update', projectID: selected.data.ID, shareData: newShareInfo}, function (shareData) {
+    CommonAjax.post('/pm/api/share', {user_id: userID, type: 'update', projectID: selected.data.ID, shareData: postData}, function (shareData) {
         selected.data.shareInfo = shareData;
         let sheet = projTreeObj.workBook.getSheet(0);
         projTreeObj.renderSheetFuc(sheet, function () {
@@ -4898,15 +5004,6 @@ function updateShareInfo(selected){
             sheet.repaint();
         });
     });
-    /*CommonAjax.post('/pm/api/updateProjects', {user_id: userID, updateData: [{updateType: 'update', updateData: {ID: selected.data.ID, shareInfo: newShareInfo}}]}, function () {
-        //todo 更新
-        selected.data.shareInfo = newShareInfo;
-        let sheet = projTreeObj.workBook.getSheet(0);
-        projTreeObj.renderSheetFuc(sheet, function () {
-            sheet.invalidateLayout();
-            sheet.repaint();
-        });
-    });*/
 }
 
 //刷新建设项目汇总金额信息

+ 2 - 8
web/building_saas/pm/js/pm_share.js

@@ -178,14 +178,8 @@ const pmShare = (function () {
         }
         //获取最新分享
         shareList.sort(function (a, b) {
-            let aV = Date.parse(a.shareDate),
-                bV = Date.parse(b.shareDate);
-            if (aV > bV) {
-                return -1;
-            } else if (aV < bV) {
-                return 1;
-            }
-            return 0;
+            //return Date.parse(b.shareDate) - Date.parse(a.shareDate)
+            return Date.parse(b.updateDate) - Date.parse(a.updateDate);
         });
         return shareList[0] || null;
 

+ 9 - 0
web/over_write/js/guangdong_2018.js

@@ -27,6 +27,15 @@ function overwriteRationCalcBases (){
     rationCalcBases['设备费'] = function (node, isTender) {
         return calcTools.rationBaseFee(node, [gljType.EQUIPMENT], priceTypes.ptMarketPrice, isTender);
     };
+    // 广东建筑管理费特殊计算:管理费=ROUND(∑(人工费+施工机具费)*定额的管理费费率*0.01,精度)。与定额同级的量价、人材机则按管理费费率为0计算。
+    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 = rst.toDecimal(decimalObj.ration.unitPrice);
+        };
+        return rst;
+    };
     rationCalcBases['工日合计'] = function (node, isTender) {
         return calcTools.labourDays(node, isTender);
     };