Browse Source

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

TonyKang 7 years ago
parent
commit
17eff66b63
34 changed files with 1061 additions and 224 deletions
  1. 15 0
      Dockerfile_pp
  2. 1 0
      config/config.js
  3. 7 0
      modules/complementary_ration_lib/controllers/compleRationController.js
  4. 2 1
      modules/complementary_ration_lib/controllers/compleViewController.js
  5. 29 0
      modules/complementary_ration_lib/controllers/searchController.js
  6. 49 0
      modules/complementary_ration_lib/models/compleRationModel.js
  7. 2 2
      modules/complementary_ration_lib/models/compleViewModel.js
  8. 76 0
      modules/complementary_ration_lib/models/searchModel.js
  9. 7 0
      modules/complementary_ration_lib/routes/routes.js
  10. 54 1
      modules/main/controllers/bills_controller.js
  11. 16 1
      modules/main/models/bills.js
  12. 2 2
      modules/main/models/ration.js
  13. 2 0
      modules/main/routes/bills_route.js
  14. 7 0
      modules/pm/models/project_schema.js
  15. 1 1
      modules/ration_glj/facade/glj_calculate_facade.js
  16. 30 0
      public/web/id_tree.js
  17. 15 0
      public/web/tree_sheet/tree_sheet_controller.js
  18. 6 5
      public/web/tree_sheet/tree_sheet_helper.js
  19. 6 1
      web/building_saas/complementary_ration_lib/js/main.js
  20. 25 0
      web/building_saas/main/html/main.html
  21. 61 8
      web/building_saas/main/js/controllers/project_controller.js
  22. 89 5
      web/building_saas/main/js/models/bills.js
  23. 39 1
      web/building_saas/main/js/models/cache_tree.js
  24. 199 47
      web/building_saas/main/js/models/calc_base.js
  25. 49 43
      web/building_saas/main/js/models/calc_program.js
  26. 18 1
      web/building_saas/main/js/models/ration.js
  27. 4 2
      web/building_saas/main/js/views/calc_base_view.js
  28. 1 1
      web/building_saas/main/js/views/glj_view.js
  29. 40 11
      web/building_saas/main/js/views/main_tree_col.js
  30. 150 61
      web/building_saas/main/js/views/project_view.js
  31. 6 6
      web/building_saas/main/js/views/std_ration_lib.js
  32. 14 14
      web/building_saas/pm/html/project-management.html
  33. 38 9
      web/building_saas/pm/js/pm_main.js
  34. 1 1
      web/users/js/login.js

+ 15 - 0
Dockerfile_pp

@@ -0,0 +1,15 @@
+FROM costbase:latest
+
+WORKDIR /home/ConstructionCost
+
+RUN git pull http://192.168.1.12:3000/SmartCost/ConstructionCost master
+
+RUN cnpm install
+
+RUN gulp build
+
+EXPOSE 6060
+
+ENV NODE_ENV=pp
+
+ENTRYPOINT babel-node server.js

+ 1 - 0
config/config.js

@@ -2,6 +2,7 @@ module.exports = {
     current: {server: "192.168.1.184", port: "60666",redis:{server:'192.168.1.184',port:'6379',pwd:'smartCost'}},
     current: {server: "192.168.1.184", port: "60666",redis:{server:'192.168.1.184',port:'6379',pwd:'smartCost'}},
     local: {server: "localhost", port: "27017"},
     local: {server: "localhost", port: "27017"},
     qa: {server: "192.168.1.184", port: "60666"},
     qa: {server: "192.168.1.184", port: "60666"},
+    pp:{server: "172.18.111.228", port: "27017"},
     prod: {server: "", port: ""},
     prod: {server: "", port: ""},
     redis_local:{server:'127.0.0.1',port:'6379',pwd:'smartCost'},
     redis_local:{server:'127.0.0.1',port:'6379',pwd:'smartCost'},
     redis_qa:{server:'192.168.1.184',port:'6379',pwd:'smartCost'},
     redis_qa:{server:'192.168.1.184',port:'6379',pwd:'smartCost'},

+ 7 - 0
modules/complementary_ration_lib/controllers/compleRationController.js

@@ -78,6 +78,13 @@ class CompleRationController extends BaseController{
         });
         });
     }
     }
 
 
+    getRationGljItemsBySection(req, res){
+        let data = JSON.parse(req.body.data);
+        compleRationDao.getRationGljItemsBySection(req.session.sessionUser.ssoId, data.sectionId, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
     getCoeList(req, res){
     getCoeList(req, res){
         let data = JSON.parse(req.body.data);
         let data = JSON.parse(req.body.data);
         coeListDAO.getCoesByLibID(data.libID, function (err, data) {
         coeListDAO.getCoesByLibID(data.libID, function (err, data) {

+ 2 - 1
modules/complementary_ration_lib/controllers/compleViewController.js

@@ -44,7 +44,8 @@ class CompleViewController extends BaseController{
     }
     }
 
 
     getRationLibs(req, res){
     getRationLibs(req, res){
-        compleViewModel.getRationLibs(req.session.sessionCompilation._id, function (err, data) {
+        let data = JSON.parse(req.body.data);
+        compleViewModel.getRationLibs(req.session.sessionCompilation._id, data.ids, function (err, data) {
             callback(req, res, err, '', data);
             callback(req, res, err, '', data);
         });
         });
     }
     }

+ 29 - 0
modules/complementary_ration_lib/controllers/searchController.js

@@ -0,0 +1,29 @@
+/**
+ * Created by Zhong on 2018/1/9.
+ */
+
+import BaseController from '../../common/base/base_controller';
+import SearchDao from '../models/searchModel';
+
+let searchDao = new SearchDao();
+let callback = function (req, res, err, message, data) {
+    res.json({error: err, message: message, data: data});
+};
+
+class SearchController extends BaseController{
+    getRationItem(req, res){
+        let data = JSON.parse(req.body.data);
+        searchDao.getRationItem(req.session.sessionUser.ssoId, data.rationRepId, data.code, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+
+    findRation(req, res){
+        let data = JSON.parse(req.body.data);
+        searchDao.findRation(req.session.sessionUser.ssoId, data.rationRepId, data.keyword, function (err, data) {
+            callback(req, res, err, '', data);
+        });
+    }
+}
+
+export default SearchController;

+ 49 - 0
modules/complementary_ration_lib/models/compleRationModel.js

@@ -134,6 +134,51 @@ class CompleRatoinDao {
             callback(err, null);
             callback(err, null);
         }
         }
     }
     }
+    //造价书定额库
+    async getRationGljItemsBySection(userId, sectionId, callback){
+        try{
+            let stdRations = await stdRationModel.find({sectionId: sectionId, $or: [{isDeleted: null}, {isDeleted: false}]});
+            for(let ration of stdRations){
+                ration._doc.type = 'std';
+            }
+            let compleRations = await compleRationModel.find({userId: userId, sectionId: sectionId, deleteInfo: null});
+            for(let ration of compleRations){
+                ration._doc.type = 'complementary';
+            }
+            let rations = stdRations.concat(compleRations);
+            rations.sort(function (a, b) {
+                let rst = 0;
+                if(a.code > b.code){
+                    rst = 1;
+                }
+                else if(a.code < b.code){
+                    rst = -1;
+                }
+                return rst;
+            });
+            for(let ration of rations){
+                let hint = '';
+                for(let rationGlj of ration.rationGljList){
+                    let glj;
+                    if(!isDef(rationGlj.type) || rationGlj.type === 'std'){
+                         glj = await stdGljModel.findOne({ID: rationGlj.gljId});
+                    }
+                    else {
+                         glj = await complementaryGljModel.findOne({uesrId: userId, ID: rationGlj.gljId});
+                    }
+                    if(isDef(glj)){
+                        let unitHint = '' + glj.code + ' ' + glj.name + ' ' + glj.unit + ' ' + rationGlj.consumeAmt + '</br>';
+                        hint += unitHint;
+                    }
+                }
+                ration._doc.hint = hint;
+            }
+            callback(0, rations);
+        }
+        catch(err){
+            callback(err, null);
+        }
+    }
 
 
     updateRationBasePrc(userID, basePrcArr, callback){
     updateRationBasePrc(userID, basePrcArr, callback){
         let me  = this;
         let me  = this;
@@ -387,4 +432,8 @@ class CompleRatoinDao {
     }
     }
 }
 }
 
 
+function isDef(v){
+    return v !== undefined && v !== null;
+}
+
 export default CompleRatoinDao;
 export default CompleRatoinDao;

+ 2 - 2
modules/complementary_ration_lib/models/compleViewModel.js

@@ -15,9 +15,9 @@ class CompleViewModel {
         }
         }
     }
     }
 
 
-    async getRationLibs(compilationId, callback){
+    async getRationLibs(compilationId, ids, callback){
         try{
         try{
-            let rationLibs = await rationRepositoryModel.find({compilationId: compilationId, $or: [{deleted: null}, {deleted: false}]});
+            let rationLibs = await rationRepositoryModel.find({compilationId: compilationId, ID: {$in: ids}, $or: [{deleted: null}, {deleted: false}]});
             callback(0, rationLibs);
             callback(0, rationLibs);
         }
         }
         catch(err) {
         catch(err) {

+ 76 - 0
modules/complementary_ration_lib/models/searchModel.js

@@ -0,0 +1,76 @@
+/**
+ * Created by Zhong on 2018/1/9.
+ */
+
+import {compleRationModel} from './schemas';
+import {complementaryGljModel, stdGljModel} from '../../complementary_glj_lib/models/schemas';
+import {compleRationSectionTreeModel} from './schemas';
+let stdSectionTreeModel = require ('../../ration_repository/models/ration_section_tree').Model;
+let stdRationModel = require ('../../ration_repository/models/ration_item').Model;
+
+class SearchDao{
+    async getRationItem(userId, rationRepId, code, callback){
+        try{
+            let ration = null;
+            let stdRation = await stdRationModel.findOne({rationRepId: rationRepId, code: code, $or: [{isDeleted: null}, {isDeleted: false}]});
+            if(isDef(stdRation)){
+                ration = stdRation._doc;
+                ration.type = 'std';
+            }
+            else{
+                let compleRation = await compleRationModel.findOne({userId: userId, rationRepId: rationRepId, code: code, deleteInfo: null});
+                if(isDef(compleRation)){
+                    ration = compleRation._doc;
+                    ration.type = 'complementary';
+                }
+            }
+            if(isDef(ration)){
+                let stdChapter = await stdSectionTreeModel.findOne({rationRepId: ration.rationRepId, ID: ration.sectionId, $or: [{isDeleted: null}, {isDeleted: false}]});
+                if(isDef(stdChapter)){
+                    ration.chapter = stdChapter._doc;
+                }
+                else{
+                    let compleChapter = await compleRationSectionTreeModel.findOne({userId: userId, ID: ration.sectionId, deleteInfo: null});
+                    if(isDef(compleChapter)){
+                        ration.chapter = compleChapter._doc;
+                    }
+                }
+            }
+            callback(0, ration);
+        }
+        catch(err){
+            callback(err, null);
+        }
+    }
+
+    async findRation(userId, rationRepId, keyword, callback){
+        try{
+            let filter = {
+                'rationRepId': rationRepId,
+                '$and': [{
+                    '$or': [{'code': {'$regex': keyword, $options: '$i'}}, {'name': {'$regex': keyword, $options: '$i'}}]
+                }, {
+                    '$or': [{'isDeleted': {"$exists":false}}, {'isDeleted': null}, {'isDeleted': false}, {deleteInfo: null}]
+                }]
+            };
+            let stdRations = await stdRationModel.find(filter);
+            for(let i = 0, len = stdRations.length; i < len; i++){
+                stdRations[i]._doc.type = 'std';
+            }
+            let compleRations = await compleRationModel.find(filter);
+            for(let i = 0, len = compleRations.length; i <len; i++){
+                compleRations[i]._doc.type = 'complementary';
+            }
+            callback(0, stdRations.concat(compleRations));
+        }
+        catch(err){
+            callback(err, null);
+        }
+    }
+}
+
+function isDef(v){
+    return v !== undefined && v !== null;
+}
+
+export default SearchDao;

+ 7 - 0
modules/complementary_ration_lib/routes/routes.js

@@ -7,12 +7,14 @@ import CompleViewController from '../controllers/compleViewController';
 import CompleSectionTreeController from '../controllers/compleSectionTreeController';
 import CompleSectionTreeController from '../controllers/compleSectionTreeController';
 import CompleRationController from '../controllers/compleRationController';
 import CompleRationController from '../controllers/compleRationController';
 import GljController from '../../complementary_glj_lib/controllers/gljController';
 import GljController from '../../complementary_glj_lib/controllers/gljController';
+import SearchController from '../controllers/searchController'
 
 
 let router = express.Router();
 let router = express.Router();
 let compleViewController = new CompleViewController();
 let compleViewController = new CompleViewController();
 let compleSectionTreeController = new CompleSectionTreeController();
 let compleSectionTreeController = new CompleSectionTreeController();
 let compleRationController = new CompleRationController();
 let compleRationController = new CompleRationController();
 let gljController = new GljController();
 let gljController = new GljController();
+let searchController = new SearchController();
 
 
 module.exports = function (app) {
 module.exports = function (app) {
     //app.get('/complementaryRation/main', compleViewController.init, compleViewController.redirectMain);
     //app.get('/complementaryRation/main', compleViewController.init, compleViewController.redirectMain);
@@ -42,5 +44,10 @@ module.exports = function (app) {
     router.post('/getCoeItemsByIDs', compleRationController.init, compleRationController.getCoeItemsByIDs);
     router.post('/getCoeItemsByIDs', compleRationController.init, compleRationController.getCoeItemsByIDs);
     router.post('/getCoeItemsByNos', compleRationController.init, compleRationController.getCoeItemsByNos);
     router.post('/getCoeItemsByNos', compleRationController.init, compleRationController.getCoeItemsByNos);
 
 
+    //造价书定额库
+    router.post('/getRationItem', searchController.init, searchController.getRationItem);
+    router.post('/findRation', searchController.init, searchController.findRation);
+    router.post('/getRationGljItemsBySection', compleRationController.init, compleRationController.getRationGljItemsBySection);
+
     app.use('/complementaryRation/api', router);
     app.use('/complementaryRation/api', router);
 };
 };

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

@@ -3,6 +3,7 @@
  */
  */
 var billsData = require('../models/bills');
 var billsData = require('../models/bills');
 let ProjectsData = require('../../pm/models/project_model').project;
 let ProjectsData = require('../../pm/models/project_model').project;
+let logger = require("../../../logs/log_helper").logger;
 //统一回调函数
 //统一回调函数
 var callback = function(req, res, err, message, data){
 var callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});
     res.json({error: err, message: message, data: data});
@@ -73,6 +74,58 @@ module.exports = {
         const message = !result || !projectResult ? '修改失败' : '修改成功';
         const message = !result || !projectResult ? '修改失败' : '修改成功';
         const err = !result || !projectResult ? 1 : 0;
         const err = !result || !projectResult ? 1 : 0;
         callback(request, response, err, message, null);
         callback(request, response, err, message, null);
+    },
+    singleDelete:async function(req, res){
+        let result={
+            error:0
+        }
+        try {
+            let data = req.body.data;
+            data = JSON.parse(data);
+            let tasks = generateSingleDeleteTasks(data);
+            let resultData= await billsData.model.bulkWrite(tasks);
+            result.data=resultData;
+        }catch (err){
+            logger.err(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        res.json(result);
     }
     }
 
 
-};
+};
+
+
+function  generateSingleDeleteTasks(data) {
+    let tasks=[];
+    let updateData = data.updateData;
+    for(let key in updateData){
+        if(updateData[key]==true){
+            let deleteInfo={deleted: true, deleteDateTime: new Date(), deleteBy: data.user_id};
+            let task={
+                updateOne:{
+                    filter:{
+                        ID:key,
+                        projectID:data.projectID
+                    },
+                    update:{
+                        deleteInfo:deleteInfo
+                    }
+                }
+            };
+            tasks.push(task);
+        }else {
+            let task={
+                updateOne:{
+                    filter:{
+                        ID:key,
+                        projectID:data.projectID
+                    },
+                    update:updateData[key]
+                }
+            };
+            tasks.push(task);
+        }
+    }
+    return tasks;
+}

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

@@ -12,6 +12,7 @@ let consts = require('./project_consts');
 let projectConsts = consts.projectConst;
 let projectConsts = consts.projectConst;
 let commonConsts = consts.commonConst;
 let commonConsts = consts.commonConst;
 let quantity_detial = require('../facade/quantity_detail_facade');
 let quantity_detial = require('../facade/quantity_detail_facade');
+let projectModel = require('../../pm/models/project_schema');
 
 
 
 
 let billsSchema = new Schema({
 let billsSchema = new Schema({
@@ -91,7 +92,21 @@ class billsModel extends baseModel {
             return function (cb) {
             return function (cb) {
                 switch (doc.updateType) {
                 switch (doc.updateType) {
                     case commonConsts.UT_UPDATE:
                     case commonConsts.UT_UPDATE:
-                        bills.update({projectID: doc.updateData.projectID, ID: doc.updateData.ID,deleteInfo: null}, doc.updateData, cb);
+                        async.parallel([      // CSL,2018.01.10 如果是总造价清单,要将4个汇总金额写到projects表中
+                            function (asyncCB) {
+                                bills.update({projectID: doc.updateData.projectID, ID: doc.updateData.ID,deleteInfo: null}, doc.updateData, asyncCB);
+                            },
+                            function (asyncCB) {
+                                if (doc.updateData.summaryFees){
+                                    // console.log('%%%%%%%%%%%%%%%%%%%  ' + doc.updateData.projectID + ' | ' + JSON.stringify(doc.updateData.summaryFees));
+                                    projectModel.update({ID: doc.updateData.projectID}, {"summaryFees": doc.updateData.summaryFees}, asyncCB);
+                                }else {
+                                    asyncCB(null, {});
+                                };
+                            }
+                        ], function(err,result){
+                            cb(err, {});
+                        });
                         break;
                         break;
                     case commonConsts.UT_CREATE:
                     case commonConsts.UT_CREATE:
                         bills.create(doc.updateData, cb);
                         bills.create(doc.updateData, cb);

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

@@ -46,6 +46,7 @@ let rationSchema = new Schema({
     deleteInfo: deleteSchema,
     deleteInfo: deleteSchema,
     type: Number,                               // 1 定额、2 量价、3 工料机定额
     type: Number,                               // 1 定额、2 量价、3 工料机定额
     subType: Number,                            // 子类型:1人工、201材料、301机械、4主材、5设备
     subType: Number,                            // 子类型:1人工、201材料、301机械、4主材、5设备
+    from:{type: String,default:'std'},//std, cpt  来自标准、补充
 
 
     // 定额特有属性:
     // 定额特有属性:
     libID: Number,
     libID: Number,
@@ -67,8 +68,7 @@ let rationSchema = new Schema({
     specs:String,//规格型号
     specs:String,//规格型号
     shortName:String,//缩写
     shortName:String,//缩写
     customQuantity:String,//自定义消耗
     customQuantity:String,//自定义消耗
-    adjCoe:Number,
-    from:{type: String,default:'std'}//std, cpt  来自标准工料机库、补充工料机库
+    adjCoe:Number
 
 
 });
 });
 
 

+ 2 - 0
modules/main/routes/bills_route.js

@@ -12,6 +12,8 @@ module.exports = function (app) {
     billsRouter.post('/updateCharacterContent', billsController.updateCharacterContent);//特征及内容更新 zhong 2017-9-1
     billsRouter.post('/updateCharacterContent', billsController.updateCharacterContent);//特征及内容更新 zhong 2017-9-1
     // 批量更新bill数据
     // 批量更新bill数据
     billsRouter.post('/updateBill', billsController.updateBill);
     billsRouter.post('/updateBill', billsController.updateBill);
+    //按条件更新清单
+    billsRouter.post('/singleDelete',billsController.singleDelete);
     app.use('/bills', billsRouter);
     app.use('/bills', billsRouter);
 };
 };
 
 

+ 7 - 0
modules/pm/models/project_schema.js

@@ -7,6 +7,7 @@ let Schema = mongoose.Schema;
 let deleteSchema = require('../../../public/models/delete_schema');
 let deleteSchema = require('../../../public/models/delete_schema');
 
 
 let collectionName = 'projects';
 let collectionName = 'projects';
+
 let ProjectSchema = new Schema({
 let ProjectSchema = new Schema({
     "ID": Number,
     "ID": Number,
     "ParentID": Number,
     "ParentID": Number,
@@ -22,6 +23,12 @@ let ProjectSchema = new Schema({
     "property": {
     "property": {
         type: Schema.Types.Mixed,
         type: Schema.Types.Mixed,
         default: {}
         default: {}
+    },
+    "summaryFees":{
+        totalFee: String,
+        estimateFee: String,
+        safetyFee: String,
+        chargeFee: String
     }
     }
 });
 });
 
 

+ 1 - 1
modules/ration_glj/facade/glj_calculate_facade.js

@@ -110,7 +110,7 @@ async function calculateQuantityPerGLJ(glj,index,coeList,assList,adjustState,noN
                 result.doc.customQuantity = glj.customQuantity;
                 result.doc.customQuantity = glj.customQuantity;
             }
             }
             let customerCoe = _.last(coeList);
             let customerCoe = _.last(coeList);
-            if(customerCoe.isAdjust==1){
+            if(customerCoe&&customerCoe.isAdjust==1){
                 quantity = calculateQuantityByCustomerCoes(quantity,customerCoe,glj);
                 quantity = calculateQuantityByCustomerCoes(quantity,customerCoe,glj);
             }
             }
             result.doc.quantity =scMathUtil.roundToString(quantity,decimal);
             result.doc.quantity =scMathUtil.roundToString(quantity,decimal);

+ 30 - 0
public/web/id_tree.js

@@ -583,6 +583,36 @@ var idTree = {
             }
             }
             return success;
             return success;
         };
         };
+        Tree.prototype.singleDelete = function (node) {//删除本身不删除子项
+            let that = this;
+            let success = false;
+            delete that.nodes[that.prefix + node.getID()];//删除本身
+            if(node.children.length>0){
+                if(node.preSibling){//子项变成前兄弟的子项
+                    for(let c of node.children){
+                        node.preSibling.addChild(c);
+                    }
+                }else if(node.nextSibling){//没有前兄弟,有后兄弟
+                    let oldChild = node.parent.children;
+                    node.parent.children = [];
+                    for(let c of node.children){
+                        node.parent.addChild(c);
+                    }
+                    for(let oc of oldChild){
+                        node.parent.addChild(oc);
+                    }
+                }else {//都没有的情况
+                    for(let c of node.children){
+                        node.parent.addChild(c);
+                    }
+                }
+                tools.sortTreeItems(this);
+                success = true;
+            }
+            return success;
+        };
+
+
         Tree.prototype.getDeleteData = function (node) {
         Tree.prototype.getDeleteData = function (node) {
             var data = [];
             var data = [];
             var addUpdateDataForDelete = function (datas, nodes) {
             var addUpdateDataForDelete = function (datas, nodes) {

+ 15 - 0
public/web/tree_sheet/tree_sheet_controller.js

@@ -39,6 +39,7 @@ var TREE_SHEET_CONTROLLER = {
                         that.setTreeSelected(newNode);
                         that.setTreeSelected(newNode);
                         that.sheet.setSelection(newNode.serialNo(), sels[0].col, 1, 1);
                         that.sheet.setSelection(newNode.serialNo(), sels[0].col, 1, 1);
                         that.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
                         that.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+                        cbTools.refreshFormulaNodes();
                     });
                     });
                 }
                 }
             }
             }
@@ -51,9 +52,22 @@ var TREE_SHEET_CONTROLLER = {
                         that.sheet.deleteRows(sels[0].row, that.tree.selected.posterityCount() + 1);
                         that.sheet.deleteRows(sels[0].row, that.tree.selected.posterityCount() + 1);
                         that.setTreeSelected(that.tree.items[sels[0].row]);
                         that.setTreeSelected(that.tree.items[sels[0].row]);
                     });
                     });
+                    cbTools.refreshFormulaNodes();
                 }
                 }
             }
             }
         };
         };
