فهرست منبع

Merge branch '1.0.0_online' of http://smartcost.f3322.net:3000/SmartCost/ConstructionOperation into 1.0.0_online

TonyKang 6 سال پیش
والد
کامیت
a60fad5395
86فایلهای تغییر یافته به همراه2713 افزوده شده و 315 حذف شده
  1. 3 3
      config/menu.js
  2. 1 0
      lib/lz-string/lz-string.min.js
  3. 7 5
      modules/all_models/engineering_lib.js
  4. 1 0
      modules/all_models/manager.js
  5. 53 0
      modules/all_models/material_replace_lib.js
  6. 1 1
      modules/all_models/stdBills_bills.js
  7. 0 2
      modules/all_models/stdBills_lib.js
  8. 2 1
      modules/all_models/stdGlj_glj.js
  9. 3 0
      modules/all_models/stdRation_ration.js
  10. 1 0
      modules/all_models/std_billsGuidance_lib.js
  11. 12 1
      modules/all_models/user.js
  12. 0 4
      modules/bills_lib/models/bills_lib_interfaces.js
  13. 2 0
      modules/bills_template_lib/facade/bills_template_facade.js
  14. 4 0
      modules/common/base/base_model.js
  15. 1 1
      modules/common/const/bills_fixed.js
  16. 1 0
      modules/common/helper/mongoose_helper.js
  17. 2 2
      modules/common/std/std_bills_lib_lists_model.js
  18. 136 0
      modules/material_replace_lib/controllers/material_replace_controller.js
  19. 133 0
      modules/material_replace_lib/facade/material_replace_facade.js
  20. 22 0
      modules/material_replace_lib/routes/material_replace_router.js
  21. 63 18
      modules/ration_repository/controllers/ration_repository_controller.js
  22. 120 18
      modules/ration_repository/models/ration_item.js
  23. 1 0
      modules/ration_repository/routes/ration_rep_routes.js
  24. 3 3
      modules/std_billsGuidance_lib/facade/facades.js
  25. 27 1
      modules/std_glj_lib/controllers/gljController.js
  26. 13 2
      modules/std_glj_lib/controllers/viewsController.js
  27. 1 0
      modules/std_glj_lib/routes/routes.js
  28. 42 6
      modules/users/controllers/compilation_controller.js
  29. 1 0
      modules/users/controllers/login_controller.js
  30. 128 2
      modules/users/controllers/user_controller.js
  31. 3 3
      modules/users/models/compilation_model.js
  32. 6 0
      modules/users/models/engineering_lib_model.js
  33. 46 3
      modules/users/models/user_model.js
  34. 2 0
      modules/users/routes/compilation_route.js
  35. 3 0
      modules/users/routes/user_route.js
  36. 2 1
      package.json
  37. 177 0
      public/scHintBox.html
  38. 24 0
      public/web/commonAlert.js
  39. 10 1
      public/web/common_ajax.js
  40. 84 23
      public/web/sheet/sheet_common.js
  41. 1 0
      public/web/sheet/sheet_data_helper.js
  42. 24 0
      public/web/tools_const.js
  43. 17 0
      web/maintain/billsGuidance_lib/css/main.css
  44. 16 1
      web/maintain/billsGuidance_lib/html/main.html
  45. 13 1
      web/maintain/billsGuidance_lib/html/zhiyin.html
  46. 117 17
      web/maintain/billsGuidance_lib/js/billsGuidance.js
  47. 5 5
      web/maintain/billsGuidance_lib/js/global.js
  48. 14 16
      web/maintain/billsGuidance_lib/js/main.js
  49. 7 11
      web/maintain/bills_lib/html/main.html
  50. 3 5
      web/maintain/bills_lib/scripts/bills_lib_ajax.js
  51. 15 2
      web/maintain/common/css/main.css
  52. 4 3
      web/maintain/common/html/edit_layout.html
  53. 2 2
      web/maintain/main_col_lib/js/main_col_lib.js
  54. 67 0
      web/maintain/material_replace_lib/html/edit.html
  55. 118 0
      web/maintain/material_replace_lib/html/main.html
  56. 131 0
      web/maintain/material_replace_lib/js/material_replace.js
  57. 188 0
      web/maintain/material_replace_lib/js/material_replace_edit.js
  58. 1 1
      web/maintain/ration_repository/js/annotation.js
  59. 1 1
      web/maintain/ration_repository/js/jobContent.js
  60. 26 2
      web/maintain/ration_repository/js/main.js
  61. 3 2
      web/maintain/ration_repository/js/ration.js
  62. 1 1
      web/maintain/ration_repository/js/ration_assist.js
  63. 2 2
      web/maintain/ration_repository/js/ration_coe.js
  64. 33 1
      web/maintain/ration_repository/js/ration_glj.js
  65. 41 7
      web/maintain/ration_repository/js/section_tree.js
  66. 2 1
      web/maintain/ration_repository/js/sheetsOpr.js
  67. 23 2
      web/maintain/ration_repository/main.html
  68. 5 0
      web/maintain/std_glj_lib/html/gongliao.html
  69. 121 25
      web/maintain/std_glj_lib/js/components.js
  70. 116 30
      web/maintain/std_glj_lib/js/glj.js
  71. 49 21
      web/maintain/std_glj_lib/js/gljComponent.js
  72. 13 1
      web/maintain/std_glj_lib/js/sheetsOpr.js
  73. 32 0
      web/over_write/js/chongqing_2018.js
  74. 11 0
      web/users/css/custom.css
  75. 18 4
      web/users/css/style.css
  76. 7 8
      web/users/js/col_setting.js
  77. 47 10
      web/users/js/compilation.js
  78. 84 1
      web/users/js/user.js
  79. 62 10
      web/users/views/compilation/add.html
  80. 1 1
      web/users/views/compilation/common.html
  81. 2 1
      web/users/views/compilation/engineering.html
  82. 11 4
      web/users/views/compilation/modal.html
  83. 3 0
      web/users/views/layout/layout.html
  84. 7 0
      web/users/views/tool/index.html
  85. 35 15
      web/users/views/user/index.html
  86. 73 0
      web/users/views/user/test_user.html

+ 3 - 3
config/menu.js

@@ -22,12 +22,12 @@ let menuData = {
                 title: '普通用户',
                 url: '/user',
                 name: 'index',
-            },
-            'last-login' : {
+            }/*,
+            'test-user' : {
                 title: '测试用户',
                 url: '/user/test-user',
                 name: 'test-user',
-            }
+            }*/
         }
     },
     'notify': {

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
lib/lz-string/lz-string.min.js


+ 7 - 5
modules/all_models/engineering_lib.js

@@ -60,12 +60,14 @@ let modelSchema = {
     valuationID:{type:String,index: true},
     //工程专业名称
     name:String,
+    //费用标准
+    feeName:String,
     //前端是否显示
-    visible:{
-        type: Boolean,
-        default: false
-    },
-    engineering:Number
+    visible:{type: Boolean, default: false},
+    //取费专业
+    engineering:Number,
+    //是否计算安装增加费
+    isInstall:{type: Boolean, default: false}
 };
 mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));
 

+ 1 - 0
modules/all_models/manager.js

@@ -24,6 +24,7 @@ let modelSchema = {
         type: Number,
         default: 0
     },
+    real_name:String,
     // 创建时间
     create_time: {
         type: Number,

+ 53 - 0
modules/all_models/material_replace_lib.js

@@ -0,0 +1,53 @@
+/**
+ * Created by zhang on 2018/8/22.
+ */
+//材料替换库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+const material_lib = new Schema({
+        ID:{type:String,index:true},
+        creator: String,
+        createDate: Number,
+        recentOpr: [oprSchema],
+        name: String,
+        compilationId: String,
+        compilationName: String,
+        billsLibId:Number,
+        billsLibName:String,
+        deleted: Boolean
+    }, {versionKey: false}
+);
+
+mongoose.model("std_material_replace_lib", material_lib,"std_material_replace_lib");
+
+
+const std_replace_bills = new Schema({
+        ID: {type:String,index:true},
+        libID:{type:String,index:true},
+        code: {type:String,index:true},
+        name: String,
+        rule:Number//规则类型
+    }, {versionKey: false}
+);
+
+mongoose.model('std_replace_bills', std_replace_bills, 'std_replace_bills');
+
+
+const std_replace_material = new Schema({
+    ID: {type:String,index:true},
+    libID:{type:String,index:true},
+    billsItemID:{type:String,index:true},
+    code: String,
+    name: String,
+    specs: String,
+    type: Number,
+    unit: String
+},{versionKey: false});
+
+mongoose.model('std_replace_material', std_replace_material, 'std_replace_material');
+
+
+
+
+

+ 1 - 1
modules/all_models/stdBills_bills.js

