Преглед изворни кода

Merge branch '1.0.0_online' of http://192.168.1.12:3000/SmartCost/ConstructionCost into 1.0.0_online

TonyKang пре 7 година
родитељ
комит
dedae1cf69
86 измењених фајлова са 2290 додато и 1227 уклоњено
  1. 25 14
      config/config.js
  2. 16 16
      config/db/db_manager.js
  3. 1 1
      gulpfile.js
  4. 1 1
      modules/all_models/block_lib_model.js
  5. 1 0
      modules/all_models/projects.js
  6. 1 0
      modules/all_models/ration_coe.js
  7. 1 0
      modules/all_models/ration_template.js
  8. 1 0
      modules/all_models/stdRation_coe.js
  9. 39 5
      modules/fee_rates/facade/fee_rates_facade.js
  10. 26 16
      modules/glj/controllers/glj_controller.js
  11. 80 0
      modules/glj/facade/glj_facade.js
  12. 16 3
      modules/glj/models/unit_price_file_model.js
  13. 1 1
      modules/main/controllers/bills_controller.js
  14. 13 10
      modules/main/facade/bill_facade.js
  15. 73 14
      modules/main/facade/block_lib_facade.js
  16. 10 10
      modules/main/facade/project_facade.js
  17. 4 2
      modules/main/facade/ration_facade.js
  18. 8 7
      modules/main/routes/main_route.js
  19. 21 16
      modules/pm/controllers/pm_controller.js
  20. 134 41
      modules/pm/facade/pm_facade.js
  21. 20 21
      modules/pm/models/project_model.js
  22. 1 0
      modules/pm/routes/pm_route.js
  23. 13 4
      modules/ration_glj/facade/glj_calculate_facade.js
  24. 2 1
      modules/ration_glj/facade/ration_glj_facade.js
  25. 4 0
      modules/users/controllers/login_controller.js
  26. 6 1
      public/gljUtil.js
  27. 1 1
      public/web/common_ajax.js
  28. 13 0
      public/web/gljUtil.js
  29. 106 4
      public/web/sheet/sheet_common.js
  30. 31 24
      public/web/sheet/sheet_data_helper.js
  31. 1 1
      public/web/slideResize.js
  32. 0 1
      public/web/socket/connection.js
  33. 14 0
      socket.js
  34. 1 1
      web/building_saas/complementary_ration_lib/html/dinge.html
  35. 4 3
      web/building_saas/complementary_ration_lib/js/coe.js
  36. 1 1
      web/building_saas/complementary_ration_lib/js/gljSelect.js
  37. 1 0
      web/building_saas/complementary_ration_lib/js/global.js
  38. 2 2
      web/building_saas/complementary_ration_lib/js/ration.js
  39. 6 28
      web/building_saas/complementary_ration_lib/js/section_tree.js
  40. 26 6
      web/building_saas/css/custom.css
  41. 1 1
      web/building_saas/fee_rates/fee_rate.html
  42. 3 3
      web/building_saas/glj/html/project_glj.html
  43. 1 1
      web/building_saas/glj/js/project_glj.js
  44. 2 1
      web/building_saas/js/global.js
  45. 1 0
      web/building_saas/main/html/calc_program_manage.html
  46. 78 40
      web/building_saas/main/html/main.html
  47. 9 1
      web/building_saas/main/js/controllers/block_controller.js
  48. 1 1
      web/building_saas/main/js/controllers/material_controller.js
  49. 2 2
      web/building_saas/main/js/controllers/project_controller.js
  50. 8 3
      web/building_saas/main/js/main.js
  51. 6 1
      web/building_saas/main/js/models/main_consts.js
  52. 4 3
      web/building_saas/main/js/models/ration_coe.js
  53. 2 2
      web/building_saas/main/js/models/ration_glj.js
  54. 20 35
      web/building_saas/main/js/views/billsElf.js
  55. 43 36
      web/building_saas/main/js/views/block_lib.js
  56. 46 24
      web/building_saas/main/js/views/calc_program_manage.js
  57. 40 3
      web/building_saas/main/js/views/fee_rate_view.js
  58. 5 4
      web/building_saas/main/js/views/glj_col.js
  59. 5 18
      web/building_saas/main/js/views/glj_view.js
  60. 1 1
      web/building_saas/main/js/views/main_tree_col.js
  61. 7 3
      web/building_saas/main/js/views/mbzm_view.js
  62. 12 9
      web/building_saas/main/js/views/project_glj_view.js
  63. 4 1
      web/building_saas/main/js/views/project_info.js
  64. 92 33
      web/building_saas/main/js/views/project_view.js
  65. 13 13
      web/building_saas/main/js/views/side_tools.js
  66. 34 9
      web/building_saas/main/js/views/std_billsGuidance_lib.js
  67. 9 5
      web/building_saas/main/js/views/std_ration_lib.js
  68. 30 13
      web/building_saas/main/js/views/sub_view.js
  69. 128 17
      web/building_saas/main/js/views/zmhs_view.js
  70. 1 1
      web/building_saas/pm/html/project-management-Recycle.html
  71. 1 1
      web/building_saas/pm/html/project-management-share.html
  72. 88 103
      web/building_saas/pm/html/project-management.html
  73. 1 2
      web/building_saas/pm/js/pm_gc.js
  74. 551 296
      web/building_saas/pm/js/pm_newMain.js
  75. 173 84
      web/building_saas/pm/js/pm_share.js
  76. 3 2
      web/building_saas/report/html/rpt_print.html
  77. 14 157
      web/building_saas/report/js/rpt_print.js
  78. 7 2
      web/common/html/header.html
  79. 0 0
      web/dest/css/img/blockLib.png
  80. BIN
      web/dest/css/img/copy.png
  81. BIN
      web/dest/css/img/work.png
  82. 34 1
      web/over_write/js/gansu_2013.js
  83. 17 8
      web/over_write/js/jiangxi_2017.js
  84. 31 0
      web/over_write/js/neimenggu_2017.js
  85. 2 1
      web/users/html/login.html
  86. 35 30
      web/users/js/login.js

+ 25 - 14
config/config.js

@@ -10,25 +10,36 @@ module.exports = {
             pass:'smartcost3850888',
             auth: {
                 "authdb": "admin"
-              },
+            },
             connectTimeoutMS: 50000,
             useMongoClient: true
         }
     },
     test_auth: {
-            server: "120.78.150.216",
-            port: "27017",
-            options:{
-                user:'smartcost',
-                pass:'smartcost3850888',
-                auth: {
-                    "authdb": "scConstruct"
-                },
-                connectTimeoutMS: 20000,
-                useMongoClient: true
-            }
+        server: "120.78.150.216",
+        port: "27017",
+        options:{
+            user:'smartcost',
+            pass:'smartcost3850888',
+            auth: {
+                "authdb": "scConstruct"
+            },
+            connectTimeoutMS: 20000,
+            useMongoClient: true
+        }
     },
