Kaynağa Gözat

Merge branch 'master' of http://smartcost.f3322.net:3000/SmartCost/ConstructionCost

chenshilong 7 yıl önce
ebeveyn
işleme
0385a8bfd7
61 değiştirilmiş dosya ile 2526 ekleme ve 402 silme
  1. 6 2
      config/gulpConfig.js
  2. 2 2
      lib/jquery-ui/jquery-ui.css
  3. 2 0
      modules/all_models/project_glj.js
  4. 26 0
      modules/all_models/std_billsGuidance_items.js
  5. 27 0
      modules/all_models/std_billsGuidance_lib.js
  6. 13 3
      modules/complementary_ration_lib/models/searchModel.js
  7. 1 1
      modules/fee_rates/controllers/fee_rates_controller.js
  8. 2 2
      modules/fee_rates/facade/fee_rates_facade.js
  9. 65 2
      modules/glj/controllers/glj_controller.js
  10. 1 3
      modules/glj/models/glj_list_model.js
  11. 2 0
      modules/glj/routes/glj_router.js
  12. 23 1
      modules/main/controllers/ration_controller.js
  13. 15 4
      modules/main/facade/ration_facade.js
  14. 1 0
      modules/main/routes/ration_route.js
  15. 3 3
      modules/pm/models/project_model.js
  16. 14 8
      modules/ration_glj/facade/ration_glj_facade.js
  17. 9 3
      modules/reports/rpt_component/jpc_flow_tab.js
  18. 136 62
      modules/reports/util/rpt_construct_data_util.js
  19. 54 0
      modules/std_billsGuidance_lib/controllers/libController.js
  20. 27 0
      modules/std_billsGuidance_lib/controllers/viewController.js
  21. 136 0
      modules/std_billsGuidance_lib/facade/facades.js
  22. 20 0
      modules/std_billsGuidance_lib/routes/routes.js
  23. 5 2
      modules/users/models/user_model.js
  24. 3 0
      public/web/PerfectLoad.js
  25. 29 14
      public/web/gljUtil.js
  26. 3 0
      public/web/scMathUtil.js
  27. 21 4
      public/web/treeDataHelper.js
  28. 3 0
      public/web/tree_sheet/tree_sheet_helper.js
  29. 107 0
      test/unit/reports/test_rpt_11_2.js
  30. 109 0
      test/unit/reports/test_rpt_test_template.js
  31. 2 1
      test/unit/reports/test_tpl_09_1.js
  32. 8 5
      web/building_saas/complementary_ration_lib/js/main.js
  33. 1 0
      web/building_saas/complementary_ration_lib/js/ration.js
  34. 1 1
      web/building_saas/fee_rates/fee_rate.html
  35. 1 1
      web/building_saas/glj/html/glj_index.html
  36. 29 2
      web/building_saas/glj/html/project_glj.html
  37. 3 0
      web/building_saas/js/global.js
  38. 41 7
      web/building_saas/main/html/main.html
  39. 6 6
      web/building_saas/main/html/tender_price.html
  40. 2 0
      web/building_saas/main/js/main.js
  41. 1 1
      web/building_saas/main/js/models/calc_program.js
  42. 12 6
      web/building_saas/main/js/models/installation_fee.js
  43. 67 4
      web/building_saas/main/js/models/project_glj.js
  44. 107 0
      web/building_saas/main/js/models/ration.js
  45. 34 14
      web/building_saas/main/js/models/ration_glj.js
  46. 6 3
      web/building_saas/main/js/views/calc_base_view.js
  47. 41 25
      web/building_saas/main/js/views/glj_view.js
  48. 6 1
      web/building_saas/main/js/views/installation_fee_view.js
  49. 55 17
      web/building_saas/main/js/views/main_tree_col.js
  50. 188 39
      web/building_saas/main/js/views/project_glj_view.js
  51. 2 0
      web/building_saas/main/js/views/project_info.js
  52. 15 10
      web/building_saas/main/js/views/project_view.js
  53. 6 1
      web/building_saas/main/js/views/side_tools.js
  54. 607 0
      web/building_saas/main/js/views/std_billsGuidance_lib.js
  55. 71 67
      web/building_saas/main/js/views/std_bills_lib.js
  56. 73 6
      web/building_saas/main/js/views/tender_price_view.js
  57. 33 30
      web/building_saas/pm/html/project-management.html
  58. 13 12
      web/building_saas/pm/js/pm_gc.js
  59. 189 21
      web/building_saas/pm/js/pm_newMain.js
  60. 8 6
      web/building_saas/report/html/rpt_main.html
  61. 33 0
      web/building_saas/report/js/rpt_main.js

+ 6 - 2
config/gulpConfig.js

