瀏覽代碼

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

chenshilong 6 年之前
父節點
當前提交
f97f0f1a86
共有 70 個文件被更改,包括 1552 次插入514 次删除
  1. 1 1
      config/config.js
  2. 5 3
      modules/all_models/bills.js
  3. 3 3
      modules/all_models/fee_rates.js
  4. 1 1
      modules/all_models/mix_ratio.js
  5. 7 4
      modules/all_models/project_glj.js
  6. 1 1
      modules/all_models/projects.js
  7. 5 3
      modules/all_models/ration.js
  8. 3 3
      modules/all_models/ration_coe.js
  9. 2 2
      modules/all_models/ration_glj.js
  10. 1 1
      modules/all_models/std_glj.js
  11. 1 1
      modules/all_models/unit_price.js
  12. 2 2
      modules/bills_lib/models/bills_lib_interfaces.js
  13. 13 6
      modules/complementary_glj_lib/controllers/gljController.js
  14. 13 49
      modules/complementary_glj_lib/models/gljModel.js
  15. 1 0
      modules/complementary_glj_lib/routes/routes.js
  16. 2 2
      modules/complementary_ration_lib/models/sectionTreeModel.js
  17. 23 3
      modules/main/controllers/ration_controller.js
  18. 0 1
      modules/main/facade/ration_facade.js
  19. 0 3
      modules/main/models/project.js
  20. 1 1
      modules/main/models/ration.js
  21. 8 0
      modules/main/routes/main_route.js
  22. 9 21
      modules/pm/controllers/pm_controller.js
  23. 305 27
      modules/pm/facade/pm_facade.js
  24. 6 3
      modules/pm/models/project_model.js
  25. 15 2
      modules/pm/models/project_property_template.js
  26. 15 9
      modules/ration_glj/facade/glj_calculate_facade.js
  27. 1 1
      modules/ration_glj/facade/ration_glj_facade.js
  28. 1 1
      modules/reports/util/rpt_pdf_util.js
  29. 1 1
      modules/std_billsGuidance_lib/facade/facades.js
  30. 6 5
      modules/users/controllers/login_controller.js
  31. 43 1
      public/web/PerfectLoad.js
  32. 4 1
      public/web/gljUtil.js
  33. 5 0
      public/web/rpt_value_define.js
  34. 5 4
      public/web/sheet/sheet_common.js
  35. 0 1
      public/web/slideResize.js
  36. 6 6
      test/unit/reports/test_rpt_test_template.js
  37. 2 8
      web/building_saas/complementary_glj_lib/js/components.js
  38. 82 36
      web/building_saas/complementary_glj_lib/js/glj.js
  39. 1 15
      web/building_saas/complementary_glj_lib/js/gljClassTree.js
  40. 14 7
      web/building_saas/complementary_glj_lib/js/gljComponent.js
  41. 1 0
      web/building_saas/complementary_glj_lib/js/sheetOpr.js
  42. 26 25
      web/building_saas/complementary_ration_lib/js/ration.js
  43. 4 0
      web/building_saas/css/custom.css
  44. 二進制
      web/building_saas/img/NextPage.cur
  45. 二進制
      web/building_saas/img/PreviousPage.cur
  46. 6 1
      web/building_saas/js/global.js
  47. 90 31
      web/building_saas/main/html/main.html
  48. 44 11
      web/building_saas/main/js/models/calc_program.js
  49. 8 2
      web/building_saas/main/js/models/project_glj.js
  50. 20 13
      web/building_saas/main/js/models/ration.js
  51. 1 4
      web/building_saas/main/js/models/ration_coe.js
  52. 2 24
      web/building_saas/main/js/models/ration_glj.js
  53. 6 4
      web/building_saas/main/js/views/character_content_view.js
  54. 38 12
      web/building_saas/main/js/views/glj_view.js
  55. 502 31
      web/building_saas/main/js/views/locate_view.js
  56. 1 1
      web/building_saas/main/js/views/material_calc_view.js
  57. 6 8
      web/building_saas/main/js/views/options_view.js
  58. 29 4
      web/building_saas/main/js/views/project_view.js
  59. 26 0
      web/building_saas/main/js/views/side_tools.js
  60. 1 1
      web/building_saas/main/js/views/std_billsGuidance_lib.js
  61. 7 10
      web/building_saas/main/js/views/zmhs_view.js
  62. 13 34
      web/building_saas/pm/html/project-management.html
  63. 2 13
      web/building_saas/pm/js/pm_gc.js
  64. 90 29
      web/building_saas/pm/js/pm_newMain.js
  65. 2 1
      web/building_saas/report/js/jpc_output.js
  66. 3 7
      web/building_saas/report/js/rpt_main.js
  67. 1 1
      web/building_saas/report/js/rpt_print.js
  68. 3 2
      web/over_write/js/chongqing_2018.js
  69. 3 3
      web/users/html/login.html
  70. 3 3
      web/users/js/login.js

文件差異過大導致無法顯示
+ 1 - 1
config/config.js


+ 5 - 3
modules/all_models/bills.js