@@ -17,7 +17,7 @@ const stdBills_bills = new Schema({
             jobs: [],
             items: [],
             recharge:String,
-            billsLibId: Number,
+            billsLibId: {type:Number,index:true},
             sectionInfo: Schema.Types.Mixed,
             deleted: Boolean
     },

+ 0 - 2
modules/all_models/stdBills_lib.js

@@ -12,8 +12,6 @@ const stdBills_lib = new Schema({
 
         billsLibId: Number,
         billsLibName: String,
-        compilationId: String,
-        compilationName: String,
         deleted: Boolean
     },
     {versionKey: false}

+ 2 - 1
modules/all_models/stdGlj_glj.js

@@ -29,7 +29,8 @@ const std_glj = new Schema({
     adjCoe: Number,
     component: [std_gljComponent],
     materialType: Number, //三材类型:钢材1、钢筋2、木材3、水泥4、标准砖5
-    materialCoe: Number //三材系数
+    materialCoe: Number, //三材系数
+    model: Number, //机型
 },{versionKey: false});
 
 mongoose.model('std_glj_lib_gljList', std_glj, 'std_glj_lib_gljList');

+ 3 - 0
modules/all_models/stdRation_ration.js

@@ -34,6 +34,9 @@ const rationItemSchema = new Schema({
     name: String,
     unit: String,
     basePrice: Number,
+    labourPrice: Number,
+    materialPrice: Number,
+    machinePrice: Number,
     sectionId: Number,
     rationRepId: Number,
     caption: String,

+ 1 - 0
modules/all_models/std_billsGuidance_lib.js

@@ -12,6 +12,7 @@ const mongoose = require('mongoose');
 const Schema = mongoose.Schema;
 
 const stdBillsGuidanceLib = new Schema({
+    type: Number, //1:清单指引 2:清单精灵
     ID: String, //uuid
     compilationId: String,
     compilationName: String,

+ 12 - 1
modules/all_models/user.js

@@ -10,6 +10,14 @@ import mongoose from "mongoose";
 
 let Schema = mongoose.Schema;
 let collectionName = 'users';
+let upgrade = mongoose.Schema({
+    compilationID:String,//编办ID
+    upgrade_time:Number,
+    isUpgrade:Boolean,
+    remark:String//描述:广东办刘飞 2018-06-17 启用/关闭
+}, { _id: false })
+
+
 let modelSchema = {
     // 用户名
     username: String,
@@ -34,15 +42,18 @@ let modelSchema = {
         default: -1
     },
     // 最后登录时间
-    last_login: {
+    latest_login: {
         type: Number,
         default: 0
     },
+    //最近使用编办
+    latest_used:String,
     // 创建时间
     create_time: {
         type: Number,
         default: 0
     },
+    upgrade_list:[upgrade],
     user_type:{
         type:String,
         default:'normal'//  normal : 普通用户,test:测试用户

+ 0 - 4
modules/bills_lib/models/bills_lib_interfaces.js

@@ -70,8 +70,6 @@ billsLibDao.prototype.createStdBillsLib = function(clibData, callback){
         let billsLibId = result.sequence_value;
         let userAccount = clibData.userAccount;
         let billsLibName = clibData.name;
-        let compilationId = clibData.compilationId;
-        let compilationName = clibData.compilationName;
         let dateStr = moment().format('YYYY-MM-DD HH:mm:ss');
         let newStdBillsLib = {
             creator: userAccount,
@@ -79,8 +77,6 @@ billsLibDao.prototype.createStdBillsLib = function(clibData, callback){
             recentOpr: [{operator: userAccount, operateDate: dateStr}],
             billsLibId: billsLibId,
             billsLibName: billsLibName,
-            compilationId: compilationId,
-            compilationName: compilationName,
             deleted: false
         };
         StdBillsLib.create(newStdBillsLib, function(err){

+ 2 - 0
modules/bills_template_lib/facade/bills_template_facade.js

@@ -53,6 +53,8 @@ async function getTemplateDatasByLibID(libID) {
     return await billTemplateItemsModel.find({libID:libID});
 }
 async function deleteLibByID(ID){
+    //删除模板详情:
+    await billTemplateItemsModel.deleteMany({libID:ID});
     return billTemplateLibModel.deleteOne({ID:ID});
 }
 

+ 4 - 0
modules/common/base/base_model.js

@@ -129,6 +129,10 @@ class BaseModel {
         return result.ok !== undefined && result.ok === 1;
     }
 
+    isDef(value){
+        return value !==undefined && value !==null
+    }
+
 }
 
 export default BaseModel;

+ 1 - 1
modules/common/const/bills_fixed.js

@@ -47,7 +47,7 @@ const fixedFlagList = [
     {name: "措施项目", value: fixedFlag.MEASURE},
     {name: "施工技术措施项目", value: fixedFlag.CONSTRUCTION_TECH},
     {name: "安全文明施工按实计算费用", value: fixedFlag.SAFETY_CONSTRUCTION_ACTUAL},
-    {name: "施工组织措施专项费用", value: fixedFlag.CONSTRUCTION_ORGANIZATION},
+    {name: "施工组织措施项目", value: fixedFlag.CONSTRUCTION_ORGANIZATION},
     {name: "安全文明施工专项费用", value: fixedFlag.SAFETY_CONSTRUCTION},
     {name: "其他项目", value: fixedFlag.OTHER},
     {name: "暂列金额", value: fixedFlag.PROVISIONAL},

+ 1 - 0
modules/common/helper/mongoose_helper.js

@@ -72,6 +72,7 @@ class MongooseHelper {
         });
     }
 
+
     /**
      * 关联查找数据
      *

+ 2 - 2
modules/common/std/std_bills_lib_lists_model.js

@@ -38,9 +38,9 @@ class STDBillsLibListsModel extends BaseModel {
         let billList = [];
         for(let tmp of billLib) {
             let tmpRation = {id: tmp.billsLibId, name: tmp.billsLibName};
-            if (compilationId !== tmp.compilationId) {
+            /*if (compilationId !== tmp.compilationId) {
                 continue;
-            }
+            }*/
             if (billList.length <= 0) {
                 billList = [tmpRation];
             } else {

+ 136 - 0
modules/material_replace_lib/controllers/material_replace_controller.js

@@ -0,0 +1,136 @@
+/**
+ * Created by zhang on 2018/8/22.
+ */
+import BaseController from "../../common/base/base_controller";
+import materialFacade from "../facade/material_replace_facade";
+let config = require("../../../config/config.js");
+
+class ReplaceController extends BaseController{
+    /**
+     * 材料替换库页面
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async main(request, response) {
+        let materialLibs = await materialFacade.findByCondition({},null,false);
+        let randerData = {
+            title:'材料替换库',
+            userAccount: request.session.managerData.username,
+            userID: request.session.managerData.userID,
+            materialLibs:materialLibs,
+            layout: 'maintain/common/html/layout'
+        };
+        response.render("maintain/material_replace_lib/html/main", randerData);
+    }
+
+    async edit(request,response){
+        //先取出替换库信息:
+        let libID = request.params.libID;
+        let materialLib = await materialFacade.findByCondition({'ID':libID});
+        if(materialLib){
+            let billsLibId = materialLib.billsLibId;
+            let compilationId = materialLib.compilationId;
+            let gljLib = await  materialFacade.findGLJLibByComID(compilationId);
+            let billsList = await materialFacade.findBillsByLibID(libID);
+            //let templateDatas = await materialFacade.getTemplateDatasByLibID(libID);
+
+            let randerData = {
+                title:'材料替换库',
+                mainURL:'/materialReplace/main',
+                libName:materialLib.name,
+                userAccount: request.session.managerData.username,
+                userID: request.session.managerData.userID,
+                billsList:JSON.stringify(billsList),
+                billsLibId:billsLibId,
+                gljLibID:gljLib.ID,
+                libID:libID,
+                LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
+                layout: 'maintain/common/html/edit_layout'
+            };
+            response.render("maintain/material_replace_lib/html/edit", randerData);
+        }else {
+            response.redirect(request.headers.referer);
+        }
+    }
+
+    async findLib(request, response){
+        let result={
+            error:0
+        };
+        try {
+            let data = request.body.data;
+            data = JSON.parse(data);
+            let conditions={};
+            if(data.compilationID) conditions.compilationId = data.compilationID;
+            if(data.billLibID) conditions.billsLibId = data.billLibID;
+            if(data.ID) conditions.ID = data.ID;
+            let resultData = await materialFacade.findByCondition(conditions);
+            result.data=resultData;
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
+    async addLib(request, response){
+        try {
+            await materialFacade.addLib(request.body);
+        }catch (error) {
+            console.log(error);
+        }
+        response.redirect(request.headers.referer);
+    }
+    async saveLib(request, response){
+        let result={
+            error:0
+        };
+        try {
+            let data = request.body.data;
+            data = JSON.parse(data);
+            let resultData= await materialFacade.saveLib(data);
+            result.data=resultData;
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
+    async deleteLibByID(request,response){
+        let result={
+            error:0
+        };
+        try {
+            let data = request.body.data;
+            data = JSON.parse(data);
+            let resultData= await materialFacade.deleteLibByID(data.ID);
+            result.data=resultData;
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
+    async saveBills(request,response){
+        let result={
+            error:0
+        };
+        try {
+            let data = request.body.data;
+            data = JSON.parse(data);
+            let resultData= await materialFacade.saveBills(data);
+            result.data=resultData;
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
+}
+
+export default ReplaceController;

+ 133 - 0
modules/material_replace_lib/facade/material_replace_facade.js

@@ -0,0 +1,133 @@
+/**
+ * Created by zhang on 2018/8/22.
+ */
+
+import mongoose from "mongoose";
+const uuidV1 = require('uuid/v1');
+let moment = require("moment");
+let compilationModel = mongoose.model("compilation");
+let materialLibModel = mongoose.model("std_material_replace_lib");
+let replaceBillModel = mongoose.model("std_replace_bills");
+let replaceMaterialModel = mongoose.model("std_replace_material");
+let StdBillsLib = mongoose.model('std_bills_lib_list');
+let stdBillsModel = mongoose.model('std_bills_lib_bills');
+
+const stdGljLibModel = mongoose.model('std_glj_lib_map');
+
+let materialReplaceLib = {
+    findByCondition:async function(conditions,options,single=true){
+        if(single == true){
+            return await materialLibModel.findOne(conditions,options);
+        }else {
+            return await  materialLibModel.find(conditions,options);
+        }
+    },
+    addLib : async function (data){
+        let now = new Date().getTime();
+        let dateStr = moment(now).format('YYYY-MM-DD HH:mm:ss');
+        //取编办信息
+        let compilation = await compilationModel.findOne({_id:data.compilationId});
+        //取清单规则信息
+        let billLib = await StdBillsLib.findOne({billsLibId:data.billsLibId});
+        if(compilation && billLib){
+            let newLib = {
+                creator: data.userAccount,
+                createDate: now,
+                recentOpr: [{operator: data.userAccount, operateDate: dateStr}],
+                name: data.name,
+                compilationId: data.compilationId,
+                compilationName: compilation.name,
+                billsLibId:billLib.billsLibId,
+                billsLibName:billLib.billsLibName,
+                deleted: false
+            };
+            newLib.ID = uuidV1();
+            return await materialLibModel.create(newLib);
+        }else {
+            throw  new Error("编办或清单规则有误!");
+        }
+    },
+    saveLib:async function(param) {
+        return await materialLibModel.findOneAndUpdate(param.query,param.data,{new:true});
+    },
+    deleteLibByID:async function(ID){
+        //删除材料数据
+        await replaceMaterialModel.deleteMany({libID:ID});
+        //删除清单数据
+        await replaceBillModel.deleteMany({libID:ID});
+        return await materialLibModel.deleteOne({ID:ID});
+    },
+    findGLJLibByComID:async function(compilationId){//跟据费用定额查找工料机库
+        return await stdGljLibModel.findOne({compilationId:compilationId},['ID']);
+    },
+    findBillsByLibID:async function(libID){
+        return await replaceBillModel.find({libID:libID});
+    },
+    saveBills:async function(data){
+        let addList = [],updateList =[],deleteList=[];
+        for(let d of data){
+            if(d.type == 'add') addList.push(d);
+            if(d.type == 'update') updateList.push(d);
+            if(d.type == 'delete') deleteList.push(d);
+        }
+        let p = await Promise.all([addBills(addList),updateBills(updateList)]);
+        return p;
+    }
+};
+
+async function addBills(datas) {
+    let newBills = [],missCodes=[];
+    for(let d of datas){
+        //先查找清单规则库找到对应的清单
+        let stdBill = await stdBillsModel.findOne({billsLibId:d.billsLibId,code:d.code});
+        if(stdBill){
+            let temBill = {
+                libID:d.libID,
+                code:d.code,
+                name:stdBill.name,
+            };
+            temBill.ID = uuidV1();
+            newBills.push(temBill);
+        }else {
+            missCodes.push(d.code);
+        }
+    }
+    if(newBills.length>0){
+        await replaceBillModel.create(newBills);
+    }
+    return {type:'add',list:newBills,missCodes:missCodes};
+}
+
+async function updateBills(datas) {
+    let tasks = [],list=[],missCodes = [];
+    for(let d of datas){
+        let updateData = null;
+        let filter = {libID:d.libID, code:d.oldCode};
+        if(d.newCode && d.newCode !=''){//说明是要替换清单
+            let stdBill = await stdBillsModel.findOne({billsLibId:d.billsLibId,code:d.newCode});
+            if(stdBill){
+                 updateData = {code:d.newCode, name:stdBill.name};
+            }else {
+                missCodes.push(d.newCode);
+            }
+        }else {
+            updateData = d.updateData;
+        }
+        if(updateData){
+            let task = {
+                updateOne:{filter:filter, update :updateData}
+            };
+            tasks.push(task);
+            list.push({code:d.oldCode,updateData:updateData})
+        }
+    }
+    if(tasks.length > 0) await replaceBillModel.bulkWrite(tasks);
+    return {type:'update',list:list,missCodes:missCodes};
+}
+
+async function deleteBills(datas) {
+
+}
+
+
+export default materialReplaceLib

+ 22 - 0
modules/material_replace_lib/routes/material_replace_router.js

@@ -0,0 +1,22 @@
+/**
+ * Created by zhang on 2018/8/22.
+ */
+
+let express = require("express");
+let repRouter =express.Router();
+import ReplaceController from "../controllers/material_replace_controller";
+let replaceController = new ReplaceController();
+
+module.exports =function (app){
+
+    repRouter.get("/main", replaceController.auth, replaceController.init, replaceController.main);
+    repRouter.get("/edit/:libID", replaceController.auth, replaceController.init, replaceController.edit);
+    repRouter.post("/findLib", replaceController.auth, replaceController.init, replaceController.findLib);
+    repRouter.post("/addLib", replaceController.auth, replaceController.init, replaceController.addLib);
+    repRouter.post("/saveLib", replaceController.auth, replaceController.init, replaceController.saveLib);
+    repRouter.post("/deleteLibByID", replaceController.auth, replaceController.init, replaceController.deleteLibByID);
+    repRouter.post("/saveBills", replaceController.auth, replaceController.init, replaceController.saveBills);
+    app.use("/materialReplace", repRouter);
+};
+
+

+ 63 - 18
modules/ration_repository/controllers/ration_repository_controller.js

@@ -16,6 +16,9 @@ const fs = require("fs");
 // excel解析
 const excel = require("node-xlsx");
 const rationItem = require("../models/ration_item");
+const rationLibModel = mongoose.model('std_ration_lib_map');
+const rationItemModel = mongoose.model('std_ration_lib_ration_items');
+import STDGLJListModel from '../../std_glj_lib/models/gljModel';
 
 class RationRepositoryController extends baseController {
     async getRationLibsByCompilation(req, res){
@@ -159,12 +162,13 @@ class RationRepositoryController extends baseController {
             msg: ''
         };
         const allowHeader = ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
-        try {
-            const uploadOption = {
-                uploadDir: './public'
-            };
-            const form = new multiparty.Form(uploadOption);
-            form.parse(request, async function(err, fields, files) {
+        const uploadOption = {
+            uploadDir: './public'
+        };
+        const form = new multiparty.Form(uploadOption);
+        let uploadFullName
+        form.parse(request, async function(err, fields, files) {
+            try{
                 const rationRepId = fields.rationRepId !== undefined && fields.rationRepId.length > 0 ?
                     fields.rationRepId[0] : 0;
                 const type = fields.type !== undefined && fields.type.length > 0 ?
@@ -181,7 +185,7 @@ class RationRepositoryController extends baseController {
                     throw '不支持该类型';
                 }
                 // 重命名文件名
-                const uploadFullName = uploadOption.uploadDir + '/' + file.originalFilename;
+                uploadFullName = uploadOption.uploadDir + '/' + file.originalFilename;
                 fs.renameSync(file.path, uploadFullName);
 
                 const sheet = excel.parse(uploadFullName);
@@ -191,22 +195,24 @@ class RationRepositoryController extends baseController {
                 const result = type === 'source_file' ?
                     await rationItem.batchAddFromExcel(rationRepId, sheet[0].data) :
                     await rationItem.batchUpdateSectionIdFromExcel(sheet[0].data);
-
-                if (rationItem.failGLJList.length > 0) {
+                if (rationItem.failGLJList && rationItem.failGLJList.length > 0) {
                     responseData.msg = rationItem.failGLJList.join("\r\n");
                 }
                 // 删除文件
-                if (result) {
+                if(uploadFullName && fs.existsSync(uploadFullName)){
                     fs.unlink(uploadFullName);
                 }
                 response.json(responseData);
-            });
-        } catch (error) {
-            responseData.err = 1;
-            responseData.msg = error;
-            response.json(responseData);
-        }
-
+            }
+            catch (error){
+                if(uploadFullName && fs.existsSync(uploadFullName)){
+                    fs.unlink(uploadFullName);
+                }
+                responseData.err = 1;
+                responseData.msg = error;
+                response.json(responseData);
+            }
+        });
         return;
     }
 
@@ -240,7 +246,46 @@ class RationRepositoryController extends baseController {
         } catch (error) {
             response.end(error);
         }
-
+    }
+    //一键重新计算所有定额数据
+    async reCalcAll(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let rationRepId = data.rationRepId;
+            let rationLib = await rationLibModel.findOne({ID: rationRepId, $or: [{deleted: null},{deleted: false}]});
+            if(!rationLib){
+                throw '不存在此定额库';
+            }
+            let task = [];
+            // 获取标准工料机库数据
+            const stdBillsLibListsModel = new STDGLJListModel();
+            const stdGLJData = await stdBillsLibListsModel.getGljItemsByRepId(rationLib.gljLib);
+            // 整理标准工料机库数据
+            let stdGLJList = {};
+            let stdGLJListByID = {};
+            for (const tmp of stdGLJData) {
+                stdGLJList[tmp.code.toString()] = tmp.ID;
+                stdGLJListByID[tmp.ID] = tmp;
+            }
+            //获取所有的定额
+            let allRations = await rationItemModel.find({rationRepId: rationRepId, $or: [{isDeleted: false}, {isDeleted: null}]});
+            for(let ration of allRations){
+                rationItem.calcForRation(stdGLJListByID, ration);
+                task.push({
+                    updateOne: {
+                        filter: {ID: ration.ID},
+                        update: {$set: {labourPrice: ration.labourPrice, materialPrice: ration.materialPrice, machinePrice: ration.machinePrice, basePrice: ration.basePrice}}
+                    }
+                });
+            }
+            if(task.length > 0){
+                await rationItemModel.bulkWrite(task);
+            }
+            res.json({error: 0, message: 'success', data: null});
+        }
+        catch (err){
+            res.json({error: 1, message: err, data: null});
+        }
     }
 
 }

+ 120 - 18
modules/ration_repository/models/ration_item.js

@@ -320,6 +320,19 @@ rationItemDAO.prototype.updateRationBasePrc = function (basePrcArr, callback) {
                                     if(theGlj.gljType > 300 && theGlj.gljType < 400){
                                         gljParentType = 3;
                                     }
+                                    //管理费
+                                    if(theGlj.gljType === 6){
+                                        gljParentType = 6;
+                                    }
+                                    //利润
+                                    if(theGlj.gljType === 7){
+                                        gljParentType = 7;
+                                    }
+                                    //风险费
+                                    if(theGlj.gljType === 8){
+                                        gljParentType = 8;
+                                    }
+                                    if(theGlj)
                                     if(theGlj.ID === adjGljId){
                                         gljArr.push({gljId: theGlj.ID, basePrice: adjBasePrice, gljParentType: gljParentType});
                                     }
@@ -336,7 +349,14 @@ rationItemDAO.prototype.updateRationBasePrc = function (basePrcArr, callback) {
                                 })
                             });
                             //recalculate the price of ration
-                            let labourPrc = [], materialPrc = [], machinePrc = [], singlePrc, updatePrc = {labourPrice: 0, materialPrice: 0, machinePrice: 0, basePrice: 0};
+                            let labourPrc = [],
+                                materialPrc = [],
+                                machinePrc = [],
+                                managePrc = [],
+                                profitPrc = [],
+                                riskPrc = [],
+                                singlePrc,
+                                updatePrc = {labourPrice: 0, materialPrice: 0, machinePrice: 0, managePrice: 0, profitPrice: 0, riskPrice: 0, basePrice: 0};
                             gljArr.forEach(function (gljItem) {
                                 if(gljItem.gljParentType !== -1){
                                     singlePrc = scMathUtil.roundTo(gljItem.basePrice * gljItem.consumeAmt, -3);
@@ -346,9 +366,18 @@ rationItemDAO.prototype.updateRationBasePrc = function (basePrcArr, callback) {
                                     else if(gljItem.gljParentType ===2){
                                         materialPrc.push(singlePrc);
                                     }
-                                    else{
+                                    else if(gljItem.gljParentType === 3){
                                         machinePrc.push(singlePrc);
                                     }
+                                    else if(gljItem.gljParentType === 6){
+                                        managePrc.push(singlePrc);
+                                    }
+                                    else if(gljItem.gljParentType === 7){
+                                        profitPrc.push(singlePrc);
+                                    }
+                                    else if(gljItem.gljParentType === 8){
+                                        riskPrc.push(singlePrc);
+                                    }
                                 }
                             });
                             if(labourPrc.length > 0){
@@ -372,7 +401,29 @@ rationItemDAO.prototype.updateRationBasePrc = function (basePrcArr, callback) {
                                 }
                                 updatePrc.machinePrice = scMathUtil.roundTo(sumMaP, -2);
                             }
-                            updatePrc.basePrice = scMathUtil.roundTo(updatePrc.labourPrice + updatePrc.materialPrice + updatePrc.machinePrice, -2);
+                            if(managePrc.length > 0){
+                                let sumMgP = 0;
+                                for(let i =0; i< managePrc.length; i++){
+                                    sumMgP = scMathUtil.roundTo(sumMgP + managePrc[i], processDecimal);
+                                }
+                                updatePrc.managePrice = scMathUtil.roundTo(sumMgP, -2);
+                            }
+                            if(profitPrc.length > 0){
+                                let sumPfP = 0;
+                                for(let i =0; i< profitPrc.length; i++){
+                                    sumPfP = scMathUtil.roundTo(sumPfP + profitPrc[i], processDecimal);
+                                }
+                                updatePrc.profitPrice = scMathUtil.roundTo(sumPfP, -2);
+                            }
+                            if(riskPrc.length > 0){
+                                let sumRkP = 0;
+                                for(let i =0; i< riskPrc.length; i++){
+                                    sumRkP = scMathUtil.roundTo(sumRkP + riskPrc[i], processDecimal);
+                                }
+                                updatePrc.riskPrice = scMathUtil.roundTo(sumRkP, -2);
+                            }
+                            updatePrc.basePrice = scMathUtil.roundTo(
+                                updatePrc.labourPrice + updatePrc.materialPrice + updatePrc.machinePrice + updatePrc.managePrice + updatePrc.profitPrice + updatePrc.riskPrice, -2);
                             let task = {
                                 updateOne: {
                                     filter: {
@@ -525,8 +576,14 @@ rationItemDAO.prototype.updateAnnotation = function (lastOpr, repId, updateArr,
 rationItemDAO.prototype.calcForRation = function (stdGljList, ration) {
     const processDecimal = -6;
     //根据工料机类型划分价格
-    const labour = [1],  material = [201, 202, 203, 204, 205, 206], machine = [301, 302, 303];
-    let labourPrc = [], materialPrc = [], machinePrc = [], singlePrc, updatePrc = {labourPrice: 0, materialPrice: 0, machinePrice: 0, basePrice: 0};
+    const labour = [1],
+        material = [201, 202, 203, 204, 205, 206],
+        machine = [301, 302, 303],
+        manage = [6],
+        profit = [7],
+        risk = [8];
+    let labourPrc = [], materialPrc = [], machinePrc = [], managePrc = [], profitPrc = [], riskPrc = [],
+        singlePrc, updatePrc = {labourPrice: 0, materialPrice: 0, machinePrice: 0, basePrice: 0, managePrice: 0, profitPrice: 0, riskPrice: 0};
     let rationGljList = ration.rationGljList;
     for(let rationGlj of rationGljList){
         let glj = stdGljList[rationGlj.gljId];
@@ -542,6 +599,15 @@ rationItemDAO.prototype.calcForRation = function (stdGljList, ration) {
             else if(prcType === 'machine'){
                 machinePrc.push(singlePrc);
             }
+            else if(prcType === 'manage'){
+                managePrc.push(singlePrc);
+            }
+            else if(prcType === 'profit'){
+                profitPrc.push(singlePrc);
+            }
+            else if(prcType === 'risk'){
+                riskPrc.push(singlePrc);
+            }
         }
     }
     //计算人工费
@@ -568,8 +634,33 @@ rationItemDAO.prototype.calcForRation = function (stdGljList, ration) {
         }
         updatePrc.machinePrice = scMathUtil.roundTo(sumMaP, -2);
     }
+    //管理费
+    if(managePrc.length > 0){
+        let sumMgP = 0;
+        for(let i = 0, len  = managePrc.length; i < len; i++){
+            sumMgP = scMathUtil.roundTo(sumMgP + managePrc[i], processDecimal);
+        }
+        updatePrc.managePrice = scMathUtil.roundTo(sumMgP, -2);
+    }
+    //利润
+    if(profitPrc.length > 0){
+        let sumPfP = 0;
+        for(let i = 0, len  = profitPrc.length; i < len; i++){
+            sumPfP = scMathUtil.roundTo(sumPfP + profitPrc[i], processDecimal);
+        }
+        updatePrc.profitPrice = scMathUtil.roundTo(sumPfP, -2);
+    }
+    //风险费
+    if(riskPrc.length > 0){
+        let sumRkP = 0;
+        for(let i = 0, len  = riskPrc.length; i < len; i++){
+            sumRkP = scMathUtil.roundTo(sumRkP + riskPrc[i], processDecimal);
+        }
+        updatePrc.riskPrice = scMathUtil.roundTo(sumRkP, -2);
+    }
     //基价
-    updatePrc.basePrice = scMathUtil.roundTo(updatePrc.labourPrice + updatePrc.materialPrice + updatePrc.machinePrice, -2);
+    updatePrc.basePrice = scMathUtil.roundTo(
+        updatePrc.labourPrice + updatePrc.materialPrice + updatePrc.machinePrice + updatePrc.managePrice + updatePrc.profitPrice + updatePrc.riskPrice, -2);
     //更新定额数据
     ration.labourPrice = updatePrc.labourPrice.toString();
     ration.materialPrice = updatePrc.materialPrice.toString();
@@ -581,15 +672,24 @@ rationItemDAO.prototype.calcForRation = function (stdGljList, ration) {
     }
     //是否属于人工、材料、机械类型
     function getParentType(type){
-        if(labour.indexOf(type) !== -1){
+        if(labour.includes(type)){
             return 'labour';
         }
-        if(material.indexOf(type) !== -1){
+        if(material.includes(type)){
             return 'material';
         }
-        if(machine.indexOf(type) !== -1){
+        if(machine.includes(type)){
             return 'machine';
         }
+        if(manage.includes(type)){
+            return 'manage';
+        }
+        if(profit.includes(type)){
+            return 'profit';
+        }
+        if(risk.includes(type)){
+            return 'risk'
+        }
         return null;
     }
 
@@ -778,24 +878,26 @@ rationItemDAO.prototype.batchUpdateSectionIdFromExcel = async function(data) {
         return false;
     }
     // 批量执行update
-    const bulk = rationItemModel.collection.initializeOrderedBulkOp();
+    let bulkOprs = [];
     for (const tmp of data) {
         let rationId = parseInt(tmp[2]);
         rationId = isNaN(rationId) || rationId <= 0 ? 0 : rationId;
         let sectionId = parseInt(tmp[0]);
         sectionId = isNaN(sectionId) || sectionId <= 0 ? 0 : sectionId;
         // 取费专业
-        let feeType = parseInt(tmp[1]);
-        feeType = isNaN(feeType) || feeType <= 0 ? 0 : feeType;
-        if (sectionId <= 0 || rationId <= 0 || feeType <= 0) {
+        let feeType = tmp[1] ? parseInt(tmp[1]) : null;
+        feeType = isNaN(feeType) || feeType <= 0 ? null : feeType;
+        let name = tmp[4];
+        name = name ? name : '';
+        if (sectionId <= 0 || rationId <= 0) {
             continue;
         }
-
-        bulk.find({"ID": rationId}).update({$set: { sectionId: sectionId, feeType: feeType }});
+        bulkOprs.push({updateOne: {filter: {ID: rationId}, update: {$set: {sectionId: sectionId, feeType: feeType, name: name, caption: name}}}});
     }
-
-    const result = await bulk.execute();
-    return result.isOk();
+    if(bulkOprs.length <= 0){
+        throw '无有效数据(树ID、定额ID不为空、且为数值)';
+    }
+    await rationItemModel.bulkWrite(bulkOprs);
 };
 
 module.exports = new rationItemDAO();

+ 1 - 0
modules/ration_repository/routes/ration_rep_routes.js

@@ -84,6 +84,7 @@ module.exports =  function (app) {
     apiRouter.post('/getRationItem',searchController.auth, searchController.init, searchController.getRationItem);
     apiRouter.post('/findRation', searchController.auth, searchController.init, searchController.findRation);
 
+    apiRouter.post('/reCalcAll', rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.reCalcAll);
     // 导入导出定额库相关
     apiRouter.post('/upload', rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.uploadSourceData);
     apiRouter.get('/export', rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.exportRationData);

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

@@ -37,16 +37,16 @@ async function getCompilationList() {
 }
 
 async function getComBillsLibInfo() {
-    let rst = [];
+    let rst = {compilationList: [], billsLibs: []};
     let compilationList = await getCompilationList();
     if(compilationList.length <= 0){
         throw '没有数据';
     }
     else{
         for(let compilation of compilationList){
-            let billsLibs = await billsLibModel.find({compilationId: compilation._id, deleted: false}, '-_id billsLibId billsLibName');
-            rst.push({_id: compilation._id, name: compilation.name, billsLibs: billsLibs});
+            rst.compilationList.push({_id: compilation._id, name: compilation.name});
         }
+        rst.billsLibs = await billsLibModel.find({deleted: false}, '-_id billsLibId billsLibName');
         return rst;
     }
 }

+ 27 - 1
modules/std_glj_lib/controllers/gljController.js

@@ -1,11 +1,14 @@
 /**
  * Created by Zhong on 2017/8/11.
  */
-
+import mongoose from 'mongoose';
 import BaseController from "../../common/base/base_controller";
 import stdgljutil  from "../../../public/cache/std_glj_type_util";
 import GljDao from "../models/gljModel";
 import rationItemDao from "../../ration_repository/models/ration_item";
+const multiparty = require("multiparty");
+const LZString = require('lz-string');
+const gljModel = mongoose.model('std_glj_lib_gljList');
 
 let gljDao = new GljDao();
 let callback = function(req, res, err, message, data){
@@ -117,6 +120,29 @@ class GljController extends BaseController{
             callback(req, res, err, message, rst);
         })
     }
+    async batchUpdateComponent(req, res){
+        const form = new multiparty.Form();
+        form.parse(req, async function(err, fields, files) {
+            try{
+                let compressData = fields.compressData !== undefined && fields.compressData.length > 0 ? fields.compressData[0] : null;
+                if(!compressData){
+                    throw '数据错误';
+                }
+                let updateDatas = JSON.parse(LZString.decompressFromUTF16(compressData));
+                let bulkArr = [];
+                for(let uData of updateDatas){
+                    bulkArr.push({updateOne: {filter: {ID: uData.ID}, update: {$set: {component: uData.component, basePrice: uData.basePrice}}}});
+                }
+                if(bulkArr.length > 0){
+                    await gljModel.bulkWrite(bulkArr);
+                }
+                res.json({err: 0, data: null, msg: 'success'});
+            }
+            catch (err){
+                res.json({err: 1, data: null, msg: err});
+            }
+        });
+    }
     mixUpdateGljItems(req, res){
         let repId = req.body.repositoryId,
             updateItems = JSON.parse(req.body.updateItems),

+ 13 - 2
modules/std_glj_lib/controllers/viewsController.js

@@ -4,6 +4,9 @@
  */
 
 import BaseController from "../../common/base/base_controller";
+import mongoose from 'mongoose';
+const compilationModel = mongoose.model('compilation');
+const stdGljLibModel = mongoose.model('std_glj_lib_map');
 let config = require("../../../config/config.js");
 class ViewsController extends BaseController{
     redirectMain(req, res){
@@ -12,11 +15,19 @@ class ViewsController extends BaseController{
             userAccount: req.session.managerData.username
         });
     }
-    redirectGlj(req, res){
+    async redirectGlj(req, res){
+        let overWriteUrl = null;
+        let stdGljLib = await stdGljLibModel.findOne({ID: req.query.gljLibId, deleted: false});
+        if(stdGljLib){
+           let compilation = await compilationModel.findOne({_id: mongoose.Types.ObjectId(stdGljLib.compilationId)});
+           overWriteUrl = stdGljLib.compilationId === '5b4d581023a924000b760f2d' ? null : compilation.overWriteUrl;
+           console.log(overWriteUrl);
+        }
         res.render('maintain/std_glj_lib/html/gongliao.html',
         {
             userAccount: req.session.managerData.username,
-            LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
+            LicenseKey:config.getLicenseKey(process.env.NODE_ENV),
+            overWriteUrl: overWriteUrl
         });
     }
 }

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

@@ -34,6 +34,7 @@ module.exports = function (app) {
     router.post("/getGljTree",gljController.auth, gljController.init, gljController.getGljTree);
     router.post("/getGljItems",gljController.auth, gljController.init, gljController.getGljItems);
     router.post("/updateComponent",gljController.auth, gljController.init, gljController.updateComponent);
+    router.post("/batchUpdateComponent",gljController.auth, gljController.init, gljController.batchUpdateComponent);
     router.post("/mixUpdateGljItems",gljController.auth, gljController.init, gljController.mixUpdateGljItems);
     router.post("/getGljItemsByIds",gljController.auth, gljController.init, gljController.getGljItemsByIds);
     router.post("/getGljItemsByCodes",gljController.auth, gljController.init, gljController.getGljItemsByCodes);

+ 42 - 6
modules/users/controllers/compilation_controller.js

@@ -100,10 +100,10 @@ class CompilationController extends BaseController {
             if (!valuationId) {
                 throw '新增计价规则失败';
             }
-            //添加标准工程专业
-            let engineeringLibModel = new EngineeringLibModel();
+            //添加标准工程专业  2018-08-24 不自动添加标准工程了
+            /*let engineeringLibModel = new EngineeringLibModel();
             let stdEngs = await engineeringLibModel.addStdLib(valuationId);
-            console.log(stdEngs);
+            console.log(stdEngs);*/
         } catch (error) {
             console.log(error);
             responseData.err = 1;
@@ -181,9 +181,9 @@ class CompilationController extends BaseController {
             let compilationModel = new CompilationModel();
             compilationList = await compilationModel.getCompilationList();
 
-            // 获取标准清单
+            // 获取标准清单,不绑定编办
             let stdBillLibListsModel = new STDBillLibListsModel();
-            billList = await stdBillLibListsModel.getBillList(selectedCompilation._id);
+            billList = await stdBillLibListsModel.getBillList();
 
             // 获取定额库
             let stdRationLibMapModel = new STDRationLibMapModel();
@@ -285,9 +285,35 @@ class CompilationController extends BaseController {
         response.redirect(request.headers.referer);
     }
 
+    /**
+     * 通过工程专业ID删除工程专业
+     * @param request
+     * @param response
+     * @returns {Promise.<void>}
+     */
+    async deleteEngineer(request,response){
+        let result={
+            error:0
+        };
+        try {
+            let data = request.body.data;
+            data = JSON.parse(data);
+            if(data.id ){
+                let engineeringLibModel = new EngineeringLibModel();
+                result.data = await engineeringLibModel.deleteById(data.id,true);
+            }else {
+                throw new Error("提交数据有误");
+            }
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
 
     /**
-     * 保存工程专业信息-用于异步操作
+     * 修改保存工程专业信息-用于异步操作
      * @param request
      * @param response
      * @returns {Promise.<void>}
@@ -576,6 +602,16 @@ class CompilationController extends BaseController {
         }
     }
 
+    async addEngineer(request,response){
+        let engineeringLibModel = new EngineeringLibModel();
+        try {
+            await engineeringLibModel.addEngineer(request.body);
+        }catch (error) {
+            console.log(error);
+        }
+        response.redirect(request.headers.referer);
+    }
+
 }
 
 export default CompilationController;

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

@@ -58,6 +58,7 @@ class LoginController extends BaseController {
                 .digest().toString('base64');
             let managerSession = {
                 username: managerData.username,
+                real_name:managerData.real_name,
                 loginTime: currentTime,
                 sessionToken: sessionToken,
                 userID: managerData.id,

+ 128 - 2
modules/users/controllers/user_controller.js

@@ -10,6 +10,7 @@ import UserModel from "../models/user_model";
 import Config from "../../../config/config";
 import CompilationModel from "../models/compilation_model";
 let config = require("../../../config/config.js");
+let _ = require("lodash");
 
 class UserController extends BaseController {
 
@@ -26,15 +27,84 @@ class UserController extends BaseController {
         let pageData = {};
         let userList = [];
         let compilationList =[];
+        let compilationString ='';
+        let compilationMap = {};
         let filter = request.query;
         try {
             //获取编办列表
             let  compilationModel = new CompilationModel();
-            compilationList = await compilationModel.getCompilationList();
+            compilationList = await compilationModel.getCompilationList({_id: 1, name: 1, is_release: 1});
+            compilationString = JSON.stringify(compilationList);
+            compilationMap = _.indexBy(compilationList,'_id');
+            let condition = userModel.getFilterCondition(request);
+            //设置搜索普通用户:
+            condition.user_type = 'normal';
+
+            //获取注册时间
+            let regtime = request.query.regtime;
+            if(regtime !== '' && regtime !== undefined){
+                filter.regtimeMsg = userModel.getDayMsg(regtime);
+            }
 
+            //获取注册时间
+            let loginTime = request.query.loginTime;
+            if(loginTime !== '' && loginTime !== undefined){
+                filter.loginMsg = userModel.getDayMsg(loginTime);
+            }
 
+            // 获取用户总数
+            total = await userModel.count(condition);
 
+            // 分页数据
+            let page = request.query.page === undefined ? 1 : request.query.page;
+            pageData = {
+                current: page,
+                total: Math.ceil(total / Config.pageSize),
+                queryData: response.locals.urlQuery
+            };
+
+            // 获取用户列表
+            userList = await userModel.getList(condition, page, Config.pageSize);
+        } catch (error) {
+            console.log(error);
+        }
+
+        // 渲染数据
+        let renderData = {
+            compilationList:compilationList,
+            compilationString:compilationString,
+            compilationMap:compilationMap,
+            adminName:request.session.managerData?request.session.managerData.real_name:'',
+            userList: userList,
+            pages: pageData,
+            total: total,
+            filter: filter,
+            model: userModel,
+            layout: 'users/views/layout/layout',
+            LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
+        };
+        response.render('users/views/user/index', renderData);
+    }
+
+
+    async testUsers(request,response){
+        let userModel = new UserModel();
+        let total = 0;
+        let pageData = {};
+        let userList = [];
+        let compilationList =[];
+        let compilationString ='';
+        let compilationMap = {};
+        let filter = request.query;
+        try {
+            //获取编办列表
+            let  compilationModel = new CompilationModel();
+            compilationList = await compilationModel.getCompilationList({_id: 1, name: 1, is_release: 1});
+            compilationString = JSON.stringify(compilationList);
+            compilationMap = _.indexBy(compilationList,'_id');
             let condition = userModel.getFilterCondition(request);
+            //设置搜索普通用户:
+            condition.user_type = 'normal';
 
             //获取注册时间
             let regtime = request.query.regtime;
@@ -42,6 +112,12 @@ class UserController extends BaseController {
                 filter.regtimeMsg = userModel.getDayMsg(regtime);
             }
 
+            //获取注册时间
+            let loginTime = request.query.loginTime;
+            if(loginTime !== '' && loginTime !== undefined){
+                filter.loginMsg = userModel.getDayMsg(loginTime);
+            }
+
             // 获取用户总数
             total = await userModel.count(condition);
 
@@ -62,6 +138,9 @@ class UserController extends BaseController {
         // 渲染数据
         let renderData = {
             compilationList:compilationList,
+            compilationString:compilationString,
+            compilationMap:compilationMap,
+            adminName:request.session.managerData?request.session.managerData.real_name:'',
             userList: userList,
             pages: pageData,
             total: total,
@@ -70,7 +149,7 @@ class UserController extends BaseController {
             layout: 'users/views/layout/layout',
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
         };
-        response.render('users/views/user/index', renderData);
+        response.render('users/views/user/test_user', renderData);
     }
 
 
@@ -105,6 +184,53 @@ class UserController extends BaseController {
         response.json(responseData);
     }
 
+    async findByID(request, response) {
+        let params = JSON.parse(request.body.data),
+            userIds = params.ID;
+        let userModel = new UserModel();
+        let responseData = {
+            error: 0,
+            msg: '',
+            data: null
+        };
+        try{
+            if(userIds === undefined || userIds === '') {
+                throw { code: 1, err: '参数有误或为空'};
+            }
+            let user = await userModel.getByID({ _id: userIds});
+            responseData.data = user;
+        } catch (error) {
+            console.log(error);
+            responseData.error = error.code;
+            responseData.msg = error.err;
+        }
+        response.json(responseData);
+    }
+
+
+    async updateUser(request, response) {
+        let data = JSON.parse(request.body.data);
+        let userModel = new UserModel();
+        let responseData = {
+            error: 0,
+            msg: '',
+            data: null
+        };
+        try{
+            if(data.ID === undefined || data.ID === '') {
+                throw { code: 1, err: '参数有误或为空'};
+            }
+            let user = await userModel.updateById(data.ID,data.updateData);
+            responseData.data = user;
+        } catch (error) {
+            console.log(error);
+            responseData.error = error.code;
+            responseData.msg = error.err;
+        }
+        response.json(responseData);
+    }
+
+
     /**
      * 根据用户id列表获取用户信息列表 json
      *

+ 3 - 3
modules/users/models/compilation_model.js

@@ -34,10 +34,10 @@ class CompilationModel extends BaseModel {
      *
      * @return {Promise}
      */
-    async getCompilationList() {
+    async getCompilationList(fields = null) {
         // 筛选字段
-        let field = {_id: 1, name: 1, is_release: 1, description: 1,overWriteUrl: 1, "ration_valuation.id": 1, "ration_valuation.name": 1, "ration_valuation.enable": 1,
-            "bill_valuation.id": 1, "bill_valuation.name": 1, "bill_valuation.enable": 1};
+        let field = fields == null ?{_id: 1, name: 1, is_release: 1, description: 1,overWriteUrl: 1, "ration_valuation.id": 1, "ration_valuation.name": 1, "ration_valuation.enable": 1,
+            "bill_valuation.id": 1, "bill_valuation.name": 1, "bill_valuation.enable": 1}:fields;
         let compilationData = await this.findDataByCondition({name: {$ne: ''}}, field, false);
 
         return compilationData === null ? [] : compilationData;

+ 6 - 0
modules/users/models/engineering_lib_model.js

@@ -77,6 +77,11 @@ class EngineeringLibModel extends BaseModel {
         return result;
     }
 
+    async addEngineer(data){
+        data.glj_col = {showAdjustPrice:false};
+        let result = await this.db.create(data);
+        return result;
+    }
 
     /**
      * 新增标准库
@@ -89,6 +94,7 @@ class EngineeringLibModel extends BaseModel {
         if(data.glj_col){
             data.glj_col =  JSON.parse(data.glj_col);
         }
+        data.isInstall == 'true'?data.isInstall=true:data.isInstall=false;
         let result = false;
         data = this.filterLibData(data);
         try {

+ 46 - 3
modules/users/models/user_model.js

@@ -6,6 +6,7 @@
  * @version
  */
 import mongoose from "mongoose";
+import Moment from "moment";
 import BaseModel from "../../common/base/base_model";
 
 class UserModel extends BaseModel {
@@ -15,21 +16,24 @@ class UserModel extends BaseModel {
      *
      * @var {object}
      */
-    province = ['广东省', '北京市'];
+    province = ['北京', '天津', '河北', '山西', '内蒙古', '辽宁', '吉林', '黑龙江', '上海', '江苏', '浙江', '安徽',
+        '福建', '江西', '山东', '河南', '湖北', '湖南', '广东', '广西', '海南', '重庆', '四川', '贵州', '云南', '西藏',
+        '陕西', '甘肃', '青海', '宁夏', '新疆', '台湾', '香港', '澳门',];
 
     /**
      * 企业类型
      *
      * @var
      */
-    companyType = ['设计', '施工'];
+    companyType = ['建设单位', '设计单位',  '施工单位', '监理单位', '审核单位', '咨询公司', '招标代理', '住建部', '财政', '审计',
+        '造价管理站', '学校', '个人', '其他'];
 
     /**
      * 企业规模
      *
      * @var
      */
-    companyScale = ['1-20', '20-50', '50-100', '100+'];
+    companyScale = ['1-50', '50-100', '100-500', '500+'];
 
     /**
      * 最近天数
@@ -50,6 +54,27 @@ class UserModel extends BaseModel {
     }
 
     /**
+     * 获取用户信息
+     *
+     * @param {object} condition
+     * @param {number} page
+     * @param {Number} pageSize
+     * @return {promise}
+     */
+    async getByID(condition) {
+        let user = await this.db.findOne(condition);
+        //企业所在省份、类型、规模等转换
+        if(this.isDef(user.province)) user._doc.province = this.province[user.province];
+        if(this.isDef(user.company_type)) user._doc.company_type = this.companyType[user.company_type];
+        if(this.isDef(user.company_scale)) user._doc.company_scale = this.companyScale[user.company_scale];
+        if(this.isDef(user.create_time)) user._doc.create_time = Moment(user.create_time).format('YYYY-MM-DD HH:mm:ss');
+        if(this.isDef(user.last_login)) user._doc.last_login = Moment(user.last_login).format('YYYY-MM-DD HH:mm:ss');
+        return user;
+    }
+
+
+
+    /**
      * 获取列表
      *
      * @param {object} condition
@@ -81,10 +106,28 @@ class UserModel extends BaseModel {
             condition.create_time = this.getTimestamp(regtime);
         }
 
+        //最近登录时间
+        let loginTime = request.query.loginTime;
+        loginTime = loginTime !== '' && loginTime !== undefined ? parseInt(loginTime) : 0;
+        if (loginTime !== 0) {
+            condition.latest_login = this.getTimestamp(loginTime);
+        }
+
         let version = request.query.version;
         if(version !== '' && version !== undefined) {
             condition.version = version;
         }
+        // 已升级费用定额
+        let upGrade = request.query.upGrade;
+        if(upGrade !== '' && upGrade !== undefined){
+            condition.upgrade_list = {"$elemMatch":{"compilationID":upGrade,"isUpgrade":true}};
+        }
+
+        // 最近使用费用定额
+        let latestUsed = request.query.latestUsed;
+        if(latestUsed !== '' && latestUsed !== undefined){
+            condition.latest_used = latestUsed;
+        }
 
         let keyword = request.query.keyword;
         if (keyword !== '' && keyword !== undefined) {

+ 2 - 0
modules/users/routes/compilation_route.js

@@ -26,9 +26,11 @@ module.exports = function (app) {
     router.post('/add-valuation', compilationController.auth, compilationController.init, compilationController.addValuation);
     router.post('/save-valuation', compilationController.auth, compilationController.init, compilationController.saveValuation);
     router.post('/update-engineer', compilationController.auth, compilationController.init, compilationController.updateEngineer);
+    router.post('/delete-engineer', compilationController.auth, compilationController.init, compilationController.deleteEngineer);
     router.post('/save-lib', compilationController.auth, compilationController.init, compilationController.saveEngineering);
     router.post('/valuation/:section/enable', compilationController.auth, compilationController.init, compilationController.enableSwitch);
     router.post('/template/:section/:id/:engineering/update', compilationController.auth, compilationController.init, compilationController.updateBillsTemplate);
+    router.post('/addEngineer', compilationController.auth, compilationController.init, compilationController.addEngineer);
 
     app.use("/compilation", router);
 };

+ 3 - 0
modules/users/routes/user_route.js

@@ -14,7 +14,10 @@ const userController = new UserController();
 module.exports =function (app) {
     // action定义区域
     router.get('/', userController.auth, userController.init, userController.normalUsers);
+    router.get('/test-user', userController.auth, userController.init, userController.testUsers);
     router.get('/search', userController.auth, userController.init, userController.search);
+    router.post('/findByID', userController.auth, userController.init, userController.findByID);
     router.post('/getUserList', userController.auth, userController.init, userController.getUserList);
+    router.post('/updateUser', userController.auth, userController.init, userController.updateUser);
     app.use("/user", router);
 };

+ 2 - 1
package.json

@@ -31,7 +31,8 @@
     "node-xlsx": "^0.11.2",
     "pdfkit": "^0.8.2",
     "ueditor": "^1.2.3",
-    "node-schedule": "^1.3.0"
+    "node-schedule": "^1.3.0",
+    "lz-string": "^1.4.4"
   },
   "scripts": {
     "start": "C:\\Users\\mai\\AppData\\Roaming\\npm\\babel-node.cmd operation.js"

+ 177 - 0
public/scHintBox.html

@@ -0,0 +1,177 @@
+<!----------------------------------------------------------------------------------------------------------------------
+    chenshilong, 2018-04-29
+    自定义对话框,通用,用于替代系统对话框。系统自带的比较简陋,最严重的是一旦被浏览器屏蔽则无法再弹出。
+    自定义对话框包括:
+        1、只有一个按钮的信息提示框。
+        2、有两个按钮的操作确认询问框。
+        3、有三个按钮的多分支选择询问框。
+        4、输入文本值对话框。
+   使用示例:ConstructionCost/test/public/test_Box.html (直接运行该文件查看效果)
+----------------------------------------------------------------------------------------------------------------------->
+<div class="modal fade" id="hintBox_form" data-backdrop="static" style="z-index: 9999">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 id="hintBox_title" class="modal-title">标题</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close" id="hintBox_btn_cross">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+
+            <div class="modal-body">
+                <div id = "hintBox_caption" style="margin:5px 10px 10px 10px;">提示明细</div>
+                <div style="margin:5px 10px 5px 10px;">
+                    <input id="hintBox_value" type="text" class="form-control" value="" />
+                    <p id="hintBox_error" style="margin-top:7px; color:red; display:none;">“xxx”已存在!</p>
+                </div>
+            </div>
+
+            <div class="modal-footer" style="justify-content: center">
+                <button type="button" class="btn btn-primary" data-dismiss="modal" id="hintBox_btn_yes">是</button>
+                <button type="button" class="btn btn-primary" data-dismiss="modal" id="hintBox_btn_no">否</button>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal" id="hintBox_btn_cancel">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
+<div class="modal" id="waitBox_form" style="z-index: 9999; cursor: wait"></div>
+
+<script>
+    const hintBox = {
+        value: null,
+        btnType: {yes: 1, yesNo: 2, yesNoCancel: 3},
+        defalultEvent: function () {
+            $.bootstrapLoading.end();
+//            alert('defalultEvent');
+            return;
+        },
+        init: function (){
+            // 事件类
+            $("#hintBox_value").unbind();
+            $("#hintBox_btn_yes").unbind();
+            $('#hintBox_btn_no').unbind();
+            $('#hintBox_btn_cancel').unbind();
+
+            $("#hintBox_value").keyup(
+                function (event) {
+                    hintBox.value = $('#hintBox_value').val();
+                    if (event.keyCode === 13) {
+                        $('#hintBox_btn_yes').click();
+                        return false;
+                    }
+                }
+            );
+            $('#hintBox_btn_cancel').click(
+                hintBox.defalultEvent
+            );
+
+            // 显示类
+            $('#hintBox_caption').hide();
+            $('#hintBox_value').hide();
+            $('#hintBox_error').hide();
+            $('#hintBox_btn_yes').hide();
+            $('#hintBox_btn_no').hide();
+            $('#hintBox_btn_cancel').hide();
+            $('#hintBox_btn_cross').show();
+        },
+        font: function(str){
+            return `<span style='color:red;font-weight:bold;font-size:15px'> ${str} </span>`;
+        },
+        error: function (err) {   // 注意:该方法只能用在valueBox()的doOK回调函数中。
+            $('#hintBox_error').text(err);
+            $('#hintBox_error').show(200);
+            $("#hintBox_value").focus();
+            $("#hintBox_value").select();
+        },
+        infoBox: function (title, caption, btnType,
+                           doYes, doNo = hintBox.defalultEvent,
+                           btnTextArr = null, showCrossBtn = true) {
+            this.init();
+            if (!showCrossBtn)
+                $('#hintBox_btn_cross').hide();
+            $('#hintBox_title').text(title);
+            $('#hintBox_caption').html(caption);
+            $('#hintBox_caption').show();
+
+            switch (btnType) {
+                case this.btnType.yes:
+                    if (btnTextArr){
+                        $('#hintBox_btn_yes').text(btnTextArr[0]);
+                    }else
+                        $('#hintBox_btn_yes').text('确定');
+
+                    $('#hintBox_btn_yes').show();
+                    break;
+                case this.btnType.yesNo:
+                    if (btnTextArr){
+                        $('#hintBox_btn_yes').text(btnTextArr[0]);
+                        $('#hintBox_btn_no').text(btnTextArr[1]);
+                    }else{
+                        $('#hintBox_btn_yes').text('是');
+                        $('#hintBox_btn_no').text('否');
+                    }
+
+                    $('#hintBox_btn_yes').show();
+                    $('#hintBox_btn_no').show();
+                    break;
+                case this.btnType.yesNoCancel:
+                    if (btnTextArr){
+                        $('#hintBox_btn_yes').text(btnTextArr[0]);
+                        $('#hintBox_btn_no').text(btnTextArr[1]);
+                        $('#hintBox_btn_cancel').text(btnTextArr[2]);
+                    }else{
+                        $('#hintBox_btn_yes').text('是');
+                        $('#hintBox_btn_no').text('否');
+                        $('#hintBox_btn_cancel').text('取消');
+                    }
+
+                    $('#hintBox_btn_yes').show();
+                    $('#hintBox_btn_no').show();
+                    $('#hintBox_btn_cancel').show();
+                    break;
+            }
+
+            if (doYes){
+                $('#hintBox_btn_yes').click(doYes);
+            }
+
+            if (doNo){
+                $('#hintBox_btn_no').click(doNo);
+            }
+
+            $("#hintBox_form").modal('show');
+
+        },
+        valueBox: function (title, value, doOK) {
+            this.init();
+            $('#hintBox_title').text(title);
+            this.value = value;
+            $('#hintBox_value').show();
+            $('#hintBox_value').val(value);
+            $("#hintBox_value").focus();
+            $("#hintBox_value").select();
+
+            $('#hintBox_btn_yes').text('确定');
+            $('#hintBox_btn_yes').show();
+            $('#hintBox_btn_yes').click(doOK);   // doOK不能给参数
+
+            $('#hintBox_btn_no').text('取消');
+            $('#hintBox_btn_no').show();
+            $('#hintBox_btn_no').click(hintBox.defalultEvent);
+
+            $("#hintBox_form").modal('show');
+        },
+        waitBox: function () {
+            $(`#waitBox_form`).modal({'backdrop': false});
+        },
+        unWaitBox: function () {
+            $('#waitBox_form').modal('hide');
+        }
+    };
+
+    $('#hintBox_form').on('hide.bs.modal', function() {
+        if($.bootstrapLoading) $.bootstrapLoading.end();
+        return;
+    });
+</script>
+

+ 24 - 0
public/web/commonAlert.js

@@ -0,0 +1,24 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/6/15
+ * @version
+ */
+
+window.alert = function(str) {
+    /*$('#commonAlert').find('p').text(str);
+     $('#commonAlert').modal('show');*/
+    hintBox.infoBox('系统提示', str, 1);
+};
+
+$(document).ready(function() {
+    !function loadHintBox(){
+        $("body").append('<div id = "hintBox_container"></div>');
+        $("#hintBox_container").load("/public/scHintBox.html");
+    }();
+
+})
+

+ 10 - 1
public/web/common_ajax.js

@@ -129,7 +129,7 @@ async function ajaxPost(url, data) {
             cache: false,
             timeout: 50000,
             success: function(result){
-                if (result.error === 0) {
+                if (result.error === 0 ||result.error ===false) {
                     resolve(result.data);
                 } else {
                     alert('error: ' + result.message);
@@ -143,4 +143,13 @@ async function ajaxPost(url, data) {
         });
 
     });
+}
+
+
+function ajaxErrorInfo(jqXHR, textStatus, errorThrown) {
+    if(textStatus == 'timeout'){
+        alert('网络连接超时,请刷新您的网页。');
+    }else {
+        alert('url: ' + url +' error ' + textStatus + " " + errorThrown);
+    }
 }

+ 84 - 23
public/web/sheet/sheet_common.js

@@ -78,8 +78,9 @@ var sheetCommonObj = {
         var me = this, ch = GC.Spread.Sheets.SheetArea.colHeader;
         for (var i = 0; i < setting.header.length; i++) {
             sheet.setValue(0, i, setting.header[i].headerName, ch);
-            sheet.setColumnWidth(i, setting.header[i].headerWidth?setting.header[i].headerWidth:100);
+            sheet.setColumnWidth(i, setting.header[i].headerWidth ? setting.header[i].headerWidth : 100);
         }
+        if(setting.headerHeight)  sheet.setRowHeight(0, setting.headerHeight, GC.Spread.Sheets.SheetArea.colHeader);
     },
     cleanData: function (sheet, setting, rowCount) {
         sheet.suspendPaint();
@@ -118,13 +119,18 @@ var sheetCommonObj = {
             area.vAlign(GC.Spread.Sheets.VerticalAlign.center);
         }
     },
-    showData: function(sheet, setting, data) {
+    showData: function(sheet, setting, data,distTypeTree) {
         var me = this, ch = GC.Spread.Sheets.SheetArea.viewport;
         sheet.suspendPaint();
         sheet.suspendEvent();
         //sheet.addRows(row, 1);
 
         sheet.clear(0, 0, sheet.getRowCount(), sheet.getColumnCount(), GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
+        if(sheet.getRowCount()<data.length){
+            data.length<30? sheet.setRowCount(30):sheet.setRowCount(data.length);
+        }else if(sheet.getRowCount()==0){
+            sheet.setRowCount(30);
+        }
         for (var col = 0; col < setting.header.length; col++) {
             var hAlign = "left", vAlign = "center";
             if (setting.header[col].hAlign) {
@@ -135,9 +141,6 @@ var sheetCommonObj = {
             vAlign = setting.header[col].vAlign?setting.header[col].vAlign:vAlign;
             me.setAreaAlign(sheet.getRange(-1, col, -1, 1), hAlign, vAlign);
             if (setting.header[col].formatter) {
-                //var style = new GC.Spread.Sheets.Style();
-                //style.formatter = setting.header[col].formatter;
-                //sheet.setStyle(row,col,style,GC.Spread.Sheets.SheetArea.viewport);
                 sheet.setFormatter(-1, col, setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
             }
             if(setting.header[col].cellType === "checkBox"||setting.header[col].cellType === "button"){//clear and reset
@@ -147,20 +150,16 @@ var sheetCommonObj = {
                 sheet.setValue(0, col, setting.header[col].headerName, header);
                 sheet.setColumnWidth(col, setting.header[col].headerWidth?setting.header[col].headerWidth:100);
             }
-            for (var row = 0; row < data.length; row++) {
-                //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
-                var val = data[row][setting.header[col].dataCode];
-                if(val&&setting.header[col].dataType === "Number"){
-                    if(setting.header[col].hasOwnProperty('tofix')){
-                        val =parseFloat(val).toFixed(setting.header[col].tofix);
-                    }else {
-                        val =parseFloat(val).toFixed(2);
-                    }
-                }
-                if(val!=null&&setting.header[col].cellType === "checkBox"){
-                    this.setCheckBoxCell(row,col,sheet,val)
-                }
-                sheet.setValue(row, col, val, ch);
+            if(setting.header[col].visible === false){
+                sheet.setColumnVisible(col,false);
+            }
+            sheet.getCell(0, col, GC.Spread.Sheets.SheetArea.colHeader).wordWrap(true);
+        }
+        for (var row = 0; row < data.length; row++) {
+            //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
+            this.showRowData(sheet,setting,row,data,distTypeTree);
+            if(setting.getStyle && setting.getStyle(data[row])){
+                sheet.setStyle(row, -1, setting.getStyle(data[row]));
             }
         }
         this.lockCells(sheet,setting);
@@ -168,6 +167,65 @@ var sheetCommonObj = {
         sheet.resumePaint();
         //me.shieldAllCells(sheet);
     },
+    showRowData:function (sheet,setting,row,data,distTypeTree=null) {
+        let ch = GC.Spread.Sheets.SheetArea.viewport;
+        for (var col = 0; col < setting.header.length; col++) {
+            //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
+            var val = data[row][setting.header[col].dataCode];
+            if(val&&setting.header[col].dataType === "Number"){
+                if(setting.header[col].hasOwnProperty('tofix')){
+                    val =scMathUtil.roundToString(val,setting.header[col].tofix);
+                } else {
+                    val =val+'';
+                }
+            }
+            if(val!=null&&setting.header[col].cellType === "checkBox"){
+                this.setCheckBoxCell(row,col,sheet,val)
+            }
+            if(setting.header[col].cellType === "comboBox"){
+                this.setComboBox(row,col,sheet,setting.header[col].options,setting.header[col].editorValueType);
+            }
+            if(setting.header[col].getText){
+                val = setting.getText[setting.header[col].getText](data[row],val)
+            }
+            sheet.setValue(row, col, val, ch);
+        }
+        this.setRowStyle(row,sheet,data[row].bgColour);
+        if(setting.autoFit==true){
+            sheet.getRange(row, -1, 1, -1, GC.Spread.Sheets.SheetArea.viewport).wordWrap(true);
+            sheet.autoFitRow(row);
+        }
+    },
+    setCheckBoxCell(row,col,sheet,val){
+        var c = new GC.Spread.Sheets.CellTypes.CheckBox();
+        c.isThreeState(false);
+        sheet.setCellType(row, col,c,GC.Spread.Sheets.SheetArea.viewport);
+        sheet.getCell(row, col).value(val);
+        sheet.getCell(row, col).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+
+    },
+    setComboBox(row,col,sheet,options,editorValueType){
+        //let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
+        let dynamicCombo = sheetCommonObj.getDynamicCombo(true);
+        if(options){
+            dynamicCombo.itemHeight(options.length).items(options);
+            if(editorValueType==true){
+                dynamicCombo.editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.value);
+            }
+        }
+        sheet.setCellType(row, col,dynamicCombo,GC.Spread.Sheets.SheetArea.viewport);
+    },
+    setRowStyle(row,sheet,bgColour) {
+        if(bgColour){
+            let style = new GC.Spread.Sheets.Style();
+            style.backColor = bgColour;
+            style.borderLeft = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+            style.borderTop = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+            style.borderRight = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+            style.borderBottom = new GC.Spread.Sheets.LineBorder("#D4D4D4", GC.Spread.Sheets.LineStyle.thin);
+            sheet.setStyle(row, -1, style);
+        }
+    },
     analyzePasteData: function(setting, pastedInfo) {
         var rst = [], propId = pastedInfo.cellRange.col, preStrIdx = 0, itemObj = {};
         for (var i = 0; i < pastedInfo.pasteData.text.length; i++) {
@@ -292,11 +350,14 @@ var sheetCommonObj = {
         let me = this;
         sheet.suspendPaint();
         let combo = me.getDynamicCombo();
+        if(itemsHeight) {
+            combo.itemHeight(itemsHeight);
+            combo._maxDropDownItems = itemsHeight + 5;
+        }
+        if(itemsType === 'value') combo.items(items).editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.value);
+        else if(itemsType === 'text') combo.items(items).editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.text);
+        else combo.items(items);
         for(let i = 0, len = rowCount; i < len; i++){
-            if(itemsHeight) combo.itemHeight(itemsHeight);
-            if(itemsType === 'value') combo.items(items).editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.value);
-            else if(itemsType === 'text') combo.items(items).editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.text);
-            else combo.items(items);
             sheet.getCell(beginRow + i, col).cellType(combo);
         }
         sheet.resumePaint();

+ 1 - 0
public/web/sheet/sheet_data_helper.js

@@ -52,6 +52,7 @@ var SheetDataHelper = {
         spread.options.cutCopyIndicatorVisible = false;
         spread.options.allowCopyPasteExcelStyle = false;
         spread.options.allowUserDragDrop = false;
+        spread.options.allowContextMenu = false;
         spread.getActiveSheet().setRowCount(3);
         return spread;
     },

+ 24 - 0
public/web/tools_const.js

@@ -0,0 +1,24 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Zhong
+ * @date 2018/8/15
+ * @version
+ */
+//允许使用的工料机类型:人工、普通材料、混凝土、砂浆、配合比、商品混凝土、商品砂浆、机械台班、机械组成物、机上人工、主材、设备
+let allowGljType = [1, 201, 202, 203, 204, 205, 206, 301, 302, 303, 4, 5];
+
+//允许含有组成物的工料机类型:混凝土、砂浆、配合比、机械台班、主材
+let allowComponent = [202, 203, 204, 301, 4];
+//可以作为组成物的工料机类型:普通材料、机械组成物、机上人工、主材
+let componentType = [201, 302, 303, 4];
+//允许含有组成物的机械工料机类型:机械台班
+let machineAllowComponent = [301];
+//可以作为机械工料机组成物的工料机类型:机械组成物、机上人工
+let machineComponent = [302, 303];
+//允许含有组成物的材料工料机类型:混凝土、砂浆、配合比
+let materialAllowComponent = [202, 203, 204];
+//可以作为材料工料机组成物的工料机类型:普通材料
+let materialComponent = [201];

+ 17 - 0
web/maintain/billsGuidance_lib/css/main.css

@@ -283,3 +283,20 @@ body {
     opacity: .65;
     color:#666
 }
+.top-content, .fluid-content {
+    overflow: auto;
+    border-bottom: 1px solid #ccc;
+    width: 100%
+}
+.top-content .main-data-top{
+    height: 370px;
+    overflow: auto;
+}
+/*.bottom-content .main-data-bottom{
+    height: 370px;
+    overflow: auto;
+}*/
+.side-search-box{
+    background:#fff;
+    border-bottom:1px solid #ddd
+}

+ 16 - 1
web/maintain/billsGuidance_lib/html/main.html

@@ -31,7 +31,7 @@
                   <div class="col-md-8">
                     <div class="warp-p2 mt-3">
                       <table class="table table-hover table-bordered">
-                        <thead><tr><th>清单指引名称</th><th>编办</th><th>清单规则</th><th width="160">添加时间</th><th width="90">操作</th></tr></thead>
+                        <thead><tr><th>清单指引名称</th><th>编办</th><th>清单规则</th><th>类型</th><th width="160">添加时间</th><th width="90">操作</th></tr></thead>
                         <tbody>
                         </tbody>
                       </table>
@@ -65,6 +65,21 @@
                       <label>清单规则</label>
                       <select id="billsLibSels" class="form-control"><option>重庆清单规则-2013</option></select>
                     </div>
+                      <div class="form-group">
+                          <label>类型</label>
+                          <div>
+                              <div class="form-check form-check-inline">
+                                  <label class="form-check-label">
+                                      <input class="form-check-input" type="radio" checked name="inlineRadioOptions" id="inlineRadio1" value="1"> 清单指引
+                                  </label>
+                              </div>
+                              <div class="form-check form-check-inline">
+                                  <label class="form-check-label">
+                                      <input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio2" value="2"> 清单精灵
+                                  </label>
+                              </div>
+                          </div>
+                      </div>
                   </form>
                 </div>
                 <div class="modal-footer">

+ 13 - 1
web/maintain/billsGuidance_lib/html/zhiyin.html

@@ -63,8 +63,20 @@
                                     <button id="insertRation" class="btn btn-primary btn-sm" type="button">插入定额</button>
                                 </div>
                             </div>
+                            <!--搜索结果窗体-->
+                            <div class="side-search-box col-12 p-0" id="rationSearchResult" style="display: none;">
+                                <div class="d-flex justify-content-between">
+                                    <span id="searchCount">搜索结果:153</span><a title="关闭搜索" class="btn btn-link btn-sm" href="javascript:void(0)"><i class="fa fa-remove" aria-hidden="true"></i></a>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="top-content" style="overflow: hidden">
+                            <div class="main-data-top" id="sectionSpread">
+                            </div>
+                        </div>
+                        <div class="bottom-content">
+                            <div class="main-data-bottom" id="rationSpread"></div>
                         </div>
-                        <div id="rationSpread" class="main-data-side-q">
                     </div>
                   </div>
                 </div>

+ 117 - 17
web/maintain/billsGuidance_lib/js/billsGuidance.js

@@ -124,11 +124,53 @@ const billsGuidance = (function () {
             }
         }
     };
+    //定额章节树
+    const section = {
+        dom: $('#sectionSpread'),
+        workBook: null,
+        cache: [],
+        tree: null,
+        controller: null,
+        treeSetting: {
+            treeCol: 0,
+            emptyRows: 0,
+            headRows: 1,
+            headRowHeight: [40],
+            defaultRowHeight: 21,
+            cols: [{
+                width: 400,
+                readOnly: true,
+                head: {
+                    titleNames: ["名称"],
+                    spanCols: [1],
+                    spanRows: [1],
+                    vAlign: [1],
+                    hAlign: [1],
+                    font: ["Arial"]
+                },
+                data: {
+                    field: "name",
+                    vAlign: 1,
+                    hAlign: 0,
+                    font: "Arial"
+                }
+            }]
+        },
+        headers: [
+            {name: '名称', dataCode: 'name', width: 400, vAlign: 'center', hAlign: 'left', formatter: '@'},
+        ],
+        events: {
+            SelectionChanged: function (sender, info) {
+                sectionInitSel(info.newSelections[0].row)
+            }
+        }
+    };
+
     const ration = {
         dom: $('#rationSpread'),
         workBook: null,
-        datas: [],
-        cache: [],
+        datas: [],//所有的数据,搜索定额时,从所有数据中筛选
+        cache: [],//显示在表格上的数据,添加定额可以有效根据行识别定额
         headers: [
             {name: '选择', dataCode: 'select', width: 50, vAlign: 'center', hAlign: 'center'},
             {name: '编码', dataCode: 'code', width: 110, vAlign: 'center', hAlign: 'left', formatter: '@'},
@@ -247,7 +289,7 @@ const billsGuidance = (function () {
     function cleanData(sheet, headers, rowCount){
         renderSheetFunc(sheet, function () {
             sheet.clear(-1, 0, -1, headers.length, GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
-            if (rowCount > 0) {
+            if (rowCount >= 0) {
                 sheet.setRowCount(rowCount);
             }
         });
@@ -391,24 +433,58 @@ const billsGuidance = (function () {
         };
         renderSheetFunc(sheet, fuc);
     }
+    //根据定额章节树ID获取定额(从数据缓存中获取,定额数据一开始一次性拉取)
+    //@param {Number}sectionId {Array}rations @return {Array}
+    function getRationsBySectionId(sectionId, rations) {
+        if(!sectionId || !rations){
+            return [];
+        }
+        return _.filter(rations, {sectionId});
+    }
+    //定额章节树焦点控制
+    //@param {Number}row @return {void}
+    function sectionInitSel(row) {
+        let rationSheet = ration.workBook.getActiveSheet();
+        let sectionNode = section.tree ? section.tree.items[row] : null;
+        if(sectionNode && sectionNode.children.length === 0){
+            let sectionRations = getRationsBySectionId(sectionNode.data.ID, ration.datas);
+            ration.cache = sectionRations;
+            showData(rationSheet, ration.headers, sectionRations);
+        }
+        else {
+            cleanData(rationSheet, ration.headers, 0);
+        }
+    }
     //初始化定额条目
     //@param {Number}rationLibId @return {void}
     function initRationItems(rationLibId){
         $.bootstrapLoading.start();
-        CommonAjax.post('/rationRepository/api/getRationItemsByLib', {rationLibId: rationLibId}, function (rstData) {
-            rstData.sort(function (a, b) {
-                let rst = 0;
-                if(a.code > b.code){
-                    rst = 1;
-                }
-                else if(a.code < b.code){
-                    rst = -1;
-                }
-                return rst;
+        //获取定额章节树
+        let sectionSheet = section.workBook.getActiveSheet();
+        CommonAjax.post('/rationRepository/api/getRationTree', {rationLibId: rationLibId}, function (sectionDatas) {
+            //获取所有定额数据
+            CommonAjax.post('/rationRepository/api/getRationItemsByLib', {rationLibId: rationLibId}, function (rstData) {
+                section.cache = sectionDatas;
+                initTree(section, section.workBook.getActiveSheet(), section.treeSetting, sectionDatas);
+                //初始焦点在第一行(切换库)
+                sectionSheet.setActiveCell(0, 0);
+                rstData.sort(function (a, b) {
+                    let rst = 0;
+                    if(a.code > b.code){
+                        rst = 1;
+                    }
+                    else if(a.code < b.code){
+                        rst = -1;
+                    }
+                    return rst;
+                });
+                ration.datas = rstData;
+                sectionInitSel(0);
+                $.bootstrapLoading.end();
+            }, function () {
+                $.bootstrapLoading.end();
             });
-            ration.datas = rstData;
-            ration.cache = rstData;
-            showData(ration.workBook.getActiveSheet(), ration.headers, rstData);
+        }, function () {
             $.bootstrapLoading.end();
         });
     }
@@ -775,16 +851,40 @@ const billsGuidance = (function () {
                     return data.code.includes(searchStr);
                 });
             }
+            $('.top-content').hide();
+            $('#searchCount').text(`搜索结果: ${ration.cache.length}`);
+            $('#rationSearchResult').show();
+            autoFlashHeight();
+            ration.workBook.refresh();
             let rationSheet = ration.workBook.getActiveSheet();
             renderSheetFunc(rationSheet, function () {
+                clearCheckedRation(getCheckedRationRows());
                 showData(rationSheet, ration.headers, ration.cache);
             })
         });
+        //关闭搜索
+        $('#rationSearchResult a').click(function () {
+            $('.top-content').show();
+            $('#rationSearchResult').hide();
+            autoFlashHeight();
+            renderSheetFunc(ration.workBook.getActiveSheet(), function () {
+                clearCheckedRation(getCheckedRationRows());
+            });
+            section.workBook.refresh();
+            ration.workBook.refresh();
+            $('#searchText').val('');
+            //恢复章节树下的定额
+            sectionInitSel(section.workBook.getActiveSheet().getActiveRowIndex());
+        });
+        //执行搜索
+        $('#searchText').keyup(function (e) {
+            $('#searchBtn').click();
+        });
     }
     //初始化视图
     //@param {void} @return {void}
     function initViews(){
-        let modules = [bills, guideItem, ration];
+        let modules = [bills, guideItem, section, ration];
         initWorkBooks(modules);
         getLibWithBills(libID);
         initBtn();

+ 5 - 5
web/maintain/billsGuidance_lib/js/global.js

@@ -1,19 +1,19 @@
 /*全局自适应高度*/
 function autoFlashHeight(){
     var headerHeight = $(".header").height();
-    var bottomContentHeight = $(".bottom-content").height();
+    var topContentHeight = $('#rationSearchResult').is(':visible') ? 0 : 370;
     var toolsBar = $(".toolsbar").height();
     var toolsBarHeightQ = $(".tools-bar-height-q").height();
     $(".content").height($(window).height()-headerHeight);
     $(".main-side").height($(window).height()-headerHeight-2);
     $(".fluid-content").height($(window).height()-headerHeight-1);
-    $(".side-content").height($(window).height()-headerHeight );
+    $(".side-content").height($(window).height()-headerHeight);
     $(".poj-list").height($(window).height()-headerHeight);
-    $(".form-list").height($(window).height()-headerHeight-50 );
-    $(".main-data-top").height($(window).height()-headerHeight-toolsBar-bottomContentHeight-2);
+    $(".form-list").height($(window).height()-headerHeight-50);
     $(".main-data").height($(window).height()-headerHeight-toolsBar);
     $(".main-data-full").height($(window).height()-headerHeight);
-    $(".main-data-side-q").height($(window).height()-headerHeight-toolsBarHeightQ-2);
+    $(".main-data-bottom").height($(window).height()-headerHeight-toolsBarHeightQ-topContentHeight-$('#rationSearchResult').height() + 30);
+    $('.bottom-content').height($('.main-data-bottom').height());
 
 };
 $(window).resize(autoFlashHeight);

+ 14 - 16
web/maintain/billsGuidance_lib/js/main.js

@@ -10,6 +10,7 @@
 
 const billsGuidanceMain = (function () {
     const updateType = {create: 'create', update: 'update', delete: 'delete'};
+    const typeString = {1: '清单指引', 2: '清单精灵'};
     let guidanceLibs = [];
     let curLib = null;
     //上一个选择的库(三次确认删除同一库时用)
@@ -31,31 +32,23 @@ const billsGuidanceMain = (function () {
                     billsLibSels.append(libOpt);
                 }
             }
-            let comIndex = {};
-            for(let i = 0; i < rstData.length; i++){
-                let compilation = rstData[i];
-                comIndex[compilation._id] = compilation;
+            setBillsLib(rstData.billsLibs);
+            for(let i = 0; i < rstData.compilationList.length; i++){
+                let compilation = rstData.compilationList[i];
                 let comOpt = `<option value = "${compilation._id}">${compilation.name}</option>`;
                 comSels.append(comOpt);
-                //设置初始选择的清单规则库
-                if(i === 0){
-                    setBillsLib(compilation.billsLibs);
-                }
             }
-            //变更编办选择
-            comSels.on('change', function () {
-                let curComId = $(this).select().val();
-                let curCom = comIndex[curComId];
-                setBillsLib(curCom.billsLibs);
-            });
         });
     }
     //html新增库
     //@param {Object}tbody {Object}lib @return {void}
     function addLibToView(tbody, lib){
+        let type = lib.type && typeString[lib.type] ? typeString[lib.type] : ''
         let tr = `<tr id="${lib.ID}">
             <td><a href="/billsGuidance/guidance/?libID=${lib.ID}">${lib.name}</a>
-            <td>${lib.compilationName}</td><td>${lib.billsLibName}</td>
+            <td>${lib.compilationName}</td>
+            <td>${lib.billsLibName}</td>
+            <td>${type}</td>
             <td>${lib.createDate.split(' ')[0]}</td>
             <td><a href="javascript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a>
             <a href="javascript:void(0);" data-toggle="modal" data-target="#del" class="text-danger" title="删除"><i class="fa fa-remove"></i></a></td></tr>`;
@@ -106,9 +99,14 @@ const billsGuidanceMain = (function () {
                 if(!billsLibId){
                     throw '请选择清单规则库';
                 }
+                //库类型
+                let addType = $('#add').find('input:checked');
+                if(!addType){
+                    throw '请选择库类型';
+                }
                 //新建
                 $.bootstrapLoading.start();
-                let createData = {ID: uuid.v1(), name: cName, compilationId: compilationId, compilationName: compilationName, billsLibId: parseInt(billsLibId), billsLibName:billsLibName};
+                let createData = {type: parseInt(addType.val()), ID: uuid.v1(), name: cName, compilationId: compilationId, compilationName: compilationName, billsLibId: parseInt(billsLibId), billsLibName:billsLibName};
                 let updateData = {updateType: updateType.create, updateData: createData};
                 CommonAjax.post('/billsGuidance/api/updateBillsGuideLib', updateData, function (rstData) {
                     guidanceLibs.push(rstData);

+ 7 - 11
web/maintain/bills_lib/html/main.html

@@ -32,7 +32,7 @@
                   <div class="col-md-8">
                     <div class="warp-p2 mt-3">
                       <table class="table table-hover table-bordered">
-                        <thead><tr><th>清单规则名称</th><th width="160">编办</th><th width="160">添加时间</th><th width="90">操作</th></tr></thead>
+                        <thead><tr><th>清单规则名称</th><th width="160">添加时间</th><th width="90">操作</th></tr></thead>
                         <tbody id="showArea">
                           <!--<tr><td><a href="qingdan.html">XX清单规则</a></td><td>2017-01-01 </td><td><a href="javacript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a> <a href="javacript:void(0);" data-toggle="modal" data-target="#del" class="text-danger" title="删除"><i class="fa fa-remove"></i></a></td></tr>
                           <tr><td><a href="qingdan.html">XX清单规则</a></td><td>2017-01-01 </td><td><a href="javacript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a> <a href="javacript:void(0);" data-toggle="modal" data-target="#del" class="text-danger" title="删除"><i class="fa fa-remove"></i></a></td></tr>
@@ -61,10 +61,6 @@
                       <label>清单规则名称</label>
                       <input id="createText" class="form-control" placeholder="输入清单规则名称" type="text">
                     </div>
-                      <div class="form-group">
-                          <label>编办名称</label>
-                          <select id="compilationSels" class="form-control"></select>
-                      </div>
                   </form>
                 </div>
                 <div class="modal-footer">
@@ -137,22 +133,22 @@
     let userAccount = '<%= userAccount %>';
     let deleteCount = 0;
     let preDeleteId = null;
-    mainAjax.getCompilationList();
+    //mainAjax.getCompilationList();
     mainAjax.getStdBillsLib();
     $(document).ready(function(){
         //main 增删改
         $("#createA").click(function(){
             let billsLibName = $("#createText").val();
-            let compilationName = $('#compilationSels option:selected').text();
-            let compilationId = $('#compilationSels option:selected').val();
+         /*   let compilationName = $('#compilationSels option:selected').text();
+            let compilationId = $('#compilationSels option:selected').val();*/
             if(billsLibName.trim().length === 0){
                 alert("请输入清单规则名称!");
             }
-            else if(compilationName.trim().length === 0){
+          /*  else if(compilationName.trim().length === 0){
                 alert("编办不可为空!");
-            }
+            }*/
             else {
-                mainAjax.createStdBillsLib(userAccount, billsLibName, compilationId, compilationName);
+                mainAjax.createStdBillsLib(userAccount, billsLibName);
                 $("#createText").val("");
             }
         });

+ 3 - 5
web/maintain/bills_lib/scripts/bills_lib_ajax.js

@@ -62,11 +62,9 @@ var mainAjax = {
                         var billsLibName = result.data[i].billsLibName;
                         var createDate = result.data[i].createDate;
                         var createDateFmt = new Date(createDate).format("yyyy-MM-dd");
-                        let compilationName = result.data[i].compilationName;
                         $("#showArea").append(
                             "<tr id='tempId'>" +
                             "<td><a href='stdBills'>"+billsLibName+"</a></td>" +
-                            "<td>"+compilationName+" </td>" +
                             "<td>"+createDateFmt+" </td>" +
                             "<td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
                             "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
@@ -80,11 +78,11 @@ var mainAjax = {
             }
         });
     },
-    createStdBillsLib: function(userAccount, billsLibName, compilationId, compilationName){
+    createStdBillsLib: function(userAccount, billsLibName){
         $.ajax({
             type: "POST",
             url: "/stdBillsEditor/createStdBillsLib",
-            data: {data: JSON.stringify({userAccount: userAccount, name: billsLibName, compilationId: compilationId, compilationName: compilationName}) },
+            data: {data: JSON.stringify({userAccount: userAccount, name: billsLibName}) },
             dataType: "json",
             success: function(result){
                 if(!result.error){
@@ -92,7 +90,7 @@ var mainAjax = {
                     var createDate = result.data[0].createDate;
                     var createDateFmt = new Date(createDate).format("yyyy-MM-dd");
                     $("#showArea").append(
-                        "<tr id='tempId'><td><a href='stdBills'>"+billsLibName+"</a></td><td>"+ compilationName+"</td><td>"+createDateFmt+" </td><td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
+                        "<tr id='tempId'><td><a href='stdBills'>"+billsLibName+"</a></td><td>"+createDateFmt+" </td><td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
                         "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
                         "<i class='fa fa-remove'></i></a></td></tr>"
                     );

+ 15 - 2
web/maintain/common/css/main.css

@@ -74,6 +74,7 @@ body {
 }
 .main-side {
     border-right: 1px solid #ccc;
+    border-left: 1px solid #ccc;
     overflow:hidden;
 }
 .main-side .tab-bar {
@@ -270,13 +271,26 @@ body {
     max-height: 200px;
     overflow:auto;
 }
-.main-data-top,.main-data-bottom,.main-data{
+.main-data-top,.main-data-bottom,.main-data,.main-side,.main-data-side-q{
     overflow: hidden;
 }
 .modal-fixed-height {
     height:400px;
     overflow-y:auto;
 }
+.modal-fixed-height2 {
+    height:368px;
+    overflow-y:auto;
+}
+.btn.disabled, .btn:disabled {
+    cursor: not-allowed;
+    opacity: .65;
+    color:#666
+}
+.modal-lgx {
+    max-width: 1022px
+}
+
 .second_header{
     background: #e1e1e1;
 }
@@ -300,7 +314,6 @@ body {
     line-height: 1.5;
     border-radius: 3px;
 }
-
 .btn-default{
     color: #333;
     background-color: #fff;

+ 4 - 3
web/maintain/common/html/edit_layout.html

@@ -9,6 +9,7 @@
     <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
     <link rel="stylesheet" href="/web/maintain/common/css/main.css">
     <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
+    <link rel="stylesheet" href="/lib/jquery-contextmenu/jquery.contextMenu.css" type="text/css">
     <!--spread-->
     <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.sc.css">
 </head>
@@ -24,7 +25,8 @@
 <script src="/lib/lodash/lodash.js"></script>
 <script src="/web/maintain/bills_lib/scripts/set_sheets.js"></script>
 <script src="/web/maintain/bills_lib/scripts/bills_lib_ajax.js"></script>
-
+<script src="/public/web/common_ajax.js"></script>
+<script src="/public/web/commonAlert.js"></script>
 
 
 <body>
@@ -32,7 +34,7 @@
     <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 ">
         <span class="header-logo px-2"><%= title%>编辑器</span>
         <div class="navbar-text">
-            <a href='<%= mainURL%>'>清单模板</a><i class='fa fa-angle-right fa-fw'></i><%= libName%>
+            <a href='<%= mainURL%>'><%= title%></a><i class='fa fa-angle-right fa-fw'></i><%= libName%>
         </div>
     </nav>
 </div>
@@ -42,5 +44,4 @@
 
 </body>
 
-
 </html>

+ 2 - 2
web/maintain/main_col_lib/js/main_col_lib.js

@@ -381,14 +381,14 @@ $('#set-column').on('shown.bs.modal', function () {
     ColSettingObj.initColSetting(ColSettingObj.colSetting);
 });
 
-$('#set-glj-col').on('show.bs.modal', function () {
+/*$('#set-glj-col').on('show.bs.modal', function () {
     let glj_col_setting = JSON.parse($("#glj_col").val());
     if(glj_col_setting.showAdjustPrice){
         $('#adjustPrice_cb').prop('checked',true);
     }else {
         $('#adjustPrice_cb').prop('checked',false);
     }
-});
+});*/
 
 $('#set-glj-comf').click(function () {
 

+ 67 - 0
web/maintain/material_replace_lib/html/edit.html

@@ -0,0 +1,67 @@
+<nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0 second_header">
+    <ul class="nav nav-tabs" role="tablist">
+        <li class="nav-item">
+            <a class="nav-link active px-3" href="javascript: void(0);">材料替换</a>
+        </li>
+    </ul>
+</nav>
+
+<div class="main">
+    <div class="content" >
+        <div class="container-fluid" >
+            <div class="row">
+                <div class="tools-bar p-1 d-flex justify-content-between col-lg-12" style="background: #f7f7f7;">
+                    <div class="input-group input-group-sm col-lg-4">
+                        <input class="form-control" placeholder="搜索定位" type="text">
+                        <span class="input-group-btn">
+                              <button class="btn btn-secondary" type="button"><i class="fa fa-search"></i></button>
+                            </span>
+                        <a class="btn btn-sm btn-link"  style="color: #0275d8;cursor:pointer" data-toggle="modal" data-target="#guize"">关于规则</a>
+                    </div>
+                </div>
+                <div class="main-content col-lg-4 p-0">
+                    <div class="main-data" id="billsSpread"></div>
+                </div>
+                    <div class="col-lg-4 main-side p-0" id="materialSpread"></div>
+            </div>
+        </div>
+        <input type="hidden" id="libID" value="<%= libID %>">
+        <input type="hidden" id="gljLibID" value="<%= gljLibID %>">
+        <input type="hidden" id="billsLibId" value="<%= billsLibId %>">
+    </div>
+</div>
+
+<!--弹出关于规则-->
+<div class="modal fade" id="guize" 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">×</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <table class="table table-bordered">
+                    <thead><tr><th width="90">规则名称</th><th>规则解释</th></tr></thead>
+                    <tr><td>规则1</td><td>材料及规格:MU5烧结页岩空心砖</td></tr>
+                    <tr><td>规则2</td><td>1.混凝土种类:商品混凝土<br>2.混凝土强度等级:C30</td></tr>
+                </table>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+<script type="text/javascript">
+    //自适应高度
+    $(".main-data").height($(window).height()-$(".header").height()-$(".tools-bar").height()-$(".navbar").height()-16);
+    let billsList = '<%- billsList %>';
+</script>
+<script type="text/javascript" src="/lib/jquery-contextmenu/jquery.contextMenu.js"></script>
+<script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
+<script type="text/javascript" src="/public/web/sheet/sheet_data_helper.js"></script>
+
+<script type="text/javascript" src="/web/maintain/material_replace_lib/js/material_replace_edit.js"></script>

+ 118 - 0
web/maintain/material_replace_lib/html/main.html

@@ -0,0 +1,118 @@
+<div class="main">
+    <div class="content">
+        <div class="container-fluid">
+            <div class="row">
+                <div class="col-md-8">
+                    <div class="warp-p2 mt-3">
+                        <table class="table table-hover table-bordered">
+                            <thead><tr><th>库名称</th><th>清单规则</th><th >费用定额</th><th width="160">添加时间</th><th width="120">操作</th></tr></thead>
+                            <tbody id="showArea">
+                            <% for(let lib of materialLibs){ %>
+                            <tr class="libTr">
+                                <td id="<%= lib.ID%>"><a href="/materialReplace/edit/<%= lib.ID%>"><%= lib.name%></a></td>
+                                <td><%= lib.billsLibName%></td>
+                                <td><%= lib.compilationName%></td>
+                                <td><%= moment(lib.createDate).format('YYYY-MM-DD')%></td>
+                                <td>
+                                    <a style="color: #0275d8" onclick='getMaterialLib("<%= lib.ID%>")' title="编辑"><i class="fa fa-pencil-square-o"></i></a>
+                                    <a style="color: #0275d8" onclick='showDeleteModal("<%= lib.ID%>")' class="text-danger" title="删除"><i class="fa fa-remove"></i></a>
+                                </td>
+                            </tr>
+                            <% } %>
+                            </tbody>
+                        </table>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+
+<!--弹出添加-->
+<div class="modal fade" id="add" data-backdrop="static" style="display: none;" aria-hidden="true">
+    <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">×</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <form id="addLibForm" method="post" action="/materialReplace/addLib" enctype="application/x-www-form-urlencoded21">
+                    <div class="form-group">
+                        <label>库名称</label>
+                        <input id="name" name="name" class="form-control" placeholder="请输入材料库名称" type="text">
+                        <small class="form-text text-danger" id="nameError" style="display: none">请输入材料库名称。</small>
+                    </div>
+                    <div class="form-group">
+                        <label>清单规则</label>
+                        <select id="billLibs" name="billsLibId" class="form-control"></select>
+                    </div>
+                    <div class="form-group">
+                        <label>编办名称</label>
+                        <select id="compilationSels" name="compilationId" class="form-control"></select>
+                    </div>
+                    <input type="hidden" name = "userAccount" value="<%= userAccount%>">
+                </form>
+            </div>
+            <div class="modal-footer">
+                <button id="addLibs"  class="btn btn-primary">新建</button>
+                <button type="button" id="cancelBtn" class="btn btn-secondary" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+<!--弹出编辑-->
+<div class="modal fade" id="edit" data-backdrop="static" style="display: none;" aria-hidden="true">
+    <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">×</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <form>
+                    <div class="form-group">
+                        <label>材料替换库名称</label>
+                        <input id="renameText" class="form-control" placeholder="输入名称" type="text" value="">
+                        <small class="form-text text-danger" id="renameError" style="display: none">请输入名称。</small>
+                        <input id="libID" type="hidden">
+                    </div>
+                </form>
+            </div>
+            <div class="modal-footer">
+                <a id="rename" 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="del" data-backdrop="static" style="display: none;" aria-hidden="true">
+    <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">×</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <h5 class="text-danger">删除后无法恢复,确认是否删除?</h5>
+                <input type="hidden" id="libID_del">
+                <input type="hidden" id="delCount">
+            </div>
+            <div class="modal-footer">
+                <a id="delete" href="javascript:void(0);" class="btn btn-danger" >确认</a>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+<script type="text/javascript" src="/web/maintain/material_replace_lib/js/material_replace.js"></script>

+ 131 - 0
web/maintain/material_replace_lib/js/material_replace.js

@@ -0,0 +1,131 @@
+/**
+ * Created by zhang on 2018/8/22.
+ */
+$(document).ready(function() {
+    $('#add').on('show.bs.modal', function () {
+        $('#compilationSels').empty();
+        $('#billLibs').empty();
+        getCompilationOptions();
+        getBillsLibOptions();
+
+    });
+
+    // 保存按钮
+    $("#addLibs").click(async function() {
+        let name = $('#name').val();
+        if(name==''){
+            $("#nameError").show();
+            return;
+        }else {
+            let result = await validateLib($('#billLibs').val(),$('#compilationSels').val());
+            if(result == true){//不存在则验证通过
+                $("#addLibs").attr("disabled",true);//防止重复提交
+                $("#addLibForm").submit();
+            }else {
+                alert('清单规则和定额库对应的材料库已存在,请重新选择');
+            }
+        }
+    });
+
+    $("#rename").click(async function() {
+        let libID = $("#libID").val();
+        let name = $('#renameText').val();
+        if(libID!=''){
+            if(name ==''){
+                $("#renameError").show();
+                return;
+            }else {
+                try {
+                    let newMaterial = await ajaxPost("/materialReplace/saveLib",{query:{ID:libID},data:{name:name}});
+                    $("#"+libID).children("a").text(newMaterial.name);
+                    $("#edit").modal('hide');
+                }catch(err) {
+                    console.log(err);
+                }
+            }
+        }
+    });
+
+    $("#delete").click(async function() {
+        let libID = $("#libID_del").val();
+        let delCount = parseInt($("#delCount").val());
+        delCount = delCount+1;
+        $("#delCount").val(delCount);
+        if(delCount == 3){
+            if(libID!=""){
+                try {
+                    let result = await ajaxPost("/materialReplace/deleteLibByID",{ID:libID});
+                    if(result.ok){
+                        $("#"+libID).parent(".libTr").remove();
+                    }
+                    $("#del").modal('hide');
+                }catch (err){
+                    console.log(err);
+                }
+            }
+        }
+    });
+
+
+})
+
+//检查库是否已经存在,存在则返回false
+async function validateLib(billLibID,compilationID){
+    try {
+        let lib = await ajaxPost("/materialReplace/findLib",{billLibID:billLibID,compilationID:compilationID});
+        return lib?false:true;
+    }catch (err){
+        console.log(err);
+        return false
+    }
+}
+
+//取所有的定额并生成下拉框
+async function getCompilationOptions() {
+    try {
+        let compilations = await ajaxPost("/stdBillsEditor/getCompilationList");
+        for(let com of compilations){
+            let $option =  $("<option >"+ com.name +"</option>");
+            $option.val( com._id);
+            $('#compilationSels').append($option);
+        }
+    }catch (err){
+        console.log(err)
+    }
+}
+
+//取所有的清单规则库并生成下拉框
+async function getBillsLibOptions(){
+    try {
+        let libs = await ajaxPost("/stdBillsEditor/getStdBillsLib");
+        for(let b of libs){
+            let $option =  $("<option >"+ b.billsLibName +"</option>");
+            $option.val( b.billsLibId);
+            $('#billLibs').append($option);
+        }
+    }catch (err){
+        console.log(err)
+    }
+
+}
+
+async function getMaterialLib (ID) {
+    try {
+        let lib = await ajaxPost("/materialReplace/findLib",{ID:ID});
+        if(lib){
+            $("#renameText").val(lib.name);
+            $("#libID").val(ID);
+            $("#edit").modal({show:true});
+        }else {
+            alert("没有找到材料库");
+        }
+    }catch (err){
+        console.log(err);
+    }
+}
+
+function showDeleteModal(ID){
+    $("#libID_del").val(ID);
+    $("#delCount").val(0);
+    $("#del").modal({show:true});
+}

+ 188 - 0
web/maintain/material_replace_lib/js/material_replace_edit.js

@@ -0,0 +1,188 @@
+/**
+ * Created by zhang on 2018/8/23.
+ */
+
+let materialOjb = {
+    billsSpread:null,
+    materialSpread:null,
+    billsList:JSON.parse(billsList),
+    billsSetting:{
+        header: [
+            {headerName: "清单编号", headerWidth: 180, dataCode: "code", dataType: "String",formatter: "@"},
+            {headerName: "清单名称", headerWidth: 240, dataCode: "name", dataType: "String"},
+            {headerName: "规则", headerWidth: 150, dataCode: "rule", hAlign: "left", dataType: "String",cellType:'comboBox',editorValueType:true,options:[{text:"规则1",value:1},{text:"规则2",value:2}]}
+        ],
+        view: {
+            lockColumns: [1]
+        },
+        headerHeight:45
+    },
+    materialSetting:{
+        header: [
+            {headerName: "材料编号", headerWidth: 180, dataCode: "code", dataType: "String"},
+            {headerName: "材料名称", headerWidth: 240, dataCode: "name", dataType: "String",cellType:'tipsCell'},
+            {headerName: "规格", headerWidth: 150, dataCode: "specs", hAlign: "left", dataType: "String",cellType:'tipsCell'}
+        ],
+        view: {
+            lockColumns: [1,2]
+        },
+        headerHeight:45
+    },
+    initSpread:function () {
+        if(!this.billsSpread){
+            this.billsSpread = SheetDataHelper.createNewSpread($("#billsSpread")[0]);
+        }
+        if(!this.materialSpread){
+            this.materialSpread = SheetDataHelper.createNewSpread($("#materialSpread")[0]);
+        }
+        this.billsSheet = this.billsSpread .getSheet(0);
+        sheetCommonObj.initSheet(this.billsSheet,this.billsSetting, 30);
+        this.billsSheet.name('billsSheet');
+        this.billsSheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onBillsValueChange);
+        this.billsSheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onBillsSelectionChange);
+        this.initRightClick("billsSpread",this.billsSpread);
+
+
+        this.materialSheet = this.materialSpread .getSheet(0);
+        sheetCommonObj.initSheet(this.materialSheet,this.materialSetting, 30);
+        this.materialSheet.name('materialSheet');
+        this.initRightClick("materialSpread",this.materialSpread);
+        this.refreshSheet();
+
+    },
+    canDelete : function (sheet) {
+        let sel =  sheet.getSelections()[0];
+        console.log(sel);
+        if(sel.row === undefined || sel.row < 0) return false ;//一行都没选中时,不能删除
+
+        //选中空行时,不能删除
+        // to do
+        return true;
+    },
+
+    initRightClick : function(id,spread) {
+        let me = this;
+        $.contextMenu({
+            selector: '#'+id,
+            build: function ($trigger, e) {
+                me.rightClickTarget = SheetDataHelper.safeRightClickSelection($trigger, e, spread);
+                return me.rightClickTarget.hitTestType === GC.Spread.Sheets.SheetArea.viewport ||
+                    me.rightClickTarget.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
+            },
+            items: {
+                "delete": {
+                    name: "删除",
+                    icon: 'fa-trash-o',
+                    disabled: function () {
+                        return !me.canDelete(spread.getActiveSheet());
+                    },
+                    callback: function (key, opt) {
+                       console.log();
+                    }
+                }
+            }
+        });
+    },
+    refreshSheet:function(){
+        sheetCommonObj.showData(this.billsSheet,this.billsSetting,this.billsList);
+        this.billsSheet.setRowCount(this.billsList.length + 1);
+    },
+    onBillsSelectionChange:function (sander,args) {
+        args.sheet.repaint();
+    },
+
+    onBillsValueChange: function(sander,args){
+        let me = materialOjb;
+        let field = me.billsSetting.header[args.col].dataCode;
+        let code = null;
+        if(args.row < me.billsList.length){
+            code = me.billsList[args.row].code;
+        }
+        if(me.validateBills(field,args.newValue)){
+            let data = me.getUpdateData(field,args.newValue,code);
+            if (data){
+                me.saveBills([data]);
+                return;
+            }
+        }
+        me.refreshSheet();
+    },
+
+    validateBills:function (field,value) {
+        if(field == 'code'){
+            if(value.length !== 9){
+                alert("清单长度不正确");
+                return false;
+            }
+            if(_.find(this.billsList,{'code':value})) {
+                alert("清单已存在");
+                return false;
+            }
+        }
+        return true;
+    },
+    getUpdateData:function (field,newValue,code) {
+        if(field == 'code'){
+            if(!isDef(code) || code ==''&&newValue!=null){//说明是新增
+                return {
+                    type:'add',
+                    code:newValue.toString(),
+                    libID:$('#libID').val(),
+                    billsLibId:parseInt($('#billsLibId').val())
+                }
+            }else {//说明是替换
+                return {
+                    type:'update',
+                    oldCode:code.toString(),
+                    newCode:newValue.toString(),
+                    libID:$('#libID').val(),
+                    billsLibId:parseInt($('#billsLibId').val())
+                }
+            }
+        }else if(isDef(code)){
+            let updateData = {};
+            updateData[field] = newValue;
+            return {
+                type:'update',
+                oldCode:code.toString(),
+                libID:$('#libID').val(),
+                updateData:updateData
+            }
+        }
+    },
+    saveBills:async function (datas) {
+        try {
+            let result = await ajaxPost("/materialReplace/saveBills",datas);
+            let missCodes = [];
+            for(let r of result){
+                if(r.missCodes && r.missCodes.length >0) missCodes =missCodes.concat(r.missCodes);
+                if(r.type == 'add'){
+                    this.billsList = this.billsList.concat(r.list);
+                }if(r.type == 'update'){
+                    for(let l of r.list){
+                        this.updateCache(l.code,l.updateData)
+                    }
+                }if(r.type == 'delete'){
+
+                }
+            }
+            if(missCodes.length > 0) alert(`没有找到清单:${missCodes.join("、")}`);
+            this.refreshSheet();
+        }catch (err){
+            console.log(err);
+        }
+    },
+    updateCache:function (code,updateData) {
+        let bill = _.find(this.billsList,{'code':code});
+        for(let key of updateData){
+            bill[key] = updateData[key]
+        }
+    }
+};
+
+function isDef(obj) {
+    return obj!==undefined && obj!==null;
+}
+
+materialOjb.initSpread();
+

+ 1 - 1
web/maintain/ration_repository/js/annotation.js

@@ -319,7 +319,7 @@ let annotationOprObj = {
     //定额工作内容相关操作
     rationAnnotationOpr: function (rationItems) {
         let me = annotationOprObj;
-        me.setRadiosDisabled(rationItems.length > 0 ? false : true, me.radios);
+        me.setRadiosDisabled(sectionTreeObj.tree.selected.children.length === 0 ? false : true, me.radios);
         me.setRadiosChecked(me.currentSituation, me.radios);
         me.buildTablePartial(me.fzTablePartial, me.getGroup(rationItems));
     },

+ 1 - 1
web/maintain/ration_repository/js/jobContent.js

@@ -328,7 +328,7 @@ let jobContentOprObj = {
     //定额工作内容相关操作
     rationJobContentOpr: function (rationItems) {
         let me = jobContentOprObj;
-        me.setRadiosDisabled(me.currentRationItems.length > 0 ? false : true, me.radios);
+        me.setRadiosDisabled(sectionTreeObj.tree.selected.children.length === 0 ? false : true, me.radios);
         me.setRadiosChecked(me.currentSituation, me.radios);
         me.buildTablePartial(me.tablePartial, me.getGroup(rationItems));
     },

+ 26 - 2
web/maintain/ration_repository/js/main.js

@@ -101,7 +101,25 @@ $(function () {
                 $('#del').modal('hide');
             }
         });
-
+        //全部计算
+        $("#showArea").on("click", "[data-target = '#reCalcAll']", function(){
+            let recalcId = $(this).parent().parent().attr("id");
+            $("#reCalcConfirm").attr("recalcId", recalcId);
+        });
+        $("#reCalcConfirm").click(function(){
+            $('#reCalcConfirm').addClass('disabled');
+            $.bootstrapLoading.start();
+            let recalcId = $(this).attr("recalcId");
+            CommonAjax.post('/rationRepository/api/reCalcAll', {rationRepId: recalcId}, function (rstData) {
+                $.bootstrapLoading.end();
+                $('#reCalcAll').modal('hide');
+                $('#reCalcConfirm').removeClass('disabled');
+            }, function () {
+                $.bootstrapLoading.end();
+                $('#reCalcAll').modal('hide');
+                $('#reCalcConfirm').removeClass('disabled')
+            });
+        });
 
     });
     getCompilationList();
@@ -130,6 +148,7 @@ $(function () {
 
     // 导入原始数据确认
     $("#source-import,#data-import").click(function() {
+        $.bootstrapLoading.start();
         const self = $(this);
         const type = self.is("#source-import") ? 'source_file' : 'import_data';
         const dialog = type === 'source_file' ? $("#import") : $("#import2");
@@ -161,6 +180,7 @@ $(function () {
                     self.removeAttr('disabled');
                     self.text('确定导入');
                     if (response.err === 0) {
+                        $.bootstrapLoading.end();
                         const message = response.msg !== undefined ? response.msg : '';
                         if (message !== '') {
                             alert(message);
@@ -168,11 +188,13 @@ $(function () {
                         // 成功则关闭窗体
                         dialog.modal("hide");
                     } else {
+                        $.bootstrapLoading.end();
                         const message = response.msg !== undefined ? response.msg : '上传失败!';
                         alert(message);
                     }
                 },
                 error: function(){
+                    $.bootstrapLoading.end();
                     alert("与服务器通信发生错误");
                     self.removeAttr('disabled');
                     self.text('确定导入');
@@ -219,7 +241,8 @@ function getAllRationLib(callback){
                         "<td>"+createDate+" </td>" +
                         "<td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
                         "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
-                        "<i class='fa fa-remove'></i></a></td>" +
+                        "<i class='fa fa-remove'></i></a>" +
+                        " <a href='javascript:void(0);' data-toggle='modal' data-target='#reCalcAll' title='全部计算'><i class='fa fa-calculator'></i></a></td>"+
                         "<td><a class='btn btn-secondary btn-sm import-source' href='javacript:void(0);' data-id='"+ id +"' title='导入原始数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
                         "<td><a class='btn btn-success btn-sm export' href='javacript:void(0);' data-toggle='modal' data-id='"+ id +"' data-target='#emport' title='导出内部数据'><i class='fa fa-sign-out fa-rotate-270'></i>导出</a> " +
                         "<a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入内部数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
@@ -309,6 +332,7 @@ function createRationLib(rationObj, dispNamesArr){
                     "<td><a href='javascript:void(0);' data-toggle='modal' data-target='#edit' title='编辑'>" +
                     "<i class='fa fa-pencil-square-o'></i></a> <a href='javascript:void(0);' data-toggle='modal' data-target='#del' class='text-danger' title='删除'>" +
                     "<i class='fa fa-remove'></i></a>" +
+                    " <a href='javascript:void(0);' data-toggle='modal' data-target='#reCalcAll' title='全部计算'><i class='fa fa-calculator'></i></a>"+
                     "<td><a class='btn btn-secondary btn-sm import-source' href='javacript:void(0);' data-id='"+ id +"' title='导入原始数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +
                     "<td><a class='btn btn-success btn-sm export' href='javacript:void(0);' data-toggle='modal' data-id='"+ id +"' data-target='#emport' title='导出内部数据'><i class='fa fa-sign-out fa-rotate-270'></i>导出</a> " +
                     "<a class='btn btn-secondary btn-sm import-data' href='javacript:void(0);' data-id='"+ id +"' title='导入内部数据'><i class='fa fa-sign-in fa-rotate-90'></i>导入</a></td>" +

+ 3 - 2
web/maintain/ration_repository/js/ration.js

@@ -140,7 +140,7 @@ let rationOprObj = {
                 if (updateArr[i]["ID"] && cacheSection[j]["ID"]) {
                     if (cacheSection[j]["ID"] == updateArr[i]["ID"]) {
                         updateArr[i]['rationGljList'] = rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] ? rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] : [];
-                        updateArr[i]['rationCoeList'] = rationCoeOprObj.cache['_Coe_' + cacheSection[j]['ID']] ? rationCoeOprObj.cache['_Coe_' + cacheSection[j]['ID']] : [];
+                        updateArr[i]['rationCoeList'] = cacheSection[j]['rationCoeList'] ? cacheSection[j]['rationCoeList'] : [];
                         updateArr[i]['rationAssList'] = cacheSection[j]['rationAssList'];
                         updateArr[i]['rationInstList'] = cacheSection[j]['rationInstList'];
                         cacheSection[j] = updateArr[i];
@@ -148,7 +148,7 @@ let rationOprObj = {
                 } else {
                     if (cacheSection[j][me.setting.header[0].dataCode] == updateArr[i][me.setting.header[0].dataCode]) {
                         updateArr[i]['rationGljList'] = rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] ? rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] : [];
-                        updateArr[i]['rationCoeList'] = rationCoeOprObj.cache['_Coe_' + cacheSection[j]['ID']] ? rationCoeOprObj.cache['_Coe_' + cacheSection[j]['ID']] : [];
+                        updateArr[i]['rationCoeList'] = cacheSection[j]['rationCoeList'] ? cacheSection[j]['rationCoeList'] : [];
                         updateArr[i]['rationAssList'] = cacheSection[j]['rationAssList'];
                         updateArr[i]['rationInstList'] = cacheSection[j]['rationInstList'];
                         cacheSection[j] = updateArr[i];
@@ -567,6 +567,7 @@ let rationOprObj = {
                     me.mixUpdate = 0;
                     me.mixDel = 0;
                 }
+                me.workBook.focus(true);
                 if(callback) callback();
             },
             error:function(){

+ 1 - 1
web/maintain/ration_repository/js/ration_assist.js

@@ -111,7 +111,7 @@ var rationAssistOprObj = {
         // 新增
         if (args.row >= assList.length) {
             if (assObj.decimal == undefined || assObj.decimal == null){assObj.decimal = '0';};
-            if (assObj.carryBit == undefined || assObj.carryBit == null){assObj.carryBit = '四舍五入';};
+            if (assObj.carryBit == undefined || assObj.carryBit == null){assObj.carryBit = '进一';};
             assList.push(assObj);
         }
         // 修改

+ 2 - 2
web/maintain/ration_repository/js/ration_coe.js

@@ -156,7 +156,7 @@ var rationCoeOprObj = {
     onClipboardPasting: function(sender, args) {
         var me = rationCoeOprObj;
         let rationSection = rationOprObj.getCache();
-        let rationRow = rationOprObj.workBook.getSheet(0).getSelections()[0].row;
+        let rationRow = rationOprObj.workBook.getActiveSheet().getSelections()[0].row;
         me.curRation = rationRow < rationSection.length ? rationSection[rationRow] : null;
         if (args.cellRange.colCount != 1 || args.cellRange.col != 0 || !(me.curRation)) {
             args.cancel = true;
@@ -221,7 +221,7 @@ var rationCoeOprObj = {
     onEditStarting: function (sender, args) {
         let me = rationCoeOprObj;
         let rationSection = rationOprObj.getCache();
-        let rationRow = rationOprObj.workBook.getSheet(0).getSelections()[0].row;
+        let rationRow = rationOprObj.workBook.getActiveSheet().getSelections()[0].row;
         me.curRation = rationRow < rationSection.length ? rationSection[rationRow] : null;
         if(!me.curRation || args.col !== 0){
             args.cancel = true;

+ 33 - 1
web/maintain/ration_repository/js/ration_glj.js

@@ -514,7 +514,9 @@ var rationGLJOprObj = {
     },
     rationCal: function () {
         let me = rationGLJOprObj;
-        let price = {gljType1: [], gljType2: [], gljType3: []}, rst = {labourPrice: 0, materialPrice: 0, machinePrice: 0}, rationBasePrc = 0;
+        let price = {gljType1: [], gljType2: [], gljType3: [], gljType6: [], gljType7: [], gljType8: []},
+            rst = {labourPrice: 0, materialPrice: 0, machinePrice: 0, managePrice: 0, profitPrice: 0, riskPrice: 0},
+            rationBasePrc = 0;
         if(me.currentRationItem && me.cache['_GLJ_' + me.currentRationItem.ID]){
             let cacheArr = me.cache['_GLJ_' + me.currentRationItem.ID];
             cacheArr.forEach(function (gljData) {
@@ -526,6 +528,9 @@ var rationGLJOprObj = {
                     if(!parent && gljData.gljType <= 3){
                         price['gljType' + gljData.gljType].push(scMathUtil.roundTo( gljData.basePrice * gljData.consumeAmt, -3));//取三位
                     }
+                    if([6, 7, 8].includes(gljData.gljType)){
+                        price['gljType' + gljData.gljType].push(scMathUtil.roundTo( gljData.basePrice * gljData.consumeAmt, -3));//取三位
+                    }
                 }
             });
             if(price.gljType1.length > 0){
@@ -555,6 +560,33 @@ var rationGLJOprObj = {
                 rst.machinePrice = roundPrice;
                 rationBasePrc = scMathUtil.roundTo(rationBasePrc + roundPrice, -2);
             }
+            if(price.gljType6.length > 0){
+                let managePrice = 0;
+                price.gljType6.forEach(function (singlePrc) {
+                    managePrice = scMathUtil.roundTo(managePrice + singlePrc, me.processDecimal);
+                });
+                let roundPrice = scMathUtil.roundTo(managePrice, -2);
+                rst.managePrice = roundPrice;
+                rationBasePrc = scMathUtil.roundTo(rationBasePrc + roundPrice, -2);
+            }
+            if(price.gljType7.length > 0){
+                let profitPrice = 0;
+                price.gljType7.forEach(function (singlePrc) {
+                    profitPrice = scMathUtil.roundTo(profitPrice + singlePrc, me.processDecimal);
+                });
+                let roundPrice = scMathUtil.roundTo(profitPrice, -2);
+                rst.profitPrice = roundPrice;
+                rationBasePrc = scMathUtil.roundTo(rationBasePrc + roundPrice, -2);
+            }
+            if(price.gljType8.length > 0){
+                let riskPrice = 0;
+                price.gljType8.forEach(function (singlePrc) {
+                    riskPrice = scMathUtil.roundTo(riskPrice + singlePrc, me.processDecimal);
+                });
+                let roundPrice = scMathUtil.roundTo(riskPrice, -2);
+                rst.riskPrice = roundPrice;
+                rationBasePrc = scMathUtil.roundTo(rationBasePrc + roundPrice, -2);
+            }
             rst.rationBasePrc = rationBasePrc;
         }
         return rst;

+ 41 - 7
web/maintain/ration_repository/js/section_tree.js

@@ -60,6 +60,23 @@ let sectionTreeObj = {
             cols:[
                 {
                     head: {
+                        titleNames: ['ID'],
+                        spanCols: [1],
+                        spanRows: [2],
+                        vAlign: [1, 1],
+                        hAlign: [1, 1],
+                        font: 'Arial'
+                    },
+                    data: {
+                        field: 'ID',
+                        vAlign: 1,
+                        hAlign: 0,
+                        font: 'Arial'
+                    },
+                    width: 40
+                },
+                {
+                    head: {
                         titleNames: ['名称'],
                         spanCols: [1],
                         spanRows: [2],
@@ -73,13 +90,13 @@ let sectionTreeObj = {
                         hAlign: 0,
                         font: 'Arial'
                     },
-                    width: 400
+                    width: 370
                 }
             ],
             headRows: 1,
             headRowHeight: [25],
             emptyRows: 0,
-            treeCol: 0
+            treeCol: 1
         },
         tree: {
             id: 'ID',
@@ -136,7 +153,9 @@ let sectionTreeObj = {
         let me = sectionTreeObj;
         const Events = GC.Spread.Sheets.Events;
         sheet.bind(Events.SelectionChanged, me.onSelectionChanged);
+        sheet.bind(Events.EditStarting, me.onEditStarting);
         sheet.bind(Events.EditEnded, me.onEditEnded);
+        sheet.bind(Events.ClipboardPasting, me.onClipboardPasting);
         sheet.bind(Events.ClipboardPasted, me.onClipboardPasted);
     },
 
@@ -153,6 +172,14 @@ let sectionTreeObj = {
         }*/
     },
 
+    onEditStarting: function (sender, args) {
+        let me = sectionTreeObj;
+        let dataCode = me.setting.sheet.cols[args.col]['data']['field'];
+        if(dataCode === 'ID'){
+            args.cancel = true;
+        }
+    },
+
     onEditEnded: function (sender, args) {
         let me = sectionTreeObj;
         let postData = [];
@@ -171,9 +198,16 @@ let sectionTreeObj = {
         }
     },
 
+    onClipboardPasting: function (sender, info) {
+        let me = sectionTreeObj;
+        if(info.cellRange.col === 0){
+            info.cancel = true;
+        }
+    },
+
     onClipboardPasted: function (sender, info) {
         let me = sectionTreeObj;
-        let items = sheetCommonObj.analyzePasteData({header: [{dataCode: 'name'}]}, info);
+        let items = sheetCommonObj.analyzePasteData({header: [{dataCode: 'ID'}, {dataCode: 'name'}]}, info);
         let postData = [];
         let frontData = [];
         for(let i = 0, len = items.length; i < len; i++){
@@ -198,7 +232,7 @@ let sectionTreeObj = {
             }, function () {
                 for(let i = 0, len = frontData.length; i < len; i++){
                     let node = me.cache[frontData[i]['row']];
-                    me.sheet.setValue(frontData[i]['row'], 0, me.isDef(node) ? node.data.name : '');
+                    me.sheet.setValue(frontData[i]['row'], 1, me.isDef(node) ? node.data.name : '');
                 }
             });
         }
@@ -556,11 +590,11 @@ let sectionTreeObj = {
             explanatoryOprObj.clickUpdate($('#explanationShow'), $('#ruleTextShow'));
             explanatoryOprObj.showText($('#explanationShow'), $('#ruleTextShow'), node.data.explanation, node.data.ruleText);
             //job
-            jobContentOprObj.currentSituation = typeof node.data.jobContentSituation !== 'undefined'? node.data.jobContentSituation : jobContentOprObj.situations.NONE;
+            jobContentOprObj.currentSituation = typeof node.data.jobContentSituation !== 'undefined'? node.data.jobContentSituation : jobContentOprObj.situations.ALL;
             jobContentOprObj.setAttribute(jobContentOprObj.currentTreeNode ? jobContentOprObj.currentTreeNode : node, node);
             jobContentOprObj.clickUpdate($('#txtareaAll'));
             //fz
-            annotationOprObj.currentSituation = typeof node.data.annotationSituation !== 'undefined'? node.data.annotationSituation : annotationOprObj.situations.NONE;
+            annotationOprObj.currentSituation = typeof node.data.annotationSituation !== 'undefined'? node.data.annotationSituation : annotationOprObj.situations.ALL;
             annotationOprObj.clickUpdate($('#fzTxtareaAll'));
         }
     },
@@ -575,7 +609,7 @@ let sectionTreeObj = {
             sheetCommonObj.cleanSheet(rationInstObj.sheet, rationInstObj.setting, -1);
             return;
         }
-        me.workBook.getActiveSheet().setActiveCell(node.serialNo(), 0);
+        //me.workBook.getActiveSheet().setActiveCell(node.serialNo(), me.workBook.getActiveSheet().getActiveColumnIndex());
         me.initTools(node);
         me.refreshBtn(node);
         if(!me.isDef(node.children) || node.children.length === 0){

+ 2 - 1
web/maintain/ration_repository/js/sheetsOpr.js

@@ -65,7 +65,8 @@ let sheetsOprObj = {
                     sheet.setValue(row, col, distTypeVal, ch);
                 }
                 else {
-                    sheet.setValue(row, col, data[row][setting.header[col].dataCode], ch);
+                    sheet.setValue(row, col, data[row][setting.header[col].dataCode] !== undefined && data[row][setting.header[col].dataCode] !== null
+                        ? data[row][setting.header[col].dataCode] : '', ch);
                     sheet.setTag(row, 0, data[row].ID, ch);
                     /*if(typeof setting.owner !== 'undefined' && setting.owner !== 'gljComponent'){
                         sheet.getCell(row, 0, GC.Spread.Sheets.SheetArea.viewport).locked(true);

+ 23 - 2
web/maintain/ration_repository/main.html

@@ -151,6 +151,27 @@
             </div>
         </div>
     </div>
+    <!--全部计算-->
+    <div class="modal fade" id="reCalcAll" data-backdrop="static" style="display: none;" aria-hidden="true">
+        <!--<input type="hidden" id="did" value="123">-->
+        <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">×</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <h5>确认重算所有定额数据?</h5>
+                </div>
+                <div class="modal-footer">
+                    <a id="reCalcConfirm" href="javascript: void(0);" class="btn btn-primary">确认</a>
+                    <button id="reCalcCancel" type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                </div>
+            </div>
+        </div>
+    </div>
     <!--弹出导入原始数据-->
     <div class="modal fade" id="import" data-backdrop="static" style="display: none;" aria-hidden="true">
         <div class="modal-dialog" role="document">
@@ -168,7 +189,7 @@
                     <form>
                         <div class="form-group">
                             <label>请选择Excel格式文件</label>
-                            <input class="form-control-file" type="file" name="source_file">
+                            <input class="form-control-file" type="file" name="source_file" accept=".xlsx,.xls">
                         </div>
                     </form>
                 </div>
@@ -197,7 +218,7 @@
                     <form>
                         <div class="form-group">
                             <label>请选择Excel格式文件</label>
-                            <input class="form-control-file" type="file" name="import_data"/>
+                            <input class="form-control-file" type="file" accept=".xlsx,.xls" name="import_data"/>
                         </div>
                     </form>
                 </div>

+ 5 - 0
web/maintain/std_glj_lib/html/gongliao.html

@@ -172,6 +172,8 @@
     <!-- zTree -->
     <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>
     <script>GC.Spread.Sheets.LicenseKey =  '<%- LicenseKey %>';</script>
+    <script type="text/javascript" src="/lib/lodash/lodash.js"></script>
+    <script type="text/javascript" src="/lib/lz-string/lz-string.min.js"></script>
     <script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
     <script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>
     <script type="text/javascript" src="/lib/ztree/jquery.ztree.exedit.js"></script>
@@ -180,6 +182,7 @@
     <script type="text/javascript" src="/public/web/QueryParam.js"></script>
     <script type="text/javascript" src="/public/web/common_ajax.js"></script>
     <script type="text/javascript" src="/public/web/id_tree.js"></script>
+    <script type="text/javascript" src="/public/web/tools_const.js"></script>
     <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_controller.js"></script>
     <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_helper.js"></script>
     <script type="text/javascript" src="/public/web/ration_glj_units.js"></script>
@@ -191,6 +194,7 @@
     <script type="text/javascript" src="/public/web/sheet/sheet_common.js"></script>
     <script type="text/javascript" src="/web/maintain/std_glj_lib/js/sheetsOpr.js"></script>
     <script type="text/javascript" src="/public/web/storageUtil.js"></script>
+    <script type="text/javascript" src="<%= overWriteUrl %>"></script>
     <SCRIPT type="text/javascript">
         let userAccount = '<%=userAccount %>';
         let gljSetting = {
@@ -269,6 +273,7 @@
             }
         };
         $(document).ready(function(){
+            console.log(scMathUtil.roundTo(268.89472, -2));
             //test
             console.log(scMathUtil.roundTo(parseFloat(25*1.277), -2));
             console.log(25*1.277);

+ 121 - 25
web/maintain/std_glj_lib/js/components.js

@@ -71,13 +71,10 @@ let componentOprObj = {
         }
     },
     setShowGljList: function (gljList, clearChecked) {
-        //初始为所有工料机,机械类型可添加机械组成物、机上人工,混凝土,砂浆、配合比可添加普通材料, 主材只能添加没有组成物的主材
-        let machineArr = [302, 303];
-        let materialArr = [202, 203, 204];//混凝土、砂浆、配合比, 201普通材料
         let that = repositoryGljObj, me = componentOprObj;
         for(let i = 0; i < gljList.length; i++){
-            if(that.currentGlj.gljType === 301 && machineArr.indexOf(gljList[i].gljType) !== -1 ||
-                materialArr.indexOf(that.currentGlj.gljType) !== -1 && gljList[i].gljType === 201||
+            if(machineAllowComponent.includes(that.currentGlj.gljType) && machineComponent.includes(gljList[i].gljType) ||
+                materialAllowComponent.includes(that.currentGlj.gljType) && gljList[i].gljType === 201||
                 that.currentGlj.gljType === 4 && gljList[i].gljType === 4 && (!gljList[i].component || gljList[i].component.length === 0) && gljList[i].ID !== that.currentGlj.ID){
                 let isExist = false;
                 for(let j = 0; j < that.currentComponent.length; j++){
@@ -143,35 +140,134 @@ let componentOprObj = {
             cacheSection = null;
         }
     },
+    //批量插入组成物
+    batchUpdateComponent: function () {
+        $.bootstrapLoading.start();
+        let me = componentOprObj, that = gljComponentOprObj, re = repositoryGljObj,
+            updateArr = [],
+            updateBasePrc = [],
+            IDMapping = {};
+        let formData = new FormData();
+        //当前工料机的工料机类型
+        let currentGljType = re.currentGlj.gljType;
+        let thisTypeGljList = _.filter(re.gljList, function (data) {
+            return data.gljType == currentGljType;
+        });
+        for(let glj of thisTypeGljList){
+            let gljComponent = glj.component ? glj.component : [];
+            let newComponent = [];
+            if(me.insertType === 'batch'){
+                for(let selectedComponent of me.selectedList){
+                    let isExist = false;
+                    for(let gljPerComponent of gljComponent){
+                        if(selectedComponent.ID === gljPerComponent.ID){
+                            //newComponent.push({ID: selectedComponent.ID, consumeAmt: gljPerComponent.consumeAmt});
+                            isExist = true;
+                            break;
+                        }
+                    }
+                    if(!isExist){
+                        newComponent.push({ID: selectedComponent.ID, consumeAmt: 0});
+                    }
+                }
+                newComponent = newComponent.concat(gljComponent);
+            }
+            else if(me.insertType === 'batchClear'){//去除消耗量为0的组成物
+                for(let gljPerComponent of gljComponent){
+                    if(gljPerComponent.consumeAmt && gljPerComponent.consumeAmt != 0){
+                        newComponent.push({ID: gljPerComponent.ID, consumeAmt: gljPerComponent.consumeAmt});
+                    }
+                }
+            }
+            let gljBasePrc = that.reCalGljBasePrc(re.getCurrentComponent(newComponent));
+            if(gljBasePrc != glj.basePrice){
+                updateBasePrc.push({gljId: glj.ID, gljType: currentGljType, basePrice: gljBasePrc});
+            }
+            IDMapping[glj.ID] = {component : newComponent, basePrice: gljBasePrc};
+            updateArr.push({ID: glj.ID, component: newComponent, basePrice: gljBasePrc});
+        }
+        formData.append('compressData', LZString.compressToUTF16(JSON.stringify(updateArr)));
+        $.ajax({
+            url: 'api/batchUpdateComponent',
+            type: 'POST',
+            data: formData,
+            cache: false,
+            contentType: false,
+            processData: false,
+            success: function(response){
+                if (response.err === 0) {
+                    //更新缓存数据
+                    for(let glj of thisTypeGljList){
+                        if(glj.ID === re.currentGlj.ID){
+                            re.currentComponent =  re.getCurrentComponent(IDMapping[glj.ID]['component']);
+                            sheetCommonObj.cleanData(that.workBook.getSheet(0), that.setting, -1);
+                            sheetsOprObj.showData(that.workBook.getSheet(0), that.setting, re.currentComponent);
+                        }
+                        glj.component = IDMapping[glj.ID]['component'];
+                        glj.basePrice = IDMapping[glj.ID]['basePrice'];
+                    }
+                    re.reSetGljBasePrc(thisTypeGljList);
+                    if($('#component').is(':visible')){
+                        $('#component').modal('hide');
+                    }
+                    $.bootstrapLoading.end();
+                    //更新定额
+                    if(updateBasePrc.length > 0){
+                        re.updateRationBasePrcRq(updateBasePrc, that.workBook);
+                    }
+                } else {
+                    if($('#component').is(':visible')){
+                        $('#component').modal('hide');
+                    }
+                    $.bootstrapLoading.end();
+                }
+            },
+            error: function(jqXHR){
+                alert(`与服务器通信发生错误${jqXHR.status} ${jqXHR.statusText}`);
+                $('#component').modal('hide');
+                $.bootstrapLoading.end();
+            }
+        });
+
+    },
     //组成物窗口按钮操作
     componentsBtnOpr: function (conf) {//确定、取消、关闭按钮
         let me = componentOprObj, that = gljComponentOprObj, re = repositoryGljObj;
         conf.click(function () {
-            //添加选择添加的组成物
-            let updateArr = [];
-            let newComponent = [];
-            for(let i = 0, len = me.selectedList.length; i < len; i++){
-                let isExist = false;
-                for(let j = 0, jLen = re.currentGlj.component.length; j < jLen; j++){
-                    if(me.selectedList[i].ID === re.currentGlj.component[j].ID){
-                        newComponent.push({ID: me.selectedList[i].ID, consumeAmt: re.currentGlj.component[j].consumeAmt});
-                        isExist = true;
-                        break;
+            if(me.insertType === 'single'){
+                let updateBasePrc = [];
+                //添加选择添加的组成物
+                let updateArr = [];
+                let newComponent = [];
+                for(let i = 0, len = me.selectedList.length; i < len; i++){
+                    let isExist = false;
+                    for(let j = 0, jLen = re.currentGlj.component.length; j < jLen; j++){
+                        if(me.selectedList[i].ID === re.currentGlj.component[j].ID){
+                            newComponent.push({ID: me.selectedList[i].ID, consumeAmt: re.currentGlj.component[j].consumeAmt});
+                            isExist = true;
+                            break;
+                        }
+                    }
+                    if(!isExist){
+                        newComponent.push({ID: me.selectedList[i].ID, consumeAmt: 0});
                     }
                 }
-                if(!isExist){
-                    newComponent.push({ID: me.selectedList[i].ID, consumeAmt: 0});
+                re.currentGlj.component = newComponent;
+                let gljBasePrc = that.reCalGljBasePrc(re.getCurrentComponent(re.currentGlj.component));
+                if(gljBasePrc !== re.currentGlj.basePrice){
+                    re.currentGlj.basePrice = gljBasePrc;
+                    re.reshowGljBasePrc(re.currentGlj);
+                    updateBasePrc.push({gljId: re.currentGlj.ID, gljType: re.currentGlj.gljType, basePrice: gljBasePrc});
+                    re.updateRationBasePrcRq(updateBasePrc, that.workBook);
                 }
+                updateArr.push(re.currentGlj);
+                that.updateComponent(updateArr);
+                $('#component').modal('hide');
+                //$('#componentsCacnel').click();
             }
-            re.currentGlj.component = newComponent;
-            let gljBasePrc = that.reCalGljBasePrc(re.getCurrentComponent(re.currentGlj.component));
-            if(gljBasePrc !== re.currentGlj.basePrice){
-                re.currentGlj.basePrice = gljBasePrc;
-                re.reshowGljBasePrc(re.currentGlj);
+            else {
+                me.batchUpdateComponent();
             }
-            updateArr.push(re.currentGlj);
-            that.updateComponent(updateArr);
-            $('#componentsCacnel').click();
         });
     }
 };

+ 116 - 30
web/maintain/std_glj_lib/js/glj.js

@@ -39,12 +39,12 @@ let repositoryGljObj = {
     currentCache: null,
     parentNodeIds: {},
     gljList: [],
-    allowComponent: [202, 203, 204, 301, 4],//可带组成物类型:混凝土、砂浆、配合比、机械台班
-    componentGljType: [201, 302, 303, 4],//可成为组成物的工料机类型: 普通材料、 机械组成物、 机上人工
     //materialType: ['钢材', '木材', '水泥', '钢筋', '标准砖'],//三材类型:钢材1、钢筋101、木材2、水泥3、标准砖4
     materialType: {textArr: ['钢材', '钢筋', '木材', '水泥', '标准砖'], comboItems: [{text: '钢材', value: 1}, {text: '钢筋', value: 2},{text: '木材', value: 3},//三材类型:钢材1、钢筋101、木材2、水泥3、标准砖4
          {text: '水泥', value: 4}, {text: '标准砖', value: 5}]},
     materialTypeIdx: {'1': '钢材', '2': '钢筋', '3': '木材', '4': '水泥', '5': '标准砖'},
+    machineModel: {textArr: ['特', '大', '中', '小'], comboItems: [{text: '特', value: 1}, {text: '大', value: 2},{text: '中', value: 3}, {text: '小', value: 4}]},
+    machineModelIdx: {'1': '特', '2': '大', '3': '中', '4': '小'},
     distTypeTree: null,//add
     setting: {
         owner: "glj",
@@ -58,6 +58,7 @@ let repositoryGljObj = {
             {headerName:"调整系数",headerWidth:60,dataCode:"adjCoe", dataType: "Number", hAlign: "center", vAlign: "center"},
             {headerName:"三材类别",headerWidth:90,dataCode:"materialType", dataType: "String", hAlign: "center", vAlign: "center"},
             {headerName:"三材系数",headerWidth:60,dataCode:"materialCoe", dataType: "Number", hAlign: "center", vAlign: "center"},
+            {headerName:"机型",headerWidth:60,dataCode:"model", dataType: "Number", hAlign: "center", vAlign: "center"},
         ],
         view:{
             comboBox:[
@@ -67,6 +68,14 @@ let repositoryGljObj = {
             ]
         }
     },
+    existsGljType: function (gljType, v) {
+        for(let attr in gljType){
+            if(gljType[attr] == v){
+                return true;
+            }
+        }
+        return false;
+    },
     setUnitCombo: function (sheet, headers) {
         let me = this;
         sheet.suspendPaint();
@@ -97,15 +106,19 @@ let repositoryGljObj = {
                 children: [],
                 parent: null
             }
-            distTypeTree.distTypes[distTypeTree.prefix + typeData.ID] = typeObj;
-            distTypeTree.distTypesArr.push(typeObj);
+            if(allowGljType.includes(typeData.ID)){
+                distTypeTree.distTypes[distTypeTree.prefix + typeData.ID] = typeObj;
+                distTypeTree.distTypesArr.push(typeObj);
+            }
         });
         gljDistType.forEach(function (typeData) {
-            distType = distTypeTree.distTypes[distTypeTree.prefix + typeData.ID];
-            let parent = distTypeTree.distTypes[distTypeTree.prefix + typeData.ParentID];
-            if(parent){
-                distType.parent = parent;
-                parent.children.push(distType);
+            if(allowGljType.includes(typeData.ID)){
+                distType = distTypeTree.distTypes[distTypeTree.prefix + typeData.ID];
+                let parent = distTypeTree.distTypes[distTypeTree.prefix + typeData.ParentID];
+                if(parent){
+                    distType.parent = parent;
+                    parent.children.push(distType);
+                }
             }
         });
         distTypeTree.distTypesArr.forEach(function (distTypeObj) {
@@ -208,11 +221,13 @@ let repositoryGljObj = {
         if (me.workBook) {
             let cacheSection = data;
             sheetCommonObj.cleanData(me.workBook.getSheet(0), me.setting, -1);
-            sheetsOprObj.showData(me.workBook.getSheet(0), me.setting, cacheSection, me.distTypeTree, me.materialTypeIdx);
-            sheetCommonObj.setDynamicCombo(me.workBook.getActiveSheet(), 0, 5, me.workBook.getActiveSheet().getRowCount(), me.distTypeTree.comboDatas, false, 'text');
+            sheetsOprObj.showData(me.workBook.getSheet(0), me.setting, cacheSection, me.distTypeTree, me.materialTypeIdx, me.machineModelIdx);
+            sheetCommonObj.setDynamicCombo(me.workBook.getActiveSheet(), 0, 5, me.workBook.getActiveSheet().getRowCount(), me.distTypeTree.comboDatas, 10, 'text');
             sheetCommonObj.setDynamicCombo(me.workBook.getActiveSheet(), 0, 7, me.workBook.getActiveSheet().getRowCount(), me.materialType.comboItems, false, 'text');
+            sheetCommonObj.setDynamicCombo(me.workBook.getActiveSheet(), 0, 9, me.workBook.getActiveSheet().getRowCount(), me.machineModel.comboItems, false, 'text');
             cacheSection = null;
-            me.initSel(0);
+            let selRow =  me.workBook.getActiveSheet().getSelections()[0].row;
+            me.initSel(selRow);
         }
     },
     bindEnterKey: function () {
@@ -286,10 +301,11 @@ let repositoryGljObj = {
         for(let i = 0; i < gljComponent.length; i++){
             let obj = {};
             for(let j = 0; j < me.gljList.length; j++){
+                let specs = me.gljList[j].specs ? ' ' + me.gljList[j].specs : '';
                 if(gljComponent[i].ID == me.gljList[j].ID){
                     obj.ID = me.gljList[j].ID;
                     obj.code = me.gljList[j].code;
-                    obj.name = me.gljList[j].name;
+                    obj.name = me.gljList[j].name + specs
                     obj.unit = me.gljList[j].unit;
                     obj.basePrice = me.gljList[j].basePrice;
                     obj.consumeAmt = gljComponent[i].consumeAmt;
@@ -354,6 +370,23 @@ let repositoryGljObj = {
             }
         }
     },
+    reSetGljBasePrc: function (gljs) {
+        let me = repositoryGljObj;
+        let cacheSection = me.currentCache;
+        let sheet = me.workBook.getSheet(0);
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        for(let i = 0; i < cacheSection.length; i++){
+            for(let glj of gljs){
+                if(glj.ID === cacheSection[i].ID){
+                    sheet.setValue(i, 4, glj.basePrice);
+                }
+            }
+        }
+        sheet.resumePaint();
+        sheet.resumeEvent();
+
+    },
     initSel: function (row) {
         let me = repositoryGljObj, that = gljComponentOprObj;
         sheetCommonObj.cleanSheet(that.workBook.getSheet(0), that.setting, -1);
@@ -363,7 +396,7 @@ let repositoryGljObj = {
         if(row < me.currentCache.length){
             //标记当前工料机
             me.currentGlj = me.currentCache[row];
-            if(me.allowComponent.indexOf(me.currentCache[row].gljType) !== -1){
+            if(allowComponent.includes(me.currentCache[row].gljType)){
                 //展示数据
                 if(me.currentGlj.component.length > 0){
                     me.currentComponent = me.getCurrentComponent(me.currentGlj.component);
@@ -394,7 +427,7 @@ let repositoryGljObj = {
         let thisDataCode = me.setting.header[args.col].dataCode,
             lastDataCode = me.setting.header[me.lastCell.col].dataCode;
         if(thisDataCode === 'unit'|| lastDataCode === 'unit' || thisDataCode === 'gljType' || lastDataCode === 'gljType'
-            || thisDataCode === 'materialType' || lastDataCode === 'materialType'){
+            || thisDataCode === 'materialType' || lastDataCode === 'materialType' || thisDataCode === 'model' || lastDataCode === 'model'){
             let rects = [];
             rects.push(args.sheet.getCellRect(args.row, args.col));
             if(me.lastCell){
@@ -417,7 +450,6 @@ let repositoryGljObj = {
         }
         if(isHasData){
             if(me.editingRowIdx !== me.cellRowIdx) {
-                let isComple = true;
                 let focusToCol;
                 function getFocusToCol (me){
                     if(!me.addGljObj[me.setting.header[0].dataCode]){
@@ -474,10 +506,11 @@ let repositoryGljObj = {
         if(args.row < me.currentCache.length){
             let dataCode = me.setting.header[args.col].dataCode;
             me.currentGlj = me.currentCache[args.row];
-            if(dataCode === 'code' || (dataCode === 'basePrice' && me.allowComponent.indexOf(me.currentGlj.gljType) !== -1
+            if(dataCode === 'code' || (dataCode === 'basePrice' && allowComponent.includes(me.currentGlj.gljType)
                 && me.currentGlj.component.length > 0)
                 || (dataCode === 'adjCoe' && me.currentGlj.gljType !== 1 && me.currentGlj.gljType !== 303)
-                || (dataCode === 'materialCoe' && !me.currentGlj.materialType)){
+                || (dataCode === 'materialCoe' && !me.currentGlj.materialType)
+                || (dataCode === 'model' && me.currentGlj.gljType !== 301)){
                 args.cancel = true;
             }
             else {
@@ -513,8 +546,13 @@ let repositoryGljObj = {
                             if((me.currentEditingGlj.gljType === 1 || me.currentEditingGlj.gljType === 303) && !(rObj.gljType === 1 || rObj.gljType === 303)){
                                 rObj.adjCoe = null;
                             }
-                            if(me.componentGljType.indexOf(me.currentEditingGlj.gljType) !== -1 &&
-                                !(me.currentEditingGlj.gljType === 302 && rObj.gljType === 303) && !(me.currentEditingGlj.gljType === 303 && rObj.gljType === 302)){//修改了原本是组成物的工料机
+                            //工料机类型不为机械台班时,清空机型
+                            if(me.currentEditingGlj.gljType === 301 && rObj.gljType !== 301 && me.currentEditingGlj.model){
+                                rObj.model = null;
+                            }
+                            if(componentType.includes(me.currentEditingGlj.gljType)&&
+                                !(machineComponent.includes(me.currentEditingGlj.gljType) && machineComponent.includes(rObj.gljType)) &&
+                                !(materialComponent.includes(me.currentEditingGlj.gljType) && materialComponent.includes(rObj.gljType))){//修改了原本是组成物的工料机
                                //寻找所有引用了此组成物的工料机,并从组成物中删去此工料机,并重算单价
                                 let updateGljs = me.getUpdateGljs(rObj, true);
                                 if(updateGljs.updateArr.length > 0 || updateGljs.updateBasePrcArr.length > 0){
@@ -680,8 +718,8 @@ let repositoryGljObj = {
                                     else {
                                         if(dataCode === 'basePrice'){
                                             //如果类型不为混凝土、砂浆、配合比、机械、主材且无组成物,才可删除单价 basePrice = 0
-                                            if(me.allowComponent.indexOf(updateObj.gljType) === -1 ||
-                                                (me.allowComponent.indexOf(updateObj.gljType) !== -1 && updateObj.component.length === 0)){
+                                            if(!allowComponent.includes(updateObj.gljType) ||
+                                                (allowComponent.includes(updateObj.gljType) && updateObj.component.length === 0)){
                                                 canUpdate = true;
                                                 updateObj[dataCode] = 0;
                                                 updateBasePrcArr.push({gljId: updateObj.ID, gljType: updateObj.gljType, basePrice: 0});
@@ -775,8 +813,13 @@ let repositoryGljObj = {
                     else if((pasteObj.gljType === 1 || pasteObj.gljType === 303) && typeof pasteObj.adjCoe !== 'undefined' && !isNaN(pasteObj.adjCoe) && pasteObj.adjCoe % 1 === 0) {
                         tempObj.adjCoe = pasteObj.adjCoe;
                     }
-                    if(me.componentGljType.indexOf(tempObj.gljType) !== -1 &&
-                        !(tempObj.gljType === 302 && pasteObj.gljType === 303) && !(tempObj.gljType === 303 && pasteObj.gljType === 302)){//修改了原本是组成物的工料机
+                    if(pasteObj.gljType !== 301 && tempObj.gljType === 301){
+                        tempObj.model = null;
+                    }
+                    if(componentType.includes(tempObj.gljType) &&
+                        //!(tempObj.gljType === 302 && pasteObj.gljType === 303) && !(tempObj.gljType === 303 && pasteObj.gljType === 302)){//修改了原本是组成物的工料机
+                        !(machineComponent.includes(tempObj.gljType) && machineComponent.includes(pasteObj.gljType)) &&
+                        !(materialComponent.includes(tempObj.gljType) && materialComponent.includes(pasteObj.gljType))){//修改了原本是组成物的工料机
                         //寻找所有引用了此组成物的工料机,并从组成物中删去此工料机,并重算单价
                         let updateGljs = me.getUpdateGljs(tempObj, true);
                         if(updateGljs.updateArr.length > 0 || updateGljs.updateBasePrcArr.length > 0){
@@ -850,6 +893,29 @@ let repositoryGljObj = {
                 tempObj.materialCoe = pasteObj.materialCoe !== '' ? scMathUtil.roundTo(parseFloat(pasteObj.materialCoe), -5) : null;
             }
         }
+        if(typeof pasteObj.model !== 'undefined'){
+            if(!me.machineModel.textArr.includes(pasteObj.model)){
+                isValid = false;
+            }
+            else {
+                let existsModel = false;
+                if((typeof pasteObj.gljType !== 'undefined' && pasteObj.gljType === 301) ||
+                    (tempObj.gljType && tempObj.gljType === 301)){
+                    me.machineModel.comboItems.forEach(function (item) {
+                        if(item.text === pasteObj.model){
+                            tempObj.model = item.value;
+                            existsModel = true;
+                        }
+                    });
+                    if(!existsModel){
+                        isValid = false;
+                    }
+                }
+                else {
+                    isValid = false;
+                }
+            }
+        }
         if(isValid){
             rst.updateGlj.push(tempObj);
             if(reCalBasePrc){
@@ -916,6 +982,16 @@ let repositoryGljObj = {
                 return false;
             }
         }
+        if(typeof pasteObj.model !== 'undefined' && pasteObj.model){
+            if(!me.machineModel.textArr.includes(pasteObj.model) || pasteObj.gljType !== 301){
+                return false;
+            }
+            me.machineModel.comboItems.forEach(function (item) {
+                if(item.text === pasteObj.model){
+                    pasteObj.model = item.value;
+                }
+            });
+        }
         pasteObj.basePrice = !isNaN(parseFloat(pasteObj.basePrice)) && (pasteObj.basePrice && typeof pasteObj.basePrice !== 'undefined') ? parseFloat(pasteObj.basePrice) : 0;
         if(!me.parentNodeIds["_pNodeId_" + me.gljCurTypeId]){
             pasteObj.gljClass = me.gljCurTypeId;
@@ -939,7 +1015,7 @@ let repositoryGljObj = {
                 for(let i = 0, len = info.cellRange.rowCount; i < len; i++){
                     let row = i + info.cellRange.row;
                     if(row < me.currentCache.length){
-                        if(me.allowComponent.indexOf(me.currentCache[row].gljType) !== -1 && me.currentCache[row].component.length > 0){
+                        if(allowComponent.includes(me.currentCache[row].gljType) && me.currentCache[row].component.length > 0){
                             rst = false;
                         }
                     }
@@ -996,7 +1072,7 @@ let repositoryGljObj = {
                 }
             }
             //if(info.cellRange.colCount === me.setting.header.length){
-            if(info.cellRange.colCount >= me.setting.header.length - 3 && info.cellRange.colCount <= me.setting.header.length){
+            if(info.cellRange.colCount >= me.setting.header.length - 4 && info.cellRange.colCount <= me.setting.header.length){
                 for(let i = updateCount ; i < items.length; i++){
                     if(me.isValidObj(items[i])){
                         items[i].component = [];
@@ -1011,7 +1087,7 @@ let repositoryGljObj = {
         }
         else{
             //if(info.cellRange.colCount === me.setting.header.length && info.cellRange.col + info.cellRange.colCount - 1 >= 5){
-            if(info.cellRange.colCount >= me.setting.header.length - 3 && info.cellRange.colCount <= me.setting.header.length && info.cellRange.col + info.cellRange.colCount - 1 >= 5){
+            if(info.cellRange.colCount >= me.setting.header.length - 4 && info.cellRange.colCount <= me.setting.header.length && info.cellRange.col + info.cellRange.colCount - 1 >= 5){
                 for(let i = 0; i < items.length; i++){
                     if(me.isValidObj(items[i])){
                         items[i].component = [];
@@ -1040,6 +1116,9 @@ let repositoryGljObj = {
                         else if(dCode === 'materialType'){
                             info.sheet.setValue(resumeArr[i], col, me.currentCache[resumeArr[i]][dCode] ? me.materialTypeIdx[me.currentCache[resumeArr[i]][dCode]]: '');
                         }
+                        else if(dCode === 'model'){
+                            info.sheet.setValue(resumeArr[i], col, me.currentCache[resumeArr[i]][dCode] ? me.machineModelIdx[me.currentCache[resumeArr[i]][dCode]]: '');
+                        }
                         else{
                             info.sheet.setValue(resumeArr[i], col, me.currentCache[resumeArr[i]][dCode]);
                         }
@@ -1060,10 +1139,9 @@ let repositoryGljObj = {
             me.updateRationBasePrcRq(updateBasePrcArr);
         }
     },
-    updateRationBasePrcRq: function (basePrcArr) {
+    updateRationBasePrcRq: function (basePrcArr, workBook, callback) {
         let me = this;
         me.prevent = true;
-        me.workBook.focus(false);
         $.bootstrapLoading.start();
         $.ajax({
             type: 'post',
@@ -1074,8 +1152,16 @@ let repositoryGljObj = {
                 if(result.error){
                     alert("计算定额基价失败");
                 }
-                me.workBook.focus(true);
+                if(workBook){
+                    workBook.focus(true);
+                }
+                else {
+                    me.workBook.focus(true);
+                }
                 me.prevent = false;
+                if(callback){
+                    callback();
+                }
                 $.bootstrapLoading.end();
             }
         });

+ 49 - 21
web/maintain/std_glj_lib/js/gljComponent.js

@@ -21,7 +21,7 @@ let gljComponentOprObj = {
     buildSheet: function(container) {
         let me = gljComponentOprObj;
         me.workBook = sheetCommonObj.buildSheet(container, me.setting, 30, me);
-        sheetCommonObj.bindEscKey(me.workBook, [{sheet: me.workBook.getSheet(0), editStarting: me.onCellEditStart, editEnded: me.onCellEditEnd}]);
+        //sheetCommonObj.bindEscKey(me.workBook, [{sheet: me.workBook.getSheet(0), editStarting: me.onCellEditStart, editEnded: me.onCellEditEnd}]);
         me.workBook.getSheet(0).setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader);
         me.workBook.getSheet(0).setFormatter(-1, 0, "@", GC.Spread.Sheets.SheetArea.viewport);
         sheetCommonObj.cleanSheet(me.workBook.getSheet(0), me.setting, -1);
@@ -123,7 +123,7 @@ let gljComponentOprObj = {
                     updateArr.push(that.currentGlj);
                     me.updateComponent(updateArr);
                     if(updateBasePrc.length > 0){
-                        that.updateRationBasePrcRq(updateBasePrc);
+                        that.updateRationBasePrcRq(updateBasePrc, me.workBook);
                     }
                 }
             }
@@ -151,7 +151,7 @@ let gljComponentOprObj = {
                     //控制按钮是否可用
                     let insertDis = false,
                         delDis = false;
-                    if(!(that.currentGlj && that.allowComponent.indexOf(that.currentGlj.gljType) !== -1) || (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.gljList))){
+                    if(!(that.currentGlj && allowComponent.includes(that.currentGlj.gljType)) || (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.gljList))){
                         insertDis = true;
                     }
                     if(!that.currentGlj || typeof that.currentComponent === 'undefined' || (typeof that.currentComponent !== 'undefined' && target.row >= that.currentComponent.length)){//右键定位在有组成物的行,删除键才显示可用
@@ -160,6 +160,16 @@ let gljComponentOprObj = {
                     return {
                         callback: function(){},
                         items: {
+                            "batchInsert": {name: '批量插入', disabled: insertDis, icon: 'fa-sign-in', callback: function (key, opt) {
+                                co.initRadio();
+                                co.gljCurTypeId = null;
+                                if(co.rootNode){
+                                    co.treeObj.selectNode(co.rootNode);
+                                    componentTypeTreeOprObj.onClick(null, 'componentTree', co.rootNode);
+                                }
+                                co.insertType = 'batch';
+                                $('#component').modal('show');
+                            }},
                             "insert": {name: "插入", disabled: insertDis, icon: "fa-sign-in", callback: function (key, opt) {
                                 //默认radio所有工料机
                                 co.initRadio();
@@ -169,6 +179,7 @@ let gljComponentOprObj = {
                                     co.treeObj.selectNode(co.rootNode);
                                     componentTypeTreeOprObj.onClick(null, 'componentTree', co.rootNode);
                                 }
+                                co.insertType = 'single';
                                 //弹出窗口
                                 $('#componentBtn').click();
                             }},
@@ -194,8 +205,12 @@ let gljComponentOprObj = {
                                 updateArr.push(that.currentGlj);
                                 me.updateComponent(updateArr);
                                 if(updateBasePrcArr.length > 0 && that.rationLibs.length > 0){
-                                    that.updateRationBasePrcRq(updateBasePrcArr);
+                                    that.updateRationBasePrcRq(updateBasePrcArr, me.workBook);
                                 }
+                            }},
+                            "batchClear": {name: '批量删除消耗量为0的组成物', disabled: insertDis, icon: 'fa-remove', callback: function (key, opt) {
+                                co.insertType = 'batchClear';
+                                co.batchUpdateComponent();
                             }}
                         }
                     };
@@ -208,12 +223,15 @@ let gljComponentOprObj = {
     },
     onCellEditStart: function(sender, args) {
         let me = gljComponentOprObj, that = repositoryGljObj;
+        if(me.isPending){
+            args.cancel = true;
+        }
         let rObj = me.getRowData(args.sheet, args.row, me.setting);
         me.currentEditingComponent = rObj;
         let thatRow = that.workBook.getSheet(0).getSelections()[0].row;
         if(thatRow < that.currentCache.length){
             that.currentGlj = that.currentCache[thatRow];
-            if(me.setting.view.lockedCols.indexOf(args.col) !== -1 || that.allowComponent.indexOf(that.currentGlj.gljType) === -1 ||
+            if(me.setting.view.lockedCols.indexOf(args.col) !== -1 || !allowComponent.includes(that.currentGlj.gljType) ||
                 (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.gljList)) ||
                 (args.col === 4 && (!that.currentComponent|| args.row >= that.currentComponent.length))){
                 args.cancel = true;
@@ -225,15 +243,15 @@ let gljComponentOprObj = {
     },
     onCellEditEnd: function (sender, args) {
         let me = gljComponentOprObj, that = repositoryGljObj, updateBasePrc = [];
-        let gljList = that.gljList, updateArr = [], materialComponent = [202, 203, 204], machineComponent = [302, 303];
+        let gljList = that.gljList, updateArr = [];
         //if(args.editingText !== me.currentEditingComponent.code){
         if(args.col === 0 && args.editingText && args.editingText.trim().length > 0 && args.editingText !== me.currentEditingComponent.code){
             let component = that.currentGlj.component, hasCode = false;
             for(let i = 0; i < gljList.length; i++){
                 if(gljList[i].code === args.editingText){//有效的组成物
                     hasCode = true;
-                    if((materialComponent.indexOf(that.currentGlj.gljType) !== -1 && gljList[i].gljType === 201)
-                        || (that.currentGlj.gljType === 301 && machineComponent.indexOf(gljList[i].gljType) !== -1 )
+                    if((materialAllowComponent.includes(that.currentGlj.gljType) && gljList[i].gljType === 201)
+                        || (machineAllowComponent.includes(that.currentGlj.gljType) && machineComponent.includes(gljList[i].gljType))
                         || (that.currentGlj.gljType === 4 && gljList[i].gljType === 4 && that.currentGlj.ID !== gljList[i].ID)){//普通材料
                         //是否与原有组成物不同
                         let isExist = false;
@@ -292,11 +310,11 @@ let gljComponentOprObj = {
 
                     }
                     else{
-                        if(materialComponent.indexOf(that.currentGlj.gljType) === 1){
-                            alert("该组成物只能是普通材料!");
+                        if(materialAllowComponent.includes(that.currentGlj.gljType)){
+                            alert("无效的组成物!");
                         }
-                        else if(that.currentGlj.gljType === 301){
-                            alert("该组成物只能是机械组成物或机上人工!")
+                        else if(machineAllowComponent.includes(that.currentGlj.gljType)){
+                            alert("无效的组成物!")
                         }
                         args.sheet.setValue(args.row, args.col, me.currentEditingComponent[me.setting.header[args.col].dataCode] ?
                             me.currentEditingComponent[me.setting.header[args.col].dataCode]: '');
@@ -346,7 +364,10 @@ let gljComponentOprObj = {
         if(updateArr.length > 0){
             me.updateComponent(updateArr);
             if(updateBasePrc.length > 0){
-                that.updateRationBasePrcRq(updateBasePrc)
+                me.isPending = true;
+                that.updateRationBasePrcRq(updateBasePrc, me.workBook, function () {
+                    me.isPending = false;
+                });
             }
         }
         let focusInter = setInterval(function () {
@@ -358,27 +379,29 @@ let gljComponentOprObj = {
     },
     onClipboardPasting: function (sender, info) {
         let me = gljComponentOprObj;
+        if(me.isPending){
+            info.cancel = true
+        }
         let that = repositoryGljObj;
         let maxCol = info.cellRange.col + info.cellRange.colCount - 1;
         //复制的列数超过正确的列数,不可复制
         if(info.cellRange.col !== 0 && info.cellRange.col !== 4 || info.cellRange.colCount > 1 || (that.currentGlj.gljType === 4 && that.isComponent(that.currentGlj.ID, that.gljList))){
-            args.cancel = true;
+            info.cancel = true;
         }
     },
     onClipboardPasted: function (sender, info) {
-        let me = gljComponentOprObj, that = repositoryGljObj, updateArr = [] ,materialComponent = [202, 203, 204], machineComponent = [302, 303],
-            component = that.currentGlj.component, newComponent = [], concatComponent = [], isChange = false, updateBasePrc = [];
+        let me = gljComponentOprObj, that = repositoryGljObj, updateArr = [],
+            component = that.currentGlj.component, isChange = false, updateBasePrc = [];
         let items = sheetCommonObj.analyzePasteData(me.setting, info);
         let gljCache = that.gljList;
-        let resumeArr = [];
         if(info.cellRange.col === 0){
             for(let i = 0; i < items.length; i++){
                 let existCode = false;
                 for(let j = 0; j < gljCache.length; j++){
                     if(items[i].code === gljCache[j].code){
                         existCode = true;
-                        if((materialComponent.indexOf(that.currentGlj.gljType) !== -1 && gljCache[j].gljType === 201)
-                            || (that.currentGlj.gljType === 301 && machineComponent.indexOf(gljCache[j].gljType) !== -1 )
+                        if((materialAllowComponent.includes(that.currentGlj.gljType) && gljCache[j].gljType === 201)
+                            || (machineAllowComponent.includes(that.currentGlj.gljType) && machineComponent.includes(gljCache[j].gljType))
                             || (that.currentGlj.gljType === 4 && gljCache[j].gljType === 4 && that.currentGlj.ID !== gljCache[i].ID)){
                             //是否与原有组成物不同
                             let isExist = false;
@@ -481,7 +504,10 @@ let gljComponentOprObj = {
         if(updateArr.length > 0){
             me.updateComponent(updateArr);
             if(updateBasePrc.length > 0){
-                that.updateRationBasePrcRq(updateBasePrc);
+                me.isPending = true;
+                that.updateRationBasePrcRq(updateBasePrc, me.workBook, function () {
+                    me.isPending = false;
+                });
             }
         }
         else {
@@ -507,7 +533,6 @@ let gljComponentOprObj = {
                 if(result.data.length > 0){
                     if(result.data[0]){
                         that.currentComponent =  that.getCurrentComponent(result.data[0].component);
-                        me.workBook.getSheet(0).getSelections()[0]
                         sheetCommonObj.cleanData(me.workBook.getSheet(0), me.setting, -1);
                         sheetsOprObj.showData(me.workBook.getSheet(0), me.setting, that.currentComponent);
                     }
@@ -523,6 +548,9 @@ let gljComponentOprObj = {
             //gljBasePrc = scMathUtil.roundTo(scMathUtil.roundTo(roundBasePrc * parseFloat(component[i].consumeAmt), -2) + gljBasePrc, -2); 旧算法
             gljBasePrc = scMathUtil.roundTo(scMathUtil.roundTo(roundBasePrc * roundConsumeAmt, me.processDecimal) + gljBasePrc, me.processDecimal);
         }
+        console.log(`scMathUtil.roundTo(gljBasePrc, -2)`);
+        console.log(scMathUtil.roundTo(gljBasePrc, -2));
+        console.log(scMathUtil.roundTo(gljBasePrc, -3));
         return scMathUtil.roundTo(gljBasePrc, -2);
     }
 };

+ 13 - 1
web/maintain/std_glj_lib/js/sheetsOpr.js

@@ -22,7 +22,7 @@ let sheetsOprObj = {
             area.vAlign(GC.Spread.Sheets.VerticalAlign.center);
         }
     },
-    showData: function(sheet, setting, data, distTypeTree, materialTypeIdx) {
+    showData: function(sheet, setting, data, distTypeTree, materialTypeIdx, machineModelIdx) {
         var me = this, ch = GC.Spread.Sheets.SheetArea.viewport;
         sheet.suspendPaint();
         sheet.suspendEvent();
@@ -45,6 +45,7 @@ let sheetsOprObj = {
                 sheet.setFormatter(-1, col, setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
             }
             for (var row = 0; row < data.length; row++) {
+               // console.log(row);
                 //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
                 if(setting.header[col].dataCode === 'gljType' && data[row].gljType){
                     let distTypeVal =  distTypeTree.distTypes[distTypeTree.prefix + data[row].gljType].data.fullName;
@@ -53,6 +54,9 @@ let sheetsOprObj = {
                 else if(setting.header[col].dataCode === 'materialType' && data[row].materialType){
                     sheet.setValue(row, col, materialTypeIdx[data[row].materialType]);
                 }
+                else if(setting.header[col].dataCode === 'model' && data[row].model){
+                    sheet.setValue(row, col, machineModelIdx[data[row].model]);
+                }
                 else if(setting.header[col].dataCode === 'select'){
                     if(data[row].isChecked === true){
                         sheet.getCell(row, col).value(1);
@@ -74,6 +78,7 @@ let sheetsOprObj = {
         let items = comboBoxCellType.items();
         let materialTypeCombo = sheet.getCellType(row, 7);
         let materialItems = materialTypeCombo.items();
+        let machineItems = sheet.getCellType(row, 9).items();
         for (var col = 0; col < setting.header.length; col++) {
             if(setting.header[col].dataCode === 'gljType'){
                 items.forEach(function(item){
@@ -92,6 +97,13 @@ let sheetsOprObj = {
                     }
                 });
             }
+            else if(setting.header[col].dataCode === 'model'){
+                machineItems.forEach(function(item){
+                    if(sheet.getValue(row, col) === item.text){
+                        rst[setting.header[col].dataCode] = item.value;
+                    }
+                });
+            }
             else if (setting.header[col].dataCode === 'code'){
                 if(repositoryGljObj){
                     let gljList = repositoryGljObj.gljList,

+ 32 - 0
web/over_write/js/chongqing_2018.js

@@ -0,0 +1,32 @@
+/**
+ * Created by Zhong on 2018/8/14.
+ */
+//允许使用的工料机类型:人工、普通材料、混凝土、砂浆、配合比、商品混凝土、商品砂浆、其他材料费、机械台班、机上人工、机械组成物、仪器仪表、燃料动力费、折旧费、
+// 检修费、维护费、安拆费及场外运费、校验费、其他费用、其他施工机具使用费、主材、企业管理费、利润、一般风险费
+if(allowGljType){
+    allowGljType = [1, 201, 202, 203, 204, 205, 206, 207, 301, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 4, 6, 7, 8];
+}
+if(allowComponent){
+    //允许含有组成物的工料机类型:混凝土、砂浆、配合比、机械台班、仪器仪表、主材
+    allowComponent = [202, 203, 204, 301, 304, 4];
+}
+if(componentType){
+    //可以作为组成物的工料机类型:普通材料、机械组成物、机上人工、燃料动力费、折旧费、检修费、维护费、安拆费及场外运费、校验费、其他费用、主材
+    componentType = [201, 303, 305, 306, 307, 308, 309, 310, 311, 4];
+}
+if(machineAllowComponent){
+    //允许含有组成物的机械工料机类型:机械台班、仪器仪表
+    machineAllowComponent = [301, 304];
+}
+if(machineComponent){
+    //可以作为机械工料机组成物的工料机类型:机械组成物、机上人工、燃料动力费、折旧费、检修费、维护费、安拆费及场外运费、校验费、其他费用
+    machineComponent = [303, 305, 306, 307, 308, 309, 310, 311];
+}
+if(materialAllowComponent){
+    //允许含有组成物的材料工料机类型:混凝土、砂浆、配合比
+    materialAllowComponent = [202, 203, 204];
+}
+if(materialComponent){
+    //可以作为材料工料机组成物的工料机类型:普通材料
+    materialComponent = [201];
+}

+ 11 - 0
web/users/css/custom.css

@@ -0,0 +1,11 @@
+
+.engineeringInput::-webkit-outer-spin-button,
+.engineeringInput::-webkit-inner-spin-button {
+  -webkit-appearance: none;
+}
+.engineeringInput {
+  -moz-appearance: textfield;
+}
+.btn-link:focus, .btn-link:hover{
+  text-decoration: none
+}

+ 18 - 4
web/users/css/style.css

@@ -82,7 +82,7 @@ body{
   left:124px;
   padding-top: 100px;
   border-right: 1px solid #ddd;
-  width: 200px
+  width: 250px
 }
 .panel-content{
   padding:115px 0 0;
@@ -96,7 +96,7 @@ body{
   margin:0 15px 15px;
 }
 .panel-sidebar+.panel-content{
-  padding: 115px 0 0 200px;
+  padding: 115px 0 0 250px;
 }
 .panel-title, .panel-title>.title-bar {
   height:50px;
@@ -112,13 +112,13 @@ body{
   box-shadow: 0 1px 3px rgba(0,0,0,.05)
 }
 .panel-sidebar .panel-title{
-  width:200px;
+  width:250px;
   border-right: 1px solid #ddd;
   box-shadow: 0 1px 3px rgba(0,0,0,.1);
 }
 .panel-content .panel-title{
   left: 0;
-  padding-left: 324px;
+  padding-left: 374px;
   padding-right: 20px;
 }
 .panel-content .panel-title.fluid{
@@ -278,6 +278,20 @@ body{
 .nav-list li.active .badge{
   background:#207fd1
 }
+.nav-list li span.title{
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  width:170px;
+  overflow: hidden;
+  display: inline-block;
+}
+.nav-list li span.text-muted{
+  position: absolute;
+  right: 0;
+  top:0;
+  text-align: right;
+}
+
 /*内容区*/
 .c-header {
   padding:0 0 5px

+ 7 - 8
web/users/js/col_setting.js

@@ -321,22 +321,21 @@ $('#set-column').on('shown.bs.modal', function () {
     }
 });
 
-$('#set-glj-col').on('show.bs.modal', function () {
+$('#other_setting').on('show.bs.modal', function () {
     let glj_col_setting = JSON.parse($("#glj_col").val());
-    if(glj_col_setting.showAdjustPrice){
-        $('#adjustPrice_cb').prop('checked',true);
-    }else {
-        $('#adjustPrice_cb').prop('checked',false);
-    }
+    glj_col_setting.showAdjustPrice?$('#adjustPrice_cb').prop('checked',true): $('#adjustPrice_cb').prop('checked',false);
+    let isInstall = $("#isInstall").val() == 'true'?true:false;
+    $('#isInstall_cb').prop('checked',isInstall);
 });
 
-$('#set-glj-comf').click(function () {
-
+$('#other_setting_comf').click(function () {
     let showAdjustPrice =  $('#adjustPrice_cb').prop('checked');
+    let isInstall =  $('#isInstall_cb').prop('checked');
     let glj_col_setting = {
         showAdjustPrice :showAdjustPrice
     };
     $("#glj_col").val(JSON.stringify(glj_col_setting));
+    $("#isInstall").val(isInstall);
 });
 
 $('#col-count').change(function () {

+ 47 - 10
web/users/js/compilation.js

@@ -315,6 +315,26 @@ $(document).ready(function() {
 
     });
 
+    //添加工程专业
+    $("#addEngineerConfirm").click(async function() {
+        if($('#name').val() == ''){
+            $("#nameError").show();
+            return;
+        }
+        if($('#feeName').val() == ''){
+            $("#feeNameError").show();
+            return;
+        }
+        if($('#engineeringInput').val() == ''){
+            $("#engineeringError").show();
+            return;
+        }
+        $("#addEngineerConfirm").attr("disabled",true);//防止重复提交
+        $("#addEngineerForm").submit();
+
+
+    });
+    //
 
 });
 
@@ -597,7 +617,7 @@ function switchChange(element) {
     return !currentStatus;
 }
 
-function editEngineerName(selector) {
+function editEngineer(selector) {
     let engineerName =  $(selector).prev("span").text();
     let parentDiv = $(selector).parent("div");
     parentDiv.next("div").find("input").val(engineerName);
@@ -605,23 +625,40 @@ function editEngineerName(selector) {
     parentDiv.next("div").show();
 }
 
-function confirmName(selector,engineerID) {
+function confirmUpdate(selector,engineerID) {
     let inputDiv = $(selector).parents(".input_group_div");
-    let oldEngineerName =  inputDiv.prev("div").find("span").text();
-    let newEngineerName = $(selector).parent(".input-group-btn").prev("input").val();
-    if(newEngineerName === "" || newEngineerName == oldEngineerName||!engineerID){
+    let input = $(selector).parent(".input-group-btn").prev("input");
+    let oldValue = inputDiv.prev("div").find("span").text();
+    let newValue = input.val();
+    let key = input.attr("name");
+    if(newValue == "" || newValue==oldValue || !engineerID){
         inputDiv.prev("div").show();
         inputDiv.hide();
         return;
     }
+     let updateData = {};
+     updateData[key] = newValue;
+     updateEngineer(engineerID,updateData,function () {
+        inputDiv.prev("div").find("span").text(newValue);
+     });
+     inputDiv.prev("div").show();
+     inputDiv.hide();
+}
 
-    updateEngineer(engineerID,{name:newEngineerName},function () {
-        inputDiv.prev("div").find("span").text(newEngineerName);
-    });
-    inputDiv.prev("div").show();
-    inputDiv.hide();
+function deleteEngineerClick(engineerID,element) {
+    console.log(engineerID);
+    console.log(element);
+    hintBox.infoBox('操作确认', '是否删除所选工程专业?', 2, async function () {
+        try {
+            let result  = await ajaxPost('/compilation/delete-engineer',{id:engineerID});
+            $(element).parent("td").parent("tr").remove();
+        }catch (err){
+            console.log(err);
+        }
+    }, null,['确定','取消'],false);
 }
 
+
 function engineerVisibleChange(checkBox,engineerID) {
     if(engineerID){
         updateEngineer(engineerID,{visible:checkBox.checked});

+ 84 - 1
web/users/js/user.js

@@ -12,6 +12,89 @@ $(document).ready(function() {
         let string = $(this).text();
         let selector = $(this).parent().parent();
         selector.next("input:hidden").val(value);
-        selector.prev("button").html(string + ' <span class="caret"></span>');
+        selector.prev("button").children("lable").text(string);
+        //selector.prev("button").html(string + ' <span class="caret"></span>');
     });
 });
+let cacheUser = null;
+
+async function getUserInfo(ID) {
+    console.log(ID);
+    let user = await ajaxPost("/user/findByID",{ID:ID});
+    let infoString = `<tr><th>注册时间</th><td>${user.create_time}</td><th>最近登录</th><td>${user.last_login}</td></tr>
+                      <tr><th>手机</th><td >${user.mobile}</td><th>邮箱</th><td>${user.email}</td></tr>
+                      <tr><th>姓名</th><td colspan="3" id>${user.real_name}</td></tr>
+                      <tr><th>企业名称</th><td colspan="3">${user.company}</td></tr>
+                      <tr><th>企业地区</th><td>${user.province}</td><th>企业类型</th><td>${user.company_type}</td></tr>
+                      <tr><th>企业规模</th><td colspan="3">${user.company_scale}</td></tr>`;
+    $('#userInfoTable').html(infoString);
+}
+
+async function getUserUpgradeInfo(ID){
+    try {
+        cacheUser  = await ajaxPost("/user/findByID",{ID:ID});
+        refreshUpgradeTable(cacheUser);
+    }catch (err){
+        console.log(err);
+    }
+
+}
+
+function refreshUpgradeTable(user) {
+    let compilationTable = ' <tr><th colspan="2">专业版升级</th></tr>';
+    let test = true;
+    for(let c of compilationList){
+        compilationTable += `<tr><th>${c.name}</th>
+                                <td>${getButtonHtml(c._id)}
+                                 </td> 
+                             </tr>`;
+    }
+    $('#upgrade_table').html(compilationTable);
+
+    function getButtonHtml(ID) {
+        let updateString = `<div class="btn-group"><button class="btn btn-success  disabled" disabled="disabled">已启用</button><button class="btn btn-default" title="关闭" onclick="updateUser('${ID}','close')">关闭</button></div>`;
+        let closeString = `<div class="btn-group"> <button class="btn btn-default" title="启用" onclick="updateUser('${ID}','upgrade')">启用</button> <button class="btn btn-danger disabled" disabled="disabled">已关闭</button> </div>`;
+        let upgradeInfo = _.find(user.upgrade_list,{'compilationID':ID});
+        if(upgradeInfo){
+            if(upgradeInfo.isUpgrade == true){
+                return updateString + upgradeInfo.remark;
+            }else {
+                return closeString + upgradeInfo.remark;
+            }
+        }else {
+            return closeString;
+        }
+    }
+}
+
+
+async function updateUser(compilationID,type) {
+    if(cacheUser){
+        let upgrade_list = cacheUser.upgrade_list?cacheUser.upgrade_list:[];
+        let upgradeInfo = _.find(upgrade_list,{'compilationID':compilationID});
+        if(!upgradeInfo){
+            upgradeInfo = {
+                compilationID:compilationID,//编办ID
+                upgrade_time:new Date().getTime(),
+                isUpgrade:true,
+            };
+            upgrade_list.push(upgradeInfo);
+        }
+        if(type == 'upgrade'){
+            upgradeInfo.isUpgrade = true;
+            upgradeInfo.remark = adminName + " "+ moment().format("YYYY-MM-DD") +" 启用";
+        }else {
+            upgradeInfo.isUpgrade = false;
+            upgradeInfo.remark = adminName + " "+ moment().format("YYYY-MM-DD") +" 关闭";
+        }
+        try {
+            await ajaxPost("/user/updateUser",{ID:cacheUser._id,updateData:{upgrade_list:upgrade_list}});
+            cacheUser.upgrade_list = upgrade_list;
+            refreshUpgradeTable(cacheUser);
+        }catch (err){
+            console.log(err);
+        }
+
+    }
+
+}

+ 62 - 10
web/users/views/compilation/add.html

@@ -27,18 +27,19 @@
                         </div>
                     </div>
                     <div class="col-md-12">
-                        <legend>
+                        <legend style="margin-bottom: 0px;">
                             工程专业
                         </legend>
+                        <a class="btn btn-link btn-sm"  data-toggle="modal" data-target="#addEngineer">添加</a>
                         <table class="table engineer_table">
                             <thead>
                             <tr>
-                                <th>工程名称</th>
+                                <th>工程专业</th>
+                                <th>费用标准</th>
+                                <th>定额取费专业</th>
                                 <th>标准清单</th>
                                 <th>定额库</th>
                                 <th>人材机库</th>
-                                <th>费率标准</th>
-                                <th>人工系数</th>
                                 <th>前台显示</th>
                                 <th>操作</th>
                             </tr>
@@ -47,22 +48,36 @@
                                 <% engineeringList.forEach(function(engineering) {%>
                                 <tr >
                                     <td>
-                                        <div><span><%= engineering.name %></span> <a onclick='editEngineerName(this)'><i class="glyphicon glyphicon-pencil"></i></a></div>
+                                        <div><span><%= engineering.name %></span> <a onclick='editEngineer(this)'><i class="glyphicon glyphicon-pencil"></i></a></div>
                                         <div class="input-group input-group-sm input_group_div" style="width:200px;display: none">
-                                            <input class="form-control">
+                                            <input class="form-control" name="name">
                                             <div class="input-group-btn">
-                                                <button type="button" class="btn btn-success" onclick='confirmName(this,"<%= engineering._id.toString()%>")'>
+                                                <button type="button" class="btn btn-success" onclick='confirmUpdate(this,"<%= engineering._id.toString()%>")'>
                                                     <span class="glyphicon glyphicon-ok"></span></button>
                                             </div>
                                         </div>
                                     </td>
+                                    <td><div><span><%= engineering.feeName %></span> <a onclick='editEngineer(this)'><i class="glyphicon glyphicon-pencil"></i></a></div>
+                                        <div class="input-group input-group-sm input_group_div" style="width:200px;display: none">
+                                            <input class="form-control" name="feeName">
+                                            <div class="input-group-btn">
+                                                <button type="button" class="btn btn-success" onclick='confirmUpdate(this,"<%= engineering._id.toString()%>")'>
+                                                    <span class="glyphicon glyphicon-ok"></span></button>
+                                            </div>
+                                        </div></td>
+                                    <td><div><span><%= engineering.engineering %></span> <a onclick='editEngineer(this)'><i class="glyphicon glyphicon-pencil"></i></a></div>
+                                        <div class="input-group input-group-sm input_group_div" style="width:200px;display: none">
+                                            <input class="form-control engineeringInput" type="number" name="engineering">
+                                            <div class="input-group-btn">
+                                                <button type="button" class="btn btn-success" onclick='confirmUpdate(this,"<%= engineering._id.toString()%>")'>
+                                                    <span class="glyphicon glyphicon-ok"></span></button>
+                                            </div>
+                                        </div></td>
                                     <td><%= engineering.bill_lib.length %></td>
                                     <td><%= engineering.ration_lib.length %></td>
                                     <td><%= engineering.glj_lib.length %></td>
-                                    <td><%= engineering.fee_lib.length %></td>
-                                    <td><%= engineering.artificial_lib.length %></td>
                                     <td><label><input type="checkbox"  <% if (engineering.visible) { %>checked<% } %>  onclick='engineerVisibleChange(this,"<%= engineering._id.toString()%>")'> 显示</label></td>
-                                    <td><a href="/compilation/<%= section %>/<%= valuationId %>/<%= engineering._id.toString()%>">编辑</a></td>
+                                    <td><a class="btn-link" href="/compilation/<%= section %>/<%= valuationId %>/<%= engineering._id.toString()%>">编辑</a>/<a onclick="deleteEngineerClick('<%= engineering._id.toString()%>',this)" class='btn btn-link btn-sm' style="padding: 0px">删除</a></td>
                                 </tr>
                                 <% }) %>
                             </tbody>
@@ -75,6 +90,43 @@
         </div>
     </div>
 </div>
+
+<!--添加工程专业窗口-->
+<div class="modal fade in" id="addEngineer"  role="dialog" tabindex="-1">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
+                <h4 class="modal-title">添加新的工程专业</h4>
+            </div>
+            <div class="modal-body">
+                <form id="addEngineerForm" method="post" action="/compilation/addEngineer" enctype="application/x-www-form-urlencoded21">
+                    <div class="form-group">
+                        <label>工程专业</label>
+                        <input class="form-control" type="text" name ="name" id="name" placeholder="请输入工程专业名称">
+                        <small class="form-text text-danger" id="nameError" style="display: none">请输入工程专业名称。</small>
+                    </div>
+                    <div class="form-group">
+                        <label>费用标准</label>
+                        <input class="form-control" type="text" name ="feeName" id="feeName" placeholder="请输入费用标准">
+                        <small class="form-text text-danger" id="feeNameError" style="display: none">请输入费用标准。</small>
+                    </div>
+                    <div class="form-group">
+                        <label>定额取费专业</label>
+                        <input class="form-control engineeringInput" type="number" name ="engineering" id="engineeringInput" placeholder="请输入定额取费专业">
+                        <small class="form-text text-danger" id="engineeringError" style="display: none">请输入定额取费专业。</small>
+                    </div>
+                    <input type="hidden" name="valuationID" value="<%= valuationId %>">
+                </form>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-primary" id="addEngineerConfirm">确定添加</button>
+            </div>
+        </div>
+    </div>
+</div>
+<script src="/public/web/commonAlert.js"></script>
 <script type="text/javascript" src="/public/web/common_ajax.js"></script>
 <script type="text/javascript" src="/web/users/js/compilation.js"></script>
 <%include ../compilation/modal.html %>

+ 1 - 1
web/users/views/compilation/common.html

@@ -8,7 +8,7 @@
         <div class="nav-box">
             <ul class="nav-list list-unstyled" id="version-select">
                 <% compilationList.forEach(function (compilation){ %>
-                <li <% if(selectedCompilation._id.toString() === compilation._id.toString()) { %>class="active"<% } %>><a href="/compilation?id=<%= compilation._id %>"><span><%= compilation.name %></span><% if (!compilation.is_release) { %><span class="text-muted">(未发布)</span><% } %></a></li>
+                <li <% if(selectedCompilation._id.toString() === compilation._id.toString()) { %>class="active"<% } %>><a href="/compilation?id=<%= compilation._id %>"><span class="title"><%= compilation.name %></span><% if (!compilation.is_release) { %><span class="text-muted">(未发布)</span><% } %></a></li>
                 <% }) %>
             </ul>
         </div>

+ 2 - 1
web/users/views/compilation/engineering.html

@@ -125,7 +125,7 @@
                             </div>
                     </div>
                     <div class="col-md-12">
-                        <a data-toggle="modal" data-target="#set-glj-col" class="btn btn-primary btn-sm " style="margin-right:5px">人材机列</a>
+                        <a data-toggle="modal" data-target="#other_setting" class="btn btn-primary btn-sm " style="margin-right:5px">显示设置</a>
                     </div>
                     <div class="col-md-12" style="padding-top:20px">
                         <legend>计算程序/清单模板/列设置</legend>
@@ -183,6 +183,7 @@
                     </div>
                 </div>
                 <input type="hidden" name="glj_col" value="<%= gljCol %>" id="glj_col">
+                <input type="hidden" name="isInstall" value="<%= libData.isInstall %>" id="isInstall">
                 <input type="hidden" name="engineering" value="<%= libData.engineering %>" id="engineering">
                 <input type="hidden" name="section" value="<%= section %>" id="section">
                 <input type="hidden" name="id" value="<%= libData._id.toString()%>">

+ 11 - 4
web/users/views/compilation/modal.html

@@ -204,13 +204,13 @@
     </div>
 </div>
 
-<!-- 弹窗人材机列设置 -->
-<div class="modal fade" id="set-glj-col" tabindex="-1" role="dialog">
+<!-- 弹窗工程专业其它设置 -->
+<div class="modal fade" id="other_setting" tabindex="-1" role="dialog">
     <div class="modal-dialog " role="document">
         <div class="modal-content">
             <div class="modal-header">
                 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
-                <h4 class="modal-title" id="glj_tit">人材机列设置</h4>
+                <h4 class="modal-title" id="glj_tit">显示设置</h4>
             </div>
             <div class="modal-body">
                 <div class="row">
@@ -221,11 +221,18 @@
                             </label>
                         </div>
                     </div>
+                    <div class="col-md-12">
+                        <div class="checkbox">
+                            <label>
+                                <input type="checkbox" id="isInstall_cb"> 显示安装增加费
+                            </label>
+                        </div>
+                    </div>
                 </div>
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-primary" data-dismiss="modal" id = "set-glj-comf">确定</button>
+                <button type="button" class="btn btn-primary" data-dismiss="modal" id = "other_setting_comf">确定</button>
             </div>
         </div>
     </div>

+ 3 - 0
web/users/views/layout/layout.html

@@ -10,6 +10,7 @@
     <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
     <link rel="stylesheet" href="/web/users/css/bootstrap.min.css">
     <link rel="stylesheet" href="/web/users/css/style.css">
+    <link rel="stylesheet" href="/web/users/css/custom.css">
     <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.sc.css" type="text/css">
     <script src="/lib/jquery/jquery.min.js"></script>
     <script src="/web/users/js/lib/bootstrap.min.js"></script>
@@ -19,6 +20,8 @@
     <script src="/web/users/js/lib/messages_zh.js"></script>
     <script src="/web/users/js/lib/bootstrap-paginator.js"></script>
     <script src="/lib/lodash/lodash.js"></script>
+    <script type="text/javascript" src="/public/web/common_ajax.js"></script>
+    <script type="text/javascript" src="/node_modules/moment/min/moment.min.js"></script>
     <!-- spreadJs -->
     <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>
     <script>GC.Spread.Sheets.LicenseKey =  '<%- LicenseKey %>';</script>

+ 7 - 0
web/users/views/tool/index.html

@@ -62,6 +62,13 @@
                     </h2>
                 </div>
             </div>
+            <div class="col-xs-6 mb-30 ">
+                <div class="c-body">
+                    <h2>材料替换库
+                        <a id="materialReplace" href="/materialReplace/main" target="_blank" class="btn btn-primary pull-right">进入</a>
+                    </h2>
+                </div>
+            </div>
         </div>
     </div>
 </div>

+ 35 - 15
web/users/views/user/index.html

@@ -12,9 +12,10 @@
                 <div class="btn-group">
                     <button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown"
                             aria-haspopup="true" aria-expanded="false">
-                       最近使用费用定额: <span class="caret"></span>
+                       最近使用费用定额:<lable><%= compilationMap[filter.latestUsed] === undefined ? '所有' : compilationMap[filter.latestUsed].name %></lable>  <span class="caret"></span>
                     </button>
                     <ul class="dropdown-menu selector">
+                        <li><a  data-value="">所有</a></li>
                         <% for(let compilation of compilationList){ %>
                         <li><a  data-value="<%= compilation._id.toString()%>"><%= compilation.name %></a></li>
                         <% } %>
@@ -25,9 +26,10 @@
                 <div class="btn-group">
                     <button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown"
                             aria-haspopup="true" aria-expanded="false">
-                        已升级费用定额: <span class="caret"></span>
+                        已升级费用定额:<lable><%= compilationMap[filter.upGrade] === undefined ? '所有' : compilationMap[filter.upGrade].name %></lable>  <span class="caret"></span>
                     </button>
                     <ul class="dropdown-menu selector">
+                        <li><a  data-value="">所有</a></li>
                         <% for(let compilation of compilationList){ %>
                         <li><a  data-value="<%= compilation._id.toString()%>"><%= compilation.name %></a></li>
                         <% } %>
@@ -38,7 +40,7 @@
                 <div class="btn-group">
                     <button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown"
                             aria-haspopup="true" aria-expanded="false">
-                        最新注册:<%= filter.regtimeMsg === undefined ? '所有' : filter.regtimeMsg %><span class="caret"></span>
+                        最新注册:<lable><%= filter.regtimeMsg === undefined ? '所有' : filter.regtimeMsg %></lable><span class="caret"></span>
                     </button>
                     <ul class="dropdown-menu selector">
                         <li><a  data-value="0">所有</a></li>
@@ -53,7 +55,7 @@
                 <div class="btn-group">
                     <button type="button" class="btn btn-default dropdown-toggle btn-sm" data-toggle="dropdown"
                             aria-haspopup="true" aria-expanded="false">
-                        最新注册:<%= filter.regtimeMsg === undefined ? '所有' : filter.regtimeMsg %><span class="caret"></span>
+                        最近登录:<lable><%= filter.loginMsg === undefined ? '所有' : filter.loginMsg %></lable><span class="caret"></span>
                     </button>
                     <ul class="dropdown-menu selector">
                         <li><a  data-value="0">所有</a></li>
@@ -105,11 +107,11 @@
                            data-content="企业类型:<%= model.companyType[user.company_type] %>,企业规模:<%= model.companyScale[user.company_scale] %>"><%= user.company %></a>
                     </td>
                     <td><%= model.province[user.province] %></td>
-                    <td>重庆01版</td>
-                    <td>登录时间</td>
+                    <td><%= compilationMap[user.latest_used]?compilationMap[user.latest_used].name:""%></td>
+                    <td><%= user.latest_login?moment(user.latest_login).format('YYYY-MM-DD HH:mm:ss'):"" %></td>
                     <td><%= moment(user.create_time).format('YYYY-MM-DD HH:mm:ss') %></td>
-                    <td><a>详细</a></td>
-                    <td>升级</td>
+                    <td><a role="button" data-toggle="modal" data-target="#view" onclick='getUserInfo("<%= user._id.toString()%>")'>详细</a></td>
+                    <td><a href="#update" data-toggle="modal" data-target="#update" onclick='getUserUpgradeInfo("<%= user._id.toString()%>")'>升级</a></td>
                 </tr>
                 <% }) %>
                 </tbody>
@@ -132,13 +134,7 @@
             </div>
             <div class="modal-body">
                 <table class="table table-bordered">
-                    <tbody>
-                    <tr><th>注册时间</th><td>2017-03-03 14:29:03</td><th>最近登录</th><td>2017-03-04 14:29:03</td></tr>
-                    <tr><th>手机</th><td>12345678909</td><th>邮箱</th><td></td></tr>
-                    <tr><th>姓名</th><td colspan="3">张三</td></tr>
-                    <tr><th>企业名称</th><td colspan="3">珠海纵横创新软件有限公司</td></tr>
-                    <tr><th>企业地区</th><td>珠海</td><th>企业类型</th><td>设计</td></tr>
-                    <tr><th>企业规模</th><td colspan="3">20-50</td></tr>
+                    <tbody id="userInfoTable">
                     </tbody>
                 </table>
             </div>
@@ -149,5 +145,29 @@
     </div>
 </div>
 
+<!-- 用户升级弹窗-->
+<div class="modal fade" id="update" tabindex="-1" role="dialog">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                <h4 class="modal-title" >产品升级</h4>
+            </div>
+            <div class="modal-body">
+                <table class="table table-bordered">
+                    <tbody id="upgrade_table">
+                    </tbody>
+                </table>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
 
+<script type="text/javascript">
+    let compilationList = JSON.parse('<%- compilationString %>');
+    let adminName = '<%- adminName %>';
+</script>
 <script type="text/javascript" src="/web/users/js/user.js"></script>

+ 73 - 0
web/users/views/user/test_user.html

@@ -0,0 +1,73 @@
+<%include ../layout/second_menu.html %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main">
+            <h2><%= secondMenu[action].title %>
+                <a href="#news-add" data-toggle="modal" data-target="#news-add" class="btn btn-primary btn-sm pull-right">添加用户</a>
+            </h2>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-header">
+            <form class="form-inline" method="get" action="">
+                <!--搜索-->
+                <div class="btn-group">
+                    <div class="input-group">
+                        <input type="text" name="keyword" class="form-control input-sm" value="<%= filter.keyword === undefined ? '' : filter.keyword %>" placeholder="手机/邮箱/姓名/公司">
+                        <span class="input-group-btn">
+                        <button class="btn btn-default btn-sm" type="submit">
+                            <i class="glyphicon glyphicon-search"></i>
+                        </button>
+                    </span>
+                    </div>
+                </div>
+            </form>
+            <div class="btn-group">
+
+            </div>
+        </div>
+        <div class="c-body">
+            <table class="table">
+                <thead>
+                <tr>
+                    <th width="350">注册手机/邮箱</th>
+                    <th>姓名</th>
+                    <th>企业名称</th>
+                    <th>企业地区</th>
+                    <th>最近使用版本</th>
+                    <th width="180">最近登录</th>
+                    <th width="180">注册时间</th>
+                    <th>详细</th>
+                </tr>
+                </thead>
+                <tbody>
+                <% userList.forEach(function (user){ %>
+                <tr>
+                    <td><%= user.mobile %> / <%= user.email %></td>
+                    <td><%= user.real_name %></td>
+                    <td><a tabindex="0" role="button" data-toggle="popover" data-trigger="focus" title="更多信息"
+                           data-content="企业类型:<%= model.companyType[user.company_type] %>,企业规模:<%= model.companyScale[user.company_scale] %>"><%= user.company %></a>
+                    </td>
+                    <td><%= model.province[user.province] %></td>
+                    <td><%= compilationMap[user.latest_used]?compilationMap[user.latest_used].name:""%></td>
+                    <td><%= user.latest_login?moment(user.latest_login).format('YYYY-MM-DD HH:mm:ss'):"" %></td>
+                    <td><%= moment(user.create_time).format('YYYY-MM-DD HH:mm:ss') %></td>
+                    <td><a role="button" data-toggle="modal" data-target="#view" onclick='getUserInfo("<%= user._id.toString()%>")'>详细</a></td>
+                </tr>
+                <% }) %>
+                </tbody>
+            </table>
+            <nav aria-label="Page navigation">
+                <%include ../layout/page.html %>
+            </nav>
+        </div>
+    </div>
+</div>
+
+
+
+<script type="text/javascript">
+    let compilationList = JSON.parse('<%- compilationString %>');
+    let adminName = '<%- adminName %>';
+</script>
+<script type="text/javascript" src="/web/users/js/user.js"></script>