@@ -27,15 +27,18 @@ module.exports = {
     ],
     pm_css:[
         'lib/ztree/css/zTreeStyle.css',
-        'lib/spreadjs/sheets/css/gc.spread.sheets.sc.css'
+        'lib/spreadjs/sheets/css/gc.spread.sheets.sc.css',
+        'lib/jquery-contextmenu/jquery.contextMenu.css'
     ],
     pm_jspaths:[
         'public/web/date_util.js',
         'public/web/tree_sheet/tree_sheet_helper.js',
+        'public/web/sheet/sheet_data_helper.js',
         'public/web/common_ajax.js',
         'lib/JSExpressionEval_src/Date.js',
         'web/building_saas/pm/js/**/*.js',
-        'lib/ztree/*.js'
+        'lib/ztree/*.js',
+        'lib/jquery-contextmenu/jquery.contextMenu.min.js'
     ],
     main_css:[
         'lib/ztree/css/zTreeStyle.css',
@@ -112,6 +115,7 @@ module.exports = {
         'web/building_saas/main/js/controllers/project_controller.js',
         'web/building_saas/main/js/controllers/block_controller.js',
         'web/building_saas/main/js/views/side_tools.js',
+        'web/building_saas/main/js/views/std_billsGuidance_lib.js',
         'web/building_saas/main/js/views/std_bills_lib.js',
         'web/building_saas/main/js/views/std_ration_lib.js',
         'web/building_saas/main/js/models/quantity_detail.js',

+ 2 - 2
lib/jquery-ui/jquery-ui.css

@@ -1063,7 +1063,7 @@ a.ui-button:active,
 	width: 16px;
 	height: 16px;
 }
-.ui-icon,
+/*.ui-icon,
 .ui-widget-content .ui-icon {
 	background-image: url("images/ui-icons_444444_256x240.png");
 }
@@ -1090,7 +1090,7 @@ a.ui-button:active,
 }
 .ui-button .ui-icon {
 	background-image: url("images/ui-icons_777777_256x240.png");
-}
+}*/
 
 /* positioning */
 .ui-icon-blank { background-position: 16px 16px; }

+ 2 - 0
modules/all_models/project_glj.js

@@ -83,6 +83,8 @@ let modelSchema = {
     unit_price: Schema.Types.Mixed,
     // 显示关联的消耗量
     quantity: String,
+    techQuantity:String,//技术措施项目消耗量
+    subdivisionQuantity:String,//分部分项消耗量
     // 不调价
     tenderPrice: String,//调整后价格
     // 显示组成物的消耗量

+ 26 - 0
modules/all_models/std_billsGuidance_items.js

@@ -0,0 +1,26 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/5/29
+ * @version
+ */
+//清单指引条目
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+
+const stdBillsGuidanceItems = new Schema({
+    libID: String,
+    ID: String, //uuid
+    ParentID: String,
+    NextSiblingID: String,
+    billsID: String, //关联清单的ID
+    name: String,
+    type: Number, //0:工作内容 1:定额
+    rationID: {type: Number, default: null}, //定额类型时
+    deleted: {type: Boolean, default: false}
+}, {versionKey: false});
+
+mongoose.model('std_billsGuidance_items', stdBillsGuidanceItems, 'std_billsGuidance_items');

+ 27 - 0
modules/all_models/std_billsGuidance_lib.js

@@ -0,0 +1,27 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/5/29
+ * @version
+ */
+//清单指引库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+
+const stdBillsGuidanceLib = new Schema({
+    ID: String, //uuid
+    compilationId: String,
+    compilationName: String,
+    billsLibId: Number,
+    billsLibName: String,
+    name: String,
+    creator: String,
+    createDate: String,
+    deleted: {type: Boolean, default: false},
+}, {versionKey: false});
+
+mongoose.model('std_billsGuidance_lib', stdBillsGuidanceLib, 'std_billsGuidance_lib');
+

+ 13 - 3
modules/complementary_ration_lib/models/searchModel.js

@@ -10,16 +10,26 @@ let stdSectionTreeModel = require ('../../ration_repository/models/ration_sectio
 let stdRationModel = require ('../../ration_repository/models/ration_item').Model;
 
 class SearchDao{
-    async getRationItem(userId, rationRepIds, code, callback){
+    async getRationItem(userId, rationRepIds, code, ID, callback){
         let ration = null;
         try{
-            let stdRation = await stdRationModel.findOne({rationRepId: {$in: rationRepIds}, code: code, $or: [{isDeleted: null}, {isDeleted: false}]});
+            let stdQuery = {rationRepId: {$in: rationRepIds}, code: code, $or: [{isDeleted: null}, {isDeleted: false}]};
+            if(ID){
+                stdQuery = {ID: ID, $or: [{isDeleted: null}, {isDeleted: false}]};
+            }
+            //let stdRation = await stdRationModel.findOne({rationRepId: {$in: rationRepIds}, code: code, $or: [{isDeleted: null}, {isDeleted: false}]});
+            let stdRation = await stdRationModel.findOne(stdQuery);
             if(isDef(stdRation)){
                 ration = stdRation._doc;
                 ration.type = 'std';
             }
             else{
-                let compleRation = await compleRationModel.findOne({userId: userId, rationRepId: {$in: rationRepIds}, code: code, deleteInfo: null});
+                let compleQuery = {userId: userId, rationRepId: {$in: rationRepIds}, code: code, deleteInfo: null};
+                if(ID){
+                    compleQuery = {ID: ID, deleteInfo: null};
+                }
+                //let compleRation = await compleRationModel.findOne({userId: userId, rationRepId: {$in: rationRepIds}, code: code, deleteInfo: null});
+                let compleRation = await compleRationModel.findOne(compleQuery);
                 if(isDef(compleRation)){
                     ration = compleRation._doc;
                     ration.type = 'complementary';

+ 1 - 1
modules/fee_rates/controllers/fee_rates_controller.js

@@ -140,7 +140,7 @@ async function getChangeInfo(req, res) {
     }
     try {
         let data = req.body.data;
-        let info= await feeRateFacde.getChangeInfo(data);
+        let info= await feeRateFacde.getChangeInfo(data,req.session.sessionCompilation._id);
         result.data= info;
     }catch (err){
         console.log(err);

+ 2 - 2
modules/fee_rates/facade/fee_rates_facade.js

@@ -322,7 +322,7 @@ async function checkFeeRateName(jdata) {
     return false;
 }
 
-async function getChangeInfo(jdata){
+async function getChangeInfo(jdata,compilation){
     let data = JSON.parse(jdata);
     //{ rootProjectID: 99, user_id: '76075' }
     let result={};
@@ -332,7 +332,7 @@ async function getChangeInfo(jdata){
     }
     //根据用户ID 找除了当前项目的其它建设项目;
     let others =await projectsModel.find({'$and': [
-            {'$or':[{'userID': data.user_id,'projType':'Project', 'deleteInfo': null}, {'userID': data.user_id,'projType':'Project', 'deleteInfo.deleted': {'$in': [null, false]}}]},
+            {'$or':[{'userID': data.user_id,'compilation': compilation,'projType':'Project', 'deleteInfo': null}, {'userID': data.user_id,'compilation': compilation,'projType':'Project', 'deleteInfo.deleted': {'$in': [null, false]}}]},
             { 'ID':{'$nin':[data.rootProjectID]}}
         ]},['ID','name']);
     for(let o of others){

+ 65 - 2
modules/glj/controllers/glj_controller.js

@@ -17,6 +17,7 @@ let glj_type_util = require('../../../public/cache/std_glj_type_util');
 let mongoose = require('mongoose');
 let ration = mongoose.model('ration');
 
+
 const ProjectModel = require('../../pm/models/project_model').project;
 class GLJController extends BaseController {
 
@@ -227,10 +228,46 @@ class GLJController extends BaseController {
             responseData.err = 1;
             responseData.msg = error;
         }
-
         response.json(responseData);
     }
 
+
+    //添加组成物
+    async addMixRatio(request,response){
+
+        let result={
+            error:0
+        };
+        try {
+            let data = request.body.data;
+            data = JSON.parse(data);
+            let gljList = data.gljList, parentInfo = data.parentInfo,mixRatios = [];
+            let projectGljModel = new GLJListModel();
+            let mixRatioModel = new MixRatioModel();
+            for(let g of gljList){
+                let newProjectGLJ = await projectGljModel.addList(g,parentInfo.unit_price_file_id);
+                let mixRatio = {
+                    glj_id:newProjectGLJ.glj_id,
+                    consumption:0,
+                    unit_price_file_id:parentInfo.unit_price_file_id,
+                    connect_key:parentInfo.connect_key,
+                    type: newProjectGLJ.type,
+                    code: newProjectGLJ.code,
+                    specs:newProjectGLJ.specs,
+                    name:newProjectGLJ.name,
+                    unit:newProjectGLJ.unit
+                };
+                newProjectGLJ.ratio_data = await mixRatioModel.add(mixRatio);
+                mixRatios.push(newProjectGLJ);
+            }
+            result.data = mixRatios;
+        }catch (err){
+            logger.err(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
     /**
      * 获取项目与单价文件对应的数据
      *
@@ -249,7 +286,7 @@ class GLJController extends BaseController {
         try {
             let sessionUserData = request.session.sessionUser;
             // 获取对应用户所有的建设项目数据
-            let projectList = await ProjectModel.getUserProjectData(sessionUserData.id);
+            let projectList = await ProjectModel.getUserProjectData(sessionUserData.id,request.session.sessionCompilation._id);
             if (projectList === null) {
                 throw '没有找到对应的项目数据';
             }
@@ -295,6 +332,7 @@ class GLJController extends BaseController {
     async changeUnitPriceFile(request, response) {
         let projectId = request.body.project_id;
         let changeUnitPriceId = request.body.change_id;
+        let newName = request.body.newName;
         let type = request.body.type;
         type = parseInt(type);
         let responseData = {
@@ -317,6 +355,7 @@ class GLJController extends BaseController {
 
                 insertData = JSON.parse(JSON.stringify(currentUnitPrice));
                 insertData.root_project_id = rootProjectId;
+                newName?insertData.name = newName:'';
                 insertData.user_id = insertData.user_id === undefined ? request.session.sessionUser.id : insertData.user_id;
                 delete insertData._id;
                 delete insertData.ID;
@@ -372,6 +411,30 @@ class GLJController extends BaseController {
         response.json(responseData);
     }
 
+    async checkUnitFileName(request, response){
+        let result={
+            error:0
+        }
+        try {
+            let data = request.body.data;
+            let nameExist = false;
+            data = JSON.parse(data);
+            let unitPriceFileModel = new UnitPriceFileModel();
+            let count = await unitPriceFileModel.model.count({root_project_id:data.rootProjectID,name:data.name,deleteInfo:null});
+            if(count>0){
+                nameExist = true;
+            }else {
+                nameExist = false;
+            }
+            result.data= nameExist;
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
+
     /**
      * 单价文件另存为
      *

+ 1 - 3
modules/glj/models/glj_list_model.js

@@ -417,7 +417,7 @@ class GLJListModel extends BaseModel {
                     };
                     newMixRatioData.push(tem);
                 }
-                mixInsertResult= mixRatioModel.add(newMixRatioData);
+                mixInsertResult= await mixRatioModel.add(newMixRatioData);
             }
         }
         return gljData;
@@ -771,8 +771,6 @@ class GLJListModel extends BaseModel {
             let u_index = this.getIndex(tmp,['code','name','specs','unit','type'])
             unitPriceData[u_index] = tmp;
         }
-
-
         return [gljData,mixRatioData,unitPriceData];
 
     }

+ 2 - 0
modules/glj/routes/glj_router.js

@@ -17,8 +17,10 @@ router.post('/getData', gljController.init, gljController.getGljList);
 router.post('/update', gljController.init, gljController.updateData);
 router.post('/get-ratio', gljController.init, gljController.getRatio);
 router.post('/delete-ratio', gljController.init, gljController.deleteMixRatio);
+router.post('/add-ratio', gljController.init, gljController.addMixRatio);
 router.post('/get-project-info', gljController.init, gljController.getProjectInfo);
 router.post('/change-file', gljController.init, gljController.changeUnitPriceFile);
+router.post('/checkUnitFileName', gljController.init, gljController.checkUnitFileName);
 router.post('/save-as', gljController.init, gljController.unitPriceSaveAs);
 router.post('/get-composition', gljController.init, gljController.getComposition);
 router.post('/updatePrice', gljController.init, gljController.updateUnitPrice);

+ 23 - 1
modules/main/controllers/ration_controller.js

@@ -45,7 +45,8 @@ module.exports = {
     },
     insertGLJAsRation:insertGLJAsRation,
     replaceRations:replaceRations,
-    addNewRation:addNewRation
+    addNewRation:addNewRation,
+    addMultiRation: addMultiRation
 };
 
 async function addNewRation(req,res) {
@@ -67,6 +68,27 @@ async function addNewRation(req,res) {
     res.json(result);
 }
 
+async function addMultiRation(req,res) {
+    let result={
+        error:0
+    }
+    try {
+        let data = req.body.data;
+        if(typeof data === 'object'){
+            data = JSON.stringify(data);
+        }
+        data = JSON.parse(data);
+        console.log(`data`);
+        console.log(data);
+        result.data = await ration_facade.addMultiRation(data.newDatas);
+    }catch (err){
+        logger.err(err);
+        result.error=1;
+        result.message = err.message;
+    }
+    res.json(result);
+}
+
 async function replaceRations(req,res) {
     let result={
         error:0

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

@@ -23,7 +23,8 @@ let projectModel = mongoose.model('projects');
 
 module.exports = {
     replaceRations: replaceRations,
-    addNewRation:addNewRation
+    addNewRation:addNewRation,
+    addMultiRation: addMultiRation
 };
 async function addNewRation(data) {
     let query = data.itemQuery;
@@ -31,8 +32,8 @@ async function addNewRation(data) {
     let startTime = +new Date();
     if(query){
         let searchDao = new SearchDao();
-        stdRation = await searchDao.getRationItem(query.userID,[query.rationRepId],query.code);
-        data.newData.code = query.code;
+        stdRation = await searchDao.getRationItem(query.userID,[query.rationRepId],query.code, query.ID);
+        //data.newData.code = query.code;
     }
     let stdRationTime = +new Date();
     console.log("取std定额时间-------------------------------"+(stdRationTime - startTime));
@@ -49,6 +50,15 @@ async function addNewRation(data) {
     }
 }
 
+async function addMultiRation(datas) {
+    let rst = [];
+    for(let data of datas){
+        let r = await addNewRation(data);
+        rst.push(r);
+    }
+    return rst;
+}
+
 async function  updateSerialNo(serialNoUpdate){
     let tasks=[];
     for(let data of serialNoUpdate){
@@ -72,6 +82,7 @@ async function  updateSerialNo(serialNoUpdate){
 async function insertNewRation(newData,firstLibID,std,calQuantity) {//插入新的定额
     let startTime = +new Date();
     if(std){
+        newData.code = std.code;
         newData.name = std.name;
         newData.caption = std.caption;
         newData.unit = std.unit;
@@ -109,7 +120,7 @@ async function replaceRations(userID,data) {
     let searchDao = new SearchDao();
     let recodes = [];
     for(let recode of data.nodeInfo){
-        let stdRation = await searchDao.getRationItem(userID,data.libIDs,recode.newCode);
+        let stdRation = await searchDao.getRationItem(userID,data.libIDs,recode.newCode, null);
         let newRecode = await replaceRation(recode,stdRation,data.firstLibID,data.projectID,data.calQuantity);
         if(newRecode){
             recodes.push(newRecode);

+ 1 - 0
modules/main/routes/ration_route.js

@@ -12,6 +12,7 @@ module.exports = function (app) {
     rationRouter.post('/insertGLJAsRation', rationController.insertGLJAsRation);
     rationRouter.post('/replaceRations', rationController.replaceRations);
     rationRouter.post('/addNewRation', rationController.addNewRation);
+    rationRouter.post('/addMultiRation', rationController.addMultiRation);
 
     app.use('/ration', rationRouter);
 };

+ 3 - 3
modules/pm/models/project_model.js

@@ -638,11 +638,11 @@ ProjectsDAO.prototype.getUnitPriceFileId = async function (projectId) {
  * @paraconsolem {Number} userId
  * @return {Promise}
  */
-ProjectsDAO.prototype.getUserProjectData = async function (userId) {
+ProjectsDAO.prototype.getUserProjectData = async function (userId,compilation) {
     let projectList = await Projects.find({
         '$or': [
-            {'userID': userId, 'deleteInfo': null, projType: 'Project'},
-            {'userID': userId, 'deleteInfo.deleted': {'$in': [null, false]}, projType: 'Project'}
+            {'userID': userId, 'compilation': compilation, 'deleteInfo': null, projType: 'Project'},
+            {'userID': userId, 'compilation': compilation,'deleteInfo.deleted': {'$in': [null, false]}, projType: 'Project'}
         ]
     }, {_id: 0, name: 1, ID: 1});
 

+ 14 - 8
modules/ration_glj/facade/ration_glj_facade.js

@@ -658,21 +658,27 @@ async function mReplaceGLJ(data) {
     let projectGljModel = new GLJListModel();
     let result = await projectGljModel.addList(getGLJSearchInfo(data.doc));
     let typeString = result.type+'';
-    data.doc.projectGLJID = result.id;
+    let newDoc = {};
+    newDoc.projectGLJID = result.id;
     let rationList = await ration_glj.distinct('rationID', data.query);
-    let updateResult = await ration_glj.update(data.query, data.doc, {multi: true});
+    for(let t of data.tasks){
+        t.updateOne.update.projectGLJID = result.id;//更新项目工料机ID
+    }
+    await ration_glj.bulkWrite(data.tasks);
+    //let updateResult = await ration_glj.update(data.query, data.doc, {multi: true});
 
-    data.doc.marketPrice = result.unit_price.market_price;
-    data.doc.adjustPrice = result.unit_price.base_price;
-    data.doc.basePrice = result.unit_price.base_price;
-    data.doc.isAdd = result.unit_price.is_add;
+    newDoc.marketPrice = result.unit_price.market_price;
+    newDoc.adjustPrice = result.unit_price.base_price;
+    newDoc.basePrice = result.unit_price.base_price;
+    newDoc.isAdd = result.unit_price.is_add;
     if (typeString.startsWith("2")||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估
-        data.doc.isEstimate = result.is_evaluate;
+        newDoc.isEstimate = result.is_evaluate;
     }
     if (result.hasOwnProperty('subList') && result.subList.length > 0) {
-        data.doc.subList = getMixRatioShowDatas(result.subList);
+        newDoc.subList = getMixRatioShowDatas(result.subList);
     }
     let stateList = await changAdjustState(data, rationList);
+    data.doc = newDoc;
     mresult.data = data;
     mresult.stateList = stateList;
     return mresult

+ 9 - 3
modules/reports/rpt_component/jpc_flow_tab.js

@@ -107,10 +107,16 @@ JpcFlowTabSrv.prototype.createNew = function(){
                     if (couldBreak) break;
                 } else {
                     //备注: 在有group的情况下,如果grpPageInfo[JV.PROP_SEG_GRP_IDX] 范围大于 grpSequenceInfo.length,则表示已经到最后了,不要再加空白数据了
+                    //      !!!但这是在有ex数据的情况下!!!
                     if (grpPageInfo[JV.PROP_SEG_GRP_IDX] < grpSequenceInfo.length) {
                         if (private_normal_add_rec(vi)) break;
                     } else {
-                        break;
+                        //还得判断是否是普通的流水数据情况,这里可以用isFollow来进行判断,暂时不需要特意加新参数(以后如isFollow的意义有变化则需要调整)
+                        if (!isFollow) {
+                            if (private_normal_add_rec(vi)) break;
+                        } else {
+                            break;
+                        }
                     }
                 }
             } else {
@@ -197,7 +203,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 }
                 let sumV = 0;
                 for (let si = preGrpIdx; si <= nexGrpIdx; si++) {
-                    sumV += JpcFieldHelper.getValue(data_field, segDataIdx[si]);
+                    sumV += parseFloat(JpcFieldHelper.getValue(data_field, segDataIdx[si]));
                 }
                 // me.group_sum_values[segIdx][j].push(sumV);
                 me.group_sum_values[segIdx][me.group_sum_fields[j][JV.PROP_SUM_KEY]].push(sumV);
@@ -587,7 +593,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                             }
                             //add page info
                             pageStatus[JV.STATUS_SEGMENT_END] = true;
-                            pageStatus[JV.STATUS_REPORT_END] = true;
+                            pageStatus[JV.STATUS_REPORT_END] = (segIdx === me.segments.length - 1);
                             private_addPage(segIdx, grpSeqInfo, false, false, -1);
                         } else {
                             private_addPage(segIdx, grpSeqInfo, false, false, -1);

+ 136 - 62
modules/reports/util/rpt_construct_data_util.js

@@ -12,6 +12,8 @@ let stringUtil = require("../../../public/stringUtil");
 let treeUtil = require('../../../public/treeUtil');
 let projectConst = consts.projectConst;
 let projectConstList = consts.projectConstList;
+const gljUtil = require('../../../public/gljUtil');
+
 
 const GLJ_TYPE = {
     Labour: 1,
@@ -134,11 +136,25 @@ class Rpt_Data_Extractor {
                             if (key === projectConst.RATION_GLJ && (rst.indexOf(projectConst.PROJECTGLJ) < 0)) {
                                 rst.push(projectConst.PROJECTGLJ);
                             }
-                            if (key === projectConst.PROJECTGLJ && (rst.indexOf(projectConst.RATION_GLJ) < 0)) {
-                                rst.push(projectConst.RATION_GLJ);
+                            if (key === projectConst.PROJECTGLJ) {
+                                if (rst.indexOf(projectConst.RATION_GLJ) < 0) rst.push(projectConst.RATION_GLJ);
+                                if (field[JV.PROP_FIELD_EXP_MAP].indexOf("'quantity'") > 0 ||
+                                    field[JV.PROP_FIELD_EXP_MAP].indexOf("'subdivisionQuantity'") > 0 ||
+                                    field[JV.PROP_FIELD_EXP_MAP].indexOf("'techQuantity'") > 0 ) {
+                                    if (rst.indexOf(projectConst.RATION) < 0) rst.push(projectConst.RATION);
+                                    if (rst.indexOf(projectConst.BILLS) < 0) rst.push(projectConst.BILLS);
+                                }
                             }
                         }
                     }
+                } else if (key === projectConst.PROJECTGLJ) {
+                    if (rst.indexOf(projectConst.RATION_GLJ) < 0) rst.push(projectConst.RATION_GLJ);
+                    if (field[JV.PROP_FIELD_EXP_MAP].indexOf("'quantity'") > 0 ||
+                        field[JV.PROP_FIELD_EXP_MAP].indexOf("'subdivisionQuantity'") > 0 ||
+                        field[JV.PROP_FIELD_EXP_MAP].indexOf("'techQuantity'") > 0 ) {
+                        if (rst.indexOf(projectConst.RATION) < 0) rst.push(projectConst.RATION);
+                        if (rst.indexOf(projectConst.BILLS) < 0) rst.push(projectConst.BILLS);
+                    }
                 }
             }
         };
@@ -202,6 +218,14 @@ class Rpt_Data_Extractor {
         for (let item of rawDataObj.prjData) {
             setupFunc($PROJECT.DETAIL, item.moduleName, item);
         }
+        let projectGLJDatas = getModuleDataByKey(rawDataObj.prjData, "projectGLJ");
+        let rationGLJDatas = getModuleDataByKey(rawDataObj.prjData, "ration_glj");
+        let rationDatas = getModuleDataByKey(rawDataObj.prjData, "ration");
+        let billsDatas = getModuleDataByKey(rawDataObj.prjData, "bills");
+        if (projectGLJDatas && rationGLJDatas && rationDatas && billsDatas) {
+            gljUtil.calcProjectGLJQuantity(projectGLJDatas.data, rationGLJDatas.data, rationDatas.data, billsDatas.data, 4);
+        }
+
         if (tpl[JV.NODE_MAP_DATA_HANDLE_INFO]) {
             for (let preHandle of tpl[JV.NODE_MAP_DATA_HANDLE_INFO]) {
                 let srcData = getModuleDataByKey(rawDataObj.prjData, preHandle[JV.PROP_DATA_KEY]);
@@ -292,7 +316,7 @@ function getModuleDataByKey(prjData, key) {
 function summaryData(sourceData, handleCfg, prjData){
     let rstArr = [], tempRstArr = [];
     let curParentPrjData = {};
-    for (let item of sourceData.data) {
+    for (let item of getActDataArr(sourceData)) {
         if (item._doc) {
             tempRstArr.push(item._doc);
         } else {
@@ -368,14 +392,13 @@ function summaryData(sourceData, handleCfg, prjData){
             }
         }
     }
-    delete sourceData.data;
-    sourceData.data = rstArr;
+    replaceActDataArr(sourceData, rstArr);
     // fsUtil.writeObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/sumRst.jsp");
 }
 
 function filterData(sourceData, handleCfg, prjData) {
     let rstArr = [], tempRstArr = [];
-    for (let item of sourceData.data) {
+    for (let item of getActDataArr(sourceData)) {
         if (item._doc) {
             tempRstArr.push(item._doc);
         } else {
@@ -414,9 +437,9 @@ function filterData(sourceData, handleCfg, prjData) {
                     rst = compVal.indexOf(src) >= 0;
                 } else {
                     //string,需要转类型
-                    let newCv = JSON.parse(compVal);
-                    if (newCv instanceof Array) {
-                        rst = newCv.indexOf(src) >= 0;
+                    let newInCv = JSON.parse(compVal);
+                    if (newInCv instanceof Array) {
+                        rst = newInCv.indexOf(src) >= 0;
                     } else {
                         rst = false;
                     }
@@ -427,9 +450,9 @@ function filterData(sourceData, handleCfg, prjData) {
                     rst = compVal.indexOf(src) < 0;
                 } else {
                     //string,需要转类型
-                    let newCv = JSON.parse(compVal);
-                    if (newCv instanceof Array) {
-                        rst = newCv.indexOf(src) < 0;
+                    let newNotInCv = JSON.parse(compVal);
+                    if (newNotInCv instanceof Array) {
+                        rst = (newNotInCv.indexOf(src) < 0);
                     } else {
                         rst = true;
                     }
@@ -442,12 +465,25 @@ function filterData(sourceData, handleCfg, prjData) {
     };
     let private_chkArrVal = function(arr, key, compVal, compStr){
         let rst = false;
-        for (let arrItem of arr) {
-            if (arrItem[key]) {
-                rst = private_chkVal(arrItem[key], compVal, compStr);
+        if (arr.length > 0) {
+            for (let arrItem of arr) {
+                if (arrItem[key]) {
+                    rst = private_chkVal(arrItem[key], compVal, compStr);
+                }
+                if (rst) {
+                    break;
+                }
             }
-            if (rst) {
-                break;
+        } else {
+            //在某些判断条件下(含有'非'判断),如arr没有数组项,默认结果反而是true
+            switch (compStr) {
+                case "!=" :
+                case "!==" :
+                case "not in":
+                    rst = true;
+                    break;
+                default:
+                    break;
             }
         }
         return rst;
@@ -462,11 +498,7 @@ function filterData(sourceData, handleCfg, prjData) {
             curComparePrjData = getModuleDataByKey(prjData, targetDataKey);
             try {
                 if (curComparePrjData !== null) {
-                    if (targetDataKey === "projectGLJ") {
-                        objDataArr = curComparePrjData.data.gljList;
-                    } else {
-                        objDataArr = curComparePrjData.data;
-                    }
+                    objDataArr = getActDataArr(curComparePrjData);
                     for (let dtl of objDataArr) {
                         if (item[refKey] === dtl[targetPropertyKey]) {
                             rst = dtl;
@@ -523,7 +555,7 @@ function filterData(sourceData, handleCfg, prjData) {
                     if (!compareObj.hasOwnProperty(cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY] + startIdx.toString())) {
                         compareObj[cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY] + startIdx.toString()] = [];
                         compareArr = compareObj[cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY] + startIdx.toString()];
-                        for (let data of curComparePrjData.data) {
+                        for (let data of getActDataArr(curComparePrjData)) {
                             if (compareArr.indexOf(data[cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY]]) < 0) {
                                 compareArr.push(data[cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY]]);
                             }
@@ -533,16 +565,35 @@ function filterData(sourceData, handleCfg, prjData) {
                     }
                     compRst = private_chkVal(item[cfg.key], compareArr, cfg[JV.PROP_FILTER_CONDITION]);
                 } else {
-                    for (let data of curComparePrjData.data) {
+                    for (let data of getActDataArr(curComparePrjData)) {
                         compRst = private_chkVal(item[cfg.key], data[cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY]], cfg[JV.PROP_FILTER_CONDITION]);
                         if (compRst) break;
                     }
                 }
             }
             startIdx++;
+            if (!compRst) {
+                break; //有不符合条件的数据则退出(这里的判断条件是and关系)
+            }
         }
         return compRst;
     };
+    let private_sub_filter_compare = function (dtlItem, subFilters) {
+        let cmpRst = false;
+        for (let dtlCfg of subFilters) {
+            cmpRst = private_filter_compare(dtlItem, dtlCfg);
+            if (cmpRst) {
+                if (dtlCfg[JV.PROP_OTHER_SUB_FILTER] && dtlCfg[JV.PROP_OTHER_SUB_FILTER].length > 0) {
+                    cmpRst = private_sub_filter_compare(dtlItem, dtlCfg[JV.PROP_OTHER_SUB_FILTER]);
+                    if (cmpRst) break;
+                } else {
+                    break;
+                }
+            }
+        }
+        return cmpRst;
+    };
+
     for (let item of tempRstArr) {
         if (private_filter_compare(item, handleCfg)) {
             rstArr.push(item);
@@ -551,25 +602,20 @@ function filterData(sourceData, handleCfg, prjData) {
     if (handleCfg[JV.PROP_OTHER_SUB_FILTER] && handleCfg[JV.PROP_OTHER_SUB_FILTER].length > 0) {
         let newRstArr = [];
         for (let dtlItem of rstArr) {
-            let cmpRst = false;
-            for (let dtlCfg of handleCfg[JV.PROP_OTHER_SUB_FILTER]) {
-                cmpRst = private_filter_compare(dtlItem, dtlCfg);
-                if (cmpRst) {
-                    newRstArr.push(dtlItem);
-                    break;
-                }
+            let cmpRst = private_sub_filter_compare(dtlItem, handleCfg[JV.PROP_OTHER_SUB_FILTER]);
+            if (cmpRst) {
+                newRstArr.push(dtlItem);
             }
         }
         rstArr = newRstArr;
     }
-    delete sourceData.data;
-    sourceData.data = rstArr;
-    // fsUtil.writeObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/filteredRst.js");
+    replaceActDataArr(sourceData, rstArr);
+    // fsUtil.writeObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/filteredRst.jsp");
 }
 
 function adjustData(sourceData, adjustCfg) {
     let rstArr = [];
-    for (let item of sourceData.data) {
+    for (let item of getActDataArr(sourceData)) {
         if (item._doc) {
             rstArr.push(item._doc);
         } else {
@@ -585,8 +631,7 @@ function adjustData(sourceData, adjustCfg) {
             }
         }
     }
-    delete sourceData.data;
-    sourceData.data = rstArr;
+    replaceActDataArr(sourceData, rstArr);
 }
 
 function moveRationData(rationData, rawDataObj) {
@@ -595,7 +640,7 @@ function moveRationData(rationData, rawDataObj) {
         let rationGljData = getModuleDataByKey(rawDataObj.prjData, projectConst.RATION_GLJ);
         let prjGljData = getModuleDataByKey(rawDataObj.prjData, projectConst.PROJECTGLJ);
         let dummyCode = " ", dummyPRJID = 10101010;
-        for (let rationItem of rationData.data) {
+        for (let rationItem of getActDataArr(rationData)) {
             if (rationItem.type === 2 || rationItem.type === 3) {
                 //2: 量材(人工/材料/机械/主材/设备) 3:材料(材料/主材/设备)
                 let copyItem = {};
@@ -672,7 +717,7 @@ function getDupGrpKeyVals(sourceData, segKeys) {
 
 function addDummyData(sourceData, addCfg) {
     let rstArr = [], tempRstArr = [];
-    for (let item of sourceData.data) {
+    for (let item of getActDataArr(sourceData)) {
         if (item._doc) {
             tempRstArr.push(item._doc);
         } else {
@@ -705,8 +750,7 @@ function addDummyData(sourceData, addCfg) {
         }
     }
     rstArr = rstArr.concat(tempRstArr);
-    delete sourceData.data;
-    sourceData.data = rstArr;
+    replaceActDataArr(sourceData, rstArr);
 }
 
 function getGLJBizType(orgType, orgCode, orgName) {
@@ -746,9 +790,10 @@ function getGLJBizType(orgType, orgCode, orgName) {
 }
 
 function sortData(sourceData, sortCfg, prjData) {
-    let rst = sourceData.data, tempRstArr = [];
+    let rst = getActDataArr(sourceData), tempRstArr = [];
     let sortType = sortCfg[JV.PROP_SORT_TYPE];
-    for (let item of sourceData.data) {
+    let srcData = getActDataArr(sourceData);
+    for (let item of srcData) {
         if (item._doc) {
             tempRstArr.push(item._doc);
         } else {
@@ -849,14 +894,12 @@ function sortData(sourceData, sortCfg, prjData) {
             }
             let destArr = [];
             treeUtil.getFlatArray(newTopArr, destArr);
-            delete sourceData.data;
-            sourceData.data = destArr;
+            replaceActDataArr(sourceData, destArr);
             // fsUtil.writeObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/sortedAndFlattedRst.jsp");
             break;
         case "normal":
             private_normal_sort(tempRstArr, sortCfg[JV.PROP_SORT_KEYS]);
-            delete sourceData.data;
-            sourceData.data = tempRstArr;
+            replaceActDataArr(sourceData, tempRstArr);
             // fsUtil.writeObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/normalSortedRst.jsp");
             break;
         case "accord_to_parent":
@@ -864,7 +907,7 @@ function sortData(sourceData, sortCfg, prjData) {
             let parentSrcData = getModuleDataByKey(prjData, pcKey[JV.PROP_PARENT_DATA_KEY]);
             if (parentSrcData) {
                 let tempParentArr = [];
-                for (let item of parentSrcData.data) {
+                for (let item of getActDataArr(parentSrcData)) {
                     if (item._doc) {
                         tempParentArr.push(item._doc);
                     } else {
@@ -896,8 +939,7 @@ function sortData(sourceData, sortCfg, prjData) {
                     }
                 }
             }
-            delete sourceData.data;
-            sourceData.data = tempRstArr;
+            replaceActDataArr(sourceData, tempRstArr);
             break;
         case "self_define":
             if (sortCfg[JV.PROP_SORT_TYPE_SELF_DEFINE_LOGIC]) {
@@ -905,8 +947,7 @@ function sortData(sourceData, sortCfg, prjData) {
                 eval('selfDefFunc = ' + sortCfg[JV.PROP_SORT_TYPE_SELF_DEFINE_LOGIC]);
                 tempRstArr.sort(selfDefFunc);
             }
-            delete sourceData.data;
-            sourceData.data = tempRstArr;
+            replaceActDataArr(sourceData, tempRstArr);
             break;
         default:
             //
@@ -1010,9 +1051,10 @@ function ext_getPropety(propKey) {
     let rst = [], parentObj = this;
     let dtObj = parentObj["myOwnRawDataObj"];
     if (propKey && dtObj) {
-        for (let dItem of dtObj.data) {
+        for (let dItem of getActDataArr(dtObj)) {
             let doc = (dItem._doc === null || dItem._doc === undefined)?dItem:dItem._doc;
             if (propKey instanceof Array) {
+                //备注:这里的key数组表示取value的优先级
                 for (let pi = 0; pi < propKey.length; pi++) {
                     if (doc.hasOwnProperty("property")) {
                         if (doc["property"].hasOwnProperty(propKey[pi])) {
@@ -1022,6 +1064,16 @@ function ext_getPropety(propKey) {
                     } else if (doc.hasOwnProperty(propKey[pi])) {
                         rst.push(doc[propKey[pi]]);
                         break;
+                    } else {
+                        let lenBefore = rst.length;
+                        getDeepProperty(propKey[pi], doc, rst);
+                        if (rst.length === (lenBefore + 1)) {
+                            if (rst[lenBefore] !== null && rst[lenBefore] !== undefined && rst[lenBefore] !== "") {
+                                break;
+                            } else {
+                                rst.splice(-1, 1); //删除末尾一条数据,给后面留空间
+                            }
+                        }
                     }
                     if (pi === propKey.length - 1) rst.push('');
                 }
@@ -1031,7 +1083,8 @@ function ext_getPropety(propKey) {
                 } else if (doc.hasOwnProperty(propKey)) {
                     rst.push(doc[propKey]);
                 } else {
-                    rst.push('');
+                    // rst.push('');
+                    getDeepProperty(propKey, doc, rst);
                 }
             }
         }
@@ -1044,7 +1097,7 @@ function ext_getPropertyByRefId(baseKey, refIDKey, propertyKey){
     let dtObj = parentObj["myOwnRawDataObj"];
     let orgDtObj = parentObj["myOwnOrgRawDataObj"];
     if (baseKey && refIDKey && propertyKey && dtObj) {
-        for (let dItem of dtObj.data) {
+        for (let dItem of getActDataArr(dtObj)) {
             let doc = (dItem._doc === null || dItem._doc === undefined)?dItem:dItem._doc;
             let tmpRst = doc[baseKey];
             if (typeof tmpRst === "string" && tmpRst[0] === "@") {
@@ -1098,7 +1151,7 @@ function ext_getFee(feeKey, dtlFeeKey) {
     let rst = [], parentObj = this;
     let dtObj = parentObj["myOwnRawDataObj"];
     if (feeKey && dtObj) {
-        for (let dItem of dtObj.data) {
+        for (let dItem of getActDataArr(dtObj)) {
             rst.push(pri_getFee(dItem, feeKey, dtlFeeKey));
         }
     }
@@ -1209,7 +1262,7 @@ function ext_getArrayValues(itemKey) {
     let rst = [], parentObj = this;
     let dtObj = parentObj["myOwnRawDataObj"];
     let keysArr = itemKey.split(".");
-    for (let dataItem of dtObj.data) {
+    for (let dataItem of getActDataArr(dtObj)) {
         let itemArr = [];
         if (keysArr.length <= 2) {
             if (dataItem[keysArr[0]] instanceof Array) {
@@ -1269,7 +1322,8 @@ function ext_getBlank(dftVal) {
     let rst = [], parentObj = this;
     let dtObj = parentObj["myOwnRawDataObj"];
     if (dtObj) {
-        for (let i = 0; i < dtObj.data.length; i++) {
+        let dtData = getActDataArr(dtObj);
+        for (let i = 0; i < dtData.length; i++) {
             if (dftVal !== null && dftVal !== undefined) {
                 rst.push(dftVal)
             } else rst.push('');
@@ -1283,7 +1337,7 @@ function ext_getPropertyByFlag(flagVal, rstKey, dftValIfEmpty) {
     let dtObj = parentObj["myOwnRawDataObj"];
     if (flagVal && rstKey && dtObj) {
         let isArr = (flagVal instanceof Array);
-        for (let dItem of dtObj.data) {
+        for (let dItem of getActDataArr(dtObj)) {
             let doc = (dItem._doc)?dItem._doc:dItem;
             if (doc.hasOwnProperty("flags")) {
                 let bFlag = false;
@@ -1325,8 +1379,7 @@ function ext_getPropertyByForeignId(foreignIdVal, adHocIdKey, propKey, dftValIfN
         if (foreignIdVal instanceof Array) {
             for (let idVal of foreignIdVal) {
                 isFound = false;
-                let dataArr = dtObj.data;
-                if (dtObj.moduleName === "projectGLJ") dataArr = dtObj.data.gljList;
+                let dataArr = getActDataArr(dtObj);
                 for (let i = 0; i < dataArr.length; i++) {
                     let item = (dataArr[i]._doc)?dataArr[i]._doc:dataArr[i];
                     if (item[IdKey] === idVal) {
@@ -1357,7 +1410,7 @@ function ext_getPropertyByForeignId(foreignIdVal, adHocIdKey, propKey, dftValIfN
                 }
             }
         } else {
-            for (let item of dtObj.data) {
+            for (let item of getActDataArr(dtObj)) {
                 if (item[IdKey] === foreignIdVal) {
                     rst.push(item[propKey]);
                     isFound = true;
@@ -1372,4 +1425,25 @@ function ext_getPropertyByForeignId(foreignIdVal, adHocIdKey, propKey, dftValIfN
     return rst;
 }
 
+function getActDataArr(dtObj) {
+    let rst = null;
+    if (dtObj) {
+        rst = dtObj.data;
+        if (dtObj.moduleName === "projectGLJ") {
+            rst = dtObj.data.gljList;
+        }
+    }
+    return rst;
+}
+
+function replaceActDataArr(dtObj, newArr) {
+    if (dtObj.moduleName === "projectGLJ") {
+        delete dtObj.data.gljList;
+        dtObj.data.gljList = newArr;
+    } else {
+        delete dtObj.data;
+        dtObj.data = newArr;
+    }
+}
+
 export default Rpt_Data_Extractor;

+ 54 - 0
modules/std_billsGuidance_lib/controllers/libController.js

@@ -0,0 +1,54 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/5/29
+ * @version
+ */
+import BaseController from '../../common/base/base_controller';
+const _ = require('lodash');
+const billsGuidanceFacade = require('../facade/facades');
+let callback = function (req, res, err, msg, data) {
+    res.json({error: err, message: msg, data: data});
+};
+
+class BillsGuideLibController extends BaseController{
+    //获取清单指引库和该库引用的清单
+    async getLibWithBills(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let rst = await billsGuidanceFacade.getLibWithBills(data.libID);
+            callback(req, res, 0, '', rst);
+        }
+        catch(err){
+            callback(req, res, 1, err, null);
+        }
+    }
+
+    async getItemsByBills(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let items = await billsGuidanceFacade.getItemsBybills(data.guidanceLibID, data.billsID);
+            callback(req, res, 0, '', items);
+        }
+        catch(err){
+            callback(req, res, 1, err, null);
+        }
+    }
+
+    async updateItems(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let updateDatas = data.updateDatas;
+            await billsGuidanceFacade.updateItems(updateDatas);
+            callback(req, res, 0, '', null);
+        }
+        catch(err){
+            callback(req, res, 1, err, null);
+        }
+    }
+}
+
+export default BillsGuideLibController;

+ 27 - 0
modules/std_billsGuidance_lib/controllers/viewController.js

@@ -0,0 +1,27 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/5/29
+ * @version
+ */
+import BaseController from "../../common/base/base_controller";
+
+class ViewsController extends BaseController{
+    redirectMain(req, res){
+        res.render('maintain/billsGuidance_lib/html/main.html',
+            {
+                userAccount: req.session.managerData.username
+            });
+    }
+    redirectGuidance(req, res){
+        res.render('maintain/billsGuidance_lib/html/zhiyin.html',
+            {
+                userAccount: req.session.managerData.username
+            });
+    }
+}
+
+export default ViewsController;

+ 136 - 0
modules/std_billsGuidance_lib/facade/facades.js

@@ -0,0 +1,136 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/6/1
+ * @version
+ */
+import mongoose from 'mongoose';
+import CompilationModel from "../../users/models/compilation_model";
+import moment from 'moment';
+const uuidV1 = require('uuid/v1');
+const billsLibModel = mongoose.model('std_bills_lib_list');
+const billsGuideLibModel = mongoose.model('std_billsGuidance_lib');
+const billsGuideItemsModel = mongoose.model('std_billsGuidance_items');
+const stdBillsLibModel = mongoose.model('std_bills_lib_list');
+const stdBillsModel = mongoose.model('std_bills_lib_bills');
+const stdBillsJobsModel = mongoose.model('std_bills_lib_jobContent');
+const stdRationModel = mongoose.model('std_ration_lib_ration_items');
+const _ = require('lodash');
+
+module.exports = {
+    getLibWithBills,
+    getItemsBybills,
+};
+
+async function getBillsGuideLibs(findData) {
+    return await billsGuideLibModel.find(findData);
+}
+
+
+async function getLibWithBills(libID){
+    let guidanceLib = await getBillsGuideLibs({ID: libID, deleted: false});
+    if(guidanceLib.length === 0){
+        throw '不存在此指引库!';
+    }
+    let billsLib = await stdBillsLibModel.findOne({billsLibId: guidanceLib[0].billsLibId, deleted: false});
+    if(!billsLib){
+        throw '引用的清单规则库不存在!';
+    }
+    let bills = await stdBillsModel.find({billsLibId: billsLib.billsLibId, deleted: false});
+    return {guidanceLib: guidanceLib[0], bills};
+}
+
+function getAttrs(field, datas){
+    let rst = [];
+    for(let data of datas){
+        if(data[field]){
+            rst.push(data[field]);
+        }
+    }
+    return rst;
+}
+
+//定额项目指所引用定额是否被删除
+function rationAllExist(rationItems, stdRationIdx) {
+    for(let item of rationItems){
+        if(!stdRationIdx[item.rationID]){
+            return false;
+        }
+    }
+    return true;
+}
+
+//将同层树结构转为顺序数组
+function chainToArr(nodes){
+    let rst = [];
+    let tempIdx = {};
+    let nodeIdx = {};
+    //建索引
+    for(let node of nodes){
+        tempIdx[node.ID] = {ID: node.ID, NextSiblingID: node.NextSiblingID, preSibling: null, nextSibling: null};
+        nodeIdx[node.ID] = node;
+    }
+    //建链
+    for(let i in tempIdx){
+        let temp = tempIdx[i];
+        if(temp.NextSiblingID != -1){
+            let next = tempIdx[temp.NextSiblingID];
+            temp.nextSibling = next;
+            next.preSibling = temp;
+        }
+    }
+    let firstNode = null;
+    for(let i in tempIdx){
+        if(!tempIdx[i].preSibling){
+            firstNode = tempIdx[i];
+            break;
+        }
+    }
+    //获得顺序队列
+    while(firstNode){
+        rst.push(nodeIdx[firstNode.ID]);
+        firstNode = firstNode.nextSibling;
+    }
+    return rst;
+}
+
+async function getItemsBybills(guidanceLibID, billsID){
+    const type = {job: 0, ration: 1};
+    let items = await billsGuideItemsModel.find({libID: guidanceLibID, billsID: billsID, deleted: false});
+    let rationItems = _.filter(items, {type: type.ration});
+    let rationIds = getAttrs('rationID', rationItems);
+    let stdRations = await stdRationModel.find({ID: {$in: rationIds}, $or: [{isDeleted: null}, {isDeleted: false}]});
+    let stdRationIndex = {};
+    for(let stdRation of stdRations){
+        stdRationIndex[stdRation.ID] = stdRation;
+    }
+    //判断定额完整性
+    if(!rationAllExist(rationItems, stdRationIndex)){
+        //建定额链, 排序后再清除不存在的定额,保证顺序正确性
+        rationItems = chainToArr(rationItems);
+        //清除已被删除的定额
+        let removeIds = [];
+        _.remove(rationItems, function (item) {
+            if(!stdRationIndex[item.rationID]){
+                removeIds.push(item.ID);
+                return true;
+            }
+            return false;
+        });
+        _.remove(items, function (item) {
+           return removeIds.includes(item.ID);
+        });
+        await billsGuideItemsModel.remove({ID: {$in: removeIds}});
+        //重组树结构
+        let bulkArr = [];
+        for(let i = 0, len = rationItems.length; i < len; i++){
+            rationItems[i].NextSiblingID = rationItems[i + 1] ? rationItems[i + 1].ID : -1;
+            bulkArr.push({updateOne: {filter: {ID: rationItems[i].ID}, update: {$set: {NextSiblingID: rationItems[i].NextSiblingID}}}});
+        }
+        await billsGuideItemsModel.bulkWrite(bulkArr);
+    }
+    return items;
+}

+ 20 - 0
modules/std_billsGuidance_lib/routes/routes.js

@@ -0,0 +1,20 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/5/29
+ * @version
+ */
+import express from 'express';
+import BillsGuideLibController from '../controllers/libController';
+const router = express.Router();
+const billsGuideLibController = new BillsGuideLibController();
+
+module.exports = function (app) {
+  router.post('/getLibWithBills', billsGuideLibController.getLibWithBills);
+  router.post('/getItemsByBills', billsGuideLibController.getItemsByBills);
+
+  app.use('/billsGuidance/api', router);
+};

+ 5 - 2
modules/users/models/user_model.js

@@ -17,14 +17,17 @@ class UserModel extends BaseModel {
      *
      * @var {object}
      */
-    province = ['广东省', '北京市'];
+    province = ['北京', '天津', '河北', '山西', '内蒙古', '辽宁', '吉林', '黑龙江', '上海', '江苏', '浙江', '安徽',
+        '福建', '江西', '山东', '河南', '湖北', '湖南', '广东', '广西', '海南', '重庆', '四川', '贵州', '云南', '西藏',
+        '陕西', '甘肃', '青海', '宁夏', '新疆', '台湾', '香港', '澳门',];
 
     /**
      * 企业类型
      *
      * @var
      */
-    companyType = ['设计', '施工'];
+    companyType = ['建设单位', '设计单位',  '施工单位', '监理单位', '审核单位', '咨询公司', '招标代理', '住建部', '财政', '审计',
+        '造价管理站', '学校', '个人', '其他'];
 
     /**
      * 企业类型

+ 3 - 0
public/web/PerfectLoad.js

@@ -4,6 +4,9 @@
 
 jQuery.bootstrapLoading = {
     start: function (options) {
+        if($('#loadingPage').is(':visible')){
+            return;
+        }
         var defaults = {
             opacity: 0.5,
             //loading页面透明度

+ 29 - 14
public/web/gljUtil.js

@@ -16,7 +16,7 @@ let gljUtil = {
         let IDarray =  this.getSubdivisionAndTechBillsLeavesID(billsDatas);//分别取分部分项和技术措施项目的所有叶子清单ID
         let billIDs = IDarray[0],tech_billIDS = IDarray[1];
         for(let pglj of project_gljs ){
-            let pg_index = this.getIndex(pglj,gljKeyArray);
+            let pg_index = this.getIndex(pglj,this.gljKeyArray);
             pglj.subdivisionQuantity = 0;
             pglj.techQuantity = 0;
             pglj.quantity = 0;
@@ -31,16 +31,19 @@ let gljUtil = {
         for(let pkey in mixRatioMap){
             let mixRatioList = mixRatioMap[pkey];
             for(let m of mixRatioList){
-                let m_index = gljOprObj.getIndex(m,gljKeyArray);
+                let m_index = this.getIndex(m,this.gljKeyArray);
                 let m_glj = quantityMap[m_index];
                 let p_glj = quantityMap[pkey];
                 if(m_glj&&p_glj){
-                    let quantity = scMathUtil.roundForObj(p_glj.quantity*parseFloat(m.consumption),q_decimal);
-                    let techQuantity = scMathUtil.roundForObj(p_glj.techQuantity*parseFloat(m.consumption),q_decimal);
-                    let subdivisionQuantity = scMathUtil.roundForObj(p_glj.subdivisionQuantity*parseFloat(m.consumption),q_decimal);
-                    m_glj.quantity =  scMathUtil.roundForObj(m_glj.quantity+quantity,q_decimal);
-                    m_glj.techQuantity =  scMathUtil.roundForObj(m_glj.techQuantity+techQuantity,q_decimal);
-                    m_glj.subdivisionQuantity =  scMathUtil.roundForObj(m_glj.subdivisionQuantity+subdivisionQuantity,q_decimal);
+                    let quantity = scMathUtil.roundForObj(parseFloat(p_glj.quantity)*parseFloat(m.consumption),q_decimal);
+                    let techQuantity = scMathUtil.roundForObj(parseFloat(p_glj.techQuantity)*parseFloat(m.consumption),q_decimal);
+                    let subdivisionQuantity = scMathUtil.roundForObj(parseFloat(p_glj.subdivisionQuantity)*parseFloat(m.consumption),q_decimal);
+                    m_glj.quantity =  scMathUtil.roundForObj(parseFloat(m_glj.quantity)+quantity,q_decimal);
+                    m_glj.techQuantity =  scMathUtil.roundForObj(parseFloat(m_glj.techQuantity)+techQuantity,q_decimal);
+                    m_glj.subdivisionQuantity =  scMathUtil.roundForObj(parseFloat(m_glj.subdivisionQuantity)+subdivisionQuantity,q_decimal);
+                    if(m_glj.id == 6832){
+                        console.log(m_glj.quantity)
+                    }
                 }
             }
         }
@@ -67,7 +70,7 @@ let gljUtil = {
             }
         }
         for(let ra of rations){//计算定额类型工料机的消耗量
-            if(ra.type == rationType.gljRation&&ra.projectGLJID===pglj.id){
+            if(ra.type == this.rationType.gljRation&&ra.projectGLJID===pglj.id){
                 let r_quantity = scMathUtil.roundForObj(ra.quantity,q_decimal);
                 r_quantity = r_quantity?r_quantity:0;
                 quantity_sum = scMathUtil.roundForObj(quantity_sum+r_quantity,q_decimal);
@@ -86,9 +89,9 @@ let gljUtil = {
         return result;
     },
     getSubdivisionAndTechBillsLeavesID:function (billsDatas) {//分别取分部分项和技术措施项目的所有叶子清单ID
-        if(projectObj){//存在,说明在前端调用
-            return [projectObj.project.Bills.getSubdivisionProjectLeavesID(),projectObj.project.Bills.getTechLeavesID()];
-        }
+         if(typeof (projectObj) !== 'undefined'){//存在,说明在前端调用
+             return [projectObj.project.Bills.getSubdivisionProjectLeavesID(),projectObj.project.Bills.getTechLeavesID()];
+         }
         let parentMap ={};
         let subdivisionBillID  = null,techBillID = null,sIDs = [],tIDS = [];
         for(let b of billsDatas){
@@ -97,10 +100,11 @@ let gljUtil = {
             }else {
                 parentMap[b.ParentID]= [b];
             }
-            if(this.isFlag(b)&&b.flagsIndex.fixed.flag==this.fixedFlag.SUB_ENGINERRING) {
+            let flag = this.getFlag(b);
+            if(this.isDef(flag)&&flag.flag == this.fixedFlag.SUB_ENGINERRING){
                 subdivisionBillID = b.ID;
             }
-            if(this.isFlag(b)&&b.flagsIndex.fixed.flag==this.fixedFlag.CONSTRUCTION_TECH){
+            if(this.isDef(flag)&&flag.flag == this.fixedFlag.CONSTRUCTION_TECH){
                 techBillID = b.ID;
             }
         }
@@ -122,6 +126,10 @@ let gljUtil = {
             }
         }
     },
+    getFlag:function (b) {
+        return _.find(b.flags,{"fieldName":"fixed"});
+
+    },
     getGLJPrice:function (glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil) {
         let result = {};
         result.marketPrice = this.getMarketPrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil);
@@ -281,4 +289,11 @@ let gljUtil = {
         EQUIPMENT: 5
     },
      notEditType : [202, 203,204, 301, 4],
+     gljKeyArray : ['code','name','specs','unit','type'],
+      rationType : {
+        ration: 1,
+        volumePrice: 2,
+        gljRation: 3,
+        install:4
+    }
 }

+ 3 - 0
public/web/scMathUtil.js

@@ -205,6 +205,9 @@ let scMathUtil = {
             value = null;
         }
         return value;
+    },
+    isDef:function (v) {
+        return v !== undefined && v !== null;
     }
 };
 

+ 21 - 4
public/web/treeDataHelper.js

@@ -1,7 +1,8 @@
 /**
  * Created by Tony on 2017/1/23.
  */
-const NODE_ID = "ID", P_ID = "ParentID", NEXT_ID = "NextSiblingID", ADHOC_PRE_ID="Previous_ID", CHILDREN_NODE = "items", SUB_ID = "sub_ids", EMPTY_ID_VAL = -1, TREE_LEVEL = 'treeLevel';
+const NODE_ID = "ID", P_ID = "ParentID", NEXT_ID = "NextSiblingID", ADHOC_PRE_ID="Previous_ID", CHILDREN_NODE = "items", SUB_ID = "sub_ids",
+      EMPTY_ID_VAL = -1, TREE_LEVEL = 'treeLevel', TOP_BILL_ID = "topBillID";
 
 let tree_Data_Helper = {
     buildTreeNodeDirectly: function(data, addLevel) {
@@ -16,7 +17,7 @@ let tree_Data_Helper = {
             }
             return tmpNodeRst;
         };
-        let private_buildNodeData = function(parentItem, idArr, treeLevel) {
+        let private_buildNodeData = function(parentItem, idArr, treeLevel, tbID) {
             let iter = [], nextNode = private_getStartNode(idArr);
             while (nextNode !== null && nextNode !== undefined ) {
                 if (parentItem) {
@@ -25,11 +26,27 @@ let tree_Data_Helper = {
                     rst.push(nextNode);
                 }
                 iter.push(nextNode);
+                nextNode[TOP_BILL_ID] = tbID;
+                if (parentItem === null) {
+                    nextNode[TOP_BILL_ID] = nextNode[NODE_ID];
+                    if (nextNode.flags && nextNode.flags.length > 0) {
+                        for (let flag of nextNode.flags) {
+                            if (flag.fieldName === "fixed") {
+                                nextNode[TOP_BILL_ID] = flag.flag;
+                                break;
+                            }
+                        }
+                    }
+                }
                 if (addLevel) nextNode[TREE_LEVEL] = treeLevel;
                 nextNode = tmpNodes[prefix + nextNode[NEXT_ID]];
             }
             for (let i = 0; i < iter.length; i++) {
-                private_buildNodeData(iter[i], iter[i][SUB_ID], (treeLevel + 1));
+                let rtbID = tbID;
+                if (parentItem === null) {
+                    rtbID = iter[i][TOP_BILL_ID];
+                }
+                private_buildNodeData(iter[i], iter[i][SUB_ID], (treeLevel + 1), rtbID);
             }
         };
 
@@ -52,7 +69,7 @@ let tree_Data_Helper = {
                 tmpNodes[prefix + data[i][P_ID]][SUB_ID].push(data[i][NODE_ID]);
             }
         }
-        private_buildNodeData(null, topArr, 0);
+        private_buildNodeData(null, topArr, 0, -1);
         //try to release and return
         tmpNodes = null;
         topArr.length = 0;

+ 3 - 0
public/web/tree_sheet/tree_sheet_helper.js

@@ -333,6 +333,9 @@ var TREE_SHEET_HELPER = {
                 else if(sheetName === 'stdRationLib_chapter'){
                     sessionStorage.setItem('stdRationLibExpState', rationLibObj.tree.getExpState(rationLibObj.tree.items));
                 }
+                else if(sheetName === 'stdBillsGuidance_bills'){
+                    sessionStorage.setItem('stdBillsGuidanceExpState', billsGuidance.bills.tree.getExpState(billsGuidance.bills.tree.items));
+                }
                 TREE_SHEET_HELPER.massOperationSheet(hitinfo.sheet, function () {
                     let iCount = node.posterityCount(), i, child;
                     for (i = 0; i < iCount; i++) {

+ 107 - 0
test/unit/reports/test_rpt_11_2.js

@@ -0,0 +1,107 @@
+/**
+ * Created by Tony on 2018/6/11.
+ */
+
+let test = require('tape');
+import JpcEx from "../../../modules/reports/rpt_component/jpc_ex";
+import JV from "../../../modules/reports/rpt_component/jpc_value_define";
+let config = require("../../../config/config.js");
+config.setupDb(process.env.NODE_ENV);
+let mongoose = require("mongoose");
+let fileUtils = require("../../../modules/common/fileUtils");
+let path = require('path');
+let dbm = require("../../../config/db/db_manager");
+let rpt_cfg = require('./rpt_cfg');
+dbm.connect(process.env.NODE_ENV);
+
+//统一引用models
+fileUtils.getGlobbedFiles('../../../modules/all_models/*.js').forEach(function(modelPath) {
+    require(path.resolve(modelPath));
+});
+
+//config.setupCache();
+let cfgCacheUtil = require("../../../config/cacheCfg");
+cfgCacheUtil.setupDftCache();
+
+let fsUtil = require("../../../public/fsUtil");
+
+let demoPrjId = - 1;
+let demoRptId = 292, pagesize = "A4"; //11-2表(新)
+
+// let userId_Leng = "59cdf14a0034a1000ba52b97"; //小冷User Id 换成_id了 QQ号
+let userId_Leng = "5acac1e885bf55000bd055ba"; //小冷User Id2
+// demoPrjId = 720; //QA: DW3
+//demoPrjId = 1626; //QA:
+demoPrjId = 2260; //QA:
+//*/
+let userId_Dft = userId_Leng;
+/*/
+ let userId_Dft = "595328da1934dc327cad08eb";
+ //*/
+
+let rptTplFacade = require("../../../modules/reports/facade/rpt_template_facade");
+let rptTplDataFacade = require("../../../modules/reports/facade/rpt_tpl_data_facade");
+
+import rptDataExtractor from "../../../modules/reports/util/rpt_construct_data_util";
+
+let fs = require('fs');
+//设置Date Format函数
+fs.readFile(__dirname.slice(0, __dirname.length - 18) + '/public/web/date_util.js', 'utf8', 'r', function (err, data) {
+    eval(data);
+});
+
+test('测试 - 测试模板啦: ', function (t) {
+    rptTplFacade.getRptTemplate(demoRptId).then(function(rptTpl) {
+        let rptDataUtil = new rptDataExtractor();
+        rptDataUtil.initialize(rptTpl._doc);
+        let filter = rptDataUtil.getDataRequestFilter();
+        console.log(filter);
+        //正常应该根据报表模板定义的数据类型来请求数据
+        rptTplDataFacade.prepareProjectData(userId_Dft, demoPrjId, filter, function (err, msg, rawDataObj) {
+            if (!err) {
+                try {
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject_建筑11-2表.jsp");
+                    let tplData = rptDataUtil.assembleData(rawDataObj);
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataAfterCacl_建筑11-2表.jsp");
+                    fsUtil.writeObjToFile(tplData, "D:/GitHome/ConstructionCost/tmp/rptTplAssembledData_建筑11-2表.jsp");
+                    //it's time to build the report!!!
+                    let printCom = JpcEx.createNew();
+                    rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pagesize;
+                    let defProperties = rpt_cfg;
+                    let dftOption = JV.PAGING_OPTION_NORMAL;
+                    printCom.initialize(rptTpl);
+                    printCom.analyzeData(rptTpl, tplData, defProperties, dftOption);
+                    let maxPages = printCom.totalPages;
+                    let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
+                    if (pageRst) {
+                        // fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult_建筑11-2表.jsp");
+                    } else {
+                        console.log("oh! no pages were created!");
+                    }
+                } catch (ex) {
+                    console.log(ex);
+                    t.pass('pass with exception!');
+                    t.end();
+                }
+
+                t.pass('pass succeeded!');
+                t.end();
+            } else {
+                console.log(msg);
+                t.pass('pass with error!');
+                t.end();
+            }
+        })
+    });
+});
+
+test('close the connection', function (t) {
+    setTimeout(function () {
+        mongoose.disconnect();
+        t.pass('closing db connection');
+        t.end();
+    }, 1000);
+    // mongoose.disconnect();
+    // t.pass('closing db connection');
+    // t.end();
+});

+ 109 - 0
test/unit/reports/test_rpt_test_template.js

@@ -0,0 +1,109 @@
+/**
+ * Created by Tony on 2018/6/12.
+ */
+
+let test = require('tape');
+import JpcEx from "../../../modules/reports/rpt_component/jpc_ex";
+import JV from "../../../modules/reports/rpt_component/jpc_value_define";
+let config = require("../../../config/config.js");
+config.setupDb(process.env.NODE_ENV);
+let mongoose = require("mongoose");
+let fileUtils = require("../../../modules/common/fileUtils");
+let path = require('path');
+let dbm = require("../../../config/db/db_manager");
+let rpt_cfg = require('./rpt_cfg');
+dbm.connect(process.env.NODE_ENV);
+
+//统一引用models
+fileUtils.getGlobbedFiles('../../../modules/all_models/*.js').forEach(function(modelPath) {
+    require(path.resolve(modelPath));
+});
+
+//config.setupCache();
+let cfgCacheUtil = require("../../../config/cacheCfg");
+cfgCacheUtil.setupDftCache();
+
+let fsUtil = require("../../../public/fsUtil");
+
+let demoPrjId = - 1;
+let demoRptId = 279, pagesize = "A4";
+//288: 11-2表(新)
+//279: 04
+
+// let userId_Leng = "59cdf14a0034a1000ba52b97"; //小冷User Id 换成_id了 QQ号
+let userId_Leng = "5acac1e885bf55000bd055ba"; //小冷User Id2
+// demoPrjId = 720; //QA: DW3
+//demoPrjId = 1626; //QA:
+demoPrjId = 2260; //QA:
+//*/
+let userId_Dft = userId_Leng;
+/*/
+ let userId_Dft = "595328da1934dc327cad08eb";
+ //*/
+
+let rptTplFacade = require("../../../modules/reports/facade/rpt_template_facade");
+let rptTplDataFacade = require("../../../modules/reports/facade/rpt_tpl_data_facade");
+
+import rptDataExtractor from "../../../modules/reports/util/rpt_construct_data_util";
+
+let fs = require('fs');
+//设置Date Format函数
+fs.readFile(__dirname.slice(0, __dirname.length - 18) + '/public/web/date_util.js', 'utf8', 'r', function (err, data) {
+    eval(data);
+});
+
+test('测试 - 测试模板啦: ', function (t) {
+    rptTplFacade.getRptTemplate(demoRptId).then(function(rptTpl) {
+        let rptDataUtil = new rptDataExtractor();
+        rptDataUtil.initialize(rptTpl._doc);
+        let filter = rptDataUtil.getDataRequestFilter();
+        console.log(filter);
+        //正常应该根据报表模板定义的数据类型来请求数据
+        rptTplDataFacade.prepareProjectData(userId_Dft, demoPrjId, filter, function (err, msg, rawDataObj) {
+            if (!err) {
+                try {
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject_测试模板.jsp");
+                    let tplData = rptDataUtil.assembleData(rawDataObj);
+                    fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataAfterCacl_测试模板.jsp");
+                    fsUtil.writeObjToFile(tplData, "D:/GitHome/ConstructionCost/tmp/rptTplAssembledData_测试模板.jsp");
+                    //it's time to build the report!!!
+                    let printCom = JpcEx.createNew();
+                    rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pagesize;
+                    let defProperties = rpt_cfg;
+                    let dftOption = JV.PAGING_OPTION_NORMAL;
+                    printCom.initialize(rptTpl);
+                    printCom.analyzeData(rptTpl, tplData, defProperties, dftOption);
+                    let maxPages = printCom.totalPages;
+                    let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
+                    if (pageRst) {
+                        // fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult_测试模板.jsp");
+                    } else {
+                        console.log("oh! no pages were created!");
+                    }
+                } catch (ex) {
+                    console.log(ex);
+                    t.pass('pass with exception!');
+                    t.end();
+                }
+
+                t.pass('pass succeeded!');
+                t.end();
+            } else {
+                console.log(msg);
+                t.pass('pass with error!');
+                t.end();
+            }
+        })
+    });
+});
+
+test('close the connection', function (t) {
+    setTimeout(function () {
+        mongoose.disconnect();
+        t.pass('closing db connection');
+        t.end();
+    }, 1000);
+    // mongoose.disconnect();
+    // t.pass('closing db connection');
+    // t.end();
+});

+ 2 - 1
test/unit/reports/test_tpl_09_1.js

@@ -59,8 +59,9 @@ test('测试 - 测试模板啦: ', function (t) {
         rptTplDataFacade.prepareProjectData(userId_Dft, demoPrjId, filter, function (err, msg, rawDataObj) {
             if (!err) {
                 try {
-                    fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject_建筑09-1表.jsp");
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject_建筑09-1表.jsp");
                     let tplData = rptDataUtil.assembleData(rawDataObj);
+                    fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataAfterCacl_建筑09-1表.jsp");
                     // fsUtil.writeObjToFile(tplData, "D:/GitHome/ConstructionCost/tmp/rptTplAssembledData_建筑09-1表.jsp");
                     //it's time to build the report!!!
                     let printCom = JpcEx.createNew();

+ 8 - 5
web/building_saas/complementary_ration_lib/js/main.js

@@ -16,11 +16,14 @@ let compleRationMain = {
                     );
                     var newHref = "/complementaryRation/ration?repository="+id;
                     $("#tempId td:first a").click(function () {
-                        let newHref = "/complementaryRation/ration?repository="+id;
-                        let newTab = window.open('about:blank');
-                        CommonAjax.get(newHref, [], function () {
-                            newTab.location.href = newHref;
-                        });
+                        $('#comple-ration').modal('hide');
+                        setTimeout(function () {
+                            let newHref = "/complementaryRation/ration?repository="+id;
+                            let newTab = window.open('about:blank');
+                            CommonAjax.get(newHref, [], function () {
+                                newTab.location.href = newHref;
+                            });
+                        }, 200);
                     });
                     $("#tempId").attr("id", id);
                 }

+ 1 - 0
web/building_saas/complementary_ration_lib/js/ration.js

@@ -198,6 +198,7 @@ let rationOprObj = {
                         callback: function(){},
                         items: {
                             "delete": {name: "删除", disabled: delDis, icon: "fa-remove", callback: function (key, opt) {
+                                me.rationsCodes.splice(me.rationsCodes.indexOf(ration.code.toString()), 1);
                                 me.mixDel = 1;
                                 me.mixUpdateRequest([], [], [ration.ID]);
                             }}

+ 1 - 1
web/building_saas/fee_rates/fee_rate.html

@@ -3,7 +3,7 @@
 <div >
 <div class="toolsbar_feeRate px-1 ">
     <div class="form-inline py-1">
-        <label class="mx-2" >当前使用:<span id="feeRateFileName">费率1</span>(<a href="#" id="pop-lv"><span id="projectCount">3</span> 单位工程使用</a>)
+        <label class="mx-2" >当前使用:<span id="feeRateFileName">费率1</span>(<a href="#" id="pop-lv"><span id="projectCount">3</span> 单位工程使用</a>)
             <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#change-lv" id="changFeeRateFile"><i class="fa fa-exchange"></i> 选择其他</a>
             <a class="btn btn-sm ml-1" href="#" data-toggle="modal" id="saveAs" data-target="#copy-lv"><i class="fa fa-files-o"></i> 另存单独用</a></label>
     </div>

+ 1 - 1
web/building_saas/glj/html/glj_index.html

@@ -5,7 +5,7 @@
 </style>
 <div class="toolsbar px-1">
     <div class="form-inline py-1">
-        <label class="mx-2">当前使用:<span id="used-name"></span>(<a href="#" id="pop-dj" data-original-title="" title=""><span id="used-count">0</span> 单位工程使用</a>)
+        <label class="mx-2">当前使用:<span id="used-name"></span>(<a href="#" id="pop-dj" data-original-title="" title=""><span id="used-count">0</span> 单位工程使用</a>)
             <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#change-dj"><i class="fa fa-exchange"></i> 选择其他</a>
             <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#file-save-as-dialog"><i class="fa fa-files-o"></i> 另存单独用</a></label>
     </div>

+ 29 - 2
web/building_saas/glj/html/project_glj.html

@@ -5,7 +5,7 @@
 </style>
 <div class="toolsbar px-1">
     <div class="form-inline py-1">
-        <label class="mx-2">当前使用:<span id="current-name"></span>(<a href="#" id="pop-used-list" data-original-title="" title=""><span id="used-project-count">0</span> 单位工程使用</a>)
+        <label class="mx-2">当前使用:<span id="current-name"></span>(<a href="#" id="pop-used-list" data-original-title="" title=""><span id="used-project-count">0</span> 单位工程使用</a>)
             <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#change-unitFile"><i class="fa fa-exchange"></i> 选择其他</a>
             <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#unitFile-save-as"><i class="fa fa-files-o"></i> 另存单独用</a></label>
     </div>
@@ -130,7 +130,34 @@
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                <a href="javascript:void(0);" class="btn btn-primary" id="save-as-confirm">确定</a>
+                <button type="button" class="btn btn-primary" id="save-as-confirm">确定</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+
+<!--弹出 重命名窗口-->
+<div class="modal fade" id="rename-unitFile" 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>单价文件名称</label>
+                    <input class="form-control" id="newUnitFileID" value="" style="display: none">
+                    <input class="form-control" id="newUnitFileName" value="">
+                    <small class="form-text text-danger" id="renameError_unitFile">本建设项目中已存在同名单价文件。</small>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <button type="button" class="btn btn-primary" data-dismiss="modal" id="renameUnitFileConfirm" disabled>确定</button>
             </div>
         </div>
     </div>

+ 3 - 0
web/building_saas/js/global.js

@@ -7,10 +7,13 @@ function autoFlashHeight(){
     // var feeRateToolsbarHeight = $(".toolsbar_feeRate").height();
     let toolsBarHeightQ = $(".tools-bar-height-q").height();
     let toolsBarHeightD = $(".tools-bar-height-d").height();
+    let toolsBarHeightZ = $(".tools-bar-height-z").height();
     //$(".main-data-side-q").height($(window).height()-headerHeight-toolsbarHeight-toolsBarHeightQ-302);
     $(".main-data-side-q").height($(window).height()-headerHeight-toolsbarHeight-toolsBarHeightQ-$('#qd').find('.bottom-content').find('.p-0').height()-5);
     //$(".main-data-side-d").height($(window).height()-headerHeight-toolsbarHeight-toolsBarHeightD-302);
     $(".main-data-side-d").height($(window).height()-headerHeight-toolsbarHeight-toolsBarHeightD-$('#stdSectionRations').height()-5);
+    $(".main-data-side-zb").height($(window).height()-headerHeight-toolsbarHeight-toolsBarHeightZ);
+    $(".main-data-side-zi").height($(window).height()-headerHeight-toolsbarHeight-toolsBarHeightZ);
     $('.main-content').width($(window).width()-$('.main-nav').width()-$('.main-side').width()-5);
     $('#glj_tree_div .modal-content').width($(window).width() < 1020 + 20 ? $(window).width() - 20 : 1020);
     //$("#main .main-data-top").height($(window).height()-headerHeight-toolsbarHeight-bottomContentHeight-1);

+ 41 - 7
web/building_saas/main/html/main.html

@@ -86,12 +86,12 @@
                       <a href="javascript:void(0)" class="btn btn-sm" name="lockBills"  title="锁定清单"> <i class="fa fa-lock" aria-hidden="true"></i> 锁定清单</a>
                       <% } %>
                   </div>
-                  <div class="tools-btn">
-                      <a href="javacript:void(0);" data-toggle="modal" data-target="#column" class="btn btn-sm"><i class="fa fa-table" aria-hidden="true"></i> 列设置</a>
-                  </div>
                   <div class="side-tabs">
                       <ul class="nav nav-tabs" role="tablist">
                           <li class="nav-item">
+                              <a class="nav-link px-3" href="javascript:void(0)" id = 'stdBillsGuidanceTab' relaPanel="#zy">清单指引</a>
+                          </li>
+                          <li class="nav-item">
                               <a class="nav-link px-3" href="javascript:void(0)" id = 'stdBillsTab' relaPanel="#qd">清单规则</a>
                           </li>
                           <li class="nav-item">
@@ -248,6 +248,37 @@
                       <div class="main-side" style="display: inline-block">
                           <div class="resize" id="sideResize" style="width: 1%; height: 100%; resize:horizontal; cursor: w-resize; float: left; background: #F1F1F1"></div>
                           <div class="tab-content" style="width: 99%; height: 100%; float: left">
+                              <!--清单指引-->
+                              <div class="tab-pane" id="zy">
+                                  <div class="sidebar-tools-bar container-fluid tools-bar-height-z">
+                                      <div class="p-1 d-flex justify-content-center">
+                                          <select class="form-control form-control-sm" id="stdBillsGuidanceLibSelect">
+                                          </select>
+                                          <div class="input-group" id="stdBillsGuidanceSearch">
+                                              <input type="text" class="form-control form-control-sm" placeholder="搜索清单">
+                                              <span class="input-group-btn">
+                                                  <button class="btn btn-secondary btn-sm" type="button"><i class="fa fa-search" aria-hidden="true"></i></button>
+                                              </span>
+                                          </div>
+                                          <button id="guidanceInsertRation" class="btn btn-primary btn-sm mx-3" type="button">插入定额</button>
+                                          <button id="guidanceInsertBills" class="btn btn-primary btn-sm mx-3" type="button">插入清单</button>
+                                      </div>
+                                      <!--搜索结果窗体-->
+                                      <div class="side-search-box col-12 p-2" id="billsGuidanceSearchResult" style="display: none;">
+                                          <div class="d-flex justify-content-between">
+                                              <span id = 'billsGuidanceSearchResultCount'>搜索结果:5</span>
+                                              <a class="btn btn-secondary btn-sm" href="javascript:void(0);" id="nextBillsGuidance">查找下一条</a>
+                                              <a title="关闭搜索" class="btn btn-link btn-sm" href="javascript:void(0);" id="closeSearchBillsGuidance"><i class="fa fa-remove" aria-hidden="true"></i></a>
+                                          </div>
+                                      </div>
+                                  </div>
+                                  <div class="row" style="margin-left: 1px;">
+                                      <div id="billsGuidance_bills" class="main-data-side-zb" style="width: 53%; float: left; margin: 0; padding: 0;">
+                                      </div>
+                                      <div id="billsGuidance_items" class="main-data-side-zi" style="width: 46%; float: left; margin: 0; padding: 0;">
+                                      </div>
+                                  </div>
+                              </div>
                               <!--清单规则-->
                               <div class="tab-pane" id="qd">
                                   <div class="tools-bar-height-q container-fluid">
@@ -556,6 +587,8 @@
                                                 </label>
                                             </div>
                                         </fieldset>
+                                        <div id="col_setting_spread" style="height:300px;overflow:hidden">
+                                        </div>
                                     </div>
                                 </div>
                             </div>
@@ -634,7 +667,7 @@
         </div>
     </div>    
     <!--弹出列设置-->
-    <div class="modal fade" id="column" data-backdrop="static">
+  <!--  <div class="modal fade" id="column" data-backdrop="static">
         <div class="modal-dialog modal-lg" role="document" style="width: 350px;">
             <div class="modal-content">
                 <div class="modal-header">
@@ -650,7 +683,7 @@
                 </div>
             </div>
         </div>
-    </div>
+    </div>-->
     <!--工料机选择窗口-->
     <div class="modal fade" id="glj_tree_div" data-backdrop="static">
         <div class="modal-dialog modal-lg" role="document" id="modalCon">
@@ -861,8 +894,8 @@
                 </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>
+                    <button type="button" class="btn btn-primary"  data-dismiss="modal" id="deleteN" style="display: none" >否</button>
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal" id="deleteCancel">否</button><!--实际是取消-->
                 </div>
             </div>
         </div>
@@ -1232,6 +1265,7 @@
         <script type="text/javascript" src="/web/building_saas/main/js/controllers/project_controller.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/controllers/block_controller.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/side_tools.js"></script>
+        <script type="text/javascript" src="/web/building_saas/main/js/views/std_billsGuidance_lib.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/std_bills_lib.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/std_ration_lib.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/models/quantity_detail.js"></script>

+ 6 - 6
web/building_saas/main/html/tender_price.html

@@ -1,11 +1,11 @@
 <div class="toolsbar px-1">
     <div class="btn-toolbar py-1">
-
-        <select class="form-control mr-2" style="width: auto; font-size: .875rem" id="calcPriceOption">
-            <option value="coeBase">根据调整系数计算报价</option>
-            <option value="priceBase" >根据报价计算调整系数</option>
-        </select>
-
+        <div class="input-group input-group-sm mr-2">
+            <select class="form-control form-control-sm" style="width: auto; font-size: .875rem" id="calcPriceOption">
+                <option value="coeBase">根据调整系数计算报价</option>
+                <option value="priceBase" >根据报价计算调整系数</option>
+            </select>
+        </div>
         <div class="input-group input-group-sm mr-2" style="width:240px">
             <div class="input-group-prepend">
                 <span class="input-group-text" id="inputGroup-sizing-sm">工料机单价调整系数</span>

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

@@ -184,6 +184,8 @@ function loadSize(eles, type, callback) {
 
 function getResizeWidthPercent(nearSize, farSize){
     const resizeWidth = 6;
+    nearSize = parseFloat(nearSize);
+    farSize = parseFloat(farSize);
     let nearPercent = (nearSize / (resizeWidth + nearSize + farSize) * 100) + '%';
     let farPercent = (farSize / (resizeWidth + nearSize + farSize) * 100) + '%';
     return {nearPercent, farPercent};

+ 1 - 1
web/building_saas/main/js/models/calc_program.js

@@ -151,7 +151,7 @@ let calcTools = {
         if (this.isRationCategory(treeNode)) {
             if (treeNode.data.type != rationType.volumePrice) {
                 treeNode.data.gljList = projectObj.project.ration_glj.getGljArrByRation(treeNode.data);
-            };
+            }
         }
         else if (this.isBill(treeNode)){
             let nodeQ = this.uiNodeQty(treeNode);

+ 12 - 6
web/building_saas/main/js/models/installation_fee.js

@@ -592,12 +592,18 @@ var installation_fee = {
                     labourQuantity = scMathUtil.roundForObj(parseFloat(project.Ration.getLabourTotalFee(ration))*parseFloat(labour),gljDecimal);
                     materialQuantity = scMathUtil.roundForObj(parseFloat(project.Ration.getMaterialTotalFee(ration))*parseFloat(material),gljDecimal);
                     machineQuantity = scMathUtil.roundForObj(parseFloat(project.Ration.getMachineTotalFee(ration))*parseFloat(machine),gljDecimal);
-                }else if(rule.base=='人工'){
-                    labourQuantity = scMathUtil.roundForObj(parseFloat(project.Ration.getLabourTotalFee(ration))*parseFloat(feeRate)*parseFloat(labour),gljDecimal);
-                }else if(rule.base=='材料'){
-                    materialQuantity = scMathUtil.roundForObj(parseFloat(project.Ration.getMaterialTotalFee(ration))*parseFloat(feeRate)*parseFloat(material),gljDecimal);
-                }else if(rule.base=='机械'){
-                    machineQuantity = scMathUtil.roundForObj(parseFloat(project.Ration.getMachineTotalFee(ration))*parseFloat(feeRate)*parseFloat(machine),gljDecimal);
+                }else {
+                    let base = 0;
+                    if(rule.base=='人工'){
+                        base = parseFloat(project.Ration.getLabourTotalFee(ration))*parseFloat(feeRate);
+                    }else if(rule.base=='材料'){
+                        base = parseFloat(project.Ration.getMaterialTotalFee(ration))*parseFloat(feeRate);
+                    }else if(rule.base=='机械'){
+                        base = parseFloat(project.Ration.getMachineTotalFee(ration))*parseFloat(feeRate);
+                    }
+                    labourQuantity = scMathUtil.roundForObj(base*parseFloat(labour),gljDecimal);
+                    materialQuantity = scMathUtil.roundForObj(base*parseFloat(material),gljDecimal);
+                    machineQuantity = scMathUtil.roundForObj(base*parseFloat(machine),gljDecimal);
                 }
                 return [labourQuantity,materialQuantity,machineQuantity];
             }

+ 67 - 4
web/building_saas/main/js/models/project_glj.js

@@ -283,8 +283,7 @@ ProjectGLJ.prototype.updatePrice = function (recode, updateField, newval,from,cb
             gljs.push(glj);
             let nodes = me.getImpactRationNodes(gljs);//取到因为改变工料机价格而受影响的定额
             projectObj.project.calcProgram.calcRationsAndSave(nodes);//触发计算程序
-            socket.emit('unitFileChangeNotify', JSON.stringify(data));
-            projectObj.project.markUpdateProject({projectID:projectObj.project.ID(),'unitFileID':socketObject.getUnitFileRoomID()},"unitFile");
+            projectGljObject.onUnitFileChange(data);
             if(cb){
                 cb(gljs);
             }
@@ -344,8 +343,7 @@ ProjectGLJ.prototype.batchUpdatePrice = function (changeInfo,callback) {
             let nodes = me.getImpactRationNodes(gljs);//取到因为改变工料机价格而受影响的定额
             projectObj.project.calcProgram.calcRationsAndSave(nodes);//触发计算程序
             gljOprObj.showRationGLJSheetData();
-            socket.emit('unitFileChangeNotify', JSON.stringify(gljs));
-            projectObj.project.markUpdateProject({projectID:projectObj.project.ID(),'unitFileID':socketObject.getUnitFileRoomID()},"unitFile");
+            projectGljObject.onUnitFileChange(gljs);
             if(callback){
                 callback(gljs);
             }
@@ -412,6 +410,71 @@ ProjectGLJ.prototype.changeFile = function (changeData,callback) {
     });
 };
 
+ProjectGLJ.prototype.addMixRatio = function(selections,callback){
+    let gljList = [],allGLJ = gljOprObj.AllRecode;
+    $("#glj_tree_div").modal('hide');
+    if(selections.length == 0) {
+        return;
+    }
+    for(let glj of allGLJ){
+        let i_key = gljOprObj.getIndex(glj, gljLibKeyArray);
+        if(_.includes(selections,i_key)){
+            let pglj = {
+                project_id: projectObj.project.ID(),
+                glj_id: glj.ID,
+                name: glj.name,
+                code: glj.code,
+                original_code: glj.code,
+                unit: glj.unit,
+                specs: glj.specs,
+                base_price: glj.basePrice,
+                market_price: glj.basePrice,
+                shortName: glj.shortName,
+                type: glj.gljType,
+                adjCoe: glj.adjCoe,
+                from:'std',
+                repositoryId:glj.repositoryId,
+                materialType:glj.materialType,
+                materialCoe:glj.materialCoe,
+            };
+            if (glj.hasOwnProperty("compilationId")) {
+                pglj.from = "cpt";
+                if (glj.code.indexOf('-') != -1) {//这条工料机是用户通过修改名称、规格、型号等保存到补充工料机库的
+                    pglj.original_code = glj.code.split('-')[0];//取-前的编号作为原始编号
+                }
+            }
+            gljList.push(pglj);
+        }
+    }
+    gljList = _.sortByAll(gljList, ['type', 'code']);
+    if(gljList.length == 0) return;
+    let praentInfo = {
+        unit_price_file_id:projectObj.project.property.unitPriceFile.id,
+        connect_key:gljOprObj.getIndex(projectGljObject.selectedProjectGLJ,gljKeyArray)
+    };
+    $.bootstrapLoading.start();
+    CommonAjax.post("/glj/add-ratio", {gljList:gljList,parentInfo:praentInfo}, function (data) {
+        $.bootstrapLoading.end();
+        if(callback){
+            callback(data);
+        }
+    }, function () {
+        $.bootstrapLoading.end();
+    });
+
+}
+
+ProjectGLJ.prototype.checkUnitFileName = function(newVal,callback){
+    let property = projectInfoObj.projectInfo.property;
+    let data = {
+        name:newVal,
+        rootProjectID:property.rootProjectID
+    }
+    CommonAjax.post('/glj/checkUnitFileName', data, function (data) {
+        callback(data);
+    });
+};
+
 ProjectGLJ.prototype.saveAs = function (saveData,callback) {
     $.bootstrapLoading.start();
     CommonAjax.specialPost('/glj/save-as',saveData,function () {

+ 107 - 0
web/building_saas/main/js/models/ration.js

@@ -434,6 +434,113 @@ var Ration = {
                 }
             })
         };
+        ration.prototype.addMultiRation = function (items, callback) {
+            let me = this;
+            let project = projectObj.project, sheetController = projectObj.mainController;
+            let engineering = projectInfoObj.projectInfo.property.engineering;
+            let selected = project.mainTree.selected, newSource = null, newNode = null,pre=null,br=null;
+            let billItemID = null,serialNo=1,nextID=null;
+            let needInstall = false;
+            let newDatas = [];
+            if (selected === null) { return; }
+            if (selected.sourceType === project.Bills.getSourceType() && selected.depth() > 0) {
+                if (selected.source.children.length > 0) {
+                    alert('当前清单已有清单子项,不能套用定额。');
+                } else if (selected.data.calcBase&&selected.data.calcBase!="") {
+                    alert('当前有基数计算不能插入定额/量价/工料机。');
+                } else {
+                    if(selected.data.type === billType.FB){
+                        return;
+                    }
+                    billItemID = selected.source.getID();
+                    nextID = selected.tree.rootID();
+                    br = this.getBillsSortRation(billItemID);
+                    serialNo = br.length > 0 ? br[br.length - 1].serialNo + 1 : 1
+                }
+            } else if (selected.sourceType === project.Ration.getSourceType()) {
+                billItemID = selected.getParentID();
+                br = this.getBillsSortRation(billItemID);
+                serialNo = selected.data.serialNo+1;
+                nextID = selected.getNextSiblingID();
+                pre = selected.source;
+            };
+            if(billItemID){
+                let calQuantity = optionsOprObj.getOption(optionsOprObj.optionsTypes.GENERALOPTS, 'rationQuanACToBillsQuan');
+                if(engineering==engineeringType.BUILD_IN) {//如果是安装工程,要看需不需要生成安装增加费
+                    let billsNode = project.mainTree.getNodeByID(billItemID);
+                    needInstall = project.Bills.isFBFX(billsNode);//在分部分项插入的定额才需要定额安装增加费
+                }
+                for(let i = 0; i < items.length; i++){
+                    let newData = me.getTempRationData(me.getNewRationID(), billItemID, serialNo, items[i].rationType);
+                    serialNo++;
+                    let brUpdate = [];
+                    //更新兄弟节点的序列号
+                    if (i ===0 && pre) {
+                        let preIndex = br.indexOf(pre), i;
+                        for (i = preIndex + 1; i < br.length; i++) {
+                            br[i].serialNo = i < br.length - 1 ? br [i + 1].serialNo + items.length - 1 : br[i].serialNo + items.length;
+                            brUpdate.push({projectID:newData.projectID,ID:br[i].ID,serialNo:br[i].serialNo});
+                        }
+                    }
+                    newDatas.push({itemQuery: items[i].itemQuery, newData: newData, firstLibID: rationLibObj.getFirstStdRationLibID(), calQuantity: calQuantity, brUpdate: brUpdate, needInstall: needInstall})
+                }
+                let showLoding = true;
+                $.bootstrapLoading.start();
+                //保证由于异步的关系loading界面被隐藏,比如清单指引插入清单定额时,endUpdate中提前隐藏了loading
+                let interval =setInterval(function () {
+                    if(!$('#loadingPage').is(':visible') && showLoding){
+                        $.bootstrapLoading.start();
+                        clearInterval(interval);
+                    }
+                    else{
+                        clearInterval(interval);
+                    }
+                }, 100);
+                CommonAjax.post("/ration/addMultiRation",{newDatas: newDatas},function (rstData) {
+                    let newNodes = [];
+                    //更新缓存
+                    for(let data of rstData){
+                        me.datas.push(data.ration);
+                        project.ration_glj.addDatasToList(data.ration_gljs);
+                        project.ration_coe.addDatasToList(data.ration_coes);
+                        project.ration_installation.addDatasToList(data.ration_installs);
+
+                        //插入树节点
+                        newSource = data.ration;
+                        newNode = project.mainTree.insert(billItemID, nextID, newSource.ID);
+                        newNodes.push(newNode);
+                        nextID = project.mainTree.selected.getNextSiblingID();
+                        newNode.source = newSource;
+                        newNode.sourceType = project.Ration.getSourceType();
+                        newNode.data = newSource;
+                        ProjectController.syncDisplayNewNode(sheetController, newNode);
+                    }
+                    project.projectGLJ.loadData(function () {
+                        for(let data of rstData){
+                            project.ration_glj.addToMainTree(data.ration_gljs);
+                        }
+                        projectObj.mainController.refreshTreeNode(newNodes, false);
+                        if(project.Bills.isFBFX(newNodes[0])) { //判断是否属于分部分项工程 ,是的话才需要做计取安装费计算
+                            project.installation_fee.calcInstallationFee(function (isChange,rations) {
+                                if(isChange){
+                                    rations = rations.concat(newNodes);
+                                    project.calcProgram.calcRationsAndSave(rations);
+                                }else {
+                                    project.calcProgram.calcRationsAndSave(newNodes);
+                                }
+                            });
+                        }else {
+                            project.calcProgram.calcNodesAndSave(newNodes);
+                        }
+                        if(callback){
+                            callback();
+                        }
+                        showLoding = false;
+                        $.bootstrapLoading.end();
+                    });
+                })
+            }
+        };
         ration.prototype.addNewRation = function (itemQuery,rationType) {
             let me = this;
             let project = projectObj.project, sheetController = projectObj.mainController;

+ 34 - 14
web/building_saas/main/js/models/ration_glj.js

@@ -640,7 +640,7 @@ var ration_glj = {
             if (selectCode == gljOprObj.getIndex(oldData, gljKeyArray)) {
                 return callback(null);
             }
-            if (oldData.createType != 'replace') {
+            if (oldData.createType == 'normal') {//只有是定额下带的工料机才需把类型改成替换,其它的保持不变
                 oldData.rcode = oldData.code;
                 oldData.createType = 'replace';
             }
@@ -669,15 +669,16 @@ var ration_glj = {
         };
 
         ration_glj.prototype.mReplaceGLJ = function (selectCode, oldData, callback) {
-            var allGLJ = gljOprObj.AllRecode;
-            var glj = _.find(allGLJ, function (item) {
-                var i_key = gljOprObj.getIndex(item, gljLibKeyArray);
+            let allGLJ = gljOprObj.AllRecode,tasks = [],updateMap={};
+            let oldIndex = gljOprObj.getIndex(oldData, gljKeyArray);
+            let glj = _.find(allGLJ, function (item) {
+                let i_key = gljOprObj.getIndex(item, gljLibKeyArray);
                 return i_key == selectCode;
             });
-            if (selectCode == gljOprObj.getIndex(oldData, gljKeyArray)) {
+            if (selectCode == oldIndex) {
                 return callback(null);
             }
-            var query = {
+            let query = {
                 projectID: oldData.projectID,
                 code: oldData.code,
                 name: oldData.name,
@@ -687,7 +688,7 @@ var ration_glj = {
             if (oldData.specs && oldData.specs != '') {
                 query.specs = oldData.specs;
             }
-            var doc = {
+            let doc = {
                 GLJID: glj.ID,
                 createType: 'replace',
                 rationItemQuantity: 0,
@@ -702,12 +703,7 @@ var ration_glj = {
                 materialType: glj.materialType,   //三材类别
                 materialCoe: glj.materialCoe,
                 projectID: oldData.projectID
-            }
-            if (oldData.createType == 'replace') {
-                doc.rcode = oldData.rcode;
-            } else {
-                doc.rcode = oldData.code;
-            }
+            };
             if (glj.hasOwnProperty("compilationId")) {
                 doc.from = "cpt";
                 if (glj.code.indexOf('-') != -1) {//这条工料机是用户通过修改包称、规格、型号等保存到补充工料机库的
@@ -716,8 +712,32 @@ var ration_glj = {
             } else {
                 doc.from = "std";
             }
+            for(let d of this.datas){//查询出所有需替换的工料机
+                let tem_index = gljOprObj.getIndex(d, gljKeyArray);
+                if(tem_index == oldIndex){
+                    let tem_doc = _.cloneDeep(doc);
+                    if(d.createType == 'replace'){
+                        tem_doc.rcode = d.rcode;
+                    }else if(d.createType == 'add'){//对于添加的类型,替换后还是添加类型
+                        tem_doc.createType = 'add';
+                    }else {
+                        tem_doc.rcode = d.code
+                    }
+                    let task = {
+                        updateOne:{
+                            filter : {ID:d.ID},
+                            update : tem_doc
+                        }
+                    };
+                    tasks.push(task);
+                    updateMap[d.ID] = tem_doc;
+                }
+            }
+
             $.bootstrapLoading.start();
-            CommonAjax.post("/rationGlj/mReplaceGLJ", {query: query, doc: doc}, callback, function () {
+            CommonAjax.post("/rationGlj/mReplaceGLJ", {query: query, doc: doc,tasks:tasks}, function (result) {
+                callback(result,updateMap);
+            }, function () {
                 $.bootstrapLoading.end();
             });
         };

+ 6 - 3
web/building_saas/main/js/views/calc_base_view.js

@@ -255,10 +255,13 @@ let calcBaseView = {
     //输入窗口控制
     inputControl: function () {
         let me = calcBaseView;
-        me.inputExpr.keydown(function (e) {
-            if(!me.arithmeticLegal(me.inputExpr.val() + e.key)){
-                return false;
+        me.inputExpr.on('input',function () {
+            if(!me.arithmeticLegal(me.inputExpr.val())){
+                if(me.preInputExpr){
+                    me.inputExpr.val(me.preInputExpr);
+                }
             }
+            me.preInputExpr = me.inputExpr.val();
         });
     },
 

+ 41 - 25
web/building_saas/main/js/views/glj_view.js

@@ -943,6 +943,8 @@ var gljOprObj = {
         }
         if ($('#actionType').val() == 'replace' || $('#actionType').val() == 'm_replace') {
             me.filterLibGLJByType();
+        }else if($('#actionType').val() == 'addMix'){
+            projectGljObject.filterLibGLJForMixRatio();
         }
         //文本筛选
         let searchStr = $('#gljSearchKeyword').val();
@@ -964,7 +966,7 @@ var gljOprObj = {
         }
     },
     setGLJSelection: function (args, newVal) {
-        if ($('#actionType').val() == 'add' || $('#actionType').val() == 'insert') {
+        if ($('#actionType').val() == 'add' || $('#actionType').val() == 'insert'|| $('#actionType').val() == 'addMix') {
             this.addGLJsSelection(args, newVal);
         } else {
             this.replaceGLJSelection(args, newVal);
@@ -1149,20 +1151,24 @@ var gljOprObj = {
         })
     },
     doMReplaceGLJ: function () {
-        var me = this;
-        var oldData = me.sheetData[gljContextMenu.selectedRow];
-        var project = projectObj.project;
-        var selectCode = me.GLJSelection[0];
+        let me = this;
+        let oldData = me.sheetData[gljContextMenu.selectedRow];
+        let project = projectObj.project;
+        let selectCode = me.GLJSelection[0];
         $("#glj_tree_div").modal('hide');
-        project.ration_glj.mReplaceGLJ(selectCode, oldData, function (result) {
-            var data = result.data;
-            var stateList = result.stateList;
-            var n_index = me.getIndex(data.query, gljKeyArray);
-            var nodes = [];
+        project.ration_glj.mReplaceGLJ(selectCode, oldData, function (result,updateMap) {
+            if(result == null){
+                return;
+            }
+            let data = result.data;
+            let stateList = result.stateList;
+            //let n_index = me.getIndex(data.query, gljKeyArray);
+            let nodes = [];
             _.forEach(project.ration_glj.datas, function (t) {
-                var t_index = me.getIndex(t, gljKeyArray);
-                if (n_index == t_index) {
+           //     let t_index = me.getIndex(t, gljKeyArray);
+                if (updateMap[t.ID]) {
                     me.updateProperty(t, data.doc);
+                    me.updateProperty(t, updateMap[t.ID]);
                     if (project.ration_glj.needShowToTree(t)) {//如果是造价书中的树节点,则也须刷新
                         project.ration_glj.transferToNodeData(t);
                         var node = project.ration_glj.findGLJNodeByID(t.ID);
@@ -1359,23 +1365,31 @@ $(function () {
             gljOprObj.gljLibSheet.name('glj_lib');
         }
         gljOprObj.gljLibSheetData = gljOprObj.AllRecode;
-        var selected = null;
-        if ($('#actionType').val() == 'add' || $('#actionType').val() == 'insert') {
+        let selections = [],selectMap = {};
+        if ($('#actionType').val() == 'add' || $('#actionType').val() == 'insert') {//插入,添加
             gljOprObj.GLJSelection = [];
-        } else {
-            selected = gljOprObj.sheetData[gljContextMenu.selectedRow];
+        } else if($('#actionType').val() =='m_replace' || $('#actionType').val() == 'replace'){//替换、批量替换
+            let selected = gljOprObj.sheetData[gljContextMenu.selectedRow];
             var connect_key = gljOprObj.getIndex(selected, gljKeyArray);
             gljOprObj.GLJSelection = [connect_key];
+            selectMap[connect_key] = true;
             gljOprObj.filterLibGLJByType();
-        }
-
-        if (selected != null) {
-            var s_key = gljOprObj.getIndex(selected, gljLibKeyArray);
-            var r = _.find(gljOprObj.gljLibSheetData, function (item) {
-                var item_key = gljOprObj.getIndex(item, gljKeyArray);
-                return s_key == item_key;
-            });
-            r ? r.select = 1 : "";
+        }else if($('#actionType').val() =='addMix'){//添加组成物
+            gljOprObj.GLJSelection = [];
+            projectGljObject.filterLibGLJForMixRatio();
+            /*selections = projectGljObject.mixRatioData;  添加组成物的时候先不选中
+            gljOprObj.GLJSelection = [];
+            for(let s of selections){
+                let s_key = gljOprObj.getIndex(s, gljKeyArray);
+                selectMap[s_key] = true;
+                gljOprObj.GLJSelection.push(s_key);
+            }*/
+        }
+        for(let item of gljOprObj.gljLibSheetData){
+            let item_key = gljOprObj.getIndex(item, gljLibKeyArray);
+            if(selectMap[item_key]){
+                item.select = 1 ;
+            }
         }
         gljOprObj.showLibGLJSheetData();
     });
@@ -1420,6 +1434,8 @@ $(function () {
             gljOprObj.doReplaceGLJ();
         } else if ($('#actionType').val() == 'm_replace') {//批量替换工料机
             gljOprObj.doMReplaceGLJ();
+        }else if($('#actionType').val() == 'addMix'){
+            projectGljObject.addMixRatio();
         }
     })
 

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

@@ -1247,6 +1247,9 @@ let installationFeeObj={
                 projectObj.project.calcProgram.calcRationsAndSave(rations);
             }
             installationFeeObj.showRationInstallationData(projectObj.project.mainTree.selected);
+            if(callback){
+                callback();
+            }
         });
     },
     initSettingRadio:function () {
@@ -1366,7 +1369,9 @@ $(function () {
         if(canChange==false){
             return;
         }
-        me.calcInstallationFee();
+        me.calcInstallationFee(function () {
+            gljOprObj.refreshView();
+        });
     });
     $('#btn_reset_to_default').click(function (){
         let ifModel =  projectObj.project.installation_fee;

+ 55 - 17
web/building_saas/main/js/views/main_tree_col.js

@@ -335,7 +335,7 @@ let MainTreeCol = {
                 case 6:
                     return '0.000000';
                 default:
-                    return '0.00';
+                    return '0';
             }
             ;
         }
@@ -354,7 +354,7 @@ let MainTreeCol = {
                 case 6:
                     return '0.######';
                 default:
-                    return '0.##';
+                    return '0';
             }
             ;
         }
@@ -399,29 +399,67 @@ let colSettingObj = {
     initSettingSpread: function () {
         this.settingSpread = SheetDataHelper.createNewSpread($('#col_setting_spread')[0], {sheetCount: 1});
         this.settingSpread.options.showScrollTip = GC.Spread.Sheets.ShowScrollTip.vertical;
+        this.settingSpread.bind(GC.Spread.Sheets.Events.ButtonClicked, function (sender, args) {
+            if(args.sheet.isEditing()){
+                args.sheet.endEdit(true);
+            }
+        });
         this.loadSetting(this.settingSpread.getActiveSheet(), projectObj.project.projSetting.main_tree_col);
+    },
+    dataChanged: function () {
+        let sheet = this.settingSpread.getActiveSheet();
+        for(let row = 0; row < sheet.getRowCount(); row++){
+            let orgData = projectObj.project.projSetting.main_tree_col.cols[row].visible;
+            let newData = sheet.getValue(row, 0);
+            if(orgData != newData){
+                return true;
+            }
+        }
+        return false;
+    },
+    updateColSetting: function () {
+        let sheet = this.settingSpread.getActiveSheet();
+         let mainSheet = projectObj.mainSpread.getActiveSheet();
+         for (let iRow = 0; iRow < sheet.getRowCount(); iRow++) {
+         projectObj.project.projSetting.main_tree_col.cols[iRow].visible = sheet.getValue(iRow, 0);
+         projectObj.project.projSetting.mainGridSetting.cols[iRow].visible = sheet.getValue(iRow, 0);
+         }
+         SheetDataHelper.massOperationSheet(mainSheet, function () {
+         SheetDataHelper.refreshColumnVisible(projectObj.project.projSetting.mainGridSetting, mainSheet);
+         //左右滚动条到最左边
+         mainSheet.showColumn(projectObj.project.projSetting.mainGridSetting.frozenCols, GC.Spread.Sheets.HorizontalPosition.left);
+         });
+         //refresh nodes to autoFitRow
+         projectObj.mainController.refreshTreeNode(projectObj.project.mainTree.roots, true);
+         projectObj.project.pushNow('editColSetting', projectObj.project.projSetting.moduleName, {
+         projectID: projectObj.project.ID(),
+         main_tree_col: projectObj.project.projSetting.main_tree_col
+         });
     }
 };
 
-$('#column').on('shown.bs.modal', function () {
+$('#poj-set').on('shown.bs.modal', function (e) {
     if (!colSettingObj.settingSpread) {
         colSettingObj.initSettingSpread();
     }
 });
 
-$('#column').on('hide.bs.modal', function () {
-    let sheet = colSettingObj.settingSpread.getActiveSheet();
-    for (let iRow = 0; iRow < sheet.getRowCount(); iRow++) {
-        projectObj.project.projSetting.main_tree_col.cols[iRow].visible = sheet.getValue(iRow, 0);
-        projectObj.project.projSetting.mainGridSetting.cols[iRow].visible = sheet.getValue(iRow, 0);
+$('#poj-set').on('hidden.bs.modal', function (e) {
+    if (colSettingObj.settingSpread) {
+        //恢复
+        let sheet = colSettingObj.settingSpread.getActiveSheet();
+        SheetDataHelper.massOperationSheet(sheet, function () {
+            for(let row = 0; row < sheet.getRowCount(); row++){
+                let orgData = projectObj.project.projSetting.main_tree_col.cols[row].visible;
+                sheet.setValue(row, 0, orgData);
+            }
+        });
+    }
+});
+
+
+$('#tab_display_setting').on('shown.bs.tab', function () {
+    if(colSettingObj.settingSpread){
+        colSettingObj.settingSpread.refresh();
     }
-    SheetDataHelper.massOperationSheet(projectObj.mainSpread.getActiveSheet(), function () {
-        SheetDataHelper.refreshColumnVisible(projectObj.project.projSetting.mainGridSetting, projectObj.mainSpread.getActiveSheet());
-    });
-    //refresh nodes to autoFitRow
-    projectObj.mainController.refreshTreeNode(projectObj.project.mainTree.roots, true);
-    projectObj.project.pushNow('editColSetting', projectObj.project.projSetting.moduleName, {
-        projectID: projectObj.project.ID(),
-        main_tree_col: projectObj.project.projSetting.main_tree_col
-    });
 });

+ 188 - 39
web/building_saas/main/js/views/project_glj_view.js

@@ -40,6 +40,7 @@ projectGljObject={
         header:[
             {headerName: "编码", headerWidth: 120, dataCode: "code", dataType: "String"},
             {headerName: "名称", headerWidth: 120, dataCode: "name", dataType: "String"},
+            {headerName: "规格型号", headerWidth: 120, dataCode: "specs", dataType: "String"},
             {headerName: "单位", headerWidth: 120, dataCode: "unit", hAlign: "center", dataType: "String"},
             {headerName: "类型", headerWidth: 120, dataCode: "short_name", hAlign: "center", dataType: "String"},
             {headerName: "定额价", headerWidth: 120, dataCode: "basePrice", hAlign: "right", dataType: "Number",decimalField:'glj.unitPrice',validator:"number"},
@@ -48,7 +49,7 @@ projectGljObject={
             {headerName: "消耗量", headerWidth: 120, dataCode: "consumption", hAlign: "right", dataType: "Number",decimalField:"glj.quantity",validator:"number"}
         ],
         view: {
-            lockColumns: [0,1,2,3,4,5,6]
+            lockColumns: [0,1,2,3,4,5,6,7]
         }
     },
     materialTreeSetting:{
@@ -136,6 +137,46 @@ projectGljObject={
     getUsedTenderInfo:function() {
         return projectGljObject.usedTenderList.join("<br>");
     },
+    filterLibGLJForMixRatio:function () {
+        let me = this;
+        if(me.selectedProjectGLJ){
+            let showTypes = [];
+            let materialArr = [202, 203, 204];//混凝土、砂浆、配合比,
+            if(me.selectedProjectGLJ.type == gljType.MAIN_MATERIAL){//对于主材,只显示没有组成物并且除了自已的主材
+                showTypes = [gljType.MAIN_MATERIAL];
+            }else if(_.includes(materialArr,me.selectedProjectGLJ.type)){//混凝土、砂浆、配合比
+                showTypes = [gljType.GENERAL_MATERIAL];
+            }else if(me.selectedProjectGLJ.type == gljType.GENERAL_MACHINE){//机械类型可添加机械组成物、机上人工
+                showTypes = [gljType.MACHINE_COMPOSITION,gljType.MACHINE_LABOUR];
+            }
+            gljOprObj.gljLibSheetData = _.filter(gljOprObj.gljLibSheetData, function (item) {
+                if(me.selectedProjectGLJ.type == gljType.MAIN_MATERIAL){
+                    let p_index = gljOprObj.getIndex(me.selectedProjectGLJ,gljKeyArray);
+                    let i_index = gljOprObj.getIndex(item,gljLibKeyArray);
+                    return item.gljType == gljType.MAIN_MATERIAL &&item.component.length == 0 && p_index!=i_index
+                }else {
+                    return _.includes(showTypes,item.gljType);
+                }
+            });
+        }
+    },
+    addMixRatio:function () {
+        let me = this, projectGLJ = projectObj.project.projectGLJ;
+        for(let mix of me.mixRatioData){
+            let m_key = gljOprObj.getIndex(mix, gljKeyArray);
+            let t_index = gljOprObj.GLJSelection.indexOf(m_key);
+            t_index != -1?gljOprObj.GLJSelection.splice(t_index,1):'';
+        }
+        projectGLJ.addMixRatio(gljOprObj.GLJSelection,function (mixRatios) {
+            me.showMixRatioData();//这里添加的组成物的消耗量默认都是0,所以对父工料机的价格不会有影响,不用触发计算
+            projectGLJ.loadData(function () {
+                me.showProjectGljData();
+                gljOprObj.showRationGLJSheetData();
+                me.onUnitFileChange(me.selectedProjectGLJ);
+            });
+
+        });
+    },
     showMixRatioData:function () {
         let me = this,gljId = null,gljType = null;
         let sheet = me.projectGljSpread.getActiveSheet();
@@ -218,7 +259,7 @@ projectGljObject={
         }
         if(dataCode=='basePrice'||dataCode=='marketPrice'||dataCode=='supply'){//有组成物时,市场单价、定额价、供货方式不能修改
             if (data.ratio_data  && data.ratio_data.length > 0){
-               return false;
+                return false;
             }
             if(dataCode=='basePrice'&&data.is_add!=1){//如果不是新增,定额价不可修改。
                 return false;
@@ -226,7 +267,7 @@ projectGljObject={
         }
         if(dataCode == 'supply_quantity'){
             if (data.supply != 1) {// 如果为部分甲供则甲供数量需要可编辑,其它的都不能编辑
-               return false;
+                return false;
             }
         }
         if(dataCode == 'materialCoe'){//三材类别为空时,三材系数应只读,不允许输入。
@@ -269,7 +310,7 @@ projectGljObject={
             changeInfo.push({row:c.row,col:c.col,value:value});
             if(me.projectGljEditChecking(c.row,c.col)==false){//如果不能编辑
                 canChange = false;
-             }
+            }
             if (canChange==true&&!me.checkData(c.col,me.projectGljSetting,value)) {
                 alert('输入的数据类型不对,请重新输入!');
                 canChange = false;
@@ -278,7 +319,7 @@ projectGljObject={
         if(canChange == false){//恢复原来的值
             info.sheetName =="materialTreeSheet"?me.showMaterialTreeData():me.showProjectGljData();
         }else if(info.sheetName =="projectGljSheet"){
-             me.batchUpdatePrice(changeInfo);
+            me.batchUpdatePrice(changeInfo);
         }
     },
     batchUpdatePrice(changeInfo){
@@ -293,6 +334,7 @@ projectGljObject={
     showProjectGljData:function () {
         this.projectGljSpread.setActiveSheetIndex(0);
         let sel = this.projectGljSheet.getSelections()[0];
+        let oldData = sel.row<this.projectGljSheetData.length?this.projectGljSheetData[sel.row]:'';
         let projectGljSheetData = [];
         let gljList = projectObj.project.projectGLJ.datas.gljList;
         gljList = this.filterProjectGLJ(gljList);
@@ -304,15 +346,19 @@ projectGljObject={
         this.projectGljSheet.setRowCount(0);
         sheetCommonObj.showData(this.projectGljSheet, this.projectGljSetting,this.projectGljSheetData);
         this.projectGljSheet.setRowCount(this.projectGljSheetData.length);
+        sel.row = _.findIndex(this.projectGljSheetData,{'id':oldData.id});
         this.projectGljSheet.setSelection(sel.row==-1?0:sel.row,sel.col,sel.rowCount,sel.colCount);
     },
     showMaterialTreeData:function () {
         this.projectGljSpread.setActiveSheetIndex(1);
         let sel = this.materialTreeSheet.getSelections()[0];
+        let oldNodeID = this.materialTree.selected?this.materialTree.selected.data.id:"";
         let gljList = projectObj.project.projectGLJ.datas.gljList;
         gljList = _.sortByAll(gljList, [ 'code']);
         this.createMaterialTree(gljList);
         this.materialTreeController.showTreeData();
+        let newNode = this.materialTree.getNodeByID(oldNodeID);
+        sel.row = newNode?newNode.serialNo():-1;
         this.materialTreeSheet.setSelection(sel.row==-1?0:sel.row,sel.col,sel.rowCount,sel.colCount);
         this.materialTreeController.setTreeSelected(this.materialTree.items[sel.row==-1?0:sel.row]);
     },
@@ -558,11 +604,12 @@ projectGljObject={
         let prow = parentSheet.getActiveRowIndex();//取父机械或组成物的下标
         let prowData = parentSheet.name() == 'projectGljSheet'?me.projectGljSheetData[prow]:me.materialTree.items[prow].data;
         composition.updateConsumption(updateData,recode,prowData.id,function (sid) {
-           /* if(parentSheet.name() == 'projectGljSheet'){ 之前是单行刷新,父工料机与组成物对应的工料机分开刷,发现这样比整个刷新慢所以先整个刷新,当以后数据量大的时候再测试
-                me.refreshProjectGljRowByID(sid);
-            }*/
+            /* if(parentSheet.name() == 'projectGljSheet'){ 之前是单行刷新,父工料机与组成物对应的工料机分开刷,发现这样比整个刷新慢所以先整个刷新,当以后数据量大的时候再测试
+             me.refreshProjectGljRowByID(sid);
+             }*/
             projectObj.project.projectGLJ.calcQuantity();
             me.refreshParentData(prow,prowData.id,sid);
+            me.onUnitFileChange(recode);
         });
     },
     refreshParentData:function (row,pid,sid) {
@@ -571,11 +618,14 @@ projectGljObject={
         let parantData = null;
         if(sheet.name() == 'projectGljSheet'){
             me.showProjectGljData();// me.refreshProjectGljRow(row)  这里原来是分开刷新的,现在整个统一刷新,先留着
-            parantData = me.projectGljSheetData[row];
+            //parantData = _.find();  //me.projectGljSheetData[row];
         }else {
             me.showMaterialTreeData();
-            parantData = me.materialTree.items[row].data;
+            //parantData = me.materialTree.items[row].data;
         }
+        let pglj =  _.find(projectObj.project.projectGLJ.datas.gljList,{'id':pid});
+        parantData = pglj?me.getSheetDataByGLJ(pglj):null;
+        //projectObj.project.projectGLJ.datas.gljList
 
         // 更新组成物缓存
         projectObj.project.composition.loadData();
@@ -593,7 +643,7 @@ projectGljObject={
         for(let r of rations){
             let r_node = projectObj.project.mainTree.getNodeByID(r.ID);
             if(r_node){
-                r_node.data.marketUnitFee =  parantData.marketPrice;//parentMarketPrice;//这里用显示的价格
+                r_node.data.marketUnitFee = parantData?parantData.marketPrice:'';//parentMarketPrice;//这里用显示的价格
                 updateNodes.push(r_node);
             }
         }
@@ -604,10 +654,15 @@ projectGljObject={
         if(updateNodes.length>0){
             projectObj.project.calcProgram.calcRationsAndSave(updateNodes,function () {
                 projectObj.mainController.refreshTreeNode(projectObj.project.mainTree.roots);
+                installationFeeObj.calcInstallationFee();//计算安装增加费
             });
         }
         gljOprObj.refreshView();
     },
+    onUnitFileChange:function (data) {
+        socket.emit('unitFileChangeNotify', JSON.stringify(data));
+        projectObj.project.markUpdateProject({projectID:projectObj.project.ID(),'unitFileID':socketObject.getUnitFileRoomID()},"unitFile");
+    },
     deleteMixRatio:function (row) {
         let me = this, deleteRecode = me.mixRatioData[row];
         let consumption = deleteRecode.consumption;
@@ -619,6 +674,7 @@ projectGljObject={
         projectObj.project.composition.deleteComposition(updateData,deleteRecode,prowData.id,function () {
             me.refreshParentData(prow,prowData.id);
             me.mixRatioSheet.deleteRows(row,1);
+            me.onUnitFileChange(deleteRecode);
         });
     },
     getCompositionSumPrice : function(scene, affectRow, newValue = 0) {
@@ -683,7 +739,6 @@ projectGljObject={
             value= scMathUtil.roundForObj(value,getDecimal('glj.unitPrice'));//修改市场价和修改定额价时需要重新记算很多受影响的树节点,现在改成与定字额工料机那里调相同的方法。
             let editField = dataCode === 'basePrice'?"base_price":"market_price";
             projectObj.project.projectGLJ.updatePrice(recode,editField,value,'pg',callback);
-
         }else {
             let extend = {};
             // 如果是供货方式则需要处理数据
@@ -745,6 +800,22 @@ projectGljObject={
         }
         return result;
     },
+    getProjectGLJSelected:function () {
+        let me = projectGljObject;
+        let sheet = me.projectGljSpread.getActiveSheet();
+        let selectedProjectGLJ = null;
+        if(sheet.name() == 'projectGljSheet'){//projectGljSheet/materialSheet 工料机汇总和三材汇总表
+            let sel = me.projectGljSheet.getSelections()[0];
+            if(sel.row != -1 && me.projectGljSheetData.length>sel.row){
+                selectedProjectGLJ = me.projectGljSheetData[sel.row]
+            }
+        }else if(sheet.name() == 'materialTreeSheet' ){
+            if(me.materialTree.selected){
+                selectedProjectGLJ = me.materialTree.selected.data;
+            }
+        }
+        return selectedProjectGLJ;
+    },
     initRightClick : function() {
         let activeSheet = this.mixRatioSheet;
         let me = this;
@@ -767,6 +838,18 @@ projectGljObject={
                         me.deleteMixRatio(row);
                     }
                 },
+                "addMixRatio":{
+                    name: '添加',
+                    icon: 'fa-sign-in',
+                    disabled: function () {
+                        let projectGLJ = projectGljObject.getProjectGLJSelected();
+                        return !_.includes(compositionTypes,projectGLJ.type);
+                    },
+                    callback: function (key, opt) {
+                        me.selectedProjectGLJ = projectGljObject.getProjectGLJSelected();
+                        getGLJData('addMix');
+                    }
+                }
             }
         });
     },
@@ -788,13 +871,28 @@ projectGljObject={
     },
     calcPartASupplyFeeByProjectGLJs: function (projectGLJsArr) {
         for (let pGLJ of projectGLJsArr){
-              if (pGLJ.supply == supplyType.BFJG){
-                  let rations = calcTools.getRationsByProjectGLJ(pGLJ.id);
-                  projectObj.project.calcProgram.calcNodesAndSave(rations, function () {
-                      projectObj.mainController.refreshTreeNode(projectObj.project.mainTree.roots);
-                  });
-              }
+            if (pGLJ.supply == supplyType.BFJG){
+                let rations = calcTools.getRationsByProjectGLJ(pGLJ.id);
+                projectObj.project.calcProgram.calcNodesAndSave(rations, function () {
+                    projectObj.mainController.refreshTreeNode(projectObj.project.mainTree.roots);
+                });
+            }
         }
+    },
+    checkUnitFileName:function (name,callback) {
+        let projectGLJ = projectObj.project.projectGLJ;
+        projectGLJ.checkUnitFileName(name,function (data) {
+            if(data){
+                $("#save-as-tips").text('已存在同名单价文件').show();
+                $('#save-as-confirm').attr("disabled","disabled");
+            }else {
+                $("#save-as-tips").hide();
+                $('#save-as-confirm').removeAttr("disabled");
+                if(callback){
+                    callback();
+                }
+            }
+        });
     }
 };
 
@@ -840,23 +938,23 @@ $(function () {
         me.refreshDataSheet();
         loadProjectGljSize();
     });
-  /*  $('#ration_link').on('shown.bs.tab', function (e) {
-        let me = projectGljObject;
-        me.showTag='ration';
-        me.showProjectGljData();
-    });
-    $('#mix_ratio_link').on('shown.bs.tab', function (e) {
-        let me = projectGljObject;
-        me.showTag='mixRatio';
-        me.showProjectGljData();
-        me.initMixRatio();
-    });
-    $('#machine_ratio_link').on('shown.bs.tab', function (e) {
-        let me = projectGljObject;
-        me.showTag='machine';
-        me.showProjectGljData();
-        me.initMixRatio();
-    });*/
+    /*  $('#ration_link').on('shown.bs.tab', function (e) {
+     let me = projectGljObject;
+     me.showTag='ration';
+     me.showProjectGljData();
+     });
+     $('#mix_ratio_link').on('shown.bs.tab', function (e) {
+     let me = projectGljObject;
+     me.showTag='mixRatio';
+     me.showProjectGljData();
+     me.initMixRatio();
+     });
+     $('#machine_ratio_link').on('shown.bs.tab', function (e) {
+     let me = projectGljObject;
+     me.showTag='machine';
+     me.showProjectGljData();
+     me.initMixRatio();
+     });*/
     $('#pop-used-list').popover({
             placement: "bottom",
             html: true,
@@ -879,6 +977,7 @@ $(function () {
                     return false;
                 }
                 let data = response.data;
+                projectGljObject.changeInfo = data;
                 $("#current-project-name").text(data.currentProjectName);
                 // 本项目中的单价文件
                 if (data.self.length > 0) {
@@ -915,14 +1014,24 @@ $(function () {
         let type = $("input[name='change-type']:checked").val();
         type = parseInt(type);
         let changeUnitPriceId = 0;
+        $('#change-unitFile').modal("hide");
         if (type === 0) {
             // 从本项目中选择
             changeUnitPriceId = $("#self-file").val();
         } else {
             // 从其他项目中复制
             changeUnitPriceId = $("#other-file").val();
+            let newName = $("#other-file").children("option:selected").text();
+            let currentOption = _.find(projectGljObject.changeInfo.self,{name:newName});
+            if(currentOption){ //存在则说明有重名的文件
+                //rename-unitFile
+                $("#rename-unitFile").modal({show:true});
+                $("#newUnitFileID").val(changeUnitPriceId);
+                $("#newUnitFileName").val(newName);
+                return;
+            }
+
         }
-        $('#change-unitFile').modal("hide");
         let data = {project_id: scUrlUtil.GetQueryString('project'), change_id: changeUnitPriceId, type: type};
         projectObj.project.projectGLJ.changeFile(data,function () {
             projectGljObject.changeFileCallback();
@@ -942,6 +1051,7 @@ $(function () {
     $("#unitFile-save-as").on('shown.bs.modal', function () {
         // 获取当前建设项数据
         $("#save-as-name").val(projectGljObject.usedUnitPriceInfo.name + '副本');
+        projectGljObject.checkUnitFileName(projectGljObject.usedUnitPriceInfo.name + '副本');
     });
 
     // 从其他建设项目中复制 选择建设项目
@@ -957,17 +1067,56 @@ $(function () {
         $("#other-file").html(otherFileHtml);
     });
 
+    $('#save-as-name').change(function () {
+        projectGljObject.checkUnitFileName(this.value);
+    });
+
+    $('#newUnitFileName').change(function () {
+        let projectGLJ = projectObj.project.projectGLJ;
+        projectGLJ.checkUnitFileName(this.value,function (data) {
+            if(data){
+                $("#renameError_unitFile").text('已存在同名单价文件').show();
+                $('#renameUnitFileConfirm').attr("disabled","disabled");
+            }else {
+                $("#renameError_unitFile").hide();
+                $('#renameUnitFileConfirm').removeAttr("disabled");
+            }
+        });
+
+    });
+    $("#renameUnitFileConfirm").click(function () {
+        let projectGLJ = projectObj.project.projectGLJ;
+        let newName = $('#newUnitFileName').val();
+        let changeUnitPriceId = $('#newUnitFileID').val();
+        projectGLJ.checkUnitFileName(newName,function (data) {
+            if(data){
+                $("#renameError_unitFile").text('已存在同名单价文件').show();
+                $('#renameUnitFileConfirm').attr("disabled","disabled");
+            }else {
+                $("#renameError_unitFile").hide();
+                $('#renameUnitFileConfirm').removeAttr("disabled");
+                let data = {project_id: scUrlUtil.GetQueryString('project'), change_id: changeUnitPriceId, type: 1,newName:newName};
+                projectObj.project.projectGLJ.changeFile(data,function () {
+                    projectGljObject.changeFileCallback();
+                })
+            }
+        });
+    });
+
     // 单价文件另存为操作
     $("#save-as-confirm").click(function () {
+        let projectGLJ = projectObj.project.projectGLJ;
         let name = $("#save-as-name").val();
         if (name === '') {
             $("#save-as-tips").text('请填写单价文件名称').show();
             return false;
         }
         let saveData = {name: name, project_id: scUrlUtil.GetQueryString('project')};
-        projectObj.project.projectGLJ.saveAs(saveData,function () {
-             projectGljObject.changeFileCallback();
-            $("#unitFile-save-as").modal("hide");
+        projectGljObject.checkUnitFileName(name,function () {
+            projectGLJ.saveAs(saveData,function () {
+                projectGljObject.changeFileCallback();
+                $("#unitFile-save-as").modal("hide");
+            });
         });
     });
 

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

@@ -31,12 +31,14 @@ var projectInfoObj = {
         CommonAjax.post('/pm/api/getProject', {"user_id": userID, "proj_id": scUrlUtil.GetQueryString('project')}, function (data) {
             if (data) {
                 that.projectInfo = data;
+                console.log(that.projectInfo);
                 //init decimal
                 setDecimal(decimalObj, data.property.decimal);
                 billsQuanDecimal.datas = data.property.billsQuantityDecimal || [billsDecimalView.angleDecimal];
                 basicInfoView.orgDatas = data.property.basicInformation ? basicInfoView.toViewDatas(data.property.basicInformation) : [];
                 projFeatureView.orgDatas = data.property.projectFeature ? projFeatureView.toViewDatas(data.property.projectFeature) : [];
                 $('#fullpath').html(that.getFullPathHtml(that.projectInfo));
+
             }
         });
     }

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

@@ -75,11 +75,11 @@ var projectObj = {
             if(node.sourceType !== that.project.Bills.getSourceType()){//焦点行是定额/量价/工料机,灰显。
                 return false;
             }else {
-                if(node.data.type == billType.FX){//是分项,灰显。
+                if(node.data.type == billType.FX || node.data.type == billType.BX){//是分项,或者补项灰显。
                     return false;
                 }
                 if(node.data.type == billType.FB&&node.nextSibling&&node.children.length>0){//焦点行是分部有后兄弟,有子项.
-                     if(node.children[0].data.type==billType.FX){ //焦点行子项是分项
+                     if(node.children[0].data.type==billType.FX || node.children[0].data.type==billType.BX){ //焦点行子项是分项
                          return false;
                      }
                 }
@@ -107,7 +107,7 @@ var projectObj = {
             if(node.sourceType !== that.project.Bills.getSourceType()) {//焦点行是定额/量价/工料机,灰显。
                 return false;
             }else {
-                if(node.data.type == billType.FX){//是分项,灰显。
+                if(node.data.type == billType.FX || node.data.type == billType.BX){//是分项,灰显。
                     return false;
                 }
                 if(!node.preSibling){//无前兄弟,灰显
@@ -116,7 +116,7 @@ var projectObj = {
                     return false
                 }
                 if(node.preSibling.children.length>0){//前兄弟有子项,子项是分项,灰显。
-                    if(node.data.type==billType.FB&&node.preSibling.children[0].data.type==billType.FX){//焦点行是分部前兄弟有子项,子项是分项,灰显。
+                    if(node.data.type==billType.FB&&(node.preSibling.children[0].data.type==billType.FX||node.preSibling.children[0].data.type==billType.BX)){//焦点行是分部前兄弟有子项,子项是分项,灰显。
                         return false;
                     }
                     if(node.data.type==billType.BILL&&node.preSibling.children[0].sourceType !== that.project.Bills.getSourceType()){//焦点行是清单,子项不是清单
@@ -638,9 +638,9 @@ var projectObj = {
                     // 综合单价、综合合价,小数部分应补0对齐。  CSLAAAAA
                     // if (col.data.field.hasSubStr("common")){
                         if (col.data.field.hasSubStr(".totalFee"))
-                            col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.totalPrice, true)
+                            col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.totalPrice, true);
                         else if (col.data.field.hasSubStr(".unitFee"))
-                            col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.unitPrice, true)
+                            col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.unitPrice, true);
                     // }
 
                 });
@@ -1100,11 +1100,12 @@ var projectObj = {
     },
 
     //根据节点获取行style(颜色、字体加粗)
-    getNodeColorStyle: function (sheet, node, colSetting = null) {
+    getNodeColorStyle: function (sheet, node, tree) {
         let colorSetting = optionsOprObj.getOption(optionsOprObj.optionsTypes.COLOROPTS);
         let mapping = {DEFAULT: 'DEFAULT', SELECTED: 'SELECTED', DXFY: 'DXFY', FB: 'FB', UNLEAFBILL: 'UNLEAFBILL',
             FX: 'FX', BX: 'BX', UNCBBILL: 'UNCBBILL', CBBILL: 'CBBILL', ZCSB: 'ZCSB'};
         let styleMap = null;
+        tree?'':tree =  this.project.mainTree;
         //中文字段名,由于同一节点中,中文字体大小和数字字体大小不同
         if(colorSetting == null){
             return null;
@@ -1187,7 +1188,7 @@ var projectObj = {
             }*/
         }
         //选中行-替换底色
-        if(node === this.project.mainTree.selected){
+        if(node === tree.selected){
              style.backColor = colorSetting[mapping.SELECTED]['backColor'];
         }
         style.borderLeft = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
@@ -1225,12 +1226,12 @@ var projectObj = {
         return style;
     },
    //设置节点style
-    setNodesStyle: function (sheet, nodes) {
+    setNodesStyle: function (sheet, nodes,tree) {
         let me = this;
         TREE_SHEET_HELPER.massOperationSheet(sheet, function () {
             for(let node of nodes){
                 if(node && node.serialNo()!= -1){
-                    sheet.getRange(node.serialNo(), -1, 1, -1).backColor(me.getNodeColorStyle(sheet, node).backColor);
+                    sheet.getRange(node.serialNo(), -1, 1, -1).backColor(me.getNodeColorStyle(sheet, node,tree).backColor);
                 }
             }
         });
@@ -1525,6 +1526,10 @@ $('#property_ok').click(function () {
     }
     // 呈现选项
     projDisplayView.updateChecking(properties);
+    //列设置(独立逻辑,只是通过项目属性确定按钮触发)
+    if(colSettingObj.dataChanged()){
+        colSettingObj.updateColSetting();
+    }
 
     if(calcOptions.updateChecking(properties)){
         reCalcRations = true;

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

@@ -14,7 +14,11 @@ sideResizeEles.nav = null;
 slideResize(sideResizeEles, {min: 250, max: $('#zaojiashu').width()-260}, 'width', function(){
     projectObj.refreshMainSpread();
     refreshSubSpread();
-    if(sideResizeEles.id === 'stdRationTab'){
+    console.log(sideResizeEles.id);
+    if(sideResizeEles.id === 'stdBillsGuidanceTab'){
+        billsGuidance.refreshWorkBook();
+    }
+    else if(sideResizeEles.id === 'stdRationTab'){
         rationLibObj.refreshSpread();
     }
     else{
@@ -75,6 +79,7 @@ var sideToolsObj = {
             tabPanel.hide();
         }
         autoFlashHeight();
+        billsGuidance.refreshWorkBook();
         billsLibObj.refreshBillsSpread();
         refreshSubSpread();
         billsLibObj.refreshBillsRelaSpread();

+ 607 - 0
web/building_saas/main/js/views/std_billsGuidance_lib.js

@@ -0,0 +1,607 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/6/11
+ * @version
+ */
+
+const billsGuidance = (function () {
+
+    const libSel = $('#stdBillsGuidanceLibSelect');
+    //工作内容
+    let stdBillsJobData = [];
+    //项目特征
+    let stdBillsFeatureData = [];
+    const bills = {
+        dom: $('#billsGuidance_bills'),
+        workBook: null,
+        cache: [],
+        tree: null,
+        controller: null,
+        treeSetting: {
+            treeCol: 0,
+            emptyRows: 0,
+            headRows: 1,
+            headRowHeight: [40],
+            defaultRowHeight: 21,
+            cols: [{
+                width: 200,
+                readOnly: true,
+                head: {
+                    titleNames: ["项目编码"],
+                    spanCols: [1],
+                    spanRows: [1],
+                    vAlign: [1],
+                    hAlign: [1],
+                    font: ["Arial"]
+                },
+                data: {
+                    field: "code",
+                    vAlign: 1,
+                    hAlign: 0,
+                    font: "Arial"
+                }
+            }, {
+                width: 200,
+                readOnly: true,
+                head: {
+                    titleNames: ["项目名称"],
+                    spanCols: [1],
+                    spanRows: [1],
+                    vAlign: [1],
+                    hAlign: [1],
+                    font: ["Arial"]
+                },
+                data: {
+                    field: "name",
+                    vAlign: 1,
+                    hAlign: 0,
+                    font: "Arial"
+                }
+            }]
+        },
+        headers: [
+            {name: '项目编码', dataCode: 'code', width: 200, vAlign: 'center', hAlign: 'left', formatter: '@'},
+            {name: '项目名称', dataCode: 'name', width: 200, vAlign: 'center', hAlign: 'left', formatter: '@'}
+        ],
+        events: {
+            SelectionChanging: function (sender, info) {
+                billsInitSel(info.newSelections[0].row);
+            },
+            CellDoubleClick: function (sender, args) {
+                let node = bills.tree.items[args.row];
+                if(!node){
+                    return;
+                }
+                if(node.children.length === 0){
+                    //插入清单
+                    let insert = billsLibObj.insertBills(stdBillsJobData, stdBillsFeatureData, node);
+                    if(insert){
+                        //插入选中的定额
+                        let addRationDatas = getInsertRationData(getCheckedRows());
+                        insertRations(addRationDatas);
+                    }
+                }
+                else {
+                    node.setExpanded(!node.expanded);
+                    //设置展开收起状态
+                    sessionStorage.setItem('stdBillsGuidanceExpState', bills.tree.getExpState(bills.tree.items));
+                    renderSheetFunc(args.sheet, function () {
+                        let iCount = node.posterityCount(), i, child;
+                        for (i = 0; i < iCount; i++) {
+                            child = bills.tree.items[args.row + i + 1];
+                            args.sheet.setRowVisible(args.row + i + 1, child.visible, args.sheetArea);
+                        }
+                        args.sheet.invalidateLayout();
+                    });
+                    args.sheet.repaint();
+                }
+            }
+        }
+    };
+    //项目指引类型
+    const itemType = {
+        job: 0,
+        ration: 1
+    };
+    const guideItem = {
+        dom: $('#billsGuidance_items'),
+        workBook: null,
+        tree: null,
+        controller: null,
+        treeSetting: {
+            treeCol: 0,
+            emptyRows: 0,
+            headRows: 1,
+            headRowHeight: [40],
+            defaultRowHeight: 21,
+            cols: [{
+                width: 300,
+                readOnly: false,
+                head: {
+                    titleNames: ["项目指引"],
+                    spanCols: [1],
+                    spanRows: [1],
+                    vAlign: [1],
+                    hAlign: [1],
+                    font: ["Arial"]
+                },
+                data: {
+                    field: "name",
+                    vAlign: 1,
+                    hAlign: 0,
+                    font: "Arial"
+                }
+            },
+            {
+                width: 50,
+                readOnly: false,
+                head: {
+                    titleNames: ["选择"],
+                    spanCols: [1],
+                    spanRows: [1],
+                    vAlign: [1],
+                    hAlign: [1],
+                    font: ["Arial"]
+                },
+                data: {
+                    field: "select",
+                    vAlign: 1,
+                    hAlign: 1,
+                    font: "Arial"
+                }
+            }
+            ]
+        },
+        headers: [
+            {name: '项目指引', dataCode: 'name', width: 300, vAlign: 'center', hAlign: 'left', formatter: '@'},
+            {name: '选择', dataCode: 'select', width: 50, vAlign: 'center', hAlign: 'center', formatter: '@'},
+        ],
+        events: {
+            EditStarting: function (sender, args) {
+                if(guideItem.headers[args.col]['dataCode'] === 'name'){
+                    args.cancel = true;
+                }
+            },
+            ButtonClicked: function (sender, args) {
+                if(args.sheet.isEditing()){
+                    args.sheet.endEdit(true);
+                }
+            },
+            CellDoubleClick: function (sender, args) {
+                if(!bills.tree.selected){
+                    return;
+                }
+                let node = bills.tree.selected.guidance.tree.selected;
+                if(!node){
+                    return;
+                }
+                if(node.children.length === 0){
+                    if(guideItem.headers[args.col]['dataCode'] === 'name'){
+                        insertRations(getInsertRationData([args.row]));
+                    }
+                }
+                else {
+                    node.setExpanded(!node.expanded);
+                    renderSheetFunc(args.sheet, function () {
+                        let iCount = node.posterityCount(), i, child;
+                        for (i = 0; i < iCount; i++) {
+                            child = bills.tree.selected.guidance.tree.items[args.row + i + 1];
+                            args.sheet.setRowVisible(args.row + i + 1, child.visible, args.sheetArea);
+                        }
+                        args.sheet.invalidateLayout();
+                    });
+                    args.sheet.repaint();
+                }
+            }
+        }
+    };
+    const options = {
+        workBook: {
+            tabStripVisible:  false,
+            allowContextMenu: false,
+            allowCopyPasteExcelStyle : false,
+            allowExtendPasteRange: false,
+            allowUserDragDrop : false,
+            allowUserDragFill: false,
+            scrollbarMaxAlign : true
+        },
+        sheet: {
+            protectionOptions: {allowResizeRows: true, allowResizeColumns: true},
+            clipBoardOptions: GC.Spread.Sheets.ClipboardPasteOptions.values
+        }
+    };
+    //渲染时方法,停止渲染
+    //@param {Object}sheet {Function}func @return {void}
+    function renderSheetFunc(sheet, func){
+        sheet.suspendEvent();
+        sheet.suspendPaint();
+        if(func){
+            func();
+        }
+        sheet.resumeEvent();
+        sheet.resumePaint();
+    }
+    //设置表选项
+    //@param {Object}workBook {Object}opts @return {void}
+    function setOptions (workBook, opts) {
+        for(let opt in opts.workBook){
+            workBook.options[opt] = opts.workBook[opt];
+        }
+        for(let opt in opts.sheet){
+            workBook.getActiveSheet().options[opt] = opts.sheet[opt];
+        }
+    }
+    //建表头
+    //@param {Object}sheet {Array}headers @return {void}
+    function buildHeader(sheet, headers) {
+        let fuc = function () {
+            sheet.setColumnCount(headers.length);
+            sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
+            for(let i = 0, len = headers.length; i < len; i++){
+                sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
+                sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
+                if(headers[i].formatter){
+                    sheet.setFormatter(-1, i, headers[i].formatter);
+                }
+                sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]);
+                sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]);
+            }
+        };
+        renderSheetFunc(sheet, fuc);
+    }
+    //表监听事件
+    //@param {Object}workBook @return {void}
+    function bindEvent(workBook, events) {
+        if(Object.keys(events).length === 0){
+            return;
+        }
+        const Events = GC.Spread.Sheets.Events;
+        for(let event in events){
+            workBook.bind(Events[event], events[event]);
+        }
+    }
+    //建表
+    //@param {Object}module @return {void}
+    function buildSheet(module) {
+        if(!module.workBook){
+            module.workBook = new GC.Spread.Sheets.Workbook(module.dom[0], {sheetCount: 1});
+            let sheet = module.workBook.getActiveSheet();
+            if(module === bills){
+                //默认初始可控制焦点在清单表中
+                module.workBook.focus();
+                sheet.options.isProtected = true;
+                sheet.name('stdBillsGuidance_bills');
+            }
+            if(module === guideItem){
+                sheet.options.isProtected = true;
+                sheet.getRange(-1, 1, -1, 1).locked(false);
+                sheet.getRange(-1, 0, -1, 1).locked(true);
+            }
+            setOptions(module.workBook, options);
+            buildHeader(module.workBook.getActiveSheet(), module.headers);
+            bindEvent(module.workBook, module.events);
+        }
+    }
+    //清空表数据
+    //@param {Object}sheet {Array}headers {Number}rowCount @return {void}
+    function cleanData(sheet, headers, rowCount){
+        renderSheetFunc(sheet, function () {
+            sheet.clear(-1, 0, -1, headers.length, GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
+            if (rowCount > 0) {
+                sheet.setRowCount(rowCount);
+            }
+        });
+    }
+    //初始化各工作表
+    //@param {Array}modules @return {void}
+    function initWorkBooks(modules){
+        for(let module of modules){
+            buildSheet(module);
+        }
+    }
+    //初始化并输出树
+    //@param {Object}module {Object}sheet {Object}treeSetting {Array}datas
+    function initTree(module, sheet, treeSetting, datas){
+        module.tree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true});
+        module.controller = TREE_SHEET_CONTROLLER.createNew(module.tree, sheet, treeSetting);
+        module.tree.loadDatas(datas);
+        if(module === bills){
+            initExpandStat();
+        }
+        module.controller.showTreeData();
+    }
+    //项目指引表焦点控制
+    //@param {Number}row @return {void}
+    function guideItemInitSel(row){
+        let billsNode = bills.tree.selected;
+        let node = null;
+        if(billsNode && billsNode.guidance.tree){
+            node = billsNode.guidance.tree.items[row];
+            if(node){
+                billsNode.guidance.tree.selected = node;
+            }
+        }
+    }
+    //根据项目指引的类型设置单元格类型,定额类型的项目指引为复选框
+    //@param {Array}nodes @return {void}
+    function setItemCellType(nodes){
+        //设置单元格类型
+        const base = new GC.Spread.Sheets.CellTypes.Base();
+        const checkBox = new GC.Spread.Sheets.CellTypes.CheckBox();
+        const sheet = guideItem.workBook.getActiveSheet();
+        renderSheetFunc(sheet, function(){
+            for(let node of nodes){
+                sheet.setCellType(node.serialNo(), 1, node.data.type === itemType.ration ?  checkBox : base);
+            }
+        });
+    }
+    //清单表焦点控制
+    //@param {Number}row @return {void}
+    function billsInitSel(row){
+        let guideSheet = guideItem.workBook.getActiveSheet();
+        cleanData(guideSheet, guideItem.headers, -1);
+        let node = bills.tree.items[row];
+        if(!node){
+            return;
+        }
+        bills.tree.selected = node;
+        if(!node.guidance.tree){
+            CommonAjax.post('/billsGuidance/api/getItemsByBills', {guidanceLibID: libSel.val(), billsID: node.getID()}, function (rstData) {
+                initTree(node.guidance, guideSheet, guideItem.treeSetting, rstData);
+                setItemCellType(node.guidance.tree.items);
+                //项目指引初始焦点
+                guideItemInitSel(guideSheet.getActiveRowIndex() ? guideSheet.getActiveRowIndex() : 0);
+            });
+        }
+        else{
+            node.guidance.controller.showTreeData();
+            setItemCellType(node.guidance.tree.items);
+            //项目指引初始焦点
+            guideItemInitSel(guideSheet.getActiveRowIndex() ? guideSheet.getActiveRowIndex() : 0);
+        }
+    }
+    //初始化清单的工作内容和项目特征
+    //@param {Number}billsLibId @return {void}
+    function initJobAndCharacter(billsLibId){
+        CommonAjax.post('/stdBillsEditor/getJobContent', {userId: userID, billsLibId: billsLibId}, function (datas) {
+            stdBillsJobData = datas;
+        });
+        CommonAjax.post('/stdBillsEditor/getItemCharacter', {userId: userID, billsLibId: billsLibId}, function (datas) {
+            stdBillsFeatureData = datas;
+        });
+    }
+    //初始化清单展开收起状态
+    //@return {void}
+    function initExpandStat(){
+        //读取展开收起状态
+        let currentExpState = sessionStorage.getItem('stdBillsGuidanceExpState');
+        if(currentExpState){
+            bills.tree.setExpandedByState(bills.tree.items, currentExpState);
+        }
+        //非叶子节点默认收起
+        else{
+            bills.tree.setRootExpanded(bills.tree.roots, false);
+        }
+    }
+    //初始选择清单指引库
+    //@param {Number}libID @return {void}
+    function libInitSel(libID){
+        //获取清单
+        CommonAjax.post('/billsGuidance/api/getLibWithBills', {libID: libID}, function(rstData){
+            //获取清单库中的工作内容和项目特征
+            initJobAndCharacter(rstData.guidanceLib.billsLibId);
+            initTree(bills, bills.workBook.getActiveSheet(), bills.treeSetting, rstData.bills);
+            //每一棵项目指引树挂在清单节点上
+            for(let node of bills.tree.items){
+                node.guidance = {tree: null, controller: null};
+            }
+            //默认初始节点
+            billsInitSel(0);
+        });
+    }
+    //初始化清单指引库
+    //@param {Array}libDats @return {void}
+    function initLibs(libDatas){
+        libSel.empty();
+        let selectedLib = sessionStorage.getItem('stdBillsGuidance');
+        for(let libData of libDatas){
+            let opt = $('<option>').val(libData.id).text(libData.name);
+            if(selectedLib && libData.id == selectedLib){
+                opt.attr('selected', 'selected');
+            }
+            libSel.append(opt);
+        }
+        //初始默认选择
+        libInitSel(libSel.select().val());
+    }
+    //初始化视图
+    //@param {void} @return {void}
+    function initViews(){
+        let modules = [bills, guideItem];
+        initWorkBooks(modules);
+
+    }
+    //获取选中的行
+    //@return {Array}
+    function getCheckedRows(){
+        let rst = [];
+        let itemSheet = guideItem.workBook.getActiveSheet();
+        for(let row = 0; row < itemSheet.getRowCount(); row++){
+            let rowV = itemSheet.getValue(row, 1);
+            if(rowV){
+                rst.push(row);
+            }
+        }
+        return rst;
+    }
+    //获取选中的定额数据
+    //@param {Array}rows @return {Array}
+    function getInsertRationData(rows){
+        let rst = [];
+        for(let row of rows){
+            let node = bills.tree.selected.guidance.tree.items[row];
+            if(node && node.data.type === itemType.ration){
+                rst.push({itemQuery: {userID: userID, ID: node.data.rationID}, rationType: rationType.ration});
+            }
+        }
+        return rst;
+    }
+    //插入定额
+    //@return {void}
+    function insertRations(addRationDatas){
+        if(addRationDatas.length > 0){
+            projectObj.project.Ration.addMultiRation(addRationDatas, function () {
+                //恢复
+                let sheet = guideItem.workBook.getActiveSheet();
+                renderSheetFunc(sheet, function () {
+                    for(let row = 0; row < sheet.getRowCount(); row++){
+                        if(sheet.getValue(row, 1)){
+                            sheet.setValue(row, 1, false);
+                        }
+                    }
+                });
+            });
+        }
+    }
+    //展开至搜索出来点的节点
+    //@param {Array}nodes @return {void}
+    function expandSearchNodes(nodes){
+        let that = this;
+        let billsSheet = bills.workBook.getActiveSheet();
+        renderSheetFunc(billsSheet, function () {
+            function expParentNode(node){
+                if(node.parent && !node.parent.expanded){
+                    node.parent.setExpanded(true);
+                    expParentNode(node.parent);
+                }
+            }
+            for(let node of nodes){
+                expParentNode(node);
+            }
+            TREE_SHEET_HELPER.refreshTreeNodeData(bills.treeSetting, billsSheet, bills.tree.roots, true);
+            TREE_SHEET_HELPER.refreshNodesVisible(bills.tree.roots, billsSheet, true);
+        });
+    }
+    //各按钮监听事件
+    //@return {void}
+    function bindBtn(){
+        //打开清单指引库
+        $('#stdBillsGuidanceTab').click(function () {
+            if(libSel.children().length === 0){
+                initLibs(projectInfoObj.projectInfo.engineeringInfo.billsGuidance_lib);
+            }
+        });
+        //更改清单指引库
+        $('#stdBillsGuidanceLibSelect').change(function () {
+            //关闭搜索窗口
+            $('#billsGuidanceSearchResult').hide();
+            billsLibObj.clearHighLight(bills.workBook);
+            libInitSel($(this).select().val());
+            //记住选项
+            sessionStorage.setItem('stdBillsGuidance', $(this).select().val());
+            //清除展开收起状态sessionStorage
+            sessionStorage.removeItem('stdBillsGuidanceExpState');
+        });
+        //插入定额
+        $('#guidanceInsertRation').click(function () {
+            let addRationDatas = getInsertRationData(getCheckedRows());
+            insertRations(addRationDatas);
+        });
+        //插入清单
+        $('#guidanceInsertBills').click(function () {
+            //插入清单
+            if(!bills.tree.selected){
+                return;
+            }
+            if(bills.tree.selected.children.length === 0){
+                let insert = billsLibObj.insertBills(stdBillsJobData, stdBillsFeatureData, bills.tree.selected);
+                if(insert){
+                    //插入选中的定额
+                    let addRationDatas = getInsertRationData(getCheckedRows());
+                    insertRations(addRationDatas);
+                }
+            }
+        });
+        //搜索
+        $('#stdBillsGuidanceSearch>span>button').click(function () {
+            let billsSheet = bills.workBook.getActiveSheet();
+            billsLibObj.clearHighLight(bills.workBook);
+            let keyword = $('#stdBillsGuidanceSearch>input').val();
+            if (!keyword || keyword === '') {
+                $('#billsGuidanceSearchResult').hide();
+                return;
+            }
+
+            let result = bills.tree.items.filter(function (item) {
+                let codeIs = item.data.code ? item.data.code.indexOf(keyword) !== -1 : false;
+                let nameIs = item.data.name ? item.data.name.indexOf(keyword) !== -1 : false;
+                return codeIs || nameIs;
+            });
+            result.sort(function (x, y) {
+                return x.serialNo() - y.serialNo();
+            });
+            if (result.length !== 0) {
+                //展开搜索出来的节点
+                expandSearchNodes(result);
+                //设置记住展开
+                sessionStorage.setItem('stdBillsGuidanceExpState', bills.tree.getExpState(bills.tree.items));
+
+                let sel = billsSheet.getSelections();
+                bills.controller.setTreeSelected(result[0]);
+                billsSheet.setSelection(result[0].serialNo(), sel[0].col, 1, 1);
+                billsInitSel(result[0].serialNo());
+
+                for (let node of result) {
+                    billsSheet.getRange(node.serialNo(), -1, 1, -1).backColor('lemonChiffon');
+                }
+
+                $('#nextBillsGuidance').show();
+                $('#nextBillsGuidance').unbind('click');
+                $('#nextBillsGuidance').bind('click', function () {
+                    let cur = bills.tree.selected, resultIndex = result.indexOf(cur), sel = billsSheet.getSelections();
+                    if (resultIndex === result.length - 1) {
+                        bills.controller.setTreeSelected(result[0]);
+                        billsSheet.setSelection(result[0].serialNo(), sel[0].col, 1, 1);
+                        billsInitSel(result[0].serialNo());
+                    } else {
+                        bills.controller.setTreeSelected(result[resultIndex + 1]);
+                        billsSheet.setSelection(result[resultIndex + 1].serialNo(), sel[0].col, 1, 1);
+                        billsInitSel(result[resultIndex + 1].serialNo());
+                    }
+                });
+            } else {
+                billsLibObj.clearHighLight(bills.workBook);
+                $('#nextBillsGuidance').hide();
+            }
+            $('#billsGuidanceSearchResultCount').text('搜索结果:' + result.length);
+            $('#billsGuidanceSearchResult').show();
+        });
+        // 关闭搜索结果
+        $('#closeSearchBillsGuidance').click(function () {
+            $('#billsGuidanceSearchResult').hide();
+            billsLibObj.clearHighLight(bills.workBook);
+            refreshWorkBook();
+        });
+    }
+    //刷新表
+    //@return {void}
+    function refreshWorkBook(){
+        if(bills.workBook){
+            bills.workBook.refresh();
+        }
+        if(guideItem.workBook){
+            guideItem.workBook.refresh();
+        }
+    }
+
+    return {initViews, bindBtn, refreshWorkBook, bills};
+})();
+
+$(document).ready(function(){
+    billsGuidance.initViews();
+    billsGuidance.bindBtn();
+});

+ 71 - 67
web/building_saas/main/js/views/std_bills_lib.js

@@ -76,6 +76,73 @@ var billsLibObj = {
             billsLibObj.loadStdBills(select.val());
         }
     },
+     sortJobsAndFeatures: function (arr) {
+        arr.sort(function (a, b) {
+            let rst = 0;
+            if(a.serialNo > b.serialNo) rst = 1;
+            else if(a.serialNo < b.serialNo) rst = -1;
+            return rst;
+        });
+    },
+     findData: function (value, field, Array) {
+        var i = 0;
+        for (i = 0; i < Array.length; i++) {
+            if (value[field] == Array[i][field]) {
+                return Array[i];
+            }
+        }
+        return null;
+    },
+    getBillsJobs: function (stdBillsJobData, node) {
+        var jobs = [], i, jobData = null;
+        if (stdBillsJobData && node && node.data.jobs) {
+            for (i = 0; i < node.data.jobs.length; i++) {
+                jobData = this.findData(node.data.jobs[i], 'id', stdBillsJobData);
+                if (jobData) {
+                    jobData.serialNo = node.data.jobs[i].serialNo;
+                    jobs.push(jobData);
+                }
+            }
+        }
+        this.sortJobsAndFeatures(jobs);
+        return jobs;
+    },
+    getBillsFeatures: function (stdBillsFeatureData, node) {
+        var features = [], i, featureData = null;
+        if (stdBillsFeatureData && node && node.data.items) {
+            for (i = 0; i < node.data.items.length; i++) {
+                featureData = this.findData(node.data.items[i], 'id', stdBillsFeatureData);
+                if (featureData) {
+                    featureData.serialNo = node.data.items[i].serialNo;
+                    features.push(featureData);
+                }
+            }
+        }
+        this.sortJobsAndFeatures(features);
+        return features;
+    },
+    insertBills: function (stdBillsJobData, stdBillsFeatureData, node) {
+        if(projectInfoObj.projectInfo.property.lockBills == true){
+            return false;
+        }
+        //特征及内容转化
+        pageCCOprObj.setItemContentNode(node, this.getBillsJobs(stdBillsJobData, node), this.getBillsFeatures(stdBillsFeatureData, node), node.data.name);
+        if (/\//.test(node.data.unit)) {
+            let existB = projectObj.project.Bills.sameStdCodeBillsData(node.data.code);
+            if (existB) {
+                let std = JSON.parse(JSON.stringify(node.data));
+                std.unit = existB.unit;
+                ProjectController.addBills(projectObj.project, projectObj.mainController, std);
+            } else {
+                ConfirmModal.stdBillsUnit.check(node.data, function (std) {
+                    ProjectController.addBills(projectObj.project, projectObj.mainController, std);
+                });
+            }
+        } else {
+            ProjectController.addBills(projectObj.project, projectObj.mainController, node.data);
+        }
+        return true;
+    },
     loadStdBills: function (stdBillsLibID) {
         var that = this;
         var stdBillsJobData, stdBillsFeatureData, stdBills;
@@ -84,51 +151,6 @@ var billsLibObj = {
         }
         that.stdBillsTree  = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true});
         var stdBillsTreeController = TREE_SHEET_CONTROLLER.createNew(that.stdBillsTree, billsLibObj.stdBillsSpread.getActiveSheet(), billsLibObj.stdBillsTreeSetting);
-        var findData = function (value, field, Array) {
-            var i = 0;
-            for (i = 0; i < Array.length; i++) {
-                if (value[field] == Array[i][field]) {
-                    return Array[i];
-                }
-            }
-            return null;
-        };
-        let sortJobsAndFeatures = function (arr) {
-            arr.sort(function (a, b) {
-                let rst = 0;
-                if(a.serialNo > b.serialNo) rst = 1;
-                else if(a.serialNo < b.serialNo) rst = -1;
-                return rst;
-            });
-        };
-        var getBillsJobs = function (node) {
-            var jobs = [], i, jobData = null;
-            if (stdBillsJobData && node && node.data.jobs) {
-                for (i = 0; i < node.data.jobs.length; i++) {
-                    jobData = findData(node.data.jobs[i], 'id', stdBillsJobData);
-                    if (jobData) {
-                        jobData.serialNo = node.data.jobs[i].serialNo;
-                        jobs.push(jobData);
-                    }
-                }
-            }
-            sortJobsAndFeatures(jobs);
-            return jobs;
-        };
-        var getBillsFeatures = function (node) {
-            var features = [], i, featureData = null;
-            if (stdBillsFeatureData && node && node.data.items) {
-                for (i = 0; i < node.data.items.length; i++) {
-                    featureData = findData(node.data.items[i], 'id', stdBillsFeatureData);
-                    if (featureData) {
-                        featureData.serialNo = node.data.items[i].serialNo;
-                        features.push(featureData);
-                    }
-                }
-            }
-            sortJobsAndFeatures(features);
-            return features;
-        };
         var showJobs = function (jobs) {
             SheetDataHelper.loadSheetHeader(billsLibObj.jobsSetting, billsLibObj.stdBillsJobSpread.getActiveSheet());
             SheetDataHelper.loadSheetData(billsLibObj.jobsSetting, billsLibObj.stdBillsJobSpread.getActiveSheet(), jobs);
@@ -142,9 +164,9 @@ var billsLibObj = {
             $('#stdBillsRemarkTab').hide();
             billsLibObj.refreshBillsRelaSpread();
             billsLibObj.checkBillsRelaSpread();
-            sortJobsAndFeatures(getBillsJobs(node));
-            showJobs(getBillsJobs(node));
-            showFeatures(getBillsFeatures(node));
+            billsLibObj.sortJobsAndFeatures(billsLibObj.getBillsJobs(node));
+            showJobs(billsLibObj.getBillsJobs(node));
+            showFeatures(billsLibObj.getBillsFeatures(node));
         };
         var showBillsRemark = function (node) {
             $('#stdBillsJobTab').hide();
@@ -190,25 +212,7 @@ var billsLibObj = {
                 let selectNode = that.stdBillsTree.items[args.row];
                 let name = selectNode.data.name;
                 if (that.stdBillsTree.items[args.row].children.length === 0) {
-                    if(projectInfoObj.projectInfo.property.lockBills == true){
-                        return;
-                    }
-                    //特征及内容转化
-                    pageCCOprObj.setItemContentNode(that.stdBillsTree.items[args.row], getBillsJobs(that.stdBillsTree.items[args.row]), getBillsFeatures(that.stdBillsTree.items[args.row]), name);
-                    if (/\//.test(selectNode.data.unit)) {
-                        let existB = projectObj.project.Bills.sameStdCodeBillsData(selectNode.data.code);
-                        if (existB) {
-                            let std = JSON.parse(JSON.stringify(selectNode.data));
-                            std.unit = existB.unit;
-                            ProjectController.addBills(projectObj.project, projectObj.mainController, std);
-                        } else {
-                            ConfirmModal.stdBillsUnit.check(selectNode.data, function (std) {
-                                ProjectController.addBills(projectObj.project, projectObj.mainController, std);
-                            });
-                        }
-                    } else {
-                        ProjectController.addBills(projectObj.project, projectObj.mainController, selectNode.data);
-                    }
+                    billsLibObj.insertBills(stdBillsJobData, stdBillsFeatureData, selectNode);
                 }
                 else{
                     let me = billsLibObj;

+ 73 - 6
web/building_saas/main/js/views/tender_price_view.js

@@ -51,7 +51,7 @@ let tender_obj={
         this.tenderController = TREE_SHEET_CONTROLLER.createNew(this.tenderTree, this.tenderSheet, this.tenderTreeSetting);
         this.tenderSheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onSheetValueChange);
         this.tenderSheet.bind(GC.Spread.Sheets.Events.EditStarting,this.onEditStarting);
-
+        this.tenderController.bind(TREE_SHEET_CONTROLLER.eventName.treeSelectedChanged, this.treeSelectedChanged);
        // this.tenderController.bind(TREE_SHEET_CONTROLLER.eventName.treeSelectedChanged, this.onSelectionChange);
     },
     createTenderTreeSetting:function () {
@@ -104,6 +104,9 @@ let tender_obj={
             }else if(value == false){
                 value = 0;
             }
+            if(value == 1){
+                updateData = me.cleanTenderCoe(updateData,node);//打勾不调价后清空消耗量调整系数
+            }
             me.updateChildrenValue(node,dataCode,value,datas,nodes);
         }
         if(updateData&&dataCode.indexOf("Coe") != -1 ){//如果是调整系统项,级联更新子项
@@ -134,15 +137,53 @@ let tender_obj={
     updateChildrenValue:function (node,dataCode,value,datas,nodes) {
          if(node.children.length > 0){
             for(let c of node.children){
+                this.updateChildrenValue(c,dataCode,value,datas,nodes);
                 let updateData = {type:c.sourceType,data:{'ID' : c.data.ID}};
                 updateData.data[dataCode] = value;
+                if(dataCode == 'is_adjust_price' && value == 1){
+                    updateData = this.cleanTenderCoe(updateData,c);
+                }else if(dataCode.indexOf("Coe")!= -1 && c.data.is_adjust_price == 1){//更新调整系数时忽略不调价的行
+                    continue;
+                }
                 datas.push(updateData);
                 nodes.push(c);
-                this.updateChildrenValue(c,dataCode,value,datas,nodes);
             }
          }
 
     },
+    cleanTenderCoe:function (updateData,node) {//清空调整系数
+        scMathUtil.isDef(node.data.rationQuantityCoe)?updateData.data["rationQuantityCoe"] = null:'';
+        if(scMathUtil.isDef(node.data.quantityCoe)){
+            scMathUtil.isDef(node.data.quantityCoe.labour)?updateData.data["quantityCoe.labour"] = null:'';
+            scMathUtil.isDef(node.data.quantityCoe.material)?updateData.data["quantityCoe.material"] = null:'';
+            scMathUtil.isDef(node.data.quantityCoe.machine)?updateData.data["quantityCoe.machine"] = null:'';
+            scMathUtil.isDef(node.data.quantityCoe.main)?updateData.data["quantityCoe.main"] = null:'';
+            scMathUtil.isDef(node.data.quantityCoe.equipment)?updateData.data["quantityCoe.equipment"] = null:'';
+        }
+        return updateData;
+    },
+    cleanTargetPrice:function (updateData,node) {//清空目标报价
+        scMathUtil.isDef(node.data.targetUnitFee)?updateData.data["targetUnitFee"] = null:'';
+        scMathUtil.isDef(node.data.targetTotalFee)?updateData.data["targetTotalFee"] = null:'';
+        return updateData;
+    },
+    calcOptionsChecking:function (option) {//调整选项检查,返回需要更新的数组
+        let datas = [];
+        let me = tender_obj;
+        for(let node of me.tenderTree.items){
+            let tem_updateData = {type:node.sourceType,data:{}};
+            if(option == 'coeBase') { //当值为“根据调整系数计算报价”时,清空目标报价。
+                me.cleanTargetPrice(tem_updateData,node);
+            }else if(option == 'priceBase'){//当值为“根据报价计算调整系数”时,清空调整系数。
+                me.cleanTenderCoe(tem_updateData,node);
+            }
+            if(!_.isEmpty(tem_updateData.data)){//如果需要更新
+                tem_updateData.data.ID = node.data.ID;
+                datas.push(tem_updateData);
+            }
+        }
+        return datas;
+    },
 
     updateTenderData:function (datas,callback) {
         let me = tender_obj;
@@ -173,8 +214,20 @@ let tender_obj={
             $.bootstrapLoading.end();
         })
     },
-
-
+    treeSelectedChanged:function (node) {
+        let me = tender_obj;
+        //设置选中行底色和恢复前选中行底色
+        let refreshNodes = [node];
+        if(!me.tenderTree.preSelected){
+            refreshNodes.push(me.tenderTree.items[0]);
+        }
+        else {
+            refreshNodes.push(me.tenderTree.preSelected);
+        }
+        me.tenderTree.preSelected = node;
+        projectObj.setNodesStyle(me.tenderSheet, refreshNodes,me.tenderTree);
+        //console.log(node);
+    },
     onEditStarting:function (sender,args) {
         let me = tender_obj, row = args.row, col = args.col;
         if(me.editChecking(row,col) == false){
@@ -245,14 +298,28 @@ $(function () {
     });
 
     $('#tenderGLJQuantity').bind('click',function () {
-        console.log($('#gljPriceTenderCoe').val()) ;
+        //console.log($('#gljPriceTenderCoe').val()) ;
+    });
+
+    $('#cleanTender').bind('click',function () {
+       console.log("clean tender")
     });
 
     $('#calcPriceOption').change(function(){
         let me = tender_obj;
         let newVal = $(this).val();
+        let datas = me.calcOptionsChecking(newVal);
         let updateData = {type:ModuleNames.project,data:{'ID' : projectObj.project.ID(),'property.tenderSetting.calcPriceOption':newVal}};
-        me.updateTenderData([updateData],function () {
+        datas.push(updateData);
+        me.updateTenderData(datas,function () {
+            let nodes = [];
+            for(let d of datas){
+                if(d.type == ModuleNames.bills || d.type == ModuleNames.ration){
+                    let node = me.tenderTree.getNodeByID(d.data.ID);
+                    node?nodes.push(node):'';
+                }
+            }
+            me.tenderController.refreshTreeNode(nodes);
             me.initPageContent();
         });
     });

+ 33 - 30
web/building_saas/pm/html/project-management.html

@@ -13,6 +13,7 @@
     <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.sc.css">
     <!--zTree-->
     <link rel="stylesheet" href="/lib/ztree/css/zTreeStyle.css" type="text/css">
+    <link rel="stylesheet" href="/lib/jquery-contextmenu/jquery.contextMenu.css">
     <!-- endinject -->
 
     <script>
@@ -87,7 +88,7 @@
                 <div class="tab-content">
                     <div class="tab-pane active" id="pm_all" role="tabpanel">
                         <div class="toolsbar">
-                            <div class="tools-btn btn-group align-top">
+                            <!--<div class="tools-btn btn-group align-top">
                                 <a href="javascript:void(0);"  id="add-tender-btn" class="btn btn-sm"><i class="fa fa-sticky-note-o"></i>新建单位工程</a>
                                 <div class="btn-group" role="group">
                                     <a href="javascript:void(0);" class="btn btn-sm dropdown-toggle" data-toggle="dropdown"></a>
@@ -99,11 +100,11 @@
                                 </div>
                                 <a href="javascript:void(0);" class="btn btn-sm" id="rename-btn">重命名</a>
                                 <a href="javascript:void(0);" class="btn btn-sm" id="del-btn">删除</a>
-                               <!-- <a href="javascript:void(0);" class="btn btn-sm" id="move-to-btn">移动到...</a>-->
+                               &lt;!&ndash; <a href="javascript:void(0);" class="btn btn-sm" id="move-to-btn">移动到...</a>&ndash;&gt;
                                 <a href="javascript:void(0);" class="btn btn-sm" id="copy-to-btn">复制到...</a>
                                 <a href="" class="btn btn-sm" id="share-btn">共享</a>
                                 <a href="" class="btn btn-sm" id="cooperate-btn">协同</a>
-                            </div>
+                            </div>-->
                             <legend class="m-0 pb-1">全部</legend>
                         </div>
                         <div class="poj-list" id="projSpread">
@@ -274,9 +275,9 @@
             <div class="modal-body">
                 <form>
                     <div>
-                        <label>建设项目</label>
                         <div class="input-group">
-                            <input type="text" class="form-control" placeholder="输入建设项目名称" id="poj-name" autocomplete="off">
+                            <label style="margin-top: 8px;">建设项目</label>
+                            <input style="margin-left: 5px; border-radius: .25rem;" type="text" class="form-control" placeholder="输入建设项目名称" id="poj-name" autocomplete="off">
                               <span class="input-group-btn">
                                 <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown"></button>
                                 <div class="dropdown-menu dropdown-menu-right" style="width:468px" id="poj-name-list">
@@ -286,12 +287,12 @@
                                 </div>
                               </span>
                         </div>
-                        <span class="form-text text-info" id="poj-name-info" style="display: none;">新建 “汽车生产车间5”</span>
                     </div>
-                    <div>
-                        <label>单项工程</label>
+                    <span class="form-text text-info" id="poj-name-info" style="display: none;">新建 “汽车生产车间5”</span>
+                    <div style="margin-top: 15px;">
                         <div class="input-group">
-                            <input type="text" class="form-control" placeholder="输入单项工程名称" id="eng-name" autocomplete="off">
+                            <label style="margin-top: 8px;">单项工程</label>
+                            <input style="margin-left: 5px; border-radius: .25rem;" type="text" class="form-control" placeholder="输入单项工程名称" id="eng-name" autocomplete="off">
                               <span class="input-group-btn">
                                 <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown"></button>
                                 <div class="dropdown-menu dropdown-menu-right" style="width:468px" id="eng-name-list">
@@ -299,25 +300,25 @@
                                     <button class="dropdown-item" type="button">左4号生产车间</button>
                                 </div>                              </span>
                         </div>
-                        <span class="form-text text-info" id="eng-name-info" style="display: none;">新建 “左2号生产车间2”</span>
                     </div>
+                    <span class="form-text text-info" id="eng-name-info" style="display: none;">新建 “左2号生产车间2”</span>
 
-                    <div>
-                        <label>单位工程</label>
-                        <input type="text" class="form-control" placeholder="输入单位工程名称" id="tender-name" autocomplete="off">
-                        <span class="form-text text-danger" id="tender-name-info" style="display: none;">已存在 “建筑工程1”</span>
+                    <div style="margin-top: 15px;" class="input-group">
+                        <label style="margin-top: 8px;">单位工程</label>
+                        <input style="margin-left: 5px; border-radius: .25rem;" type="text" class="form-control" placeholder="输入单位工程名称" id="tender-name" autocomplete="off">
                     </div>
-                    <div>
-                        <label>单价文件</label>
-                        <select class="form-control" id="unit-price"><option value="">新建单价文件</option></select>
+                    <span class="form-text text-danger" id="tender-name-info" style="display: none;">已存在 “建筑工程1”</span>
+                    <div style="margin-top: 15px;" class="input-group">
+                        <label style="margin-top: 8px;">单价文件</label>
+                        <select style="margin-left: 5px; border-radius: .25rem;" class="form-control" id="unit-price"><option value="">新建单价文件</option></select>
                     </div>
-                    <div>
-                        <label>费率文件</label>
-                        <select class="form-control" id="tender-fee-rate"><option value="">新建费率文件</option></select>
+                    <div style="margin-top: 15px;" class="input-group">
+                        <label style="margin-top: 8px;">费率文件</label>
+                        <select style="margin-left: 5px; border-radius: .25rem;" class="form-control" id="tender-fee-rate"><option value="">新建费率文件</option></select>
                     </div>
-                    <div>
+                    <div style="margin-top: 15px;" class="input-group">
                         <label>计价方式</label>
-                        <div class="row">
+                        <div style="margin-left: 5px; border-radius: .25rem;"  class="row">
                             <label class="custom-control custom-radio" style="margin-left: 20px;">
                                 <input name="valuation_type" id="radioBill" value="bill" type="radio" class="custom-control-input">
                                 <label class="custom-control-label" for="radioBill">清单计价</label>
@@ -328,16 +329,16 @@
                             </label>-->
                         </div>
                     </div>
-                    <div>
-                        <label>计价规则</label>
-                        <select class="form-control" id="valuation"><option value="">请选择计价规则</option></select>
-                        <span class="form-text text-danger" id="valuation-info" style="display: none;">请选择计价规则</span>
+                    <div style="margin-top: 15px;" class="input-group">
+                        <label style="margin-top: 8px;">计价规则</label>
+                        <select style="margin-left: 5px; border-radius: .25rem;" class="form-control" id="valuation"><option value="">请选择计价规则</option></select>
                     </div>
-                    <div>
-                        <label>工程专业</label>
-                        <select class="form-control" id="tender-engineering"><option value="">请选择对应的工程专业</option></select>
-                        <span class="form-text text-danger" id="engineering-info" style="display: none;">请选择工程专业</span>
+                    <span class="form-text text-danger" id="valuation-info" style="display: none;">请选择计价规则</span>
+                    <div style="margin-top: 15px;" class="input-group">
+                        <label style="margin-top: 8px;">工程专业</label>
+                        <select style="margin-left: 5px; border-radius: .25rem;" class="form-control" id="tender-engineering"><option value="">请选择对应的工程专业</option></select>
                     </div>
+                    <span class="form-text text-danger" id="engineering-info" style="display: none;">请选择工程专业</span>
                 </form>
             </div>
             <div class="modal-footer">
@@ -495,6 +496,7 @@
 <script src="/public/web/date_util.js"></script>
 <script src="/web/building_saas/pm/js/pm_tree.js"></script>
 <script src="/public/web/tree_sheet/tree_sheet_helper.js"></script>
+<script src="/public/web/sheet/sheet_data_helper.js"></script>
 <script type="text/javascript" src="/public/web/common_ajax.js"></script>
 <script src="/lib/JSExpressionEval_src/Date.js"></script>
 <script src="/web/building_saas/pm/js/pm_ajax.js"></script>
@@ -503,6 +505,7 @@
 <!-- zTree -->
 <script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
 <script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>
+<script src="/lib/jquery-contextmenu/jquery.contextMenu.min.js"></script>
 <!-- endinject -->
 
 </body>

+ 13 - 12
web/building_saas/pm/js/pm_gc.js

@@ -17,15 +17,15 @@ const gcTreeObj = {
             autoUpdate: false
         },
         header: [
-            {name: '工程列表', dataCode: 'name', width: 800, vAlign: 'center', hAlign: 'left'},
-            {name: '删除日期', dataCode: 'deleteDateTime', width: 170, vAlign: 'center', hAlign: 'left'},
-            {name: '创建日期', dataCode: 'createDateTime', width: 170, vAlign: 'center', hAlign: 'left'},
-            {name: '恢复', dataCode: 'recovery', width: 100, vAlign: 'center', hAlign: 'left'},
-            {name: '彻底删除', dataCode: 'delete', width: 100, vAlign: 'center', hAlign: 'left'},
-            {name: '单价文件', dataCode: 'unitPriceFile', width: 100, vAlign: 'center', hAlign: 'left'},
-            {name: '单价文件-清除', dataCode: 'unitPriceFile_delete', width: 100, vAlign: 'center', hAlign: 'left'},
-            {name: '费率文件', dataCode: 'feeRateFile', width: 100, vAlign: 'center', hAlign: 'left'},
-            {name: '费率文件-清除', dataCode: 'feeRateFile_delete', width: 100, vAlign: 'center', hAlign: 'left'}
+            {name: '工程列表', dataCode: 'name', width: 0.5, vAlign: 'center', hAlign: 'left'},
+            {name: '删除日期', dataCode: 'deleteDateTime', width: 0.1, vAlign: 'center', hAlign: 'left'},
+            {name: '创建日期', dataCode: 'createDateTime', width: 0.1, vAlign: 'center', hAlign: 'left'},
+            {name: '恢复', dataCode: 'recovery', width: 0.05, vAlign: 'center', hAlign: 'left'},
+            {name: '彻底删除', dataCode: 'delete', width: 0.05, vAlign: 'center', hAlign: 'left'},
+            {name: '单价文件', dataCode: 'unitPriceFile', width: 0.05, vAlign: 'center', hAlign: 'left'},
+            {name: '单价文件-清除', dataCode: 'unitPriceFile_delete', width: 0.05, vAlign: 'center', hAlign: 'left'},
+            {name: '费率文件', dataCode: 'feeRateFile', width: 0.05, vAlign: 'center', hAlign: 'left'},
+            {name: '费率文件-清除', dataCode: 'feeRateFile_delete', width: 0.05, vAlign: 'center', hAlign: 'left'}
         ],
         //恢复和彻底删除字体色
         style: {
@@ -68,10 +68,11 @@ const gcTreeObj = {
                 allowResizeRows: true,
                 allowResizeColumns: true
             };
+            let workBookWidth = getWorkBookWidth();
             sheet.setColumnCount(headers.length);
             sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
             for(let i = 0, len = headers.length; i < len; i++){
-                sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
+                sheet.setColumnWidth(i, workBookWidth * headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
                 if(headers[i].dataCode === 'unitPriceFile' || headers[i].dataCode === 'feeRateFile'){
                     //合并列
                     sheet.addSpan(0, i, 1, 2, GC.Spread.Sheets.SheetArea.colHeader);
@@ -633,10 +634,10 @@ function v_getMoBody(type, oprNode, nodes){
             html += ('</p>');
         }
 
-        html += ('<p>点“确定”按钮,确认从回收站中恢复</p>');
+        html += ('<p>点“确定”按钮,确认从回收站中恢复</p>');
     }
     else{
-        html += ('<p>点“确定”按钮,确认彻底删除数据</p>');
+        html += ('<p>点“确定”按钮,确认彻底删除数据</p>');
     }
     return html;
 }

+ 189 - 21
web/building_saas/pm/js/pm_newMain.js

@@ -39,11 +39,11 @@ const projTreeObj = {
             autoUpdate: false
         },
         header: [
-            {name: '工程列表', dataCode: 'name', width: 800, vAlign: 'center', hAlign: 'left'},
-            {name: '工程造价', dataCode: 'engineeringCost', width: 170, vAlign: 'center', hAlign: 'right'},
-            {name: '单价文件', dataCode: 'unitPriceFile', width: 250, vAlign: 'center', hAlign: 'left'},
-            {name: '费率文件', dataCode: 'feeRateFile', width: 250, vAlign: 'center', hAlign: 'left'},
-            {name: '创建日期', dataCode: 'createDateTime', width: 90, vAlign: 'center', hAlign: 'center'}
+            {name: '工程列表', dataCode: 'name', width: 0.48, vAlign: 'center', hAlign: 'left'},
+            {name: '工程造价', dataCode: 'engineeringCost', width: 0.13, vAlign: 'center', hAlign: 'right'},
+            {name: '单价文件', dataCode: 'unitPriceFile', width: 0.15, vAlign: 'center', hAlign: 'left'},
+            {name: '费率文件', dataCode: 'feeRateFile', width: 0.15, vAlign: 'center', hAlign: 'left'},
+            {name: '创建日期', dataCode: 'createDateTime', width: 0.09, vAlign: 'center', hAlign: 'center'}
         ],
         //选中行颜色
         style: {
@@ -110,9 +110,11 @@ const projTreeObj = {
             };
             sheet.setColumnCount(headers.length);
             sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
+            let workBookWidth = getWorkBookWidth();
             for(let i = 0, len = headers.length; i < len; i++){
                 sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
-                sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
+                let width = workBookWidth * headers[i].width;
+                sheet.setColumnWidth(i, width, GC.Spread.Sheets.SheetArea.colHeader);
             }
         };
         me.renderSheetFuc(sheet, fuc);
@@ -124,9 +126,147 @@ const projTreeObj = {
             this.setOptions(newWorkBook, setting.options);
             this.buildHeader(newWorkBook.getActiveSheet(), setting.header);
             this.bindEvent(newWorkBook);
+            this.loadContextMenu()
         }
         return newWorkBook;
     },
+    loadContextMenu: function () {
+        let me = this;
+        $.contextMenu({
+            selector: '#projSpread',
+            build: function ($trigger, e) {
+                let target = SheetDataHelper.safeRightClickSelection($trigger, e, me.workBook);
+                me.initSelection({row: target.row, rowCount: 1}, me.preSelection ? me.preSelection : null, me.workBook.getActiveSheet());
+                return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
+            },
+            items: {
+                "addFolder": {
+                    name: "新建文件夹",
+                    icon: 'fa-folder-o',
+                    disabled: function () {
+                        return false;
+                    },
+                    callback: function (key, opt) {
+                        $("#add-folder-dialog").modal("show");
+                        setTimeout(function () {
+                            $('#folder-name')[0].focus();
+                        }, 300);
+                    }
+                },
+                "addProject": {
+                    name: "新建建设项目",
+                    icon: 'fa-cubes',
+                    disabled: function () {
+                        return false;
+                    },
+                    callback: function (key, opt) {
+                        $('#add-project-dialog').modal('show');
+                        setTimeout(function () {
+                            $('#project-name')[0].focus();
+                        }, 300);
+                    }
+                },
+                "addEngineering": {
+                    name: "新建单项工程",
+                    icon: 'fa-cube',
+                    disabled: function () {
+                        let node = me.tree.selected;
+                        if(node && node.data.projType !== projectType.folder){
+                            return false;
+                        }
+                        return true;
+                    },
+                    callback: function (key, opt) {
+                        let selectedItem = me.tree.selected;
+                        try {
+                            if(selectedItem !== null  && selectedItem.data.projType !== projectType.folder){
+                                $("#add-engineering-dialog").modal("show");
+                                setTimeout(function () {
+                                    $('#engineering-name')[0].focus();
+                                }, 300);
+                            }
+
+                        } catch (error) {
+                            alert(error);
+                        }
+                    }
+                },
+                "addTender": {
+                    name: "新建单位工程",
+                    icon: 'fa-sticky-note-o',
+                    disabled: function () {
+                        return false;
+                    },
+                    callback: function (key, opt) {
+                        //弹出新建单位工程之前,判断当前使用版本,且当前使用单位工程数是否已到最大值
+                        let selectedItem = me.tree.selected;
+                        $("#add-tender-dialog").modal("show");
+                    }
+                },
+                "spr1": '--------',
+                "rename": {
+                    name: "重命名",
+                    icon: 'fa-edit',
+                    disabled: function () {
+                        return !me.tree.selected;
+                    },
+                    callback: function (key, opt) {
+                        $('#rename-name').val(projTreeObj.tree.selected.data.name ? projTreeObj.tree.selected.data.name : '');
+                        $('#rename-dialog').modal('show');
+                        setTimeout(function () {
+                            $('#rename-name')[0].focus();
+                        }, 300);
+                    }
+                },
+                "delete": {
+                    name: "删除",
+                    icon: 'fa-remove',
+                    disabled: function () {
+                        let node = me.tree.selected;
+                        return !node || (node.data.projType === projectType.folder && node.children.length > 0);
+                    },
+                    callback: function (key, opt) {
+                        if (projTreeObj.tree && projTreeObj.tree.selected) {
+                            $('#del').modal('show');
+                        }
+                    }
+                },
+                "copyTo": {
+                    name: "复制到",
+                    icon: 'fa-copy',
+                    disabled: function () {
+                        let node = me.tree.selected;
+                        return !(node && node.data.projType === projectType.tender);
+                    },
+                    callback: function (key, opt) {
+                        let selectedItem = projTreeObj.tree.selected;
+                        try {
+                            let selectedType = selectedItem !== null && selectedItem.data !== undefined ?
+                                selectedItem.data.projType : '';
+                            if (selectedType !== projectType.tender) {
+                                throw '请选择单位工程进行复制';
+                            }
+                        } catch (error) {
+                            alert(error);
+                            return false;
+                        }
+                        $('#copy-to-dialog').modal('show');
+                    }
+                },
+                "spr2": '--------',
+                "share": {
+                    name: "分享",
+                    icon: 'fa-share',
+                    disabled: function () {
+                        return true;
+                    },
+                    callback: function (key, opt) {
+
+                    }
+                },
+            }
+        });
+    },
     getSelStyle: function (backColor) {
         let style = new GC.Spread.Sheets.Style();
         style.backColor = backColor;
@@ -152,6 +292,7 @@ const projTreeObj = {
     initSelection: function (newSel, oldSel = null,sheet) {
         let me = this;
         let node = me.tree.items[newSel.row];
+        node = node ? node : null;
         //恢复底色
         if(oldSel){
             me.setSelStyle(oldSel, me.setting.style.defalutBackColor,sheet);
@@ -839,6 +980,13 @@ const projTreeObj = {
 };
 
 $(document).ready(function() {
+    //列宽随着屏幕改变
+    $(window).resize(function () {
+        autoPmWdith(projTreeObj.workBook, projTreeObj.setting.header);
+        autoPmWdith(gcTreeObj.workBook, gcTreeObj.setting.header);
+
+    });
+
     init();
     $('#tab_pm_all').on('show.bs.tab', function () {
         if(gcTreeObj.workBook){
@@ -883,13 +1031,13 @@ $(document).ready(function() {
     bindModalsHidden($('#add-project-dialog'), $('#add-engineering-dialog'), $('#add-folder-dialog'), $('#rename-dialog'));
 
     // 新增建设项目点击
-    $('#add-project-btn').click(function () {
+    /*$('#add-project-btn').click(function () {
         let selectedItem = projTreeObj.tree.selected;
         $('#add-project-dialog').modal('show');
         setTimeout(function () {
             $('#project-name')[0].focus();
         }, 300);
-    });
+    });*/
 
     // 新增建设项目操作
     $('#addProjOk').click(function () {
@@ -920,7 +1068,7 @@ $(document).ready(function() {
     });
 
     // 新增单项项目点击
-    $("#add-engineering-btn").click(function() {
+   /* $("#add-engineering-btn").click(function() {
         let selectedItem = projTreeObj.tree.selected;
         try {
             if(selectedItem !== null  && selectedItem.data.projType !== projectType.folder){
@@ -933,7 +1081,7 @@ $(document).ready(function() {
         } catch (error) {
             alert(error);
         }
-    });
+    });*/
 
     // 新增单项工程操作
     $("#add-engineering-confirm").click(function() {
@@ -941,11 +1089,11 @@ $(document).ready(function() {
     });
 
     // 新增单位工程点击
-    $("#add-tender-btn").click(function() {
+    /*$("#add-tender-btn").click(function() {
         //弹出新建单位工程之前,判断当前使用版本,且当前使用单位工程数是否已到最大值
         let selectedItem = projTreeObj.tree.selected;
         $("#add-tender-dialog").modal("show");
-    });
+    });*/
 
     //新建单位工程-建设项目提示
     $('#poj-name').change(function () {
@@ -1041,12 +1189,12 @@ $(document).ready(function() {
     });
 
     // 新增文件夹按钮点击
-    $("#add-folder-btn").click(function() {
+    /*$("#add-folder-btn").click(function() {
         $("#add-folder-dialog").modal("show");
         setTimeout(function () {
             $('#folder-name')[0].focus();
         }, 300);
-    });
+    });*/
 
     // 新增文件夹操作
     $("#add-folder-confirm").click(function() {
@@ -1054,11 +1202,11 @@ $(document).ready(function() {
     });
 
     // 删除按钮点击
-    $('#del-btn').click(function() {
+   /* $('#del-btn').click(function() {
         if (projTreeObj.tree && projTreeObj.tree.selected) {
             $('#del').modal('show');
         }
-    });
+    });*/
 
     // 删除时文字替换
     $('#del').on('show.bs.modal', function() {
@@ -1120,7 +1268,7 @@ $(document).ready(function() {
     });
 
     // 重命名按钮点击
-    $('#rename-btn').click(function() {
+    /*$('#rename-btn').click(function() {
         if (!projTreeObj.tree) {
             return false;
         }
@@ -1133,7 +1281,7 @@ $(document).ready(function() {
         setTimeout(function () {
             $('#rename-name')[0].focus();
         }, 300);
-    });
+    });*/
 
     // 重命名操作
     $("#rename-confirm").click(function() {
@@ -1160,7 +1308,7 @@ $(document).ready(function() {
 
 
     // 复制到按钮点击
-    $('#copy-to-btn').click(function () {
+    /*$('#copy-to-btn').click(function () {
         let selectedItem = projTreeObj.tree.selected;
         try {
             let selectedType = selectedItem !== null && selectedItem.data !== undefined ?
@@ -1173,7 +1321,7 @@ $(document).ready(function() {
             return false;
         }
         $('#copy-to-dialog').modal('show');
-    });
+    });*/
     // 复制到弹层替换
   /*  $('#copy-to-dialog').on('show.bs.modal', function () {
         copytoZTree = ConvertTreeToZtree(projTreeObj.tree, $('#treeDemo2'), null);
@@ -1246,6 +1394,24 @@ $(document).ready(function() {
     });
 });
 
+//获取工作表总宽度
+function getWorkBookWidth(){
+    return workBookWidth = $(window).width() - $('.pm-side').width() - 90;
+}
+
+//根据当前工作表的宽度更改比例
+function autoPmWdith(workBook, headers){
+    if(workBook){
+        const sheet = workBook.getActiveSheet();
+        projTreeObj.renderSheetFuc(sheet, function () {
+            let workBookWidth = getWorkBookWidth();
+            for(let col = 0; col < headers.length; col++){
+                sheet.setColumnWidth(col, workBookWidth * headers[col]['width'], GC.Spread.Sheets.SheetArea.colHeader)
+            }
+        });
+    }
+}
+
 /**
  * 初始化数据
  *
@@ -1715,6 +1881,7 @@ function setProjOptions(projs, selected){
                 $("#poj-name").val(projs[i].data.name);
                 setFileOptions(projs[i].data.ID);
                 setEngOptions(projs[i].data.ID);
+                $('#poj-name-info').hide();
             });
             $("#poj-name-list").append(proj);
         }
@@ -1757,6 +1924,7 @@ function setEngOptions(projID){
                 eng.attr("type", "button");
                 eng.click(function () {
                     $("#eng-name").val(engineerings[i].data.name);
+                    $('#eng-name-info').hide();
                 });
                 $("#eng-name-list").append(eng);
             }
@@ -1982,7 +2150,7 @@ function AddFolder() {
         $('#folder-name').val('');
         setDangerInfo($('#folder-name-info'), '', false);
     };
-    if (selectedItem !== null) {
+    if (selectedItem) {
         // 判断是否超过3层
         if(!withinTreble(selectedItem)){
             alert("文件夹不能超过3层");

+ 8 - 6
web/building_saas/report/html/rpt_main.html

@@ -62,13 +62,15 @@
                     <div class="panel">
                         <div class="panel-body">
                             <div class="input-group input-group-sm" role="group">
-                            <span class="input-group-btn">
-                              <button type="button" class="btn btn-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="上一页" onclick="rptControlObj.prePage(this)"><i class="fa fa-chevron-left"></i></button>
-                            </span>
-                                <input class="form-control" id="rpt_page_num" value="" style="width:60px"  data-toggle="tooltip" data-placement="bottom" title="输入页码按回车键,快速跳转">
                                 <span class="input-group-btn">
-                              <button type="button" class="btn btn-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="下一页" onclick="rptControlObj.nextPage(this)"><i class="fa fa-chevron-right"></i></button>
-                            </span>
+                                    <button type="button" class="btn btn-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="首页" onclick="rptControlObj.firstPage(this)"><i class="fa fa-chevron-left"></i><i class="fa fa-chevron-left"></i></button>
+                                    <button type="button" class="btn btn-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="上一页" onclick="rptControlObj.prePage(this)"><i class="fa fa-chevron-left"></i></button>
+                                </span>
+                                <input class="form-control" id="rpt_page_num" value="" onKeydown="rptControlObj.onKeydown(event, this)" style="width:60px"  data-toggle="tooltip" data-placement="bottom" title="输入页码按回车键,快速跳转">
+                                <span class="input-group-btn">
+                                    <button type="button" class="btn btn-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="下一页" onclick="rptControlObj.nextPage(this)"><i class="fa fa-chevron-right"></i></button>
+                                    <button type="button" class="btn btn-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="尾页" onclick="rptControlObj.lastPage(this)"><i class="fa fa-chevron-right"></i><i class="fa fa-chevron-right"></i></button>
+                                </span>
                             </div>
                         </div>
                         <div class="panel-foot text-muted">

+ 33 - 0
web/building_saas/report/js/rpt_main.js

@@ -302,6 +302,10 @@ let rptControlObj = {
             window.location = url;//这里不能使用get方法跳转,否则下载不成功
         }
     },
+    firstPage: function(dom) {
+        let canvas = document.getElementById("rptCanvas");
+        zTreeOprObj.showPage(1, canvas);
+    },
     prePage: function(dom) {
         let canvas = document.getElementById("rptCanvas");
         zTreeOprObj.showPage(zTreeOprObj.currentPage - 1, canvas);
@@ -310,6 +314,35 @@ let rptControlObj = {
         let canvas = document.getElementById("rptCanvas");
         zTreeOprObj.showPage(zTreeOprObj.currentPage + 1, canvas);
     },
+    lastPage: function(dom) {
+        let me = zTreeOprObj;
+        let canvas = document.getElementById("rptCanvas");
+        zTreeOprObj.showPage(me.maxPages, canvas);
+    },
+    onKeydown: function (event, dom) {
+        let me = zTreeOprObj, keyPressed = null;
+        if (window.event) {
+            keyPressed = window.event.keyCode; // IE/Chrome
+        } else {
+            keyPressed = event.which; // Firefox
+        }
+        if (keyPressed == 13) {
+            let pageNum = 1;
+            try {
+                pageNum = parseInt(dom.value);
+            } catch (e) {
+                pageNum = 1;
+            }
+            let canvas = document.getElementById("rptCanvas");
+            if (pageNum < 1) {
+                pageNum = 1;
+            } else if (pageNum > me.maxPages) {
+                pageNum = me.maxPages;
+            }
+            zTreeOprObj.showPage(pageNum, canvas);
+            return false;
+        }
+    },
     changeMargin: function(marginPropStr, marginDom) {
         zTreeOprObj.reportPageCfg.margins[marginPropStr] = marginDom.value;
     },