Просмотр исходного кода

Merge branch 'master' of http://smartcost.f3322.net:3000/SmartCost/ConstructionOperation

zhongzewei 8 лет назад
Родитель
Сommit
3055542488
32 измененных файлов с 1133 добавлено и 259 удалено
  1. 2 0
      Dockerfile
  2. 15 0
      Dockerfile_qa
  3. 4 14
      config/config.js
  4. 64 0
      modules/common/const/bills_fixed.js
  5. 56 0
      modules/common/std/schemas/std_fee_rate_libs.js
  6. 50 0
      modules/common/std/std_fee_rate_libs_model.js
  7. 58 14
      modules/reports/controllers/rpt_controller.js
  8. 4 1
      modules/reports/routes/report_router.js
  9. 4 1
      modules/reports/rpt_component/jpc_ex.js
  10. 144 17
      modules/reports/util/rpt_excel_util.js
  11. 111 11
      modules/users/controllers/compilation_controller.js
  12. 2 2
      modules/users/models/bills_template_model.js
  13. 42 36
      modules/users/models/compilation_model.js
  14. 160 0
      modules/users/models/engineering_lib_model.js
  15. 10 0
      modules/users/models/schemas/bills_template.js
  16. 12 17
      modules/users/models/schemas/compilation.js
  17. 47 0
      modules/users/models/schemas/engineering_lib.js
  18. 2 0
      modules/users/routes/compilation_route.js
  19. 1 1
      operation.js
  20. 7 0
      public/fsUtil.js
  21. 3 0
      public/web/rpt_value_define.js
  22. 3 0
      public/web/tree_sheet/tree_sheet_helper.js
  23. 19 2
      test/calculation/testJSCalc.js
  24. 1 1
      web/maintain/report/js/jpc_output.js
  25. 1 0
      web/maintain/report/js/jpc_output_value_define.js
  26. 10 0
      web/maintain/report/rpt_test.html
  27. 61 40
      web/users/js/compilation.js
  28. 83 7
      web/users/js/template.js
  29. 26 95
      web/users/views/compilation/add.html
  30. 120 0
      web/users/views/compilation/engineering.html
  31. 10 0
      web/users/views/compilation/modal.html
  32. 1 0
      web/users/views/compilation/template.html

+ 2 - 0
Dockerfile

@@ -10,4 +10,6 @@ RUN cnpm install
 
 
 EXPOSE 6080
 EXPOSE 6080
 
 
+ENV NODE_ENV=prod
+
 ENTRYPOINT babel-node operation.js
 ENTRYPOINT babel-node operation.js

+ 15 - 0
Dockerfile_qa

@@ -0,0 +1,15 @@
+FROM server:2.0
+
+COPY . ConstructionOperation
+
+WORKDIR ConstructionOperation
+
+RUN mkdir tmp
+
+RUN cnpm install
+
+EXPOSE 6080
+
+ENV NODE_ENV=qa
+
+ENTRYPOINT babel-node operation.js

+ 4 - 14
config/config.js

@@ -3,20 +3,10 @@ module.exports = {
     local: {server: "localhost", port: "27017"},
     local: {server: "localhost", port: "27017"},
     qa: {server: "192.168.1.184", port: "60666"},
     qa: {server: "192.168.1.184", port: "60666"},
     prod: {server: "", port: ""},
     prod: {server: "", port: ""},
-    setToLocalDb: function() {
-        var me = this;
-        me.current.server = me.local.server;
-        me.current.port = me.local.port;
-    },
-    setToQaDb: function() {
-        var me = this;
-        me.current.server = me.qa.server;
-        me.current.port = me.qa.port;
-    },
-    setToProdDb: function() {
-        var me = this;
-        me.current.server = me.prod.server;
-        me.current.port = me.prod.port;
+    setupDb:function (env="local") {
+        let me = this;
+        me.current.server = me[env].server;
+        me.current.port = me[env].port;
     },
     },
     pageSize: 30
     pageSize: 30
 }
 }

+ 64 - 0
modules/common/const/bills_fixed.js

@@ -0,0 +1,64 @@
+/**
+ * Created by Mai on 2017/8/29.
+ */
+
+const fixedFlag = {
+    // 分部分项工程
+    SUB_ENGINERRING: 1,
+    // 措施项目
+    MEASURE: 2,
+    // 施工技术措施项目
+    CONSTRUCTION_TECH: 3,
+    // 安全文明施工按实计算费用
+    SAFETY_CONSTRUCTION_ACTUAL: 4,
+    // 施工组织措施专项费用
+    CONSTRUCTION_ORGANIZATION: 5,
+    // 安全文明施工专项费用
+    SAFETY_CONSTRUCTION: 6,
+    // 其他项目
+    OTHER: 7,
+    // 暂列金额
+    PROVISIONAL: 8,
+    // 暂估价
+    ESTIMATE: 9,
+    // 材料(工程设备)暂估价
+    MATERIAL_PROVISIONAL: 10,
+    // 专业工程暂估价
+    ENGINEERING_ESITIMATE: 11,
+    // 计日工
+    DAYWORK: 12,
+    // 总承包服务费
+    TURN_KEY_CONTRACT: 13,
+    // 索赔与现场签证
+    CLAIM_VISA: 14,
+    // 规费
+    CHARGE: 15,
+    // 社会保险费及住房公积金 Social insurance fee and housing accumulation fund
+    SOCIAL_INSURANCE_HOUSING_FUND: 16,
+    // 工程排污费 charges for disposing pollutants
+    POLLUTANTS: 17,
+    // 税金
+    TAX: 18
+};
+const fixedFlagList = [
+    {name: "分部分项工程", value: fixedFlag.SUB_ENGINERRING},
+    {name: "措施项目", value: fixedFlag.MEASURE},
+    {name: "施工技术措施项目", value: fixedFlag.CONSTRUCTION_TECH},
+    {name: "安全文明施工按实计算费用", value: fixedFlag.SAFETY_CONSTRUCTION_ACTUAL},
+    {name: "施工组织措施专项费用", value: fixedFlag.CONSTRUCTION_ORGANIZATION},
+    {name: "安全文明施工专项费用", value: fixedFlag.SAFETY_CONSTRUCTION},
+    {name: "其他项目", value: fixedFlag.OTHER},
+    {name: "暂列金额", value: fixedFlag.PROVISIONAL},
+    {name: "暂估价", value: fixedFlag.ESTIMATE},
+    {name: "材料(工程设备)暂估价", value: fixedFlag.MATERIAL_PROVISIONAL},
+    {name: "专业工程暂估价", value: fixedFlag.ENGINEERING_ESITIMATE},
+    {name: "计日工", value: fixedFlag.DAYWORK},
+    {name: "总承包服务费", value: fixedFlag.TURN_KEY_CONTRACT},
+    {name: "索赔与现场签证", value: fixedFlag.CLAIM_VISA},
+    {name: "规费", value: fixedFlag.CHARGE},
+    {name: "社会保险费及住房公积金", value: fixedFlag.SOCIAL_INSURANCE_HOUSING_FUND},
+    {name: "工程排污费", value: fixedFlag.POLLUTANTS},
+    {name: "税金", value: fixedFlag.TAX}
+];
+
+export {fixedFlag as default, fixedFlagList as List};

+ 56 - 0
modules/common/std/schemas/std_fee_rate_libs.js

@@ -0,0 +1,56 @@
+/**
+ * 费率标准库数据模型
+ *
+ * @author CaiAoLin
+ * @date 2017/8/30
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'std_fee_rate_libs';
+
+let optionSchema = new Schema({
+    name:String,
+    value:String,
+    selected:Boolean
+}, {_id: false});
+
+let recordSchema = new Schema({
+    ID:Number,
+    name:String,
+    optionList:[optionSchema]
+}, {_id: false});
+
+let valueMapSchema = new Schema({
+    ID:String,
+    value:Number
+}, {_id: false});
+
+let subFeeRatesSchema = new Schema({
+    recodes :[recordSchema],
+    valueMaps:[valueMapSchema],
+}, {_id: false});
+
+let ratesSchema = new Schema({
+    ID: Number,
+    ParentID: Number,
+    name: String,
+    rate: Number,
+    memo: String,
+    subFeeRate:subFeeRatesSchema
+}, {_id: false});
+
+let modelSchema = {
+    // 自增id
+    ID: String,
+    // 工程所在地
+    region: String,
+    // 标准名称
+    libName: String,
+    // 费率数据
+    rates: [ratesSchema]
+};
+
+let model = mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));
+export {model as default, collectionName as collectionName};

+ 50 - 0
modules/common/std/std_fee_rate_libs_model.js

@@ -0,0 +1,50 @@
+/**
+ * 费率文件标准库业务逻辑
+ *
+ * @author CaiAoLin
+ * @date 2017/8/30
+ * @version
+ */
+import BaseModel from "../base/base_model";
+import STDFeeRateLibsSchema from "./schemas/std_fee_rate_libs";
+
+class STDFeeRateLibsModel extends BaseModel {
+
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = STDFeeRateLibsSchema;
+        parent.init();
+    }
+
+    /**
+     * 获取费率列表
+     *
+     * @return {Promise}
+     */
+    async getFeeRateList() {
+        let result = [];
+        let field = {ID: 1, libName: 1};
+        let feeRateList = await this.findDataByCondition({ID: {$ne: ''}}, field, false);
+
+        if (feeRateList === null) {
+            return result;
+        }
+        // 整理数据
+        for(let feeRate of feeRateList) {
+            let tmpData = {
+                id: feeRate.ID,
+                name: feeRate.libName
+            };
+            result.push(tmpData);
+        }
+        return result;
+    }
+
+}
+
+export default STDFeeRateLibsModel;

+ 58 - 14
modules/reports/controllers/rpt_controller.js

@@ -3,6 +3,7 @@
  */
  */
 
 
 let mongoose = require('mongoose');
 let mongoose = require('mongoose');
+let async = require('async');
 
 
 let JV = require('../rpt_component/jpc_value_define');
 let JV = require('../rpt_component/jpc_value_define');
 
 
@@ -28,7 +29,7 @@ let callback = function(req, res, err, data){
     }
     }
 };
 };
 
 
-function getAllPagesCommonOrg(req, res, rpt_id, pageSize, cb) {
+function getAllPagesCommonOrg(rpt_id, pageSize, cb) {
     let rptTpl = null;
     let rptTpl = null;
     rptTplFacade.getRptTemplate(rpt_id).then(function(rst) {
     rptTplFacade.getRptTemplate(rpt_id).then(function(rst) {
         rptTpl = rst;
         rptTpl = rst;
@@ -36,10 +37,12 @@ function getAllPagesCommonOrg(req, res, rpt_id, pageSize, cb) {
             if (rptTpl.ID_KEY) {
             if (rptTpl.ID_KEY) {
                 return demoTemplateFacade.getDemoData(rptTpl.ID_KEY);
                 return demoTemplateFacade.getDemoData(rptTpl.ID_KEY);
             } else {
             } else {
-                callback(req, res, 'No report template data were found!', null);
+                //callback(req, res, 'No report template data were found!', null);
+                cb('No report template data were found!', null);
             }
             }
         } else {
         } else {
-            callback(req, res, 'No report template was found!', null);
+            //callback(req, res, 'No report template was found!', null);
+            cb('No report template was found!', null);
         }
         }
     }).then(function(tplData){
     }).then(function(tplData){
             if (tplData) {
             if (tplData) {
@@ -51,18 +54,20 @@ function getAllPagesCommonOrg(req, res, rpt_id, pageSize, cb) {
                 let maxPages = printCom.totalPages;
                 let maxPages = printCom.totalPages;
                 let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
                 let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
                 if (pageRst) {
                 if (pageRst) {
-                    cb(pageRst);
+                    cb(null, pageRst);
                 } else {
                 } else {
-                    callback(req, res, "Have errors while on going...", null);
+                    //callback(req, res, "Have errors while on going...", null);
+                    cb('Have errors while on going...', null);
                 }
                 }
             } else {
             } else {
-                callback(req, res, 'No report data were found!', null);
+                //callback(req, res, 'No report data were found!', null);
+                cb('No report data were found!', null);
             }
             }
         }
         }
     );
     );
 };
 };
 
 
