Parcourir la source

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

Tony Kang il y a 2 ans
Parent
commit
850f5c568a
74 fichiers modifiés avec 4257 ajouts et 14630 suppressions
  1. 3 0
      lib/fileSaver/FileSaver.min.js
  2. 136 12553
      lib/lodash/lodash.js
  3. 7 0
      lib/moment/moment.min.js
  4. 36 0
      lib/spreadjs/sheets/interop/gc.spread.excelio.11.1.2.min.js
  5. 1 0
      modules/all_models/bill_class.js
  6. 2 0
      modules/all_models/bills_template.js
  7. 2 0
      modules/all_models/bills_template_items.js
  8. 11 6
      modules/all_models/compilation.js
  9. 2 2
      modules/all_models/monomer_template.js
  10. 19 15
      modules/all_models/ration.js
  11. 13 9
      modules/all_models/stdRation_ration.js
  12. 4 3
      modules/all_models/stdRation_section.js
  13. 2 0
      modules/all_models/std_billsGuidance_items.js
  14. 15 0
      modules/all_models/std_price_info_index.js
  15. 2 0
      modules/all_models/std_price_info_items.js
  16. 4 1
      modules/all_models/system_setting.js
  17. 2 2
      modules/bills_lib/controllers/bills_lib_controllers.js
  18. 46 46
      modules/bills_lib/controllers/bills_permissionController.js
  19. 13 1
      modules/bills_lib/models/bills_lib_interfaces.js
  20. 30 30
      modules/common/const/category_const.js
  21. 6 0
      modules/common/const/locationList.js
  22. 33 0
      modules/price_info_lib/controllers/index.js
  23. 106 2
      modules/price_info_lib/facade/index.js
  24. 3 0
      modules/price_info_lib/routes/index.js
  25. 1 1
      modules/ration_repository/controllers/installation_controller.js
  26. 32 22
      modules/ration_repository/controllers/ration_section_tree_controller.js
  27. 44 27
      modules/ration_repository/models/installation.js
  28. 317 216
      modules/ration_repository/models/ration_item.js
  29. 106 94
      modules/ration_repository/models/ration_section_tree.js
  30. 46 45
      modules/ration_repository/routes/ration_rep_routes.js
  31. 24 0
      modules/std_billsGuidance_lib/controllers/libController.js
  32. 224 40
      modules/std_billsGuidance_lib/facade/facades.js
  33. 2 0
      modules/std_billsGuidance_lib/routes/routes.js
  34. 108 1
      modules/users/controllers/compilation_controller.js
  35. 2 1
      modules/users/controllers/login_controller.js
  36. 3 0
      modules/users/controllers/system_controller.js
  37. 94 3
      modules/users/models/compilation_model.js
  38. 8 15
      modules/users/models/manager_model.js
  39. 5 1
      modules/users/routes/compilation_route.js
  40. BIN
      public/share/images/erratumRecord/d1dd6acc3258f998a9ebafc16ea8ff6f_1.jpg
  41. BIN
      public/share/images/rationExplanation/d1dd6acc3258f998a9ebafc16ea8ff6f_1.jpg
  42. BIN
      public/share/images/rationRuleText/d1dd6acc3258f998a9ebafc16ea8ff6f_1.jpg
  43. 16 0
      public/web/id_tree.js
  44. 10 6
      web/maintain/bill_template_lib/html/main.html
  45. 35 2
      web/maintain/bill_template_lib/js/bills_template.js
  46. 645 565
      web/maintain/bill_template_lib/js/bills_template_edit.js
  47. 11 2
      web/maintain/billsGuidance_lib/html/main.html
  48. 27 1
      web/maintain/billsGuidance_lib/html/zhiyin.html
  49. 257 104
      web/maintain/billsGuidance_lib/js/billsGuidance.js
  50. 371 0
      web/maintain/billsGuidance_lib/js/exportExcel.js
  51. 2 0
      web/maintain/billsGuidance_lib/js/main.js
  52. 31 0
      web/maintain/billsGuidance_lib/js/util.js
  53. 49 4
      web/maintain/bills_lib/html/main.html
  54. 4 0
      web/maintain/bills_lib/scripts/bills_lib_ajax.js
  55. 29 1
      web/maintain/price_info_lib/html/edit.html
  56. 2 1
      web/maintain/price_info_lib/html/main.html
  57. 31 0
      web/maintain/price_info_lib/js/index.js
  58. 5 0
      web/maintain/price_info_lib/js/main.js
  59. 12 0
      web/maintain/ration_repository/dinge.html
  60. 74 41
      web/maintain/ration_repository/js/explanatory.js
  61. 25 23
      web/maintain/ration_repository/js/global.js
  62. 18 5
      web/maintain/ration_repository/js/installation.js
  63. 181 175
      web/maintain/ration_repository/js/ration.js
  64. 1 1
      web/maintain/ration_repository/js/ration_coe.js
  65. 99 100
      web/maintain/ration_repository/js/section_tree.js
  66. 48 48
      web/maintain/ration_repository/js/sheetsOpr.js
  67. 25 0
      web/maintain/report/css/main.css
  68. 21 1
      web/maintain/report/html/rpt_tpl_dtl_info.html
  69. 274 178
      web/maintain/report/js/rpt_tpl_main.js
  70. 4 2
      web/over_write/crawler/guangdong_2018_price_crawler.js
  71. 351 230
      web/users/js/compilation.js
  72. 30 0
      web/users/views/compilation/index.html
  73. 23 0
      web/users/views/compilation/modal.html
  74. 32 4
      web/users/views/system/index.html

Fichier diff supprimé car celui-ci est trop grand
+ 3 - 0
lib/fileSaver/FileSaver.min.js


Fichier diff supprimé car celui-ci est trop grand
+ 136 - 12553
lib/lodash/lodash.js


Fichier diff supprimé car celui-ci est trop grand
+ 7 - 0
lib/moment/moment.min.js


Fichier diff supprimé car celui-ci est trop grand
+ 36 - 0
lib/spreadjs/sheets/interop/gc.spread.excelio.11.1.2.min.js


+ 1 - 0
modules/all_models/bill_class.js