+        controller.prototype.singleDelete = function () {//只删除当前节点,不删除子节点
+            var that = this, sels = this.sheet.getSelections();
+            if (this.tree.selected) {
+                if (this.tree.singleDelete(this.tree.selected)) {
+                    TREE_SHEET_HELPER.massOperationSheet(this.sheet, function () {
+                        that.sheet.deleteRows(sels[0].row,1);
+                        that.setTreeSelected(that.tree.items[sels[0].row]);
+                    });
+                }
+            }
+        };
+
         controller.prototype.deleteNode = function (node,next) {
         controller.prototype.deleteNode = function (node,next) {
             var that = this;
             var that = this;
             if (node){
             if (node){
@@ -63,6 +77,7 @@ var TREE_SHEET_CONTROLLER = {
                         that.sheet.deleteRows(row,1);
                         that.sheet.deleteRows(row,1);
                         next?that.setTreeSelected(that.tree.items[row]):"";
                         next?that.setTreeSelected(that.tree.items[row]):"";
                     });
                     });
+                    cbTools.refreshFormulaNodes();
                 }
                 }
             }
             }
 
 

+ 6 - 5
public/web/tree_sheet/tree_sheet_helper.js

@@ -161,6 +161,7 @@ var TREE_SHEET_HELPER = {
     },
     },
     showTreeData: function (setting, sheet, tree) {
     showTreeData: function (setting, sheet, tree) {
         let indent = 20;
         let indent = 20;
+        let levelIndent = -5;
         let halfBoxLength = 5;
         let halfBoxLength = 5;
         let halfExpandLength = 3;
         let halfExpandLength = 3;
 
 
@@ -229,7 +230,7 @@ var TREE_SHEET_HELPER = {
             let showTreeLine = true;
             let showTreeLine = true;
             if (!node) { return; }
             if (!node) { return; }
 
 
-            let centerX = Math.floor(x) + node.depth() * indent + indent / 2;
+            let centerX = Math.floor(x) + node.depth() * indent + node.depth() * levelIndent + indent / 2;
             let x1 = centerX + indent / 2;
             let x1 = centerX + indent / 2;
             let centerY = Math.floor((y + (y + h)) / 2);
             let centerY = Math.floor((y + (y + h)) / 2);
             let y1;
             let y1;
@@ -255,7 +256,7 @@ var TREE_SHEET_HELPER = {
             }
             }
             // Draw Parent Line
             // Draw Parent Line
             if (showTreeLine) {
             if (showTreeLine) {
-                var parent = node.parent, parentCenterX = centerX - indent;
+                var parent = node.parent, parentCenterX = centerX - indent - levelIndent;
                 while (parent) {
                 while (parent) {
                     if (!parent.isLast()) {
                     if (!parent.isLast()) {
                         if (parentCenterX < x + w) {
                         if (parentCenterX < x + w) {
@@ -263,11 +264,11 @@ var TREE_SHEET_HELPER = {
                         }
                         }
                     }
                     }
                     parent = parent.parent;
                     parent = parent.parent;
-                    parentCenterX -= indent;
+                    parentCenterX -= (indent + levelIndent);
                 }
                 }
             };
             };
             // Draw Text
             // Draw Text
-            x = x + (node.depth() + 1) * indent;
+            x = x + (node.depth() + 1) * indent +  node.depth() * levelIndent;
             GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
             GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
         };
         };
         TreeNodeCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
         TreeNodeCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
@@ -286,7 +287,7 @@ var TREE_SHEET_HELPER = {
             let node = tree.items[hitinfo.row];
             let node = tree.items[hitinfo.row];
             tree.selected = node;
             tree.selected = node;
             if (!node || node.children.length === 0) { return; }
             if (!node || node.children.length === 0) { return; }
-            let centerX = hitinfo.cellRect.x + offset + node.depth() * indent + indent / 2;
+            let centerX = hitinfo.cellRect.x + offset + node.depth() * indent + node.depth() * levelIndent + indent / 2;
             let centerY = (hitinfo.cellRect.y + offset + (hitinfo.cellRect.y + offset + hitinfo.cellRect.height)) / 2;
             let centerY = (hitinfo.cellRect.y + offset + (hitinfo.cellRect.y + offset + hitinfo.cellRect.height)) / 2;
 
 
             if (hitinfo.x > centerX - halfBoxLength && hitinfo.x < centerX + halfBoxLength && hitinfo.y > centerY - halfBoxLength && hitinfo.y < centerY + halfBoxLength) {
             if (hitinfo.x > centerX - halfBoxLength && hitinfo.x < centerX + halfBoxLength && hitinfo.y > centerY - halfBoxLength && hitinfo.y < centerY + halfBoxLength) {

+ 6 - 1
web/building_saas/complementary_ration_lib/js/main.js

@@ -22,7 +22,12 @@ let compleRationMain = {
                 }
                 }
             }
             }
         };
         };