@@ -6,10 +6,10 @@ let subSchema = require("../all_schemas/bills_sub_schemas");
 let deleteSchema = require('../all_schemas/delete_schema');
 let Schema = mongoose.Schema;
 let billsSchema = new Schema({
-    ID: String,
+    ID: {type: String, index: true},
     ParentID: String,
     NextSiblingID: String,
-    projectID: Number,
+    projectID:{type: Number, index: true} ,
     serialNo: Number,
     chapterID: Number,
     billsLibId: Number,
@@ -71,7 +71,9 @@ let billsSchema = new Schema({
     engineeringContent:String,//工程内容
     serviceContent:String,//服务内容
     claimVisa:String,//签证及索赔依据
-    calcFlag: {type: Number}    // 叶子清单的计算类型。末定义:按定额计算。1:用户输入金额。2:用户输入单价。3:用户输入设计单价。
+    calcFlag: {type: Number},    // 叶子清单的计算类型。末定义:按定额计算。1:用户输入金额。2:用户输入单价。3:用户输入设计单价。
+    bookmarkBackground:String,//书签背景色
+    bookmarkAnnotation:String//批注
 });
 
 mongoose.model("bills", billsSchema);

+ 3 - 3
modules/all_models/fee_rates.js

@@ -51,7 +51,7 @@ let ratesSchema = new Schema({
 },{versionKey:false,_id: false});
 
 let feeRatesSchema = new Schema({
-    ID: String,
+    ID: {type: String, index: true},
     rates: [ratesSchema],
     deleteInfo: deleteSchema
 },{versionKey:false});
@@ -60,7 +60,7 @@ mongoose.model('fee_rates', feeRatesSchema, 'fee_rates');
 
 
 let feeRateFileSchema = new Schema({
-    ID: String,
+    ID: {type: String, index: true},
     rootProjectID:Number,//顶层项目ID
     userID:String,
     name:String,
@@ -75,7 +75,7 @@ mongoose.model('fee_rate_file', feeRateFileSchema, 'fee_rate_file');
 
 
 let feeRatesLibSchema = new Schema({
-    ID: String,
+    ID: {type: String, index: true},
     region: String,                     // 工程所在地
     libName: String,
     rates: [ratesSchema]

+ 1 - 1
modules/all_models/mix_ratio.js

@@ -23,7 +23,7 @@ let modelSchema = {
         index: true
     },
     // 单价文件表id (因为选择单价文件后配合比数据也需要同步,所以记录单价文件id)
-    unit_price_file_id: Number,
+    unit_price_file_id: {type: Number, index: true},
     // 关联项目工料机的key 不能关联id,因为单价文件导入别的项目后项目工料机id不同
     connect_key: {
         type: String,

+ 7 - 4
modules/all_models/project_glj.js

@@ -18,21 +18,24 @@ let modelSchema = {
     // 工料机总库ID
     glj_id: Number,
     // 标段ID
-    project_id: Number,
+    project_id: {
+        type: Number,
+        index: true
+    },
     // 编码
     code: {
         type: String,
-        index: true
+        index: false
     },
     //原始的编码
     original_code: {
         type: String,
-        index: true
+        index: false
     },
     // 名称
     name: {
         type: String,
-        index: true,
+        index: false,
         default: ''
     },
     // 是否暂估 (0为否 1为是)

+ 1 - 1
modules/all_models/projects.js

@@ -14,7 +14,7 @@ const shareSchema = new Schema({
     shareDate: String,
 }, {versionKey: false, _id: false});
 const ProjectSchema = new Schema({
-    "ID": Number,
+    "ID":{type: Number, index: true},
     "ParentID": Number,
     "NextSiblingID": Number,
     "userID": String,

+ 5 - 3
modules/all_models/ration.js

@@ -27,8 +27,8 @@ var rationAssItemSchema = mongoose.Schema({
 // 定额、量价、工料机定额 合并存储
 let rationSchema = new Schema({
     // 公用属性部分
-    ID: String,
-    projectID: Number,
+    ID: {type: String, index: true},
+    projectID: {type: Number, index: true},
     billsItemID: String,
     serialNo: Number,
     code: String,
@@ -83,7 +83,9 @@ let rationSchema = new Schema({
     customQuantity:String,//自定义消耗
     model: Number,// 机型
     adjCoe:Number,
-    remark:String
+    remark:String,
+    bookmarkBackground:String,//书签背景色
+    bookmarkAnnotation:String//批注
 });
 
 let ration = mongoose.model("ration", rationSchema, "ration");

+ 3 - 3
modules/all_models/ration_coe.js

@@ -17,15 +17,15 @@ var coeSchema = mongoose.Schema({
 
 var coeListSchema = mongoose.Schema({
     libID: Number,                      // 所属定额库ID
-    ID: String,                         // 系数ID(流水号ID)
+    ID: {type: String, index: true},                         // 系数ID(流水号ID)
     name: String,                       // 名称
     content: String,                    // 说明
     original_code:String,               //原人材机编码
     option_codes:String,                //可选人材机编码
     option_list:[Schema.Types.Mixed],//下拉列表选项
     select_code:String,
-    rationID:String,
-    projectID:Number,
+    rationID:{type: String, index: true},
+    projectID:{type: Number, index: true},
     coeID:Number,
     isAdjust:Number, //0不调整,1调整
     seq:Number,//序数,排序用

+ 2 - 2
modules/all_models/ration_glj.js

@@ -5,10 +5,10 @@ var mongoose = require('mongoose'),
     Schema = mongoose.Schema;
 
 var ration_glj = new Schema({
-    ID:String,
+    ID:{type: String, index: true},
     GLJID:Number,
     repositoryId:Number,
-    projectID: Number,
+    projectID: {type: Number, index: true},
     rationID:String,
     projectGLJID:Number,
     name:String,

+ 1 - 1
modules/all_models/std_glj.js

@@ -20,7 +20,7 @@ const std_gljComponent = new Schema(
 
 const std_glj = new Schema({
     deleted: Boolean,
-    repositoryId: Number,
+    repositoryId: {type: Number,index: true},
     ID: Number,
     code: String,
     name: String,

+ 1 - 1
modules/all_models/unit_price.js

@@ -43,7 +43,7 @@ let modelSchema = {
     // 类型简称
     short_name: String,
     // 单价文件表id
-    unit_price_file_id: Number,
+    unit_price_file_id: {type: Number, index: true},
     // 对应标准库工料机id
     glj_id: Number,
     //是否新增1为是,0为否

+ 2 - 2
modules/bills_lib/models/bills_lib_interfaces.js

@@ -1791,7 +1791,7 @@ billsLibDao.prototype.deleteBills = function(delData, callback){
 
 billsLibDao.prototype.getJobContent = function(gJobData, callback){
     let billsLibId = gJobData.billsLibId;
-    JobContent.find({billsLibId: billsLibId, deleted: false}, '-_id').sort({code: 1}).exec(function(err, result){
+    JobContent.find({billsLibId: billsLibId, deleted: false}, '-_id').lean().sort({code: 1}).exec(function(err, result){
         if(err){
             callback(1, 'Error', null);
         }
@@ -2249,7 +2249,7 @@ billsLibDao.prototype.edUpdateJob = function(data, callback){
 //----------------------ItemCharacter---------------------
 billsLibDao.prototype.getItemCharacter = function(gdata, callback){
     let billsLibId = gdata.billsLibId;
-    ItemCharacter.find({billsLibId: billsLibId, deleted: false}, '-_id').sort({code: 1}).exec(function(err, result){
+    ItemCharacter.find({billsLibId: billsLibId, deleted: false}, '-_id').lean().sort({code: 1}).exec(function(err, result){
         if(err){
             callback(1, 'Error', null);
         }

+ 13 - 6
modules/complementary_glj_lib/controllers/gljController.js

@@ -101,12 +101,19 @@ class GljController extends BaseController{
     }
     getGljItems(req, res) {
         let data = JSON.parse(req.body.data);
-        let stdGljLibId = data.stdGljLibId,
-            userId = data.userId,
-            compilationId = data.compilationId
-            gljDao.getGljItems(stdGljLibId, req.session.sessionUser.id, req.session.sessionCompilation._id, function(err, data){
-                callback(req,res,err,'Get Items',data)
-            });
+        let stdGljLibId = data.stdGljLibId;
+        let projection = data.projection;
+        gljDao.getGljItems(stdGljLibId, req.session.sessionUser.id, req.session.sessionCompilation._id, projection, function(err, data){
+            callback(req,res,err,'Get Items',data)
+        });
+    }
+    getStdItems(req, res) {
+        let data = JSON.parse(req.body.data),
+            stdGljLibId = data.stdGljLibId,
+            projection = data.projection;
+        gljDao.getStdItems(stdGljLibId, projection, function (err, data) {
+            callback(req, res, err, '获取人材机数据失败', data);
+        });
     }
 
     updateComponent(req, res){

+ 13 - 49
modules/complementary_glj_lib/models/gljModel.js

@@ -41,59 +41,14 @@ class GljDao {
         }
     }
     //获得用户的补充工料机和用户当前所在编办的标准工料机
-    async getGljItems (stdGljLibId, userId, compilationId, callback){
+    async getGljItems (stdGljLibId, userId, compilationId, projection, callback){
         let me = this;
         let rst = {stdGljs: [], complementaryGljs: []};
         //批量获取异步
-       /* let functions = [];
-        let count = await stdGljModel.find({repositoryId: stdGljLibId, $or: [{deleted: null}, {deleted: false}]}).count();
-        let findCount = Math.ceil(count/500);
-        for(let i = 0, len = findCount; i < len; i++){
-            functions.push((function(flag) {
-                return function (cb) {
-                    stdGljModel.find({repositoryId: stdGljLibId, deleted: null}, cb).skip(flag).sort({ID: 1}).limit(500);
-                }
-            })(i*500));
-        }
-        async.parallel(functions,  function (err, results) {
-            if(err){
-                callback(err, null);
-            }
-            else{
-                for(let stdGljs of results){
-                    rst.stdGljs = rst.stdGljs.concat(stdGljs);
-                }
-                callback(0, rst);
-            }
-        });*/
         async.parallel([
            async function (cb) {
                try{
-                   let stdGljs = [];
-                   let first = await stdGljModel.find({repositoryId: stdGljLibId}).sort({ID: 1}).limit(1);
-                   let count = await stdGljModel.find({repositoryId: stdGljLibId, $or: [{deleted: null}, {deleted: false}]}).count();
-                   let findCount = Math.ceil(count/500);
-                   let flag = first[0].ID;
-                   //let flag = 0;
-                   //批量获取,非skip
-                   for(let i = 0, len = findCount; i < len; i++){
-                       let tempStdGlj;
-                       if(i === 0){
-                           tempStdGlj = await stdGljModel.find({repositoryId: stdGljLibId, deleted: null, ID: {$gte: flag}}).sort({ID: 1}).limit(500);
-                           if(tempStdGlj.length > 0){
-                               flag = tempStdGlj[tempStdGlj.length - 1].ID;
-                           }
-                       }
-                       else {
-                           tempStdGlj = await stdGljModel.find({repositoryId: stdGljLibId, deleted: null, ID: {$gt: flag}}).sort({ID: 1}).limit(500);
-                           if(tempStdGlj.length > 0){
-                               flag = tempStdGlj[tempStdGlj.length - 1].ID;
-                           }
-                       }
-                       if(tempStdGlj){
-                           stdGljs = stdGljs.concat(tempStdGlj);
-                       }
-                   }
+                   let stdGljs = await stdGljModel.find({repositoryId: stdGljLibId}, projection).lean();
                    me.sortToNumber(stdGljs);
                    rst.stdGljs = stdGljs;
                    cb(null);
@@ -104,7 +59,7 @@ class GljDao {
 
             },
             function (cb) {
-                complementaryGljModel.find({userId: userId, compilationId: compilationId}, function (err, complementaryGljs) {
+                complementaryGljModel.find({userId: userId, compilationId: compilationId}, '-_id', {lean: true}, function (err, complementaryGljs) {
                     if(err){
                         cb(err);
                     }
@@ -124,7 +79,16 @@ class GljDao {
             }
         })
 
-    };
+    }
+
+    async getStdItems (stdGljLibId, projection, callback) {
+        try {
+            let stdItems = await stdGljModel.find({repositoryId: stdGljLibId}, projection).lean();
+            callback(0, stdItems);
+        } catch (err) {
+            callback(1, null);
+        }
+    }
 
     getGljItemsByCode (repositoryId, codes, callback){
         gljModel.find({"repositoryId": repositoryId,"code": {"$in": codes}},function(err,data){

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

@@ -21,6 +21,7 @@ module.exports = function (app) {
     router.post("/getGljDistType", gljController.init, gljController.getGljDistType);
     router.post("/getGljTree", gljController.init, gljController.getGljTree);
     router.post("/getGljItems", gljController.init, gljController.getGljItems);
+    router.post('/getStdItems', gljController.init, gljController.getStdItems);
     router.post("/updateComponent", gljController.init, gljController.updateComponent);
     router.post("/mixUpdateGljItems", gljController.init, gljController.mixUpdateGljItems);
     router.post("/updateRationBasePrc",compleRationController.init, compleRationController.updateRationBasePrc);//更新定额单价

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

@@ -57,9 +57,9 @@ class SectionTreeDao {
         try {
             let treeData;
             if (type === rationLibType.complementary) {
-                treeData = await compleRationSectionTreeModel.find({userId: userId, compilationId: compilationId, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]});
+                treeData = await compleRationSectionTreeModel.find({userId: userId, compilationId: compilationId, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}).lean();
             } else {
-                treeData = await stdSectionTreeModel.find({rationRepId: rationRepId});
+                treeData = await stdSectionTreeModel.find({rationRepId: rationRepId}).lean();
             }
             callback(0, treeData);
         } catch (err) {

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

@@ -8,6 +8,7 @@ let ration_facade = require('../facade/ration_facade');
 let bill_facade = require('../facade/bill_facade');
 let project_facade = require("../facade/project_facade");
 let logger = require("../../../logs/log_helper").logger;
+import GLJController from "../../glj/controllers/glj_controller";
 let controller = {
     insertGLJAsRation:async function (req){
         let data = req.body.data;
@@ -26,7 +27,15 @@ let controller = {
             data = JSON.stringify(data);
         }
         data = JSON.parse(data);
-        return await ration_facade.addNewRation(data,req.session.sessionCompilation);
+        let start = +new Date();
+        let result = await ration_facade.addNewRation(data,req.session.sessionCompilation);
+        //合并取项目工料机数据的情求,用于刷新项目工料机数据,当有添加、替换项目工料机的情况,才需要刷新
+        if(result.ration_gljs && result.ration_gljs.length > 0 && data.newData){
+            result.projectGLJDatas =  await getProjectGLJData(data.newData.projectID);
+        }
+        let end = +new Date();
+        console.log("实际插入时间为-------------------------------"+(end-start));
+        return result
     },
     addMultiRation: async function (req) {
         let data = req.body.data;
@@ -78,12 +87,23 @@ let controller = {
     updateCoeAdjust:async function(req){
         let data = req.body.data;
         data = JSON.parse(data);
-        return await ration_facade.updateCoeAdjust(data,req.session.sessionCompilation);
+        let result = await ration_facade.updateCoeAdjust(data,req.session.sessionCompilation);
+        //合并取项目工料机数据的情求,用于刷新项目工料机数据,当有添加、替换项目工料机的情况,才需要刷新
+        if(result.add.length > 0 || result.replace.length > 0){
+            result.projectGLJDatas =  await getProjectGLJData(data.projectID);
+        }
+        return result
 
     }
+};
 
 
-};
+async function getProjectGLJData(projectID) {
+    let gljController = new GLJController();
+    let responseData = await gljController.getProjectGLJsByProjectID(projectID);
+    return responseData.data;
+}
+
 
 function prepareUpdateNodes(datas,nodes,type) {
     for(let d of datas){

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

@@ -485,7 +485,6 @@ async function updateCoeAdjust(data,compilation) {
             replace.push(await  ration_glj_facade.replaceGLJByData(r,compilation)) ;
         }
     }
-
     let cal_result = await glj_calculate_facade.calculateQuantity({projectID:data.projectID,rationID:data.rationID},null,true);
     let coe = {
         query:{ID:data.ID,projectID:data.projectID},

+ 0 - 3
modules/main/models/project.js

@@ -103,10 +103,7 @@ Project.prototype.getData = function(projectID, callback){
     for (itemName in moduleMap){
         functions.push((function(itemName){
             return function (cb) {
-                let startTime = +new Date();
                 moduleMap[itemName].getData(projectID, function(err, moduleName, data){
-                    let endTime = +new Date();
-                    console.log(moduleName+'---------------'+(endTime - startTime));
                     cb(err, {moduleName: moduleName, data: data})
                 })
             }

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

@@ -18,7 +18,7 @@ class rationModel extends baseModel {
     }
 
     getData (projectID, callback) {
-        ration.find({'$or': [{projectID: projectID, deleteInfo: null}, {projectID: projectID, 'deleteInfo.deleted': {$in: [null, false]}}]}, '-_id', function(err, datas){
+        ration.find({projectID: projectID}, '-_id', function(err, datas){//{'$or': [{projectID: projectID, deleteInfo: null}, {projectID: projectID, 'deleteInfo.deleted': {$in: [null, false]}}]}
             if (!err) {
                 callback(0, projectConsts.RATION, datas);
             } else {

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

@@ -5,6 +5,8 @@
 
 import BaseController from "../../common/base/base_controller";
 const projectModel = require("../../pm/models/project_model");
+import OptionsDao from '../../options/models/optionsModel';
+import optionSetting from '../../options/models/optionTypes';
 let config = require("../../../config/config.js");
 module.exports =function (app) {
     const baseController = new BaseController();
@@ -22,6 +24,11 @@ module.exports =function (app) {
                     //允许协作的项目允许编辑,非只读
                     projectReadOnly = !projectCooperate;
                 }
+                let optionsDao = new OptionsDao();
+                let options = await optionsDao.getOptions(req.session.sessionUser.id, req.session.sessionCompilation._id);
+                if(options){
+                    options = await optionsDao.saveOptions(req.session.sessionUser.id, req.session.sessionCompilation._id, optionSetting);
+                }
                 res.render('building_saas/main/html/main.html',
                     {
                         userAccount: req.session.userAccount,
@@ -32,6 +39,7 @@ module.exports =function (app) {
                         projectReadOnly: projectReadOnly,
                         projectCooperate: projectCooperate,
                         LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
+                        options:JSON.stringify(options),
                         overWriteUrl:req.session.sessionCompilation.overWriteUrl
                     });
             } else {

+ 9 - 21
modules/pm/controllers/pm_controller.js

@@ -683,36 +683,24 @@ module.exports = {
 
     },
     importProject:async function(req,res){
-        let form = new multiparty.Form({uploadDir: './public'});
+        let form = new multiparty.Form({uploadDir: './tmp'});
         let uploadFullName;
         form.parse(req, async function (err, fields, files) {
             try {
+                console.log(fields);
                 const file = typeof files.file !== 'undefined' ? files.file[0] : null;
                 if (err || !file) {
                     throw '上传失败。';
-                }
-                console.log(file);
+                };
                 let data = fs.readFileSync(file.path,'utf-8');
-                console.log(data);
+                let result = await pm_facade.importProject(data,req,fields);
+                fs.unlinkSync(file.path);
+                res.json(result);
             }catch (e){
-
+                console.log(e);
+                res.json({error:1,msg:"导入失败请检查文件!"})
             }
-            res.json({error:0})
-        })
-        /*let result={
-            error:0
-        };
-        try {
-            console.log(req.files[0]);
-           /!* let data = JSON.parse(req.body.data);
-            result.data = await pm_facade.exportProject(req.session.sessionUser.id, data);*!/
-        }catch (err){
-            console.log(err);
-            result.error=1;
-            result.message = err.message;
-        }
-        res.json(result);*/
-
 
+        })
     }
 };

+ 305 - 27
modules/pm/facade/pm_facade.js

@@ -27,7 +27,8 @@ module.exports={
     prepareInitialData: prepareInitialData,
     changeFile:changeFile,
     copyForSectionError: copyForSectionError,
-    exportProject:exportProject
+    exportProject:exportProject,
+    importProject:importProject
 };
 
 
@@ -293,35 +294,34 @@ async function copyProjectSetting(originalID,newProjectID) {
 async function copyBills(newProjectID,billMap) {
      let uuidMaping = billMap.uuidMaping;//做ID映射
      for(let doc of billMap.datas){
-         doc.projectID = newProjectID;
-         doc.ID = uuidMaping[doc.ID] ? uuidMaping[doc.ID] : -1;
-         doc.ParentID = uuidMaping[doc.ParentID] ? uuidMaping[doc.ParentID] : -1;
-         doc.NextSiblingID = uuidMaping[doc.NextSiblingID] ? uuidMaping[doc.NextSiblingID] : -1;
-         //对于有基数计算的节点,需要替换计算基数中引用的ID为新的ID
-         if(doc.calcBase && doc.calcBase != ""){
-             let idArr = scMathUtil.getFIDArr(doc.calcBase);
-             for(let re of idArr){
-                 let oID = re.substr(1);//去掉开头的@字符
-                 if(!uuidMaping[oID]) continue;
-                 doc.calcBase = doc.calcBase.replace(new RegExp(oID, "g"),uuidMaping[oID]);
-             }
-         }
+         doc = getCopyBillDatas(doc,newProjectID,uuidMaping)
      }
     await insertMany(billMap.datas,billsModel);
     return billMap.datas;
 }
 
+
+function getCopyBillDatas(doc,newProjectID,uuidMaping) {
+    doc.projectID = newProjectID;
+    doc.ID = uuidMaping[doc.ID] ? uuidMaping[doc.ID] : -1;
+    doc.ParentID = uuidMaping[doc.ParentID] ? uuidMaping[doc.ParentID] : -1;
+    doc.NextSiblingID = uuidMaping[doc.NextSiblingID] ? uuidMaping[doc.NextSiblingID] : -1;
+    //对于有基数计算的节点,需要替换计算基数中引用的ID为新的ID
+    if(doc.calcBase && doc.calcBase != ""){
+        let idArr = scMathUtil.getFIDArr(doc.calcBase);
+        for(let re of idArr){
+            let oID = re.substr(1);//去掉开头的@字符
+            if(!uuidMaping[oID]) continue;
+            doc.calcBase = doc.calcBase.replace(new RegExp(oID, "g"),uuidMaping[oID]);
+        }
+    }
+    return doc;
+}
+
 async function copyRations(newProjectID,billsIDMap,rationMap,projectGLJIDMap) {
     let uuidMaping = rationMap.uuidMaping;
     for(let doc of rationMap.datas){
-        doc.projectID = newProjectID;
-        doc.ID = uuidMaping[doc.ID] ? uuidMaping[doc.ID] : -1;
-        if(doc.billsItemID){
-            doc.billsItemID = billsIDMap[doc.billsItemID]?billsIDMap[doc.billsItemID]:-1;
-        }
-        if(doc.referenceRationID) doc.referenceRationID = uuidMaping[doc.referenceRationID]?uuidMaping[doc.referenceRationID]:undefined;
-        //绑定定类型的工料机 项目工料机ID
-        doc.type==3&&doc.projectGLJID&&projectGLJIDMap[doc.projectGLJID]?doc.projectGLJID = projectGLJIDMap[doc.projectGLJID]:'';
+        doc = getCopyRationData(doc,newProjectID,billsIDMap,uuidMaping,projectGLJIDMap);
     }
     if(rationMap.datas.length > 0){
         await insertMany(rationMap.datas,rationModel);
@@ -329,6 +329,20 @@ async function copyRations(newProjectID,billsIDMap,rationMap,projectGLJIDMap) {
     return rationMap.datas;
 }
 
+
+function getCopyRationData(doc,newProjectID,billsIDMap,uuidMaping,projectGLJIDMap){
+    doc.projectID = newProjectID;
+    doc.ID = uuidMaping[doc.ID] ? uuidMaping[doc.ID] : -1;
+    if(doc.billsItemID){
+        doc.billsItemID = billsIDMap[doc.billsItemID]?billsIDMap[doc.billsItemID]:-1;
+    }
+    if(doc.referenceRationID) doc.referenceRationID = uuidMaping[doc.referenceRationID]?uuidMaping[doc.referenceRationID]:undefined;
+    //绑定定类型的工料机 项目工料机ID
+    doc.type==3&&doc.projectGLJID&&projectGLJIDMap[doc.projectGLJID]?doc.projectGLJID = projectGLJIDMap[doc.projectGLJID]:'';
+    return doc;
+}
+
+
 async function copyProjectGLJ(gljList) {
     await insertMany(gljList,gljListModel);
 }
@@ -416,7 +430,8 @@ async function copyRationSubList(originalPID,newProjectID,billIDMap,rationIDMap,
     let subList = await model.find({projectID:originalPID}, '-_id');
     let newList =[];
     for(let s of subList){
-        s._doc.ID = uuidV1();
+        s._doc = getCopyRationSubData(s._doc,newProjectID,billIDMap,rationIDMap,projectGLJIDMap);
+   /*     s._doc.ID = uuidV1();
         s._doc.projectID = newProjectID;
         s._doc.rationID&&rationIDMap[s._doc.rationID]?s._doc.rationID = rationIDMap[s._doc.rationID]:'';
         s._doc.billID&&billIDMap[s._doc.billID]?s._doc.billID = billIDMap[s._doc.billID]:'';
@@ -427,12 +442,30 @@ async function copyRationSubList(originalPID,newProjectID,billIDMap,rationIDMap,
                 if(t.billID && billIDMap[t.billID]) t.billID =  billIDMap[t.billID];
                 if(t.fxID && billIDMap[t.fxID]) t.fxID =  billIDMap[t.fxID];
             }
-        }
+        }*/
         newList.push(s._doc);
     }
     await insertMany(newList,model);
 }
 
+function getCopyRationSubData(doc,newProjectID,billIDMap,rationIDMap,projectGLJIDMap){
+    doc.ID = uuidV1();
+    doc.projectID = newProjectID;
+    doc.rationID&&rationIDMap[doc.rationID]?doc.rationID = rationIDMap[doc.rationID]:'';
+    doc.billID&&billIDMap[doc.billID]?doc.billID = billIDMap[doc.billID]:'';
+    doc.billsItemID&&billIDMap[doc.billsItemID]?doc.billsItemID = billIDMap[doc.billsItemID]:'';
+    doc.projectGLJID&&projectGLJIDMap[doc.projectGLJID]?doc.projectGLJID = projectGLJIDMap[doc.projectGLJID]:'';
+    if(doc.templateList && doc.templateList.length > 0 ){
+        for(let t of doc.templateList){
+            if(t.billID && billIDMap[t.billID]) t.billID =  billIDMap[t.billID];
+            if(t.fxID && billIDMap[t.fxID]) t.fxID =  billIDMap[t.fxID];
+        }
+    }
+    return doc;
+}
+
+
+
 async function moveProject(data) {
     data = JSON.parse(data);
     let projectMap = data.projectMap,feeRateMap = data.feeRateMap,unitPriceMap = data.unitPriceMap;
@@ -465,7 +498,7 @@ async function moveProject(data) {
         }
     }
     if(!_.isEmpty(unitPriceMap)&&data.rootProjectID) {//如果单价文件有修改
-        let unitPriceFiles =  await unitPriceFileModel.find({root_project_id: data.rootProjectID, deleteInfo: null});
+        let unitPriceFiles = await unitPriceFileModel.find({root_project_id: data.rootProjectID, deleteInfo: null});
         for(let projectID in unitPriceMap){
             let checkUn = _.find(unitPriceFiles,{'name':unitPriceMap[projectID].name});
             let rename = unitPriceMap[projectID].name;
@@ -731,7 +764,7 @@ async function getSummaryInfo(projectIDs){
     if(tenders.length > 0){
         for(let tender of tenders){
             tenderIDs.push(tender.ID);
-            IDMapping[tender.ID] = {totalCost: 0, changeMark:tender.changeMark};//property:tender.property
+            IDMapping[tender.ID] = {totalCost: 0, changeMark:tender.changeMark,property:tender.property};//property:tender.property
         }
         //需要获取的清单固定类别综合合价:总造价
         let needFlags = [billsFlags.TOTAL_COST];
@@ -979,7 +1012,6 @@ async function changeFile(datas,userID,fileID,name,from,type){//from 费率或
 }
 
 async function exportProject(userID,data){//导出建设项目
-    console.log(data);
     if(data.type == 'main'){
         return await exportMainData(userID,data.projectID);
     }else {
@@ -1054,4 +1086,250 @@ async function exportTenderData(data){
     result.labourCoes = await labourCoesModel.findOne({projectID:data.projectID});
 
     return cipher.aesEncrypt(JSON.stringify(result));
+}
+
+
+async function importProject(data,req,fields) {
+    let result = {error:0};
+    let stringArr = data.split("|----|");
+    let datas = [];
+    for(let s of stringArr){
+        datas.push(JSON.parse(cipher.aesDecrypt(s)));
+    }
+    let mainData = datas.length > 0 ?datas[0]:null;
+    if(mainData){
+         if(mainData.compilationID != req.session.sessionCompilation._id){
+             result.error = 1;
+             result.msg = "编办不同,无法导入,请重新选择!";
+         }else {
+            let [projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap] = await handleMainProjectDatas(mainData,JSON.parse(fields.updateData[0]),req.session.sessionUser.id);
+            if(datas.length > 1 ){
+                for(let i = 1;i<datas.length;i++){
+                    await handleEachProject(datas[i],projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap)
+                }
+            }
+
+         }
+    }
+    return result;
+}
+
+async function handleEachProject(data,projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap){
+    let bills = [],rations = [],projectGLJs = [],rationGLJs=[],rationCoes=[],quantityDetails=[],rationInstallations=[],rationTemplates=[];
+    let newProjectSetting =null,newCalcProgramsFile = null,newLabourCoe = null;
+    let billsIDMap = {},projectGLJIDMap={},rationIDMap = {};
+    let newProjectID = projectIDMap[data.projSetting.projectID];
+    //生成新的清单;
+    if(data.bills && data.bills.length > 0){
+        for(let b of data.bills){
+            billsIDMap[b.ID] = uuidV1();
+        }
+        for(let b of data.bills){
+            delete b._id;
+            b = getCopyBillDatas(b,newProjectID,billsIDMap);
+            bills.push(b);
+        }
+    }
+
+    //生成项目工料机数据
+    if(data.projectGLJs && data.projectGLJs.length > 0){
+        let gljCount = await counter.counterDAO.getIDAfterCountSync(counter.moduleName.glj_list, data.projectGLJs.length);
+        for(let i = 0; i < data.projectGLJs.length; i++){
+            let d = data.projectGLJs[i];
+            delete d._id;
+            let newID = gljCount.sequence_value - (data.projectGLJs.length - 1) + i;
+            projectGLJIDMap[d.id] = newID;
+            d.project_id = newProjectID;
+            d.id = newID;
+            projectGLJs.push(d);
+        }
+    }
+
+    //生成新的定额
+    if(data.rations && data.rations.length > 0){
+        for(let r of data.rations){
+            rationIDMap[r.ID] = uuidV1();
+        }
+        for(let r of data.rations){
+            delete r._id;
+            r = getCopyRationData(r,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
+            rations.push(r);
+        }
+    }
+
+    //生成定额下挂的定额工料机等等数据
+    if(data.rationGLJs && data.rationGLJs.length > 0) rationGLJs = setRationSubList(data.rationGLJs,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
+    if(data.rationCoes && data.rationCoes.length > 0) rationCoes = setRationSubList(data.rationCoes,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
+    if(data.quantityDetails && data.quantityDetails.length > 0) quantityDetails = setRationSubList(data.quantityDetails,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
+    if(data.rationInstallations && data.rationInstallations.length > 0) rationInstallations = setRationSubList(data.rationInstallations,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
+    if(data.rationTemplates && data.rationTemplates.length > 0) rationTemplates = setRationSubList(data.rationTemplates,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
+
+    //生成projectSetting 文件
+    if(data.projSetting){
+        data.projSetting.projectID =newProjectID;
+        newProjectSetting = data.projSetting;
+        delete newProjectSetting._id;
+    }
+
+    //生成计算程序文件,系数文件
+    if(data.calcProgramsFile && calcProgramFileIDMap[data.calcProgramsFile.ID]){
+        data.calcProgramsFile.ID = calcProgramFileIDMap[data.calcProgramsFile.ID];
+        data.calcProgramsFile.projectID = newProjectID;
+        newCalcProgramsFile =  data.calcProgramsFile;
+        delete newCalcProgramsFile._id;
+
+    }
+    if(data.labourCoes && labourCoeFileIDMap[data.labourCoes.ID]){
+        data.labourCoes.ID = labourCoeFileIDMap[data.labourCoes.ID];
+        data.labourCoes.projectID = newProjectID;
+        newLabourCoe = data.labourCoes;
+        delete newLabourCoe._id;
+    }
+
+    if(newProjectSetting) await projectSettingModel.create(newProjectSetting);
+    if(bills.length > 0) await insertMany(bills,billsModel);
+    if(rations.length > 0) await insertMany(rations,rationModel);
+    if(projectGLJs.length > 0) await insertMany(projectGLJs,gljListModel);
+    if(rationGLJs.length > 0) await insertMany(rationGLJs,rationGLJModel);
+    if(rationCoes.length > 0) await insertMany(rationCoes,rationCoeModel);
+    if(quantityDetails.length > 0) await insertMany(quantityDetails,quantityDetailModel);
+    if(rationInstallations.length > 0) await insertMany(rationInstallations,rationInstallationModel);
+    if(rationTemplates.length > 0) await insertMany(rationTemplates,rationTemplateModel);
+    if(newCalcProgramsFile) await calcProgramsModel.create(newCalcProgramsFile);
+    if(newLabourCoe) await labourCoesModel.create(newLabourCoe);
+
+
+}
+
+
+function setRationSubList(datas,newProjectID,billIDMap,rationIDMap,projectGLJIDMap) {
+    let arrs = [];
+    for(let d of datas){
+        delete d._id;
+        d = getCopyRationSubData(d,newProjectID,billIDMap,rationIDMap,projectGLJIDMap);
+        arrs.push(d);
+    }
+    return arrs;
+}
+
+async function handleMainProjectDatas(mainData,updateData,userID) {
+    let mainProjectID = -1;
+    let projectIDMap = {},feeRateFileIDMap={},unitPriceFileIDMap={},labourCoeFileIDMap={},calcProgramFileIDMap={};
+    let tasks = [];
+    //生成新的projectID
+    for(let p of mainData.projects){
+        let newProjectID = await getCounterID("projects");
+        projectIDMap[p.ID] = newProjectID;
+        if(p.projType == "Project") mainProjectID =  newProjectID;
+        if(p.projType == "Tender"){
+            if(p.property.calcProgramFile) calcProgramFileIDMap[p.property.calcProgramFile.ID] = uuidV1();//新的计算程序文件ID
+            if(p.property.labourCoeFile) labourCoeFileIDMap[p.property.labourCoeFile.ID] = uuidV1();//新的人工调整系数文件ID
+            if(p.property.feeFile) feeRateFileIDMap[p.property.feeFile.id] = uuidV1();//新的费率文件ID
+            if(p.property.unitPriceFile) unitPriceFileIDMap[p.property.unitPriceFile.id] = await getCounterID("unit_price_file");//新的单价文件ID
+        }
+    }
+    if(mainProjectID == -1) throw new Error("文件里面没包含建设项目信息!");
+
+    //处理项目信息  ----- 费率文件,单价文件ID信息要重新生成----to do
+    for(let p of mainData.projects){
+        delete p._id;
+        delete p.__v;
+        p.ID = projectIDMap[p.ID];
+        if(p.ID == mainProjectID){//对于建设项目,要父和下一节点ID要使用前端传入的位置ID
+            p.ParentID = updateData.self.ParentID;
+            p.NextSiblingID = updateData.self.NextSiblingID;
+            if(updateData.update){//树节构中的上一节点的下一节点设置为本建设项目ID;
+                tasks.push({updateOne:{filter : updateData.update.query, update : {NextSiblingID:mainProjectID}}});
+            }
+            //查看是否重名;
+            let temp = await projectModel.findOne({userID:userID,ParentID:p.ParentID,name:p.name});
+            if(temp) p.name = p.name + '(' + moment(Date.now()).format('MM-DD HH:mm:ss') + '导入)';
+        }else {
+            p.ParentID = projectIDMap[p.ParentID];
+            p.NextSiblingID = projectIDMap[p.NextSiblingID];
+        }
+        p.userID =userID;
+        p.shareInfo=[];
+        if(p.projType == "Tender"){
+            if(p.property.calcProgramFile) p.property.calcProgramFile.ID = calcProgramFileIDMap[p.property.calcProgramFile.ID];
+            if(p.property.labourCoeFile) p.property.labourCoeFile.ID = labourCoeFileIDMap[p.property.labourCoeFile.ID];
+            if(p.property.feeFile) p.property.feeFile.id = feeRateFileIDMap[p.property.feeFile.id];
+            if(p.property.unitPriceFile) p.property.unitPriceFile.id = unitPriceFileIDMap[p.property.unitPriceFile.id];
+            p.property.rootProjectID = mainProjectID
+        }
+        tasks.push({insertOne: {document: p}})
+    }
+    //项目树节构数据生成:
+      await projectModel.bulkWrite(tasks);
+
+    //生成所有的费率文件
+    await importFeeRateFiles(mainData,projectIDMap,feeRateFileIDMap,userID);
+
+    //生成所有的单价文件
+    await importUnitPriceFiles(mainData,projectIDMap,unitPriceFileIDMap,userID);
+
+
+    return [projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap]
+}
+
+
+async function importUnitPriceFiles(mainData,projectIDMap,unitPriceFileIDMap,userID) {
+    if(!mainData.files.unitFiles) return;
+    let unitFiles = [],unitPrices =[],mixRatios=[],freights=[],originals=[];
+    for(let f of mainData.files.unitFiles){
+        let file = f.unitFile,prices = f.unitPrices,mixs = f.mixRatios,fres = f.freights,ors = f.originals;
+        //生成单价文件
+        delete file._id;
+        file.id = unitPriceFileIDMap[file.id]?unitPriceFileIDMap[file.id]:await getCounterID("unit_price_file");
+        file.project_id = projectIDMap[file.project_id];
+        file.root_project_id = projectIDMap[file.root_project_id];
+        file.user_id = userID;
+        unitFiles.push(file);
+
+        //生成子数据
+        if(prices) await  setSubList(prices,unitPrices,file.id,unitPriceModel);
+        if(mixs) await setSubList(mixs,mixRatios,file.id,mixRatioModel);
+        if(fres) await setSubList(fres,freights,file.id,freightModel,true);
+        if(ors) await setSubList(ors,originals,file.id,originalModel,true);
+    }
+    if(unitFiles.length > 0) await insertMany(unitFiles,unitPriceFileModel);
+    if(unitPrices.length > 0) await insertMany(unitPrices,unitPriceModel);
+    if(mixRatios.length > 0) await insertMany(mixRatios,mixRatioModel);
+    if(freights.length > 0) await insertMany(freights,freightModel);
+    if(originals.length > 0) await insertMany(originals,originalModel);
+
+    async function setSubList(oList,nList,fileID,model,UUID=false) {
+        for(let o of oList){
+            delete o._id;
+            o.unit_price_file_id = fileID;
+            UUID == true?o.ID = uuidV1():o.id = await getCounterID(model.modelName);
+            nList.push(o)
+        }
+    }
+
+
+}
+
+
+async function importFeeRateFiles(mainData,projectIDMap,feeRateFileIDMap,userID) {
+    let feeRateFiles = [], feeRates = [];
+    if(!mainData.files.feeRateFiles) return;
+    for(let f of mainData.files.feeRateFiles){
+        //生成费率记录
+        let rate = f.feeRate;
+        delete rate._id;
+        rate.ID = uuidV1();
+        feeRates.push(rate);
+
+        //生成费率文件记录
+        let file = f.feeRateFile;
+        delete file._id;
+        file.ID = feeRateFileIDMap[file.ID]?feeRateFileIDMap[file.ID]:uuidV1();
+        file.userID = userID;
+        file.rootProjectID = projectIDMap[file.rootProjectID];
+        file.feeRateID = rate.ID;
+        feeRateFiles.push(file);
+    }
+    if(feeRateFiles.length > 0) await insertMany(feeRateFiles,feeRateFileModel);
+    if(feeRates.length > 0) await insertMany(feeRates,feeRateModel);
 }

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

@@ -28,7 +28,8 @@ import {
     projectFeature,
     displaySetting,
     calcOptions,
-    tenderSetting
+    tenderSetting,
+    bookmarkSetting
 } from './project_property_template';
 import optionSetting from '../../options/models/optionTypes';
 import fixedFlag from '../../common/const/bills_fixed';
@@ -65,7 +66,7 @@ ProjectsDAO.prototype.getUserProjects = async function (userId, compilation, cal
                 'compilation': compilation,
                 'deleteInfo': null
             }, {'userID': userId, 'compilation': compilation, 'deleteInfo.deleted': {'$in': [null, false]}}]
-        }, '-_id');
+        }, '-_id', {lean: true});
         let projIDs= [];
         for(let project of projects){
             if(project.projType === projectType.project){
@@ -77,7 +78,7 @@ ProjectsDAO.prototype.getUserProjects = async function (userId, compilation, cal
         for(let proj of projects){
             let summaryProj = summaryInfo[proj.ID];
             if(summaryProj){
-                proj._doc.totalCost = summaryProj.totalCost;
+                proj.totalCost = summaryProj.totalCost;
             }
         }
         callback(0, '', projects);
@@ -203,6 +204,8 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     data.updateData.property.lockBills = false;
                     //工料机单价调整系数
                     data.updateData.property.tenderSetting = tenderSetting;
+                    //书签和批注
+                    data.updateData.property.bookmarkSetting =  bookmarkSetting;
                 }
 
                 newProject = new Projects(data.updateData);

+ 15 - 2
modules/pm/models/project_property_template.js

@@ -33,7 +33,7 @@ const calcOptions={
 * 单位工程清单工程量精度模板
 * */
 const billsQuantityDecimal = [
-    {unit: '其他未列单位', decimal: 2},
+    {unit: '其他未列单位', decimal: 3},
     {unit: 't', decimal: 3},
     {unit: '吨', decimal: 3},
     {unit: 'km', decimal: 3},
@@ -139,4 +139,17 @@ const projectFeature = [
     {dispName: '门窗材料及装饰', key: 'doorsWindowsMaterial', value: ''}
 ];
 
-export {defaultDecimal, billsQuantityDecimal, basicInformation, projectFeature,displaySetting,calcOptions,tenderSetting};
+const bookmarkSetting = {
+    settingList :[
+        {background:"E2F2C5",describe:""},
+        {background:"F9E2CF",describe:""},
+        {background:"F2EFD9",describe:""},
+        {background:"F5D1DA",describe:""},
+        {background:"E3E3E3",describe:""},
+        {background:"B6F3F2",describe:""},
+        {background:"ECE0F5",describe:""}
+    ],
+    selected:"E2F2C5"
+};
+
+export {defaultDecimal, billsQuantityDecimal, basicInformation, projectFeature,displaySetting,calcOptions,tenderSetting,bookmarkSetting};

+ 15 - 9
modules/ration_glj/facade/glj_calculate_facade.js

@@ -48,9 +48,9 @@ async function calculateQuantity(query,noNeedCal=null,refreshRationName = false)
              glj_result:[],
              rationID:query.rationID
          };
-         let impactRation = await ration.findOne({ID:query.rationID,projectID:query.projectID});
+         let impactRation = await ration.findOne({ID:query.rationID});
          let gljList = await ration_glj.find(query);//{projectID:query.projectID,rationID:query.rationID}
-         let coeList = await ration_coe.find({projectID:query.projectID,rationID:query.rationID}).sort('seq').exec();
+         let coeList = await ration_coe.find({rationID:query.rationID}).sort('seq').exec();
          let assList=[], assRation = null, adjustState=[],mixRatioMap = {};
          if(!impactRation){//如果定额不存在或者已删除,返回空
              return null;
@@ -87,10 +87,10 @@ async function calculateQuantity(query,noNeedCal=null,refreshRationName = false)
         gljList = gljUtil.sortRationGLJ(gljList);
         for(let i =0;i<gljList.length;i++ ){
             let r = await calculateQuantityPerGLJ(gljList[i],gljList,coeList,assList,adjustState,mixRatioMap,noNeedCal);
-            result.glj_result.push(r);
+            if(quantityUpdateCheck(gljList[i],r) == true) result.glj_result.push(r);
         }
-         if(noNeedCal==null){
-            await ration_glj.bulkWrite(generateUpdateTasks(result.glj_result));
+         if(noNeedCal==null && result.glj_result.length > 0){
+             await ration_glj.bulkWrite(generateUpdateTasks(result.glj_result));
          }
          adjustState= _.sortByOrder(adjustState, ['index'], ['asc']);
          adjustState=_.map(adjustState, _.property('content'));
@@ -101,7 +101,7 @@ async function calculateQuantity(query,noNeedCal=null,refreshRationName = false)
              setData.name = newName;
              result.rationName = newName;
          }
-         await ration.update({projectID:query.projectID,ID:query.rationID,deleteInfo: null},setData);
+         await ration.update({ID:query.rationID},setData);
          result.adjustState=adjustStateString;
          return result;
     }catch (err){
@@ -110,6 +110,13 @@ async function calculateQuantity(query,noNeedCal=null,refreshRationName = false)
     }
 }
 
+function quantityUpdateCheck(glj,r) {//检查,有改变的才更新
+    for(let key in r.doc){
+        if(glj._doc[key] != r.doc[key]) return true
+    }
+    return false
+}
+
 function generateRationName(ration,gljList) {
     let caption = ration.caption ? ration.caption:ration.name;
     let replaceList = [];
@@ -158,7 +165,7 @@ function generateUpdateTasks(result) {
                 filter: result[i].query,
                 update: result[i].doc
             }
-        }
+        };
         tasks.push(task);
     }
     return tasks;
@@ -179,8 +186,7 @@ async function calculateQuantityPerGLJ(glj,gljList,coeList,assList,adjustState,m
     let quantity =  scMathUtil.roundTo(parseFloat(glj.quantity),-decimal);
     let result={
         query:{
-            ID:glj.ID,
-            projectID:glj.projectID
+            ID:glj.ID
         },
         doc:{
             quantity: quantity

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

@@ -561,7 +561,7 @@ function getGLJData(info, callback) {
             }
         },
         function (cb) {
-            gljDao.getGljItems(info.gljLibId, info.userID, info.compilationId, function (err, data) {
+            gljDao.getGljItems(info.gljLibId, info.userID, info.compilationId, {_id: 0}, function (err, data) {
                 if (err) {
                     cb(err);
                 } else {

+ 1 - 1
modules/reports/util/rpt_pdf_util.js

@@ -154,7 +154,7 @@ function export_pdf_file (pageData, paperSize, fName, callback) {
                 // area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + i * (height / values.length) + offsetY;
                 // area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (height / values.length) + offsetY;
                 area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + i * (ah / values.length) + offsetY + restTopH;
-                area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (ah / values.length) + offsetY + restTopH;
+                area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (ah / values.length) + offsetY + restBottomH;
                 if (values[i] === null || values[i] === undefined || values[i] === 'null') {
                     values[i] = "";
                 }

+ 1 - 1
modules/std_billsGuidance_lib/facade/facades.js

@@ -40,7 +40,7 @@ async function getLibWithBills(libID){
     if(!billsLib){
         throw '引用的清单规则库不存在!';
     }
-    let bills = await stdBillsModel.find({billsLibId: billsLib.billsLibId}, '-_id');
+    let bills = await stdBillsModel.find({billsLibId: billsLib.billsLibId}, '-_id').lean();
     //return {guidanceLib: guidanceLib[0], bills};
     return {bills};
 }

+ 6 - 5
modules/users/controllers/login_controller.js

@@ -215,11 +215,12 @@ class LoginController {
             // }
 
             // 判断极验验证码是否通过
-            const captcha = new Captcha();
-            const captchResult = await captcha.validate(request);
-            if (!captchResult) {
-                throw '极验验证码错误';
-            }
+            // 先不使用,出现验证慢的情况
+            // const captcha = new Captcha();
+            // const captchResult = await captcha.validate(request);
+            // if (!captchResult) {
+            //     throw '极验验证码错误';
+            // }
 
             // 判断用户是否开启了只使用短信登录
             const userInfo = await userModel.findDataByAccount(userData.mobile);

+ 43 - 1
public/web/PerfectLoad.js

@@ -83,5 +83,47 @@ jQuery.bootstrapLoading = {
     },
     end: function () {
         $("#loadingPage").remove();
+    },
+    progressStop:true,
+    progressStart:async function(title="导出文件",autoBar = false){
+        if($("#progressModal").length == 0){
+            let phtml =    `<div class="modal fade" id="progressModal" data-backdrop="static">
+                            <div class="modal-dialog" role="document">
+                                <div class="modal-content">
+                                    <div class="modal-header">
+                                         <h5 class="modal-title" id="progress_modal_title">${title}</h5>
+                                    </div>
+                                     <div class="modal-body">
+                                        <!--正在生成-->
+                                        <h5 class="my-3" id="progress_modal_body">正在${title}</h5>
+                                        <div class="progress mb-3">
+                                        <div id="progress_modal_bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100" style="width: 10%"></div>
+                                        </div>
+                                     </div>
+                                   </div>
+                                </div>
+                            </div>`;
+            $("body").append(phtml);
+        }else {
+            $("#progress_modal_title").text(title);
+            $("#progress_modal_body").text(`正在${title}`);
+         }
+        $("#progress_modal_bar").css('width','0%');
+        $("#progressModal").modal('show');
+        if(autoBar == true){//假的进度条
+            $.bootstrapLoading.progressStop = false;
+            let width = 0;
+            while ($.bootstrapLoading.progressStop == false){
+                await  setTimeoutSync(null,1000);
+                width += 5;
+                if(width > 90) width -= 50;
+                $("#progress_modal_bar").css('width',`${width}%`);
+            }
+        }
+    },
+    progressEnd:function () {
+        $("#progress_modal_bar").css('width','100%');
+        $.bootstrapLoading.progressStop = true;
+        $("#progressModal").modal('hide');
     }
-}
+};

+ 4 - 1
public/web/gljUtil.js

@@ -357,12 +357,15 @@ let gljUtil = {
     },
     //是否从混凝土改成商品混凝土,并且混凝土的定额消耗量不为空,则原混凝土的自定义消耗改成0,插入一条新的商品混凝土自定义消耗量为原自定义或定额消耗
     isAddCommercialForReplace:function (oldType,newType,rationItemQuantity) {
-        return gljUtil.isConcreteType(oldType)&&gljUtil.isCommercialConcreteType(newType)&&rationItemQuantity&&rationItemQuantity!='0';
+        return gljUtil.isConcreteToCommercialConcrete(oldType,newType)&&rationItemQuantity&&rationItemQuantity!='0';
     },
     isMaterialType:function (type) {
        let materialType = [gljType.GENERAL_MATERIAL,gljType.GREEN_SEEDLING,gljType.PURCHASE_COMPONENT,gljType.COMMERCIAL_CONCRETE,gljType.COMMERCIAL_MORTAR];//可以添加材料计算的类型普通材料”、“绿化苗木”、“外购砼构件”、“商品混凝土”、“商品砂浆”
         return materialType.indexOf(type)!= -1
     },
+    isConcreteToCommercialConcrete:function (oldType,newType) {
+        return gljUtil.isConcreteType(oldType)&&gljUtil.isCommercialConcreteType(newType)
+    },
     hasComposition:function (ration_glj,isRationType) {//判断是否有组成物,有则返回true   现在主材类型的工料机也有可能有组成物。
         let type = isRationType==true? ration_glj.subType:ration_glj.type;
         if(gljUtil.notEditType.indexOf(type)!=-1||type==gljType.MAIN_MATERIAL){

+ 5 - 0
public/web/rpt_value_define.js

@@ -21,6 +21,7 @@ const JV = {
     NODE_DETAIL_FIELDS_EX: "从数据指标_拓展集合",
     NODE_BAND_COLLECTION: "布局框_集合",
     NODE_FORMULAS: "计算式_集合",
+    NODE_EVENTS: "事件_集合",
     NODE_DISCRETE_INFO: "离散信息",
     NODE_BILL_INFO: "账单式表_信息",
     NODE_BILL_CONTENT : "账单式表_数据",
@@ -263,6 +264,10 @@ const JV = {
     CAL_TYPE_PERCENTAGE: 0,
     CAL_TYPE_ABSTRACT: 1,
 
+    EVENT_TYPE: ["GRP_ON_CREATE", "FLOW_CONTENT_ON_CREATE"],
+    EVENT_IDX_GRP_ON_CREATE: 0,
+    EVENT_IDX_FLOW_CONTENT_ON_CREATE: 1,
+
     PAGE_ORIENTATION_V_FIRST: 0,
     PAGE_ORIENTATION_H_FIRST: 1,
 

+ 5 - 4
public/web/sheet/sheet_common.js

@@ -246,7 +246,6 @@ var sheetCommonObj = {
         }
         return result;
     },
-    //todo
     analyzePasteData: function(setting, pastedInfo) {
         var rst = [], propId = pastedInfo.cellRange.col, preStrIdx = 0, itemObj = {};//propId = 0 to proId = pastedInfo.cellRange.col, update by zhong
         for (var i = 0; i < pastedInfo.pasteData.text.length; i++) {
@@ -258,15 +257,17 @@ var sheetCommonObj = {
                     itemObj = {};
                 }
             } else if (pastedInfo.pasteData.text[i] === "\t" || pastedInfo.pasteData.text[i] === "\r") {
-                itemObj[setting.header[propId].dataCode] = pastedInfo.pasteData.text.slice(preStrIdx, i);
+                if (setting.header[propId]) {
+                    itemObj[setting.header[propId].dataCode] = pastedInfo.pasteData.text.slice(preStrIdx, i);
+                }
                 propId++;
                 preStrIdx = i + 1;
                 //if the last copied-cell were empty, should check whether the end of text
-                if (i == pastedInfo.pasteData.text.length - 1) {
+                if (i == pastedInfo.pasteData.text.length - 1 && setting.header[propId]) {
                     itemObj[setting.header[propId].dataCode] = pastedInfo.pasteData.text.slice(preStrIdx);
                     rst.push(itemObj);
                 }
-            } else if (i == pastedInfo.pasteData.text.length - 1) {
+            } else if (i == pastedInfo.pasteData.text.length - 1 && setting.header[propId]) {
                 itemObj[setting.header[propId].dataCode] = pastedInfo.pasteData.text.slice(preStrIdx);
                 rst.push(itemObj);
             }

+ 0 - 1
public/web/slideResize.js

@@ -118,7 +118,6 @@ const SlideResize = (function() {
             let cache = getLocalCache(`${module}${ele.attr('id')}Width`);
             if (cache) {
                 ele.css('width', cache);
-                console.log(ele)
             }
         }
         for (let resize of resizes) {

+ 6 - 6
test/unit/reports/test_rpt_test_template.js

@@ -39,7 +39,7 @@ let demoPrjId = - 1;
 // let demoRptId = 56; //24
 // let demoRptId = 36; //5.1
 // let demoRptId = 46; //5.5测试
-// let demoRptId = 49; //5.5
+let demoRptId = 49; //5.5
 // let demoRptId = 66; //5.4
 // let demoRptId = 67; //21-2
 // let demoRptId = 31; //21-1
@@ -47,7 +47,7 @@ let demoPrjId = - 1;
 // let demoRptId = 68; //01-2
 // let demoRptId = 71; //21-2
 // let demoRptId = 74; //22
-let demoRptId = 83; //02 预算
+// let demoRptId = 83; //02 预算
 // let demoRptId = 84; //02 清单
 
 let pagesize = "A4";
@@ -71,7 +71,7 @@ let userId_Leng = "5c3ffa9aa0a92732f41216e0"; //小冷User Id (养护的)
 // demoPrjId = 618; //PROD:
 // demoPrjId = 2580; //PROD:
 // demoPrjId = 815; //PROD:
-demoPrjId = 3261; //UAT:
+demoPrjId = 5289; //UAT:
 // demoPrjId = 738; //UAT:
 // demoPrjId = 670; //UAT: 清单项目
 //*/
@@ -136,9 +136,9 @@ test('测试 - 测试模板啦: ', function (t) {
                     if (pageRst) {
                         // fsUtil.writeObjToFile(pageRst, "D:/GitHome/YangHuCost/tmp/testBuiltPageResult_测试模板" + dt.getTime() + ".jsp");
                         // fsUtil.writeObjToFile(pageRst, "D:/GitHome/YangHuCost/tmp/testBuiltPageResult_测试模板.jsp");
-                        rpt_xl_util.exportExcel(pageRst, pagesize, "local_test_rpt_excel", true, null, null, function(uuidName){
-                            console.log("excel uuid: " + uuidName);
-                        });
+                        // rpt_xl_util.exportExcel(pageRst, pagesize, "local_test_rpt_excel", true, null, null, function(uuidName){
+                        //     console.log("excel uuid: " + uuidName);
+                        // });
                         // rpt_pdf_util.export_pdf_file(pageRst, pagesize, 'local_test_rpt_pdf', function(uuidName){
                         //     console.log("pdf uuid: " + uuidName);
                         // });

+ 2 - 8
web/building_saas/complementary_glj_lib/js/components.js

@@ -87,9 +87,7 @@ let componentOprObj = {
                         }
                     }
                     if(!isExist){
-                        if(clearChecked){
-                            gljList[i].isChecked = false;
-                        }
+                        gljList[i].isChecked = false;
                     }
                     else {
                         gljList[i].isChecked = true;
@@ -223,7 +221,6 @@ let componentOprObj = {
                     cacheSection.push(data[i]);
                 }
             }
-            sheetOpr.cleanSheet(me.workBook.getSheet(0), me.setting, -1);
             sheetOpr.showData(me.workBook.getSheet(0), me.setting, cacheSection, re.distTypeTree);
             me.workBook.getSheet(0).setRowCount(cacheSection.length);
             cacheSection = null;
@@ -236,7 +233,6 @@ let componentOprObj = {
             //添加选择添加的组成物
             let updateArr = [];
             let newComponent = [];
-            //re.currentGlj.component = [];
             for(let i = 0, len = me.selectedList.length; i < len; i++){
                 let isExist = false;
                 for(let j = 0, jLen = re.currentGlj.component.length; j < jLen; j++){
@@ -250,14 +246,12 @@ let componentOprObj = {
                 if(!isExist){
                     newComponent.push({isStd: typeof me.selectedList[i].isStd !== 'undefined' ? me.selectedList[i].isStd : false, ID: me.selectedList[i].ID, consumeAmt: 0});
                 }
-                //re.currentGlj.component.push({ID: me.selectedList[i].ID, consumeAmt: 0});
             }
             re.currentGlj.component = newComponent;
             let gljBasePrc = that.reCalGljBasePrc(re.getCurrentComponent(re.currentGlj.component));
             if(gljBasePrc !== re.currentGlj.basePrice){
                 re.currentGlj.basePrice = gljBasePrc;
                 re.reshowGljBasePrc(re.currentGlj);
-                //updateBasePrc.push({gljId: that.currentGlj.ID, gljType: that.currentGlj.gljType, basePrice: that.currentGlj.basePrice});
             }
             updateArr.push(re.currentGlj);
             that.updateComponent(updateArr);
@@ -282,7 +276,7 @@ let componentTypeTreeOprObj = {
     }
 }
 $(document).ready(function () {
-    $('#gljSearchKeyword').change(function () {
+    $('#gljSearchKeyword').bind('keyup', function () {
         componentOprObj.filterDatasAndShow();
     });
     $('#gljSearchKeyword').bind('keypress', function (e) {

+ 82 - 36
web/building_saas/complementary_glj_lib/js/glj.js

@@ -60,8 +60,10 @@ let pageOprObj = {
         //repositoryGljObj.getRationGljIds(gljLibId);
         repositoryGljObj.getGljDistType(function () {
             repositoryGljObj.currentRepositoryId = me.stdGljLibId;
-            repositoryGljObj.getGljItems(me.stdGljLibId, function () {
-                gljClassTreeObj.getGljClassTree(stdGljLibId);
+            gljClassTreeObj.getGljClassTree(stdGljLibId, function () {
+                repositoryGljObj.getGljItems(me.stdGljLibId, function () {
+                    gljClassTreeObj.initSelection(gljClassTreeObj.tree.selected);
+                });
             });
         });
     }
@@ -70,6 +72,10 @@ let pageOprObj = {
 let repositoryGljObj = {
     treeObj : null,
     workBook: null,
+    // 是否获取了完整的人材机数据
+    // 第一次打开页面只加载补充人材机和标准人材机的编码
+    // 第一次打开选择组成物的窗口才加载标准人材机剩余数据
+    pullCompleteData: false,
     gljCurTypeId: -1,
     currentRepositoryId: -1,
     currentCache: null,
@@ -83,7 +89,7 @@ let repositoryGljObj = {
         header:[
             {headerName:"编码",headerWidth:80,dataCode:"code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
             {headerName:"名称",headerWidth:160,dataCode:"name", dataType: "String", hAlign: "left", vAlign: "center"},
-            {headerName:"规格型号",headerWidth:120,dataCode:"specs", dataType: "String", hAlign: "left", vAlign: "center"},
+            {headerName:"规格型号",headerWidth:120,dataCode:"specs", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
             {headerName:"单位",headerWidth:45,dataCode:"unit", dataType: "String", hAlign: "center", vAlign: "center"},
             {headerName:"定额价",headerWidth:80,dataCode:"basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center"},
             {headerName:"类型",headerWidth:90,dataCode:"gljType", dataType: "String", hAlign: "center", vAlign: "center"},
@@ -179,8 +185,19 @@ let repositoryGljObj = {
         });
     },
     getGljItems: function(stdGljLibId, callback) {
-        let me = this;
-        CommonAjax.post('complementartGlj/api/getGljItems', {stdGljLibId: stdGljLibId}, function (rstData) {
+        let me = this,
+            // 一开始获取的标准人材机只包含code,提升打开页面速度
+            projection = {
+                _id: 0,
+                ID: 1,
+                code: 1,
+                unit: 1,
+                name: 1,
+                priceProperty: 1,
+                basePrice: 1
+            };
+        $.bootstrapLoading.start();
+        CommonAjax.post('/complementartGlj/api/getGljItems', {stdGljLibId, projection}, function (rstData) {
             me.stdGljList = rstData.stdGljs;
             //兼容多单价情况
             for(let sGlj of me.stdGljList){
@@ -188,14 +205,44 @@ let repositoryGljObj = {
                     sGlj.basePrice = sGlj.priceProperty.price1;
                 }
             }
-            me.complementaryGljList = rstData.complementaryGljs;
-            me.workBook.getSheet(0).setRowCount(me.stdGljList.length);
             me.sortGlj(me.stdGljList);
             me.setProp('isStd', true, me.stdGljList);
+            me.complementaryGljList = rstData.complementaryGljs;
             me.sortGlj(me.complementaryGljList);
             if(callback){
                 callback();
             }
+            $.bootstrapLoading.end();
+        }, function () {
+            $.bootstrapLoading.end();
+        });
+    },
+    // 获取标准人材机数据
+    getStdItems: function (stdGljLibId, callback) {
+        $.bootstrapLoading.start();
+        let me = this;
+        let projection = {
+            _id: 0,
+            ID: 1,
+            specs: 1,
+            gljType: 1,
+            shortName: 1,
+            gljClass: 1
+        };
+        CommonAjax.post('/complementartGlj/api/getStdItems', {stdGljLibId, projection}, function (data) {
+            me.pullCompleteData = true;
+            // 更新标准人材机数据
+            let IDMapping = {};
+            for (let glj of data) {
+                IDMapping[glj.ID] = glj;
+            }
+            for (let glj of me.stdGljList) {
+                Object.assign(glj, IDMapping[glj.ID]);
+            }
+            callback();
+            $.bootstrapLoading.end();
+        }, function () {
+            $.bootstrapLoading.end();
         });
     },
     showGljItems: function(data, type) {
@@ -283,32 +330,23 @@ let repositoryGljObj = {
     },
 
     getCurrentComponent: function (gljComponent) {
-        let me = repositoryGljObj, rst = [];
-        for(let i = 0; i < gljComponent.length; i++){
-            let obj = {};
-            for(let j = 0; j < me.complementaryGljList.length; j++){
-                if(gljComponent[i].ID == me.complementaryGljList[j].ID){
-                    obj.isStd = false;
-                    obj.ID = me.complementaryGljList[j].ID;
-                    obj.code = me.complementaryGljList[j].code;
-                    obj.name = me.complementaryGljList[j].name;
-                    obj.unit = me.complementaryGljList[j].unit;
-                    obj.basePrice = me.complementaryGljList[j].basePrice;
-                    obj.consumeAmt = gljComponent[i].consumeAmt;
-                    rst.push(obj);
-                }
-            }
-            for(let j = 0; j < me.stdGljList.length; j++){
-                if(gljComponent[i].ID == me.stdGljList[j].ID){
-                    obj.isStd = true;
-                    obj.ID = me.stdGljList[j].ID;
-                    obj.code = me.stdGljList[j].code;
-                    obj.name = me.stdGljList[j].name;
-                    obj.unit = me.stdGljList[j].unit;
-                    obj.basePrice = me.stdGljList[j].basePrice;
-                    obj.consumeAmt = gljComponent[i].consumeAmt;
-                    rst.push(obj);
-                }
+        let me = repositoryGljObj,
+            rst = [];
+        for(let thisGlj of gljComponent){
+            let toFindGljList = thisGlj.isStd
+                ? me.stdGljList
+                : me.complementaryGljList;
+            let matchGlj = toFindGljList.find(glj => glj.ID === thisGlj.ID);
+            if (matchGlj) {
+                rst.push({
+                    isStd: thisGlj.isStd ? true : false,
+                    ID: matchGlj.ID,
+                    code: matchGlj.code,
+                    name: matchGlj.name,
+                    unit: matchGlj.unit,
+                    basePrice: matchGlj.basePrice,
+                    consumeAmt: thisGlj.consumeAmt
+                });
             }
         }
         rst.sort(function (a, b) {
@@ -526,10 +564,18 @@ let repositoryGljObj = {
         }
     },
     onCellEditEnd: function(sender, args) {
-        let me = repositoryGljObj, that = gljComponentOprObj,
-            rObj = sheetOpr.combineRowData(me.workBook.getSheet(0), me.setting, args.row, me),
-            updateArr = [], addArr = [], updateBasePrcArr = [];
+        let me = repositoryGljObj, that = gljComponentOprObj;
+        // 输入编号、名称、规格时,如果输入回车符或粘贴回车符,提交时应转换为空格。
+        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.sheet.setValue(args.row, args.col, args.editingText);
+        }
+        let rObj = sheetOpr.combineRowData(me.workBook.getSheet(0), me.setting, args.row, me),
+            updateArr = [],
+            addArr = [],
+            updateBasePrcArr = [];
         me.editingRowIdx = args.row;
         rObj.basePrice = rObj.basePrice ? rObj.basePrice : 0;
         //更新

+ 1 - 15
web/building_saas/complementary_glj_lib/js/gljClassTree.js

@@ -111,7 +111,6 @@ let gljClassTreeObj = {
     },
 
     getGljClassTree: function (gljLibId, callback) {
-        console.log('enter1');
         let me = gljClassTreeObj;
         let re = repositoryGljObj;
         let url = '/complementartGlj/api/getMixedTree';
@@ -119,11 +118,6 @@ let gljClassTreeObj = {
         let sucFunc = function (rstData) {
             me.treeData = rstData;
             let compleTreeData = me.treeData.comple;
-            /*zTreeHelper.createTree(rstData.std, componentSetting, "componentTree", componentOprObj);
-            let rootNode = componentOprObj.treeObj.getNodes()[0];
-            if(rootNode && rootNode.isParent && rootNode.isFirstNode){
-                componentOprObj.rootNode = rootNode;
-            }*/
             if (compleTreeData && compleTreeData.length > 0) {
                 me.gljCurTypeId = compleTreeData[0].ID;
             }
@@ -135,15 +129,11 @@ let gljClassTreeObj = {
             me.initController(me.tree, me.sheet, me.setting.sheet);
             me.controller.showTreeData();
             me.sheet.setFormatter(-1, 0, '@');
-            me.initSelection(me.tree.selected);
             if(callback){
                 callback();
             }
         };
-        let errFunc = function () {
-
-        };
-        CommonAjax.post(url, postData, sucFunc, errFunc);
+        CommonAjax.post(url, postData, sucFunc);
     },
 
     initTree: function (datas) {
@@ -155,10 +145,6 @@ let gljClassTreeObj = {
     initController: function (tree, sheet, setting) {
         this.controller = TREE_SHEET_CONTROLLER.createNew(tree, sheet, setting);
     },
-
-    gljClassTreeAjax: function (postData, scFunc, errFunc) {
-        CommonAjax.post('api/updateNodes', {updateData: postData, lastOpr: userAccount}, scFunc, errFunc);
-    },
     //模仿默认点击
     initSelection: function (node) {
         let me = this,

+ 14 - 7
web/building_saas/complementary_glj_lib/js/gljComponent.js

@@ -92,13 +92,20 @@ let gljComponentOprObj = {
                         callback: function(){},
                         items: {
                             "insert": {name: "插入", disabled: insertDis, icon: "fa-sign-in", callback: function (key, opt) {
-                                //默认radio所有工料机
-                                co.initRadio();
-                                co.gljCurTypeId = null;
-                                //默认点击树根节点
-                                co.initClassTree('std', gljClassTreeObj.treeData.std);
-                                //弹出窗口
-                                $('#component').modal('show');
+                                let oprFunc = function () {
+                                    //默认radio所有工料机
+                                    co.initRadio();
+                                    co.gljCurTypeId = null;
+                                    //默认点击树根节点
+                                    co.initClassTree('std', gljClassTreeObj.treeData.std);
+                                    //弹出窗口
+                                    $('#component').modal('show');
+                                };
+                                if (repositoryGljObj.pullCompleteData) {
+                                    oprFunc();
+                                } else {
+                                    repositoryGljObj.getStdItems(pageOprObj.stdGljLibId, oprFunc);
+                                }
                             }},
                             "delete": {name: "删除", disabled: delDis, icon: "fa-remove", callback: function (key, opt) {
                                 //删除

+ 1 - 0
web/building_saas/complementary_glj_lib/js/sheetOpr.js

@@ -43,6 +43,7 @@ let sheetOpr = {
         spreadBook.options.allowCopyPasteExcelStyle = false;
         spreadBook.options.allowExtendPasteRange = true;
         spreadBook.options.allowUserDragDrop = false;
+        spreadBook.options.allowUserDragFill = false;
         spreadBook.options.allowContextMenu = false;
         var spreadNS = GC.Spread.Sheets;
         var sheet = spreadBook.getSheet(0);

+ 26 - 25
web/building_saas/complementary_ration_lib/js/ration.js

@@ -170,6 +170,9 @@ let rationOprObj = {
     isInt: function (num) {
         return !isNaN(num) && num % 1 === 0;
     },
+    isDef: function (v) {
+        return v !== undefined && v !== null;
+    },
     getCache: function() {
         let me = this, rst = me.currentRations["_SEC_ID_" + me.currentSectionId];
         if (!(rst)) {
@@ -417,13 +420,17 @@ let rationOprObj = {
         }
     },
     onCellEditEnd: function(sender, args) {
-        let edV = args.sheet.getValue(args.row, args.col);
-        if(edV){
-            args.sheet.setValue(args.row, args.col, edV.toString().trim());
-        }
-        let me = rationOprObj, rObj = sheetsOprObj.combineRationRowData(me.workBook.getSheet(0), me.setting, args.row),
-            updateArr = [], addArr = [];
+        let me = rationOprObj;
+        // 输入编号、名称、单位时,如果输入回车符或粘贴回车符,提交时应转换为空格。
         let dataCode = me.setting.header[args.col].dataCode;
+        let deESCFields = ['code', 'name', 'unit'];
+        if(deESCFields.includes(dataCode)){
+            args.editingText = me.isDef(args.editingText) ? args.editingText.toString().replace(/[\r, \n]/g, ' ') : '';
+            args.sheet.setValue(args.row, args.col, args.editingText);
+        }
+        let rObj = sheetsOprObj.combineRationRowData(me.workBook.getSheet(0), me.setting, args.row),
+            updateArr = [],
+            addArr = [];
         me.editingRowIdx = args.row;
         if (me.currentEditingRation["ID"]) {
             if((!args.editingText || args.editingText.toString().trim().length === 0) && args.col === 0){
@@ -498,16 +505,21 @@ let rationOprObj = {
         }
     },
     canPasted: function (beginCol, maxCol) {
-        let rst = false;
-        if(maxCol < 3 || beginCol > 6){
-            rst = true;
-        }
-        return rst;
+        let me = rationOprObj;
+        // 粘贴的列不可包含不可编辑的“基价”列
+        // 粘贴的最大列不可超出表格的最大列
+        if (me.canRations &&
+            (maxCol < 3 ||
+            (beginCol > 3 && maxCol <= me.setting.header.length - 1))
+        ) {
+            return true;
+        }
+        return false;
     },
     onClipboardPasting: function(sender, args) {
         let me = rationOprObj;
         let maxCol = args.cellRange.col + args.cellRange.colCount -1;
-        if(!me.canRations || !me.canPasted(args.cellRange.col, maxCol) || maxCol > me.setting.header.length - 1){
+        if (!me.canPasted(args.cellRange.col, maxCol)) {
             args.cancel = true;
         }
     },
@@ -714,49 +726,38 @@ let rationOprObj = {
             sheetGLJ = rationGLJOprObj.sheet, settingGLJ = rationGLJOprObj.setting,
             sheetCoe = rationCoeOprObj.sheet, settingCoe = rationCoeOprObj.setting,
             sheetAss = rationAssistOprObj.sheet, settingAss = rationAssistOprObj.setting;
-            //sheetInst = rationInstObj.sheet, settingInst = rationInstObj.setting;
         if (me.workBook) {
-            if (me.currentRations && me.currentRations["_SEC_ID_" + sectionID] && me.currentRations["_SEC_ID_" + sectionID].length > 0) {
+            sheetCommonObj.cleanData(me.workBook.getSheet(0), me.setting, -1);
+            if (me.currentRations && me.currentRations["_SEC_ID_" + sectionID]) {
                 let cacheSection = me.currentRations["_SEC_ID_" + sectionID];
-                sheetCommonObj.cleanData(me.workBook.getSheet(0), me.setting, -1);
                 sheetsOprObj.showData(me.workBook.getSheet(0), me.setting, cacheSection);
-                //combo
-                //sheetCommonObj.setStaticCombo(me.workBook.getActiveSheet(), 0, 2, cacheSection.length, rationUnits, 10, false);
-                //--sheetCommonObj.setDynamicCombo(me.workBook.getActiveSheet(), 0, 2, me.workBook.getActiveSheet().getRowCount(), rationUnits, 10, false);
                 if(me.mixDel === 1){
                     let row = me.workBook.getSheet(0).getSelections()[0].row;
                     if (cacheSection && row < cacheSection.length) {
                         sheetCommonObj.cleanData(sheetGLJ, settingGLJ, -1);
                         sheetCommonObj.cleanData(sheetCoe, settingCoe, -1);
                         sheetCommonObj.cleanData(sheetAss, settingAss, -1);
-                        //sheetCommonObj.cleanData(sheetInst, settingInst, -1);
                         rationGLJOprObj.getGljItems(cacheSection[row]);
                         rationCoeOprObj.getCoeItems(cacheSection[row]);
                         rationAssistOprObj.getAssItems(cacheSection[row]);
-                        //rationInstObj.getInstItems(cacheSection[row]);
                     }
                     else {
                         rationGLJOprObj.currentRationItem = null;
                         sheetCommonObj.cleanData(sheetGLJ, settingGLJ, -1);
                         sheetCommonObj.cleanData(sheetCoe, settingCoe, -1);
                         sheetCommonObj.cleanData(sheetAss, settingAss, -1);
-                        //sheetCommonObj.cleanData(sheetInst, settingInst, -1);
                         sheetCommonObj.setDynamicCombo(sheetAss, 0, 5, sheetAss.getRowCount(), rationAssistOprObj.setting.comboItems, false, false);
                     }
                 }
 
             } else {
                 sheetCommonObj.setDynamicCombo(sheetAss, 0, 5, sheetAss.getRowCount(), rationAssistOprObj.setting.comboItems, false, false);
-                //--sheetCommonObj.setDynamicCombo(me.workBook.getActiveSheet(), 0, 2, me.workBook.getActiveSheet().getRowCount(), rationUnits, 10, false);
                 //清除ration数据及工料机数据
                 rationGLJOprObj.currentRationItem = null;
-                sheetCommonObj.cleanSheet(me.workBook.getSheet(0), me.setting, -1);
                 sheetCommonObj.cleanSheet(sheetGLJ, settingGLJ, -1);
                 sheetCommonObj.cleanSheet(sheetCoe, settingCoe, -1);
                 sheetCommonObj.cleanSheet(sheetAss, settingAss, -1);
-                //sheetCommonObj.cleanSheet(sheetInst, settingInst, -1);
             }
-            //--- me.workBook.focus(true);
         }
         sectionTreeObj.workBook.focus(true);
     },

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

@@ -319,4 +319,8 @@ input.text-right{
     display: none;
     color: #43CD80;
     margin-left: 8px
+}
+/*占位底色*/
+.occupied {
+    background: #f1f1f1;
 }

二進制
web/building_saas/img/NextPage.cur


二進制
web/building_saas/img/PreviousPage.cur


+ 6 - 1
web/building_saas/js/global.js

@@ -156,4 +156,9 @@ function setTimeoutSync(handle, time) {
             resolve();
         }, time);
     });
-}
+}
+
+async function progressStart(title,autoProgress = false){
+
+}
+

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

@@ -41,6 +41,7 @@
         let userID = '<%- userID %>';
         let projectReadOnly = JSON.parse('<%- projectReadOnly %>');
         let projectCooperate = JSON.parse('<%- projectCooperate %>');
+        let projectOptins =  JSON.parse('<%- options %>');
         const G_SHOW_BLOCK_LIB = false;
 //        const G_SHOW_BLOCK_LIB = false;
     </script>
@@ -160,9 +161,9 @@
                           </li>
 
                           <li class="nav-item dropdown">
-                              <a class="nav-link dropdown-toggle more" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" style="display:none">更多</a>
+                              <a class="nav-link dropdown-toggle more" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" >更多</a>
                               <div class="dropdown-menu" id="div_more_dropdown_right">
-                                  <!--<a class="dropdown-item  right-nav-link"  href="javascript:void(0)" id = 'locateTab' relaPanel="#locate">查找定位</a>-->
+                                  <a class="dropdown-item  right-nav-link"  href="javascript:void(0)" id = 'locateTab' relaPanel="#locate">查找定位</a>
                                   <!--<a class="dropdown-item" data-toggle="tab" href="#sqpz" role="tab">书签批注</a>-->
                                   <script>
                                       //2018-11-23  zhang 模板库移动到更多下拉框
@@ -334,7 +335,7 @@
                                   <div class="sidebar-tools-bar container-fluid tools-bar-height-y" id="searchPanel">
                                       <div class="p-1 row">
                                           <div class="input-group input-group-sm col-12">
-                                              <input type="text" class="form-control form-control-sm" placeholder="查找内容" value="">
+                                              <input type="text" class="form-control form-control-sm" placeholder="查找内容" id="locateInput" value="">
                                               <div class="input-group-append">
                                                   <button class="btn btn-secondary btn-sm" type="button" id="locate_btn"><i class="fa fa-search" aria-hidden="true"></i></button>
                                               </div>
@@ -352,50 +353,108 @@
                                                   <input class="form-check-input" type="radio" name="content_type" id="raion_glj" value="ration_glj">
                                                   <label class="form-check-label" for="raion_glj">工料机</label>
                                               </div>
-                                              <!--<div class="form-check form-check-inline">
-                                                  <input class="form-check-input" type="radio" name="inlineRadioOptions" id="bookmark" value="option4">
-                                                  <label class="form-check-label" for="bookmark">书签注</label>
-                                              </div>-->
+                                              <div class="form-check form-check-inline">
+                                                  <input class="form-check-input" type="radio" name="content_type" id="bookmark" value="bookmark">
+                                                  <label class="form-check-label" for="bookmark">书签注</label>
+                                              </div>
                                           </div>
                                           <!--搜索分项/清单 出现-->
                                           <div class="col-12"  id="outstandingOptions">
                                               <div class="form-group form-check mb-0">
                                                   <input type="checkbox" class="form-check-input" id ="outstanding">
-                                                  <label class="form-check-label" for="outstanding">超 <input type="number" style="width:50px"> % 时突出显示</label>
+                                                  <label class="form-check-label" for="outstanding">超 <input id="outInp" type="number" style="width:50px"> % 时突出显示</label>
                                               </div>
                                           </div>
                                       </div>
                                   </div>
-                                  <!--上下结构-->
-                                  <div class="top-content" id="locateTopDiv" style="overflow: hidden">
-                                      <div class="" id="locate_result" >
+                                  <div id="aboutLocateDiv">
+                                      <!--上下结构-->
+                                      <div class="top-content" id="locateTopDiv" style="overflow: hidden">
+                                          <div class="" id="locate_result" >
+                                          </div>
+                                      </div>
+                                      <div class="resize-y" id="locate_resize"></div>
+                                      <div class="bottom-content" id="locateBottomDiv">
+                                          <div class="" id="locate_sub"></div>
                                       </div>
                                   </div>
-                                  <div class="resize-y" id="locate_resize"></div>
-                                  <div class="bottom-content" id="locateBottomDiv">
-                                      <div class="" id="locate_sub"></div>
-                                  </div>
-                                <!--  <div class="main-data-side-y">
-                                      <table class="table table-sm table-bordered">
-                                          <tr><th>编码</th><th>项目名称</th><th>工程量</th><th>单位</th><th>综合单价</th><th>综合合价</th></tr>
-                                      </table>
-                                  </div>
-                                  <div class="sidebar-bottom container-fluid">
-                                      <div class="row">
-                                          <div class="col-lg-12">
-                                              <table class="table table-sm table-bordered">
-                                                  <tr><th>定额编号</th><th>定额名称</th></tr>
-                                                  <tr><td>AA0047</td><td>人工沟槽 较硬岩 槽深4m以内</td></tr>
-                                                  <tr><td>AA0005</td><td>人工挖沟槽土方 槽深4m以内</td></tr>
-                                              </table>
+                                  <div id="aboutBookmarkDiv" style="display: none">
+                                      <!--上下结构-->
+                                      <div id="bookmarkTopDiv">
+                                          <div class="sidebar-tools-bar container-fluid tools-bar-height-q">
+                                              <div class="p-1 row" style="padding-top:0px!important">
+                                                  <div class="dropdown" id="bookmarkSettingDropdown">
+                                                      <button class="btn btn-sm btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+                                                          书签设置
+                                                      </button>
+                                                      <form class="dropdown-menu p-2" id = "bookmarkSettingForm" onsubmit="return false;">
+                                                          <input type="hidden" id="bookmarkSelected">
+                                                          <div id="bookmarkSettingList">
+                                                              <div class="input-group input-group-sm mb-2" style="width:200px">
+                                                                  <div class="input-group-prepend">
+                                                                      <span class="input-group-text annotate-color-1">&nbsp;&nbsp;&nbsp;&nbsp;</span>
+                                                                  </div>
+                                                                  <input type="text" class="form-control" placeholder="描述">
+                                                             </div>
+                                                              <div class="input-group input-group-sm mb-2">
+                                                                  <div class="input-group-prepend">
+                                                                      <span class="input-group-text annotate-color-2">&nbsp;&nbsp;&nbsp;&nbsp;</span>
+                                                                  </div>
+                                                                  <input type="text" class="form-control" id="E2F2C5" placeholder="描述">
+                                                              </div>
+                                                              <div class="input-group input-group-sm mb-2">
+                                                                  <div class="input-group-prepend">
+                                                                      <span class="input-group-text annotate-color-3">&nbsp;&nbsp;&nbsp;&nbsp;</span>
+                                                                  </div>
+                                                                  <input type="text" class="form-control" placeholder="描述">
+                                                              </div>
+                                                              <div class="input-group input-group-sm mb-2">
+                                                                  <div class="input-group-prepend">
+                                                                      <span class="input-group-text annotate-color-4">&nbsp;&nbsp;&nbsp;&nbsp;</span>
+                                                                  </div>
+                                                                  <input type="text" class="form-control" placeholder="描述">
+                                                              </div>
+                                                              <div class="input-group input-group-sm mb-2">
+                                                                  <div class="input-group-prepend">
+                                                                      <span class="input-group-text annotate-color-5">&nbsp;&nbsp;&nbsp;&nbsp;</span>
+                                                                  </div>
+                                                                  <input type="text" class="form-control" placeholder="描述">
+                                                              </div>
+                                                              <div class="input-group input-group-sm mb-2">
+                                                                  <div class="input-group-prepend">
+                                                                      <span class="input-group-text annotate-color-6">&nbsp;&nbsp;&nbsp;&nbsp;</span>
+                                                                  </div>
+                                                                  <input type="text" class="form-control" placeholder="描述">
+                                                              </div>
+                                                              <div class="input-group input-group-sm mb-2">
+                                                                  <div class="input-group-prepend">
+                                                                      <span class="input-group-text annotate-color-7">&nbsp;&nbsp;&nbsp;&nbsp;</span>
+                                                                  </div>
+                                                                  <input type="text" class="form-control" placeholder="描述">
+                                                              </div>
+                                                          </div>
+                                                          <button  class="btn btn-sm btn-primary" id = "bookmarkSettingConfirm">确定</button>
+                                                      </form>
+                                                  </div>
+                                              </div>
                                           </div>
+                                          <div class="" id = "bookmarkSpread" style="overflow: hidden"></div>
                                       </div>
-                                  </div>-->
-
+                                      <div class="resize-y" id="bookmark_resize"></div>
+                                      <div class=" container-fluid" id="annotationDiv">
+                                          <div class="row">
+                                              <div class="col-lg-12" style="padding: 0px" >
+                                                  <input type="hidden" id="bookmarkNodeID">
+                                                  <input type="hidden" id="bookmarkNodeType">
+                                                  <textarea class="form-control" id="annotationTextarea"  placeholder = "批注内容"></textarea>
+                                              </div>
+                                          </div>
+                                      </div>
+                                  </div>
                               </div>
 
                               <!--清单指引-->
-                              <div class="tab-pane" id="zy">
+                              <div class="tab-pane occupied" id="zy">
                                   <div class="sidebar-tools-bar container-fluid tools-bar-height-z">
                                       <div class="p-1 row">
                                           <div class="col p-0">

+ 44 - 11
web/building_saas/main/js/models/calc_program.js

@@ -113,7 +113,7 @@ let calcTools = {
         delete treeNode.data.gljList;
         if (this.isRationCategory(treeNode)) {
             if (treeNode.data.type != rationType.volumePrice) {
-                treeNode.data.gljList = projectObj.project.ration_glj.getGljArrByRation(treeNode.data);
+                treeNode.data.gljList = projectObj.project.calcProgram.getGljArrByRation(treeNode.data);
             }
         }
         else if (this.isBill(treeNode)){
@@ -1409,6 +1409,8 @@ class CalcProgram {
         let me = this;
         me.project = project;
         me.datas = [];
+        me.rationMap = null;//定额 - 工料机映射临时变量
+        me.pgljMap = null;
         project.registerModule(ModuleNames.calc_program, me);
     };
 
@@ -1631,6 +1633,8 @@ class CalcProgram {
         };
 
         let me = this;
+        //设置定额工料机映射表
+        me.setRationMap();
         me.setUpdateDataToNode(treeNode);                                       // 先更新要计算的节点信息
         if(!treeNode.temData) treeNode.temData = _.cloneDeep(treeNode.data);    // 有可能会有多次计算,只有第一次才保存原始数据,用来对于更新。
 
@@ -1875,15 +1879,14 @@ class CalcProgram {
             return;
         };
         $.bootstrapLoading.start();
-        let startTime = +new Date();
         me.project.updateNodes(dataArr, function (data) {
-            let endShowTime = +new Date();
-            console.log(`保存所需时间——${endShowTime - startTime}`);
             for (let node of treeNodes){
                 delete node.changed;
                 delete node.temData;
                 node.updateData = {};
             };
+            me.rationMap = null;
+            me.pgljMap = null;
             if(callback){
                 callback(data);
             };
@@ -1981,7 +1984,7 @@ class CalcProgram {
                 rationNodes.push(node)
             else
                 billNodes.push(node);
-        };
+        }
 
         // 多条定额同属一条叶子清单时,避免叶子清单重复计算
         for (let ration of rationNodes) {
@@ -1989,14 +1992,14 @@ class CalcProgram {
             let leafBill = ration.parent;
             if (leafBill && leafBills.indexOf(leafBill) < 0)
                 leafBills.push(leafBill);
-        };
+        }
 
         billNodes.merge(leafBills);
 
         for (let bill of billNodes){
             let changeBills = me.calculate(bill, true, false, tender);
             allChangedNodes.merge(changeBills);
-        };
+        }
 
         me.calcFormulaNodes(allChangedNodes, tender);
         me.saveNodes(allChangedNodes, callback);
@@ -2020,10 +2023,10 @@ class CalcProgram {
                     while (curNode){
                         me.innerCalc(curNode, changedArr, tender);
                         curNode = curNode.parent;
-                    };
-                };
-            };
-        };
+                    }
+                }
+            }
+        }
     };
 
     // 计算叶子清单下的所有子结点、自身、所有父结点、公式引用结点(即跟该叶子清单相关的所有结点)。最后打包存储。
@@ -2134,6 +2137,36 @@ class CalcProgram {
 
 
     };
+
+    setRationMap(){
+        if(this.rationMap == null){
+            this.rationMap = {};
+            for(let glj of projectObj.project.ration_glj.datas){
+                if(this.rationMap[glj.rationID]){
+                    this.rationMap[glj.rationID].push(glj)
+                }else {
+                    this.rationMap[glj.rationID] = [glj];
+                }
+            }
+        }
+        if(this.pgljMap == null ){
+            this.pgljMap = _.indexBy(projectObj.project.projectGLJ.datas.gljList, 'id');
+        }
+    };
+    getGljArrByRation(ration){
+        if (ration.type == rationType.gljRation){
+            let glj = JSON.parse(JSON.stringify(ration));
+            glj.type = glj.subType;
+            glj.quantity = 1;
+            glj.totalQuantity = parseFloatPlus(ration.quantity);
+            return [glj];
+        } else{
+            if(!this.rationMap) return [];
+            let result = this.rationMap[ration.ID];
+            result = gljOprObj.combineWithProjectGlj(result,false,ration,this.pgljMap);
+            return result;
+        }
+    }
 };
 
 // export default analyzer;

+ 8 - 2
web/building_saas/main/js/models/project_glj.js

@@ -44,8 +44,7 @@ ProjectGLJ.prototype.loadData = function (callback = null,error=null) {
                 if(error) error();
                 return false;
             }
-            self.datas = response.data;
-            self.calcQuantity();
+            self.refreshByDatas(response.data);
             // 回调函数
             if (callback !== null) {
                 callback(response.data);
@@ -56,6 +55,13 @@ ProjectGLJ.prototype.loadData = function (callback = null,error=null) {
     });
 };
 
+//更新项目工料机数据和缓存
+ProjectGLJ.prototype.refreshByDatas = function(datas){
+    this.datas = datas;
+    this.calcQuantity();
+};
+
+
 ProjectGLJ.prototype.synLoadData = function () {
     return new Promise(function (resolve, reject) {
         projectObj.project.projectGLJ.loadData(function (data) {

+ 20 - 13
web/building_saas/main/js/models/ration.js

@@ -392,8 +392,14 @@ var Ration = {
             if(libIDs == null){
                 return;
             }
-            //设置定额库的优先级,默认先取选中的定额库,如果没有再取default定额库
-            let selectedLib = sessionStorage.getItem("stdRationLib");
+            //设置定额库的优先级, 当是清空子目换算时,使用原定额的定额库ID,其它情况再按: 默认先取选中的定额库,如果没有再取default定额库
+            let selectedLib = null;
+            if(cleanzmhs == true && recodes.length > 0){
+                //原定额的定额库是补充工料机库,则用补充的库代替,不是的用原始定额库ID
+                selectedLib = recodes[0].node.data.from == "cpt"?rationLibObj.compleRationLibId:recodes[0].node.data.libID;
+            }else {
+                selectedLib =  sessionStorage.getItem("stdRationLib")
+            }
             selectedLib&&selectedLib!='undefined'?libIDs.unshift(selectedLib):libIDs.unshift(defaultLibID);
             for(let r of recodes){
                 let needInstall = false;
@@ -558,6 +564,7 @@ var Ration = {
             let billItemID = null,serialNo=1,nextID=null;
             let needInstall = false;
             if (selected === null) { return null; }
+            let startTime = +new Date();
             if (selected.sourceType === project.Bills.getSourceType() && selected.depth() > 0) {
                 if(selected.data.type === billType.FB){
                     return null;
@@ -607,18 +614,18 @@ var Ration = {
                         syncNodeOper(data);
                         if(callback) callback(newNode);
                     }else {
-                        project.projectGLJ.loadData(function () {
-                            syncNodeOper(data);
-                            if (newNode.parent.data.calcFlag)        // 删除定额时不用改Flag,反正添加定额时已经改好了。
-                                newNode.parent.updateData.calcFlag = null;
-                            project.calcProgram.calcAndSave(newNode,function () {
-                                if(project.Bills.isFBFX(newNode)) { //判断是否属于分部分项工程 ,是的话才需要做计取安装费计算
-                                    installationFeeObj.calcInstallationFee();
-                                }
-                            });
-                            //如果添加规则中,添加内容为定额子目,则更新相关清单
-                            if(callback) callback(newNode);
+                        if(data.projectGLJDatas) projectObj.project.projectGLJ.refreshByDatas(data.projectGLJDatas);
+                        syncNodeOper(data);
+                        if (newNode.parent.data.calcFlag)  newNode.parent.updateData.calcFlag = null;    // 删除定额时不用改Flag,反正添加定额时已经改好了。
+                        project.calcProgram.calcAndSave(newNode,function () {
+                            let endShowTime = +new Date();
+                            console.log(`插入定额总时间——${endShowTime - startTime}`);
+                            if(project.Bills.isFBFX(newNode)) { //判断是否属于分部分项工程 ,是的话才需要做计取安装费计算
+                                installationFeeObj.calcInstallationFee();
+                            }
                         });
+                        //如果添加规则中,添加内容为定额子目,则更新相关清单
+                        if(callback) callback(newNode);
                     }
                     $.bootstrapLoading.end();
                 });

+ 1 - 4
web/building_saas/main/js/models/ration_coe.js

@@ -197,7 +197,7 @@ var ration_coe = {
                 CommonAjax.post("/ration/updateCoeAdjust",updateData,function (result) {
                     $.bootstrapLoading.end();
                     me.refreshAfterUpdate(result.coe);
-                    zmhs_obj.refreshAfterUpdate(result,true)
+                    zmhs_obj.refreshAfterUpdate(result)
                 })
             });
 
@@ -229,9 +229,6 @@ var ration_coe = {
             }
         };
 
-
-
-
         ration_coe.prototype.updateCustomerCoe = function (data) {
             var updateData = this.getUpdateData('ut_update',data.query,data.doc,'updateCustomerCoe');
             project.pushNow('updateCustomerCoe',[this.getSourceType()],updateData);

+ 2 - 24
web/building_saas/main/js/models/ration_glj.js

@@ -40,27 +40,6 @@ let ration_glj = {
             this.datas = datas;
         };
 
-        ration_glj.prototype.getGljArrByRation = function (ration) {
-            if (ration.type == rationType.gljRation){
-                let glj = JSON.parse(JSON.stringify(ration));
-                glj.type = glj.subType;
-                glj.quantity = 1;
-                glj.totalQuantity = parseFloatPlus(ration.quantity);
-                return [glj];
-            }
-            else{
-                let result = this.datas.filter(function (data) {
-                    if(data.rationID === ration.ID){
-                        gljOprObj.getTotalQuantity(data, ration);
-                        return true;
-                    }
-                    return false;
-                })
-                result = gljOprObj.combineWithProjectGlj(result);
-                return result;
-            }
-        };
-
         ration_glj.prototype.getGLJListByRationID = function (rationID) {
             return  _.filter(this.datas, {'rationID': rationID})
         };
@@ -93,9 +72,8 @@ let ration_glj = {
                     glj.basePrice = glj.marketUnitFee;
                     glj.adjustPrice = glj.marketUnitFee;
                     result.push(glj);
-                }
-                else{
-                    let rationGljs = this.getGljArrByRation(ration);
+                } else{
+                    let rationGljs = projectObj.project.calcProgram.getGljArrByRation(ration);
                     for (let glj of rationGljs) {
                         let sameGlj = findGlj(glj, result);
                         if (!sameGlj) {

+ 6 - 4
web/building_saas/main/js/views/character_content_view.js

@@ -204,11 +204,12 @@ let contentOprObj = {
         if(args.sheet.isEditing()){
             args.sheet.endEdit(true);
         }
+        let isChecked = args.sheet.getValue(args.row, args.col);
+        // 锁定清单值不变
         if(projectObj.project.projectInfo.property.lockBills && projectObj.project.withinBillsLocked(projectObj.project.mainTree.selected)){
-            args.sheet.setValue(args.row, args.col, 0);
+            args.sheet.setValue(args.row, args.col, !isChecked);
             return;
         }
-        let isChecked = args.sheet.getValue(args.row, args.col);
         if(me.currentCache.length > args.row){
             me.currentCache[args.row].isChecked = isChecked;
             me.save();
@@ -766,11 +767,12 @@ let characterOprObj = {
         if(args.sheet.isEditing()){
             args.sheet.endEdit(true);
         }
+        let isChecked = args.sheet.getValue(args.row, args.col);
+        // 锁定清单值不变
         if(projectObj.project.projectInfo.property.lockBills && projectObj.project.withinBillsLocked(projectObj.project.mainTree.selected)){
-            args.sheet.setValue(args.row, args.col, 0);
+            args.sheet.setValue(args.row, args.col, !isChecked);
             return;
         }
-        let isChecked = args.sheet.getValue(args.row, args.col);
         if(me.currentCache.length > args.row){
             me.currentCache[args.row].isChecked = isChecked;
             me.save();

+ 38 - 12
web/building_saas/main/js/views/glj_view.js

@@ -702,27 +702,28 @@ var gljOprObj = {
         }
         this.sheetData = newList;
     },
-    combineWithProjectGlj: function (ration_gljs,needRatio=true) {
+    combineWithProjectGlj: function (ration_gljs,needRatio=true,ration,p_gljMap) {
         let projectGLJData = projectObj.project.projectGLJ.datas;
         let projectGljs = projectGLJData.gljList;
         let mixRatioMap = projectGLJData.mixRatioMap;
         if (ration_gljs && ration_gljs.length > 0 && projectGljs && projectGljs.length > 0) {
-
+            let pgljMap = p_gljMap?p_gljMap:_.indexBy(projectGljs, 'id');
             for (let i = 0; i < ration_gljs.length; i++) {
-                let glj = _.find(projectGljs, {'id': ration_gljs[i].projectGLJID});
+                let glj = pgljMap[ration_gljs[i].projectGLJID];
                 if (glj) {
                     if(projectObj.project.projectGLJ.isEstimateType(ration_gljs[i].type )){
                         ration_gljs[i].isEstimate = glj.is_evaluate;
                     }
                     ration_gljs[i].shortName =projectObj.project.projectGLJ.getShortNameByID(ration_gljs[i].type);
                     ration_gljs[i].isAdd = glj.unit_price.is_add;
-                    ration_gljs[i]=this.setGLJPrice(ration_gljs[i],glj);//设置工料机价格
+                    ration_gljs[i]=this.setGLJPrice(ration_gljs[i],glj,false);//设置工料机价格
                     delete ration_gljs[i].subList; //置空,再设置
                     let connect_index = this.getIndex(glj, gljKeyArray);
                     if (needRatio==true&&mixRatioMap.hasOwnProperty(connect_index)) {
                         let mixRatios = this.getMixRationShowDatas(mixRatioMap[connect_index], projectGljs);
                         ration_gljs[i].subList = mixRatios;
                     }
+                    if(ration) gljOprObj.getTotalQuantity(ration_gljs[i], ration);
                 }
             }
         }
@@ -1148,12 +1149,37 @@ var gljOprObj = {
             });//doc.rationID=selected.data.ID;
         }
     },
-    doReplaceGLJ: function () {
+    concreteTypeReplaceChecking:function (selectCode, oldData,selected) {//selected为空,表示批量替换   混凝土替换前的检查,是否给出确认提示
+        let allGLJ = gljOprObj.AllRecode;
+        let glj = _.find(allGLJ, function (item) {
+            let i_key = gljOprObj.getIndex(item, gljLibKeyArray);
+            return i_key == selectCode;
+        });
+        if(! glj) return false;
+        if(gljUtil.isConcreteToCommercialConcrete(oldData.type,glj.gljType)){//被替换的是混凝土,替换成商品砼或商品砂浆
+            if(selected){ //如果有选中的,说明是替换,还要判断是否有辅助定额, 批量替换不用判断
+                return selected.data.rationAssList && selected.data.rationAssList.length > 0 ? true:false;
+            }
+            return true;
+        }
+        return false;
+    },
+    replaceGLJConfirm:function(mreplace = false){
         let me = this;
         let oldData = me.sheetData[gljContextMenu.selectedRow];
-        let project = projectObj.project;
         let selectCode = gljOprObj.GLJSelection[0];
-        let selected = projectObj.project.mainTree.selected;
+        let selected = mreplace == true?null:projectObj.project.mainTree.selected;
+        if(me.concreteTypeReplaceChecking(selectCode, oldData,selected)){
+            hintBox.infoBox('操作确认', '请先调整厚度,再替换商品砼。确定要继续吗?', 2, function () {
+                mreplace == true ? $("#mreplace_next_div").modal('show'):me.doReplaceGLJ(selectCode, oldData,selected);
+            }, null,['确定','取消'],false)
+        }else {
+            mreplace == true ? $("#mreplace_next_div").modal('show'):me.doReplaceGLJ(selectCode, oldData,selected);
+        }
+    },
+    doReplaceGLJ: function (selectCode, oldData,selected) {
+        let me = this;
+        let project = projectObj.project;
         project.ration_glj.replaceGLJ(selectCode, oldData, function (result) {
             if (result) {
                 //result.adjustState;
@@ -1185,9 +1211,9 @@ var gljOprObj = {
     },
     doMReplaceGLJ: function () {
         let me = this;
-        let oldData = me.sheetData[gljContextMenu.selectedRow];
         let project = projectObj.project;
-        let selectCode = me.GLJSelection[0];
+        let oldData = me.sheetData[gljContextMenu.selectedRow];
+        let selectCode = gljOprObj.GLJSelection[0];
         project.ration_glj.mReplaceGLJ(selectCode, oldData, function (result,updateMap) {
             if(result == null){
                 return;
@@ -1605,9 +1631,9 @@ $(function () {
         } else if ($('#actionType').val() == 'add') { //添加工料机
             gljOprObj.doAddGLJ();
         } else if ($('#actionType').val() == 'replace') {//替换工料机
-            gljOprObj.doReplaceGLJ();
+            gljOprObj.replaceGLJConfirm(false);
         } else if ($('#actionType').val() == 'm_replace') {//批量替换工料机
-            gljOprObj.doMReplaceGLJ();
+            gljOprObj.replaceGLJConfirm(true);
         }else if($('#actionType').val() == 'addMix'){
             projectGljObject.addMixRatio();
         }
@@ -1619,7 +1645,7 @@ $(function () {
     });
     $('#replace_next_btn').click(function () {
         $("#glj_tree_div").modal('hide');
-        $("#mreplace_next_div").modal('show');
+        gljOprObj.replaceGLJConfirm(true);
     });
     $('#class_selected_conf').click(function () {
         var gljClass = $('#selected_class').val();

+ 502 - 31
web/building_saas/main/js/views/locate_view.js

@@ -32,7 +32,7 @@ let locateObject={
         header:[
             {headerName: "编码", headerWidth: 120, dataCode: "code", dataType: "String"},
             {headerName: "名称", headerWidth: 80, dataCode: "name", dataType: "String"},
-            {headerName: "规格型号", headerWidth: 80, dataCode: "code", dataType: "String"},
+            {headerName: "规格型号", headerWidth: 80, dataCode: "specs", dataType: "String"},
             {headerName: "单位", headerWidth: 50, dataCode: "unit", dataType: "String",hAlign: "center"},
             {headerName: "市场价", headerWidth: 65, dataCode: "marketPrice", dataType: "Number", hAlign: "right"}
         ],
@@ -41,6 +41,32 @@ let locateObject={
             colHeaderHeight:30
         }
     },
+    datas:[],
+    bookMarkSetting:{
+        header:[
+            {headerName: "编码", headerWidth: 120, dataCode: "code", dataType: "String"},
+            {headerName: "书签名称", headerWidth: 200, dataCode: "name", dataType: "String"},
+        ],
+        view: {
+            lockColumns: [0,1],
+            colHeaderHeight:30
+        }
+    },
+    bookmarkDatas:[],
+    seletedNodeID:null,//右键设置书签时选中的节点ID临时存储
+    //为了兼容旧项目,这里给个默认值
+    bookmarkPropertySetting:{
+        settingList :[
+            {background:"E2F2C5",describe:""},
+            {background:"F9E2CF",describe:""},
+            {background:"F2EFD9",describe:"hehe"},
+            {background:"F5D1DA",describe:""},
+            {background:"E3E3E3",describe:""},
+            {background:"B6F3F2",describe:""},
+            {background:"ECE0F5",describe:""}
+        ],
+        selected:"E2F2C5"
+    },
     initMainSpread:function(){
         if(!this.mainSpread){
             this.mainSpread = SheetDataHelper.createNewSpread($("#locate_result")[0],3);
@@ -51,65 +77,166 @@ let locateObject={
         }
     },
     initMainSheet:function () {
-       // this.mainSheet = this.mainSpread .getSheet(0);
-        //this.spread.bind(GC.Spread.Sheets.Events.ButtonClicked, this.onReplaceButtonClick);
-       //初始化清单表格
+        //初始化清单表格
         sheetCommonObj.initSheet(this.mainSpread .getSheet(0),this.bills_setting);
         this.mainSpread .getSheet(0).setRowCount(0);
         //初始化定额表格
         sheetCommonObj.initSheet(this.mainSpread .getSheet(1),this.ration_setting);
         this.mainSpread .getSheet(1).setRowCount(0);
-
         //初始化人材机表格
         sheetCommonObj.initSheet(this.mainSpread.getSheet(2),this.ration_glj_setting);
         this.mainSpread .getSheet(2).setRowCount(0);
+        this.mainSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick,this.onSheetDoubleClick);
+        this.mainSpread .getSheet(2).bind(GC.Spread.Sheets.Events.SelectionChanged,this.gljSelectionChange);
     },
     initSubSpread:function () {
         if(!this.subSpread){
             this.subSpread = SheetDataHelper.createNewSpread($("#locate_sub")[0]);
             sheetCommonObj.spreadDefaultStyle(this.subSpread);
             this.initSubSheet();
+            this.subSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick,this.onSheetDoubleClick);
         }else {
             this.subSpread.refresh();
         }
     },
-    refreshWorkBook: function () {
-        if (this.mainSpread) {
-            this.mainSpread.refresh();
-        }
-        if (this.subSpread) {
-            this.subSpread.refresh();
+    initBookmarkSpread:function(){
+        if(!this.bookmarkSpread){
+            this.bookmarkSpread = SheetDataHelper.createNewSpread($("#bookmarkSpread")[0]);
+            sheetCommonObj.spreadDefaultStyle(this.bookmarkSpread);
+            this.initBookmarkSheet();
+            this.bookmarkSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick,this.onSheetDoubleClick);
+            if(!projectReadOnly) this.initBookmarkRightClick();
+        }else {
+            this.bookmarkSpread.refresh();
         }
+        this.showBookmarkDatas();
+    },
+    refreshWorkBook: function () {
+        if (this.mainSpread) this.mainSpread.refresh();
+        if (this.subSpread) this.subSpread.refresh();
+        if (this.bookmarkSpread) this.bookmarkSpread.refresh();
+
     },
     initSubSheet:function () {
         this.subSheet = this.subSpread .getSheet(0);
         sheetCommonObj.initSheet( this.subSheet, this.ration_setting);
         this.subSheet.setRowCount(0);
-        //this.spread.bind(GC.Spread.Sheets.Events.ButtonClicked, this.onReplaceButtonClick);
         this.subSheet.name('locate_sub');
     },
-    showMainData:function () {
-        let datas = [];
-        //sheetCommonObj.showData(this.mainSheet,this.mainSettiong,datas);
+    initBookmarkSheet:function () {
+        this.bookmarkSheet = this.bookmarkSpread .getSheet(0);
+        sheetCommonObj.initSheet( this.bookmarkSheet, this.bookMarkSetting);
+        this.bookmarkSheet.setRowCount(0);
+        this.bookmarkSheet.name('bookmark');
+        this.bookmarkSheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.bookmarkSelectionChange);
+    },
+    initOutstanding:function () {
+        if(!projectObj.project.property.locateSetting) return;
+        let outstd = projectObj.project.property.locateSetting;
+        $("#outstanding").prop("checked",outstd.outstanding);
+        $("#outInp").val(parseFloat(outstd.outInp));
+    },
+    initBookmarkSetting:function () {
+        $("#bookmarkSettingList").empty();
+        let setting = projectObj.project.property.bookmarkSetting?projectObj.project.property.bookmarkSetting:this.bookmarkPropertySetting;
+        for(let s of setting.settingList){
+            let b = `<div class="input-group input-group-sm mb-2" style="width:200px">
+                          <div class="input-group-prepend">
+                              <span class="input-group-text " style="background: #${s.background}">&nbsp;&nbsp;&nbsp;&nbsp;</span>
+                          </div>
+                          <input type="text" class="form-control" id="${s.background}"  placeholder="描述" value="${s.describe}">
+                     </div>`;
+            $("#bookmarkSettingList").append(b);
+            $("#"+s.background).bind('focus', bookmarkSelected);
+        }
+    },
+    showMainData:function (datas,setting) {
+        sheetCommonObj.showData(this.mainSpread.getActiveSheet(),setting,datas);
         this.mainSpread.getActiveSheet().setRowCount(datas.length);
     },
+    showSubRateDatas:function () {
+        this.subRationDatas = this.getSubRationDatas();
+        sheetCommonObj.showData(this.subSheet,this.ration_setting,this.subRationDatas);
+        this.subSheet.setRowCount(this.subRationDatas.length);
+    },
+    showBookmarkDatas:function(refresh = false){
+        let sheet = this.bookmarkSheet;
+        let sel = sheet.getSelections()[0];
+        let oldData = sel.row<this.bookmarkDatas.length?this.bookmarkDatas[sel.row]:null;
+        this.bookmarkDatas = this.getBookmarkDatas();
+        sheetCommonObj.showData(sheet, this.bookMarkSetting,this.bookmarkDatas);
+        let selectedID = null;
+        let focus = false;
+        if(oldData) selectedID = oldData.ID;
+        if(this.seletedNodeID && refresh == false){
+            selectedID =  this.seletedNodeID;
+            this.seletedNodeID = null;
+            focus = true;
+        }
+        sel.row = selectedID?_.findIndex(this.bookmarkDatas,{'ID':selectedID}):0;
+        sheet.setSelection(sel.row==-1?0:sel.row,sel.col,sel.rowCount,sel.colCount);
+        sheet.setRowCount(this.bookmarkDatas.length);
+        if(sel.row!=-1) sheet.showRow(sel.row, GC.Spread.Sheets.VerticalPosition.bottom);
+        this.showAnnotation(sel.row,focus);
+    },
+    getBookmarkDatas:function(){
+        let datas = [];
+        let nodes = projectObj.project.mainTree.items;
+        for(let n of nodes){
+            if(!_.isEmpty(n.data.bookmarkBackground)){
+                let tem = {
+                    ID:n.data.ID,
+                    code:n.data.code,
+                    type:n.sourceType,
+                    name:n.data.name,
+                    bookmarkAnnotation:n.data.bookmarkAnnotation,
+                    bgColour:"#"+n.data.bookmarkBackground
+                };
+                datas.push(tem);
+            }
+        }
+        return datas;
+    },
+
+    getSubRationDatas:function () {
+        let datas = [];
+        let sheet = this.mainSpread.getActiveSheet();
+        let oldSel = sheet.getSelections()[0];
+        if(this.gljDatas && this.gljDatas.length > 0){
+            let glj = this.gljDatas[oldSel.row];
+            if(!glj) return datas;
+            let  nodes = projectObj.project.projectGLJ.getImpactRationNodes([glj.reference]);
+            for(let n of nodes){
+                datas.push(this.getShowRationDatas(n.data));
+            }
+        }
+        return datas;
+    },
+
     refreshView: function (options, refreshWorkBook) {
         let me = this;
         let mainHeight = $(window).height()-$(".header").height()-$(".toolsbar").height()-$("#searchPanel").height();
         let subHeight = 0;
-        $('#locateTopDiv').height(mainHeight);
-        $('#locate_result').height(mainHeight);
-        $('#locateBottomDiv').height(subHeight);
-        $('#locate_sub').height(subHeight - 7);
-        if(options == "ration_glj"){
-            let locateLibResize = getLocateLibResize();
-            SlideResize.loadVerticalHeight(locateLibResize.eleObj.module, locateLibResize.eleObj, locateLibResize.limit, function () {
-                locateObject.refreshWorkBook();
-            });
+        if(options == "bookmark"){
+            loadHeight(getBookmarkResize());
+        }else {
+            $('#locateTopDiv').height(mainHeight);
+            $('#locate_result').height(mainHeight);
+            $('#locateBottomDiv').height(subHeight);
+            $('#locate_sub').height(subHeight - 7);
+            if(options == "ration_glj"){
+                loadHeight(getLocateLibResize());
+            }
         }
         if (refreshWorkBook) {
             me.refreshWorkBook();
         }
+
+        function loadHeight(libResize) {
+            SlideResize.loadVerticalHeight(libResize.eleObj.module, libResize.eleObj, libResize.limit, function () {
+                locateObject.refreshWorkBook();
+            });
+        }
     },
     init:function () {
         let me = this;
@@ -118,28 +245,333 @@ let locateObject={
             me.refreshView(options, false);
             me.initMainSpread();
             me.initSubSpread();
-            me.showMainData();
+            me.initBookmarkSpread();
         };
-        options == "bills"?$("#outstandingOptions").show(0,callback):$("#outstandingOptions").hide(0,callback);
-
+        if(options == 'bookmark'){
+            $("#aboutLocateDiv").hide();
+            $("#outstandingOptions").hide();
+            me.initBookmarkSetting();
+            $("#aboutBookmarkDiv").show(0,callback);
+        }else {
+            $("#aboutBookmarkDiv").hide();
+            $("#aboutLocateDiv").show(0,function () {
+                if(options == "bills") me.initOutstanding();
+                options == "bills"?$("#outstandingOptions").show(0,callback):$("#outstandingOptions").hide(0,callback);
+            });
+        }
     },
     findRecodes:function () {
-
+        let options = $("input[name='content_type']:checked").val();
+        let keyword = $("#locateInput").val();
+        switch (options){
+            case "bills":
+                this.billsDatas = this.findBills(keyword);
+                this.showMainData(this.billsDatas,this.bills_setting);
+                break;
+            case "ration":
+                this.rationDatas = this.findRations(keyword);
+                this.showMainData(this.rationDatas,this.ration_setting);
+                break;
+            case "ration_glj":
+                this.gljDatas = this.findGLJs(keyword);
+                this.showMainData(this.gljDatas,this.ration_glj_setting);
+                this.showSubRateDatas();
+                break;
+        }
     },
     onshow:function () {
         locateObject.init();
+    },
+    matchItem:function (keyword,i) {//true 匹配上,false匹配失败
+        let match = false;
+        if(keyword && keyword !="") {//如果keyword为空,匹配所有
+            if (i.code && i.code.indexOf(keyword) != -1) match = true;
+            if (i.name && i.name.indexOf(keyword) != -1) match = true;
+            if(match == false) return false
+        }
+        return true;
+    },
+    findGLJs:function(keyword){
+        let datas = [];
+        let gljList = projectObj.project.projectGLJ.datas.gljList;
+        gljList =  sortProjectGLJ(gljList);
+        for(let glj of gljList){
+            // if(glj.quantity == 0 || glj.quantity == '0') continue;  2019-07-01 需求改成消耗量为0也显示
+            let match = this.matchItem(keyword,glj);
+            if(match == false) continue;
+            let data = getGLJDatas(glj);
+            gljOprObj.setGLJPrice(data,glj);
+            datas.push(data);
+        }
+        return datas;
+        function getGLJDatas(tem) {
+            return{
+                ID:tem.id,
+                name:tem.name,
+                code:tem.code,
+                unit:tem.unit,
+                specs:tem.specs,
+                reference:tem
+            }
+        }
+
+    },
+    findRations:function (keyword) {
+        let datas = [];
+        let items = projectObj.project.mainTree.items;
+        for(let  i of items){
+            if(i.sourceType == ModuleNames.ration){
+                let match = this.matchItem(keyword,i.data);
+                if(match == false) continue;
+                let bills = this.getShowRationDatas(i.data);
+                datas.push(bills);
+            }
+        }
+        return datas;
+    },
+    getShowRationDatas:function(data){
+        return{
+            ID:data.ID,
+            name:data.name,
+            code:data.code,
+            unit:data.unit,
+            quantity:data.quantity
+        }
+    },
+    findBills:function(keyword){
+        let datas = [],priceMap={};
+        let items = projectObj.project.mainTree.items;
+        for(let  i of items){
+            if(i.sourceType == ModuleNames.bills){
+                let match = this.matchItem(keyword,i.data);
+                if(match == false) continue;
+                let bills = getBillData(i.data);
+                priceMap = setPriceMap(bills,priceMap);
+                datas.push(bills);
+            }
+        }
+        setBgColour(datas,priceMap);
+        datas =  _.sortByAll(datas,['code']);
+        return datas;
+
+
+        function setBgColour(bills,map) {
+            let outStd = $("#outstanding").prop("checked");
+            let outInp = $("#outInp").val();
+            if(outStd == true && outInp && outInp!=""){
+                for(let b of bills){
+                    if(b.code && b.code.length >= 9){
+                        let key = b.code.substr(0,9);
+                        if(map[key] && map[key].count > 1){
+                            let avg = map[key].total/map[key].count;
+                            let unitPrice = b.unitPrice?parseFloat(b.unitPrice):0;
+                            if(unitPrice ==0 ) continue;
+                            if(Math.abs(unitPrice - avg)/avg * 100  >= parseFloat(outInp)) b.bgColour = "#FFFACD"
+                        }
+                    }
+                }
+            }
+        }
+        function setPriceMap (bills,map) {
+            if(bills.code && bills.code.length >= 9){
+                let key = bills.code.substr(0,9);
+                let unitPrice = bills.unitPrice?parseFloat(bills.unitPrice):0;
+                if(map[key]){
+                    map[key].total += unitPrice;
+                    map[key].count ++;
+                }else {
+                    map[key] = {total:unitPrice,count:1}
+                }
+
+            }
+
+            return map;
+        }
+
+        function getBillData(data) {
+            return{
+                ID:data.ID,
+                name:data.name,
+                code:data.code,
+                unit:data.unit,
+                quantity:data.quantity,
+                unitPrice:data.feesIndex&&data.feesIndex.common?data.feesIndex.common.unitFee:"",
+                totalPrice:data.feesIndex&&data.feesIndex.common?data.feesIndex.common.totalFee:"",
+                bgColour:"white"
+            }
+        }
+    },
+    onSheetDoubleClick:function (e,args) {
+        let me = locateObject;
+        let options = $("input[name='content_type']:checked").val();
+        let sheetName = args.sheet.name()
+        if(options == "ration_glj"&&sheetName != "locate_sub" ) return;
+        let datas = options == "bills"? me.billsDatas:me.rationDatas;
+        if( args.sheet.name() == "locate_sub") datas = me.subRationDatas;
+        if(args.sheet.name() == "bookmark") datas = me.bookmarkDatas;
+        me.locateNode(datas[args.row].ID);
+    },
+    gljSelectionChange:function (e,args) {
+        let me = locateObject;
+        let newSel = args.newSelections[0];
+        let oldSel = args.oldSelections?args.oldSelections[0]:{};
+        if(newSel.row != oldSel.row){
+            me.showSubRateDatas();
+        }
+    },
+    bookmarkSelectionChange:function (e,args) {
+        let me = locateObject;
+        let newSel = args.newSelections[0];
+        let oldSel = args.oldSelections?args.oldSelections[0]:{};
+        if(newSel.row != oldSel.row){
+            me.showAnnotation(newSel.row);
+        }
+    },
+    showAnnotation:function (row,focus = false) {
+        let me = locateObject;
+        let recode =   me.bookmarkDatas[row];
+        if(recode){
+            $("#annotationTextarea").val(recode.bookmarkAnnotation);
+            $("#bookmarkNodeID").val(recode.ID);
+            $("#bookmarkNodeType").val(recode.type);
+            if(focus) $("#annotationTextarea").focus();
+        }
+    },
+    locateNode:function (ID) {
+        let node =  projectObj.project.mainTree.findNode(ID);
+        if(node) projectObj.loadFocusLocation(node.serialNo(),1);
+    },
+    updateProjectProperty:function(fieldID,property){
+        let updateData = {type:ModuleNames.project,data:{'ID' : projectObj.project.ID()}};//,'property.locateSetting':outstd
+        updateData.data["property."+fieldID] = property;
+        $.bootstrapLoading.start();
+        projectObj.project.updateNodes([updateData],function () {
+            $.bootstrapLoading.end();
+            projectObj.project.property[fieldID] = property;
+        });
+    },
+    updateOutStanding:function (outstanding,outInp) {
+        let outstd = {outstanding:outstanding,outInp:outInp};
+        this.updateProjectProperty('locateSetting',outstd);
+    },
+    updateBookmarkSetting:function () {
+        let setting = projectObj.project.property.bookmarkSetting?projectObj.project.property.bookmarkSetting:locateObject.bookmarkPropertySetting;
+        for(let s of setting.settingList){
+            s.describe = $("#"+s.background).val();
+        }
+        setting.selected = $("#bookmarkSelected").val();
+        this.updateProjectProperty("bookmarkSetting",setting);
+    },
+    setOrCancelBookmark:function(node){
+        $("#bookmark").prop("checked", true);
+        let setting = projectObj.project.property.bookmarkSetting?projectObj.project.property.bookmarkSetting:locateObject.bookmarkPropertySetting;
+        let background = null;
+        if(_.isEmpty(node.data.bookmarkBackground)) background = setting.selected;
+        let updateData = {type:node.sourceType,data:{'ID' : node.data.ID,bookmarkBackground:background}};
+        if(background == null) updateData.data.bookmarkAnnotation = null;
+        $.bootstrapLoading.start();
+        projectObj.project.updateNodes([updateData],function () {
+            $.bootstrapLoading.end();
+            node.data.bookmarkBackground = background;
+            projectObj.mainController.refreshTreeNode([node]);
+            locateObject.seletedNodeID = node.data.ID;
+            //如果没有打开,自动打开书签批注设置
+            $('#locate').is(':visible')?locateObject.init():$("#locateTab").click();
+        });
+    },
+    initBookmarkRightClick:function(){
+        //如果当前行是无组成物的“普通材料”、“绿化苗木”、“外购砼构件”、“商品混凝土”、“商品砂浆”,则右键“添加计算材料”按钮有效。
+        let me = this;
+        $.contextMenu({
+            selector: '#bookmarkSpread',
+            build: function ($trigger, e) {
+                me.rightClickTarget = SheetDataHelper.safeRightClickSelection($trigger, e, me.bookmarkSpread);
+                return me.rightClickTarget.hitTestType === GC.Spread.Sheets.SheetArea.viewport ||
+                    me.rightClickTarget.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
+            },
+            items: {
+                "deleteBookmark": {
+                    name: "删除书签批注",
+                    icon: 'fa-remove',
+                    disabled: function () {
+                        return  me.bookmarkDatas.length == 0;
+                    },
+                    callback: function (key, opt) {
+                        me.deleteSelectedBookmark();
+                    }
+                },
+                "deleteAllBookmarks": {
+                    name: "删除所有书签批注",
+                    icon: 'fa-remove',
+                    disabled: function () {
+                        return  me.bookmarkDatas.length == 0;
+                    },
+                    callback: function (key, opt) {
+                        me.deleteBookmarkByDatas(me.bookmarkDatas);
+                    }
+                }
+            }
+        });
+    },
+    deleteSelectedBookmark:function () {
+        let sel = this.bookmarkSheet.getSelections()[0];
+        if(sel.row != -1 && this.bookmarkDatas.length>sel.row){
+            let record = this.bookmarkDatas[sel.row];
+            this.deleteBookmarkByDatas([record]);
+        }
+    },
+    deleteBookmarkByDatas:function(datas){
+        let postDatas = [];
+        for(let d of datas){
+            let tem = {
+                type:d.type,
+                data:{
+                    'ID':d.ID,
+                    'bookmarkAnnotation':null,
+                    'bookmarkBackground':null
+                }
+            };
+            postDatas.push(tem);
+        }
+       this.updateBookmarkNodes(postDatas);
+    },
+    updateBookmarkNodes:function (postDatas,refreshsNode = true) {
+        $.bootstrapLoading.start();
+        projectObj.project.updateNodes(postDatas,function () {
+            $.bootstrapLoading.end();
+            let nodes = [];
+            for(let p of postDatas){
+                let node =  projectObj.project.mainTree.findNode(p.data.ID);
+                if(!node) continue;
+                for(let key in p.data){
+                    if(key == 'ID') continue;
+                    node.data[key] = p.data[key];
+                }
+                nodes.push(node);
+            }
+            locateObject.showBookmarkDatas();
+            if(refreshsNode) projectObj.mainController.refreshTreeNode(nodes);
+        });
     }
-}
+};
 
 
 $("#locate_btn").click(function () {
     locateObject.findRecodes();
 });
 
+//回车键搜索
+$('#locateInput').bind('keypress', function (event) {
+    if(event.keyCode === 13){
+        $(this).blur();
+        locateObject.findRecodes();
+    }
+});
+
 $("input[name='content_type']").each(function(){
     $(this).click(function(){
-        let optins = $(this).val();
-        switch (optins){
+        let options = $(this).val();
+        switch (options){
             case "bills":
                 locateObject.mainSpread.setActiveSheetIndex(0);
                 break;
@@ -153,3 +585,42 @@ $("input[name='content_type']").each(function(){
         locateObject.init();
     });
 });
+
+
+$('#outInp').change(function(){
+    let me = locateObject;
+    let process = getDecimal('process');
+    var newVal = $(this).val();
+    let outInp = scMathUtil.roundForObj(newVal,process);
+    let outStd = $("#outstanding").prop("checked");
+    me.updateOutStanding(outStd,outInp);
+});
+$('#outstanding').change(function(){
+    let me = locateObject;
+    let outInp = $("#outInp").val();
+    let outStd = $("#outstanding").prop("checked");
+    me.updateOutStanding(outStd,scMathUtil.roundForObj(outInp,getDecimal('process')));
+});
+
+$("#annotationTextarea").change(function(){
+    let updateData = {type:$("#bookmarkNodeType").val(),data:{'ID' :$("#bookmarkNodeID").val(),'bookmarkAnnotation':$(this).val()}};
+    let node =  projectObj.project.mainTree.findNode($("#bookmarkNodeID").val());
+    if(!node) return;
+    locateObject.updateBookmarkNodes([updateData],false);
+});
+
+$('#bookmarkSettingDropdown').on('shown.bs.dropdown', function showDropdown() {
+    locateObject.initBookmarkSetting();
+    let setting = projectObj.project.property.bookmarkSetting?projectObj.project.property.bookmarkSetting:locateObject.bookmarkPropertySetting;
+    $("#"+setting.selected).focus();
+});
+
+$("#bookmarkSettingConfirm").click(function () {
+    locateObject.updateBookmarkSetting();
+    $("#bookmarkSettingDropdown").click();
+});
+
+
+function bookmarkSelected() {
+    $("#bookmarkSelected").val($(this)[0].id);
+}

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

@@ -43,7 +43,7 @@ materialCalcObj = {
             {headerName: "其它\n费用", headerWidth: 60, dataCode: "otherFee", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:"glj.unitPrice"
             {headerName: "运价增\n加率(%)", headerWidth: 60, dataCode: "freightIncreaseRate", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:"glj.unitPrice"
             {headerName: "加权\n系数", headerWidth: 60, dataCode: "weightCoe", hAlign: "right", dataType: "Number",validator:"number"},
-            {headerName: "计算式", headerWidth: 170, dataCode: "exp", hAlign: "right", dataType: "Number",getText:'forExp'},//,decimalField:"glj.unitPrice"
+            {headerName: "计算式", headerWidth: 170, dataCode: "exp", hAlign: "left", dataType: "Number",getText:'forExp'},//,decimalField:"glj.unitPrice"
         ],
         view: {
             lockColumns: ["exp"],

+ 6 - 8
web/building_saas/main/js/views/options_view.js

@@ -8,15 +8,13 @@ let optionsOprObj = {
     rationQuanACToRationUnit: $('#generalOpts2'),
     getOptions: function () {
         let me = this;
-        CommonAjax.post('/options/getOptions', [], function (rstData) {
-            me.options = rstData;
-            let gOpts = me.options[me.optionsTypes.GENERALOPTS];
-            if(isDef(gOpts)){
-                for(let attr in gOpts){
-                    me[attr].prop('checked', gOpts[attr]);
-                }
+        me.options = projectOptins;
+        let gOpts = me.options[me.optionsTypes.GENERALOPTS];
+        if(isDef(gOpts)){
+            for(let attr in gOpts){
+                me[attr].prop('checked', gOpts[attr]);
             }
-        });
+        }
     },
     saveOptions: function (type, opts) {
         let optSettingType = 'options.' + type;

+ 29 - 4
web/building_saas/main/js/views/project_view.js

@@ -1291,7 +1291,7 @@ var projectObj = {
                         return !project.Ration.canAdd(project.mainTree.selected);
                     },
                     callback: function (key, opt) {
-                        project.Ration.addNewRation(null,rationType.ration,projectObj.selectColAndFocus,true);
+                        project.Ration.addNewRation(null,rationType.ration,projectObj.selectColAndFocus,false);
                        // ProjectController.addRation(project, controller, rationType.ration);
                     }/*,
                     visible: function(key, opt){
@@ -1394,7 +1394,31 @@ var projectObj = {
                             return true;
                         }
                         return false;
+                    },
+                    disabled: function () {
+                        let selected = project.mainTree.selected;
+                        if (projectReadOnly) {
+                            return true;
+                        }
+                        if(selected && selected.data.type != rationType.ration){
+                            return true;
+                        }
+                        return false;
+                    },
+                },
+                "setBookMark": {
+                    name: '设置/取消书签批注',
+                    icon: 'fa-flag',
+                    disabled: function () {
+                        if (projectReadOnly || project.mainTree.selected.sourceType == ModuleNames.ration_glj) {
+                            return true;
+                        }
+                        return false
+                    },
+                    callback: function () {
+                        locateObject.setOrCancelBookmark(project.mainTree.selected)
                     }
+
                 },
                 "delete": {
                     name: '删除',
@@ -1567,10 +1591,10 @@ var projectObj = {
     },
 
     // 获取上次退出时的焦点位置
-    loadFocusLocation: function() {
+    loadFocusLocation: function(orow,ocol) {
         const projectId = scUrlUtil.GetQueryString('project');
-        let row = getLocalCache('lastRow:' + projectId);
-        let col = getLocalCache('lastCol:' + projectId);
+        let row = gljUtil.isDef(orow)?orow:getLocalCache('lastRow:' + projectId);
+        let col = gljUtil.isDef(ocol)?ocol:getLocalCache('lastCol:' + projectId);
         if(row == null || col == null){
             //默认焦点定位到造价书的第一行“分项”。
             col = 1;
@@ -1858,6 +1882,7 @@ var projectObj = {
         if(node === tree.selected){
              style.backColor = colorSetting[mapping.SELECTED]['backColor'];
         }
+        if(_ && !_.isEmpty(node.data.bookmarkBackground)) style.backColor = "#"+ node.data.bookmarkBackground;//设置书签和批注背景色
         //大项费用加粗(数字与中文字符大小不一问题由字体造成,暂时不考虑分别设置大小)
        /* if(node.sourceType === this.project.Bills.getSourceType() && node.data.type === billType.DXFY){
             style.font = 'bold 0.9rem Arial';

+ 26 - 0
web/building_saas/main/js/views/side_tools.js

@@ -95,6 +95,32 @@ SlideResize.verticalSlide(locateLibResize.eleObj, locateLibResize.limit, functio
     locateObject.refreshWorkBook();
 });
 
+
+function getBookmarkResize() {
+    let resizeObj = {};
+    resizeObj.eleObj = {
+        module: 'bookmark',
+        resize: $('#bookmark_resize'),
+        top: $('#bookmarkTopDiv'),
+        topSpread: $('#bookmarkSpread'),
+        bottom: $('#annotationDiv'),
+        bottomSpread: $('#annotationTextarea')
+    };
+    resizeObj.limit = {
+        min: 150,
+        max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#searchPanel').height()-100-5`,//5: resize.height()
+        notTopSpread: 35,
+        notBottomSpread: 15,
+        totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#searchPanel').height()-5`//5: resize.height()
+    };
+    return resizeObj;
+}
+
+let bookMarkLibResize = getBookmarkResize();
+SlideResize.verticalSlide(bookMarkLibResize.eleObj, bookMarkLibResize.limit, function () {
+    locateObject.refreshWorkBook();
+});
+
 // 块模板库上下拖动(上中)
 let blockLibTopMid = {};
 blockLibTopMid.eleObj = {

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

@@ -971,8 +971,8 @@ const billsGuidance = (function () {
                 elfItem.workBook = null;
             }
             initViews();
+            initTree(bills, bills.workBook.getActiveSheet(), bills.treeSetting, rstData.bills);
             let callback = function () {
-                initTree(bills, bills.workBook.getActiveSheet(), bills.treeSetting, rstData.bills);
                 if(doAfterLoadGuidance){
                     doAfterLoadGuidance();
                 }

+ 7 - 10
web/building_saas/main/js/views/zmhs_view.js

@@ -203,9 +203,9 @@ let zmhs_obj = {
         this.assSheetData = assList;
         return assList;
     },
-    refreshAfterUpdate:function(result,reload){
+    refreshAfterUpdate:function(result){
         let ration_glj = projectObj.project.ration_glj;
-        let calcInstall = false;//是否记安装增加费
+        let calcInstall = false;//是否记安装增加费
         let nodes = projectObj.project.updateNodesCache([{type:ModuleNames.ration,data:result.ration}]);
         if(result.add && result.add.length > 0){//需添加定额工料机的情况
             ration_glj.datas = ration_glj.datas.concat(result.add);
@@ -223,14 +223,11 @@ let zmhs_obj = {
         projectObj.mainController.refreshTreeNode(nodes, false);
 
         let rationID= ration_glj.updateCacheAfterAdjust(result.ration_glj);
-        if(reload == true){//有添加、替换、工料机等需重新加载的情况
-            $.bootstrapLoading.start();
-            projectObj.project.projectGLJ.loadData(function () {
-                $.bootstrapLoading.end();
-                if(result.add && result.add.length > 0) ration_glj.addToMainTree(result.add);//这个方法有再去项目工料机那里取价格,所以要在回调里调用,不像替换工料的情况
-                ration_glj.reCalcWhenGLJChange({rationID:rationID});
-                if(result.delete && result.delete.length > 0 && calcInstall) installationFeeObj.calcInstallationFee();//如果是删除节点的话,
-            });
+        if(result.projectGLJDatas){//有添加、替换、工料机等需重新加载的情况
+            projectObj.project.projectGLJ.refreshByDatas(result.projectGLJDatas);
+            if(result.add && result.add.length > 0) ration_glj.addToMainTree(result.add);//这个方法有再去项目工料机那里取价格,所以要在回调里调用,不像替换工料的情况
+            ration_glj.reCalcWhenGLJChange({rationID:rationID});
+            if(result.delete && result.delete.length > 0 && calcInstall) installationFeeObj.calcInstallationFee();//如果是删除节点的话,
         }else {
             ration_glj.reCalcWhenGLJChange({rationID:rationID});
         }

+ 13 - 34
web/building_saas/pm/html/project-management.html

@@ -646,54 +646,33 @@
     </div>
 </div>
 
-<!--弹出 导出-->
-<div class="modal fade" id="export" data-backdrop="static">
-    <div class="modal-dialog" role="document">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h5 class="modal-title">导出文件</h5>
-              <!--  <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-                    <span aria-hidden="true">&times;</span>
-                </button>-->
-            </div>
-            <div class="modal-body">
-                <!--正在生成-->
-                <h5 class="my-3">正在生成文件</h5>
-                <div class="progress mb-3">
-                    <div id="export_progress_bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100" style="width: 10%"></div>
-                </div>
-            </div>
-        </div>
-    </div>
-</div>
 
-<!--弹出 导出-->
+
+<!--弹出 导入-->
 <div class="modal fade" id="import" data-backdrop="static">
-    <div class="modal-dialog" role="document">
+    <div class="modal-dialog" style="z-index: 800" role="document">
         <div class="modal-content">
             <div class="modal-header">
-                <h5 class="modal-title">导入建设项目</h5><button type="button" class="close" data-dismiss="modal" aria-label="Close">
-                <span aria-hidden="true">&times;</span>
-            </button>
+                <h5 class="modal-title">导入建设项目</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
             </div>
             <div class="modal-body">
-                <form>
-                    <div class="form-group">
-                        <label>请选择ybp格式文件</label>
-                        <input class="form-control-file" type="file" accept=".ybp" name="import_project_data"/>
-                    </div>
-                </form>
+                <div class="custom-file">
+                    <input type="file" class="custom-file-input" name="import_project_data" id="import_project_data" lang="zh" accept=".ybp">
+                    <label class="custom-file-label"  id="import_project_label" style="white-space: nowrap; overflow: hidden;">请选择建设项目文件</label>
+                </div>
             </div>
             <div class="modal-footer">
-                <button type="button" class="btn btn-primary" id="confirm-import">确定导入</button>
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <button type="button" class="btn btn-primary " disabled id="confirm-import">确定导入</button>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
             </div>
         </div>
     </div>
 </div>
 
 
-
 <!-- JS. -->
 <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>
 <script src = "/lib/fileSaver/FileSaver.min.js"></script>

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

@@ -845,22 +845,11 @@ function m_getDelDatas(oprNode){
     getChild(oprNode);
     //父节点只有一个单位工程,则清除此单位工程的时候,父节点也清除,(建设项目单价、费率文件存在时不清除)
     if(oprNode.data.projType === projectType.tender){
-        let eng = oprNode.parent, proj = null;
-        if(eng && deleted(eng)){
-            proj = eng.parent;
-            rst.push({updateType: 'Project', ID: eng.data.ID});
-        }
-        if(proj && deleted(proj) && fileEmpty(proj)){
-            rst.push({updateType: 'Project', ID: proj.data.ID})
-        }
-    }
-    else if(oprNode.data.projType === projectType.engineering){
         let proj = oprNode.parent;
         if(proj && deleted(proj) && fileEmpty(proj)){
-            rst.push({updateType: 'Project', ID: proj.data.ID});
+            rst.push({updateType: 'Project', ID: proj.data.ID})
         }
-    }
-    else if(oprNode.data.projType === projectType.project){
+    } else if(oprNode.data.projType === projectType.project){
         for(let uf of oprNode.data.unitPriceFiles){
             rst.push({updateType: fileType.unitPriceFile, ID: uf.id});
         }

+ 90 - 29
web/building_saas/pm/js/pm_newMain.js

@@ -341,29 +341,38 @@ const projTreeObj = {
         },
         exportProject: {
             name: "导出建设项目",
-            icon: 'fa-external-link',
+            icon: 'fa-cloud-download',
             disabled: function () {
                 let selectedItem = projTreeObj.tree.selected;
                 return !(selectedItem && selectedItem.data.projType === projectType.project);
             },
-            visible:function () {
+           /* visible:function () {
                 return false
-            },
+            },*/
             callback: function (key, opt) {
                 //获取当前节点的建设项目ID
                 projTreeObj.exportProject(projTreeObj.tree.selected.data.ID,projTreeObj.tree.selected.data.name);
             }
         },
-        improtProject:{
+        importProject:{
             name: "导入建设项目",
-            icon: 'fa-external-link',
+            icon: 'fa-upload',
             disabled: function () {
                 let selectedItem = projTreeObj.tree.selected;
-                return !(selectedItem && selectedItem.data.projType === projectType.project);
+                if(selectedItem){
+                    if(selectedItem.data.projType === projectType.project) return false;//如果是建设项目,可用
+                    if(selectedItem.data.projType === projectType.folder){//如果是文件夹
+                        if(selectedItem.children){
+                            if(selectedItem.children.length == 0) return false;//如果文件夹没有子项,可用
+                            if(selectedItem.children[0] .projType === projectType.project ) return false;//如果文件夹有子项,并且是建设项目,可用
+                        }
+                    }
+                }
+                return true;
             },
-            visible:function () {
+          /*  visible:function () {
               return false
-            },
+            },*/
             callback: function (key, opt) {
                 //获取当前节点的建设项目ID
                 $("#import").modal('show');
@@ -401,7 +410,7 @@ const projTreeObj = {
                 "manageFiles": me.contextMenuItems.manageFiles,
                 "refreshSummary": me.contextMenuItems.refreshSummary,
                 "exportProject":me.contextMenuItems.exportProject,
-                "importProject":me.contextMenuItems.improtProject
+                "importProject":me.contextMenuItems.importProject
             }
         });
     },
@@ -1474,13 +1483,13 @@ const projTreeObj = {
         this.refreshProjectData(projectID);
     },
      exportProject:async function(projectID,projectName){
-        $("#export_progress_bar").css('width','0%');
-        $("#export").modal('show');
+        $.bootstrapLoading.progressStart();
         let spString = "|----|";
         try {
             let sumString = "";
+            $("#progress_modal_bar").css('width','5%');
             let result = await getProjectInfo({projectID:projectID,type:"main",user_id: userID});
-            $("#export_progress_bar").css('width','10%');
+            $("#progress_modal_bar").css('width','10%');
             let result_arr = result.split(spString);
             sumString = result_arr[0];
             if(result_arr.length == 2){
@@ -1491,20 +1500,19 @@ const projTreeObj = {
                 for(let t of tenders){
                     let tenderString = await getProjectInfo({projectID:t,rootProjectID:projectID,type:"sub",user_id: userID});
                     width += each;
-                    $("#export_progress_bar").css('width',width+'%');
+                    $("#progress_modal_bar").css('width',width+'%');
                     await  setTimeoutSync(null,500);//设置间隔
                     sumString = sumString + spString +tenderString;
-                    console.log(JSON.parse(tenderString));
                 }
 
             }
-            $("#export_progress_bar").css('width','100%');
-            $("#export").modal('hide');
+            $.bootstrapLoading.progressEnd();
           //  console.log(JSON.parse(sumString));
 
             saveProjectFile(sumString);
 
         }catch (e){
+            alert("导出失败!请查看log.");
             console.log(e)
         }
 
@@ -1512,23 +1520,29 @@ const projTreeObj = {
         async function getProjectInfo(data) {
             let result = await ajaxPost("/pm/api/exportProject",data);
             return result;
-           // let blob = new Blob([result], {type: 'text/plain;charset=utf-8'});
-           // saveAs(blob, 'textName.ybp');
         }
 
         function saveProjectFile(data) {
             let blob = new Blob([data], {type: 'text/plain;charset=utf-8'});
             saveAs(blob, projectName+'.ybp');
         }
-
-       /* setTimeout(function(){
-            $("#progressbar").css('width','50%');
-            setTimeout(function(){
-                $("#export").modal('hide');
-            },1000)
-            //$("#export").modal('hide');
-        },1000)*/
+    },
+    getImportProjectDate:function () {//导入建设项目时,需要在现有的树节点中插入新的节点,这里是取插入所需的项目数据
+        let selectNode = projTreeObj.tree.selected;
+        let parent = null,next=null;
+        let updateData = {};
+        if(selectNode && selectNode.data.projType == projectType.folder){
+            parent = selectNode;
+            next = selectNode.firstChild();
+        }else if(selectNode &&  selectNode.data.projType == projectType.project){
+            parent = selectNode.parent;
+            next = selectNode.nextSibling;
+            updateData["update"] = {query:{ID:selectNode.id()}}
+        }
+        updateData["self"] ={ParentID:parent.id(),NextSiblingID:next?next.id():-1};
+        return updateData;
     }
+
 };
 
 $(document).ready(function() {
@@ -2093,11 +2107,11 @@ function initProjects(callback) {
  *
  * @return {void}
  */
-function init() {
+function init(refresh = false) {//refresh是刷新页面时才使用的
     billValuation = billValuation.replace(/\n/g, '\\n');
     rationValuation = rationValuation.replace(/\n/g, '\\n');
     //init spread and pmTree
-    socketObject.connect('pm');//socket 连接;
+    if(refresh == false) socketObject.connect('pm');//socket 连接;
     if (isFirst) {
         $('#progress').modal('show');
         let intervalTime = prepareInitialTimer();
@@ -2120,6 +2134,16 @@ function init() {
     engineering = engineeringList !== null && engineeringList !== undefined ? JSON.parse(engineeringList) : [];
 }
 
+function refreshAllPage(){
+    if(gcTreeObj.workBook){
+        gcTreeObj.workBook.destroy();
+        gcTreeObj.workBook = null;
+    }
+    gcTreeObj.tree = null;
+    init(true);
+}
+
+
 /**
  * 新增建设项目
  *
@@ -3575,6 +3599,7 @@ $('#otherProject').change(function(){
     }
 });
 
+
 //分享给...界面确认
 $('#shareToConfirm').click(function () {
     let selected = projTreeObj.tree.selected;
@@ -3596,6 +3621,9 @@ $("#confirm-import").click(function() {
         }
         formData.append('file', file.files[0]);
         formData.append('userID', userID);
+        formData.append("updateData",JSON.stringify(projTreeObj.getImportProjectDate()));
+        $('#import').modal("hide");
+        $.bootstrapLoading.progressStart("导入建设项目",true);
         $.ajax({
             url: '/pm/api/importProject',
             type: 'POST',
@@ -3608,10 +3636,21 @@ $("#confirm-import").click(function() {
                 self.text('上传中...');
             },
             success: function(response){
+                self.text('确定导入');
+                $.bootstrapLoading.progressEnd();
+                if(response.error == 1){
+                    alert(response.msg);
+                }else {
+                    refreshAllPage();
+                }
 
             },
             error: function(){
-
+                setTimeout(function () {
+                    self.text('确定导入');
+                    $.bootstrapLoading.progressEnd();
+                    alert("导入失败,请检查文件!");
+                },1000)
             }
         });
     } catch(error) {
@@ -3620,6 +3659,28 @@ $("#confirm-import").click(function() {
     }
 });
 
+$("#import_project_data").change(function(){
+    let file = $(this)[0];
+    let projectFile = file.files[0];
+    if(projectFile) {
+        let ybpReg = /ybp$/g;
+        if(projectFile.name && ybpReg.test(projectFile.name)){
+            $('#import_project_label').text(`${projectFile.name}`);
+            $('#confirm-import').removeAttr("disabled");
+        }else {
+            alert("请选择ybp项目文件");
+            $(this).val('');
+            $('#confirm-import').attr("disabled","disabled");
+        }
+    }
+});
+
+//清空导入清单选择文件
+$('#import').on('show.bs.modal', function(){
+    $('#import_project_data').val('');
+    $('.custom-file-label').text(`请选择建设项目文件`);
+});
+
 //设置分享给界面数据
 //@param {Object}selected @return {void}
 function setShareToModal(selected){

+ 2 - 1
web/building_saas/report/js/jpc_output.js

@@ -290,7 +290,8 @@ let JpcCanvasOutput = {
                     // area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + i * (height / values.length) + me.offsetY;
                     // area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (height / values.length) + me.offsetY;
                     area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + i * (ah / values.length) + me.offsetY + restTopH;
-                    area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (ah / values.length) + me.offsetY + restTopH;
+                    // area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (ah / values.length) + me.offsetY + restTopH;
+                    area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (ah / values.length) + me.offsetY + restBottomH;
                     if (values[i] === null || values[i] === undefined || values[i] === 'null') {
                         values[i] = "";
                     }

+ 3 - 7
web/building_saas/report/js/rpt_main.js

@@ -598,14 +598,10 @@ let canvasOprObj = {
         if (zTreeOprObj.currentNode) {
             let x = event.offsetX - JpcCanvasOutput.offsetX, canvas = event.originalTarget;
             if (!(canvas)) canvas = event.target; //chrome浏览器不认event.originalTarget,只认event.target或event.currentTarget
-            if (x < FIRST_PAGE_OFFSET) {
-                canvas.style.cursor = "url(/web/building_saas/img/FirstPageSimple.cur), auto";
-            } else if (x < PRE_PAGE_OFFSET) {
-                canvas.style.cursor = "url(/web/building_saas/img/PreviousPageSimple.cur), auto";
-            } else if ((canvas.width - x) < LAST_PAGE_OFFSET) {
-                canvas.style.cursor = "url(/web/building_saas/img/LastPageSimple.cur), auto";
+            if (x < PRE_PAGE_OFFSET) {
+                canvas.style.cursor = "url(/web/building_saas/img/PreviousPage.cur), auto";
             } else if ((canvas.width - x) < NEXT_PAGE_OFFSET) {
-                canvas.style.cursor = "url(/web/building_saas/img/NextPageSimple.cur), auto";
+                canvas.style.cursor = "url(/web/building_saas/img/NextPage.cur), auto";
             } else {
                 canvas.style.cursor = "";
             }

+ 1 - 1
web/building_saas/report/js/rpt_print.js

@@ -298,7 +298,7 @@ function buildText(destRst, cell, font, control, offsetX, offsetY, adjustY, canv
         // area[JV.IDX_TOP] = top + vidx * (height / values.length);
         // area[JV.IDX_BOTTOM] = top + (vidx + 1) * (height / values.length);
         area[JV.IDX_TOP] = top + vidx * (ah / values.length) + restTopH;
-        area[JV.IDX_BOTTOM] = top + (vidx + 1) * (ah / values.length) + restTopH;
+        area[JV.IDX_BOTTOM] = top + (vidx + 1) * (ah / values.length) + restBottomH;
         inner_draw_text(values[vidx]);
     }
 }

+ 3 - 2
web/over_write/js/chongqing_2018.js

@@ -315,7 +315,7 @@ if(typeof module !== 'undefined'){
 }
 
 function getCusCoeContent() {
-    return '人工×1,材料×1,施工机具×1,主材×1'
+    return '人工×1,材料×1,施工机具×1,主材×1,设备×1'//2019-07-08 bug 添加自定义系数添加设备
 }
 
 function getCustomerCoeData() {
@@ -324,6 +324,7 @@ function getCustomerCoeData() {
         { amount:1, operator:'*', gljCode:null, coeType:'人工'},
         { amount:1, operator:'*', gljCode:null, coeType:'材料'},
         { amount:1, operator:'*', gljCode:null, coeType:'施工机具'},
-        { amount:1, operator:'*', gljCode:null, coeType:'主材'}
+        { amount:1, operator:'*', gljCode:null, coeType:'主材'},
+        { amount:1, operator:'*', gljCode:null, coeType:'设备'}
     ]
 }

文件差異過大導致無法顯示
+ 3 - 3
web/users/html/login.html


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

@@ -42,8 +42,8 @@ $(document).ready(function () {
         captchaObj.appendTo('#captcha-box');
         captchaObj.onSuccess(function () {
             $(".btn-area").slideDown("fast");
-            $('#login').click();
-            captchaObj.getValidate();
+            // $('#login').click();
+            // captchaObj.getValidate();
         });
 
         $("#login").click(function () {
@@ -479,7 +479,7 @@ function setVersion(versionData) {
     let html = '';
     for (let version of versionData) {
         let description = version.description ? version.description : '介绍内容';
-        let tmpHtml = '<div class="col-sm-6">' +
+        let tmpHtml = '<div class="col-sm-6 mb-3">' +
             '<div class="card card-block">' +
             '<div class="card-body">' +
             '<h3 class="card-title">'+ version.name +'</h3>' +