-    pp:{  server: "112.74.42.187",
+    pp:{  server: "172.18.111.231",
+        port: "27017",
+        options:{
+            user:'smartcost',
+            pass:'SmartCost3850888',
+            auth: {
+                "authdb": "admin"
+            },
+            connectTimeoutMS: 50000,
+            useMongoClient: true
+        }},
+    ab:{  server: "112.74.42.187",
         port: "27017",
         options:{
             user:'smartcost',
@@ -65,7 +76,7 @@ module.exports = {
     getLicenseKey:function (env = "local") {
         let me = this;
         if (me[env].LicenseKey){
-           return  me[env].LicenseKey;
+            return  me[env].LicenseKey;
         }else {
             return me.defaultLicenseKey;
         }

+ 16 - 16
config/db/db_manager.js

@@ -11,29 +11,29 @@ module.exports = {
         var dbURL = 'mongodb://' + server + ":" + port + '/' + dbName;
         return mg.createConnection(dbURL);
         /*/
-        if (port) {
-            mg.connect('mongodb://' + server + ":" + port + '/' + dbName);
-        } else {
-            mg.connect('mongodb://' + server + '/' + dbName);
-        }
-        return mg;
-        //*/
+         if (port) {
+         mg.connect('mongodb://' + server + ":" + port + '/' + dbName);
+         } else {
+         mg.connect('mongodb://' + server + '/' + dbName);
+         }
+         return mg;
+         //*/
     },
     getQAConnection: function(dbName) {
         //*/
         return mg.createConnection("mongodb://192.168.1.184:60666/" + dbName);
         /*/
-        mg.connect('mongodb://192.168.1.184:60666/' + dbName);
-        return mg;
-        //*/
+         mg.connect('mongodb://192.168.1.184:60666/' + dbName);
+         return mg;
+         //*/
     },
     getLocalConnection: function(dbName) {
         //*/
         return mg.createConnection("mongodb://localhost/" + dbName);
         /*/
-        mg.connect('mongodb://localhost:27017/' + dbName);
-        return mg;
-        //*/
+         mg.connect('mongodb://localhost:27017/' + dbName);
+         return mg;
+         //*/
     },
     getCfgConnection: function(dbName) {
         var config = require("../config.js");
@@ -42,9 +42,9 @@ module.exports = {
         var dbURL = 'mongodb://' + config.current.server + ":" + config.current.port + '/' + dbName;
         return mg.createConnection(dbURL);
         /*/
-        mg.connect('mongodb://' + config.current.server + ":" + config.current.port + '/' + dbName);
-        return mg;
-        //*/
+         mg.connect('mongodb://' + config.current.server + ":" + config.current.port + '/' + dbName);
+         return mg;
+         //*/
     },
     connect:function (env="local") {
         var config = require("../config.js");

+ 1 - 1
gulpfile.js

@@ -276,7 +276,7 @@ gulp.task('main_css',function () {
     return css(mainOptions);
 })
 
-gulp.task('main_inject',['main_minify','main_css'],function () {
+gulp.task('main_inject',['main_minify'],function () {//, ['main_minify','main_css'  ] main css 打包到一起会出现样式冲突问题, 现改成不打包
     return inject(mainOptions);
 })
 

+ 1 - 1
modules/all_models/block_lib_model.js

@@ -26,7 +26,7 @@ let dataSchema = new Schema({
 let blockLibsSchema = new Schema({
     userID: String,
     compilationID: String,
-    libID: Number,
+    libID: String,
     libName: String,
     datas: [dataSchema],
     share: {}

+ 1 - 0
modules/all_models/projects.js

@@ -10,6 +10,7 @@ const collectionName = 'projects';
 const shareSchema = new Schema({
     userID: String, //userID
     allowCopy: {type: Boolean, default: false},
+    allowCooperate: {type: Boolean, default: false},
     shareDate: String,
 }, {versionKey: false, _id: false});
 const ProjectSchema = new Schema({

+ 1 - 0
modules/all_models/ration_coe.js

@@ -22,6 +22,7 @@ var coeListSchema = mongoose.Schema({
     content: String,                    // 说明
     original_code:String,               //原人材机编码
     option_codes:String,                //可选人材机编码
+    option_list:[Schema.Types.Mixed],//下拉列表选项
     select_code:String,
     rationID:String,
     projectID:Number,

+ 1 - 0
modules/all_models/ration_template.js

@@ -14,6 +14,7 @@ let ration_template =  new Schema({
         code:String,
         name:String,
         type:String,
+        defaultLocation:String,//记录默认给定的清单编号,恢复原始数据时用(目前复制整块)
         billsLocation:String,//这个是清单编号
         fxID:String,//这个是分项对应的ID
         unit:String,

+ 1 - 0
modules/all_models/stdRation_coe.js

@@ -25,6 +25,7 @@ const coeListSchema = new Schema({
     content: String,                    // 说明
     original_code:String,               //原人材机编码
     option_codes:String,                //可选人材机编码
+    option_list:[Schema.Types.Mixed],//下拉列表选项
     coes: [coeSchema]
 }, {versionKey: false});
 

+ 39 - 5
modules/fee_rates/facade/fee_rates_facade.js

@@ -33,7 +33,8 @@ module.exports={
     updateFeeRates:updateFeeRates,
     updateRates:update_rates,
     feeRateFileSaveAs:feeRateFileSaveAs,
-    getFeeRateByID:getFeeRateByID
+    getFeeRateByID:getFeeRateByID,
+    changeFeeRateFile:changeFeeRateFile
 };
 let operationMap={
     'ut_create':create_fee_rate,
@@ -401,7 +402,7 @@ async function updateFeeRates(datas){//批量更新费率
 async function changeFeeRateFileFromCurrent(jdata){
     let data = JSON.parse(jdata);
     let newFeeRateFile=data.newFeeRateFile;
-    let result = await  projectsModel.findOneAndUpdate({ID:data.projectID},{'property.feeFile':newFeeRateFile});
+    await changeFeeRateFile(data,newFeeRateFile,0);
     let feeRateData = await feeRateFileModel.findOne({'ID':newFeeRateFile.id});
     if(feeRateData!==null){
         let feeRate = await feeRateModel.findOne({ID:feeRateData.feeRateID});
@@ -412,10 +413,43 @@ async function changeFeeRateFileFromCurrent(jdata){
     return feeRateData;
 }
 
+async function changeFeeRateFile(projectData,feeRateFile,type,userID) {
+    let temFile=null,newFeeRateFile = {};
+    if(type == 0){//从本建设项目中替换,直接赋值
+        temFile =  feeRateFile
+    }else if(type == 1) {//从其它建设项目中复制
+        let oldFeeRateFile = await feeRateFileModel.findOne({'ID':feeRateFile.id});
+        let feeRate = await feeRateModel.findOne({ID:oldFeeRateFile.feeRateID});
+        let newFeeRate={};
+        if(! feeRate){
+            throw '不存在对应费率文件';
+        }
+        newFeeRate.ID=uuidV1();
+        newFeeRate.rates =feeRate.rates;
+        newFeeRateFile.ID = uuidV1();
+        newFeeRateFile.name = feeRateFile.name;
+        newFeeRateFile.userID = userID;
+        newFeeRateFile.libName = oldFeeRateFile.libName;
+        newFeeRateFile.libID=oldFeeRateFile.libID;
+        newFeeRateFile.rootProjectID = projectData.rootProjectID;
+        newFeeRateFile.feeRateID =newFeeRate.ID;
+        await feeRateModel.create(newFeeRate);
+        await feeRateFileModel.create(newFeeRateFile);
+        temFile={
+            id:newFeeRateFile.ID,
+            name:feeRateFile.name
+        };
+        newFeeRateFile.rates=newFeeRate.rates;//构建返回数据
+    }
+    await  projectsModel.findOneAndUpdate({ID:projectData.projectID},{'property.feeFile':temFile});
+    return newFeeRateFile
+}
+
+
 async function changeFeeRateFileFromOthers(jdata) {
     let data = JSON.parse(jdata);
-    console.log(data);
-    let feeRateFile = await feeRateFileModel.findOne({'ID':data.feeRateFileID});
+    let newFeeRateFile = await changeFeeRateFile(data,{id:data.feeRateFileID,name:data.name},1,data.userID);
+   /* let feeRateFile = await feeRateFileModel.findOne({'ID':data.feeRateFileID});
     let feeRate = await feeRateModel.findOne({ID:feeRateFile.feeRateID});
     let newFeeRate={};
     newFeeRate.ID=uuidV1();
@@ -435,7 +469,7 @@ async function changeFeeRateFileFromOthers(jdata) {
         name:data.name
     }
     await projectsModel.findOneAndUpdate({ID:data.projectID},{'property.feeFile':feeFile});
-    newFeeRateFile.rates=newFeeRate.rates;
+    newFeeRateFile.rates=newFeeRate.rates;*/
     newFeeRateFile.usageProjects=await getUsageProjects(newFeeRateFile.ID);
     return newFeeRateFile;
 }

+ 26 - 16
modules/glj/controllers/glj_controller.js

@@ -14,6 +14,7 @@ import UnitPriceFileModel from "../models/unit_price_file_model";
 let logger = require("../../../logs/log_helper").logger;
 let consts = require('../../main/models/project_consts');
 let glj_type_util = require('../../../public/cache/std_glj_type_util');
+let ration_glj_facade = require('../../ration_glj/facade/ration_glj_facade');
 let mongoose = require('mongoose');
 let ration = mongoose.model('ration');
 let projectModel = mongoose.model('projects');
@@ -244,23 +245,29 @@ class GLJController extends BaseController {
             let gljList = data.gljList, parentInfo = data.parentInfo,mixRatios = [];
             let projectGljModel = new GLJListModel();
             let mixRatioModel = new MixRatioModel();
-            for(let g of gljList){
-                let newProjectGLJ = await projectGljModel.addList(g,parentInfo.unit_price_file_id);
-                let mixRatio = {
-                    glj_id:newProjectGLJ.glj_id,
-                    consumption:0,
-                    unit_price_file_id:parentInfo.unit_price_file_id,
-                    connect_key:parentInfo.connect_key,
-                    type: newProjectGLJ.type,
-                    code: newProjectGLJ.code,
-                    specs:newProjectGLJ.specs,
-                    name:newProjectGLJ.name,
-                    unit:newProjectGLJ.unit,
-                    model:newProjectGLJ.model
-                };
-                newProjectGLJ.ratio_data = await mixRatioModel.add(mixRatio);
-                mixRatios.push(newProjectGLJ);
+            if(gljList.length > 0){
+                let [unitFileId,ext] = await ration_glj_facade.prepareExtData(gljList[0].project_id,request.session.sessionCompilation);
+                console.log(ext);
+                for(let g of gljList){
+                    let newProjectGLJ = await projectGljModel.addList(g,unitFileId,ext);
+                    let mixRatio = {
+                        glj_id:newProjectGLJ.glj_id,
+                        consumption:0,
+                        unit_price_file_id:unitFileId,
+                        connect_key:parentInfo.connect_key,
+                        type: newProjectGLJ.type,
+                        code: newProjectGLJ.code,
+                        specs:newProjectGLJ.specs,
+                        name:newProjectGLJ.name,
+                        unit:newProjectGLJ.unit,
+                        model:newProjectGLJ.model
+                    };
+                    newProjectGLJ.ratio_data = await mixRatioModel.add(mixRatio);
+                    mixRatios.push(newProjectGLJ);
+                }
+
             }
+
             result.data = mixRatios;
         }catch (err){
             logger.err(err);
@@ -277,6 +284,9 @@ class GLJController extends BaseController {
      * @return {void}
      */
     async getProjectInfo(request, response) {
+        if(typeof request.body.data == "string"){
+            request.body = JSON.parse(request.body.data)
+        }
         let projectId = request.body.project_id;
         let rootProjectID = request.body.rootProjectID;
         projectId = parseInt(projectId);

+ 80 - 0
modules/glj/facade/glj_facade.js

@@ -0,0 +1,80 @@
+/**
+ * Created by zhang on 2019/1/2.
+ */
+module.exports={ //先导出后require可以解决循环引用问题
+    changeUnitFile:changeUnitFile
+};
+
+const ProjectModel = require('../../pm/models/project_model').project;
+import UnitPriceFileModel from "../models/unit_price_file_model";
+import UnitPriceModel from "../models/unit_price_model";
+
+async function changeUnitFile(projectData,unitFile,type,userID) {
+    let projectId = projectData.projectID;
+    let changeUnitPriceId = unitFile.id;
+    let newName = unitFile.name;
+    type = parseInt(type);
+
+        let currentUnitPriceId = await ProjectModel.getUnitPriceFileId(projectId);
+        let unitPriceFileModel = new UnitPriceFileModel();
+
+        let insertData = null;
+        if (type > 0) {
+            let currentUnitPrice = await unitPriceFileModel.findDataByCondition({id: changeUnitPriceId});
+            if (currentUnitPrice === null) {
+                throw '不存在对应单价文件';
+            }
+            // 获取当前项目的rootProjectId
+            let projectData = await ProjectModel.getProject(projectId);
+            let rootProjectId = projectData.property.rootProjectID !== undefined ? projectData.property.rootProjectID : 0;
+
+            insertData = JSON.parse(JSON.stringify(currentUnitPrice));
+            insertData.root_project_id = rootProjectId;
+            newName?insertData.name = newName:'';
+            insertData.user_id = userID;
+            delete insertData._id;
+            delete insertData.ID;
+        }
+        // 获取即将更改的单价文件信息
+        let targetUnitPriceFile = type === 0 ? await unitPriceFileModel.findDataByCondition({id: changeUnitPriceId}) :
+            await unitPriceFileModel.add(insertData);
+        if (targetUnitPriceFile === null) {
+            throw '没有找到对应的单价文件';
+        }
+
+        // 查找对应单价文件的项目工料机数据
+        let unitPriceModel = new UnitPriceModel();
+        if(type ===1){//从其它项目复制,则先复制一份数据。
+            let needCopyList = await unitPriceModel.findDataByCondition({unit_price_file_id: changeUnitPriceId}, null, false);
+            if(needCopyList){
+                // 过滤mongoose格式
+                needCopyList = JSON.stringify(needCopyList);
+                needCopyList = JSON.parse(needCopyList);
+                let copyList = [];
+                for(let n of needCopyList){
+                    delete n._id;  // 删除原有id信息
+                    delete n.id;
+                    n.unit_price_file_id = targetUnitPriceFile.id;
+                    copyList.push(n);
+                }
+                copyList.length>0 ? await unitPriceModel.add(copyList):'';
+            }
+        }
+
+
+        let copyResult = await unitPriceModel.copyNotExist(currentUnitPriceId, targetUnitPriceFile.id,projectId);
+        // 复制成功后更改project数据
+        if (!copyResult) {
+            throw '复制数据失败';
+        }
+
+        let changeUnitPriceFileInfo = {
+            id: targetUnitPriceFile.id,
+            name: targetUnitPriceFile.name
+        };
+        let result = ProjectModel.changeUnitPriceFileInfo(projectId, changeUnitPriceFileInfo);
+        if (!result) {
+            throw '切换单价文件失败!';
+        }
+        return changeUnitPriceFileInfo;
+}

+ 16 - 3
modules/glj/models/unit_price_file_model.js

@@ -8,9 +8,8 @@
 import mongoose from "mongoose";
 import BaseModel from "../../common/base/base_model";
 import CounterModel from "./counter_model";
-const ProjectModel = require('../../pm/models/project_model').project;
 let collectionName = 'unit_price_file';
-
+let Projects = mongoose.model('projects');
 class UnitPriceFileModel extends BaseModel {
 
     /**
@@ -74,7 +73,7 @@ class UnitPriceFileModel extends BaseModel {
                 throw '标段id有误';
             }
 
-            let unitPriceFileId =await ProjectModel.getUnitPriceFileId(projectId);
+            let unitPriceFileId =await this.getUnitPriceFileId(projectId);
             if (unitPriceFileId <= 0) {
                 throw '没有对应的单价文件';
             }
@@ -88,6 +87,20 @@ class UnitPriceFileModel extends BaseModel {
         return result;
     }
 
+    async getUnitPriceFileId(projectId){
+        let result = 0;
+        let startTime = +new Date();
+        let projectData = await Projects.find({ID: projectId},['property.unitPriceFile']);
+        if (projectData === null) {
+            return result;
+        }
+        let endTime = +new Date();
+        console.log("取单价文件列表id时间-----"+(endTime - startTime));
+        projectData = projectData[0];
+        result = projectData.property.unitPriceFile !== undefined ? projectData.property.unitPriceFile.id : 0;
+        return result;
+    }
+
     /**
      * 新增单条工料机数据
      *

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

@@ -183,7 +183,7 @@ module.exports = {
         try {
             let data = req.body.data;
             data = JSON.parse(data);
-            let pasteResult = await bill_facade.pasteBlock(data);
+            let pasteResult = await bill_facade.pasteBlock(data,req.session.sessionCompilation);
             result.data = pasteResult;
         }catch (err){
             logger.err(err);

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

@@ -72,9 +72,9 @@ module.exports={
         }
        return result;
     },
-    pasteBlock : async function(data){
+    pasteBlock : async function(data,compilation){
         let pasteTasks = [
-            pasteRationsAndRationGLJ(data.rations,data.ration_gljs),//这一步会花费比较多时间
+            pasteRationsAndRationGLJ(data.rations,data.ration_gljs,compilation),//这一步会花费比较多时间
             pasteOtherData(data)
         ];
         let [rationsAndRationGLJ,resultMap] = await Promise.all(pasteTasks);
@@ -148,19 +148,22 @@ async function pasteOtherData(data) {
     return {bills:bills,quantity_details:quantity_details,ration_coes:ration_coes,ration_installations:ration_installations,ration_templates:ration_templates,updateData:updateData}
 }
 
-async function pasteRationsAndRationGLJ (rations,ration_gljs) {
+async function pasteRationsAndRationGLJ (rations,ration_gljs,compilation) {
     let projectGljModel = new GLJListModel();
-    let gljMap = {};
-    let new_ration_gljs=[];
+    let gljMap = {}, new_ration_gljs=[],projectID=null;
+    if(rations.length > 0) projectID = rations[0].projectID;
+    if(projectID==null && ration_gljs.length > 0) projectID = ration_gljs[0].projectID;
+    if(projectID == null) return {rations:rations,new_ration_gljs:new_ration_gljs};
+    let [unitFileId,ext] = await ration_glj_facade.prepareExtData(projectID,compilation);
     //先根据定额类型的工料机,插入到项目工料机中
     for(let r of rations){
         if(r.type == rationType.gljRation){
-            await getProjectGLJ(r,rationKeyArray,gljMap);
+            await getProjectGLJ(r,rationKeyArray,gljMap,unitFileId,ext);
         }
     }
 
     for(let rg of ration_gljs){
-        await getProjectGLJ(rg,gljKeyArray,gljMap);
+        await getProjectGLJ(rg,gljKeyArray,gljMap,unitFileId,ext);
         let temRecord = ration_glj_facade.createNewRecord(rg);
         rg.rcode?temRecord.rcode = rg.rcode:'';
         rg.hasOwnProperty("customQuantity")?temRecord.customQuantity = rg.customQuantity:'';
@@ -170,16 +173,16 @@ async function pasteRationsAndRationGLJ (rations,ration_gljs) {
     rations.length>0?await insertMany(rations,ration_Model):'';
     new_ration_gljs.length>0?await insertMany(new_ration_gljs,ration_glj_Model):'';
 
-    return{rations:rations,new_ration_gljs:new_ration_gljs};
+    return {rations:rations,new_ration_gljs:new_ration_gljs};
 
-    async function getProjectGLJ (glj,keyArray,gljMap) {
+    async function getProjectGLJ (glj,keyArray,gljMap,unitFileId,ext) {
         let keyIndex = projectGljModel.getIndex(glj,keyArray);
         let pgljResult = null;
         if(gljMap[keyIndex]){
             pgljResult = gljMap[keyIndex]
         }else {
             let p_glj = ration_glj_facade.getGLJSearchInfo(glj);
-            pgljResult = await projectGljModel.addList(p_glj);//逐条添加到项目工料机
+            pgljResult = await projectGljModel.addList(p_glj,unitFileId,ext);//逐条添加到项目工料机
             gljMap[keyIndex] = pgljResult;
         }
         setResult(glj,pgljResult);

+ 73 - 14
modules/main/facade/block_lib_facade.js

@@ -4,17 +4,19 @@
 
 let mongoose = require('mongoose');
 let blModel = mongoose.model('blockLibsModel');
+let uuid = require('../../../public/web/uuid');
 
 module.exports = {
     getLibNames: getLibNames,
     getLib: getLib,
     getLibNamesAndFirstLib: getLibNamesAndFirstLib,
+    copyTemplateLib: copyTemplateLib,
     saveBlock: saveBlock
 };
 
 // userID、compilationID
 async function getLibNames(data) {
-    let libNames = await blModel.find({userID: data.userID, compilation: data.compilationID}, ["libID","libName","-_id"]);
+    let libNames = await blModel.find({userID: data.userID, compilationID: data.compilationID}, ["libID","libName","-_id"]);
     return libNames;
 };
 
@@ -27,30 +29,87 @@ async function getLib(data) {
 // userID、compilationID
 async function getLibNamesAndFirstLib(data) {
     let libNames = await getLibNames(data);
-    let firstLib = await getLib(libNames[0]);
-    return {libNames: libNames, firstLib: firstLib};
+    let lib = null;
+    if (libNames.length == 0){
+        lib = await copyTemplateLib(data.userID, data.userName, data.compilationID);
+        libNames.push({libID: lib.libID, libName: lib.libName});
+    }
+    else{
+        lib = await getLib(libNames[0]);
+    }
+    return {libNames: libNames, firstLib: lib};
 };
 
-/*------------------------------------------------------------------------------
-data参数示例:
-        {
-            libID: 3,
-            nodeID: 5,
-            create: {node}
-            delete: true
-            update: {nodeName: 'xxx', children: [...]}
+
+async function copyTemplateLib(userID, userName, compilationID) {
+    // let template = await getLib({libID: '00000000'});
+    let template = {
+        libID: "00000000",
+        libName: "模板",
+        datas: [
+            {
+                "ID": "00000001",
+                "ParentID": "-1",
+                "NextSiblingID": "00000002",
+                "type": 1,
+                "nodeName": "分类1"
+            },
+            {
+                "ID": "00000002",
+                "ParentID": "-1",
+                "NextSiblingID": "00000003",
+                "type": 1,
+                "nodeName": "分类2"
+            },
+            {
+                "ID": "00000003",
+                "ParentID": "-1",
+                "NextSiblingID": "-1",
+                "type": 1,
+                "nodeName": "分类3"
+            }
+        ],
+        share: {
+            "shareName": "共享",
+            "shareTo": []
         }
+    };
+
+    let newLib = {
+        userID: userID,
+        compilationID: compilationID,
+        libID: uuid.v1(),
+        libName: `${userName}的块模板库`,
+        datas: template.datas,
+        share: template.share
+    };
+    newLib.share.shareName = `共享-${newLib.libName}`;
+    await blModel.create(newLib);
+    // console.log(JSON.stringify(newLib));
+    return newLib;
+};
+
+/*------------------------------------------------------------------------------
+参数:   {libID: n, nodeID: m, create: {node} | delete: true | update: {A:'xxx', B:'xxx'} }
 说明:   libID、nodeID 必须。 create|update|delete三选一。
-        create属性值是完整的node节点数据。
-        delete属性值是true。
-        update属性值是要修改的属性键值对组成的对象。
+        create属性值:完整的node节点数据。
+        delete属性值:固定为true(false没有实际意义)。
+        update属性值:列出多个要修改的结点属性(键值对组成的对象)。
+示例:   {libID: 3, nodeID: 5, create: {....}}
+        {libID: 3, nodeID: 5, delete: true}
+        {libID: 3, nodeID: 5, update: {nodeName: 'xxx', children: [...]} }
 ------------------------------------------------------------------------------*/
 async function saveBlock(data) {
     if (data.create) {
         await blModel.update({libID: data.libID}, {$addToSet: {datas: data.create}});
     }
     if (data.delete) {
+        console.log(JSON.stringify(data));
+        console.log(data.nodeID);
         await blModel.update({libID: data.libID}, {$pull: {datas: {ID: data.nodeID}}});
+        if (data.delete.nodeType == 1){    // 同步删除所有子结点
+            await blModel.update({libID: data.libID}, {$pull: {datas: {ParentID: data.nodeID}}});
+        }
     }
     else if (data.update){
         let doc = await blModel.findOne({libID: data.libID});

+ 10 - 10
modules/main/facade/project_facade.js

@@ -24,7 +24,8 @@ module.exports = {
     updateNodes:updateNodes,
     calcInstallationFee:calcInstallationFee,
     saveProperty: saveProperty,
-    getDefaultColSetting: getDefaultColSetting
+    getDefaultColSetting: getDefaultColSetting,
+    markProjectsToChange:markProjectsToChange
 };
 
 async function calcInstallationFee(data) {
@@ -214,9 +215,7 @@ async function updateNodes(datas){
 
 //data = {feeRateID:111111,projectID:1245}; type = feeRate
 async function markUpdateProject(data,type) {
-    let tasks=[];
     let query = {deleteInfo:null};
-    let result = null;
     if(type=="feeRate"){//更改了费率
         query['property.feeFile.id'] = data.feeRateID;
     }
@@ -224,15 +223,16 @@ async function markUpdateProject(data,type) {
         query['property.unitPriceFile.id'] = data.unitFileID;//unitPriceFile
     }
     let projects = await projectsModel.find(query);
+    return await markProjectsToChange(projects,type,data.projectID);
+}
+
+async function markProjectsToChange(projects,type,extProjectID){
+    let tasks=[];
     for(let p of projects){
-        if(p.ID!=data.projectID){//当前项目不用更新
-            tasks.push(generateMarkTask(type,p.ID));
-        }
-    }
-    if(tasks.length>0){
-        result = await projectsModel.bulkWrite(tasks);
+        if(extProjectID && p.ID===extProjectID) continue;//排除当前项目
+        tasks.push(generateMarkTask(type,p.ID));
     }
-    return result;
+    return tasks.length>0 ? await projectsModel.bulkWrite(tasks):null;
 }
 
 async function removeProjectMark(projectID) {

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

@@ -215,7 +215,7 @@ async function addRationSubList(stdRation,newRation,needInstall,compilation) {
     console.log("添加定额install时间-----"+(addRationInstallFeeTime - addRationCoeTime));
     //添加定额模板子目
     let ration_template = await addRationTemplate(stdRation,newRation);
-    return {ration:newRation,ration_gljs:ration_gljs,ration_coes:ration_coes,ration_installations:ration_installations,ration_templates:[ration_template]};
+    return {ration:newRation,ration_gljs:ration_gljs,ration_coes:ration_coes,ration_installations:ration_installations,ration_templates:ration_template?[ration_template]:[]};
 }
 
 async function addRationInstallFee(std,newRation) {
@@ -274,6 +274,7 @@ async function addRationTemplate(std,newRation) {
                 template.type = tem.type;
                 template.unit = re_ration.unit;
                 template.billsLocation = tem.billsLocation;
+                template.defaultLocation = tem.billsLocation;
                 templateList.push(template)
             }
         }
@@ -312,6 +313,7 @@ async function addRationCoe(std,newRation,compilation) {
                 newCoe.content = libCoe.content;
                 newCoe.original_code = libCoe.original_code;
                 newCoe.option_codes = libCoe.option_codes;
+                newCoe.option_list = libCoe.option_list;
                 newCoe.isAdjust=0;
                 newCoe.coes = libCoe.coes;
                 newCoe.rationID = newRation.ID;
@@ -347,7 +349,7 @@ async function getCustomerCoe(projectID,rationID,seq,compilation){//取自定义
         coeID:-1,
         name : '自定义系数',
         content:'人工×1,材料×1,机械×1,主材×1,设备×1',
-        isAdjust:0,
+        isAdjust:1,
         seq:seq,
         rationID : rationID,
         projectID : projectID

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

@@ -11,16 +11,16 @@ module.exports =function (app) {
     app.get('/main', baseController.init, function(req, res) {
         let pm = require('../../pm/controllers/pm_controller');
 
-        pm.checkProjectRight(req.session.sessionUser.id, req.query.project, async function (hasRight) {
+        pm.checkProjectRight(req.session.sessionUser.id, req.query.project, async function (hasRight, projectData, shareInfo) {
             if (hasRight) {
-                // 获取项目信息
-                const projectId = req.query.project;
-                const projectData = await projectModel.project.getProject(projectId);
-                //分享的项目,只读
-                let projectReadOnly = false;
+                //分享的项目,只读、协作(允许编辑)
+                let projectReadOnly = false,
+                    projectCooperate = false;
                 if(req.session.sessionUser.id !== projectData.userID){
                     projectData._doc.readOnly = true;
-                    projectReadOnly = true;
+                    projectCooperate = !!shareInfo.allowCooperate;
+                    //允许协作的项目允许编辑,非只读
+                    projectReadOnly = !projectCooperate;
                 }
                 res.render('building_saas/main/html/main.html',
                     {
@@ -30,6 +30,7 @@ module.exports =function (app) {
                         compilationName: req.session.sessionCompilation.name,
                         versionName: `纵横建筑云计价(${req.session.compilationVersion})`,
                         projectReadOnly: projectReadOnly,
+                        projectCooperate: projectCooperate,
                         LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
                         overWriteUrl:req.session.sessionCompilation.overWriteUrl
                     });

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

@@ -52,13 +52,13 @@ module.exports = {
              * result._doc.userID(Number): MongoDB
              * userId(String): Session.userID
              */
-            let isShare = false;
-            //判断是否是打开分享的项目
+            let shareInfo = null;
+            //判断是否是打开分享的项目,分享项目shareInfo不为null
             if(userId !== result.userID){
-                isShare = await pm_facade.isShare(userId, result);
+                shareInfo = await pm_facade.getShareInfo(userId, result);
             }
-            if ((userId === result.userID || isShare) && result._doc.projType === projType.tender) {
-                callback(true);
+            if ((userId === result.userID || shareInfo) && result._doc.projType === projType.tender) {
+                callback(true, result, shareInfo);
             } else {
                 callback(false);
             }
@@ -67,8 +67,6 @@ module.exports = {
         });
     },
     getProjects: async function(req, res){
-        console.log(`req.session.sessionCompilation`);
-        console.log(req.session.sessionCompilation);
          await ProjectsData.getUserProjects(req.session.sessionUser.id, req.session.sessionCompilation._id, function(err, message, projects){
             if (projects) {
                 callback(req, res, err, message, projects);
@@ -250,14 +248,7 @@ module.exports = {
         request.session.sessionCompilation = compilationData;
         sessionCompilation = request.session.sessionCompilation;
         //更新用户的使用过的费用定额列表
-        let userData = await userModel.findOne({_id: mongoose.Types.ObjectId(request.session.sessionUser.id)}, '-_id used_list');
-        //是否第一次进入该费用定额
-        let isFirst = false;
-        if (userData) {
-            isFirst = !_.find(userData.used_list, function (o) {
-                return o.compilationId === compilationData._id.toString();
-            });;
-        }
+        let isFirst = await pm_facade.isFirst(request.session.sessionUser.id, compilationData._id.toString());
         // 清单计价
         let billValuation = sessionCompilation.bill_valuation !== undefined ?
             sessionCompilation.bill_valuation : [];
@@ -536,12 +527,14 @@ module.exports = {
                 for (let sData of data.shareData) {
                     await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$addToSet: {shareInfo: sData}});
                 }
+            } else if (data.type === 'update') {
+                await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$set: {shareInfo: data.shareData}});
             }
             //取消分享
             else {
                 await projectModel.update({ID: data.projectID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]}, {$pull: {shareInfo: {userID: {$in: shareUserIDs}}}});
             }
-            callback(req, res, 0, 'success', null);
+            callback(req, res, 0, 'success', data.shareData);
         }
         catch (err){
             callback(req, res, 1, err, null);
@@ -646,4 +639,16 @@ module.exports = {
             callback(req, res, 1, err, null);
         }
     },
+    changeFile:async function(req,res){
+        try{
+            let data = JSON.parse(req.body.data);
+            console.log(data);
+            await pm_facade.changeFile(data.projects,data.user_id,data.fileID,data.name,data.from,data.type);
+            callback(req, res, 0, 'success', []);
+        }
+        catch (err){
+            console.log(err);
+            callback(req, res, 1, err, null);
+        }
+    }
 };

+ 134 - 41
modules/pm/facade/pm_facade.js

@@ -1,9 +1,39 @@
 /**
  * Created by zhang on 2018/4/17.
  */
+const projectType = {
+    folder: 'Folder',
+    tender: 'Tender',
+    project: 'Project',
+    engineering: 'Engineering',
+};
+//先导出后require可以解决循环引用问题
+module.exports={
+    moveProject:moveProject,
+    copyProject:copyProject,
+    copyExample: copyExample,
+    getSummaryInfo: getSummaryInfo,
+    getSummaryInfoByTender: getSummaryInfoByTender,
+    getTendersFeeInfo: getTendersFeeInfo,
+    getConstructionProject: getConstructionProject,
+    getFullPath: getFullPath,
+    getProjectFeature:getProjectFeature,
+    projectType: projectType,
+    getPosterityProjects: getPosterityProjects,
+    isShare: isShare,
+    isFirst: isFirst,
+    getShareInfo: getShareInfo,
+    prepareInitialData: prepareInitialData,
+    changeFile:changeFile,
+};
+
+
+
 let mongoose = require('mongoose');
 let _ = require("lodash");
 let feeRate_facade = require('../../fee_rates/facade/fee_rates_facade');
+let glj_facade = require('../../glj/facade/glj_facade');
+let project_facade = require('../../main/facade/project_facade');
 let logger = require("../../../logs/log_helper").logger;
 const uuidV1 = require('uuid/v1');
 let projectModel = mongoose.model('projects');
@@ -23,6 +53,7 @@ let rationGLJModel = mongoose.model('ration_glj');
 let rationCoeModel = mongoose.model('ration_coe');
 let rationInstallationModel = mongoose.model('ration_installation');
 let quantityDetailModel = mongoose.model('quantity_detail');
+let rationTemplateModel = mongoose.model('ration_template');
 let userModel = mongoose.model('user');
 let compleGljSectionModel = mongoose.model('complementary_glj_section');
 let compleGljSectionTModel = mongoose.model('complementary_glj_section_templates');
@@ -35,30 +66,9 @@ let sectionTreeDao = new SectionTreeDao();
 import CounterModel from "../../glj/models/counter_model";
 import moment from 'moment';
 import billsFlags from '../../common/const/bills_fixed';
-const projectType = {
-    folder: 'Folder',
-    tender: 'Tender',
-    project: 'Project',
-    engineering: 'Engineering',
-};
 const notDeleted = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
 
 
-module.exports={
-    moveProject:moveProject,
-    copyProject:copyProject,
-    copyExample: copyExample,
-    getSummaryInfo: getSummaryInfo,
-    getSummaryInfoByTender: getSummaryInfoByTender,
-    getTendersFeeInfo: getTendersFeeInfo,
-    getConstructionProject: getConstructionProject,
-    getFullPath: getFullPath,
-    getProjectFeature:getProjectFeature,
-    projectType: projectType,
-    getPosterityProjects: getPosterityProjects,
-    isShare: isShare,
-    prepareInitialData: prepareInitialData,
-};
 
 //拷贝例题项目
 //@param {String}userID {Array}projIDs拷贝的例题项目ID(建设项目、文件夹)@return {Boolean}
@@ -204,7 +214,8 @@ async function copyProject(userID, compilationID,data,newProjectID = null) {
         copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationGLJModel),
         copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationCoeModel),
         copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,quantityDetailModel),
-        copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationInstallationModel)
+        copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationInstallationModel),
+        copyRationSubList(originalID,newProjectID,billMap.uuidMaping,rationMap.uuidMaping,projectGLJMap.IDMap,rationTemplateModel)
     ];
     if(originalProperty.calcProgramFile){
         copyTasks.push(commonCopy(newProjectID,originalProperty.calcProgramFile.ID,calcProgramFileID,calcProgramsModel));
@@ -292,6 +303,7 @@ async function copyRations(newProjectID,billsIDMap,rationMap,projectGLJIDMap) {
         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]:'';
     }
@@ -382,7 +394,7 @@ async function copyInstallFee(originalPID,newProjectID) {
     return result;
 }
 
-async function copyRationSubList(originalPID,newProjectID,billIDMap,rationIDMap,projectGLJIDMap,model) {// 定额工料机,附注条件,工程量明细,定额安装增加费
+async function copyRationSubList(originalPID,newProjectID,billIDMap,rationIDMap,projectGLJIDMap,model) {// 定额工料机,附注条件,工程量明细,定额安装增加费,模板子目
     let subList = await model.find({projectID:originalPID}, '-_id');
     let newList =[];
     for(let s of subList){
@@ -392,7 +404,14 @@ async function copyRationSubList(originalPID,newProjectID,billIDMap,rationIDMap,
         s._doc.billID&&billIDMap[s._doc.billID]?s._doc.billID = billIDMap[s._doc.billID]:'';
         s._doc.billsItemID&&billIDMap[s._doc.billsItemID]?s._doc.billsItemID = billIDMap[s._doc.billsItemID]:'';
         s._doc.projectGLJID&&projectGLJIDMap[s._doc.projectGLJID]?s._doc.projectGLJID = projectGLJIDMap[s._doc.projectGLJID]:'';
+        if(s._doc.templateList && s._doc.templateList.length > 0 ){
+            for(let t of s._doc.templateList){
+                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);
 }
@@ -574,7 +593,7 @@ function isDef(v){
     return typeof v !== 'undefined' && v !== null;
 }
 
-function getCommonTotalFee(bills) {
+function getTotalFee(bills, feeName) {
     if(!isDef(bills)){
         return 0;
     }
@@ -582,7 +601,7 @@ function getCommonTotalFee(bills) {
         return 0;
     }
     for(let fee of bills.fees){
-        if(isDef(fee.fieldName) && fee.fieldName === 'common'){
+        if(isDef(fee.fieldName) && fee.fieldName === feeName){
             return isDef(fee.totalFee) ? fee.totalFee : 0;
         }
     }
@@ -591,13 +610,18 @@ function getCommonTotalFee(bills) {
 
 function summarizeToParent(parent, child) {
     const decimal = -2;
+    let costFields = ['engineeringCost', 'subEngineering', 'measure', 'safetyConstruction', 'other', 'charge', 'tax', 'estimate'];
+    for (let field of costFields) {
+        parent[field] = scMathUtil.roundTo(parseFloat(parent[field]) + parseFloat(child[field]), decimal);
+    }
+   /* const decimal = -2;
     parent.engineeringCost = scMathUtil.roundTo(parseFloat(parent.engineeringCost) + parseFloat(child.engineeringCost), decimal);
     parent.subEngineering = scMathUtil.roundTo(parseFloat(parent.subEngineering) + parseFloat(child.subEngineering), decimal);
     parent.measure = scMathUtil.roundTo(parseFloat(parent.measure) + parseFloat(child.measure), decimal);
     parent.safetyConstruction = scMathUtil.roundTo(parseFloat(parent.safetyConstruction) + parseFloat(child.safetyConstruction), decimal);
     parent.other = scMathUtil.roundTo(parseFloat(parent.other) + parseFloat(child.other), decimal);
     parent.charge = scMathUtil.roundTo(parseFloat(parent.charge) + parseFloat(child.charge), decimal);
-    parent.tax = scMathUtil.roundTo(parseFloat(parent.tax) + parseFloat(child.tax), decimal);
+    parent.tax = scMathUtil.roundTo(parseFloat(parent.tax) + parseFloat(child.tax), decimal);*/
 }
 
 function getBuildingArea(projFeature){
@@ -670,7 +694,7 @@ async function getTendersFeeInfo(tenders) {
     if(tenders.length > 0){
         for(let tender of tenders){
             tenderIDs.push(tender.ID);
-            IDMapping[tender.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, buildingArea: '', perCost: ''};
+            IDMapping[tender.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, estimate: 0, rate: 0, buildingArea: '', perCost: ''};
             IDMapping[tender.ID]['buildingArea'] = '';
         }
         //需要获取的清单固定类别综合合价:工程造价、分部分项、措施项目、安全文明施工专项、规费、其他项目、税金
@@ -683,7 +707,11 @@ async function getTendersFeeInfo(tenders) {
         for(let bills of allBills){
             let billsFlag = bills.flags[0]['flag'];
             let costField = flagFieldMapping[billsFlag];
-            IDMapping[bills.projectID][costField] = getCommonTotalFee(bills);
+            IDMapping[bills.projectID][costField] = getTotalFee(bills, 'common');
+            //暂估合价(工程造价暂估合价)
+            if (billsFlag === billsFlags.ENGINEERINGCOST){
+                IDMapping[bills.projectID]['estimate'] = getTotalFee(bills, 'estimate');
+            }
         }
         //占造价比例、单方造价
         for(let tender of tenders){
@@ -723,7 +751,7 @@ async function getSummaryInfo(projectIDs){
                 }
             }
         }
-        IDMapping[project.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, buildingArea: grossArea, perCost: ''};
+        IDMapping[project.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, estimate: 0, rate: 0, buildingArea: grossArea, perCost: ''};
     }
 
     //单项工程
@@ -733,7 +761,7 @@ async function getSummaryInfo(projectIDs){
     let engIDs = [];
     for(let eng of engineerings){
         engIDs.push(eng.ID);
-        IDMapping[eng.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, buildingArea: '', perCost: ''};
+        IDMapping[eng.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, estimate: 0, rate: 0, buildingArea: '', perCost: ''};
     }
     if(engIDs.length > 0){
         tenders = await projectModel.find({ParentID: {$in : engIDs}, projType: projectType.tender, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]});
@@ -742,7 +770,8 @@ async function getSummaryInfo(projectIDs){
     if(tenders.length > 0){
         for(let tender of tenders){
             tenderIDs.push(tender.ID);
-            IDMapping[tender.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, buildingArea: '', perCost: '',changeMark:tender.changeMark,property:tender.property};
+            IDMapping[tender.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, estimate: 0,
+                buildingArea: '', perCost: '',changeMark:tender.changeMark,property:tender.property};
             let buildingArea = getBuildingArea(tender.property.projectFeature);
             if(buildingArea){
                 IDMapping[tender.ID]['buildingArea'] = buildingArea;
@@ -758,7 +787,11 @@ async function getSummaryInfo(projectIDs){
         for(let bills of allBills){
             let billsFlag = bills.flags[0]['flag'];
             let costField = flagFieldMapping[billsFlag];
-            IDMapping[bills.projectID][costField] = getCommonTotalFee(bills);
+            IDMapping[bills.projectID][costField] = getTotalFee(bills, 'common');
+            //暂估合价(工程造价暂估合价)
+            if (billsFlag === billsFlags.ENGINEERINGCOST){
+                IDMapping[bills.projectID]['estimate'] = getTotalFee(bills, 'estimate');
+            }
         }
         //进行单项工程级别的汇总
         for(let tender of tenders){
@@ -872,7 +905,35 @@ async function getPosterityProjects(projectIDs) {
     return rst;
 }
 
-//打开的单位工程是否是被分享的
+//根据项目获得分享信息(分享层级不一定在项目级)(以最新为准)
+//@param {String}userId {Object}tender @return {Object} || {null}
+async function getShareInfo(userId, project) {
+    //与该用户相关的分享
+    let shareList = [];
+    while (project) {
+        for(let shareData of project.shareInfo){
+            if(shareData.userID === userId){
+                shareList.push(shareData);
+                break;
+            }
+        }
+        project = await projectModel.findOne({ID: project.ParentID}, '-_id shareInfo ID ParentID');
+    }
+    //获取最新分享
+    shareList.sort(function (a, b) {
+        let aV = Date.parse(a.shareDate),
+            bV = Date.parse(b.shareDate);
+        if (aV > bV) {
+            return -1;
+        } else if (aV < bV) {
+            return 1;
+        }
+        return 0;
+    });
+    return shareList[0] || null;
+}
+
+//打开的单位工程是否是被分享的.
 async function isShare(userId, project){
     //判断是否是打开分享的项目,属于分享文件的子项也算
     while (project) {
@@ -886,17 +947,32 @@ async function isShare(userId, project){
     return false;
 }
 
+//用户是否第一次进入费用定额
+async function isFirst(userId, compilationId) {
+    let userData = await userModel.findOne({_id: mongoose.Types.ObjectId(userId)}, '-_id used_list');
+    let first = false;
+    if (userData) {
+        first = !_.find(userData.used_list, function (o) {
+            return o.compilationId === compilationId;
+        });;
+    }
+    return first;
+}
+
 //用户第一次进入费用定额的数据准备
 async function prepareInitialData(userId, compilation, example) {
-    let prepareTask = [
-        updateUsedList(userId, compilation),
-        copyCompleRationSection(userId, compilation),
-        copyCompleGljSection(userId, compilation)
-    ];
-    if (example && example.length > 0) {
-        prepareTask.push(copyExample(userId, compilation, example));
+    let first = await isFirst(userId, compilation);
+    if (first) {
+        await updateUsedList(userId, compilation);
+        let prepareTask = [
+            copyCompleRationSection(userId, compilation),
+            copyCompleGljSection(userId, compilation)
+        ];
+        if (example && example.length > 0) {
+            prepareTask.push(copyExample(userId, compilation, example));
+        }
+        await Promise.all(prepareTask);
     }
-    await Promise.all(prepareTask);
 }
 
 async function updateUsedList(userId, compilation) {
@@ -932,3 +1008,20 @@ async function copyCompleGljSection(userId, compilationId) {
         await compleGljSectionModel.insertMany(insertDatas);
     }
 }
+
+
+async function changeFile(datas,userID,fileID,name,from,type){//from 费率或单价文件,type从单前建设项目还是从其它建设项目中复制
+    let projectIDs = [],newFile = {id:fileID,name:name};//计录从其它项目中复制的文件,选中多个的时候只需复制一次
+    let projectUpdateType = from == "feeRateFile"?"feeRate":"unitFile";
+    for(let d of datas){
+        let tem_file = from == "feeRateFile"? await feeRate_facade.changeFeeRateFile(d, newFile,type,userID):await glj_facade.changeUnitFile(d, newFile,type,userID);
+        if(type == 1 && tem_file){//从建设项目复制时,只有第一次需要复制,剩下的就相当于使用同个建设项目的情况了
+            let newID =  from == "feeRateFile"?tem_file.ID:tem_file.id;
+            newFile = {id:newID,name:tem_file.name};
+            type = 0;
+        }
+        projectIDs.push({ID:d.projectID})
+    }
+    await project_facade.markProjectsToChange(projectIDs,projectUpdateType)//项目标记为待刷新状态
+
+}

+ 20 - 21
modules/pm/models/project_model.js

@@ -1,6 +1,22 @@
 /**
  * Created by Mai on 2017/1/18.
  */
+let projectType = {
+    folder: 'Folder',
+    tender: 'Tender',
+    project: 'Project',
+    engineering: 'Engineering',
+};
+let fileType = {
+    unitPriceFile: 'UnitPriceFile',
+    feeRateFile: 'FeeRateFile'
+};
+//先导出后require可以解决循环引用问题
+module.exports ={    project: new ProjectsDAO(),
+    projType: projectType,
+    fileType: fileType
+};
+
 import mongoose from 'mongoose';
 import async_c from 'async';
 import UnitPriceFileModel from "../../glj/models/unit_price_file_model";
@@ -34,19 +50,9 @@ let Projects = mongoose.model('projects');
 let mainColLibModel = mongoose.model('std_main_col_lib');
 let projSettingModel = mongoose.model('proj_setting');
 let optionModel = mongoose.model('options');
-let projectType = {
-    folder: 'Folder',
-    tender: 'Tender',
-    project: 'Project',
-    engineering: 'Engineering',
-};
-let fileType = {
-    unitPriceFile: 'UnitPriceFile',
-    feeRateFile: 'FeeRateFile'
-};
 
-let ProjectsDAO = function () {
-};
+function ProjectsDAO() {
+}
 
 let G_FILE_VER = '1.0.1';
 
@@ -316,14 +322,14 @@ ProjectsDAO.prototype.udpateUserFiles = async function (userId, datas, callback)
                 await Projects.update({
                     userID: userId,
                     'property.unitPriceFile.id': data.updateData.id
-                }, {$set: {'property.unitPriceFile.name': data.updateData.name}});
+                }, {$set: {'property.unitPriceFile.name': data.updateData.name}}, {multi: true});
             }
             else if (data.updateType === updateType.update && data.fileType === fileType.feeRateFile) {
                 await FeeRateFiles.update({ID: data.updateData.ID}, data.updateData);
                 await Projects.update({
                     userID: userId,
                     'property.feeFile.id': data.updateData.ID
-                }, {$set: {'property.feeFile.name': data.updateData.name}});
+                }, {$set: {'property.feeFile.name': data.updateData.name}}, {multi: true});
             }
             else if (data.updateType === updateType.delete && data.fileType === fileType.unitPriceFile) {
                 data.updateData.deleteInfo = deleteInfo;
@@ -844,11 +850,4 @@ ProjectsDAO.prototype.defaultSettings = async function (userID, compilationId, p
     await optionModel.update({user_id: userID, compilation_id: compilationId}, {$set: {options: optionSetting}});
     await Projects.update({ID: projectID}, {$set: {property: cloneProperty}});
     return true;
-};
-
-
-
-module.exports ={    project: new ProjectsDAO(),
-    projType: projectType,
-    fileType: fileType
 };

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

@@ -60,6 +60,7 @@ module.exports = function (app) {
     pmRouter.post('/getProjectShareInfo', pmController.projectShareInfo);
     pmRouter.post('/share', pmController.share);
     pmRouter.post('/receiveProjects', pmController.receiveProjects);
+    pmRouter.post('/changeFile', pmController.changeFile);
 
     app.use('/pm/api', pmRouter);
 };

+ 13 - 4
modules/ration_glj/facade/glj_calculate_facade.js

@@ -13,6 +13,7 @@ let std_glj_lib_gljList_model = mongoose.model('std_glj_lib_gljList');
 let glj_type_util = require('../../../public/cache/std_glj_type_util');
 const scMathUtil = require('../../../public/scMathUtil').getUtil();
 let decimal_facade = require('../../main/facade/decimal_facade');
+let gljUtil = require('../../../public/gljUtil');
 
 module.exports={
     calculateQuantity:calculateQuantity,
@@ -131,7 +132,7 @@ function generateUpdateTasks(result) {
 
 function sortRationGLJ(list) {
     list = _.sortByAll(list, [function (item) {
-        return item.type + "";
+        return _.indexOf(gljUtil.getGljTypeSeq(),item.type);
     }, "code"])
     return list;
 }
@@ -165,7 +166,8 @@ async function calculateQuantityPerGLJ(glj,gljList,coeList,assList,adjustState,n
                 quantity = calculateQuantityByCustomerCoes(quantity,customerCoe,glj,decimal);
             }
             result.doc.quantity =scMathUtil.roundToString(quantity,decimal);
-            glj.quantity = quantity;//这里保存中间过程计算出来的消耗量,后面处理“+*”操作符时要用到
+            //2019-01-03 需求修改中间过程的价格不参与计算
+            //glj.quantity = quantity;//这里保存中间过程计算出来的消耗量,后面处理“+*”操作符时要用到
         }
         generateAdjustState(glj,coeList,adjustState,gljList,result.doc.quantity);
         return result;
@@ -354,6 +356,7 @@ function getCoeSelectedGLJ(gljList,rcode,code) {
 
 function getCalculateResult(quantify,c,coe,gljList,decimal) {
     let q = quantify;
+    let o_glj = null;
     switch (c.operator){
         case '+' :
             q = q + c.amount;
@@ -368,9 +371,15 @@ function getCalculateResult(quantify,c,coe,gljList,decimal) {
             q = q / c.amount;
             break;
         case '+*' :
-            let o_glj = getCoeSelectedGLJ(gljList,coe.original_code,coe.select_code);
+            o_glj = getCoeSelectedGLJ(gljList,coe.original_code,coe.select_code);
             if(o_glj){
-              q = q +  c.amount * scMathUtil.roundForObj(o_glj.quantity,decimal);
+              q = q +  c.amount * scMathUtil.roundForObj(o_glj.rationItemQuantity,decimal);
+            }
+            break;
+        case '-*' :
+            o_glj = getCoeSelectedGLJ(gljList,coe.original_code,coe.select_code);
+            if(o_glj){
+                q = q -  c.amount * scMathUtil.roundForObj(o_glj.rationItemQuantity,decimal);
             }
             break;
         case '=' :

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

@@ -51,7 +51,8 @@ module.exports = {
     createNewRecord:createNewRecord,
     getGLJSearchInfo:getGLJSearchInfo,
     updateRationGLJFromDoc:updateRationGLJFromDoc,
-    getGLJLibByEngineerID:getGLJLibByEngineerID
+    getGLJLibByEngineerID:getGLJLibByEngineerID,
+    prepareExtData:prepareExtData
 }
 
 let operationMap = {

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

@@ -43,6 +43,10 @@ class LoginController {
             // 调用接口验证登录信息
             let userModel = new UserModel();
             let responseData = await userModel.getInfoFromSSO(account, password);
+            // 先判断返回值是否为未激活状态
+            if ( responseData === '-3') {
+                throw '因邮箱未完成认证,账号未激活;去<a href="https://sso.smartcost.com.cn" target="_blank">激活</a>。';
+            }
             responseData = JSON.parse(responseData);
             if (typeof responseData !== 'object') {
                 throw '邮箱/手机 或 密码错误';

+ 6 - 1
public/gljUtil.js

@@ -15,7 +15,8 @@ module.exports = {
     calcPriceDiff:calcPriceDiff,
     getMarketPrice:getMarketPrice,
     getBasePrice:getBasePrice,
-    getAdjustPrice:getAdjustPrice
+    getAdjustPrice:getAdjustPrice,
+    getGljTypeSeq:getGljTypeSeq
 };
 
 function calcProjectGLJQuantity(projectGLJDatas,rationGLJDatas,rationDatas,billsDatas,q_decimal) {
@@ -40,4 +41,8 @@ function getAdjustPrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalOb
 
 function calcPriceDiff(glj,calcOptions) {
     gljNodeUtil.calcPriceDiff(glj,calcOptions);
+}
+
+function getGljTypeSeq() {
+    return gljNodeUtil.getGljTypeSeq();
 }

+ 1 - 1
public/web/common_ajax.js

@@ -173,7 +173,7 @@ async function ajaxPost(url, data) {
             cache: false,
             timeout: 50000,
             success: function(result){
-                if (result.error === 0) {
+                if (result.error === 0 || result.err ===0) {
                     resolve(result.data);
                 } else {
                     alert('error: ' + result.message);

+ 13 - 0
public/web/gljUtil.js

@@ -295,6 +295,19 @@ let gljUtil = {
         t_index = k_arr.join("|-|");
         return t_index;
     },
+    getGljTypeSeq:function () {
+        let gljType = this.gljType;
+        return   [gljType.LABOUR,gljType.MAIN_MATERIAL,gljType.CONCRETE,gljType.MORTAR,gljType.MIX_RATIO,gljType.COMMERCIAL_CONCRETE,
+                gljType.COMMERCIAL_MORTAR,gljType.GENERAL_MATERIAL,gljType.OTHER_MATERIAL,gljType.GENERAL_MACHINE,gljType.INSTRUMENT,gljType.OTHER_MACHINE_USED,
+                gljType.MACHINE_COMPOSITION,gljType.MACHINE_LABOUR,gljType.FUEL_POWER_FEE,gljType.DEPRECIATION_FEE,gljType.INSPECTION_FEE,gljType.MAINTENANCE,
+                gljType.DISMANTLING_FREIGHT_FEE,gljType.VERIFICATION_FEE,gljType.OTHER_FEE,gljType.EQUIPMENT,gljType.MANAGEMENT_FEE,gljType.PROFIT,gljType.GENERAL_RISK_FEE]
+    },
+    sortRationGLJ:function (list) {
+        list = _.sortByAll(list, [function (item) {
+            return _.indexOf(gljTypeSeq,item.type)
+        }, "code"])
+        return list;
+    },
     fixedFlag : {
         // 分部分项工程
         SUB_ENGINERRING: 1,

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

@@ -33,7 +33,9 @@ var sheetCommonObj = {
         if (setting && setting.view && setting.view.rowHeaderWidth) {
             sheet.setColumnWidth(0, setting.view.rowHeaderWidth, spreadNS.SheetArea.rowHeader);
         };
-
+        if (setting.emptyRowHeader) {
+            sheet.setColumnWidth(0, 1, GC.Spread.Sheets.SheetArea.rowHeader);
+        }
         sheet.options.colHeaderAutoTextIndex = 1;
         sheet.options.colHeaderAutoText = spreadNS.HeaderAutoText.numbers;
         sheet.options.clipBoardOptions = GC.Spread.Sheets.ClipboardPasteOptions.values;
@@ -150,6 +152,12 @@ var sheetCommonObj = {
                 sheet.setStyle(row, -1, setting.getStyle(data[row]));
             }
         }
+        if(setting.emptyRowHeader){
+            let rowCount = sheet.getRowCount();
+            for (let row = 0; row < rowCount; row++) {
+                sheet.setValue(row, 0, '', GC.Spread.Sheets.SheetArea.rowHeader);
+            }
+        }
         this.lockCells(sheet,setting);
         sheet.resumeEvent();
         sheet.resumePaint();
@@ -217,6 +225,24 @@ var sheetCommonObj = {
             sheet.autoFitRow(row);
         }
     },
+    checkData : function(col,setting, value) {
+        let result = true;
+        let validator = setting.header[col].validator !== undefined ? setting.header[col].validator : null;
+        if (validator === null) {
+            return result;
+        }
+        switch (validator) {
+            case 'number':
+                let regular = /^\d+(\.\d+)?$/;
+                result = regular.test(value);
+                break;
+            case 'boolean':
+                let booleanValue = [true, false];
+                result = booleanValue.indexOf(value) >= 0;
+                break;
+        }
+        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
@@ -282,7 +308,7 @@ var sheetCommonObj = {
         //let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
         let dynamicCombo = sheetCommonObj.getDynamicCombo(true);
         if(options){
-            dynamicCombo.itemHeight(options.length).items(options);
+            dynamicCombo.items(options);
             if(editorValueType==true){
                 dynamicCombo.editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.value);
             }
@@ -366,7 +392,7 @@ var sheetCommonObj = {
 
     },
     setSelectButton(row,col,sheet,header){
-        let getSelectButton = function (cellWidth=100) {
+      /*  let getSelectButton = function (cellWidth=100) {
             function moreButton() {
 
             }
@@ -439,8 +465,84 @@ var sheetCommonObj = {
                 }
             };
             return new selectButton();
+        };*/
+        sheet.setCellType(row, col,this.getSelectButton(header.headerWidth),GC.Spread.Sheets.SheetArea.viewport);
+    },
+    getSelectButton(cellWidth=100){
+
+        function moreButton() {
+
+        }
+        moreButton.prototype = new GC.Spread.Sheets.CellTypes.Button();
+        moreButton.prototype.paint = function (ctx, value, x, y, w, h, style, options){
+            GC.Spread.Sheets.CellTypes.Button.prototype.paint.call(this, ctx, value, x, y, w, h, style, options);
+            ctx.font = '14px Calibri';
+            let buttonW = cellWidth/5;
+            let endX = x+w-2;
+            if(value){
+                let textWidth = ctx.measureText(value).width;
+                let spaceWidth = cellWidth - buttonW;
+                let textEndX = x+textWidth+2;
+                if(spaceWidth<textWidth){
+                    for(let i = value.length-1;i>1;i--){
+                        let newValue = value.substr(0,i);
+                        let newTestWidth =  ctx.measureText(newValue).width;
+                        if(spaceWidth>newTestWidth){
+                            value = newValue;
+                            textEndX = x+newTestWidth+2;
+                            break;
+                        }
+                    }
+                }
+                ctx.fillText(value,textEndX,y+h-6);
+            }
+
+            //画三个点
+            ctx.save();
+            ctx.beginPath();
+            ctx.arc(endX-buttonW/2,y+h/2,1,0,360,false);
+            ctx.arc(endX-buttonW/2-4,y+h/2,1,0,360,false);
+            ctx.arc(endX-buttonW/2+4,y+h/2,1,0,360,false);
+            ctx.fillStyle="black";//填充颜色,默认是黑色
+            ctx.fill();//画实心圆
+            ctx.closePath();
+            ctx.restore();
+        };
+
+        moreButton.prototype.processMouseLeave= function (hitinfo) {
+            let newCell = new selectButton();
+            hitinfo.sheet.setCellType(hitinfo.row, hitinfo.col, newCell, GC.Spread.Sheets.SheetArea.viewport);
+            hitinfo.sheet.getCell(hitinfo.row, hitinfo.col).locked(false);
+        };
+
+        function selectButton() {
+        }
+
+        selectButton.prototype = new GC.Spread.Sheets.CellTypes.Text();
+
+        selectButton.prototype.paint = function (ctx, value, x, y, w, h, style, options){
+            GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this,arguments);
+        };
+        selectButton.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
+            return {
+                x: x,
+                y: y,
+                row: context.row,
+                col: context.col,
+                cellStyle: cellStyle,
+                cellRect: cellRect,
+                sheetArea: context.sheetArea
+            };
+        };
+        selectButton.prototype.processMouseDown = function (hitinfo){
+            if(hitinfo.sheet.getCell(hitinfo.row,hitinfo.col).locked()!=true){
+                let b1 = new moreButton();
+                b1.marginLeft(cellWidth*4/5);
+                hitinfo.sheet.setCellType(hitinfo.row, hitinfo.col, b1, GC.Spread.Sheets.SheetArea.viewport);
+                hitinfo.sheet.getCell(hitinfo.row, hitinfo.col).locked(true);
+            }
         };
-        sheet.setCellType(row, col,getSelectButton(header.headerWidth),GC.Spread.Sheets.SheetArea.viewport);
+        return new selectButton();
     },
     setReplaceButton(row,col,sheet){
         let replaceButton = function(){

+ 31 - 24
public/web/sheet/sheet_data_helper.js

@@ -173,40 +173,47 @@ var SheetDataHelper = {
             sheet.defaults.rowHeight = setting.defaultRowHeight;
         }
         sheet.setRowCount(datas.length + setting.emptyRows, GC.Spread.Sheets.SheetArea.viewport);
+        let rowCount = sheet.getRowCount();
         setting.cols.forEach(function (colSetting, iCol) {       
             sheet.setStyle(-1, iCol, SheetDataHelper.getSheetCellStyle(colSetting));
             if (colSetting.showHint) {
                 sheet.getRange(-1, iCol, -1, 1).cellType(new TipCellType());
             }
-            datas.forEach(function (data, iRow) {
-                var cell = sheet.getCell(iRow, iCol, GC.Spread.Sheets.SheetArea.viewport);
-                var getFieldText2 = function () {
-                    var fields = colSetting.data.field.split('.'), iField, value = data;
-                    for (iField = 0; iField < fields.length; iField++) {
-                        if (value[fields[iField]]) {
-                            value = value[fields[iField]];
-                        } else {
-                            return '';
+            for (let iRow = 0; iRow < rowCount; iRow++) {
+                let data = datas[iRow];
+                if (setting.emptyRowHeader) {
+                    sheet.setValue(iRow, 0, '', GC.Spread.Sheets.SheetArea.rowHeader);
+                }
+                if (data) {
+                    let cell = sheet.getCell(iRow, iCol, GC.Spread.Sheets.SheetArea.viewport);
+                    let getFieldText2 = function () {
+                        let fields = colSetting.data.field.split('.'), iField, value = data;
+                        for (iField = 0; iField < fields.length; iField++) {
+                            if (value[fields[iField]]) {
+                                value = value[fields[iField]];
+                            } else {
+                                return '';
+                            }
                         }
+                        return value;
+                    };
+                    cell.value(data[colSetting.data.field]);
+                    if (colSetting.data.getText) {
+                        cell.value(colSetting.data.getText(data));
+                    } else {
+                        cell.value(getFieldText2());
                     }
-                    return value;
-                };
-                cell.value(data[colSetting.data.field]);
-                if (colSetting.data.getText) {
-                    cell.value(colSetting.data.getText(data));
-                } else {
-                    cell.value(getFieldText2());
-                }
-                if (colSetting.readOnly) {
-                    if (Object.prototype.toString.apply(colSetting.readOnly) === "[object Function]") {
-                        cell.locked(colSetting.readOnly(node));
+                    if (colSetting.readOnly) {
+                        if (Object.prototype.toString.apply(colSetting.readOnly) === "[object Function]") {
+                            cell.locked(colSetting.readOnly(node));
+                        } else {
+                            cell.locked(true);
+                        }
                     } else {
-                        cell.locked(true);
+                        cell.locked(false);
                     }
-                } else {
-                    cell.locked(false);
                 }
-            });
+            }
         });
 
         sheet.resumeEvent();

+ 1 - 1
public/web/slideResize.js

@@ -18,7 +18,7 @@ const SlideResize = (function() {
     //设置水平拖动条的宽度
     //@param {Object dom}resize滚动条
     function setResizeWidth (resize) {
-        const fixedWidth = 10;
+        const fixedWidth = 5;
         //滚动条节点 及 同层非滚动条节点的索引
         let bros = resize.parent().children();
         let index = bros.index(resize),

+ 0 - 1
public/web/socket/connection.js

@@ -41,7 +41,6 @@ socketObject={
           //window.location.reload();
       });
       socket.on('unitFileChange', function (data) {
-          data = JSON.parse(data);
           /*console.log(data);
           if (data.newValue === undefined) {
               return false;

+ 14 - 0
socket.js

@@ -15,6 +15,7 @@ socketIO.on('connection', function(socket) {
     console.log("new connection");
     // 加入房间
     socket.on('join', function(data) {
+        console.log(data);
         for(let key in data){
             roomInfo[key] = data[key];
             socket.join(data[key]);
@@ -44,6 +45,19 @@ socketIO.on('connection', function(socket) {
             socket.broadcast.to(data.userID).emit('refreshProjectIcon', data);
         }
     });
+    socket.on('multiFileChangeNotify', function(data) {
+        console.log(data);
+        let projectID = data.projects[0].projectID;
+        let userID = data.user_id;
+        if(projectID && userID){//通知项目管理页面
+            socket.broadcast.to(userID).emit('fileDataChange', {projectID:projectID});
+        }
+        for(let fileID of data.oldFileIDs){//通知已打开的项目页面
+            let messageTitle = data.from == "feeRateFile"?"feeRateChange":"unitFileChange";
+            socket.broadcast.to(fileID).emit(messageTitle, data);
+        }
+    });
+
 
     socket.on('disconnect', function () {
         console.log("client disconnect =========="+JSON.stringify(roomInfo));

+ 1 - 1
web/building_saas/complementary_ration_lib/html/dinge.html

@@ -19,7 +19,7 @@
     <link rel="icon" type="image/gif" href="/web/building_saas/css/animated_favicon1.gif">
     <style type="text/css">
         div.resize-y{
-            height: 10px;
+            height: 5px;
             background: #efefef;
             width: 100%;
             cursor: s-resize;

+ 4 - 3
web/building_saas/complementary_ration_lib/js/coe.js

@@ -31,6 +31,7 @@ $(document).ready(function () {
     leftElesObj.right = $('#mainContent');
     let maxEval = `$('#zmhsContent').is(':visible') ? $('#dataRow').width() - $('#zmhsContent').width() - 300 : $('#dataRow').width()  - 300`;
     SlideResize.horizontalSlide(leftElesObj, {min: 300, max: maxEval}, function () {
+        sectionTreeObj.loadRateWidth();
         refreshALlWorkBook();
     });
     SlideResize.loadHorizonWidth(moduleName, [$('#slideResizeLeft')], [$('#leftContent'), $('#mainContent')], function () {
@@ -40,7 +41,6 @@ $(document).ready(function () {
         let surplus = 100 - leftContentWidth - mainContentWidth;
         $('#leftContent').css('width', `${leftContentWidth + surplus / 2}%`);
         $('#mainContent').css('width', `${mainContentWidth + surplus / 2}%`);
-
         refreshALlWorkBook();
     });
     //定额表与子目换算表
@@ -105,6 +105,7 @@ $(document).ready(function () {
         for (let resize of resizes) {
             setResizeWidth(resize);
         }
+        sectionTreeObj.loadRateWidth();
     }
     $('#zmhs').click(function () {
         if(!$(this).hasClass('active')){
@@ -146,8 +147,8 @@ function getZmhsAdjResize() {
     };
     zmhsAdjResize.limit = {
         min: 150,
-        max: `$(window).height()-$('.header').height()-150-10`,
-        totalHeight: `$(window).height()-$('.header').height()-10`,
+        max: `$(window).height()-$('.header').height()-150-5`,
+        totalHeight: `$(window).height()-$('.header').height()-5`,
         notTopSpread: 0,
         notBottomSpread: 0,
     };

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

@@ -136,7 +136,7 @@ let gljSelOprObj = {
                 }
                 if(!isExist){
                     thisGlj.consumeAmt = 0;
-                    me.selectedList.push(thisGlj);
+                    me.selectedList.push(_.cloneDeep(thisGlj));
                 }
             }
             else if(val === false){

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

@@ -27,6 +27,7 @@ function autoFlashHeight(){
     $('#ruleTextShow').height($(window).height()-headerHeight-toolsBar-100);
     typeof loadRationSubSize !== 'undefined' ? loadRationSubSize() : '';
     typeof loadZmhsAdjSize !== 'undefined' ? loadZmhsAdjSize() : '';
+    typeof sectionTreeObj !== 'undefined' ? sectionTreeObj.loadRateWidth() : '';
 };
 $(window).resize(autoFlashHeight);
 /*全局自适应高度结束*/

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

@@ -34,8 +34,8 @@ function getRationSubResize() {
     };
     rationSubResize.limit = {
         min: 150,
-        max: `$(window).height()-$('.header').height()-$('.tools-bar').height()-150-10`,
-        totalHeight: `$(window).height()-$('.header').height()-$('.tools-bar').height()-10`,
+        max: `$(window).height()-$('.header').height()-$('.tools-bar').height()-150-5`,
+        totalHeight: `$(window).height()-$('.header').height()-$('.tools-bar').height()-5`,
         notTopSpread: 0,
         notBottomSpread: $('#subContent ul').height(),
     };

+ 6 - 28
web/building_saas/complementary_ration_lib/js/section_tree.js

@@ -44,33 +44,6 @@ let pageOprObj = {
     getRationLibInfo: function (rationLibId, callback) {
         CommonAjax.post('api/getRationLib', {rationRepId: rationLibId}, callback);
     },
-    //获取定额库列表
-    /*getRationLibs: function () {
-        let scFunc = function (rstData) {
-            $("#comple_ration_table").empty();
-            for(let i = 0; i < rstData.length; i++){
-                storageUtil.setSessionCache("RationGrp","repositoryID_" + rstData[i].ID, rstData[i].dispName);
-                if(rstData[i].gljLib !== undefined && rstData[i].gljLib && rstData[i].gljLib != -1){
-                    storageUtil.setSessionCache("gljLib","repositoryID_" + rstData[i].ID, rstData[i].gljLib);
-                    let id = rstData[i].ID;
-                    let libName = rstData[i].dispName;
-                    $("#comple_ration_table").append(
-                        "<tr id='tempId'>" +
-                        "<td><a href='/stdGljRepository/glj'>"+libName+"</a></td></tr>"
-                    );
-                    var newHref = "/complementaryRation/ration?repository="+id;
-                    $("#tempId td:first a").attr("href", newHref);
-                    $("#tempId").attr("id", id);
-                }
-            }
-        };
-        let ration_lib = projectInfoObj.projectInfo.engineeringInfo.ration_lib;
-        let ids = [];
-        for(lib of ration_lib){
-            ids.push(parseInt(lib.id));
-        }
-        CommonAjax.post('/complementaryRation/api/getRationLibs', {user_id: userID, ids: ids}, scFunc);
-    }*/
 };
 
 let sectionTreeObj = {
@@ -245,7 +218,11 @@ let sectionTreeObj = {
             });
         }
     },
-
+    loadRateWidth: function () {
+        if (this.workBook) {
+            sheetCommonObj.setColumnWidthByRate($('#sectionSpread').width() - 65, this.workBook, [{rateWidth: 1}]);//65: 列头宽度和垂直滚动条宽度和
+        }
+    },
     getSectionTree: function () {
         let me = sectionTreeObj;
         let url = 'api/getRationTree';
@@ -265,6 +242,7 @@ let sectionTreeObj = {
             me.setColor(me.cache);
             me.sheet.setFormatter(-1, 0, '@');
             me.initSelection(me.tree.selected);
+            me.loadRateWidth();
             //explanatoryOprObj.bindEvents($('#explanationShow'), $('#ruleTextShow'));
         };
         let errFunc = function () {

+ 26 - 6
web/building_saas/css/custom.css

@@ -16,7 +16,7 @@ div.resize{
     cursor: s-resize;
 }
 div.resize-y{
-    height: 10px;
+    height: 5px;
     background: #efefef;
     width: 100%;
     cursor: s-resize;
@@ -48,15 +48,20 @@ legend.legend{
 }
 
 .filterType{
-    padding-left: .75rem;
+    padding-left: 6px;
+    padding-right: 6px;
+    width: 122px;
 }
 
+.filterType ul{
+    width: 110px;
+}
 .a_color{
     color: #007bff;
 }
 
 .filterType a{
-    padding: 8px;
+    padding: 1px;
     padding-top: 7px;
     padding-bottom: 7px;
 }
@@ -259,9 +264,9 @@ legend.legend{
     white-space:nowrap;
 }
 
-.dropdown-toggle::after{
+/*.dropdown-toggle::after{
     vertical-align:.5em
-}
+}*/
 #esInput{
     font-size:13px;
     color: black;
@@ -283,7 +288,8 @@ input.text-right{
 }
 
 .cus-width{
-    width: 100%;
+    width: 100px;
+    margin-left: 10px;
 }
 .more{
     padding-left:.25rem!important
@@ -295,4 +301,18 @@ input.text-right{
     bottom:30px;
     left:0px;
     z-index: 999
+}
+
+.zmhs-link{
+    padding:0.4em 0.4em !important;
+}
+
+/*修改tooltip默认最大宽度 */
+.tooltip-inner{
+    max-width: 400px !important;
+}
+.applySuccess{
+    display: none;
+    color: #43CD80;
+    margin-left: 8px
 }

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

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

+ 3 - 3
web/building_saas/glj/html/project_glj.html

@@ -5,7 +5,7 @@
 </style>
 <div class="toolsbar px-1" id="projectGljToolsBar">
     <div class="form-inline py-1">
-        <label class="mx-2">当前使用:<span id="current-name"></span>(<label class="a_color" id="pop-used-list" data-original-title="" title=""><span id="used-project-count">0</span>个单位工程使用</label>)
+        <label class="mx-2">使用单价文件:<span id="current-name"></span>(<label class="a_color" id="pop-used-list" data-original-title="" title=""><span id="used-project-count">0</span>个单位工程同步</label>)
             <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#change-unitFile"><i class="fa fa-exchange"></i> 选择其他</a>
             <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#unitFile-save-as"><i class="fa fa-files-o"></i> 另存单独用</a></label>
     </div>
@@ -13,7 +13,7 @@
 
 <div class="container-fluid">
     <div class="row">
-        <div class="gl-side col-lg-1 filterType" id='filterType'>
+        <div class="gl-side  filterType" id='filterType'>
             <ul class="nav flex-column nav-pills mt-2 mb-2">
                 <li class="nav-item"><a class="nav-link active" href="#" id="ALL">所有人材机</a></li>
              <!--   <li class="nav-item li_sub"><a class="nav-link" href="javascript:void(0)" id="LABOUR">人工</a></li>
@@ -29,7 +29,7 @@
                 <li class="nav-item"><a class="nav-link" href="javascript:void(0)" id="ZYCL">主要材料</a></li>
             </ul>
         </div>
-        <div class="main-content col p-0 col-lg-11" id="project-glj-main">
+        <div class="main-content col p-0" id="project-glj-main">
             <div class="top-content" id="projectGljTop">
                 <div class="main-data-top" style="width: 100% " id="project_glj_sheet">
                 </div>

+ 1 - 1
web/building_saas/glj/js/project_glj.js

@@ -344,7 +344,7 @@ function filterProjectGLJ(jsonData) {
 function sortProjectGLJ(jsonData) {
     if (jsonData.length > 0) {
         jsonData = _.sortByAll(jsonData, [function (item) {
-            return item.unit_price.type + "";
+            return _.indexOf(gljTypeSeq,item.unit_price.type);
         }, 'code']);
     }
     return jsonData

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

@@ -32,7 +32,8 @@ function autoFlashHeight(){
     $(".form-view").height($(window).height()-headerHeight-ftoolsbarHeight);
     $(".form-list").height($(window).height()-headerHeight);
     $('#comments').find('textarea').height($('#comments').height() - 25);
-    typeof(adaptiveTzjnrWidth)== 'function' ?adaptiveTzjnrWidth():''
+    typeof(adaptiveTzjnrWidth)== 'function' ?adaptiveTzjnrWidth():'';
+    $('#project-glj-main').width($(window).width()-($('.main-nav').width()+ 2)-($('.filterType').width()+12)-5); //2、12是padding宽度,width 是不算padding宽度的
     //typeof zmhs_obj === 'object' ? zmhs_obj.loadSideResize() : '';
 };
 

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

@@ -14,6 +14,7 @@
     </div>
     <div class="toolsbar px-1" />
     <div class="container-fluid">
+        <div style="height:35px;width:100%;line-height:35px;font-size:15px;">总计算程序-设置</div>
         <div class="row">
             <div class="col-lg-2 p-0">
 <!--                <div id="divSelect" style="text-align:left;height:45px;line-height:45px;">

+ 78 - 40
web/building_saas/main/html/main.html

@@ -7,7 +7,7 @@
     <meta http-equiv="x-ua-compatible" content="ie=edge">
     <title><%= projectData.name !== undefined ? projectData.name : '造价书' %>-纵横建筑云计价</title>
 
-    <!-- inject:css -->
+
     <link rel="stylesheet" href="/lib/jquery-ui/jquery-ui.css" type="text/css">
     <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
     <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.sc.css" type="text/css">
@@ -24,7 +24,7 @@
     <link rel="stylesheet" href="/lib/spreadjs/views/gc.spread.views.dataview.10.0.0.css">
     <!-- jquery.contextmenu -->
    <!-- <link rel="stylesheet" href="/lib/jquery-contextmenu/jquery.contextMenu.css" type="text/css">-->
-    <!-- endinject -->
+   
     <link rel="shortcut icon" href="/web/building_saas/css/favicon.ico">
     <link rel="icon" type="image/gif" href="/web/building_saas/css/animated_favicon1.gif">
     <style type="text/css">
@@ -39,6 +39,8 @@
         let userAccount = '<%- userAccount %>';
         let userID = '<%- userID %>';
         let projectReadOnly = JSON.parse('<%- projectReadOnly %>');
+        let projectCooperate = JSON.parse('<%- projectCooperate %>');
+        console.log(projectCooperate);
         const G_SHOW_BLOCK_LIB = true;
 //        const G_SHOW_BLOCK_LIB = false;
     </script>
@@ -68,7 +70,7 @@
                 <li class="nav-item"><a class="active" data-toggle="tab" href="#zaojiashu" id="tab_zaojiashu" role="tab">造价书</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#project_glj" id="tab_project_glj" data-name="tab_project_glj" role="tab">人材机汇总</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#fee_rates" id="tab_fee_rate" role="tab" >费率</a></li>
-                <li class="nav-item"><a data-toggle="tab" href="#calc_program_manage" id="tab_calc_program_manage" role="tab">计算程序</a></li>
+                <li class="nav-item"><a data-toggle="tab" href="#calc_program_manage" id="tab_calc_program_manage" role="tab" style="display:none">计算程序</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#tender_price" id="tab_tender_price" role="tab">调价</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#reports" role="tab" id="tab_report" onclick="rptTplObj.iniPage();">报表</a></li>
             </ul>
@@ -82,11 +84,11 @@
                     <!--<a href="javascript:void(0)" class="btn btn-sm" title="复制" ><i class="fa fa-files-o" aria-hidden="true"></i></a>
                     <a href="javascript:void(0)" class="btn btn-sm" title="剪切"><i class="fa fa-scissors" aria-hidden="true"></i></a>
                     <a href="javascript:void(0)" class="btn btn-sm" title="粘贴"><i class="fa fa-clipboard" aria-hidden="true"></i></a>-->
-                      <span class="btn btn-light btn-sm" data-toggle="tooltip" data-original-title="项目属性" data-placement="bottom">
-                        <a href="javascript:void(0);" id="openProjSet"><i class="fa fa-cog"></i></a>
+                      <span id="openProjSet" class="btn btn-light btn-sm" data-toggle="tooltip" data-original-title="项目属性" data-placement="bottom">
+                        <a href="javascript:void(0);"><i class="fa fa-cog"></i></a>
                     </span>
-                    <span class="btn btn-light btn-sm" id="importSpan" data-toggle="tooltip" data-original-title="导入" data-placement="bottom">
-                        <a class="dropdown-toggle" href="#" data-toggle="dropdown"><i class="fa fa-cloud-upload"></i></a>
+                      <span class="btn btn-light btn-sm" id="importSpan" data-toggle="tooltip" data-original-title="导入" data-placement="bottom">
+                        <a id="importDropDown" class="dropdown-toggle" href="#"><i class="fa fa-cloud-upload"></i></a>
                         <div class="dropdown-menu">
                             <a id="uploadLj" class="dropdown-item" href="#import" data-toggle="modal" data-target="#import">导入报表Excel清单</a>
                             <a id="uploadGld" class="dropdown-item" href="#import" data-toggle="modal" data-target="#import">导入广联达算量Excel清单</a>
@@ -119,6 +121,7 @@
                               <a href="javascript:void(0)"  class="dropdown-item" name="lockBills"> <i class="fa fa-lock" aria-hidden="true"></i> 锁定清单</a>
                               <% } %>
                               <a id="switchTznr" href="javascript:void(0);"  class="dropdown-item"><i class="fa fa-eye" aria-hidden="true"></i> 显示特征</a>
+                              <a id = "menu_calc_program_manage"  href="javascript:void(0);" class="dropdown-item"><i class="fa fa-calculator" aria-hidden="true"></i> 总计算程序</a>
                           </div>
                       </div>
                  <!--   <span class="btn btn-light btn-sm">
@@ -159,20 +162,19 @@
                           </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">更多</a>-->
-                              <div class="dropdown-menu">
-                                  <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>-->
+                              <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" data-toggle="tab" href="#sqpz" role="tab">书签批注</a>-->
+                                  <script>
+                                      //2018-11-23  zhang 模板库移动到更多下拉框
+                                      if (G_SHOW_BLOCK_LIB) {
+                                          $("#div_more_dropdown_right").append('<a class="dropdown-item right-nav-link" href="javascript:void(0)" ' +
+                                              'id="blockLibTab" relaPanel="#kmbk">块模板库</a>');
+                                      }
+                                  </script>
                               </div>
                           </li>
-
-                          <script>
-                              //2018-11-23  zhang 模板库移动到更多下拉框
-                              if (G_SHOW_BLOCK_LIB) {
-                                  $("#locateTab").after('<a class="dropdown-item right-nav-link" href="javascript:void(0)" ' +
-                                      'id="blockLibTab" relaPanel="#kmbk">块模板库</a>');
-                              }
-                          </script>
                       </ul>
                   </div>
               </div>
@@ -185,7 +187,7 @@
                           </div>
                           <div class="resize-y" id="mainVerticalResize"></div>
                           <div class="bottom-content" id="bottom_div">
-                              <ul class="nav nav-tabs" role="tablist">
+                              <ul class="nav nav-tabs" role="tablist" id="bottom_div_ul">
                                   <li class="nav-item" id="QDJL_div">
                                       <a class="nav-link sub-item" id="linkQDJL" data-toggle="tab" href="#subSpread" role="tab">清单精灵</a>
                                   </li>
@@ -228,8 +230,8 @@
                                           <div class="resize-x main-data-bottom ovf-hidden" id="rgResize" style="display: none"></div>
                                           <div class="item_spread main-data-bottom ovf-hidden " id="gljSubDiv" style="width: 99%;">
                                               <div class="tab-content">
-                                                  <div class="tab-pane" id="rnc-xm">
-                                                      <div class="main-data-bottom ovf-hidden" id="itemCharacterText">
+                                                  <div class="tab-pane" id="rnc-xm" style="margin-top:-2px">
+                                                      <div class="main-data-bottom" id="itemCharacterText" >
                                                           项目特征 内容
                                                       </div>
                                                   </div>
@@ -237,6 +239,10 @@
                                                       <div class="main-data-bottom ovf-hidden" id = "coeSpread">
                                                       </div>
                                                   </div>
+                                                  <div class="tab-pane" id="rnc-cus">
+                                                      <div class="main-data-bottom ovf-hidden" id = "cusSpread">
+                                                      </div>
+                                                  </div>
                                                   <div class="tab-pane" id="rnc-fz">
                                                       <div class="main-data-bottom ovf-hidden" id="assSpread"></div>
                                                   </div>
@@ -252,16 +258,29 @@
                                           </div>
                                           <div class=" main-data-bottom ovf-hidden col-auto p-0" id="gljItemTab" style="width: 30px">
                                               <div class="rn-nav d-flex align-items-start flex-column gljSubTab">
-                                                  <ul class="nav nav-tabs">
-                                                      <li class="nav-item" data-toggle="tooltip" data-placement="left" title="项目特征">
-                                                          <a data-toggle="tab" href="#rnc-xm" role="tab" class="nav-link "><i class="fa fa-info-circle"></i><span>项目特征</span></a>
-                                                      </li>
-                                                      <li class="nav-item" data-toggle="tooltip" data-placement="left" title="子目换算"><a data-toggle="tab" href="#rnc-zm" role="tab"class="nav-link"><i class="fa fa-exchange"></i><span>子目换算</span></a></li>
-                                                      <li class="nav-item" data-toggle="tooltip" data-placement="left" title="辅助定额"><a data-toggle="tab" href="#rnc-fz" role="tab"class="nav-link"><i class="fa fa-wrench"></i><span>辅助定额</span></a></li>
-                                                    <!--  <li class="nav-item"><a data-toggle="tab" href="#rnc-xm" role="tab"  class="nav-link">项目特征</a></li>
-                                                      <li class="nav-item"><a data-toggle="tab" href="#rnc-zm" role="tab" class="nav-link">子目换算</a></li>
-                                                      <li class="nav-item"><a data-toggle="tab" href="#rnc-fz" role="tab" class="nav-link">辅助定额</a></li>-->
-                                                  </ul>
+                                                  <div id="zmhs_toogle">
+                                                      <div class="tn-nav d-flex align-items-start flex-column" data-toggle="tooltip" data-placement="left" title="" data-original-title="打开子目换算">
+                                                          <span class="mt-3 ml-2 text-primary">子目换算</span>
+                                                          <i class="fa fa-arrow-left mt-auto mb-3 text-primary ml-2"></i>
+                                                      </div>
+                                                  </div>
+                                                  <!--<a  role="tab" class="zmhs-link nav-link">子目换算</a>-->
+                                                  <div id="zmhs_nav" style="display: none">
+                                                      <ul class="nav nav-tabs">
+                                                          <li class="nav-item" data-toggle="tooltip" data-placement="left" title="收起">
+                                                              <a data-toggle="tab" href="#rnc-close" role="tab" class="zmhs-link nav-link"><i class="fa fa-arrow-right"></i></a>
+                                                          </li>
+                                                          <li class="nav-item" data-toggle="tooltip" data-placement="left" title="项目特征">
+                                                              <a data-toggle="tab" id="xm-nav" href="#rnc-xm" role="tab" class="zmhs-link nav-link"><i class="fa fa-info-circle"></i></a>
+                                                          </li>
+                                                          <li class="nav-item" data-toggle="tooltip" data-placement="left" title="附注条件"><a data-toggle="tab" href="#rnc-zm" role="tab"class="zmhs-link nav-link"><i class="fa fa-check-circle-o"></i></a></li>
+                                                          <li class="nav-item" data-toggle="tooltip" data-placement="left" title="自定义系数"><a data-toggle="tab" href="#rnc-cus" role="tab"class="zmhs-link nav-link"><i class="fa fa-wrench"></i></a></li>
+                                                          <li class="nav-item" data-toggle="tooltip" data-placement="left" title="增减换算"><a data-toggle="tab" href="#rnc-fz" role="tab"class="zmhs-link nav-link "><i class="fa fa-plus"></i></a></li>
+                                                        <!--  <li class="nav-item"><a data-toggle="tab" href="#rnc-xm" role="tab"  class="nav-link">项目特征</a></li>
+                                                          <li class="nav-item"><a data-toggle="tab" href="#rnc-zm" role="tab" class="nav-link">子目换算</a></li>
+                                                          <li class="nav-item"><a data-toggle="tab" href="#rnc-fz" role="tab" class="nav-link">辅助定额</a></li>-->
+                                                      </ul>
+                                                  </div>
                                               </div>
                                           </div>
                                       </div>
@@ -283,12 +302,12 @@
                                                               <option value="3">模板子目分别放在对应混凝土子目下</option>
                                                           </select>
                                                       </div>
-                                                      <div class="col-1">
+                                                      <div class="">
                                                           <button class=" btn btn-primary btn-sm cus-width" type="button" id="apply_mbzm">应用</button>
-                                                      </div>
-                                                      <div class="col-1">
+                                                          <label class="applySuccess" ><i class="fa fa-check" aria-hidden="true"></i>成功</label>
                                                           <button class=" btn btn-primary btn-sm cus-width" type="button" id="next_mbzm">下一条</button>
                                                       </div>
+
                                                   </div>
                                               </div>
                                               <div class=" ovf-hidden" style="" id="mbzmSpread"></div>
@@ -299,7 +318,7 @@
                                       <div id="tzjnrCon" class="container-fluid main-data-bottom" style="background: #F1F1F1; overflow: hidden">
                                           <div class="row" style="overflow: hidden">
                                               <div class="p-0" id="contentDiv" style="width: 90%; float: left">
-                                                  <div id="jobDiv" style="width: 25%; height: 100%;float: left">
+                                                  <div id="jobDiv" style="width: 33%; height: 100%;float: left">
                                                       <div class="main-data-bottom ovf-hidden" id="jobSpread" style="width: 99%; float: left; position: relative">
                                                           <!--工具栏-->
                                                           <div class="bottom-tznrTools btn-group position-absolute">
@@ -312,7 +331,7 @@
                                                       </div>
                                                       <div class="resize-x" id="TZJNRResize"></div>
                                                   </div>
-                                                  <div id="itemDiv" style="width: 75%; height: 100%; float: left;">
+                                                  <div id="itemDiv" style="width: 67%; height: 100%; float: left;">
                                                       <div class="main-data-bottom ovf-hidden" id="itemSpread" style="position: relative;">
                                                           <!--工具栏-->
                                                           <div class="bottom-tznrTools btn-group position-absolute">
@@ -419,11 +438,11 @@
                                       </div>
                                       <div class="container-fluid" id="qdjl" role="tabpanel">
                                           <div class="row p-0" style="background: #efefef">
-                                              <div class="col-10 p-0">
+                                              <div class="col-6 p-0">
                                                   <div class="main-data-bottom ovf-hidden" id="elfItems">
                                                   </div>
                                               </div>
-                                              <div class="col-2 p-1">
+                                              <div class="col-6 p-1">
                                                   <p class="mt-3"><a id="elfInsertRation" href="javascript:void(0);" class="btn btn-sm btn-primary">应用选项</a></p>
                                                   <p><a id="elfInsertSingle" href="javascript:void(0)" class="btn btn-sm btn-primary">应用单条</a></p>
                                               </div>
@@ -525,7 +544,8 @@
                                       <div class="side-search-box col-12 p-2" id="billsGuidanceSearchResult" style="display: none;">
                                           <div class="d-flex justify-content-between">
                                               <span id = 'billsGuidanceSearchResultCount'>搜索结果:5</span>
-                                              <a class="btn btn-secondary btn-sm" href="javascript:void(0);" id="nextBillsGuidance">查找下一条</a>
+                                              <a class="btn btn-secondary btn-sm" href="javascript:void(0);" id="preBillsGuidance">上一条</a>
+                                              <a class="btn btn-secondary btn-sm" href="javascript:void(0);" id="nextBillsGuidance">下一条</a>
                                               <a title="关闭搜索" class="btn btn-link btn-sm" href="javascript:void(0);" id="closeSearchBillsGuidance"><i class="fa fa-remove" aria-hidden="true"></i></a>
                                           </div>
                                       </div>
@@ -1275,6 +1295,24 @@
                                     <input class="form-control feerateInput" id="inputFeeRate" value="">
                                 </div>
                             </div>-->
+                            <div class="form-check form-check-inline">
+                                <input class="form-check-input" type="radio" name="editFeeRateOptions" id="inputFeeRate" value="0">
+                                <label class="form-check-label" for="inputFeeRate">自定义费率</label>
+                            </div>
+                            <div class="form-check form-check-inline">
+                                <input class="form-check-input" type="radio" name="editFeeRateOptions" id="selectStd" value="1">
+                                <label class="form-check-label" for="selectStd">选择标准费率</label>
+                            </div>
+                            <div id="selfDiv">
+                                <div class="form-group row">
+                                    <label class="col-auto col-form-label col-form-label-sm">手工输入费率</label>
+                                    <div class="col">
+                                        <div class="input-group input-group-sm">
+                                            <input id="customFeeRate" type="text" class="form-control"  placeholder="输入费率" style="width:100px">
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
                             <div class="modal-fixed-height" style="overflow: hidden" id="fee_rate_sheet">
                             </div>
                         </div>

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

@@ -340,7 +340,7 @@ let BlockController = {
                 i==0?firstNode = temNode:'';
             }
         }
-        ProjectController.syncDisplayNewNodes(projectObj.mainController, newNodes);
+        ProjectController.syncDisplayNewNodes(projectObj.mainController, newNodes,true);
         let sels = projectObj.mainController.sheet.getSelections();
         //设置选中并更新下方显示
         projectObj.mainController.setTreeSelected(firstNode);
@@ -475,6 +475,14 @@ let BlockController = {
             template.ID = uuid.v1();
             template.projectID = projectObj.project.ID();
             template.rationID = rationData.ID;
+            //其它值恢复成默认
+            for(let t of template.templateList){
+                t.billID = "";
+                t.fxID="";
+                t.quantity="0";
+                t.coe = "";
+                if(t.defaultLocation) t.billsLocation = t.defaultLocation;
+            }
             return template;
         }
         

+ 1 - 1
web/building_saas/main/js/controllers/material_controller.js

@@ -228,7 +228,7 @@ let MaterialController = {
         }*/
         //$('#replaceM').css('margin-top',0);
         //this.toggleItemInit();
-        $("#itemCharacterText").html("<br>"+text);
+        $("#itemCharacterText").html(text);
     },
     //初始化人材机和项目特征文本两个区域的宽度,改变窗口大小时调用此方法,实时刷新
     initItemWidth: function () {

+ 2 - 2
web/building_saas/main/js/controllers/project_controller.js

@@ -16,7 +16,7 @@ ProjectController = {
             cbTools.refreshFormulaNodes();
         });
     },
-    syncDisplayNewNodes: function (sc, newNodes) {
+    syncDisplayNewNodes: function (sc, newNodes,withOutSelect=false) {//withOutSelect 不需要自动选中,外面自已处理
         TREE_SHEET_HELPER.massOperationSheet(sc.sheet, function () {
             var sels = sc.sheet.getSelections();
             newNodes.sort(function (a, b) {
@@ -36,7 +36,7 @@ ProjectController = {
                 lastNode = newNode
                // sc.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);
             }
-            if(lastNode){
+            if(withOutSelect==false&& lastNode){
                 sc.setTreeSelected(lastNode);
                 sc.sheet.setSelection(lastNode.serialNo(), sels[0].col, 1, 1);
             }

+ 8 - 3
web/building_saas/main/js/main.js

@@ -22,6 +22,8 @@ $(function () {
         billsLibObj.refreshBillsSpread();
         billsLibObj.refreshBillsRelaSpread();
         rationLibObj.refreshSpread();
+        subObj.initGljSubTab();
+        refreshSubSpread();
     });
 
     $('#tab_report').on('shown.bs.tab', function(e){
@@ -59,14 +61,17 @@ function getMainResizeEles() {
         bottomSpread: $('#bottom_div').children().find('.main-data-bottom'),
     };
     mainResizeEles.limit = {
-        min: 150,
-        max: `$(window).height()-$('.header').height()-$('#headerToolsBar').height()-150-10`,
+        min: 180,
+        max: `$(window).height()-$('.header').height()-$('#headerToolsBar').height()-180-5`,
         notTopSpread: 0,
         notBottomSpread: $('#bottom_div ul').height(),
-        totalHeight: `$(window).height()-$('.header').height()-$('#headerToolsBar').height()-10`
+        totalHeight: `$(window).height()-$('.header').height()-$('#headerToolsBar').height()-5`
     };
     return mainResizeEles;
 }
+function getMaxLim(ele) {
+    $(window).height()-$('.header').height()-$('#headerToolsBar').height()-150-10
+}
 
 function loadMainSize() {//加载造价书页面各高度
     // 读取本地存储的高度(必须放在载入spread之前)

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

@@ -20,6 +20,11 @@ const ModuleNames = {
 };
 
 let gljType = gljUtil.gljType;
+let gljTypeSeq =gljUtil.getGljTypeSeq(); /*[gljType.LABOUR,gljType.MAIN_MATERIAL,gljType.CONCRETE,gljType.MORTAR,gljType.MIX_RATIO,gljType.COMMERCIAL_CONCRETE,
+    gljType.COMMERCIAL_MORTAR,gljType.GENERAL_MATERIAL,gljType.OTHER_MATERIAL,gljType.GENERAL_MACHINE,gljType.INSTRUMENT,gljType.OTHER_MACHINE_USED,
+    gljType.MACHINE_COMPOSITION,gljType.MACHINE_LABOUR,gljType.FUEL_POWER_FEE,gljType.DEPRECIATION_FEE,gljType.INSPECTION_FEE,gljType.MAINTENANCE,
+    gljType.DISMANTLING_FREIGHT_FEE,gljType.VERIFICATION_FEE,gljType.OTHER_FEE,gljType.EQUIPMENT,gljType.MANAGEMENT_FEE,gljType.PROFIT,gljType.GENERAL_RISK_FEE];*/
+
 // 计算基数 [定额基价材料费] 要用到的材料类型。
 const baseMaterialTypes = [
     gljType.GENERAL_MATERIAL,
@@ -140,7 +145,7 @@ const rationFrom = {
     std: 'std',
     cpt: 'cpt'
 };
-const leafBillGetFeeType = {
+let leafBillGetFeeType = {
     rationContent: 0,
     rationPriceConverse: 1,
     rationPrice: 2,

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

@@ -38,7 +38,7 @@ var ration_coe = {
         };
         ration_coe.prototype.refreshAfterSave=function(data){
             projectObj.project.ration_coe.addDatasToList(data);
-            zmhs_obj.showCoeData();
+            zmhs_obj.showDatas();
         };
 
         ration_coe.prototype.addDatasToList = function (datas) {
@@ -63,13 +63,14 @@ var ration_coe = {
             _.forEach(data.doc, function(n, key) {
                 coe_list[coe_index][key] = n;
             });
-            zmhs_obj.showCoeData();
+            $('#coeSpread').is(':visible'),
+            zmhs_obj.showDatas();
         };
         ration_coe.prototype.refreshAfterDelete=function(data){
             var glj_list = projectObj.project.ration_coe.datas;
             _.remove(glj_list,data.query);
             _.remove(gljOprObj.sheetData,data.query);
-            zmhs_obj.showCoeData();
+            zmhs_obj.showDatas();
         };
 
         ration_coe.prototype.getRationCoedata=function(newRation,data){

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

@@ -200,7 +200,7 @@ let ration_glj = {
         };
 
         ration_glj.prototype.addToMainTree = function (datas) {
-            datas = sortRationGLJ(datas);
+            datas = gljUtil.sortRationGLJ(datas);
             for (let data of datas) {
                 if (this.needShowToTree(data)) {
                     gljOprObj.setGLJPrice(data);
@@ -874,7 +874,7 @@ let ration_glj = {
             let gljList = _.filter(this.datas, function (n) {
                 return n.rationID == rationID && (n.type == gljType.MAIN_MATERIAL || n.type == gljType.EQUIPMENT)
             });
-            gljList = sortRationGLJ(gljList);
+            gljList = gljUtil.sortRationGLJ(gljList);
             return gljOprObj.combineWithProjectGlj(gljList);
         };
         ration_glj.prototype.transferToNodeData = function (data) {

+ 20 - 35
web/building_saas/main/js/views/billsElf.js

@@ -72,8 +72,8 @@ const BillsElf = (function() {
             ]
         },
         headers: [
-            {name: '施工工序', dataCode: 'name', width: 250, rateWidth: 0.5, vAlign: 'center', hAlign: 'center', formatter: '@'},
-            {name: '选项', dataCode: 'options', width: 250, rateWidth: 0.5,  vAlign: 'center', hAlign: 'left', formatter: '@'},
+            {name: '施工工序', dataCode: 'name', width: 180, rateWidth: 0.5, vAlign: 'center', hAlign: 'center', formatter: '@'},
+            {name: '选项', dataCode: 'options', width: 180, rateWidth: 0.5,  vAlign: 'center', hAlign: 'left', formatter: '@'},
         ],
         rowHeaderWidth:25,
         events: {
@@ -205,7 +205,7 @@ const BillsElf = (function() {
             }
             setOptions(elfItem.workBook, options);
             buildHeader(elfItem.workBook.getActiveSheet(), elfItem.headers);
-            setColumnWidthByRate(elfItem.workBook, $('#elfItems').width(), elfItem.headers);
+            //setColumnWidthByRate(elfItem.workBook, $('#elfItems').width(), elfItem.headers);
             bindEvent(elfItem.workBook, elfItem.events);
         }
     }
@@ -247,7 +247,6 @@ const BillsElf = (function() {
                 billsNode.elf.tree.selected = node;
             }
         }
-        refreshInsertSingle();
     }
     //清单焦点变换-清单精灵操作,获取清单前九位编码的标准清单清单精灵选项
     //@param {String}code @return {void}
@@ -255,8 +254,6 @@ const BillsElf = (function() {
         let elfSheet = elfItem.workBook.getActiveSheet();
         cleanData(elfSheet, elfItem.headers, -1);
         if (!code || code === '') {
-            $('#elfInsertRation').addClass('disabled');
-            $('#elfInsertSingle').addClass('disabled');
             return;
         }
         let nineCode = code.substr(0, 9);
@@ -272,11 +269,11 @@ const BillsElf = (function() {
                 guidanceLibID = projectInfoObj.projectInfo.engineeringInfo.billsGuidance_lib[0] ? projectInfoObj.projectInfo.engineeringInfo.billsGuidance_lib[0].id : null;
             }
             CommonAjax.post('/billsGuidance/api/getItemsByCode', {guidanceLibID: guidanceLibID, code: nineCode}, function (rstData) {
-                //定额数据删除编号信息
+                //定额数据删除编号信息,(编码后+空格才会去除编码)
                 for(let rData of rstData){
                     if(rData.type === itemType.ration){
                         let nameArr = rData.name.split(' ');
-                        if(nameArr.length > 0){
+                        if(nameArr.length > 1){
                             nameArr.splice(0, 1);
                             rData.name = nameArr.join(' ');
                         }
@@ -311,7 +308,6 @@ const BillsElf = (function() {
                     setOptionsCellType(node.elf.tree.items);
                     //项目指引初始焦点
                     elfItemInitSel(elfSheet.getActiveRowIndex() ? elfSheet.getActiveRowIndex() : 0);
-                    refreshInsertRation();
                 });
             });
         }
@@ -321,7 +317,6 @@ const BillsElf = (function() {
                 setOptionsCellType(node.elf.tree.items);
                 //项目指引初始焦点
                 elfItemInitSel(elfSheet.getActiveRowIndex() ? elfSheet.getActiveRowIndex() : 0);
-                refreshInsertRation();
             });
         }
     }
@@ -367,6 +362,7 @@ const BillsElf = (function() {
             let obj = IDMapping[ID];
             if(!obj.pre){
                 first = obj;
+                break;
             }
         }
         while(first){
@@ -375,6 +371,17 @@ const BillsElf = (function() {
             rst.push(first.self);
             first = first.next;
         }
+        //兼容同层节点NextSibling错误的情况下,同层节点还是能显示出来(但是无法保证正确的顺序)
+        //兼容模式下,不按照NextSibling排序,直接按照options元素位置排序
+        if (rank !== options.length) {
+            rst = [];
+            rank = 0;
+            for (let opt of options) {
+                rank++;
+                opt.rank = rank;
+                rst.push(opt);
+            }
+        }
 
         return rst;
     }
@@ -461,7 +468,7 @@ const BillsElf = (function() {
             }
             let height = cellRect.height;
             let options = getOptions(node.data, bills.selected.elf.datas);
-            top = options.length - 2 > 4 ? top - 4 * height : top - (options.length - 2) * height;
+            top = options.length > 6 ? top - 6 * height : top - options.length * height;
             let $editInput = $(`<div style="height: ${height}px; background: ${cellStyle.backColor};overflow: hidden; white-space: nowrap; text-overflow: ellipsis">${node.data.options}</div>`),
                 $optDiv = $(`<div style="position: fixed; width: ${cellRect.width}px; top: ${top}px;background: ${cellStyle.backColor};border: 1px solid; overflow: auto; height: ${options.length > 6 ? height*6+5 : height*options.length+5}px; font-size: 0.9rem;"></div>`);
             for(let opt of options){
@@ -530,8 +537,6 @@ const BillsElf = (function() {
             }
             TREE_SHEET_HELPER.refreshTreeNodeData(elfItem.treeSetting, elfSheet, node.tree.items, false);
             setOptionsCellType(node.tree.items);
-            refreshInsertRation();
-            refreshInsertSingle();
         }
         //获取删除节点
         function getDeleteNodes(node, optionChecked) {
@@ -566,7 +571,8 @@ const BillsElf = (function() {
                 $editor.css("background", "white");
                 $editor.css("width", cellRect.width);
                 $editor.attr("gcUIElement", "gcEditingInput");
-                let top = $('.header').height() + $('#zaojiashu').find('.toolsbar').height() + $('#top_div').height();
+                //编辑文本框距离浏览器的top
+                let top = $('.header').height() + $('#zaojiashu').find('.toolsbar').height() + $('#top_div').height() + $('#bottom_div_ul').height() + 1 + $('.resize-y').height();
                 let activeCellTop = $editor.parent().parent().css('top');
                 activeCellTop = parseFloat(activeCellTop.replace('px', ''));
                 let node = bills.selected.elf.tree.items[elfSheet.getActiveRowIndex()];
@@ -723,31 +729,10 @@ const BillsElf = (function() {
     function insertRations(addRationDatas){
         if(addRationDatas.length > 0){
             projectObj.project.Ration.addMultiRation(addRationDatas, function () {
-                refreshInsertRation();
                 projectObj.setActiveCell('quantity', true);
             });
         }
     }
-    //更新插入定额按钮有效性
-    function refreshInsertRation(){
-        if (!projectReadOnly) {
-            if (getInsertElfRationData().length > 0) {
-                $('#elfInsertRation').removeClass('disabled');
-            } else {
-                $('#elfInsertRation').addClass('disabled');
-            }
-        }
-    }
-    //更新插入单条按钮有效性
-    function refreshInsertSingle() {
-        if (!projectReadOnly) {
-            if (getInsertElfSingleRation().length > 0) {
-                $('#elfInsertSingle').removeClass('disabled');
-            } else {
-                $('#elfInsertSingle').addClass('disabled');
-            }
-        }
-    }
     //各监听事件
     //@return {void}
     function bindListener(){

+ 43 - 36
web/building_saas/main/js/views/block_lib.js

@@ -3,7 +3,7 @@
  * Created by CSL on 2018-09-19.
  */
 var blockLibObj = {
-    libs: [],
+    // libs: [],
     activeLib: null,
     mainSpread: null,
     mainSheet: null,
@@ -72,19 +72,23 @@ var blockLibObj = {
     buildSheet: async function () {
         $.bootstrapLoading.start();
         let me = this;
-       /* me.mainDatas = [
-            {ID: 1, ParentID: -1, NextSiblingID: 2, nodeName: '分类1', type: 1},
-            {ID: 2, ParentID: -1, NextSiblingID: 3, nodeName: '分类2', type: 1},
-            {ID: 3, ParentID: -1, NextSiblingID: 4, nodeName: '分类3', type: 1},
-            // {ID: 105, ParentID: 1, NextSiblingID: 106, name: '块1', type: 2},
-            // {ID: 106, ParentID: 1, NextSiblingID: 107, name: '块2', type: 2},
-            {ID: 7, ParentID: -1, NextSiblingID: 8, nodeName: '分类7', type: 1},
-            {ID: 9, ParentID: -1, NextSiblingID: -1, nodeName: '分类9', type: 1}//,
-            // {ID: 201, ParentID: 52, NextSiblingID: -1, nodeName: '块201', type: 2}
-        ];*/
-
-       if (me.libs.length > 0) me.libs.splice(0, me.libs.length);
-       if (me.mainSpread) {
+        let namesAndLib = await ajaxPost('/blockLib/getLibNamesAndFirstLib',
+            {userID: userID, userName: userName, compilationID: projectInfoObj.projectInfo.compilation});
+        function getLibNamesHtml(libsArr) {
+            let result = '';
+            for (let lib of libsArr) {
+                result += '<option value="' + lib.libID + '">' + lib.libName + '</option>';
+            };
+            return result;
+        };
+        let html = getLibNamesHtml(namesAndLib.libNames);
+        $("#select_block_lib_names").html(html);
+        await me.loadLib(namesAndLib.firstLib);
+        $.bootstrapLoading.end();
+    },
+    loadLib: async function (lib){
+        let me = this;
+        if (me.mainSpread) {
             me.mainSpread.destroy();
             me.mainSpread = null;
         };
@@ -97,23 +101,9 @@ var blockLibObj = {
             me.rationSpread = null;
         };
 
-        let namesAndLib = await ajaxPost('/blockLib/getLibNamesAndFirstLib', {userID: userID, compilationID: projectInfoObj.projectInfo.compilation});
-        me.mainDatas = namesAndLib.firstLib.datas;
-        me.libs.push(namesAndLib.firstLib);
-        me.activeLib = namesAndLib.firstLib;
-
-        function getLibNamesHtml(libsArr) {
-            let result = '';
-            for (let lib of libsArr) {
-                result += '<option value="' + lib.libID + '">' + lib.libName + '</option>';
-            };
-            return result;
-        };
-        let html = getLibNamesHtml(namesAndLib.libNames);
-        $("#select_block_lib_names").html(html);
-
+        me.mainDatas = lib.datas;
+        me.activeLib = lib;
         me.mainSpread = SheetDataHelper.createNewSpread($('#div_block_tree')[0]);
-        // me.mainSpread = TREE_SHEET_HELPER.createNewSpread($('#div_block_tree')[0]);
         me.mainSheet = me.mainSpread.getSheet(0);
         me.mainSheet.name('blockLibSheet');
         sheetCommonObj.spreadDefaultStyle(me.mainSpread);
@@ -145,8 +135,6 @@ var blockLibObj = {
 
         me.mainSpread.bind(GC.Spread.Sheets.Events.EnterCell, me.onEnterCell);
         me.mainSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick, this.onCellDoubleClick);
-
-        $.bootstrapLoading.end();
     },
     loadDetailDatas: function (node){
         let me = this;
@@ -364,6 +352,7 @@ var blockLibObj = {
         return new TreeCell();
     },
     newNode: async function (nodeType, nodeName, categoryID, source){     // 1 分类(只用前两个参数)  2 块文件
+        if (nodeName == '') return;
         let tree = blockLibObj.mainTree;
         let ID = uuid.v1();
         let pID = (nodeType == 2) ? categoryID : -1;
@@ -448,10 +437,11 @@ var blockLibObj = {
         // this.mainTreeController.moveTo(parentID);
     },
     delete: async function () {
+        let node = blockLibObj.mainTree.selected;
         let obj = {
             libID: blockLibObj.activeLib.libID,
-            nodeID: blockLibObj.mainTree.selected.data.ID,
-            delete: true
+            nodeID: node.data.ID,
+            delete: {nodeType: node.data.type}
         };
         await ajaxPost('/blockLib/saveBlock', obj);
         this.mainTreeController.delete();
@@ -583,8 +573,15 @@ var blockLibObj = {
         me.mainTree.selected = me.mainTree.items[me.mainSheet.getActiveRowIndex()];
     },
     onCellDoubleClick: function (sender, args) {
+        if (blockLibObj.curIsCategory()) {
+            hintBox.infoBox('系统提示', `双击是“一对一克隆”,不支持分类操作,请在块文件上双击!`, 1);
+            return;
+        }
         let projectNode = projectObj.project.mainTree.selected;
-        if (!calcTools.isLeafBill(projectNode)) return;
+        if (!calcTools.isLeafBill(projectNode)) {
+            hintBox.infoBox('系统提示', `双击是“一对一克隆”,请在造价书界面选择最底层的分项/补项/清单进行操作!`, 1);
+            return;
+        }
         blockLibObj.cloneType = 1;
         $("#div_cloneOptions").modal({show: true});
     },
@@ -640,7 +637,7 @@ $(document).ready(function(){    // 这里不需要处理异步:因为不需
 
     $('#btn_block_newFolder_add').on('click', function (){
         let name = $('#input_block_newFolder').val();
-        if (name != '') blockLibObj.newNode(1, name);
+        blockLibObj.newNode(1, name);
     });
 
     $('#btn_block_reName').on('click', function (){
@@ -655,4 +652,14 @@ $(document).ready(function(){    // 这里不需要处理异步:因为不需
         if (oldName != newName) blockLibObj.reName(select, newName);
     });
 
+    $("#select_block_lib_names").change(function() {
+        async function getLib(){
+            let libID = $("#select_block_lib_names").val();
+            let lib = await ajaxPost('/blockLib/getLib', {libID: libID});
+            blockLibObj.loadLib(lib);
+        };
+        $.bootstrapLoading.start();
+        getLib();
+        $.bootstrapLoading.end();
+    });
 });

+ 46 - 24
web/building_saas/main/js/views/calc_program_manage.js

@@ -6,6 +6,8 @@ let calcProgramManage = {
     datas: [],
     mainSpread: null,
     detailSpread: null,
+    mainSheet: null,
+    detailSheet: null,
     mainSetting: {
         header:[
             // {headerName:"ID",headerWidth:80,dataCode:"ID", hAlign: "center"},
@@ -49,30 +51,30 @@ let calcProgramManage = {
             me.detailSpread = null;
         };
         me.mainSpread = sheetCommonObj.buildSheet($('#mainSpread')[0], me.mainSetting, me.datas.length);
+        me.mainSheet = me.mainSpread.getSheet(0);
         sheetCommonObj.spreadDefaultStyle(me.mainSpread);
         me.detailSpread = sheetCommonObj.buildSheet($('#detailSpread')[0], me.detailSetting, me.datas[0].calcItems.length);
+        me.detailSheet = me.detailSpread.getSheet(0);
         sheetCommonObj.spreadDefaultStyle(me.detailSpread);
         let arr = projectObj.project.calcProgram.compiledFeeTypeNames.slice();
         // arr.delete('暂估费');
         let fieldName = new GC.Spread.Sheets.CellTypes.ComboBox();
         fieldName.items(arr);
-        me.detailSpread.getSheet(0).getRange(-1, 4, -1, 1).cellType(fieldName);
+        me.detailSheet.getRange(-1, 4, -1, 1).cellType(fieldName);
 
-        me.mainSpread.getSheet(0).bind(GC.Spread.Sheets.Events.EnterCell, me.onMainEnterCell);
-        me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.ValueChanged, me.onDetailValueChanged);
-        me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.RangeChanged, me.onRangeChanged);
-        me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.EnterCell, me.onDetailEnterCell);
-        me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
+        me.mainSheet.bind(GC.Spread.Sheets.Events.EnterCell, me.onMainEnterCell);
+        me.detailSheet.bind(GC.Spread.Sheets.Events.ValueChanged, me.onDetailValueChanged);
+        me.detailSheet.bind(GC.Spread.Sheets.Events.RangeChanged, me.onRangeChanged);
+        me.detailSheet.bind(GC.Spread.Sheets.Events.EnterCell, me.onDetailEnterCell);
+        me.detailSheet.bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
+        sheetCommonObj.showData(me.mainSheet, me.mainSetting, me.datas);
 
-        let mSheet = me.mainSpread.getSheet(0);
-        sheetCommonObj.showData(mSheet, me.mainSetting, me.datas);
-
-        let dSheet = me.detailSpread.getSheet(0);
-        dSheet.name('calc_detail');
-        feeRateObject.setFeeRateCellCol(dSheet,_.findIndex(me.detailSetting.header,{'dataCode':'feeRate'}));
-        dSheet.getRange(-1, _.findIndex(me.detailSetting.header, {'dataCode': 'dispExprUser'}), -1, 1).cellType(calcBaseView.getCalcBaseCellType('ration'));
-        sheetCommonObj.showData(dSheet, me.detailSetting, me.datas[0].calcItems);
-        customRowHeader(dSheet, me.datas[0].calcItems.length);
+        me.detailSheet.name('calc_detail');
+        feeRateObject.setFeeRateCellCol(me.detailSheet, _.findIndex(me.detailSetting.header,{'dataCode':'feeRate'}));
+        me.detailSheet.getRange(-1, _.findIndex(me.detailSetting.header, {'dataCode': 'dispExprUser'}), -1, 1).cellType(calcBaseView.getCalcBaseCellType('ration'));
+        sheetCommonObj.showData(me.detailSheet, me.detailSetting, me.datas[0].calcItems);
+        me.getfeeRateColor(me.datas[0].calcItems);
+        customRowHeader(me.detailSheet, me.datas[0].calcItems.length);
         if(!projectReadOnly){
             me.loadMainContextMenu();
             me.loadDetailContextMenu();
@@ -109,11 +111,11 @@ let calcProgramManage = {
         var row = args.sheet.getActiveRowIndex();
 
         me.detailSpread.suspendPaint();
-        var dSheet = me.detailSpread.getSheet(0);
         var dData = me.datas[row].calcItems;
-        dSheet.setRowCount(dData.length, GC.Spread.Sheets.SheetArea.viewport);
-        sheetCommonObj.showData(dSheet, me.detailSetting, dData);
-        customRowHeader(dSheet, dData.length);
+        me.detailSheet.setRowCount(dData.length, GC.Spread.Sheets.SheetArea.viewport);
+        sheetCommonObj.showData(me.detailSheet, me.detailSetting, dData);
+        me.getfeeRateColor(dData);
+        customRowHeader(me.detailSheet, dData.length);
         me.detailSpread.resumePaint();
     },
     onRangeChanged:function (sender,args) {
@@ -254,14 +256,20 @@ let calcProgramManage = {
                         newTemplate.custom = true;
                         newTemplate.calcItems = [];
                         $.extend(true, newTemplate.calcItems, template.calcItems);
+                        // 清理掉费率ID关联
+                        for (let ci of newTemplate.calcItems){
+                            if (ci.feeRateID || ci.feeRateID == null)
+                                delete ci.feeRateID;
+                        };
 
                         let data = {
                             'projectID': projectObj.project.ID(),
                             'ID': newTemplate.ID,
                             'name': newTemplate.name,
                             'custom': newTemplate.custom,
-                            'calcItems': template.calcItems
+                            'calcItems': newTemplate.calcItems
                         };
+
                         calcProgramManage.addTemplate(data, function (rst) {
                             if (rst){
                                 let ts = projectObj.project.calcProgram.templates;
@@ -269,11 +277,12 @@ let calcProgramManage = {
                                 projectObj.project.calcProgram.compileTemplateMaps();
                                 projectObj.project.calcProgram.compileTemplate(newTemplate);
                                 calcProgramManage.buildSheet();
-                                calcProgramManage.mainSpread.getActiveSheet().setSelection(ts.length - 1, 0, 1, 1);
+                                calcProgramManage.mainSheet.setSelection(ts.length - 1, 0, 1, 1);
+                                calcProgramManage.mainSheet.showRow(ts.length - 1, GC.Spread.Sheets.VerticalPosition.center);
                                 calcProgramManage.refreshDetailSheet();
+                                $.bootstrapLoading.end();
                             }
                         });
-                        $.bootstrapLoading.end();
                     }
                 },
                 "reNameTemplate": {
@@ -335,6 +344,7 @@ let calcProgramManage = {
                         return !canDelete;
                     },
                     callback: function () {
+                        $.bootstrapLoading.start();
                         let template = calcProgramManage.getSelectionInfo().template;
                         if (analyzer.templateIsUsed(template.ID)) {
                             $.bootstrapLoading.end();
@@ -349,12 +359,14 @@ let calcProgramManage = {
                             };
                             calcProgramManage.deleteTemplate(data, function (rst) {
                                 if (rst){
-                                    let idx = calcProgramManage.mainSpread.getActiveSheet().getActiveRowIndex();
+                                    let idx = calcProgramManage.mainSheet.getActiveRowIndex();
                                     projectObj.project.calcProgram.templates.splice(idx, 1);
                                     projectObj.project.calcProgram.compileTemplateMaps();
                                     calcProgramManage.buildSheet();
-                                    calcProgramManage.mainSpread.getActiveSheet().setSelection(idx - 1, 0, 1, 1);
+                                    calcProgramManage.mainSheet.setSelection(idx - 1, 0, 1, 1);
+                                    calcProgramManage.mainSheet.showRow(idx - 1, GC.Spread.Sheets.VerticalPosition.center);
                                     calcProgramManage.refreshDetailSheet();
+                                    $.bootstrapLoading.end();
                                 }
                             });
                         };
@@ -505,8 +517,18 @@ let calcProgramManage = {
             let detailSheet = me.detailSpread.getActiveSheet();
             detailSheet.setRowCount(calcItems.length);
             sheetCommonObj.showData(detailSheet, me.detailSetting, calcItems);
+            me.getfeeRateColor(calcItems);
             customRowHeader(detailSheet, calcItems.length);
         }
+    },
+    getfeeRateColor: function (calcItems) {    // 有费率ID关联的变个色
+        var me = this;
+        for (let i = 0; i < calcItems.length; i++) {
+            if (calcItems[i].feeRateID != undefined && calcItems[i].feeRateID != null)
+                me.detailSheet.getCell(i, 3).foreColor("#0aa8ea")
+            else
+                me.detailSheet.getCell(i, 3).foreColor("black");
+        }
     }
 };
 

+ 40 - 3
web/building_saas/main/js/views/fee_rate_view.js

@@ -188,6 +188,29 @@ var feeRateObject={
             return 0
         }
     },
+    initFeeRateEditDiv:function(optionValue){//“0” 手工输入; “1” 选择费率
+        let radioValue = optionValue,feeRateValue;
+        if(!gljUtil.isDef(optionValue)){
+            let fID = 0;
+            if ($("#calc_program_manage").is(":visible")){
+                fID = calcProgramManage.getSelectionInfo().calcItem.feeRateID;
+                feeRateValue = calcProgramManage.getSelectionInfo().calcItem.feeRate;
+            } else if ($("#zaojiashu").is(":visible")){
+                fID = projectObj.project.mainTree.selected.data.feeRateID;
+                feeRateValue = projectObj.project.mainTree.selected.data.feeRate;
+            }
+            radioValue = fID?"1":"0";
+            $("#customFeeRate").val(feeRateValue);
+        }
+        $("input[name='editFeeRateOptions'][value='"+radioValue+"']").attr("checked",true);
+        if(radioValue == "0"){
+            $("#selfDiv").show();
+            $("#fee_rate_sheet").hide();
+        }else {
+            $("#selfDiv").hide();
+            $("#fee_rate_sheet").show();
+        }
+    },
     locate: function(){   // CSL,2018.07.18
         let sheet = feeRateObject.feeRateSpreads.getSheet(0);
         let fID = 0;
@@ -955,7 +978,7 @@ function getPopoverContent() {
     var usageProjects = feeRateFile.usageProjects;
     let names = _.map(usageProjects,'name');
     let popover_content = names.join('<br>');
-    return popover_content;
+    return "费率的变化,将自动影响以下单位工程造价:<br>"+ popover_content;
 }
 
 $(function(){
@@ -1109,6 +1132,7 @@ $(function(){
         if(feeRateObject.feeRateSpreads==null){
             feeRateObject.createSheet();
         }
+        feeRateObject.initFeeRateEditDiv();
         feeRateObject.feeRateSelection=null;
         feeRateObject.showFeeRateTree(feeRateObject.feeRateSheet,feeRateObject.sheetSetting,projectObj.project.FeeRate.getActivateFeeRate().rates);
         feeRateObject.locate();
@@ -1134,7 +1158,21 @@ $(function(){
             return;
         }
         feeRateObject.submitFeeRateBySelect();
-    })
+    });
+    $("input[name='editFeeRateOptions']").each(function(){
+        $(this).click(function(){
+            let optins = $(this).val();
+            if(optins == "0"){
+                $("#selfDiv").show();
+                $("#fee_rate_sheet").hide();
+            }else {
+                $("#selfDiv").hide();
+                $("#fee_rate_sheet").show(function () {
+                    feeRateObject.feeRateSpreads.refresh();
+                });
+            }
+        });
+    });
 })
 function changeFRadioClick() {
     var radioV= $("input[name='chaneg-lv-Radio']:checked").val();
@@ -1146,4 +1184,3 @@ function changeFRadioClick() {
         $("#fromOther").show();
     }
 }
-

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

@@ -4,21 +4,21 @@
 let gljCol = {
     ration_glj_setting: {
         header: [
-            {headerName: "编码", headerWidth: 130, dataCode: "code", dataType: "String", formatter: "@"},
+            {headerName: "编码", headerWidth: 110, dataCode: "code", dataType: "String", formatter: "@"},
             {headerName: "名称", headerWidth: 160, dataCode: "name", dataType: "String",cellType:'tipsCell'},
             {headerName: "规格型号", headerWidth: 120, dataCode: "specs", dataType: "String", hAlign: "left",cellType:'tipsCell'},
             {headerName: "单位", headerWidth: 45, dataCode: "unit", dataType: "String", hAlign: "center"},
             {headerName: "市场价", headerWidth: 65, dataCode: "marketPrice", dataType: "Number", hAlign: "right"},//, decimalField: "glj.unitPrice"
             {headerName: "调整价", headerWidth: 65, dataCode: "adjustPrice", dataType: "Number", hAlign: "right"},//, decimalField: "glj.unitPrice"1
-            {headerName: "定额价", headerWidth: 65, dataCode: "basePrice", dataType: "Number", hAlign: "right"},//, decimalField: "glj.unitPrice"
-            {headerName: "定额消耗", headerWidth: 65, dataCode: "rationItemQuantity", dataType: "Number", hAlign: "right", decimalField: "glj.quantity"},   // dataType: "Number", formatter: "0.00"
             {headerName: "自定消耗", headerWidth: 65, dataCode: "customQuantity", dataType: "Number", hAlign: "right", decimalField: "glj.quantity"},
             {headerName: "消耗量", headerWidth: 65, dataCode: "quantity", dataType: "Number", hAlign: "right", decimalField: "glj.quantity"},
+            {headerName: "定额价", headerWidth: 65, dataCode: "basePrice", dataType: "Number", hAlign: "right"},//, decimalField: "glj.unitPrice"
+            {headerName: "定额消耗", headerWidth: 65, dataCode: "rationItemQuantity", dataType: "Number", hAlign: "right", decimalField: "glj.quantity"},   // dataType: "Number", formatter: "0.00"
             {headerName: "总消耗量", headerWidth: 80, dataCode: "totalQuantity", dataType: "Number", hAlign: "right", decimalField: "glj.quantity"},
             {headerName: "暂估", headerWidth: 45, dataCode: "isEstimate", dataType: "String", hAlign: "center", vAlign: "center", cellType: "checkBox"}
         ],
         view: {
-            lockColumns: [ 5, 7, 9, 10, 11],//这里以后改成dataCode好一点
+            lockColumns: [ "adjustPrice", "rationItemQuantity", "quantity", "totalQuantity", "isEstimate"],//这里以后改成dataCode好一点
             rowHeaderWidth:25
         },
         getStyle:function (data) {
@@ -80,6 +80,7 @@ let gljCol = {
             setting.header.splice(colIndex,1);//去掉列;
             let newArray = [];
             for(let l of setting.view.lockColumns){
+                if(_.isString(l)) return;//如果是用dataCode表示的,不用处理
                 if(l == colIndex)  continue;
                 if(l > colIndex)  l = l -1;
                 newArray.push(l);

+ 5 - 18
web/building_saas/main/js/views/glj_view.js

@@ -359,14 +359,8 @@ var gljOprObj = {
         if(gljOprObj.isInstallationNode(selected)==true){
             return;
         }
-        let newval = 0;
-        if (checkboxValue) {
-            newval = 0;
-            args.sheet.getCell(args.row, args.col).value(newval);
-        } else {
-            newval = 1;
-            args.sheet.getCell(args.row, args.col).value(newval);
-        }
+        let newval = checkboxValue? 0:1;
+        args.sheet.getCell(args.row, args.col).value(newval);
         if (args.sheetName == 'ration_glj') {
             gljOprObj.updateIsEstimate(args,newval);
         }  else if (args.sheetName == 'quantity_detail') {
@@ -564,7 +558,7 @@ var gljOprObj = {
         }
         this.sheetData = gljList;
         this.sheet.setRowCount(0);
-        this.sheetData = sortRationGLJ(this.sheetData);
+        this.sheetData = gljUtil.sortRationGLJ(this.sheetData);
         this.sheet.getRange(-1, 0, -1, 1).cellType(this.getTreeNodeCellType([]));
         sheetCommonObj.showData(this.sheet, this.setting, this.sheetData);
         //初始选择
@@ -593,7 +587,7 @@ var gljOprObj = {
         let selected = this.sheet.getSelections();
         this.combineWithProjectGlj(this.sheetData);
         this.sheet.setRowCount(0);
-        this.sheetData = sortRationGLJ(this.sheetData);
+        this.sheetData = gljUtil.sortRationGLJ(this.sheetData);
         this.sumQuantity();//计算总消耗量
         this.addMixRatioToShow();//显示组成物信息
         this.initRationTree(init,this.getUnitPriceCodeMap());
@@ -833,7 +827,7 @@ var gljOprObj = {
             }
             temRationGLJs.push(tem);
         }
-        temRationGLJs = _.sortBy(temRationGLJs, 'code');
+        temRationGLJs = gljUtil.sortRationGLJ(temRationGLJs);
         return temRationGLJs;
     },
     showQuantityDetailData: function (node) {
@@ -1650,13 +1644,6 @@ function getDecimal(fieldID, node) {
 }
 
 
-function sortRationGLJ(list) {
-    list = _.sortByAll(list, [function (item) {
-        return item.type + "";
-    }, "code"])
-    return list;
-}
-
 function compareRationGLJ(a, b) {
     if ((a.type + "") < (b.type + "")) {
         return true

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

@@ -442,7 +442,7 @@ let MainTreeCol = {
         let tips="";
         let ration_glj = projectObj.project.ration_glj;
         let gljList = gljOprObj.filterGljByRation(node.data, ration_glj.datas);
-        gljList = sortRationGLJ(gljList);
+        gljList = gljUtil.sortRationGLJ(gljList);
         for(let glj of gljList){
             tips += `${glj.code} ${glj.name}${glj.specs ? '&nbsp;&nbsp;&nbsp;' + glj.specs : ''}&nbsp;&nbsp&nbsp;${glj.unit}&nbsp;&nbsp;&nbsp;${glj.quantity}<br>`;
         }

+ 7 - 3
web/building_saas/main/js/views/mbzm_view.js

@@ -181,11 +181,15 @@ let mbzm_obj={
                 projectObj.project.calcProgram.calcNodesAndSave(calRations,function () {
                     installationFeeObj.calcInstallationFee();
                 });
-
+                mbzm_obj.showApplySuccess();
             });
-            console.log(result);
         })
-
+    },
+    showApplySuccess:function () {
+        $(".applySuccess").show();
+        setTimeout(function () {
+            $(".applySuccess").hide();
+        },1500)
     },
     positionChecking(type,data){//这个要之后再测试一下
         let validate = true;

+ 12 - 9
web/building_saas/main/js/views/project_glj_view.js

@@ -130,7 +130,7 @@ projectGljObject={
         $("#used-project-count").text(usedCount);
     },
     getUsedTenderInfo:function() {
-        return projectGljObject.usedTenderList.join("<br>");
+        return "人材机单价的变化,将自动影响以下单位工程造价:<br>"+projectGljObject.usedTenderList.join("<br>");
     },
     filterLibGLJForMixRatio:function () {
         let me = this;
@@ -194,11 +194,12 @@ projectGljObject={
             if(gljId !== projectObj.project.projectGLJ.getRatioId){//两个id不一致说明不是最新的请求,不用往下执行。
                 return;
             }
-            let rationList =[];
+            let ratioList =[];
             for(let glj of data){
-                rationList.push(me.getMixRatioSheetData(glj)) ;
+                ratioList.push(me.getMixRatioSheetData(glj)) ;
             }
-            me.mixRatioData = rationList;
+            ratioList = gljUtil.sortRationGLJ(ratioList);
+            me.mixRatioData = ratioList;
             me.mixRatioSheet.setRowCount(0);
             sheetCommonObj.showData(me.mixRatioSheet, me.mixRatioSetting,me.mixRatioData);
             me.mixRatioSheet.setRowCount(me.mixRatioData.length);
@@ -947,7 +948,8 @@ projectGljObject={
         return supply_quantity
     },
     checkData : function(col,setting, value) {
-        let result = true;
+        return sheetCommonObj.checkData(col,setting, value);
+     /*   let result = true;
         let validator = setting.header[col].validator !== undefined ? setting.header[col].validator : null;
         if (validator === null) {
             return result;
@@ -962,7 +964,7 @@ projectGljObject={
                 result = booleanValue.indexOf(value) >= 0;
                 break;
         }
-        return result;
+        return result;*/
     },
     getProjectGLJSelected:function () {
         let me = projectGljObject;
@@ -1080,10 +1082,10 @@ function getProjectResizeEles() {
     };
     pojGljResizeEles.limit = {
         min: 150,
-        max: `$(window).height()-$('.header').height()-$('#projectGljToolsBar').height()-150-10`,//10: resize.height()
+        max: `$(window).height()-$('.header').height()-$('#projectGljToolsBar').height()-150-5`,//5: resize.height()
         notTopSpread: 0,
-        notBottomSpread: $('#projectGljBottom ul').height(),
-        totalHeight: `$(window).height()-$('.header').height()-$('#projectGljToolsBar').height()-10`
+        notBottomSpread: 0,
+        totalHeight: `$(window).height()-$('.header').height()-$('#projectGljToolsBar').height()-5`
     };
     return pojGljResizeEles;
 }
@@ -1233,6 +1235,7 @@ $(function () {
             changeUnitPriceId = $("#self-file").val();
             if(!changeUnitPriceId){
                 alert('单价文件不可为空');
+                return;
             }
             submitFileChange(changeUnitPriceId,type);
         } else {

+ 4 - 1
web/building_saas/main/js/views/project_info.js

@@ -19,8 +19,11 @@ var projectInfoObj = {
                 <span class="text-muted px-1">\</span>
                  <span><i class="fa fa-sticky-note-o"></i></span>
                 <span class="text-truncate"  data-toggle="tooltip" data-placement="bottom" data-original-title="${proj.name}">&nbsp;${proj.name}</span>
-                ${projectReadOnly ? '' +
+                ${projectReadOnly ?
                 '<span data-toggle="tooltip" data-placement="bottom" data-original-title="当前的工程状态为“只读”,如果要进行编辑,请在项目管理-分享界面,使用“拷贝工程”功能。">(只读)</span>' 
+                : ''}
+                ${projectCooperate ? 
+                '<span data-toggle="tooltip" data-placement="bottom" data-original-title="当前的工程状态为“协作”,可直接编辑分享人的原始数据。">(协作)</span>'
                 : ''}`;
             fullPath.push(newHtml);
 

+ 92 - 33
web/building_saas/main/js/views/project_view.js

@@ -1,7 +1,6 @@
 /**
  * Created by Mai on 2017/6/21.
  */
-
 var projectObj = {
     project: null,
     mainSpread: null,
@@ -19,7 +18,10 @@ var projectObj = {
         let s = `&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${c}${value}`;
         $('#testDisplay').html(s);
     },
+    selectedChangeNowTime: 0,
+    selectedChangeDelayTime: 20,
     treeSelectedChanged: function (node) {
+        let me = this;
         let project = projectObj.project;
         let mainSheet = projectObj.mainController.sheet;
         let init = true;
@@ -35,23 +37,34 @@ var projectObj = {
         mbzm_obj.nodeChanged = init;
         project.mainTree.preSelected = node;
         projectObj.setNodesStyle(projectObj.mainController.sheet, refreshNodes);
-        if($('#linkComments').hasClass('active')){
-            subViewObj.loadComments(node);
-        }
-        let nodeID = node ? node.getID() : null;
-        gljOprObj.mainTreeSelectedChange = gljOprObj.selectedNodeId != nodeID;
-        if(init) subObj.initNavItem(node);
-       /*
-       2018-11-9 在NavItem里设置了默认显示的item,在里执行了click这个操作所以这两个操作不用重复执行了
-       gljOprObj.showDataIfRationSelect(node);
-        if (activeSubSheetIsCalcProgram())
-            calcProgramObj.refreshCalcProgram(node, 3);*/
-
-        //zhong 2017-9-1 特征及内容
-        if(pageCCOprObj.active){
-            pageCCOprObj.mainActiveCell = projectObj.mainSpread.getActiveSheet().getSelections()[0];//mainSpread焦点单元格
-            pageCCOprObj.setCacheAndShow(node);
-        }
+        function delayOpr(callback) {
+            let nowTime = Date.now();
+            me.selectedChangeNowTime = nowTime;
+            setTimeout(function () {
+                if (nowTime - me.selectedChangeNowTime == 0) {
+                    callback();
+                }
+            }, me.selectedChangeDelayTime);
+        }
+        delayOpr(function () {
+            if($('#linkComments').hasClass('active')){
+                subViewObj.loadComments(node);
+            }
+            let nodeID = node ? node.getID() : null;
+            gljOprObj.mainTreeSelectedChange = gljOprObj.selectedNodeId != nodeID;
+            if(init) subObj.initNavItem(node);
+            /*
+             2018-11-9 在NavItem里设置了默认显示的item,在里执行了click这个操作所以这两个操作不用重复执行了
+             gljOprObj.showDataIfRationSelect(node);
+             if (activeSubSheetIsCalcProgram())
+             calcProgramObj.refreshCalcProgram(node, 3);*/
+
+            //zhong 2017-9-1 特征及内容
+            if(pageCCOprObj.active){
+                pageCCOprObj.mainActiveCell = projectObj.mainSpread.getActiveSheet().getSelections()[0];//mainSpread焦点单元格
+                pageCCOprObj.setCacheAndShow(node);
+            }
+        });
     },
     refreshBaseActn: function (tree) {
         let setButtonValid = function (valid, btn) {
@@ -1315,8 +1328,6 @@ var projectObj = {
                         if (projectReadOnly) {
                             return true;
                         }
-                        // var selected = project.mainTree.selected;
-                        // return project.Ration.addRationChecking(selected);  // Vincent, 2018-01-02
                         return !project.Ration.canAdd(project.mainTree.selected);
                     },
                     callback: function (key, opt) {
@@ -1356,6 +1367,13 @@ var projectObj = {
                         insertEquipment:{
                             name:"设备" ,
                             icon: 'fa-sign-in',
+                            visible: function () {
+                                if (typeof isCQ2018 != 'undefined') {
+                                    return false;
+                                }else{
+                                    return true;
+                                }
+                            },
                             callback:function(key){
                                 project.Ration.insertVolumePrice(gljType.EQUIPMENT);
                             }
@@ -1583,8 +1601,16 @@ var projectObj = {
         let row = getLocalCache('lastRow:' + projectId);
         let col = getLocalCache('lastCol:' + projectId);
         if(row == null || col == null){
+            //默认焦点定位到造价书的第一行“分项”。
+            col = 1;
             row = 0;
-            col = 0;
+            for(let i =0;i<this.mainController.tree.items.length;i++){
+                let node = this.mainController.tree.items[i];
+                if(node &&  node.sourceType == ModuleNames.bills && (node.data.type === billType.FX ||node.data.type === billType.BX )){//默认字位到第一条分项或补项
+                    row = i;
+                    break;
+                }
+            }
        }
         row = parseInt(row);
         col = parseInt(col);
@@ -2212,6 +2238,21 @@ let displayLevel = function(nodes, depth, type){
         TREE_SHEET_HELPER.refreshNodesVisible(refreshNodes, projectObj.mainSpread.getActiveSheet(), true)
     });
 };
+//导入下拉
+$('#importSpan').click(function () {
+    $('[data-toggle="tooltip"]').tooltip('hide');
+    let toggle = $('#importDropDown').attr('data-toggle');
+    if (toggle) {
+        $('#importDropDown').removeAttr('data-toggle');
+    }
+    $('#importDropDown').dropdown('toggle');
+    setTimeout(function () {
+        $('#importDropDown').attr('data-toggle', 'dropdown');
+    }, 100);
+});
+$('#importDropDown').click(function () {
+    $('[data-toggle="tooltip"]').tooltip('hide');
+});
 $('body').click(function () {
     //点击完后隐藏子菜单
    if ($('#subDisplay').is(':visible')) {
@@ -2275,8 +2316,11 @@ $('#poj-set').on('show.bs.modal', function () {
         }
     }
     if (projectObj.project) {
-        let ft = projectObj.project.property.billsCalcMode ? projectObj.project.property.billsCalcMode : leafBillGetFeeType.rationContent;
-        let zg = projectObj.project.property.zanguCalcMode ? projectObj.project.property.zanguCalcMode : zanguCalcType.common;
+        //江西重定义了leafBillGetFeeType的内容
+        let ft = projectObj.project.property.billsCalcMode !== undefined &&
+                 projectObj.project.property.billsCalcMode !== null ? projectObj.project.property.billsCalcMode : leafBillGetFeeType.rationContent;
+        let zg = projectObj.project.property.zanguCalcMode !== undefined &&
+                 projectObj.project.property.zanguCalcMode !== null ? projectObj.project.property.zanguCalcMode : zanguCalcType.common;
         setCalcFlag($('#rationContent'), leafBillGetFeeType.rationContent, ft);
         setCalcFlag($('#rationPriceConverse'), leafBillGetFeeType.rationPriceConverse, ft);
         setCalcFlag($('#rationPrice'), leafBillGetFeeType.rationPrice, ft);
@@ -3059,10 +3103,10 @@ $(function () {
             async function createRecursion(node){
                 if (!node) return;
 
-                if (calcTools.isLeafBill(node)) createBlock(node);
+                if (calcTools.isLeafBill(node)) await createBlock(node);
 
-                if (node.firstChild()) createRecursion(node.firstChild());
-                if (node.nextSibling) createRecursion(node.nextSibling);
+                if (node.firstChild()) await createRecursion(node.firstChild());
+                if (node.nextSibling) await createRecursion(node.nextSibling);
             };
 
             if (calcTools.isLeafBill(aNode))
@@ -3254,10 +3298,23 @@ $('#calcBaseFeeRateConf').click(function () {
     if(!toggle || toggle !== 'commonTotalFee'){
         return
     }
-    let needToSave = false;
-    let validateFeeRate = feeRateObject.checkSelectedFeeRate();
     let calcBaseValue = calcBaseView.getInputExpr() ? calcBaseView.getInputExpr() : '';
     let selected = projectObj.project.mainTree.selected;
+    let needToSave = false,validateFeeRate=false,cusFeeRate = false;
+    if($("input[name='editFeeRateOptions']:checked").val() == "0"){ //等于”0“ 是自定义输入,删除费率关联ID,直接取值
+        let newVal = null;
+        if($("#customFeeRate").val() != ""){
+            newVal = number_util.checkNumberValue( $("#customFeeRate").val(),getDecimal("feeRate"));
+            if(newVal == null) return
+        }
+        selected.data.feeRateID = null;
+        selected.data.feeRate = newVal;
+        selected.changed = true;
+        needToSave = true;
+        cusFeeRate = true;
+    }else {
+        validateFeeRate =  feeRateObject.checkSelectedFeeRate();
+    }
     if(calcBaseValue !== selected.data.calcBase){
         needToSave = true;
         selected.data.userCalcBase = calcBaseValue;
@@ -3265,17 +3322,19 @@ $('#calcBaseFeeRateConf').click(function () {
     }
     if(validateFeeRate){
         feeRateObject.submitFeeRateFromBill();
-    }
-    else {
+    } else {
         if(calcBaseValue === calcBaseValue){
             $('#calcBaseFeeRate').modal('hide');
         }
     }
-    if(!projectObj.project.calcBase.success){
+    if(!projectObj.project.calcBase.success && cusFeeRate==false){
         return;
-    }
-    else if((!validateFeeRate || selected.data.feeRateID === parseInt(feeRateObject.feeRateSelection.ID)) && needToSave) {
+    } else if((!validateFeeRate || selected.data.feeRateID === parseInt(feeRateObject.feeRateSelection.ID)) && needToSave) {
         projectObj.project.calcProgram.calcAndSave(selected);
         $('#calcBaseFeeRate').modal('hide');
     }
 });
+
+$('#menu_calc_program_manage').click(function () {
+    $('#tab_calc_program_manage').click();
+});

+ 13 - 13
web/building_saas/main/js/views/side_tools.js

@@ -2,11 +2,12 @@
  * Created by Mai on 2017/6/16.
  */
 $(window).resize(function() {
+    autoFlashHeight();
     sheetCommonObj.setColumnWidthByRate($('#stdRationChapter').width() - 40, rationLibObj.rationChapterSpread, rationLibObj.rationChapterTreeSetting.cols);
     billsGuidance.setColumnWidthByRate(billsGuidance.elfItem.workBook, $('#zy').width(), billsGuidance.elfItem.headers);
     billsGuidance.refreshWorkBook();
     rationLibObj.refreshSpread();
-    BillsElf.setColumnWidthByRate();
+    //BillsElf.setColumnWidthByRate();
     loadSideToolsHeight();
     //刷新主界面与各库中间的拖动条宽度:始终保持为一个宽度(在小窗口打开一个库,再放大窗口后,该拖动条宽度会变大)
     SlideResize.setResizeWidth($('#sideResize'));
@@ -31,7 +32,7 @@ SlideResize.horizontalSlide(sideResizeEles.eleObj, sideResizeEles.limit, functio
    // MaterialController.showReplaceDiv();
     subObj.initGljSubTab();
     pageCCOprObj.resizeWidth();
-    BillsElf.setColumnWidthByRate();
+    //BillsElf.setColumnWidthByRate();
     projectObj.refreshMainSpread();
     refreshSubSpread();
     if (sideResizeEles.eleObj.module === 'stdBillsGuidanceTab') {//清单精灵(规则)
@@ -59,10 +60,10 @@ rationLibResizeEles.eleObj = {
 };
 rationLibResizeEles.limit = {
     min: 150,
-    max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#deToolsBar').height()-150-10`,//10: resize.height()
+    max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#deToolsBar').height()-150-5`,//5: resize.height()
     notTopSpread: 0,
     notBottomSpread: 0,
-    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#deToolsBar').height()-10`
+    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#deToolsBar').height()-5`
 };
 SlideResize.verticalSlide(rationLibResizeEles.eleObj, rationLibResizeEles.limit, function () {
     rationLibObj.refreshSpread();
@@ -81,10 +82,10 @@ function getLocateLibResize(){
     };
     resizeObj.limit = {
         min: 150,
-        max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#searchPanel').height()-150-10`,//10: resize.height()
+        max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#searchPanel').height()-150-5`,//5: resize.height()
         notTopSpread: 0,
         notBottomSpread: 0,
-        totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#searchPanel').height()-10`
+        totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#searchPanel').height()-5`
     };
     return resizeObj;
 }
@@ -105,10 +106,10 @@ blockLibTopMid.eleObj = {
 };
 blockLibTopMid.limit = {
     min: 100,
-    max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkBottomDiv').height()-100-10*2`,
+    max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkBottomDiv').height()-100-5*2`,
     notTopSpread: 0,
     notBottomSpread: 0,
-    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkBottomDiv').height()-10*2` //10: resize.height()
+    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkBottomDiv').height()-5*2` //5: resize.height()
 };
 SlideResize.verticalSlide(blockLibTopMid.eleObj, blockLibTopMid.limit, function () {
     blockLibObj.refreshSpread();
@@ -126,10 +127,10 @@ blockLibMidBottom.eleObj = {
 };
 blockLibMidBottom.limit = {
     min: 100,
-    max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkTopDiv').height()-100-10*2`,
+    max: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkTopDiv').height()-100-5*2`,
     notTopSpread: 0,
     notBottomSpread: 0,
-    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkTopDiv').height()-10*2` //10: resize.height()
+    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-$('#kmbkTopDiv').height()-5*2` //5: resize.height()
 };
 SlideResize.verticalSlide(blockLibMidBottom.eleObj, blockLibMidBottom.limit, function () {
     blockLibObj.refreshSpread();
@@ -143,7 +144,7 @@ let blockLibMulti = {
         {container: $('#kmbkMidDiv'), spread: $('#div_block_bill'), notSpread: 0, defaultProportion: 0.15},
         {container: $('#kmbkBottomDiv'), spread: $('#div_block_ration'), notSpread: 0, defaultProportion: 0.25},
     ],
-    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-10*2`
+    totalHeight: `$(window).height()-$('.header').height()-$('.toolsbar').height()-$('#kmbkToolsBar').height()-5*2`
 };
 
 //加载各库内部上下高度(有的库需要上下拖动)
@@ -194,14 +195,13 @@ var sideToolsObj = {
         adaptiveTzjnrWidth();
         autoFlashHeight();
         subObj.initGljSubTab();
-        //MaterialController.showReplaceDiv();
         pageCCOprObj.resizeWidth();
         billsGuidance.refreshWorkBook();
         billsLibObj.refreshBillsSpread();
-        BillsElf.setColumnWidthByRate();
         refreshSubSpread();
         billsLibObj.refreshBillsRelaSpread();
         rationLibObj.refreshSpread();//subSpread、jobSpread、itemSpread显示问题
+        zmhs_obj.refresh();
     }
 };
 

+ 34 - 9
web/building_saas/main/js/views/std_billsGuidance_lib.js

@@ -95,7 +95,7 @@ const billsGuidance = (function () {
             {name: '项目名称', dataCode: 'name', width: 190, vAlign: 'center', hAlign: 'left', formatter: '@'},
             {name: '单位', dataCode: 'unit', width: 45, vAlign: 'center', hAlign: 'center', formatter: '@'},
         ],
-        rowHeaderWidth:25,
+        rowHeaderWidth:1,
         events: {
             CellDoubleClick: function (sender, args) {
                 if(!bills.tree){
@@ -334,7 +334,7 @@ const billsGuidance = (function () {
         let fuc = function () {
             sheet.setColumnCount(headers.length);
             sheet.setRowHeight(0, 30, GC.Spread.Sheets.SheetArea.colHeader);
-            sheet.setColumnWidth(0, sheet.getParent() === bills.workBook ? 15 : 25, GC.Spread.Sheets.SheetArea.rowHeader);
+            //sheet.setColumnWidth(0, sheet.getParent() === bills.workBook ? 15 : 25, GC.Spread.Sheets.SheetArea.rowHeader);
             if(sheet.getParent() === elfItem.workBook || sheet.getParent() === guideItem.workBook){
                 sheet.setRowHeight(0, 20, GC.Spread.Sheets.SheetArea.colHeader);
             }
@@ -396,6 +396,7 @@ const billsGuidance = (function () {
             let sheet = module.workBook.getActiveSheet();
             if(module === bills){
                 //默认初始可控制焦点在清单表中
+                sheet.options.rowHeaderVisible = false;
                 module.workBook.focus();
                 sheet.options.isProtected = true;
                 sheet.name('stdBillsGuidance_bills');
@@ -412,7 +413,9 @@ const billsGuidance = (function () {
                 sheet.getRange(-1, 0, -1, 1).locked(true);
                 sheet.getRange(-1, 1, -1, 1).locked(false);
             }
-            if(module.rowHeaderWidth)  sheet.setColumnWidth(0, module.rowHeaderWidth, GC.Spread.Sheets.SheetArea.rowHeader);
+            if(module.rowHeaderWidth) {
+                sheet.setColumnWidth(0, module.rowHeaderWidth, GC.Spread.Sheets.SheetArea.rowHeader);
+            }
             setOptions(module.workBook, options);
             buildHeader(module.workBook.getActiveSheet(), module.headers);
             if(module === elfItem){
@@ -484,6 +487,7 @@ const billsGuidance = (function () {
         }
         module.controller.showTreeData();
         if(module === bills){
+            module.workBook.getSheet(0).options.rowHeaderVisible = true;
             setBillsHint(bills.tree.items, stdBillsJobData, stdBillsFeatureData);
             renderSheetFunc(sheet, function () {
                 for(let i = 0; i < bills.tree.items.length; i++){
@@ -719,8 +723,10 @@ const billsGuidance = (function () {
         let billsSheet = bills.workBook.getActiveSheet();
         renderSheetFunc(billsSheet, function () {
             function expParentNode(node){
-                if(node.parent && !node.parent.expanded){
-                    node.parent.setExpanded(true);
+                if(node.parent){
+                    if (!node.parent.expanded) {
+                        node.parent.setExpanded(true);
+                    }
                     expParentNode(node.parent);
                 }
             }
@@ -787,8 +793,8 @@ const billsGuidance = (function () {
                     }
                 });
                 //搜索初始定位
-                billsSheet.showRow(result[0].serialNo(), GC.Spread.Sheets.VerticalPosition.bottom);
-
+                billsSheet.showRow(result[0].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+                //查找下一条
                 $('#nextBillsGuidance').show();
                 $('#nextBillsGuidance').unbind('click');
                 $('#nextBillsGuidance').bind('click', function () {
@@ -796,19 +802,37 @@ const billsGuidance = (function () {
                     if (resultIndex === result.length - 1) {
                         bills.controller.setTreeSelected(result[0]);
                         billsSheet.setSelection(result[0].serialNo(), sel[0].col, 1, 1);
-                        billsSheet.showRow(result[0].serialNo(), GC.Spread.Sheets.VerticalPosition.bottom);
+                        billsSheet.showRow(result[0].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
                     } else {
                         bills.controller.setTreeSelected(result[resultIndex + 1]);
                         billsSheet.setSelection(result[resultIndex + 1].serialNo(), sel[0].col, 1, 1);
-                        billsSheet.showRow(result[resultIndex + 1].serialNo(), GC.Spread.Sheets.VerticalPosition.bottom);
+                        billsSheet.showRow(result[resultIndex + 1].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+                    }
+                });
+                //查找上一条
+                $('#preBillsGuidance').show();
+                $('#preBillsGuidance').unbind('click');
+                $('#preBillsGuidance').bind('click', function () {
+                    let cur = bills.tree.selected, resultIndex = result.indexOf(cur), sel = billsSheet.getSelections();
+                    if (resultIndex === 0) {
+                        bills.controller.setTreeSelected(result[result.length - 1]);
+                        billsSheet.setSelection(result[result.length - 1].serialNo(), sel[0].col, 1, 1);
+                        billsSheet.showRow(result[result.length - 1].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
+                    } else {
+                        bills.controller.setTreeSelected(result[resultIndex - 1]);
+                        billsSheet.setSelection(result[resultIndex - 1].serialNo(), sel[0].col, 1, 1);
+                        billsSheet.showRow(result[resultIndex - 1].serialNo(), GC.Spread.Sheets.VerticalPosition.center);
                     }
                 });
             } else {
                 billsLibObj.clearHighLight(bills.workBook);
                 $('#nextBillsGuidance').hide();
+                $('#preBillsGuidance').hide();
             }
             $('#billsGuidanceSearchResultCount').text('搜索结果:' + result.length);
             $('#billsGuidanceSearchResult').show();
+            autoFlashHeight();
+            refreshWorkBook();
         });
         //搜索框回车
         $('#stdBillsGuidanceSearch>input').bind('keypress', function (event) {
@@ -821,6 +845,7 @@ const billsGuidance = (function () {
         $('#closeSearchBillsGuidance').click(function () {
             $('#billsGuidanceSearchResult').hide();
             billsLibObj.clearHighLight(bills.workBook);
+            autoFlashHeight();
             refreshWorkBook();
         });
     }

+ 9 - 5
web/building_saas/main/js/views/std_ration_lib.js

@@ -20,12 +20,14 @@ var rationLibObj = {
     checkSpread: function () {
         if (!this.rationChapterSpread) {
             this.rationChapterSpread = SheetDataHelper.createNewSpread($('#stdRationChapter')[0]);
+            this.rationChapterSpread.getSheet(0).options.rowHeaderVisible = false;
             sheetCommonObj.spreadDefaultStyle(this.rationChapterSpread);
             this.rationChapterSpread.getSheet(0).name('stdRationLib_chapter');
             this.rationChapterSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick, this.onChapterSpreadCellDoubleClick);
         }
         if (!this.sectionRationsSpread) {
             this.sectionRationsSpread = SheetDataHelper.createNewSpread($('#stdSectionRations')[0]);
+            this.sectionRationsSpread.getSheet(0).setColumnWidth(0, 1, GC.Spread.Sheets.SheetArea.rowHeader);
             sheetCommonObj.spreadDefaultStyle(this.sectionRationsSpread);
             if (!projectReadOnly) {
                 this.sectionRationsSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick, this.onRationSpreadCellDoubleClick);
@@ -125,7 +127,7 @@ var rationLibObj = {
                 }
             }
             rationChapterTreeController.showTreeData();
-
+            rationLibObj.rationChapterSpread.getSheet(0).options.rowHeaderVisible = true;
             rationChapterTreeController.bind(TREE_SHEET_CONTROLLER.eventName.treeSelectedChanged, function (node) {
                 rationLibObj.loadSectionRations(node && node.children.length === 0 ? node.getID() : null);
             });
@@ -182,9 +184,9 @@ var rationLibObj = {
         let me = this;
         var showDatas = function (datas, setting) {
             let rationSheet = rationLibObj.sectionRationsSpread.getActiveSheet();
-            TREE_SHEET_HELPER.massOperationSheet(rationSheet, function () {
+            /*TREE_SHEET_HELPER.massOperationSheet(rationSheet, function () {
                 rationSheet.setColumnWidth(0, 25, GC.Spread.Sheets.SheetArea.rowHeader);
-            });
+            });*/
             SheetDataHelper.loadSheetHeader(setting, rationLibObj.sectionRationsSpread.getActiveSheet());
             SheetDataHelper.loadSheetData(setting, rationLibObj.sectionRationsSpread.getActiveSheet(), datas);
             rationLibObj.setTagForHint(rationSheet, datas);
@@ -369,7 +371,7 @@ var rationLibObj = {
     },
     rationChapterTreeSetting: {
         "emptyRowHeader": true,
-        "rowHeaderWidth": 15,
+        "rowHeaderWidth": 1,
         "emptyRows":0,
         "headRows":1,
         "headRowHeight":[30],
@@ -396,6 +398,8 @@ var rationLibObj = {
         }]
     },
     sectionRationsSetting: {
+        "emptyRowHeader": true,
+        "rowHeaderWidth": 1,
         "emptyRows":3,
         "headRows":1,
         "headRowHeight":[20],
@@ -723,7 +727,7 @@ function seachRation(){
             resultObj.hide();
             $(".main-data-side-search", resultObj).height(0);
             autoFlashHeight();
-            rationLibObj.refreshSpread();
+            loadSideToolsHeight();
         });
         resultObj.show();
         $(".main-data-side-search", resultObj).height($(window).height() - $(".header").height() - $(".toolsbar").height() - 64);

+ 30 - 13
web/building_saas/main/js/views/sub_view.js

@@ -97,10 +97,11 @@ let subObj = {
         let totalWidth = $('#subItems').width();
         //人材机和项目特征文本比例
         const openWidth = 30;//打开项目特征工具条
+        const tab_tem = (305+openWidth+10)/totalWidth;//tab显示框默认宽度:305(表格宽度) + 30(工具条宽度)+10(resize div 宽度)
         let textVisible = $('#replaceText').is(':visible'),
             //默认比例
-            textPercent = '15%',
-            rcjPercent = '85%';
+            textPercent = tab_tem * 100 + '%',//'15%',
+            rcjPercent = (1 - tab_tem)* 100 + '%';//85
         //文本没显示,则打开工具条固定30px转换百分比
         if (!subObj.showGljSubTab) {
             textPercent = openWidth / totalWidth;
@@ -135,8 +136,7 @@ let subObj = {
     },
     showGljSubTabData:function () {
         this.initGljSubTab();
-        if($('#rnc-zm').is(':visible')) zmhs_obj.showCoeData();
-        if($('#rnc-fz').is(':visible')) zmhs_obj.showAssData();
+        zmhs_obj.showDatas();
         refreshSubSpread();
     }
 };
@@ -716,30 +716,47 @@ $('#linkAZZJF').on('shown.bs.tab', function () {
     gljOprObj.showDataIfRationSelect(projectObj.project.mainTree.selected, '111111');
 });
 
+$('#zmhs_toogle').bind('click',function (){
+   $("#zmhs_nav").show();
+   if(subObj.showGljSubTab == false){
+       subObj.activeTab?$(subObj.activeTab).click():$("#xm-nav").click();
+   }
+    $("#zmhs_toogle").hide();
+});
+
 $('.gljSubTab ul li a').bind('click',function () {
-    if($(this).hasClass("active")){//点击展开了后又点击了自身,这时要隐藏tab和修改本身class
-        subObj.showGljSubTab = false;
+    if(this.hash =="#rnc-close"){
+        $("#zmhs_nav").hide();
+        $("#zmhs_toogle").show();
         closeTab(this);
-        subSpread.focus();//要加上这个,不然右边侧栏的选中状态的border线不会消换
-    }else {
+        subObj.showGljSubTab = false;
+    } else {
         subObj.showGljSubTab = true;
+        subObj.activeTab =this;
     }
+
     subObj.initGljSubTab();
     refreshSubSpread();
+    /* if($(this).hasClass("active")){//点击展开了后又点击了自身,这时要隐藏tab和修改本身class
+     subObj.showGljSubTab = false;
+     closeTab(this);
+     subSpread.focus();//要加上这个,不然右边侧栏的选中状态的border线不会消换
+     }*/
 });
 
 $('.gljSubTab ul li a').on('shown.bs.tab', function () {
     if(this.hash == "#rnc-xm"){
-        MaterialController.showItemCharacterText();
+        //初始化项目特征表格位置,如果以后需要的话,showdata 统一移动至zmhs_obj中
+       //todo
     }else if(this.hash == "#rnc-zm"){
         zmhs_obj.initCoeSpread();
-        zmhs_obj.refresh();
-        zmhs_obj.showCoeData();
     }else if(this.hash == "#rnc-fz"){
         zmhs_obj.initAssSpread();
-        zmhs_obj.refresh();
-        zmhs_obj.showAssData();
+    }else if(this.hash == "#rnc-cus"){
+        zmhs_obj.initCusSpread();
     }
+    zmhs_obj.refresh();
+    zmhs_obj.showDatas();
 });
 
 function closeTab(elem) {

+ 128 - 17
web/building_saas/main/js/views/zmhs_view.js

@@ -10,25 +10,47 @@ let zmhs_obj = {
     coeSetting: {
         header: [
             {headerName: "调整", headerWidth: 35, dataCode: "isAdjust", dataType: "String", cellType: "checkBox"},
-            {headerName: "条件", headerWidth: 250, dataCode: "name", dataType: "String", cellType: "button"},
-            {headerName: "内容", headerWidth: 160, dataCode: "content", dataType: "String", hAlign: "left",getText:'forContent'}
+            {headerName: "条件", headerWidth: 180, dataCode: "name", dataType: "String", cellType: "button",getText:'forName'},
+            {headerName: "内容", headerWidth: 70, dataCode: "content", dataType: "String", hAlign: "left",getText:'forContent'}
         ],
         view: {
             lockColumns:[0,1,2],
             rowHeaderWidth:25
         },
         getText:{
-            forContent:function (item) {
-               if(gljUtil.isDef(item.select_code)&&item.select_code!=""){
-                   return item.select_code;
+            forContent:function (item) {//所选人材机,内容和条件互换位置
+               if(gljUtil.isDef(item.option_codes)&&item.option_codes!=""){
+                   return item.name;
                }else {
                    return item.content;
                }
-
+            },
+            forName:function (item) {
+                if(gljUtil.isDef(item.select_code)&&item.select_code!=""){
+                    let option = _.find(item.option_list,{"value":item.select_code})
+                    return option?option.text:item.select_code;
+                }else {
+                    return item.name;
+                }
             }
         },
+        emptyRowHeader: true,
         autoFit:true,
-        fitRow:['name']
+        fitRow:['name','content']
+    },
+    cusSpread:null,
+    cusSheet:null,
+    cusSheetData:null,
+    cusSetting:{
+        header: [
+            {headerName: "类型", headerWidth: 100, dataCode: "coeType", dataType: "String",hAlign: "left"},
+            {headerName: "系数", headerWidth: 80, dataCode: "amount", dataType: "String", hAlign: "right",validator:"number"}
+        ],
+        view: {
+            lockColumns:["coeType"],
+            rowHeaderWidth:25
+        },
+        emptyRowHeader: true
     },
     assSpread:null,
     assSheet:null,
@@ -42,7 +64,8 @@ let zmhs_obj = {
         view: {
             lockColumns: [0, 1],
             rowHeaderWidth:25
-        }
+        },
+        emptyRowHeader: true
     },
     initSpread:function () {
         this.initCoeSpread();
@@ -64,6 +87,18 @@ let zmhs_obj = {
             SheetDataHelper.protectdSheet(this.coeSheet);
         }
     },
+    initCusSpread:function () {
+        if(zmhs_obj.cusSpread == null){
+            this.cusSpread = SheetDataHelper.createNewSpread($("#cusSpread")[0]);
+            sheetCommonObj.spreadDefaultStyle(this.cusSpread);
+            this.cusSheet = this.cusSpread.getSheet(0);
+            sheetCommonObj.initSheet(this.cusSheet, this.cusSetting, 30);
+            this.cusSheet.name('ration_cus');
+            this.cusSheet.bind(GC.Spread.Sheets.Events.ValueChanged,this.onCusValueChange);
+            this.cusSheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onCusRangeChanged);
+            SheetDataHelper.protectdSheet(this.cusSheet);
+        }
+    },
     initAssSpread:function () {
         if(zmhs_obj.assSheet == null){
             this.assSpread = SheetDataHelper.createNewSpread($("#assSpread")[0]);
@@ -83,7 +118,9 @@ let zmhs_obj = {
         if(selected&&selected.sourceType == "ration"){
             let ration = selected.data;
             coeList = ration_coe.getCoeByRationID(ration.ID);
+            _.remove(coeList,{"coeID":-1})//2018-12-24 新需求,把自定义乘系数分离出来,这里排除自定义乘系数行
         }
+        this.coeSheet.setRowCount(0);
         sheetCommonObj.showData(this.coeSheet, this.coeSetting,coeList);
         if (coeList.length > 0) {
             this.coeSheet.suspendPaint();
@@ -105,16 +142,34 @@ let zmhs_obj = {
             disableSpread(zmhs_obj.coeSpread);
         }
     },
+    showCusData:function (node) {
+        let selected = node?node:projectObj.project.mainTree.selected;
+        let ration_coe = projectObj.project.ration_coe;
+        let cusList = [];
+        if(selected&&selected.sourceType == "ration"){
+            let ration = selected.data;
+            let coeList = ration_coe.getCoeByRationID(ration.ID);
+            this.cusSheetData = _.find(coeList,{"coeID":-1});
+            if(this.cusSheetData) cusList = this.cusSheetData.coes;
+        }
+        sheetCommonObj.showData(this.cusSheet, this.cusSetting,cusList);
+        this.cusSheet.getRange(cusList.length,-1,this.cusSheet.getRowCount()-cusList.length, -1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+        if(projectReadOnly){
+            disableSpread(zmhs_obj.cusSpread);
+        }
+    },
+
     getComboBoxForCodes:function (coe,i) {
-        this.coeSheet.getCell(i, 2, GC.Spread.Sheets.SheetArea.viewport).locked(false);
-        let options = coe.option_codes.split("|");
+        this.coeSheet.getCell(i, 1, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+        let options = coe.option_list; //coe.option_codes.split("|");
         let combo = sheetCommonObj.getDynamicCombo(true);
-        combo.itemHeight(options.length).items(options);
-        this.coeSheet.setCellType(i, 2, combo, GC.Spread.Sheets.SheetArea.viewport);
-        this.coeSheet.setValue(i, 2, coe.select_code);
+        let buttonRow =  this.coeSheet.getViewportBottomRow(1);
+        combo.editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.value);
+        combo.items(options).maxDropDownItems(buttonRow - i -1 < 3 ?3:buttonRow - i -1 );//itemHeight(options.length).
+        this.coeSheet.setCellType(i, 1, combo, GC.Spread.Sheets.SheetArea.viewport);
+        this.coeSheet.setValue(i, 1, coe.select_code);
 
     },
-
     showAssData:function (node) {
         this.assSheet.suspendPaint();
         this.assSheet.suspendEvent();
@@ -186,8 +241,16 @@ let zmhs_obj = {
 
 
     refresh:function () {
-        this.coeSpread?this.coeSpread.refresh():'';
-        this.assSpread?this.assSpread.refresh():'';
+        $('#coeSpread').is(':visible')&&this.coeSpread?this.coeSpread.refresh():'';
+        $('#coeSpread').is(':visible')&&this.coeSpread?this.showDatas():'';//这里combobox下拉框要重新加载一下
+        $('#cusSpread').is(':visible')&&this.cusSpread?this.cusSpread.refresh():'';
+        $('#assSpread').is(':visible')&&this.assSpread?this.assSpread.refresh():'';
+    },
+    showDatas:function () {
+        if($('#itemCharacterText').is(':visible'))MaterialController.showItemCharacterText()
+        if($('#coeSpread').is(':visible')) this.showCoeData();
+        if($('#cusSpread').is(':visible')) this.showCusData();
+        if($('#assSpread').is(':visible')) this.showAssData();
     },
     showZMHSData:function (node) {
         if(this.coeSpread&& this.assSpread && $('#linkZMHS').hasClass('active')){
@@ -343,11 +406,51 @@ let zmhs_obj = {
     onCoeValueChange:function (e,args) {
         let fieldID =  zmhs_obj.coeSetting.header[args.col].dataCode;
         let recode = zmhs_obj.coeSheetData[args.row];
-        if(gljUtil.isDef(recode.option_codes)&&recode.option_codes!=""&& fieldID == 'content'){//说明是选择了下拉框
+        if(gljUtil.isDef(recode.option_codes)&&recode.option_codes!=""&& fieldID == 'name'){//说明是选择了下拉框
             projectObj.project.ration_coe.adjustCoeClick(recode, 1,{'select_code':args.newValue});
         }
     },
+    onCusValueChange:function (e,args) {
+      zmhs_obj.changeCusValue([{row:args.row,col:args.col,value:args.newValue}]);
+    },
+    changeCusValue:function (datas) {//[{row:,col,value}]
+        if(this.cusSheetData){
+            let tem_coes = _.cloneDeep(this.cusSheetData.coes);
+            for(let d of datas){
+                if(d.value&&!sheetCommonObj.checkData(d.col,this.cusSetting,d.value)){
+                    this.showDatas();
+                    alert('输入的数据类型不对,请重新输入!');
+                    return;
+                }
+                if(gljUtil.isDef(d.value)&&d.value !=""){
+                    if(tem_coes[d.row].coeType=="定额"){
+                        for(let t of tem_coes){
+                            t.amount = d.value;
+                        }
+                    }else {
+                        tem_coes[d.row].amount = d.value;
+                    }
+                }
+            }
+            let doc = {'coes':tem_coes,'content':this.generationContent(tem_coes)};
+            projectObj.project.ration_coe.adjustCoeClick(this.cusSheetData, 1,doc);
+        }
+    },
+    generationContent:function (coes) {
+        let rationAmount = coes[0].amount;
+        let string ='';
+        if(_.every(coes,'amount',rationAmount)){
+            string = coes[0].coeType + 'x'+rationAmount;
+        }else {
+            let context_arr =[];
+            for(let i =1;i<coes.length;i++){
+                context_arr.push( coes[i].coeType + 'x'+coes[i].amount);
+            }
+            string = context_arr.join(',');
 
+        }
+        return string;
+    },
     onAssEditEnded:function (e,args) {
         var me = zmhs_obj;
         if (args.row >= me.assSheetData.length) {
@@ -358,6 +461,14 @@ let zmhs_obj = {
             me.updateRationAss(args);
         }
     },
+    onCusRangeChanged:function (e,args) {
+        let datas = [];
+        for(let c of args.changedCells){
+            let value=  args.sheet.getCell(c.row, c.col).text();
+            datas.push({row:c.row,col:c.col,value:value})
+        }
+        zmhs_obj.changeCusValue(datas);
+    },
     onAssRangeChanged:function (e,args) {
         let me = zmhs_obj;
         if (args.action == GC.Spread.Sheets.RangeChangedAction.clear) {

+ 1 - 1
web/building_saas/pm/html/project-management-Recycle.html

@@ -1,5 +1,5 @@
 <div class="toolsbar">
-    <legend class="m-0 pb-1">回收站</legend>
+    <legend class="m-0 px-4 pb-1">回收站</legend>
 </div>
 <div class="top-content">
   <!--  <div class="main-data-top" id="gc_waiting">

+ 1 - 1
web/building_saas/pm/html/project-management-share.html

@@ -1,5 +1,5 @@
 <div class="toolsbar">
-    <legend class="m-0 pb-1">分享</legend>
+    <legend class="m-0 px-4 pb-1">分享</legend>
 </div>
 <div class="share-list" id="shareSpread">
 </div>

+ 88 - 103
web/building_saas/pm/html/project-management.html

@@ -6,7 +6,6 @@
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     <meta http-equiv="x-ua-compatible" content="ie=edge">
     <title>项目管理-纵横建筑云计价</title>
-    <!-- inject:css -->
     <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
     <link rel="stylesheet" href="/web/building_saas/css/main.css">
     <link rel="stylesheet" href="/web/building_saas/css/custom.css">
@@ -15,7 +14,6 @@
     <!--zTree-->
     <link rel="stylesheet" href="/lib/ztree/css/zTreeStyle.css" type="text/css">
     <link rel="stylesheet" href="/lib/jquery-contextmenu/jquery.contextMenu.css">
-    <!-- endinject -->
     <link rel="shortcut icon" href="/web/building_saas/css/favicon.ico">
     <link rel="icon" type="image/gif" href="/web/building_saas/css/animated_favicon1.gif">
     <script>
@@ -48,6 +46,8 @@
 <img src="/web/dest/css/img/tender.png" id="tender_pic" style="display: none">
 <img src="/web/dest/css/img/refresh.png" id="refresh_pic" style="display: none">
 <img src="/web/dest/css/img/share.png" id="share_pic" style="display: none">
+<img src="/web/dest/css/img/copy.png" id="copy_pic" style="display: none">
+<img src="/web/dest/css/img/work.png" id="work_pic" style="display: none">
 <div class="header">
     <div class="top-msg clearfix">
         <div class="alert alert-warning mb-0 py-0" role="alert" style="display: none;">
@@ -63,23 +63,23 @@
         <div class="poj-manage container-fluid p-0">
             <div class="pm-side">
                 <div class="poj-cate">
-                    <div class="dropdown">
-                        <a class="btn btn-light dropdown-toggle" data-toggle="dropdown">
+                    <div class="dropdown" style="height: 38px">
+                        <!--<a class="btn dropdown-toggle" data-toggle="dropdown">
                             <i class="fa fa-search"></i>
                         </a>
                         <div class="dropdown-menu p-3" aria-labelledby="dropdownMenuButton">
                             <div class="form-group m-0">
                                 <input type="text" class="form-control form-control-sm" placeholder="搜索所有工程"style="width:300px">
                             </div>
-                        </div>
+                        </div>-->
                     </div>
                     <ul class="nav nav-pills flex-column" id="sideTab">
                         <li class="nav-item" data-original-title="全部" data-placement="right" data-toggle="tooltip">
                             <a class="nav-link active" href="#pm_all" role="tab" id="tab_pm_all" data-toggle="tab"><i class="fa fa-bars"></i></a>
                         </li>
-                        <li class="nav-item" data-original-title="最近使用" data-placement="right" data-toggle="tooltip">
+                        <!--<li class="nav-item" data-original-title="最近使用" data-placement="right" data-toggle="tooltip">
                             <a class="nav-link" href="javascript:void(0);"><i class="fa fa-bookmark"></i></a>
-                        </li>
+                        </li>-->
                         <li class="nav-item" data-original-title="分享" data-placement="right" data-toggle="tooltip">
                             <a class="nav-link" href="#pm_share" id="tab_pm_share" data-toggle="tab"><i class="fa fa-share-alt"></i></a>
                         </li>
@@ -99,7 +99,15 @@
                 <div class="tab-content">
                     <div class="tab-pane active" id="pm_all" role="tabpanel">
                         <div class="toolsbar">
-                            <legend class="m-0 pb-1">全部</legend>
+                            <legend class="m-0 px-4 pb-1">全部
+                                <div class="tools-btn btn-group align-top px-3 ">
+                                    <div class="dropdown">
+                                        <a id="startA" class="btn btn-sm" href="javascript:void(0);" role="button" data-toggle="modal" aria-haspopup="true" aria-expanded="false">
+                                            新建
+                                        </a>
+                                    </div>
+                                </div>
+                            </legend>
                         </div>
                         <div class="poj-list" id="projSpread">
                         </div>
@@ -614,6 +622,76 @@
         </div>
     </div>
 </div>
+
+<!--弹出 批量替换单价文件-->
+<div class="modal fade" id="m_replace_file" data-backdrop="static">
+    <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title" id="mr_title">批量替换单价文件</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <input type="hidden" id="mr_from">
+            <div class="modal-body">
+                <div class="row">
+                    <div class="col-6">
+                        <h5>选择项目</h5>
+                        <div class="modal-auto-height">
+                            <div id="replaceSpread" style="height: 100%"></div>
+                        </div>
+                        <div class="custom-control custom-checkbox">
+                            <input type="checkbox" class="custom-control-input" id="selectSameTypeProject">
+                            <label class="custom-control-label" for="selectSameTypeProject">自动勾选同专业工程</label>
+                        </div>
+                    </div>
+                    <div class="col-6">
+                        <h5>更换为</h5>
+                        <div class="form-group">
+                            <div class="custom-control custom-radio custom-control-inline">
+                                <input type="radio" id="customRadioInline33" name="select_from" value="0" class="custom-control-input" checked>
+                                <label class="custom-control-label" for="customRadioInline33">从本建设项目中选择</label>
+                            </div>
+                            <div class="custom-control custom-radio custom-control-inline">
+                                <input type="radio" id="customRadioInline44" name="select_from" value="1" class="custom-control-input">
+                                <label class="custom-control-label" for="customRadioInline44">从其他建设项目中复制</label>
+                            </div>
+                        </div>
+                        <!--从本建设项目中选择-->
+                        <label id="project_name">9.21<!--本建设项目名称--></label>
+                        <div class="form-group" id = "fromProject">
+                            <select class="form-control" id="currentOptions">
+                                <option>测试5单价文件</option><!--单价文件-->
+                            </select>
+                        </div>
+                        <!--从其他建设项目中复制-->
+                        <div id = "fromOther">
+                            <div class="form-group" >
+                                <label>选择建设项目</label>
+                                <select class="form-control" id="otherProject" >
+                                    <option>10.9建筑例题内测</option><!--建设项目-->
+                                </select>
+                            </div>
+                            <div class="form-group">
+                                <select class="form-control" id="otherFileOptions">
+                                    <option>10.9建筑例题内测单价文件</option><!--建设项目下单价文件-->
+                                </select>
+                                <span class="form-text text-muted">你选择的文件将复制一份至新项目,不会影响原建设项目的文件。</span>
+                            </div>
+                        </div>
+
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <button type="button" class="btn btn-primary mr-3" id="changeFileConfirm">确定</button>
+            </div>
+        </div>
+    </div>
+</div>
+
 <!--弹出删除 单价/费率 文件-->
 <div class="modal fade" id="del-wj" data-backdrop="static">
     <div class="modal-dialog" role="document">
@@ -657,8 +735,8 @@
                 </div>
                 <table class="table table-sm" id="shareFindDiv">
                     <tbody style="display: block">
-                    <tr><th style="width: 112px;">姓名</th><th style="width: 165px;">公司</th><th style="width: 136px;">手机</th><th style="width: 160px;">邮箱</th><th style="width: 90px;">允许拷贝</th><th style="width: 90px;">添加分享</th></tr>
-                    <tr><td id="user_name">张三</td><td id="user_company">XX公司</td><td id="user_mobile">12345678900</td><td id="user_email"></td><td><input id="allowCopy" type="checkbox"></td><td><a id="share-confirm" href="javascript:void(0)" class="btn btn-sm btn-primary">添加分享</a></td></tr>
+                    <tr><th style="width: 112px;">姓名</th><th style="width: 165px;">公司</th><th style="width: 136px;">手机</th><th style="width: 160px;">邮箱</th><th style="width: 90px;">允许拷贝</th><th style="width: 90px;">允许协作</th><th style="width: 90px;">添加分享</th></tr>
+                    <tr><td id="user_name">张三</td><td id="user_company">XX公司</td><td id="user_mobile">12345678900</td><td id="user_email"></td><td><input id="allowCopy" type="checkbox"></td><td><input id="allowCooperate" type="checkbox"></td><td><a id="share-confirm" href="javascript:void(0)" class="btn btn-sm btn-primary">添加分享</a></td></tr>
                     </tbody>
                 </table>
                 <p id="share-info" class="text-danger">不存在手机号 15812777651 的用户</p>
@@ -696,99 +774,6 @@
         </div>
     </div>
 </div>
-<!--弹出分享-->
-<!--<div class="modal fade" id="share" data-backdrop="static">
-    <div class="modal-dialog" role="document">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h5 class="modal-title">分享</h5>
-                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-                    <span aria-hidden="true">&times;</span>
-                </button>
-            </div>
-            <div class="modal-body">
-                <div class="form-group">
-                    <label>分享给...</label>
-                    <input id="sharePhone" class="form-control" placeholder="输入对方手机号" type="text">
-                    <span id="share-info" class="form-text text-danger">账号不存在。</span>
-                </div>
-                <div class="card">
-                    <div class="card-body">
-                        <h4 id="user_name" class="card-title">张三</h4>
-                        <h6 id="user_company" class="card-subtitle mb-2 text-muted">珠海纵横创新软件有限公司</h6>
-                    </div>
-                    <ul class="list-group list-group-flush">
-                        <li id="user_mobile" class="list-group-item" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="通行账号手机"><i class="fa fa-tablet"></i> 15812644017</li>
-                        <li id="user_email" class="list-group-item" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="通行账号邮箱"><i class="fa fa-envelope-o "></i> 0756-3850891</li>
-                        <li class="list-group-item" data-toggle="tooltip" data-placement="bottom" title="">
-                            <div class="form-group my-1">
-                                <p class="m-0">分享后,该用户仅可查阅工程,不具备任何编辑修改功能。</p>
-                            </div>
-                            <div class="form-check mb-2">
-                                <input type="checkbox" class="form-check-input" id="allowCopy">
-                                <label class="form-check-label" for="allowCopy">允许该用户拷贝该工程</label>
-                                &lt;!&ndash;打勾后出现提示&ndash;&gt;
-                                <div id="allowCopyHint" class="form-text text-danger"><i class="fa fa-exclamation-triangle"></i> 该用户可以把你的项目拷贝成为他的数据,请谨慎勾选。 </div>
-                            </div>
-                            <a id="addShareUser" class="btn btn-sm btn-primary" href="javascript:void(0);"><i class="fa fa-plus"></i> 添加</a>
-                        </li>
-                    </ul>
-                </div>
-                <div class="form-group mt-3" id="shareUsers" style="overflow: auto; display: none">
-                    <p>确认分享 <b>文件夹</b> 给</p>
-                    <p><h4><span class="badge badge-light mr-3">张三(15812644017) <a href="" class="text-danger" title="移除分享"><i class="fa fa-remove"></i></a></span>
-                    <span class="badge badge-light mr-3">王五(15812644017) <a href="" class="text-danger" title="移除分享"><i class="fa fa-remove"></i></a></span></h4></p>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <a id="share-confirm" href="javascript:void(0);" class="btn btn-primary">确定分享</a>
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-            </div>
-        </div>
-    </div>
-</div>-->
-<!--弹出分享给交互-->
-<!--<div class="modal fade" id="shareTo" data-backdrop="static">
-    <div class="modal-dialog" role="document">
-        <div class="modal-content" style="width: 750px;">
-            <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 modal-fixed-height">
-                &lt;!&ndash;     <p>勾选需要恢复的文件,点“确定”按钮,确认从回收站中恢复。</p>&ndash;&gt;
-                <table class="table table-hover table-sm mb-5">
-                    <thead>
-                    <tr style="display: block;">
-                        <th width="106px">姓名</th>
-                        <th width="146px">公司</th>
-                        <th width="146px">手机</th>
-                        <th width="156px">邮箱</th>
-                        <th width="70px">允许拷贝</th>
-                        <th width="70px">取消分享</th>
-                    </tr>
-                    </thead>
-                    <tbody id="shareToInfo" style="display:block; height: 300px; overflow: auto;">
-                    <tr>
-                        <td width="106px;">钟泽伟</td>
-                        <td width="146px;">珠海纵横创新软件有限公司</td>
-                        <td width="146px;">13160675110</td>
-                        <td width="156px;">707820685@qq.com</td>
-                        <td width="70px;" style="text-align: center"><input type="checkbox"></td>
-                        <td width="70px;" style="text-align: center"><input type="checkbox"></td>
-                    </tr>
-                    </tbody>
-                </table>
-            </div>
-            <div class="modal-footer">
-                <a href="javascript:void(0);" class="btn btn-primary" id="shareToConfirm" data-dismiss="modal">确定</a>
-                <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>GC.Spread.Sheets.LicenseKey = '<%- LicenseKey %>';</script>

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

@@ -930,8 +930,7 @@ function m_getFilesObjs(nodes){
     for(let i = 0, len = nodes.length; i < len; i++){
         let fileId = $(nodes[i]).attr('fileId') || null;
         if(fileId){
-            let dispName = $('td:eq(0)', $(nodes[i])[0].parentNode.parentNode)[0].textContent;
-            let name = dispName.slice(0, dispName.length - 4);
+            let name = $('td:eq(0)', $(nodes[i])[0].parentNode.parentNode)[0].textContent;
             if($(nodes[i]).attr('fileType') === fileType.unitPriceFile){
                 fileId = parseInt(fileId);
             }

Разлика између датотеке није приказан због своје велике величине
+ 551 - 296
web/building_saas/pm/js/pm_newMain.js


+ 173 - 84
web/building_saas/pm/js/pm_share.js

@@ -16,7 +16,8 @@ const pmShare = (function () {
     const shareType = {receive: 'receive', shareTo: 'shareTo'};
     //操作类型
     const oprType = {copy: 'copy', cancel: 'cancel'};
-    let tree = null;
+    let tree = null,
+        actualIDShareInfo = {};//项目真实树ID与项目分享信息映射
     const treeCol = 0;
     const treeSetting = {
         tree: {
@@ -29,9 +30,8 @@ const pmShare = (function () {
     };
     const headers = [
         {name: '工程列表', dataCode: 'name', width: 300, rateWidth: 0.55, vAlign: 'center', hAlign: 'left'},
-        {name: '由...分享', dataCode: 'from', width: 120, rateWidth: 0.15, vAlign: 'center', hAlign: 'left'},
-     /*   {name: '拷贝工程', dataCode: 'copy', width: 100, rateWidth: 0.075, vAlign: 'center', hAlign: 'left'},
-        {name: '清除', dataCode: 'cancel', width: 100, rateWidth: 0.075, vAlign: 'center', hAlign: 'left'},*/
+        {name: '来自', dataCode: 'from', width: 80, rateWidth: 0.15, vAlign: 'center', hAlign: 'left'},
+        {name: '分享时间', dataCode: 'shareDate', width: 140, rateWidth: 0.15, vAlign: 'center', hAlign: 'left'},
         {name: '工程造价', dataCode: 'engineeringCost', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
         {name: '分部分项合计', dataCode: 'subEngineering', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
         {name: '措施项目合计', dataCode: 'measure', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
@@ -125,12 +125,6 @@ const pmShare = (function () {
                 if(headers[i].formatter){
                     sheet.setFormatter(-1, i, headers[i].formatter);
                 }
-              /*  if(headers[i].dataCode === oprType.copy){
-                    //合并列
-                    sheet.addSpan(0, i, 1, 2, GC.Spread.Sheets.SheetArea.colHeader);
-                    sheet.setValue(0, i, '操作', GC.Spread.Sheets.SheetArea.colHeader);
-                    continue;
-                }*/
                 sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
                 sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]);
                 sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]);
@@ -162,15 +156,56 @@ const pmShare = (function () {
         spreadObj.sheet.getRange(-1, -1, -1, -1).locked(true);
 
     }
+    //此项目的分享权限信息(可能会被父级项目覆盖,以新为准)
+    //@param {String}userID(本用户id) {Object}project(项目) @return {Object} || {Null}
+    function getShareInfo(userID, project) {
+        if (!project.actualTreeInfo) {
+            return null;
+        }
+        //获取跟本用户和选中项目相关的分享信息
+        let shareList = [];
+        let actualID = project.actualTreeInfo.ID,
+            actualData = actualIDShareInfo[actualID];
+        while (actualData) {
+            for (let data of actualData.shareInfo) {
+                if (data.userID === userID) {
+                    shareList.push(data);
+                    break;
+                }
+            }
+            actualData = actualIDShareInfo[actualData.ParentID];
+        }
+        //获取最新分享
+        shareList.sort(function (a, b) {
+            let aV = Date.parse(a.shareDate),
+                bV = Date.parse(b.shareDate);
+            if (aV > bV) {
+                return -1;
+            } else if (aV < bV) {
+                return 1;
+            }
+            return 0;
+        });
+        return shareList[0] || null;
+
+    }
     //此项目是否可以拷贝
     //@param {String}userID {Object}project @return {Boolean}
     function isAllowCopy(userID, project){
-        for(let shareData of project.shareInfo){
-            if(shareData.userID === userID){
-                return shareData.allowCopy;
-            }
+        let myShareInfo = getShareInfo(userID, project);
+        if (!myShareInfo) {
+            return false;
+        }
+        return !!myShareInfo.allowCopy;
+    }
+    //此项目是否可以协作
+    //@param {String}userID {Object}project @return {Boolean}
+    function isAllowCoop(userID, project) {
+        let myShareInfo = getShareInfo(userID, project);
+        if (!myShareInfo) {
+            return false;
         }
-        return false;
+        return !!myShareInfo.allowCooperate;
     }
     //获取树节点
     //@param {Object}tree @return {Object}
@@ -398,9 +433,44 @@ const pmShare = (function () {
     }
     //互动单元格
     function getInteractionCell() {
+        let workImg = document.getElementById('work_pic'),
+            workImgWidth = 13,
+            workImgHeight = 13,
+            copyImg = document.getElementById('copy_pic'),
+            copyImgWidth = 13,
+            copyImgHeight = 13;
         let InteractionCell = function () {
         };
         InteractionCell.prototype = new GC.Spread.Sheets.CellTypes.Text();
+        InteractionCell.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
+            if (style.backColor) {
+                ctx.save();
+                ctx.fillStyle = style.backColor;
+                ctx.fillRect(x, y, w, h);
+                ctx.restore();
+            } else {
+                ctx.clearRect(x, y, w, h);
+            }
+            let node = tree.items[options.row];
+            // Draw Text
+            GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
+            if (node && node.data.projType === projectType.tender) {
+                let text = options.sheet.getText(options.row, options.col);
+                let acStyle = options.sheet.getActualStyle(options.row, options.col),
+                    zoom = options.sheet.zoom();
+                let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: options.sheet, row: options.row, col: options.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
+                let nowX  = Math.floor(x) + textLength + 3,
+                    nowY = Math.floor((y + (y + h)) / 2) - 7;
+                if (node.data.allowCooperate) {
+                    ctx.drawImage(workImg, nowX, nowY, workImgWidth, workImgHeight);
+                    nowX += workImgWidth;
+                }
+                if (node.data.allowCopy) {
+                    ctx.drawImage(copyImg, nowX, nowY, copyImgWidth, copyImgHeight);
+                }
+            }
+
+        };
         InteractionCell.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
             return {
                 x: x,
@@ -434,36 +504,6 @@ const pmShare = (function () {
                         $('#userinfo').modal('show');
                     }
                 }
-                //分享给
-                else if(dataCode === 'to'){
-                    if(node.data.shareType === shareType.shareTo){
-                        setShareToModal(node);
-                        $('#shareTo').modal('show');
-                    }
-                }
-                //操作
-                else if(dataCode === oprType.copy){
-                   /* if(node.data.copy === '添加分享'){
-                        $('#sharePhone').val('');
-                        $('#share-info').hide();
-                        $('#share').find('.card').hide();
-                        $('#share').modal('show');
-                        $('#allowCopy').prop('checked', false);
-                        $('#allowCopyHint').hide();
-                    }
-                    else*/
-                    if(node.data.copy === '拷贝工程'){
-                        $('#copyShare').modal('show');
-                    }
-                }
-                else if (dataCode === oprType.cancel) {
-                    if (node.data.cancel === '清除') {
-                        let $p = $('<p>').text(`点“确定”按钮,确认清除分享文件 “${node.data.name}”。`);
-                        $('#cancelShare').find('.modal-body').empty();
-                        $('#cancelShare').find('.modal-body').append($p);
-                        $('#cancelShare').modal('show');
-                    }
-                }
             }
         };
         InteractionCell.prototype.processMouseMove = function (hitInfo) {
@@ -573,45 +613,28 @@ const pmShare = (function () {
                     sheet.getRange(-1, j, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[j]['hAlign']]);
                     sheet.getRange(-1, j, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[j]['vAlign']]);
                     let dataCode = headers[j].dataCode;
-                    if(dataCode === oprType.copy){
+                    if(dataCode === 'from'){
                         let style = new GC.Spread.Sheets.Style();
                         style.foreColor = foreColor;
                         sheet.setStyle(i, j, style);
                         sheet.getCell(i, j).cellType(getInteractionCell());
                     }
-                    else if (dataCode === oprType.cancel) {
-                        let style = new GC.Spread.Sheets.Style();
-                        style.foreColor = cancelForeColor;
-                        sheet.setStyle(i, j, style);
-                        sheet.getCell(i, j).cellType(getInteractionCell());
-                    }
-                    else if(dataCode === 'from'){
-                        if(nodes[i].data.shareType && nodes[i].data.shareType === shareType.receive){
-                            let style = new GC.Spread.Sheets.Style();
-                            style.foreColor = foreColor;
-                            sheet.setStyle(i, j, style);
-                            sheet.getCell(i, j).cellType(getInteractionCell());
-                        }
-                    }
-                    else if(dataCode === 'to'){
-                        if(nodes[i].data.shareType && nodes[i].data.shareType === shareType.shareTo){
-                            let style = new GC.Spread.Sheets.Style();
-                            style.foreColor = foreColor;
-                            sheet.setStyle(i, j, style);
-                            sheet.getCell(i, j).cellType(getInteractionCell());
-                        }
-                    }
                     sheet.setValue(i, j, nodes[i].data[dataCode] !== null && typeof nodes[i].data[dataCode] !== 'undefined' ? nodes[i].data[dataCode] : '');
                 }
             }
         };
         renderSheetFunc(sheet, fuc);
     }
-    //同一棵树,可能存在相同数据显示多条的问题(传入的datas中不存在相同数据),将真实树结构数据存在actualTreeInfo中,外部树结构数据用uuid重置。
+    //同一棵树,可能存在相同数据显示多条的问题(传入的datas中不存在相同数据)
+    //将真实树结构数据存在actualTreeInfo中,外部树结构数据用uuid重置。
     //@param {Array}datas
     function setTreeInfo(datas) {
         let IDMapping = {};
         for (let data of datas) {
+            //项目真实ID与项目分享信息映射,方便确定项目的权限
+            if (!actualIDShareInfo[data.ID]) {
+                actualIDShareInfo[data.ID] = {ID: data.ID, ParentID: data.ParentID, NextSiblingID: data.NextSiblingID, shareInfo: data.shareInfo};
+            }
             IDMapping[data.ID] = uuid.v1();
         }
         for (let data of datas) {
@@ -631,21 +654,17 @@ const pmShare = (function () {
             data.ParentID = pid;
         }
     }
-    //给项目设置分享信息:由xx分享、分享给我、可进行的操作,含有userInfo信息的文件为他人直接分享的文件,他人分享父级文件,子文件不含有userInfo信息
+    //给项目设置分享信息:由xx分享、分享时间、分享给我,含有userInfo信息的文件为他人直接分享的文件,他人分享父级文件,子文件不含有userInfo信息
     //@param {Array}datas @return {void}
     function setShareInfo(datas) {
         for (let data of datas) {
             if (data.userInfo) {
-                data.from = `由 ${data.userInfo.name} 分享`;
+                //shareInfo中我的条目
+                let selfInfo = _.find(data.shareInfo, {userID: userID});
+                data.shareDate = selfInfo ? selfInfo.shareDate : ''
+                data.from = data.userInfo.name;
                 data.to = '分享给 我';
                 data.cancel = '清除';
-
-                //拷贝操作只允许到单位工程级
-                let tendersCanCopy = isAllowCopy(userID, data);
-                let tenders = data.projType === projectType.tender ? [data] : _.filter(data.children, {projType: projectType.tender});
-                for (let tender of tenders) {
-                    tender.copy = tendersCanCopy ? '拷贝工程' : '';
-                }
             }
         }
     }
@@ -678,6 +697,30 @@ const pmShare = (function () {
             }
         }
     }
+    //从同层树数据获取第一个节点ID
+    //@param {Array}treeDatas树的数据 @return {String}第一个节点的虚拟树ID
+    function getFirstID(treeDatas) {
+        let treeMapping = {};
+        //建立ID索引
+        for (let data of treeDatas) {
+            //新建一个简单对象,防止污染treeDatas的数据
+            treeMapping[data.ID] = {ID: data.ID, prev: null, next: null};
+        }
+        //绑定prev next
+        for (let data of treeDatas) {
+            let me =  treeMapping[data.ID],
+                next = treeMapping[data.NextSiblingID];
+            if (next) {
+                me.next = next;
+                next.prev = me;
+            }
+        }
+        //返回没有prev属性的数据
+        let result = _.find(treeDatas, function (data) {
+            return !treeMapping[data.ID].prev
+        });
+        return  result ? result.ID : -1;
+    }
     //获取可成树的数据
     //@param {Array}datas @return {Array}
     function getTreeDatas(groupedDatas, ungroupedDatas){
@@ -694,12 +737,14 @@ const pmShare = (function () {
         let rst = [];
         //整理树结构
         sortSameDepthData(groupedDatas, -1);
+        //第一个根节点数据
+        let firstID = getFirstID(groupedDatas);
         //新建未分类建设项目及单项工程
-        let ungroupedProj = {ID: uuid.v1(), ParentID: -1, NextSiblingID: -1, name: '未分类建设项目', projType: projectType.project};
+        let ungroupedProj = {ID: uuid.v1(), ParentID: -1, NextSiblingID: firstID, name: '未分类建设项目', projType: projectType.project};
         let ungroupedEng = {ID: uuid.v1(), ParentID: ungroupedProj.ID, NextSiblingID: -1, name: '未分类单项工程', projType: projectType.engineering};
-        if (groupedDatas.length > 0) {
+        /*if (groupedDatas.length > 0) {
             groupedDatas[groupedDatas.length - 1].NextSiblingID = ungroupedProj.ID;
-        }
+        }*/
         //将未分类的数据归类
         sortSameDepthData(engs, ungroupedProj.ID);
         sortSameDepthData(tenders, ungroupedEng.ID);
@@ -735,6 +780,19 @@ const pmShare = (function () {
             return 0;
         });
     }
+    //设置节点数据权限
+    //@param {Array}datas项目数据
+    function setPermissionsInfo(datas) {
+        //data.allowCopy与shareInfo里allowCopy的区别:
+        //data.allowCopy为该单位实际的权限(跟着最新的分享信息走,可能随着父项)
+        for (let data of datas) {
+            if (data.projType === projectType.tender) {
+                data.allowCopy = isAllowCopy(userID, data);
+                data.allowCooperate = isAllowCoop(userID, data);
+            }
+        }
+        
+    }
     //建立树
     //@return void
     function initShareTree(){
@@ -750,6 +808,7 @@ const pmShare = (function () {
                 setSummaryInfo(rstData.ungrouped, rstData.summaryInfo.ungrouped);
             }
             let treeDatas = getTreeDatas(rstData.grouped, rstData.ungrouped);
+            setPermissionsInfo(treeDatas);
             tree = pmTree.createNew(treeSetting, treeDatas);
             tree.selected = tree.items[0];
             showTreeData(tree.items, headers);
@@ -777,7 +836,7 @@ const pmShare = (function () {
                     icon: 'fa-copy',
                     disabled: function () {
                         let selected = tree.selected;
-                        return !(selected && selected.data.copy && selected.data.copy === '拷贝工程');
+                        return !(selected && selected.data.allowCopy);
                     },
                     callback: function (key, opt) {
                         $('#copyShare').modal('show');
@@ -1001,12 +1060,42 @@ const pmShare = (function () {
             copyShareProject(tree.selected, parseInt(selProj), parseInt(selEng));
         });
         //清除分享
+        //清除了该节点后,可能还有该节点的数据在树上(树允许有重复数据),需要更新分享信息
+        function updateAfterCancel(userID, projectID) {
+            for (let item of tree.items) {
+                if (item.data.actualTreeInfo && item.data.actualTreeInfo.ID === projectID) {
+                    _.remove(item.data.shareInfo, function (data) {
+                        return data.userID === userID;
+                    });
+                }
+            }
+        }
         $('#cancelShareConfirm').click(function () {
             $.bootstrapLoading.start();
-            CommonAjax.post('/pm/api/share', {user_id: userID, type: oprType.cancel,  projectID: tree.selected.data.actualTreeInfo.ID, shareData:[{userID: userID}]}, function (rstData) {
-                $.bootstrapLoading.end();
+            let cancelProjID = tree.selected.data.actualTreeInfo.ID;
+            CommonAjax.post('/pm/api/share', {user_id: userID, type: oprType.cancel,  projectID: cancelProjID, shareData:[{userID: userID}]}, function (rstData) {
                 tree.removeNode(tree.selected);
+                //更新与清除节点数据相同,且为被清除缓存分享信息
+                updateAfterCancel(userID, cancelProjID);
+                //重新设置actualIDShareInfo,以正确更新权限(清除了分享信息后,可能会导致权限变化 eg:清除了新的分享,则存留的分享项目采用旧的)
+                actualIDShareInfo = {};
+                let treeDatas = [];
+                for (let item of tree.items) {
+                    treeDatas.push(item.data);
+                    let actualTreeInfo = item.data.actualTreeInfo;
+                    if (actualTreeInfo && !actualIDShareInfo[actualTreeInfo.ID]) {
+                        actualIDShareInfo[actualTreeInfo.ID] = {
+                            ID: actualTreeInfo.ID,
+                            ParentID: actualTreeInfo.ParentID,
+                            NextSiblingID: actualTreeInfo.NextSiblingID,
+                            shareInfo: item.data.shareInfo
+                        };
+                    }
+                }
+                //重新设置权限
+                setPermissionsInfo(treeDatas);
                 showTreeData(tree.items, headers);
+                $.bootstrapLoading.end();
             }, function () {
                 $.bootstrapLoading.end();
             });

+ 3 - 2
web/building_saas/report/html/rpt_print.html

@@ -37,6 +37,7 @@
 <script type="text/javascript" src="/web/building_saas/report/js/jpc_output.js"></script>
 <script type="text/javascript" src="/web/building_saas/report/js/rpt_print.js"></script>
 <SCRIPT type="text/javascript">
+    let G_OFFSET_X = 0, G_OFFSET_Y = 0;
     function loading() {
         if (sessionStorage.multiRptsData) {
             let multiRptData = JSON.parse(sessionStorage.multiRptsData);
@@ -46,7 +47,7 @@
                 if (idx === 0) {
                     $(document).attr("title", pageData[JV.NODE_PAGE_INFO][JV.NODE_MAIN_INFO_RPT_NAME]);
                 }
-                let svgArr = rptPrintHelper.buildSvgArr(pageData, -30, -30);
+                let svgArr = rptPrintHelper.buildSvgArr(pageData, G_OFFSET_X, G_OFFSET_Y);
                 //let orientation = (pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][0] < pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][1])?"纵向":"横向";
                 let orientation = "纵向";
                 showPreviewData(svgArr, scaleFactor, sessionStorage.pageSize, orientation);
@@ -55,7 +56,7 @@
         } else if (sessionStorage.currentPageData) {
             let pageData = JSON.parse(sessionStorage.currentPageData);
             let scaleFactor = parseInt(sessionStorage.scaleFactor);
-            let svgArr = rptPrintHelper.buildSvgArr(pageData, -30, -30);
+            let svgArr = rptPrintHelper.buildSvgArr(pageData, G_OFFSET_X, G_OFFSET_Y);
             $(document).attr("title", pageData[JV.NODE_PAGE_INFO][JV.NODE_MAIN_INFO_RPT_NAME]);
             //showPreviewData(svgArr, scaleFactor, sessionStorage.pageSize, sessionStorage.orientation);
             showPreviewData(svgArr, scaleFactor, sessionStorage.pageSize, "纵向");

+ 14 - 157
web/building_saas/report/js/rpt_print.js

@@ -60,7 +60,7 @@ let rptPrintHelper = {
         let isHtoV = false;
         if (pixelSize[0] > pixelSize[1]) {
             // changeHtoV(pagesData, pixelSize);
-            // isHtoV = true;
+            isHtoV = true;
         }
         for (let idx = 0; idx < pagesData.items.length; idx++) {
             let page = pagesData.items[idx];
@@ -69,7 +69,7 @@ let rptPrintHelper = {
             // let adjustY = 0.5 * ((idx + 1) % 2);
             let adjustY = 0.5;
             for (let cell of page.cells) {
-                svgPageArr.push(buildCellSvg(cell, fonts, styles, controls, page[JV.PROP_PAGE_MERGE_BORDER], pagesData[JV.BAND_PROP_MERGE_BAND], offsetX, offsetY, adjustY, canvas, isHtoV));
+                svgPageArr.push(buildCellSvg(cell, fonts, styles, controls, page[JV.PROP_PAGE_MERGE_BORDER], pagesData[JV.BAND_PROP_MERGE_BAND], offsetX, offsetY, adjustY, canvas, isHtoV, pixelSize));
             }
             svgPageArr.push("</svg>");
             rst.push(svgPageArr);
@@ -78,36 +78,6 @@ let rptPrintHelper = {
     }
 };
 
-function changeHtoV(pagesData, pixelSize) {
-    //坐标从横向变纵向
-    if (pixelSize[0] > pixelSize[1]) {
-        let tmpP = pixelSize[0];
-        pixelSize[0] = pixelSize[1];
-        pixelSize[1] = tmpP;
-    }
-    let offsetX = pixelSize[0];
-    // let RotAngF = (90 * Math.PI / 180); //这里默认就是90度旋转
-    let sinVal = 1; //sin 90度 = 1 不用算了
-    let cosVal = 0; //cos 90度 = 0 不用算了
-    for (let page of pagesData.items) {
-        for (let cell of page.cells) {
-            rotateCellArea(cell[JV.PROP_AREA], sinVal, cosVal, offsetX);
-        }
-    }
-}
-
-function rotateCellArea(area, sinVal, cosVal, offsetX) {
-    let Nx, Ny;
-    Nx = (area[JV.PROP_LEFT] * cosVal - area[JV.PROP_TOP] * sinVal);
-    Ny = (area[JV.PROP_TOP] * cosVal + area[JV.PROP_LEFT] * sinVal);
-    area[JV.PROP_LEFT] = Nx + offsetX;
-    area[JV.PROP_TOP] = Ny;
-    Nx = (area[JV.PROP_RIGHT] * cosVal - area[JV.PROP_BOTTOM] * sinVal);
-    Ny = (area[JV.PROP_BOTTOM] * cosVal + area[JV.PROP_RIGHT] * sinVal);
-    area[JV.PROP_RIGHT] = Nx + offsetX;
-    area[JV.PROP_BOTTOM] = Ny;
-}
-
 function getActualBorderStyle(cell, styles, mergeBorderStyle, pageBorderArea, borderStr) {
     let rst = styles[cell[JV.PROP_STYLE]][borderStr];
     if (mergeBorderStyle) {
@@ -128,7 +98,7 @@ function getActualBorderStyle(cell, styles, mergeBorderStyle, pageBorderArea, bo
     return rst;
 }
 
-function buildCellSvg(cell, fonts, styles, controls, pageMergeBorder, rptMergeBorder, offsetX, offsetY, adjustY, canvas, isHtoV) {
+function buildCellSvg(cell, fonts, styles, controls, pageMergeBorder, rptMergeBorder, offsetX, offsetY, adjustY, canvas, isHtoV, pixelSize) {
     let rst = [];
     let style = styles[cell[JV.PROP_STYLE]];
     let mergeBandStyle = null;
@@ -144,163 +114,50 @@ function buildCellSvg(cell, fonts, styles, controls, pageMergeBorder, rptMergeBo
         top = parseInt(cell[JV.PROP_AREA][JV.PROP_TOP]) + offsetY + adjustY,
         bottom = parseInt(cell[JV.PROP_AREA][JV.PROP_BOTTOM]) + offsetY + adjustY
     ;
+    let HtoVStr = "";
+    if (isHtoV) {
+        HtoVStr = ` transform="translate(`+ pixelSize[1] + `,0) rotate(90)"`;
+    }
     if (style) {
         let leftBS = getActualBorderStyle(cell, styles, mergeBandStyle, (pageMergeBorder)?pageMergeBorder:rptMergeBorder[JV.PROP_AREA], JV.PROP_LEFT);
         // if (style[JV.PROP_LEFT] && parseFloat(style[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT]) > 0) {
         if (leftBS && parseFloat(leftBS[JV.PROP_LINE_WEIGHT]) > 0) {
             rst.push("<line x1='" + left + "' y1='" + top +
                 "' x2='" + left + "' y2='" + bottom +
-                "' style='stroke:rgb(0,0,0);stroke-width:" + leftBS[JV.PROP_LINE_WEIGHT] +"'/>")
+                "' style='stroke:rgb(0,0,0);stroke-width:" + leftBS[JV.PROP_LINE_WEIGHT] + "'" + HtoVStr + "/>")
         }
         let rightBS = getActualBorderStyle(cell, styles, mergeBandStyle, (pageMergeBorder)?pageMergeBorder:rptMergeBorder[JV.PROP_AREA], JV.PROP_RIGHT);
         // if (style[JV.PROP_RIGHT] && parseFloat(style[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT]) > 0) {
         if (rightBS && parseFloat(rightBS[JV.PROP_LINE_WEIGHT]) > 0) {
             rst.push("<line x1='" + right + "' y1='" + top +
                 "' x2='" + right + "' y2='" + bottom +
-                "' style='stroke:rgb(0,0,0);stroke-width:" + rightBS[JV.PROP_LINE_WEIGHT] +"'/>")
+                "' style='stroke:rgb(0,0,0);stroke-width:" + rightBS[JV.PROP_LINE_WEIGHT] +"'" + HtoVStr + "/>")
         }
         let topBS = getActualBorderStyle(cell, styles, mergeBandStyle, (pageMergeBorder)?pageMergeBorder:rptMergeBorder[JV.PROP_AREA], JV.PROP_TOP);
         // if (style[JV.PROP_TOP] && parseFloat(style[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]) > 0) {
         if (topBS && parseFloat(topBS[JV.PROP_LINE_WEIGHT]) > 0) {
             rst.push("<line x1='" + left + "' y1='" + top +
                 "' x2='" + right + "' y2='" + top +
-                "' style='stroke:rgb(0,0,0);stroke-width:" + topBS[JV.PROP_LINE_WEIGHT] +"'/>")
+                "' style='stroke:rgb(0,0,0);stroke-width:" + topBS[JV.PROP_LINE_WEIGHT] +"'" + HtoVStr + "/>")
         }
         let bottomBS = getActualBorderStyle(cell, styles, mergeBandStyle, (pageMergeBorder)?pageMergeBorder:rptMergeBorder[JV.PROP_AREA], JV.PROP_BOTTOM);
         // if (style[JV.PROP_BOTTOM] && parseFloat(style[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]) > 0) {
         if (bottomBS && parseFloat(bottomBS[JV.PROP_LINE_WEIGHT]) > 0) {
             rst.push("<line x1='" + left + "' y1='" + bottom +
                 "' x2='" + right + "' y2='" + bottom +
-                "' style='stroke:rgb(0,0,0);stroke-width:" + bottomBS[JV.PROP_LINE_WEIGHT] +"'/>")
+                "' style='stroke:rgb(0,0,0);stroke-width:" + bottomBS[JV.PROP_LINE_WEIGHT] +"'" + HtoVStr + "/>")
         }
     }
     let control = cell[JV.PROP_CONTROL];
     if (typeof control === 'string') {
         control = controls[cell[JV.PROP_CONTROL]];
     }
-    buildText(rst, cell, font, control, offsetX, offsetY, adjustY, canvas, isHtoV);
+    buildText(rst, cell, font, control, offsetX, offsetY, adjustY, canvas, isHtoV, HtoVStr);
 
     return rst.join("");
 }
 
-function buildTextHtoV(destRst, cell, font, control, offsetX, offsetY, adjustY, canvas, isHtoV) {
-    let orgFontHeight = parseInt(font[JV.FONT_PROPS[JV.FONT_PROP_IDX_HEIGHT]]);
-    let fontWeight = (font[JV.FONT_PROPS[JV.FONT_PROP_IDX_BOLD]] === 'T')?"bold":"normal";
-    let fontStyle = (font[JV.FONT_PROPS[JV.FONT_PROP_IDX_ITALIC]] === 'T')?"italic":"normal";
-    let fontUnderline = (font[JV.FONT_PROPS[JV.FONT_PROP_IDX_UNDERLINE]] === 'T')?"underline":"normal";
-    let left = parseInt(cell[JV.PROP_AREA][JV.PROP_LEFT]) + offsetX + 0.5,
-        right = parseInt(cell[JV.PROP_AREA][JV.PROP_RIGHT]) + offsetX + 0.5,
-        top = parseInt(cell[JV.PROP_AREA][JV.PROP_TOP]) + offsetY + adjustY,
-        bottom = parseInt(cell[JV.PROP_AREA][JV.PROP_BOTTOM]) + offsetY + adjustY,
-        x = left, y = top,
-        text_anchor = "start"
-    ;
-    let value = cell[JV.PROP_VALUE];
-    if (!(value)) {
-        value = "";
-    }
-    let values = null;
-    if (typeof value === "string") {
-        values = value.split("|");
-    } else {
-        values = [value];
-    }
-    // let stepHeight = (parseInt(cell[JV.PROP_AREA][JV.PROP_BOTTOM]) - parseInt(cell[JV.PROP_AREA][JV.PROP_TOP])) / values.length;
-    if (control) {
-        if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_HORIZON]] === "left") {
-            text_anchor = "start";
-            x = left + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
-        } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_HORIZON]] === "right") {
-            text_anchor = "end";
-            x = right - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
-        } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_HORIZON]] === "center") {
-            text_anchor = "middle";
-            x = Math.round((left + right) / 2);
-        }
-    }
-
-    let area = [0,0,0,0];
-    area[JV.IDX_TOP] = top;
-    area[JV.IDX_BOTTOM] = bottom;
-    area[JV.IDX_LEFT] = left;
-    area[JV.IDX_RIGHT] = right;
-    let height = bottom - top;
-    let ctx = canvas.getContext("2d");
-    let inner_draw_text = function (textValue) {
-        let dftFontHeight = orgFontHeight;
-        ctx.font = ((font[JV.FONT_PROPS[JV.FONT_PROP_IDX_BOLD]] === 'T')?"bold ":"") + ((font[JV.FONT_PROPS[JV.FONT_PROP_IDX_ITALIC]] === 'T')?"italic":"") + dftFontHeight + "px " + font[JV.PROP_NAME];
-        function inner_build_text(innerTxt, innerArea) {
-            let innerDftFontHeight = (dftFontHeight * 3 / 4); //SVG的字体与canvas的字体大小的切换, 不用考虑取整
-            if (control) {
-                if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "top") {
-                    y = innerArea[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_TOP];
-                } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "bottom") {
-                    y = innerArea[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
-                } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "center") {
-                    y = Math.round((innerArea[JV.IDX_TOP] + innerArea[JV.IDX_BOTTOM] + innerDftFontHeight) / 2 );
-                }
-            } else {
-                y = innerArea[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_TOP];
-            }
-            if (font[JV.PROP_NAME] === "宋体") {
-                y--;
-            }
-            destRst.push("<text style='fill:black;font-family:" + font[JV.PROP_NAME] +
-                ";font-weight:" + fontWeight +
-                ";font-style:" + fontStyle +
-                ";text-decoration:" + fontUnderline +
-                // ";text-decoration:normal" +
-                ";font-size:" + innerDftFontHeight + "pt' x='" +
-                x +"' y='" + y + "' text-anchor='" + text_anchor + "' xml:space='preserve'>" + innerTxt + "</text>");
-        }
-        let actLines = private_splitString(textValue, (area[JV.IDX_RIGHT] - area[JV.IDX_LEFT]), ctx);
-        if (actLines.length === 1 || (control && control.Shrink !== 'T')) {
-            inner_build_text(textValue, area);
-        } else {
-            while (true) {
-                if (dftFontHeight > 6) {
-                    let lines = Math.floor((area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) / (dftFontHeight + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.IDX_TOP] + 4));
-                    lines = (lines === 0)?1:lines;
-                    actLines = private_splitString(textValue, (area[JV.IDX_RIGHT] - area[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.IDX_RIGHT]), ctx);
-                    if (lines >= actLines.length) {
-                        let aH = dftFontHeight + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.IDX_TOP] + 4;
-                        if ((aH * actLines.length) < (area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) && (control && control.Vertical !== 'top')) {
-                            if (control.Vertical === 'bottom') {
-                                area[JV.IDX_TOP] = area[JV.IDX_BOTTOM] - (aH * actLines.length);
-                            } else {
-                                area[JV.IDX_TOP] = (area[JV.IDX_TOP] + area[JV.IDX_BOTTOM]) / 2 - (aH * actLines.length) / 2
-                                area[JV.IDX_BOTTOM] = area[JV.IDX_TOP] + (aH * actLines.length);
-                            }
-                        }
-                        let newArea = [], baseTop = area[JV.IDX_TOP];
-                        for (let ai = 0; ai < area.length; ai++) {
-                            newArea[ai] = area[ai];
-                        }
-                        for (let lIdx = 0; lIdx < actLines.length; lIdx++) {
-                            newArea[JV.IDX_TOP] = Math.round(aH * lIdx + baseTop);
-                            newArea[JV.IDX_BOTTOM] = Math.round(aH * (lIdx + 1) + baseTop);
-                            inner_build_text(actLines[lIdx], newArea);
-                        }
-                        break;
-                    } else {
-                        dftFontHeight--;
-                        ctx.font = ((font[JV.FONT_PROPS[JV.FONT_PROP_IDX_BOLD]] === 'T')?"bold ":"") + ((font[JV.FONT_PROPS[JV.FONT_PROP_IDX_ITALIC]] === 'T')?"italic":"") + dftFontHeight + "px " + font[JV.PROP_NAME];
-                    }
-                } else {
-                    inner_build_text(textValue, area);
-                    break;
-                }
-            }
-        }
-    };
-    for (let vidx = 0; vidx < values.length; vidx++) {
-        area[JV.IDX_TOP] = top + vidx * (height / values.length);
-        area[JV.IDX_BOTTOM] = top + (vidx + 1) * (height / values.length);
-        inner_draw_text(values[vidx]);
-    }
-}
-
-function buildText(destRst, cell, font, control, offsetX, offsetY, adjustY, canvas, isHtoV) {
+function buildText(destRst, cell, font, control, offsetX, offsetY, adjustY, canvas, isHtoV, HtoVStr) {
     let orgFontHeight = parseInt(font[JV.FONT_PROPS[JV.FONT_PROP_IDX_HEIGHT]]);
     let fontWeight = (font[JV.FONT_PROPS[JV.FONT_PROP_IDX_BOLD]] === 'T')?"bold":"normal";
     let fontStyle = (font[JV.FONT_PROPS[JV.FONT_PROP_IDX_ITALIC]] === 'T')?"italic":"normal";
@@ -368,7 +225,7 @@ function buildText(destRst, cell, font, control, offsetX, offsetY, adjustY, canv
                 ";text-decoration:" + fontUnderline +
                 // ";text-decoration:normal" +
                 ";font-size:" + innerDftFontHeight + "pt' x='" +
-                x +"' y='" + y + "' text-anchor='" + text_anchor + "' xml:space='preserve'>" + innerTxt + "</text>");
+                x +"' y='" + y + "' text-anchor='" + text_anchor + "' xml:space='preserve'" + HtoVStr + ">" + innerTxt + "</text>");
         }
         let actLines = private_splitString(textValue, (area[JV.IDX_RIGHT] - area[JV.IDX_LEFT]), ctx);
         if (actLines.length === 1 || (control && control.Shrink !== 'T')) {

+ 7 - 2
web/common/html/header.html

@@ -2,7 +2,7 @@
     <% if(controller === 'boot' || controller === 'pm'){ %>
     <!--<a style="text-decoration: none" href="javascript:void(0);" class="header-logo">-->
     <% }else { %>
-    <div class="mx-2"><a href="/pm" class="btn btn-sm" data-toggle="tooltip" title="返回"><i class="fa fa-angle-left" style="font-size:24px"></i></a></div>
+    <div class="mx-2"><a href="/pm" class="btn btn-sm" data-toggle="tooltip" title="返回项目管理"><i class="fa fa-angle-left" style="font-size:24px"></i></a></div>
         <!--<a style="text-decoration: none" href="/pm" class="header-logo">-->
     <% } %>
     <div class="header-logo">
@@ -31,7 +31,12 @@
     <div class="ml-auto navbar-text p-0">
         <ul class="nav navbar-nav">
             <li class="nav-item dropdown">
-                <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown"><%= sessionUser.real_name === '' ? sessionUser.mobile : sessionUser.real_name %></a>
+                <!--<a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown"><%= sessionUser.real_name === '' ? sessionUser.mobile : sessionUser.real_name %></a>-->
+                <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" id="link_userName"></a>
+                <script>
+                    let userName = "<%= sessionUser.real_name === '' ? sessionUser.mobile : sessionUser.real_name %>";
+                    document.getElementById('link_userName').innerHTML = userName;
+                </script>
                 <div class="dropdown-menu dropdown-menu-right">
                     <a class="dropdown-item" href="/user/info" target="_blank">账号资料</a>
                     <a class="dropdown-item" href="/user/buy" target="_blank">产品激活</a>

web/dest/css/img/blocklib.png → web/dest/css/img/blockLib.png


BIN
web/dest/css/img/copy.png


BIN
web/dest/css/img/work.png


+ 34 - 1
web/over_write/js/gansu_2013.js

@@ -27,4 +27,37 @@ if(typeof region !== 'undefined') {
         '白银',
     ];
     console.log(region);
-}
+}
+
+(function overwriteFeeTypes() {
+    if (typeof cpFeeTypes == 'undefined') return;
+    cpFeeTypes = [
+        {type: 'labour', name: '人工费'},
+        {type: 'marketMaterial', name: '市场价材料费'},
+        {type: 'marketMachine', name: '市场价机械费'},
+        {type: 'mainMaterial', name: '主材费'},
+        {type: 'equipment', name: '设备费'},
+        {type: 'manage', name: '管理费'},
+        {type: 'profit', name: '利润'},
+        {type: 'risk', name: '风险费'},
+        {type: 'labourDiff', name: '人工价差'},
+        {type: 'secondMaterialAdjust', name: '二类材料调整'},
+        {type: 'machineDiff', name: '机械调整及价差'},
+        {type: 'safeMeasures', name: '安全文明施工费'},
+        {type: 'environment', name: '环境保护费'},
+        {type: 'civilization', name: '文明施工费'},
+        {type: 'safe', name: '安全施工费'},
+        {type: 'tempFacility', name: '临时设施费'},
+        {type: 'otherTotalMeasures', name: '其他总价措施费'},
+        {type: 'night', name: '夜间施工增加费'},
+        {type: 'secondHandling', name: '二次搬运费'},
+        {type: 'protect', name: '已完工程及设备保护费'},
+        {type: 'winter', name: '冬雨季施工增加费'},
+        {type: 'retest', name: '工程定位复测费'},
+        {type: 'factor', name: '施工因素增加费'},
+        {type: 'specialArea', name: '特殊地区施工增加费'},
+        {type: 'force', name: '规费'},
+        {type: 'tax', name: '税金'},
+        {type: 'common', name: '工程造价'}
+    ];
+})();

+ 17 - 8
web/over_write/js/jiangxi_2017.js

@@ -123,7 +123,7 @@ function overwriteRationCalcBases (taxType){
 (function overwriteFeeTypes() {
     if (typeof cpFeeTypes == 'undefined') return;
     cpFeeTypes = [
-        {type: 'direct', name: '直接费'},
+        // {type: 'direct', name: '直接费'},
         {type: 'labour', name: '人工费'},
         {type: 'marketLabour', name: '市场价人工费'},
         {type: 'marketMaterial', name: '市场价材料费'},
@@ -151,7 +151,7 @@ if(typeof baseFigureMap !== 'undefined'){
     baseFigureMap = {
         //与清单直接关联=======
         '分部分项工程费': {base: 'FBFXGCF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
-        '分部分项直接费': {base: 'FBFXZJF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
+        //'分部分项直接费': {base: 'FBFXZJF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
         '分部分项定额人工费': {base: 'FBFXDEJJRGF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
         '分部分项人工费': {base: 'FBFXRGF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
         '分部分项材料费': {base: 'FBFXCLF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
@@ -203,7 +203,7 @@ if(typeof baseFigureMap !== 'undefined'){
         '分包人工工日': {base: 'FBRGGR', class: 'FBF'},
         '估价项目定额人工费': {base: 'GJXMDERGF', class: 'GJXM'},
         '估价项目定额机械费': {base: 'GJXMDEJXF', class: 'GJXM'},
-        '估价项目直接费': {base: 'GJXMZJF', class: 'GJXM'},
+        //'估价项目直接费': {base: 'GJXMZJF', class: 'GJXM'},
         '估价项目人工费': {base: 'GJXMRGF', class: 'GJXM'},
         '估价项目材料费': {base: 'GJXMCLF', class: 'GJXM'},
         '估价项目机械费': {base: 'GJXMJXF', class: 'GJXM'},
@@ -212,7 +212,7 @@ if(typeof baseFigureMap !== 'undefined'){
     };
 }
 if(typeof baseFigureTemplate !== 'undefined'){
-    baseFigureTemplate['FBFXZJF'] =  function (tender) {//分部分项直接费
+    /*baseFigureTemplate['FBFXZJF'] =  function (tender) {//分部分项直接费
         if(cbTools.isUnDef(calcBase.fixedBills[fixedFlag.SUB_ENGINERRING])){
             return 0;
         }
@@ -221,7 +221,7 @@ if(typeof baseFigureTemplate !== 'undefined'){
         if(cbTools.isUnDef(bill)) return 0;
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
         return cbTools.isDef(bill.feesIndex.direct) && cbTools.isDef(bill.feesIndex.direct[totalFeeType]) ? bill.feesIndex.direct[totalFeeType] : 0;
-    };
+    };*/
     baseFigureTemplate['FBFXRGF'] =  function (tender) {//分部分项人工费(市场人工费)
         if(cbTools.isUnDef(calcBase.fixedBills[fixedFlag.SUB_ENGINERRING])){
             return 0;
@@ -367,7 +367,7 @@ if(typeof baseFigureTemplate !== 'undefined'){
         }
         return rst;
     };
-    baseFigureTemplate['GJXMZJF'] =  function (tender) {//估计项目直接费
+    /*baseFigureTemplate['GJXMZJF'] =  function (tender) {//估计项目直接费
         const totalFeeType = tender ? 'tenderTotalFee' : 'totalFee';
         let rst = 0;
         let rations = calcBase.project.Ration.datas;
@@ -377,7 +377,7 @@ if(typeof baseFigureTemplate !== 'undefined'){
             }
         }
         return rst;
-    };
+    };*/
     baseFigureTemplate['GJXMRGF'] =  function (tender) {//估计项目人工费(市场人工费)
         const totalFeeType = tender ? 'tenderTotalFee' : 'totalFee';
         let rst = 0;
@@ -448,7 +448,16 @@ if(typeof $ !== 'undefined' && $('#cbClassList')){
 if (typeof calcBaseView !== 'undefined') {
     calcBaseView.billsCBClass = {ALL: [], FBFX: [], CSXM: [], QTXM: [], FBF: [], RCJ: [], GF: [], SJ: [], GJXM: []};
 }
-
+// (江西)项目属性-关于计算中的取费方式默认勾选子目单价取费(反算)方式。
+// 根据重写去给项目的billsCalcMode赋值比这种形式麻烦
+if (typeof leafBillGetFeeType !== 'undefined') {
+    leafBillGetFeeType = {
+        rationPriceConverse: 0,
+        rationContent: 1,
+        rationPrice: 2,
+        billsPrice: 3
+    };
+}
 
 
 

+ 31 - 0
web/over_write/js/neimenggu_2017.js

@@ -0,0 +1,31 @@
+'use strict';
+
+// CSL, 2019-01-18
+
+(function overwriteFeeTypes() {
+    if (typeof cpFeeTypes == 'undefined') return;
+    cpFeeTypes = [
+        {type: 'marketLabour', name: '市场价人工费'},
+        {type: 'marketMaterial', name: '市场价材料费'},
+        {type: 'marketMachine', name: '市场价机械费'},
+        {type: 'equipment', name: '设备费'},
+        {type: 'mainMaterial', name: '主材费'},
+        {type: 'manage', name: '管理费'},
+        {type: 'profit', name: '利润'},
+        {type: 'risk', name: '风险费'},
+        {type: 'safeMeasures', name: '安全文明施工费'},
+        {type: 'safeAndEnvironment', name: '安全文明施工与环境保护费'},
+        {type: 'tempFacility', name: '临时设施费'},
+        {type: 'rain', name: '雨季施工增加费'},
+        {type: 'protect', name: '已完工程及设备保护费'},
+        {type: 'retest', name: '工程定位复测费'},
+        {type: 'secondHandling', name: '二次搬运费'},
+        {type: 'specialArea', name: '特殊地区施工增加费'},
+        {type: 'night', name: '夜间施工增加费'},
+        {type: 'basement', name: '白天在地下室施工增加费'},
+        {type: 'winter', name: '冬季施工增加费'},
+        {type: 'force', name: '规费'},
+        {type: 'tax', name: '税金'},
+        {type: 'common', name: '工程造价'}
+    ];
+})();

+ 2 - 1
web/users/html/login.html

@@ -18,7 +18,8 @@
         <form class="form-signin" method="post" onsubmit="return false">
             <h1 class="d-flex justify-content-center mb-5">纵横建筑云计价</h1>
             <div class="form-group">
-                <input id="inputEmail" class="form-control " name="inputEmail" placeholder="通行账号 邮箱/手机" autofocus="" />
+                <input id="inputEmail" class="form-control " name="inputEmail" placeholder="邮箱/手机" autofocus="" />
+                <small id="emailHelp" class="form-text text-danger"></small>
             </div>
             <div class="form-group">
                 <input id="inputPassword" class="form-control " name="inputPassword" placeholder="输入密码" type="password"/>

+ 35 - 30
web/users/js/login.js

@@ -15,39 +15,44 @@ $(document).ready(function () {
         let account = $("#inputEmail").val();
         let pw = $("#inputPassword").val();
 
-        $.ajax({
-            url: '/login',
-            type: 'post',
-            data: {"account": account, "pw": pw},
-            success: function (response) {
-                if (response.error === 0) {
-                    const url = response.last_page !== null && response.last_page !== undefined && response.last_page !== '' ?
-                        response.last_page : '/pm';
-                    if (response.login_ask === 0) {
-                        location.href = url;
-                    } else {
-                        response.compilation_list = response.compilation_list === undefined || response.compilation_list === '' ?
-                            null : JSON.parse(response.compilation_list);
-                        if (response.compilation_list === null || response.compilation_list.length <= 0) {
+        // 判断输入的邮箱/手机是否格式正确
+        if(/^1[3456789]\d{9}$/.test(account) || /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(account)) {
+            $.ajax({
+                url: '/login',
+                type: 'post',
+                data: {"account": account, "pw": pw},
+                success: function (response) {
+                    if (response.error === 0) {
+                        const url = response.last_page !== null && response.last_page !== undefined && response.last_page !== '' ?
+                            response.last_page : '/pm';
+                        if (response.login_ask === 0) {
                             location.href = url;
-                            return false;
+                        } else {
+                            response.compilation_list = response.compilation_list === undefined || response.compilation_list === '' ?
+                                null : JSON.parse(response.compilation_list);
+                            if (response.compilation_list === null || response.compilation_list.length <= 0) {
+                                location.href = url;
+                                return false;
+                            }
+                            console.log(response.compilation_list);
+                            setVersion(response.compilation_list);
+                            $('#ver').modal('show');
                         }
-                        console.log(response.compilation_list);
-                        setVersion(response.compilation_list);
-                        $('#ver').modal('show');
+                    } else if(response.error === 2) {
+                        $('#check_ssoId').val(response.ssoId);
+                        $('#phone').modal('show');
+                    } else {
+                        let msg = response.msg !== undefined ? response.msg : '未知错误';
+                        showError(msg, $("input"));
                     }
-                } else if(response.error === 2) {
-                    $('#check_ssoId').val(response.ssoId);
-                    $('#phone').modal('show');
-                } else {
-                    let msg = response.msg !== undefined ? response.msg : '未知错误';
-                    showError(msg, $("input"));
+                },
+                error: function (result) {
+                    showError('内部程序错误', null);
                 }
-            },
-            error: function (result) {
-                showError('内部程序错误', null);
-            }
-        });
+            });
+        } else {
+            $('#emailHelp').text('您输入的 邮箱/手机 格式不对');
+        }
     });
 
     $("input").blur(function () {
@@ -224,7 +229,7 @@ function showError(msg, element) {
     if (element !== null) {
         element.parent().addClass('has-danger');
     }
-    $("#message").text(msg);
+    $("#message").html(msg);
     $("#error-tips").show("fast");
 }