-        CommonAjax.post('/complementaryRation/api/getRationLibs', {user_id: userID}, scFunc);
+        let ration_lib = projectInfoObj.projectInfo.engineeringInfo.ration_lib;
+        let ids = [];
+        for(lib of ration_lib){
+            ids.push(parseInt(lib.id));
+        }
+        CommonAjax.post('/complementaryRation/api/getRationLibs', {user_id: userID, ids: ids}, scFunc);
     }
     }
 };
 };
 
 

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

@@ -764,6 +764,31 @@
             </div>
             </div>
         </div>
         </div>
     </div>
     </div>
+
+    <!--弹出 是否删除所选行窗口-->
+    <div class="modal fade" id="delete_row" data-backdrop="static">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">删除确认</h5>
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">&times;</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <div class="form-group">
+                        <label id="delete_showinfo">确认要删除当前选中行吗?</label>
+                    </div>
+                </div>
+                <div class="modal-footer" style="justify-content: center">
+                    <button type="button" class="btn btn-primary"  data-dismiss="modal" id="deleteY" >是</button>
+                    <button type="button" class="btn btn-primary"  data-dismiss="modal" id="deleteN" >否</button>
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal" id="deleteCancel">取消</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
         <!-- JS. -->
         <!-- JS. -->
         <script type="text/javascript" src="/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
         <script type="text/javascript" src="/lib/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js"></script>
 
 

+ 61 - 8
web/building_saas/main/js/controllers/project_controller.js

@@ -12,6 +12,7 @@ ProjectController = {
             sc.setTreeSelected(newNode);
             sc.setTreeSelected(newNode);
             sc.sheet.setSelection(newNode.serialNo(), sels[0].col, 1, 1);
             sc.sheet.setSelection(newNode.serialNo(), sels[0].col, 1, 1);
             sc.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
             sc.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+            cbTools.refreshFormulaNodes();
         });
         });
     },
     },
     syncDisplayNewRationGljNode:function (sc,newNode) {
     syncDisplayNewRationGljNode:function (sc,newNode) {
@@ -19,28 +20,65 @@ ProjectController = {
             sc.sheet.addRows(newNode.serialNo(), 1);
             sc.sheet.addRows(newNode.serialNo(), 1);
             TREE_SHEET_HELPER.refreshTreeNodeData(sc.setting, sc.sheet, [newNode], false);
             TREE_SHEET_HELPER.refreshTreeNodeData(sc.setting, sc.sheet, [newNode], false);
             sc.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
             sc.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+            cbTools.refreshFormulaNodes();
         });
         });
     },
     },
     addBills: function (project, sheetController, std) {
     addBills: function (project, sheetController, std) {
         if (!project || !sheetController) { return null; }
         if (!project || !sheetController) { return null; }
         let target = project.getParentTarget(project.mainTree.selected, 'sourceType', project.Bills.getSourceType());
         let target = project.getParentTarget(project.mainTree.selected, 'sourceType', project.Bills.getSourceType());
-        let newSource = null, newNode = null, parentID, nextSiblingID;
+        let newSource = null, newNode = null, parentID, nextSiblingID, nodeParentID, nodeNextSiblingID;
         if (target) {
         if (target) {
-            console.log(target.depth());
+            if(target.depth() === 0){
+                parentID = target.source.getID();
+                nextSiblingID = project.Bills.tree.setting.rootId;
+                nodeParentID = target.getID();
+                nodeNextSiblingID = project.mainTree.rootID();
+            }
+            else{
+                parentID = target.source.getParentID();
+                nextSiblingID = target.source.getNextSiblingID();
+                nodeParentID = target.getParentID();
+                nodeNextSiblingID = target.getNextSiblingID();
+            }
             parentID = target.depth() === 0 ? target.source.getID() : target.source.getParentID();
             parentID = target.depth() === 0 ? target.source.getID() : target.source.getParentID();
             nextSiblingID = target.depth() === 0 ? project.Bills.tree.setting.rootId : target.source.getNextSiblingID();
             nextSiblingID = target.depth() === 0 ? project.Bills.tree.setting.rootId : target.source.getNextSiblingID();
 
 
             if (std) {
             if (std) {
+                let fixedNode = getRootFixedNode(target);
+                if(!isFlag(fixedNode.data) || (fixedNode.data.flagsIndex.fixed.flag !== fixedFlag.SUB_ENGINERRING && fixedNode.data.flagsIndex.fixed.flag !== fixedFlag.MEASURE)){
+                    return;
+                }
+                //焦点行属于分部分项
+                if(fixedNode.data.flagsIndex.fixed.flag === fixedFlag.SUB_ENGINERRING){
+                    std.type = billType.FX;
+                    //焦点行是分部分项
+                    let subType = getSubType(target);
+                    if(target.sourceType === project.Bills.getSourceType() && target.data.type === billType.DXFY && subType === billType.FB){
+                        return;
+                    }
+                    //焦点行是分部
+                    else if(target.sourceType === project.Bills.getSourceType() && target.data.type === billType.FB){
+                        if(!subType || subType === billType.FX){
+                            parentID = target.source.getID();
+                            nextSiblingID = project.Bills.tree.setting.rootId;
+                            nodeParentID = target.getID();
+                            nodeNextSiblingID = project.mainTree.rootID();
+                        }
+                        else{
+                            return;
+                        }
+                    }
+                }
+                else {
+                    std.type = billType.BILL;
+                }
+
                 let newCode = project.Bills.newFormatCode(std.code);
                 let newCode = project.Bills.newFormatCode(std.code);
                 newSource = project.Bills.insertStdBills(parentID, nextSiblingID, std, newCode);
                 newSource = project.Bills.insertStdBills(parentID, nextSiblingID, std, newCode);
             } else {
             } else {
                 newSource = project.Bills.insertBills(parentID, nextSiblingID);
                 newSource = project.Bills.insertBills(parentID, nextSiblingID);
             }
             }
-            if (target.depth() === 0) {
-                newNode = project.mainTree.insert(target.getID(), project.mainTree.rootID())
-            } else {
-                newNode = project.mainTree.insert(target.getParentID(), target.getNextSiblingID());
-            }
+            newNode = project.mainTree.insert(nodeParentID, nodeNextSiblingID);
         } else {
         } else {
             alert('不可添加清单');
             alert('不可添加清单');
         }
         }
@@ -52,6 +90,17 @@ ProjectController = {
 
 
             this.syncDisplayNewNode(sheetController, newNode);
             this.syncDisplayNewNode(sheetController, newNode);
         }
         }
+        function getSubType(node){
+            for(let sub of node.children){
+                if(sub.sourceType === project.Bills.getSourceType() && sub.data.type === billType.FB){
+                    return billType.FB;
+                }
+                else if(sub.sourceType === project.Bills.getSourceType() && sub.data.type === billType.FX){
+                    return billType.FX;
+                }
+            }
+            return null;
+        }
     },
     },
     addRootBill:function (project, sheetController) {//添加大项费用
     addRootBill:function (project, sheetController) {//添加大项费用
         if (!project || !sheetController) { return null; }
         if (!project || !sheetController) { return null; }
@@ -109,6 +158,9 @@ ProjectController = {
             } else if (selected.data.calcBase&&selected.data.calcBase!="") {
             } else if (selected.data.calcBase&&selected.data.calcBase!="") {
                 alert('当前有基数计算不能插入定额/量价/工料机。');
                 alert('当前有基数计算不能插入定额/量价/工料机。');
             } else {
             } else {
+                if(selected.data.type === billType.FB){
+                    return;
+                }
                 if (std) {
                 if (std) {
                     newSource = project.Ration.insertStdRation(selected.source.getID(), null, std);
                     newSource = project.Ration.insertStdRation(selected.source.getID(), null, std);
                     project.ration_glj.addRationGLJ(newSource,std);
                     project.ration_glj.addRationGLJ(newSource,std);
@@ -132,6 +184,7 @@ ProjectController = {
             newNode.data = newSource;
             newNode.data = newSource;
 
 
             this.syncDisplayNewNode(sheetController, newNode);
             this.syncDisplayNewNode(sheetController, newNode);
+
         }
         }
     },
     },
     replaceRation: function (project, sheetController, std) {
     replaceRation: function (project, sheetController, std) {
@@ -140,7 +193,7 @@ ProjectController = {
         let selected = project.mainTree.selected, newSource = null, newNode = null;
         let selected = project.mainTree.selected, newSource = null, newNode = null;
         if (selected === null) { return; }
         if (selected === null) { return; }
 
 
-        if (selected.sourceType === project.Ration.getSourceType()) {
+        if (  selected.sourceType === project.Ration.getSourceType()) {
             project.Ration.replaceRation(selected.source, std);
             project.Ration.replaceRation(selected.source, std);
             project.ration_glj.addRationGLJ(selected.source, std);
             project.ration_glj.addRationGLJ(selected.source, std);
             sheetController.refreshTreeNode([selected], false);
             sheetController.refreshTreeNode([selected], false);

+ 89 - 5
web/building_saas/main/js/models/bills.js

@@ -203,7 +203,7 @@ var Bills = {
                     data.data.jobContentText = stdBillsData.jobContentText;
                     data.data.jobContentText = stdBillsData.jobContentText;
                     data.data.itemCharacterText = stdBillsData.itemCharacterText;
                     data.data.itemCharacterText = stdBillsData.itemCharacterText;
                     data.data.programID = stdBillsData.engineering;
                     data.data.programID = stdBillsData.engineering;
-                    data.data.type = billType.BILL;//插入清单类型
+                    data.data.type = stdBillsData.type;//插入清单类型
                     //zhong
                     //zhong
                     newData = data.data;
                     newData = data.data;
                 }
                 }
@@ -236,6 +236,64 @@ var Bills = {
             return this.tree.delete(node);
             return this.tree.delete(node);
         };
         };
 
 
+        bills.prototype.singleDeleteBills=function(node,controller){
+            let updateData = {};
+            let updateNode={};
+            let me = this;
+            if(node){
+                updateData[node.data.ID]=true;
+                if(node.children.length>0){//有子项
+                    if(node.preSibling){//有前兄弟,则子项变成前兄弟的子项
+                        if(node.preSibling.children.length>0){//前兄弟有子项,
+                            let preNode = node.preSibling.children[node.preSibling.children.length-1];
+                            updateData[preNode.data.ID]={
+                                NextSiblingID:node.children[0].data.ID
+                            }
+                            updateNode[preNode.data.ID] = preNode;
+                        }
+                        for(let i=0;i<node.children.length;i++){
+                            updateData[node.children[i].data.ID]={
+                                ParentID:node.preSibling.data.ID
+                            };
+                            updateNode[node.children[i].data.ID]=node.children[i];
+                        }
+                    }else {//没有前兄弟,则子项升一级
+                        let parent = node.nextSibling.parent;
+                        for(let i=0;i<node.children.length;i++){
+                            if(i == node.children.length-1&&node.nextSibling){//最后一个子项,在有后兄弟的情况下,作为后兄弟的前兄弟
+                                updateData[node.children[i].data.ID]={
+                                    ParentID:parent.data.ID,
+                                    NextSiblingID:node.nextSibling.data.ID
+                                };
+                            }else {
+                                updateData[node.children[i].data.ID]={
+                                    ParentID:parent.data.ID
+                                };
+                            }
+                            updateNode[node.children[i].data.ID]=node.children[i];
+                        }
+                    }
+                }
+                $.bootstrapLoading.start();
+                CommonAjax.post("/bills/singleDelete", {updateData:updateData,projectID:node.data.projectID,user_id:userID}, function () {
+                    controller.singleDelete();//删除树节点
+                    me.tree.singleDelete(node);
+                    //更新缓存
+                    console.log(updateNode);
+                    _.remove(me.datas,{'ID':node.data.ID});
+                    for(let n_key in updateNode){
+                        let updateDoc =  updateData[n_key];
+                        for(let u_key in updateDoc){
+                            updateNode[n_key].data[u_key] =updateDoc[u_key];
+                        }
+                    }
+                    $.bootstrapLoading.end();
+                }, function () {
+                    $.bootstrapLoading.end();
+                });
+            }
+
+        };
         bills.prototype.upMoveBills = function (node) {
         bills.prototype.upMoveBills = function (node) {
             var upMoveData = node.getUpMoveData();
             var upMoveData = node.getUpMoveData();
             project.pushNow('upMoveBills', this.getSourceType(), tools.coverseTreeUpdateData(upMoveData, this.project.ID()));
             project.pushNow('upMoveBills', this.getSourceType(), tools.coverseTreeUpdateData(upMoveData, this.project.ID()));
@@ -403,17 +461,24 @@ var Bills = {
         };
         };
         bills.prototype.getRootNode = function (node) {
         bills.prototype.getRootNode = function (node) {
             if(node.parent){
             if(node.parent){
-                return this.getRootNode(node.parent)
+                return this.getRootNode(node.parent);
             }else {
             }else {
-                return node
+                return node;
             }
             }
         };
         };
         bills.prototype.isFBFX = function (node) {//判读是否属于分部分项
         bills.prototype.isFBFX = function (node) {//判读是否属于分部分项
            let rootNode = this.getRootNode(node);
            let rootNode = this.getRootNode(node);
             if(isFlag(rootNode.data)&&rootNode.data.flagsIndex.fixed.flag==fixedFlag.SUB_ENGINERRING){
             if(isFlag(rootNode.data)&&rootNode.data.flagsIndex.fixed.flag==fixedFlag.SUB_ENGINERRING){
-                return true
+                return true;
             }else {
             }else {
-                return false
+                return false;
+            }
+        };
+        bills.prototype.isEngineeringCost = function (node) {//判断这个节点是否是工程造价节点
+            if(isFlag(node.data)&&node.data.flagsIndex.fixed.flag==fixedFlag.ENGINEERINGCOST){
+                return true;
+            }else {
+                return false;
             }
             }
         };
         };
         return new bills(project);
         return new bills(project);
@@ -426,3 +491,22 @@ function isDef(v) {
 function isFlag(v) {
 function isFlag(v) {
     return this.isDef(v.flagsIndex) && this.isDef(v.flagsIndex.fixed);
     return this.isDef(v.flagsIndex) && this.isDef(v.flagsIndex.fixed);
 }
 }
+
+function getRootFixedNode(node) {
+    let parent = node.parent;
+    if(isFlag(node.data) && (node.data.flagsIndex.fixed.flag === fixedFlag.SUB_ENGINERRING
+        || node.data.flagsIndex.fixed.flag === fixedFlag.MEASURE
+        || node.data.flagsIndex.fixed.flag === fixedFlag.OTHER
+        || node.data.flagsIndex.fixed.flag === fixedFlag.CHARGE
+        || node.data.flagsIndex.fixed.flag === fixedFlag.TAX)){
+        return node;
+    }
+    else {
+        if(!parent){
+            return node;
+        }
+        else {
+            return getRootFixedNode(parent);
+        }
+    }
+}

+ 39 - 1
web/building_saas/main/js/models/cache_tree.js

@@ -363,8 +363,15 @@ var cacheTree = {
         };
         };
         Tree.prototype.delete = function (node) {
         Tree.prototype.delete = function (node) {
             var success = false;
             var success = false;
+            var me = this;
+            var removeNodes = function (node) {
+                delete me.nodes[me.prefix + node.getID()];
+                for(let ch of node.children){
+                    removeNodes(ch);
+                }
+            };
             if (node) {
             if (node) {
-                delete this.nodes[this.prefix + node.getID()];
+                removeNodes(node);
                 if (node.preSibling) {
                 if (node.preSibling) {
                     node.preSibling.setNextSibling(node.nextSibling);
                     node.preSibling.setNextSibling(node.nextSibling);
                 } else if (node.nextSibling) {
                 } else if (node.nextSibling) {
@@ -380,6 +387,37 @@ var cacheTree = {
             }
             }
             return success;
             return success;
         };
         };
+        Tree.prototype.singleDelete = function (node) {//只删除当前节点,不删除子节点
+            var success = false;
+            var me = this;
+            if(node){
+                delete me.nodes[me.prefix + node.getID()];
+                if(node.children.length>0){
+                    if(node.preSibling){//子项变成前兄弟的子项
+                        for(let c of node.children){
+                            node.preSibling.addChild(c);
+                        }
+                    }else if(node.nextSibling){//没有前兄弟,有后兄弟
+                        let oldChild = node.parent.children;
+                        node.parent.children = [];
+                        for(let c of node.children){
+                            node.parent.addChild(c);
+                        }
+                        for(let oc of oldChild){
+                            node.parent.addChild(oc);
+                        }
+                    }else {//都没有的情况
+                        for(let c of node.children){
+                            node.parent.addChild(c);
+                        }
+                    }
+                    this.sortTreeItems();
+                    success = true;
+                }
+            }
+            return success;
+
+        };
         return new Tree(owner);
         return new Tree(owner);
     }
     }
 };
 };

+ 199 - 47
web/building_saas/main/js/models/calc_base.js

@@ -25,7 +25,7 @@ let cbTools = {
     findBill: function (fixedFlag) {
     findBill: function (fixedFlag) {
         let bills = projectObj.project.Bills.datas;
         let bills = projectObj.project.Bills.datas;
         for(let i = 0, len = bills.length; i < len; i++){
         for(let i = 0, len = bills.length; i < len; i++){
-            if(bills[i].flagsIndex.flag === fixedFlag){
+            if(bills[i].flagsIndex && bills[i].flagsIndex.fixed && bills[i].flagsIndex.fixed.flag && bills[i].flagsIndex.fixed.flag === fixedFlag){
                 return bills[i];
                 return bills[i];
             }
             }
         }
         }
@@ -40,6 +40,25 @@ let cbTools = {
         }
         }
         return null;
         return null;
     },
     },
+    //通过ID获取节点行
+    getRowByID: function (items, ID) {
+        for(let i = 0, len = items.length; i < len; i++){
+            if(items[i]['data']['ID'] == ID){
+                return i + 1;
+            }
+        }
+        return null;
+    },
+    //通过ID获取节点
+    getNodeByID: function (items, ID) {
+        ID = parseInt(ID);
+        for(let i = 0, len = items.length; i < len; i++){
+            if(items[i]['data']['ID'] === ID){
+                return items[i];
+            }
+        }
+        return null;
+    },
     //获取该节点所有父节点
     //获取该节点所有父节点
     getParents: function (node) {
     getParents: function (node) {
         let rst = [];
         let rst = [];
@@ -69,7 +88,7 @@ let cbTools = {
             return rst;
             return rst;
         }
         }
         //获取表达式中的基数和行引用
         //获取表达式中的基数和行引用
-        let figureF = cbParser.getFigureF(cbParser.getFigure(exp), cbParser.getRArr(cbParser.getFArr(exp)));
+        let figureF = cbParser.getFigureF(cbParser.getFigure(exp), cbParser.getXNum(cbParser.getFArr(exp)));
         for(let i = 0, len = figureF.length; i < len; i++){
         for(let i = 0, len = figureF.length; i < len; i++){
             let figure = figureF[i];
             let figure = figureF[i];
             if(figure.type === 'base' && cbTools.isDef(calcBase.baseFigures[figure.value])){
             if(figure.type === 'base' && cbTools.isDef(calcBase.baseFigures[figure.value])){
@@ -156,28 +175,22 @@ let cbTools = {
         let parent = node.parent;
         let parent = node.parent;
         if(this.isFlag(node.data) && (node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.SUB_ENGINERRING
         if(this.isFlag(node.data) && (node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.SUB_ENGINERRING
             || node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CONSTRUCTION_TECH)){
             || node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CONSTRUCTION_TECH)){
-            //node.data.baseFigureClass = null;
             return null;
             return null;
         }
         }
         else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION){
         else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION){
-            //node.data.baseFigureClass = 'CONSTRUCTION_ORGANIZATION';
             return calcBase.baseFigureClass.CONSTRUCTION_ORGANIZATION;
             return calcBase.baseFigureClass.CONSTRUCTION_ORGANIZATION;
         }
         }
         else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.OTHER){
         else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.OTHER){
-            //node.data.baseFigureClass = 'OTHER';
             return calcBase.baseFigureClass.OTHER;
             return calcBase.baseFigureClass.OTHER;
         }
         }
         else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CHARGE){
         else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CHARGE){
-            //node.data.baseFigureClass = 'CHARGE';
             return calcBase.baseFigureClass.CHARGE;
             return calcBase.baseFigureClass.CHARGE;
         }
         }
         else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.TAX){
         else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.TAX){
-            //node.data.baseFigureClass = 'TAX';
             return calcBase.baseFigureClass.TAX;
             return calcBase.baseFigureClass.TAX;
         }
         }
         else {
         else {
             if(!parent){
             if(!parent){
-                //node.data.baseFigureClass = 'OTHERS';
                 return calcBase.baseFigureClass.OTHERS;
                 return calcBase.baseFigureClass.OTHERS;
             }
             }
             else {
             else {
@@ -229,8 +242,8 @@ let cbTools = {
                 if(bases[i]['type'] === 'base' && cbTools.isDef(calcBase.baseFigures[bases[i]['value']])){
                 if(bases[i]['type'] === 'base' && cbTools.isDef(calcBase.baseFigures[bases[i]['value']])){
                     block.push(calcBase.baseFigures[bases[i]['value']]['fixedBill']['bill']['ID']);
                     block.push(calcBase.baseFigures[bases[i]['value']]['fixedBill']['bill']['ID']);
                 }
                 }
-                else if(bases[i]['type'] === 'row'){
-                    let node = cbTools.getBillByRow(calcBase.project.mainTree.items, bases[i]['value'] - 1);
+                else if(bases[i]['type'] === 'id'){
+                    let node = cbTools.getNodeByID(calcBase.project.mainTree.items, bases[i]['value']);
                     if(cbTools.isDef(node)){
                     if(cbTools.isDef(node)){
                         block.push(node.data.ID);
                         block.push(node.data.ID);
                     }
                     }
@@ -241,7 +254,7 @@ let cbTools = {
         function getBase(node){
         function getBase(node){
             if(node && node.children.length === 0){
             if(node && node.children.length === 0){
                 if(cbTools.isDef(node.data.calcBase) && node.data.calcBase !== ''){
                 if(cbTools.isDef(node.data.calcBase) && node.data.calcBase !== ''){
-                    let figureF = cbParser.getFigureF(cbParser.getFigure(node.data.calcBase), cbParser.getRArr(cbParser.getFArr(node.data.calcBase)));
+                    let figureF = cbParser.getFigureF(cbParser.getFigure(node.data.calcBase), cbParser.getXNum(cbParser.getFIDArr(node.data.calcBase)));
                     tempBases = tempBases.concat(figureF);
                     tempBases = tempBases.concat(figureF);
                 }
                 }
             }
             }
@@ -259,6 +272,52 @@ let cbTools = {
             }
             }
             return null;
             return null;
         }
         }
+    },
+
+    // 获取全部有公式的树节点清单。 CSL, 2018-01-05
+    getFormulaNodes: function (needOrder = false) {
+        // 给公式结点清单换照引用计算顺序排序。
+        function orderFormulaNodes (nodesArr) {
+            let orderArr = [];
+            function recursionNode(nodes) {
+                for (let node of nodes){
+                    if (orderArr.includes(node)) continue;    // 已排过序的节点则跳过
+                    if (node.data.calcBase){
+                        let subNodes = cbTools.getNodesByExp(node.data.calcBase);
+                        recursionNode(subNodes);
+                    };
+                    if (nodesArr.includes(node) && !orderArr.includes(node)) orderArr.push(node);
+                };
+            }
+            recursionNode(nodesArr);
+            return orderArr;
+        };
+
+        let nodes = [];
+        for (let node of projectObj.project.mainTree.items){
+            if (node.sourceType == ModuleNames.bills && node.data.calcBase && node.data.calcBase != '')
+                nodes.push(node);
+        };
+        if (needOrder && nodes.length >= 2) return orderFormulaNodes(nodes)
+        else return nodes;
+    },
+    // 刷新全部行引用的公式清单。 CSL, 2018-01-05
+    refreshFormulaNodes: function () {
+        try {
+            let nodes = this.getFormulaNodes();
+            if (nodes.length > 0) projectObj.mainController.refreshTreeNode(nodes);
+        } catch (err) {
+            alert('公式引用行号显示刷新失败:' + err.message);
+        }
+    },
+    // 判断结点是否被其它结点的表达式引用。
+    isUsedByFormula: function(node){
+        let nodes = this.getFormulaNodes();
+        if (nodes.length == 0) return false;
+        let sID = '@' + node.data.ID;
+        for (let node of nodes){
+             if (node.data.calcBase.hasSubStr(sID)) return true;
+        };
     }
     }
 };
 };
 
 
@@ -477,7 +536,7 @@ let cbAnalyzer = {
     },
     },
     //输入合法性
     //输入合法性
     inputLegal: function (exp) {
     inputLegal: function (exp) {
-        let ilegalRex = /[^0-9,\u4e00-\u9fa5,\+,\-,\/,\*,\(,\),.,{,},F]/g;
+        let ilegalRex = /[^0-9,\u4e00-\u9fa5,\+,\-,\/,\*,\(,\),.,{,},F,%]/g;
         return !ilegalRex.test(exp);
         return !ilegalRex.test(exp);
     },
     },
     //基数合法性、存在性
     //基数合法性、存在性
@@ -503,15 +562,22 @@ let cbAnalyzer = {
     },
     },
     //行引用合法性、存在性
     //行引用合法性、存在性
     fLegal: function (items, exp) {
     fLegal: function (items, exp) {
+        //提取F标记
+        let fmArr = cbParser.getFMArr(exp);
         //提取行引用
         //提取行引用
         let fArr = cbParser.getFArr(exp);
         let fArr = cbParser.getFArr(exp);
+        if(fmArr.length !== fArr.length){
+            return false;
+        }
         //提取行数
         //提取行数
-        let rArr = cbParser.getRArr(fArr);
+        let rArr = cbParser.getXNum(fArr);
+        if(fArr.length !== rArr.length){
+            return false;
+        }
         //判断合法性和存在性
         //判断合法性和存在性
         for(let i = 0, len = rArr.length; i < len; i++){
         for(let i = 0, len = rArr.length; i < len; i++){
             let idx = rArr[i] - 1;
             let idx = rArr[i] - 1;
             if(cbTools.isUnDef(cbTools.getBillByRow(items, idx))){
             if(cbTools.isUnDef(cbTools.getBillByRow(items, idx))){
-                calcBase.errMsg = '行引用不合法';
                 return false;
                 return false;
             }
             }
         }
         }
@@ -525,16 +591,16 @@ let cbAnalyzer = {
         }
         }
         //用于判断的起始清单ID
         //用于判断的起始清单ID
         let sIDs = cbTools.getNodeIDs(Array.from(new Set([cbTools.getBaseBill(node)].concat(cbTools.getParents(node)))));
         let sIDs = cbTools.getNodeIDs(Array.from(new Set([cbTools.getBaseBill(node)].concat(cbTools.getParents(node)))));
-        let figureF = cbParser.getFigureF(cbParser.getFigure(exp), cbParser.getRArr(cbParser.getFArr(exp)));
+        let figureF = cbParser.getFigureF(cbParser.getFigure(exp), cbParser.getXNum(cbParser.getFIDArr(exp)));
         for(let i = 0, len = figureF.length; i < len; i++){
         for(let i = 0, len = figureF.length; i < len; i++){
             let figure = figureF[i];
             let figure = figureF[i];
             let bill = null;
             let bill = null;
             if(figure.type === 'base' && cbTools.isDef(baseFigures[figure.value])){
             if(figure.type === 'base' && cbTools.isDef(baseFigures[figure.value])){
                 bill = baseFigures[figure.value]['fixedBill']['bill'];
                 bill = baseFigures[figure.value]['fixedBill']['bill'];
             }
             }
-            else if(figure.type === 'row'){
-                let tempBill = cbTools.getBillByRow(calcBase.project.mainTree.items, figure.value - 1);
-                bill = cbTools.isDef(tempBill) ? tempBill.data : null;
+            else if(figure.type === 'id'){
+                let node = cbTools.getNodeByID(calcBase.project.mainTree.items, figure.value);
+                bill = cbTools.isDef(node) ? node.data : null;
             }
             }
             if(cbTools.isDef(bill) && checkStack(getRefStack([bill.ID]), sIDs)){
             if(cbTools.isDef(bill) && checkStack(getRefStack([bill.ID]), sIDs)){
                 console.log('循环计算');
                 console.log('循环计算');
@@ -569,20 +635,27 @@ let cbAnalyzer = {
         let ilegalRex = /[\+,\-,\*,\/]{2}/g;
         let ilegalRex = /[\+,\-,\*,\/]{2}/g;
         let rex2 = /[{]{2}/g;
         let rex2 = /[{]{2}/g;
         let rex3 = /[}]{2}/g;
         let rex3 = /[}]{2}/g;
-        let rex4 = /[F]{2}/g
-        return !ilegalRex.test(exp) && !rex2.test(exp) && !rex3.test(exp) && !rex4.test(exp);
+        let rex4 = /[F]{2}/g;
+        let rex5 = /[.]{2}/g;
+        let rex6 = /[%]{2}/g;
+        return !ilegalRex.test(exp) && !rex2.test(exp) && !rex3.test(exp) && !rex4.test(exp) && !rex5.test(exp) && !rex6.test(exp);
     },
     },
     //
     //
     legalExp: function (node) {
     legalExp: function (node) {
         let exp = this.standar(node.data.userCalcBase);
         let exp = this.standar(node.data.userCalcBase);
         if(this.inputLegal(exp)){
         if(this.inputLegal(exp)){
-            if(this.baseLegal(cbTools.getFigure(node), exp)){
-                if(this.fLegal(calcBase.project.mainTree.items, exp)){
-                    if(!this.cycleCalc(node, cbTools.getFigure(node), exp)){
-                        if(this.arithmeticLegal(exp)){
+            if(this.arithmeticLegal(exp)){
+                if(this.baseLegal(cbTools.getFigure(node), exp)){
+                    if(this.fLegal(calcBase.project.mainTree.items, exp)){
+                        //转换成ID引用
+                        exp = cbParser.toIDExpr(exp);
+                        if(!this.cycleCalc(node, cbTools.getFigure(node), exp)){
                             return exp;
                             return exp;
                         }
                         }
                     }
                     }
+                    else {
+                        calcBase.errMsg = '行引用不合法';
+                    }
                 }
                 }
             }
             }
         }
         }
@@ -592,22 +665,34 @@ let cbAnalyzer = {
 
 
 //输入式转换器
 //输入式转换器
 let cbParser = {
 let cbParser = {
+    //获取标记F
+    getFMArr: function (exp) {
+        let fmRex = /F/g;
+        let fmArr = exp.match(fmRex);
+        return cbTools.isDef(fmArr) ? fmArr : [];
+    },
     //获取行引用 eg: F10
     //获取行引用 eg: F10
     getFArr: function (exp) {
     getFArr: function (exp) {
         let fRex = /F\d+/g;
         let fRex = /F\d+/g;
         let fArr = exp.match(fRex);
         let fArr = exp.match(fRex);
         return cbTools.isDef(fArr) ? fArr : [];
         return cbTools.isDef(fArr) ? fArr : [];
     },
     },
-    //获取行 eg: F10  10
-    getRArr: function (fArr) {
+    //获取X+num eg: F10  10 @105 105
+    getXNum: function (arr) {
         let rRex = /\d+/g;
         let rRex = /\d+/g;
         let tempArr = [];
         let tempArr = [];
-        for(let i = 0, len = fArr.length; i < len; i++){
-            tempArr = tempArr.concat(fArr[i].match(rRex));
+        for(let i = 0, len = arr.length; i < len; i++){
+            tempArr = tempArr.concat(arr[i].match(rRex));
         }
         }
         let rArr = Array.from(new Set(tempArr));
         let rArr = Array.from(new Set(tempArr));
         return rArr;
         return rArr;
     },
     },
+    //获取ID引用
+    getFIDArr: function (exp) {
+        let fidRex = /@\d+/g;
+        let fidArr = exp.match(fidRex);
+        return cbTools.isDef(fidArr) ? fidArr : [];
+    },
     //获取表达式中的中文式,没有{}需求时
     //获取表达式中的中文式,没有{}需求时
     getCN: function(expr){
     getCN: function(expr){
         let rst = [];
         let rst = [];
@@ -632,8 +717,8 @@ let cbParser = {
         }
         }
         return rst;
         return rst;
     },
     },
-    //获取表达式中的基数和
-    getFigureF: function (figures, rArr) {
+    //获取表达式中的基数和ID引用
+    getFigureF: function (figures, fidArr) {
         let rst = [];
         let rst = [];
         for(let i = 0, len = figures.length; i < len; i++){
         for(let i = 0, len = figures.length; i < len; i++){
             let obj = Object.create(null);
             let obj = Object.create(null);
@@ -641,15 +726,75 @@ let cbParser = {
             obj.value = figures[i];
             obj.value = figures[i];
             rst.push(obj);
             rst.push(obj);
         }
         }
-        for(let i = 0, len = rArr.length; i < len; i++){
+        for(let i = 0, len = fidArr.length; i < len; i++){
             let obj = Object.create(null);
             let obj = Object.create(null);
-            obj.type = 'row';
-            obj.value = rArr[i];
+            obj.type = 'id';
+            obj.value = fidArr[i];
             rst.push(obj);
             rst.push(obj);
         }
         }
         return rst;
         return rst;
     },
     },
-
+    //表达式中的百分数转换成小数
+    percentToNum: function (exp) {
+        let rex = /\d+(\.\d+)?%/g;
+        let percents = exp.match(rex);
+        let numRex = /\d+(\.\d+)?/g;
+        if(cbTools.isDef(percents)){
+            for(let i = 0, len = percents.length; i < len; i++){
+                let percentNum = percents[i].match(numRex);
+                if(cbTools.isDef(percentNum) && percentNum.length === 1){
+                    exp = exp.replace(new RegExp(percents[i], 'g'), percentNum[0]/100);
+                }
+            }
+        }
+        return exp;
+    },
+    //将行引用转换成ID引用
+    toIDExpr: function (exp) {
+        let exps = [];
+        //获得行引用
+        let fArr = this.getFArr(exp);
+        for(let i = 0, len = fArr.length; i < len; i++){
+            let r = this.getXNum([fArr[i]]);
+            if(r.length === 1){
+                let node = cbTools.getBillByRow(calcBase.project.mainTree.items, r[0] - 1);
+                if(cbTools.isUnDef(node)){
+                    //continue;
+                    calcBase.errMsg = '行引用错误';
+                    throw '行引用错误';
+                }
+                exps.push({orgExp: fArr[i], newExp: '@' + node.data.ID});
+            }
+            else {
+                calcBase.errMsg = '行引用错误';
+                throw '行引用错误';
+            }
+        }
+        for(let i = 0, len = exps.length; i < len; i++){
+            exp = exp.replace(new RegExp(exps[i].orgExp, 'g'), exps[i].newExp);
+        }
+        return exp;
+    },
+    //将ID引用转换成行引用
+    toFExpr: function (exp) {
+        let exps = [];
+        //获得ID引用
+        let fidArr = this.getFIDArr(exp);
+        for(let i = 0, len = fidArr.length; i < len; i++){
+            let id = this.getXNum([fidArr[i]]);
+            if(id.length === 1){
+                let row = cbTools.getRowByID(calcBase.project.mainTree.items, id[0]);
+                if(cbTools.isUnDef(row)){
+                    continue;
+                }
+                exps.push({orgExp: fidArr[i], newExp: 'F' + row});
+            }
+        }
+        for(let i = 0, len = exps.length; i < len; i++){
+            exp = exp.replace(new RegExp(exps[i].orgExp, 'g'), exps[i].newExp);
+        }
+        return exp;
+    },
     //将表达式转换为可编译的表达式
     //将表达式转换为可编译的表达式
     toCompileExpr: function(v){
     toCompileExpr: function(v){
         if(v === ''){
         if(v === ''){
@@ -670,15 +815,15 @@ let cbParser = {
             v = v.replace(new RegExp(exps[i].orgExp, 'g'), exps[i].compileExp);
             v = v.replace(new RegExp(exps[i].orgExp, 'g'), exps[i].compileExp);
         }
         }
         //行引用
         //行引用
-        let fArr = this.getFArr(v);
+        let fidArr = this.getFIDArr(v);
         let fExps = [];
         let fExps = [];
-        for(let i = 0, len = fArr.length; i < len; i++){
+        for(let i = 0, len = fidArr.length; i < len; i++){
             let fExp = Object.create(null);
             let fExp = Object.create(null);
-            fExp.orgExp = fArr[i];
+            fExp.orgExp = fidArr[i];
             fExps.push(fExp);
             fExps.push(fExp);
         }
         }
         for(let i = 0, len = fExps.length; i < len; i++){
         for(let i = 0, len = fExps.length; i < len; i++){
-            fExps[i].compileExp = '$CBC.f(\'' + fExps[i].orgExp + '\')';
+            fExps[i].compileExp = '$CBC.ref(\'' + fExps[i].orgExp + '\')';
             v = v.replace(new RegExp(fExps[i].orgExp, 'g'), fExps[i].compileExp);
             v = v.replace(new RegExp(fExps[i].orgExp, 'g'), fExps[i].compileExp);
         }
         }
         return v;
         return v;
@@ -693,13 +838,18 @@ let cbCalctor = {
         }
         }
         return baseFigureTemplate[calcBase.baseFigures[figure]['base']]();
         return baseFigureTemplate[calcBase.baseFigures[figure]['base']]();
     },
     },
-    //行引用
-    f: function (fExp) {
-        let r = cbParser.getRArr([fExp]);
-        return cbTools.isDef(calcBase.project.mainTree.items[r[0] - 1]['data']['feesIndex']) &&
-            cbTools.isDef(calcBase.project.mainTree.items[r[0] - 1]['data']['feesIndex']['common'])&&
-            cbTools.isDef(calcBase.project.mainTree.items[r[0] - 1]['data']['feesIndex']['common']['totalFee']) ?
-            calcBase.project.mainTree.items[r[0] - 1]['data']['feesIndex']['common']['totalFee'] : 0;
+    //ID引用
+    ref: function (fExp) {
+        let ID = cbParser.getXNum([fExp]);
+        if(ID.length === 1){
+            let node = cbTools.getNodeByID(calcBase.project.mainTree.items, parseInt(ID[0]));
+            return cbTools.isDef(node) &&
+                    cbTools.isDef(node.data.feesIndex) &&
+                    cbTools.isDef(node.data.feesIndex.common) &&
+                    cbTools.isDef(node.data.feesIndex.common.totalFee) ?
+                    node.data.feesIndex.common.totalFee : 0;
+        }
+        return 0;
     },
     },
     //计算
     //计算
     exec: function () {
     exec: function () {
@@ -738,7 +888,7 @@ let calcBase = {
         return cbTools.getBaseBill(node);
         return cbTools.getBaseBill(node);
     },
     },
     calculate: function (node, reCalc = null) {
     calculate: function (node, reCalc = null) {
-        let me = calcBase,
+            let me = calcBase,
             $CBA = cbAnalyzer,
             $CBA = cbAnalyzer,
             $CBP = cbParser,
             $CBP = cbParser,
             $CBC = cbCalctor;
             $CBC = cbCalctor;
@@ -754,10 +904,12 @@ let calcBase = {
             if(!cbTools.isDef(exp)){
             if(!cbTools.isDef(exp)){
                 throw '表达式不正确';
                 throw '表达式不正确';
             }
             }
+
             //输入式转换表达式
             //输入式转换表达式
             let compileExp = $CBP.toCompileExpr(exp);
             let compileExp = $CBP.toCompileExpr(exp);
             //计算
             //计算
-            let calcBaseValue = eval(compileExp);
+            let calcExp = $CBP.percentToNum(compileExp);
+            let calcBaseValue = eval(calcExp);
             if(!cbTools.isNum(calcBaseValue)){
             if(!cbTools.isNum(calcBaseValue)){
                 throw '表达式不正确';
                 throw '表达式不正确';
             }
             }

+ 49 - 43
web/building_saas/main/js/models/calc_program.js

@@ -422,39 +422,6 @@ let executeObj = {
 };
 };
 
 
 let treeNodeTools = {
 let treeNodeTools = {
-    // 获取全部有公式的树节点清单
-    getFormulaNodes: function () {
-        let nodes = [];
-        for (let node of projectObj.project.mainTree.items){
-              if (node.sourceType == ModuleNames.bills && node.data.calcBase && node.data.calcBase != '')
-                  nodes.push(node);
-        };
-
-        if (nodes.length >= 2) return this.orderFormulaNodes(nodes)
-        else return nodes;
-    },
-
-    // 给公式结点清单换照引用计算顺序排序。
-    orderFormulaNodes: function (nodesArr) {
-        let orderArr = [];
-
-        function recursionNode(nodes) {
-            for (let node of nodes){
-                if (orderArr.includes(node)) continue;    // 已排过序的节点则跳过
-
-                if (node.data.calcBase){
-                    let subNodes = cbTools.getNodesByExp(node.data.calcBase);
-                    recursionNode(subNodes);
-                };
-
-                if (nodesArr.includes(node) && !orderArr.includes(node)) orderArr.push(node);
-            };
-        }
-
-        recursionNode(nodesArr);
-        return orderArr;
-    },
-
     isBill: function(treeNode){
     isBill: function(treeNode){
         return treeNode.sourceType === ModuleNames.bills;
         return treeNode.sourceType === ModuleNames.bills;
     },
     },
@@ -466,6 +433,10 @@ let treeNodeTools = {
     isNullBill: function (treeNode) {
     isNullBill: function (treeNode) {
         return this.isLeafBill(treeNode) && (treeNode.children.length === 0) && (!treeNode.data.calcBase);
         return this.isLeafBill(treeNode) && (treeNode.children.length === 0) && (!treeNode.data.calcBase);
     },
     },
+    isEngineeringCostBill: function (treeNode) {
+        return treeNode.data.flagsIndex && treeNode.data.flagsIndex.fixed && treeNode.data.flagsIndex.fixed.flag &&
+            treeNode.data.flagsIndex.fixed.flag == fixedFlag.ENGINEERINGCOST;
+    },
 
 
     isRationCategory: function(treeNode){
     isRationCategory: function(treeNode){
         return treeNode.sourceType === ModuleNames.ration;
         return treeNode.sourceType === ModuleNames.ration;
@@ -496,8 +467,19 @@ let treeNodeTools = {
             treeNode.data.fees.push(fee);
             treeNode.data.fees.push(fee);
             treeNode.data.feesIndex[fieldName] = fee;
             treeNode.data.feesIndex[fieldName] = fee;
         };
         };
+        treeNode.changed = true;
+    },
+    initSummaryFee(treeNode){
+        if (!treeNode.data.summaryFees){
+            treeNode.data.summaryFees = {
+                totalFee: 0,
+                estimateFee: 0,
+                safetyFee: 0,
+                chargeFee: 0
+            };
+            treeNode.changed = true;
+        };
     },
     },
-
     getCalcType(treeNode) {
     getCalcType(treeNode) {
         if (this.isRationCategory(treeNode)){
         if (this.isRationCategory(treeNode)){
             return treeNodeCalcType.ctRationCalcProgram;
             return treeNodeCalcType.ctRationCalcProgram;
@@ -753,6 +735,7 @@ class CalcProgram {
                     contain:node.data.contain,
                     contain:node.data.contain,
                     quantityEXP:node.data.quantityEXP
                     quantityEXP:node.data.quantityEXP
                 };
                 };
+                if (node.data.summaryFees) data.summaryFees = node.data.summaryFees;
                 if(node.sourceType==ModuleNames.ration && node.data.type==rationType.gljRation){//定额类型的工料机做特殊处理
                 if(node.sourceType==ModuleNames.ration && node.data.type==rationType.gljRation){//定额类型的工料机做特殊处理
                     data.code=node.data.code;
                     data.code=node.data.code;
                     data.projectGLJID = node.data.projectGLJID;
                     data.projectGLJID = node.data.projectGLJID;
@@ -932,14 +915,37 @@ class CalcProgram {
             let tf = (me.project.property.billsCalcMode === leafBillGetFeeType.rationPrice) ? (b * f / 100).toDecimal(decimalObj.bills.totalPrice) : (uf * q).toDecimal(decimalObj.bills.totalPrice);
             let tf = (me.project.property.billsCalcMode === leafBillGetFeeType.rationPrice) ? (b * f / 100).toDecimal(decimalObj.bills.totalPrice) : (uf * q).toDecimal(decimalObj.bills.totalPrice);
             let ttf = tf;
             let ttf = tf;
 
 
-            delete treeNode.data.fees;    // 直接删掉再新增,不用一个个费判断更新,效率更高。
-            delete treeNode.data.feesIndex;
-            treeNodeTools.initFeeField(treeNode, 'common');
-            treeNode.data.feesIndex.common.unitFee = uf;
-            treeNode.data.feesIndex.common.totalFee = tf;
-            treeNode.data.feesIndex.common.tenderUnitFee = tuf;
-            treeNode.data.feesIndex.common.tenderTotalFee = ttf;
-            treeNode.changed = true;
+            function newCommonFee(){
+                treeNodeTools.initFeeField(treeNode, 'common');
+                treeNode.data.feesIndex.common.unitFee = uf;
+                treeNode.data.feesIndex.common.totalFee = tf;
+                treeNode.data.feesIndex.common.tenderUnitFee = tuf;
+                treeNode.data.feesIndex.common.tenderTotalFee = ttf;
+                treeNode.changed = true;
+                // 如果是总造价清单,还要做单项工程、建设项目金额汇总
+                if (treeNodeTools.isEngineeringCostBill(treeNode)){
+                    treeNodeTools.initSummaryFee(treeNode);
+                    treeNode.data.summaryFees.totalFee = tf;
+                    treeNode.data.summaryFees.estimateFee = 0;//treeNode.data.feesIndex.zangu.totalFee;
+                    let bill_safe = cbTools.findBill(fixedFlag.SAFETY_CONSTRUCTION);
+                    treeNode.data.summaryFees.safetyFee = (bill_safe && bill_safe.feesIndex && bill_safe.feesIndex.common)?bill_safe.feesIndex.common.totalFee:0;
+                    let bill_charge = cbTools.findBill(fixedFlag.CHARGE);
+                    treeNode.data.summaryFees.chargeFee = (bill_charge && bill_charge.feesIndex && bill_charge.feesIndex.common)?bill_charge.feesIndex.common.totalFee:0;
+                }
+            };
+
+            if (treeNode.data.feesIndex && treeNode.data.feesIndex.common){
+                if (treeNode.data.feesIndex.common.unitFee != uf ||
+                    treeNode.data.feesIndex.common.totalFee != tf ||
+                    treeNode.data.feesIndex.common.tenderUnitFee != tuf ||
+                    treeNode.data.feesIndex.common.tenderTotalFee != ttf ){
+                    delete treeNode.data.fees;    // 直接删掉再新增。从其它计算方式切换到公式计算方式,会多出其它的费(不光是common)所以这里直接删掉,不用一个个费判断更新,效率更高。
+                    delete treeNode.data.feesIndex;
+                    newCommonFee();
+                }
+            }else{
+                newCommonFee();
+            };
             treeNode.data.calcTemplate = {"calcItems": []};
             treeNode.data.calcTemplate = {"calcItems": []};
         }
         }
         // 定额或叶子清单自己的计算程序计算
         // 定额或叶子清单自己的计算程序计算
@@ -1059,7 +1065,7 @@ class CalcProgram {
     // 计算全部公式项。 (参数意义:将通过本方法后发生改变的节点存入changedNodesArr中)
     // 计算全部公式项。 (参数意义:将通过本方法后发生改变的节点存入changedNodesArr中)
     calcFormulaNodes(changedArr){
     calcFormulaNodes(changedArr){
         let me = this;
         let me = this;
-        let formulaNodes = treeNodeTools.getFormulaNodes();
+        let formulaNodes = cbTools.getFormulaNodes(true);
         if (formulaNodes.length == 0) return;
         if (formulaNodes.length == 0) return;
         for (let formulaNode of formulaNodes){
         for (let formulaNode of formulaNodes){
             formulaNode.data.userCalcBase = formulaNode.data.calcBase;    // 这句不该出现,projectObj.project.calcBase中要改进。
             formulaNode.data.userCalcBase = formulaNode.data.calcBase;    // 这句不该出现,projectObj.project.calcBase中要改进。

+ 18 - 1
web/building_saas/main/js/models/ration.js

@@ -213,6 +213,7 @@ var Ration = {
                         data.updateData.comments = std.chapter.explanation;
                         data.updateData.comments = std.chapter.explanation;
                         data.updateData.ruleText = std.chapter.ruleText;
                         data.updateData.ruleText = std.chapter.ruleText;
                     }
                     }
+                    data.updateData.from = std.type === 'complementary' ? 'cpt' : 'std';
                     data.updateData.programID = std.feeType;
                     data.updateData.programID = std.feeType;
                     data.updateData.rationAssList =  projectObj.project.ration_ass.CreateNewAss(std);
                     data.updateData.rationAssList =  projectObj.project.ration_ass.CreateNewAss(std);
                     // calculate ration Quantity
                     // calculate ration Quantity
@@ -374,6 +375,7 @@ var Ration = {
                 ration.comments = std.chapter.explanation;
                 ration.comments = std.chapter.explanation;
                 ration.ruleText = std.chapter.ruleText;
                 ration.ruleText = std.chapter.ruleText;
             }
             }
+            ration.from = std.type === 'complementary' ? 'cpt' : 'std';
             ration.programID = std.feeType;
             ration.programID = std.feeType;
             ration.rationAssList = projectObj.project.ration_ass.CreateNewAss(std);
             ration.rationAssList = projectObj.project.ration_ass.CreateNewAss(std);
             // calculate ration Quantity
             // calculate ration Quantity
@@ -411,7 +413,22 @@ var Ration = {
             project.calcProgram.calcAndSave(node);
             project.calcProgram.calcAndSave(node);
             projectObj.mainController.refreshTreeNode(node.children);//刷新子工料机树节点总消耗量
             projectObj.mainController.refreshTreeNode(node.children);//刷新子工料机树节点总消耗量
         };
         };
-        
+        ration.prototype.addRationChecking=function(selected){
+            if (selected) {// Vincent, 2018-01-02
+                if(selected.sourceType === project.Ration.getSourceType()){ // 焦点行是定额/量价/工料机,有效显示。
+                    return false;
+                }else if(selected.sourceType === project.Bills.getSourceType()){
+                    if(selected.data.type == billType.FX){//焦点行是分项,有效显示。
+                        return false
+                    }
+                    if(selected.data.type == billType.BILL && selected.source.children.length === 0){//焦点行是清单,且没有子项,有效显示。
+                        return false
+                    }
+                }
+            }
+            return true;
+        };
+
         return new ration(project);
         return new ration(project);
     }
     }
 };
 };

+ 4 - 2
web/building_saas/main/js/views/calc_base_view.js

@@ -132,7 +132,7 @@ let calcBaseView = {
         let me = calcBaseView;
         let me = calcBaseView;
         //输入框显示原本的
         //输入框显示原本的
         if(me.isDef(node.data.calcBase)){
         if(me.isDef(node.data.calcBase)){
-            me.inputExpr.val(node.data.calcBase);
+            me.inputExpr.val(cbParser.toFExpr(node.data.calcBase));
         }
         }
         me.buildSheet();
         me.buildSheet();
         let baseObj = projectObj.project.calcBase.getBaseByClass(node);
         let baseObj = projectObj.project.calcBase.getBaseByClass(node);
@@ -151,7 +151,9 @@ let calcBaseView = {
         let rex2 = /[{]{2}/g;
         let rex2 = /[{]{2}/g;
         let rex3 = /[}]{2}/g;
         let rex3 = /[}]{2}/g;
         let rex4 = /[F]{2}/g;
         let rex4 = /[F]{2}/g;
-        return !rex.test(v) && !rex2.test(v) && !rex3.test(v) && !rex4.test(v);
+        let rex5 = /[.]{2}/g;
+        let rex6 = /[%]{2}/g;
+        return !rex.test(v) && !rex2.test(v) && !rex3.test(v) && !rex4.test(v) && !rex5.test(v) && !rex6.test(v);
     },
     },
 
 
     //运算符点击显示到运算窗口
     //运算符点击显示到运算窗口

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

@@ -397,7 +397,7 @@ var gljOprObj = {
     },
     },
     onCheckBoxClick: function (sender, args) {
     onCheckBoxClick: function (sender, args) {
         let selected = projectObj.project.mainTree.selected;
         let selected = projectObj.project.mainTree.selected;
-        if(selected.sourceType == ModuleNames.ration_glj||(selected.sourceType == ModuleNames.ration&&selected.data.type==rationType.gljRation)){//选中的是工料机时不可编辑
+        if(selected.sourceType == ModuleNames.ration_glj){//选中的是工料机时不可编辑
             return ;
             return ;
         }
         }
         var checkboxValue = args.sheet.getCell(args.row, args.col).value();
         var checkboxValue = args.sheet.getCell(args.row, args.col).value();

+ 40 - 11
web/building_saas/main/js/views/main_tree_col.js

@@ -33,12 +33,36 @@ let MainTreeCol = {
             let programID = node.data.programID;
             let programID = node.data.programID;
             if (!programID) return
             if (!programID) return
             else return projectObj.project.calcProgram.compiledTemplateMaps[programID];
             else return projectObj.project.calcProgram.compiledTemplateMaps[programID];
+        },
+        calcBase: function (node) {
+            if (node.data.calcBase && node.data.calcBase != ""){
+                return cbParser.toFExpr(node.data.calcBase);
+            }
+        },
+        code: function (node) {
+            if(node.sourceType === projectObj.project.Ration.getSourceType() && isDef(node.data.code) && isDef(node.data.from) && node.data.from === 'cpt'){
+                return '补' +  node.data.code.replace(new RegExp('补'), '');
+            }
+            else {
+                return isDef(node.data.code) ? node.data.code : '';
+            }
         }
         }
     },
     },
     readOnly: {
     readOnly: {
-        // CSL, 2017-11-28
+        // Vincent, 2018-01-09
         subType: function (node) {
         subType: function (node) {
-            return MainTreeCol.readOnly.bills(node)||(node.data.type != 2 && node.data.type != 3 && !MainTreeCol.readOnly.glj(node)) || (node.data.type == rationType.gljRation && MainTreeCol.readOnly.non_editSubType(node));
+            if(MainTreeCol.readOnly.bills(node)){
+                return true;
+            }
+            if(MainTreeCol.readOnly.ration(node)){
+                return true;
+            }
+            if(MainTreeCol.readOnly.non_editSubType(node)){
+                return true;
+            }else if(gljOprObj.hasComposition(node.data,node.sourceType === ModuleNames.ration)){
+                return true;
+            }
+            return false;
         },
         },
         calcProgramName: function (node) {
         calcProgramName: function (node) {
             if (
             if (
@@ -168,20 +192,25 @@ let MainTreeCol = {
             }
             }
         },
         },
 
 
-        // CSL, 2017-11-28
+        // Vincent, 2018-01-09
         subType: function (node) {
         subType: function (node) {
             if(node.sourceType!=projectObj.project.Bills.getSourceType()){
             if(node.sourceType!=projectObj.project.Bills.getSourceType()){
-                if (node.data.type == rationType.volumePrice || node.data.type == rationType.gljRation || node.sourceType === projectObj.project.ration_glj.getSourceType()) {
-                    let VPType = sheetCommonObj.getDynamicCombo();
-                    if (node.data.type == rationType.volumePrice)
+                let VPType = sheetCommonObj.getDynamicCombo();
+                if(node.sourceType == projectObj.project.Ration.getSourceType()){//是定额类型
+                    if(node.data.type == rationType.volumePrice){
                         VPType.itemHeight(5).items(["人工", "材料", "机械", "主材", "设备"])
                         VPType.itemHeight(5).items(["人工", "材料", "机械", "主材", "设备"])
-                    else if (node.data.type == rationType.gljRation || node.sourceType === projectObj.project.ration_glj.getSourceType())
-                        if (!MainTreeCol.readOnly.non_editSubType(node)) {
+                        return VPType;
+                    }else if(node.data.type == rationType.gljRation){
+                        if(!MainTreeCol.readOnly.non_editSubType(node)&&gljOprObj.hasComposition(node.data,true)==false){
                             VPType.itemHeight(3).items(["材料", "主材", "设备"]);
                             VPType.itemHeight(3).items(["材料", "主材", "设备"]);
-                        } else {
-                            return null;
+                            return VPType;
                         }
                         }
-                    return VPType;
+                    }
+                }else if(node.sourceType === projectObj.project.ration_glj.getSourceType()){//是工料机类型
+                    if(!MainTreeCol.readOnly.non_editSubType(node)&&gljOprObj.hasComposition(node.data)==false){
+                        VPType.itemHeight(3).items(["材料", "主材", "设备"]);
+                        return VPType;
+                    }
                 }
                 }
             }
             }
         },
         },

+ 150 - 61
web/building_saas/main/js/views/project_view.js

@@ -66,10 +66,13 @@ var projectObj = {
         let canDelete = function (node) {
         let canDelete = function (node) {
             if (selected) {
             if (selected) {
                 if (selected.sourceType === that.project.Bills.getSourceType()) {
                 if (selected.sourceType === that.project.Bills.getSourceType()) {
-                    return !(selected.data.flagsIndex && selected.data.flagsIndex.fixed && selected.data.flagsIndex.fixed.flag > 0);
-                } else {
-                    return true;
+                    if(selected.data.type == billType.DXFY&&selected.data.isAdd!=1){//如果
+                        return false;
+                    }
+                }if(selected.sourceType === that.project.ration_glj.getSourceType()){
+                    return false;
                 }
                 }
+                return true;
             } else {
             } else {
                 return false;
                 return false;
             }
             }
@@ -229,25 +232,20 @@ var projectObj = {
         } 
         } 
     },
     },
     updateRationCode: function (node, value) {
     updateRationCode: function (node, value) {
-        if (/[\w]{2}[\d]{4}/.test(value)) {
-            if (projectInfoObj.projectInfo.engineeringInfo.ration_lib.length === 0) {
-                alert('当前项目无定额库,请添加定额库。');
-                this.mainController.refreshTreeNode([node], false);
-            } else {
-                let libId = projectInfoObj.projectInfo.engineeringInfo.ration_lib[0].id;
-                CommonAjax.postRationLib('/rationRepository/api/matchRation', {user_id: userID, rationLibId: libId, code: value}, function (data) {
-                    if (data) {
-                        projectObj.project.Ration.replaceRation(node.source, data);
-                        projectObj.project.ration_glj.addRationGLJ(node.source, data);
-                    } else {
-                        alert('当前库中找不到定额"' + value + '"');
-                    }
-                    projectObj.mainController.refreshTreeNode([node], false);
-                });
-            }
-        } else {
-            alert('输入的定额编码有误,请检查。');
+        if (projectInfoObj.projectInfo.engineeringInfo.ration_lib.length === 0) {
+            alert('当前项目无定额库,请添加定额库。');
             this.mainController.refreshTreeNode([node], false);
             this.mainController.refreshTreeNode([node], false);
+        } else {
+            let libId = projectInfoObj.projectInfo.engineeringInfo.ration_lib[0].id;
+            CommonAjax.post('/complementaryRation/api/getRationItem', {user_id: userID, rationRepId: libId, code: value}, function (data) {
+                if (data) {
+                    projectObj.project.Ration.replaceRation(node.source, data);
+                    projectObj.project.ration_glj.addRationGLJ(node.source, data);
+                } else {
+                    alert('当前库中找不到定额"' + value + '"');
+                }
+                projectObj.mainController.refreshTreeNode([node], false);
+            });
         }
         }
     },
     },
     updateCode: function (node, value) {
     updateCode: function (node, value) {
@@ -306,7 +304,9 @@ var projectObj = {
                     treeNodeTools.initFeeField(node, 'common');
                     treeNodeTools.initFeeField(node, 'common');
                     node.data.feesIndex.common.unitFee = value;
                     node.data.feesIndex.common.unitFee = value;
                 }
                 }
-                else node.data[fieldName] = value;
+                else if(fieldName !== 'calcBase'){
+                    node.data[fieldName] = value;
+                }
                 project.calcProgram.calcAndSave(node);
                 project.calcProgram.calcAndSave(node);
                 gljOprObj.showRationGLJSheetData();
                 gljOprObj.showRationGLJSheetData();
             } else if (node.sourceType === project.Bills.getSourceType()&&fieldName === 'unit'){//修改清单单位的时候清单工程量要重新4舍5入
             } else if (node.sourceType === project.Bills.getSourceType()&&fieldName === 'unit'){//修改清单单位的时候清单工程量要重新4舍5入
@@ -346,6 +346,15 @@ var projectObj = {
             info.sheet.repaint();
             info.sheet.repaint();
         }
         }
     },
     },
+    mainSpreadEditStarting: function (sender, info) {
+        let project = projectObj.project;
+        let node = project.mainTree.items[info.row];
+        if(isDef(node) && node.sourceType === project.Ration.getSourceType() && isDef(node.data.code) && isDef(node.data.from) && node.data.from === 'cpt'){
+            let orgV = info.sheet.getValue(info.row, info.col);
+            let newV = orgV.replace(new RegExp('补'), '');
+            info.sheet.setValue(info.row, info.col, newV);
+        }
+    },
     mainSpreadEditEnded: function (sender, info) {
     mainSpreadEditEnded: function (sender, info) {
         let project = projectObj.project;
         let project = projectObj.project;
         let node = project.mainTree.items[info.row];
         let node = project.mainTree.items[info.row];
@@ -462,6 +471,7 @@ var projectObj = {
 
 
                 that.mainSpread.bind(GC.Spread.Sheets.Events.LeaveCell, that.mainSpreadLeaveCell);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.LeaveCell, that.mainSpreadLeaveCell);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.EnterCell, that.mainSpreadEnterCell);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.EnterCell, that.mainSpreadEnterCell);
+                that.mainSpread.bind(GC.Spread.Sheets.Events.EditStarting, that.mainSpreadEditStarting);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.EditEnded, that.mainSpreadEditEnded);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.EditEnded, that.mainSpreadEditEnded);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.RangeChanged, that.mainSpreadRangeChanged);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.RangeChanged, that.mainSpreadRangeChanged);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.SelectionChanged, that.amountAreaNumber);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.SelectionChanged, that.amountAreaNumber);
@@ -511,6 +521,8 @@ var projectObj = {
                             if(isFlag(selected.data)&&selected.data.flagsIndex.fixed.flag==fixedFlag.SUB_ENGINERRING){//焦点行是分部分项工程
                             if(isFlag(selected.data)&&selected.data.flagsIndex.fixed.flag==fixedFlag.SUB_ENGINERRING){//焦点行是分部分项工程
                                 if(selected.children.length>0){
                                 if(selected.children.length>0){
                                    return selected.children[0].data.type==billType.FX;//焦点行是分部分项工程,且子项是分项
                                    return selected.children[0].data.type==billType.FX;//焦点行是分部分项工程,且子项是分项
+                                }else {
+                                    return false
                                 }
                                 }
                             }
                             }
                         }
                         }
@@ -580,19 +592,7 @@ var projectObj = {
                     icon: 'fa-sign-in',
                     icon: 'fa-sign-in',
                     disabled: function () {
                     disabled: function () {
                         var selected = project.mainTree.selected;
                         var selected = project.mainTree.selected;
-                        if (selected) {// Vincent, 2018-01-02
-                            if(selected.sourceType === project.Ration.getSourceType()){ // 焦点行是定额/量价/工料机,有效显示。
-                                return false;
-                            }else if(selected.sourceType === project.Bills.getSourceType()){
-                               if(selected.data.type == billType.FX){//焦点行是分项,有效显示。
-                                  return false
-                               }
-                               if(selected.data.type == billType.BILL && selected.source.children.length === 0){//焦点行是清单,且没有子项,有效显示。
-                                    return false
-                               }
-                            }
-                        }
-                        return true;
+                        return project.Ration.addRationChecking(selected);  // Vincent, 2018-01-02
                     },
                     },
                     callback: function (key, opt) {
                     callback: function (key, opt) {
                         ProjectController.addRation(project, controller, rationType.ration);
                         ProjectController.addRation(project, controller, rationType.ration);
@@ -611,16 +611,18 @@ var projectObj = {
                     icon: 'fa-sign-in',
                     icon: 'fa-sign-in',
                     disabled: function () {
                     disabled: function () {
                         var selected = project.mainTree.selected;
                         var selected = project.mainTree.selected;
-                        if (selected) {
-                            if (            // CSL, 2017-11-28
-                            selected.sourceType === project.Ration.getSourceType() ||
-                            (selected.sourceType === project.Bills.getSourceType() && selected.source.children.length === 0)
-                            ) return false
-                            else return true
-                        } else return true
+                        return project.Ration.addRationChecking(selected);  // Vincent, 2018-01-02
                     },
                     },
                     callback: function (key, opt) {
                     callback: function (key, opt) {
                         ProjectController.addRation(project, controller, rationType.volumePrice);
                         ProjectController.addRation(project, controller, rationType.volumePrice);
+                    },
+                    visible: function(key, opt){
+                        var selected = project.mainTree.selected;
+                        if(selected.sourceType == ModuleNames.bills&&selected.data.type == billType.DXFY){
+                            return false
+                        }else {
+                            return true
+                        }
                     }
                     }
                 },
                 },
                 "insertGLJ": {
                 "insertGLJ": {
@@ -628,11 +630,27 @@ var projectObj = {
                     icon: 'fa-sign-in',
                     icon: 'fa-sign-in',
                     disabled: function () {
                     disabled: function () {
                         var selected = project.mainTree.selected;
                         var selected = project.mainTree.selected;
-                        var readOnly = MainTreeCol.readOnly;
-                        return readOnly.billsParent(selected)||(readOnly.bills(selected)&&!readOnly.forCalcBase(selected))||readOnly.glj(selected);
+                        return project.Ration.addRationChecking(selected);  // Vincent, 2018-01-02
                     },
                     },
                     callback: function (key, opt) {
                     callback: function (key, opt) {
+                        var selected = project.mainTree.selected;
+                        if(selected.sourceType == ModuleNames.bills){
+                            if(selected.data.type == billType.FX||selected.data.type ==billType.BILL){
+                                if(selected.data.calcBase&&selected.data.calcBase!=""){
+                                    alert("当前有基数计算不能插入子项。");
+                                    return;
+                                }
+                            }
+                        }
                         getGLJData('insert');// ProjectController.addRation(project, controller, rationType.volumePrice);
                         getGLJData('insert');// ProjectController.addRation(project, controller, rationType.volumePrice);
+                    },
+                    visible: function(key, opt){
+                        var selected = project.mainTree.selected;
+                        if(selected.sourceType == ModuleNames.bills&&selected.data.type == billType.DXFY){
+                            return false
+                        }else {
+                            return true
+                        }
                     }
                     }
                 },
                 },
                 "spr1": '--------',
                 "spr1": '--------',
@@ -647,6 +665,10 @@ var projectObj = {
                         var selected = controller.tree.selected, parent = selected.parent;
                         var selected = controller.tree.selected, parent = selected.parent;
                         if (selected) {
                         if (selected) {
                             if (selected.sourceType === project.Bills.getSourceType()) {
                             if (selected.sourceType === project.Bills.getSourceType()) {
+                                if (cbTools.isUsedByFormula(selected)){
+                                    alert('该清单行被其它公式结点引用,不允许删除!');
+                                    return;
+                                };
                                 project.Bills.deleteBills(selected.source);
                                 project.Bills.deleteBills(selected.source);
                                 controller.delete();
                                 controller.delete();
                             } else if (selected.sourceType === project.Ration.getSourceType()) {
                             } else if (selected.sourceType === project.Ration.getSourceType()) {
@@ -661,8 +683,10 @@ var projectObj = {
                 "calculateAll_RationContent": {
                 "calculateAll_RationContent": {
                     name: '造价计算',
                     name: '造价计算',
                     callback: function () {
                     callback: function () {
+                        $.bootstrapLoading.start();
                         let changedNodes = project.calcProgram.calcAllNodes();
                         let changedNodes = project.calcProgram.calcAllNodes();
                         project.calcProgram.saveNodes(changedNodes);
                         project.calcProgram.saveNodes(changedNodes);
+                        $.bootstrapLoading.end();
                     }
                     }
                 }
                 }
             }
             }
@@ -683,7 +707,7 @@ var projectObj = {
             calc = null;
             calc = null;
         }*/
         }*/
         projectObj.project.calcProgram.calcAndSave(node);
         projectObj.project.calcProgram.calcAndSave(node);
-    },
+},
     // 计算全部清单
     // 计算全部清单
 /*    calculateAll: function () {
 /*    calculateAll: function () {
         let calc = new BillsCalcHelper(this.project);
         let calc = new BillsCalcHelper(this.project);
@@ -805,25 +829,13 @@ $('#insert').click(function () {
         ProjectController.addBills(project, controller);
         ProjectController.addBills(project, controller);
     } else if (selected.sourceType === project.Ration.getSourceType()) {
     } else if (selected.sourceType === project.Ration.getSourceType()) {
         ProjectController.addRation(project, controller, selected.data.type);
         ProjectController.addRation(project, controller, selected.data.type);
-    }
+    };
 });
 });
-$('#delete').click(function () {
-    var controller = projectObj.mainController, project = projectObj.project;
-    var selected = controller.tree.selected, parent = selected.parent;
 
 
-    if (selected) {
-        if (selected.sourceType === project.Bills.getSourceType()) {
-            project.Bills.deleteBills(selected.source);
-            controller.delete();
-        } else if (selected.sourceType === project.Ration.getSourceType()) {
-            project.Ration.delete(selected.source);
-            controller.delete();
-        }else if(selected.sourceType==ModuleNames.ration_glj){
-            project.ration_glj.updataOrdelete(selected.source);
-        };
-        projectObj.converseCalculateBills(parent);
-    }
+$('#delete').click(function () {
+    $("#delete_row").modal({show:true});//弹出删除提示框;
 });
 });
+
 $('#upLevel').click(function () {
 $('#upLevel').click(function () {
     var controller = projectObj.mainController, project = projectObj.project;
     var controller = projectObj.mainController, project = projectObj.project;
     var selected = controller.tree.selected, orgParent = selected.parent;
     var selected = controller.tree.selected, orgParent = selected.parent;
@@ -1021,3 +1033,80 @@ $('#property_ok').click(function () {
         });
         });
     }
     }
 });
 });
+
+$('#delete_row').on('shown.bs.modal', function (e) {
+    var controller = projectObj.mainController, project = projectObj.project;
+    var selected = controller.tree.selected, parent = selected.parent;
+    var showinfo = "确认要删除当前选中行吗?";
+    var showN = false;
+    var cancelText = "否";
+    if(selected.sourceType == project.Bills.getSourceType()&&selected.data.type==billType.FB&&selected.children.length>0){
+         showinfo = "是否删除其下的子项?";
+         showN = true;
+         cancelText = "取消";
+    }
+    $('#delete_showinfo').text(showinfo);
+    showN==true? $('#deleteN').show():$('#deleteN').hide();
+    $('#deleteCancel').text(cancelText);
+});
+
+$('#deleteY').click(function () { //正常删除,级联删除子项
+     let controller = projectObj.mainController, project = projectObj.project;
+     let selected = controller.tree.selected, parent = selected.parent;
+     if (selected) {
+         if (selected.sourceType === project.Bills.getSourceType()) {
+             if (cbTools.isUsedByFormula(selected)){
+                 alert('该清单行被其它公式结点引用,不允许删除!');
+                 return;
+             }
+             project.Bills.deleteBills(selected.source);
+             controller.delete();
+         } else if (selected.sourceType === project.Ration.getSourceType()) {
+             project.Ration.delete(selected.source);
+             controller.delete();
+         }else if(selected.sourceType==ModuleNames.ration_glj){
+            project.ration_glj.updataOrdelete(selected.source);
+         }
+         if(parent){
+             projectObj.converseCalculateBills(parent);
+         }else { //删除的是大项费用要重新计算工程造价节点
+             let roots =  controller.tree.roots;
+             for(let root of roots){
+                 if(project.Bills.isEngineeringCost(root)==true){
+                     project.calcProgram.calcAndSave(root);
+                     break;
+                 }
+             }
+         }
+     }
+});
+
+$('#deleteN').click(function () {//不删除子项
+    let controller = projectObj.mainController, project = projectObj.project;
+    let selected = controller.tree.selected, parent = selected.parent;
+    let updateData = {};
+    if(selected){
+        let preNode = selected.preSibling;
+        let nextNode = selected.nextSibling;
+        if(preNode){//有前兄弟
+            if(preNode.children.length>0&&preNode.children[0].data.type != selected.children[0].data.type){//并且前兄弟子项和焦点行子项类别不同。
+                alert("删除分部会导致分部和分项同级,不允许该操作!");
+                return;
+            }
+        }else if(nextNode){
+            if(nextNode.data.type != selected.children[0].data.type){
+                alert("删除分部会导致分部和分项同级,不允许该操作! ");
+                return;
+            }
+        }
+        project.Bills.singleDeleteBills(selected,controller);
+
+
+    }
+
+
+
+
+
+
+});

+ 6 - 6
web/building_saas/main/js/views/std_ration_lib.js

@@ -61,7 +61,7 @@ var rationLibObj = {
             };
             };
         };
         };
 
 
-        CommonAjax.postRationLib('/rationRepository/api/getRationTree', {userId: userID, rationRepositoryId: rationLibID}, function (datas) {
+        CommonAjax.post('/complementaryRation/api/getRationTree', {userId: userID, rationRepId: rationLibID}, function (datas) {
             showRationChapterTree(datas);
             showRationChapterTree(datas);
         }, function () {
         }, function () {
             showRationChapterTree([]);
             showRationChapterTree([]);
@@ -87,7 +87,7 @@ var rationLibObj = {
             rationLibObj.setTagForHint(datas);
             rationLibObj.setTagForHint(datas);
         };
         };
         if (sectionID) {
         if (sectionID) {
-            CommonAjax.postRationLib('/rationRepository/api/getRationGljItems', {userId: userID, sectionID: sectionID}, function (datas) {
+            CommonAjax.post('/complementaryRation/api/getRationGljItemsBySection', {user_Id: userID, sectionId: sectionID}, function (datas) {
                 showDatas(datas, rationLibObj.sectionRationsSetting);
                 showDatas(datas, rationLibObj.sectionRationsSetting);
             }, function () {
             }, function () {
                 showDatas([], rationLibObj.sectionRationsSetting);
                 showDatas([], rationLibObj.sectionRationsSetting);
@@ -99,7 +99,7 @@ var rationLibObj = {
     onRationSpreadCellDoubleClick: function (sender, args) {
     onRationSpreadCellDoubleClick: function (sender, args) {
         var select = $('#stdRationLibSelect'), rationCode = args.sheet.getText(args.row, 0);
         var select = $('#stdRationLibSelect'), rationCode = args.sheet.getText(args.row, 0);
         if (rationCode !== '') {
         if (rationCode !== '') {
-            CommonAjax.postRationLib('/rationRepository/api/getRationItem', {user_id: userID, rationLibId: select.val(), code: rationCode}, function (data) {
+            CommonAjax.post('/complementaryRation/api/getRationItem', {user_id: userID, rationRepId: select.val(), code: rationCode}, function (data) {
                 ProjectController.addRation(projectObj.project, projectObj.mainController, rationType.ration, data);
                 ProjectController.addRation(projectObj.project, projectObj.mainController, rationType.ration, data);
             });
             });
         }
         }
@@ -120,7 +120,7 @@ var rationLibObj = {
                         let select = $('#stdRationLibSelect'), rationSelect = rationSheet.getSelections();
                         let select = $('#stdRationLibSelect'), rationSelect = rationSheet.getSelections();
                         let rationCode = rationSelect.length > 0 ? rationSheet.getText(rationSelect[0].row, 0) : '';
                         let rationCode = rationSelect.length > 0 ? rationSheet.getText(rationSelect[0].row, 0) : '';
                         if (rationCode !== '') {
                         if (rationCode !== '') {
-                            CommonAjax.postRationLib('/rationRepository/api/getRationItem', {user_id: userID, rationLibId: select.val(), code: rationCode}, function (data) {
+                            CommonAjax.post('/complementaryRation/api/getRationItem', {user_id: userID, rationRepId: select.val(), code: rationCode}, function (data) {
                                 ProjectController.addRation(projectObj.project, projectObj.mainController, rationType.ration, data);
                                 ProjectController.addRation(projectObj.project, projectObj.mainController, rationType.ration, data);
                             });
                             });
                         }
                         }
@@ -133,7 +133,7 @@ var rationLibObj = {
                         let select = $('#stdRationLibSelect'), rationSelect = rationSheet.getSelections();
                         let select = $('#stdRationLibSelect'), rationSelect = rationSheet.getSelections();
                         let rationCode = rationSelect.length > 0 ? rationSheet.getText(rationSelect[0].row, 0) : '';
                         let rationCode = rationSelect.length > 0 ? rationSheet.getText(rationSelect[0].row, 0) : '';
                         if (rationCode !== '') {
                         if (rationCode !== '') {
-                            CommonAjax.postRationLib('/rationRepository/api/getRationItem', {user_id: userID, rationLibId: select.val(), code: rationCode}, function (data) {
+                            CommonAjax.post('/complementaryRation/api/getRationItem', {user_id: userID, rationRepId: select.val(), code: rationCode}, function (data) {
                                 ProjectController.replaceRation(projectObj.project, projectObj.mainController, data);
                                 ProjectController.replaceRation(projectObj.project, projectObj.mainController, data);
                             });
                             });
                         }
                         }
@@ -286,7 +286,7 @@ $('#rationSearch').click(function () {
 
 
         resultSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick, rationLibObj.onRationSpreadCellDoubleClick);
         resultSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick, rationLibObj.onRationSpreadCellDoubleClick);
     };
     };
-    CommonAjax.postRationLib('/rationRepository/api/findRation', {'user_id': userID, 'rationLibId': rationLibID, 'keyword': keyword}, function (result) {
+    CommonAjax.post('/complementaryRation/api/findRation', {'user_id': userID, 'rationRepId': rationLibID, 'keyword': keyword}, function (result) {
         var resultObj = $('#rationSearchResult'), resultSpread = null;
         var resultObj = $('#rationSearchResult'), resultSpread = null;
         resultObj.empty();
         resultObj.empty();
         resultObj.append(getResultHtml(result));
         resultObj.append(getResultHtml(result));

+ 14 - 14
web/building_saas/pm/html/project-management.html

@@ -123,15 +123,15 @@
                     <thead>
                     <thead>
                     <tr>
                     <tr>
                         <th rowspan="2"></th>
                         <th rowspan="2"></th>
-                        <th rowspan="2">序号</th>
-                        <th rowspan="2">单位工程名称</th>
-                        <th rowspan="2">金额(元)</th>
-                        <th colspan="3">其中</th>
+                        <th rowspan="2" style="text-align:center;vertical-align:middle;">序号</th>
+                        <th rowspan="2" style="text-align:center;vertical-align:middle;">单位工程名称</th>
+                        <th rowspan="2" style="text-align:center;vertical-align:middle;">金额(元)</th>
+                        <th colspan="3" style="text-align:center;vertical-align:middle;">其中</th>
                     </tr>
                     </tr>
                     <tr>
                     <tr>
-                        <th>暂估价(元)</th>
-                        <th>安全文明施工费(元)</th>
-                        <th>规费(元)</th>
+                        <th style="text-align:center;vertical-align:middle;">暂估价(元)</th>
+                        <th style="text-align:center;vertical-align:middle;">安全文明施工费(元)</th>
+                        <th style="text-align:center;vertical-align:middle;">规费(元)</th>
                     </tr>
                     </tr>
                     </thead>
                     </thead>
                     <tbody></tbody>
                     <tbody></tbody>
@@ -168,15 +168,15 @@
                     <thead>
                     <thead>
                     <tr>
                     <tr>
                         <th rowspan="2"></th>
                         <th rowspan="2"></th>
-                        <th rowspan="2">序号</th>
-                        <th rowspan="2">单位工程名称</th>
-                        <th rowspan="2">金额(元)</th>
-                        <th colspan="3">其中</th>
+                        <th rowspan="2" style="text-align:center;vertical-align:middle">序号</th>
+                        <th rowspan="2" style="text-align:center;vertical-align:middle">单位工程名称</th>
+                        <th rowspan="2" style="text-align:center;vertical-align:middle">金额(元)</th>
+                        <th colspan="3" style="text-align:center;vertical-align:middle">其中</th>
                     </tr>
                     </tr>
                     <tr>
                     <tr>
-                        <th>暂估价(元)</th>
-                        <th>安全文明施工费(元)</th>
-                        <th>规费(元)</th>
+                        <th style="text-align:center;vertical-align:middle;">暂估价(元)</th>
+                        <th style="text-align:center;vertical-align:middle;">安全文明施工费(元)</th>
+                        <th style="text-align:center;vertical-align:middle;">规费(元)</th>
                     </tr>
                     </tr>
                     </thead>
                     </thead>
                     <tbody>
                     <tbody>

+ 38 - 9
web/building_saas/pm/js/pm_main.js

@@ -101,7 +101,9 @@ let ProjTreeSetting = {
             event: {
             event: {
                 getText: function (html, node, text) {
                 getText: function (html, node, text) {
                     if(node.data.projType === projectType.tender){
                     if(node.data.projType === projectType.tender){
-                        let engineeringCostText = node.data.engineeringCost ? node.data.engineeringCost : 0;
+                        // let engineeringCostText = node.data.engineeringCost ? node.data.engineeringCost : 0;
+                        let engineeringCostText = node.data.summaryFees ? node.data.summaryFees.totalFee : 0;
+                        html.push(engineeringCostText);
                     }
                     }
                 }
                 }
             }
             }
@@ -1656,29 +1658,56 @@ function setDataToSideBar() {
         return;
         return;
     }*/
     }*/
     if(selectedItem.children.length > 0){
     if(selectedItem.children.length > 0){
+        // CSL, 2018-01-11 汇总单项工程、建设项目。
+        function calcNode(node){
+            if (node.data.projType == projectType.project || node.data.projType == projectType.engineering){
+                node.data.summaryFees = {totalFee: 0.00, estimateFee: 0.00, safetyFee: 0.00, chargeFee: 0.00};
+                for (let child of node.children){
+                    calcNode(child);
+                    node.data.summaryFees.totalFee = (parseFloat(node.data.summaryFees.totalFee) + parseFloat(child.data.summaryFees.totalFee)).toFixed(2);
+                    node.data.summaryFees.estimateFee = (parseFloat(node.data.summaryFees.estimateFee) + parseFloat(child.data.summaryFees.estimateFee)).toFixed(2);
+                    node.data.summaryFees.safetyFee = (parseFloat(node.data.summaryFees.safetyFee) + parseFloat(child.data.summaryFees.safetyFee)).toFixed(2);
+                    node.data.summaryFees.chargeFee = (parseFloat(node.data.summaryFees.chargeFee) + parseFloat(child.data.summaryFees.chargeFee)).toFixed(2);
+                };
+            }else{
+                if (!node.data.summaryFees)
+                    node.data.summaryFees = {totalFee: 0.00, estimateFee: 0.00, safetyFee: 0.00, chargeFee: 0.00}
+                else{
+                    node.data.summaryFees.totalFee = parseFloat(node.data.summaryFees.totalFee).toFixed(2);
+                    node.data.summaryFees.estimateFee = parseFloat(node.data.summaryFees.estimateFee).toFixed(2);
+                    node.data.summaryFees.safetyFee = parseFloat(node.data.summaryFees.safetyFee).toFixed(2);
+                    node.data.summaryFees.chargeFee = parseFloat(node.data.summaryFees.chargeFee).toFixed(2);
+                }
+            };
+        };
+
         // 建设项目相关
         // 建设项目相关
         let counter = 1;
         let counter = 1;
         let html = '';
         let html = '';
+
+        calcNode(selectedItem);
         for(let tmp of selectedItem.children) {
         for(let tmp of selectedItem.children) {
+
             html += '<tr>' +
             html += '<tr>' +
                 '<td>'+ counter +'</td>' +
                 '<td>'+ counter +'</td>' +
                 '<td>'+ counter +'</td>' +
                 '<td>'+ counter +'</td>' +
                 '<td>'+ tmp.data.name +'</td>' +
                 '<td>'+ tmp.data.name +'</td>' +
-                '<td></td>' +
-                '<td></td>' +
-                '<td></td>' +
-                '<td></td>' +
+                '<td style="text-align:right">'+ tmp.data.summaryFees.totalFee + '</td>' +
+                '<td style="text-align:right">'+ tmp.data.summaryFees.estimateFee + '</td>' +
+                '<td style="text-align:right">'+ tmp.data.summaryFees.safetyFee + '</td>' +
+                '<td style="text-align:right">'+ tmp.data.summaryFees.chargeFee + '</td>' +
                 '</tr>';
                 '</tr>';
 
 
         }
         }
+
         html += '<tr>' +
         html += '<tr>' +
             '<td>'+ (counter + 1) +'</td>' +
             '<td>'+ (counter + 1) +'</td>' +
             '<td> </td>' +
             '<td> </td>' +
             '<td>合计</td>' +
             '<td>合计</td>' +
-            '<td></td>' +
-            '<td></td>' +
-            '<td></td>' +
-            '<td></td>' +
+            '<td style="text-align:right">'+ selectedItem.data.summaryFees.totalFee + '</td>' +
+            '<td style="text-align:right">'+ selectedItem.data.summaryFees.estimateFee + '</td>' +
+            '<td style="text-align:right">'+ selectedItem.data.summaryFees.safetyFee + '</td>' +
+            '<td style="text-align:right">'+ selectedItem.data.summaryFees.chargeFee + '</td>' +
             '</tr>';
             '</tr>';
         $(target + '-table tbody').html(html);
         $(target + '-table tbody').html(html);
     }
     }

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

@@ -21,7 +21,7 @@ $(document).ready(function () {
             data: {"account": account, "pw": pw},
             data: {"account": account, "pw": pw},
             success: function (response) {
             success: function (response) {
                 if (response.error === 0) {
                 if (response.error === 0) {
-                    const url = response.last_page !== null && response.last_page !== '' ?
+                    const url = response.last_page !== null && response.last_page !== undefined && response.last_page !== '' ?
                         response.last_page : '/pm';
                         response.last_page : '/pm';
                     if (response.login_ask === 0) {
                     if (response.login_ask === 0) {
                         location.href = url;
                         location.href = url;