@@ -6,6 +6,7 @@ const Schema = mongoose.Schema;
 const billClass = new Schema({
     compilationID: { type: String, index: true},
     name: String,
+    key: String,
     code: String,
     itemCharacter: String,
     class: { type: Number, index: true }, // 分类

+ 2 - 0
modules/all_models/bills_template.js

@@ -35,6 +35,8 @@ let BillsTemplateSchema = {
     engineering: Number,
     //计算基数
     calcBase: String,
+    itemCharacterText: String,
+    jobContentText: String,
     //费率ID
     feeRateID:Number
 };

+ 2 - 0
modules/all_models/bills_template_items.js

@@ -33,6 +33,8 @@ let BillsTemplateSchema = {
     libID: {type:String,index:true},
     //计算基数
     calcBase: String,
+    itemCharacterText: String,
+    jobContentText: String,
     //费率ID
     feeRateID:Number,
     quantity: String,

+ 11 - 6
modules/all_models/compilation.js

@@ -10,7 +10,7 @@ import mongoose from "mongoose";
 let Schema = mongoose.Schema;
 let collectionName = 'compilation';
 let childrenSchema = new Schema({
-    id:String,
+    id: String,
     // 计价名称
     name: String,
     // 是否启用
@@ -21,8 +21,9 @@ let childrenSchema = new Schema({
     // 类型
     type: {
         type: Number
-    }
-},{_id: false});
+    },
+    fileTypes: [Number]//创建项目时可用文件类型 估算,概算,预算 变更预算
+}, { _id: false });
 let modelSchema = {
     // 是否发布
     is_release: {
@@ -52,9 +53,11 @@ let modelSchema = {
     //描述
     description: String,
     //代码覆盖路径
-    overWriteUrl:String,
+    overWriteUrl: String,
     //例题建设项目ID
     example: Array,
+    // 版本号
+    edition: String,
     // 发布时间
     release_time: {
         type: Number,
@@ -74,6 +77,8 @@ let modelSchema = {
     categoryID: {
         type: Number,
         default: 12 // 总部id
-    }
+    },
+    defaultLocation:String,//默认工程所在地
+    freeUse:Boolean
 };
-mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));
+mongoose.model(collectionName, new Schema(modelSchema, { versionKey: false, collection: collectionName }));

+ 2 - 2
modules/all_models/monomer_template.js

@@ -13,8 +13,8 @@ const monomerTemplate_lib = new Schema({
         name: String,
         compilationID: String,
         data: {
-            type: [Schema.Types.Mixed],
-            default: []
+            type: Schema.Types.Mixed,
+            default: {}
         }
     },
     {versionKey: false}

+ 19 - 15
modules/all_models/ration.js

@@ -11,7 +11,7 @@ var rationAssItemSchema = mongoose.Schema({
     assistID: Number,
     assistCode: String,
     stdValue: Number,
-    actualValue:Number,
+    actualValue: Number,
     stepValue: String,
     decimal: Number,
     carryBit: String,
@@ -30,8 +30,8 @@ let rationSchema = new Schema({
     name: String,
     unit: String,
     quantity: String,
-    contain:String,//含量
-    quantityEXP:String,//工程量表达式
+    contain: String,//含量
+    quantityEXP: String,//工程量表达式
     programID: Number,
     marketUnitFee: String,
     marketTotalFee: String,
@@ -39,15 +39,15 @@ let rationSchema = new Schema({
     deleteInfo: deleteSchema,
     type: Number,                               // 1 定额、2 量价、3 工料机定额
     subType: Number,                            // 子类型:1人工、201材料、301机械、4主材、5设备
-    from:{type: String,default:'std'},          //std, cpt  来自标准、补充
+    from: { type: String, default: 'std' },          //std, cpt  来自标准、补充
     isSubcontract: Boolean,                     // 是否分包
-    installationKey:String,                   //用来记录安装增加费的关联字段
+    installationKey: String,                   //用来记录安装增加费的关联字段
 
     // 定额特有属性:
     libID: Number,
     maskName: String,
     caption: String,
-    isFromDetail:{type: Number,default:0},       // 1 true 2 false
+    isFromDetail: { type: Number, default: 0 },       // 1 true 2 false
     adjustState: String,
     rationProjName: String,
     comments: String,                           // 说明
@@ -55,17 +55,21 @@ let rationSchema = new Schema({
     rationAssList: [rationAssItemSchema],
     content: String,                            // 工作内容
     ruleText: String,                            // 计算规则
-    prefix: {type: String, default: ''},                              //定额是补充、借用时用  补 借
+    prefix: { type: String, default: '' },                              //定额是补充、借用时用  补 借
 
     //工料机特有属性
-    projectGLJID:Number,  //项目工料机ID
-    GLJID:Number,//工料机库ID
-    original_code:String, //原始编码
-    specs:String,//规格型号
-    shortName:String,//缩写
-    customQuantity:String,//自定义消耗
-    adjCoe:Number,
-    remark:String
+    projectGLJID: Number,  //项目工料机ID
+    GLJID: Number,//工料机库ID
+    original_code: String, //原始编码
+    specs: String,//规格型号
+    shortName: String,//缩写
+    customQuantity: String,//自定义消耗
+    adjCoe: Number,
+    remark: String,
+    manageFee1: Number, // 1类管理费
+    manageFee2: Number, // 2类管理费
+    manageFee3: Number, // 3类管理费
+    manageFee4: Number, // 4类管理费
 });
 
 let ration = mongoose.model("ration", rationSchema, "ration");

+ 13 - 9
modules/all_models/stdRation_ration.js

@@ -20,19 +20,19 @@ const rationAssItemSchema = new Schema({
     carryBit: String,
     minValue: String,
     maxValue: String,
-    paramName:String,//参数名称
-    param:String,//参数
-    thirdRationCode:String//第三定额
+    paramName: String,//参数名称
+    param: String,//参数
+    thirdRationCode: String//第三定额
 }, { _id: false });
 
 //定额安装增加费用
 const rationInstSchema = new Schema({
     feeItemId: String,
     sectionId: String
-},{_id: false});
+}, { _id: false });
 
 const rationItemSchema = new Schema({
-    ID:Number,
+    ID: Number,
     code: String,
     name: String,
     unit: String,
@@ -41,9 +41,9 @@ const rationItemSchema = new Schema({
     materialPrice: Number,
     machinePrice: Number,
     sectionId: Number,
-    rationRepId: {type: Number, index: true},
+    rationRepId: { type: Number, index: true },
     caption: String,
-    feeType: Number,
+    feeType: String,
     jobContent: String,
     annotation: String,
     manageFeeRate: String, // 管理费费率
@@ -55,8 +55,12 @@ const rationItemSchema = new Schema({
         type: Array,
         default: []
     },
-    jobContentText:String,//默认的工作内容
-    isDeleted: {type: Boolean, default: false}
+    jobContentText: String,//默认的工作内容
+    manageFee1: Number, // 1类地区管理费
+    manageFee2: Number, // 2类地区管理费
+    manageFee3: Number, // 3类地区管理费
+    manageFee4: Number, // 4类地区管理费
+    isDeleted: { type: Boolean, default: false }
 });
 
 mongoose.model('std_ration_lib_ration_items', rationItemSchema, 'std_ration_lib_ration_items');

+ 4 - 3
modules/all_models/stdRation_section.js

@@ -6,11 +6,12 @@ const mongoose = require('mongoose');
 const Schema = mongoose.Schema;
 const rationChapterTreeSchema = new Schema({//章节树  //生成唯一id改为sectionID  改成string
     rationRepId: Number,
-    ID:Number,
-    ParentID:Number,
-    NextSiblingID:Number,
+    ID: Number,
+    ParentID: Number,
+    NextSiblingID: Number,
     name: String,
     explanation: String,//说明
+    erratumRecord: String, // 勘误记录
     ruleText: String,//计算规则,
     jobContentSituation: String,//工作内容适用情况,ALL适用本项全部定额,PARTIAL适用本项部分定额
     annotationSituation: String,//附注适用情况,ALL适用本项全部定额,PARTIAL适用本项部分定额

+ 2 - 0
modules/all_models/std_billsGuidance_items.js

@@ -30,4 +30,6 @@ const stdBillsGuidanceItems = new Schema({
     isDefaultOption: {type: Boolean, default: false}, // 是否是默认选项
 }, {versionKey: false});
 
+stdBillsGuidanceItems.index({ libID: 1, billsID: 1 });
+
 mongoose.model('std_billsGuidance_items', stdBillsGuidanceItems, 'std_billsGuidance_items');

+ 15 - 0
modules/all_models/std_price_info_index.js

@@ -0,0 +1,15 @@
+// 信息价类型
+const mongoose = require('mongoose');
+
+const Schema = mongoose.Schema;
+const priceInfoClass = new Schema({
+    ID: String,
+    code: String,//编码前4位
+    period: String, // 期数 eg: 2020-05
+    areaID: String,
+    compilationID: String, // 费用定额
+    index: Number//指数,保留两位小数
+}, {versionKey: false});
+priceInfoClass.index({ areaID:1});
+priceInfoClass.index({ period:1});
+mongoose.model('std_price_info_index', priceInfoClass, 'std_price_info_index');

+ 2 - 0
modules/all_models/std_price_info_items.js

@@ -83,4 +83,6 @@ const priceInfoItems = new Schema({
         default: []
     }
 }, { versionKey: false });
+priceInfoItems.index({ areaID:1,period:1});
+
 mongoose.model('std_price_info_items', priceInfoItems, 'std_price_info_items');

+ 4 - 1
modules/all_models/system_setting.js

@@ -23,6 +23,9 @@ let modelSchema = {
     },
     company: String, // 软件供应商
     product: String, // 产品名
-    version: String // 版本号
+    version: String, // 计算版本号(原本叫版本号,需要兼容旧的处理所以还是叫version)
+    dskVersion: String, // 大司空显示版本号
+    platformVersion: String, // 平台显示版本号
+    updateDate: String, // 更新日期
 };
 mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));

+ 2 - 2
modules/bills_lib/controllers/bills_lib_controllers.js

@@ -36,8 +36,8 @@ module.exports = {
     },
     getStdBillsLib: function(req, res){
         billsLibDao.getStdBillsLib(function(err, message, stdBillsLib){
-            callback(req, res, err, message, stdBillsLib );
-        });
+            callback(req, res, err, message, stdBillsLib);
+        },req.session.managerData.isTemporary);
     },
     createStdBillsLib: function(req, res){
         let data = JSON.parse(req.body.data);

+ 46 - 46
modules/bills_lib/controllers/bills_permissionController.js

@@ -11,69 +11,69 @@ const excel = require("node-xlsx");
 const uuidV1 = require('uuid/v1');
 
 const shareDir = 'public/share/images';
-const imgTriggers = ['billsRecharge', 'rationExplanation', 'rationRuleText'];
+const imgTriggers = ['billsRecharge', 'rationExplanation', 'rationRuleText', 'erratumRecord'];
 
 
-class billsPermContr extends baseController{
-    getCurrentUniqId(req, res){
+class billsPermContr extends baseController {
+    getCurrentUniqId(req, res) {
         billsController.getCurrentUniqId(req, res);
     }
-    getBills(req, res){
+    getBills(req, res) {
         billsController.getBills(req, res);
     }
-    createBills(req, res){
+    createBills(req, res) {
         billsController.createBills(req, res);
     }
-    updatePNId(req, res){
+    updatePNId(req, res) {
         billsController.updatePNId(req, res);
     }
-    upMove(req, res){
+    upMove(req, res) {
         billsController.upMove(req, res);
     }
-    downMove(req, res){
+    downMove(req, res) {
         billsController.downMove(req, res);
     }
-    upLevel(req, res){
+    upLevel(req, res) {
         billsController.upLevel(req, res);
     }
-    downLevel(req, res){
+    downLevel(req, res) {
         billsController.downLevel(req, res);
     }
-    updateBills(req, res){
+    updateBills(req, res) {
         billsController.updateBills(req, res);
     }
-    updateSectionInfo(req, res){
+    updateSectionInfo(req, res) {
         billsController.updateSectionInfo(req, res);
     }
-    updateBillsArr(req, res){
+    updateBillsArr(req, res) {
         billsController.updateBillsArr(req, res);
     }
-    removeTotal(req, res){
+    removeTotal(req, res) {
         billsController.removeTotal(req, res);
     }
-    updateSerialNo(req, res){
+    updateSerialNo(req, res) {
         billsController.updateSerialNo(req, res);
     }
-    pasteBills(req, res){
+    pasteBills(req, res) {
         billsController.pasteBills(req, res);
     }
-    updateRecharge(req, res){
+    updateRecharge(req, res) {
         billsController.updateRecharge(req, res);
     }
-    pasteRel(req, res){
+    pasteRel(req, res) {
         billsController.pasteRel(req, res);
     }
-    deleteBills(req, res){
+    deleteBills(req, res) {
         billsController.deleteBills(req, res);
     }
-    isUsed(req, res){
+    isUsed(req, res) {
         billsController.isUsed(req, res);
     }
     /*
      * 导入标准清单(确定节点结构:深度数组)
      * */
-    importBills(req, res){
-        let form = new multiparty.Form({uploadDir: './public'});
+    importBills(req, res) {
+        let form = new multiparty.Form({ uploadDir: './public' });
         const allowHeader = ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
         let uploadFullName;
         form.parse(req, async function (err, fields, files) {
@@ -103,18 +103,18 @@ class billsPermContr extends baseController{
                 //插入清单
                 await billsLibDao.importBills(billsLibId, sheet[0].data);
                 // 删除文件
-                if(uploadFullName && fs.existsSync(uploadFullName)){
+                if (uploadFullName && fs.existsSync(uploadFullName)) {
                     fs.unlinkSync(uploadFullName);
                 }
-                res.json({error: 0, data: null, msg: ''});
+                res.json({ error: 0, data: null, msg: '' });
 
             } catch (err) {
                 console.log(err);
                 // 删除文件
-                if(uploadFullName && fs.existsSync(uploadFullName)){
+                if (uploadFullName && fs.existsSync(uploadFullName)) {
                     fs.unlinkSync(uploadFullName);
                 }
-                res.json({error: 1, data: null, msg: err});
+                res.json({ error: 1, data: null, msg: err });
             }
         });
     }
@@ -122,13 +122,13 @@ class billsPermContr extends baseController{
     /*
     *上传图片
     * */
-    uploadImg(req, res){
+    uploadImg(req, res) {
         let uploadDir = path.join(req.app.locals.rootDir, shareDir);
-        let form = new multiparty.Form({uploadDir: uploadDir});
-        form.parse(req, async function(err, fields, files){
+        let form = new multiparty.Form({ uploadDir: uploadDir });
+        form.parse(req, async function (err, fields, files) {
             try {
                 const file = typeof files.file !== 'undefined' ? files.file[0] : null;
-                if(err || !file) {
+                if (err || !file) {
                     throw '上传失败';
                 }
                 //触发上传图片的地方
@@ -151,17 +151,17 @@ class billsPermContr extends baseController{
                 let newPath = path.join(triggerPath, newFileName);
                 fs.renameSync(file.path, newPath);
                 //返回图片域名后的url
-                res.json({error: 0, data: `${shareDir}/${trigger}/${newFileName}`, message: 'success'});
+                res.json({ error: 0, data: `${shareDir}/${trigger}/${newFileName}`, message: 'success' });
             } catch (err) {
                 console.log(err);
-                res.json({error: 1, data: null, message: err});
+                res.json({ error: 1, data: null, message: err });
             }
         });
     }
     /*
     * 删除图片
     * */
-    delImg(req, res){
+    delImg(req, res) {
         try {
             let data = JSON.parse(req.body.data),
                 trigger = data.trigger,
@@ -172,16 +172,16 @@ class billsPermContr extends baseController{
             //拼接完整的删除路径
             let delUrl = path.join(req.app.locals.rootDir, url);
             fs.unlinkSync(delUrl);
-            res.json({error: 0, data: null, message: 'success'});
-        } catch(err) {
-            res.json({error: 1, data: null, message: err});
+            res.json({ error: 0, data: null, message: 'success' });
+        } catch (err) {
+            res.json({ error: 1, data: null, message: err });
         }
     }
     /*
      *  根据页码加载图片
      *  返回总页码和当前页码的图片信息
      * */
-    loadImgs(req, res){
+    loadImgs(req, res) {
         try {
             let data = JSON.parse(req.body.data),
                 trigger = data.trigger,
@@ -201,12 +201,12 @@ class billsPermContr extends baseController{
             allImgs.sort(function (a, b) {
                 let aV = a.split('.')[0],
                     bV = b.split('.')[0];
-                    if(aV > bV) {
-                        return -1;
-                    } else if(aV < bV) {
-                        return 1;
-                    }
-                    return 0;
+                if (aV > bV) {
+                    return -1;
+                } else if (aV < bV) {
+                    return 1;
+                }
+                return 0;
             });
             let pageCount = Math.ceil(allImgs.length / perImgs) || 1;
             //当前页图片信息
@@ -214,14 +214,14 @@ class billsPermContr extends baseController{
                 endIdx = startIdx + 3,
                 currentPageArr = allImgs.slice(startIdx, endIdx),
                 currentImgsUrl = [];
-            for (let img of currentPageArr){
+            for (let img of currentPageArr) {
                 currentImgsUrl.push(`${shareDir}/${trigger}/${img}`);
             }
-            res.json({error: 0, data: {pageCount: pageCount, currentImgsUrl: currentImgsUrl}, message: 'success'});
+            res.json({ error: 0, data: { pageCount: pageCount, currentImgsUrl: currentImgsUrl }, message: 'success' });
 
         } catch (err) {
             console.log(err);
-            res.json({error: 1, data: {pageCount: 1, currentImgsUrl: []}, message: err});
+            res.json({ error: 1, data: { pageCount: 1, currentImgsUrl: [] }, message: err });
         }
     }
 }

+ 13 - 1
modules/bills_lib/models/bills_lib_interfaces.js

@@ -138,8 +138,18 @@ billsLibDao.prototype.getABillsLib = function(data, callback){
 };
 
 
-billsLibDao.prototype.getStdBillsLib = function(callback){
+billsLibDao.prototype.getStdBillsLib = function(callback,isTemporary){
    // let userId = data.userId;
+   if(isTemporary){
+    StdBillsLib.find({deleted: false,billsLibId:590}, "-_id", function(err, data){
+        if(err){
+            callback(1, "Error", null);
+        }
+        else{
+            callback(0, "", data);
+        }
+    });
+   }else{
     StdBillsLib.find({deleted: false}, "-_id", function(err, data){
         if(err){
             callback(1, "Error", null);
@@ -148,6 +158,8 @@ billsLibDao.prototype.getStdBillsLib = function(callback){
             callback(0, "", data);
         }
     });
+   }
+    
 };
 
 billsLibDao.prototype.createStdBillsLibSync = async function (userName, libName ,libType) {

+ 30 - 30
modules/common/const/category_const.js

@@ -9,7 +9,7 @@
  */
 
 const category = {
-    ANHUI: 2,
+    // ANHUI: 2,
     GANSU: 3,
     GUANGDONG: 4,
     GUANGXI: 5,
@@ -20,24 +20,24 @@ const category = {
     ZHEJIANG: 10,
     SHANDONG: 11,
     ZONGBU: 12,
-    YUNNAN: 13,
-    GUIZHOU: 14,
-    BEIJING: 15,
-    FUJIAN: 16,
-    HAINAN: 17,
-    HEBEI: 18,
-    HENAN: 19,
-    HEILONGJIANG: 20,
-    HUBEI: 21,
-    HUNAN: 22,
-    JILIN: 23,
-    JIANGSU: 24,
-    LIAONING: 25,
-    NINGXIA: 26
+    // YUNNAN: 13,
+    // GUIZHOU: 14,
+    // BEIJING: 15,
+    // FUJIAN: 16,
+    // HAINAN: 17,
+    // HEBEI: 18,
+    // HENAN: 19,
+    // HEILONGJIANG: 20,
+    // HUBEI: 21,
+    // HUNAN: 22,
+    // JILIN: 23,
+    // JIANGSU: 24,
+    // LIAONING: 25,
+    // NINGXIA: 26
 };
 
 const categoryList = [
-    {id: category.ANHUI, name: '安徽办'},
+    // {id: category.ANHUI, name: '安徽办'},
     {id: category.GANSU, name: '甘肃办'},
     {id: category.GUANGDONG, name: '广东办'},
     {id: category.GUANGXI, name: '广西办'},
@@ -48,20 +48,20 @@ const categoryList = [
     {id: category.ZHEJIANG, name: '浙江办'},
     {id: category.SHANDONG, name: '山东办'},
     {id: category.ZONGBU, name: '总部'},
-    {id: category.YUNNAN, name: '云南办'},
-    {id: category.GUIZHOU, name: '贵州办'},
-    {id: category.BEIJING, name: '北京办'},
-    {id: category.FUJIAN, name: '福建办'},
-    {id: category.HAINAN, name: '海南办'},
-    {id: category.HEBEI, name: '河北办'},
-    {id: category.HENAN, name: '河南办'},
-    {id: category.HEILONGJIANG, name: '黑龙江办'},
-    {id: category.HUBEI, name: '湖北办'},
-    {id: category.HUNAN, name: '湖南办'},
-    {id: category.JILIN, name: '吉林办'},
-    {id: category.JIANGSU, name: '江苏办'},
-    {id: category.LIAONING, name: '辽宁办'},
-    {id: category.NINGXIA, name: '宁夏办'}
+    // {id: category.YUNNAN, name: '云南办'},
+    // {id: category.GUIZHOU, name: '贵州办'},
+    // {id: category.BEIJING, name: '北京办'},
+    // {id: category.FUJIAN, name: '福建办'},
+    // {id: category.HAINAN, name: '海南办'},
+    // {id: category.HEBEI, name: '河北办'},
+    // {id: category.HENAN, name: '河南办'},
+    // {id: category.HEILONGJIANG, name: '黑龙江办'},
+    // {id: category.HUBEI, name: '湖北办'},
+    // {id: category.HUNAN, name: '湖南办'},
+    // {id: category.JILIN, name: '吉林办'},
+    // {id: category.JIANGSU, name: '江苏办'},
+    // {id: category.LIAONING, name: '辽宁办'},
+    // {id: category.NINGXIA, name: '宁夏办'}
 ];
 
 export {category as default, categoryList as List};

+ 6 - 0
modules/common/const/locationList.js

@@ -0,0 +1,6 @@
+const locationList = ['北京','天津','河北','山西','内蒙古','辽宁',
+'吉林','黑龙江','上海','江苏','浙江','安徽','福建','江西','山东','河南',
+'湖北','湖南','四川','贵州','云南','西藏','陕西','甘肃','青海','宁夏','新疆',
+'广东','广西','海南','重庆']
+
+export default locationList

+ 33 - 0
modules/price_info_lib/controllers/index.js

@@ -217,6 +217,18 @@ class PriceInfoController extends BaseController {
         }
     }
 
+    async calcPriceIndex(req, res) {
+        try {
+            const { period, libID, compilationID } = JSON.parse(req.body.data);
+            const areaID = '971fb9a0-0f93-11eb-b53c-45271c1df90f';//写死珠海地区
+            const data = await facade.calcPriceIndex(libID, period, areaID, compilationID);
+            res.json({ error: 0, message: 'getCLass success', data });
+        } catch (err) {
+            console.log(err);
+            res.json({ error: 1, message: err.toString() });
+        }
+    }
+
     async getPriceData(req, res) {
         try {
             const { classIDList } = JSON.parse(req.body.data);
@@ -250,6 +262,27 @@ class PriceInfoController extends BaseController {
         }
     }
 
+    async exportPriceData(request, response) {
+        const libID = request.query.libID;
+        try {
+            const excelData = await facade.exportExcelData(libID, '珠海市-珠海市');
+            const buffer = excel.build([{ name: "信息价主表", data: excelData }]);
+            const filePath = './public/exportInfo.xlsx';
+            fs.writeFileSync(filePath, buffer, 'binary');
+            const stats = fs.statSync(filePath);
+            // 下载相关header
+            response.set({
+                'Content-Type': 'application/octet-stream',
+                'Content-Disposition': 'attachment; filename=infoPrice.xlsx',
+                'Content-Length': stats.size
+            });
+            fs.createReadStream(filePath).pipe(response);
+            fs.unlink(filePath);
+        } catch (error) {
+            response.end(error);
+        }
+    }
+
 }
 
 module.exports = {

+ 106 - 2
modules/price_info_lib/facade/index.js

@@ -1,5 +1,7 @@
 const mongoose = require('mongoose');
 const uuidV1 = require('uuid/v1');
+const _ = require('lodash');
+const scMathUtil = require('../../../public/scMathUtil').getUtil();
 const { CRAWL_LOG_KEY, ProcessStatus } = require('../../../public/constants/price_info_constant');
 
 const priceInfoLibModel = mongoose.model('std_price_info_lib');
@@ -8,6 +10,9 @@ const priceInfoItemModel = mongoose.model('std_price_info_items');
 const priceInfoAreaModel = mongoose.model('std_price_info_areas');
 const compilationModel = mongoose.model('compilation');
 const importLogsModel = mongoose.model('import_logs');
+const priceInfoIndexModel = mongoose.model('std_price_info_index');
+
+
 
 async function getLibs(query) {
     return await priceInfoLibModel.find(query).lean();
@@ -307,7 +312,7 @@ async function importKeyData(libID, mainData, subData) {
             taxPrice: rowData[5] || '',
             noTaxPrice: rowData[6] || '',
             dateRemark: rowData[7] || '',
-            expString: rowData[8] ||  '',
+            expString: rowData[8] || '',
             keywordList: keywordMap[code] || [],
         }
         priceItems.push(priceItem);
@@ -532,6 +537,103 @@ async function editClassData(updateData) {
     }
 }
 
+//计算指标平均值
+function calcIndexAvg(period, areaID, compilationID, preCodeMap) {
+    const newData = [];
+    for (const code in preCodeMap) {
+        const indexArr = preCodeMap[code];
+        let total = 0;
+
+        for (const index of indexArr) {
+            total = scMathUtil.roundForObj(total + index, 2);
+        }
+        const avg = scMathUtil.roundForObj(total / indexArr.length, 2);
+        newData.push({ ID: uuidV1(), code, period, areaID, compilationID, index: avg })
+    }
+    return newData
+}
+
+//一个月里有classCode相同,但是价格不同的情况,取平均值
+function getClassCodePriceAvgMap(items) {
+    const classCodeMap = {};
+    for (const b of items) {
+        classCodeMap[b.classCode] ? classCodeMap[b.classCode].push(b) : classCodeMap[b.classCode] = [b];
+    }
+
+    for (const classCode in classCodeMap) {
+        const baseItems = classCodeMap[classCode];
+        const item = baseItems[0];
+        if (baseItems.length > 1) {
+            let sum = 0;
+            for (const b of baseItems) {
+                sum += parseFloat(b.noTaxPrice);
+            }
+            classCodeMap[classCode] = { code: item.code, name: item.name, price: scMathUtil.roundForObj(sum / baseItems.length, 2) };
+        } else {
+            classCodeMap[classCode] = { code: item.code, name: item.name, price: parseFloat(item.noTaxPrice) }
+        }
+
+    }
+
+    return classCodeMap
+
+}
+
+async function calcPriceIndex(libID, period, areaID, compilationID) {
+    const baseItems = await priceInfoItemModel.find({ areaID, period: '2022年-01月' }).lean();//以珠海 22年1月的数据为基准
+    const currentItems = await priceInfoItemModel.find({ areaID, period }).lean();
+    const preCodeMap = {};//编码前4位-指数映射
+    const baseAvgMap = getClassCodePriceAvgMap(baseItems);
+    const currentAvgMap = getClassCodePriceAvgMap(currentItems);
+
+    let message = '';
+
+    for (const classCode in currentAvgMap) {
+        const c = currentAvgMap[classCode];
+        const preCode = c.code.substr(0, 4);
+        let index = 1;
+        const baseItem = baseAvgMap[classCode];
+        const tem = { index, classCode, name: c.name, code: c.code };
+
+        if (baseItem && baseItem.price) {//一个月份里有多个值时,先取平均再计算
+            index = scMathUtil.roundForObj(c.price / baseItem.price, 2);
+            tem.baseName = baseItem.name;
+        }
+        tem.index = index;
+        if (Math.abs(index - 1) > 0.2) {
+            const string = `classCode:${tem.classCode},编号:${tem.code},基础名称:${tem.baseName},当前库中名称:${tem.name},指数:${tem.index};\n`;
+            message += string;
+            console.log(string)
+        }
+
+        preCodeMap[preCode] ? preCodeMap[preCode].push(index) : preCodeMap[preCode] = [index];
+    }
+    const newIndexData = calcIndexAvg(period, areaID, compilationID, preCodeMap)
+    //删除旧数据
+    await priceInfoIndexModel.deleteMany({ areaID, period });
+    //插入新数据
+    await priceInfoIndexModel.insertMany(newIndexData);
+    return message;
+}
+
+async function exportExcelData(libID, areaName) {
+    const area = await priceInfoAreaModel.findOne({ name: areaName }).lean();
+    if (!area) {
+        return [];
+    }
+    const priceItems = await priceInfoItemModel.find({ libID, areaID: area.ID }).lean();
+    // 整理数据
+    let priceData = [];
+    for (const tmp of priceItems) {
+        const item = [tmp.code || '', tmp.classCode || '', tmp.name || '', tmp.specs || '', tmp.unit || '', tmp.taxPrice || '', tmp.noTaxPrice || '', tmp.dateRemark || '', tmp.expString || ''];
+        priceData.push(item);
+    }
+    const excelData = [['主从对应码', '别名编码', '材料名称', '规格型号', '单位', '含税价(元)', '除税价(元)', '多价备注', '计算式']];
+    excelData.push.apply(excelData, priceData);
+
+    return excelData;
+}
+
 module.exports = {
     getLibs,
     createLib,
@@ -546,7 +648,9 @@ module.exports = {
     insertAreas,
     deleteAreas,
     getClassData,
+    calcPriceIndex,
     getPriceData,
     editPriceData,
-    editClassData
+    editClassData,
+    exportExcelData
 }

+ 3 - 0
modules/price_info_lib/routes/index.js

@@ -21,10 +21,13 @@ module.exports = function (app) {
     router.post("/insertArea", priceInfoController.auth, priceInfoController.init, priceInfoController.insertArea);
     router.post("/deleteArea", priceInfoController.auth, priceInfoController.init, priceInfoController.deleteArea);
     router.post("/getClassData", priceInfoController.auth, priceInfoController.init, priceInfoController.getClassData);
+    router.post("/calcPriceIndex", priceInfoController.auth, priceInfoController.init, priceInfoController.calcPriceIndex);
     router.post("/getPriceData", priceInfoController.auth, priceInfoController.init, priceInfoController.getPriceData);
     router.post("/editPriceData", priceInfoController.auth, priceInfoController.init, priceInfoController.editPriceData);
     router.post("/editClassData", priceInfoController.auth, priceInfoController.init, priceInfoController.editClassData);
 
+    router.get("/export", priceInfoController.auth, priceInfoController.init, priceInfoController.exportPriceData);
+
     app.use("/priceInfo", router);
 };
 

+ 1 - 1
modules/ration_repository/controllers/installation_controller.js

@@ -19,7 +19,7 @@ class InstallationController extends BaseController {
 
   updateSection(req, res) {
     let data = JSON.parse(req.body.data);
-    installationDao.updateSection(data.updateData, function (err, data) {
+    installationDao.updateSection(data.updateData, data.libID, function (err, data) {
       callback(req, res, err, "", data);
     });
   }

+ 32 - 22
modules/ration_repository/controllers/ration_section_tree_controller.js

@@ -4,18 +4,18 @@
 
 var rationChapterTreeData = require('../models/ration_section_tree');
 import BaseController from "../../common/base/base_controller";
-var callback = function(req,res,err,message, data){
-    res.json({error: err, message: message, data: data});
+var callback = function (req, res, err, message, data) {
+    res.json({ error: err, message: message, data: data });
 }
 
-class RationChapterTreeController extends BaseController{
+class RationChapterTreeController extends BaseController {
     //某费用定额下补充定额库章节树模板数据条数
     async sectionTemplateCount(req, res) {
         try {
             let count = await rationChapterTreeData.sectionTemplateCount(req.params.compilationId);
-            callback(req, res, 0, 'success', {count});
+            callback(req, res, 0, 'success', { count });
         } catch (err) {
-            callback(req, res, 1, err, {count: 0});
+            callback(req, res, 1, err, { count: 0 });
         }
     }
     //将该标准定额库的章节树设置为该费用定额下补充定额章节树的模板
@@ -28,41 +28,41 @@ class RationChapterTreeController extends BaseController{
             callback(req, res, 1, err, null)
         }
     }
-    getRationChapterTree(req,res){
+    getRationChapterTree(req, res) {
         let data = JSON.parse(req.body.data);
         var rationLibId = data.rationLibId;
         var repId = data.rationRepositoryId;
         if (rationLibId) {
-            rationChapterTreeData.getRationChapterTree(rationLibId,function(err,data){
-                callback(req,res,err, "", data);
+            rationChapterTreeData.getRationChapterTree(rationLibId, function (err, data) {
+                callback(req, res, err, "", data);
             })
         } else if (repId) {
-            rationChapterTreeData.getRationChapterTreeByRepId(repId,function(err,data){
-                callback(req,res,err,"", data)
+            rationChapterTreeData.getRationChapterTreeByRepId(repId, function (err, data) {
+                callback(req, res, err, "", data)
             })
         }
     }
-    getNewRationTreeID(req, res){
+    getNewRationTreeID(req, res) {
         rationChapterTreeData.getNewRationTreeID(function (err, data) {
             callback(req, res, err, '', data);
         });
 
     }
-    createNewNode(req, res){
+    createNewNode(req, res) {
         var libId = req.body.rationLibId;
         var lastNodeId = req.body.lastNodeId;
         let lastOpr = req.body.lastOpr;
         var nodeData = JSON.parse(req.body.rawNodeData);
-        rationChapterTreeData.createNewNode(lastOpr, libId, lastNodeId, nodeData, function(err,data){
-            callback(req,res,err,"", data)
+        rationChapterTreeData.createNewNode(lastOpr, libId, lastNodeId, nodeData, function (err, data) {
+            callback(req, res, err, "", data)
         });
     }
     updateNodes(req, res) {
         let data = JSON.parse(req.body.data);
         let lastOpr = data.lastOpr;
         let updateData = data.updateData;
-        rationChapterTreeData.updateNodes(lastOpr, updateData, function(err,results){
-            callback(req,res, err, "", results)
+        rationChapterTreeData.updateNodes(lastOpr, updateData, function (err, results) {
+            callback(req, res, err, "", results)
         });
     }
     deleteNodes(req, res) {
@@ -71,11 +71,11 @@ class RationChapterTreeController extends BaseController{
         var preNodeNextId = req.body.preNodeNextId;
         let repId = req.body.repId;
         let lastOpr = req.body.lastOpr;
-        rationChapterTreeData.removeNodes(repId, lastOpr, nodes, preNodeId, preNodeNextId, function(err,results){
-            callback(req,res, err, "", results)
+        rationChapterTreeData.removeNodes(repId, lastOpr, nodes, preNodeId, preNodeNextId, function (err, results) {
+            callback(req, res, err, "", results)
         });
     }
-    updateExplanation(req, res){
+    updateExplanation(req, res) {
         let repId = req.body.repId,
             nodeId = req.body.nodeId,
             explanation = req.body.explanation,
@@ -85,7 +85,17 @@ class RationChapterTreeController extends BaseController{
         });
 
     }
-    updateRuleText(req, res){
+    updateErratumRecord(req, res) {
+        let repId = req.body.repId,
+            nodeId = req.body.nodeId,
+            erratumRecord = req.body.erratumRecord,
+            lastOpr = req.body.lastOpr;
+        rationChapterTreeData.updateErratumRecord(lastOpr, repId, nodeId, erratumRecord, function (err) {
+            callback(req, res, err, '', null);
+        });
+
+    }
+    updateRuleText(req, res) {
         let repId = req.body.repId,
             nodeId = req.body.nodeId,
             ruleText = req.body.ruleText,
@@ -95,7 +105,7 @@ class RationChapterTreeController extends BaseController{
         });
 
     }
-    updateSituation(req, res){
+    updateSituation(req, res) {
         let repId = req.body.repId,
             nodeId = req.body.nodeId,
             situation = req.body.situation,
@@ -104,7 +114,7 @@ class RationChapterTreeController extends BaseController{
             callback(req, res, err, '', null);
         });
     }
-    updateAnnoSituation(req, res){
+    updateAnnoSituation(req, res) {
         let repId = req.body.repId,
             nodeId = req.body.nodeId,
             situation = req.body.situation,

+ 44 - 27
modules/ration_repository/models/installation.js

@@ -6,9 +6,15 @@ const rationItemModel = mongoose.model('std_ration_lib_ration_items');
 const installFeeItemModel = mongoose.model('std_ration_lib_installation');
 const installSectionModel = mongoose.model('std_ration_lib_installationSection');
 
-class InstallationDao{
-    async getInstallation(rationRepId, callback){
+class InstallationDao {
+    // 安装增加费库映射(12修缮定额需要直接用18定额的安装数据)
+    getInstLibID(libID) {
+        return +libID === 248 ? 214 : +libID;
+    }
+
+    async getInstallation(rationRepId, callback) {
         try {
+            rationRepId = this.getInstLibID(rationRepId);
             const feeItems = await installFeeItemModel.find({ rationRepId }).lean();
             const feeItemMap = {};
             const sectionIds = [];
@@ -17,7 +23,7 @@ class InstallationDao{
                 item.section.forEach(s => sectionIds.push(s.ID));
                 item.section = [];
             });
-            const sections = await installSectionModel.find({ID: {$in: sectionIds}});
+            const sections = await installSectionModel.find({ ID: { $in: sectionIds } });
             sections.forEach(section => {
                 const matchFeeItem = feeItemMap[section.feeItemId];
                 if (matchFeeItem) {
@@ -29,7 +35,7 @@ class InstallationDao{
             }
             callback(0, feeItems);
         }
-        catch(err){
+        catch (err) {
             if (!callback) {
                 return [];
             }
@@ -56,55 +62,66 @@ class InstallationDao{
         }
     }*/
 
-    async updateSection(updateData, callback){
-        try{
-            for(let data of updateData){
-                if(data.updateType === 'new'){
+    async updateSection(updateData, libID, callback) {
+        try {
+            const delIDs = [];
+            for (let data of updateData) {
+                if (data.updateData.rationRepId) {
+                    data.updateData.rationRepId = this.getInstLibID(data.updateData.rationRepId);
+                }
+                if (data.updateType === 'new') {
                     await installSectionModel.create(data.updateData);
                 }
-                else if(data.updateType === 'update' && !data.updateData.deleted){
-                    await installSectionModel.update({ID: data.updateData.ID}, data.updateData);
+                else if (data.updateType === 'update' && !data.updateData.deleted) {
+                    await installSectionModel.update({ ID: data.updateData.ID }, data.updateData);
                 }
                 else {
-                    await installSectionModel.remove({ID: data.updateData.ID});
+                    delIDs.push(data.updateData.ID);
+                    await installSectionModel.remove({ ID: data.updateData.ID });
                 }
             }
+            if (delIDs.length) {
+                await rationItemModel.updateMany({ rationRepId: libID }, { $pull: { rationInstList: { sectionId: { $in: delIDs } } } });
+            }
             callback(0, null);
         }
-        catch(err){
+        catch (err) {
             callback(err, null);
         }
     }
 
-    async updateFeeItem(updateData, callback){
-        try{
-            for(let data of updateData){
-                if(data.updateType === 'new'){
+    async updateFeeItem(updateData, callback) {
+        try {
+            for (let data of updateData) {
+                if (data.updateData.rationRepId) {
+                    data.updateData.rationRepId = this.getInstLibID(data.updateData.rationRepId);
+                }
+                if (data.updateType === 'new') {
                     await installFeeItemModel.create(data.updateData);
                 }
-                else if(data.updateType === 'update' && !data.updateData.deleted){
-                    await installFeeItemModel.update({ID: data.updateData.ID}, data.updateData);
+                else if (data.updateType === 'update' && !data.updateData.deleted) {
+                    await installFeeItemModel.update({ ID: data.updateData.ID }, data.updateData);
                 }
-                else{
-                    await installFeeItemModel.remove({ID: data.updateData.ID});
+                else {
+                    await installFeeItemModel.remove({ ID: data.updateData.ID });
                 }
             }
             callback(0, null);
         }
-        catch(err){
+        catch (err) {
             callback(err, null);
         }
     }
 
-    async batchUpdateInst(rationSection, inst, callback){
-        try{
-            for(let sectionId of rationSection){
-                await rationItemModel.update({sectionId: sectionId, $or: [{isDeleted: null}, {isDeleted: false}]},
-                    {$addToSet: {rationInstList: {feeItemId: inst.feeItemId, sectionId: inst.sectionId}}}, {multi: true});
+    async batchUpdateInst(rationSection, inst, callback) {
+        try {
+            for (let sectionId of rationSection) {
+                await rationItemModel.update({ sectionId: sectionId, $or: [{ isDeleted: null }, { isDeleted: false }] },
+                    { $addToSet: { rationInstList: { feeItemId: inst.feeItemId, sectionId: inst.sectionId } } }, { multi: true });
             }
             callback(0, null);
         }
-        catch(err){
+        catch (err) {
             callback(err, null);
         }
     }

Fichier diff supprimé car celui-ci est trop grand
+ 317 - 216
modules/ration_repository/models/ration_item.js


+ 106 - 94
modules/ration_repository/models/ration_section_tree.js

@@ -9,7 +9,7 @@ let rationRepositoryDao = require('./repository_map');
 const rationChapterTreeModel = mongoose.model('std_ration_lib_ration_chapter_trees');
 const rationModel = mongoose.model('std_ration_lib_ration_items');
 const compleRationSectionTemp = mongoose.model('complementary_ration_section_templates');
-var rationChapterTreeDAO = function(){};
+var rationChapterTreeDAO = function () { };
 
 rationChapterTreeDAO.prototype.importSection = async function (rationRepId, sheetData) {
     const counterRst = await counter.counterDAO.getIDAfterCount(counter.moduleName.rationTree, sheetData.length);
@@ -33,55 +33,55 @@ rationChapterTreeDAO.prototype.importSection = async function (rationRepId, shee
 };
 
 rationChapterTreeDAO.prototype.sectionTemplateCount = async function (compilationId) {
-    return await compleRationSectionTemp.find({compilationId}).count();
+    return await compleRationSectionTemp.find({ compilationId }).count();
 };
 
 rationChapterTreeDAO.prototype.initSectionTemplate = async function (rationLibId, compilationId) {
-    let sectionTempCount = await compleRationSectionTemp.find({compilationId}).count();
+    let sectionTempCount = await compleRationSectionTemp.find({ compilationId }).count();
     if (sectionTempCount > 0) {
-        await compleRationSectionTemp.remove({compilationId});
+        await compleRationSectionTemp.remove({ compilationId });
     }
     let bulks = [];
-    let stdRationSection = await rationChapterTreeModel.find({rationRepId: rationLibId});
+    let stdRationSection = await rationChapterTreeModel.find({ rationRepId: rationLibId });
     for (let data of stdRationSection) {
         delete data._doc._id;
         data._doc.compilationId = compilationId;
-        bulks.push({insertOne: {document: data}});
+        bulks.push({ insertOne: { document: data } });
     }
     if (bulks.length > 0) {
         await compleRationSectionTemp.bulkWrite(bulks);
     }
 };
 
-rationChapterTreeDAO.prototype.getRationChapterTree = function(rationLibId,callback){
-    rationChapterTreeModel.find({"rationRepId": rationLibId, "$or": [{"isDeleted": null}, {"isDeleted": false} ]},function(err,data){
-        if(data.length) callback(0,data);
-        else  if(err) callback("获取定额树错误!",[])
-        else callback(0,[]);
+rationChapterTreeDAO.prototype.getRationChapterTree = function (rationLibId, callback) {
+    rationChapterTreeModel.find({ "rationRepId": rationLibId, "$or": [{ "isDeleted": null }, { "isDeleted": false }] }, function (err, data) {
+        if (data.length) callback(0, data);
+        else if (err) callback("获取定额树错误!", [])
+        else callback(0, []);
     })
 }
 
 rationChapterTreeDAO.prototype.getNewRationTreeID = function (callback) {
-    counter.counterDAO.getIDAfterCount(counter.moduleName.rationTree, 1, function(err, result){
-        if(err){
+    counter.counterDAO.getIDAfterCount(counter.moduleName.rationTree, 1, function (err, result) {
+        if (err) {
             callback(err, null);
         }
-        else{
+        else {
             callback(0, result.sequence_value);
         }
     });
 };
 
-rationChapterTreeDAO.prototype.getRationChapterTreeByRepId = function(repId,callback){
-    rationChapterTreeModel.find({"rationRepId": repId, "$or": [{"isDeleted": null}, {"isDeleted": false} ]},function(err,data){
-        if(data.length) callback(0,data);
-        else  if(err) callback("获取定额树错误!",[])
-        else callback(false,[]);
+rationChapterTreeDAO.prototype.getRationChapterTreeByRepId = function (repId, callback) {
+    rationChapterTreeModel.find({ "rationRepId": repId, "$or": [{ "isDeleted": null }, { "isDeleted": false }] }, function (err, data) {
+        if (data.length) callback(0, data);
+        else if (err) callback("获取定额树错误!", [])
+        else callback(false, []);
     })
 }
 
-rationChapterTreeDAO.prototype.createNewNode = function(lastOpr, libId, lastNodeId, nodeData,callback){
-    counter.counterDAO.getIDAfterCount(counter.moduleName.rationTree, 1, function(err, result){
+rationChapterTreeDAO.prototype.createNewNode = function (lastOpr, libId, lastNodeId, nodeData, callback) {
+    counter.counterDAO.getIDAfterCount(counter.moduleName.rationTree, 1, function (err, result) {
         nodeData.rationRepId = libId;
         nodeData.ID = result.sequence_value;
         var node = new rationChapterTreeModel(nodeData);
@@ -92,7 +92,7 @@ rationChapterTreeDAO.prototype.createNewNode = function(lastOpr, libId, lastNode
                         cb("章节树ID错误!", false);
                     } else {
                         if (lastNodeId > 0) {
-                            rationChapterTreeModel.update({ID: lastNodeId}, {"NextSiblingID": nodeData.ID}, function(err, rst){
+                            rationChapterTreeModel.update({ ID: lastNodeId }, { "NextSiblingID": nodeData.ID }, function (err, rst) {
                                 if (err) {
                                     cb("章节树ID错误!", false);
                                 } else {
@@ -104,118 +104,130 @@ rationChapterTreeDAO.prototype.createNewNode = function(lastOpr, libId, lastNode
                 });
             },
             function (cb) {
-                rationRepositoryDao.updateOprArr({ID: libId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
-                    if(err){
+                rationRepositoryDao.updateOprArr({ ID: libId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
+                    if (err) {
                         cb(err);
                     }
-                    else{
+                    else {
                         cb(null);
                     }
                 });
             }
         ], function (err, result) {
-            if(err){
+            if (err) {
                 callback("章节树ID错误!", false);
             }
-            else{
+            else {
                 callback(false, result[0]);
             }
         });
     });
 },
 
-rationChapterTreeDAO.prototype.removeNodes = function(repId, lastOpr, nodeIds, preNodeId, preNodeNextId, callback){
-    var functions = [];
-    if (preNodeId != -1) {
-        functions.push((function(nodeId, nextId) {
-            return function(cb) {
-                rationChapterTreeModel.update({ID: nodeId}, {"NextSiblingID": nextId}, cb);
-            };
-        })(preNodeId, preNodeNextId));
-    }
-    for (var i=0; i < nodeIds.length; i++) {
-        functions.push((function(nodeId) {
-            return function(cb) {
-                rationChapterTreeModel.update({ID: nodeId}, {"isDeleted": true}, cb);
-            };
-        })(nodeIds[i]));
-    }
-    functions.push((function () {
-        return function (cb) {
-            rationRepositoryDao.updateOprArr({ID: repId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
-                if(err){
-                    cb(err);
-                }
-                else{
-                    cb(null);
-                }
-            })
+    rationChapterTreeDAO.prototype.removeNodes = function (repId, lastOpr, nodeIds, preNodeId, preNodeNextId, callback) {
+        var functions = [];
+        if (preNodeId != -1) {
+            functions.push((function (nodeId, nextId) {
+                return function (cb) {
+                    rationChapterTreeModel.update({ ID: nodeId }, { "NextSiblingID": nextId }, cb);
+                };
+            })(preNodeId, preNodeNextId));
         }
-    })());
-    async.parallel(functions, function(err, results) {
-        callback(err, results);
-    });
-}
+        for (var i = 0; i < nodeIds.length; i++) {
+            functions.push((function (nodeId) {
+                return function (cb) {
+                    rationChapterTreeModel.update({ ID: nodeId }, { "isDeleted": true }, cb);
+                };
+            })(nodeIds[i]));
+        }
+        functions.push((function () {
+            return function (cb) {
+                rationRepositoryDao.updateOprArr({ ID: repId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
+                    if (err) {
+                        cb(err);
+                    }
+                    else {
+                        cb(null);
+                    }
+                })
+            }
+        })());
+        async.parallel(functions, function (err, results) {
+            callback(err, results);
+        });
+    }
 
 rationChapterTreeDAO.prototype.updateExplanation = function (lastOpr, repId, nodeId, explanation, callback) {
-    rationChapterTreeModel.update({rationRepId: repId, ID: nodeId}, {$set: {explanation: explanation}}, function (err, result) {
-        if(err){
+    rationChapterTreeModel.update({ rationRepId: repId, ID: nodeId }, { $set: { explanation: explanation } }, function (err, result) {
+        if (err) {
             callback(err);
         }
-        else{
-            rationRepositoryDao.updateOprArr({ID: repId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
+        else {
+            rationRepositoryDao.updateOprArr({ ID: repId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
+                callback(null);
+            });
+        }
+    });
+};
+rationChapterTreeDAO.prototype.updateErratumRecord = function (lastOpr, repId, nodeId, erratumRecord, callback) {
+    rationChapterTreeModel.update({ rationRepId: repId, ID: nodeId }, { $set: { erratumRecord: erratumRecord } }, function (err, result) {
+        if (err) {
+            callback(err);
+        }
+        else {
+            rationRepositoryDao.updateOprArr({ ID: repId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
                 callback(null);
             });
         }
     });
 };
 rationChapterTreeDAO.prototype.updateRuleText = function (lastOpr, repId, nodeId, ruleText, callback) {
-    rationChapterTreeModel.update({rationRepId: repId, ID: nodeId}, {$set: {ruleText: ruleText}}, function (err, result) {
-        if(err){
+    rationChapterTreeModel.update({ rationRepId: repId, ID: nodeId }, { $set: { ruleText: ruleText } }, function (err, result) {
+        if (err) {
             callback(err);
         }
-        else{
-            rationRepositoryDao.updateOprArr({ID: repId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
+        else {
+            rationRepositoryDao.updateOprArr({ ID: repId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
                 callback(null);
             });
         }
     });
 };
 rationChapterTreeDAO.prototype.updateSituation = function (lastOpr, repId, nodeId, situation, callback) {
-    rationChapterTreeModel.update({rationRepId: repId, ID: nodeId}, {$set: {jobContentSituation: situation}}, function (err, result) {
-        if(err){
+    rationChapterTreeModel.update({ rationRepId: repId, ID: nodeId }, { $set: { jobContentSituation: situation } }, function (err, result) {
+        if (err) {
             callback(err);
         }
-        else{
-            rationRepositoryDao.updateOprArr({ID: repId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
+        else {
+            rationRepositoryDao.updateOprArr({ ID: repId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
                 callback(null);
             });
         }
     });
 };
 rationChapterTreeDAO.prototype.updateAnnoSituation = function (lastOpr, repId, nodeId, situation, callback) {
-    rationChapterTreeModel.update({rationRepId: repId, ID: nodeId}, {$set: {annotationSituation: situation}}, function (err, result) {
-        if(err){
+    rationChapterTreeModel.update({ rationRepId: repId, ID: nodeId }, { $set: { annotationSituation: situation } }, function (err, result) {
+        if (err) {
             callback(err);
         }
-        else{
-            rationRepositoryDao.updateOprArr({ID: repId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
+        else {
+            rationRepositoryDao.updateOprArr({ ID: repId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
                 callback(null);
             });
         }
     });
 };
 
-rationChapterTreeDAO.prototype.updateNodes = function(lastOpr, updateData,callback){
+rationChapterTreeDAO.prototype.updateNodes = function (lastOpr, updateData, callback) {
     var functions = [];
-    for (var i=0; i < updateData.length; i++) {
+    for (var i = 0; i < updateData.length; i++) {
         //var md = new rationChapterTreeModel(nodes[i]);
         //md.isNew = false;
-        functions.push((function(doc) {
-            return function(cb) {
-                if(doc.updateType === 'update' && !doc.updateData.isDeleted){
-                    rationChapterTreeModel.update({rationRepId: doc.updateData.rationRepId, ID: doc.updateData.ID}, doc.updateData, function (err) {
-                        if(err){
+        functions.push((function (doc) {
+            return function (cb) {
+                if (doc.updateType === 'update' && !doc.updateData.isDeleted) {
+                    rationChapterTreeModel.update({ rationRepId: doc.updateData.rationRepId, ID: doc.updateData.ID }, doc.updateData, function (err) {
+                        if (err) {
                             cb(err);
                         }
                         else {
@@ -223,14 +235,14 @@ rationChapterTreeDAO.prototype.updateNodes = function(lastOpr, updateData,callba
                         }
                     });
                 }
-                else if(doc.updateType === 'update' && doc.updateData.isDeleted){
-                    rationChapterTreeModel.remove({rationRepId: doc.updateData.rationRepId, ID: doc.updateData.ID}, function (err) {
-                        if(err){
+                else if (doc.updateType === 'update' && doc.updateData.isDeleted) {
+                    rationChapterTreeModel.remove({ rationRepId: doc.updateData.rationRepId, ID: doc.updateData.ID }, function (err) {
+                        if (err) {
                             cb(err);
                         }
                         else {
-                            rationModel.remove({sectionId: doc.updateData.ID}, function(err){
-                                if(err){
+                            rationModel.remove({ sectionId: doc.updateData.ID }, function (err) {
+                                if (err) {
                                     cb(err);
                                 }
                                 else {
@@ -241,9 +253,9 @@ rationChapterTreeDAO.prototype.updateNodes = function(lastOpr, updateData,callba
                         }
                     });
                 }
-                else if(doc.updateType === 'new'){
+                else if (doc.updateType === 'new') {
                     rationChapterTreeModel.create(doc.updateData, function (err) {
-                        if(err){
+                        if (err) {
                             cb(err);
                         }
                         else {
@@ -254,22 +266,22 @@ rationChapterTreeDAO.prototype.updateNodes = function(lastOpr, updateData,callba
             };
         })(updateData[i]));
     }
-    if(updateData.length > 0){
+    if (updateData.length > 0) {
         functions.push((function () {
             return function (cb) {
-                rationRepositoryDao.updateOprArr({ID: updateData[0].updateData.rationRepId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
-                    if(err){
+                rationRepositoryDao.updateOprArr({ ID: updateData[0].updateData.rationRepId }, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
+                    if (err) {
                         cb(err);
                     }
-                    else{
+                    else {
                         cb(null);
                     }
                 })
             }
         })());
     }
-    async.parallel(functions, function(err, results) {
-        if(!err){
+    async.parallel(functions, function (err, results) {
+        if (!err) {
             err = 0;
         }
         callback(err, results);

+ 46 - 45
modules/ration_repository/routes/ration_rep_routes.js

@@ -2,7 +2,7 @@
  * Created by Tony on 2017/4/20.
  */
 var express = require("express");
-var apiRouter =express.Router();
+var apiRouter = express.Router();
 //var _rootDir = __dirname;
 import ViewsController from "../controllers/repository_views_controller";
 import RationRepositoryController from "../controllers/ration_repository_controller";
@@ -23,9 +23,9 @@ let searchController = new SearchController();
 let repositoryGljController = new RepositoryGljController();
 let gljController = new GljController();
 
-module.exports =  function (app) {
+module.exports = function (app) {
     app.get('/rationRepository/main', viewsController.auth, viewsController.init, viewsController.redirectMain);
-    app.get('/rationRepository/ration',viewsController.auth, viewsController.init, viewsController.redirectRation);
+    app.get('/rationRepository/ration', viewsController.auth, viewsController.init, viewsController.redirectRation);
     app.get('/rationRepository/lmm', viewsController.auth, viewsController.init, viewsController.redirectGlj);
     app.get('/rationRepository/coeList', viewsController.auth, viewsController.init, viewsController.redirectCoeList);
     app.get('/rationRepository/installation', viewsController.auth, viewsController.init, viewsController.redirectInstallation);
@@ -33,53 +33,54 @@ module.exports =  function (app) {
     apiRouter.post("/prepareInitData", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.prepareInitData);
     apiRouter.post("/getCompilationList", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getCompilationList);
     apiRouter.post("/getRationLibsByCompilation", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getRationLibsByCompilation);
-    apiRouter.post("/getRationLib",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getRationLib);
+    apiRouter.post("/getRationLib", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getRationLib);
 
-    apiRouter.post("/getRationDisplayNames",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getDisPlayRationLibs);
-    apiRouter.post("/editRationLibs",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.updateRationRepositoryName);
-    apiRouter.post("/addRationRepository",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.addRationRepository);
-    apiRouter.post("/deleteRationLibs",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.deleteRationLib);
-    apiRouter.post("/getRealLibName",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getRealLibName);
-    apiRouter.post("/getLibIDByName",rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getLibIDByName);
+    apiRouter.post("/getRationDisplayNames", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getDisPlayRationLibs);
+    apiRouter.post("/editRationLibs", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.updateRationRepositoryName);
+    apiRouter.post("/addRationRepository", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.addRationRepository);
+    apiRouter.post("/deleteRationLibs", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.deleteRationLib);
+    apiRouter.post("/getRealLibName", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getRealLibName);
+    apiRouter.post("/getLibIDByName", rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.getLibIDByName);
 
     apiRouter.get('/sectionTemplateCount/:compilationId', rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.sectionTemplateCount);
     apiRouter.post('/initSectionTemplate', rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.initSectionTemplate);
-    apiRouter.post("/getRationTree",rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.getRationChapterTree);
-    apiRouter.post("/getNewRationTreeID",rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.getNewRationTreeID);
-    apiRouter.post("/createNewNode",rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.createNewNode);
-    apiRouter.post("/updateNodes",rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.updateNodes);
-    apiRouter.post("/deleteNodes",rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.deleteNodes);
-    apiRouter.post("/updateExplanation",rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.updateExplanation);
-    apiRouter.post("/updateRuleText",rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.updateRuleText);
-    apiRouter.post("/updateSituation",rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.updateSituation);
-    apiRouter.post("/updateAnnoSituation",rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.updateAnnoSituation);
+    apiRouter.post("/getRationTree", rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.getRationChapterTree);
+    apiRouter.post("/getNewRationTreeID", rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.getNewRationTreeID);
+    apiRouter.post("/createNewNode", rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.createNewNode);
+    apiRouter.post("/updateNodes", rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.updateNodes);
+    apiRouter.post("/deleteNodes", rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.deleteNodes);
+    apiRouter.post("/updateExplanation", rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.updateExplanation);
+    apiRouter.post("/updateErratumRecord", rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.updateErratumRecord);
+    apiRouter.post("/updateRuleText", rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.updateRuleText);
+    apiRouter.post("/updateSituation", rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.updateSituation);
+    apiRouter.post("/updateAnnoSituation", rationChapterTreeController.auth, rationChapterTreeController.init, rationChapterTreeController.updateAnnoSituation);
 
-    apiRouter.post("/getRationItems",rationController.auth, rationController.init, rationController.getRationItemsBySection);
-    apiRouter.post("/getRationItemsByLib",rationController.auth, rationController.init, rationController.getRationItemsByLib);
-    apiRouter.post("/mixUpdateRationItems",rationController.auth, rationController.init, rationController.mixUpdateRationItems);
-    apiRouter.post("/updateRationBasePrc",rationController.auth, rationController.init, rationController.updateRationBasePrc);
-    apiRouter.post("/getRationGljIds",rationController.auth, rationController.init, rationController.getRationGljIds);
-    apiRouter.post("/getRationsCodes",rationController.auth, rationController.init, rationController.getRationsCodes);
-    apiRouter.post("/updateJobContent",rationController.auth, rationController.init, rationController.updateJobContent);
-    apiRouter.post("/updateAnnotation",rationController.auth, rationController.init, rationController.updateAnnotation);
-    apiRouter.post("/updateRationTemplate",rationController.auth, rationController.init, rationController.updateRationTemplate);
-    apiRouter.post("/updateRationBySection",rationController.auth, rationController.init, rationController.updateRationBySection);
+    apiRouter.post("/getRationItems", rationController.auth, rationController.init, rationController.getRationItemsBySection);
+    apiRouter.post("/getRationItemsByLib", rationController.auth, rationController.init, rationController.getRationItemsByLib);
+    apiRouter.post("/mixUpdateRationItems", rationController.auth, rationController.init, rationController.mixUpdateRationItems);
+    apiRouter.post("/updateRationBasePrc", rationController.auth, rationController.init, rationController.updateRationBasePrc);
+    apiRouter.post("/getRationGljIds", rationController.auth, rationController.init, rationController.getRationGljIds);
+    apiRouter.post("/getRationsCodes", rationController.auth, rationController.init, rationController.getRationsCodes);
+    apiRouter.post("/updateJobContent", rationController.auth, rationController.init, rationController.updateJobContent);
+    apiRouter.post("/updateAnnotation", rationController.auth, rationController.init, rationController.updateAnnotation);
+    apiRouter.post("/updateRationTemplate", rationController.auth, rationController.init, rationController.updateRationTemplate);
+    apiRouter.post("/updateRationBySection", rationController.auth, rationController.init, rationController.updateRationBySection);
 
-    apiRouter.post("/createNewGljTypeNode",repositoryGljController.auth, gljController.init, gljController.createNewGljTypeNode);
-    apiRouter.post("/updateGljNodes",repositoryGljController.auth, gljController.init, gljController.updateGljNodes);
-    apiRouter.post("/deleteGljNodes",repositoryGljController.auth, gljController.init, gljController.deleteGljNodes);
-    apiRouter.post("/getGljDistType",repositoryGljController.auth, gljController.init, gljController.getGljDistType);
-    apiRouter.post("/getGljTree",repositoryGljController.auth, gljController.init, gljController.getGljTree);
-    apiRouter.post("/getGljItems",repositoryGljController.auth, gljController.init, gljController.getGljItems);
-    apiRouter.post("/mixUpdateGljItems",repositoryGljController.auth, gljController.init, gljController.mixUpdateGljItems);
-    apiRouter.post("/getGljItemsByIds",repositoryGljController.auth, gljController.init, gljController.getGljItemsByIds);
-    apiRouter.post("/getGljItemsByCodes",repositoryGljController.auth, gljController.init, gljController.getGljItemsByCodes);
+    apiRouter.post("/createNewGljTypeNode", repositoryGljController.auth, gljController.init, gljController.createNewGljTypeNode);
+    apiRouter.post("/updateGljNodes", repositoryGljController.auth, gljController.init, gljController.updateGljNodes);
+    apiRouter.post("/deleteGljNodes", repositoryGljController.auth, gljController.init, gljController.deleteGljNodes);
+    apiRouter.post("/getGljDistType", repositoryGljController.auth, gljController.init, gljController.getGljDistType);
+    apiRouter.post("/getGljTree", repositoryGljController.auth, gljController.init, gljController.getGljTree);
+    apiRouter.post("/getGljItems", repositoryGljController.auth, gljController.init, gljController.getGljItems);
+    apiRouter.post("/mixUpdateGljItems", repositoryGljController.auth, gljController.init, gljController.mixUpdateGljItems);
+    apiRouter.post("/getGljItemsByIds", repositoryGljController.auth, gljController.init, gljController.getGljItemsByIds);
+    apiRouter.post("/getGljItemsByCodes", repositoryGljController.auth, gljController.init, gljController.getGljItemsByCodes);
 
-    apiRouter.post("/getCoeReference",coeListController.auth, coeListController.init, coeListController.getCoeReference);
-    apiRouter.post("/getCoeList",coeListController.auth, coeListController.init, coeListController.getCoeList);
-    apiRouter.post("/saveCoeList",coeListController.auth, coeListController.init, coeListController.saveCoeList);
-    apiRouter.post("/getCoeItemsByIDs",coeListController.auth, coeListController.init, coeListController.getCoeItemsByIDs);
-    apiRouter.post("/getCoeItemsByNos",coeListController.auth, coeListController.init, coeListController.getCoeItemsByNos);
+    apiRouter.post("/getCoeReference", coeListController.auth, coeListController.init, coeListController.getCoeReference);
+    apiRouter.post("/getCoeList", coeListController.auth, coeListController.init, coeListController.getCoeList);
+    apiRouter.post("/saveCoeList", coeListController.auth, coeListController.init, coeListController.saveCoeList);
+    apiRouter.post("/getCoeItemsByIDs", coeListController.auth, coeListController.init, coeListController.getCoeItemsByIDs);
+    apiRouter.post("/getCoeItemsByNos", coeListController.auth, coeListController.init, coeListController.getCoeItemsByNos);
 
     //安装增加费
     apiRouter.post('/getInstallation', installationController.auth, installationController.init, installationController.getInstallation);
@@ -88,7 +89,7 @@ module.exports =  function (app) {
     apiRouter.post('/batchUpdateInst', installationController.auth, installationController.init, installationController.batchUpdateInst);
 
     apiRouter.post('/getRationByID', searchController.auth, searchController.init, searchController.getRationByID);
-    apiRouter.post('/getRationItem',searchController.auth, searchController.init, searchController.getRationItem);
+    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);
@@ -96,5 +97,5 @@ module.exports =  function (app) {
     apiRouter.post('/upload', rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.uploadSourceData);
     apiRouter.get('/export', rationRepositoryController.auth, rationRepositoryController.init, rationRepositoryController.exportRationData);
 
-    app.use("/rationRepository/api",apiRouter);
+    app.use("/rationRepository/api", apiRouter);
 }

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

@@ -86,6 +86,17 @@ class BillsGuideLibController extends BaseController{
         }
     }
 
+    async getItemsByBillIDs(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let items = await billsGuidanceFacade.getItemsByBillIDs(data.guidanceLibID, data.billIDs);
+            callback(req, res, 0, '', items);
+        }
+        catch(err){
+            callback(req, res, 1, err, null);
+        }
+    }
+
     async updateItems(req, res){
         try{
 
@@ -142,6 +153,19 @@ class BillsGuideLibController extends BaseController{
         }
     }
 
+    async autoSetMaterial(req, res) {
+        try{
+            res.setTimeout(1000 * 60 * 10); // 不设置的话,处理时间过长,会触发默认的响应超时,报错(前端报错,后台还继续在处理)
+            const data = JSON.parse(req.body.data);
+            await billsGuidanceFacade.autoSetMaterial(data.libID);
+            callback(req, res, 0, '', []);
+        }
+        catch(err){
+            console.log(err);
+            callback(req, res, 1, err.message, []);
+        }
+    }
+
     async exportClassExcel(req, res) {
         try{
             const excelData = await billsGuidanceFacade.getClassExcelData(req.query.libID);

+ 224 - 40
modules/std_billsGuidance_lib/facade/facades.js

@@ -36,12 +36,14 @@ module.exports = {
     updateBillsGuideLib,
     getLibWithBills,
     getItemsBybills,
+    getItemsByBillIDs,
     updateItems,
     getBillMaterials,
     editBillMaterials,
     generateClassData,
     getClassExcelData,
-    testItems
+    autoSetMaterial,
+    testItems,
 };
 
 function setChildren(bill, parentMap) {
@@ -290,7 +292,7 @@ async function getLibWithBills(libID) {
     if (!billsLib) {
         throw '引用的清单规则库不存在!';
     }
-    let bills = await stdBillsModel.find({ billsLibId: billsLib.billsLibId }, '-_id code name ID NextSiblingID ParentID jobs items comment').lean();
+    let bills = await stdBillsModel.find({ billsLibId: billsLib.billsLibId }, '-_id code name ID unit NextSiblingID ParentID jobs items comment').lean();
     const guideItems = await billsGuideItemsModel.find({ libID: guidanceLib[0].ID }, '-_id billsID').lean();
     const billsMap = {};
     for (const item of guideItems) {
@@ -359,9 +361,8 @@ function chainToArr(nodes) {
     return rst;
 }
 
-async function getItemsBybills(guidanceLibID, billsID) {
+async function checkItems(items) {
     const type = { job: 0, ration: 1 };
-    let items = await billsGuideItemsModel.find({ libID: guidanceLibID, billsID: billsID, deleted: false });
     let rationItems = _.filter(items, { type: type.ration });
     let rationIds = getAttrs('rationID', rationItems);
     let stdRations = await stdRationModel.find({ ID: { $in: rationIds }, $or: [{ isDeleted: null }, { isDeleted: false }] });
@@ -394,6 +395,17 @@ async function getItemsBybills(guidanceLibID, billsID) {
         }
         await billsGuideItemsModel.bulkWrite(bulkArr);
     }
+}
+
+async function getItemsBybills(guidanceLibID, billsID) {
+    let items = await billsGuideItemsModel.find({ libID: guidanceLibID, billsID: billsID});
+    await checkItems(items);
+    return items;
+}
+
+async function getItemsByBillIDs(guidanceLibID, billIDs) {
+    let items = await billsGuideItemsModel.find({ libID: guidanceLibID, billsID: { $in: billIDs }});
+    await checkItems(items);
     return items;
 }
 
@@ -539,18 +551,19 @@ function getOptionalData(node, list = []) {
     return list;
 }
 
-    // 获取必填项下的ID和name的键值对
-    function getClassCodeStrData(nodes,data={}){
-        nodes.forEach(node=>{
-           if (isProcessNode(node)&&node.data.required) {
-               node.children.forEach(subNode=>{
-                   data[subNode.data.ID]=subNode.data.name;  
-               })
-           }
-           getClassCodeStrData(node.children,data);
-        })
-       return data;
-   }
+  // 获取必填项下的ID和name的键值对
+  function getClassCodeStrData(nodes,data={classGroups:{},keyGroup:{}}){
+    nodes.forEach(node=>{
+       if (isProcessNode(node)&&node.data.required) {
+           node.children.forEach(subNode=>{
+               data.classGroups[subNode.data.ID]=subNode.data.name;  
+               data.keyGroup[subNode.data.ID]=`${subNode.parent.data.name}:${subNode.data.name}`; 
+           })
+       }
+       getClassCodeStrData(node.children,data);
+    })
+   return data;
+}
 
 
 //获取定额数据
@@ -558,7 +571,7 @@ function getOptionalData(node, list = []) {
     // optionalRationData 选逃定额对象
     // classGroups classCode文字和id键值对
     // classCodeList 各个classCode的pID和ID的关系
-function getItemData(nodes, requireRationData = {}, optionalRationData = {}, classGroups = {}, prefixID = '', prefixSonID = '', IDData = {}) {
+function getItemData(nodes, requireRationData = {}, optionalRationData = {}, classGroups = {}, prefixID = '', prefixSonID = '', IDData = {}, keyGroup={}) {
     const processNodes = nodes.filter(node => isProcessNode(node));
     // const classGroups = []; // 同层必填选项的数组(二维数组)
     processNodes.forEach(processNode => {
@@ -582,15 +595,23 @@ function getItemData(nodes, requireRationData = {}, optionalRationData = {}, cla
                     const kV = {};
                     kV[optionNode.data.ID] = optionNode.data.name;
                     Object.assign(classGroups, kV);
+
+                    const keyData={};
+                    keyData[optionNode.data.ID] = `${optionNode.parent.data.name}:${optionNode.data.name}`;
+                    Object.assign(keyGroup,keyData);
                 } else {
                     const kV = {};
                     kV[optionNode.data.ID] = optionNode.data.name;
                     Object.assign(classGroups, kV);
+
+                    const keyData={};
+                    keyData[optionNode.data.ID] = `${optionNode.parent.data.name}:${optionNode.data.name}`;
+                    Object.assign(keyGroup,keyData);
                     // 后代项是否有必填
                     if (hasRequireData(optionNode)) {
                         //后代项有必填
                         prefixSonID = '';
-                        getItemData(optionNode.children, requireRationData, optionalRationData, classGroups, optionNode.data.ID, prefixSonID, IDData);
+                        getItemData(optionNode.children, requireRationData, optionalRationData, classGroups, optionNode.data.ID, prefixSonID, IDData, keyGroup);
                     } else {
                         //后代项无必填
                         optionNode.children.forEach(subOptionNode => {
@@ -626,7 +647,8 @@ function getItemData(nodes, requireRationData = {}, optionalRationData = {}, cla
                                     classGroups,
                                     prefixID,
                                     requireChildrenID,
-                                    IDData
+                                    IDData,
+                                    keyGroup
 
                                 )
                             })
@@ -639,7 +661,11 @@ function getItemData(nodes, requireRationData = {}, optionalRationData = {}, cla
                        if (!optionalRationData[key]) optionalRationData[key] = [];
                        optionalRationData[key].push(...getOptionalData(processNode));
                        // 因为这里没有按照走整个流程,所以文字和ID的关系需要获取补充
-                      if(hasRequireData(processNode))  Object.assign(classGroups,getClassCodeStrData(processNode.children)) ;
+                      if(hasRequireData(processNode)){
+                        const result =getClassCodeStrData(processNode.children)
+                        Object.assign(classGroups,result.classGroups);
+                        Object.assign(keyGroup,result.keyGroup);
+                      }  
                     }
                 }
             } else {
@@ -657,7 +683,7 @@ function getItemData(nodes, requireRationData = {}, optionalRationData = {}, cla
             }
         }
     })
-    return { requireRationData, optionalRationData, classGroups, IDData }
+    return { requireRationData, optionalRationData, classGroups, IDData, keyGroup}
 }
 
 
@@ -746,11 +772,9 @@ function getItemClassData(nodes, prefix,
 // 获取选套定额:把所有分类数据的必套定额确定好了先。选套定额就是清单下所有定额除了必套的
 function getOptionalRationIDs(optionalRationData) {
     const optionalRationIDs = [];
-    if(optionalRationData){
-        Object.values(optionalRationData).forEach(optionalRation => {
-            if (optionalRation.length) optionalRationIDs.push(...optionalRation);
-        })
-    }
+    Object.values(optionalRationData).forEach(optionalRation => {
+        if (optionalRation.length) optionalRationIDs.push(...optionalRation);
+    })
     return [...new Set(optionalRationIDs)];
 }
 
@@ -770,7 +794,7 @@ function getErrorRationIDs(requiredRationIDList, optionalRationIDs, allRationIDs
 }
 
 //把classcode和必套选套定额结合在一起
-function combineData(codeData, requireRationData, optionalRationData, classGroups, IDData) {
+function combineData(codeData, requireRationData, optionalRationData, classGroups, IDData, keyGroup) {
     // 这里要记录下已经被绑定的选套定额,因为没有被用的定额需要绑定到各个classcode下
     const matchRationList = [];
     //这里需要把绑定在子节点的定额更新到必填的白色选项中(classcode的值)
@@ -798,13 +822,16 @@ function combineData(codeData, requireRationData, optionalRationData, classGroup
         const optionalRationIDs = [];
         const requiredRationIDs = [];
         let name = '';
+        let key = ''; 
         const classCodeIDs = classCodeData.ID;
         if (/@/.test(classCodeIDs)) {
             classCodeIDs.split('@').forEach((classCodeID) => {
                 if (name) {
-                    name = name + '@' + classGroups[classCodeID]
+                    name = name + '@' + classGroups[classCodeID];
+                    key += keyGroup[classCodeID];
                 } else {
-                    name = classGroups[classCodeID]
+                    name = classGroups[classCodeID];
+                    key = keyGroup[classCodeID];
                 };
                 // 一组的必套定额,先去重
                 const unitRation = [];
@@ -837,10 +864,11 @@ function combineData(codeData, requireRationData, optionalRationData, classGroup
                 }
 
             })
-            return { name, requiredRationIDs, optionalRationIDs: [...new Set(optionalRationIDs)], errorRationIDs }
+            return { name, key, requiredRationIDs, optionalRationIDs: [...new Set(optionalRationIDs)], errorRationIDs }
         } else {
             const unitRation = [];
             name = classGroups[classCodeIDs];
+            key = keyGroup[classCodeIDs];
             if (requireRationData[classCodeIDs] && requireRationData[classCodeIDs].length){
                 requireRationData[classCodeIDs].forEach(subItem => {
                     unitRation.push(...new Set(subItem));
@@ -864,7 +892,7 @@ function combineData(codeData, requireRationData, optionalRationData, classGroup
                 optionalRationIDs.push(...optionCombineData[classCodeIDs]);
                 matchRationList.push(...optionalRationData[classCodeIDs]);
             }
-            return { name, requiredRationIDs, optionalRationIDs: [...new Set(optionalRationIDs)], errorRationIDs }
+            return { name,key, requiredRationIDs, optionalRationIDs: [...new Set(optionalRationIDs)], errorRationIDs }
         }
     })
     const unMatchRation = [];
@@ -888,7 +916,6 @@ function combineData(codeData, requireRationData, optionalRationData, classGroup
     return { itemClassData: finData, unMatchRation };
 }
 
-
 // 生成清单分类
 async function generateClassData(libID) {
     const lib = await billsGuideLibModel.findOne({ ID: libID }).lean();
@@ -901,7 +928,7 @@ async function generateClassData(libID) {
     guidanceItems.forEach(item => {
         (guidanceMap[item.billsID] || (guidanceMap[item.billsID] = [])).push(item);
     });
-    const bills = await stdBillsModel.find({ billsLibId: lib.billsLibId }, '-_id ID ParentID NextSiblingID name code').lean();
+    const bills = await stdBillsModel.find({ billsLibId: lib.billsLibId }, '-_id ID ParentID NextSiblingID name code unit').lean();
     const billTree = idTree.createNew({ id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true });
     billTree.loadDatas(bills);
     // 叶子清单
@@ -914,29 +941,30 @@ async function generateClassData(libID) {
         if (!guidanceItems || !guidanceItems.length) {
             continue;
         }
-        if (billNode.data.code.startsWith('03')) continue;//先屏蔽掉03开头的清单
+        // if (billNode.data.code.startsWith('03')) continue;//先屏蔽掉03开头的清单
         const guidanceTree = idTree.createNew({ id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true });
         guidanceTree.loadDatas(guidanceItems);
         //console.log('getItemClassData start',billNode.data.name,billNode.data.code,billNode.data.ID);
         const classCodeData = getItemClassData(guidanceTree.roots); // 必套定额在这个方法内就获取了,避免重复执行递归方法
-        const { requireRationData, optionalRationData, classGroups, IDData } = getItemData(guidanceTree.roots);
-        const { itemClassData, unMatchRation } = combineData(classCodeData, requireRationData, optionalRationData, classGroups, IDData);
+        const { requireRationData, optionalRationData, classGroups, IDData, keyGroup } = getItemData(guidanceTree.roots);
+
+        const { itemClassData, unMatchRation } = combineData(classCodeData, requireRationData, optionalRationData, classGroups, IDData, keyGroup);
 
         const allRationIDs = guidanceTree.items.filter(node => !!node.data.rationID).map(node => node.data.rationID);
         // 选套定额ID
-        const optionalRationIDs = getOptionalRationIDs(itemClassData, allRationIDs);
+        const optionalRationIDs = getOptionalRationIDs(optionalRationData);
         //if(itemClassData.length > 1000) console.log('getItemClassData end',billNode.data.name,billNode.data.code,billNode.data.ID,itemClassData.length)
         itemClassData.forEach(item => {
             // 错套定额
             item.optionalRationIDs.push(...unMatchRation);
             const errorRationIDs = getErrorRationIDs(item.requiredRationIDs, item.optionalRationIDs, allRationIDs);
-            if (billNode.data.ID == '1d32fa34-0a9b-11ea-a33d-5388f9783b09') console.log(item.name)
             billClassData.push({
                 itemCharacter: item.name,
                 class: classNum++,
                 classCode: `${billNode.data.code}@${item.name}`,
                 compilationID: lib.compilationId,
                 name: billNode.data.name,
+                key: `${billNode.data.code}${billNode.data.name}${billNode.data.unit}${item.key}`,
                 code: billNode.data.code,
                 requiredRationIDs: item.requiredRationIDs || [],
                 optionalRationIDs: item.optionalRationIDs || [],
@@ -950,19 +978,21 @@ async function generateClassData(libID) {
                     if (data.length) optionalRationIDs.push(...data);
                 })
             })
+           
             const errorRationIDs = getErrorRationIDs([], optionalRationIDs, allRationIDs);
+           
             billClassData.push({
                 itemCharacter: '',
                 class: classNum++,
                 classCode: `${billNode.data.code}`,
                 compilationID: lib.compilationId,
                 name: billNode.data.name,
+                key:`${billNode.data.code}${billNode.data.name}${billNode.data.unit}`,
                 code: billNode.data.code,
                 requiredRationIDs: [],
                 optionalRationIDs: optionalRationIDs || [],
                 errorRationIDs,
             });
-
         }
     }
     console.log(`billClassData.length`);
@@ -989,7 +1019,7 @@ async function getClassExcelData(libID) {
     const classData = await billClassModel.find({ compilationID: lib.compilationId }).lean();
     console.log('end');
     console.log(Date.now() - date);
-    const excelData = [['类别', '编码', '清单名称', '必填特征排列组合', '类别别名', '必套定额', '选套定额', '错套定额']];
+    const excelData = [['类别', '编码', '清单名称', '必填特征排列组合', '类别别名', '必套定额', '选套定额', '错套定额','基础样本']];
     classData.forEach(item => {
         const excelItem = [
             item.class,
@@ -1000,6 +1030,7 @@ async function getClassExcelData(libID) {
             (item.requiredRationIDs || []).join('@'),
             (item.optionalRationIDs || []).join('@'),
             (item.errorRationIDs || []).join('@'),
+            item.key,
         ];
         excelData.push(excelItem);
     });
@@ -1068,4 +1099,157 @@ async function testItems(libID) {
    
        }*/
     return delBulk.length;
+}
+
+// 获取清单ID - 指引数据映射
+async function getGuidanceMap(libID) {
+    const guidanceItems = await billsGuideItemsModel.find({ libID }, '-_id').lean();
+    // 清单ID - 指引数据映射
+    const guidanceMap = {};
+    guidanceItems.forEach(item => {
+        (guidanceMap[item.billsID] || (guidanceMap[item.billsID] = [])).push(item);
+    });
+    return guidanceMap;
+}
+
+// 获取清单树
+async function getBillTree(libID) {
+    const lib = await billsGuideLibModel.findOne({ ID: libID }).lean();
+    if (!lib) {
+        throw new Error('无有效精灵库');
+    }
+    const bills = await stdBillsModel.find({ billsLibId: lib.billsLibId }, '-_id ID ParentID NextSiblingID name code unit').lean();
+    const billTree = idTree.createNew({ id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true });
+    billTree.loadDatas(bills);
+    return billTree;
+}
+
+// 获取定额ID - 人材机数组 映射
+async function getRationIDGljMap(rationIDs) {
+    let allGljList = [];
+    const rations = await stdRationModel.find({ ID: { $in: rationIDs } }, '-_id ID rationGljList');
+    const gljIDs = [];
+    rations.forEach(ration => {
+        if (ration.rationGljList && ration.rationGljList.length) {
+            gljIDs.push(...ration.rationGljList.map(rGlj => rGlj.gljId));
+        }
+    });
+    if (gljIDs.length) {
+        allGljList = await gljModel.find({ ID: { $in: [...new Set(gljIDs)] } }, '-_id ID code name specs gljType').lean();
+    }
+    const gljMap = {};
+    allGljList.forEach(glj => gljMap[glj.ID] = glj);
+    const rationIDGljMap = {};
+    rations.forEach(ration => {
+        if (ration.rationGljList && ration.rationGljList.length) {
+            rationIDGljMap[ration.ID] = ration.rationGljList.map(rGlj => gljMap[rGlj.gljId]);
+        } else {
+            rationIDGljMap[ration.ID] = [];
+        }
+    });
+    return rationIDGljMap;
+}
+
+// 需要自动配置材料的工序行
+function needAutoMaterialNode(node) {
+    const needAutoNames = [
+        '水泥强度等级',
+        '混凝土强度等级',
+        '砂浆强度等级',
+        '砌筑砂浆强度等级',
+        '砂浆配合比',
+        '砂强度等级',
+        '构件混凝土强度等级',
+    ];
+    const name = (node.data.name || '').trim();
+    return isProcessNode(node) && needAutoNames.includes(name);
+}
+
+// 获取需要自动配置的数据
+function getNeedAutoSetData(leafBills, guidanceMap) {
+    const allRationIDs = [];
+    const toAutoSetData = []; // 准备要自动配置的数据
+    const markMaterialIDs = []; // 需要打勾材料的数据ID
+    for (let billNode of leafBills) {
+        const guidanceItems = guidanceMap[billNode.data.ID];
+        if (!guidanceItems || !guidanceItems.length) {
+            continue;
+        }
+        const guidanceTree = idTree.createNew({ id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true });
+        guidanceTree.loadDatas(guidanceItems);
+        const needAutoSetItems = guidanceTree.items.filter(node => needAutoMaterialNode(node));
+        // 存在需要自动配置材料
+        if (needAutoSetItems.length) {
+            const rationIDs = guidanceTree.items
+                .filter(node => node.data.rationID)
+                .map(node => node.data.rationID);
+            allRationIDs.push(...rationIDs);
+            markMaterialIDs.push(...needAutoSetItems.map(node => node.data.ID));
+            toAutoSetData.push({
+                rationIDs, // 选择的材料只能从当前定额人材机下选
+                billID: billNode.data.ID,
+            });
+        }
+    }
+
+    return { allRationIDs, markMaterialIDs, toAutoSetData };
+}
+
+const autoSetGljCodes = [
+    '0401',
+    '8001',
+    '8003',
+    '8005',
+    '8009',
+    '8011',
+    '8013',
+    '8015',
+    '8017',
+    '8019',
+    '8021',
+]
+
+// 自动配置材料
+async function autoSetMaterial(libID) {
+    const billTree = await getBillTree(libID);
+    const guidanceMap = await getGuidanceMap(libID);
+    const leafBills = billTree.items.filter(node => !node.children || !node.children.length);
+    const { allRationIDs, markMaterialIDs, toAutoSetData } = getNeedAutoSetData(leafBills, guidanceMap);
+    if (!toAutoSetData.length) {
+        return;
+    }
+    const rationIDGljMap = await getRationIDGljMap([...new Set(allRationIDs)]);
+    const billMaterials = []; // 自动配置材料 (如果原本有配置,则替换原本的:删除旧的doc,插入新的doc)
+    const billIDs = [];
+    toAutoSetData.forEach(({ billID, rationIDs }) => {
+        billIDs.push(billID);
+        // 清单工料机
+        const billGljList = rationIDs.reduce((list, cur) => {
+            if (rationIDGljMap[cur]) {
+                list.push(...rationIDGljMap[cur])
+            }
+            return list;
+        }, []);
+        // 从清单工料机列表中筛选,当前清单下定额工料机中存在的,配置到“配置材料”中,需要命中材料编码前四位
+        const materialIDs = [];
+        billGljList.forEach(glj => {
+            const fourCode = (glj.code || '').substr(0, 4);
+            if (autoSetGljCodes.includes(fourCode) && !materialIDs.includes(glj.ID)) {
+                materialIDs.push(glj.ID);
+            }
+        });
+        const materials = materialIDs.map(gljID => ({ gljID }));
+        billMaterials.push({
+            libID,
+            billID,
+            ID: uuidV1(),
+            materials
+        });
+    });
+    // 打勾材料
+    await billsGuideItemsModel.updateMany({ ID: { $in: markMaterialIDs } }, { $set: { isMaterial: true } });
+    // 删除要被替换的清单材料
+    await billMaterialModel.deleteMany({ libID, billID: { $in: billIDs } });
+    // 插入新的材料
+    await billMaterialModel.insertMany(billMaterials);
 }

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

@@ -22,10 +22,12 @@ module.exports = function (app) {
     router.post('/updateBillsGuideLib', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.updateBillsGuideLib);
     router.post('/getLibWithBills', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.getLibWithBills);
     router.post('/getItemsByBills', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.getItemsByBills);
+    router.post('/getItemsByBillIDs', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.getItemsByBillIDs);
     router.post('/updateItems', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.updateItems);
     router.post('/getBillMaterials', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.getBillMaterials);
     router.post('/editBillMaterials', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.editBillMaterials);
     router.post('/generateClassData', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.generateClassData);
+    router.post('/autoSetMaterial', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.autoSetMaterial);
     router.get('/exportClassExcel', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.exportClassExcel);
     //test
     //router.post('/testItems', billsGuideLibController.auth, billsGuideLibController.init, billsGuideLibController.testItems);

+ 108 - 1
modules/users/controllers/compilation_controller.js

@@ -31,6 +31,8 @@ import economicFacade from "../../economic_lib/facade/economic_facade";
 import overHeightFacade from "../../over_height_lib/facade/over_height_facade";
 import progressiveFacade from "../../progressive_interval_lib/facade/progressive_facade";
 import {default as category, List as categoryList} from "../../common/const/category_const.js";
+import locationList from  "../../common/const/locationList";
+
 let config = require("../../../config/config.js");
 const fs = require('fs');
 let _ = require('lodash');
@@ -66,7 +68,6 @@ class CompilationController extends BaseController {
 
             selectedCompilation = Object.keys(selectedCompilation).length <= 0 ? compilationList[0] : selectedCompilation;
             request.session.selectedCompilation = selectedCompilation;
-
         } catch (error) {
             console.log(error);
         }
@@ -77,6 +78,7 @@ class CompilationController extends BaseController {
             id: id,
             compilationList: compilationList,
             categoryList: categoryList,
+            locationList:locationList,
             selectedCompilation: selectedCompilation,
             layout: 'users/views/layout/layout',
             LicenseKey:config.getLicenseKey(process.env.NODE_ENV)
@@ -503,6 +505,39 @@ class CompilationController extends BaseController {
         response.json(responseData);
     }
 
+
+    /**
+     * 设置计价规则适用类型
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+     async setFileTypes(request, response) {
+        let id = request.body.id;
+        let section = request.params.section;
+        let fileTypes = request.body.fileTypes;
+
+        let responseData = {
+            err: 0,
+            msg: ''
+        };
+        try {
+            let compilationModel = new CompilationModel();
+            let result = await compilationModel.setFileTypes(id, section, fileTypes);
+
+            if (!result) {
+                throw '设置类型失败';
+            }
+        } catch (error) {
+            console.log(error);
+            responseData.err = 1;
+            responseData.msg = error;
+        }
+
+        response.json(responseData);
+    }
+
     /**
      * 发布/取消编办
      *
@@ -582,6 +617,18 @@ class CompilationController extends BaseController {
             response.json({err: 1, msg: err, data: null});
         }
     }
+    async setEdition(request, response){
+        let compilationId = request.body.id;
+        let edition = request.body.edition;
+        try{
+            let compilationModel = new CompilationModel();
+            await compilationModel.setEdition(compilationId, edition);
+            response.json({err: 0, msg: '', data: null});
+        }
+        catch (err){
+            response.json({err: 1, msg: err, data: null});
+        }
+    }
     async setOverWriteUrl(request, response){
         let compilationId = request.body.id;
         let overWriteUrl = request.body.overWriteUrl;
@@ -711,6 +758,18 @@ class CompilationController extends BaseController {
 
     }
 
+    async copyValuation(req, res) {
+        const compilationModel = new CompilationModel();
+        const { compilationID, valuationType, orgValuationID, newName } = JSON.parse(req.body.data);
+        try {
+            await compilationModel.copyValuation(compilationID, valuationType, orgValuationID, newName);
+            res.json({ error: 0, message: '复制成功', data: null });
+        } catch (err) {
+            res.json({ error: 1, message: String(err), data: null });
+        }
+
+    }
+
     async addEngineer(request,response){
         let engineeringLibModel = new EngineeringLibModel();
         try {
@@ -745,6 +804,54 @@ class CompilationController extends BaseController {
         }
     }
 
+
+     /**
+     * 更改编办默认工程所在工
+     *
+     * @param request
+     * @param response
+     * @return {Promise.<void>}
+     */
+      async changeLocation(request, response) {
+        let compilationId = request.body.id;
+        let location = request.body.location;
+        try {
+            let compilationModel = new CompilationModel();
+            let result = await compilationModel.updateLocation(compilationId, location);
+            if (result) {
+                response.json({error: 0, message: '', data: null});
+            } else {
+                response.json({error: 1, message: '更新数据错误', data: null});
+            }
+        } catch(error) {
+            response.json({error: 1, message: '更新数据错误', data: null});
+        }
+    }
+
+
+     /**
+     * 更改编办默认工程所在工
+     *
+     * @param request
+     * @param response
+     * @return {Promise.<void>}
+     */
+      async changeFreeUse(request, response) {
+        let compilationId = request.body.id;
+        let freeUse = request.body.freeUse;
+        try {
+            let compilationModel = new CompilationModel();
+            let result = await compilationModel.updateFreeUse(compilationId, freeUse);
+            if (result) {
+                response.json({error: 0, message: '', data: null});
+            } else {
+                response.json({error: 1, message: '更新数据错误', data: null});
+            }
+        } catch(error) {
+            response.json({error: 1, message: '更新数据错误', data: null});
+        }
+    }
+
 }
 
 export default CompilationController;

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

@@ -216,12 +216,13 @@ class LoginController extends BaseController {
                 loginTime: currentTime,
                 sessionToken: sessionToken,
                 userID: managerData.id,
-                toolPermission: managerData.isTemporary ? 'billsGuidance' : toolPermissionController.join(','),
+                toolPermission: managerData.isTemporary ? 'billsGuidance,stdBillsmain,stdBills,stdBillsEditor' : toolPermissionController.join(','),
                 toolMenuData: toolMenuData,
                 toolAllPermission: toolAllPermission.join(','),
                 menuData: menuData,
                 superAdmin: managerData.super_admin,
                 isTemporary: managerData.isTemporary,
+                lockOperate: managerData.lockOperate
             };
             request.session.managerData = managerSession;
             console.log(managerSession);

+ 3 - 0
modules/users/controllers/system_controller.js

@@ -56,6 +56,9 @@ class SystemController extends BaseController {
             setting.company = data.company;
             setting.product = data.product;
             setting.version = data.version;
+            setting.dskVersion = data.dskVersion;
+            setting.platformVersion = data.platformVersion;
+            setting.updateDate = data.updateDate;
         }
         if (!data.ID || data.ID == "") {
             setting.ID = uuidV1();

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

@@ -8,6 +8,8 @@
 import mongoose from "mongoose";
 import BaseModel from "../../common/base/base_model";
 import  uuidV1  from 'uuid/v1';
+const engineeringModel = mongoose.model('engineering_lib');
+const compilationModel = mongoose.model('compilation');
 
 class CompilationModel extends BaseModel {
 
@@ -36,8 +38,8 @@ class CompilationModel extends BaseModel {
      */
     async getCompilationList(fields = null) {
         // 筛选字段
-        let field = fields == null ?{_id: 1, name: 1, is_release: 1, release_time:1,categoryID: 1, description: 1,overWriteUrl: 1,example: 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 field = fields == null ?{_id: 1, name: 1, is_release: 1, release_time:1,categoryID: 1, defaultLocation:1,description: 1,overWriteUrl: 1,example: 1,edition: 1,freeUse: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, "bill_valuation.fileTypes": 1}:fields;
         let compilationData = await this.findDataByCondition({name: {$ne: ''}}, field, false);
 
         return compilationData === null ? [] : compilationData;
@@ -137,6 +139,17 @@ class CompilationModel extends BaseModel {
     async setDescription(compilationId, description){
         return await this.updateById(compilationId, {description: description});
     }
+
+    /*
+    * 设置版本号
+    *
+    * @param {String} compilationId
+    * @param {String} edition
+    * @return {Promise}
+    * */
+   async setEdition(compilationId, edition){
+    return await this.updateById(compilationId, {edition: edition});
+   }
     /*
         设置代码覆盖路径
      */
@@ -154,7 +167,11 @@ class CompilationModel extends BaseModel {
         let data = [];
         if (example) {
             for (let projId of example) {
-                data.push(parseInt(projId));
+                if (/^[0-9]+$/.test(projId)) {
+                    data.push(parseInt(projId));
+                } else if (projId) {
+                    data.push(projId);
+                }
             }
         }
         return await this.updateById(compilationId, {example: data});
@@ -232,6 +249,28 @@ class CompilationModel extends BaseModel {
         return result !== null && result.ok === 1;
     }
 
+    
+    /**
+     * 设置计价规则适用类型
+     *
+     * @param {String} valuationId
+     * @param {String} section
+     * @param {String} setFileTypes
+     * @return {Promise}
+     */
+     async setFileTypes(valuationId, section, fileTypes) {
+        let sectionString = section + "_valuation";
+        let condition = {};
+        condition[sectionString + ".id"] = valuationId;
+
+        let updateData = {};
+        updateData[sectionString + ".$.fileTypes"] = fileTypes;
+
+        let result = await this.db.update(condition, updateData);
+
+        return result !== null && result.ok === 1;
+    }
+
     /**
      * 过滤计价数据
      *
@@ -424,6 +463,58 @@ class CompilationModel extends BaseModel {
         return await this.updateById(compilationId, {categoryID: category});
     }
 
+    /*
+        * 设置工程默认所在地
+        *
+        * @param {String} compilationId
+        * @param {int} location
+        * @return {Promise}
+        * */
+    async updateLocation(compilationId, location) {
+        return await this.updateById(compilationId, {defaultLocation: location});
+    }
+
+    /*
+    * 设置是否提供免费版
+    *
+    * @param {String} compilationId
+    * @param {int} location
+    * @return {Promise}
+    * */
+    async updateFreeUse(compilationId, freeUse) {
+        return await this.updateById(compilationId, {freeUse: freeUse});
+    }
+
+
+    // 拷贝计价规则
+    async copyValuation(compilationID, valuationType, orgValuationID, newName) {
+        const objectId = mongoose.Types.ObjectId(compilationID);
+        const compilationData = await compilationModel.findOne({_id: objectId }).lean();
+        const orgValuation = compilationData[valuationType].find(item => item.id === orgValuationID);
+        if (!orgValuation) {
+            throw '不存在对应计价规则';
+        }
+        const newValuation = {
+            ...orgValuation,
+            id: uuidV1(),
+            enable: false,
+            name: newName
+        };
+        await compilationModel.update({ _id:  objectId }, { $push: { [valuationType]: newValuation } });
+        await this.copyEngineeringList(orgValuationID, newValuation.id);
+    }
+    
+
+    // 拷贝工程专业
+    async copyEngineeringList(orgValuationID, newValuationID) {
+        const engineeringList = await engineeringModel.find({ valuationID: orgValuationID }, '-_id').lean();
+        console.log(engineeringList);
+        const newEngineeringList = engineeringList.map(item => ({ ...item, valuationID: newValuationID }));
+        if (newEngineeringList.length) {
+            await engineeringModel.insertMany(newEngineeringList);
+        }
+    }
+
 }
 
 export default CompilationModel;

+ 8 - 15
modules/users/models/manager_model.js

@@ -147,26 +147,18 @@ class ManagerModel extends BaseModel {
      */
     temporaryLogin(username, password) {
         const users = [
-            { name: '中洲一', pwd: '123456' },
-            { name: '中洲二', pwd: '123456' },
-            { name: '中洲三', pwd: '123456' },
-            { name: '中洲四', pwd: '123456' },
-            { name: '中洲五', pwd: '123456' },
-            { name: '财审一', pwd: '123456' },
-            { name: '财审二', pwd: '123456' },
-            { name: '财审三', pwd: '123456' },
-            { name: '财审四', pwd: '123456' },
-            { name: '财审五', pwd: '123456' },
-            { name: '财审六', pwd: '123456' },
-            { name: '财审七', pwd: '123456' },
-            { name: '财审八', pwd: '123456' },
-            { name: '财审九', pwd: '123456' },
-            { name: '财审十', pwd: '123456' },
+            { name: '财审一', pwd: '123456'  },
+            { name: '财审二', pwd: '123456' , lockOperate:true},
+            { name: '财审三', pwd: '123456' , lockOperate:true},
+            { name: '财审四', pwd: '123456' , lockOperate:true},
+            { name: '财审五', pwd: '123456' , lockOperate:true},
+            { name: '财审六', pwd: '123456' , lockOperate:true},
         ];
         const user = users.find(item => item.name === username && item.pwd === password);
         if (!user) {
             return null;
         }
+      
         return {
             can_login: 1,
             create_time: Date.now(),
@@ -177,6 +169,7 @@ class ManagerModel extends BaseModel {
             login_ip: '',
             username: user.name,
             isTemporary: true,
+            lockOperate:user.lockOperate || false,
         }
     }
 

+ 5 - 1
modules/users/routes/compilation_route.js

@@ -21,6 +21,7 @@ module.exports = function (app) {
     router.post('/release', compilationController.auth, compilationController.init, compilationController.release);
     router.post('/add', compilationController.auth, compilationController.init, compilationController.addCompilation);
     router.post('/setDescription', compilationController.auth, compilationController.init, compilationController.setDescription);
+    router.post('/setEdition', compilationController.auth, compilationController.init, compilationController.setEdition);
     router.post('/setOverWriteUrl', compilationController.auth, compilationController.init, compilationController.setOverWriteUrl);
     router.post('/setExample', compilationController.auth, compilationController.init, compilationController.setExample);
     router.post('/add-valuation', compilationController.auth, compilationController.init, compilationController.addValuation);
@@ -29,11 +30,14 @@ module.exports = function (app) {
     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('/valuation/:section/fileTypes', compilationController.auth, compilationController.init, compilationController.setFileTypes);
     router.post('/template/:section/:id/:engineering/update', compilationController.auth, compilationController.init, compilationController.updateBillsTemplate);
     router.post('/addEngineer', compilationController.auth, compilationController.init, compilationController.addEngineer);
     router.post('/copyRationLibs', compilationController.auth, compilationController.init, compilationController.copyRationLibs);
+    router.post('/copyValuation', compilationController.auth, compilationController.init, compilationController.copyValuation);
 
     router.post('/changeCategory', compilationController.auth, compilationController.init, compilationController.changeCategory);
-
+    router.post('/changeLocation', compilationController.auth, compilationController.init, compilationController.changeLocation);
+    router.post('/changeFreeUse', compilationController.auth, compilationController.init, compilationController.changeFreeUse);
     app.use("/compilation", router);
 };

BIN
public/share/images/erratumRecord/d1dd6acc3258f998a9ebafc16ea8ff6f_1.jpg


BIN
public/share/images/rationExplanation/d1dd6acc3258f998a9ebafc16ea8ff6f_1.jpg


BIN
public/share/images/rationRuleText/d1dd6acc3258f998a9ebafc16ea8ff6f_1.jpg


+ 16 - 0
public/web/id_tree.js

@@ -215,6 +215,11 @@ var idTree = {
              }) + node.children.count;*/
         };
 
+        Node.prototype.posterityLeafCount = function () {
+            return this.getPosterity().filter(item => !item.children.length).length;
+        };
+
+
         // 获取节点所有后代节点
         Node.prototype.getPosterity = function() {
             let posterity = [];
@@ -230,6 +235,17 @@ var idTree = {
             }
         };
 
+        // 担心链有问题,preSibling不靠谱的话,按照显示顺序算preSibling
+        Node.prototype.prevNode = function() {
+            const parent = this.parent || this.tree.roots;
+            if (!parent) {
+                return null;
+            }
+            const children = parent === this.tree.roots ? this.tree.roots :  parent.children;
+            const index = children.indexOf(this);
+            return children[index - 1] || null;
+        }
+
         Node.prototype.setExpanded = function (expanded) {
             var setNodesVisible = function (nodes, visible) {
                 nodes.forEach(function (node) {

+ 10 - 6
web/maintain/bill_template_lib/html/main.html

@@ -21,9 +21,9 @@
                         <table class="table table-hover table-bordered">
                             <thead>
                                 <tr>
-                                    <th>清单模板名称</th>
+                                    <th>清单模板名称 <i class="fa fa-sort sort-table" data-status="asc" data-sort="name" aria-hidden="true"></i></th>
                                     <th width="160">编办</th>
-                                    <th width="160">添加时间</th>
+                                    <th width="160">添加时间 <i class="fa fa-sort sort-table" data-status="asc" data-sort="time" aria-hidden="true"></i></th>
                                     <th width="70">操作</th>
                                     <th width="60">复制</th>
                                 </tr>
@@ -35,8 +35,8 @@
                                 <td><%= lib.compilationName%></td>
                                 <td><%= moment(lib.createDate).format('YYYY-MM-DD')%></td>
                                 <td>
-                                    <a class="lock-btn-control disabled" href="javacript:void(0);" onclick='getTemplateLib("<%= lib.ID%>")' title="编辑"><i class="fa fa-pencil-square-o"></i></a>
-                                    <a class="text-danger lock-btn-control disabled" href="javacript:void(0);" onclick='showDeleteModal("<%= lib.ID%>")' title="删除"><i class="fa fa-remove"></i></a>
+                                    <a class="lock-btn-control disabled" href="javascript:void(0);" onclick='getTemplateLib("<%= lib.ID%>")' title="编辑"><i class="fa fa-pencil-square-o"></i></a>
+                                    <a class="text-danger lock-btn-control disabled" href="javascript:void(0);" onclick='showDeleteModal("<%= lib.ID%>")' title="删除"><i class="fa fa-remove"></i></a>
                                     <a class="lock" data-locked="true" href="javascript:void(0);" title="解锁"><i class="fa fa-unlock-alt"></i></a>
                                 </td>
                                 <td>
@@ -159,8 +159,12 @@
         </div>
     </div>
 </div>
-
+<script>
+    const templateLibs =  JSON.parse(unescape('<%- escape(JSON.stringify(templateLibs)) %>'));
+</script>
 <script src="/public/web/PerfectLoad.js"></script>
 <script src="/public/web/lock_util.js"></script>
 <script src="/web/maintain/bills_lib/scripts/bills_lib_ajax.js"></script>
-<script type="text/javascript" src="/web/maintain/bill_template_lib/js/bills_template.js"></script>
+<script src="/lib/moment/moment.min.js"></script>
+<script src="/lib/lodash/lodash.js"></script>
+<script type="text/javascript" src="/web/maintain/bill_template_lib/js/bills_template.js"></script>

+ 35 - 2
web/maintain/bill_template_lib/js/bills_template.js

@@ -54,7 +54,7 @@ $(document).ready(function() {
     });
 
     // 锁定、解锁
-    $('.lock').click(function () {
+    $('body').on('click', '.lock', function () {
         lockUtil.handleLockClick($(this));
     });
 
@@ -74,6 +74,39 @@ $(document).ready(function() {
             $.bootstrapLoading.end();
         });
     });
+
+    // 排序更改
+    $('.sort-table').on('click', function () {
+        const sortBy = $(this).data('sort');
+        const sortAsc = $(this).attr('data-status');
+        $(this).removeClass('fa-sort fa-sort-amount-asc fa-sort-amount-desc').addClass('fa-sort-amount-' + sortAsc);
+        $(this).attr('data-status', sortAsc === 'asc' ? 'desc' : 'asc');
+        let sortList = templateLibs;
+        if (sortBy === 'time') {
+            $('i[data-sort="name"]').removeClass('fa-sort fa-sort-amount-asc fa-sort-amount-desc').addClass('fa-sort');
+            sortList = _.orderBy(templateLibs, ['createDate'], [sortAsc]);
+        } else {
+            $('i[data-sort="time"]').removeClass('fa-sort fa-sort-amount-asc fa-sort-amount-desc').addClass('fa-sort');
+            sortList = _.orderBy(templateLibs, ['name'], [sortAsc]);
+        }
+        let html = '';
+        for (const lib of sortList) {
+            html += '<tr class="libTr">\n' +
+                '                                <td id="' + lib.ID + '"><a href="/billsTemplate/editTemplate/' + lib.ID + '?locked=true">' + lib.name + '</a></td>\n' +
+                '                                <td>' + lib.compilationName + '</td>\n' +
+                '                                <td>' + moment(lib.createDate).format('YYYY-MM-DD') + '</td>\n' +
+                '                                <td>\n' +
+                '                                    <a class="lock-btn-control disabled" href="javascript:void(0);" onclick="getTemplateLib(\'' + lib.ID + '\')" title="编辑"><i class="fa fa-pencil-square-o"></i></a>\n' +
+                '                                    <a class="text-danger lock-btn-control disabled" href="javascript:void(0);" onclick="showDeleteModal(\'' + lib.ID + '\')" title="删除"><i class="fa fa-remove"></i></a>\n' +
+                '                                    <a class="lock" data-locked="true" href="javascript:void(0);" title="解锁"><i class="fa fa-unlock-alt"></i></a>\n' +
+                '                                </td>\n' +
+                '                                <td>\n' +
+                '                                    <a class="btn btn-secondary btn-sm copy-data lock-btn-control disabled" href="javascript:void(0);" onclick="showCopyModal(\'' + lib.ID + '\')" title="复制数据"><i class="fa fa-clone"></i>复制</a>\n' +
+                '                                </td>\n' +
+                '                            </tr>'
+        }
+        $('#showArea').html(html);
+    });
 });
 
 function getTemplateLib (ID) {
@@ -93,4 +126,4 @@ function showDeleteModal(ID){
 function showCopyModal(ID) {
     $('#libID').val(ID);
     $('#copy').modal('show');
-}
+}

Fichier diff supprimé car celui-ci est trop grand
+ 645 - 565
web/maintain/bill_template_lib/js/bills_template_edit.js


+ 11 - 2
web/maintain/billsGuidance_lib/html/main.html

@@ -33,6 +33,7 @@
   </style>
     <script>
       const isTemporary = '<%- manager.isTemporary %>';
+      const lockOperate = '<%- manager.lockOperate %>';
     </script>
 </head>
 
@@ -40,6 +41,14 @@
   <div class="header">
     <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 " style="display: flex; justify-content: space-between;">
       <span class="header-logo px-2"><%= manager.isTemporary ? '清单精灵编辑器' : '清单指引编辑器' %></span>
+      <!-- <% if (manager.isTemporary)  { %>
+        <div style="cursor: pointer;">
+          <a href="/stdBillsmain">
+            <span>切换到清单规则编辑器</span>
+        </a>
+          
+        </div>
+      <% } %>-->
       <% if (manager.isTemporary)  { %>
               <div class="avatar btn-group">
                   <a class="dropdown-toggle" data-toggle="dropdown">
@@ -48,7 +57,7 @@
                   <ul class="dropdown-menu dropdown-menu-right">
                       <li><a href="/login/logout">退出登录</a></li>
                   </ul>
-      <% } %>
+      <% } %> 
     </nav>
     <% if (!manager.isTemporary)  { %>
       <nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0">
@@ -76,7 +85,7 @@
                     <th width="100">类型</th>
                     <th width="160">添加时间</th>
                     <th width="70">操作</th>
-                    <%- manager.isTemporary ? '' : '<th width="120">生成清单分类</th>' %>
+                    <%- manager.isTemporary ? '' : '<th width="120">生成清单分类v1</th>' %>
                     <%- manager.isTemporary ? '' : '<th width="120">导出分类excel</th>' %>
                   </tr>
                 </thead>

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

@@ -69,6 +69,8 @@
                                     <button id="searchBillBtn" class="btn btn-secondary btn-sm" type="button"><i class="fa fa-search" aria-hidden="true"></i></button>
                                 </span>
                                 </div>
+                                <a id="autoSetMaterial" href="javascript:void(0);" class="btn btn-sm"><i class="fa fa-edit" aria-hidden="true"></i> 自动配置材料</a>
+                                <a id="buildExcel" href="javascript:void(0);" class="btn btn-sm"><i class="fa fa-sign-out" aria-hidden="true"></i> 导出excel</a>
                                
                             </div>
                             <div id="searchBillsResult" style="display: none;">
@@ -227,6 +229,26 @@
             </div>
         </div>
     </div>
+    <div class="modal fade" id="excel-modal" data-backdrop="static" style="display: none;" aria-hidden="true">
+        <div class="modal-dialog" id="excel-dialog" role="document" style="max-width: none; width: 500px">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">导出excel</h5>
+                    <button type="button"  class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">×</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <div id="excel-info"></div>
+                    <div id="excel-spread" style="height: 500px; display: none;"></div>
+                </div>
+                <div class="modal-footer">
+                    <a id="export-excel-confirm" href="javascript: void(0);" class="btn btn-primary" style="display: none;">导出</a>
+                    <button type="button" class="btn btn-secondary"  data-dismiss="modal">关闭</button>
+                </div>
+            </div>
+        </div>
+    </div>
     <div class="modal fade" id="alert" data-backdrop="static" style="display: none;" aria-hidden="true">
         <div class="modal-dialog" role="document">
             <div class="modal-content">
@@ -252,8 +274,10 @@
     <script src="/lib/bootstrap/bootstrap.min.js"></script>
     <script src="/lib/jquery-contextmenu/jquery.contextMenu.js"></script>
     <script src="/lib/jquery-contextmenu/jquery.ui.position.js"></script>
-    <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>
+    <script src ="/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>
+    <script src="/lib/spreadjs/sheets/interop/gc.spread.excelio.11.1.2.min.js"></script>
     <script>GC.Spread.Sheets.LicenseKey =  '<%- LicenseKey %>';</script>
+    <script src="/lib/fileSaver/FileSaver.min.js"></script>
     <script src="/lib/lodash/lodash.js"></script>
     <script src="/public/web/uuid.js"></script>
     <script src="/public/web/sheet/sheet_common.js"></script>
@@ -266,6 +290,8 @@
     <script src="/public/web/id_tree.js"></script>
     <script src="/public/web/tree_sheet/tree_sheet_controller.js"></script>
     <script src="/public/web/tree_sheet/tree_sheet_helper.js"></script>
+    <script src="/web/maintain/billsGuidance_lib/js/util.js"></script>
+    <script src="/web/maintain/billsGuidance_lib/js/exportExcel.js"></script>
     <script src="/web/maintain/billsGuidance_lib/js/billsGuidance.js"></script>
     <script src="/web/common/js/slideResize.js"></script>
 </body>

+ 257 - 104
web/maintain/billsGuidance_lib/js/billsGuidance.js

@@ -7,10 +7,10 @@
  * @version
  */
 
+
+
+
 const billsGuidance = (function () {
-    function _isDef(v) {
-        return typeof v !== 'undefined' && v !== null;
-    }
 
 
     function sortByCode(arr) {
@@ -45,6 +45,7 @@ const billsGuidance = (function () {
             return recurCompare(aArr, bArr, 0);
         });
     }
+    // 导出实例
     let curCompilationID = '';
     const locked = lockUtil.getLocked();
     let moduleName = 'stdBillsGuidance';
@@ -118,11 +119,6 @@ const billsGuidance = (function () {
     const selectedBgColor = '#DFE8F9';
     const searchBgColor = 'lemonChiffon';
 
-    //项目指引类型
-    const itemType = {
-        job: 0,
-        ration: 1
-    };
     //项目指引复制整块localStorage key
     const itemCopyBlockKey = 'guideItemCopyBlock';
     const updateType = {
@@ -438,6 +434,9 @@ const billsGuidance = (function () {
         }
     }
 
+    /* 导出excel */
+    let exportExcelWorkBook = null;
+
     // 显示清单材料数据
     function showBillMaterialData(sheet, headers, datas, emptyRow = 0) {
         let fuc = function () {
@@ -522,16 +521,6 @@ const billsGuidance = (function () {
         }
     }
 
-    // 是否为工序行
-    function isProcessNode(node) {
-        return node && node.depth() % 2 === 0 && _isDef(node.data.type) && node.data.type === itemType.job
-    }
-
-    // 是否是选项行
-    function isOptionNode(node) {
-        return node && node.depth() % 2 === 1 && _isDef(node.data.type) && node.data.type === itemType.job
-    }
-
     //渲染时方法,停止渲染
     //@param {Object}sheet {Function}func @return {void}
     function renderSheetFunc(sheet, func) {
@@ -647,7 +636,7 @@ const billsGuidance = (function () {
 
     //清单表焦点控制
     //@param {Number}row @return {void}
-    function billsInitSel(row, oldSel) {
+    function billsInitSel(row, oldSel, force = false) {
         let guideSheet = guideItem.workBook.getActiveSheet();
         cleanData(guideSheet, guideItem.headers, -1);
         let node = bills.tree.items[row];
@@ -665,7 +654,7 @@ const billsGuidance = (function () {
         $('#editMaterial').removeClass('disabled');
         //显示备注
         $('.main-side-bottom').find('textarea').val(node.data.comment ? node.data.comment : '');
-        if (!node.guidance.tree) {
+        if (!node.guidance.tree || force) {
             getItemsByBills(libID, node.data.ID, function (rstData) {
                 initTree(node.guidance, guideSheet, guideItem.treeSetting, rstData);
                 setNodesExpandState(node.guidance.tree.items, curExpandState);
@@ -893,6 +882,8 @@ const billsGuidance = (function () {
         if (isProcessNode(node)) {
             $('.main-bottom-content').find('textarea').attr('readonly', false);
         }
+        // 配置材料
+        $('#editMaterial').removeClass('disabled');
     }
     //项目指引表焦点控制
     //@param {Number}row @return {void}
@@ -917,6 +908,7 @@ const billsGuidance = (function () {
     //初始化各工作表
     //@param {Array}modules @return {void}
     function initWorkBooks(modules) {
+        exportExcelWorkBook = new GC.Spread.Sheets.Workbook($('#excel-spread')[0], { sheetCount: 1 });
         for (let module of modules) {
             buildSheet(module);
         }
@@ -2273,6 +2265,7 @@ const billsGuidance = (function () {
     //初始化dom时间
     //@return {void}
     function initDomEvents() {
+
         // 清单材料窗口
         $("#bill-material-modal").on('hidden.bs.modal', function () {
             billMaterial.cache = [];
@@ -2286,6 +2279,57 @@ const billsGuidance = (function () {
             }
         });
 
+        /* 自动配置材料 */
+        $('#autoSetMaterial').click(async function() {
+            $.bootstrapLoading.start();
+            try {
+                await ajaxPost('/billsGuidance/api/autoSetMaterial', { libID}, 1000 * 60 * 10);
+                // 刷新显示
+                window.location.reload();
+            } catch (error) {
+                alert(error);
+            }
+            $.bootstrapLoading.end();
+        });
+
+        /* excel */
+        // 生成excel
+        $('#buildExcel').click(function () {
+            if (bills && bills.tree) {
+                $('#excel-modal').modal('show');
+            }
+        });
+        $("#excel-modal").on('hidden.bs.modal', function () {
+            $('#excel-info').text(`导出排版中:`);
+            $('#excel-spread').hide();
+            $('#export-excel-confirm').hide();
+            $('#excel-dialog').width('500px');
+            if (exportExcelWorkBook) {
+                exportExcelWorkBook.clearSheets();
+                exportExcelWorkBook.addSheet();
+            }
+        });
+        let excelInstance;
+        $("#excel-modal").on('shown.bs.modal', async function () {
+            exportExcelWorkBook.refresh();
+            if (bills.tree) {
+                excelInstance = new ExportExcel(exportExcelWorkBook, bills.tree, libID);
+                try {
+                    // await excelInstance.paintOnSheet();
+                    await excelInstance.paintOnWorkBook();
+                } catch (error) {
+                    console.log(error);
+                    alert(error);
+                    $("#excel-modal").modal('hide');
+                }
+            }
+        });
+        $('#export-excel-confirm').click(() => {
+            if (excelInstance) {
+                excelInstance.export();
+            }
+        })
+
         $('#insert').click(function () {
             insert([{ type: itemType.job, name: '', outputItemCharacter: true }], false);
         });
@@ -2649,13 +2693,26 @@ const billsGuidance = (function () {
         return list;
     }
 
+    // 获取必填项下的ID和name的键值对
+    function getClassCodeStrData(nodes,data={classGroups:{},keyGroup:{}}){
+         nodes.forEach(node=>{
+            if (isProcessNode(node)&&node.data.required) {
+                node.children.forEach(subNode=>{
+                    data.classGroups[subNode.data.ID]=subNode.data.name;  
+                    data.keyGroup[subNode.data.ID]=`${subNode.parent.data.name}:${subNode.data.name}`; 
+                })
+            }
+            getClassCodeStrData(node.children,data);
+         })
+        return data;
+    }
 
     //获取定额数据
     // requireRationData必套定额对象
     // optionalRationData 选逃定额对象
     // classGroups classCode文字和id键值对
     // classCodeList 各个classCode的pID和ID的关系
-    function getItemData(nodes, requireRationData={}, optionalRationData={}, classGroups={},  prefixID = '', prefixSonID = '',IDData={}) {
+    function getItemData(nodes, requireRationData = {}, optionalRationData = {}, classGroups = {}, prefixID = '', prefixSonID = '', IDData = {},keyGroup={}) {
         const processNodes = nodes.filter(node => isProcessNode(node));
         // const classGroups = []; // 同层必填选项的数组(二维数组)
         processNodes.forEach(processNode => {
@@ -2679,15 +2736,24 @@ const billsGuidance = (function () {
                         const kV = {};
                         kV[optionNode.data.ID] = optionNode.data.name;
                         Object.assign(classGroups, kV);
+
+                        const keyData={};
+                        keyData[optionNode.data.ID] = `${optionNode.parent.data.name}:${optionNode.data.name}`;
+                        Object.assign(keyGroup,keyData);
                     } else {
                         const kV = {};
                         kV[optionNode.data.ID] = optionNode.data.name;
                         Object.assign(classGroups, kV);
+
+                        const keyData={};
+                        keyData[optionNode.data.ID] = `${optionNode.parent.data.name}:${optionNode.data.name}`;
+                        Object.assign(keyGroup,keyData);
+
                         // 后代项是否有必填
                         if (hasRequireData(optionNode)) {
                             //后代项有必填
-                            prefixSonID='';
-                            getItemData(optionNode.children, requireRationData, optionalRationData, classGroups, optionNode.data.ID,prefixSonID,IDData);
+                            prefixSonID = '';
+                            getItemData(optionNode.children, requireRationData, optionalRationData, classGroups, optionNode.data.ID, prefixSonID, IDData,keyGroup);
                         } else {
                             //后代项无必填
                             optionNode.children.forEach(subOptionNode => {
@@ -2696,7 +2762,7 @@ const billsGuidance = (function () {
                                     if (!requireRationData[subOptionNode.parent.data.ID]) requireRationData[subOptionNode.parent.data.ID] = [];
                                     requireRationData[subOptionNode.parent.data.ID].push(getOptionalData(subOptionNode));
                                 } else {
-                                    if (!optionalRationData[subOptionNode.parent.data.ID]) optionalRationData[subOptionNode.data.ID] = [];
+                                    if (!optionalRationData[subOptionNode.parent.data.ID]) optionalRationData[subOptionNode.parent.data.ID] = [];
                                     optionalRationData[subOptionNode.parent.data.ID].push(...getOptionalData(subOptionNode));
                                 }
                             })
@@ -2706,27 +2772,44 @@ const billsGuidance = (function () {
             } else {
                 // 蓝色节点,非必填
                 if (hasRequireData(processNode)) {
-                     //后代项有必填
-                   if(isProcessNode(processNode)){
+                    //后代项有必填
+                    if (isProcessNode(processNode)) {
                         //蓝色
-                        processNode.children.forEach((subProcessNode)=>{
-                            subProcessNode.children.forEach((sSubProcessNode)=>{
-                                //这里是特殊处理,因为原来的逻辑是直接把定额绑到必填白色选项中下面的,每个蓝色的一组,但是这样是不对的,需要绑定在必填白色选项下的蓝色节点,所以这里就需要传入蓝色节点的id
-                                const requireChildrenID=sSubProcessNode.parent.data.required?prefixSonID:sSubProcessNode.data.ID;
-                                IDData[sSubProcessNode.data.ID]=prefixID;
-                                getItemData(
-                                    [sSubProcessNode], 
-                                    requireRationData,
-                                    optionalRationData,
-                                    classGroups,
-                                    prefixID,
-                                    requireChildrenID,
-                                    IDData
-
-                                )
+                        // 是否必套定额
+                        if (isAllRationData(processNode)) {
+                            processNode.children.forEach((subProcessNode) => {
+                                subProcessNode.children.forEach((sSubProcessNode) => {
+                                    //这里是特殊处理,因为原来的逻辑是直接把定额绑到必填白色选项中下面的,每个蓝色的一组,但是这样是不对的,需要绑定在必填白色选项下的蓝色节点,所以这里就需要传入蓝色节点的id
+                                    const requireChildrenID = sSubProcessNode.parent.data.required ? prefixSonID : sSubProcessNode.data.ID;
+                                    IDData[sSubProcessNode.data.ID] = prefixID;
+                                    getItemData(
+                                        [sSubProcessNode],
+                                        requireRationData,
+                                        optionalRationData,
+                                        classGroups,
+                                        prefixID,
+                                        requireChildrenID,
+                                        IDData,
+                                        keyGroup
+                                    )
+                                })
                             })
-                        })
-                   }
+                        }else{
+                            // 全部选套就不用走循环了,直接按照选套执行
+                            let key = processNode.data.ID;
+                            if (prefixID) key = prefixID;
+                            if (prefixSonID) key = prefixSonID;
+                            if (!optionalRationData[key]) optionalRationData[key] = [];
+                            optionalRationData[key].push(...getOptionalData(processNode));
+                            // 因为这里没有按照走整个流程,所以文字和ID的关系需要获取补充
+                           if(hasRequireData(processNode)) {
+                                const result =getClassCodeStrData(processNode.children)
+                                Object.assign(classGroups,result.classGroups);
+                                Object.assign(keyGroup,result.keyGroup);
+                            } ;
+                            
+                        }
+                    }
                 } else {
                     let key = processNode.data.ID;
                     if (prefixID) key = prefixID;
@@ -2742,14 +2825,14 @@ const billsGuidance = (function () {
                 }
             }
         })
-        return { requireRationData, optionalRationData, classGroups,IDData}
+        return { requireRationData, optionalRationData, classGroups, IDData, keyGroup }
     }
 
 
 
 
     /* 生成特征分类: 前端测试使用,想要前端测试,需要在zhiyin.html中,将id=generate-classa的按钮放开 */
-    function getItemCharacterData(nodes, prefix ,prefixID) {
+    function getItemCharacterData(nodes, prefix, prefixID) {
         const processNodes = nodes.filter(node => isProcessNode(node));
         const classGroups = []; // 同层必填选项的数组(二维数组)
         processNodes.forEach(processNode => {
@@ -2768,8 +2851,8 @@ const billsGuidance = (function () {
                 } else {
                     // classItems.push(...getItemCharacterData(optionNode.children, optionNode.parent && optionNode.parent.data.required ? optionNode.data.name : ''));
                     const childrenClassItem = getItemCharacterData(
-                        optionNode.children, 
-                        optionNode.parent && optionNode.parent.data.required ? optionNode.data.name : '' ,
+                        optionNode.children,
+                        optionNode.parent && optionNode.parent.data.required ? optionNode.data.name : '',
                         optionNode.parent && optionNode.parent.data.required ? optionNode.data.ID : ''
                     );
 
@@ -2779,9 +2862,9 @@ const billsGuidance = (function () {
                         && optionNode.parent.data.required
                         && childrenClassItem.length === 0
                     ) {
-                        classItems.push({ name: optionNode.data.name,ID: optionNode.data.ID });
+                        classItems.push({ name: optionNode.data.name, ID: optionNode.data.ID });
                     } else {
-                       
+
                         classItems.push(...childrenClassItem);
                     }
                 }
@@ -2811,7 +2894,7 @@ const billsGuidance = (function () {
                     // 拼接文本
                     const mergedName = `${prevClassItems[i].name}@${nextClassItems[j].name}`;
                     const mergedID = `${prevClassItems[i].ID}@${nextClassItems[j].ID}`;
-                    mergedClassItems.push({ name: mergedName,ID:mergedID});
+                    mergedClassItems.push({ name: mergedName, ID: mergedID });
                 }
             }
             classGroups.splice(0, 2, mergedClassItems);
@@ -2831,17 +2914,17 @@ const billsGuidance = (function () {
 
     // 获取选套定额:把所有分类数据的必套定额确定好了先。选套定额就是清单下所有定额除了必套的
     function getOptionalRationIDs(optionalRationData) {
-        const optionalRationIDs=[];
-       Object.values(optionalRationData).forEach(optionalRation=>{
-           if(optionalRation.length) optionalRationIDs.push(...optionalRation);
+        const optionalRationIDs = [];
+        Object.values(optionalRationData).forEach(optionalRation => {
+            if (optionalRation.length) optionalRationIDs.push(...optionalRation);
         })
         return [...new Set(optionalRationIDs)];
     }
 
     // 获取错套定额:清单下所有定额,除了分类对应的必套、选套定额
     function getErrorRationIDs(requiredRationIDList, optionalRationIDs, guideNodes) {
-        const finRequireData=[];
-        requiredRationIDList.forEach(requiredRationIDs=>{
+        const finRequireData = [];
+        requiredRationIDList.forEach(requiredRationIDs => {
             finRequireData.push(...requiredRationIDs);
         })
         const errorRationIDs = [];
@@ -2854,76 +2937,146 @@ const billsGuidance = (function () {
     }
 
     //把classcode和必套选套定额结合在一起
-    function combineData(codeData,requireRationData,classGroups,IDData){
+    function combineData(codeData, requireRationData, optionalRationData, classGroups, IDData,keyGroup) {
+        // 这里要记录下已经被绑定的选套定额,因为没有被用的定额需要绑定到各个classcode下
+        const matchRationList = [];
         //这里需要把绑定在子节点的定额更新到必填的白色选项中(classcode的值)
-        const requireCombineData={};
-        Object.keys(IDData).forEach(key=>{
-            if(!requireCombineData[IDData[key]])requireCombineData[IDData[key]]=new Set();
-            if(requireRationData[key]){
-             requireRationData[key].forEach(subData=>{
-                 subData.forEach(subItem=>{
-                     requireCombineData[IDData[key]].add(subItem);
-                 })
-             })
+        const requireCombineData = {};
+        const optionCombineData = {};
+        Object.keys(IDData).forEach(key => {
+            if (!requireCombineData[IDData[key]]) requireCombineData[IDData[key]] = new Set();
+            if (!optionCombineData[IDData[key]]) optionCombineData[IDData[key]] = new Set();
+            if (requireRationData[key]) {
+                requireRationData[key].forEach(subData => {
+                    subData.forEach(subItem => {
+                        requireCombineData[IDData[key]].add(subItem);
+                    })
+                })
+            }
+            if (optionalRationData[key]) {
+                optionalRationData[key].forEach(subData => {
+                    optionCombineData[IDData[key]].add(subData);
+                })
             }
-         })
 
-        return  codeData.map(classCodeData=>{
-            const errorRationIDs=[];
-            const optionalRationIDs=[];
-            const requiredRationIDs=[];
-            let name='';
-            const classCodeIDs=classCodeData.ID;
-            if(/@/.test(classCodeIDs)){
-                classCodeIDs.split('@').forEach((classCodeID)=>{
-                    if(name){ 
-                        name=name+'@'+classGroups[classCodeID]
-                    }else{
-                        name=classGroups[classCodeID]
+        })
+        const finData = codeData.map(classCodeData => {
+            const errorRationIDs = [];
+            const optionalRationIDs = [];
+            const requiredRationIDs = [];
+            let name = '';
+            let key = '';            
+            const classCodeIDs = classCodeData.ID;
+            if (/@/.test(classCodeIDs)) {
+                classCodeIDs.split('@').forEach((classCodeID) => {
+                    if (name) {
+                        name = name + '@' + classGroups[classCodeID];
+                        key += keyGroup[classCodeID];
+                    } else {
+                        name = classGroups[classCodeID];
+                        key = keyGroup[classCodeID];
                     };
-                    const unitRation=[];
-                    requireRationData[classCodeID].forEach(subItem=>{
-                        unitRation.push(...new Set(subItem));
-                    })
-                    if(requireRationData[classCodeID]&&requireRationData[classCodeID].length) {
+                    // 一组的必套定额,先去重
+                    const unitRation = [];
+                  
+                    // 这里是必填选项下绑定必套定额
+                    if (requireRationData[classCodeID] && requireRationData[classCodeID].length) {
+                        requireRationData[classCodeID].forEach(subItem => {
+                            unitRation.push(...new Set(subItem));
+                        })
                         requiredRationIDs.push(unitRation);
+                        // 这里也要把用过的必套定额先存起来
+                        matchRationList.push(...unitRation);
                     }
-                    if(requireCombineData[classCodeID]&&requireCombineData[classCodeID].size){
+                    //这里是必填选项下绑定在蓝色节点下的必套定额
+                    if (requireCombineData[classCodeID] && requireCombineData[classCodeID].size) {
                         requiredRationIDs.push([...requireCombineData[classCodeID]]);
+                        // 这里也要把用过的必套定额先存起来
+                        matchRationList.push(...requireCombineData[classCodeID]);
                     }
+
+                    // 这里是必填选项下绑定选套定额
+                    if (optionalRationData[classCodeID] && optionalRationData[classCodeID].length) {
+                        optionalRationIDs.push(...optionalRationData[classCodeID]);
+                        matchRationList.push(...optionalRationData[classCodeID]);
+                    }
+                    //这里是必填选项下绑定在蓝色节点下的选套定额,下同
+                    if (optionCombineData[classCodeID] && optionCombineData[classCodeID].size) {
+                        optionalRationIDs.push(...optionCombineData[classCodeID]);
+                        matchRationList.push(...optionCombineData[classCodeID]);
+                    }
+
                 })
-                return {name,requiredRationIDs,optionalRationIDs,errorRationIDs}
-            }else{
-                const unitRation=[];
-                requireRationData[classCodeIDs].forEach(subItem=>{
-                    unitRation.push(...new Set(subItem));
-                })
-                name=classGroups[classCodeIDs];
-                if(requireRationData[classCodeIDs]&&requireRationData[classCodeIDs].length) requiredRationIDs.push(unitRation);
-                if(requireCombineData[classCodeIDs]&&requireCombineData[classCodeIDs].size) requiredRationIDs.push([...requireCombineData[classCodeIDs]]);
-                return {name,requiredRationIDs,optionalRationIDs,errorRationIDs}
+                return { name,key, requiredRationIDs, optionalRationIDs: [...new Set(optionalRationIDs)], errorRationIDs }
+            } else {
+                const unitRation = [];
+                name = classGroups[classCodeIDs];
+                key = keyGroup[classCodeIDs];
+                if (requireRationData[classCodeIDs] && requireRationData[classCodeIDs].length){
+                    requireRationData[classCodeIDs].forEach(subItem => {
+                        unitRation.push(...new Set(subItem));
+                    })
+                    requiredRationIDs.push(unitRation); 
+                    // 这里也要把用过的必套定额先存起来
+                    matchRationList.push(...unitRation);
+                }
+              
+                if (requireCombineData[classCodeIDs] && requireCombineData[classCodeIDs].size) {
+                    requiredRationIDs.push([...requireCombineData[classCodeIDs]])
+                     // 这里也要把用过的必套定额先存起来
+                     matchRationList.push(...requireCombineData[classCodeIDs]);
+                };
+
+                if (optionalRationData[classCodeIDs] && optionalRationData[classCodeIDs].length) {
+                    optionalRationIDs.push(...optionalRationData[classCodeIDs]);
+                    matchRationList.push(...optionalRationData[classCodeIDs]);
+                }
+                if (optionCombineData[classCodeIDs] && optionCombineData[classCodeIDs].size) {
+                    optionalRationIDs.push(...optionCombineData[classCodeIDs]);
+                    matchRationList.push(...optionalRationData[classCodeIDs]);
+                }
+                return { name,key, requiredRationIDs, optionalRationIDs: [...new Set(optionalRationIDs)], errorRationIDs }
             }
         })
+        const unMatchRation = [];
+        Object.values(optionalRationData).forEach(data => {
+            data.forEach((rationID) => {
+                if (!matchRationList.includes(rationID)) {
+                    unMatchRation.push(rationID);
+                }
+            })
+        })
+        // 这里把没有使用过的必套定额也丢到了选套里面
+        Object.values(requireRationData).forEach(data => {
+            data.forEach((rationData) => {
+                rationData.forEach(rationID=>{
+                    if (!matchRationList.includes(rationID)) {
+                        unMatchRation.push(rationID);
+                    }
+                })
+            })
+        })
+        return { classData: finData, unMatchRation };
     }
 
     $('#generate-class').click(() => {
         if (bills.tree.selected && bills.tree.selected.guidance.tree) {
-           const classCodeData = getItemCharacterData(bills.tree.selected.guidance.tree.roots);
-           const {requireRationData,optionalRationData,classGroups,IDData} = getItemData(bills.tree.selected.guidance.tree.roots);
-           const classData= combineData(classCodeData,requireRationData,classGroups,IDData);
-           //因为所有的选套都是一样的,所以这里就直接赋值了
+            const classCodeData = getItemCharacterData(bills.tree.selected.guidance.tree.roots);
+            const { requireRationData, optionalRationData, classGroups, IDData, keyGroup } = getItemData(bills.tree.selected.guidance.tree.roots);
+            //    const noMatchOptionRation=[];
+            const { classData, unMatchRation } = combineData(classCodeData, requireRationData, optionalRationData, classGroups, IDData,keyGroup);
+            //因为所有的选套都是一样的,所以这里就直接赋值了
             const optionalRationIDs = getOptionalRationIDs(optionalRationData);
             classData.forEach(item => {
-                item.optionalRationIDs=optionalRationIDs
-                item.errorRationIDs = getErrorRationIDs(item.requiredRationIDs, optionalRationIDs, bills.tree.selected.guidance.tree.items);
+                // 不在必填项下的选套都要绑定在每个classcode下
+                item.optionalRationIDs.push(...unMatchRation);
+                item.errorRationIDs = getErrorRationIDs(item.requiredRationIDs, item.optionalRationIDs, bills.tree.selected.guidance.tree.items);
             })
-            // console.log(optionalRationIDs);
+            console.log(optionalRationIDs);
             console.log(classData);
         }
     });
-
-
-    return { initViews, initSlideSize };
+    return { initViews, initSlideSize, bills };
 })();
 
 $(document).ready(function () {

+ 371 - 0
web/maintain/billsGuidance_lib/js/exportExcel.js

@@ -0,0 +1,371 @@
+class ExportExcel {
+  workBook = null;
+
+  sheet = null;
+  
+  sheetIndex = 0;
+
+  border = new GC.Spread.Sheets.LineBorder('#000', GC.Spread.Sheets.LineStyle.thin);
+
+  excelIo = new GC.Spread.Excel.IO();
+
+  $info = $('#excel-info');
+
+  // 表格当前画到的行
+  curRow = 0;
+
+  curMaxCol = 0;
+
+  billTree = null;
+
+  libID = '';
+
+  // 分部章节单元格数据
+  sections = [];
+
+
+  // 清单ID - 清单精灵映射
+  billIDElfMap = {};
+
+  // 叶子清单ID
+  leafIDs = [];
+
+  // 叶子清单总数量
+  total = 0;
+
+  // 清单ID - 最大列映射
+  maxColMap = {};
+
+  // 叶子节点的父项ID
+  leafParentIDs = [];
+
+  // 字体
+  font = 'normal normal 9pt 宋体';
+  blockTitleFont = 'bold normal 9pt 宋体';
+  bigSectionFont = 'bold normal 12pt 黑体';
+  leafSectionFont = 'bold normal 11pt 黑体';
+
+  constructor(workBook, billTree, libID) {
+    this.workBook = workBook;
+    this.sheet = this.workBook.getSheet(0);
+    this.billTree = billTree;
+    this.libID = libID;
+    this.leafIDs = billTree.items.filter(node => !node.children.length).map(node => node.data.ID);
+    this.total = this.leafIDs.length;
+  }
+
+  // 导出
+  async export() {
+    if (!this.workBook) {
+      return;
+    }
+    const json = this.workBook.toJSON();
+    this.excelIo.save(json, function (blob) {
+      saveAs(blob, '清单精灵排版.xlsx');
+    }, function (e) {
+        // process error
+        alert(e);
+        console.log(e);
+    });
+    }
+
+    // 将数据画在工作簿上
+    async paintOnWorkBook() {
+      this.updateProcessInfo();
+      // 根据专业区分不同sheet
+      for (const root of this.billTree.roots) {
+        this.initSheet(this.sheetIndex++, root.data.name);
+        const nodes = [root, ...root.getPosterity()];
+        await this.paintOnSheet(nodes);
+      }
+      this.afterPaint();
+    }
+
+  /* ========================================================以下为私有方法============================================== */
+
+  // 当前到多少条叶子清单
+  get curProcessCount () {
+    return this.total - this.leafIDs.length;
+  }
+
+  // 将数据画在表格上
+  async paintOnSheet(nodes) {
+    this.updateProcessInfo();
+    let i = 0;
+    this.sheet.suspendPaint();
+    this.sheet.suspendEvent();
+    for (const billNode of nodes) {
+      if (this.curRow >= this.sheet.getRowCount()) {
+        this.sheet.addRows(this.curRow, 2);
+      }
+      this.curMaxCol = 0;
+      if (billNode.children.length) {
+        // 清单分部章节,合并的列数依赖主体表格,所以先存数据画空行,后续再画具体内容
+        this.sections.push({ ID: billNode.data.ID, isNotLeaf: true, row: this.curRow, col: 0, text: `${billNode.data.code} ${billNode.data.name}`, rowCount: 1, colCount: 1, font: this.bigSectionFont });
+        this.curRow++;
+      } else {
+        if (!this.leafParentIDs.includes(billNode.data.ParentID)) {
+          this.leafParentIDs.push(billNode.data.ParentID);
+        }
+        if (this.maxColMap[billNode.data.ParentID] === undefined) {
+          this.maxColMap[billNode.data.ParentID] = 0;
+        }
+        // 叶子清单,合并的列数依赖主体表格,所以先存数据画空行,后续再画具体内容
+        const billText = `编码:${billNode.data.code}    名称:${billNode.data.name}    单位:${billNode.data.unit}`;
+        this.sections.push({ ID: billNode.data.ID, row: this.curRow, col: 0, text: billText, rowCount: 1, colCount: 1, font: this.leafSectionFont });
+        this.curRow++;
+        // 画清单精灵表格
+        const elfTree = await this.getElfTree(billNode.data.ID);
+        if (!elfTree) {
+          continue;
+        }
+        this.drawBlock(elfTree);
+        if (this.maxColMap[billNode.data.ParentID] < this.curMaxCol) {
+          this.maxColMap[billNode.data.ParentID] = this.curMaxCol;
+        }
+        i++;
+        
+      }
+      /* if (i === 10) {
+        break;
+      } */
+    }
+    // 画章节
+    this.drawSection(this.sections);
+
+    const range = this.sheet.getRange(0, 0, this.sheet.getRowCount(), this.sheet.getColumnCount());
+    range.vAlign(GC.Spread.Sheets.VerticalAlign.center);
+    range.wordWrap(true);
+    this.sheet.resumeEvent();
+    this.sheet.resumePaint();
+  }
+
+  // 画完表格后的处理
+  afterPaint() {
+      $('#excel-dialog').width('800px');
+      $('#excel-spread').show();
+      this.workBook.refresh();
+      $('#export-excel-confirm').show();
+  }
+
+  // 超出范围追加行列
+  checkRange(blockRange) {
+    // 不够行数,追加行数
+    const needRows = this.curRow + blockRange.rowCount;
+    const curRowCount = this.sheet.getRowCount();
+    if (curRowCount < needRows) {
+      this.sheet.addRows(this.curRow, needRows - curRowCount + 5);
+    }
+    // 不够列数,追加列数
+    const curColCount = this.sheet.getColumnCount();
+    if (curColCount < blockRange.colCount) {
+      this.sheet.addColumns(curColCount - 1, blockRange.colCount - curColCount);
+    }
+  }
+
+  // 画单元格、合并单元格
+  drawCell(block, addCurRow) {
+    block.forEach(item => {
+      const row =  addCurRow ? item.row + this.curRow : item.row;
+      this.sheet.addSpan(row, item.col, item.rowCount, item.colCount);
+      this.sheet.setFormatter(row, item.col, '@');
+      const font = item.font || this.font;
+      this.sheet.getCell(row, item.col).font(font);
+      if (item.isTitle) {
+        // 标题水平居中,字体加粗
+        const range = this.sheet.getRange(row, item.col, 1, 1);
+        range.hAlign(GC.Spread.Sheets.VerticalAlign.center);
+      } else if (item.isNotLeaf) {
+        const range = this.sheet.getRange(row, item.col, 1, 1);
+        range.hAlign(GC.Spread.Sheets.VerticalAlign.center);
+      }
+      this.sheet.setText(row, item.col, item.text);
+    });
+  }
+
+  // 画边框
+  drawBorder(range) {
+    range.setBorder(this.border, { all: true })
+  }
+
+  // 更新进度信息
+  updateProcessInfo() {
+    this.$info.text(`导出排版中: ${this.curProcessCount} / ${this.total}`)
+  }
+
+  // 完善章节清单ID - 最大列映射
+  setSectionMaxCol() {
+    this.leafParentIDs.forEach(ID => {
+      const node = this.billTree.findNode(ID);
+      if (!node) {
+        return;
+      }
+      node.children.forEach(child => {
+        this.maxColMap[child.data.ID] = this.maxColMap[ID];
+      });
+      let parent = node.parent;
+      while (parent && this.maxColMap[parent.data.ID] === undefined) {
+        this.maxColMap[parent.data.ID] = this.maxColMap[ID];
+        parent = parent.parent;
+      }
+    });
+  }
+
+
+  // 画章节
+  drawSection(sections) {
+    this.setSectionMaxCol();
+    sections.forEach(section => {
+      const maxCol = this.maxColMap[section.ID] || 0;
+      section.colCount = maxCol + 1;
+    });
+    this.drawCell(sections, false);
+  }
+
+  // 画主体表格
+  async drawBlock(elfTree) {
+    const block = this.getBlock(elfTree);
+    if (!block.length) {
+      return;
+    }
+    const blockRange = this.getBlockRange(elfTree);
+    this.checkRange(blockRange);
+    const range = this.sheet.getRange(block[0].row + this.curRow, block[0].col, blockRange.rowCount, blockRange.colCount)
+    // 画单元格
+    this.drawCell(block, true);
+    // 画边框
+    this.drawBorder(range);
+    this.curRow += blockRange.rowCount;
+  }
+
+  // 精灵树数据转换为表格块单元格数据
+  getBlock(elfTree) {
+    const block = [];
+    // 表格正文
+    const blockContent = this.getBlockContent(elfTree);
+    // 表格标题:获取完正文,才知道标题的合并列数,因此先获取表格正文,再获取表格标题
+    const blockTitle = this.getBlockTitle();
+    // 表格正文的行号,整体下移
+    blockContent.forEach(cellInfo => {
+      cellInfo.row += 1;
+    });
+    block.push(...blockTitle);
+    block.push(...blockContent);
+    return block;
+  }
+
+  // 获取表格块正文单元格数据
+  getBlockContent(elfTree) {
+    const block = elfTree.items.map(node => {
+      // rowCount、colCount标记合并单元格范围
+      const rowCount = node.posterityLeafCount() || 1;
+      const parentRow = node.parent && node.parent.cellInfo ? node.parent.cellInfo.row : 0;
+      // let prevRowCount = node.preSibling && node.preSibling.cellInfo ? node.preSibling.cellInfo.row + node.preSibling.cellInfo.rowCount - parentRow  : 0;
+      const prev = node.prevNode();
+      let prevRowCount = prev && prev.cellInfo ? prev.cellInfo.row + prev.cellInfo.rowCount - parentRow  : 0;
+      const row = parentRow + prevRowCount;
+      const col = node.depth();
+      const name = node.data.type === itemType.ration ? node.data.name.split(' ')[0] : node.data.name;
+      const text = `${isProcessNode(node) && node.data.required ? '* ' : ''}${name}`
+      node.cellInfo = {
+        row,
+        col,
+        rowCount,
+      };
+      if (this.curMaxCol < col) {
+        this.curMaxCol = col;
+      }
+      return {
+        row,
+        col,
+        rowCount,
+        text,
+        isRation: node.data.type === itemType.ration,
+        colCount: 1,
+        font: this.font,
+      }
+    });
+    this.moveRationTextToLastCol(block);
+    return block;
+  }
+
+  // 获取表格标题单元格数据,计算标题合并列依赖正文表格
+  getBlockTitle() {
+    return [
+      { row: 0, col: 0, rowCount: 1, colCount: 1, text: '工序', isTitle: true, font: this.blockTitleFont },
+      { row: 0, col: 1, rowCount: 1, colCount: this.curMaxCol === 0 ? 1 : this.curMaxCol - 1, text: '选项', isTitle: true, font: this.blockTitleFont },
+      { row: 0, col: this.curMaxCol === 0 ? 2 : this.curMaxCol, rowCount: 1, colCount: 1, text: '定额', isTitle: true, font: this.blockTitleFont },
+    ];
+  }
+  
+  // 将定额文本挪到表格最大列处显示
+  moveRationTextToLastCol(block) {
+    block.forEach(cellInfo => {
+      if (cellInfo.isRation) {
+        cellInfo.col = this.curMaxCol;
+      }
+    });
+  }
+
+  // 从表格中获取最大列号
+  getMaxCol(block) {
+    return Math.max(...block.map(cellInfo => cellInfo.col));
+  }
+
+  // 根据精灵树数据,获取表格块range
+  getBlockRange(elfTree) {
+    const rowCount = elfTree.roots.reduce((prev, node) => prev + (node.posterityLeafCount() || 1), 0) + 1; // +1是因为有一行标题
+    const a = Date.now();
+    const colCount = Math.max(...elfTree.items.map(node => node.depth())) + 1;
+    console.log(Date.now() - a);
+    return {
+      rowCount,
+      colCount: colCount === 1 ? 3 : colCount, // 有些表格没有选项和定额
+    }
+  }
+
+  // 获取清单的精灵树
+  async getElfTree(billID) {
+    const items = await this.getElfItems(billID);
+    if (!items || !items.length) {
+      return null;
+    }
+    const tree = idTree.createNew({ id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true });
+    tree.loadDatas(items);
+    return tree;
+  }
+
+  // 获取清单的精灵数据
+  async getElfItems(billID) {
+    if (this.billIDElfMap[billID]) {
+      return this.billIDElfMap[billID];
+    }
+    if (!this.leafIDs.length) {
+      return null;
+    }
+    const count = 20; // 每次拉取数据条数
+    const billIDs = this.leafIDs.splice(0, count)
+    await setTimeoutSync(null, 100);
+    const items = await ajaxPost('/billsGuidance/api/getItemsByBillIDs', { guidanceLibID: this.libID, billIDs });
+    this.updateProcessInfo();
+    items.forEach(item => {
+      (this.billIDElfMap[item.billsID] || (this.billIDElfMap[item.billsID] = [])).push(item)
+    });
+    return this.billIDElfMap[billID];
+  }
+
+  initSheet(index, name) {
+    this.curRow = 0;
+    this.sections = [];
+    this.leafParentIDs = [];
+    if (index !== 0) {
+      // 工作簿自身会有一张表
+      this.workBook.addSheet(index);
+    }
+    this.sheet = this.workBook.getSheet(index);
+    this.sheet.name(name);
+    for (let col = 0; col < this.sheet.getColumnCount(); col++) {
+      this.sheet.setColumnWidth(col, 100);
+    }
+  }
+}

+ 2 - 0
web/maintain/billsGuidance_lib/js/main.js

@@ -55,7 +55,9 @@ const billsGuidanceMain = (function () {
             <a class="lock-btn-control disabled" href="javascript:void(0);" data-toggle="modal" data-target="#edit" title="编辑"><i class="fa fa-pencil-square-o"></i></a>
             <a class="lock-btn-control disabled text-danger" href="javascript:void(0);" data-toggle="modal" data-target="#del" title="删除"><i class="fa fa-remove"></i></a>
             ` : '' }
+            ${ lockOperate !== 'true' ? `
             <a class="lock" data-locked="true" href="javascript:void(0);" title="解锁"><i class="fa fa-unlock-alt"></i></a>
+            ` : '' }
             </td>
             ${ isTemporary !== 'true' ? `
             <td style="text-align: center;">

+ 31 - 0
web/maintain/billsGuidance_lib/js/util.js

@@ -0,0 +1,31 @@
+
+//项目指引类型
+const itemType = {
+    job: 0,
+    ration: 1
+};
+
+function _isDef(v) {
+    return typeof v !== 'undefined' && v !== null;
+}
+
+// 是否为工序行
+function isProcessNode(node) {
+    return node && node.depth() % 2 === 0 && _isDef(node.data.type) && node.data.type === itemType.job
+}
+
+// 是否是选项行
+function isOptionNode(node) {
+    return node && node.depth() % 2 === 1 && _isDef(node.data.type) && node.data.type === itemType.job
+}
+
+function setTimeoutSync(handle, time) {
+    return new Promise(function (resolve, reject) {
+        setTimeout(function () {
+            if (handle && typeof handle === 'function') {
+                handle();
+            }
+            resolve();
+        }, time);
+    });
+}

+ 49 - 4
web/maintain/bills_lib/html/main.html

@@ -9,14 +9,57 @@
     <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
     <link rel="stylesheet" href="/web/maintain/bills_lib/css/main.css">
     <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
+    <style>
+        .avatar {
+          display: flex;
+          align-items: center;
+          height: 38px;
+          cursor: pointer;
+          padding: 0 20px;
+        }
+        .avatar:hover {
+          text-decoration: none;
+          box-shadow: inset 0 3px 5px rgb(0 0 0 / 13%);
+        }
+        .avatar .dropdown-menu a {
+          display: block;
+          padding: 3px 20px;
+          clear: both;
+          font-weight: 400;
+          line-height: 1.42857143;
+          color: #333;
+          white-space: nowrap;
+        }
+      </style>
+    <script>
+        const isTemporary = '<%- manager.isTemporary %>';
+      </script>
 </head>
 
 <body>
     <div class="header">
-        <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 ">
+        <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 "  style="display: flex; justify-content: space-between;">
             <span class="header-logo px-2">清单规则编辑器</span>
-            <div class="navbar-text"></div>
+            <!-- <% if (manager.isTemporary)  { %>
+                <div style="cursor: pointer;">
+                    <a href="/billsGuidance/main">
+                        <span>切换到清单精灵编辑器</span>
+                    </a>
+                </div>
+            <% } %> -->
+            <% if (manager.isTemporary)  { %>
+                <div class="avatar btn-group">
+                    <a class="dropdown-toggle" data-toggle="dropdown">
+                        <span><%= manager.username %></span>
+                    </a>
+                    <ul class="dropdown-menu dropdown-menu-right">
+                        <li><a href="/login/logout">退出登录</a></li>
+                    </ul>
+                </div>
+            <% } %>
         </nav>
+       
+        <% if (!manager.isTemporary)  { %>
         <nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0">
           <ul class="nav navbar-nav px-1">
                           <li class="nav-item">
@@ -24,7 +67,9 @@
                           </li>
                       </ul>
         </nav>
+        <% } %>
     </div>
+   
     <div class="main">
         <div class="content">
             <div class="container-fluid">
@@ -38,8 +83,8 @@
                                 <th>清单规则类型</th>
                                 <th width="160">添加时间</th>
                                 <th width="70">操作</th>
-                                <th width="90">导入</th>
-                                <th width="90">复制</th>
+                                <% if (!manager.isTemporary)  { %><th width="90" >导入</th> <% } %>
+                                <% if (!manager.isTemporary)  { %><th width="90">复制</th><% } %>
                             </tr>
                         </thead>
                         <tbody id="showArea">

+ 4 - 0
web/maintain/bills_lib/scripts/bills_lib_ajax.js

@@ -63,16 +63,20 @@ var mainAjax = {
                     <td>${libTypeName}</td>
                     <td>${createDateFmt}</td>
                     <td>
+                    ${ isTemporary !== 'true' ? `
                         <a class="lock-btn-control disabled" data-toggle="modal" data-target="#edit" href="javascript:void(0);" title="编辑"><i class="fa fa-pencil-square-o"></i></a>
                         <a class="text-danger lock-btn-control disabled" data-toggle="modal" data-target="#del" href="javascript:void(0);" title="删除"><i class="fa fa-remove"></i></a>
+                    ` : '' }
                         <a class="lock" data-locked="true" href="javascript:void(0);" title="解锁"><i class="fa fa-unlock-alt"></i></a>
                     </td>
+                    ${ isTemporary !== 'true' ? `
                     <td>
                         <a class="btn btn-secondary btn-sm import-data lock-btn-control disabled" data-id="${id}" href="javascript:void(0);" title="导入数据"><i class="fa fa-sign-in fa-rotate-90"></i>导入</a>
                     </td>
                     <td>
                         <a class="btn btn-secondary btn-sm copy-data lock-btn-control disabled" data-id="${id}" data-type="${libType}" href="javascript:void(0);" title="复制数据"><i class="fa fa-clone"></i>复制</a>
                     </td>
+                    ` : '' }
                  </tr>`;
             return acc += html;
         }, '');

+ 29 - 1
web/maintain/price_info_lib/html/edit.html

@@ -18,7 +18,10 @@
         <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 ">
             <span class="header-logo px-2">Smartcost</span>
             <div class="navbar-text"><a href="/priceInfo/main">信息价库</a><i
-                    class="fa fa-angle-right fa-fw"></i><%= libName  %></div>
+                    class="fa fa-angle-right fa-fw"></i><%= libName  %>
+               <button id="calc-price-index">计算指数</button>     
+            </div>
+
         </nav>
     </div>
     <div class="wrapper">
@@ -55,6 +58,31 @@
             </div>
         </div>
     </div>
+
+
+    <div class="modal fade in" id="result-info" data-backdrop="static">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content" style=" width: 900px;">
+                <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"  >
+                    <div class="form-group">
+                        <div>以下指数偏差较大,请确认:</div>
+                        <div id="result-info-body">
+                         
+                        </div>
+                    </div>
+                </div>
+                <div class="modal-footer" style="justify-content: center">
+                    <button type="button" class="btn btn-primary" data-dismiss="modal" id="copy-lib-confirm">确定</button>
+                </div>
+            </div>
+        </div>
+    </div>
     <!-- JS. -->
     <script src="/lib/jquery/jquery.min.js"></script>
     <script src="/lib/jquery-contextmenu/jquery.contextMenu.min.js"></script>

+ 2 - 1
web/maintain/price_info_lib/html/main.html

@@ -28,7 +28,7 @@
                                     <th width="160">费用定额</th>
                                     <th width="160">添加时间</th>
                                     <th width="70">操作</th>
-                                    <th width="70">原始数据</th>
+                                    <th width="150">原始数据</th>
                                     <th width="70">关键字</th>
                                 </tr>
                             </thead>
@@ -52,6 +52,7 @@
                                                 class="fa fa-unlock-alt"></i></a>
                                     </td>
                                     <td>
+                                        <a class="btn btn-success btn-sm export-data lock-btn-control disabled" href="javascript:void(0);" onclick='handleExportClick("<%= lib.ID%>")' title="导出数据"><i class="fa fa-sign-out fa-rotate-270"></i>导出</a>
                                         <a class="btn btn-secondary btn-sm import-data lock-btn-control disabled"
                                             onclick='handleImportClick("<%= lib.ID%>", "originalData")' href="javacript:void(0);"
                                             title="导入数据"><i class="fa fa-sign-in fa-rotate-90"></i>导入</a>

+ 31 - 0
web/maintain/price_info_lib/js/index.js

@@ -322,6 +322,7 @@ const CLASS_BOOK = (() => {
     const $downLevel = $('#tree-down-level');
     const $downMove = $('#tree-down-move');
     const $upMove = $('#tree-up-move');
+    const $calcPriceIndex = $('#calc-price-index');
 
     // 插入
     let canInsert = true;
@@ -640,6 +641,31 @@ const CLASS_BOOK = (() => {
     }, DEBOUNCE_TIME, { leading: true });
     sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, debounceSelectionChanged);
 
+
+
+    $calcPriceIndex.click(_.debounce(async()=>{
+        $.bootstrapLoading.start();
+        try {
+        const data = await ajaxPost('/priceInfo/calcPriceIndex', { libID, period:curLibPeriod,compilationID }, TIME_OUT);
+          //alert(data);
+          
+          if(data){
+              const htmlStr = data.replace(/\n/gm,'<br>'); //replaceAll('\n','<br>',data);
+              $("#result-info-body").html(htmlStr);
+              $("#result-info").modal('show');
+          }else{
+              alert('计算完成!')
+          }  
+
+
+        } catch (error) {
+            console.log(error);
+        }
+        $.bootstrapLoading.end();
+
+    }, DEBOUNCE_TIME, { leading: true }));
+
+
     return {
         initData,
         handleSelectionChanged,
@@ -712,6 +738,7 @@ const PRICE_BOOK = (() => {
         $.bootstrapLoading.start();
         try {
             cache = await ajaxPost('/priceInfo/getPriceData', { classIDList }, TIME_OUT);
+            cache = _.sortBy(cache,'classCode');
             showData(sheet, cache, setting.header, 5);
             const row = sheet.getActiveRowIndex();
             const keywordList = cache[row] && cache[row].keywordList || [];
@@ -847,4 +874,8 @@ $(document).ready(() => {
     AREA_BOOK.handleSelectionChanged(0);
     const $range = $(document.body);
     lockUtil.lockTools($range, locked);
+
+
+
+
 });

+ 5 - 0
web/maintain/price_info_lib/js/main.js

@@ -88,6 +88,11 @@ function handleImportClick(libID, type) {
     $('#import').modal('show');
 }
 
+// 点击导出按钮
+function handleExportClick(libID) {
+    window.location.href = '/priceInfo/export?libID=' + libID;
+}
+
 // 导入确认
 function handleImportConfirm() {
     $.bootstrapLoading.start();

+ 12 - 0
web/maintain/ration_repository/dinge.html

@@ -92,6 +92,9 @@
                                 <a class="nav-link" data-toggle="tab" href="#tjs" role="tab" id="ruleTextLink">计算规则</a>
                             </li>
                             <li class="nav-item">
+                                <a class="nav-link" data-toggle="tab" href="#erratumRecord" role="tab" id="erratumRecordLink">勘误记录</a>
+                            </li>
+                            <li class="nav-item">
                                 <a id="gznr" class="nav-link" data-toggle="tab" href="#tgz" role="tab">工作内容</a>
                             </li>
                             <li class="nav-item">
@@ -155,6 +158,15 @@
                                     </div>
                                 </div>
                             </div>
+                            <!--勘误记录-->
+                            <div class="tab-pane" id="erratumRecord" role="tabpanel">
+                                <div class="main-data">
+                                <div class="main-content m-2">
+                                    <a trigger="erratumRecord" class="mr-3 uploadImgTrigger lock-btn-control" href="javacript:void(0);" data-toggle="modal" data-target="#uploadimg" ><i class="fa fa-image"></i>上传图片</a><a href="javacript:void(0);" data-toggle="modal" data-target="#help" >html怎么写?</a></p>
+                                    <textarea id="erratumRecordShow" name="editor" class="form-control "></textarea>
+                                </div>
+                            </div>
+                            </div>
                             <!--工作内容-->
                             <div class="tab-pane" id="tgz" role="tabpanel">
                                 <div class="main-data">

+ 74 - 41
web/maintain/ration_repository/js/explanatory.js

@@ -5,9 +5,11 @@
 let explanatoryOprObj = {
     exEditor: null,
     calcEditor: null,
+    erratumEditor: null,
     preTreeNode: null,
     currentTreeNode: null,//定额章节树节点
     currentExplanation: null,
+    currentErratum: null,
     currentRuleText: null,
     // 初始化说明、计算规则编辑器
     initEditor: function () {
@@ -15,16 +17,32 @@ let explanatoryOprObj = {
         const exEditor = CodeMirror.fromTextArea(document.getElementById("explanationShow"), {
             mode: "text/html",
             lineNumbers: true,
-            theme:"material",
+            theme: "material",
             readOnly: locked
         });
-        exEditor.setSize('auto','500px');
+        exEditor.setSize('auto', '500px');
         $('#explanationLink').click(function () {
             setTimeout(function () {
                 exEditor.refresh();
             }, 100);
         });
         this.exEditor = exEditor;
+
+        const erratumEditor = CodeMirror.fromTextArea(document.getElementById("erratumRecordShow"), {
+            mode: "text/html",
+            lineNumbers: true,
+            theme: "material",
+            readOnly: locked
+        });
+        erratumEditor.setSize('auto', '500px');
+        $('#erratumRecordLink').click(function () {
+            setTimeout(function () {
+                erratumEditor.refresh();
+            }, 100);
+        });
+        this.erratumEditor = erratumEditor;
+
+
         const calcEditor = CodeMirror.fromTextArea(document.getElementById("ruleTextShow"), {
             mode: 'text/html',
             lineNumbers: true,
@@ -39,93 +57,108 @@ let explanatoryOprObj = {
         });
         this.calcEditor = calcEditor;
     },
-    setAttribute: function (preNode, currentNode, explanation, ruleText) {
+    setAttribute: function (preNode, currentNode, explanation, erratum, ruleText) {
         let me = explanatoryOprObj;
         me.preTreeNode = preNode;
         me.currentTreeNode = currentNode;
         me.currentExplanation = explanation;
+        me.currentErratum = erratum;
         me.currentRuleText = ruleText;
     },
-    clickUpdate: function (exarea, ruarea) {//解决编辑完后在未失去焦点的时候直接定额章节树
+    clickUpdate: function (exarea, errArea, ruarea) {//解决编辑完后在未失去焦点的时候直接定额章节树
         let me = explanatoryOprObj;
-        if(exarea.is(':focus')){
+        if (exarea.is(':focus')) {
             let explanation = exarea.val();
-            if(explanation !== me.currentExplanation){
+            if (explanation !== me.currentExplanation) {
                 me.preTreeNode.data.explanation = explanation;
-                me.unbindEvents(exarea, ruarea);
+                me.unbindEvents(exarea, errArea, ruarea);
                 exarea.blur();
                 me.updateExplanation(pageOprObj.rationLibId, me.preTreeNode.getID(), explanation, function () {
-                    me.bindEvents(exarea, ruarea);
+                    me.bindEvents(exarea, errArea, ruarea);
                 });
             }
         }
-        if(ruarea.is(':focus')){
+        if (errArea.is(':focus')) {
+            let erratum = errArea.val();
+            if (erratum !== me.currentErratum) {
+                me.preTreeNode.data.erratumRecord = erratum;
+                me.unbindEvents(exarea, errArea, ruarea);
+                errArea.blur();
+                me.updateErratumRecord(pageOprObj.rationLibId, me.preTreeNode.getID(), erratum, function () {
+                    me.bindEvents(exarea, errArea, ruarea);
+                });
+            }
+        }
+        if (ruarea.is(':focus')) {
             let ruleText = ruarea.val();
-            if(ruleText !== me.currentRuleText){
+            if (ruleText !== me.currentRuleText) {
                 me.preTreeNode.data.ruleText = ruleText;
-                me.unbindEvents(exarea, ruarea);
+                me.unbindEvents(exarea, errArea, ruarea);
                 ruarea.blur();
                 me.updateRuleText(pageOprObj.rationLibId, me.preTreeNode.getID(), ruleText, function () {
-                    me.bindEvents(exarea, ruarea);
+                    me.bindEvents(exarea, errArea, ruarea);
                 });
             }
         }
     },
-    unbindEvents: function (exarea, ruarea) {
+    unbindEvents: function (exarea, errArea, ruarea) {
         exarea.unbind();
+        errArea.unbind();
         ruarea.unbind();
     },
-    bindEvents: function (exEd, calcEd) {
+    bindEvents: function (exEd, errEd, calcEd) {
         let me = explanatoryOprObj;
         exEd.on('change', function () {
             let node = me.currentTreeNode;
             let newData = exEd.getValue();
-            if(node && node.data.explanation !== newData){
+            if (node && node.data.explanation !== newData) {
                 me.updateExplanation(pageOprObj.rationLibId, node.getID(), newData, function () {
                     node.data.explanation = newData;
                 });
             }
         });
+        errEd.on('change', function () {
+            let node = me.currentTreeNode;
+            let newData = errEd.getValue();
+            if (node && node.data.erratumRecord !== newData) {
+                me.updateErratumRecord(pageOprObj.rationLibId, node.getID(), newData, function () {
+                    node.data.erratumRecord = newData;
+                });
+            }
+        });
         calcEd.on('change', function () {
             let node = me.currentTreeNode;
             let newData = calcEd.getValue();
-            if(node && node.data.ruleText !== newData){
+            if (node && node.data.ruleText !== newData) {
                 me.updateRuleText(pageOprObj.rationLibId, node.getID(), newData, function () {
                     node.data.ruleText = newData;
                 });
             }
         })
-        /*exarea.bind('change', function () {
-            let explanation = exarea.val();
-            let node = me.currentTreeNode;
-            exarea.attr('disabled', true);
-            me.updateExplanation(pageOprObj.rationLibId, node.getID(), explanation, function () {
-                node.data.explanation = explanation;
-                exarea.attr('disabled', false);
-            });
-        });*/
-        /*ruarea.bind('change', function () {
-            let ruleText = ruarea.val();
-            let node = me.currentTreeNode;
-            ruarea.attr('disabled', true);
-            me.updateRuleText(pageOprObj.rationLibId, node.getID(), ruleText, function () {
-                node.data.ruleText = ruleText;
-                ruarea.attr('disabled', false);
-            });
-        });*/
     },
-    showText: function (exEd, calcEd, explanation, ruleText) {
-        exEd.setValue(explanation && explanation !== 'undefined' ? explanation : '');
-        calcEd.setValue(ruleText && ruleText !== 'undefined' ? ruleText : '');
-        //exarea.val(explanation && explanation !== 'undefined' ? explanation : '');
-        //ruarea.val(ruleText && ruleText !== 'undefined' ? ruleText : '');
+    showText: function (explanation, erratumRecord, ruleText) {
+        this.exEditor.setValue(explanation && explanation !== 'undefined' ? explanation : '');
+        this.erratumEditor.setValue(erratumRecord && erratumRecord !== 'undefined' ? erratumRecord : '');
+        this.calcEditor.setValue(ruleText && ruleText !== 'undefined' ? ruleText : '');
     },
     //更新说明
     updateExplanation: function (repId, nodeId, explanation, callback) {
         $.ajax({
             type: 'post',
             url: 'api/updateExplanation',
-            data: {lastOpr: userAccount, repId: pageOprObj.rationLibId, nodeId: nodeId, explanation: explanation},
+            data: { lastOpr: userAccount, repId: pageOprObj.rationLibId, nodeId: nodeId, explanation: explanation },
+            dataType: 'json',
+            success: function () {
+                callback();
+            }
+        });
+    },
+    //更新勘误记录
+    updateErratumRecord: function (repId, nodeId, erratumRecord, callback) {
+        $.ajax({
+            type: 'post',
+            url: 'api/updateErratumRecord',
+            data: { lastOpr: userAccount, repId: pageOprObj.rationLibId, nodeId: nodeId, erratumRecord: erratumRecord },
             dataType: 'json',
             success: function () {
                 callback();
@@ -137,7 +170,7 @@ let explanatoryOprObj = {
         $.ajax({
             type: 'post',
             url: 'api/updateRuleText',
-            data: {lastOpr: userAccount, repId: pageOprObj.rationLibId, nodeId: nodeId, ruleText: explanation},
+            data: { lastOpr: userAccount, repId: pageOprObj.rationLibId, nodeId: nodeId, ruleText: explanation },
             dataType: 'json',
             success: function () {
                 callback();

+ 25 - 23
web/maintain/ration_repository/js/global.js

@@ -1,19 +1,19 @@
 /*全局自适应高度*/
-function autoFlashHeight(){
+function autoFlashHeight() {
     var headerHeight = $(".header").height();
     var bottomContentHeight = $(".bottom-content").height();
     var toolsBar = $(".tools-bar").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 );
-    $(".poj-list").height($(window).height()-headerHeight);
-    $(".form-list").height($(window).height()-headerHeight-50 );
-    $(".main-data-top").height($(window).height()-headerHeight-toolsBar-bottomContentHeight-2);
-    $(".main-data-top-fluid").height($(window).height()-headerHeight-bottomContentHeight-2);
-    $(".main-data").height($(window).height()-headerHeight);
-    $(".main-side .tab-content").height($(window).height()-headerHeight-38);
-    $('#partialBody').height($(window).height()-headerHeight-toolsBar - 60);
+    $(".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);
+    $(".poj-list").height($(window).height() - headerHeight);
+    $(".form-list").height($(window).height() - headerHeight - 50);
+    $(".main-data-top").height($(window).height() - headerHeight - toolsBar - bottomContentHeight - 2);
+    $(".main-data-top-fluid").height($(window).height() - headerHeight - bottomContentHeight - 2);
+    $(".main-data").height($(window).height() - headerHeight);
+    $(".main-side .tab-content").height($(window).height() - headerHeight - 38);
+    $('#partialBody').height($(window).height() - headerHeight - toolsBar - 60);
     let partialWidth = $('#tablePartial').width();
     $('#tablePartial').find('th:eq(0)').width(partialWidth * 0.06);
     $('#tablePartial').find('th:eq(1)').width(partialWidth * 0.3);
@@ -21,24 +21,26 @@ function autoFlashHeight(){
     $('#partialBody').find('tr').find('td:eq(0)').width(partialWidth * 0.06);
     $('#partialBody').find('tr').find('td:eq(1)').width(partialWidth * 0.3);
     $('#partialBody').find('tr').find('td:eq(2)').width(partialWidth * 0.64);
-//说明
-    $('#explanationShow').height($(window).height()-headerHeight-toolsBar-100);
-//计算规则
-    $('#ruleTextShow').height($(window).height()-headerHeight-toolsBar-100);
+    //说明
+    $('#explanationShow').height($(window).height() - headerHeight - toolsBar - 100);
+    // 勘误记录
+    $('#erratumRecordShow').height($(window).height() - headerHeight - toolsBar - 100);
+    //计算规则
+    $('#ruleTextShow').height($(window).height() - headerHeight - toolsBar - 100);
     typeof loadRationSubSize !== 'undefined' ? loadRationSubSize() : '';
     typeof loadZmhsAdjSize !== 'undefined' ? loadZmhsAdjSize() : '';
     typeof sectionTreeObj !== 'undefined' ? sectionTreeObj.loadRateWidth() : '';
 };
 $(window).resize(autoFlashHeight);
 /*全局自适应高度结束*/
-$(function(){
+$(function () {
     /*侧滑*/
-    $(".open-sidebar").click(function(){
-        $(".slide-sidebar").animate({width:"800"}).addClass("open");
+    $(".open-sidebar").click(function () {
+        $(".slide-sidebar").animate({ width: "800" }).addClass("open");
     });
-    $("body").click(function(event){
+    $("body").click(function (event) {
         var e = event || window.event; //浏览器兼容性
-        if(!$(event.target).is('a')) {
+        if (!$(event.target).is('a')) {
             var elem = event.target || e.srcElement;
             while (elem) { //循环判断至跟节点,防止点击的是div子元素
                 if (elem.className == "open-sidebar" || elem.className == 'slide-sidebar open') {
@@ -46,13 +48,13 @@ $(function(){
                 }
                 elem = elem.parentNode;
             }
-            $(".slide-sidebar").animate({width:"0"}).removeClass("open")// 关闭处理
+            $(".slide-sidebar").animate({ width: "0" }).removeClass("open")// 关闭处理
         }
 
     });
     /*侧滑*/
     /*工具提示*/
-    $('*[data-toggle=tooltip]').mouseover(function() {
+    $('*[data-toggle=tooltip]').mouseover(function () {
         $(this).tooltip('show');
     });
     /*工具提示*/

+ 18 - 5
web/maintain/ration_repository/js/installation.js

@@ -69,19 +69,19 @@ $(document).ready(function () {
       for (let i = 0, len = sels.length; i < len; i++) {
         let sel = sels[i];
         //delete
-        if (sel.colCount === me.setting.header.length) {
+        // if (sel.colCount === me.setting.header.length) {
           for (let j = 0, jLen = sel.rowCount; j < jLen; j++) {
             let row = sel.row + j;
             let section = me.cache[row];
             //有数据,删除数据
             if (me.isDef(section)) {
-              sePostData.push({ updateType: me.updateType.update, updateData: { ID: section.ID, deleted: true } });
+              sePostData.push({ updateType: me.updateType.del, updateData: { ID: section.ID, deleted: true } });
               fiPostData.push({ updateType: me.updateType.update, updateData: { ID: fi.currentFeeItem.ID, $pull: { section: { ID: section.ID } } } });
             }
           }
           //front delete
           me.cache.splice(sel.row, sel.rowCount);
-        }
+        // }
       }
       //update currentSection
       me.currentSection = fi.getCurrentData(me.sheet, me.cache);
@@ -394,7 +394,7 @@ let sectionObj = {
   sheet: null,
   cache: [],
   currentSection: null,
-  updateType: { update: "update", new: "new" },
+  updateType: { update: "update", new: "new", del: 'delete' },
   deleteType: "section",
   setting: {
     header: [
@@ -496,6 +496,19 @@ let sectionObj = {
                   $("#sectionTreeModal").modal("show");
                 },
               },
+              del: {
+                name: "删除章节",
+                disabled: function () {
+                  const inValidCell = !commonUtil.isDef(target.row) || !commonUtil.isDef(target.col);
+                  const inValidData = target.row >= me.cache.length;
+                  return locked || inValidCell || inValidData;
+                },
+                icon: "fa-times",
+                callback: function (key, opt) {
+                  curDeleteType = me.deleteType;
+                  $("#delAlert").modal("show");
+                },
+              },
             },
           };
         } else {
@@ -647,7 +660,7 @@ let sectionObj = {
     me.workBook.commandManager().setShortcutKey("sectionDel", GC.Spread.Commands.Key.del, false, false, false, false);
   },
   updateSection: function (updateData, callback) {
-    CommonAjax.post("/rationRepository/api/updateSection", { updateData: updateData }, function (rstData) {
+    CommonAjax.post("/rationRepository/api/updateSection", { updateData: updateData, libID: feeItemObj.rationRepId }, function (rstData) {
       if (callback) {
         callback();
       }

+ 181 - 175
web/maintain/ration_repository/js/ration.js

@@ -3,7 +3,7 @@
  */
 
 $(document).ready(function () {
-   //定额表与下方子表上下拖动
+    //定额表与下方子表上下拖动
     let rationSubResize = getRationSubResize();
     SlideResize.verticalSlide(rationSubResize.eleObj, rationSubResize.limit, function () {
         if (rationOprObj.workBook) {
@@ -67,36 +67,40 @@ let rationOprObj = {
     currentSectionId: -1,
     rationsCodes: [],
     setting: {
-        header:[
-            {headerName:"编码",headerWidth:70,dataCode:"code", dataType: "String", formatter: "@"},
-            {headerName:"名称",headerWidth:240,dataCode:"name", dataType: "String"},
-            {headerName:"计量单位",headerWidth:70,dataCode:"unit", dataType: "String", hAlign: "center"},
-            {headerName:"人工费",headerWidth:80,dataCode:"labourPrice", dataType: "Number", formatter: "0.00", hAlign: "right"},
-            {headerName:"材料费",headerWidth:80,dataCode:"materialPrice", dataType: "Number", formatter: "0.00",  hAlign: "right"},
-            {headerName:"机械费",headerWidth:80,dataCode:"machinePrice", dataType: "Number", formatter: "0.00", hAlign: "right"},
-            {headerName:"基价",headerWidth:80,dataCode:"basePrice", dataType: "Number", formatter: "0.00", hAlign: "right"},
-            {headerName:"显示名称(以%s表示参数)",headerWidth:240,dataCode:"caption", dataType: "String"},
-            {headerName:"取费专业",headerWidth:70,dataCode:"feeType", dataType: "Number", hAlign: "center"},
-            {headerName:"管理费费率(%)",headerWidth:100,dataCode:"manageFeeRate", dataType: "String", hAlign: "center"},
-            {headerName:"工作内容",headerWidth:130,dataCode:"jobContentText", dataType: "String"},
+        header: [
+            { headerName: "编码", headerWidth: 70, dataCode: "code", dataType: "String", formatter: "@" },
+            { headerName: "名称", headerWidth: 240, dataCode: "name", dataType: "String" },
+            { headerName: "计量单位", headerWidth: 70, dataCode: "unit", dataType: "String", hAlign: "center" },
+            { headerName: "人工费", headerWidth: 80, dataCode: "labourPrice", dataType: "Number", formatter: "0.00", hAlign: "right" },
+            { headerName: "材料费", headerWidth: 80, dataCode: "materialPrice", dataType: "Number", formatter: "0.00", hAlign: "right" },
+            { headerName: "机械费", headerWidth: 80, dataCode: "machinePrice", dataType: "Number", formatter: "0.00", hAlign: "right" },
+            { headerName: "基价", headerWidth: 80, dataCode: "basePrice", dataType: "Number", formatter: "0.00", hAlign: "right" },
+            { headerName: "显示名称(以%s表示参数)", headerWidth: 240, dataCode: "caption", dataType: "String" },
+            { headerName: "取费专业", headerWidth: 70, dataCode: "feeType", dataType: "String", hAlign: "center" },
+            { headerName: "管理费费率(%)", headerWidth: 100, dataCode: "manageFeeRate", dataType: "String", hAlign: "center" },
+            { headerName: "一类地区管理费", headerWidth: 100, dataCode: "manageFee1", dataType: "Number", hAlign: "right" },
+            { headerName: "二类地区管理费", headerWidth: 100, dataCode: "manageFee2", dataType: "Number", hAlign: "right" },
+            { headerName: "三类地区管理费", headerWidth: 100, dataCode: "manageFee3", dataType: "Number", hAlign: "right" },
+            { headerName: "四类地区管理费", headerWidth: 100, dataCode: "manageFee4", dataType: "Number", hAlign: "right" },
+            { headerName: "工作内容", headerWidth: 130, dataCode: "jobContentText", dataType: "String" },
         ],
-        view:{
-            comboBox:[
-                {row:-1,col:2,rowCount:-1,colCount:1}
+        view: {
+            comboBox: [
+                { row: -1, col: 2, rowCount: -1, colCount: 1 }
             ],
-            lockedCells:[
-                {row:-1,col:3,rowCount:-1, colCount:1}
+            lockedCells: [
+                { row: -1, col: 3, rowCount: -1, colCount: 1 }
             ],
             lockColumns: [
                 3, 4, 5, 6
             ]
         }
     },
-    buildSheet: function(container) {
+    buildSheet: function (container) {
         let rationRepId = getQueryString("repository");
         let me = rationOprObj;
         me.workBook = sheetCommonObj.buildSheet(container, me.setting, 30);
-        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.onContextmenuOpr();
         me.rationDelOpr();
         me.setCombo(me.workBook.getSheet(0), 'dynamic');
@@ -112,7 +116,7 @@ let rationOprObj = {
         let me = rationOprObj;
         sheet.suspendPaint();
         sheet.suspendEvent();
-        if(combo){
+        if (combo) {
             combo = sheetCommonObj.getDynamicCombo();
             combo.items(rationAndGljUnits).itemHeight(10).editable(true);
         }
@@ -123,7 +127,7 @@ let rationOprObj = {
     // TODO info.oldSelections is null
     onSelectionChanged: function (sender, info) {
         console.log(info);
-        if(info.oldSelections.length === 0 && info.newSelections.length > 0 || info.oldSelections[0].row !== info.newSelections[0].row){
+        if (info.oldSelections.length === 0 && info.newSelections.length > 0 || info.oldSelections[0].row !== info.newSelections[0].row) {
             let row = info.newSelections[0].row;
             let me = rationOprObj;
             me.rationSelInit(row);
@@ -144,14 +148,14 @@ let rationOprObj = {
         RationTemplate.rationInitSel(cacheSection[row]);
         if (cacheSection && row < cacheSection.length) {
             rationGLJOprObj.getGljItems(cacheSection[row], function () {
-                if (focusOnSection){
+                if (focusOnSection) {
                     sectionTreeObj.workBook.focus(true);
                 } else {
                     me.workBook.focus(true);
                 }
             });
             rationCoeOprObj.getCoeItems(cacheSection[row], function () {
-                if (focusOnSection){
+                if (focusOnSection) {
                     sectionTreeObj.workBook.focus(true);
                 } else {
                     me.workBook.focus(true);
@@ -159,7 +163,7 @@ let rationOprObj = {
             });
             rationAssistOprObj.getAssItems(cacheSection[row]);
             rationInstObj.getInstItems(cacheSection[row], function () {
-                if (focusOnSection){
+                if (focusOnSection) {
                     sectionTreeObj.workBook.focus(true);
                 } else {
                     me.workBook.focus(true);
@@ -177,7 +181,7 @@ let rationOprObj = {
     isInt: function (num) {
         return !isNaN(num) && num % 1 === 0;
     },
-    getCache: function() {
+    getCache: function () {
         let me = this, rst = me.currentRations["_SEC_ID_" + me.currentSectionId];
         if (!(rst)) {
             me.currentRations["_SEC_ID_" + me.currentSectionId] = [];
@@ -185,14 +189,14 @@ let rationOprObj = {
         }
         return rst;
     },
-    updateCache: function(addArr, updateArr, removeIds, result) {
+    updateCache: function (addArr, updateArr, removeIds, result) {
         let me = this, cacheSection = me.getCache();
         if (addArr.length > 0) {
             me.currentRations["_SEC_ID_" + me.currentSectionId] = cacheSection.concat(addArr);
             cacheSection = me.currentRations["_SEC_ID_" + me.currentSectionId];
         }
         for (let i = removeIds.length - 1; i >= 0; i--) {
-            for (let j = cacheSection.length - 1; j >= 0 ; j--) {
+            for (let j = cacheSection.length - 1; j >= 0; j--) {
                 if (cacheSection[j].rationTemplateList) {
                     //清除模板关联
                     _.remove(cacheSection[j].rationTemplateList, function (data) {
@@ -200,7 +204,7 @@ let rationOprObj = {
                     });
                 }
                 if (cacheSection[j]["ID"] == removeIds[i]) {
-                    cacheSection.splice(j,1);
+                    cacheSection.splice(j, 1);
                 }
             }
         }
@@ -222,9 +226,9 @@ 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']] :
-                                                        cacheSection[j]['rationGljList'] ?
-                                                            cacheSection[j]['rationGljList'] : [];
+                            rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] :
+                            cacheSection[j]['rationGljList'] ?
+                                cacheSection[j]['rationGljList'] : [];
                         updateArr[i]['rationCoeList'] = cacheSection[j]['rationCoeList'] ? cacheSection[j]['rationCoeList'] : [];
                         updateArr[i]['rationAssList'] = cacheSection[j]['rationAssList'];
                         updateArr[i]['rationInstList'] = cacheSection[j]['rationInstList'];
@@ -234,9 +238,9 @@ 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']] :
-                                                        cacheSection[j]['rationGljList'] ?
-                                                            cacheSection[j]['rationGljList'] : [];
+                            rationGLJOprObj.cache['_GLJ_' + cacheSection[j]['ID']] :
+                            cacheSection[j]['rationGljList'] ?
+                                cacheSection[j]['rationGljList'] : [];
                         updateArr[i]['rationCoeList'] = cacheSection[j]['rationCoeList'] ? cacheSection[j]['rationCoeList'] : [];
                         updateArr[i]['rationAssList'] = cacheSection[j]['rationAssList'];
                         updateArr[i]['rationInstList'] = cacheSection[j]['rationInstList'];
@@ -252,25 +256,25 @@ let rationOprObj = {
         let me = this;
         $.contextMenu({
             selector: '#rationItemsSheet',
-            build: function($triggerElement, e){
+            build: function ($triggerElement, e) {
                 //控制允许右键菜单在哪个位置出现
                 let target = SheetDataHelper.safeRightClickSelection($triggerElement, e, me.workBook);
                 let sheet = me.workBook.getSheet(0);
                 let cacheSection = me.getCache();
                 let ration = cacheSection[target.row];
-                if(target.hitTestType === 3){//在表格内&& typeof target.row !== 'undefined' && typeof target.col !== 'undefined'
-                    if(typeof target.row !== 'undefined'){
+                if (target.hitTestType === 3) {//在表格内&& typeof target.row !== 'undefined' && typeof target.col !== 'undefined'
+                    if (typeof target.row !== 'undefined') {
                         //控制按钮是否可用
                         sheet.setActiveCell(target.row, target.col);
                     }
                     return {
-                        callback: function(){},
+                        callback: function () { },
                         items: {
                             "delete": {
                                 name: "删除",
                                 disabled: function () {
                                     const inValidCell = !commonUtil.isDef(target.row) || !commonUtil.isDef(target.col);
-                                    const inValidData = !cacheSection ||target.row >= cacheSection.length;
+                                    const inValidData = !cacheSection || target.row >= cacheSection.length;
                                     return locked || inValidCell || inValidData;
                                 },
                                 icon: "fa-remove",
@@ -285,11 +289,12 @@ let rationOprObj = {
                                         $('#delRationConfirm').unbind('click');
                                         $('#delRationAlert').modal('hide');
                                     });
-                                }}
+                                }
+                            }
                         }
                     };
                 }
-                else{
+                else {
                     return false;
                 }
             }
@@ -305,12 +310,12 @@ let rationOprObj = {
             let sels = rationSheet.getSelections(), updateArr = [], removeArr = [], lockCols = me.setting.view.lockColumns;
             let removeCodes = [];
             let cacheSection = me.getCache();
-            if(sels.length > 0){
-                for(let sel = 0; sel < sels.length; sel++){
-                    if(sels[sel].colCount === me.setting.header.length){
-                        if(cacheSection){
-                            for(let i = 0; i < sels[sel].rowCount; i++){
-                                if(sels[sel].row + i < cacheSection.length){
+            if (sels.length > 0) {
+                for (let sel = 0; sel < sels.length; sel++) {
+                    if (sels[sel].colCount === me.setting.header.length) {
+                        if (cacheSection) {
+                            for (let i = 0; i < sels[sel].rowCount; i++) {
+                                if (sels[sel].row + i < cacheSection.length) {
                                     removeArr.push(cacheSection[sels[sel].row + i].ID);
                                     removeCodes.push(cacheSection[sels[sel].row + i].code);
                                     me.rationsCodes.splice(me.rationsCodes.indexOf(cacheSection[sels[sel].row + i].code.toString()), 1);
@@ -318,8 +323,8 @@ let rationOprObj = {
                             }
                         }
                     }
-                    else{
-                        if(sels[sel].col === 0){
+                    else {
+                        if (sels[sel].col === 0) {
                             $('#alertText').text("编号不能为空,修改失败!");
                             $('#alertModalBtn').click();
                             $('#alertModalCls').click(function () {
@@ -327,17 +332,17 @@ let rationOprObj = {
                             $('#alertModalCof').click(function () {
                             })
                         }
-                        else if(sels[sel].col !== 0 && !(sels[sel].col === 3 && sels.col + sels[sel].colCount -1 === 6)){
-                            if(cacheSection){
-                                for(let i = sels[sel].row === -1 ? 1 : 0; i < sels[sel].rowCount; i++){
-                                    if(sels[sel].row + i < cacheSection.length){
-                                        for(let col = sels[sel].col; col <= sels[sel].col + sels[sel].colCount - 1; col++){
-                                            if(lockCols.indexOf(col) === -1){
+                        else if (sels[sel].col !== 0 && !(sels[sel].col === 3 && sels.col + sels[sel].colCount - 1 === 6)) {
+                            if (cacheSection) {
+                                for (let i = sels[sel].row === -1 ? 1 : 0; i < sels[sel].rowCount; i++) {
+                                    if (sels[sel].row + i < cacheSection.length) {
+                                        for (let col = sels[sel].col; col <= sels[sel].col + sels[sel].colCount - 1; col++) {
+                                            if (lockCols.indexOf(col) === -1) {
                                                 cacheSection[sels[sel].row + i][me.setting.header[col].dataCode] = '';
                                             }
                                         }
                                     }
-                                    if(cacheSection[sels[sel].row + i] && typeof cacheSection[sels[sel].row + i] !== 'undefined'){
+                                    if (cacheSection[sels[sel].row + i] && typeof cacheSection[sels[sel].row + i] !== 'undefined') {
                                         updateArr.push(cacheSection[sels[sel].row + i]);
                                     }
                                 }
@@ -346,16 +351,16 @@ let rationOprObj = {
                     }
                 }
             }
-          /*  if(updateArr.length > 0 || removeArr.length > 0){
-                me.mixUpdate = 1;
-                me.mixDel = removeArr.length > 0 ? 1 : 0;
-                me.mixUpdateRequest(updateArr, [], removeArr);
-            }*/
-            if(updateArr.length > 0){
+            /*  if(updateArr.length > 0 || removeArr.length > 0){
+                  me.mixUpdate = 1;
+                  me.mixDel = removeArr.length > 0 ? 1 : 0;
+                  me.mixUpdateRequest(updateArr, [], removeArr);
+              }*/
+            if (updateArr.length > 0) {
                 me.mixUpdate = 1;
                 me.mixUpdateRequest(updateArr, [], []);
             }
-            if(removeArr.length > 0){
+            if (removeArr.length > 0) {
                 let removeInfo = `确定要删除定额 “${removeCodes.join(',')}” 及其下的所有数据吗?`;
                 $('#delRationAlert').find('.modal-body h5').text(removeInfo);
                 $('#delRationAlert').modal('show');
@@ -380,27 +385,27 @@ let rationOprObj = {
     },
     onEnterCell: function (sender, args) {
         let me = rationOprObj;
-        if(me.setting.header[args.col]['dataCode'] === 'unit' || me.lastCol.dataCode === 'unit'){
+        if (me.setting.header[args.col]['dataCode'] === 'unit' || me.lastCol.dataCode === 'unit') {
             args.sheet.repaint();
         }
         me.cellRowIdx = args.row;
         let isHasData = false;
-        if(me.addRationItem){
-            for(let i=0; i<me.setting.header.length; i++){
-                if(me.addRationItem[me.setting.header[i].dataCode]){
+        if (me.addRationItem) {
+            for (let i = 0; i < me.setting.header.length; i++) {
+                if (me.addRationItem[me.setting.header[i].dataCode]) {
                     isHasData = true;
                     break;
                 }
             }
         }
-        if(isHasData){
-            if(me.editingRowIdx !== me.cellRowIdx) {
+        if (isHasData) {
+            if (me.editingRowIdx !== me.cellRowIdx) {
                 let focusToCol = !me.addRationItem.code ? 0 : -1;
-                if(focusToCol !== -1){
+                if (focusToCol !== -1) {
                     $('#rationAlertBtn').click();
                     $('#rationAlertCac').click(function () {
                         me.addRationItem = null;
-                        for(let col=0; col<me.setting.header.length; col++){
+                        for (let col = 0; col < me.setting.header.length; col++) {
                             me.workBook.getSheet(0).getCell(me.editingRowIdx, col).value('');
                         }
                     });
@@ -414,12 +419,12 @@ let rationOprObj = {
             }
         }
     },
-    onCellEditStart: function(sender, args) {
+    onCellEditStart: function (sender, args) {
         let me = rationOprObj;
-        if(!me.canRations || me.setting.view.lockColumns.indexOf(args.col) !== -1){
+        if (!me.canRations || me.setting.view.lockColumns.indexOf(args.col) !== -1) {
             args.cancel = true;
         }
-        else{
+        else {
             let rObj = sheetsOprObj.combineRationRowData(me.workBook.getSheet(0), me.setting, args.row);
             me.currentEditingRation = rObj;
             let cacheSection = me.getCache();
@@ -433,12 +438,12 @@ let rationOprObj = {
             }
         }
     },
-    onCellEditEnd: function(sender, args) {
+    onCellEditEnd: function (sender, args) {
         let me = rationOprObj;
         // 输入编号、名称、单位时,如果输入回车符或粘贴回车符,提交时应转换为空格。
         let dataCode = me.setting.header[args.col].dataCode;
         let deESCFields = ['code', 'name', 'unit'];
-        if(deESCFields.includes(dataCode)){
+        if (deESCFields.includes(dataCode)) {
             args.editingText = me.isDef(args.editingText) ? args.editingText.toString().replace(/[\r\n]/g, ' ') : '';
             args.sheet.setValue(args.row, args.col, args.editingText);
         }
@@ -447,51 +452,52 @@ let rationOprObj = {
             addArr = [];
         me.editingRowIdx = args.row;
         if (me.currentEditingRation["ID"]) {
-            if((!args.editingText || args.editingText.toString().trim().length === 0) && args.col === 0){
+            if ((!args.editingText || args.editingText.toString().trim().length === 0) && args.col === 0) {
                 args.sheet.setValue(args.row, args.col, me.currentEditingRation[dataCode] + '');
             }
             else {
                 rObj["ID"] = me.currentEditingRation["ID"];
-                if(me.currentEditingRation[dataCode] !== rObj[dataCode]){
+                if (me.currentEditingRation[dataCode] !== rObj[dataCode]) {
                     me.addRationItem = rObj;
-                    if(dataCode === 'code'){
-                        if(me.rationsCodes.indexOf(rObj.code.toString()) === -1){
+                    if (dataCode === 'code') {
+                        if (me.rationsCodes.indexOf(rObj.code.toString()) === -1) {
                             me.rationsCodes.splice(me.rationsCodes.indexOf(rObj.code.toString()), 1);
                             me.rationsCodes.push(rObj.code.toString());
                             updateArr.push(rObj);
                         }
-                        else{
+                        else {
                             alert("编码已存在!");
                             args.sheet.setValue(args.row, args.col, me.currentEditingRation[dataCode]);
 
                         }
                     }
-                    else if (dataCode === 'feeType') {//取费专业控制为整数    
-                        if(me.isInt(rObj[dataCode])){
+                    else if (dataCode === 'feeType') {
+                        updateArr.push(rObj);
+                        /* if (me.isInt(rObj[dataCode])) {
                             updateArr.push(rObj);
                         }
                         else {
                             rObj[dataCode] = '';
                             args.sheet.setValue(args.row, args.col, typeof me.currentEditingRation[dataCode] !== 'undefined' && me.currentEditingRation[dataCode] ? me.currentEditingRation[dataCode] : '');
-                        }
+                        } */
                     }
-                    else{
+                    else {
                         updateArr.push(rObj);
                     }
                 }
             }
         }
-        else if(!me.currentEditingRation["ID"]) {
+        else if (!me.currentEditingRation["ID"]) {
             if (!sheetCommonObj.chkIfEmpty(rObj, me.setting)) {
                 //addArr.push(rObj);
                 me.addRationItem = rObj;
-                if(rObj.code && rObj.code.toString().trim().length > 0){
-                    if(me.rationsCodes.indexOf(rObj.code.toString()) === -1){
+                if (rObj.code && rObj.code.toString().trim().length > 0) {
+                    if (me.rationsCodes.indexOf(rObj.code.toString()) === -1) {
                         //jobContent
-                        if(jobContentOprObj && jobContentOprObj.currentSituation === jobContentOprObj.situations.ALL){
+                        if (jobContentOprObj && jobContentOprObj.currentSituation === jobContentOprObj.situations.ALL) {
                             rObj.jobContent = jobContentOprObj.currentJobContent ? jobContentOprObj.currentJobContent : '';
                         }
-                        if(annotationOprObj && annotationOprObj.currentSituation === annotationOprObj.situations.ALL){
+                        if (annotationOprObj && annotationOprObj.currentSituation === annotationOprObj.situations.ALL) {
                             rObj.annotation = annotationOprObj.currentAnnotation ? annotationOprObj.currentAnnotation : '';
                         }
                         me.setInitPrc(rObj);
@@ -499,12 +505,12 @@ let rationOprObj = {
                         me.rationsCodes.push(rObj.code.toString());
                         me.addRationItem = null;
                     }
-                    else{
+                    else {
                         alert('编码已存在!');
                         me.workBook.getSheet(0).setValue(args.row, args.col, '');
                     }
                 }
-                else if(rObj.code && rObj.code.toString.trim().length === 0){
+                else if (rObj.code && rObj.code.toString.trim().length === 0) {
                     me.workBook.getSheet(0).setValue(args.row, args.col, '');
                 }
             }
@@ -517,20 +523,20 @@ let rationOprObj = {
     },
     canPasted: function (beginCol, maxCol) {
         let rst = false;
-        if(maxCol < 3 || beginCol > 6){
+        if (maxCol < 3 || beginCol > 6) {
             rst = true;
         }
         return rst;
     },
-    onClipboardPasting: function(sender, args) {
+    onClipboardPasting: function (sender, args) {
         let me = rationOprObj;
-        let maxCol = args.cellRange.col + args.cellRange.colCount -1;
-        if(!me.canRations || !me.canPasted(args.cellRange.col, maxCol) || maxCol > me.setting.header.length - 1){
+        let maxCol = args.cellRange.col + args.cellRange.colCount - 1;
+        if (!me.canRations || !me.canPasted(args.cellRange.col, maxCol) || maxCol > me.setting.header.length - 1) {
             args.cancel = true;
         }
     },
     //todo: overwrite?
-    onClipboardPasted: function(e, info) {
+    onClipboardPasted: function (e, info) {
         console.log('cp');
         let me = rationOprObj;
         let cacheSection = me.getCache();
@@ -539,80 +545,80 @@ let rationOprObj = {
         for (let i = 0; i < items.length; i++) {
             let rowIdx = info.cellRange.row + i;
             if (cacheSection) {
-              /*  if(!me.isValidUnit(items[i], rationUnits)){//无效单位
-                    items[i].unit = rowIdx < cacheSection.length  && typeof cacheSection[rowIdx].unit !== 'undefined' ? cacheSection[rowIdx].unit : '';
-                }*/
-                if(!cacheSection[rowIdx] && info.cellRange.col === 0 ){
-                    if(me.rationsCodes.indexOf(items[i].code.toString()) === -1){
+                /*  if(!me.isValidUnit(items[i], rationUnits)){//无效单位
+                      items[i].unit = rowIdx < cacheSection.length  && typeof cacheSection[rowIdx].unit !== 'undefined' ? cacheSection[rowIdx].unit : '';
+                  }*/
+                if (!cacheSection[rowIdx] && info.cellRange.col === 0) {
+                    if (me.rationsCodes.indexOf(items[i].code.toString()) === -1) {
                         //jobConten
-                        if(jobContentOprObj && jobContentOprObj.currentSituation === jobContentOprObj.situations.ALL){
+                        if (jobContentOprObj && jobContentOprObj.currentSituation === jobContentOprObj.situations.ALL) {
                             items[i].jobContent = jobContentOprObj.currentJobContent ? jobContentOprObj.currentJobContent : '';
                         }
-                        if(annotationOprObj && annotationOprObj.currentSituation === annotationOprObj.situations.ALL){
+                        if (annotationOprObj && annotationOprObj.currentSituation === annotationOprObj.situations.ALL) {
                             items[i].annotation = annotationOprObj.currentAnnotation ? annotationOprObj.currentAnnotation : '';
                         }
                         me.setInitPrc(items[i]);
                         addArr.push(items[i]);
                         me.rationsCodes.push(items[i].code.toString());
                     }
-                    else{
+                    else {
                         me.workBook.getSheet(0).setValue(rowIdx, 0, '');
                     }
                 }
-                else if(cacheSection[rowIdx]){
-                    for(let col = 0; col < me.setting.header.length; col++){
-                        if(!items[i][me.setting.header[col].dataCode] && typeof cacheSection[rowIdx][me.setting.header[col].dataCode] !== 'undefined'){
+                else if (cacheSection[rowIdx]) {
+                    for (let col = 0; col < me.setting.header.length; col++) {
+                        if (!items[i][me.setting.header[col].dataCode] && typeof cacheSection[rowIdx][me.setting.header[col].dataCode] !== 'undefined') {
                             items[i][me.setting.header[col].dataCode] = cacheSection[rowIdx][me.setting.header[col].dataCode];
                         }
                     }
-                    if(items[i].feeType && !me.isInt(items[i].feeType)){
+                    if (items[i].feeType && !me.isInt(items[i].feeType)) {
                         items[i].feeType = '';
                         me.workBook.getSheet(0).setValue(rowIdx, 8, '');
                     }
-                    if(info.cellRange.col === 0){
-                        if(me.rationsCodes.indexOf(items[i].code.toString()) === -1){
+                    if (info.cellRange.col === 0) {
+                        if (me.rationsCodes.indexOf(items[i].code.toString()) === -1) {
                             items[i].ID = cacheSection[rowIdx].ID;
                             updateArr.push(items[i]);
                         }
-                        else{
+                        else {
                             me.workBook.getSheet(0).setValue(rowIdx, 0, cacheSection[rowIdx].code);
                         }
                     }
-                    else{
+                    else {
                         items[i].ID = cacheSection[rowIdx].ID;
                         updateArr.push(items[i]);
                     }
                 }
 
             } else {
-               /* if(!me.isValidUnit(items[i], rationUnits)){//无效单位
-                    items[i].unit = '';
-                }*/
+                /* if(!me.isValidUnit(items[i], rationUnits)){//无效单位
+                     items[i].unit = '';
+                 }*/
                 //add
-                if(info.cellRange.col === 0){
+                if (info.cellRange.col === 0) {
                     //是否含有已存在的编号
-                        if(me.rationsCodes.indexOf(items[i].code.toString()) === -1){
-                            //jobConten
-                            if(jobContentOprObj && jobContentOprObj.currentSituation === jobContentOprObj.situations.ALL){
-                                items[i].jobContent = jobContentOprObj.currentJobContent ? jobContentOprObj.currentJobContent : '';
-                            }
-                            if(annotationOprObj && annotationOprObj.currentSituation === annotationOprObj.situations.ALL){
-                                items[i].annotation = annotationOprObj.currentAnnotation ? annotationOprObj.currentAnnotation : '';
-                            }
-                            me.setInitPrc(items[i]);
-                            addArr.push(items[i]);
+                    if (me.rationsCodes.indexOf(items[i].code.toString()) === -1) {
+                        //jobConten
+                        if (jobContentOprObj && jobContentOprObj.currentSituation === jobContentOprObj.situations.ALL) {
+                            items[i].jobContent = jobContentOprObj.currentJobContent ? jobContentOprObj.currentJobContent : '';
                         }
+                        if (annotationOprObj && annotationOprObj.currentSituation === annotationOprObj.situations.ALL) {
+                            items[i].annotation = annotationOprObj.currentAnnotation ? annotationOprObj.currentAnnotation : '';
+                        }
+                        me.setInitPrc(items[i]);
+                        addArr.push(items[i]);
+                    }
                 }
             }
         };
-         if (updateArr.length > 0 || addArr.length > 0) {
-             console.log(updateArr);
-             me.mixUpdate = 1;
+        if (updateArr.length > 0 || addArr.length > 0) {
+            console.log(updateArr);
+            me.mixUpdate = 1;
             me.mixUpdateRequest(updateArr, addArr, []);
         }
-        else{
-             me.getRationItems(me.currentSectionId);
-         }
+        else {
+            me.getRationItems(me.currentSectionId);
+        }
     },
     setInitPrc: function (obj) {
         obj.labourPrice = 0;
@@ -622,22 +628,22 @@ let rationOprObj = {
     },
     isValidUnit: function (rationObj, validUnits) {
         let rst = true;
-        if(typeof rationObj.unit !== 'undefined' && rationObj.unit && validUnits.indexOf(rationObj.unit) === -1){//无效
+        if (typeof rationObj.unit !== 'undefined' && rationObj.unit && validUnits.indexOf(rationObj.unit) === -1) {//无效
             rst = false;
         }
         return rst;
     },
-    mixUpdateRequest: function(updateArr, addArr, removeIds, callback) {
+    mixUpdateRequest: function (updateArr, addArr, removeIds, callback) {
         let me = rationOprObj;
         me.saveInString(updateArr);
         $.ajax({
-            type:"POST",
-            url:"api/mixUpdateRationItems",
-            data:{"rationLibId": getQueryString("repository"), "lastOpr": userAccount, "sectionID": me.currentSectionId, "updateItems": JSON.stringify(updateArr), "addItems": JSON.stringify(addArr), "removeIds": JSON.stringify(removeIds)},
-            dataType:"json",
-            cache:false,
-            timeout:20000,
-            success:function(result){
+            type: "POST",
+            url: "api/mixUpdateRationItems",
+            data: { "rationLibId": getQueryString("repository"), "lastOpr": userAccount, "sectionID": me.currentSectionId, "updateItems": JSON.stringify(updateArr), "addItems": JSON.stringify(addArr), "removeIds": JSON.stringify(removeIds) },
+            dataType: "json",
+            cache: false,
+            timeout: 20000,
+            success: function (result) {
                 if (result.error) {
                     alert('error');
                     me.getRationItems(me.currentSectionId);
@@ -655,24 +661,24 @@ let rationOprObj = {
                     me.rationSelInit(curRow);
                     //add
                     //jobContent
-                    if(jobContentOprObj ){
+                    if (jobContentOprObj) {
                         jobContentOprObj.currentRationItems = cacheSection;
                         jobContentOprObj.setRadiosDisabled(cacheSection.length > 0 ? false : true, jobContentOprObj.radios);
-                        if(cacheSection.length === 0){
+                        if (cacheSection.length === 0) {
                             jobContentOprObj.updateSituation(pageOprObj.rationLibId, me.currentSectionId, 'NONE');
                         }
                         jobContentOprObj.setRadiosChecked(jobContentOprObj.currentSituation, jobContentOprObj.radios);
-                        if(jobContentOprObj.currentSituation === jobContentOprObj.situations.PARTIAL){
+                        if (jobContentOprObj.currentSituation === jobContentOprObj.situations.PARTIAL) {
                             jobContentOprObj.buildTablePartial(jobContentOprObj.tablePartial, jobContentOprObj.getGroup(cacheSection));
                         }
                     }
-                    if(annotationOprObj ){
+                    if (annotationOprObj) {
                         annotationOprObj.setRadiosDisabled(cacheSection.length > 0 ? false : true, annotationOprObj.radios);
-                        if(cacheSection.length === 0){
+                        if (cacheSection.length === 0) {
                             annotationOprObj.updateAnnoSituation(pageOprObj.rationLibId, me.currentSectionId, 'NONE');
                         }
                         annotationOprObj.setRadiosChecked(annotationOprObj.currentSituation, annotationOprObj.radios);
-                        if(annotationOprObj.currentSituation === annotationOprObj.situations.PARTIAL){
+                        if (annotationOprObj.currentSituation === annotationOprObj.situations.PARTIAL) {
                             annotationOprObj.buildTablePartial(annotationOprObj.fzTablePartial, annotationOprObj.getGroup(cacheSection));
                         }
                     }
@@ -681,14 +687,14 @@ let rationOprObj = {
                     me.mixDel = 0;
                 }
                 me.workBook.focus(true);
-                if(callback) callback();
+                if (callback) callback();
             },
-            error:function(){
+            error: function () {
             }
         });
     },
     doAfterGetRation: null,
-    getRationItems: function(sectionID, callback = null){
+    getRationItems: function (sectionID, callback = null) {
         if (sectionID != -1) {
             let me = rationOprObj;
             me.mixUpdate = 0;
@@ -706,13 +712,13 @@ let rationOprObj = {
                 }
             } else */{
                 $.ajax({
-                    type:"POST",
-                    url:"api/getRationItems",
-                    data:{"rationRepId": pageOprObj.rationLibId, "sectionID": sectionID},
-                    dataType:"json",
-                    cache:false,
-                    timeout:10000,
-                    success:function(result){
+                    type: "POST",
+                    url: "api/getRationItems",
+                    data: { "rationRepId": pageOprObj.rationLibId, "sectionID": sectionID },
+                    dataType: "json",
+                    cache: false,
+                    timeout: 10000,
+                    success: function (result) {
                         if (result) {
                             me.currentRations["_SEC_ID_" + sectionID] = result.data;
                             me.sortByCode(me.currentRations["_SEC_ID_" + sectionID]);
@@ -726,11 +732,11 @@ let rationOprObj = {
                         if (!locked) {
                             sectionTreeObj.removeBtn.removeClass('disabled');
                         }
-                        if(callback) {
+                        if (callback) {
                             callback(result.data);
                         }
                     },
-                    error:function(err){
+                    error: function (err) {
                         sectionTreeObj.removeBtn.removeClass('disabled');
                         alert(err);
                     }
@@ -738,7 +744,7 @@ let rationOprObj = {
             }
         }
     },
-    showRationItems: function(sectionID){
+    showRationItems: function (sectionID) {
         let me = rationOprObj,
             sheetGLJ = rationGLJOprObj.sheet, settingGLJ = rationGLJOprObj.setting,
             sheetCoe = rationCoeOprObj.sheet, settingCoe = rationCoeOprObj.setting,
@@ -749,7 +755,7 @@ let rationOprObj = {
             if (me.currentRations && me.currentRations["_SEC_ID_" + sectionID]) {
                 let cacheSection = me.currentRations["_SEC_ID_" + sectionID];
                 sheetsOprObj.showData(me.workBook.getSheet(0), me.setting, cacheSection);
-                if(me.mixDel === 1){
+                if (me.mixDel === 1) {
                     let row = me.workBook.getSheet(0).getSelections()[0].row;
                     if (cacheSection && row < cacheSection.length) {
                         sheetCommonObj.cleanData(sheetGLJ, settingGLJ, -1);
@@ -780,12 +786,12 @@ let rationOprObj = {
                 sheetCommonObj.cleanSheet(sheetAss, settingAss, -1);
                 sheetCommonObj.cleanSheet(sheetInst, settingInst, -1);
             }
-           //--- me.workBook.focus(true);
+            //--- me.workBook.focus(true);
         }
         sectionTreeObj.workBook.focus(true);
     },
-    sortByCode: function(arr){
-        function recurCompare(a, b, index){
+    sortByCode: function (arr) {
+        function recurCompare(a, b, index) {
             if (a[index] && !b[index]) {
                 return 1;
             } else if (!a[index] && b[index]) {
@@ -816,25 +822,25 @@ let rationOprObj = {
             return recurCompare(aArr, bArr, 0);
         });
     },
-    saveInString(datas){
-        for(let i = 0, len = datas.length; i < len; i++){
+    saveInString(datas) {
+        for (let i = 0, len = datas.length; i < len; i++) {
             let data = datas[i];
-            if(data.labourPrice !== undefined && data.labourPrice){
+            if (data.labourPrice !== undefined && data.labourPrice) {
                 data.labourPrice = data.labourPrice.toString();
             }
-            if(data.materialPrice !== undefined && data.materialPrice){
+            if (data.materialPrice !== undefined && data.materialPrice) {
                 data.materialPrice = data.materialPrice.toString();
             }
-            if(data.machinePrice !== undefined && data.machinePrice){
+            if (data.machinePrice !== undefined && data.machinePrice) {
                 data.machinePrice = data.machinePrice.toString();
             }
-            if(data.basePrice !== undefined && data.basePrice){
+            if (data.basePrice !== undefined && data.basePrice) {
                 data.basePrice = data.basePrice.toString();
             }
-            if(data.rationGljList !== undefined && data.rationGljList && data.rationGljList.length > 0){
-                for(let j = 0, jLen = data.rationGljList.length; j < jLen; j++){
+            if (data.rationGljList !== undefined && data.rationGljList && data.rationGljList.length > 0) {
+                for (let j = 0, jLen = data.rationGljList.length; j < jLen; j++) {
                     let raGljObj = data.rationGljList[j];
-                    if(raGljObj.consumeAmt !== undefined && raGljObj.consumeAmt){
+                    if (raGljObj.consumeAmt !== undefined && raGljObj.consumeAmt) {
                         raGljObj.consumeAmt = raGljObj.consumeAmt.toString();
                     }
                 }

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

@@ -327,7 +327,7 @@ var rationCoeOprObj = {
                     sheetCommonObj.cleanData(me.sheet, me.setting, -1);
                     if (result.data) {
                         var tempResult = [];
-                        let stdMap = _.indexBy(result.data,'ID');
+                        let stdMap = _.keyBy(result.data,'ID');
                         for(let i = 0, len = coeList.length; i < len; i++){
                             let obj = stdMap[coeList[i].ID];
                             if(obj){

+ 99 - 100
web/maintain/ration_repository/js/section_tree.js

@@ -6,10 +6,10 @@ const moduleName = 'stdRation';
 //上下拖动div节点的高度
 const verticalResize = 10;
 let pageOprObj = {
-    rationLibName : null,
-    rationLibId : null,
+    rationLibName: null,
+    rationLibId: null,
     gljLibId: null,
-    initPage : function(libInfo) {
+    initPage: function (libInfo) {
         this.rationLibId = libInfo.ID;
         this.gljLibId = libInfo.gljLib;
         this.rationLibName = libInfo.dispName;
@@ -37,7 +37,7 @@ let sectionTreeObj = {
     controller: null,
     workBook: null,
     sheet: null,
-    updateType: {new: 'new', update: 'update'},
+    updateType: { new: 'new', update: 'update' },
     insertBtn: $('#tree_Insert'),
     removeBtn: $('#tree_remove'),
     upLevelBtn: $('#tree_upLevel'),
@@ -46,7 +46,7 @@ let sectionTreeObj = {
     upMoveBtn: $('#tree_upMove'),
     setting: {
         sheet: {
-            cols:[
+            cols: [
                 {
                     head: {
                         titleNames: ['ID'],
@@ -94,13 +94,13 @@ let sectionTreeObj = {
             rootId: -1
         },
         options: {
-            tabStripVisible:  false,
+            tabStripVisible: false,
             allowContextMenu: false,
-            allowCopyPasteExcelStyle : false,
+            allowCopyPasteExcelStyle: false,
             allowExtendPasteRange: false,
-            allowUserDragDrop : false,
+            allowUserDragDrop: false,
             allowUserDragFill: false,
-            scrollbarMaxAlign : true
+            scrollbarMaxAlign: true
         }
     },
 
@@ -112,7 +112,7 @@ let sectionTreeObj = {
     },
     //sheet things
     setOptions: function (workbook, opts) {
-        for(let opt in opts){
+        for (let opt in opts) {
             workbook.options[opt] = opts[opt];
         }
     },
@@ -120,7 +120,7 @@ let sectionTreeObj = {
     renderFunc: function (sheet, func) {
         sheet.suspendPaint();
         sheet.suspendEvent();
-        if(this.isFunc(func)){
+        if (this.isFunc(func)) {
             func();
         }
         sheet.resumePaint();
@@ -128,9 +128,9 @@ let sectionTreeObj = {
     },
 
     buildSheet: function () {
-        if(!this.isDef(this.workBook)){
-            this.workBook = new GC.Spread.Sheets.Workbook($('#sectionSpread')[0], {sheetCount: 1});
-            sheetCommonObj.bindEscKey(this.workBook, [{sheet: this.workBook.getSheet(0), editStarting: this.onEditStarting, editEnded: this.onEditEnded}]);
+        if (!this.isDef(this.workBook)) {
+            this.workBook = new GC.Spread.Sheets.Workbook($('#sectionSpread')[0], { sheetCount: 1 });
+            sheetCommonObj.bindEscKey(this.workBook, [{ sheet: this.workBook.getSheet(0), editStarting: this.onEditStarting, editEnded: this.onEditEnded }]);
             this.sheet = this.workBook.getActiveSheet();
             this.setOptions(this.workBook, this.setting.options);
             this.sheet.options.clipBoardOptions = GC.Spread.Sheets.ClipboardPasteOptions.values;
@@ -159,7 +159,7 @@ let sectionTreeObj = {
     onEditStarting: function (sender, args) {
         let me = sectionTreeObj;
         let dataCode = me.setting.sheet.cols[args.col]['data']['field'];
-        if(dataCode === 'ID'){
+        if (dataCode === 'ID') {
             args.cancel = true;
         }
     },
@@ -169,7 +169,7 @@ let sectionTreeObj = {
         let postData = [];
         let v = me.isDef(args.editingText) ? args.editingText.toString().trim() : '';
         let node = me.cache[args.row];
-        if(me.isDef(node) && node.data.name !== v){
+        if (me.isDef(node) && node.data.name !== v) {
             let updateObj = me.getUpdateObj(me.updateType.update, node.getID(), null, null, v, null);
             postData.push(updateObj);
             //ajax
@@ -184,37 +184,37 @@ let sectionTreeObj = {
 
     onClipboardPasting: function (sender, info) {
         let me = sectionTreeObj;
-        if(info.cellRange.col === 0){
+        if (info.cellRange.col === 0) {
             info.cancel = true;
         }
     },
 
     onClipboardPasted: function (sender, info) {
         let me = sectionTreeObj;
-        let items = sheetCommonObj.analyzePasteData({header: [{dataCode: 'ID'}, {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++){
+        for (let i = 0, len = items.length; i < len; i++) {
             let row = info.cellRange.row + i;
             let node = me.cache[row];
-            if(me.isDef(node) && me.isDef(items[i].name) && node.data.name !== items[i].name){
+            if (me.isDef(node) && me.isDef(items[i].name) && node.data.name !== items[i].name) {
                 let updateObj = me.getUpdateObj(me.updateType.update, node.getID(), null, null, items[i].name, null);
                 postData.push(updateObj);
-                frontData.push({row: row, name: items[i].name});
+                frontData.push({ row: row, name: items[i].name });
                 node.data.name = items[i].name;
             }
         }
-        if(postData.length > 0){
+        if (postData.length > 0) {
             //ajax
             me.sectionTreeAjax(postData, function (rstData) {
-                for(let i = 0, len = frontData.length; i < len; i++){
+                for (let i = 0, len = frontData.length; i < len; i++) {
                     let node = me.cache[frontData[i]['row']];
-                    if(me.isDef(node)){
+                    if (me.isDef(node)) {
                         node.data.name = frontData[i]['name'];
                     }
                 }
             }, function () {
-                for(let i = 0, len = frontData.length; i < len; i++){
+                for (let i = 0, len = frontData.length; i < len; i++) {
                     let node = me.cache[frontData[i]['row']];
                     me.sheet.setValue(frontData[i]['row'], 1, me.isDef(node) ? node.data.name : '');
                 }
@@ -227,14 +227,14 @@ let sectionTreeObj = {
             let spreadWidth = $('#sectionSpread').width() - 65; //65: 列头宽度和垂直滚动条宽度和
             let IDRate = 40 / spreadWidth,
                 nameRate = 1 - IDRate;
-            sheetCommonObj.setColumnWidthByRate($('#sectionSpread').width() - 65, this.workBook, [{rateWidth: IDRate}, {rateWidth: nameRate}]);
+            sheetCommonObj.setColumnWidthByRate($('#sectionSpread').width() - 65, this.workBook, [{ rateWidth: IDRate }, { rateWidth: nameRate }]);
         }
     },
     buildContextMenu: function () {//右键菜单
         const me = this;
         $.contextMenu({
             selector: '#sectionSpread',
-            build: function($triggerElement, e){
+            build: function ($triggerElement, e) {
                 //控制允许右键菜单在哪个位置出现
                 const target = SheetDataHelper.safeRightClickSelection($triggerElement, e, me.workBook);
                 const sheet = me.workBook.getSheet(0);
@@ -244,7 +244,7 @@ let sectionTreeObj = {
                         me.initSelection(section);
                     }
                     return {
-                        callback: function(){},
+                        callback: function () { },
                         items: {
                             "setManage": {
                                 name: "设置管理费率",
@@ -295,7 +295,7 @@ let sectionTreeObj = {
         this.controller.showTreeData();
         this.sheet.setFormatter(-1, 0, '@');
         this.initSelection(this.tree.selected);
-        explanatoryOprObj.bindEvents(explanatoryOprObj.exEditor, explanatoryOprObj.calcEditor);
+        explanatoryOprObj.bindEvents(explanatoryOprObj.exEditor, explanatoryOprObj.erratumEditor, explanatoryOprObj.calcEditor);
         this.loadRateWidth();
         this.autoLocate();
     },
@@ -317,7 +317,7 @@ let sectionTreeObj = {
     initController: function (tree, sheet, setting) {
         this.controller = TREE_SHEET_CONTROLLER.createNew(tree, sheet, setting);
     },
-    
+
     refreshBtn: function (selected) {
         if (locked) {
             return;
@@ -329,7 +329,7 @@ let sectionTreeObj = {
         me.downLevelBtn.removeClass('disabled');
         me.downMoveBtn.removeClass('disabled');
         me.upMoveBtn.removeClass('disabled');
-        if(!me.isDef(selected)){
+        if (!me.isDef(selected)) {
             me.removeBtn.addClass('disabled');
             me.upLevelBtn.addClass('disabled');
             me.downLevelBtn.addClass('disabled');
@@ -337,26 +337,26 @@ let sectionTreeObj = {
             me.upMoveBtn.addClass('disabled');
         }
         else {
-            if(!me.isDef(selected.preSibling)){
+            if (!me.isDef(selected.preSibling)) {
                 me.downLevelBtn.addClass('disabled');
                 me.upMoveBtn.addClass('disabled');
             }
-            if(!me.isDef(selected.nextSibling)){
+            if (!me.isDef(selected.nextSibling)) {
                 me.downMoveBtn.addClass('disabled');
             }
-            if(!me.isDef(selected.parent)){
+            if (!me.isDef(selected.parent)) {
                 me.upLevelBtn.addClass('disabled');
             }
         }
     },
-    
+
     bindBtn: function () {
         let me = this;
         me.insertBtn.click(function () {
             me.insert();
         });
         $('#delConfirm').click(function () {
-            if(me.canRemoveSection){
+            if (me.canRemoveSection) {
                 me.remove(me.tree.selected);
             }
             else {
@@ -366,12 +366,12 @@ let sectionTreeObj = {
         me.removeBtn.click(function () {
             //不可删除有子节点或有定额数据的节点
             let section = me.cache[me.workBook.getActiveSheet().getActiveRowIndex()];
-            if(!section){
+            if (!section) {
                 return;
             }
             let sectionName = me.isDef(section.data.name) ? section.data.name : '';
             let sectionRations = rationOprObj.currentRations[`_SEC_ID_${section.data.ID}`];
-            if(section.children.length > 0 || (sectionRations && sectionRations.length > 0)){
+            if (section.children.length > 0 || (sectionRations && sectionRations.length > 0)) {
                 me.canRemoveSection = false;
                 $('#delAlert').find('.modal-body h5').text('当前节点下有数据,不可删除。');
             }
@@ -413,8 +413,8 @@ let sectionTreeObj = {
             });
         });
 
-           // 设置默认工作内容,设置给其下所有定额
-           $('#set-job-content-confirm').click(function () {
+        // 设置默认工作内容,设置给其下所有定额
+        $('#set-job-content-confirm').click(function () {
             $.bootstrapLoading.start();
             const jobContentText = $('#default-job-content').val();
             const section = me.tree.selected;
@@ -439,22 +439,22 @@ let sectionTreeObj = {
         me.insertBtn.addClass('disabled');
         let postData = [];
         CommonAjax.post('api/getNewRationTreeID', {}, function (newID) {
-            if(!me.isDef(newID)){
+            if (!me.isDef(newID)) {
                 return;
             }
             me.tree.maxNodeID(newID - 1);
             let selected = me.tree.selected;
             let insertObj = me.getUpdateObj(me.updateType.new, newID, -1, -1, '', null);
-            if(me.isDef(selected)) {
+            if (me.isDef(selected)) {
                 let updateObj = me.getUpdateObj(me.updateType.update, selected.getID(), newID, null, null, null);
                 postData.push(updateObj);
                 insertObj.updateData.ParentID = selected.getParentID();
-                if(me.isDef(selected.nextSibling)){
+                if (me.isDef(selected.nextSibling)) {
                     insertObj.updateData.NextSiblingID = selected.getNextSiblingID();
                 }
             }
             postData.push(insertObj);
-            if(postData.length > 0){
+            if (postData.length > 0) {
                 //ajax
                 me.sectionTreeAjax(postData, function (rstData) {
                     me.controller.insert();
@@ -471,31 +471,31 @@ let sectionTreeObj = {
         let me = this;
         me.removeBtn.addClass('disabled');
         let postData = [], IDs = [];
-        if(!selected){
+        if (!selected) {
             return;
         }
         getDelIds(selected);
-        function getDelIds(node){
-            if(me.isDef(node)){
+        function getDelIds(node) {
+            if (me.isDef(node)) {
                 IDs.push(node.getID());
-                if(node.children.length > 0){
-                    for(let i = 0, len = node.children.length; i < len; i++){
+                if (node.children.length > 0) {
+                    for (let i = 0, len = node.children.length; i < len; i++) {
                         getDelIds(node.children[i]);
                     }
                 }
             }
         }
-        if(me.isDef(selected.preSibling)){
+        if (me.isDef(selected.preSibling)) {
             let updateObj = me.getUpdateObj(me.updateType.update, selected.preSibling.getID(), selected.getNextSiblingID(), null, null, null);
             postData.push(updateObj);
         }
-        if(IDs.length > 0){
-            for(let i = 0, len = IDs.length; i < len; i++){
+        if (IDs.length > 0) {
+            for (let i = 0, len = IDs.length; i < len; i++) {
                 let delObj = me.getUpdateObj(me.updateType.update, IDs[i], null, null, null, true);
                 postData.push(delObj);
             }
         }
-        if(postData.length > 0){
+        if (postData.length > 0) {
             //ajax
             me.sectionTreeAjax(postData, function (rstData) {
                 $('#delAlert').modal('hide');
@@ -509,17 +509,17 @@ let sectionTreeObj = {
         }
     },
     removeRationsCodes: function (rations) {
-        for(let ration of rations){
+        for (let ration of rations) {
             rationOprObj.rationsCodes.splice(rationOprObj.rationsCodes.indexOf(ration.code), 1);
         }
     },
-    getSameDepthNodes: function(){
+    getSameDepthNodes: function () {
         let rst = [];
         let sel = this.sheet.getSelections()[0];
         let selectedDepth = this.tree.selected.depth();
-        for(let i = 0; i < sel.rowCount; i++){
+        for (let i = 0; i < sel.rowCount; i++) {
             let row = sel.row + i;
-            if(this.cache[row].depth() === selectedDepth){
+            if (this.cache[row].depth() === selectedDepth) {
                 rst.push(this.cache[row]);
             }
         }
@@ -530,42 +530,42 @@ let sectionTreeObj = {
         me.upLevelBtn.addClass('disabled');
         let postData = [];
         let selNodes = me.getSameDepthNodes();
-        if(selNodes.length <= 0){
-            return ;
+        if (selNodes.length <= 0) {
+            return;
         }
         let firstParent = selNodes[0].parent;
-        if(!me.isDef(firstParent)){
+        if (!me.isDef(firstParent)) {
             return;
         }
         //更新父节点
         postData.push(me.getUpdateObj(me.updateType.update, firstParent.getID(), selNodes[0].getID(), null, null, null));
         //更新前节点
-        if(me.isDef(selNodes[0].preSibling)){
+        if (me.isDef(selNodes[0].preSibling)) {
             postData.push(me.getUpdateObj(me.updateType.update, selNodes[0].preSibling.getID(), -1, null, null, null));
         }
         //更新选中节点的后兄弟节点
         let lastSelNode = selNodes[selNodes.length - 1];
         let nextIDs = [];
         getNext(lastSelNode);
-        function getNext(node){
-            if(me.isDef(node.nextSibling)){
+        function getNext(node) {
+            if (me.isDef(node.nextSibling)) {
                 nextIDs.push(node.getNextSiblingID());
                 getNext(node.nextSibling);
             }
         }
-        for(let nextID of nextIDs){
+        for (let nextID of nextIDs) {
             postData.push(me.getUpdateObj(me.updateType.update, nextID, null, lastSelNode.getID(), null, null));
         }
         //更新选中节点
-        for(let i = 0; i < selNodes.length; i++){
+        for (let i = 0; i < selNodes.length; i++) {
             let selNode = selNodes[i];
             let nid = i === selNodes.length - 1 ? firstParent.getNextSiblingID() : selNode.getNextSiblingID();
             postData.push(me.getUpdateObj(me.updateType.update, selNode.getID(), nid, firstParent.getParentID(), null, null));
         }
-        if(postData.length > 0){
+        if (postData.length > 0) {
             //ajax
             me.sectionTreeAjax(postData, function (rstData) {
-                for(let selNode of selNodes){
+                for (let selNode of selNodes) {
                     me.controller.setTreeSelected(selNode);
                     me.controller.upLevel();
                 }
@@ -579,28 +579,28 @@ let sectionTreeObj = {
         me.downLevelBtn.addClass('disabled');
         let postData = [];
         let selNodes = me.getSameDepthNodes();
-        if(selNodes.length <= 0 ){
+        if (selNodes.length <= 0) {
             return;
         }
         let firstPreSibling = selNodes[0].preSibling;
-        if(!me.isDef(firstPreSibling)){
+        if (!me.isDef(firstPreSibling)) {
             return;
         }
         //更新前节点
         postData.push(me.getUpdateObj(me.updateType.update, firstPreSibling.getID(), selNodes[selNodes.length - 1].getNextSiblingID(), null, null, null));
         //更新前节点最末子节点
-        if(firstPreSibling.children.length > 0){
+        if (firstPreSibling.children.length > 0) {
             postData.push(me.getUpdateObj(me.updateType.update, firstPreSibling.children[firstPreSibling.children.length - 1].getID(), selNodes[0].getID(), null, null, null));
         }
         //更新选中节点
-        for(let i = 0; i < selNodes.length; i++){
+        for (let i = 0; i < selNodes.length; i++) {
             let selNode = selNodes[i];
             postData.push(me.getUpdateObj(me.updateType.update, selNode.getID(), i === selNodes.length - 1 ? -1 : selNode.getNextSiblingID(), firstPreSibling.getID(), null, null));
         }
-        if(postData.length > 0){
+        if (postData.length > 0) {
             //ajax
             me.sectionTreeAjax(postData, function (rstData) {
-                for(let selNode of selNodes){
+                for (let selNode of selNodes) {
                     me.controller.setTreeSelected(selNode);
                     me.controller.downLevel();
                 }
@@ -613,21 +613,21 @@ let sectionTreeObj = {
         let me = this;
         me.upMoveBtn.addClass('disabled');
         let postData = [];
-        if(!me.isDef(selected)){
+        if (!me.isDef(selected)) {
             return;
         }
-        if(!me.isDef(selected.preSibling)){
+        if (!me.isDef(selected.preSibling)) {
             return;
         }
         let updateObj = me.getUpdateObj(me.updateType.update, selected.getID(), selected.preSibling.getID(), null, null, null);
         postData.push(updateObj);
         let updatePre = me.getUpdateObj(me.updateType.update, selected.preSibling.getID(), selected.getNextSiblingID(), null, null, null);
         postData.push(updatePre);
-        if(me.isDef(selected.preSibling.preSibling)){
+        if (me.isDef(selected.preSibling.preSibling)) {
             let updatePrepre = me.getUpdateObj(me.updateType.update, selected.preSibling.preSibling.getID(), selected.getID(), null, null, null);
             postData.push(updatePrepre);
         }
-        if(postData.length > 0){
+        if (postData.length > 0) {
             //ajax
             me.sectionTreeAjax(postData, function (rstData) {
                 me.controller.upMove();
@@ -640,13 +640,13 @@ let sectionTreeObj = {
         let me = this;
         me.downMoveBtn.addClass('disabled');
         let postData = [];
-        if(!me.isDef(selected)){
+        if (!me.isDef(selected)) {
             return;
         }
-        if(!me.isDef(selected.nextSibling)){
+        if (!me.isDef(selected.nextSibling)) {
             return;
         }
-        if(me.isDef(selected.preSibling)){
+        if (me.isDef(selected.preSibling)) {
             let updatePre = me.getUpdateObj(me.updateType.update, selected.preSibling.getID(), selected.getNextSiblingID(), null, null, null);
             postData.push(updatePre);
         }
@@ -654,7 +654,7 @@ let sectionTreeObj = {
         postData.push(updateObj);
         let updateNext = me.getUpdateObj(me.updateType.update, selected.getNextSiblingID(), selected.getID(), null, null, null);
         postData.push(updateNext);
-        if(postData.length > 0){
+        if (postData.length > 0) {
             //ajax
             me.sectionTreeAjax(postData, function (rstData) {
                 me.controller.downMove();
@@ -668,50 +668,49 @@ let sectionTreeObj = {
         updateObj.updateType = '';
         updateObj.updateData = Object.create(null);
         updateObj.updateData.rationRepId = pageOprObj.rationLibId;
-        if(this.isDef(updateType)){
+        if (this.isDef(updateType)) {
             updateObj.updateType = updateType;
         }
-        if(this.isDef(id)){
+        if (this.isDef(id)) {
             updateObj.updateData.ID = id;
         }
-        if(this.isDef(nid)){
+        if (this.isDef(nid)) {
             updateObj.updateData.NextSiblingID = nid;
         }
-        if(this.isDef(pid)){
+        if (this.isDef(pid)) {
             updateObj.updateData.ParentID = pid;
         }
-        if(this.isDef(name)){
+        if (this.isDef(name)) {
             updateObj.updateData.name = name;
         }
-        if(this.isDef(deleted)){
+        if (this.isDef(deleted)) {
             updateObj.updateData.isDeleted = true;
         }
         return updateObj;
     },
     sectionTreeAjax: function (postData, scFunc, errFunc) {
-        CommonAjax.post('api/updateNodes', {updateData: postData, lastOpr: userAccount}, scFunc, errFunc);
+        CommonAjax.post('api/updateNodes', { updateData: postData, lastOpr: userAccount }, scFunc, errFunc);
     },
     initTools: function (node) {
-        if(this.isDef(node)){
-            explanatoryOprObj.setAttribute(explanatoryOprObj.currentTreeNode ? explanatoryOprObj.currentTreeNode : node, node, node.data.explanation, node.data.ruleText);
-            //explanatoryOprObj.clickUpdate($('#explanationShow'), $('#ruleTextShow'));
-            explanatoryOprObj.showText(explanatoryOprObj.exEditor, explanatoryOprObj.calcEditor, node.data.explanation, node.data.ruleText);
+        if (this.isDef(node)) {
+            explanatoryOprObj.setAttribute(explanatoryOprObj.currentTreeNode ? explanatoryOprObj.currentTreeNode : node, node, node.data.explanation, node.data.erratumRecord, node.data.ruleText);
+            explanatoryOprObj.showText(node.data.explanation, node.data.erratumRecord, node.data.ruleText);
             //job
-            jobContentOprObj.currentSituation = typeof node.data.jobContentSituation !== 'undefined'? node.data.jobContentSituation : jobContentOprObj.situations.ALL;
+            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.ALL;
+            annotationOprObj.currentSituation = typeof node.data.annotationSituation !== 'undefined' ? node.data.annotationSituation : annotationOprObj.situations.ALL;
             annotationOprObj.clickUpdate($('#fzTxtareaAll'));
         }
     },
     //模仿默认点击
     initSelection: function (node, doAfterGetRation = null) {
-        if (node && node.tree){
+        if (node && node.tree) {
             node.tree.selected = node ? node : null;
         }
         let me = this;
-        if(!me.isDef(node)){
+        if (!me.isDef(node)) {
             sheetCommonObj.cleanSheet(rationOprObj.workBook.getActiveSheet(), rationOprObj.setting, -1);
             sheetCommonObj.cleanSheet(rationGLJOprObj.sheet, rationGLJOprObj.setting, -1);
             sheetCommonObj.cleanSheet(rationAssistOprObj.sheet, rationAssistOprObj.setting, -1);
@@ -722,7 +721,7 @@ let sectionTreeObj = {
         //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){
+        if (!me.isDef(node.children) || node.children.length === 0) {
             //需要根据章节树下是否含有定额数据判断是否可以删除,在异步获取定额数据前将删除按钮无效化
             me.removeBtn.addClass('disabled');
             rationOprObj.canRations = true;
@@ -765,7 +764,7 @@ let sectionTreeObj = {
         $seach.val(rationCode);
         //去后台搜索该定额
         $.bootstrapLoading.start();
-        CommonAjax.post('/rationRepository/api/getRationItem', {rationLibId: pageOprObj.rationLibId, code: rationCode}, function (rstData) {
+        CommonAjax.post('/rationRepository/api/getRationItem', { rationLibId: pageOprObj.rationLibId, code: rationCode }, function (rstData) {
             if (!rstData) {
                 alert(`不存在定额${rationCode}`);
                 $.bootstrapLoading.end();
@@ -787,7 +786,7 @@ let sectionTreeObj = {
             me.sheet.showRow(sectionRow, GC.Spread.Sheets.VerticalPosition.top);
             $.bootstrapLoading.end();
             let doAfterGetRation = function (rations) {
-                let findRation = _.find(rations, {code: rationCode}),
+                let findRation = _.find(rations, { code: rationCode }),
                     rIdx = rations.indexOf(findRation),
                     rationSheet = rationOprObj.workBook.getActiveSheet();
                 rationSheet.setActiveCell(rIdx, 0);
@@ -802,7 +801,7 @@ let sectionTreeObj = {
 };
 $(document).ready(function () {
     $('#rationSearch').keydown(function (event) {
-        if(event.keyCode === 13){
+        if (event.keyCode === 13) {
             $(this).blur();
             let rationCode = $(this).val().toUpperCase();
             if (rationCode) {

+ 48 - 48
web/maintain/ration_repository/js/sheetsOpr.js

@@ -2,7 +2,7 @@
  * Created by Zhong on 2017/9/29.
  */
 let sheetsOprObj = {
-    setAreaAlign: function(area, hAlign, vAlign){
+    setAreaAlign: function (area, hAlign, vAlign) {
         if (!(hAlign) || hAlign === "left") {
             area.hAlign(GC.Spread.Sheets.HorizontalAlign.left);
         } else if (hAlign === "right") {
@@ -22,14 +22,14 @@ let sheetsOprObj = {
             area.vAlign(GC.Spread.Sheets.VerticalAlign.center);
         }
     },
-    showData: function(sheet, setting, data, distTypeTree) {
+    showData: function (sheet, setting, data, distTypeTree) {
         var me = this, ch = GC.Spread.Sheets.SheetArea.viewport;
         sheet.suspendPaint();
         sheet.suspendEvent();
-        if(typeof setting.owner !== 'undefined' && setting.owner === 'gljComponent'){
+        if (typeof setting.owner !== 'undefined' && setting.owner === 'gljComponent') {
             sheet.setRowCount(data.length + 5);
         }
-        else{
+        else {
             sheet.setRowCount(typeof repositoryGljObj !== 'undefined' && repositoryGljObj.currentOprParent === 1 ? data.length : data.length + 10);
         }
         /*if(data.length === 0){
@@ -41,10 +41,10 @@ let sheetsOprObj = {
             var hAlign = "left", vAlign = "center";
             if (setting.header[col].hAlign) {
                 hAlign = setting.header[col].hAlign;
-            } else if (setting.header[col].dataType !== "String"){
+            } else if (setting.header[col].dataType !== "String") {
                 hAlign = "right";
             }
-            vAlign = setting.header[col].vAlign?setting.header[col].vAlign:vAlign;
+            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();
@@ -54,14 +54,14 @@ let sheetsOprObj = {
             }
             for (var row = 0; row < data.length; row++) {
                 //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
-                if(setting.header[col].dataCode === 'gljType' && data[row].gljType){
-                   /* if(typeof repositoryGljObj !== 'undefined' && typeof repositoryGljObj.allowComponent !== 'undefined' && repositoryGljObj.allowComponent.indexOf(data[row].gljType) !== -1){
-                        sheet.getCell(row, 4, GC.Spread.Sheets.SheetArea.viewport).locked(true);
-                    }
-                    else if(typeof repositoryGljObj !== 'undefined' && typeof repositoryGljObj.allowComponent !== 'undefined' && repositoryGljObj.allowComponent.indexOf(data[row].gljType) === -1){
-                        sheet.getCell(row, 4, GC.Spread.Sheets.SheetArea.viewport).locked(false);
-                    }*/
-                    let distTypeVal =  distTypeTree.distTypes[distTypeTree.prefix + data[row].gljType].data.fullName;
+                if (setting.header[col].dataCode === 'gljType' && data[row].gljType) {
+                    /* if(typeof repositoryGljObj !== 'undefined' && typeof repositoryGljObj.allowComponent !== 'undefined' && repositoryGljObj.allowComponent.indexOf(data[row].gljType) !== -1){
+                         sheet.getCell(row, 4, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+                     }
+                     else if(typeof repositoryGljObj !== 'undefined' && typeof repositoryGljObj.allowComponent !== 'undefined' && repositoryGljObj.allowComponent.indexOf(data[row].gljType) === -1){
+                         sheet.getCell(row, 4, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+                     }*/
+                    let distTypeVal = distTypeTree.distTypes[distTypeTree.prefix + data[row].gljType].data.fullName;
                     sheet.setValue(row, col, distTypeVal, ch);
                 }
                 else {
@@ -73,40 +73,40 @@ let sheetsOprObj = {
                     }*/
                 }
             }
-          /*  for(let i = data.length; i < sheet.getRowCount(); i++){
-                sheet.getCell(i, 4, GC.Spread.Sheets.SheetArea.viewport).locked(false);
-            }*/
+            /*  for(let i = data.length; i < sheet.getRowCount(); i++){
+                  sheet.getCell(i, 4, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+              }*/
         }
         sheet.resumeEvent();
         sheet.resumePaint();
         //me.shieldAllCells(sheet);
     },
-    showDataForGljSel: function(sheet, setting, data, distTypeTree) {
+    showDataForGljSel: function (sheet, setting, data, distTypeTree) {
         var me = this, ch = GC.Spread.Sheets.SheetArea.viewport;
         sheet.suspendPaint();
         sheet.suspendEvent();
         let checkBoxType = new GC.Spread.Sheets.CellTypes.CheckBox();
-        if(typeof setting.owner !== 'undefined' && setting.owner === 'gljComponent'){
+        if (typeof setting.owner !== 'undefined' && setting.owner === 'gljComponent') {
             sheet.setRowCount(data.length + 5);
         }
-        else{
+        else {
             sheet.setRowCount(typeof repositoryGljObj !== 'undefined' && repositoryGljObj.currentOprParent === 1 ? data.length : data.length + 10);
         }
         for (var col = 0; col < setting.header.length; col++) {
             var hAlign = "left", vAlign = "center";
             if (setting.header[col].hAlign) {
                 hAlign = setting.header[col].hAlign;
-            } else if (setting.header[col].dataType !== "String"){
+            } else if (setting.header[col].dataType !== "String") {
                 hAlign = "right";
             }
-            vAlign = setting.header[col].vAlign?setting.header[col].vAlign:vAlign;
+            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) {
                 sheet.setFormatter(-1, col, setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
             }
             for (var row = 0; row < data.length; row++) {
-                if(setting.header[col].dataCode === 'gljType' && data[row].gljType){
-                    let distTypeVal =  distTypeTree.distTypes[distTypeTree.prefix + data[row].gljType].data.fullName;
+                if (setting.header[col].dataCode === 'gljType' && data[row].gljType) {
+                    let distTypeVal = distTypeTree.distTypes[distTypeTree.prefix + data[row].gljType].data.fullName;
                     sheet.setValue(row, col, distTypeVal, ch);
                 }
                 else {
@@ -114,19 +114,19 @@ let sheetsOprObj = {
                     sheet.setTag(row, 0, data[row].ID, ch);
                 }
                 //复选框
-                if(setting.header[col].dataCode === 'isComplementary'){
+                if (setting.header[col].dataCode === 'isComplementary') {
                     sheet.setCellType(row, col, checkBoxType);
                     sheet.getCell(row, col).value(1);
                 }
                 //新增组成物表,选择复选框
-                if(setting.header[col].dataCode === 'select'){
+                if (setting.header[col].dataCode === 'select') {
                     sheet.setCellType(row, col, checkBoxType)
-                    if(data[row].isChecked === true){
+                    if (data[row].isChecked === true) {
                         sheet.getCell(row, col).value(1);
                     }
                 }
             }
-            for(let i = data.length; i < sheet.getRowCount(); i++){
+            for (let i = data.length; i < sheet.getRowCount(); i++) {
                 sheet.setCellType(i, 6, null);
             }
         }
@@ -134,35 +134,35 @@ let sheetsOprObj = {
         sheet.resumePaint();
         //me.shieldAllCells(sheet);
     },
-    combineRowData: function(sheet, setting, row, repositoryGljObj) {
+    combineRowData: function (sheet, setting, row, repositoryGljObj) {
         let me = this;
         var rst = {};
         let comboBoxCellType = sheet.getCellType(row, 5);
         let items = comboBoxCellType.items();
         for (var col = 0; col < setting.header.length; col++) {
-            if(setting.header[col].dataCode === 'gljType'){
-                items.forEach(function(item){
-                    if(sheet.getValue(row, col) === item.text){
+            if (setting.header[col].dataCode === 'gljType') {
+                items.forEach(function (item) {
+                    if (sheet.getValue(row, col) === item.text) {
                         rst[setting.header[col].dataCode] = item.value;
-                        if(repositoryGljObj){
+                        if (repositoryGljObj) {
                             rst.shortName = repositoryGljObj.distTypeTree.distTypes[repositoryGljObj.distTypeTree.prefix + item.value].data.shortName;
                         }
                     }
                 });
             }
-            else if (setting.header[col].dataCode === 'code'){
-                if(repositoryGljObj){
+            else if (setting.header[col].dataCode === 'code') {
+                if (repositoryGljObj) {
                     let gljList = repositoryGljObj.gljList,
                         orgCode = repositoryGljObj.orgCode,
                         isExist = false;
-                    for(let i=0; i< gljList.length; i++){
-                        if(gljList[i].code === sheet.getValue(row, col) && sheet.getValue(row, col)!== orgCode){
-                           // sheetCommonObj.lockAllCells(sheet);
+                    for (let i = 0; i < gljList.length; i++) {
+                        if (gljList[i].code === sheet.getValue(row, col) && sheet.getValue(row, col) !== orgCode) {
+                            // sheetCommonObj.lockAllCells(sheet);
                             $('#alertText').text("输入的编号已存在,请重新输入!");
                             $('#codeAlertBtn').click();
                             $('#codAleConfBtn').click(function () {
                                 // me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
-                               // sheetCommonObj.unLockAllCells(sheet);
+                                // sheetCommonObj.unLockAllCells(sheet);
                                 //me.reLockSomeCodes(sheet, 0, repositoryGljObj.currentCache.length);
                                 sheet.setValue(row, 0, orgCode);
                                 sheet.getCell(row, 0).formatter("@");
@@ -180,21 +180,21 @@ let sheetsOprObj = {
                             isExist = true
                         }
                     }
-                    if(!isExist){
+                    if (!isExist) {
                         rst[setting.header[col].dataCode] = sheet.getValue(row, col);
                     }
                 }
-                else{
+                else {
                     rst[setting.header[col].dataCode] = sheet.getValue(row, col);
                 }
             }
-            else{
+            else {
                 rst[setting.header[col].dataCode] = sheet.getValue(row, col);
             }
         }
         return rst;
     },
-    combineRationRowData: function(sheet, setting, row) {
+    combineRationRowData: function (sheet, setting, row) {
         var rst = {};
         for (var col = 0; col < setting.header.length; col++) {
             rst[setting.header[col].dataCode] = sheet.getValue(row, col);
@@ -211,10 +211,10 @@ let sheetsOprObj = {
         unLockStyle.locked = false;
         let lockStyle = new GC.Spread.Sheets.Style();
         lockStyle.locked = true;
-        for(let row = beginRow; row < endRow; row++){
+        for (let row = beginRow; row < endRow; row++) {
             sheet.setStyle(row, 0, lockStyle);
         }
-        for(let row = endRow; row < sheet.getRowCount(); row++){
+        for (let row = endRow; row < sheet.getRowCount(); row++) {
             sheet.setStyle(row, 0, unLockStyle);
         }
         sheet.options.isProtected = true;
@@ -225,11 +225,11 @@ let sheetsOprObj = {
         let defaultStyle = new GC.Spread.Sheets.Style();
         defaultStyle.locked = false;
         sheet.setDefaultStyle(defaultStyle, GC.Spread.Sheets.SheetArea.viewport);
-        let style = new  GC.Spread.Sheets.Style();
+        let style = new GC.Spread.Sheets.Style();
         style.locked = true;
         sheet.suspendPaint();
         sheet.suspendEvent();
-        for(let i = beginRow; i < endRow; i++){
+        for (let i = beginRow; i < endRow; i++) {
             sheet.setStyle(i, 0, style);
         }
         sheet.options.isProtected = true;
@@ -246,7 +246,7 @@ let sheetsOprObj = {
         let style = new GC.Spread.Sheets.Style();
         style.locked = true;
         sheet.setStyle(-1, 0, style);
-        for(let i =rowCount; i<sheetRowCount; i++){
+        for (let i = rowCount; i < sheetRowCount; i++) {
             sheet.setStyle(i, -1, style);
         }
         sheet.options.isProtected = true;

+ 25 - 0
web/maintain/report/css/main.css

@@ -294,3 +294,28 @@ body {
   bottom:0;
   left:0
 }
+.valuationSelector{
+     cursor: pointer;
+    position: absolute;
+    left: 105px;
+    top: 38px;
+    border: 1px solid #d9d9d9;
+    display: none;
+}
+.mutiSelector{
+    width: 130px;
+    margin: 0;
+    padding: 0 10px;
+}
+.mutiSelector li{
+    list-style: none;font-size: 16px;
+}
+.mutiSelector .checked{
+    background-color: #0275d8;
+    color: #fff;
+}
+.mutiSelector li:hover{
+    background-color: #0275d8;
+    color: #fff;
+    cursor: pointer;
+}

+ 21 - 1
web/maintain/report/html/rpt_tpl_dtl_info.html

@@ -56,7 +56,7 @@
                 </div>
                 <div class="input-group col-2">
                     <div class="input-group-addon">审核对比类型</div>
-                    <select class="form-control input-sm" id="element_constructSumFlags_audit" onchange="zTreeOprObj.onChangeFlag('auditType', this)"><option value ="NA">N/A</option><option value ="audit_compare">审核对比</option></select>
+                    <select class="form-control input-sm" id="element_constructSumFlags_audit" onchange="zTreeOprObj.onChangeFlag('auditType', this)"><option value ="NA">N/A</option><option value ="audit_compare">审核对比</option><option value="project_compare">步骤对比</option></select>
                 </div>
             </div>
             <p>
@@ -80,6 +80,26 @@
                     <div class="input-group-addon">报表模板级别</div>
                     <select class="form-control input-sm" id="element_Flags_tplType" onchange="zTreeOprObj.onChangeFlag('rptTplType', this)"><option value ="NA">N/A</option><option value ="construct">建设项目级别</option><option value ="single">单项工程级别</option><option value ="unit">单位工程级别</option></select>
                 </div>
+                <div class="input-group col-4">
+                    <div class="input-group-addon">工程类型</div>
+                    <input class="form-control input-sm" id="element_prjFlags_select" 
+                        onchange="zTreeOprObj.onChangeFlag('valuationType', this)" style="display: none;">
+                    <input class="form-control input-sm" id="element_prjFlags_selectStr"
+                        readonly>
+                        <div id="valuationSelector" class="valuationSelector">
+                        <ul class="mutiSelector">
+                            <li id="valuationSelector_suggestion" value="suggestion">建议估算</li>
+                            <li id="valuationSelector_feasibility" value="feasibility">可行性估算</li>
+                            <li id="valuationSelector_rough" value="rough">概算</li>
+                            <li id="valuationSelector_bill" value="bill">预算</li>
+                            <li id="valuationSelector_three_bill_budget" value="three_bill_budget">三级清单预算</li>
+                            <li id="valuationSelector_ration" value="ration">清单预算</li>
+                            <li id="valuationSelector_changeBudget"  value="changeBudget">变更预算</li>
+                            <li id="valuationSelector_settlement" value="settlement">结算</li>
+                        </ul>
+                   
+                    </div>
+                </div>
             </div>
             <!--
             -->

+ 274 - 178
web/maintain/report/js/rpt_tpl_main.js

@@ -15,8 +15,21 @@ const
     NODE_LEVEL_COMPILATION_NEW = 1,
     NODE_LEVEL_USER = 0;
 
+// 工程类型枚举值
+const valuationSelectorMap = {
+    valuationSelector_NA: 'N/A',
+    valuationSelector_suggestion: '建议估算',
+    valuationSelector_feasibility: '可行性估算',
+    valuationSelector_rough: '概算',
+    valuationSelector_bill: '预算',
+    valuationSelector_three_bill_budget: '三级清单预算',
+    valuationSelector_ration: '清单预算',
+    valuationSelector_changeBudget: '变更预算',
+    valuationSelector_settlement: '结算'
+}
+
 let rptTplObj = {
-    iniPage: function() {
+    iniPage: function () {
         zTreeOprObj.getCompilationList();
         rpt_tpl_cfg_helper.getReportTplCfg();
         selectableFiledTreeOprObj.iniTree();
@@ -33,23 +46,23 @@ let zTreeOprObj = {
     moveSrcTopNode: null,
     dupTplIds: null,
     hasRefreshedDupRefIds: false,
-    getCompilationList: function(){
+    getCompilationList: function () {
         let me = zTreeOprObj, params = {};
-        CommonAjax.postEx("report_tpl_api/getCompilationList", params, 20000, true, function(result){
-                //console.log(result);
-                for (let item of result) {
-                    // if (item.is_release) {
-                        $("#compilations").append("<option value='" + item._id + "'>" + item.name + "</option>");
-                    // }
-                }
-                // me.getReportTemplateTree($("#compilations").get(0));
-                me.getReportTemplateTreeEx($("#compilations").get(0));
-            }, null, null
+        CommonAjax.postEx("report_tpl_api/getCompilationList", params, 20000, true, function (result) {
+            //console.log(result);
+            for (let item of result) {
+                // if (item.is_release) {
+                $("#compilations").append("<option value='" + item._id + "'>" + item.name + "</option>");
+                // }
+            }
+            // me.getReportTemplateTree($("#compilations").get(0));
+            me.getReportTemplateTreeEx($("#compilations").get(0));
+        }, null, null
         );
     },
-    refreshNodes: function() {
+    refreshNodes: function () {
         let me = this;
-        let private_setupIsParent = function(node){
+        let private_setupIsParent = function (node) {
             // if (node.nodeType === RT.NodeType.NODE || node.level === 0) {
             if (node.nodeType === RT.NodeType.NODE || node.level <= NODE_LEVEL_COMPILATION_NEW) {
                 node.isParent = true;
@@ -68,7 +81,7 @@ let zTreeOprObj = {
         }
         me.treeObj.refresh();
     },
-    removeTreeRootNode: function(rawNode, isAsync, callback, failCallback) {
+    removeTreeRootNode: function (rawNode, isAsync, callback, failCallback) {
         let params = {};
         params.compilationId = rawNode.compilationId;
         params.engineerId = rawNode.engineerId;
@@ -76,13 +89,13 @@ let zTreeOprObj = {
         params.isPhysically = true;
         CommonAjax.postEx("report_tpl_api/removeTreeRootNode", params, 5000, isAsync, callback, failCallback, null);
     },
-    copyReportTemplate: function(orgID, newID, isAsync, callback, failCallback) {
+    copyReportTemplate: function (orgID, newID, isAsync, callback, failCallback) {
         let params = {};
         params.orgRptTplId = orgID;
         params.newRptTplId = newID;
         CommonAjax.postEx("report_tpl_api/copyRptTpl", params, 5000, isAsync, callback, failCallback, null);
     },
-    updateTreeRootNode: function(rawNode, isAsync, callback, failCallback) {
+    updateTreeRootNode: function (rawNode, isAsync, callback, failCallback) {
         let params = {};
         params.doc = rawNode;
         CommonAjax.postEx("report_tpl_api/updateTreeRootNode", params, 5000, isAsync, callback, failCallback, null);
@@ -119,7 +132,7 @@ let zTreeOprObj = {
         params.subNode = subNode;
         CommonAjax.postEx("report_tpl_api/updateSubLevelOneNode", params, 5000, isAsync, callback, failCallback, null);
     },
-    createIniNode: function() {
+    createIniNode: function () {
         return {
             nodeType: RT.NodeType.TEMPLATE,
             refId: -1,
@@ -128,7 +141,7 @@ let zTreeOprObj = {
             items: null
         };
     },
-    buildRootNodeDoc: function(topNode, excludeNode) {
+    buildRootNodeDoc: function (topNode, excludeNode) {
         let me = this, rst = null;
         if (topNode) {
             rst = {
@@ -144,7 +157,7 @@ let zTreeOprObj = {
         }
         return rst;
     },
-    getNodePath: function(node, includeCurrentNode) {
+    getNodePath: function (node, includeCurrentNode) {
         const rst = [];
         if (includeCurrentNode && node.level > 1) {
             // 备注:因结构有所变化,这里level判断要>1 (多了一层)
@@ -155,12 +168,12 @@ let zTreeOprObj = {
             rst.unshift(parentNode.name);
             parentNode = parentNode.getParentNode();
             if (parentNode === null || parentNode === undefined || parentNode.level === 0) {
-                rst.splice(0,1); // 删除头节点(后台不需要)
+                rst.splice(0, 1); // 删除头节点(后台不需要)
             }
         }
         return rst;
     },
-    buildSubRootNodeDoc: function(subNode) {
+    buildSubRootNodeDoc: function (subNode) {
         let me = this, rst = null;
         if (subNode) {
             let isReleased = false;
@@ -209,18 +222,18 @@ let zTreeOprObj = {
         return itemRst;
     },
 
-    addHoverDom: function(treeId, treeNode) {
+    addHoverDom: function (treeId, treeNode) {
         let me = zTreeOprObj, sObj = $("#" + treeNode.tId + "_span");
-        if (treeNode.editNameFlag || $("#addBtn_"+treeNode.tId).length > 0 || treeNode.nodeType === RT.NodeType.TEMPLATE) return;
+        if (treeNode.editNameFlag || $("#addBtn_" + treeNode.tId).length > 0 || treeNode.nodeType === RT.NodeType.TEMPLATE) return;
         if (treeNode.level === 0) {
             let addStr = "<span class='button star' id='addBtn_" + treeNode.tId + "' title='新增编办类型' onfocus='this.blur();'></span>";
             sObj.after(addStr);
-            let btn = $("#addBtn_"+treeNode.tId);
-            if (btn) btn.bind("click", function(){
+            let btn = $("#addBtn_" + treeNode.tId);
+            if (btn) btn.bind("click", function () {
                 let rawNode = me.createIniComilationNode();
                 if (!me.chkIfDupCompilationNode(rawNode, treeNode)) {
                     rawNode.userId = treeNode.userId;
-                    me.addNewNodeEx(rawNode, function(rst){
+                    me.addNewNodeEx(rawNode, function (rst) {
                         if (rst) {
                             let newNodes = [], isSilent = false;
                             rawNode.isParent = true;
@@ -250,8 +263,8 @@ let zTreeOprObj = {
         } else {
             let addStr = "<span class='button add' id='addBtn_" + treeNode.tId + "' title='新增子目录' onfocus='this.blur();'></span>";
             sObj.after(addStr);
-            let btn = $("#addBtn_"+treeNode.tId);
-            if (btn) btn.bind("click", function(){
+            let btn = $("#addBtn_" + treeNode.tId);
+            if (btn) btn.bind("click", function () {
                 me.getNewNodeID(1, function (newNodeID) {
                     let rawNode = me.createIniNode();
                     rawNode.nodeType = RT.NodeType.NODE;
@@ -280,11 +293,11 @@ let zTreeOprObj = {
                         //*
                         let pathArr = [];
                         let nodeArr = [];
-                        let path = {operation_type: 'add', node_path: []};
+                        let path = { operation_type: 'add', node_path: [] };
                         path.node_path = me.getNodePath(treeNode, true);
                         pathArr.push(path);
                         nodeArr.push(rawNode);
-                        me.partialUpdateTreeNode(newTopNode, pathArr, nodeArr, true, function(rst){
+                        me.partialUpdateTreeNode(newTopNode, pathArr, nodeArr, true, function (rst) {
                             if (!(rst)) {
                                 alert("新增节点失败!");
                             }
@@ -303,8 +316,8 @@ let zTreeOprObj = {
             });
             addStr = "<span class='button blue_core' id='addBtn2_" + treeNode.tId + "' title='新增报表模板' onfocus='this.blur();'></span>";
             sObj.after(addStr);
-            btn = $("#addBtn2_"+treeNode.tId + "");
-            if (btn) btn.bind("click", function(){
+            btn = $("#addBtn2_" + treeNode.tId + "");
+            if (btn) btn.bind("click", function () {
                 // let me = zTreeOprObj;
                 if (treeNode.nodeType === RT.NodeType.NODE || treeNode.level === NODE_LEVEL_COMPILATION_NEW) {
                     me.getNewNodeID(1, function (newNodeID) {
@@ -321,11 +334,11 @@ let zTreeOprObj = {
                         //*
                         let pathArr = [];
                         let nodeArr = [];
-                        let path = {operation_type: 'add', node_path: []};
+                        let path = { operation_type: 'add', node_path: [] };
                         path.node_path = me.getNodePath(treeNode, true);
                         pathArr.push(path);
                         nodeArr.push(rawNode);
-                        me.partialUpdateTreeNode(topNode, pathArr, nodeArr, true, function(rst){
+                        me.partialUpdateTreeNode(topNode, pathArr, nodeArr, true, function (rst) {
                             if (!(rst)) {
                                 alert("新增节点失败!");
                             }
@@ -344,11 +357,11 @@ let zTreeOprObj = {
             });
         }
     },
-    removeHoverDom: function(treeId, treeNode) {
-        $("#addBtn_"+treeNode.tId).unbind().remove();
-        $("#addBtn2_"+treeNode.tId).unbind().remove();
+    removeHoverDom: function (treeId, treeNode) {
+        $("#addBtn_" + treeNode.tId).unbind().remove();
+        $("#addBtn2_" + treeNode.tId).unbind().remove();
     },
-    addNewNodeEx: function(rawNode, callback, failCallback) {
+    addNewNodeEx: function (rawNode, callback, failCallback) {
         let params = {};
         params.doc = rawNode;
         CommonAjax.postEx("report_tpl_api/createTreeRootNode", params, 5000, true, callback, failCallback, null);
@@ -357,7 +370,7 @@ let zTreeOprObj = {
         let me = zTreeOprObj;
         let topPNode = me.getParentNodeByNodeLevel(treeNode, NODE_LEVEL_COMPILATION_NEW);
         let newTopNode = me.buildRootNodeDoc(topPNode);
-        me.updateTreeRootNode(newTopNode, true, function(rst){
+        me.updateTreeRootNode(newTopNode, true, function (rst) {
             if (!(rst)) {
                 alert("修改发布状态失败!");
             }
@@ -428,7 +441,7 @@ let zTreeOprObj = {
                 treeNodes[0].ID = newNodeID;
                 if (confirm("是否引用相同的报表模板?")) {
                     newTopNode = me.buildRootNodeDoc(targetTopNode);
-                    me.updateTreeRootNode(newTopNode, false, function(goodRst){
+                    me.updateTreeRootNode(newTopNode, false, function (goodRst) {
                         canContinue = true;
                         if (treeNodes[0].rptTpl) {
                             treeNodes[0].rptTpl.ID = newNodeID;
@@ -437,7 +450,7 @@ let zTreeOprObj = {
                         me.chkAndSetDupRefTplIds(me.treeObj.getNodes(), null);
                         me.treeObj.refresh();
                         me.chkAndRreshRefTpl();
-                    }, function(badRst){
+                    }, function (badRst) {
                         displayMessage("更新模板节点失败!", "red", 2000);
                         // console.log(badRst.toString());
                         console.log(badRst);
@@ -446,8 +459,8 @@ let zTreeOprObj = {
                     treeNodes[0].refId = newNodeID;
                     // targetNode.refId = newNodeID; //targetNode可以是父节点也可以是兄弟节点,没必要引用相同的tplID
                     newTopNode = me.buildRootNodeDoc(targetTopNode);
-                    me.copyReportTemplate(orgID, newNodeID, true, function(goodResult){
-                        me.updateTreeRootNode(newTopNode, true, function(goodRst){
+                    me.copyReportTemplate(orgID, newNodeID, true, function (goodResult) {
+                        me.updateTreeRootNode(newTopNode, true, function (goodRst) {
                             canContinue = true;
                             // treeObj.updateNode(nodes[0]);
                             zTreeOprObj.treeObj.updateNode(treeNodes[0]);
@@ -458,12 +471,12 @@ let zTreeOprObj = {
                             me.chkAndSetDupRefTplIds(me.treeObj.getNodes(), null);
                             me.treeObj.refresh();
                             me.chkAndRreshRefTpl();
-                        }, function(badRst){
+                        }, function (badRst) {
                             displayMessage("更新模板节点失败!", "red", 2000);
                             // console.log(badRst.toString());
                             console.log(badRst);
                         });
-                    }, function(badResult){
+                    }, function (badResult) {
                         displayMessage("Copy请求失败!", "red", 2000);
                         // console.log(badResult.toString());
                         console.log(badResult);
@@ -475,19 +488,19 @@ let zTreeOprObj = {
             // }
         } else {
             newTopNode = me.buildRootNodeDoc(targetTopNode);
-            me.updateTreeRootNode(newTopNode, false, function(rst){
+            me.updateTreeRootNode(newTopNode, false, function (rst) {
                 canContinue = true;
                 me.currentNode = treeNodes[0];
-            }, function(badResult){
+            }, function (badResult) {
                 displayMessage("移动请求失败!", "red", 2000);
                 console.log(badResult.toString());
                 canContinue = false;
             });
             if (canContinue && !isCopy && me.moveSrcTopNode) {
                 let newSrcTopNode = me.buildRootNodeDoc(me.moveSrcTopNode);
-                me.updateTreeRootNode(newSrcTopNode, true, function(rst){
+                me.updateTreeRootNode(newSrcTopNode, true, function (rst) {
                     // canContinue = true;
-                }, function(badResult){
+                }, function (badResult) {
                     displayMessage("移动请求失败!", "red", 2000);
                     canContinue = true;
                 });
@@ -495,7 +508,7 @@ let zTreeOprObj = {
             me.moveSrcTopNode = null;
         }
     },
-    addReportTemplate: function(newUsers) {
+    addReportTemplate: function (newUsers) {
         let me = zTreeOprObj, params = {};
         params.compilationId = $("#compilations").get(0).value;
         params.userId = [];
@@ -509,11 +522,11 @@ let zTreeOprObj = {
             allEngIds.push(item.value);
         }
         params.engineerId = allEngIds;
-        CommonAjax.postEx("report_tpl_api/getRptTplTree", params, 20000, true, function(result){
-            result.sort(function(item1, item2){
+        CommonAjax.postEx("report_tpl_api/getRptTplTree", params, 20000, true, function (result) {
+            result.sort(function (item1, item2) {
                 let rst = 0;
                 if (item1.userId === item2.userId) {
-                    rst = (item1.engineerId > item2.engineerId)?1:((item1.engineerId < item2.engineerId)?-1:0);
+                    rst = (item1.engineerId > item2.engineerId) ? 1 : ((item1.engineerId < item2.engineerId) ? -1 : 0);
                 } else {
                     if (item1.userId === "-100") {
                         rst = 1
@@ -527,7 +540,7 @@ let zTreeOprObj = {
                             if (idx1 >= 0 && idx2 >= 0) {
                                 break;
                             }
-                            rst = (idx1 > idx2)?1:((idx1 < idx2)?-1:0);
+                            rst = (idx1 > idx2) ? 1 : ((idx1 < idx2) ? -1 : 0);
                         }
                     }
                 }
@@ -537,7 +550,7 @@ let zTreeOprObj = {
             let allTopTplNodes = [];
             for (let user of newUsers) {
                 allTopUserIdNodes.push(user.userId);
-                allTopTplNodes.push({userId: user.userId, name: user.real_name, items: [], isParent: true});
+                allTopTplNodes.push({ userId: user.userId, name: user.real_name, items: [], isParent: true });
             }
             for (let item of result) {
                 let uidx = allTopUserIdNodes.indexOf(item.userId);
@@ -633,8 +646,8 @@ let zTreeOprObj = {
     getReportTemplateTreeEx: function (compilationSelect) {
         let me = zTreeOprObj, params = {};
         params.compilationId = compilationSelect.value;
-        CommonAjax.postEx("report_tpl_api/getTplTreeByCompilation", params, 20000, true, function(result){
-            result.sort(function(item1, item2){
+        CommonAjax.postEx("report_tpl_api/getTplTreeByCompilation", params, 20000, true, function (result) {
+            result.sort(function (item1, item2) {
                 let rst = 0;
                 if (item1.userId === "-100") {
                     rst = -1;
@@ -645,7 +658,7 @@ let zTreeOprObj = {
             });
             // me.chkAndSetDupRefTplIds(result);
             // console.log(dupRefIds);
-            let allTopTplNodes = [{userId: "-100", name: "公共模板", items:[], isParent: true, refId: ""}];
+            let allTopTplNodes = [{ userId: "-100", name: "公共模板", items: [], isParent: true, refId: "" }];
             if (result.length > 0) {
                 if (!result[0].hasOwnProperty("refId")) {
                     result[0].refId = "";
@@ -665,7 +678,7 @@ let zTreeOprObj = {
                     for (let itemIdx = 1; itemIdx < result.length; itemIdx++) {
                         let item = result[itemIdx];
                         if (item.userId === user._id) {
-                            allTopTplNodes.push({userId: user.userId, name: user.real_name, items: [], isParent: true, refId: ""});
+                            allTopTplNodes.push({ userId: user.userId, name: user.real_name, items: [], isParent: true, refId: "" });
                             allTopTplNodes[allTopTplNodes.length - 1].items.push(result[itemIdx]);
                             break;
                         }
@@ -718,11 +731,11 @@ let zTreeOprObj = {
         }
         return rst;
     },
-    createIniComilationNode: function() {
+    createIniComilationNode: function () {
         //在新的需求下,无需工程id
         let rst = {
             compilationId: $("#compilations").get(0).selectedOptions[0].value,
-            userId: (userAccount ===  'admin')?("-100"):userID,
+            userId: (userAccount === 'admin') ? ("-100") : userID,
             properties: [],
             released: true,
             isDeleted: false,
@@ -731,7 +744,7 @@ let zTreeOprObj = {
         };
         return rst;
     },
-    onBeforeRemove: function(treeId, treeNode){
+    onBeforeRemove: function (treeId, treeNode) {
         let canRemove = false;
         if (treeNode.level > NODE_LEVEL_USER) {
             if (!(treeNode.items) || treeNode.items.length < 1) {
@@ -744,13 +757,13 @@ let zTreeOprObj = {
         }
         return canRemove;
     },
-    onRemove: function(e, treeId, treeNode){
+    onRemove: function (e, treeId, treeNode) {
         if (treeNode.level > NODE_LEVEL_USER) {
             let me = zTreeOprObj,
                 topPNode = me.getParentNodeByNodeLevel(treeNode, NODE_LEVEL_COMPILATION_NEW);
             let rawNode = me.buildRootNodeDoc(topPNode, treeNode);
             if (treeNode.level === NODE_LEVEL_COMPILATION_NEW) {
-                me.removeTreeRootNode(rawNode, true, function(rst){
+                me.removeTreeRootNode(rawNode, true, function (rst) {
                     if (!(rst)) {
                         alert("删除请求失败!");
                     }
@@ -763,7 +776,7 @@ let zTreeOprObj = {
                 // });
                 let pathArr = [];
                 let nodeArr = [];
-                let path = {operation_type: 'delete', node_path: []};
+                let path = { operation_type: 'delete', node_path: [] };
                 path.node_path = me.getNodePath(treeNode, true);
                 pathArr.push(path);
                 nodeArr.push('');
@@ -779,12 +792,12 @@ let zTreeOprObj = {
     },
     beforeEditName: function (treeId, treeNode) {
         if (treeNode.level > NODE_LEVEL_COMPILATION_NEW) {
-            setTimeout(function(){
+            setTimeout(function () {
                 let ip = $("#" + treeNode.tId + IDMark_Input);
                 if (ip.length > 0) {
                     ip[0].className = "individualRename";
                 } else {
-                    setTimeout(function(){
+                    setTimeout(function () {
                         let ip = $("#" + treeNode.tId + IDMark_Input);
                         if (ip.length > 0) {
                             ip[0].className = "individualRename";
@@ -799,13 +812,13 @@ let zTreeOprObj = {
             return false;
         }
     },
-    beforeRename: function(treeId, treeNode, newName, isCancel) {
+    beforeRename: function (treeId, treeNode, newName, isCancel) {
         if (newName.length === 0) {
             return false;
         }
         return true;
     },
-    onRename : function(e, treeId, treeNode, isCancel) {
+    onRename: function (e, treeId, treeNode, isCancel) {
         if (!isCancel) {
             let me = zTreeOprObj;
             if (treeNode.level === 0) {
@@ -814,7 +827,7 @@ let zTreeOprObj = {
                 let subTopNode = me.getParentNodeByNodeLevel(treeNode, NODE_LEVEL_COMPILATION_NEW + 1);
                 let topPNode = subTopNode.getParentNode();
                 let rawNode = me.buildSubRootNodeDoc(subTopNode);
-                me.updateSubNode(topPNode, rawNode, true, function(rst){
+                me.updateSubNode(topPNode, rawNode, true, function (rst) {
                     if (!(rst)) {
                         alert('修改名称请求失败!');
                     }
@@ -822,24 +835,40 @@ let zTreeOprObj = {
             }
         }
     },
-    onChangeFlag: function(flagProp, flagDom){
+    onChangeFlag: function (flagProp, flagDom) {
         let me = zTreeOprObj;
         if (me.currentNode && me.currentNode.nodeType === RT.NodeType.TEMPLATE) {
             if (!me.currentNode.hasOwnProperty("flags")) {
                 me.currentNode.flags = {};
             }
-            me.currentNode.flags[flagProp] = (flagDom.selectedOptions[0].value === 'NA')?null:flagDom.selectedOptions[0].value;
+            me.currentNode.flags[flagProp] = (flagDom.selectedOptions[0].value === 'NA') ? null : flagDom.selectedOptions[0].value;
             let subTopNode = me.getParentNodeByNodeLevel(me.currentNode, NODE_LEVEL_COMPILATION_NEW + 1);
             let topPNode = subTopNode.getParentNode();
             let rawNode = me.buildSubRootNodeDoc(subTopNode);
-            me.updateSubNode(topPNode, rawNode, true, function(rst){
+            me.updateSubNode(topPNode, rawNode, true, function (rst) {
+                if (!(rst)) {
+                    alert('修改标记:[' + flagProp + '] 失败!');
+                }
+            });
+        }
+    },
+    onMutiChangeFlag: function (flagProp, flagDom) {
+        let me = zTreeOprObj;
+        if (me.currentNode && me.currentNode.nodeType === RT.NodeType.TEMPLATE) {
+            if (!me.currentNode.hasOwnProperty("flags")) {
+                me.currentNode.flags = {};
+            }
+            me.currentNode.flags[flagProp] = flagDom[0].value.split(',');
+            let subTopNode = me.getParentNodeByNodeLevel(me.currentNode, NODE_LEVEL_COMPILATION_NEW + 1);
+            let topPNode = subTopNode.getParentNode();
+            let rawNode = me.buildSubRootNodeDoc(subTopNode);
+            me.updateSubNode(topPNode, rawNode, true, function (rst) {
                 if (!(rst)) {
                     alert('修改标记:[' + flagProp + '] 失败!');
                 }
             });
         }
     },
-
     createNewTpl: function () {
         let me = zTreeOprObj, params = {};
         if (me.currentNode && me.currentNode.nodeType === RT.NodeType.TEMPLATE) {
@@ -858,14 +887,14 @@ let zTreeOprObj = {
             params.engineerId = topPNode.engineerId;
             params.userId = topPNode.userId;
             params.subNode = rawNode;
-            CommonAjax.postEx("report_tpl_api/createDftRptTpl", params, 10000, true, function(result){
-                    if (result) {
-                        me.currentNode.rptTpl = result;
-                        me.chkAndRreshRefTpl();
-                    } else {
-                        alert('update error!');
-                    }
-                }, null, null
+            CommonAjax.postEx("report_tpl_api/createDftRptTpl", params, 10000, true, function (result) {
+                if (result) {
+                    me.currentNode.rptTpl = result;
+                    me.chkAndRreshRefTpl();
+                } else {
+                    alert('update error!');
+                }
+            }, null, null
             );
         }
     },
@@ -882,7 +911,7 @@ let zTreeOprObj = {
         }
         return true;
     },
-    onClick: function(event,treeId,treeNode) {
+    onClick: function (event, treeId, treeNode) {
         let me = zTreeOprObj;
         me.currentNode = treeNode;
         bandTreeOprObj.currentNode = null;
@@ -936,122 +965,155 @@ let zTreeOprObj = {
         }
         return rst;
     },
-    chkAndRreshRefTpl: function(forceRefresh) {
+    chkAndRreshRefTpl: function (forceRefresh) {
         let me = zTreeOprObj, params = {};
+        const valuationTypes = ['suggestion', 'feasibility', 'rough', 'bill', 'three_bill_budget', 'ration', 'changeBudget', 'settlement'];
         if (me.currentNode && me.currentNode.nodeType === RT.NodeType.TEMPLATE && me.currentNode.refId > 0) {
             if (forceRefresh || !(me.currentNode.rptTpl)) {
                 params.rptTplId = me.currentNode.refId;
-                CommonAjax.postEx("report_tpl_api/getRefRptTpl", params, 20000, true, function(result){
-                        me.currentNode.rptTpl = result;
-                        me.currentNode.rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MAIN_INFO_RPT_NAME] = me.currentNode.name;
-                        if (me.currentNode.rptTpl["GROUP_KEY"]) {
-                            let grp_keys = me.currentNode.rptTpl["GROUP_KEY"].split('_');
-                            if (grp_keys.length > 0) {
-                                grp_keys[1] = me.currentNode.name;
-                            }
-                            me.currentNode.rptTpl["GROUP_KEY"] = grp_keys.join("_");
+                CommonAjax.postEx("report_tpl_api/getRefRptTpl", params, 20000, true, function (result) {
+                    me.currentNode.rptTpl = result;
+                    me.currentNode.rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MAIN_INFO_RPT_NAME] = me.currentNode.name;
+                    if (me.currentNode.rptTpl["GROUP_KEY"]) {
+                        let grp_keys = me.currentNode.rptTpl["GROUP_KEY"].split('_');
+                        if (grp_keys.length > 0) {
+                            grp_keys[1] = me.currentNode.name;
                         }
-                        tplHelper.refreshTplView(me.currentNode.rptTpl);
-                        if (me.currentNode.hasOwnProperty('flags')) {
-                            if (me.currentNode.flags.hasOwnProperty('taxType')) {
-                                let val = parseInt(me.currentNode.flags['taxType']);
-                                $("#element_flags_select")[0].selectedIndex = val;
-                            } else {
-                                $("#element_flags_select")[0].selectedIndex = 0;
-                            }
-                            if (me.currentNode.flags.hasOwnProperty('constructSumType')) {
-                                let val = me.currentNode.flags['constructSumType'];
-                                if (val === 'constructSum') {
-                                    $("#element_constructSumFlags_select")[0].selectedIndex = 1;
-                                } else {
-                                    $("#element_constructSumFlags_select")[0].selectedIndex = 0;
-                                }
+                        me.currentNode.rptTpl["GROUP_KEY"] = grp_keys.join("_");
+                    }
+                    tplHelper.refreshTplView(me.currentNode.rptTpl);
+                    if (me.currentNode.hasOwnProperty('flags')) {
+                        if (me.currentNode.flags.hasOwnProperty('taxType')) {
+                            let val = parseInt(me.currentNode.flags['taxType']);
+                            $("#element_flags_select")[0].selectedIndex = val;
+                        } else {
+                            $("#element_flags_select")[0].selectedIndex = 0;
+                        }
+                        if (me.currentNode.flags.hasOwnProperty('constructSumType')) {
+                            let val = me.currentNode.flags['constructSumType'];
+                            if (val === 'constructSum') {
+                                $("#element_constructSumFlags_select")[0].selectedIndex = 1;
                             } else {
                                 $("#element_constructSumFlags_select")[0].selectedIndex = 0;
                             }
-                            if (me.currentNode.flags.hasOwnProperty('auditType')) {
-                                let val = me.currentNode.flags['auditType'];
-                                if (val === 'audit_compare') {
-                                    $("#element_constructSumFlags_audit")[0].selectedIndex = 1;
-                                } else {
-                                    $("#element_constructSumFlags_audit")[0].selectedIndex = 0;
-                                }
+                        } else {
+                            $("#element_constructSumFlags_select")[0].selectedIndex = 0;
+                        }
+                        if (me.currentNode.flags.hasOwnProperty('auditType')) {
+                            let val = me.currentNode.flags['auditType'];
+                            if (val === 'audit_compare') {
+                                $("#element_constructSumFlags_audit")[0].selectedIndex = 1;
+                            } else if (val === 'project_compare') {
+                                $("#element_constructSumFlags_audit")[0].selectedIndex = 2;
                             } else {
                                 $("#element_constructSumFlags_audit")[0].selectedIndex = 0;
                             }
-                            if (me.currentNode.flags.hasOwnProperty('budgetType')) {
-                                let val = me.currentNode.flags['budgetType'];
-                                if (val === '1') {
-                                    $("#element_Flags_budgetType")[0].selectedIndex = 1;
-                                } else if (val === '2') {
-                                    $("#element_Flags_budgetType")[0].selectedIndex = 2;
-                                } else {
-                                    $("#element_Flags_budgetType")[0].selectedIndex = 0;
-                                }
+                        } else {
+                            $("#element_constructSumFlags_audit")[0].selectedIndex = 0;
+                        }
+                        if (me.currentNode.flags.hasOwnProperty('budgetType')) {
+                            let val = me.currentNode.flags['budgetType'];
+                            if (val === '1') {
+                                $("#element_Flags_budgetType")[0].selectedIndex = 1;
+                            } else if (val === '2') {
+                                $("#element_Flags_budgetType")[0].selectedIndex = 2;
                             } else {
                                 $("#element_Flags_budgetType")[0].selectedIndex = 0;
                             }
-                            if (me.currentNode.flags.hasOwnProperty('budgetSumType')) {
-                                let val = me.currentNode.flags['budgetSumType'];
-                                if (val === 'budget_construct') {
-                                    $("#element_Flags_budgetSummaryType")[0].selectedIndex = 1;
-                                } else if (val === 'budget_single') {
-                                    $("#element_Flags_budgetSummaryType")[0].selectedIndex = 2;
-                                } else {
-                                    $("#element_Flags_budgetSummaryType")[0].selectedIndex = 0;
-                                }
+                        } else {
+                            $("#element_Flags_budgetType")[0].selectedIndex = 0;
+                        }
+                        if (me.currentNode.flags.hasOwnProperty('budgetSumType')) {
+                            let val = me.currentNode.flags['budgetSumType'];
+                            if (val === 'budget_construct') {
+                                $("#element_Flags_budgetSummaryType")[0].selectedIndex = 1;
+                            } else if (val === 'budget_single') {
+                                $("#element_Flags_budgetSummaryType")[0].selectedIndex = 2;
                             } else {
                                 $("#element_Flags_budgetSummaryType")[0].selectedIndex = 0;
                             }
-                            if (me.currentNode.flags.hasOwnProperty('budgetCalcType')) {
-                                let val = me.currentNode.flags['budgetCalcType'];
-                                if (val === 'budget_cacl_type1') {
-                                    $("#element_Flags_budgetCalcType")[0].selectedIndex = 1;
-                                } else {
-                                    $("#element_Flags_budgetCalcType")[0].selectedIndex = 0;
-                                }
+                        } else {
+                            $("#element_Flags_budgetSummaryType")[0].selectedIndex = 0;
+                        }
+                        if (me.currentNode.flags.hasOwnProperty('budgetCalcType')) {
+                            let val = me.currentNode.flags['budgetCalcType'];
+                            if (val === 'budget_cacl_type1') {
+                                $("#element_Flags_budgetCalcType")[0].selectedIndex = 1;
                             } else {
                                 $("#element_Flags_budgetCalcType")[0].selectedIndex = 0;
                             }
-                            if (me.currentNode.flags.hasOwnProperty('rptTplType')) {
-                                let val = me.currentNode.flags['rptTplType'];
-                                if (val === 'construct') {
-                                    $("#element_Flags_tplType")[0].selectedIndex = 1;
-                                } else if (val === 'single') {
-                                    $("#element_Flags_tplType")[0].selectedIndex = 2;
-                                } else if (val === 'unit') {
-                                    $("#element_Flags_tplType")[0].selectedIndex = 3;
-                                } else {
-                                    $("#element_Flags_tplType")[0].selectedIndex = 0;
+                        } else {
+                            $("#element_Flags_budgetCalcType")[0].selectedIndex = 0;
+                        }
+
+                        $("#valuationSelector").hide();
+                        if (me.currentNode.flags.hasOwnProperty('valuationType')) {
+                            $(".mutiSelector").find('li').removeClass('checked');
+                            let valuationTypeStr = '';
+                            let valuationTypeStrList = [];
+                            let vType = me.currentNode.flags['valuationType'];
+                            if (vType instanceof Array) {
+                                for (let i = 0; i < vType.length; i++) {
+                                    $("#valuationSelector_" + vType[i]).addClass('checked');
+                                    valuationTypeStrList.push(valuationSelectorMap["valuationSelector_" + vType[i]]);
                                 }
+                                valuationTypeStr = valuationTypeStrList.join(',');
+                            } else if (vType) {
+                                $("#valuationSelector_" + vType).addClass('checked');
+                                valuationTypeStr = valuationSelectorMap["valuationSelector_" + vType];
+                            }
+                            $("#element_prjFlags_select")[0].value = vType;
+                            $("#element_prjFlags_selectStr")[0].value = valuationTypeStr;
+                        } else {
+                            $("#element_prjFlags_select")[0].value = '';
+                            $("#element_prjFlags_selectStr")[0].value = '';
+                            $('#valuationSelector .mutiSelector li').removeClass('checked');
+                        }
+                        if (me.currentNode.flags.hasOwnProperty('rptTplType')) {
+                            let val = me.currentNode.flags['rptTplType'];
+                            if (val === 'construct') {
+                                $("#element_Flags_tplType")[0].selectedIndex = 1;
+                            } else if (val === 'single') {
+                                $("#element_Flags_tplType")[0].selectedIndex = 2;
+                            } else if (val === 'unit') {
+                                $("#element_Flags_tplType")[0].selectedIndex = 3;
                             } else {
                                 $("#element_Flags_tplType")[0].selectedIndex = 0;
                             }
                         } else {
-                            $("#element_flags_select")[0].selectedIndex = 0;
-                            $("#element_constructSumFlags_select")[0].selectedIndex = 0;
-                            $("#element_constructSumFlags_audit")[0].selectedIndex = 0;
-                            $("#element_Flags_budgetType")[0].selectedIndex = 0;
-                            $("#element_Flags_budgetSummaryType")[0].selectedIndex = 0;
-                            $("#element_Flags_budgetCalcType")[0].selectedIndex = 0;
                             $("#element_Flags_tplType")[0].selectedIndex = 0;
                         }
+                    } else {
+                        $("#element_flags_select")[0].selectedIndex = 0;
+                        $("#element_constructSumFlags_select")[0].selectedIndex = 0;
+                        $("#element_constructSumFlags_audit")[0].selectedIndex = 0;
+                        $("#element_Flags_budgetType")[0].selectedIndex = 0;
+                        $("#element_Flags_budgetSummaryType")[0].selectedIndex = 0;
+                        $("#element_Flags_budgetCalcType")[0].selectedIndex = 0;
+                        $("#element_Flags_tplType")[0].selectedIndex = 0;
+                        $("#element_prjFlags_select")[0].selectedIndex = 0;
+                        // 清空工程类型
+                        $("#valuationSelector").hide();
+                        $("#element_prjFlags_select")[0].value = '';
+                        $("#element_prjFlags_selectStr")[0].value = '';
+                        $('#valuationSelector .mutiSelector li').removeClass('checked');
+                    }
 
-                        if ($("#rpt_tpl_visual_tab")[0].className === "nav-link p-1 active") {
-                            setTimeout(function(){visualJumbo.iniSpreadJs(); visualJumbo.setupTpl()}, 50)
-                        }
-                    }, null, null
+                    if ($("#rpt_tpl_visual_tab")[0].className === "nav-link p-1 active") {
+                        setTimeout(function () { visualJumbo.iniSpreadJs(); visualJumbo.setupTpl() }, 50)
+                    }
+                }, null, null
                 );
             } else {
                 me.currentNode.rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MAIN_INFO_RPT_NAME] = me.currentNode.name;
                 tplHelper.refreshTplView(me.currentNode.rptTpl);
                 if ($("#rpt_tpl_visual_tab")[0].className === "nav-link p-1 active") {
-                    setTimeout(function(){visualJumbo.iniSpreadJs(); visualJumbo.setupTpl()}, 50)
+                    setTimeout(function () { visualJumbo.iniSpreadJs(); visualJumbo.setupTpl() }, 50)
                 }
             }
         }
     },
-    getRefTpl: function() {
+    getRefTpl: function () {
         let me = zTreeOprObj, rst = null;
         if (me.currentNode && me.currentNode.nodeType === RT.NodeType.TEMPLATE && me.currentNode.refId > 0) {
             rst = me.currentNode.rptTpl
@@ -1099,11 +1161,11 @@ let zTreeOprObj = {
 let userListObj = {
     foundedUserList: [],
     UserIdList: [],
-    pushUser: function(user, newUsers) {
+    pushUser: function (user, newUsers) {
         let me = userListObj;
         if (me.UserIdList.indexOf(user._id) < 0) {
             me.UserIdList.push(user._id);
-            let newUser = {userId: user._id, real_name: user.real_name, username: user.username, mobile: user.mobile};
+            let newUser = { userId: user._id, real_name: user.real_name, username: user.username, mobile: user.mobile };
             me.foundedUserList.push(newUser);
             if (newUsers) {
                 newUsers.push(newUser);
@@ -1114,11 +1176,11 @@ let userListObj = {
         let key = $("#rpt_user_input1").get(0).value;
         let newUsers = [];
         $.ajax({
-            type:"GET",
+            type: "GET",
             url: "user/search?keyword=" + key,
             cache: false,
             timeout: 5000,
-            success: function(result){
+            success: function (result) {
                 if (result.data && result.data.length > 0) {
                     for (let user of result.data) {
                         userListObj.pushUser(user, newUsers);
@@ -1128,21 +1190,21 @@ let userListObj = {
                     }
                 }
             },
-            error: function(jqXHR, textStatus, errorThrown){
+            error: function (jqXHR, textStatus, errorThrown) {
             }
         });
     },
     findUsersByIds: function (userIds, cb) {
         let params = {};
         params.userIds = userIds;
-        CommonAjax.postEx("user/getUserList", params, 20000, true, function(result){
-                for (let user of result) {
-                    userListObj.pushUser(user, null);
-                }
-                if (cb) {
-                    cb(result);
-                }
-            }, null, null
+        CommonAjax.postEx("user/getUserList", params, 20000, true, function (result) {
+            for (let user of result) {
+                userListObj.pushUser(user, null);
+            }
+            if (cb) {
+                cb(result);
+            }
+        }, null, null
         );
     }
 };
@@ -1152,7 +1214,41 @@ function displayMessage(message, color, disappearTime, id) {
     if (!domId) domId = "id_after_saved_lbl";
     $("#" + domId)[0].style.color = color;
     $("#" + domId)[0].innerHTML = message;
-    setTimeout(function(){
+    setTimeout(function () {
         $("#" + domId)[0].innerHTML = "";
     }, disappearTime);
-}
+}
+
+$("#element_prjFlags_selectStr").on('click', function () {
+    if ($('#valuationSelector').visible) {
+        $('#valuationSelector').hide();
+    } else {
+        $('#valuationSelector').show();
+    }
+    return false;
+})
+
+$('#rpttplinfo').on('click', function () {
+    $('#valuationSelector').hide();
+
+})
+
+$('.mutiSelector').find('li').on('click', function (e) {
+    const hasChecked = $(this).hasClass('checked');
+    if (hasChecked) {
+        $(this).removeClass('checked');
+    } else {
+        $(this).addClass('checked');
+    }
+    const resultIDList = [];
+    const resultList = [];
+    $('.mutiSelector .checked').each(function (index, value) {
+        resultList.push(valuationSelectorMap[$(value).attr('id')]);
+        resultIDList.push($(value).attr('value'));
+    })
+    const result = resultList.join(',');
+    $('#element_prjFlags_selectStr').val(result);
+    $('#element_prjFlags_select').val(resultIDList);
+    zTreeOprObj.onMutiChangeFlag('valuationType', $('#element_prjFlags_select'));
+    return false;
+})

+ 4 - 2
web/over_write/crawler/guangdong_2018_price_crawler.js

@@ -248,13 +248,13 @@ function getDateForApi(journalList, period) {
     return matchQuater.date;
   }
   // 没匹配到季度数据,去匹配半年数据
-  if (month / 6 <= 1 ) {
+  if (month / 6 <= 1) {
     const firstHalfYear = journalList.find(dateItem => dateItem.date === `${year}-06-25`);
     if (firstHalfYear) {
       return firstHalfYear.date;
     }
   }
-  if (month /6 > 1) {
+  if (month / 6 > 1) {
     const secondHalfYear = journalList.find(dateItem => dateItem.date === `${year}-12-25`);
     if (secondHalfYear) {
       return secondHalfYear.date;
@@ -310,6 +310,7 @@ async function getPriceInfoSource(token, period, city, county) {
     taxPrice: item.tax_price,
     noTaxPrice: item.no_tax_price,
     specs: item.spec,
+    dateRemark: item.notes,
     remark: item.notes,
   }));
   /* if (insertData.length) {
@@ -442,6 +443,7 @@ async function saveData(compilationID, period, areaID, sourceData, classNameMap)
       unit: sourceItem.unit,
       specs: sourceItem.specs,
       taxPrice: sourceItem.taxPrice,
+      dateRemark: sourceItem.dateRemark,
       remark: sourceItem.remark,
     };
   }

Fichier diff supprimé car celui-ci est trop grand
+ 351 - 230
web/users/js/compilation.js


+ 30 - 0
web/users/views/compilation/index.html

@@ -27,6 +27,7 @@
                     <tr>
                         <th>计价规则</th>
                         <th>启用/禁用</th>
+                        <th>适用类型</th>
                         <th>操作</th>
                     </tr>
                     </thead>
@@ -49,6 +50,14 @@
                             <% } %>
                         </td>
                         <td>
+                           <input type="checkbox" data-id="<%= bill.id %>" class="fileType" id="<%= bill.id %>_gusuan" <% if (bill.fileTypes && bill.fileTypes.includes(15)) { %> checked <% } %> /> 估算  
+                            <input type="checkbox" data-id="<%= bill.id %>" class="fileType" id="<%= bill.id %>_estimate"  <% if (bill.fileTypes && bill.fileTypes.includes(5)) { %> checked <% } %>  /> 概算    
+                            <input type="checkbox" data-id="<%= bill.id %>" class="fileType" id="<%= bill.id %>_submission" <% if (bill.fileTypes && bill.fileTypes.includes(1)) { %> checked <% } %>  /> 预算      
+                            <input type="checkbox" data-id="<%= bill.id %>" class="fileType" id="<%= bill.id %>_changeBudget" <% if (bill.fileTypes && bill.fileTypes.includes(4)) { %> checked <% } %>  /> 变更预算
+                            <input type="checkbox" data-id="<%= bill.id %>" class="fileType" id="<%= bill.id %>_settlement" <% if (bill.fileTypes && bill.fileTypes.includes(10)) { %> checked <% } %>  /> 结算      
+                        </td>
+                        <td>
+                            <a class="copy-bill-valuation" data-id="<%= bill.id %>" href="javascript:void(0);" class="btn btn-sm">拷贝</a>
                             <a href="/compilation/valuation/bill/<%= bill.id %>" class="btn btn-sm">编辑</a>
                             <a onclick="$('#del').attr('selectedId', '<%= bill.id %>')" href="#" data-id="<%= bill.id %>" data-toggle="modal" data-target="#del" class="btn btn-sm text-danger">删除</a>
                             <!--<a href="/compilation/valuation/bill/delete/<%= bill.id %>" class="btn btn-sm text-danger">删除</a>-->
@@ -66,6 +75,7 @@
                     <tr>
                         <th>计价规则</th>
                         <th>启用/禁用</th>
+                        <th>适用类型</th>
                         <th>操作</th>
                     </tr>
                     </thead>
@@ -88,6 +98,11 @@
                             <% } %>
                         </td>
                         <td>
+
+                            
+                        </td>
+                        <td>
+                            <a class="copy-ration-valuation" data-id="<%= ration.id %>" href="javascript:void(0);" class="btn btn-sm">拷贝</a>
                             <a href="/compilation/valuation/ration/<%= ration.id %>" class="btn btn-sm">编辑</a>
                             <a href="/compilation/valuation/ration/delete/<%= ration.id %>" class="btn btn-sm text-danger">删除</a>
                         </td>
@@ -108,6 +123,21 @@
                         <% }) %>
                     </select>
                 </td></tr>
+              
+                <tr><td><p>默认工程所在地</p>
+                    <select class="form-control" style="width:200px" id="location-select">
+                        <option value=""></option>
+                        <% locationList.forEach(function(location) { %>
+                            <option value="<%= location %>" <% if (selectedCompilation.defaultLocation !== undefined && location === selectedCompilation.defaultLocation) { %>selected="selected"<% } %> ><%= location %></option>
+                            <% }) %>
+                    </select>
+                </td></tr>
+                <tr>
+                    <td>
+                        <p><span> 提供免费版:</span> <input type="checkbox" id="freeUse"  <% if (selectedCompilation.freeUse) { %> checked <% } %>></p>       
+                    </td>
+                </tr>
+                <tr><td><span>版本号:</span><input class="form-control" type="text" id="edition" value="<%= selectedCompilation.edition%>"></td></tr>  
             </table>
         </div>
         <input type="hidden" name="id" value="<%= selectedCompilation._id %>" id="compilation-id">

+ 23 - 0
web/users/views/compilation/modal.html

@@ -456,4 +456,27 @@
     </div>
 </div>
 
+<div class="modal fade in" id="copy-valuation-modal" 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">
+                <div class="form-group">
+                    <label>计价规则</label>
+                    <input class="form-control" placeholder="请输入新的计价规则" id="valuation-name">
+                </div>
+            </div>
+            <div class="modal-footer" style="justify-content: center">
+                <button type="button" class="btn btn-primary" data-dismiss="modal" id="copy-valuation-confirm">是</button>
+                <button type="button" class="btn btn-primary" data-dismiss="modal">否</button>
+            </div>
+        </div>
+    </div>
+</div>
+
 <script type="text/javascript" src="/web/users/js/col_setting.js"></script>

+ 32 - 4
web/users/views/system/index.html

@@ -15,35 +15,63 @@
                     <div class="form-group col-lg-4">
                         <label>软件供应商</label>
                         <% if (superAdmin === 1) { %>
-                            <input class="form-control" type="text" name="company" value="<%= setting.company %>">
+                            <input class="form-control" type="text" name="company" value="<%= setting.company %>"  placeholder="请输入软件供应商">
 
                         <% } else { %>
                             <input class="form-control" type="text" name="company" value="<%= setting.company %>" disabled="disabled">
 
                         <% } %>
                     </div>
+                    <div class="form-group col-lg-4">
+                        <label>大司空显示版本号</label>
+                        <% if (superAdmin === 1) { %>
+                            <input class="form-control" type="text" name="dskVersion" value="<%= setting.dskVersion %>" placeholder="请输入大司空显示版本号">
+
+                        <% } else { %>
+                            <input class="form-control" type="text" name="dskVersion" value="<%= setting.dskVersion %>" disabled="disabled">
+
+                        <% } %>
+                    </div>
                 </div>
                 <div class="row">
                     <div class="form-group col-lg-4">
                         <label>名称</label>
                         <% if (superAdmin === 1) { %>
-                            <input class="form-control" type="text" name="product" value="<%= setting.product %>">
+                            <input class="form-control" type="text" name="product" value="<%= setting.product %>"  placeholder="请输入名称">
 
                         <% } else { %>
                             <input class="form-control" type="text" name="product" value="<%= setting.product %>" disabled="disabled">
 
                         <% } %>
                     </div>
+                    <div class="form-group col-lg-4">
+                        <label>平台显示版本号</label>
+                        <% if (superAdmin === 1) { %>
+                            <input class="form-control" type="text" name="platformVersion" placeholder="请输入平台显示版本号" value="<%= setting.platformVersion %>">
+
+                        <% } else { %>
+                            <input class="form-control" type="text" name="platformVersion" value="<%= setting.platformVersion %>" disabled="disabled">
+
+                        <% } %>
+                    </div>
                 </div>
                 <div class="row">
                     <div class="form-group col-lg-4">
-                        <label>版本号</label>
+                        <label>计算版本号</label>
                         <% if (superAdmin === 1) { %>
-                            <input class="form-control" type="text" value="<%= setting.version %>" name="version" placeholder="请输入产品版本号">
+                            <input class="form-control" type="text" value="<%= setting.version %>" name="version" placeholder="请输入计算版本号">
                         <% } else { %>
                                 <input class="form-control" type="text" value="<%= setting.version %>" name="version" disabled="disabled">
                         <% } %>
                     </div>
+                    <div class="form-group col-lg-4">
+                        <label>更新日期</label>
+                        <% if (superAdmin === 1) { %>
+                            <input class="form-control" type="text" value="<%= setting.updateDate %>" name="updateDate" placeholder="请输入更新日期">
+                        <% } else { %>
+                                <input class="form-control" type="text" value="<%= setting.updateDate %>" name="updateDate" disabled="disabled">
+                        <% } %>
+                    </div>
                 </div>
             </div>
             <div class="c-header">