Explorar el Código

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

TonyKang hace 4 años
padre
commit
60c8010df4
Se han modificado 100 ficheros con 2543 adiciones y 1034 borrados
  1. 1 1
      config/config.js
  2. 10 1
      config/gulpConfig.js
  3. 4 0
      logs/online_logs.js
  4. 5 0
      modules/all_models/bills.js
  5. 2 2
      modules/all_models/compilation.js
  6. 2 1
      modules/all_models/compleRation_ration.js
  7. 3 0
      modules/all_models/projects.js
  8. 1 0
      modules/all_models/ration.js
  9. 2 1
      modules/all_models/ration_glj.js
  10. 18 0
      modules/all_models/share_lib.js
  11. 2 2
      modules/all_models/unit_price.js
  12. 1 0
      modules/all_models/unit_price_file.js
  13. 9 1
      modules/all_models/user.js
  14. 56 22
      modules/complementary_glj_lib/controllers/gljController.js
  15. 33 0
      modules/complementary_glj_lib/models/gljModel.js
  16. 2 1
      modules/complementary_glj_lib/routes/routes.js
  17. 4 2
      modules/complementary_ration_lib/controllers/compleRationController.js
  18. 2 1
      modules/complementary_ration_lib/controllers/compleSectionTreeController.js
  19. 34 18
      modules/complementary_ration_lib/controllers/compleViewController.js
  20. 14 4
      modules/complementary_ration_lib/models/compleRationModel.js
  21. 48 18
      modules/complementary_ration_lib/models/searchModel.js
  22. 4 4
      modules/complementary_ration_lib/routes/routes.js
  23. 1 1
      modules/fee_rates/controllers/fee_rates_controller.js
  24. 1 1
      modules/fee_rates/facade/fee_rates_facade.js
  25. 2 1
      modules/glj/controllers/glj_controller.js
  26. 2 2
      modules/glj/facade/glj_facade.js
  27. 0 2
      modules/glj/models/unit_price_model.js
  28. 1 0
      modules/main/controllers/block_lib_controller.js
  29. 12 0
      modules/main/controllers/ration_controller.js
  30. 10 1
      modules/main/facade/bill_facade.js
  31. 30 3
      modules/main/facade/block_lib_facade.js
  32. 42 10
      modules/main/facade/ration_facade.js
  33. 1 0
      modules/main/routes/main_route.js
  34. 79 4
      modules/pm/controllers/pm_controller.js
  35. 99 15
      modules/pm/facade/pm_facade.js
  36. 12 25
      modules/pm/models/project_model.js
  37. 3 0
      modules/pm/routes/pm_route.js
  38. 19 6
      modules/ration_glj/controllers/ration_glj_controller.js
  39. 1 1
      modules/ration_glj/facade/glj_calculate_facade.js
  40. 10 3
      modules/ration_glj/facade/ration_glj_facade.js
  41. 54 1
      modules/users/controllers/cld_controller.js
  42. 1 3
      modules/users/controllers/login_controller.js
  43. 43 2
      modules/users/models/user_model.js
  44. 4 0
      modules/users/routes/cld_route.js
  45. 2 2
      package.json
  46. 24 5
      public/billsUtil.js
  47. 8 0
      public/common_constants.js
  48. 14 2
      public/common_util.js
  49. 13 4
      public/web/gljUtil.js
  50. 140 21
      public/web/sheet/sheet_common.js
  51. 11 2
      public/web/tree_sheet/tree_sheet_helper.js
  52. 1 0
      server.js
  53. 13 5
      web/building_saas/complementary_glj_lib/html/tools-gongliaoji.html
  54. 10 5
      web/building_saas/complementary_glj_lib/js/glj.js
  55. 6 4
      web/building_saas/complementary_glj_lib/js/gljComponent.js
  56. 118 0
      web/building_saas/complementary_glj_lib/js/init.js
  57. 0 1
      web/building_saas/complementary_ration_lib/html/anzhuang.html
  58. 5 0
      web/building_saas/complementary_ration_lib/html/dinge.html
  59. 0 1
      web/building_saas/complementary_ration_lib/html/main.html
  60. 9 2
      web/building_saas/complementary_ration_lib/js/coe.js
  61. 2 1
      web/building_saas/complementary_ration_lib/js/gljSelect.js
  62. 71 2
      web/building_saas/complementary_ration_lib/js/init.js
  63. 5 5
      web/building_saas/complementary_ration_lib/js/installation.js
  64. 11 5
      web/building_saas/complementary_ration_lib/js/ration.js
  65. 3 1
      web/building_saas/complementary_ration_lib/js/ration_assist.js
  66. 2 2
      web/building_saas/complementary_ration_lib/js/ration_coe.js
  67. 14 3
      web/building_saas/complementary_ration_lib/js/ration_glj.js
  68. 9 9
      web/building_saas/complementary_ration_lib/js/repository_glj.js
  69. 5 2
      web/building_saas/complementary_ration_lib/js/section_tree.js
  70. 10 1
      web/building_saas/css/custom.css
  71. 12 3
      web/building_saas/fee_rates/fee_rate.html
  72. 4 0
      web/building_saas/glj/html/project_glj.html
  73. 31 13
      web/building_saas/main/html/main.html
  74. 5 1
      web/building_saas/main/js/controllers/block_controller.js
  75. 7 0
      web/building_saas/main/js/controllers/project_controller.js
  76. 1 0
      web/building_saas/main/js/main.js
  77. 89 23
      web/building_saas/main/js/models/calc_program.js
  78. 97 0
      web/building_saas/main/js/models/feeRateConsts.js
  79. 6 1
      web/building_saas/main/js/models/main_consts.js
  80. 29 13
      web/building_saas/main/js/models/project.js
  81. 4 3
      web/building_saas/main/js/models/project_glj.js
  82. 7 5
      web/building_saas/main/js/models/ration.js
  83. 6 0
      web/building_saas/main/js/models/ration_glj.js
  84. 71 39
      web/building_saas/main/js/views/block_lib.js
  85. 2 2
      web/building_saas/main/js/views/calc_program_manage.js
  86. 2 2
      web/building_saas/main/js/views/config_material_view.js
  87. 27 8
      web/building_saas/main/js/views/divide_view.js
  88. 1 1
      web/building_saas/main/js/views/electrovalence_view.js
  89. 84 6
      web/building_saas/main/js/views/fee_rate_view.js
  90. 20 5
      web/building_saas/main/js/views/glj_col.js
  91. 20 4
      web/building_saas/main/js/views/glj_view.js
  92. 3 2
      web/building_saas/main/js/views/glj_view_contextMenu.js
  93. 94 15
      web/building_saas/main/js/views/importBills.js
  94. 1 1
      web/building_saas/main/js/views/locate_view.js
  95. 702 628
      web/building_saas/main/js/views/main_tree_col.js
  96. 22 8
      web/building_saas/main/js/views/material_calc_view.js
  97. 1 1
      web/building_saas/main/js/views/mbzm_view.js
  98. 2 2
      web/building_saas/main/js/views/project_glj_view.js
  99. 3 3
      web/building_saas/main/js/views/project_info.js
  100. 0 0
      web/building_saas/main/js/views/project_property_basicInfo.js

+ 1 - 1
config/config.js