-function getAllPagesCommon(req, res, rpt_id, pageSize, cb) {
+function getAllPagesCommon(rpt_id, pageSize, cb) {
     let rptTpl = null;
     let rptTpl = null;
     rptTplFacade.getRptTemplate(rpt_id).then(function(rst) {
     rptTplFacade.getRptTemplate(rpt_id).then(function(rst) {
         rptTpl = rst;
         rptTpl = rst;
@@ -96,10 +101,10 @@ function getAllPagesCommon(req, res, rpt_id, pageSize, cb) {
                 //return demoTemplateData.findOne({"Data_Key": rptTpl.ID_KEY}).exec();
                 //return demoTemplateData.findOne({"Data_Key": rptTpl.ID_KEY}).exec();
 
 
             } else {
             } else {
-                callback(req, res, 'No report template data were found!', null);
+                cb('No report template data were found!', null);
             }
             }
         } else {
         } else {
-            callback(req, res, 'No report template was found!', null);
+            cb('No report template was found!', null);
         }
         }
     })
     })
 };
 };
@@ -108,9 +113,9 @@ module.exports = {
     getReportAllPages: function(req, res){
     getReportAllPages: function(req, res){
         let rpt_id = req.body.ID;
         let rpt_id = req.body.ID;
         let pageSize = req.body.pageSize;
         let pageSize = req.body.pageSize;
-        getAllPagesCommonOrg(req, res, rpt_id, pageSize, function(pageRst){
+        getAllPagesCommonOrg(rpt_id, pageSize, function(err, pageRst){
             //fs.writeFileSync('D:/GitHome/ConstructionOperation/tmp/testRpt.js', JSON.stringify(pageRst));
             //fs.writeFileSync('D:/GitHome/ConstructionOperation/tmp/testRpt.js', JSON.stringify(pageRst));
-            callback(req, res, null, pageRst);
+            callback(req, res, err, pageRst);
         })
         })
     },
     },
     getExcel: function(req, res) {
     getExcel: function(req, res) {
@@ -119,8 +124,8 @@ module.exports = {
             rptName = req.params.rptName,
             rptName = req.params.rptName,
             isOneSheet = req.params.isOneSheet;
             isOneSheet = req.params.isOneSheet;
         ;
         ;
-        getAllPagesCommonOrg(req, res, rpt_id, pageSize, function(pageRst){
-            rpt_xl_util.exportExcel(pageRst, pageSize, rptName, isOneSheet, function(newName){
+        getAllPagesCommonOrg(rpt_id, pageSize, function(err, pageRst){
+            rpt_xl_util.exportExcel(pageRst, pageSize, rptName, isOneSheet, null, function(newName){
                 res.setHeader('Content-Type', 'application/vnd.openxmlformats');
                 res.setHeader('Content-Type', 'application/vnd.openxmlformats');
                 res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".xlsx");
                 res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".xlsx");
                 let filestream = fs.createReadStream(__dirname.slice(0, __dirname.length - 28) + '/tmp/' + newName + '.xlsx');
                 let filestream = fs.createReadStream(__dirname.slice(0, __dirname.length - 28) + '/tmp/' + newName + '.xlsx');
@@ -133,12 +138,51 @@ module.exports = {
             });
             });
         })
         })
     },
     },
+    getExcelInOneBook: function(req, res) {
+        let rpt_ids = req.params.ids.split(','),
+            pageSize = req.params.size,
+            rptName = req.params.rptName;
+        ;
+        let parallelFucs = [];
+        for (let id of rpt_ids) {
+            parallelFucs.push((function (rpt_id) {
+                return function (cb) {
+                    getAllPagesCommonOrg(rpt_id, pageSize, function (err, pageRst) {
+                        if(err){
+                            cb(err);
+                        }
+                        else{
+                            cb(null, pageRst);
+                        }
+                    })
+                }
+            })(parseInt(id)));
+        }
+        async.parallel(parallelFucs, function (err, pageRstArray) {
+            if (err) {
+                callback(req, res, '数据有误', null);
+            } else {
+                rpt_xl_util.exportExcelInOneBook(pageRstArray, pageSize, rptName, function(tmpFilePath){
+                    res.setHeader('Content-Type', 'application/vnd.openxmlformats');
+                    res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".xlsx");
+                    let filestream = fs.createReadStream(__dirname.slice(0, __dirname.length - 28) + '/tmp/' + tmpFilePath + '.xlsx');
+                    filestream.on('data', function(chunk) {
+                        res.write(chunk);
+                    });
+                    filestream.on('end', function() {
+                        res.end();
+                    });
+                });
+                //callback(req, res, false, '', {compilation: rst, gljLibs: gljLibsRst});
+            }
+        })
+    },
     getPDF:function (req, res) {
     getPDF:function (req, res) {
         let rpt_id = req.params.id,
         let rpt_id = req.params.id,
             pageSize = req.params.size,
             pageSize = req.params.size,
             rptName = req.params.rptName;
             rptName = req.params.rptName;
 
 
-        getAllPagesCommonOrg(req, res, rpt_id, pageSize, function(pageRst){
+        getAllPagesCommonOrg(rpt_id, pageSize, function(err, pageRst){
             rpt_pdf_util.export_pdf_file(pageRst, pageSize, rptName,function (newName) {
             rpt_pdf_util.export_pdf_file(pageRst, pageSize, rptName,function (newName) {
                 res.setHeader('Content-Type', 'application/vnd.openxmlformats');
                 res.setHeader('Content-Type', 'application/vnd.openxmlformats');
                 res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".pdf");
                 res.setHeader("Content-Disposition", "attachment; filename=" + strUtil.getPinYinCamelChars(rptName) + ".pdf");

+ 4 - 1
modules/reports/routes/report_router.js

@@ -18,7 +18,10 @@ module.exports =function (app) {
         }
         }
     });
     });
     rptRouter.post('/getReport', reportController.getReportAllPages);
     rptRouter.post('/getReport', reportController.getReportAllPages);
+
     rptRouter.get('/getExcel/:id/:size/:rptName/:isOneSheet', reportController.getExcel);
     rptRouter.get('/getExcel/:id/:size/:rptName/:isOneSheet', reportController.getExcel);
-        rptRouter.get('/getPDF/:id/:size/:rptName', reportController.getPDF);//2/A4/07-1表
+    rptRouter.get('/getExcelInOneBook/:ids/:size/:rptName', reportController.getExcelInOneBook);
+
+    rptRouter.get('/getPDF/:id/:size/:rptName', reportController.getPDF);//2/A4/07-1表
     app.use("/report_api", rptRouter);
     app.use("/report_api", rptRouter);
 }
 }

+ 4 - 1
modules/reports/rpt_component/jpc_ex.js

@@ -169,7 +169,10 @@ JpcExSrv.prototype.createNew = function(){
             rst[JV.NODE_CONTROL_COLLECTION] = private_buildDftControls(rptTpl, (defProperties == null)?null:defProperties.ctrls);
             rst[JV.NODE_CONTROL_COLLECTION] = private_buildDftControls(rptTpl, (defProperties == null)?null:defProperties.ctrls);
             rst[JV.NODE_STYLE_COLLECTION] = private_buildDftStyles(rptTpl, (defProperties == null)?null:defProperties.styles);
             rst[JV.NODE_STYLE_COLLECTION] = private_buildDftStyles(rptTpl, (defProperties == null)?null:defProperties.styles);
             rst[JV.NODE_FONT_COLLECTION] = private_buildDftFonts(rptTpl, (defProperties == null)?null:defProperties.fonts);
             rst[JV.NODE_FONT_COLLECTION] = private_buildDftFonts(rptTpl, (defProperties == null)?null:defProperties.fonts);
-            rst[JV.NODE_PAGE_INFO] = JpcCommonHelper.getPageSize(rptTpl);
+            rst[JV.NODE_PAGE_INFO] = {};
+            rst[JV.NODE_PAGE_INFO][JV.NODE_MAIN_INFO_RPT_NAME] = rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MAIN_INFO_RPT_NAME];
+            rst[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE] = JpcCommonHelper.getPageSize(rptTpl);
+            rst[JV.NODE_PAGE_INFO][JV.NODE_MARGINS] = rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS];
             rst.items = [];
             rst.items = [];
             let bands = JpcBand.createNew(rptTpl, defProperties);
             let bands = JpcBand.createNew(rptTpl, defProperties);
             try {
             try {

+ 144 - 17
modules/reports/util/rpt_excel_util.js

@@ -7,6 +7,7 @@ let JSZip = require("jszip");
 let strUtil = require('../../../public/stringUtil');
 let strUtil = require('../../../public/stringUtil');
 let jpcCmnHelper = require('../rpt_component/helper/jpc_helper_common');
 let jpcCmnHelper = require('../rpt_component/helper/jpc_helper_common');
 let DPI = jpcCmnHelper.getScreenDPI()[0];
 let DPI = jpcCmnHelper.getScreenDPI()[0];
+let fsUtil = require('../../../public/fsUtil');
 const dftHeadXml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
 const dftHeadXml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
 
 
 function writeContentTypes(sheets, isSinglePage) {
 function writeContentTypes(sheets, isSinglePage) {
@@ -331,6 +332,7 @@ function writeSheets(pageData, paperSize, sharedStrList, stylesObj, isSinglePage
 function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
 function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
     let rst = [], xPos = [], yPos = [], yMultiPos = [], headerStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
     let rst = [], xPos = [], yPos = [], yMultiPos = [], headerStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
     let cacheBorderCell = {};
     let cacheBorderCell = {};
+    let currentPageMergePos = null;
     let private_pre_analyze_pos = function(){
     let private_pre_analyze_pos = function(){
         let cell, pos;
         let cell, pos;
         let self_analyze_sheet_pos = function (theShtData, theXPos, theYPos) {
         let self_analyze_sheet_pos = function (theShtData, theXPos, theYPos) {
@@ -446,22 +448,22 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
         borderLineWidths.push(border[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]);
         borderLineWidths.push(border[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]);
         borderLineWidths.push(border[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]);
         borderLineWidths.push(border[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]);
         if (sheetBorder[JV.PROP_LEFT] && sheetBorder[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT]) {
         if (sheetBorder[JV.PROP_LEFT] && sheetBorder[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT]) {
-            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_LEFT));
+            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_LEFT, true));
         } else {
         } else {
             sheetBorderLineWidths.push(0);
             sheetBorderLineWidths.push(0);
         }
         }
         if (sheetBorder[JV.PROP_RIGHT] && sheetBorder[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT]) {
         if (sheetBorder[JV.PROP_RIGHT] && sheetBorder[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT]) {
-            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_RIGHT));
+            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_RIGHT, true));
         } else {
         } else {
             sheetBorderLineWidths.push(0);
             sheetBorderLineWidths.push(0);
         }
         }
         if (sheetBorder[JV.PROP_TOP] && sheetBorder[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]) {
         if (sheetBorder[JV.PROP_TOP] && sheetBorder[JV.PROP_TOP][JV.PROP_LINE_WEIGHT]) {
-            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_TOP));
+            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_TOP, false));
         } else {
         } else {
             sheetBorderLineWidths.push(0);
             sheetBorderLineWidths.push(0);
         }
         }
         if (sheetBorder[JV.PROP_BOTTOM] && sheetBorder[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]) {
         if (sheetBorder[JV.PROP_BOTTOM] && sheetBorder[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT]) {
-            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_BOTTOM));
+            sheetBorderLineWidths.push(private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_BOTTOM, false));
         } else {
         } else {
             sheetBorderLineWidths.push(0);
             sheetBorderLineWidths.push(0);
         }
         }
@@ -473,14 +475,45 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
         }
         }
         return rst;
         return rst;
     };
     };
-    let private_chkAndGetMergeLine = function(cell, sheetBorder, borderStr) {
+    let private_chkAndGetMergeLine = function(cell, sheetBorder, borderStr, needFurtherChk) {
         let rst = 0, mergeBorder = pageData[JV.BAND_PROP_MERGE_BAND];
         let rst = 0, mergeBorder = pageData[JV.BAND_PROP_MERGE_BAND];
-        if (sheetBorder[borderStr] && sheetBorder[borderStr][JV.PROP_LINE_WEIGHT] != undefined) {
+        if (sheetBorder[borderStr] && sheetBorder[borderStr][JV.PROP_LINE_WEIGHT] !== undefined) {
             rst = sheetBorder[borderStr][JV.PROP_LINE_WEIGHT];
             rst = sheetBorder[borderStr][JV.PROP_LINE_WEIGHT];
         }
         }
-        if (cell[JV.PROP_AREA][borderStr] == mergeBorder[borderStr]) {
-            let destStyle = pageData[JV.NODE_STYLE_COLLECTION][mergeBorder[JV.PROP_STYLE][JV.PROP_ID]];
-            rst = destStyle[borderStr][JV.PROP_LINE_WEIGHT];
+        if (currentPageMergePos) {
+            let side = currentPageMergePos[borderStr];
+            if (side.indexOf(cell[JV.PROP_AREA][borderStr]) >= 0) {
+                if (needFurtherChk) {
+                    let topSide = currentPageMergePos[JV.PROP_TOP];
+                    let bottomSide = currentPageMergePos[JV.PROP_BOTTOM];
+                    for (let i = 0; i < topSide.length; i++) {
+                        if (cell[JV.PROP_AREA][JV.PROP_TOP] >= topSide[i]) {
+                            if (cell[JV.PROP_AREA][JV.PROP_BOTTOM] <= bottomSide[i]) {
+                                let destStyle = pageData[JV.NODE_STYLE_COLLECTION][mergeBorder[JV.PROP_STYLE][JV.PROP_ID]];
+                                rst = destStyle[borderStr][JV.PROP_LINE_WEIGHT];
+                                break;
+                            }
+                        } else {
+                            break;
+                        }
+                    }
+                } else {
+                    let destStyle = pageData[JV.NODE_STYLE_COLLECTION][mergeBorder[JV.PROP_STYLE][JV.PROP_ID]];
+                    rst = destStyle[borderStr][JV.PROP_LINE_WEIGHT];
+                }
+            }
+        } else {
+            if (cell[JV.PROP_AREA][borderStr] === mergeBorder[borderStr]) {
+                let destStyle = pageData[JV.NODE_STYLE_COLLECTION][mergeBorder[JV.PROP_STYLE][JV.PROP_ID]];
+                if (needFurtherChk) {
+                    if (cell[JV.PROP_AREA][JV.PROP_TOP] >= mergeBorder[JV.PROP_TOP] &&
+                        cell[JV.PROP_AREA][JV.PROP_BOTTOM] <= mergeBorder[JV.PROP_BOTTOM]) {
+                        rst = destStyle[borderStr][JV.PROP_LINE_WEIGHT];
+                    }
+                } else {
+                    rst = destStyle[borderStr][JV.PROP_LINE_WEIGHT];
+                }
+            }
         }
         }
         return parseInt(rst);
         return parseInt(rst);
     };
     };
@@ -503,10 +536,10 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
         }
         }
         let sheetBorder = pageData[JV.NODE_STYLE_COLLECTION][cell.style];
         let sheetBorder = pageData[JV.NODE_STYLE_COLLECTION][cell.style];
         let mergedBorder = private_getIniBorder();
         let mergedBorder = private_getIniBorder();
-        mergedBorder[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_LEFT);
-        mergedBorder[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_RIGHT);
-        mergedBorder[JV.PROP_TOP][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_TOP);
-        mergedBorder[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_BOTTOM);
+        mergedBorder[JV.PROP_LEFT][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_LEFT, true);
+        mergedBorder[JV.PROP_RIGHT][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_RIGHT, true);
+        mergedBorder[JV.PROP_TOP][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_TOP, false);
+        mergedBorder[JV.PROP_BOTTOM][JV.PROP_LINE_WEIGHT] = private_chkAndGetMergeLine(cell, sheetBorder, JV.PROP_BOTTOM, false);
         for (let i = 0; i < stylesObj.borders.length; i++) {
         for (let i = 0; i < stylesObj.borders.length; i++) {
             let border = stylesObj.borders[i];
             let border = stylesObj.borders[i];
             if (private_checkBorder(cell, border, mergedBorder)) {
             if (private_checkBorder(cell, border, mergedBorder)) {
@@ -723,12 +756,14 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
         private_cacheMergeBandBorderIdxs();
         private_cacheMergeBandBorderIdxs();
         if (sheetData) {
         if (sheetData) {
             //current sheet data
             //current sheet data
+            currentPageMergePos = sheetData[JV.PAGE_SPECIAL_MERGE_POS];
             self_setDataEx(sheetData, yPos, 0);
             self_setDataEx(sheetData, yPos, 0);
         } else {
         } else {
             //total data in one sheet
             //total data in one sheet
             let cnt = 0;
             let cnt = 0;
             for (let i = 0; i < pageData.items.length; i++) {
             for (let i = 0; i < pageData.items.length; i++) {
                 let shtItemData = pageData.items[i];
                 let shtItemData = pageData.items[i];
+                currentPageMergePos = shtItemData[JV.PAGE_SPECIAL_MERGE_POS];
                 let tmpPos = yMultiPos[i];
                 let tmpPos = yMultiPos[i];
                 cellIdx = 0;
                 cellIdx = 0;
                 self_setDataEx(shtItemData, tmpPos, cnt);
                 self_setDataEx(shtItemData, tmpPos, cnt);
@@ -758,15 +793,30 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
     if (paperSizeIdx >= 0) {
     if (paperSizeIdx >= 0) {
         pStr = 'paperSize="' + JV.PAGES_SIZE_IDX[paperSizeIdx] + '"';
         pStr = 'paperSize="' + JV.PAGES_SIZE_IDX[paperSizeIdx] + '"';
     }
     }
-    let orientationStr = (pageData[JV.NODE_PAGE_INFO][0] > pageData[JV.NODE_PAGE_INFO][1])?'landscape':'portrait';
+    let orientationStr = (pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][0] > pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][1])?'landscape':'portrait';
     rst.push('<pageSetup ' + pStr + ' fitToWidth="0" fitToHeight="0" orientation="' + orientationStr + '" />');
     rst.push('<pageSetup ' + pStr + ' fitToWidth="0" fitToHeight="0" orientation="' + orientationStr + '" />');
     rst.push('<headerFooter alignWithMargins="0"/>');
     rst.push('<headerFooter alignWithMargins="0"/>');
     rst.push('</worksheet>');
     rst.push('</worksheet>');
     return rst;
     return rst;
 }
 }
 
 
+function mergeProperties(orgObj, newObj) {
+    let orgPropArr = [], newPropArr = [];
+    for (let p in orgObj) {
+        orgPropArr.push(p);
+    }
+    for (let p in newObj) {
+        newPropArr.push(p);
+    }
+    for (let i = 0; i < newPropArr.length; i++) {
+        if (orgPropArr.indexOf(newPropArr[i]) < 0) {
+            orgObj[newPropArr[i]] = newObj[newPropArr[i]];
+        }
+    }
+}
+
 module.exports = {
 module.exports = {
-    exportExcel: function (pageData, paperSize, fName, options, callback) {
+    exportExcel: function (pageData, paperSize, fName, options, custSheetNames, callback) {
         let rptOptions = ({singlePage: false, fileName: 'report'});
         let rptOptions = ({singlePage: false, fileName: 'report'});
         if (options === 'true') {
         if (options === 'true') {
             rptOptions.singlePage = true;
             rptOptions.singlePage = true;
@@ -776,8 +826,14 @@ module.exports = {
         if (isSinglePage) {
         if (isSinglePage) {
             sheets.push({sheetName: '全部页'});
             sheets.push({sheetName: '全部页'});
         } else {
         } else {
-            for (let i = 0; i < pageData.items.length; i++) {
-                sheets.push({sheetName: '第' + (i + 1) + '页'});
+            if (custSheetNames && custSheetNames.length === pageData.items.length) {
+                for (let i = 0; i < pageData.items.length; i++) {
+                    sheets.push({sheetName: custSheetNames[i]});
+                }
+            } else {
+                for (let i = 0; i < pageData.items.length; i++) {
+                    sheets.push({sheetName: '第' + (i + 1) + '页'});
+                }
             }
             }
         }
         }
         //1.
         //1.
@@ -849,5 +905,76 @@ module.exports = {
             //return zip.generateNodeStream({type:'nodebuffer',streamFiles:true});
             //return zip.generateNodeStream({type:'nodebuffer',streamFiles:true});
             return zip;
             return zip;
         }
         }
+    },
+
+    exportExcelInOneBook: function (pageDataArray, paperSize, fName, callback) {
+        let me = this, newPageData = {};
+        //1. 重新编排一下数据,把一份报表的pageData合并到一起作为一个Sheet输出(需要重新调整数据纵向坐标),多份报表数据就形成多个Sheet
+        //   -- 简单来说,就是重新包装数据
+        try {
+            // 1.1 newPageData外围属性
+            let newContrl = {}, newFont = {}, newStyle = {};
+            for (let i = 0; i < pageDataArray.length; i++) {
+                mergeProperties(newContrl, pageDataArray[i][JV.NODE_CONTROL_COLLECTION]);
+                mergeProperties(newFont, pageDataArray[i][JV.NODE_FONT_COLLECTION]);
+                mergeProperties(newStyle, pageDataArray[i][JV.NODE_STYLE_COLLECTION]);
+            }
+            newPageData[JV.NODE_CONTROL_COLLECTION] = newContrl;
+            newPageData[JV.NODE_FONT_COLLECTION] = newFont;
+            newPageData[JV.NODE_STYLE_COLLECTION] = newStyle;
+            newPageData[JV.NODE_PAGE_INFO] = pageDataArray[0][JV.NODE_PAGE_INFO];
+            newPageData[JV.BAND_PROP_MERGE_BAND] = pageDataArray[0][JV.BAND_PROP_MERGE_BAND];
+
+            // 1.2 重新设置pageDataArray的各个cell的Top/Bottom坐标
+            let sheetNames = [], newPagePos = [];
+            for (let i = 0; i < pageDataArray.length; i++) {
+                let offsetY = 0;
+                let mergeBand = {};
+                mergeBand[JV.PROP_LEFT] = [];
+                mergeBand[JV.PROP_RIGHT] = [];
+                mergeBand[JV.PROP_TOP] = [];
+                mergeBand[JV.PROP_BOTTOM] = [];
+                newPagePos.push(mergeBand);
+                mergeBand[JV.PROP_LEFT].push(pageDataArray[i][JV.BAND_PROP_MERGE_BAND][JV.PROP_LEFT]);
+                mergeBand[JV.PROP_RIGHT].push(pageDataArray[i][JV.BAND_PROP_MERGE_BAND][JV.PROP_RIGHT]);
+                sheetNames.push(pageDataArray[i][JV.NODE_PAGE_INFO][JV.NODE_MAIN_INFO_RPT_NAME]);
+
+                for (let j = 0; j < pageDataArray[i].items.length; j++) {
+                    let maxY = 0, minY = 100000;
+                    mergeBand[JV.PROP_TOP].push(pageDataArray[i][JV.BAND_PROP_MERGE_BAND][JV.PROP_TOP] + offsetY);
+                    mergeBand[JV.PROP_BOTTOM].push(pageDataArray[i][JV.BAND_PROP_MERGE_BAND][JV.PROP_BOTTOM] + offsetY);
+                    for (let k = 0; k < pageDataArray[i].items[j].cells.length; k++) {
+                        if (maxY < pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_BOTTOM]) {
+                            maxY = pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_BOTTOM];
+                        }
+                        if (minY > pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_TOP]) {
+                            minY = pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_TOP];
+                        }
+                        pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_BOTTOM] += offsetY;
+                        pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_TOP] += offsetY;
+                    }
+                    offsetY += (maxY - minY);
+                }
+            }
+            //2. newPageData的items属性
+            newPageData.items = [];
+            for (let i = 0; i < pageDataArray.length; i++) {
+                let pageItem = {};
+                pageItem[JV.PROP_PAGE_SEQ] = i + 1;
+                pageItem[JV.PROP_CELLS] = [];
+                for (let j = 0; j < pageDataArray[i].items.length; j++) {
+                    for (let k = 0; k < pageDataArray[i].items[j].cells.length; k++) {
+                        pageItem[JV.PROP_CELLS].push(pageDataArray[i].items[j].cells[k]);
+                    }
+                }
+                pageItem[JV.PAGE_SPECIAL_MERGE_POS] = newPagePos[i];
+                newPageData.items.push(pageItem);
+            }
+            //3. everything is ok, then call me
+            me.exportExcel(newPageData, paperSize, fName, 'false', sheetNames, callback);
+            fsUtil.wirteObjToFile(newPageData, 'D:/GitHome/ConstructionOperation/tmp/combinedHeader.js');
+        } catch (e) {
+            console.log(e);
+        }
     }
     }
 }
 }

+ 111 - 11
modules/users/controllers/compilation_controller.js

@@ -10,8 +10,11 @@ import CompilationModel from "../models/compilation_model";
 import STDRationLibMapModel from "../../common/std/std_ration_lib_map_model";
 import STDRationLibMapModel from "../../common/std/std_ration_lib_map_model";
 import STDBillLibListsModel from "../../common/std/std_bills_lib_lists_model";
 import STDBillLibListsModel from "../../common/std/std_bills_lib_lists_model";
 import STDGLJLibMapModel from "../../common/std/std_glj_lib_map_model";
 import STDGLJLibMapModel from "../../common/std/std_glj_lib_map_model";
+import STDFeeRateLibsModel from "../../common/std/std_fee_rate_libs_model";
 import {default as EngineeringConst, List as EngineeringList} from "../../common/const/engineering";
 import {default as EngineeringConst, List as EngineeringList} from "../../common/const/engineering";
 import BillsTemplateModel from "../models/bills_template_model";
 import BillsTemplateModel from "../models/bills_template_model";
+import {default as BillsFixedFlagConst, List as BillsFixedFlagList} from "../../common/const/bills_fixed.js";
+import EngineeringLibModel from "../models/engineering_lib_model";
 
 
 class CompilationController extends BaseController {
 class CompilationController extends BaseController {
 
 
@@ -111,13 +114,70 @@ class CompilationController extends BaseController {
         let valuationId = request.params.id;
         let valuationId = request.params.id;
         let section = request.params.section;
         let section = request.params.section;
 
 
-        let billList = {};
-        let rationList = {};
         let compilationList = [];
         let compilationList = [];
         let valuationData = {};
         let valuationData = {};
         let valuationList = {};
         let valuationList = {};
+        try {
+            let compilationModel = new CompilationModel();
+            compilationList = await compilationModel.getCompilationList();
+
+            // 获取对应的计价规则数据
+            [valuationData, valuationList] = await compilationModel.getValuation(selectedCompilation._id, valuationId, section);
+            if (Object.keys(valuationData).length <= 0) {
+                throw '不存在数据';
+            }
+
+        } catch (error) {
+            console.log(error);
+        }
+
+        let renderData = {
+            compilationList: compilationList,
+            engineeringList: EngineeringList,
+            selectedCompilation: selectedCompilation,
+            valuationData: valuationData,
+            valuationList: valuationList,
+            valuationId: valuationId,
+            section: section,
+            layout: 'users/views/layout/layout'
+        };
+        response.render('users/views/compilation/add', renderData);
+    }
+
+    /**
+     * 编辑工程专业页面
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async editEngineering(request, response) {
+        let engineering = parseInt(request.params.engineering);
+        let valuationId = request.params.id;
+        let section = request.params.section;
+        let selectedCompilation = request.session.selectedCompilation;
+
+        // 获取当前工程专业名称
+        let engineeringInfo = {
+            id: engineering,
+            name: ''
+        };
+        for(let tmp of EngineeringList) {
+            if (tmp.value === engineering) {
+                engineeringInfo.name = tmp.name;
+                break;
+            }
+        }
+
+        let compilationList = [];
+        let billList = [];
+        let rationList = [];
         let gljList = [];
         let gljList = [];
+        let feeRateList = [];
+        let libData = {};
         let billsTemplateData = [];
         let billsTemplateData = [];
+        let valuationData = {};
+        let valuationList = {};
         try {
         try {
             let compilationModel = new CompilationModel();
             let compilationModel = new CompilationModel();
             compilationList = await compilationModel.getCompilationList();
             compilationList = await compilationModel.getCompilationList();
@@ -134,12 +194,20 @@ class CompilationController extends BaseController {
             let stdGLJLibMapModel = new STDGLJLibMapModel();
             let stdGLJLibMapModel = new STDGLJLibMapModel();
             gljList = await stdGLJLibMapModel.getGLJLibList(selectedCompilation._id);
             gljList = await stdGLJLibMapModel.getGLJLibList(selectedCompilation._id);
 
 
+            // 获取费率库
+            let stdFeeRateLibsModel = new STDFeeRateLibsModel();
+            feeRateList = await stdFeeRateLibsModel.getFeeRateList();
+
             // 获取对应的计价规则数据
             // 获取对应的计价规则数据
             [valuationData, valuationList] = await compilationModel.getValuation(selectedCompilation._id, valuationId, section);
             [valuationData, valuationList] = await compilationModel.getValuation(selectedCompilation._id, valuationId, section);
             if (Object.keys(valuationData).length <= 0) {
             if (Object.keys(valuationData).length <= 0) {
                 throw '不存在数据';
                 throw '不存在数据';
             }
             }
 
 
+            // 获取对应专业工程下的标准库数据
+            let engineeringLibModel = new EngineeringLibModel();
+            libData = await engineeringLibModel.getLib(valuationData.engineering_list, engineering);
+
             // 获取清单模板数据
             // 获取清单模板数据
             let billsTemplateModel = new BillsTemplateModel();
             let billsTemplateModel = new BillsTemplateModel();
             billsTemplateData = await billsTemplateModel.getTemplateData(valuationId);
             billsTemplateData = await billsTemplateModel.getTemplateData(valuationId);
@@ -149,21 +217,51 @@ class CompilationController extends BaseController {
         }
         }
 
 
         let renderData = {
         let renderData = {
+            section: section,
+            valuationId: valuationId,
+            engineeringInfo: engineeringInfo,
             compilationList: compilationList,
             compilationList: compilationList,
+            selectedCompilation: selectedCompilation,
+            libData: libData,
             billList: JSON.stringify(billList),
             billList: JSON.stringify(billList),
             rationList: JSON.stringify(rationList),
             rationList: JSON.stringify(rationList),
             gljList: JSON.stringify(gljList),
             gljList: JSON.stringify(gljList),
-            mainTreeCol: JSON.stringify(valuationData.main_tree_col),
+            feeRateList: JSON.stringify(feeRateList),
             billsTemplateData: JSON.stringify(billsTemplateData),
             billsTemplateData: JSON.stringify(billsTemplateData),
-            engineeringList: EngineeringList,
-            selectedCompilation: selectedCompilation,
-            valuationData: valuationData,
-            valuationList: valuationList,
-            valuationId: valuationId,
-            section: section,
+            mainTreeCol: JSON.stringify(valuationData.main_tree_col),
             layout: 'users/views/layout/layout'
             layout: 'users/views/layout/layout'
         };
         };
-        response.render('users/views/compilation/add', renderData);
+        response.render('users/views/compilation/engineering', renderData);
+    }
+
+    /**
+     * 保存工程专业标准库
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async saveEngineering(request, response) {
+        let valuationId = request.body.id;
+
+        try {
+            if (valuationId === '') {
+                throw 'id参数错误';
+            }
+
+            // 先存入工程专业标准库表
+            let engineeringLibModel = new EngineeringLibModel();
+            let result = engineeringLibModel.addLib(valuationId, request.body);
+
+            if (!result) {
+                throw '保存失败';
+            }
+
+        } catch (error) {
+            console.log(error);
+        }
+
+        response.redirect(request.headers.referer);
     }
     }
 
 
     /**
     /**
@@ -362,6 +460,7 @@ class CompilationController extends BaseController {
         let renderData = {
         let renderData = {
             billList: JSON.stringify(billList),
             billList: JSON.stringify(billList),
             billsTemplateData: JSON.stringify(billsTemplateData),
             billsTemplateData: JSON.stringify(billsTemplateData),
+            billsFixedFlagList: JSON.stringify(BillsFixedFlagList),
             valuationData: valuationData,
             valuationData: valuationData,
             valuationList: valuationList,
             valuationList: valuationList,
             selectedCompilation: selectedCompilation,
             selectedCompilation: selectedCompilation,
@@ -375,6 +474,7 @@ class CompilationController extends BaseController {
 
 
     /**
     /**
      * 清单模板,更新数据操作
      * 清单模板,更新数据操作
+     *
      * @param request
      * @param request
      * @param response
      * @param response
      */
      */
@@ -383,7 +483,6 @@ class CompilationController extends BaseController {
         let section = request.params.section;
         let section = request.params.section;
         let data = JSON.parse(request.body.data);
         let data = JSON.parse(request.body.data);
 
 
-        console.log(data);
         let billsTemplateModel = new BillsTemplateModel();
         let billsTemplateModel = new BillsTemplateModel();
         let result = await billsTemplateModel.updateTemplate(valuationId, data);
         let result = await billsTemplateModel.updateTemplate(valuationId, data);
 
 
@@ -392,6 +491,7 @@ class CompilationController extends BaseController {
         } else {
         } else {
             response.json({error: 1, message: '更新数据错误', data: null});
             response.json({error: 1, message: '更新数据错误', data: null});
         }
         }
+
     }
     }
 
 
 }
 }

+ 2 - 2
modules/users/models/bills_template_model.js

@@ -24,7 +24,7 @@ class BillsTemplateModel extends BaseModel {
      */
      */
     async getTemplateData (valuationId) {
     async getTemplateData (valuationId) {
         // 筛选字段
         // 筛选字段
-        let field = {_id: 1, valuationId: 1, ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1};
+        let field = {_id: 1, valuationId: 1, ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1, flags: 1};
         let data = await this.findDataByCondition({valuationId: valuationId}, field, false);
         let data = await this.findDataByCondition({valuationId: valuationId}, field, false);
 
 
         return data === null ? [] : data;
         return data === null ? [] : data;
@@ -37,7 +37,7 @@ class BillsTemplateModel extends BaseModel {
      */
      */
     async getTemplateDataForNewProj (valuationId) {
     async getTemplateDataForNewProj (valuationId) {
         // 筛选字段
         // 筛选字段
-        let field = {ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1};
+        let field = {ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1, flags: 1};
         let data = await this.findDataByCondition({valuationId: valuationId}, field, false);
         let data = await this.findDataByCondition({valuationId: valuationId}, field, false);
 
 
         return data === null ? [] : data;
         return data === null ? [] : data;

+ 42 - 36
modules/users/models/compilation_model.js

@@ -73,7 +73,6 @@ class CompilationModel extends BaseModel {
 
 
         this.setScene('add');
         this.setScene('add');
         data.create_time = new Date().getTime();
         data.create_time = new Date().getTime();
-        console.log(data);
         result = this.db.create(data);
         result = this.db.create(data);
         return result;
         return result;
     }
     }
@@ -121,12 +120,7 @@ class CompilationModel extends BaseModel {
         condition[sectionString + "._id"] = valuationId;
         condition[sectionString + "._id"] = valuationId;
 
 
         let updateData = {};
         let updateData = {};
-        updateData[sectionString + ".$.bill_lib"] = data.bill_lib;
-        updateData[sectionString + ".$.ration_lib"] = data.ration_lib;
-        updateData[sectionString + ".$.glj_lib"] = data.glj_lib;
         updateData[sectionString + ".$.name"] = data.name;
         updateData[sectionString + ".$.name"] = data.name;
-        updateData[sectionString + ".$.engineering"] = data.engineering;
-        updateData[sectionString + ".$.main_tree_col"] = JSON.parse(data.main_tree_col);
 
 
         let result = await this.db.update(condition, updateData);
         let result = await this.db.update(condition, updateData);
 
 
@@ -173,36 +167,6 @@ class CompilationModel extends BaseModel {
         if (data.name === undefined || data.name === '') {
         if (data.name === undefined || data.name === '') {
             throw '名称不能为空';
             throw '名称不能为空';
         }
         }
-        // 判断工程专业
-        if (data.engineering === undefined || data.engineering === '') {
-            throw '名称不能为空';
-        }
-        data.engineering = parseInt(data.engineering);
-        // 判断标准清单
-        if (data.bill_lib === undefined || data.bill_lib === '') {
-            throw '判断标准清单不能为空';
-        }
-        data.bill_lib = data.bill_lib instanceof Array ? data.bill_lib : [data.bill_lib];
-        for(let tmp in data.bill_lib) {
-            data.bill_lib[tmp] = JSON.parse(data.bill_lib[tmp]);
-        }
-        // 判断定额库
-        if (data.ration_lib === undefined || data.ration_lib === '') {
-            throw '判断标准清单不能为空';
-        }
-        data.ration_lib = data.ration_lib instanceof Array ? data.ration_lib : [data.ration_lib];
-        for(let tmp in data.ration_lib) {
-            data.ration_lib[tmp] = JSON.parse(data.ration_lib[tmp]);
-        }
-
-        // 判断工料机库
-        if (data.glj_lib === undefined || data.glj_lib === '') {
-            throw '判断工料机库不能为空';
-        }
-        data.glj_lib = data.glj_lib instanceof Array ? data.glj_lib : [data.glj_lib];
-        for(let tmp in data.glj_lib) {
-            data.glj_lib[tmp] = JSON.parse(data.glj_lib[tmp]);
-        }
 
 
         return data;
         return data;
     }
     }
@@ -303,6 +267,48 @@ class CompilationModel extends BaseModel {
         return this.updateById(id, updateData);
         return this.updateById(id, updateData);
     }
     }
 
 
+    /**
+     * 根据专业工程获取对应专业工程标准库id
+     *
+     * @param {String} valuationId
+     * @param {String} section
+     * @param {Number} engineering
+     * @return {Promise}
+     */
+    async getEngineeringLib(valuationId, section, engineering) {
+        let sectionString = section + "_valuation";
+        let condition = {};
+        condition[sectionString + "._id"] = valuationId;
+        condition[sectionString + ".engineering_list.engineering"] = engineering;
+
+        let engineeringLib = await this.findDataByCondition(condition);
+        if (engineeringLib === null) {
+            return engineeringLib;
+        }
+        return engineeringLib[sectionString].length > 0 && engineeringLib[sectionString][0].engineering_list ?
+            engineeringLib[sectionString][0].engineering_list : {};
+    }
+
+    /**
+     * 新增专业工程标准库
+     *
+     * @param {String} valuationId
+     * @param {String} section
+     * @param {Object} data
+     * @return {Promise}
+     */
+    async addEngineeringLib(valuationId, section, data) {
+        let sectionString = section + "_valuation";
+        let condition = {};
+        condition[sectionString + "._id"] = valuationId;
+
+        let insertData = {};
+        insertData[sectionString + ".$.engineering_list"] = data;
+        let result = await this.db.addToSet(condition, insertData);
+
+        return result.ok === 1;
+    }
+
 }
 }
 
 
 export default CompilationModel;
 export default CompilationModel;

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

@@ -0,0 +1,160 @@
+/**
+ * 计价规则标准库业务逻辑
+ *
+ * @author CaiAoLin
+ * @date 2017/8/31
+ * @version
+ */
+import BaseModel from "../../common/base/base_model";
+import EngineeringLibSchema from "./schemas/engineering_lib";
+import CompilationModel from "./compilation_model";
+import {default as EngineeringConst, List as EngineeringList} from "../../common/const/engineering";
+
+class EngineeringLibModel extends BaseModel {
+    /**
+     * 构造函数
+     *
+     * @return {void}
+     */
+    constructor() {
+        let parent = super();
+        parent.model = EngineeringLibSchema;
+        parent.init();
+    }
+
+    /**
+     * 获取标准库数据
+     *
+     * @param {Object} data
+     * @param {Number} engineering
+     * @return {Promise}
+     */
+    async getLib(data, engineering) {
+        let result = {};
+        if (data.length <= 0) {
+            return result;
+        }
+        let id = '';
+        for(let tmp of data) {
+            if (tmp.engineering === engineering) {
+                id = tmp.engineering_id;
+                break;
+            }
+        }
+        if (id === '') {
+            return result;
+        }
+        let condition = {_id: id};
+        return this.findDataByCondition(condition);
+    }
+
+    /**
+     * 新增标准库
+     *
+     * @param {String} valuationId
+     * @param {Object} data
+     * @return {Promise}
+     */
+    async addLib(valuationId, data) {
+        let result = false;
+        data = this.filterLibData(data);
+        try {
+            // 查找计价规则表中是否有对应工程专业标准库的数据
+            let compilationModel = new CompilationModel();
+            let engineeringLib = await compilationModel.getEngineeringLib(valuationId, data.section, data.engineering);
+
+            let result = false;
+            if (engineeringLib === null) {
+                // 不存在则插入
+                result = await this.db.create(data);
+            } else {
+                engineeringLib = engineeringLib.length > 0 ? engineeringLib[0] : {};
+                // 存在则直接更新
+                let condition = {_id: engineeringLib.engineering_id};
+                result = await this.db.update(condition, data);
+                result = result.ok === 1;
+            }
+            // 失败直接返回
+            if (!result) {
+                throw '操作失败';
+            }
+
+            // 新增后更新编办数据表中专业工程字段
+            if (result && engineeringLib === null) {
+                let insertData = {
+                    engineering: data.engineering,
+                    engineering_id: result._id
+                };
+                let updateResult = await compilationModel.addEngineeringLib(valuationId, data.section, insertData);
+                if (!updateResult) {
+                    throw '新增编办数据中的专业工程失败!';
+                }
+            }
+        } catch (error) {
+            console.log(error);
+            result = false;
+        }
+
+        return result;
+    }
+
+    /**
+     * 过滤计价数据
+     *
+     * @param {Object} data
+     * @return {Object}
+     */
+    filterLibData(data) {
+        if (Object.keys(data).length <= 0 || data.section === undefined) {
+            throw '数据有误';
+        }
+        // 检测专业工程是否合法
+        data.engineering = parseInt(data.engineering);
+        let match = false;
+        for(let index in EngineeringConst) {
+            if (EngineeringConst[index] === data.engineering) {
+                match = true;
+                break;
+            }
+        }
+        if (!match) {
+            throw '工程专业错误';
+        }
+
+        // 判断标准清单
+        data.bill_lib = this._validLib(data.bill_lib);
+
+        // 判断定额库
+        data.ration_lib = this._validLib(data.ration_lib);
+
+        // 判断工料机库
+        data.glj_lib = this._validLib(data.glj_lib);
+
+        // 判断费率库
+        data.fee_lib = this._validLib(data.fee_lib);
+
+        return data;
+    }
+
+    /**
+     * 校验库数据
+     *
+     * @param {Object} libData
+     * @return {Object}
+     */
+    _validLib(libData) {
+        let result = [];
+        // 判断费率库
+        if (libData === undefined || libData === '') {
+            throw '判断费率库不能为空';
+        }
+        libData = libData instanceof Array ? libData : [libData];
+        for(let tmp in libData) {
+            result[tmp] = JSON.parse(libData[tmp]);
+        }
+        return result;
+    }
+
+}
+
+export default EngineeringLibModel;

+ 10 - 0
modules/users/models/schemas/bills_template.js

@@ -6,6 +6,11 @@ let Schema = mongoose.Schema;
 
 
 let collectionName = 'temp_bills';
 let collectionName = 'temp_bills';
 
 
+// 标记字段
+let flagsSchema = new Schema({
+    fieldName: String,
+    flag: Number
+});
 let BillsTemplateSchema = {
 let BillsTemplateSchema = {
     // 树结构所需ID
     // 树结构所需ID
     ID: Number,
     ID: Number,
@@ -17,6 +22,11 @@ let BillsTemplateSchema = {
     name: String,
     name: String,
     // 单位
     // 单位
     unit: String,
     unit: String,
+    // 标记
+    flags:{
+        type: [flagsSchema],
+        default: []
+    },
     // 所属计价ID
     // 所属计价ID
     valuationId: String
     valuationId: String
 };
 };

+ 12 - 17
modules/users/models/schemas/compilation.js

@@ -9,27 +9,22 @@ import mongoose from "mongoose";
 
 
 let Schema = mongoose.Schema;
 let Schema = mongoose.Schema;
 let collectionName = 'compilation';
 let collectionName = 'compilation';
-let childrenSchema = new Schema({
-    // 计价名称
-    name: String,
-    // 工程专业
+let engineeringListSchema = new Schema({
+    // 工程专业id
     engineering: {
     engineering: {
-        type: Number,
-        default: ''
-    },
-    // 标准清单
-    bill_lib: {
-        type: Schema.Types.Mixed,
-        default: []
+        type: Number
     },
     },
-    // 定额库
-    ration_lib: {
+    engineering_id: {
         type: Schema.Types.Mixed,
         type: Schema.Types.Mixed,
         default: []
         default: []
-    },
-    // 工料机库
-    glj_lib: {
-        type: Schema.Types.Mixed,
+    }
+}, {_id: false});
+let childrenSchema = new Schema({
+    // 计价名称
+    name: String,
+    // 工程专业列表
+    engineering_list: {
+        type: [engineeringListSchema],
         default: []
         default: []
     },
     },
     // 是否启用
     // 是否启用

+ 47 - 0
modules/users/models/schemas/engineering_lib.js

@@ -0,0 +1,47 @@
+/**
+ * 计价规则数据结构
+ *
+ * @author CaiAoLin
+ * @date 2017/8/31
+ * @version
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'engineering_lib';
+let modelSchema = {
+    // 标准清单
+    bill_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    },
+    // 定额库
+    ration_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    },
+    // 工料机库
+    glj_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    },
+    // 列设置
+    main_tree_col: {
+        type: Schema.Types.Mixed,
+        default: {
+            "emptyRows":3,
+            "headRows":0,
+            "treeCol": 0,
+            "headRowHeight":[],
+            "cols":[]
+        }
+    },
+    // 费率标准库
+    fee_lib: {
+        type: Schema.Types.Mixed,
+        default: []
+    }
+};
+let model = mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));
+export {model as default, collectionName as collectionName};
+

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

@@ -15,6 +15,7 @@ module.exports = function (app) {
     // action定义区域
     // action定义区域
     router.get('/', compilationController.auth, compilationController.init, compilationController.index);
     router.get('/', compilationController.auth, compilationController.init, compilationController.index);
     router.get('/valuation/:section/:id', compilationController.auth, compilationController.init, compilationController.editValuation);
     router.get('/valuation/:section/:id', compilationController.auth, compilationController.init, compilationController.editValuation);
+    router.get('/:section/:id/:engineering', compilationController.auth, compilationController.init, compilationController.editEngineering);
     router.get('/valuation/:section/delete/:id', compilationController.auth, compilationController.init, compilationController.deleteValuation);
     router.get('/valuation/:section/delete/:id', compilationController.auth, compilationController.init, compilationController.deleteValuation);
     router.get('/template/:section/:id', compilationController.auth, compilationController.init, compilationController.template);
     router.get('/template/:section/:id', compilationController.auth, compilationController.init, compilationController.template);
 
 
@@ -22,6 +23,7 @@ module.exports = function (app) {
     router.post('/add', compilationController.auth, compilationController.init, compilationController.addCompilation);
     router.post('/add', compilationController.auth, compilationController.init, compilationController.addCompilation);
     router.post('/add-valuation', compilationController.auth, compilationController.init, compilationController.addValuation);
     router.post('/add-valuation', compilationController.auth, compilationController.init, compilationController.addValuation);
     router.post('/save-valuation', compilationController.auth, compilationController.init, compilationController.saveValuation);
     router.post('/save-valuation', compilationController.auth, compilationController.init, compilationController.saveValuation);
+    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/enable', compilationController.auth, compilationController.init, compilationController.enableSwitch);
     router.post('/template/:section/:id/update', compilationController.auth, compilationController.init, compilationController.updateBillsTemplate)
     router.post('/template/:section/:id/update', compilationController.auth, compilationController.init, compilationController.updateBillsTemplate)
 
 

+ 1 - 1
operation.js

@@ -1,7 +1,7 @@
 let express = require('express');
 let express = require('express');
 
 
 let config = require("./config/config.js");
 let config = require("./config/config.js");
-config.setToQaDb();
+config.setupDb(process.env.NODE_ENV);
 let dbm = require("./config/db/db_manager");
 let dbm = require("./config/db/db_manager");
 
 
 let path = require('path');
 let path = require('path');

+ 7 - 0
public/fsUtil.js

@@ -24,5 +24,12 @@ module.exports = {
                 console.log('Write file: ' + filePath + ' ok!');
                 console.log('Write file: ' + filePath + ' ok!');
             });
             });
         }
         }
+    },
+    wirteObjToFile: function(obj, filePath) {
+        if (obj) {
+            let arr = [];
+            arr.push(JSON.stringify(obj));
+            this.writeArrayToFile(arr, filePath);
+        }
     }
     }
 }
 }

+ 3 - 0
public/web/rpt_value_define.js

@@ -35,6 +35,7 @@ let JV = {
     NODE_MAIN_INFO: "主信息",
     NODE_MAIN_INFO: "主信息",
     NODE_MAIN_INFO_RPT_NAME: "报表名称",
     NODE_MAIN_INFO_RPT_NAME: "报表名称",
     NODE_PAGE_INFO: "打印页面_信息",
     NODE_PAGE_INFO: "打印页面_信息",
+    NODE_PAGE_SIZE: "纸张宽高",
     NODE_MARGINS: "页边距",
     NODE_MARGINS: "页边距",
 
 
     NODE_FONT_COLLECTION: "font_collection",
     NODE_FONT_COLLECTION: "font_collection",
@@ -192,8 +193,10 @@ let JV = {
     OFFSET_IDX_BOTTOM: 3,
     OFFSET_IDX_BOTTOM: 3,
 
 
     PROP_PAGE_SEQ: "page_seq",
     PROP_PAGE_SEQ: "page_seq",
+    PROP_CELLS: "cells",
 
 
     PAGE_SELF_DEFINE: "自定义",
     PAGE_SELF_DEFINE: "自定义",
+    PAGE_SPECIAL_MERGE_POS: "page_merge_pos",
 
 
     PAGES_SIZE_STR: ["A3", "A4", "A5", "B5", "LETTER", "LEGAL", "EXECUTIVE", "16K"],
     PAGES_SIZE_STR: ["A3", "A4", "A5", "B5", "LETTER", "LEGAL", "EXECUTIVE", "16K"],
     PAGES_SIZE_IDX: [8, 9, 11, 13, 1, 5, 7, 93],
     PAGES_SIZE_IDX: [8, 9, 11, 13, 1, 5, 7, 93],

+ 3 - 0
public/web/tree_sheet/tree_sheet_helper.js

@@ -109,6 +109,9 @@ var TREE_SHEET_HELPER = {
                 } else {
                 } else {
                     cell.value(getFieldText2());
                     cell.value(getFieldText2());
                 }
                 }
+                if (colSetting.data.cellType) {
+                    cell.cellType(colSetting.data.cellType);
+                }
             });
             });
             if (recursive) {
             if (recursive) {
                 TREE_SHEET_HELPER.refreshTreeNodeData(setting, sheet, node.children, recursive);
                 TREE_SHEET_HELPER.refreshTreeNodeData(setting, sheet, node.children, recursive);

+ 19 - 2
test/calculation/testJSCalc.js

@@ -4,8 +4,25 @@
 
 
 var test = require('tape');
 var test = require('tape');
 
 
-test('计算式测试', function(t){
-    console.log(10 / 96 * 25.4 / 0.3612);
+// test('计算式测试', function(t){
+//     console.log(10 / 96 * 25.4 / 0.3612);
+//     t.pass('just pass for js calculation!');
+//     t.end();
+// })
+
+test('四舍五入测试', function(t){
+    let a1 = Math.round(17.4, 2);
+    let a2 = Math.round(17.5, 2);
+    let a3 = Math.round(17.6, 2);
+    let a4 = Math.round(18.4, 2);
+    let a5 = Math.round(18.5, 2);
+    let a6 = Math.round(18.6, 2);
+    console.log(a1);
+    console.log(a2);
+    console.log(a3);
+    console.log(a4);
+    console.log(a5);
+    console.log(a6);
     t.pass('just pass for js calculation!');
     t.pass('just pass for js calculation!');
     t.end();
     t.end();
 })
 })

+ 1 - 1
web/maintain/report/js/jpc_output.js

@@ -183,7 +183,7 @@ let JpcCanvasOutput = {
     },
     },
     drawPageBorder: function(rptTpl, canvas, resolution) {
     drawPageBorder: function(rptTpl, canvas, resolution) {
         var me = this;
         var me = this;
-        var size = rptTpl[JV.NODE_PAGE_INFO].slice(0);
+        var size = rptTpl[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE].slice(0);
         size[0] = Math.round(resolution[0] * size[0]);
         size[0] = Math.round(resolution[0] * size[0]);
         size[1] = Math.round(resolution[0] * size[1]);
         size[1] = Math.round(resolution[0] * size[1]);
 
 

+ 1 - 0
web/maintain/report/js/jpc_output_value_define.js

@@ -5,6 +5,7 @@
 let JV = {
 let JV = {
     NODE_MAIN_INFO: "主信息",
     NODE_MAIN_INFO: "主信息",
     NODE_PAGE_INFO: "打印页面_信息",
     NODE_PAGE_INFO: "打印页面_信息",
+    NODE_PAGE_SIZE: "纸张宽高",
     NODE_MARGINS: "页边距",
     NODE_MARGINS: "页边距",
 
 
     NODE_FONT_COLLECTION: "font_collection",
     NODE_FONT_COLLECTION: "font_collection",

+ 10 - 0
web/maintain/report/rpt_test.html

@@ -33,6 +33,7 @@
                 <input type="button" value="后一页 >" onclick="showPage(1)"/>
                 <input type="button" value="后一页 >" onclick="showPage(1)"/>
                 <input type="button" value="打印" onclick="printCurrentPage()"/>
                 <input type="button" value="打印" onclick="printCurrentPage()"/>
                 <input type="button" value="Excel" onclick="getExcel()"/>
                 <input type="button" value="Excel" onclick="getExcel()"/>
+                <input type="button" value="ExcelInOneBook" onclick="getExcelInOneBook()"/>
                 <input type="button" value="PDF" onclick="getPDF()"/>
                 <input type="button" value="PDF" onclick="getPDF()"/>
                 <label>
                 <label>
                     <input type="checkbox" id="isOneSheetChk" onclick="isOneSheet = this.checked;">
                     <input type="checkbox" id="isOneSheetChk" onclick="isOneSheet = this.checked;">
@@ -131,6 +132,14 @@
         window.location = url;//这里不能使用get方法跳转,否则下载不成功
         window.location = url;//这里不能使用get方法跳转,否则下载不成功
     }
     }
 
 
+    function getExcelInOneBook() {
+        let rptIds = "2,3";
+        let size = "A4";
+        let rpt_name = 'OneBook';
+        let url =  "/report_api/getExcelInOneBook/" + rptIds + "/" + size + "/" + rpt_name;
+        window.location = url;//这里不能使用get方法跳转,否则下载不成功
+    }
+
     function getPDF() {
     function getPDF() {
         let rpt = document.getElementById("select_k1");
         let rpt = document.getElementById("select_k1");
         let size = document.getElementById("select_k2");
         let size = document.getElementById("select_k2");
@@ -179,6 +188,7 @@
             });
             });
         }
         }
     }
     }
+
 </script>
 </script>
 
 
 </html>
 </html>

+ 61 - 40
web/users/js/compilation.js

@@ -12,7 +12,7 @@ $(document).ready(function() {
     let id = $("#compilation-id").val();
     let id = $("#compilation-id").val();
 
 
     // 计价规则页面初始化数据
     // 计价规则页面初始化数据
-    if ($("#section").length > 0) {
+    if ($("#save-lib").length > 0) {
         initCompilation();
         initCompilation();
     }
     }
 
 
@@ -24,15 +24,14 @@ $(document).ready(function() {
     // 新增编办
     // 新增编办
     $("#add-compilation").click(function() {
     $("#add-compilation").click(function() {
         try {
         try {
-            let [name, standardBill, rationLib, gljLib, standardBillString, rationLibString, gljLibString] = getAndValidData(model);
-
+            let data = getAndValidData(model);
             let url = '/compilation/add';
             let url = '/compilation/add';
             if (model === 'all') {
             if (model === 'all') {
                 // 新增编办操作
                 // 新增编办操作
                 $.ajax({
                 $.ajax({
                     url: url,
                     url: url,
                     type: 'post',
                     type: 'post',
-                    data: {name: name},
+                    data: {name: data.name},
                     error: function() {
                     error: function() {
                         isAdding = false;
                         isAdding = false;
                     },
                     },
@@ -52,22 +51,9 @@ $(document).ready(function() {
             } else {
             } else {
                 // 新增标准清单/定额库
                 // 新增标准清单/定额库
                 let addLib = {
                 let addLib = {
-                    name: '',
-                    id: ''
+                    name: data[model].name,
+                    id: data[model].id
                 };
                 };
-                switch (model) {
-                    case 'bill':
-                        addLib.name = standardBillString;
-                        addLib.id = standardBill;
-                        break;
-                    case 'ration':
-                        addLib.name = rationLibString;
-                        addLib.id = rationLib;
-                        break;
-                    case 'glj':
-                        addLib.name = gljLibString;
-                        addLib.id = gljLib;
-                }
                 // 判断是否有重复的数据
                 // 判断是否有重复的数据
                 if ($("input:hidden[name='"+ model +"_lib'][data-id='"+ addLib.id +"']").length > 0) {
                 if ($("input:hidden[name='"+ model +"_lib'][data-id='"+ addLib.id +"']").length > 0) {
                     alert('重复添加数据!');
                     alert('重复添加数据!');
@@ -127,48 +113,45 @@ $(document).ready(function() {
     // 添加
     // 添加
     $(".add-compilation").click(function() {
     $(".add-compilation").click(function() {
         model = $(this).data('model');
         model = $(this).data('model');
+        $("#addcompilation .modal-body > div").hide();
         switch (model) {
         switch (model) {
             case 'all':
             case 'all':
                 $("#name-area").show();
                 $("#name-area").show();
-                $("#bill-area").hide();
-                $("#ration-area").hide();
-                $("#glj-area").hide();
                 $("#add-compilation-title").text('添加新编办');
                 $("#add-compilation-title").text('添加新编办');
                 break;
                 break;
             case 'bill':
             case 'bill':
-                $("#name-area").hide();
                 $("#bill-area").show();
                 $("#bill-area").show();
-                $("#ration-area").hide();
-                $("#glj-area").hide();
                 $("#add-compilation-title").text('添加标准清单');
                 $("#add-compilation-title").text('添加标准清单');
                 break;
                 break;
             case 'ration':
             case 'ration':
-                $("#name-area").hide();
-                $("#bill-area").hide();
                 $("#ration-area").show();
                 $("#ration-area").show();
-                $("#glj-area").hide();
                 $("#add-compilation-title").text('添加定额库');
                 $("#add-compilation-title").text('添加定额库');
                 break;
                 break;
             case 'glj':
             case 'glj':
-                $("#name-area").hide();
-                $("#bill-area").hide();
-                $("#ration-area").hide();
                 $("#glj-area").show();
                 $("#glj-area").show();
                 $("#add-compilation-title").text('添加定额库');
                 $("#add-compilation-title").text('添加定额库');
+                break;
+            case 'fee':
+                $("#fee-area").show();
+                $("#add-compilation-title").text('添加费率库');
         }
         }
 
 
         $("#addcompilation").modal('show');
         $("#addcompilation").modal('show');
     });
     });
 
 
-    // 保存计价规则
-    $("#save-valuation").click(function() {
-        if (validValuation()) {
+    // 保存专业工程标准库
+    $("#save-lib").click(function() {
+        if (validLib()) {
             $("form").submit();
             $("form").submit();
         }
         }
     });
     });
+    // 保存计价规则
+    $("#save-valuation").click(function() {
+        $("form").submit();
+    });
 
 
     // 移除操作
     // 移除操作
-    $(".bill-list, .ration-list").on("click", ".remove-lib", function() {
+    $(".bill-list, .ration-list, .glj-list, .fee-list").on("click", ".remove-lib", function() {
         $(this).parent().remove();
         $(this).parent().remove();
     });
     });
 
 
@@ -245,6 +228,7 @@ function initCompilation() {
     let billListData = billList === undefined ? [] : JSON.parse(billList);
     let billListData = billList === undefined ? [] : JSON.parse(billList);
     let rationLibData = rationList === undefined ? [] : JSON.parse(rationList);
     let rationLibData = rationList === undefined ? [] : JSON.parse(rationList);
     let gljLibData = gljList === undefined ? [] : JSON.parse(gljList);
     let gljLibData = gljList === undefined ? [] : JSON.parse(gljList);
+    let feeLibData = feeRateList === undefined ? [] : JSON.parse(feeRateList);
 
 
     // 初始化 造价书列设置
     // 初始化 造价书列设置
     colSpread = TREE_SHEET_HELPER.createNewSpread($('#main-tree-col')[0]);
     colSpread = TREE_SHEET_HELPER.createNewSpread($('#main-tree-col')[0]);
@@ -281,19 +265,28 @@ function initCompilation() {
     }
     }
     $("select[name='glj_lib']").children("option").first().after(html);
     $("select[name='glj_lib']").children("option").first().after(html);
 
 
+    // 费率库
+    html = '';
+    for(let tmp of feeLibData) {
+        let tmpHtml = '<option value="' + tmp.id + '">' + tmp.name + '</option>';
+        html += tmpHtml;
+    }
+    $("select[name='fee_lib']").children("option").first().after(html);
+
 }
 }
 
 
 /**
 /**
  * 校验数据
  * 校验数据
  *
  *
  * @param {String} model
  * @param {String} model
- * @return {Array}
+ * @return {Object}
  */
  */
 function getAndValidData(model) {
 function getAndValidData(model) {
     let name = $("input[name='compilation_name']").val();
     let name = $("input[name='compilation_name']").val();
     let standardBill = $("select[name='standard_bill']").children("option:selected").val();
     let standardBill = $("select[name='standard_bill']").children("option:selected").val();
     let rationLib = $("select[name='ration_lib']").children("option:selected").val();
     let rationLib = $("select[name='ration_lib']").children("option:selected").val();
     let gljLib = $("select[name='glj_lib']").children("option:selected").val();
     let gljLib = $("select[name='glj_lib']").children("option:selected").val();
+    let feeLib = $("select[name='fee_lib']").children("option:selected").val();
 
 
     if (name === '' && model === 'all') {
     if (name === '' && model === 'all') {
         throw '编办名字不能为空';
         throw '编办名字不能为空';
@@ -311,19 +304,43 @@ function getAndValidData(model) {
         throw '请选择工料机库';
         throw '请选择工料机库';
     }
     }
 
 
+    if (model === 'fee' && (feeLib === '' || feeLib === undefined)) {
+        throw '请选择费率库';
+    }
+
     let standardBillString = $("select[name='standard_bill']").children("option:selected").text();
     let standardBillString = $("select[name='standard_bill']").children("option:selected").text();
     let rationLibString = $("select[name='ration_lib']").children("option:selected").text();
     let rationLibString = $("select[name='ration_lib']").children("option:selected").text();
     let gljLibString = $("select[name='glj_lib']").children("option:selected").text();
     let gljLibString = $("select[name='glj_lib']").children("option:selected").text();
-
-    return [name, standardBill, rationLib, gljLib, standardBillString, rationLibString, gljLibString];
+    let feeLibString = $("select[name='fee_lib']").children("option:selected").text();
+
+    let result = {
+        name: name,
+        bill: {
+            id: standardBill,
+            name: standardBillString
+        },
+        ration: {
+            id: rationLib,
+            name: rationLibString
+        },
+        glj: {
+            id: gljLib,
+            name: gljLibString
+        },
+        fee: {
+            id: feeLib,
+            name: feeLibString
+        }
+    };
+    return result;
 }
 }
 
 
 /**
 /**
- * 验证计价规则数据
+ * 验证标准库数据
  *
  *
  * @return {boolean}
  * @return {boolean}
  */
  */
-function validValuation() {
+function validLib() {
     let result = false;
     let result = false;
     try {
     try {
         let valuationName = $("input[name='name']").val();
         let valuationName = $("input[name='name']").val();
@@ -344,6 +361,10 @@ function validValuation() {
             throw '请添加定额库';
             throw '请添加定额库';
         }
         }
 
 
+        if ($("input:hidden[name='fee_lib']").length <= 0) {
+            throw '请添加费率库';
+        }
+
         result = true;
         result = true;
     } catch (error) {
     } catch (error) {
         alert(error);
         alert(error);

+ 83 - 7
web/users/js/template.js

@@ -9,7 +9,7 @@ let TEMPLATE_BILLS_SETTING = {
     "treeCol": 0,
     "treeCol": 0,
     "cols":[{
     "cols":[{
         "width":200,
         "width":200,
-        "readOnly":null,
+        "readOnly":false,
         "head":{
         "head":{
             "titleNames":["编号"],
             "titleNames":["编号"],
             "spanCols":[1],
             "spanCols":[1],
@@ -26,7 +26,7 @@ let TEMPLATE_BILLS_SETTING = {
         }
         }
     }, {
     }, {
         "width":300,
         "width":300,
-        "readOnly":null,
+        "readOnly":false,
         "head":{
         "head":{
             "titleNames":["名称"],
             "titleNames":["名称"],
             "spanCols":[1],
             "spanCols":[1],
@@ -43,7 +43,7 @@ let TEMPLATE_BILLS_SETTING = {
         }
         }
     }, {
     }, {
         "width":50,
         "width":50,
-        "readOnly":null,
+        "readOnly":false,
         "head":{
         "head":{
             "titleNames":["单位"],
             "titleNames":["单位"],
             "spanCols":[1],
             "spanCols":[1],
@@ -59,6 +59,23 @@ let TEMPLATE_BILLS_SETTING = {
             "font":"Arail"
             "font":"Arail"
         }
         }
     }, {
     }, {
+        "width":200,
+        "readOnly":false,
+        "head":{
+            "titleNames":["清单固定类别"],
+            "spanCols":[1],
+            "spanRows":[1],
+            "vAlign":[1],
+            "hAlign":[1],
+            "font":["Arial"]
+        },
+        "data":{
+            "field":"flagsIndex.fixed.flag",
+            "vAlign":0,
+            "hAlign":3,
+            "font":"Arail",
+        }
+    }, {
         "width":50,
         "width":50,
         "readOnly":true,
         "readOnly":true,
         "head":{
         "head":{
@@ -135,6 +152,52 @@ $(document).ready(function () {
             }
             }
         });
         });
     };
     };
+    let getFixedFlagCellType = function () {
+        let billsFixedFlagData = JSON.parse(billsFixedFlagList);
+        let comboItems = [];
+        for (let data of billsFixedFlagData) {
+            comboItems.push({text: data.name, value: data.value});
+        }
+        let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
+        combo.editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.value)
+            .items(comboItems);
+        return combo;
+    };
+    let setFee = function (data, fullField, value) {
+        let fields = fullField.split('.'), valueField = data;
+        for (let i in fields) {
+            if (valueField[fields[i]]) {
+                if (i == fields.length - 1) {
+                    valueField[fields[i]] = value;
+                } else {
+                    valueField = valueField[fields[i]];
+                }
+            } else {
+                if (i == fields.length - 1) {
+                    valueField[fields[i]] = value;
+                } else {
+                    valueField[fields[i]] = {};
+                };
+                valueField = valueField[fields[i]];
+            }
+        }
+    }
+
+    let templateData = JSON.parse(billsTemplateData);
+    for (let data of templateData) {
+        if (data.flags) {
+            data.flagsIndex = {};
+            for (let flag of data.flags) {
+                data.flagsIndex[flag.fieldName] = flag;
+            }
+        }
+    }
+
+    for (col of TEMPLATE_BILLS_SETTING.cols) {
+        if (col.data.field === 'flagsIndex.fixed.flag' && TEMPLATE_BILLS_SETTING.cols.indexOf(col) !== TEMPLATE_BILLS_SETTING.treeCol) {
+            col.data.cellType = getFixedFlagCellType();
+        }
+    }
 
 
     let tree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true});
     let tree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true});
     let billsSpread = TREE_SHEET_HELPER.createNewSpread($('#billsSpread')[0]);
     let billsSpread = TREE_SHEET_HELPER.createNewSpread($('#billsSpread')[0]);
@@ -146,10 +209,16 @@ $(document).ready(function () {
         var node = controller.tree.items[info.row];
         var node = controller.tree.items[info.row];
         var fieldName = controller.setting.cols[info.col].data.field;
         var fieldName = controller.setting.cols[info.col].data.field;
         var data = {type: 'update', data: {ID: node.getID()}};
         var data = {type: 'update', data: {ID: node.getID()}};
-        data.data[fieldName] = info.editingText;
+        if (/flagsIndex/.test(fieldName)) {
+            data.data.flags = [];
+            let flagField = fieldName.split('.');
+            data.data.flags.push({fieldName: flagField[1], flag: info.editingText});
+        } else {
+            setFee(data.data, fieldName, info.editingText);
+        }
         var updateData = [data];
         var updateData = [data];
         CommonAjax.post(updateUrl, updateData, function (data) {
         CommonAjax.post(updateUrl, updateData, function (data) {
-            node.data[fieldName] = info.editingText;
+            setFee(node.data, fieldName, info.editingText);
             controller.refreshTreeNode([node], false);
             controller.refreshTreeNode([node], false);
         }, function () {
         }, function () {
             controller.refreshTreeNode([node], false);
             controller.refreshTreeNode([node], false);
@@ -166,7 +235,14 @@ $(document).ready(function () {
                 for (iCol = 0; iCol < info.cellRange.colCount; iCol++) {
                 for (iCol = 0; iCol < info.cellRange.colCount; iCol++) {
                     curCol = info.cellRange.col + iCol;
                     curCol = info.cellRange.col + iCol;
                     fieldName = controller.setting.cols[curCol].data.field;
                     fieldName = controller.setting.cols[curCol].data.field;
-                    data.data[fieldName] = info.sheet.getText(curRow, curCol);
+
+                    if (/flagsIndex/.test(fieldName)) {
+                        data.data.flags = [];
+                        let flagField = fieldName.split('.');
+                        data.data.flags.push({fieldName: flagField[1],flag: info.sheet.getText(curRow, curCol)});
+                    } else {
+                        setFee(data.data, fieldName, info.sheet.getText(curRow, curCol));
+                    }
                 }
                 }
                 datas.push(data);
                 datas.push(data);
             }
             }
@@ -179,7 +255,7 @@ $(document).ready(function () {
         });
         });
     });
     });
 
 
-    tree.loadDatas(JSON.parse(billsTemplateData));
+    tree.loadDatas(templateData);
     controller.showTreeData();
     controller.showTreeData();
     RefreshBaseActn(tree);
     RefreshBaseActn(tree);
 
 

+ 26 - 95
web/users/views/compilation/add.html

@@ -3,11 +3,8 @@
     <div class="panel-title">
     <div class="panel-title">
         <div class="title-main">
         <div class="title-main">
             <h2>
             <h2>
-                <%= selectedCompilation.name %>
-                <% if(selectedCompilation.is_release) {%>
-                <span class="text-muted" style="margin-left: 5px;">已发布 <%= moment(selectedCompilation.update_time).format('YYYY-MM-DD')%></span>
-                <% } %>
-                <a href="javascript:void(0);" data-id="<%= selectedCompilation._id %>" data-status="<%= selectedCompilation.is_release ? 0 : 1 %>" class="btn btn-primary btn-sm pull-right" id="release"><% if(selectedCompilation.is_release) {%>取消<% }else{ %>发布<% } %>版本</a>
+                <a href="javascript:void(0);" id="save-valuation" class="btn btn-primary btn-sm pull-right">保存</a>
+                <a href="/compilation" class="btn btn-default btn-sm pull-right">返回</a>
             </h2>
             </h2>
         </div>
         </div>
     </div>
     </div>
@@ -20,95 +17,40 @@
             </ul>
             </ul>
         </div>
         </div>
         <div class="c-body">
         <div class="c-body">
-            <form method="post" action="/compilation/save-valuation" enctype="application/x-www-form-urlencoded21">
+            <form action="/compilation/save-valuation" method="post" enctype="application/x-www-form-urlencoded">
                 <div class=" row">
                 <div class=" row">
                     <div class="col-md-4">
                     <div class="col-md-4">
                         <div class="form-group">
                         <div class="form-group">
                             <label>名称</label>
                             <label>名称</label>
-                            <div class="input-group">
-                                <input type="text" class="form-control" value="<%= valuationData.name %>" name="name">
-                                <span class="input-group-btn">
-                                     <button class="btn btn-default" type="button" id="save-valuation">保存全部</button>
-                                </span>
-                            </div>
+                            <input type="text" class="form-control" name="name" value="<%= valuationData.name %>">
                         </div>
                         </div>
                     </div>
                     </div>
                     <div class="col-md-12">
                     <div class="col-md-12">
                         <legend>
                         <legend>
-                            <div class="form-group row">
-                                <label class="col-sm-2 col-form-label">工程专业</label>
-                                <div class="col-sm-3">
-                                    <select class="form-control" name="engineering">
-                                        <option value="">请选择工程</option>
-                                        <% engineeringList.forEach(function(engineering) {%>
-                                        <option value="<%= engineering.value %>" <% if (engineering.value === valuationData.engineering) {%>selected="selected"<% } %>><%= engineering.name %></option>
-                                        <% }) %>
-                                    </select>
-                                </div>
-                            </div>
+                            工程专业
                         </legend>
                         </legend>
-                    </div>
-                    <div class="col-md-4">
-                        <div class="form-group">
-                            <label>标准清单</label>
-                            <div class="bill-list">
-                                <% if (valuationData.bill_lib.length > 0) { %>
-                                <% valuationData.bill_lib.forEach(function (bill, index){ %>
-                                <p class="form-control-static">
-                                    <a class="pull-right text-danger remove-lib" data-model="bill" title="移除">
-                                        <span class="glyphicon glyphicon-remove"></span>
-                                    </a>
-                                    <input type="hidden" name="bill_lib" data-id="<%= bill.id %>" value="<%= JSON.stringify({id: bill.id, name: bill.name}) %>">
-                                    <% if (index === 0) {%><i class="glyphicon glyphicon-flag"></i>&nbsp;<% } %><%= bill.name %>
-                                </p>
+                        <table class="table">
+                            <thead>
+                            <tr>
+                                <th>工程名称</th>
+                                <th>标准清单</th>
+                                <th>定额库</th>
+                                <th>工料机库</th>
+                                <th>操作</th>
+                            </tr>
+                            </thead>
+                            <tbody>
+                                <% engineeringList.forEach(function(engineering) {%>
+                                <tr>
+                                    <td><%= engineering.name %></td>
+                                    <td>0</td>
+                                    <td>0</td>
+                                    <td>0</td>
+                                    <td><a href="/compilation/<%= section %>/<%= valuationId %>/<%= engineering.value %>">编辑</a></td>
+                                </tr>
                                 <% }) %>
                                 <% }) %>
-                                <% } %>
-                            </div>
-                            <a class="btn btn-link btn-sm add-compilation" href="javascript:void(0)" data-model="bill">添加</a>
-                        </div>
-                        <div class="form-group">
-                            <label>定额库</label>
-                            <div class="ration-list">
-                                <% if (valuationData.ration_lib.length > 0) { %>
-                                <% valuationData.ration_lib.forEach(function (ration, index){ %>
-                                <p class="form-control-static">
-                                    <a class="pull-right text-danger remove-lib" data-model="ration" title="移除" data-id="<%= ration.id %>">
-                                        <span class="glyphicon glyphicon-remove"></span>
-                                    </a>
-                                    <input type="hidden" name="ration_lib" data-id="<%= ration.id %>" value="<%= JSON.stringify({id: ration.id, name: ration.name}) %>">
-                                    <% if (index === 0) {%><i class="glyphicon glyphicon-flag"></i>&nbsp;<% } %><%= ration.name %>
-                                </p>
-                                <% }) %>
-                                <% } %>
-                            </div>
-                            <a href="#" class="btn btn-link btn-sm add-compilation" data-model="ration">添加</a>
-                        </div>
-                        <div class="form-group">
-                            <label>工料机库</label>
-                            <div class="glj-list">
-                                <% if (valuationData.glj_lib.length > 0) { %>
-                                <% valuationData.glj_lib.forEach(function (glj, index){ %>
-                                <p class="form-control-static">
-                                    <a class="pull-right text-danger remove-lib" data-model="glj" title="移除" data-id="<%= glj.id %>">
-                                        <span class="glyphicon glyphicon-remove"></span>
-                                    </a>
-                                    <input type="hidden" name="glj_lib" data-id="<%= glj.id %>" value="<%= JSON.stringify({id: glj.id, name: glj.name}) %>">
-                                    <% if (index === 0) {%><i class="glyphicon glyphicon-flag"></i>&nbsp;<% } %><%= glj.name %>
-                                </p>
-                                <% }) %>
-                                <% } %>
-                            </div>
-                            <a href="#" class="btn btn-link btn-sm add-compilation" data-model="glj">添加</a>
-                        </div>
-                    </div>
-                    <div class="col-md-8">
-                        <legend>
-                            清单模板 / 造价书列
-                            <a href="javascript:void(0)" data-toggle="modal" data-target="#set-column" class="btn btn-primary btn-sm pull-right">设置</a>
-                            <a href="/compilation/template/<%= section %>/<%= valuationId %>" data-toggle="modal" data-target="" class="btn btn-primary btn-sm pull-right" style="margin-right:5px">模板设置</a>
-                        <input type="hidden" name="main_tree_col" value="<%= mainTreeCol %>">
-                        <div id="main-tree-col">
-                        </div>
+                            </tbody>
+                        </table>
                     </div>
                     </div>
                 </div>
                 </div>
                 <input type="hidden" name="section" value="<%= section %>" id="section">
                 <input type="hidden" name="section" value="<%= section %>" id="section">
@@ -117,16 +59,5 @@
         </div>
         </div>
     </div>
     </div>
 </div>
 </div>
-<script type="text/javascript">
-    let billList = '<%- billList %>';
-    let rationList = '<%- rationList %>';
-    let gljList = '<%- gljList %>';
-    let mainTreeCol = '<%- mainTreeCol %>';
-    let billsTemplateData = '<%- billsTemplateData %>';
-    let colSpread = null;
-    let colEditSpread = null;
-</script>
-<script type="text/javascript" src="/public/web/id_tree.js"></script>
-<script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_helper.js"></script>
 <script type="text/javascript" src="/web/users/js/compilation.js"></script>
 <script type="text/javascript" src="/web/users/js/compilation.js"></script>
 <%include ../compilation/modal.html %>
 <%include ../compilation/modal.html %>

+ 120 - 0
web/users/views/compilation/engineering.html

@@ -0,0 +1,120 @@
+<%include ./common.html %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main">
+            <h2>
+                <a href="javascript:void(0);" id="save-lib" class="btn btn-primary btn-sm pull-right">保存</a>
+                <a href="/compilation/valuation/<%= section %>/<%= valuationId %>" class="btn btn-default btn-sm pull-right">返回</a>
+            </h2>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-header" style="padding:0">
+            <ul class="nav nav-tabs">
+                <li role="presentation" class="active"><a href="javascript:void(0);"><%= engineeringInfo.name %></a></li>
+            </ul>
+        </div>
+        <div class="c-body">
+            <form method="post" action="/compilation/save-lib" enctype="application/x-www-form-urlencoded21">
+                <div class="row">
+                    <div class="col-md-4">
+                        <div class="form-group">
+                            <label>标准清单</label>
+                            <div class="bill-list">
+                                <% if (Object.keys(libData).length > 0 && libData.bill_lib.length > 0) { %>
+                                <% libData.bill_lib.forEach(function (bill, index){ %>
+                                <p class="form-control-static">
+                                    <a class="pull-right text-danger remove-lib" data-model="bill" title="移除">
+                                        <span class="glyphicon glyphicon-remove"></span>
+                                    </a>
+                                    <input type="hidden" name="bill_lib" data-id="<%= bill.id %>" value="<%= JSON.stringify({id: bill.id, name: bill.name}) %>">
+                                    <% if (index === 0) {%><i class="glyphicon glyphicon-flag"></i>&nbsp;<% } %><%= bill.name %>
+                                </p>
+                                <% }) %>
+                                <% } %>
+                            </div>
+                            <a class="btn btn-link btn-sm add-compilation" href="javascript:void(0)" data-model="bill">添加</a>
+                        </div>
+                        <div class="form-group">
+                            <label>定额库</label>
+                            <div class="ration-list">
+                                <% if (Object.keys(libData).length > 0 && libData.ration_lib.length > 0) { %>
+                                <% libData.ration_lib.forEach(function (ration, index){ %>
+                                <p class="form-control-static">
+                                    <a class="pull-right text-danger remove-lib" data-model="ration" title="移除" data-id="<%= ration.id %>">
+                                        <span class="glyphicon glyphicon-remove"></span>
+                                    </a>
+                                    <input type="hidden" name="ration_lib" data-id="<%= ration.id %>" value="<%= JSON.stringify({id: ration.id, name: ration.name}) %>">
+                                    <% if (index === 0) {%><i class="glyphicon glyphicon-flag"></i>&nbsp;<% } %><%= ration.name %>
+                                </p>
+                                <% }) %>
+                                <% } %>
+                            </div>
+                            <a href="#" class="btn btn-link btn-sm add-compilation" data-model="ration">添加</a>
+                        </div>
+                        <div class="form-group">
+                            <label>工料机库</label>
+                            <div class="glj-list">
+                                <% if (Object.keys(libData).length > 0 && libData.glj_lib.length > 0) { %>
+                                <% libData.glj_lib.forEach(function (glj, index){ %>
+                                <p class="form-control-static">
+                                    <a class="pull-right text-danger remove-lib" data-model="glj" title="移除" data-id="<%= glj.id %>">
+                                        <span class="glyphicon glyphicon-remove"></span>
+                                    </a>
+                                    <input type="hidden" name="glj_lib" data-id="<%= glj.id %>" value="<%= JSON.stringify({id: glj.id, name: glj.name}) %>">
+                                    <% if (index === 0) {%><i class="glyphicon glyphicon-flag"></i>&nbsp;<% } %><%= glj.name %>
+                                </p>
+                                <% }) %>
+                                <% } %>
+                            </div>
+                            <a href="#" class="btn btn-link btn-sm add-compilation" data-model="glj">添加</a>
+                        </div>
+                        <div class="form-group">
+                            <label>费率标准</label>
+                            <div class="fee-list">
+                                <% if (Object.keys(libData).length > 0 && libData.fee_lib.length > 0) { %>
+                                <% libData.fee_lib.forEach(function (fee, index){ %>
+                                <p class="form-control-static">
+                                    <a class="pull-right text-danger remove-lib" data-model="fee" title="移除" data-id="<%= fee.id %>">
+                                        <span class="glyphicon glyphicon-remove"></span>
+                                    </a>
+                                    <input type="hidden" name="fee_lib" data-id="<%= fee.id %>" value="<%= JSON.stringify({id: fee.id, name: fee.name}) %>">
+                                    <% if (index === 0) {%><i class="glyphicon glyphicon-flag"></i>&nbsp;<% } %><%= fee.name %>
+                                </p>
+                                <% }) %>
+                                <% } %>
+                            </div>
+                            <a href="#" class="btn btn-link btn-sm add-compilation" data-model="fee">添加</a>
+                        </div>
+                    </div>
+                    <div class="col-md-8">
+                        <legend>
+                            清单模板 / 造价书列
+                            <a href="javascript:void(0)" data-toggle="modal" data-target="#set-column" class="btn btn-primary btn-sm pull-right">设置</a>
+                            <a href="/compilation/template/<%= section %>/<%= valuationId %>" data-toggle="modal" data-target="" class="btn btn-primary btn-sm pull-right" style="margin-right:5px">模板设置</a>
+                            <input type="hidden" name="main_tree_col" value="<%= mainTreeCol %>">
+                            <div id="main-tree-col">
+                            </div>
+                    </div>
+                </div>
+                <input type="hidden" name="engineering" value="<%= engineeringInfo.id %>" id="engineering">
+                <input type="hidden" name="section" value="<%= section %>" id="section">
+                <input type="hidden" name="id" value="<%= valuationId %>">
+            </form>
+        </div>
+    </div>
+</div>
+<script type="text/javascript">
+    let billList = '<%- billList %>';
+    let rationList = '<%- rationList %>';
+    let gljList = '<%- gljList %>';
+    let feeRateList = '<%- feeRateList %>';
+    let mainTreeCol = '<%- mainTreeCol %>';
+    let billsTemplateData = '<%- billsTemplateData %>';
+    let colSpread = null;
+    let colEditSpread = null;
+</script>
+<script type="text/javascript" src="/public/web/id_tree.js"></script>
+<script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_helper.js"></script>
+<script type="text/javascript" src="/web/users/js/compilation.js"></script>
+<%include ../compilation/modal.html %>

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

@@ -41,6 +41,16 @@
                         </div>
                         </div>
                     </div>
                     </div>
                 </div>
                 </div>
+                <div class="form-group" id="fee-area">
+                    <label>费率库</label>
+                    <div class="row">
+                        <div class="col-xs-12">
+                            <select class="form-control" name="fee_lib">
+                                <option value="">请选择费率库</option>
+                            </select>
+                        </div>
+                    </div>
+                </div>
             </div>
             </div>
             <div class="modal-footer">
             <div class="modal-footer">
                 <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                 <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>

+ 1 - 0
web/users/views/compilation/template.html

@@ -52,6 +52,7 @@
 </div>
 </div>
 <script>
 <script>
     let billsTemplateData = '<%- billsTemplateData %>';
     let billsTemplateData = '<%- billsTemplateData %>';
+    let billsFixedFlagList = '<%- billsFixedFlagList %>';
     let updateUrl = '/compilation/template/<%= section %>/<%= valuationId %>/update';
     let updateUrl = '/compilation/template/<%= section %>/<%= valuationId %>/update';
 </script>
 </script>
 <script type="text/javascript" src="/public/web/id_tree.js"></script>
 <script type="text/javascript" src="/public/web/id_tree.js"></script>