@@ -123,7 +123,7 @@ module.exports = {
   pp_sc: {
     title: "纵横公路云造价",
     startPort: 3060,
-    server: "172.18.111.231",
+    server: "112.74.42.187",
     port: "27017",
     dbname: 'smartcost',
     options: {

+ 10 - 1
config/gulpConfig.js

@@ -3,7 +3,7 @@
  */
 
 module.exports = {
-    version:'1.0.2',
+    version:'1.0.3',
     common_jspaths:[
         'lib/jquery/jquery-3.2.1.min.js',
         'lib/jquery-ui/jquery-ui.min.js',
@@ -44,6 +44,7 @@ module.exports = {
     pm_jspaths:[
         'public/web/syntax-detection.js',
         'public/web/uuid.js',
+        'public/billsUtil.js',
         'public/web/date_util.js',
         'public/web/upload_cdn.js',
         'public/web/id_tree.js',
@@ -82,6 +83,7 @@ module.exports = {
         'lib/pinyinjs/pinyin_dict_firstletter.js',
         'lib/pinyinjs/pinyinUtil.js',
         'web/building_saas/main/js/models/main_consts.js',
+        'web/building_saas/main/js/models/feeRateConsts.js',
         'public/web/common_util.js',
         'web/building_saas/glj/js/project_glj.js',
         'web/building_saas/glj/js/composition.js',
@@ -197,6 +199,9 @@ module.exports = {
         'lib/ztree/css/zTreeStyle.css',
     ],
     compleGlj_jspaths: [
+        'lib/pinyinjs/pinyin_dict_firstletter.js',
+        'lib/pinyinjs/pinyinUtil.js',
+        'web/common/components/share/index.js',
         'public/web/common_ajax.js',
         'public/web/treeDataHelper.js',
         'public/web/QueryParam.js',
@@ -206,6 +211,7 @@ module.exports = {
         'public/web/tree_sheet/tree_sheet_helper.js',
         'public/web/tools_const.js',
         'public/web/ration_glj_units.js',
+        'web/building_saas/complementary_glj_lib/js/init.js',
         'web/building_saas/complementary_glj_lib/js/glj.js',
         'web/building_saas/complementary_glj_lib/js/gljClassTree.js',
         'web/building_saas/complementary_glj_lib/js/gljComponent.js',
@@ -226,6 +232,9 @@ module.exports = {
         'lib/jquery-contextmenu/jquery.ui.position.js',
         'lib/ztree/jquery.ztree.core.js',
         'web/building_saas/complementary_ration_lib/js/global.js',
+        'lib/pinyinjs/pinyin_dict_firstletter.js',
+        'lib/pinyinjs/pinyinUtil.js',
+        'web/common/components/share/index.js',
         'public/web/id_tree.js',
         'public/web/tree_sheet/tree_sheet_controller.js',
         'public/web/tree_sheet/tree_sheet_helper.js',

+ 4 - 0
logs/online_logs.js

@@ -8,6 +8,7 @@ module.exports = {
 let mongoose = require("mongoose");
 const moment = require("moment");
 let logs_model = mongoose.model("online_logs");
+let user_model = mongoose.model("user");
 
 async function saveOnlineTime(req) {
     let online_times = 0;
@@ -26,14 +27,17 @@ async function saveOnlineTime(req) {
         if(!req.session.sessionUser||!req.session.sessionCompilation) return;
         let dataString = moment(end).format('YYYY-MM-DD');
         let condition = {userID:req.session.sessionUser.id,compilationID:req.session.sessionCompilation._id,dateString:dataString};
+        let userCondition = {_id: mongoose.Types.ObjectId(req.session.sessionUser.id)};
         let record = await logs_model.findOne(condition);
         if(record){ //如果找到,则累加
             await logs_model.update(condition,{$inc:{'online_times' : online_times }});
+            await user_model.update(userCondition,{$inc:{'online_times' : online_times }});
         }else {//如果没找到,则新增一条记录
             condition["online_times"] = online_times;
             let today = moment(dataString).toDate();
             condition["dateTime"] = +today;
             await logs_model.create(condition);
+            await user_model.update(userCondition,{'online_times' : online_times});
         }
     }catch (e){
         console.log("统计登录时间错误,online_times值:"+online_times);

+ 5 - 0
modules/all_models/bills.js

@@ -20,6 +20,7 @@ let billsSchema = new Schema({
   chapterID: Number,
   billsLibId: Number,
   code: String,
+  sectionCode: String, // 清单章节号,池州接口需要
   fullCode: String,
   type: {
     type: Number,
@@ -96,6 +97,10 @@ let billsSchema = new Schema({
     default: 0
   }, // 1 true 0 false 单价分析
   specialProvisional: String,
+  outPutMaxPrice:{type:Schema.Types.Mixed,default:false},//输出最高限价 true 是,false否,null 不确定,三个状态
+  outPutLimitPrice:{type:Schema.Types.Mixed,default:false},//输出限价 true 是,false否,null 不确定,三个状态
+  maxPrice:String,//最高限价
+  minPrice:String,//最低限价
   remark: String,
   engineeringContent: String, //工程内容
   serviceContent: String, //服务内容

+ 2 - 2
modules/all_models/compilation.js

@@ -62,11 +62,11 @@ let modelSchema = {
         type: Number,
         default: 0
     },
-
     // cld 办事处id
     categoryID: {
         type: Number,
         default: 12 // 总部id
-    }
+    },
+    defaultLocation:String//默认工程所在地
 };
 mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));

+ 2 - 1
modules/all_models/compleRation_ration.js

@@ -10,7 +10,8 @@ const deleteSchema = require('../all_schemas/delete_schema');
 const compleRationGljItemSchema = new Schema({
     gljId: Number,
     consumeAmt: String,
-    type: String    //std or complementary
+    type: String,    //std or complementary
+    fromUser: String,
 
 }, { _id: false });
 

+ 3 - 0
modules/all_models/projects.js

@@ -3,6 +3,7 @@
  */
 /*项目*/
 const mongoose = require('mongoose');
+const { stringAt } = require('pdfkit/js/data');
 const Schema = mongoose.Schema;
 const deleteSchema = require('../all_schemas/delete_schema');
 
@@ -18,6 +19,7 @@ const ProjectSchema = new Schema({
     "ParentID": Number,
     "NextSiblingID": Number,
     "userID": String,
+    "importedByInterface": {type: Boolean, default: false},
     "name": String,
     "projType": String,
     "recentDateTime": Date,
@@ -30,6 +32,7 @@ const ProjectSchema = new Schema({
         type: Schema.Types.Mixed,
         default: {}
     },
+    "location":String,//工程所在地
     "summaryFees":{
         totalFee: String,
         estimateFee: String,

+ 1 - 0
modules/all_models/ration.js

@@ -54,6 +54,7 @@ let rationSchema = new Schema({
     type: Number,                               // 1 定额、2 量价、3 工料机定额
     subType: Number,                            // 子类型:1人工、201材料、301机械、4主材、5设备
     from:{type: String,default:'std'},          //std, cpt  来自标准、补充
+    fromUser: String, // 来自某个用户的定额(分享补充定额)
     isSubcontract: Boolean,                     // 是否分包
     installationKey:String,                   //用来记录安装增加费的关联字段
     // 定额特有属性:

+ 2 - 1
modules/all_models/ration_glj.js

@@ -45,7 +45,8 @@ var ration_glj = new Schema({
         default: 0
     },
     createType: {type: String,default:'normal'},//normal、add、replace  正常、添加工料机、替换工料机
-    from:{type: String,default:'std'}//std, cpt  来自标准工料机库、补充工料机库
+    from:{type: String,default:'std'},//std, cpt  来自标准工料机库、补充工料机库
+    fromUser: String, // 来自某个用户的人材机(分享补充人材机)
 },{versionKey:false});
 
 mongoose.model('ration_glj', ration_glj);

+ 18 - 0
modules/all_models/share_lib.js

@@ -0,0 +1,18 @@
+// 分享库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const shareSchema = new Schema({
+    ID: String,
+    compilationID: String,
+    owner: String, // 拥有者ID
+    receiver: String, // 接收者ID
+    libType: Number, // 1: 定额库; 2: 人材机库; 3: 组价模板库;
+    allowCooperate: {
+        type: Boolean,
+        default: false
+    },
+    shareDate: String,
+    updateDate: String
+}, {versionKey: false});
+
+mongoose.model('share_libs', shareSchema, 'share_libs');

+ 2 - 2
modules/all_models/unit_price.js

@@ -13,9 +13,9 @@ let modelSchema = {
     // 自增ID
     id: {type:Number,unique: true},
     // 基价单价
-    base_price: String,
+    base_price: {type:String,default: '0'},
     // 市场单价
-    market_price: String,
+    market_price: {type:String,default: '0'},
     // 编码
     code: {
         type: String,

+ 1 - 0
modules/all_models/unit_price_file.js

@@ -28,6 +28,7 @@ let modelSchema = {
     root_project_id: Number,
     vvTaxFileID:String,//车船税文件ID
     assistProductionFeeRate:String,//辅助生产间接费费率
+    machineConstCoe:String,//机械不变费用系数
     deleteInfo: deleteSchema
 };
 mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));

+ 9 - 1
modules/all_models/user.js

@@ -120,6 +120,14 @@ let schema = {
         default: 0
     },
     welcomeShowTime:String,
-    token: String
+    token: String,
+    online_times: {
+        type: Number,
+        default: 0
+    }, //最近一天的登录时长累计
+    is_cld: {
+        type: Number,
+        default: 0, // 0为普通用户,时间戳代表CLD剔除用户并按时间戳排序
+    },
 };
 mongoose.model(collectionName, new Schema(schema, {versionKey: false}));

+ 56 - 22
modules/complementary_glj_lib/controllers/gljController.js

@@ -6,46 +6,80 @@ const stdgljutil  = require("../../../public/cache/std_glj_type_util");
 const GljDao = require("../models/gljModel");
 const EngineeringLibModel = require("../../users/models/engineering_lib_model");
 const config = require("../../../config/config.js");
-
+const pmFacade = require('../../pm/facade/pm_facade');
+const { ShareLibType } = require('../../../public/common_constants');
 let gljDao = new GljDao();
 let callback = function(req, res, err, message, data){
     res.json({error: err, message: message, data: data});
 };
 
+async function getGljLibId(sessionCompilation) {
+    let gljLibId = null,
+        rationValuation = sessionCompilation.ration_valuation,
+        billValuation = sessionCompilation.bill_valuation,
+        engineeringLibModel = new EngineeringLibModel(),
+        valuationIDs = [] ;
+    for(let r of rationValuation){//{ "glj_lib.0": {$exists:1} }
+        if(r.id){
+            valuationIDs.push(r.id);
+        }
+    }
+    for(let b of billValuation){
+        if(b.id){
+            valuationIDs.push(b.id);
+        }
+    }
+    if(valuationIDs.length > 0){
+        let engineeringInfo = await engineeringLibModel.findDataByCondition({'valuationID': {"$in": valuationIDs},"glj_lib.0": {$exists:1}});//数组大于0
+        gljLibId = engineeringInfo.glj_lib.length > 0 && typeof engineeringInfo.glj_lib !== 'undefined' ? engineeringInfo.glj_lib[0].id : null;
+    }
+    return gljLibId;
+}
+
 class GljController extends BaseController{
     async redirectGlj(req, res){
-        let gljLibId = null, engineeringId, sessionCompilation = req.session.sessionCompilation,
-            rationValuation = sessionCompilation.ration_valuation,
-            billValuation = sessionCompilation.bill_valuation,
-            engineeringLibModel = new EngineeringLibModel(),
-            valuationIDs = [] ;
-        for(let r of rationValuation){//{ "glj_lib.0": {$exists:1} }
-            if(r.id){
-                valuationIDs.push(r.id);
+        const { userID } = req.params;
+        const sessionUserID = req.session.sessionUser.id;
+        const compilationID = req.session.sessionCompilation._id;
+        if (userID !== sessionUserID) {
+            const receiveList = await pmFacade.getReceiveLibList(sessionUserID, compilationID, ShareLibType.GLJ_LIB);
+            const isValid = !!receiveList.find(user => String(user._id) === userID);
+            if (!isValid) {
+                return res.redirect(`/complementaryGlj/${sessionUserID}`);
             }
         }
-        for(let b of billValuation){
-            if(b.id){
-                valuationIDs.push(b.id);
-            }
-        }
-        if(valuationIDs.length > 0){
-            let engineeringInfo = await engineeringLibModel.findDataByCondition({'valuationID': {"$in": valuationIDs},"glj_lib.0": {$exists:1}});//数组大于0
-            gljLibId = engineeringInfo.glj_lib.length > 0 && typeof engineeringInfo.glj_lib !== 'undefined' ? engineeringInfo.glj_lib[0].id : null;
-        }
-        let overWriteUrl = req.session.sessionCompilation && req.session.sessionCompilation.overWriteUrl &&
-                            req.session.sessionCompilation._id !== '5b4d581023a924000b760f2d' ? req.session.sessionCompilation.overWriteUrl : null;
+        const sessionCompilation = req.session.sessionCompilation;
+        const gljLibId = await getGljLibId(sessionCompilation);
+        let overWriteUrl = sessionCompilation && req.session.sessionCompilation.overWriteUrl &&
+            compilationID !== '5b4d581023a924000b760f2d' ? req.session.sessionCompilation.overWriteUrl : null;
+        const isReadOnly = userID !== sessionUserID;
         res.render('building_saas/complementary_glj_lib/html/tools-gongliaoji.html',{
-            userID: req.session.sessionUser.id,
+            isReadOnly,
+            userID: sessionUserID,
             gljLibId: gljLibId,
             compilationId: sessionCompilation._id,
             compilationName: sessionCompilation.name,
             versionName: req.session.compilationVersion,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
             overWriteUrl: overWriteUrl,
-            title:config[process.env.NODE_ENV].title?config[process.env.NODE_ENV].title:"?????????"
+            title:config[process.env.NODE_ENV].title?config[process.env.NODE_ENV].title:"纵横公路养护云造价"
         });
     }
+
+    async prepareInitData(req, res) {
+        try {
+            const { userID, projection } = JSON.parse(req.body.data);
+            const sessionUserID = req.session.sessionUser.id;
+            const gljLibID = await getGljLibId(req.session.sessionCompilation);
+            const compilationID = req.session.sessionCompilation._id;
+            const initData = await gljDao.prepareInitData(gljLibID, userID, sessionUserID, compilationID, projection);
+            res.json({error: 0, message: 'success', data: initData});
+        } catch (err) {
+            console.log(err);
+            res.json({error: 1, message: 'fail', data: null});
+        }
+    }
+    
     getGljDistType (req, res) {
         let gljDistTypeCache = stdgljutil.getStdGljTypeCacheObj().toArray();
         if(gljDistTypeCache.length >0 ){

+ 33 - 0
modules/complementary_glj_lib/models/gljModel.js

@@ -9,8 +9,27 @@ const compleClassModel = mongoose.model('complementary_glj_section');
 const counter = require("../../../public/counter/counter");
 const async = require("async");
 const STDGLJLibGLJListModel = require("../../common/std/std_glj_lib_glj_list_model");
+const stdgljutil = require("../../../public/cache/std_glj_type_util");
+const { ShareLibType } = require('../../../public/common_constants');
 
 class GljDao {
+
+    async prepareInitData(gljLibID, userID, sessionUserID, compilationID, projection) {
+        const pmFacade = require('../../pm/facade/pm_facade');
+        const receiveLibs = await pmFacade.getReceiveLibList(sessionUserID, compilationID, ShareLibType.GLJ_LIB);
+        const shareLibs = sessionUserID === userID ? await pmFacade.getLibShareList(sessionUserID, compilationID, ShareLibType.GLJ_LIB) : [];
+        const gljItems = await this.getGLJItemsSync(gljLibID, userID, compilationID, projection);
+        const mixTree = await this.getMixedTree(gljLibID, userID, compilationID);
+        const gljDistTypeCache = stdgljutil.getStdGljTypeCacheObj().toArray();
+        return {
+            receiveLibs,
+            shareLibs,
+            gljItems,
+            mixTree,
+            distTypeData: gljDistTypeCache,
+        };
+    }
+
     getGljTypes (gljLibId, callback){
         gljClassModel.find({"repositoryId": gljLibId},function(err,data){
             if(data.length) {
@@ -96,6 +115,20 @@ class GljDao {
 
     }
 
+    async getGLJItemsSync(stdGljLibId, userId, compilationId, projection) {
+        const rst = { stdGljs: [], complementaryGljs: [] };
+        const task = [
+            stdGljModel.find({ repositoryId: stdGljLibId }, projection).lean(),
+            complementaryGljModel.find({ userId: userId, compilationId: compilationId }, '-_id').lean()
+        ];
+        const [ stdRst, cptRst ] = await Promise.all(task);
+        this.sortToNumber(stdRst);
+        rst.stdGljs = stdRst;
+        this.sortToNumber(cptRst);
+        rst.complementaryGljs = cptRst;
+        return rst;
+    }
+
     async getStdItems (stdGljLibId, projection, callback) {
         try {
             let stdItems = await stdGljModel.find({repositoryId: stdGljLibId}, projection).lean();

+ 2 - 1
modules/complementary_glj_lib/routes/routes.js

@@ -11,13 +11,14 @@ let gljController = new GljController();
 let compleRationController = new CompleRationController();
 
 module.exports = function (app) {
-    app.get('/complementaryGlj', gljController.init, gljController.redirectGlj);
+    app.get('/complementaryGlj/:userID', gljController.init, gljController.redirectGlj);
 
    /* router.post("/updateRationBasePrc",gljController.init, gljController.updateRationBasePrc);//更新定额单价
     router.post("/getRationGljIds", gljController.init, gljController.getRationGljIds);
     router.post("/createNewGljTypeNode", gljController.init, gljController.createNewGljTypeNode);
     router.post("/updateGljNodes", gljController.init, gljController.updateGljNodes);
     router.post("/deleteGljNodes", gljController.init, gljController.deleteGljNodes);*/
+    router.post("/initData", gljController.init, gljController.prepareInitData);
     router.post("/getGljDistType", gljController.init, gljController.getGljDistType);
     router.post("/getGljTree", gljController.init, gljController.getGljTree);
     router.post("/getGljItems", gljController.init, gljController.getGljItems);

+ 4 - 2
modules/complementary_ration_lib/controllers/compleRationController.js

@@ -99,7 +99,8 @@ class CompleRationController extends BaseController{
                 if(overWrite.sortRationGLJ) util = overWrite;
             }
             if (data.type === libType.complementary) {
-                rations = await compleRationDao.getCompleRationBySection(req.session.sessionUser.id, data.sectionId,util);
+                const userID = data.owner || req.session.sessionUser.id;
+                rations = await compleRationDao.getCompleRationBySection(userID, data.sectionId,util);
             }  else {
                 rations = await compleRationDao.getRationGljItemsBySection(data.sectionId,util);
             }
@@ -111,7 +112,8 @@ class CompleRationController extends BaseController{
 
     async getCoeList(req, res){
         try{
-            let coeList = await coeFacade.getComplementaryCoes(req.session.sessionUser.id, req.session.sessionCompilation._id);
+            const { userID } = JSON.parse(req.body.data);
+            let coeList = await coeFacade.getComplementaryCoes(userID, req.session.sessionCompilation._id);
             callback(req, res, 0, 'success', coeList);
         } catch (err) {
             callback(req, res, 1, err, null);

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

@@ -20,7 +20,8 @@ class CompleSectionTreeController extends BaseController{
 
     getRationTree(req, res){
         let data = JSON.parse(req.body.data);
-        sectionTreeDao.getRationTree(req.session.sessionUser.id, req.session.sessionCompilation._id, data.rationRepId, data.type, function (err, data) {
+        const userID = data.owner || req.session.sessionUser.id;
+        sectionTreeDao.getRationTree(userID, req.session.sessionCompilation._id, data.rationRepId, data.type, function (err, data) {
             callback(req, res, err, '', data);
         });
     }

+ 34 - 18
modules/complementary_ration_lib/controllers/compleViewController.js

@@ -9,6 +9,8 @@ let config = require("../../../config/config.js");
 let compleViewModel = new CompleViewModel();
 const CompleRationDao = require('../models/compleRationModel');
 const compleRationDao = new CompleRationDao();
+const pmFacade = require('../../pm/facade/pm_facade');
+const { ShareLibType } = require('../../../public/common_constants');
 let callback = function (req, res, err, msg, data) {
     res.json({error: err, message: msg, data: data});
 };
@@ -38,12 +40,24 @@ async function getGljLibId(sessionCompilation) {
 
 class CompleViewController extends BaseController{
     async redirectRation(req, res){
+        const { userID } = req.params;
+        const sessionUserID = req.session.sessionUser.id;
+        const compilationID = req.session.sessionCompilation._id;
+        if (userID !== sessionUserID) {
+            const receiveList = await pmFacade.getReceiveLibList(sessionUserID, compilationID, ShareLibType.RATION_LIB);
+            const isValid = !!receiveList.find(user => String(user._id) === userID);
+            if (!isValid) {
+                return res.redirect(`/complementaryRation/ration/${sessionUserID}`);
+            }
+        }
         const gljLibId = await getGljLibId(req.session.sessionCompilation);
-        const redirectGlj = `/complementaryRation/glj`;
-        const redirectCoe = `/complementaryRation/coe`;
-        const redirectInstallation = `/complementaryRation/installation`;
+        const redirectGlj = `/complementaryRation/glj/${userID}`;
+        const redirectCoe = `/complementaryRation/coe/${userID}`;
+        const redirectInstallation = `/complementaryRation/installation/${userID}`;
+        const isReadOnly = userID !== sessionUserID;
         res.render('building_saas/complementary_ration_lib/html/dinge.html', {
-            userID: req.session.sessionUser.id,
+            isReadOnly,
+            userID: sessionUserID,
             redirectGlj: redirectGlj,
             redirectCoe: redirectCoe,
             redirectInstallation: redirectInstallation,
@@ -51,16 +65,17 @@ class CompleViewController extends BaseController{
             compilationName: req.session.sessionCompilation.name,
             versionName: req.session.compilationVersion,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
-            title:config[process.env.NODE_ENV].title?config[process.env.NODE_ENV].title:"?????????"
+            title:config[process.env.NODE_ENV].title?config[process.env.NODE_ENV].title:"纵横公路养护云造价"
         });
     }
 
     async prepareInitData (req, res) {
         try {
+            const { userID } = req.query;
+            const sessionUserID = req.session.sessionUser.id;
             const gljLibId = await getGljLibId(req.session.sessionCompilation);
-            const userId = req.session.sessionUser.id;
             const compilationId = req.session.sessionCompilation._id;
-            const initData = await compleRationDao.prepareInitData(userId, compilationId, gljLibId);
+            const initData = await compleRationDao.prepareInitData(sessionUserID, userID, compilationId, gljLibId);
             res.json({error: 0, message: 'success', data: initData});
         } catch (err) {
             res.json({error: 1, message: 'fail', data: null});
@@ -68,10 +83,11 @@ class CompleViewController extends BaseController{
     }
 
     async redirectGljList(req, res){
+        const { userID } = req.params;
         const gljLibId = await getGljLibId(req.session.sessionCompilation);
-        const redirectRation = `/complementaryRation/ration`;
-        const redirectCoe = `/complementaryRation/coe`;
-        const redirectInstallation = `/complementaryRation/installation`;
+        const redirectRation = `/complementaryRation/ration/${userID}`;
+        const redirectCoe = `/complementaryRation/coe/${userID}`;
+        const redirectInstallation = `/complementaryRation/installation/${userID}`;
         res.render('building_saas/complementary_ration_lib/html/gongliao.html', {
             userID: req.session.sessionUser.id,
             redirectRation: redirectRation,
@@ -81,15 +97,15 @@ class CompleViewController extends BaseController{
             compilationName: req.session.sessionCompilation.name,
             versionName: req.session.compilationVersion,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
-            title:config[process.env.NODE_ENV].title?config[process.env.NODE_ENV].title:"?????????"
+            title:config[process.env.NODE_ENV].title?config[process.env.NODE_ENV].title:"纵横公路养护云造价"
         });
     }
 
     async redirectCoeList(req, res){
         const gljLibId = await getGljLibId(req.session.sessionCompilation);
-        const redirectRation = `/complementaryRation/ration`;
-        const redirectGlj = `/complementaryRation/glj`;
-        const redirectInstallation = `/complementaryRation/installation`;
+        const redirectRation = `/complementaryRation/ration/${userID}`;
+        const redirectGlj = `/complementaryRation/glj/${userID}`;
+        const redirectInstallation = `/complementaryRation/installation/${userID}`;
         res.render('building_saas/complementary_ration_lib/html/fuzhu.html', {
             userID: req.session.sessionUser.id,
             redirectRation: redirectRation,
@@ -99,15 +115,15 @@ class CompleViewController extends BaseController{
             compilationName: req.session.sessionCompilation.name,
             versionName: req.session.compilationVersion,
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
-            title:config[process.env.NODE_ENV].title?config[process.env.NODE_ENV].title:"?????????"
+            title:config[process.env.NODE_ENV].title?config[process.env.NODE_ENV].title:"纵横公路养护云造价"
         });
     }
 
     redirectInstallation(req, res){
         const repId = req.query.repository;
-        const redirectRation = `/complementaryRation/ration`;
-        const redirectGlj = `/complementaryRation/glj?repository=${repId}`;
-        const redirectCoe = `/complementaryRation/coe?repository=${repId}`;
+        const redirectRation = `/complementaryRation/ration/${userID}`;
+        const redirectGlj = `/complementaryRation/glj?repository=${repId}/${userID}`;
+        const redirectCoe = `/complementaryRation/coe?repository=${repId}/${userID}`;
         res.render('building_saas/complementary_ration_lib/html/anzhuang.html', {
             userID: req.session.sessionUser.id,
             redirectRation: redirectRation,

+ 14 - 4
modules/complementary_ration_lib/models/compleRationModel.js

@@ -19,7 +19,8 @@ const gljDao = new GljDao();
 let counter = require('../../../public/counter/counter');
 const scMathUtil = require('../../../public/scMathUtil').getUtil();
 let gljUtil = require('../../../public/gljUtil');
-
+const { ShareLibType } = require('../../../public/common_constants');
+const pmFacade = require('../../pm/facade/pm_facade');
 class CompleRatoinDao {
     async updateRation(userID, compilationId, updateData, callback){
         try{
@@ -99,7 +100,8 @@ class CompleRatoinDao {
                     }
                 }
                 else if(ids[i].type === 'complementary'){
-                    let compleGlj = await complementaryGljModel.find({userId: userID, ID: ids[i].id, deleteInfo: null});
+                    const owner = ids[i].fromUser || userID;
+                    let compleGlj = await complementaryGljModel.find({userId: owner, ID: ids[i].id, deleteInfo: null});
                     if(compleGlj.length > 0){
                         compleGlj[0]._doc.type = 'complementary';
                         rst.push(compleGlj[0]);
@@ -148,6 +150,7 @@ class CompleRatoinDao {
                 comGljIds = [],
                 stdGljs = [],
                 comGljs = [];
+            const users = [userId];
             let gljAmtMapping = {};
             for(let rationGlj of ration.rationGljList){
                 gljAmtMapping[rationGlj.gljId] = rationGlj.consumeAmt;
@@ -155,6 +158,9 @@ class CompleRatoinDao {
                     stdGljIds.push(rationGlj.gljId);
                 }
                 else {
+                    if (rationGlj.fromUser && !users.includes(rationGlj.fromUser)) {
+                        users.push(rationGlj.fromUser);
+                    }
                     comGljIds.push(rationGlj.gljId);
                 }
             }
@@ -162,7 +168,7 @@ class CompleRatoinDao {
                 stdGljs = await stdGljModel.find({ID: {$in: stdGljIds}}).lean();
             }
             if(comGljIds.length > 0) {
-                comGljs = await complementaryGljModel.find({userId: userId, ID: {$in: comGljIds}});
+                comGljs = await complementaryGljModel.find({userId: { $in: users }, ID: {$in: comGljIds}}).lean();
             }
             if(!gUtil) gUtil = gljUtil;
             let gljDatas = gUtil.sortRationGLJ(stdGljs.concat(comGljs), true);
@@ -463,7 +469,9 @@ class CompleRatoinDao {
         return codes;
     }
 
-    async prepareInitData (userId, compilationId, gljLibId) {
+    async prepareInitData (sessionUserID, userId, compilationId, gljLibId) {
+        const receiveLibs = await pmFacade.getReceiveLibList(sessionUserID, compilationId, ShareLibType.RATION_LIB);
+        const shareLibs = sessionUserID === userId ? await pmFacade.getLibShareList(sessionUserID, compilationId, ShareLibType.RATION_LIB) : [];
         const rationsCodes = await this.getCodes(userId, compilationId);
         const gljDistTypeCache = stdgljutil.getStdGljTypeCacheObj().toArray();
         const installationData = await installFacade.getInstallation(userId, compilationId);
@@ -471,6 +479,8 @@ class CompleRatoinDao {
         const mixedTreeData = await gljDao.getMixedTree(gljLibId, userId, compilationId);
         const mixedGLJData = await gljDao.getGLJDataSync(gljLibId, userId, compilationId);
         return {
+            shareLibs,
+            receiveLibs,
             rationsCodes,
             gljDistTypeCache,
             installationData,

+ 48 - 18
modules/complementary_ration_lib/models/searchModel.js

@@ -6,6 +6,7 @@ const compleRationModel = mongoose.model('complementary_ration_items');
 const complementaryGljModel = mongoose.model('complementary_glj_lib');
 const stdGljModel = mongoose.model('std_glj_lib_gljList');
 const compleRationSectionTreeModel = mongoose.model('complementary_ration_section_tree');
+const rationLibModel = mongoose.model('std_ration_lib_map');
 let stdSectionTreeModel = require ('../../ration_repository/models/ration_section_tree').Model;
 let stdRationModel = require ('../../ration_repository/models/ration_item').Model;
 
@@ -15,15 +16,19 @@ class SearchDao{
     async getRationItem(userId, compilationId, rationRepIds, code, ID, callback){
         let ration = null;
         let otherLibs=[];
+        const compleLibUsers = [userId];
         try{
-            let firstLib = rationRepIds[0];//优先取第一个
+            let [firstLib] = String(rationRepIds[0]).split('*');//优先取第一个
             for (let l of rationRepIds){
-                if(l != firstLib && l != compleRationLib){
-                    otherLibs.push(l);
+                const [libID, owner] = String(l).split('*');
+                if(libID != firstLib && libID != compleRationLib){
+                    otherLibs.push(libID);
+                } else if (libID === compleRationLib && owner && !compleLibUsers.includes(owner)) {
+                    compleLibUsers.push(owner);
                 }
             }
             if(firstLib == compleRationLib){//说明选中的是补充定额库
-                ration = await this.getCompleRation(userId,compilationId,code,ID);
+                ration = await this.getCompleRation(compleLibUsers,compilationId,code,ID);
             }else {
                 firstLib = parseInt(firstLib);
                 let firstQuery = {rationRepId: firstLib, code: code};
@@ -38,16 +43,16 @@ class SearchDao{
                     stdQuery = {ID: ID};
                 }
                 ration = await this.getStdRation(stdQuery);
-                if(ration == null) ration = await this.getCompleRation(userId,compilationId,code,ID);
+                if(ration == null) ration = await this.getCompleRation(compleLibUsers,compilationId,code,ID);
             }
             if(isDef(ration)){
                 if (ration.type === 'std') {
-                    let stdChapter = await stdSectionTreeModel.findOne({rationRepId: ration.rationRepId, ID: ration.sectionId, $or: [{isDeleted: null}, {isDeleted: false}]});
+                    let stdChapter = await stdSectionTreeModel.findOne({ID: ration.sectionId});
                     if(isDef(stdChapter)){
                         ration.chapter = stdChapter._doc;
                     }
                 } else {
-                    let compleChapter = await compleRationSectionTreeModel.findOne({ID: ration.sectionId, $or: [{isDeleted: null}, {isDeleted: false}]});
+                    let compleChapter = await compleRationSectionTreeModel.findOne({ID: ration.sectionId});
                     if(isDef(compleChapter)){
                         ration.chapter = compleChapter._doc;
                     }
@@ -64,9 +69,9 @@ class SearchDao{
         }
         return ration;
     }
-    async getCompleRation(userId,compilationId,code,ID){
+    async getCompleRation(users,compilationId,code,ID){
         let ration = null;
-        let compleQuery = {userId: userId, compilationId: compilationId, code: code, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]};
+        let compleQuery = {userId: { $in: users }, compilationId: compilationId, code: code, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]};
         if(ID){
             compleQuery.ID = ID;
         }
@@ -86,6 +91,21 @@ class SearchDao{
         }
         return ration;
     }
+    // 设置定额所属定额库数据
+    async setRationLibName(stdRations, compleRations) {
+        const rationLibIDSet = new Set();
+        stdRations.forEach(ration => {
+            rationLibIDSet.add(ration.rationRepId);
+        });
+        const rationLibNameList = await rationLibModel.find({ ID: { $in: [...rationLibIDSet] } }, '-_id dispName ID').lean();
+        const rationLibNameMap = {};
+        rationLibNameList.forEach(lib => rationLibNameMap[lib.ID] = lib.dispName);
+        stdRations.forEach(ration => {
+            ration.rationLibName = rationLibNameMap[ration.rationRepId];
+        });
+        compleRations.forEach(ration => ration.rationLibName = '我的补充定额');
+    }
+
     //@param {Object}skip({std: Number, comple: Number})
     async findRation(userId, compilationId, rationRepId, keyword, skip, callback){
         //每次限制结果数
@@ -94,14 +114,21 @@ class SearchDao{
         let resultCount = 0,
             rst = {data: [], count: null};
         try{
+            let compleLibUsers = new Set();
+            const stdRationLibs = [];
+            rationRepId.forEach(libItem => {
+                const [libID, owner] = String(libItem).split('*');
+                if (libID === compleRationLib) {
+                    compleLibUsers.add(owner || userId);
+                } else {
+                    stdRationLibs.push(libID);
+                }
+            });
+            compleLibUsers = [...compleLibUsers];
             //是否需要查找补充定额
-            let findCompleRtion = rationRepId.length > 0 && rationRepId.includes(compleRationLib) ? true : false;
-            //剔除补充定额库id
-            if (rationRepId.includes(compleRationLib)) {
-                rationRepId.splice(rationRepId.indexOf(compleRationLib), 1);
-            }
+            let findCompleRtion = compleLibUsers.length > 0;
             let filter = {
-                'rationRepId': {$in: rationRepId},
+                'rationRepId': {$in: stdRationLibs},
                 '$and': [{
                     '$or': [{'code': {'$regex': keyword, $options: '$i'}}, {'name': {'$regex': keyword, $options: '$i'}}]
                 }, {
@@ -109,7 +136,7 @@ class SearchDao{
                 }]
             };
             let compleFilter = {
-                userId: userId,
+                userId: { $in: compleLibUsers },
                 compilationId: compilationId,
                 '$and': [{
                     '$or': [{'code': {'$regex': keyword, $options: '$i'}}, {'name': {'$regex': keyword, $options: '$i'}}]
@@ -119,14 +146,14 @@ class SearchDao{
             };
             //结果数
             if (skip && skip.std === 0 && skip.comple === 0) {
-                resultCount += rationRepId.length === 0 ? 0 : await stdRationModel.find(filter).count();
+                resultCount += stdRationLibs.length === 0 ? 0 : await stdRationModel.find(filter).count();
                 resultCount += findCompleRtion ? await compleRationModel.find(compleFilter).count() : 0;
                 rst.count = resultCount;
             }
             //搜索定额
             let stdGljIds = [],
                 comGljIds = [];
-            let stdRations = rationRepId.length === 0 ? [] : await stdRationModel.find(filter).lean().sort({code: 1}).skip(skip.std).limit(limit);
+            let stdRations = stdRationLibs.length === 0 ? [] : await stdRationModel.find(filter).lean().sort({code: 1}).skip(skip.std).limit(limit);
             for(let i = 0, len = stdRations.length; i < len; i++){
                 stdRations[i].type = 'std';
                 for(let glj of stdRations[i].rationGljList){
@@ -150,6 +177,9 @@ class SearchDao{
                 }
             }
 
+            // 设置定额所属定额库名称
+            await this.setRationLibName(stdRations, compleRations);
+
             //设置悬浮信息
             stdGljIds = Array.from(new Set(stdGljIds));
             comGljIds = Array.from(new Set(comGljIds));

+ 4 - 4
modules/complementary_ration_lib/routes/routes.js

@@ -17,10 +17,10 @@ let gljController = new GljController();
 let searchController = new SearchController();
 
 module.exports = function (app) {
-    app.get('/complementaryRation/ration', compleViewController.init, compleViewController.redirectRation);
-    app.get('/complementaryRation/glj', compleViewController.init, compleViewController.redirectGljList);
-    app.get('/complementaryRation/coe', compleViewController.init, compleViewController.redirectCoeList);
-    app.get('/complementaryRation/installation', compleViewController.init, compleViewController.redirectInstallation);
+    app.get('/complementaryRation/ration/:userID', compleViewController.init, compleViewController.redirectRation);
+    app.get('/complementaryRation/glj/:userID', compleViewController.init, compleViewController.redirectGljList);
+    app.get('/complementaryRation/coe/:userID', compleViewController.init, compleViewController.redirectCoeList);
+    app.get('/complementaryRation/installation/:userID', compleViewController.init, compleViewController.redirectInstallation);
     router.get('/initData', compleViewController.init, compleViewController.prepareInitData);
 
     router.post('/getRationLib', compleViewController.init, compleViewController.getRationLib);

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

@@ -111,7 +111,7 @@ async function changeFeeRateStandard(req, res) {
         let newFeeRateFile= await feeRateFacde.changeFeeRateStandard(data);
         result.data= newFeeRateFile;
     }catch (err){
-        console.log(err);
+        console.log(err.stack);
         result.error=1;
         result.message = err.message;
     }

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

@@ -259,7 +259,7 @@ async function getFeeRateStandardsByProjectID(projectID) {
 
 async function changeFeeRateStandard(jdata){
     let data = JSON.parse(jdata);
-    let template = await std_fee_rate_lib_model.findOne({"ID":data.newLibID});
+    let template = await std_fee_rate_lib_model.findOne({"ID":data.newLibID}).lean();
     let newFeeRate = {};
     newFeeRate.ID =uuidV1();
     newFeeRate.rates=template.rates;

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

@@ -945,7 +945,8 @@ async function getGLJListByProjectID(projectId){
             usedUnitPriceInfo: usedUnitPriceInfo,
             gljTypeMap:gljTypeMap,
             vvTaxFileID:unitFileInfo.vvTaxFileID,
-            assistProductionFeeRate:unitFileInfo.assistProductionFeeRate?unitFileInfo.assistProductionFeeRate:3
+            assistProductionFeeRate:unitFileInfo.assistProductionFeeRate?unitFileInfo.assistProductionFeeRate:3,
+            machineConstCoe:unitFileInfo.machineConstCoe?unitFileInfo.machineConstCoe:1
         };
     } catch (error) {
         console.log(error);

+ 2 - 2
modules/glj/facade/glj_facade.js

@@ -126,9 +126,9 @@ async function changeVvTaxFile(data){//对于车船税,现在只是在组成
 }
 
 async function changeAssistProductionFeeRate(data){
-    let unitFileID = data.unitFileID,assistProductionFeeRate = data.assistProductionFeeRate;
+    let unitFileID = data.unitFileID;//assistProductionFeeRate = data.assistProductionFeeRate;
     let unitPriceFileModel = new UnitPriceFileModel();
-    await unitPriceFileModel.model.update({id:unitFileID},{assistProductionFeeRate:assistProductionFeeRate});
+    await unitPriceFileModel.model.update({id:unitFileID},data.updateData);
 }
 
 async function handleVvTaxForChang(unitFileID,newVvTaxFileID) {//切换车船税,选择共用的单价文件时调用

+ 0 - 2
modules/glj/models/unit_price_model.js

@@ -69,8 +69,6 @@ class UnitPriceModel extends BaseModel {
         switch (scene) {
             // 新增数据的验证规则
             case 'add':
-                this.model.schema.path('base_price').required(true);
-                this.model.schema.path('market_price').required(true);
                 this.model.schema.path('name').required(true);
                 this.model.schema.path('code').required(true);
                 // this.model.schema.path('unit').required(true);

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

@@ -11,6 +11,7 @@ module.exports = {
         try {
             let funcName = req.url.replace(/\//g, "");
             let dataObj = JSON.parse(req.body.data);
+            dataObj.sessionUser = req.session.sessionUser;
             result.data = await blFacade[funcName](dataObj);
         } catch (err) {
             console.log(err);

+ 12 - 0
modules/main/controllers/ration_controller.js

@@ -9,6 +9,9 @@ let bill_facade = require('../facade/bill_facade');
 let project_facade = require("../facade/project_facade");
 let logger = require("../../../logs/log_helper").logger;
 const GLJController = require("../../glj/controllers/glj_controller");
+const pmFacade = require('../../pm/facade/pm_facade');
+const { ShareLibType } = require('../../../public/common_constants');
+const compleRationLib = 'compleRationLib';
 let controller = {
     insertGLJAsRation:async function (req){
         let data = req.body.data;
@@ -19,6 +22,14 @@ let controller = {
         let data = req.body.data;
         data = JSON.parse(data);
         let userID = req.session.sessionUser.id;
+        const compilationID = req.session.sessionCompilation._id;
+        if (data.libIDs && !data.libIDs.includes(compleRationLib)) {
+            const rationLibUsers = await pmFacade.getReceiveLibList(userID, compilationID, ShareLibType.RATION_LIB);
+            data.libIDs.push(compleRationLib);
+            rationLibUsers.forEach(user => {
+                data.libIDs.push(`${compleRationLib}*${user._id}`);
+            });
+        }
         return await ration_facade.replaceRations(userID,data,req.session.sessionCompilation);
     },
     addNewRation:async function(req) {
@@ -28,6 +39,7 @@ let controller = {
         }
         data = JSON.parse(data);
         let start = +new Date();
+        data.sessionUserID = req.session.sessionUser.id;
         let result = await ration_facade.addNewRation(data,req.session.sessionCompilation);
         //合并取项目工料机数据的情求,用于刷新项目工料机数据,当有添加、替换项目工料机的情况,才需要刷新
       /*  if(result.ration_gljs && result.ration_gljs.length > 0 && data.newData){

+ 10 - 1
modules/main/facade/bill_facade.js

@@ -114,7 +114,16 @@ module.exports={
         let bulks = [];
         for (let data of datas) {
             if (data.updateType === 'update') {
-                bulks.push({updateOne: {filter: {ID: data.updateData.ID}, update: {NextSiblingID: data.updateData.NextSiblingID}}});
+                let updateItem;
+                if (data.updateData.NextSiblingID !== undefined) {
+                    updateItem = { NextSiblingID: data.updateData.NextSiblingID }
+                }
+                if (data.updateData.name !== undefined) {
+                    updateItem = { name: data.updateData.name }
+                }
+                if (updateItem) {
+                    bulks.push({updateOne: {filter: {ID: data.updateData.ID}, update: updateItem}});
+                }
             } else {
                 bulks.push({insertOne: {document: data.updateData}});
             }

+ 30 - 3
modules/main/facade/block_lib_facade.js

@@ -5,6 +5,8 @@
 let mongoose = require('mongoose');
 let blModel = mongoose.model('blockLibsModel');
 let uuid = require('../../../public/web/uuid');
+const pmFacade = require('../../pm/facade/pm_facade');
+const { ShareLibType } = require('../../../public/common_constants');
 
 module.exports = {
     getLibNames: getLibNames,
@@ -17,6 +19,24 @@ module.exports = {
 // userID、compilationID
 async function getLibNames(data) {
     let libNames = await blModel.find({userID: data.userID, compilationID: data.compilationID}, ["libID","libName","-_id"]);
+    // 块模板库改成组价模板,兼容旧数据
+    const bulks = [];
+    const reg = /块模板库/;
+    libNames.forEach(lib => {
+        if (reg.test(lib.libName)) {
+            const newLibName = lib.libName.replace('块模板库', '组价模板');
+            lib.libName = newLibName;
+            bulks.push({
+                updateOne: {
+                    filter: { libID: lib.libID },
+                    update: { libName: newLibName }
+                }
+            });
+        }
+    });
+    if (bulks.length) {
+        await blModel.bulkWrite(bulks);
+    }
     return libNames;
 };
 
@@ -31,13 +51,20 @@ async function getLibNamesAndFirstLib(data) {
     let libNames = await getLibNames(data);
     let lib = null;
     if (libNames.length == 0){
-        lib = await copyTemplateLib(data.userID, data.userName, data.compilationID);
+        lib = await copyTemplateLib(data.userID, data.sessionUser.real_name, data.compilationID);
         libNames.push({libID: lib.libID, libName: lib.libName});
     }
     else{
         lib = await getLib(libNames[0]);
     }
-    return {libNames: libNames, firstLib: lib};
+    // 别人分享的组价模板
+    const receiveLibs = await pmFacade.getReceiveLibList(data.userID, data.compilationID, ShareLibType.BLOCK_LIB);
+    const userIDList = receiveLibs.map(user => user._id);
+    const receiveLibNames = await blModel.find({userID: { $in: userIDList }, compilationID: data.compilationID}, ["libID","libName","-_id"]);
+    libNames.push(...receiveLibNames);
+    // 分享给别人
+    const shareList = await pmFacade.getLibShareList(data.userID, data.compilationID, ShareLibType.BLOCK_LIB);
+    return {libNames: libNames, firstLib: lib, shareList};
 };
 
 
@@ -79,7 +106,7 @@ async function copyTemplateLib(userID, userName, compilationID) {
         userID: userID,
         compilationID: compilationID,
         libID: uuid.v1(),
-        libName: `${userName}的块模板库`,
+        libName: `${userName}的组价模板`,
         datas: template.datas,
         share: template.share
     };

+ 42 - 10
modules/main/facade/ration_facade.js

@@ -15,6 +15,7 @@ module.exports = {
   deleteSubListByQuery:deleteSubListByQuery,
   updateCoeAdjust:updateCoeAdjust,
   getUnitPriceData:getUnitPriceData,
+  transGljType:transGljType
 };
 
 
@@ -56,6 +57,7 @@ let complementaryGljLibModel = mongoose.model('complementary_glj_lib');
 
 let _= require('lodash');
 const projectDao = require('../../pm/models/project_model').project;
+const pmFacade = require('../../pm/facade/pm_facade');
 let projectModel = mongoose.model('projects');
 let unitPriceModel = mongoose.model('unit_price');
 let unitPriceFileModel = mongoose.model('unit_price_file');
@@ -71,6 +73,9 @@ async function addNewRation(data,compilation) {
     if(query){
         let searchDao = new SearchDao();
         stdRation = await searchDao.getRationItem(query.userID, compilation._id, [query.rationRepId],query.code, query.ID);
+        if (stdRation && data.sessionUserID !== query.userID) {
+            stdRation.owner = query.userID;
+          }
         //data.newData.code = query.code;
     }
     let stdRationTime = +new Date();
@@ -234,17 +239,12 @@ async function createNewMaterialRation(std,quantityDecimal,projectID){
 }
 
 async function addMultiRation(datas,compilation) {
-    /* let rst = [];
+    let rst = [];
     for(let data of datas){
         let r = await addNewRation(data,compilation);
         rst.push(r);
     }
-    return rst; */
-    const task = [];
-    for (const data of datas) {
-        task.push(addNewRation(data, compilation));
-    }
-    return await Promise.all(task);
+    return rst;
 }
 
 async function getSameSectionRations(data,userId,compilationId){
@@ -306,6 +306,10 @@ function getProgramID(programArray,feeType) {
 async function insertNewRation(newData,defaultLibID,std,calQuantity,programArray) {//插入新的定额
     let startTime = +new Date();
     if(std){
+        if (std.owner) {
+            // 别人分享的定额
+            newData.fromUser = std.owner;
+        }
         newData.code = std.code;
         newData.name = std.name;
         newData.caption = std.caption;
@@ -353,6 +357,9 @@ async function replaceRations(userID,data,compilation) {
     let recodes = [];
     for(let recode of data.nodeInfo){
         let stdRation = await searchDao.getRationItem(userID,compilation._id,data.libIDs,recode.newCode, null);
+        if (stdRation && stdRation.userId && stdRation.userId !== userID) {
+            stdRation.owner = stdRation.userId;
+        }
         let newRecode = await replaceRation(recode,stdRation,data.defaultLibID,data.projectID,data.calQuantity,compilation,data.cleanzmhs,data.programArray);
         if(newRecode){
             recodes.push(newRecode);
@@ -566,10 +573,19 @@ async function getCustomerCoe(projectID,rationID,seq,compilation){//取自定义
 
 //对于多单价,多组成物消耗量的编办,通过这个方法获取单价、组成物消耗量的字段,
 function getExtendData(property,compilation) {
-    return projectDao.getExtendData(property,compilation);
+    return pmFacade.getExtendData(property,compilation);
 }
 
 
+//查看是否需要将“设备”的处理成“普通材料”
+function transGljType(compilation,newGlJ){
+    if(compilation.overWriteUrl && compilation.overWriteUrl!=""){
+        let overWrite = require("../../.."+compilation.overWriteUrl);
+        if(overWrite.ifTransEqToMateria && overWrite.ifTransEqToMateria()){
+            if(newGlJ.type == 5) newGlJ.type = 201;
+        }
+     }
+}
 
 
 async function addRationGLJ(std,newRation,compilation,isMaterial,connect_key) {
@@ -586,12 +602,16 @@ async function addRationGLJ(std,newRation,compilation,isMaterial,connect_key) {
     }
     let ext = getExtendData(property,compilation);
     let first = +new Date();
+    const users = [std.userId];
     if(std.hasOwnProperty('rationGljList') && std.rationGljList.length > 0){
         let stdGLJID =[];//标准工料机ID数组
         let cptGLJID=[];//补充工料机ID数组
             //let stdGLJID = _.map(std.rationGljList,'gljId');
         for(let tem_g  of std.rationGljList){
              if(tem_g.type == 'complementary'){
+                 if (tem_g.fromUser && !users.includes(tem_g.fromUser)) {
+                     users.push(tem_g.fromUser);
+                 }
                 cptGLJID.push(tem_g.gljId);
              }else {
                 stdGLJID.push(tem_g.gljId);
@@ -599,7 +619,7 @@ async function addRationGLJ(std,newRation,compilation,isMaterial,connect_key) {
         }
        let stdGLJList = stdGLJID.length > 0 ? await std_glj_lib_gljList_model.find({'ID':{'$in':stdGLJID}}).lean():[];//速度优化-------先一次性取出所有的工料机列表
        let stdGLJMap = _.indexBy(stdGLJList, 'ID');
-       let cptGLJList =  cptGLJID.length > 0 ? await complementary_glj_model.find({'userId':std.userId,'ID':{'$in':cptGLJID}}).lean():[];
+       let cptGLJList =  cptGLJID.length > 0 ? await complementary_glj_model.find({'userId':{$in: users},'ID':{'$in':cptGLJID}}):[];
        let cptGLJMap = _.indexBy(cptGLJList, 'ID');
         let stdGLJMapTime = +new Date();
         console.log("找到工料机映射表时间-------------------------------"+(stdGLJMapTime - first));
@@ -622,9 +642,14 @@ async function addRationGLJ(std,newRation,compilation,isMaterial,connect_key) {
             newGLJ.glj_repository_id = std.rationRepId;
             newGLJ.rationProportion = proportion;
             newGLJ.adjustProportion = proportion;
+            if (sub.fromUser) {
+                newGLJ.fromUser = sub.fromUser;
+            }
             let std_glj = getStdGlj(sub,stdGLJMap,cptGLJMap,{},ext);
             if(std_glj){
                 ration_glj_facade.setPropertyFromStd(newGLJ,std_glj);
+                //有些编办要把设备类型转成普通材料  -- todo
+                transGljType(compilation,newGLJ);
                 let tindex = getIndex(newGLJ);
                 if(std_glj.component && std_glj.component.length > 0) mixRatioMap[tindex] = std_glj.component
                 let tdata = ration_glj_facade.getGLJSearchInfo(newGLJ);
@@ -746,7 +771,6 @@ async function getUnitPriceData(newProjectGLJList,gljCodes,unitPriceFileId){
   for(let np of newProjectGLJList){
     let pkey = getIndex(np);
     if(unitPriceMap[pkey]) continue;
-
     let insertData = {
       code: np.code,
       base_price: np.base_price,
@@ -765,6 +789,10 @@ async function getUnitPriceData(newProjectGLJList,gljCodes,unitPriceFileId){
       offSiteTransportLossRate:np.offSiteTransportLossRate,
       handlingLossRate:np.handlingLossRate
     };
+    if(np.code == '80CCS'){//车船税默认价格为1
+        insertData.base_price = '1';
+        insertData.market_price = '1';
+    }
     if(np.from=='cpt') insertData.is_add=1;//如果是来自补充工料机,则都添加新增标记
     if(insertData.code != insertData.original_code) insertData.is_add=1;//添加的时候如果是复制整块来的,可能在源项目中是新增的工料机,这里也要添上(暂时可能还用不到)
     newUnitPriceList.push(insertData);
@@ -1067,6 +1095,10 @@ async function updateCoeAdjust(data,compilation) {
 async function  updateRation(std,defaultLibID,rationID,billsItemID,projectID,calQuantity,cleanzmh=false,programArray) {
     // insertNewRation
     let ration ={};
+    if (std.owner) {
+        // 别人分享的定额
+        ration.fromUser = std.owner;
+    }
     ration.code = std.code;
     ration.name = std.name;
     ration.caption = std.caption;

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

@@ -45,6 +45,7 @@ module.exports =function (app) {
                         userName: req.session.sessionUser.username,
                         projectData: projectData,
                         compilationName: req.session.sessionCompilation.name,
+                        defaultLocation:req.session.sessionCompilation.defaultLocation,
                         versionName: req.session.compilationVersion,
                         projectReadOnly: projectReadOnly,
                         projectCooperate: projectCooperate,

+ 79 - 4
modules/pm/controllers/pm_controller.js

@@ -639,6 +639,81 @@ module.exports = {
             callback(req, res, 1, err.message, null);
         }
     },
+    getReceiveLibList: async function (req, res) {
+        try {
+            const { libType } = JSON.parse(req.body.data);
+            const userID = req.session.sessionUser.id;
+            const compilationID = req.session.sessionCompilation._id;
+            const list = await pm_facade.getReceiveLibList(userID, compilationID, libType);
+            callback(req, res, 0, 'success', list);
+        } catch (err) {
+            callback(req, res, 1, err.message, null);
+        }
+    },
+    getInitialShareLibData: async function (req, res) {
+        try {
+            const { libType, count } = JSON.parse(req.body.data);
+            const userID = req.session.sessionUser.id;
+            const compilationID = req.session.sessionCompilation._id;
+            // 最近分享
+            const recentUsers = await pm_facade.getRecentShareList(userID, count);
+            // 联系人
+            const contacts = await userModelObj.getContacts(userID);
+            // 分享过的人
+            const sharedUsers = await pm_facade.getLibShareList(userID, compilationID, libType, count);
+            callback(req, res, 0, 'success', { recentUsers, contacts, sharedUsers });
+        } catch (err) {
+            console.log(err);
+            callback(req, res, 1, err.message, null);
+        }
+    },
+    shareLib: async function (req, res) {
+        try {
+            const { type, libType, shareData, count } = JSON.parse(req.body.data);
+            const owner = req.session.sessionUser.id;
+            const compilationID = req.session.sessionCompilation._id;
+            const shareDate = moment(Date.now()).format('YYYY-MM-DD HH:mm:ss');
+            shareData.forEach(item => item.shareDate = shareDate);
+            const task = [];
+            // 是否只是单纯的更新分享选项,如果不是,需要重新获取最近分享和联系人
+            let isSimpleUpdate = true;
+            if (type === 'create') {
+                isSimpleUpdate = false;
+                // 生成分享记录
+                const docs = shareData.map(item => ({
+                    compilationID,
+                    owner,
+                    libType,
+                    ID: uuidV1(),
+                    receiver: item.receiver,
+                    allowCooperate: false,
+                    shareDate: item.shareDate,
+                    updateDate: item.shareDate
+                }));
+                task.push(pm_facade.addShareList(docs, true));
+                // 分享即互相添加为联系人
+                task.push(userModelObj.addContact(docs[0].owner, docs[0].receiver));
+            } else if (type === 'cancel') { // 取消分享
+                const cancelReceivers = shareData.map(item => item.receiver);
+                task.push(pm_facade.deleteShareList({ owner, libType, compilationID, receiver: { $in: cancelReceivers } }, true));
+            }
+            await Promise.all(task);
+            const rst = {};
+            if (!isSimpleUpdate) {
+                const rstTask = [
+                    pm_facade.getRecentShareList(owner, count),
+                    userModelObj.getContacts(owner)
+                ];
+                const [recentUsers, contacts] = await Promise.all(rstTask);
+                Object.assign(rst, { recentUsers, contacts });
+            }
+            callback(req, res, 0, 'success', rst);
+        } catch (err) {
+            console.log(err);
+            logger.info(err);
+            callback(req, res, 1, err, null);
+        }
+    },
     share: async function (req, res) {
         try {
             const data = JSON.parse(req.body.data);
@@ -701,15 +776,15 @@ module.exports = {
                 task.push(pm_facade.deleteShareList({ projectID, receiver: { $in: cancelReceivers } }));
             }
             await Promise.all(task);
-            const rstTask = [
-                pm_facade.getRecentShareList(userID, count),
-                userModelObj.getContacts(userID)
-            ];
             // 获取需要广播推送的单位工程
             // shareData数组的形式是以前需求需要,现在的需求下,shareData数组必定只有一个元素
             const emitTenders = await pm_facade.getShareInfoAfterChangePermission(permissionType, shareData[0].userID, projectID);
             let rst = { emitTenders };
             if (!isSimpleUpdate) {
+                const rstTask = [
+                    pm_facade.getRecentShareList(userID, count),
+                    userModelObj.getContacts(userID)
+                ];
                 const [recentUsers, contacts] = await Promise.all(rstTask);
                 Object.assign(rst, { recentUsers, contacts });
             }

+ 99 - 15
modules/pm/facade/pm_facade.js

@@ -9,6 +9,7 @@
     };
 //先导出后require可以解决循环引用问题
 module.exports={
+    getExtendData,
     getBasicInfo,
     getImportTemplateData,
     getProjectByGranularity,
@@ -20,6 +21,8 @@ module.exports={
     getShareInfoMap,
     getRecentShareList,
     getProjectShareList,
+    getReceiveLibList,
+    getLibShareList,
     getUnreadShareListByCompilation,
     getShareTip,
     getShareState,
@@ -54,7 +57,7 @@ module.exports={
     importInterface,
     copyConstructionProject,
     isTenderOverrun,
-    getWelcomeInfo:getWelcomeInfo
+    getWelcomeInfo:getWelcomeInfo,
 };
 
 
@@ -106,6 +109,7 @@ let compleGljSectionTModel = mongoose.model('complementary_glj_section_templates
 let progressiveModel = mongoose.model('std_progressive_lib');
 let importLogsModel = mongoose.model("import_logs");
 const shareListModel = mongoose.model('share_list');
+const shareLibModel = mongoose.model('share_libs');
 let welcomeModel = mongoose.model("welcome_setting");
 let divideModel = mongoose.model("divide_setting");
 let evaluateListModel = mongoose.model("evaluate_list");
@@ -138,6 +142,29 @@ let path = require("path");
 let request = require("request");
 const systemSettingModel = mongoose.model('system_setting');
 
+function getExtendData(property, compilation) {
+    let ext = {};
+    if (property) {
+        let region = property.region;
+        let taxType = property.taxType;
+        if (compilation.priceProperties && compilation.priceProperties.length > 0) {//如果是具有多单价的编办,取单价对应的字段
+            let priceProperty = _.find(compilation.priceProperties, { region: region, taxModel: parseInt(taxType) });
+            if (priceProperty) {
+                ext['priceField'] = priceProperty.price.dataCode;
+            }
+        }
+        if (compilation.consumeAmtProperties && compilation.consumeAmtProperties.length > 0) {
+            let consumeAmt = _.find(compilation.consumeAmtProperties, { region: region, taxModel: parseInt(taxType) });
+            if (consumeAmt) {
+                ext['quantityField'] = consumeAmt.consumeAmt.dataCode;
+            }
+        }
+    }
+    return _.isEmpty(ext) ? null : ext;
+}
+
+
+
 let qiniu_config = {
     "AccessKey": "_gR1ed4vi1vT2G2YITGSf4_H0fJu_nRS9Tzk3T4z",
     "SecretKey": "ty4zd0FHqgEDaiVzSLC8DfHlai99aS7bspLkw6s6",
@@ -214,19 +241,23 @@ async function prepareShareList() {
 
 
 // 获取分享列表
-async function getShareList(query) {
-    return await shareListModel.find(query, '-_id').lean();
+async function getShareList(query, isShareLib = false) {
+    const model = isShareLib ? shareLibModel : shareListModel;
+    return await model.find(query, '-_id').lean();
 }
 
-async function addShareList(docs) {
-    await shareListModel.insertMany(docs);
+async function addShareList(docs, isShareLib = false) {
+    const model = isShareLib ? shareLibModel : shareListModel;
+    await model.insertMany(docs);
 }
 
-async function deleteShareList(query) {
-    await shareListModel.deleteMany(query);
+async function deleteShareList(query, isShareLib = false) {
+    const model = isShareLib ? shareLibModel : shareListModel;
+    await model.deleteMany(query);
 }
 
-async function updateShareList(updateData) {
+async function updateShareList(updateData, isShareLib = false) {
+    const model = isShareLib ? shareLibModel : shareListModel;
     const bulks = updateData.map(item => (
         {
             updateOne: {
@@ -236,7 +267,7 @@ async function updateShareList(updateData) {
         }
     ));
     if (bulks.length) {
-        await shareListModel.bulkWrite(bulks);
+        await model.bulkWrite(bulks);
     }
 }
 
@@ -262,7 +293,10 @@ async function getShareInfoMap(projectIDs, shareList = null) {
 
 // 获取最近分享(只算分享出去的记录)
 async function getRecentShareList(userID, count) {
-    const shareList = await getShareList({owner: userID});
+    // 合并分享的项目和库
+    const shareProjectList = await getShareList({owner: userID});
+    const shareLibList = await getShareList({owner: userID}, true);
+    const shareList = [...shareProjectList, ...shareLibList];
     shareList.sort((a, b) => Date.parse(b.shareDate) - Date.parse(a.shareDate));
     const set = new Set();
     for(const item of shareList) {
@@ -304,6 +338,51 @@ async function getProjectShareList(projectID, limit = null) {
     return users;
 }
 
+async function getReceiveLibList(receiver, compilationID, libType) {
+    const sharedList = await shareLibModel.find({ receiver, compilationID, libType }).lean().sort({ shareDate: -1 });
+    const userIDs = [];
+    const userMap = {};
+    sharedList.forEach((item, index) => {
+        userIDs.push(item.owner);
+        userMap[item.owner] = item;
+        userMap[item.owner].index = index;
+    });
+    const userObjectIDs = userIDs.map(userID => mongoose.Types.ObjectId(userID));
+    const users = await userModel.find({ _id: { $in: userObjectIDs } }, 'real_name').lean();
+    users.forEach(user => {
+        const matched = userMap[user._id];
+        if (matched) {
+            user.index = matched.index;
+        }
+    });
+    users.sort((a, b) => a.index - b.index);
+    return users;
+}
+
+// 获取某库的分享记录
+async function getLibShareList(owner, compilationID, libType, limit = null) {
+    const sharedList = limit 
+        ? await shareLibModel.find({ owner, compilationID, libType }).lean().sort({ shareDate: -1 }).limit(limit)
+        : await shareLibModel.find({ owner, compilationID, libType }).lean().sort({ shareDate: -1 });
+    const userIDs = [];
+    const userMap = {};
+    sharedList.forEach((item, index) => {
+        userIDs.push(item.receiver);
+        userMap[item.receiver] = item;
+        userMap[item.receiver].index = index;
+    });
+    const userObjectIDs = userIDs.map(userID => mongoose.Types.ObjectId(userID));
+    const users = await userModel.find({_id: {$in: userObjectIDs}}, 'real_name mobile company').lean();
+    users.forEach(user => {
+        const matched = userMap[user._id];
+        if (matched) {
+            user.index = matched.index;
+        }
+    });
+    users.sort((a, b) => a.index - b.index);
+    return users;
+}
+
 // 获取某用户某费用定额的未读的被分享记录
 async function getUnreadShareListByCompilation(userID, compilationID, isGetCount) {
     const fields = isGetCount ? '-_id projectID ' : '-_id';
@@ -1819,14 +1898,14 @@ async function handleImportInterface(key, session) {
             throw '无有效数据';
         }
         const userID = session.sessionUser.id;
-        const compilationID = session.sessionCompilation._id;
+        const compilation = session.sessionCompilation;
         const importData = JSON.parse(srcData);
         const tenderCount = importData.tenders.length;
         if (await isTenderOverrun(tenderCount, session)) {
             throw '您创建的项目个数超限,请联系我们的客服人员,或者导出建设项目保存到本地备份,删除云上数据。';
         }
         const overWriteUrl = session.sessionCompilation.overWriteUrl;
-        const projectID = await importInterfaceProject(importData, userID, compilationID, overWriteUrl);
+        const projectID = await importInterfaceProject(importData, userID, compilation, overWriteUrl);
         doc.projectID = projectID;
     } catch (err) {
         console.log(err);
@@ -1841,7 +1920,8 @@ async function handleImportInterface(key, session) {
 /*
 * 接口导入 项目详细数据都导入完成了,再生成项目数据(项目管理界面数据)
 * */
-async function importInterfaceProject(importObj, userID, compilationID, overWriteUrl) {
+async function importInterfaceProject(importObj, userID, compilation, overWriteUrl) {
+    const compilationID = compilation._id;
     const toInsertProjects = [importObj];  //待新增项目数据
     let defaultCalcMode;
     if (overWriteUrl) {
@@ -1855,7 +1935,7 @@ async function importInterfaceProject(importObj, userID, compilationID, overWrit
     for (const curTender of importObj.tenders) {
         await setupProject(curTender);
         // 插入单位工程的详细数据
-        await importTenderDetail(curTender);
+        await importTenderDetail(curTender, compilation);
         delete curTender.bills;
         toInsertProjects.push(curTender);
     }
@@ -1890,6 +1970,8 @@ async function importInterfaceProject(importObj, userID, compilationID, overWrit
     }
     //给单位工程设置一些数据
     async function setupTender(data) {
+        // 将项目标记为通过接口导入的项目
+        data.importedByInterface = true;
         if (!data.property.decimal) {
             //小数位数 需要修改,所以深拷贝
             data.property.decimal = JSON.parse(JSON.stringify(defaultDecimal));
@@ -1916,7 +1998,7 @@ async function importInterfaceProject(importObj, userID, compilationID, overWrit
 }
 
 //插入单位工程内部详细数据
-async function importTenderDetail(tenderData) {
+async function importTenderDetail(tenderData, compilation) {
     // 单价文件
     const upFile = {
         id: tenderData.property.unitPriceFile.id,
@@ -1926,6 +2008,8 @@ async function importTenderDetail(tenderData) {
         root_project_id: tenderData.property.rootProjectID
     };
     await unitPriceFileModel.create(upFile);
+    // 新增单价文件的同时,在项目工料机和空白的单价文件中先插入机械组成物等信息
+    await glj_facade.addMixRatioForNew(tenderData.ID, upFile.id, tenderData.property.engineering_id, getExtendData(tenderData.property, compilation))
     // 费率文件
     const feeRateFileID = await feeRate_facade.newFeeRateFile(tenderData.userID, tenderData);
     tenderData.property.feeFile = feeRateFileID ? feeRateFileID : -1;

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

@@ -174,7 +174,7 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     }
                     data.updateData.property.unitPriceFile.id = addResult.id;
                     //新增单价文件的同时,在项目工料机和空白的单价文件中先插入机械组成物等信息
-                    await gljFacade.addMixRatioForNew(data.updateData.ID,addResult.id,data.updateData.property.engineering_id,this.getExtendData(data.updateData.property,compilation));
+                    await gljFacade.addMixRatioForNew(data.updateData.ID,addResult.id,data.updateData.property.engineering_id,pmFacade.getExtendData(data.updateData.property,compilation));
                 }
                 if (data.updateData.projType === projectType.tender) {
                     //单价文件
@@ -188,15 +188,24 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     //data.updateData.property.basicInformation = basicInformation;
                     //工程特征
                     if(data.updateData.property.featureLibID){
+                        const matchedConstructionProject = datas.find(item => item.updateData.projType === projectType.project);
+                        let constructionProjectName = '';
+                        if (matchedConstructionProject) {
+                            constructionProjectName = matchedConstructionProject.updateData.name;
+                        } else {
+                            const findConstructionProject = await Projects.findOne({ ID: data.updateData.ParentID }).lean();
+                            constructionProjectName = findConstructionProject && findConstructionProject.name || '';
+                        }
                         //项目类别(valuationType)、养护类别(engineering)、费用标准(feeStandard)根据新建分选的选项去赋值
                         let assign = {
                             valuationType: data.updateData.property.valuationType === ValuationType.BUDGET ? '预算' : '工程量清单',
                             engineering: data.updateData.property.engineeringName,
                             feeStandard: data.updateData.property.feeStandardName,
-                            // 新建分段文件时,默认将“工程特征”-“单项工程名称”、“编制范围”填写分段文件的名称
+                            // 新建分段文件时,默认将“编制范围”填写分段文件的名称
                             // 为了防止用户漏填,导出电子招标文件时,有数据
                             compilationScope: data.updateData.name,
-                            singleProjName: data.updateData.name,
+                            // 新建分段文件时,默认将“工程特征”-“单项工程名称”填写建设项目名称
+                            singleProjName: constructionProjectName,
                         };
                         data.updateData.property.projectFeature = await pmFacade.getProjectFeature(data.updateData.property.featureLibID, assign);
                     }
@@ -684,28 +693,6 @@ ProjectsDAO.prototype.getProjectProperty = async function (projectId) {
     return projectData.property;
 };
 
-ProjectsDAO.prototype.getExtendData = function(property,compilation) {
-    let ext = {};
-    if(property){
-        let region = property.region;
-        let taxType = property.taxType;
-        if(compilation.priceProperties && compilation.priceProperties.length > 0){//如果是具有多单价的编办,取单价对应的字段
-            let priceProperty  = _.find(compilation.priceProperties,{region:region,taxModel:parseInt(taxType)});
-            if(priceProperty){
-                ext['priceField'] =  priceProperty.price.dataCode;
-            }
-        }
-        if(compilation.consumeAmtProperties && compilation.consumeAmtProperties.length > 0){
-            let  consumeAmt =   _.find(compilation.consumeAmtProperties,{region:region,taxModel:parseInt(taxType)});
-            if(consumeAmt){
-                ext['quantityField'] =  consumeAmt.consumeAmt.dataCode;
-            }
-        }
-    }
-    return _.isEmpty(ext)?null:ext;
-}
-
-
 /**
  * 获取当前用户的建设项目数据
  *

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

@@ -56,9 +56,12 @@ module.exports = function (app) {
     pmRouter.post('/getGCDatas', pmController.getGC);
     pmRouter.post('/recGC', pmController.recGC);
     pmRouter.post('/delGC', pmController.delGC);
+    pmRouter.post('/getReceiveLibList', pmController.getReceiveLibList);
     pmRouter.post('/getProjectShareInfo', pmController.projectShareInfo);
     pmRouter.post('/getInitialShareData', pmController.getInitialShareData);
+    pmRouter.post('/getInitialShareLibData', pmController.getInitialShareLibData);
     pmRouter.post('/share', pmController.share);
+    pmRouter.post('/shareLib', pmController.shareLib);
     pmRouter.post('/receiveProjects', pmController.receiveProjects);
     pmRouter.post('/changeFile', pmController.changeFile);
     pmRouter.post('/exportProject', pmController.exportProject);

+ 19 - 6
modules/ration_glj/controllers/ration_glj_controller.js

@@ -4,7 +4,8 @@
 let mongoose = require("mongoose")
 let ration_glj_facade = require('../facade/ration_glj_facade')
 let logger = require("../../../logs/log_helper").logger;
-const { COMPLEMENTARY_LIB, COMPILATION } = require ('../../../public/common_constants');
+const { COMPILATION, COMPLEMENTARY_LIB, ShareLibType } = require('../../../public/common_constants');
+const pmFacade = require('../../pm/facade/pm_facade');
 
 module.exports={
     createRationGLJ:createRationGLJ,
@@ -66,7 +67,10 @@ async function getGLJData(req, res) {
     try {
         let libData = null;
         let { engineerID, gljLibId, isInitial } = req.params;
-        if (gljLibId !== COMPLEMENTARY_LIB) {
+        const userID = req.session.sessionUser.id;
+        const compilationId = req.session.sessionCompilation._id;
+        const cptLibReg = new RegExp(COMPLEMENTARY_LIB);
+        if (!cptLibReg.test(gljLibId)) {
             gljLibId = +gljLibId;
         }
         isInitial = JSON.parse(isInitial);
@@ -74,7 +78,12 @@ async function getGLJData(req, res) {
             libData = engineerID === COMPILATION 
             ? await ration_glj_facade.getLibOptionsForCompilation(req.session.sessionCompilation._id)
             : await ration_glj_facade.getLibOptions(engineerID);
-            libData.push({ name: '补充工料机', gljLibId: COMPLEMENTARY_LIB });
+            libData.push({ name: '我的补充工料机库', gljLibId: COMPLEMENTARY_LIB });
+            // 设置被分享的人材机库
+            const receiveData = await pmFacade.getReceiveLibList(userID, compilationId, ShareLibType.GLJ_LIB);
+            receiveData.forEach(user => {
+                libData.push({ name: `${user.real_name}的补充工料机库`, gljLibId: `${COMPLEMENTARY_LIB}*${user._id}` });
+            });
             if (gljLibId) { // 替换人材机初始化会触发此条件
                 const orgDefalutLib = libData.find(lib => lib.isDefault);
                 const newDefaultLib = libData.find(lib => lib.gljLibId === gljLibId);
@@ -87,9 +96,13 @@ async function getGLJData(req, res) {
         if (!gljLibId && libData) {
             gljLibId = (libData.find(lib => lib.isDefault) || {}).gljLibId;
         }
-        const info = gljLibId === COMPLEMENTARY_LIB 
-            ? { gljLibId: null, userID: req.session.sessionUser.id, compilationId: req.session.sessionCompilation._id }
-            : { gljLibId, userID: null, compilationId: null };
+        let info;
+        if (cptLibReg.test(gljLibId)) {
+            const owner = gljLibId.split('*')[1] || userID;
+            info = { gljLibId: null, userID: owner, compilationId  };
+        } else {
+            info = { gljLibId, userID: null, compilationId: null };
+        }
         ration_glj_facade.getGLJData(info,function (err,datas) {
             if(err){
                 result.error=1;

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

@@ -405,7 +405,7 @@ function generateAdjustState(glj,coeList,adjustState,gljList,quantity) {
     }
 
     //自定义消耗量
-    if(glj.createType!='add'&&glj.hasOwnProperty('customQuantity')){
+    if(glj.createType!='add'&&glj._doc.hasOwnProperty('customQuantity')){
         if(glj.customQuantity!==null&&glj.customQuantity!=""){
             adjustState.push({index:stateSeq.cusQuantity,content:glj.code+'量'+parseFloat(glj.customQuantity)});
         }

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

@@ -50,6 +50,7 @@ let glj_calculate_facade = require('./glj_calculate_facade');
 let glj_type_util = require('../../../public/cache/std_glj_type_util');
 let quantity_detail_facade = require('../../main/facade/quantity_detail_facade');
 let ration_installation_facade = require('../../main/facade/ration_installation_facade');
+let ration_facade = require('../../main/facade/ration_facade');
 let logger = require("../../../logs/log_helper").logger;
 const stdgljutil = require("../../../public/cache/std_glj_type_util");
 const EngineeringLibModel = require("../../users/models/engineering_lib_model");
@@ -59,6 +60,7 @@ const complementaryGljModel = mongoose.model('complementary_glj_lib');
 const stdGljModel = mongoose.model('std_glj_lib_gljList');
 const gljClassModel = mongoose.model('std_glj_lib_gljClass');
 const projectDao = require('../../pm/models/project_model').project;
+const pmFacade = require('../../pm/facade/pm_facade');
 const commonFacade = require('../../main/facade/common_facade');
 const compleClassModel = mongoose.model('complementary_glj_section');
 const stdRationLibModel = mongoose.model('std_ration_lib_map');
@@ -205,6 +207,9 @@ function createNewRecord(ration_glj) {
   newRecoed.repositoryId = ration_glj.repositoryId;
   newRecoed.projectGLJID = ration_glj.projectGLJID;
   newRecoed.adjCoe = ration_glj.adjCoe;
+  if (ration_glj.fromUser) {
+    newRecoed.fromUser = ration_glj.fromUser;
+  }
   return newRecoed
 }
 
@@ -725,7 +730,8 @@ function getGLJSearchInfo(ration_glj) {
     is_adjust_price: 0,
     is_evaluate: 0,
     is_eval_material: 0,
-    from: ration_glj.from ? ration_glj.from : 'std' //std:标准工料机库, cpt:补充工料机库
+    from: ration_glj.from ? ration_glj.from : 'std', //std:标准工料机库, cpt:补充工料机库
+    fromUser: ration_glj.fromUser,
   };
   let glj_type_object = glj_type_util.getStdGljTypeCacheObj();
   let type = glj_type_object.getItemById(data.type);
@@ -740,7 +746,7 @@ function getGLJSearchInfo(ration_glj) {
 async function prepareExtData(projectID, compilation) {
   let ext, unitFileId;
   let property = await projectDao.getProjectProperty(projectID);
-  ext = projectDao.getExtendData(property, compilation);
+  ext = pmFacade.getExtendData(property, compilation);
   unitFileId = property.unitPriceFile !== undefined ? property.unitPriceFile.id : 0;
   return [unitFileId, ext];
 }
@@ -791,6 +797,7 @@ async function insertAddTypeGLJ(rgList, compilation, needInsert = true) {
   let projectGLJList = [];
   let [unitFileId, ext] = await prepareExtData(rgList[0].projectID, compilation);
   for (let g of rgList) {
+    ration_facade.transGljType(compilation,g);
     let projectGljModel = new GLJListModel();
     let result = await projectGljModel.addList(getGLJSearchInfo(g), unitFileId, ext);
     let typeString = result.type + '';
@@ -1295,7 +1302,7 @@ async function getGLJDataByCodes(data, compilation) {
     });
     if (stdList.length > 0) {
       let property = await projectDao.getProjectProperty(data.projectID);
-      let ext = projectDao.getExtendData(property, compilation); //多单价处理
+      let ext = pmFacade.getExtendData(property, compilation); //多单价处理
       for (let s of stdList) {
         let tem = JSON.parse(JSON.stringify(s));
         if (ext && ext.priceField && tem && tem.priceProperty) {

+ 54 - 1
modules/users/controllers/cld_controller.js

@@ -232,6 +232,16 @@ class CLDController {
         }
     }
 
+    async provinceList(request, response) {
+        let userModel = new UserModel();
+        let responseData = {
+            error: 0,
+            msg: '',
+            data: userModel.province,
+        };
+        response.json(responseData);
+    }
+
     /**
      * 获取用户列表分页
      * @param request
@@ -253,6 +263,11 @@ class CLDController {
             let condition = userModel.getFilterCondition(request);
             //设置搜索普通用户:
             condition.user_type = 'normal';
+            //设置剔除CLD用户列表不显示
+            let keyword = request.query.keyword;
+            if(keyword === undefined || keyword === '') {
+                condition.is_cld = {$in: [null, 0]};
+            }
 
             //获取注册时间
             let regtime = request.query.regtime;
@@ -270,8 +285,14 @@ class CLDController {
             let sortType = request.query.sortType !== '' && request.query.sortType !== undefined ? request.query.sortType : -1;
 
             // 排序条件
+            // 排序条件
             let sortField = request.query.sortField;
-            let sort = sortField !== '' && sortField !== undefined && sortField === 'latest_login' ? {latest_login: sortType}: {_id: sortType};
+            let sort = {_id: sortType};
+            if (sortField !== '' && sortField !== undefined && sortField === 'latest_login') {
+                sort = {latest_login: sortType}
+            } else if(sortField !== '' && sortField !== undefined && sortField === 'online_times')  {
+                sort = {online_times: sortType}
+            }
 
             // 获取用户总数
             total = await userModel.count(condition);
@@ -289,6 +310,10 @@ class CLDController {
             // 获取用户列表
             userList = await userModel.getList(condition, page, pageSize, sort);
             await online_facade.setOnlineTimes(userList,condition);
+            userList = JSON.parse(unescape(escape(JSON.stringify(userList))));
+            for (const userData of userList) {
+                userData.province = userData.province !== -1 ? userModel.province[userData.province] : '';
+            }
             response.json({error: 0, msg: 'success', data: {
                 userInfo: userList,
                 pageData: pageData,
@@ -316,6 +341,34 @@ class CLDController {
         }
         response.json(responseData);
     }
+
+    async getRejectUsers(request, response) {
+        let userModel = new UserModel();
+        let total = 0;
+        let pageSize = 12;
+        let pageData = {};
+        let userList = [];
+        try {
+            const condition = {
+                user_type: 'normal',
+                is_cld: {$exists:true, $ne: 0}
+            };
+            // 获取用户总数
+            total = await userModel.count(condition);
+            // 分页数据
+            let page = request.query.page === undefined ? 1 : request.query.page;
+            pageSize = request.query.pageSize === undefined ? 12 : parseInt(request.query.pageSize);
+            userList = await userModel.getList(condition, page, pageSize, {is_cld:-1});
+            pageData = {
+                current: page,
+                total: total,
+                queryData: response.locals.urlQuery
+            };
+            response.json({error: 0, msg: 'success', data: { userList: userList, pageData: pageData }});
+        } catch (error) {
+            response.json({error: 1, msg: error});
+        }
+    }
 }
 
 module.exports = CLDController;

+ 1 - 3
modules/users/controllers/login_controller.js

@@ -287,9 +287,7 @@ class LoginController {
             const userinfo2 = await userModel.findDataByAccount(userData.mobile);
             if (userinfo2.isLoginValid === 1) {
                 // 获取本次访问ip
-                let ip = request.connection.remoteAddress;
-                ip = ip.split(':');
-                ip = ip[3] === undefined ? '' : ip[3];
+                let ip = request.headers["x-real-ip"]? request.headers["x-real-ip"]:"";
                 let logModel = new LogModel();
                 let logCount = await logModel.count();
                 logCount = logCount > 30 ? 30 : logCount;

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

@@ -348,7 +348,8 @@ class UserModel extends BaseModel {
      */
     async getVersionFromUpgrade(ssoId, compilationId) {
         let title = config[process.env.NODE_ENV].title?config[process.env.NODE_ENV].title:"纵横公路养护云造价";
-        let version = title+'(学习版)';//'纵横公路养护造价(免费云版)'; 2019-03-28 需求修改,听说不知道多久的以后还会改回来--勿删!!!!!
+        let versionText = title === '纵横公路云造价'?'免费版':'学习版';
+        let version = `${title}(${versionText})`;//'纵横公路养护造价(免费云版)'; 2019-03-28 需求修改,听说不知道多久的以后还会改回来--勿删!!!!!
         let lock = 0;
         let userData = await this.findDataBySsoId(ssoId);
         if (userData.upgrade_list !== undefined) {
@@ -395,7 +396,7 @@ class UserModel extends BaseModel {
         if (!sessionVersion) {
             return true;
         }
-        return sessionVersion.indexOf('学习') >= 0;
+        return sessionVersion.indexOf('免费') >= 0;
     }
 
     /*
@@ -484,6 +485,20 @@ class UserModel extends BaseModel {
             condition.latest_used = latestUsed;
         }
 
+        // 最近登录时长
+        let onlineTimes = request.query.onlineTimes;
+        onlineTimes = onlineTimes !== '' && onlineTimes !== undefined ? parseInt(onlineTimes) : 0;
+        if (onlineTimes !== 0) {
+            condition.online_times = this.getOnlineTimestamp(onlineTimes);
+        }
+
+        // 企业所在地区
+        let province = request.query.province;
+        province = province !== '' && province !== undefined ? parseInt(province) - 1 : -1;
+        if (province !== -1) {
+            condition.province = province;
+        }
+
         let keyword = request.query.keyword;
         if (keyword !== '' && keyword !== undefined) {
             condition.$or = [{real_name : {$regex: keyword}},{email : {$regex: keyword}},{mobile : {$regex: keyword}},{qq : {$regex: keyword}},{company : {$regex: keyword}}];
@@ -520,6 +535,32 @@ class UserModel extends BaseModel {
     }
 
     /**
+     * 获取时间戳区间
+     *
+     * @return {Object}
+     */
+    getOnlineTimestamp(type) {
+        let startTime = 0;
+        switch (type) {
+            case 1 :
+                startTime = 1800*1000;
+                break;
+            case 2 :
+                startTime = 3600*1000;
+                break;
+            case 3 :
+                startTime = 3600*1000*2;
+                break;
+            case 4 :
+                startTime = 3600*1000*3;
+                break;
+            default :
+                break;
+        }
+        return startTime === 0 ? '' : {'$gte': startTime};
+    }
+
+    /**
      * 获取daymsg
      *
      */

+ 4 - 0
modules/users/routes/cld_route.js

@@ -30,5 +30,9 @@ module.exports = function (app) {
 
     router.post('/getUserOnlineInfo', cldController.getUserOnlineInfo);
 
+    router.get('/getRejectUsers', cldController.getRejectUsers);
+
+    router.get('/provinceList', cldController.provinceList);
+
     app.use('/cld',router)
 };

+ 2 - 2
package.json

@@ -34,8 +34,8 @@
     "gulp-load-plugins": "^0.10.0",
     "gulp-plumber": "^1.0.1",
     "gulp-size": "^1.2.1",
-    "gulp-uglify": "^1.1.0",
-    "gulp-uglify-es": "^0.1.3",
+    "gulp-uglify": "^3.0.2",
+    "gulp-uglify-es": "^2.0.0",
     "ioredis": "^3.1.4",
     "jszip": "^3.1.3",
     "log4js": "~2.3.3",

+ 24 - 5
public/billsUtil.js

@@ -15,7 +15,7 @@
         window.BILLS_UTIL = factory();
     }
 })(() => {
-    // 清单模板各清单重设ID时,重新转换清单基数的ID引用
+    // 清单模板各清单重设ID时,重新转换清单基数的ID引用(清单模板基数中使用@x标识行号)
     function parseCalcBase(calcBase, uuidMapping) {
         const orgIDRefs = [...new Set(calcBase.match(/@\d+/g))];
         orgIDRefs.forEach(orgRef => {
@@ -31,12 +31,24 @@
         return calcBase;
     }
 
+    // 重新转换清单基数的ID引用(@xxx标识的是ID)
+    function parseIDRefCalcBase(calcBase, uuidMapping) {
+        let rst = calcBase;
+        Object
+            .entries(uuidMapping)
+            .forEach(([orgID, newID]) => {
+                rst = rst.replace(orgID, newID);
+            });
+        return rst;
+    }
+
     /*
      * @param {Array}billsList (完整的清单树结构数据)
      * @param {Function}idFactory 生成ID的方法
+     * @param {boolean}isIDRef 清单的计算基数,是否可能使用了ID引用(区分模板清单的行引用)
      * @return {void}
      * */
-    function resetTreeData(billsList, idFactory) {
+    function resetTreeData(billsList, idFactory, isIDRef = false) {
         const idMapping = {};
         idMapping['-1'] = -1;
         // 建立新ID-旧ID映射
@@ -46,9 +58,16 @@
             bills.ID = idMapping[bills.ID] ? idMapping[bills.ID] : -1;
             bills.ParentID = idMapping[bills.ParentID] ? idMapping[bills.ParentID] : -1;
             bills.NextSiblingID = idMapping[bills.NextSiblingID] ? idMapping[bills.NextSiblingID] : -1;
-            const needToParseCalcBase = bills.calcBase && reg.test(bills.calcBase);
-            if (needToParseCalcBase) {
-                bills.calcBase = parseCalcBase(bills.calcBase, idMapping);
+            if (isIDRef) {
+                const IDRefReg = /@/;
+                if (bills.calcBase && IDRefReg.test(bills.calcBase)) {
+                    bills.calcBase = parseIDRefCalcBase(bills.calcBase, idMapping);
+                }
+            } else {
+                const needToParseCalcBase = bills.calcBase && reg.test(bills.calcBase);
+                if (needToParseCalcBase) {
+                    bills.calcBase = parseCalcBase(bills.calcBase, idMapping);
+                }
             }
         });
     }

+ 8 - 0
public/common_constants.js

@@ -174,6 +174,13 @@
         BX: 5 // 补项
     };
 
+    // 分享库类型
+    const ShareLibType = {
+        RATION_LIB: 1,
+        GLJ_LIB: 2,
+        BLOCK_LIB: 3,
+    };
+
     return {
         fixedFlag,
         GRANULARITY,
@@ -189,5 +196,6 @@
         EXPORT_KIND,
         RationType,
         BillType,
+        ShareLibType,
     };
 })

+ 14 - 2
public/common_util.js

@@ -22,7 +22,10 @@
     function isEmptyVal(val) {
         return val === null || val === undefined || val === '';
     }
-
+    // 是否数值
+    function isNumber(val) {
+        return !isEmptyVal(val) && !isNaN(val);
+    }
     // v是否有值,不为undefined、null、''
     function hasValue(v) {
         return typeof v !== 'undefined' && v !== null && v !== '';
@@ -128,15 +131,24 @@
         const standardIntPart = temp.reverse().join('');
         return `${standardIntPart}${decimalPart ? '.' + decimalPart : ''}`;
     }
-
+    //判断是否公路云
+    function isGLYun(){
+        return $('title').text().indexOf("纵横公路云造价")!= -1 
+    }
+    function getVersionText(){
+        return isGLYun()?"免费版":"学习版"
+    }
     return {
         isDef,
         isEmptyVal,
+        isNumber,
         hasValue,
         similarEqual,
         isHan,
         getSortedTreeData,
         handleFullscreen,
         standardNumber,
+        isGLYun,
+        getVersionText
     };
 });

+ 13 - 4
public/web/gljUtil.js

@@ -314,11 +314,17 @@ let gljUtil = {
     let price_hasM_decimal = decimalObj.glj.unitPriceHasMix ? decimalObj.glj.unitPriceHasMix : decimalObj.glj.unitPrice;
     let quantity_decimal = decimalObj.glj.quantity;
     let process_decimal = this.isDef(decimalObj.marketPriceProcess) ? decimalObj.marketPriceProcess : decimalObj.process; //20200722  旧的项目还是默认6位,新的用两位
+    let feeRate_decimal = decimalObj.feeRate;
     let priceCoe = this.isDef(tenderCoe) ? tenderCoe : 1;
     if (priceCoe == '0' || priceCoe == 0) priceCoe = 1; // 这里加个保护
     if (['GLF', 'LR', 'FXF'].includes(glj.code)) priceCoe = 1; // 类型是“企业管理费”、“利润”、“一般风险费”的,不应调整单价。
     if (!this.isConcreteType(glj.unit_price.type) && this.notEditType.indexOf(glj.unit_price.type) != -1 && glj.ratio_data.length > 0) { //对于机械台班等有组成物的材料,价格需根据组成物计算得出(排除混凝土、配合比、砂浆这几个类型直接为0)。
       let p = 0;
+      let consSum = 0; //不变费用总和
+      let temSum = 0;//可变费用总和
+      //不变费用组成物包括:折旧费、检修费、维护费、安拆辅助费,这几个材料只能通过名称判断了,类型没有细分。
+      let constNames = ['折旧费','检修费','维护费','安拆辅助费'];
+      let constCoe = scMathUtil.roundForObj(projectGLJDatas.constData.machineConstCoe,feeRate_decimal);
       for (let ratio of glj.ratio_data) {
         let rIndex = gljUtil.getIndex(ratio);
         let tem = _.find(projectGLJDatas.gljList, function (item) {
@@ -329,15 +335,18 @@ let gljUtil = {
           if (ext && ext[tem.id] && this.isDef(ext[tem.id].marketPrice)) { //在修改组成物的价格或消耗量时,影响了父工料机的价格,这时以父工料机的价格应当用组成物的新值来记算
             tem_marketPrice = ext[tem.id].marketPrice;
           };
-
-
           let temP = scMathUtil.roundForObj(tem_marketPrice * priceCoe, price_decimal) * scMathUtil.roundForObj(ratio.consumption, quantity_decimal);
           if(decimalObj.temProcess) temP = scMathUtil.roundForObj(temP, decimalObj.temProcess);//取两次防止中间过程使用两位导致 4舍5入后少0.01的情况
           temP = scMathUtil.roundForObj(temP,process_decimal);
-          p = scMathUtil.roundForObj(temP + p, process_decimal);
+          if(constNames.includes(tem.name) && constCoe !== 1){//不等于1的时候才要另外计算
+            temP = scMathUtil.roundForObj(temP*constCoe,process_decimal);
+            consSum = scMathUtil.roundForObj(temP + consSum,process_decimal);
+          }else {
+            temSum = scMathUtil.roundForObj(temP + temSum, process_decimal);
+          }
         }
       }
-      return scMathUtil.roundForObj(p, price_hasM_decimal);
+      return scMathUtil.roundForObj(temSum + consSum, price_hasM_decimal);
     } else {
       let tem_decimal = price_decimal; //isRadio==true?process_decimal:price_decimal;
       let tem_price = scMathUtil.roundForObj(glj.unit_price.market_price, price_decimal);

+ 140 - 21
public/web/sheet/sheet_common.js

@@ -179,6 +179,7 @@ var sheetCommonObj = {
     },
     showRowData: function (sheet, setting, row, data, distTypeTree = null) {
         let ch = GC.Spread.Sheets.SheetArea.viewport;
+        this.setRowStyle(row, sheet, data[row].bgColour);
         for (var col = 0; col < setting.header.length; col++) {
             //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
             var val = _.get(data[row],setting.header[col].dataCode);
@@ -211,7 +212,7 @@ var sheetCommonObj = {
             }
 
             if (setting.header[col].cellType === "tipsCell") {
-                this.setTipsCell(row, col, sheet, setting.header[col]);
+                this.setTipsCell(row, col, sheet);
             }
             if (setting.owner === 'gljTree') {
                 if (setting.header[col].cellType === "checkBox") {
@@ -223,12 +224,18 @@ var sheetCommonObj = {
                     val = distTypeVal;
                 }
             }
+            if(setting.setCellType) setting.setCellType(sheet,data[row],row,col)
             if (setting.header[col].getText) {
                 val = setting.getText[setting.header[col].getText](data[row], val)
             }
             sheet.setValue(row, col, val, ch);
+            if(setting.getStyle && setting.getStyle(data[row],row,null,setting.header[col].dataCode)){
+                let cstyle = setting.getStyle(data[row],row,null,setting.header[col].dataCode);
+                if(cstyle){
+                    sheet.setStyle(row, col,cstyle);
+                }   
+            }
         }
-        this.setRowStyle(row, sheet, data[row].bgColour);
         if (setting.autoFit == true) {//设置自动行高
             if (setting.fitRow && setting.fitRow.length > 0) {//如果有设置特定的某些列才需要自动行高就按设置的来,没有设置就默认所有列
                 for (let dataCode of setting.fitRow) {
@@ -241,8 +248,8 @@ var sheetCommonObj = {
 
             sheet.autoFitRow(row);
         }
-        if (setting.getStyle && setting.getStyle(data[row], row, sheet.getActiveRowIndex())) {
-            sheet.setStyle(row, -1, setting.getStyle(data[row]));
+        if(setting.getStyle && setting.getStyle(data[row],row,sheet.getActiveRowIndex())){
+            sheet.setStyle(row, -1, setting.getStyle(data[row],row,sheet.getActiveRowIndex()));
         }
     },
     showTreeData:function (sheet,setting,data) {
@@ -400,10 +407,19 @@ var sheetCommonObj = {
         sheet.getCell(row, col).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
 
     },
-    getCheckBox(threeState = false) {
-      var c = new GC.Spread.Sheets.CellTypes.CheckBox();
-      c.isThreeState(threeState);
-      return c
+    getCheckBox(threeState = false){
+        var c = new GC.Spread.Sheets.CellTypes.CheckBox();
+        c.isThreeState(threeState);
+        return c
+    },
+    // 无法勾选的复选框
+    getReadOnlyCheckBox (threeState = false) {
+        function ReadOnlyCheckBox() {}
+        ReadOnlyCheckBox.prototype = this.getCheckBox(threeState);
+        ReadOnlyCheckBox.prototype.processMouseUp = function () {
+            return;
+        };
+        return new ReadOnlyCheckBox();
     },
     setComboBox(row, col, sheet, options, editorValueType, editable, maxDropDownItems) {
         //let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
@@ -673,7 +689,7 @@ var sheetCommonObj = {
         sheet.setCellType(row, col, cellType, GC.Spread.Sheets.SheetArea.viewport);
     },
 
-    setTipsCell(row, col, sheet, header) {
+    setTipsCell(row, col, sheet,tips) {
         let TipCellType = function () { };
         TipCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
         TipCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
@@ -690,16 +706,19 @@ var sheetCommonObj = {
         };
         TipCellType.prototype.processMouseEnter = function (hitinfo) {
             let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
-            let value = hitinfo.sheet.getValue(hitinfo.row, hitinfo.col);
-            let tag = hitinfo.sheet.getTag(hitinfo.row, hitinfo.col);
-            let acStyle = hitinfo.sheet.getActualStyle(hitinfo.row, hitinfo.col),
-                zoom = hitinfo.sheet.zoom();
-            let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, { sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport });
-            let cellWidth = hitinfo.sheet.getCell(-1, hitinfo.col).width();
             let setting = {};
-            if (textLength <= cellWidth) {
-                return;
+            if(!tips){
+                let value = hitinfo.sheet.getValue(hitinfo.row, hitinfo.col);
+                let tag = hitinfo.sheet.getTag(hitinfo.row, hitinfo.col);
+                let acStyle = hitinfo.sheet.getActualStyle(hitinfo.row, hitinfo.col),
+                    zoom = hitinfo.sheet.zoom();
+                let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, { sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport });
+                let cellWidth = hitinfo.sheet.getCell(-1, hitinfo.col).width();
+                if (textLength <= cellWidth) {
+                    return;
+                }
             }
+            text = tips;
             if (sheet && sheet.getParent().qo) {
                 setting.pos = SheetDataHelper.getObjPos(sheet.getParent().qo);
             }
@@ -763,7 +782,59 @@ var sheetCommonObj = {
         };
         return new ComboCellForActiveCell();
     },
-    getTipsCombo: function (forLocked, tips, setting, node) {
+    getTipsCell: function (baseCell, cellPrototype, tips, setting, node) {
+        let getTipsCell = function () {
+            this.clickCom=false;
+        };
+        getTipsCell.prototype = baseCell;
+        if(tips && tips !=""){
+            getTipsCell.prototype.processMouseEnter = function(hitinfo){
+                if(this.clickCom == true){ //点击了下拉框的三角形,则不用再显示悬浮框了
+                    this.clickCom = false;
+                    return;
+                }
+                let text =  typeof tips == 'function'?tips(node):tips;
+                TREE_SHEET_HELPER.delayShowTips(hitinfo,setting,text);
+            };
+            getTipsCell.prototype.processMouseLeave = function (hitinfo) {
+                TREE_SHEET_HELPER.hideTipsDiv();
+            };
+            getTipsCell.prototype.processMouseDown = function (hitinfo){
+                if(hitinfo.isReservedLocation == true){//这里是点击了下拉框的三角形才会有这个属性
+                    TREE_SHEET_HELPER.hideTipsDiv();
+                    this.clickCom = true;
+                }
+                cellPrototype.processMouseDown.apply(this, arguments);
+            };
+
+            getTipsCell.prototype.updateEditor = function (editorContext, cellStyle, cellRect, context){
+                TREE_SHEET_HELPER.hideTipsDiv();
+                cellPrototype.updateEditor.apply(this, arguments);
+            };
+        }
+        return new getTipsCell();
+    },
+    getTipsText: function (tips, setting, node) {
+        function baseTextCell() {}
+        baseTextCell.prototype = new GC.Spread.Sheets.CellTypes.Text();
+        baseTextCell.prototype.getHitInfo =  function (x, y, cellStyle, cellRect, context) {
+            return {
+                x: x,
+                y: y,
+                row: context.row,
+                col: context.col,
+                cellStyle: cellStyle,
+                cellRect: cellRect,
+                sheetArea: context.sheetArea
+            };
+        };
+        return this.getTipsCell(new baseTextCell(), GC.Spread.Sheets.CellTypes.Text.prototype, tips, setting, node);
+    },
+    getTipsCombo:function (forLocked,tips,setting,node) {
+        const baseCell = sheetCommonObj.getDynamicCombo(forLocked);
+        return this.getTipsCell(baseCell, GC.Spread.Sheets.CellTypes.ComboBox.prototype, tips, setting, node);
+    },
+    /* getTipsCombo: function (forLocked, tips, setting, node) {
         let getTipsCombo = function () {
             this.clickCom = false;
         };
@@ -794,8 +865,8 @@ var sheetCommonObj = {
             };
         }
         return new getTipsCombo();
-    },
-    getTreeNodeCellType: function (datas, row, parentMap,treeCol, paintFunc) {// 2018-09-26  不用spreadjs默认的树结构,自定义控件
+    }, */
+    getTreeNodeCellType: function (datas, row, parentMap,treeCol, paintFunc,tips) {// 2018-09-26  不用spreadjs默认的树结构,自定义控件
         var ns = GC.Spread.Sheets;
         let rectW = 10;
         let rectH = 10;
@@ -860,6 +931,26 @@ var sheetCommonObj = {
                 sheetArea: context.sheetArea
             };
         }
+        if(tips){
+            TreeNodeCellType.prototype.processMouseEnter = function (hitinfo) {
+                let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
+                let setting = {};
+                text = tips;
+                if (hitinfo.sheet && hitinfo.sheet.getParent().qo) {
+                    setting.pos = SheetDataHelper.getObjPos(hitinfo.sheet.getParent().qo);
+                }
+    
+                TREE_SHEET_HELPER.showTipsDiv(text, setting, hitinfo);
+            };
+            TreeNodeCellType.prototype.processMouseLeave = function (hitinfo) {
+                TREE_SHEET_HELPER.tipDiv = 'hide';
+                if (TREE_SHEET_HELPER._toolTipElement) {
+                    $(TREE_SHEET_HELPER._toolTipElement).hide();
+                    TREE_SHEET_HELPER._toolTipElement = null;
+                };
+                TREE_SHEET_HELPER.tipDivCheck();//延时检查:当tips正在show的时候,就调用了hide方法,会导致tips一直存在,所以设置一个超时处理
+            };
+        }
         TreeNodeCellType.prototype.processMouseDown = function (hitinfo) {
             ////方框外1像素内都有效
             if (!_.isEmpty(this.rectInfo) && Math.floor(hitinfo.x) <= this.rectInfo.x + this.rectInfo.rectW + 2 && Math.floor(hitinfo.x) >= this.rectInfo.x - 2) {
@@ -909,7 +1000,7 @@ var sheetCommonObj = {
         return new TreeNodeCellType()
 
         function getTreeLevel(item, data) {
-            if (item.ParentID && item.ParentID!=-1) {
+            if (item && item.ParentID && item.ParentID!=-1) {
                 let pitem = _.find(data, { 'ID': item.ParentID });
                 return getTreeLevel(pitem, data) + 1;
             } else {
@@ -1263,6 +1354,34 @@ var sheetCommonObj = {
         }
         return null;
     },
+    disableSpread(spread) {
+        spread.unbind(GC.Spread.Sheets.Events.ButtonClicked);
+        let sheetCount = spread.getSheetCount();
+        for(let i = 0; i < sheetCount; i++){
+            let sheet = spread.getSheet(i);
+            sheet.unbind(GC.Spread.Sheets.Events.ButtonClicked);
+            sheet.unbind(GC.Spread.Sheets.Events.EditStarting);
+            sheet.unbind(GC.Spread.Sheets.Events.EditEnded);
+            sheet.unbind(GC.Spread.Sheets.Events.RangeChanged);
+            sheet.unbind(GC.Spread.Sheets.Events.ClipboardChanging);
+            sheet.unbind(GC.Spread.Sheets.Events.ClipboardChanged);
+            sheet.unbind(GC.Spread.Sheets.Events.CellDoubleClick);
+            sheet.unbind(GC.Spread.Sheets.Events.CellClick);
+            sheet.unbind(GC.Spread.Sheets.Events.ValueChanged);
+            sheet.suspendPaint();
+            sheet.suspendEvent();
+            sheet.options.isProtected = true;
+            let rowCount = sheet.getRowCount();
+            let colCount = sheet.getColumnCount();
+            for(let row = 0; row < rowCount; row++){
+                for(let col = 0; col < colCount; col++){
+                    sheet.getCell(row, col).locked(true);
+                }
+            }
+            sheet.resumePaint();
+            sheet.resumeEvent();
+        }
+    },
     // 延迟一段时间刷新表格,因为有的弹窗里面有表格,马上刷新可能会造成,弹窗界面还未完全显示完就完成了表格刷新,导致表格显示不完整
     refreshWorkbookDelDefer(workbook, time) {
         if (workbook) {

+ 11 - 2
public/web/tree_sheet/tree_sheet_helper.js

@@ -158,6 +158,7 @@ var TREE_SHEET_HELPER = {
                     }
                     return data;
                 };
+                var cell = sheet.getCell(iRow, iCol, GC.Spread.Sheets.SheetArea.viewport);
                 if(sheet.name()=="mainSheet"){
                  /*   if(colSetting.data.field=="quantity"){  2018-08-06 去掉工程量列表达式
                         let tag = node.data.quantityEXP?node.data.quantityEXP:'';
@@ -172,15 +173,21 @@ var TREE_SHEET_HELPER = {
                         }*/
                         if(tag!=null) sheet.setTag(iRow, iCol,tag);
                     }
+                    // 单元格字体颜色
+                    const foreColorFunc = MainTreeCol.foreColor[colSetting.data.field];
+                    if (foreColorFunc) {
+                        cell.foreColor(foreColorFunc(node));
+                    }
                     /*if(colSetting.data.field=="name"){ 2018-08-06 改成在编号列悬浮提示
                         let tag = node.data.itemCharacterText?node.data.itemCharacterText:'';
                         sheet.setTag(iRow, iCol,tag);
                     }*/
                 }
                 if(colSetting.visible == false) return;//隐藏列不做其它操作
-                var cell = sheet.getCell(iRow, iCol, GC.Spread.Sheets.SheetArea.viewport);
                 if (colSetting.data.getText && Object.prototype.toString.apply(colSetting.data.getText) === "[object Function]") {
                     cell.value(colSetting.data.getText(node));
+                } else if(['outPutMaxPrice', 'outPutLimitPrice'].includes(colSetting.data.field) && node.sourceType === projectObj.project.Bills.getSourceType()){//主要清单有三种状态,所以直接显示就好,不走最后的逻辑
+                    cell.value(node.data[colSetting.data.field]===undefined?false:node.data[colSetting.data.field]);
                 } else {
                     cell.value(getFieldText2());
                 }
@@ -192,7 +199,9 @@ var TREE_SHEET_HELPER = {
                 if(colSetting.data.autoHeight == true){
                     colSetting.setAutoHeight(cell,node);
                 }
-                if(colSetting.editChecking&&colSetting.editChecking(node)){
+                // “清单锁定”功能 “单价”和“金额”不锁定
+                const lockBillsWhiteList = ['feesIndex.common.unitFee', 'feesIndex.common.totalFee'];
+                if(colSetting.editChecking&&colSetting.editChecking(node) && !lockBillsWhiteList.includes(colSetting.data.field)){
                     cell.locked(true);
                 }else if (colSetting.readOnly) {
                     if(typeof projectReadOnly !== 'undefined' && projectReadOnly){

+ 1 - 0
server.js

@@ -20,6 +20,7 @@ dbm.connect(process.env.NODE_ENV);
 fileUtils.getGlobbedFiles('./modules/all_models/*.js').forEach(function(modelPath) {
     require(path.resolve(modelPath));
 })
+
 //config.setupCache();
 let cfgCacheUtil = require("./config/cacheCfg");
 cfgCacheUtil.setupDftCache();

+ 13 - 5
web/building_saas/complementary_glj_lib/html/tools-gongliaoji.html

@@ -23,6 +23,13 @@
         }
         .modal-lg{max-width: 1000px}
     </style>
+    <script>
+        const isReadOnly = JSON.parse('<%= isReadOnly %>');
+        const userID = "<%= userID%>";
+        let userId = "<%= userID%>";
+        let compilationId = "<%= compilationId%>";
+        let stdGljLibId = "<%= gljLibId%>";//用户当前编办下的标准工料机库ID,目前认为一个编办只有一个标准工料机库
+    </script>
 </head>
 <body>
     <div class="header">
@@ -145,6 +152,7 @@
             </div>
         </div>
     </div>
+    <%include ../../../common/components/share/index.html %>
     <!-- JS. -->
     <script src="/lib/jquery-contextmenu/jquery.contextMenu.min.js"></script>
     <script src="/lib/jquery-contextmenu/jquery.ui.position.js"></script>
@@ -154,8 +162,10 @@
     <script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>
     <script type="text/javascript" src="/lib/ztree/jquery.ztree.exedit.js"></script>
     <!--inject:js-->
-    <script src="/web/building_saas/js/global.js"></script>
     <!-- zTree -->
+    <script src="/lib/pinyinjs/pinyin_dict_firstletter.js"></script>
+    <script src="/lib/pinyinjs/pinyinUtil.js"></script>
+    <script src="/web/common/components/share/index.js"></script>
     <script type="text/javascript" src="/public/web/common_ajax.js"></script>
     <script type="text/javascript" src="/public/web/treeDataHelper.js"></script>
     <script type="text/javascript" src="/public/web/QueryParam.js"></script>
@@ -165,6 +175,7 @@
     <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_controller.js"></script>
     <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_helper.js"></script>
     <script type="text/javascript" src="/public/web/ration_glj_units.js"></script>
+    <script type="text/javascript" src="/web/building_saas/complementary_glj_lib/js/init.js"></script>
     <script type="text/javascript" src="/web/building_saas/complementary_glj_lib/js/glj.js"></script>
     <script type="text/javascript" src="/web/building_saas/complementary_glj_lib/js/gljClassTree.js"></script>
     <script type="text/javascript" src="/web/building_saas/complementary_glj_lib/js/gljComponent.js"></script>
@@ -177,9 +188,6 @@
     <!--endinject-->
     <script type="text/javascript" src="<%= overWriteUrl %>"></script>
     <SCRIPT type="text/javascript">
-        let userId = "<%= userID%>";
-        let compilationId = "<%= compilationId%>";
-        let stdGljLibId = "<%= gljLibId%>";//用户当前编办下的标准工料机库ID,目前认为一个编办只有一个标准工料机库
         let gljSetting = {
             view: {
                 //addHoverDom: gljTypeTreeOprObj.addHoverDom,
@@ -257,7 +265,7 @@
             $('#componentTreeDiv').height($(window).height() - 300);
             $("#componentSheet").height($("#componentTreeDiv").height() - 15);
             $("#componentSheet").width($('#modalCon').width() * 0.63); */
-            pageOprObj.initPage($("#GLJListSheet")[0], $('#gljComponentSheet')[0], $("#componentSheet")[0]);
+            //pageOprObj.initPage($("#GLJListSheet")[0], $('#gljComponentSheet')[0], $("#componentSheet")[0]);
         });
         //组成物弹出窗大小设置
         /* $(window).resize(function () {

+ 10 - 5
web/building_saas/complementary_glj_lib/js/glj.js

@@ -161,7 +161,7 @@ let repositoryGljObj = {
     },
     getGljDistType: function (callback) {
         let me = this;
-        CommonAjax.post('complementartGlj/api/getGljDistType', {}, function (rstData) {
+        CommonAjax.post('/complementartGlj/api/getGljDistType', {}, function (rstData) {
             if(callback){
                 me.distTypeTree = me.getComboData(rstData);
                 console.log(me.distTypeTree);
@@ -175,7 +175,7 @@ let repositoryGljObj = {
     },
     getGljTree: function(gljLibId, callback) {
         let me = this;
-        CommonAjax.post('complementartGlj/api/getGljTree', {gljLibId: gljLibId}, function (rstData) {
+        CommonAjax.post('/complementartGlj/api/getGljTree', {gljLibId: gljLibId}, function (rstData) {
             zTreeHelper.createTree(rstData, gljSetting, "repositoryTree", me);
             zTreeHelper.createTree(rstData, componentSetting, "componentTree", componentOprObj);
             if (rstData && rstData.length > 0) {
@@ -316,6 +316,9 @@ let repositoryGljObj = {
     buildSheet: function(container) {
         let me = repositoryGljObj;
         me.workBook = sheetOpr.buildSheet(container, me.setting, 30);
+        if (isReadOnly) {
+            sheetCommonObj.disableSpread(me.workBook);
+        }
         sheetCommonObj.spreadDefaultStyle(me.workBook);
         me.repositoryGljDelOpr();
         me.onContextmenuOpr();
@@ -574,7 +577,9 @@ let repositoryGljObj = {
         let deESCFields = ['code', 'name', 'specs'];
         let dataCode = me.setting.header[args.col].dataCode;
         if(deESCFields.includes(dataCode)){
-            args.editingText = me.isDef(args.editingText) ? args.editingText.toString().replace(/[\r, \n]/g, ' ') : '';
+            args.editingText = me.isDef(args.editingText) 
+                ? args.editingText.toString().replace(/[\r, \n]/g, ' ').replace(/\s$/, '')
+                : '';
             args.sheet.setValue(args.row, args.col, args.editingText);
         }
         let rObj = sheetOpr.combineRowData(me.workBook.getSheet(0), me.setting, args.row, me),
@@ -831,7 +836,7 @@ let repositoryGljObj = {
                             "delete": {
                                 name: "删除",
                                 disabled: function () {
-                                    return !(me.currentCache && me.currentCache[target.row]);
+                                    return isReadOnly || !(me.currentCache && me.currentCache[target.row]);
                                 },
                                 icon: "fa-remove",
                                 callback: function (key, opt) {
@@ -1153,7 +1158,7 @@ let repositoryGljObj = {
         if(addArr.length > 0){
             me.saveInString(addArr);
         }
-        let url = 'complementartGlj/api/mixUpdateGljItems';
+        let url = '/complementartGlj/api/mixUpdateGljItems';
         let post = {updateItems: updateArr, addItems: addArr, removeIds: removeIds};
         let scCaller = function (rstData) {
             me.updateCache(addArr, updateArr, removeIds, rstData);

+ 6 - 4
web/building_saas/complementary_glj_lib/js/gljComponent.js

@@ -35,7 +35,9 @@ let gljComponentOprObj = {
         me.workBook.getSheet(0).setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader);
         me.workBook.getSheet(0).setFormatter(-1, 0, "@", GC.Spread.Sheets.SheetArea.viewport);
         sheetOpr.cleanData(me.workBook.getSheet(0), me.setting, -1);
-
+        if (isReadOnly) {
+            sheetCommonObj.disableSpread(me.workBook);
+        }
         me.onContextmenuOpr();//右键菜单
         me.gljComponentDelOpr();
         me.workBook.getSheet(0).bind(GC.Spread.Sheets.Events.EditStarting, me.onCellEditStart);
@@ -91,7 +93,7 @@ let gljComponentOprObj = {
                     return {
                         callback: function(){},
                         items: {
-                            "insert": {name: "插入", disabled: insertDis, icon: "fa-sign-in", callback: function (key, opt) {
+                            "insert": {name: "插入", disabled: isReadOnly || insertDis, icon: "fa-sign-in", callback: function (key, opt) {
                                 let oprFunc = function () {
                                     //默认radio所有工料机
                                     co.initRadio();
@@ -107,7 +109,7 @@ let gljComponentOprObj = {
                                     repositoryGljObj.getStdItems(pageOprObj.stdGljLibId, oprFunc);
                                 }
                             }},
-                            "delete": {name: "删除", disabled: delDis, icon: "fa-remove", callback: function (key, opt) {
+                            "delete": {name: "删除", disabled: isReadOnly || delDis, icon: "fa-remove", callback: function (key, opt) {
                                 //删除
                                 let deleteObj = that.currentComponent[target.row];
                                 let gljComponent = that.currentGlj.component;
@@ -488,7 +490,7 @@ let gljComponentOprObj = {
         that.saveInString(updateArr);
         $.ajax({
             type: 'post',
-            url: 'complementartGlj/api/updateComponent',
+            url: '/complementartGlj/api/updateComponent',
             data: {"userId": pageOprObj.userId, "updateArr": JSON.stringify(updateArr)},
             dataType: 'json',
             success: function (result) {

+ 118 - 0
web/building_saas/complementary_glj_lib/js/init.js

@@ -0,0 +1,118 @@
+const GLJ_INIT = (() => {
+  const params = location.href.split('/');
+  const curUserID = params[params.length - 1];
+  console.log('curUserID', curUserID);
+
+  // 头部按钮相关
+  function initHeaderTools(receiveList, shareList) {
+    // 设置下拉项
+    const selectHtml = `
+    <select class="form-control  form-control-sm" id="glj-libs">
+    </select>`;
+    // 设置分享按钮
+    const shareHtml = `
+    <span id="share-tip" class="ml-2" data-toggle="tooltip" data-placement="bottom" data-original-title="">
+        <a id="init-share" href="javascript:;" class="btn btn-xs btn-primary ${isReadOnly ? 'disabled' : ''}"><i class="fa fa-share-alt"></i> 分享</a>
+    </span>`;
+    const html = `
+        <div style="display: flex; align-items: center">
+            ${selectHtml}
+            ${shareHtml}
+        </div>
+    `
+    $('#fullpath').html(html);
+    initShareTip(shareList);
+    $('[data-toggle="tooltip"]').tooltip();
+    initLibOptions(receiveList);
+    // 分享给
+    SHARE_TO.handleEventListener();
+    $('#init-share').click(() => {
+      SHARE_TO.initModal(SHARE_TO.Mode.GLJ_LIB);
+      $('#share-tip').tooltip('hide');
+    });
+
+    // 库下拉
+    function initShareTip(shareList) {
+      if (shareList.length) {
+        const owners = shareList.map(owner => owner.real_name);
+        const tips = `已分享给 ${owners.join(' ')}`;
+        $('#share-tip').attr('data-original-title', tips);
+      }
+    }
+
+    // 库下拉
+    function initLibOptions(receiveList) {
+      const libList = [
+        `<option value="${userID}">我的补充人材机库</option>`
+      ];
+      const options = receiveList.map(owner => `<option value=${owner._id} ${curUserID === owner._id ? 'selected' : ''}>${owner.real_name}的补充人材机库</option>`);
+      libList.push(...options);
+      $('#glj-libs').html(libList.join(''))
+    }
+
+    $('#glj-libs').change(function () {
+      const userID = $(this).val();
+      window.location.href = `/complementaryGlj/${userID}`;
+    });
+  }
+
+  $(document).ready(() => {
+    $.bootstrapLoading.start();
+    const projection = {
+      _id: 0,
+      ID: 1,
+      code: 1,
+      unit: 1,
+      name: 1,
+      priceProperty: 1,
+      basePrice: 1
+    };
+    CommonAjax.post('/complementartGlj/api/initData', { projection, userID: curUserID }, res => {
+        if (res.error) {
+            alert('数据初始化失败,请重试。');
+            setTimeout(() => {
+                window.location.href = '/'
+            }, 1200);
+        } else {
+          const { receiveLibs, shareLibs, gljItems, mixTree, distTypeData } = res;
+          initHeaderTools(receiveLibs, shareLibs);
+          pageOprObj.stdGljLibId = stdGljLibId;
+          repositoryGljObj.currentRepositoryId = stdGljLibId;
+          pageOprObj.userId = userId;
+          pageOprObj.compilationId = compilationId;
+          repositoryGljObj.buildSheet($("#GLJListSheet")[0]);
+          gljComponentOprObj.buildSheet($('#gljComponentSheet')[0]);
+          componentOprObj.buildSheet($("#componentSheet")[0]);
+          // distTypeTree
+          repositoryGljObj.distTypeTree = repositoryGljObj.getComboData(distTypeData);
+          // tree
+          gljClassTreeObj.treeData = mixTree;
+          if (mixTree.comple && mixTree.comple.length > 0) {
+            gljClassTreeObj.gljCurTypeId = mixTree.comple[0].ID;
+          }
+          gljClassTreeObj.buildSheet();
+          gljClassTreeObj.initTree(mixTree.comple);
+          gljClassTreeObj.cache = gljClassTreeObj.tree.items;
+          repositoryGljObj.updateParentNodeIds(gljClassTreeObj.cache, repositoryGljObj);
+          gljClassTreeObj.initController(gljClassTreeObj.tree, gljClassTreeObj.sheet, gljClassTreeObj.setting.sheet);
+          gljClassTreeObj.controller.showTreeData();
+          gljClassTreeObj.sheet.setFormatter(-1, 0, '@');
+          // gljItems
+          repositoryGljObj.stdGljList = gljItems.stdGljs;
+          // 兼容多单价情况
+          for (const sGlj of repositoryGljObj.stdGljList) {
+              if (sGlj.priceProperty && typeof sGlj.priceProperty.price1 !== 'undefined') {
+                  sGlj.basePrice = sGlj.priceProperty.price1;
+              }
+          }
+          repositoryGljObj.sortGlj(repositoryGljObj.stdGljList);
+          repositoryGljObj.setProp('isStd', true, repositoryGljObj.stdGljList);
+          repositoryGljObj.complementaryGljList = gljItems.complementaryGljs;
+          repositoryGljObj.sortGlj(repositoryGljObj.complementaryGljList);
+          gljClassTreeObj.initSelection(gljClassTreeObj.tree.selected);
+        }
+        $.bootstrapLoading.end();
+    });
+  });
+
+})();

+ 0 - 1
web/building_saas/complementary_ration_lib/html/anzhuang.html

@@ -188,7 +188,6 @@
     <script src="/public/web/tree_sheet/tree_sheet_helper.js"></script>
     <script src="/public/web/sheet/sheet_common.js"></script>
     <script src="/public/web/common_ajax.js"></script>
-    <script src="/web/building_saas/complementary_ration_lib/js/global.js"></script>
     <script src="/web/building_saas/complementary_ration_lib/js/installation.js"></script>
     <!--endinject-->
 </body>

+ 5 - 0
web/building_saas/complementary_ration_lib/html/dinge.html

@@ -56,6 +56,7 @@
         }
     </style>
     <script>
+        const isReadOnly = JSON.parse('<%= isReadOnly %>');
         const gljLibId = '<%= gljLibId %>';
         const userID = '<%=userID %>';
     </script>
@@ -603,6 +604,7 @@
         </div>
     </div>
 </div>
+<%include ../../../common/components/share/index.html %>
 <!-- JS. -->
 <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>
 <script>GC.Spread.Sheets.LicenseKey =  '<%- LicenseKey %>';</script>
@@ -612,6 +614,9 @@
 <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.ui.position.js"></script>
 <script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
 <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/global.js"></script>
+<script src="/lib/pinyinjs/pinyin_dict_firstletter.js"></script>
+<script src="/lib/pinyinjs/pinyinUtil.js"></script>
+<script src="/web/common/components/share/index.js"></script>
 <script type="text/javascript" src="/public/web/id_tree.js"></script>
 <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_controller.js"></script>
 <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_helper.js"></script>

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

@@ -40,7 +40,6 @@
     <script src="/lib/popper/popper.min.js"></script>
     <script src="/lib/jquery/jquery-3.2.1.min.js"></script>
     <script src="/lib/bootstrap/bootstrap.min.js"></script>
-    <script src="/web/building_saas/js/global.js"></script>
     <!-- zTree -->
     <script type="text/javascript" src="/public/web/date_util.js"></script>
     <script type="text/javascript" src="/public/web/common_ajax.js"></script>

+ 9 - 2
web/building_saas/complementary_ration_lib/js/coe.js

@@ -173,6 +173,10 @@ var pageObj = {
         let me = this;
         coeOprObj.buildSheet($('#mainSpread')[0]);
         gljAdjOprObj.buildSheet($('#contentSpread')[0]);
+        if (isReadOnly) {
+            sheetCommonObj.disableSpread(coeOprObj.workBook);
+            sheetCommonObj.disableSpread(gljAdjOprObj.workBook);
+        }
         coeOprObj.getCoeList();
         //gljAdjOprObj.getGljItemsOcc();
 
@@ -452,9 +456,12 @@ let coeOprObj = {
     },
     getCoeList: function () {
         let me = coeOprObj;
+        const params = location.href.split('/');
+        const curUserID = params[params.length - 1];
         $.ajax({
             type: 'post',
-            url: 'api/getCoeList',
+            url: '/complementaryRation/api/getCoeList',
+            data: {data: JSON.stringify({userID: curUserID})},
             dataType: 'json',
             timeout:20000,
             success: function (result) {
@@ -475,7 +482,7 @@ let coeOprObj = {
         let me = coeOprObj;
         $.ajax({
             type:"POST",
-            url:"api/saveCoeList",
+            url:"/complementaryRation/api/saveCoeList",
             data: {data: JSON.stringify({addArr: addArr, updateArr: updateArr, deleteArr: deleteArr})},
             dataType:"json",
             timeout:5000,

+ 2 - 1
web/building_saas/complementary_ration_lib/js/gljSelect.js

@@ -195,7 +195,8 @@ let gljSelOprObj = {
         let me = gljSelOprObj;
         //选择改变,数据重新筛选显示
         me.showGljList = [];
-        if (gljLib === commonConstants.COMPLEMENTARY_LIB) {
+        const cptLibReg = new RegExp(commonConstants.COMPLEMENTARY_LIB);
+        if (cptLibReg.test(gljLib)) {
             me.setShowGljList(me.complementaryGljList);
         } else {
             me.setShowGljList(me.stdGljList);

+ 71 - 2
web/building_saas/complementary_ration_lib/js/init.js

@@ -8,9 +8,65 @@
  * @version
  */
 const initialization = (() => {
+    const params = location.href.split('/');
+    const curUserID = params[params.length - 1];
+
+    // 头部按钮相关
+    function initHeaderTools(receiveList, shareList) {
+        // 设置下拉项
+        const selectHtml = `
+        <select class="form-control  form-control-sm" id="ration-libs">
+        </select>`;
+        // 设置分享按钮
+        const shareHtml = `
+        <span id="share-tip" class="ml-2" data-toggle="tooltip" data-placement="bottom" data-original-title="">
+            <a id="init-share" href="javascript:;" class="btn btn-xs btn-primary"><i class="fa fa-share-alt"></i> 分享</a>
+        </span>`;
+        const html = `
+            <div style="display: flex; align-items: center">
+                ${selectHtml}
+                ${shareHtml}
+            </div>
+        `
+        $('#fullpath').html(html);
+        initShareTip(shareList);
+        $('[data-toggle="tooltip"]').tooltip();
+        initLibOptions(receiveList);
+        // 分享给
+        SHARE_TO.handleEventListener();
+        $('#init-share').click(() => {
+            SHARE_TO.initModal(SHARE_TO.Mode.RATION_LIB);
+            $('#share-tip').tooltip('hide');
+        });
+
+        // 定额库下拉
+        function initShareTip(shareList) {
+            if (shareList.length) {
+                const owners = shareList.map(owner => owner.real_name);
+                const tips = `已分享给 ${owners.join(' ')}`;
+                $('#share-tip').attr('data-original-title', tips);
+            }
+        }
+
+        // 定额库下拉
+        function initLibOptions(receiveList) {
+            const libList = [
+                `<option value="${userID}">我的补充定额库</option>`
+            ];
+            const options = receiveList.map(owner => `<option value=${owner._id} ${curUserID === owner._id ? 'selected' : ''}>${owner.real_name}的补充定额库</option>`);
+            libList.push(...options);
+            $('#ration-libs').html(libList.join(''))
+        }
+
+        $('#ration-libs').change(function () {
+            const userID = $(this).val();
+            window.location.href = `/complementaryRation/ration/${userID}`;
+        });
+    }
+
     $(document).ready(function () {
         $.bootstrapLoading.start();
-        CommonAjax.get('/complementaryRation/api/initData', {}, res => {
+        CommonAjax.get('/complementaryRation/api/initData', { userID: curUserID }, res => {
             if (res.error) {
                 alert('数据初始化失败,请重试。');
                 setTimeout(() => {
@@ -18,6 +74,7 @@ const initialization = (() => {
                 }, 1200);
             } else {
                 const data = res.data;
+                initHeaderTools(data.receiveLibs, data.shareLibs);
                 pageOprObj.rationTreeData = data.rationTreeData;
                 pageOprObj.mixedTreeData = data.mixedTreeData;
                 pageOprObj.mixedGLJData = data.mixedGLJData;
@@ -28,6 +85,7 @@ const initialization = (() => {
                 var rdSpread = sheetCommonObj.createSpread($("#rdSpread")[0], 4);
                 rdSpread.options.allowUserDragFill = false;
                 rdSpread.options.allowUserDragDrop = false;
+                rdSpread.options.allowExtendPasteRange = true;
                 sheetCommonObj.spreadDefaultStyle(rdSpread);
                 rationGLJOprObj.buildSheet(rdSpread.getSheet(0));
                 rationAssistOprObj.buildSheet(rdSpread.getSheet(1));
@@ -42,7 +100,18 @@ const initialization = (() => {
                 sheetCommonObj.bindEscKey(rdSpread, rdSpreadEscSheets);
                 gljAdjOprObj.gljList = data.mixedGLJData.stdGljs.concat(data.mixedGLJData.complementaryGljs);
                 pageOprObj.initPage();
-
+                if (isReadOnly) {
+                    sheetCommonObj.disableSpread(sectionTreeObj.workBook);
+                    sheetCommonObj.disableSpread(rationOprObj.workBook);
+                    sheetCommonObj.disableSpread(rdSpread);
+                    $('#tree_Insert').addClass('disabled');
+                    $('#tree_remove').addClass('disabled');
+                    $('#tree_upLevel').addClass('disabled');
+                    $('#tree_downLevel').addClass('disabled');
+                    $('#tree_downMove').addClass('disabled');
+                    $('#tree_upMove').addClass('disabled');
+                    $('#init-share').addClass('disabled');
+                }
                 $("#linkGLJ").click(function(){
                     rationGLJOprObj.bindRationGljDelOpr();
                     rdSpread.setActiveSheetIndex(0);

+ 5 - 5
web/building_saas/complementary_ration_lib/js/installation.js

@@ -339,7 +339,7 @@ let feeItemObj = {
     },
     getInstallation: function (callback) {
         let me = this;
-        CommonAjax.post('api/getInstallation', {}, function (rstData) {
+        CommonAjax.post('/complementaryRation/api/getInstallation', {}, function (rstData) {
             me.cache = rstData;
             if(callback){
                 callback(rstData);
@@ -348,7 +348,7 @@ let feeItemObj = {
     },
     updateFeeItem: function (updateData, callback) {
         let me = this;
-        CommonAjax.post('api/updateFeeItem', {updateData: updateData}, function (rstData) {
+        CommonAjax.post('/complementaryRation/api/updateFeeItem', {updateData: updateData}, function (rstData) {
             if(callback){
                 callback();
             }
@@ -577,7 +577,7 @@ let sectionObj = {
         me.workBook.commandManager().setShortcutKey('sectionDel', GC.Spread.Commands.Key.del, false, false, false, false);
     },
     updateSection: function (updateData, callback) {
-        CommonAjax.post('api/updateInstallSection', {updateData: updateData}, function (rstData) {
+        CommonAjax.post('/complementaryRation/api/updateInstallSection', {updateData: updateData}, function (rstData) {
             if(callback){
                 callback();
             }
@@ -1140,7 +1140,7 @@ let batchSectionObj = {
     },
     getSectionTree: function () {
         let me = this;
-        let url = 'api/getRationTree';
+        let url = '/complementaryRation/api/getRationTree';
         //type:0补充定额库,1标准定额库
         let postData = {type: 0};
         let sucFunc = function (rstData) {
@@ -1258,7 +1258,7 @@ let batchSectionObj = {
     },
     //inst: 定额安装费用, rationSection: 定额章节树IDs
     batchUpdate: function (feeItemId, sectionId, rationSection) {
-        CommonAjax.post('api/batchUpdateInst', {inst: {feeItemId: feeItemId, sectionId: sectionId}, rationSection: rationSection}, function (rstData) {
+        CommonAjax.post('/complementaryRation/api/batchUpdateInst', {inst: {feeItemId: feeItemId, sectionId: sectionId}, rationSection: rationSection}, function (rstData) {
             $('#sectionTreeModal').modal('hide');
         });
     }

+ 11 - 5
web/building_saas/complementary_ration_lib/js/ration.js

@@ -619,7 +619,7 @@ let rationOprObj = {
     mixUpdateRequest: function(updateArr, addArr, removeIds, callback) {
         let me = rationOprObj;
         me.saveInString(updateArr);
-        CommonAjax.post('api/mixUpdateRationItems', {sectionId: me.currentSectionId, updateItems: updateArr, addItems: addArr, removeIds: removeIds}, function (rstData) {
+        CommonAjax.post('/complementaryRation/api/mixUpdateRationItems', {sectionId: me.currentSectionId, updateItems: updateArr, addItems: addArr, removeIds: removeIds}, function (rstData) {
             let cacheSection = me.updateCache(addArr, updateArr, removeIds, rstData);
             me.sortByCode(cacheSection);
             /*cacheSection.sort(function(a, b){
@@ -675,12 +675,14 @@ let rationOprObj = {
                 //annotation
                 //annotationOprObj.rationAnnotationOpr(me.currentRations["_SEC_ID_" + sectionID]);
                 me.showRationItems(sectionID);
-                sectionTreeObj.removeBtn.removeClass('disabled');
+                if (!isReadOnly) {
+                    sectionTreeObj.removeBtn.removeClass('disabled');
+                }
                 if(callback){
                     callback();
                 }
             } else {
-                CommonAjax.post('api/getRationItems', {sectionId: sectionID}, function (rstData) {
+                CommonAjax.post('/complementaryRation/api/getRationItems', {sectionId: sectionID}, function (rstData) {
                     me.currentRations["_SEC_ID_" + sectionID] = rstData;
                     me.sortByCode(me.currentRations["_SEC_ID_" + sectionID]);
                     //job--
@@ -689,12 +691,16 @@ let rationOprObj = {
                     //annotation
                     //annotationOprObj.rationAnnotationOpr(me.currentRations["_SEC_ID_" + sectionID]);
                     me.showRationItems(sectionID);
-                    sectionTreeObj.removeBtn.removeClass('disabled');
+                    if (!isReadOnly) {
+                        sectionTreeObj.removeBtn.removeClass('disabled');
+                    }
                     if(callback) {
                         callback();
                     }
                 }, function () {
-                    sectionTreeObj.removeBtn.removeClass('disabled');
+                    if (!isReadOnly) {
+                        sectionTreeObj.removeBtn.removeClass('disabled');
+                    }
                 });
             }
         }

+ 3 - 1
web/building_saas/complementary_ration_lib/js/ration_assist.js

@@ -172,7 +172,9 @@ var rationAssistOprObj = {
         me.ration = ration;
 
         sheetCommonObj.cleanData(me.sheet, me.setting, -1);
-        sheetCommonObj.unShieldAllCells(me.sheet);
+        if (!isReadOnly) {
+            sheetCommonObj.unShieldAllCells(me.sheet);
+        }
 
         if (ration == undefined || ration.rationAssList == undefined ||
             ration.rationAssList.length == 0){

+ 2 - 2
web/building_saas/complementary_ration_lib/js/ration_coe.js

@@ -235,7 +235,7 @@ var rationCoeOprObj = {
             }else{
                 $.ajax({
                     type:"POST",
-                    url:"api/getCoeItemsByNos",
+                    url:"/complementaryRation/api/getCoeItemsByNos",
                     data: {"data": JSON.stringify({"coeNos": temp})},
                     dataType:"json",
                     cache:false,
@@ -292,7 +292,7 @@ var rationCoeOprObj = {
                 var data = {"coeIDs": coeIDs};
                 $.ajax({
                     type:"POST",
-                    url:"api/getCoeItemsByIDs",
+                    url:"/complementaryRation/api/getCoeItemsByIDs",
                     data: {"data": JSON.stringify(data)},
                     dataType:"json",
                     cache:false,

+ 14 - 3
web/building_saas/complementary_ration_lib/js/ration_glj.js

@@ -412,7 +412,7 @@ var rationGLJOprObj = {
     },
     addGljItems: function (codes, repId, args) {
         let me = this;
-        CommonAjax.post('api/getGljItemsByCodes', { gljCodes: codes, rationRepId: repId }, function (rstData) {
+        CommonAjax.post('/complementaryRation/api/getGljItemsByCodes', { gljCodes: codes, rationRepId: repId }, function (rstData) {
             if (rstData.length > 0) {
                 sheetCommonObj.cleanData(me.sheet, me.setting, -1);
                 let rstArr = [], dummyR = { gljId: 0, consumeAmt: 0 }, newAddArr = [];
@@ -525,7 +525,12 @@ var rationGLJOprObj = {
         if (me.currentRationItem && me.cache["_GLJ_" + me.currentRationItem.ID]) {
             var cacheArr = me.cache["_GLJ_" + me.currentRationItem.ID];
             for (var i = 0; i < cacheArr.length; i++) {
-                rst.push({ gljId: cacheArr[i].gljId, consumeAmt: cacheArr[i].consumeAmt, type: cacheArr[i].type });
+                const newItem = { gljId: cacheArr[i].gljId, consumeAmt: cacheArr[i].consumeAmt, type: cacheArr[i].type };
+                if (cacheArr[i].userId && cacheArr[i].userId !== userID) {
+                    // 是分享人材机
+                    newItem.fromUser = cacheArr[i].userId;
+                }
+                rst.push(newItem);
             }
         }
         return rst;
@@ -542,6 +547,9 @@ var rationGLJOprObj = {
         rst.unit = repGlj.unit;
         rst.basePrice = repGlj.basePrice;
         rst.gljType = repGlj.gljType;
+        if (rItem.fromUser) {
+            rst.userId = rItem.fromUser;
+        }
         return rst;
     },
     getGljItems: function (rationItem, callback) {
@@ -555,9 +563,12 @@ var rationGLJOprObj = {
                 let idObj = Object.create(null);
                 idObj.type = rationGljList[i].type;
                 idObj.id = rationGljList[i].gljId;
+                if (rationGljList[i].fromUser) {
+                    idObj.fromUser = rationGljList[i].fromUser;
+                }
                 gljIds.push(idObj);
             }
-            CommonAjax.post('api/getGljItemsByIds', { ids: gljIds }, function (rstData) {
+            CommonAjax.post('/complementaryRation/api/getGljItemsByIds', { ids: gljIds }, function (rstData) {
                 sheetCommonObj.cleanSheet(me.sheet, me.setting, -1);
                 var cacheArr = [];
                 for (let i = 0; i < rstData.length; i++) {

+ 9 - 9
web/building_saas/complementary_ration_lib/js/repository_glj.js

@@ -81,7 +81,7 @@ repositoryGljObj = {
     },
     getGljDistType: function (callback) {
         let me = this;
-        CommonAjax.post('api/getGljDistType', {}, function (rstData) {
+        CommonAjax.post('/complementaryRation/api/getGljDistType', {}, function (rstData) {
             me.distTypeTree = me.getComboData(rstData);
             me.workBook.getSheet(0).getCell(-1, 5, GC.Spread.Sheets.SheetArea.viewport).value(me.distTypeTree.comboDatas[0].text);
             if(callback){
@@ -91,7 +91,7 @@ repositoryGljObj = {
     },
     getGljTree: function(gljLibId, callback) {
         var me = this;
-        CommonAjax.post('api/getGljTree', {gljLibId: gljLibId}, function (rstData) {
+        CommonAjax.post('/complementaryRation/api/getGljTree', {gljLibId: gljLibId}, function (rstData) {
             zTreeHelper.createTree(rstData, gljSetting, "repositoryTree", me);
             if (rstData && rstData.length > 0) {
                 me.gljCurTypeId = rstData[0].ID;
@@ -103,7 +103,7 @@ repositoryGljObj = {
     },
     getGljItems: function(gljLibId) {
         var me = this;
-        CommonAjax.post('api/getGljItems', {stdGljLibId: gljLibId}, function (rstData) {
+        CommonAjax.post('/complementaryRation/api/getGljItems', {stdGljLibId: gljLibId}, function (rstData) {
             me.gljList = rstData.stdGljs.concat(rstData.complementaryGljs);
             me.workBook.getSheet(0).setRowCount(rstData.length);
             me.sortGlj();
@@ -620,7 +620,7 @@ repositoryGljObj = {
     updateRationBasePrcRq: function (basePrcArr) {
         $.ajax({
             type: 'post',
-            url: 'api/updateRationBasePrc',
+            url: '/complementaryRation/api/updateRationBasePrc',
             data:{data: JSON.stringify({repId: pageOprObj.rationLibId, lastOpr: userAccount, basePrcArr: basePrcArr})},
             dataType: 'json',
             success: function (result) {
@@ -634,7 +634,7 @@ repositoryGljObj = {
         let me = repositoryGljObj;
         $.ajax({
             type: 'post',
-            url: 'api/getRationGljIds',
+            url: '/complementaryRation/api/getRationGljIds',
             data: {data: JSON.stringify({repId: repId})},
             dataType: 'json',
             success: function(result){
@@ -648,7 +648,7 @@ repositoryGljObj = {
         var me = repositoryGljObj;
         $.ajax({
             type:"POST",
-            url:"api/mixUpdateGljItems",
+            url:"/complementaryRation/api/mixUpdateGljItems",
             data:{"repositoryId": me.currentRepositoryId, "lastOpr": userAccount, "updateItems": JSON.stringify(updateArr), "addItems": JSON.stringify(addArr), "removeIds": JSON.stringify(removeIds)},
             dataType:"json",
             cache:false,
@@ -806,7 +806,7 @@ var gljTypeTreeOprObj = {
         }
         $.ajax({
             type:"POST",
-            url:"api/deleteGljNodes",
+            url:"/complementaryRation/api/deleteGljNodes",
             data:{"repId": pageOprObj.rationLibId, "lastOpr": userAccount, "nodes": JSON.stringify(nodeIds), "preNodeId": preNodeId, "preNodeNextId": treeNode.NextSiblingID},
             dataType:"json",
             cache:false,
@@ -845,7 +845,7 @@ var gljTypeTreeOprObj = {
             }
             $.ajax({
                 type:"POST",
-                url:"api/updateGljNodes",
+                url:"/complementaryRation/api/updateGljNodes",
                 data:{"repId": pageOprObj.rationLibId, "lastOpr": userAccount, "nodes": JSON.stringify(reqData)},
                 dataType:"json",
                 cache:false,
@@ -876,7 +876,7 @@ var gljTypeTreeOprObj = {
     addNewNode : function(rawNode, lastNodeId, callback){
         $.ajax({
             type:"POST",
-            url:"api/createNewGljTypeNode",
+            url:"/complementaryRation/api/createNewGljTypeNode",
             data:{"lastOpr": userAccount, "repositoryId": repositoryGljObj.currentRepositoryId,"lastNodeId": lastNodeId, "rawNodeData": JSON.stringify(rawNode)},
             dataType:"json",
             cache:false,

+ 5 - 2
web/building_saas/complementary_ration_lib/js/section_tree.js

@@ -22,7 +22,7 @@ let pageOprObj = {
         annotationOprObj.bindAllEvents($('#fzTxtareaAll'));
     },
     getRationLibInfo: function (rationLibId, callback) {
-        CommonAjax.post('api/getRationLib', {rationRepId: rationLibId}, callback);
+        CommonAjax.post('/complementaryRation/api/getRationLib', {rationRepId: rationLibId}, callback);
     },
 };
 
@@ -242,6 +242,9 @@ let sectionTreeObj = {
     },
     
     refreshBtn: function (selected) {
+        if (isReadOnly) {
+            return;
+        }
         let me = this;
         me.insertBtn.removeClass('disabled');
         me.removeBtn.removeClass('disabled');
@@ -529,7 +532,7 @@ let sectionTreeObj = {
         return updateObj;
     },
     sectionTreeAjax: function (postData, scFunc, errFunc) {
-        CommonAjax.post('api/updateRationSection', {updateData: postData}, scFunc, errFunc);
+        CommonAjax.post('/complementaryRation/api/updateRationSection', {updateData: postData}, scFunc, errFunc);
     },
     initTools: function (node) {
         if(this.isDef(node)){

+ 10 - 1
web/building_saas/css/custom.css

@@ -603,4 +603,13 @@ input.text-right {
 
 .top-msg{
   top:35px !important;
-  }
+  }
+
+.add-select-bills-btn {
+  margin: 5px 0;
+}
+
+.limit-price-input {
+  display: inline-block;
+  width: 80px;
+}

+ 12 - 3
web/building_saas/fee_rates/fee_rate.html

@@ -11,9 +11,18 @@
     <div class="toolsbar_feeRate px-1">
         <div class="row" style="margin-left: 0px">
             <div class="col-lg-8 p-0">
-                <div class="form-inline py-1">
-                    <label class="mx-2" >基于&nbsp;&nbsp;<span id="feeRateLibName">重庆渝建发[2016]35号</span></label>
-                    <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#set-lv" id="setNewFeeRate"><i class="fa fa-cog"></i> 重选标准</a>
+                <div class="form-inline py-1 row">
+                    <div class="col-12 form-inline">   
+                        <label >工程所在地:</label> &nbsp;&nbsp;
+                        <select class="form-control form-control-sm" id="location"></select> 
+                        &nbsp;&nbsp;&nbsp;&nbsp;
+                        <label >费率标准:</label> &nbsp;&nbsp;
+                        <select class="form-control form-control-sm" id="feeRateStandard" style="width: 495px;"><option value=""></option></select>   
+                    </div>
+                
+
+                       <!-- <label class="mx-2" >基于&nbsp;&nbsp;<span id="feeRateLibName">重庆渝建发[2016]35号</span></label>                 
+                 <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#set-lv" id="setNewFeeRate"><i class="fa fa-cog"></i> 重选标准</a> -->
                 </div>
             </div>
             <!--<div class="col-lg-4 p-0">

+ 4 - 0
web/building_saas/glj/html/project_glj.html

@@ -252,6 +252,10 @@
             </div>
             <div class="modal-body">
                 <div class="form-group">
+                    <label id = "machineConstCoeLabel">机械不变费用系数</label>
+                    <input class="form-control" id="machineConstCoe" value="">
+                </div>
+                <div class="form-group">
                     <label id = "assistProductionLabel">辅助生产间接费费率(%)</label>
                     <input class="form-control" id="assistProductionFeeRate" value="">
                 </div>

+ 31 - 13
web/building_saas/main/html/main.html

@@ -39,12 +39,13 @@
         let lockBills = '<%- projectData.property.lockBills %>';
         let userAccount = '<%- userAccount %>';
         let userID = '<%- userID %>';
+        let defaultLocation = '<%- defaultLocation %>';
         const USER_NAME = '<%- userName %>';
         let projectReadOnly = JSON.parse('<%- projectReadOnly %>');
         let projectCooperate = JSON.parse('<%- projectCooperate %>');
         let projectOptins =  JSON.parse('<%- options %>');
-        // const G_SHOW_BLOCK_LIB = true;
-        const G_SHOW_BLOCK_LIB = false;
+        const G_SHOW_BLOCK_LIB = true;
+        // const G_SHOW_BLOCK_LIB = false;
         const markReadProjectIDs = JSON.parse('<%- markReadProjectIDs %>');
         const VERSION = '<%- version %>';
         const CUR_BOQ_TYPE = '<%- boqType %>';
@@ -112,7 +113,7 @@
                               </div>
                               <!--<a href="javascript:void(0);" id="ZLFB_btn" class="dropdown-item" data-placement="bottom"><i class="fa fa-retweet" aria-hidden="true"></i> 整理分部</a>
                                 <a id="switchTznr" href="javascript:void(0);"  class="dropdown-item"><i class="fa fa-eye" aria-hidden="true"></i> 显示特征</a>-->
-                            <% if((compilationName === '公路造价(2018)' || compilationName === '安徽养护(2018)') && boqType) { %>
+                            <% if((compilationName === '公路造价(2018)' || compilationName === '安徽养护(2018)' || compilationName === '广东公路造价(2018)') && boqType) { %>
                                 <a class="dropdown-item" id="open-export-modal" href="javascript:void(0);"><i class="fa fa-code-fork"></i> 数据接口</a>
                                 <!-- <a class="dropdown-item" id="open-export-modal" href="javascript:void(0);" data-toggle="modal" data-target="#interface-export-modal"><i class="fa fa-code-fork"></i> 数据接口</a> -->
                             <% }%>
@@ -171,7 +172,7 @@
                                       //2018-11-23  zhang 模板库移动到更多下拉框
                                       if (G_SHOW_BLOCK_LIB) {
                                           $("#div_more_dropdown_right").append('<a class="dropdown-item right-nav-link" href="javascript:void(0)" ' +
-                                              'id="blockLibTab" relaPanel="#kmbk">块模板库</a>');
+                                              'id="blockLibTab" relaPanel="#kmbk">组价模板</a>');
                                       }
                                   </script>
                               </div>
@@ -490,6 +491,7 @@
                                       </div>
                                   </div>
                                   <div class="top-content" style="overflow: hidden">
+                                    <a id="add-select-bills" href="javascript:;" class="btn btn-xs btn-primary add-select-bills-btn">添加选用</a>
                                       <div class="main-data-side-zb" id="billsGuidance_bills">
                                       </div>
                                   </div>
@@ -602,7 +604,7 @@
                                           <select class="form-control form-control-sm col-6" id="select_block_lib_names">
                                               <option>我的模板库</option>
                                           </select>
-                                          <div class="col-6">
+                                          <div class="col-6 pl-1 pr-0">
                                               <div class="d-inline">
                                                   <button type="button" class="btn btn-sm btn-secondary" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" id="btn_block_newFolder">
                                                       新建分类
@@ -639,16 +641,21 @@
                                                       </form>
                                                   </div>
                                               </div>
+                                              <div class="d-inline">
+                                                <button type="button" class="btn btn-sm btn-secondary"
+                                                  id="btn_block_share" data-toggle="tooltip" data-placement="bottom" data-original-title="">
+                                                  分享
+                                              </div>
                                           </div>
                                       </div>
                                   </div>
                                   <div class="top-content" style="overflow: hidden" id="kmbkTopDiv">
                                       <div id="div_block_tree"></div>
                                   </div>
-                                  <div class="resize-y" id="kmbkResizeA"></div>
+                                  <!-- <div class="resize-y" id="kmbkResizeA"></div>
                                   <div class="bottom-content" id="kmbkMidDiv">
                                       <div id="div_block_bill"></div>
-                                  </div>
+                                  </div> -->
                                   <div class="resize-y" id="kmbkResizeB"></div>
                                   <div id="kmbkBottomDiv">
                                       <div id="div_block_ration"></div>
@@ -802,6 +809,17 @@
                                             </div>
 
                                         </fieldset>
+                                        <% if (!projectData.importedByInterface) { %>
+                                            <fieldset class="form-group">
+                                              <h5>清单限价</h5>
+                                              <div class="mt-1">
+                                                <span data-toggle="tooltip" data-placement="bottom" data-original-title="最高限价=清单综合单价*(1+X%)">最高限价 </span><input id="max-price-rate" data-limit="max" class="form-control form-control-sm limit-price-input" value="0" type="text"> %
+                                              </div>
+                                            <div class="mt-1">
+                                                <span data-toggle="tooltip" data-placement="bottom" data-original-title="最低限价=清单综合单价*(1-X%)">最低限价 </span><input id="min-price-rate" data-limit="min" class="form-control form-control-sm limit-price-input" value="0" type="text"> %
+                                            </div>
+                                            </fieldset>
+                                            <% } %>
                                     </div>
                                 </div>
                                 <!--清单工程精度-->
@@ -1107,7 +1125,7 @@
                         </div>
                 </div>
                 <div class="modal-footer" style="position: relative;">
-                    <a href="/complementaryGlj" target="_blank" class="btn btn-primary" style="position: absolute; left: 20px">新增人材机</a>
+                    <a href=<%- "/complementaryGlj/" + userID %> target="_blank" class="btn btn-primary" style="position: absolute; left: 20px">新增人材机</a>
                     <a href="javascript:void(0);" id="glj_selected_conf" class="btn btn-primary">确定</a>
                     <a href="javascript:void(0);" id="replace_next_btn" class="btn btn-primary">下一步</a>
                     <button type="button" id="componentsCacnel" class="btn btn-secondary" data-dismiss="modal">取消</button>
@@ -1860,11 +1878,11 @@
                         <div>
                             <div class="form-check form-check-inline">
                                 <input class="form-check-input" type="checkbox" name="inlineRadioOptions1" id="clone_option_code" value="option1" checked>
-                                <label class="form-check-label" for="clone_option_code">项目编码(前9位)</label>
+                                <label class="form-check-label" for="clone_option_code">编号</label>
                             </div>
                             <div class="form-check form-check-inline">
                                 <input class="form-check-input" type="checkbox" name="inlineRadioOptions2" id="clone_option_name" value="option2">
-                                <label class="form-check-label" for="clone_option_name">项目名称</label>
+                                <label class="form-check-label" for="clone_option_name">名称</label>
                             </div>
                             <div class="form-check form-check-inline">
                                 <input class="form-check-input" type="checkbox" name="inlineRadioOptions3" id="clone_option_unit" value="option3" checked>
@@ -1877,11 +1895,11 @@
                         <div>
                             <div class="form-check form-check-inline">
                                 <input class="form-check-input" type="radio" name="rationQuantity" id="clone_option_quantity" value="option1" checked>
-                                <label class="form-check-label" for="clone_option_quantity">根据含量计算定额工程量</label>
+                                <label class="form-check-label" for="clone_option_quantity">根据分解系数计算定额工程量</label>
                             </div>
                             <div class="form-check form-check-inline">
                                 <input class="form-check-input" type="radio" name="rationQuantity" id="clone_option_zeroQuantity" value="option2">
-                                <label class="form-check-label" for="clone_option_zeroQuantity">含量和定额工程量为零</label>
+                                <label class="form-check-label" for="clone_option_zeroQuantity">分解系数和定额工程量为零</label>
                             </div>
                         </div>
                     </div>
@@ -2029,6 +2047,7 @@
     <script src="/lib/pinyinjs/pinyin_dict_firstletter.js"></script>
     <script src="/lib/pinyinjs/pinyinUtil.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/main_consts.js"></script>
+    <script type="text/javascript" src="/web/building_saas/main/js/models/feeRateConsts.js"></script>
     <script type="text/javascript" src="/public/web/common_util.js"></script>
     <script type="text/javascript" src="/web/building_saas/glj/js/project_glj.js"></script>
     <script type="text/javascript" src="/web/building_saas/glj/js/composition.js"></script>
@@ -2058,7 +2077,6 @@
     <!-- JS. -->
     <!--<script src="/lib/popper/popper.min.js"></script>
     <script src="/lib/bootstrap/bootstrap.min.js"></script>-->
-    <script src="/web/building_saas/js/global.js"></script>
     <script src="/web/common/components/share/index.js"></script>
     <!--报表 zTree -->
 

+ 5 - 1
web/building_saas/main/js/controllers/block_controller.js

@@ -255,7 +255,7 @@ let BlockController = {
      * @param selected
      * @param position next/pre/sub
      */
-    confirmPaste:function (blockData,selected,position) {
+    confirmPaste:function (blockData,selected,position,callback) {
         let me = this;
         let project = projectObj.project;
         let Bills = project.Bills;
@@ -329,6 +329,10 @@ let BlockController = {
              //主材设备工料机插入主树
              project.ration_glj.addToMainTree(result.ration_gljs);
              //更新计算程序模板,并进行重新计算
+             if(callback){
+                 callback(bottomNodes);
+                 return;
+             }
              project.calcProgram.calcNodesAndSave(bottomNodes, function () {
                  installationFeeObj.calcInstallationFee();
              });

+ 7 - 0
web/building_saas/main/js/controllers/project_controller.js

@@ -92,6 +92,13 @@ ProjectController = {
     } else {
       projectObj.project.Bills.tree.insertByDatas(treeData);
       newNodes = projectObj.project.mainTree.insertByDatas(treeData);
+      const updateData = postData.filter(item => item.updateType === 'update');
+      updateData.forEach(item => {
+        const node = projectObj.project.Bills.tree.findNode(item.updateData.ID);
+        if (node) {
+          node.data.NextSiblingID = item.updateData.NextSiblingID;
+        }
+      });
     }
     for (const node of newNodes) {
       node.source = projectObj.project.Bills.tree.nodes[projectObj.project.Bills.tree.prefix + node.getID()];

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

@@ -30,6 +30,7 @@ $(function () {
     });
 
     $('#tab_report').on('shown.bs.tab', function(e){
+        projectObj.project.calcProgram.doTenderCalc();   // 进入报表前先自动调价计算一遍
         sessionStorage.setItem('mainTab', '#tab_report');
         autoFlashHeight();
     });

+ 89 - 23
web/building_saas/main/js/models/calc_program.js

@@ -1046,9 +1046,37 @@
      let arr = Object.keys(obj);
      return arr.length == 0;
    },
+       // 清单价格是否大于最高限价
+   unitFeeGTMaxPrice: function (node, feeField) {
+     if (!this.isBill(node)) {
+       return false;
+     }
+     const totalFee = this.getFee(node, feeField);
+     const maxPrice = node.data.maxPrice;
+     // 最高限价有值才对比
+     if (!commonUtil.isNumber(maxPrice)) {
+       return false;
+     }
+     return totalFee > +maxPrice;
+   },
+   // 清单价格是否小于最低限价
+   unitFeeLTMinPrice: function (node, feeField) {
+     if (!this.isBill(node)) {
+       return false;
+     }
+     const totalFee = this.getFee(node, feeField);
+     const minPrice = node.data.minPrice;
+     // 最低限价有值才对比
+     if (!commonUtil.isNumber(minPrice)) {
+       return false;
+     }
+     return totalFee < +minPrice;
+   },
+   // 概预算项目
    isBudgetProject() {
      return projectObj.project.property.valuationType == 'bill';
    },
+   // 招投标项目
    isBillProject() {
      return projectObj.project.property.valuationType == 'ration';
    },
@@ -1065,6 +1093,23 @@
       array.push({name:p.name,ID:p.ID});
     } 
     return array;
+  },
+  getCodeForBlock: function(node){
+    let code = node.data.code;
+    if (calcTools.isBillProject()){
+        let tempNode = node;
+        while ((tempNode.data.code.indexOf('-') == 0) && (tempNode.parent != undefined)) {
+            code = tempNode.parent.data.code + code;
+            tempNode = tempNode.parent;
+        }
+    };
+    return code;
+  },
+  getCodeFromBlock: function(block){
+    let code = '';
+    let i = block.data.nodeName.indexOf(' ');
+    if (i != -1) code = block.data.nodeName.slice(0, i);
+    return code;
   }
  };
 
@@ -1779,7 +1824,7 @@
 
    // 只计算treeNode自身。changedArr: 外部传来的一个数组,专门存储发生变动的节点。
    innerCalc(treeNode, changedArr, tenderType) {
-     if (treeNode.data.lockUnitPrice == true) return;
+     // if (treeNode.data.lockUnitPrice == true) return;
      if (treeNode.sourceType === ModuleNames.ration_glj) return; // 仅用作树节点显示的工料机不能参与计算。
 
      let me = this;
@@ -1851,31 +1896,52 @@
                buf = (btf / bq).toDecimal(decimalObj.process);
                btuf = (bttf / bq).toDecimal(decimalObj.process);
              }
+             else{      // TASK #3409 招投标:清单父项的单价=ROUND(金额/工程量,精度)。如果清单父项的工程量为空或0,则清单父项的单价为空。
+               if (nQ == 0)
+                 buf = 0
+               else
+                 buf = (btf / bq).toDecimal(decimalObj.process);
+
+               if (nTQ == 0)
+                 btuf = 0
+               else
+                 btuf = (bttf / bq).toDecimal(decimalObj.process);
+             }
            };
          };
        } else if ((commonCalcType == 1) || (commonCalcType == 3)) {
-         let sum_rtf = 0,
-           sum_rttf = 0;
-         for (let node of nodes) {
-           let ruf = 0,
-             rtuf = 0,
-             rtf = 0,
-             rttf = 0;
-           if (node.data.feesIndex && node.data.feesIndex[ft.type]) {
-             ruf = parseFloatPlus(node.data.feesIndex[ft.type].unitFee).toDecimal(decimalObj.bills.unitPrice);
-             rtuf = parseFloatPlus(node.data.feesIndex[ft.type].tenderUnitFee).toDecimal(decimalObj.bills.unitPrice);
-             rtf = parseFloatPlus(node.data.feesIndex[ft.type].totalFee).toDecimal(decimalObj.bills.totalPrice);
-             rttf = parseFloatPlus(node.data.feesIndex[ft.type].tenderTotalFee).toDecimal(decimalObj.bills.totalPrice);
-           };
-
-           sum_rtf = (sum_rtf + rtf).toDecimal(decimalObj.process);
-           sum_rttf = (sum_rttf + rttf).toDecimal(decimalObj.process);
-         };
-
-         buf = (sum_rtf / bq).toDecimal(decimalObj.process);
-         btuf = (sum_rttf / btq).toDecimal(decimalObj.process);
-         btf = sum_rtf;
-         bttf = sum_rttf;
+           if (treeNode.data.lockUnitPrice == true){       // 清单单价锁定
+               if (treeNode.data.feesIndex && treeNode.data.feesIndex[ft.type]) {
+                   buf = parseFloatPlus(treeNode.data.feesIndex[ft.type].unitFee).toDecimal(decimalObj.bills.unitPrice);
+                   btuf = parseFloatPlus(treeNode.data.feesIndex[ft.type].tenderUnitFee).toDecimal(decimalObj.bills.unitPrice);
+                   btf = (bq * buf).toDecimal(decimalObj.bills.totalPrice);
+                   bttf = (btq * btuf).toDecimal(decimalObj.bills.totalPrice);
+               }
+           }
+           else{
+               let sum_rtf = 0,
+                   sum_rttf = 0;
+               for (let node of nodes) {
+                   let ruf = 0,
+                       rtuf = 0,
+                       rtf = 0,
+                       rttf = 0;
+                   if (node.data.feesIndex && node.data.feesIndex[ft.type]) {
+                       ruf = parseFloatPlus(node.data.feesIndex[ft.type].unitFee).toDecimal(decimalObj.bills.unitPrice);
+                       rtuf = parseFloatPlus(node.data.feesIndex[ft.type].tenderUnitFee).toDecimal(decimalObj.bills.unitPrice);
+                       rtf = parseFloatPlus(node.data.feesIndex[ft.type].totalFee).toDecimal(decimalObj.bills.totalPrice);
+                       rttf = parseFloatPlus(node.data.feesIndex[ft.type].tenderTotalFee).toDecimal(decimalObj.bills.totalPrice);
+                   };
+
+                   sum_rtf = (sum_rtf + rtf).toDecimal(decimalObj.process);
+                   sum_rttf = (sum_rttf + rttf).toDecimal(decimalObj.process);
+               };
+
+               buf = (sum_rtf / bq).toDecimal(decimalObj.process);
+               btuf = (sum_rttf / btq).toDecimal(decimalObj.process);
+               btf = sum_rtf;
+               bttf = sum_rttf;
+           }
 
          if (calcTools.isBillProject() && (ft.type == 'common' || ft.type == 'rationCommon')) { // 招投标项目, 还要反算
            buf = buf.toDecimal(decimalObj.bills.unitPrice);

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 97 - 0
web/building_saas/main/js/models/feeRateConsts.js


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

@@ -325,4 +325,9 @@ const materialComboMap = [
     {text:materialType[materialTypeMap.MC],value:materialTypeMap.MC},
     {text:materialType[materialTypeMap.SN],value:materialTypeMap.SN},
     {text:materialType[materialTypeMap.SZ],value:materialTypeMap.SZ}
-];
+];
+
+const locationList = ['北京','天津','河北','山西','内蒙古','辽宁',
+'吉林','黑龙江','上海','江苏','浙江','安徽','福建','江西','山东','河南',
+'湖北','湖南','四川','贵州','云南','西藏','陕西','甘肃','青海','宁夏','新疆',
+'广东','广西','海南','重庆']

+ 29 - 13
web/building_saas/main/js/models/project.js

@@ -459,7 +459,7 @@ var PROJECT = {
               type:node.sourceType,
               data:{ID:node.data.ID}
           };
-          setData(data.data,newval,fieldName);
+          setData(data.data,newval,fieldName, node);
           datas.push(data);
           setChildren(node,newval,datas);//同步设置所有子项
           if(needSetParent) setParent(node,newval,datas);//设置父节点
@@ -484,12 +484,14 @@ var PROJECT = {
 
           function setChildren(pnode,newValue,datas) {//同步设置所有子项
               if(pnode.children.length > 0 && pnode.children[0].sourceType == ModuleNames.bills){//设置子项不包括定额
-                  for(let c of pnode.children){
+                  for(let c of pnode.children){  
                       let data =  {
                           type:c.sourceType,
                           data:{ID:c.data.ID}
                       };
-                      setData(data.data,newval,fieldName);
+                      //有基数计算的子项值清空
+                      let val = fieldName == "lockUnitPrice" && c.data.calcBase && c.data.calcBase != ""?null:newval;
+                      setData(data.data,val,fieldName, c);
                       datas.push(data);
                       setChildren(c,newValue,datas)
                   }
@@ -497,7 +499,7 @@ var PROJECT = {
           }
           function setParent(cnode,newValue,datas) {
               let diferrent = false;
-              if(cnode.parent && !projectObj.project.Bills.isMeasureNode(cnode.parent)){//排除措施项目节点
+              if(cnode.parent){//排除措施项目节点
                   for(b of cnode.parent.children){
                       if(b == cnode) continue
                       if(b.data[fieldName]!== newValue){//有兄弟节点的值和本节点不一样,则父节点设置为null
@@ -510,14 +512,26 @@ var PROJECT = {
                       type:cnode.parent.sourceType,
                       data:{ID:cnode.parent.data.ID}
                   };
-                  setData(data.data,pvalue,fieldName);
+                  setData(data.data,pvalue,fieldName, cnode.parent);
                   datas.push(data);
                   setParent(cnode.parent,pvalue,datas);
               }
           }
-          function setData(data,avalue,fieldName) {
+          function setData(data,avalue,fieldName, node) {
               data[fieldName] = avalue;
-              if(fieldName == "outPutMaxPrice") data.maxPrice = null;
+               // 二次修改项目属性上下限设置,前端的最高、最低限价不重算,要去掉输出限价列的√,再重新勾选才计算。因此输出最高限价、输出限价时,需要给节点的maxPrice、minPrice设置一个算好的值
+               if (['outPutLimitPrice', 'outPutMaxPrice'].includes(fieldName)) {
+                if (avalue) {
+                    const unitFee = node.data && node.data.feesIndex && node.data.feesIndex.common && node.data.feesIndex.common.unitFee || 0;
+                    const maxPriceRate = projectObj.project.property.maxPriceRate || 0;
+                    data.maxPrice = scMathUtil.roundForObj(unitFee * (1 + maxPriceRate * 0.01), decimalObj.bills.unitPrice) || null;
+                    const minPriceRate = projectObj.project.property.minPriceRate || 0;
+                    data.minPrice = scMathUtil.roundForObj(unitFee * (1 - minPriceRate * 0.01), decimalObj.bills.unitPrice) || null;
+                } else {
+                    data.maxPrice = null;
+                    data.minPrice = null;
+                }
+            }
           }
       };
         project.prototype.syncUpdateNodesAndRefresh =async function (datas) {
@@ -530,7 +544,7 @@ var PROJECT = {
               });
           });
       };
-        project.prototype.updateNodesCache =function (datas) {
+        project.prototype.updateNodesCache =function (datas, reCalc=true) {
           let refreshNode = [];
           let reclacQuantity = false;
           let deleteNode=[],addNodeDatas=[];
@@ -559,7 +573,7 @@ var PROJECT = {
                       }
                   }
               }else if(d.type == ModuleNames.project){
-                  temObj = this;
+                  temObj = d.isInfo?this.projectInfo:this;
               }else if (d.type == ModuleNames.ration_glj && d.action == "add"){
                   this[d.type].datas.push(d.data);
                   if(d.projectGLJ) this.projectGLJ.loadNewProjectGLJToCache(d.projectGLJ);
@@ -571,6 +585,7 @@ var PROJECT = {
                       if(key == 'ID' || key == 'id'){
                           continue;
                       }
+    
                       this.setValue(temObj,key,d.data[key])
                   }
               }
@@ -583,7 +598,7 @@ var PROJECT = {
           });
 
 
-          if(reclacQuantity) this.projectGLJ.calcQuantity();
+          if(reCalc && reclacQuantity) this.projectGLJ.calcQuantity();
           return refreshNode;
 
 
@@ -611,12 +626,13 @@ var PROJECT = {
               let Bill = projectObj.project.Bills;
               let newAddNode = [];
               for(let nr of newDatas){
-                  let nextID = -1;
+                  let nextID = nr.data && nr.data.NextSiblingID ||  -1;
+                  let parentID = nr.parentID || (nr.data && nr.data.ParentID || -1);
                   let preNode = projectObj.project.mainTree.getNodeByID(nr.preSiblingID);
                   if(preNode) nextID = preNode.getNextSiblingID();
-                  let newNode = projectObj.project.mainTree.insert(nr.parentID, nextID, nr.data.ID);
+                  let newNode = projectObj.project.mainTree.insert(parentID, nextID, nr.data.ID);
                   if(nr.type == ModuleNames.bills){
-                      let newSource = Bill.tree.insertByData(nr.data, nr.ParentID, nextID, true);
+                      let newSource = Bill.tree.insertByData(nr.data, parentID, nextID, true);
                       newNode.source = newSource;
                   }else {
                       newNode.source = nr.data;

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

@@ -1,3 +1,4 @@
+
 /**
  * 工料机汇总相关数据
  *
@@ -831,11 +832,11 @@ ProjectGLJ.prototype.addMaterialRation = async function (code,type,parentID,conn
         await this.updateMaterialRation(datas);
 };
 
-ProjectGLJ.prototype.changeAssistProductionFeeRate = async function (newFeeRate) {
+ProjectGLJ.prototype.changeAssistProductionFeeRate = async function (updateData) {//newFeeRate  机械不变费用系数 和 辅助生产间接费费率(%) 计算放一起
     $.bootstrapLoading.start();
     try {
-        await ajaxPost("/glj/changeAssistProductionFeeRate",{unitFileID:projectObj.project.property.unitPriceFile.id,assistProductionFeeRate:newFeeRate});
-        this.datas.constData.assistProductionFeeRate = newFeeRate;
+        await ajaxPost("/glj/changeAssistProductionFeeRate",{unitFileID:projectObj.project.property.unitPriceFile.id,updateData:updateData});
+        gljUtil.setProperty(this.datas.constData,updateData) //this.datas.constData.assistProductionFeeRate = newFeeRate;
         //todo  调用材料计算方法,所有材料重算一遍
         let [unitPrices,sumMap] = this.calcAllMaterial([],true);
         sumMap["unitPrice"] = unitPrices;

+ 7 - 5
web/building_saas/main/js/models/ration.js

@@ -119,7 +119,7 @@ var Ration = {
             if(rType == rationType.ration){//空定额暂时不输入取费专业
                // newData['programID'] = projectObj.project.projectInfo.property.engineering;
             }else if(rType == rationType.volumePrice){//量价取费专业默认为费率为0
-                newData['programID'] = projectObj.project.calcProgram.compiledTemplateMaps["费率为0"];
+                newData['programID'] = projectObj.project.calcProgram.compiledTemplateMaps["量价(计利润税金)"];
             }else {
                 if(pEngineer) newData['programID'] = pEngineer;
             }
@@ -532,14 +532,16 @@ var Ration = {
                 }
             }
         };
-        ration.prototype.insertVolumePrice = function(type){
+        ration.prototype.insertVolumePrice = function(type,ext){
+            let isEmpty = ext?false:true;
             this.addNewRation(null,rationType.volumePrice,function (newNode) {//插入人工不需要自动定位到编号列
                 projectObj.selectColAndFocus(newNode,null);
-            },true,type);
+                projectObj.refreshBaseActn(projectObj.project.mainTree);
+            },isEmpty,type,true,ext);
         };
 
 
-        ration.prototype.addNewRation = function (itemQuery,rationType,callback=null,isEmpty=false,priceType,needCalcAndSave=true) {//priceType 是量价类型
+        ration.prototype.addNewRation = function (itemQuery,rationType,callback=null,isEmpty=false,priceType,needCalcAndSave=true,ext) {//priceType 是量价类型
             let me = this;
             let project = projectObj.project, sheetController = projectObj.mainController;
             let engineering = projectObj.project.projectInfo.property.engineering;
@@ -586,6 +588,7 @@ var Ration = {
                     let billsNode = project.mainTree.getNodeByID(billItemID);
                     needInstall = project.Bills.isFBFX(billsNode);//在分部分项插入的定额才需要定额安装增加费
                 }
+                if(ext) gljUtil.setProperty(newData,ext);
               $.bootstrapLoading.start();
                 let tdata = {
                   projectID: me.project.ID(),
@@ -795,7 +798,6 @@ var Ration = {
             node.updateData.quantityEXP="QDL*"+contain;
             node.updateData.quantity=scMathUtil.roundForObj(billQuantity*contain,getDecimal("quantity",node));
             if(!gljUtil.isKGtoT(billNode.data.unit,node.data.unit)){
-              console.log('hehe')
               let times = parseInt(node.data.unit);
               if (!isNaN(times)) {
                   node.updateData.quantityEXP+='*'+times;

+ 6 - 0
web/building_saas/main/js/models/ration_glj.js

@@ -718,6 +718,9 @@ let ration_glj = {
                     return i_key == g;
                 });
                 let ration_glj = me.getAddDataByStd(glj,ration.ID,ration.billsItemID,ration.projectID);
+                if (glj.userId) {
+                    ration_glj.fromUser = glj.userId;
+                }
                 gljList.push(ration_glj);
             });
             $.bootstrapLoading.start();
@@ -822,6 +825,9 @@ let ration_glj = {
             oldData.handlingLossRate = glj.handlingLossRate;
             if (glj.hasOwnProperty("compilationId")) {
                 oldData.from = "cpt";
+                if (glj.userId) {
+                    oldData.fromUser = glj.userId;
+                }
                 if (glj.code.indexOf('-') != -1) {//这条工料机是用户通过修改包称、规格、型号等保存到补充工料机库的
                     oldData.original_code = glj.code.split('-')[0];//取-前的编号作为原始编号
                 }

+ 71 - 39
web/building_saas/main/js/views/block_lib.js

@@ -44,11 +44,11 @@ var blockLibObj = {
             {headerName: "项目编码", headerWidth: 90, dataCode: "code", dataType: "String", hAlign: "center"},
             {headerName: "项目名称", headerWidth: 100, dataCode: "name", dataType: "String"},
             {headerName: "单位", headerWidth: 40, dataCode: "unit", dataType: "String", hAlign: "center"},
-            {headerName: "综合单价", headerWidth: 70, dataCode: "unitFee", dataType: "Number"},
-            {headerName: "项目特征", headerWidth: 160, dataCode: "itemCharacterText", dataType: "String"}
+            {headerName: "综合单价", headerWidth: 70, dataCode: "unitFee", dataType: "Number"}//,
+        //    {headerName: "项目特征", headerWidth: 160, dataCode: "itemCharacterText", dataType: "String"}
         ],
         view: {
-            lockColumns: [0, 1, 2, 3, 4]
+            lockColumns: [0, 1, 2, 3]
         }
     },
     rationSpread: null,
@@ -58,22 +58,23 @@ var blockLibObj = {
             {headerName: "编码", headerWidth: 45, dataCode: "code", dataType: "String", hAlign: "center"},
             {headerName: "名称", headerWidth: 100, dataCode: "name", dataType: "String"},
             {headerName: "单位", headerWidth: 40, dataCode: "unit", dataType: "String", hAlign: "center"},
-            {headerName: "含量", headerWidth: 40, dataCode: "contain", dataType: "Number"},
-            {headerName: "取费专业", headerWidth: 70, dataCode: "programName", dataType: "String", hAlign: "center"},
+            /* {headerName: "分解系数", headerWidth: 70, dataCode: "contain", dataType: "Number"},
+            {headerName: "取费类别", headerWidth: 70, dataCode: "programName", dataType: "String", hAlign: "center"}, */
             {headerName: "综合单价", headerWidth: 70, dataCode: "unitFee", dataType: "Number"},
-            {headerName: "子目换算状态", headerWidth: 90, dataCode: "adjustState", dataType: "String"}
+            //{headerName: "子目换算状态", headerWidth: 90, dataCode: "adjustState", dataType: "String"}
         ],
         view: {
             lockColumns: [0, 1, 2, 3, 4, 5, 6]
         }
     },
     cloneType: null,
+    initialShareTip: '',
 
     buildSheet: async function () {
         $.bootstrapLoading.start();
         let me = this;
         let namesAndLib = await ajaxPost('/blockLib/getLibNamesAndFirstLib',
-            {userID: userID, userName: $("#link_userName").text(), compilationID: projectObj.project.projectInfo.compilation});
+            {userID: userID, compilationID: projectObj.project.projectInfo.compilation});
         function getLibNamesHtml(libsArr) {
             let result = '';
             for (let lib of libsArr) {
@@ -83,6 +84,10 @@ var blockLibObj = {
         };
         let html = getLibNamesHtml(namesAndLib.libNames);
         $("#select_block_lib_names").html(html);
+        this.initialShareTip = namesAndLib.shareList && namesAndLib.shareList.length
+            ? namesAndLib.shareList.reduce((acc, user) => acc += ` ${user.real_name}`, '已分享给')
+            : '';
+        $('#btn_block_share').attr('data-original-title', this.initialShareTip);
         await me.loadLib(namesAndLib.firstLib);
         $.bootstrapLoading.end();
     },
@@ -121,10 +126,10 @@ var blockLibObj = {
         };
         showBlockTree(me.mainDatas);
 
-        me.billSpread = sheetCommonObj.buildSheet($('#div_block_bill')[0], me.billSetting, 1);
+        /* me.billSpread = sheetCommonObj.buildSheet($('#div_block_bill')[0], me.billSetting, 1);
         me.billSheet = me.billSpread.getSheet(0);
         sheetCommonObj.spreadDefaultStyle(me.billSpread);
-        me.billSheet.setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader);
+        me.billSheet.setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader); */
 
         me.rationSpread = sheetCommonObj.buildSheet($('#div_block_ration')[0], me.rationSetting, 1);
         me.rationSheet = me.rationSpread.getSheet(0);
@@ -142,13 +147,13 @@ var blockLibObj = {
         if (node.data.type == 2){
             let bill = node.data;
             let rations = bill.children;
-            sheetCommonObj.showData(me.billSheet, me.billSetting, [bill]);
+            //sheetCommonObj.showData(me.billSheet, me.billSetting, [bill]);
             let rCount = (rations.length > 0) ? rations.length : 1;
             me.rationSheet.setRowCount(rCount, GC.Spread.Sheets.SheetArea.viewport);
             sheetCommonObj.showData(me.rationSheet, me.rationSetting, rations);
         }
         else{
-            sheetCommonObj.cleanSheet(me.billSheet, me.billSetting, 1);
+            //sheetCommonObj.cleanSheet(me.billSheet, me.billSetting, 1);
             sheetCommonObj.cleanSheet(me.rationSheet, me.rationSetting, 1);
         }
     },
@@ -353,7 +358,7 @@ var blockLibObj = {
         };
         return new TreeCell();
     },
-    newNode: async function (nodeType, nodeName, categoryID, source){     // 1 分类(只用前两个参数)  2 块文件
+    newNode: async function (nodeType, nodeName, categoryID, source){     // nodeType: 1 分类(只用前两个参数)  2 块文件
         if (nodeName == '') return;
         let tree = blockLibObj.mainTree;
         let ID = uuid.v1();
@@ -463,12 +468,12 @@ var blockLibObj = {
     curIsCategory: function () {
         return this.mainTree.selected.data.type == 1;
     },
-    getSameNameNode: function(name){
+    getSameNameNode: function(name, categoryID){
         let rst = null;
         let nodes = blockLibObj.mainTree.items;
         for (let i = 0; i < nodes.length; i++) {
             let node = nodes[i];
-            if (node.data.nodeName == name){
+            if (node.data.nodeName == name && node.data.ParentID == categoryID){
                 rst = node;
                 break;
             }
@@ -541,7 +546,7 @@ var blockLibObj = {
                     name: '删除',
                     icon: "delete",
                     disabled: function () {
-
+                        return $("#select_block_lib_names option:selected").prop("index") !== 0;
                     },
                     visible: function(key, opt){
                         return true;
@@ -588,30 +593,39 @@ var blockLibObj = {
         $("#div_cloneOptions").modal({show: true});
     },
     oneToOneClone: function (projectNode, block, options) {
-        let canClone = true;
-        if (options.checkCode)
-            canClone = canClone && (projectNode.data.code.substr(0, 9) == block.data.code.substr(0, 9));
-        if (options.checkName)
-            canClone = canClone && (projectNode.data.name == block.data.name);
-        if (options.checkUnit)
-            canClone = canClone && (projectNode.data.unit == block.data.unit);
-        if (!canClone) return;
-        
-        if (options.overwriteRations)
-            projectObj.project.Bills.deleteChildren(projectNode);
-        /*  这里封装成伟城的块文件格式,可直接使用伟城的“粘贴块”接口。
-            但这里结构要作出调整:忽略叶子清单层,直接从定额开始(跟粘贴块有区别),始终强制在叶子清单下插入定额。
-            该操作前提:当前块文件的全部数据已从后台取到前台。  */
-        let vBlock_WC = {
-            compilationID: block.data.compilationID,
-            copyTime: block.data.copyTime,
-            firstNodeType: 1,           // 强制改成1 (因为是从清单下的定额开始。清单自身的还是保留,暂不使用使用)。
-            isFBFX: block.data.isFBFX,
-            zeroQuantity: options.zeroQuantity,
-            datas: block.data.children       // rations
-        };
-        vBlock_WC = JSON.parse(JSON.stringify(vBlock_WC));
-        BlockController.confirmPaste(vBlock_WC, projectNode, 'sub');
+        return new Promise(function (resolve, reject) {
+            let canClone = true;
+            if (options.checkCode){
+                let nodeCode = calcTools.getCodeForBlock(projectNode);
+                let blockCode = calcTools.getCodeFromBlock(block);
+                canClone = canClone && (nodeCode == blockCode);
+            }
+                
+            if (options.checkName)
+                canClone = canClone && (projectNode.data.name == block.data.name);
+            if (options.checkUnit)
+                canClone = canClone && (projectNode.data.unit == block.data.unit);
+            if (!canClone) return resolve([]);
+            
+            if (options.overwriteRations)
+                projectObj.project.Bills.deleteChildren(projectNode);
+            /*  这里封装成伟城的块文件格式,可直接使用伟城的“粘贴块”接口。
+                但这里结构要作出调整:忽略叶子清单层,直接从定额开始(跟粘贴块有区别),始终强制在叶子清单下插入定额。
+                该操作前提:当前块文件的全部数据已从后台取到前台。  */
+            let vBlock_WC = {
+                compilationID: block.data.compilationID,
+                copyTime: block.data.copyTime,
+                firstNodeType: 1,           // 强制改成1 (因为是从清单下的定额开始。清单自身的还是保留,暂不使用使用)。
+                isFBFX: block.data.isFBFX,
+                zeroQuantity: options.zeroQuantity,
+                datas: block.data.children       // rations
+            };
+            vBlock_WC = JSON.parse(JSON.stringify(vBlock_WC));
+            BlockController.confirmPaste(vBlock_WC, projectNode, 'sub',function(buttomNodes){
+                resolve(buttomNodes)
+            });
+        })
+       
     },
     checkShow: async function () {   // 这里需要处理异步:模板库装载完再弹出位置选择窗。
         if (!$("#kmbk").is(":visible")){  // 如果还没显示
@@ -655,13 +669,31 @@ $(document).ready(function(){    // 这里不需要处理异步:因为不需
     });
 
     $("#select_block_lib_names").change(function() {
+        const index = $("#select_block_lib_names option:selected").prop("index");
+        if (index !== 0) {
+            // 只读
+            $('#btn_block_newFolder').hide();
+            $('#btn_block_reName').hide();
+            $('#btn_block_share').prop('disabled', true);
+        } else {
+            $('#btn_block_newFolder').show();
+            $('#btn_block_reName').show();
+            $('#btn_block_share').prop('disabled', false);
+        }
         async function getLib(){
             let libID = $("#select_block_lib_names").val();
             let lib = await ajaxPost('/blockLib/getLib', {libID: libID});
             blockLibObj.loadLib(lib);
+            if (userID === lib.userID) {
+                $('#btn_block_share').attr('data-original-title', blockLibObj.initialShareTip);
+            }
         };
         $.bootstrapLoading.start();
         getLib();
         $.bootstrapLoading.end();
     });
+
+    $('#btn_block_share').click(function () {
+        SHARE_TO.initModal(SHARE_TO.Mode.BLOCK_LIB);
+    })
 });

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

@@ -99,8 +99,8 @@ let calcProgramManage = {
             if(me.detailSetting.view.lockColumns){
                 me.detailSetting.view.lockColumns = null;
             }
-            disableSpread(me.mainSpread);
-            disableSpread(me.detailSpread);
+            sheetCommonObj.disableSpread(me.mainSpread);
+            sheetCommonObj.disableSpread(me.detailSpread);
         }
     },
     getStdCalcProgramFiles: function(){

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

@@ -314,8 +314,8 @@ let configMaterialObj = {
     this.initEvaluateRelateSheet();
     //打开别人分享的项目,只读
     if (projectReadOnly) {
-      disableSpread(this.configSpread);
-      disableSpread(this.relatedSpread);
+      sheetCommonObj.disableSpread(this.configSpread);
+      sheetCommonObj.disableSpread(this.relatedSpread);
     } else {
       this.initRightClick();
     }

+ 27 - 8
web/building_saas/main/js/views/divide_view.js

@@ -79,9 +79,9 @@ let divideObj = {
     if(!projectReadOnly){
       this.initDivideRightClick();
     }else {
-      disableSpread(this.divideSpread);
-      disableSpread(this.billsSpread);
-      disableSpread(this.divideSubSpread);
+      sheetCommonObj.disableSpread(this.divideSpread);
+      sheetCommonObj.disableSpread(this.billsSpread);
+      sheetCommonObj.disableSpread(this.divideSubSpread);
     }
   },
   initExecSpread:function(){
@@ -252,30 +252,49 @@ let divideObj = {
     this.execBillsSheet.setRowCount(this.execBillsDatas.length);
   },
 
-  getExeBillCode:function(ID){
+  getExeBillCode:function(ID){//从后面往前匹配好像简单一点,可能想得复杂了
     let bNode = projectObj.project.mainTree.findNode(ID);
     if(!bNode) return "";
     let nodes= [];
     getNodes(bNode);
     let newCode = "";
+    let index = 0;
     for(let n of nodes){
       if(n.data.code && n.data.code !=""){
         if(newCode == ""){
           newCode = n.data.code;
         }else{
           let exp = new RegExp("^"+newCode);
-          if(exp.test(n.data.code)){
+          if(exp.test(n.data.code)){//如果后一个直接包含前面所有,则直接使用全字段
             newCode = n.data.code
           }else{
-            let mid = "-"
-            if(newCode.substr(-1,1) == "-" ||n.data.code.substr(0,1)=="-")mid="";
-            newCode = newCode+mid+n.data.code
+            let mid = "-";
+            let tcode = n.data.code;
+            if(nodes[index-1]){//拿前一结点单独来匹配一下
+              let  preCode = removeSymble(nodes[index-1].data.code);
+              let code =  removeSymble(n.data.code);     
+              let preExp = new RegExp("^"+preCode);
+              if(preExp.test(code)){//如果后一个只包含前面一个节点,则忽略前一节点字段
+                tcode  = code.replace(preCode,"");
+              }
+            }  
+            if(newCode.substr(-1,1) == "-" ||tcode.substr(0,1)=="-")mid="";
+            newCode = newCode+mid+tcode    
           }
         }  
       }
+      index ++;
     }
     return newCode;
 
+    //去除前后的-
+    function removeSymble(str){
+      let pr = str.match(/^-(.+)/);
+      if(pr)str = pr[1];
+      let fr = str.match(/(.+)-$/);
+      if(fr)str = fr[1];
+      return str;
+    }
 
     function getNodes (node){
       nodes.unshift(node);

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

@@ -145,7 +145,7 @@ let electrovalenceObj = {
     this.sheet.bind(GC.Spread.Sheets.Events.EditStarting, this.onElectrovalenceEditStarting);
     this.sheet.name('electrovalence_sheet');
     if (projectReadOnly) {
-      disableSpread(this.spread);
+      sheetCommonObj.disableSpread(this.spread);
     }
   },
   showDatas: function (datas) {

+ 84 - 6
web/building_saas/main/js/views/fee_rate_view.js

@@ -8,6 +8,7 @@ var feeRateObject={
     mainFeeRateSpread:null,
     mainFeeRateSheet:null,
     mainFeeRateData:null,
+    feeRateSTDList:[],
     mainFeeRateSetting:{
         header: [
             {headerName: "专业名称", headerWidth: 250, dataCode: "name", dataType: "String"},
@@ -447,7 +448,7 @@ var feeRateObject={
         disableRightMenu("divFee",this.mainFeeRateSpread,this.rightClickCallback);
         //打开他人分享的项目、只读
         if(projectReadOnly){
-            disableSpread(this.mainFeeRateSpread);
+            sheetCommonObj.disableSpread(this.mainFeeRateSpread);
         }
     },
     rightClickCallback:function (row) {
@@ -754,10 +755,61 @@ var feeRateObject={
     loadPageContent:function(){
         var feeRateFile = projectObj.project.FeeRate.getActivateFeeRate();
         var usageProjects = feeRateFile.usageProjects;
+        feeRateObject.setLocAndFeeRateSTD();
         $('#feeRateFileName').text(feeRateFile.name);
         $('#feeRateLibName').text(feeRateFile.libName);
         $('#projectCount').text(usageProjects.length);
     },
+    setLocAndFeeRateSTD:function(){
+        if(feeRateObject.feeRateSTDLoaded)  return;
+        let location = this.getLocation();
+        $('#location').val(location);
+        //养护的工程所在地下拉框不可选
+        if(!commonUtil.isGLYun()) $('#location').attr("disabled","disabled");
+        feeRateObject.setFeeRateSTD(location);
+        feeRateObject.feeRateSTDLoaded = true;
+    },
+    getLocation:function(){
+        let location = projectObj.project.projectInfo.location;
+        if(!gljUtil.isDef(location)) location = defaultLocation;
+        return location;
+    },
+    setFeeRateSTD(location){
+        let feeRateFile = projectObj.project.FeeRate.getActivateFeeRate();
+        $('#feeRateStandard').empty();
+        setOption(feeRateFile.libID,feeRateFile.libName)
+        feeRateObject.getFeeRateStandards(function (data) {
+            _.forEach(data,function (s) {
+                if(s.ID != feeRateFile.libID){  
+                    if(s.libName.startsWith("部颁")){
+                        setOption(s.ID,s.libName) 
+                    }else {
+                        if(location){
+                            if(s.libName.startsWith(location)) setOption(s.ID,s.libName) 
+                        }else{
+                            setOption(s.ID,s.libName) 
+                        } 
+                    }
+                }
+            })
+            $('#feeRateStandard').val(feeRateFile.libID);
+        });
+
+        function setOption(ID,name){
+            var option =  $("<option>").val(ID).text(name);
+            $('#feeRateStandard').append(option);
+        }
+    },
+
+    loadLocationList:function(){
+        let htmlS = "<option></option>";
+        for(let l of locationList){
+            htmlS += `<option value='${l}'>${l} </option>`
+        }
+
+        $('#location').html(htmlS)
+    },
+
     loadFeeRateSelection:function() {
         if(!this.selectionLoad){
             var selectedID=0;
@@ -772,16 +824,22 @@ var feeRateObject={
         }
     },
     getFeeRateStandards:function (callback) {
-        CommonAjax.post('/feeRates/getFeeRateStandards', {"projectID": projectObj.project.ID()}, function (data) {
-            if (data) {
-                callback(data);
-            }
-        });
+        if(feeRateObject.feeRateSTDList.length == 0){//没有的话发送请求,存在的话直接返回
+            CommonAjax.post('/feeRates/getFeeRateStandards', {"projectID": projectObj.project.ID()}, function (data) {
+                if (data) {
+                    feeRateObject.feeRateSTDList = data;
+                    callback(data);
+                }
+            });
+        }else{
+            callback(feeRateObject.feeRateSTDList);
+        }
     },
     changeFeeRateStandard:function(newVal){
         $.bootstrapLoading.start();
         var callback=function () {
             feeRateObject.reFreshRateViews();
+            feeRateObject.setFeeRateSTD($("#location").val());
             $.bootstrapLoading.end();
         };
         projectObj.project.FeeRate.changeFeeRateStandard(newVal,callback);
@@ -1015,6 +1073,8 @@ function getPopoverContent() {
     return "费率的变化,将自动影响以下单位工程造价:<br>"+ popover_content;
 }
 
+
+
 $(function(){
     $('#pop-lv').tooltip({
             placement:"bottom",
@@ -1024,6 +1084,8 @@ $(function(){
         }
     );
 
+    feeRateObject.loadLocationList();
+
     $('#tab_fee_rate').on('shown.bs.tab', function (e) {
         sessionStorage.setItem('mainTab', '#tab_fee_rate');
         let me = feeRateObject;
@@ -1034,6 +1096,22 @@ $(function(){
         me.loadPageContent();
     });
 
+    //切换选择工程所在地
+    $('#location').change(async function () {
+        //console.log(this.value);
+        let updateData = {type:ModuleNames.project,isInfo:true,data:{'ID' : projectObj.project.ID(),location:this.value}};//,'property.locateSetting':outstd
+        $.bootstrapLoading.start();
+        await projectObj.project.syncUpdateNodesAndRefresh([updateData]);
+        feeRateObject.setFeeRateSTD(this.value);
+        subRateObject.showSubRateData();
+        $.bootstrapLoading.end();
+    });
+
+    //切换费率标准
+    $('#feeRateStandard').change(async function () {
+        feeRateObject.changeFeeRateStandard(this.value);
+    });
+
     $('#setNewFeeRate').bind('click', function () {
         var feeRateFile = projectObj.project.FeeRate.getActivateFeeRate();
         var usageProjects = feeRateFile.usageProjects;

+ 20 - 5
web/building_saas/main/js/views/glj_col.js

@@ -57,11 +57,22 @@ let gljCol = {
         view: {
             lockColumns: ["code","name","specs","unit","short_name","quantity","is_add","tenderPrice","tenderQuantity"]
         },
-        getStyle:function (data,row,activeRow) {
-            if(row == activeRow){//选中黄色显示
-                return {backColor:"#FFFACD"};
-            }
-            return null;
+        getStyle:function (data,row,activeRow,dataCode) {
+          let style = {};
+          if(row === activeRow){//选中黄色显示
+            style = new GC.Spread.Sheets.Style();
+            style.backColor = "#FFFACD";
+            style.borderLeft = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+            style.borderTop = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+            style.borderRight = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+            style.borderBottom = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+          }
+          if(dataCode === "marketPrice"){
+              if(data.marketPrice == data.basePrice) style.foreColor = 'black';//改回相等的时候,要改回来
+              if(data.marketPrice > data.basePrice) style.foreColor = 'red';
+              if(data.marketPrice < data.basePrice) style.foreColor = 'green';
+          }
+          return _.isEmpty(style)?null:style;
         },
         frozenCols:4
     },
@@ -276,6 +287,10 @@ let gljCol = {
             }
         };
 
+        colSettingObj.setVisible('feesIndex.common.tenderUnitFee', showFields);
+        colSettingObj.setVisible('feesIndex.common.tenderTotalFee', showFields);
+        colSettingObj.updateColSetting(true);
+
         if (needRefresh){
             if(projectGljObject.projectGljSpread) {
                 projectGljObject.projectGljSheet = projectGljObject.projectGljSpread .getSheet(0);

+ 20 - 4
web/building_saas/main/js/views/glj_view.js

@@ -984,7 +984,8 @@ var gljOprObj = {
     filterLibGLJSheetData: function () {
         let me = this;
         const selectLibID = $('#glj-lib-select').val();
-        me.gljLibSheetData = selectLibID === commonConstants.COMPLEMENTARY_LIB
+        const cptLibReg = new RegExp(commonConstants.COMPLEMENTARY_LIB);
+        me.gljLibSheetData = cptLibReg.test(selectLibID)
             ? me.complementaryGLJs
             : me.stdGLJ;
         if ($('#actionType').val() == 'replace' || $('#actionType').val() == 'm_replace') {
@@ -1129,6 +1130,7 @@ var gljOprObj = {
                 }else {
                     me.showRationGLJSheetData();
                 }
+                projectObj.refreshBaseActn(project.mainTree);
                 $.bootstrapLoading.end();
             });
 
@@ -1192,9 +1194,10 @@ var gljOprObj = {
             mreplace == true ? $("#mreplace_next_div").modal('show'):me.doReplaceGLJ(selectCode, oldData,selected);
         }
     },
-    doReplaceGLJ: function (selectCode, oldData,selected) {
+    doReplaceGLJ: function (selectCode, oldData,selected,is) {
         let me = this;
         let project = projectObj.project;
+        let oldType = oldData.type;    
         project.ration_glj.replaceGLJ(selectCode, oldData, function (result) {
             if (result) {
                 //result.adjustState;
@@ -1216,17 +1219,28 @@ var gljOprObj = {
                 selected.data.adjustState = result.adjustState;
                 selected.data.name = result.name;
                 projectObj.mainController.refreshTreeNode(nodes);
-                project.calcProgram.calcAndSave(selected);
+                project.calcProgram.calcAndSave(selected,function(){
+                    me.replaceProgramInfo(oldType,result.projectGLJ.type);
+                });
                 gljOprObj.refreshView();
                 $.bootstrapLoading.end();
             }
         })
     },
+
+    replaceProgramInfo:function(oldType,newType){
+        //检查是否由混凝土替换为商品砼或者商品砂浆
+        if(gljUtil.isConcreteToCommercialConcrete(oldType,newType)){
+           setTimeout(()=>{alert("请手动修改取费类别为构造物III");},300); 
+        }
+    },
+
     doMReplaceGLJ: function () {
         let me = this;
         let project = projectObj.project;
         let oldData = me.sheetData[gljContextMenu.selectedRow];
         let selectCode = gljOprObj.GLJSelection[0];
+        let oldType = oldData.type;  
         project.ration_glj.mReplaceGLJ(selectCode, oldData, function (result,updateMap) {
             if(result == null){
                 return;
@@ -1258,7 +1272,9 @@ var gljOprObj = {
             })
             project.projectGLJ.loadNewProjectGLJToCaches([result.projectGLJ],true);
             var rationNodes = me.refreshStateAfterMreplace(stateList, nodes);
-            project.calcProgram.calcNodesAndSave(rationNodes);
+            project.calcProgram.calcNodesAndSave(rationNodes,function(){
+                me.replaceProgramInfo(oldType,result.projectGLJ.type);
+            });
             me.refreshView();
             $.bootstrapLoading.end();
 

+ 3 - 2
web/building_saas/main/js/views/glj_view_contextMenu.js

@@ -453,7 +453,8 @@ function getActionUrl(actionType) {
         case 'replace':
         case 'm_replace':
             const selected = gljOprObj.sheetData[gljContextMenu.selectedRow];
-            const gljLibId = selected.repositoryId || commonConstants.COMPLEMENTARY_LIB;
+            const cptLibID = selected.fromUser ? `${commonConstants.COMPLEMENTARY_LIB}*${selected.fromUser}` : commonConstants.COMPLEMENTARY_LIB;
+            const gljLibId = selected.repositoryId || cptLibID;
             return `${rootUrl}/${gljLibId}/true`;
         case 'change': // 更改选择库
             const selectGLJLibID = $('#glj-lib-select').val();
@@ -470,7 +471,7 @@ function getGLJData(actionType, isInitial = true,getLibFunc) {
     $.bootstrapLoading.start();
     if(!getLibFunc)getLibFunc = projectObj.project.ration_glj.getGLJData;
     getLibFunc(url, function (result) {
-        // 目前只有浙江2015需要特殊处理处理
+        // 目前只有浙江2015 湖南 - 山东 需要特殊处理处理
         if (gljOprObj.sortSelectViewGLJ) {
             gljOprObj.sortSelectViewGLJ(result.datas.stdGLJ);
             gljOprObj.sortSelectViewGLJ(result.datas.complementaryGLJs);

+ 94 - 15
web/building_saas/main/js/views/importBills.js

@@ -24,7 +24,7 @@ const importBills = (function () {
     }
 
     function _deNR(data) {
-        return _isDef(data) ? data.toString().replace(/\r\r/g, '\r') : data;
+        return _isDef(data) ? data.toString().replace(/[\r\n]/g, '') : data;
     }
     //find 返回最后匹配
     function findLast(datas, func) {
@@ -36,7 +36,8 @@ const importBills = (function () {
     }
     const fileType = {
         gcl: 0, //工程量清单
-        qdsl: 1 //清单示例
+        qdsl: 1, //清单示例
+        gclex: 2, // 单机版导出的工程量清单预算表,需要转换成清单示例表来处理
     };
     //获取列字段对应
     function getColMapping(type) {
@@ -46,18 +47,29 @@ const importBills = (function () {
             return { code: 0, name: 1, unit: 2, quantity: 3 };
         }
     }
-    function isGCLHead(dataRow) {
-        let cell = dataRow[0];
-        return cell && cell.value === '工程量清单';
+    function isGCLHead(dataRow, nextDataRow) {
+        const cell = dataRow[0];
+        const nextCell = nextDataRow && nextDataRow[0];
+        return cell && cell.value === '工程量清单' && (!nextCell || !/建设项目名称/.test(nextCell.value)); // 兼容招清单01-1表
+    }
+    function isGCLExtendHead(dataRow, nextDataRow) {
+        const cell = dataRow[0];
+        const nextCell = nextDataRow && nextDataRow[0];
+        if ((cell && cell.value === '工程量清单预算表') || (nextCell && /建设项目名称/.test(nextCell.value))) { // 兼容招清单01-1表
+            return true;
+        }
     }
     //分析文件,1、工程量清单 2、清单示例表
     function getFileType(sheetData) {
         let dataTable = sheetData.data.dataTable,
             rowCount = sheetData.rowCount;
         for (let row = 0; row < rowCount; row++) {
-            if (isGCLHead(dataTable[row])) {
+            if (isGCLHead(dataTable[row], dataTable[row + 1])) {
                 return fileType.gcl;
             }
+            if (isGCLExtendHead(dataTable[row], dataTable[row + 1])) {
+                return fileType.gclex;
+            }
         }
         return fileType.qdsl;
     }
@@ -70,9 +82,9 @@ const importBills = (function () {
         let rst = [];
         for (let row = 0; row < rowCount; row++) {
             //表格中顶层节点
-            if (isGCLHead(dataTable[row])) {
+            if (isGCLHead(dataTable[row], dataTable[row + 1])) {
                 let rootRow = dataTable[row + 2];
-                let name = rootRow[0].value ? _deESC(rootRow[0].value) : '';
+                let name = rootRow[0].value ? _deNR(rootRow[0].value) : '';
                 let existsRoot = findLast(rst, x => x.name === name && x.depth === 0);
                 if (!existsRoot) {
                     let root = {
@@ -94,7 +106,7 @@ const importBills = (function () {
                 continue;
             }
             let code = dataTable[row][colMapping.code] ? dataTable[row][colMapping.code].value : null,
-                name = dataTable[row][colMapping.name] ? _deESC(dataTable[row][colMapping.name].value) : null,
+                name = dataTable[row][colMapping.name] ? _deNR(dataTable[row][colMapping.name].value) : null,
                 unit = dataTable[row][colMapping.unit] ? dataTable[row][colMapping.unit].value : null,
                 quantity = dataTable[row][colMapping.quantity] ? dataTable[row][colMapping.quantity].value : null;
             if (!code && !name || /合计/.test(code)) {   //过滤掉同时没有编号和名称的、过滤合计行
@@ -166,18 +178,77 @@ const importBills = (function () {
         return match ? match[1] : null;
     }
 
+    // 示例列映射
+    const slColMap = { code: 0, name: 1, unit: 2, quantity: 3 };
+
+    function isValidGCLExRow(rowData) {
+        if (rowData[0] && /编制[::]/.test(rowData[0].value)) {
+            return false;
+        }
+        if (rowData[1] && /合计/.test(rowData[1].value)) {
+            return false;
+        }
+        if ((!rowData[slColMap.code] || !rowData[slColMap.code].value) &&
+            (!rowData[slColMap.name] || !rowData[slColMap.name].value) &&
+            (!rowData[slColMap.unit] || !rowData[slColMap.unit].value) &&
+            (!rowData[slColMap.quantity] || !rowData[slColMap.quantity].value)) {
+            return false;
+        }
+        return true;
+    }
+
+    // 将“工程量清单预算表”去掉表头表尾,并转换成清单示例表。
+    // 工程量清单预算表的格式可参考需求:BUG #3037
+    function transformGCLExToSL(sheetData) {
+        const rst = {
+            data: { dataTable: [] },
+            rowCount: 0,
+        };
+        const dataTable = sheetData.data.dataTable;
+        const rowCount = sheetData.rowCount;
+        let preRootName;
+        for (let row = 0; row < rowCount; row++) {
+            const rowData = dataTable[row];
+            if (isGCLExtendHead(rowData, dataTable[row + 1])) {
+                const rootRowdata = dataTable[row + 3];
+                const name = rootRowdata[0].value;
+                if (name) {
+                    const rootName = name.replace('工程量清单', '清单');
+                    if (rootName !== preRootName) {
+                        preRootName = rootName;
+                        rst.data.dataTable.push({
+                            [slColMap.name]: { value: rootName }
+                        });
+                    }
+                }
+                row += 4;
+                continue;
+            }
+            if (isValidGCLExRow(rowData)) {
+                const cellData = {
+                    [slColMap.code]: { value: rowData[slColMap.code] && rowData[slColMap.code].value || null },
+                    [slColMap.name]: { value: rowData[slColMap.name] && rowData[slColMap.name].value || null },
+                    [slColMap.unit]: { value: rowData[slColMap.unit] && rowData[slColMap.unit].value || null },
+                    [slColMap.quantity]: { value: rowData[slColMap.quantity] && rowData[slColMap.quantity].value || null },
+                };
+                rst.data.dataTable.push(cellData);
+            }
+        }
+        rst.rowCount = rst.data.dataTable.length;
+        return rst;
+    }
+
     //提取清单示例数据
     function extractSLDatas(sheetData) {
-        let colMapping = { code: 0, name: 1, unit: 2, quantity: 3 };
         let dataTable = sheetData.data.dataTable,
             rowCount = sheetData.rowCount;
         let rst = [];
         let curRoot = null;
         for (let row = 0; row < rowCount; row++) {
-            let code = dataTable[row][colMapping.code] && dataTable[row][colMapping.code].value ? String(dataTable[row][colMapping.code].value).trim() : null,
-                name = dataTable[row][colMapping.name] ? _deESC(dataTable[row][colMapping.name].value) : null,
-                unit = dataTable[row][colMapping.unit] ? dataTable[row][colMapping.unit].value : null,
-                quantity = dataTable[row][colMapping.quantity] ? dataTable[row][colMapping.quantity].value : null;
+            let code = dataTable[row][slColMap.code] && dataTable[row][slColMap.code].value ? String(dataTable[row][slColMap.code].value).trim() : null,
+                name = dataTable[row][slColMap.name] ? _deNR(dataTable[row][slColMap.name].value) : null,
+                unit = dataTable[row][slColMap.unit] ? dataTable[row][slColMap.unit].value : null,
+                quantity = dataTable[row][slColMap.quantity] ? dataTable[row][slColMap.quantity].value : null;
             if (!code) {    //没有编号的数据,名称必须为:清单 第xx章,认为新的表根节点
                 const reg = /清单\s+第[^章]+章/;
                 //if (name && /清单 第\d+章/.test(name)) {
@@ -243,7 +314,15 @@ const importBills = (function () {
             }
             curSheetType = sheetType;
             let colMapping = getColMapping(sheetType);
-            let datas = sheetType === fileType.gcl ? extractGCLDatas(sheetData, colMapping) : extractSLDatas(sheetData, colMapping);
+            let datas = [];
+            if (sheetType === fileType.gcl) {
+                datas = extractGCLDatas(sheetData, colMapping);
+            } else if (sheetType === fileType.qdsl) {
+                datas = extractSLDatas(sheetData, colMapping);
+            } else {
+                const slSheetData = transformGCLExToSL(sheetData);
+                datas = extractSLDatas(slSheetData, colMapping);
+            }
             rst = rst.concat(datas);
         }
         //编号去除空格 清除多余数据 设置数据

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

@@ -59,7 +59,7 @@ let locateObject={
         settingList :[
             {background:"E2F2C5",describe:""},
             {background:"F9E2CF",describe:""},
-            {background:"F2EFD9",describe:"hehe"},
+            {background:"F2EFD9",describe:""},
             {background:"F5D1DA",describe:""},
             {background:"E3E3E3",describe:""},
             {background:"B6F3F2",describe:""},

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 702 - 628
web/building_saas/main/js/views/main_tree_col.js


+ 22 - 8
web/building_saas/main/js/views/material_calc_view.js

@@ -108,7 +108,7 @@ materialCalcObj = {
         this.materialSheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onMaterialRangeChange);
         this.materialSheet.name('material_calc');
         if(projectReadOnly){
-            disableSpread(this.materialSpread);
+            sheetCommonObj.disableSpread(this.materialSpread);
         }else {
             this.initRightClick("materialCalcSheet",this.materialSpread)
         }
@@ -124,7 +124,7 @@ materialCalcObj = {
         this.freightSheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onFreightPriceRangeChange);
         this.freightSheet.name('freight_calc');
         if(projectReadOnly){
-            disableSpread(this.freightSpread);
+            sheetCommonObj.disableSpread(this.freightSpread);
         }else {
             this.initRightClick("freightSheet",this.freightSpread)
         }
@@ -140,7 +140,7 @@ materialCalcObj = {
         this.freightRationSheet.bind(GC.Spread.Sheets.Events.EditStarting,this.onFreightRationEditStarting);
         this.freightRationSheet.name('freight_ration');
         if(projectReadOnly){
-            disableSpread(this.freightRationSpread);
+            sheetCommonObj.disableSpread(this.freightRationSpread);
         }else {
             this.initRightClick("freight_ration_sheet",this.freightRationSpread);
         }
@@ -156,7 +156,7 @@ materialCalcObj = {
 
         this.priceRationSheet.name('price_ration');
         if(projectReadOnly){
-            disableSpread(this.priceRationSpread);
+            sheetCommonObj.disableSpread(this.priceRationSpread);
         }else {
             this.initRightClick("price_ration_sheet",this.priceRationSpread);
         }
@@ -172,7 +172,7 @@ materialCalcObj = {
         this.priceSheet.bind(GC.Spread.Sheets.Events.EditStarting,this.onPriceEditStarting);
         this.priceSheet.name('price_calc');
         if(projectReadOnly){
-            disableSpread(this.priceSpread);
+            sheetCommonObj.disableSpread(this.priceSpread);
         }else {
             this.initRightClick("priceSheet",this.priceSpread)
         }
@@ -1055,16 +1055,30 @@ $(function () {
     $('#calcCoeDiv').on('show.bs.modal', function () {
         if(materialCalcObj.getAssistProductionLabel) $("#assistProductionLabel").text(materialCalcObj.getAssistProductionLabel);
         $("#assistProductionFeeRate").val(scMathUtil.roundForObj(projectObj.project.projectGLJ.datas.constData.assistProductionFeeRate,getDecimal("feeRate")));
+        $("#machineConstCoe").val(scMathUtil.roundForObj(projectObj.project.projectGLJ.datas.constData.machineConstCoe,getDecimal("feeRate")));
+        
     })
     $("#calcCoeConfirm").click(function () {
         let feeRate =  $("#assistProductionFeeRate").val();
-        if(!number_util.isNum(feeRate)){
+        let constCoe = $("#machineConstCoe").val();
+        let rawFeeRate = scMathUtil.roundForObj(projectObj.project.projectGLJ.datas.constData.assistProductionFeeRate,getDecimal("feeRate"));
+        let rawConstCoe = scMathUtil.roundForObj(projectObj.project.projectGLJ.datas.constData.machineConstCoe,getDecimal("feeRate"));
+        if(!number_util.isNum(rawFeeRate)){
             alert("输入的数据类型不对,请重新输入!");
-           return $("#assistProductionFeeRate").val(scMathUtil.roundForObj(projectObj.project.projectGLJ.datas.constData.assistProductionFeeRate,getDecimal("feeRate")));
+           return $("#assistProductionFeeRate").val(rawFeeRate);
         }
+        if(!number_util.isNum(constCoe)){
+           alert("输入的数据类型不对,请重新输入!");
+           return $("#machineConstCoe").val(rawConstCoe);
+        }
+        let updateData = {};
         feeRate = scMathUtil.roundForObj(feeRate,getDecimal("feeRate"));
+        constCoe = scMathUtil.roundForObj(constCoe,getDecimal("feeRate"));
+        if(feeRate != rawFeeRate) updateData.assistProductionFeeRate = feeRate;
+        if(constCoe != rawConstCoe) updateData.machineConstCoe = constCoe;
+
         $("#calcCoeDiv").modal("hide");
-        projectObj.project.projectGLJ.changeAssistProductionFeeRate(feeRate);
+        if(!_.isEmpty(updateData))projectObj.project.projectGLJ.changeAssistProductionFeeRate(updateData);
     });
 
     $("#insertFreightconfirm").click(function () {

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

@@ -58,7 +58,7 @@ let mbzm_obj={
         this.spread.bind(GC.Spread.Sheets.Events.ButtonClicked, installationFeeObj.onPositionButtonClick);//共用一个位置选择器
         this.sheet.name('ration_template');
         if(projectReadOnly){
-            disableSpread(this.spread);
+            sheetCommonObj.disableSpread(this.spread);
         }
     },
     refresh:function () {

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

@@ -83,7 +83,7 @@ projectGljObject={
             if(this.projectGljSetting.view.lockColumns){
                 this.projectGljSetting.view.lockColumns = null;
             }
-            disableSpread(this.projectGljSpread);  //disableRightMenu("project_glj_sheet",this.projectGljSpread,this.rightClickCallback);
+            sheetCommonObj.disableSpread(this.projectGljSpread);  //disableRightMenu("project_glj_sheet",this.projectGljSpread,this.rightClickCallback);
         }else {
             this.initProjectGljRightClick();
         }
@@ -121,7 +121,7 @@ projectGljObject={
             if(this.mixRatioSetting.view.lockColumns){
                 this.mixRatioSetting.view.lockColumns = null;
             }
-            disableSpread(this.mixRatioSpread);
+            sheetCommonObj.disableSpread(this.mixRatioSpread);
         }
     },
     initRelatedRationSheet:function(){

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

@@ -99,16 +99,16 @@ var projectInfoObj = {
             $('#fullpath').html(this.getFullPathHtml(data));
             // 分享给
             $('#init-share').click(() => {
-                SHARE_TO.initModal(projectObj.project.ID());
+                SHARE_TO.initModal(SHARE_TO.Mode.PROJECT, projectObj.project.ID());
                 $('#share-tip').tooltip('hide');
             });
             SHARE_TO.handleEventListener();
             $("[data-toggle='tooltip']").tooltip();
             if (data.property.valuationType == BUDGET) {
                 $("#tab_tender_price").css('display', 'none');
-            } else {
+            }/*  else {
                 $("#about-calc").css('display', 'none');
-            };
+            }; */
         }
     },
     // 刷新总造价显示span

+ 0 - 0
web/building_saas/main/js/views/project_property_basicInfo.js


Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio