Browse Source

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

TonyKang 7 years ago
parent
commit
e1bfd9c0a6
35 changed files with 3175 additions and 201 deletions
  1. 41 0
      modules/all_models/bills_template_items.js
  2. 21 0
      modules/all_models/bills_template_lib.js
  3. 0 15
      modules/all_models/compilation.js
  4. 22 16
      modules/all_models/engineering_lib.js
  5. 31 0
      modules/all_models/main_col_lib.js
  6. 140 0
      modules/bills_template_lib/controllers/bills_template_controller.js
  7. 94 0
      modules/bills_template_lib/facade/bills_template_facade.js
  8. 24 0
      modules/bills_template_lib/routes/bills_template_routes.js
  9. 7 0
      modules/common/std/schemas/std_calc_program.js
  10. 5 4
      modules/common/std/std_calc_program_model.js
  11. 148 0
      modules/main_col_lib/controllers/main_col_controller.js
  12. 67 0
      modules/main_col_lib/facade/main_col_facade.js
  13. 25 0
      modules/main_col_lib/routes/main_col_routes.js
  14. 64 42
      modules/users/controllers/compilation_controller.js
  15. 0 1
      modules/users/models/bills_template_model.js
  16. 6 7
      modules/users/models/compilation_model.js
  17. 40 44
      modules/users/models/engineering_lib_model.js
  18. 2 1
      modules/users/routes/compilation_route.js
  19. 43 0
      web/maintain/bill_template_lib/html/edit.html
  20. 114 0
      web/maintain/bill_template_lib/html/main.html
  21. 69 0
      web/maintain/bill_template_lib/js/bills_template.js
  22. 508 0
      web/maintain/bill_template_lib/js/bills_template_edit.js
  23. 2 2
      web/maintain/bills_lib/scripts/bills_lib_ajax.js
  24. 3 1
      web/maintain/bills_lib/scripts/global.js
  25. 345 0
      web/maintain/common/css/main.css
  26. 46 0
      web/maintain/common/html/edit_layout.html
  27. 43 0
      web/maintain/common/html/layout.html
  28. 179 0
      web/maintain/main_col_lib/html/main.html
  29. 507 0
      web/maintain/main_col_lib/js/main_col_lib.js
  30. 228 0
      web/maintain/main_col_lib/js/main_tree_col.js
  31. 176 5
      web/users/js/compilation.js
  32. 22 14
      web/users/views/compilation/add.html
  33. 65 33
      web/users/views/compilation/engineering.html
  34. 62 10
      web/users/views/compilation/modal.html
  35. 26 6
      web/users/views/tool/index.html

+ 41 - 0
modules/all_models/bills_template_items.js

@@ -0,0 +1,41 @@
+/**
+ * Created by zhang on 2018/7/13.
+ */
+import mongoose from "mongoose";
+let Schema = mongoose.Schema;
+
+let collectionName = 'std_bills_template_items';
+
+// 标记字段
+let flagsSchema = new Schema({
+    fieldName: String,
+    flag: Number
+});
+let BillsTemplateSchema = {
+    // 树结构所需ID
+    ID: Number,
+    ParentID: Number,
+    NextSiblingID: Number,
+    // 编号
+    code: String,
+    // 名称
+    name: String,
+    // 单位
+    unit: String,
+    // 类别
+    type: Number,
+    // 标记
+    flags:{
+        type: [flagsSchema],
+        default: []
+    },
+    // 所属模板库ID
+    libID: {type:String,index:true},
+    //计算基数
+    calcBase: String,
+    //费率ID
+    feeRateID:Number
+};
+
+mongoose.model(collectionName, new Schema(BillsTemplateSchema, {versionKey: false, collection: collectionName}));
+

+ 21 - 0
modules/all_models/bills_template_lib.js

@@ -0,0 +1,21 @@
+/**
+ * Created by zhang on 2018/7/12.
+ */
+//清单模板库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+const stdBillsTemplate_lib = new Schema({
+        ID:{type:String,index:true},
+        creator: String,
+        createDate: Number,
+        recentOpr: [oprSchema],
+        name: String,
+        compilationId: String,
+        compilationName: String,
+        deleted: Boolean
+    },
+    {versionKey: false}
+);
+
+mongoose.model("std_bills_template_lib", stdBillsTemplate_lib,"std_bills_template_lib");

+ 0 - 15
modules/all_models/compilation.js

@@ -9,25 +9,10 @@ import mongoose from "mongoose";
 
 let Schema = mongoose.Schema;
 let collectionName = 'compilation';
-let engineeringListSchema = new Schema({
-    // 工程专业id
-    engineering: {
-        type: Number
-    },
-    engineering_id: {
-        type: Schema.Types.Mixed,
-        default: []
-    }
-}, {_id: false});
 let childrenSchema = new Schema({
     id:String,
     // 计价名称
     name: String,
-    // 工程专业列表
-    engineering_list: {
-        type: [engineeringListSchema],
-        default: []
-    },
     // 是否启用
     enable: {
         type: Boolean,

+ 22 - 16
modules/all_models/engineering_lib.js

@@ -9,6 +9,14 @@ import mongoose from "mongoose";
 
 let Schema = mongoose.Schema;
 let collectionName = 'engineering_lib';
+let taxGroupSchema = new  Schema({
+    taxType: String,//计税方式
+    program_lib: { type: Schema.Types.Mixed,default:{}},// 计算程序标准库
+    template_lib:{ type: Schema.Types.Mixed,default:{}},//清单模板库
+    col_lib:{ type: Schema.Types.Mixed,default:{}}
+},{_id: false});
+
+
 let modelSchema = {
     // 标准清单
     bill_lib: {
@@ -30,16 +38,9 @@ let modelSchema = {
         type: Schema.Types.Mixed,
         default: []
     },
-    // 列设置
-    main_tree_col: {
-        type: Schema.Types.Mixed,
-        default: {
-            emptyRows: 3,
-            headRows: 0,
-            treeCol: 0,
-            headRowHeight: [],
-            cols:[]
-        }
+    tax_group :{
+      type: [taxGroupSchema],
+      default: []
     },
     // 费率标准库
     fee_lib: {
@@ -51,15 +52,20 @@ let modelSchema = {
         type: Schema.Types.Mixed,
         default: []
     },
-    // 计算程序标准库
-    program_lib: {
-        type: Schema.Types.Mixed,
-        default: []
-    },
     //设置人材机显示列
     glj_col:{
         showAdjustPrice:Boolean//是否显示调整价列
-    }
+    },
+    //清单或定额计价规则ID
+    valuationID:{type:String,index: true},
+    //工程专业名称
+    name:String,
+    //前端是否显示
+    visible:{
+        type: Boolean,
+        default: false
+    },
+    engineering:Number
 };
 mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));
 

+ 31 - 0
modules/all_models/main_col_lib.js

@@ -0,0 +1,31 @@
+/**
+ * Created by zhang on 2018/7/14.
+ */
+
+//列设置库
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+const main_col_lib = new Schema({
+        ID:{type:String,index:true},
+            main_tree_col: {
+                type: Schema.Types.Mixed,
+                default: {
+                    emptyRows: 3,
+                    headRows: 0,
+                    treeCol: 0,
+                    headRowHeight: [],
+                    cols:[]
+                }
+            },
+        creator: String,
+        createDate: Number,
+        recentOpr: [oprSchema],
+        name: String,
+        compilationId: String,
+        compilationName: String,
+        deleted: Boolean
+    }, {versionKey: false}
+);
+
+mongoose.model("std_main_col_lib", main_col_lib,"std_main_col_lib");

+ 140 - 0
modules/bills_template_lib/controllers/bills_template_controller.js

@@ -0,0 +1,140 @@
+/**
+ * 清单模板控制控制器
+ *
+ * @author CaiAoLin
+ * @date 2017/7/28
+ * @compilation
+ */
+import BaseController from "../../common/base/base_controller";
+import billsTemplateFacade from "../facade/bills_template_facade";
+import {default as BillsFixedFlagConst, List as BillsFixedFlagList} from "../../common/const/bills_fixed.js";
+import {default as BillsTypeFlagConst, List as BillsTypeFlagList} from "../../common/const/bills_type.js";
+
+class BillsTemplateController extends BaseController {
+
+    /**
+     * 清单模板库页面
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async main(request, response) {
+        let templateLibs = await billsTemplateFacade.getAllLibs();
+        let randerData = {
+            title:'清单模板',
+            userAccount: request.session.managerData.username,
+            userID: request.session.managerData.userID,
+            templateLibs:templateLibs,
+            layout: 'maintain/common/html/layout'
+        };
+
+        response.render("maintain/bill_template_lib/html/main", randerData);
+    }
+    async updateBillsTemplateItem(request, response) {
+        let libID = request.params.libID;
+        let result = {error: 1, message: '更新数据错误', data: null};
+        try {
+            let data = JSON.parse(request.body.data);
+            if(libID){
+                 result = await await billsTemplateFacade.updateTemplateItem(libID,data);
+                if (result) {
+                    result = {error: 0, message: '', data: data};
+                }
+            }
+
+        }catch (err){
+            console.log(err);
+        }
+        response.json(result);
+    }
+
+    async editTemplate(request, response){
+
+        //先取出清单库信息:
+        let libID = request.params.libID;
+        let templateLib = await billsTemplateFacade.getLibByID(libID);
+        if(templateLib){
+
+            let templateDatas = await billsTemplateFacade.getTemplateDatasByLibID(libID);
+
+            let randerData = {
+                title:'清单模板',
+                mainURL:'/billsTemplate/main',
+                libName:templateLib.name,
+                userAccount: request.session.managerData.username,
+                userID: request.session.managerData.userID,
+                billsTemplateData:JSON.stringify(templateDatas),
+                billsFixedFlagList: JSON.stringify(BillsFixedFlagList),
+                billsTypeFlagList: JSON.stringify(BillsTypeFlagList),
+                libID:libID,
+                layout: 'maintain/common/html/edit_layout'
+            };
+            response.render("maintain/bill_template_lib/html/edit", randerData);
+        }else {
+            response.redirect(request.headers.referer);
+        }
+    }
+
+    async deleteLibByID(request,response){
+        let result={
+            error:0
+        };
+        try {
+            let data = request.body.data;
+            data = JSON.parse(data);
+            let resultData= await billsTemplateFacade.deleteLibByID(data.ID);
+            result.data=resultData;
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
+
+    async saveLib(request, response){
+        let result={
+            error:0
+        };
+        try {
+            let data = request.body.data;
+            data = JSON.parse(data);
+            let resultData= await billsTemplateFacade.saveLib(data);
+            result.data=resultData;
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
+
+    async getLibByID(request, response){
+        let result={
+            error:0
+        };
+        try {
+            let data = request.body.data;
+            data = JSON.parse(data);
+            let resultData= await billsTemplateFacade.getLibByID(data.libID);
+            result.data=resultData;
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
+
+    async addLib(request, response){
+        try {
+            await billsTemplateFacade.addLib(request.body);
+        }catch (error) {
+            console.log(error);
+        }
+        response.redirect(request.headers.referer);
+    }
+}
+
+export default BillsTemplateController;

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

@@ -0,0 +1,94 @@
+/**
+ * Created by Zhang on 2018/7/13.
+ * 清单模板,新建项目使用
+ */
+import mongoose from "mongoose";
+const uuidV1 = require('uuid/v1');
+let moment = require("moment");
+let compilationModel = mongoose.model("compilation");
+let billTemplateLibModel = mongoose.model("std_bills_template_lib");
+let billTemplateItemsModel = mongoose.model("std_bills_template_items");
+
+let billTemplate={
+    addLib:addLib,
+    getAllLibs:getAllLibs,
+    getLibByID:getLibByID,
+    saveLib:saveLib,
+    deleteLibByID:deleteLibByID,
+    getTemplateDatasByLibID:getTemplateDatasByLibID,
+    updateTemplateItem:updateTemplateItem,
+    getTemplateLibByCompilationID:getTemplateLibByCompilationID
+};
+
+async function getTemplateLibByCompilationID(compilationID) {
+    return await billTemplateLibModel.find({compilationId:compilationID},['ID','name']);
+}
+
+async function updateTemplateItem (libID, datas) {
+        for (let data of datas) {
+            data.data.libID  = libID;
+            let condition = {libID: libID, ID: data.data.ID}, result;
+            if (data.type === 'update') {
+                result = await billTemplateItemsModel.update(condition, data.data);
+                if (result === undefined || result.ok ===undefined || !result.ok) {
+                    throw '更新数据错误';
+                }
+            } else if (data.type === 'new') {
+                result = await billTemplateItemsModel.create(data.data);
+                if (!result) {
+                    throw '新增数据错误';
+                }
+            } else if (data.type === 'delete') {
+                result = await billTemplateItemsModel.deleteOne(condition);
+                result = result.result;
+                if (result === undefined || result.ok ===undefined || !result.ok) {
+                    throw '删除数据错误';
+                }
+            }
+        }
+        return true;
+}
+
+async function getTemplateDatasByLibID(libID) {
+    return await billTemplateItemsModel.find({libID:libID});
+}
+async function deleteLibByID(ID){
+    return billTemplateLibModel.deleteOne({ID:ID});
+}
+
+async function getLibByID(ID) {
+    return await billTemplateLibModel.findOne({ID:ID});
+}
+
+async function getAllLibs() {
+    return await billTemplateLibModel.find();
+}
+
+async function saveLib(param) {
+    return await billTemplateLibModel.findOneAndUpdate(param.query,param.data,{new:true});
+}
+
+async function addLib(data){
+    let now = new Date().getTime();
+    let dateStr = moment(now).format('YYYY-MM-DD HH:mm:ss');
+    //取编办信息
+    let compilation = await compilationModel.findOne({_id:data.compilationId});
+    if(compilation){
+        let newLib = {
+            creator: data.userAccount,
+            createDate: now,
+            recentOpr: [{operator: data.userAccount, operateDate: dateStr}],
+            name: data.name,
+            compilationId: data.compilationId,
+            compilationName: compilation.name,
+            deleted: false
+        };
+        newLib.ID = uuidV1();
+        return await billTemplateLibModel.create(newLib);
+    }else {
+        throw  new Error("没有找到该编办!");
+    }
+}
+
+
+export default  billTemplate

+ 24 - 0
modules/bills_template_lib/routes/bills_template_routes.js

@@ -0,0 +1,24 @@
+/**
+ * Created by zhang on 2017/7/12.
+ */
+let express = require("express");
+let templateRouter =express.Router();
+import BillsTemplateController from "../controllers/bills_template_controller";
+let billsTemplateController = new BillsTemplateController();
+
+
+
+module.exports =function (app) {
+
+    templateRouter.get("/main", billsTemplateController.auth, billsTemplateController.init, billsTemplateController.main);
+    templateRouter.get("/editTemplate/:libID", billsTemplateController.auth, billsTemplateController.init, billsTemplateController.editTemplate);
+    templateRouter.post("/getLibByID", billsTemplateController.auth, billsTemplateController.init, billsTemplateController.getLibByID);
+    templateRouter.post("/saveLib", billsTemplateController.auth, billsTemplateController.init, billsTemplateController.saveLib);
+    templateRouter.post("/deleteLibByID", billsTemplateController.auth, billsTemplateController.init, billsTemplateController.deleteLibByID);
+    templateRouter.post("/add-lib", billsTemplateController.auth, billsTemplateController.init, billsTemplateController.addLib);
+    templateRouter.post("/updateBillsTemplateItem/:libID", billsTemplateController.auth, billsTemplateController.init, billsTemplateController.updateBillsTemplateItem);
+    app.use("/billsTemplate", templateRouter);
+
+};
+
+

+ 7 - 0
modules/common/std/schemas/std_calc_program.js

@@ -16,6 +16,13 @@ let modelSchema = {
     region: String,
     // 标准名称
     libName: String,
+    //后台选择计算程序时展示的名称,在用户新建时看不到这个名称
+    displayName:String,
+    // 编办id
+    compilationId: {
+        type: String,
+        index: true
+    },
     // 模板数据
     templates: Schema.Types.Mixed
 };

+ 5 - 4
modules/common/std/std_calc_program_model.js

@@ -26,10 +26,10 @@ class STDCalcProgramModel extends BaseModel {
      *
      * @return {Promise}
      */
-    async getProgramList() {
+    async getProgramList(compilationId) {
         let result = [];
-        let field = {ID: 1, libName: 1};
-        let programList = await this.findDataByCondition({ID: {$ne: ''}}, field, false);
+        let field = {ID: 1, libName: 1,displayName:1};
+        let programList = await this.findDataByCondition({compilationId:compilationId,ID: {$ne: ''}}, field, false);
 
         if (programList === null) {
             return result;
@@ -38,7 +38,8 @@ class STDCalcProgramModel extends BaseModel {
         for(let program of programList) {
             let tmpData = {
                 id: program.ID,
-                name: program.libName
+                name: program.libName,
+                displayName:program.displayName
             };
             result.push(tmpData);
         }

+ 148 - 0
modules/main_col_lib/controllers/main_col_controller.js

@@ -0,0 +1,148 @@
+/**
+ * Created by zhang on 2018/7/14.
+ */
+
+/**
+ * 列设置控制器
+ *
+ */
+import BaseController from "../../common/base/base_controller";
+import mainColFacade from "../facade/main_col_facade";
+
+
+class MainColController extends BaseController {
+
+    /**
+     * 修改计价规则页面
+     *
+     * @param {object} request
+     * @param {object} response
+     * @return {void}
+     */
+    async main(request, response) {
+        let mainColLibs = await mainColFacade.getAllLibs();
+        let randerData = {
+            title:'列设置',
+            userAccount: request.session.managerData.username,
+            userID: request.session.managerData.userID,
+            mainColLibs:mainColLibs,
+            layout: 'maintain/common/html/layout'
+        };
+
+        response.render("maintain/main_col_lib/html/main", randerData);
+    }
+
+    async addLib(request, response){
+        try {
+            await mainColFacade.addLib(request.body);
+        }catch (error) {
+            console.log(error);
+        }
+        response.redirect(request.headers.referer);
+    }
+
+    async deleteLibByID(request,response){
+        let result={
+            error:0
+        };
+        try {
+            let data = request.body.data;
+            data = JSON.parse(data);
+            let resultData= await mainColFacade.deleteLibByID(data.ID);
+            result.data=resultData;
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
+
+    async getLibByID(request, response){
+        let result={
+            error:0
+        };
+        try {
+            let data = request.body.data;
+            data = JSON.parse(data);
+            let resultData= await mainColFacade.getLibByID(data.libID);
+            result.data=resultData;
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
+
+    async saveLib(request, response){
+        let result={
+            error:0
+        };
+        try {
+            let data = request.body.data;
+            data = JSON.parse(data);
+            let resultData= await mainColFacade.saveLib(data);
+            result.data=resultData;
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
+
+    /*async updateBillsTemplateItem(request, response) {
+        let libID = request.params.libID;
+        let result = {error: 1, message: '更新数据错误', data: null};
+        try {
+            let data = JSON.parse(request.body.data);
+            if(libID){
+                result = await await billsTemplateFacade.updateTemplateItem(libID,data);
+                if (result) {
+                    result = {error: 0, message: '', data: data};
+                }
+            }
+
+        }catch (err){
+            console.log(err);
+        }
+        response.json(result);
+    }
+
+    async editTemplate(request, response){
+
+        //先取出清单库信息:
+        let libID = request.params.libID;
+        let templateLib = await billsTemplateFacade.getLibByID(libID);
+        if(templateLib){
+
+            let templateDatas = await billsTemplateFacade.getTemplateDatasByLibID(libID);
+
+            let randerData = {
+                title:'清单模板',
+                mainURL:'/billsTemplate/main',
+                libName:templateLib.name,
+                userAccount: request.session.managerData.username,
+                userID: request.session.managerData.userID,
+                billsTemplateData:JSON.stringify(templateDatas),
+                billsFixedFlagList: JSON.stringify(BillsFixedFlagList),
+                billsTypeFlagList: JSON.stringify(BillsTypeFlagList),
+                libID:libID,
+                layout: 'maintain/common/html/edit_layout'
+            };
+            response.render("maintain/bill_template_lib/html/edit", randerData);
+        }else {
+            response.redirect(request.headers.referer);
+        }
+    }
+
+
+
+
+
+
+   */
+}
+
+export default MainColController;

+ 67 - 0
modules/main_col_lib/facade/main_col_facade.js

@@ -0,0 +1,67 @@
+/**
+ * Created by zhang on 2018/7/14.
+ */
+
+import mongoose from "mongoose";
+const uuidV1 = require('uuid/v1');
+let moment = require("moment");
+let compilationModel = mongoose.model("compilation");
+let mainColLibModel = mongoose.model("std_main_col_lib");
+
+let mainCol={
+    addLib:addLib,
+    getAllLibs:getAllLibs,
+    deleteLibByID:deleteLibByID,
+    getLibByID:getLibByID,
+    saveLib:saveLib,
+    getColLibsByCompilationID:getColLibsByCompilationID
+};
+
+async function saveLib(param) {
+    if(param.data.main_tree_col){
+        param.data.main_tree_col = JSON.parse(param.data.main_tree_col);
+    }
+    return await mainColLibModel.findOneAndUpdate(param.query,param.data,{new:true});
+}
+
+async function getLibByID(ID) {
+    return await mainColLibModel.findOne({ID:ID});
+}
+async function getColLibsByCompilationID(compilationID) {
+    return await mainColLibModel.find({compilationId:compilationID},['ID','name']);
+}
+
+
+async function deleteLibByID(ID){
+    return mainColLibModel.deleteOne({ID:ID});
+}
+
+async function getAllLibs() {
+    return await mainColLibModel.find();
+}
+
+async function addLib(data){
+    let now = new Date().getTime();
+    let dateStr = moment(now).format('YYYY-MM-DD HH:mm:ss');
+    //取编办信息
+    let compilation = await compilationModel.findOne({_id:data.compilationId});
+    if(compilation){
+        let newLib = {
+            creator: data.userAccount,
+            createDate: now,
+            recentOpr: [{operator: data.userAccount, operateDate: dateStr}],
+            name: data.name,
+            compilationId: data.compilationId,
+            compilationName: compilation.name,
+            deleted: false
+        };
+        newLib.ID = uuidV1();
+        return await mainColLibModel.create(newLib);
+    }else {
+        throw  new Error("没有找到该编办!");
+    }
+}
+
+
+
+export default  mainCol

+ 25 - 0
modules/main_col_lib/routes/main_col_routes.js

@@ -0,0 +1,25 @@
+/**
+ * Created by zhang on 2018/7/14.
+ */
+let express = require("express");
+let colRouter =express.Router();
+import MainColController from "../controllers/main_col_controller";
+let mainColController = new MainColController();
+
+
+
+module.exports =function (app) {
+
+    colRouter.get("/main", mainColController.auth, mainColController.init, mainColController.main);
+    colRouter.post("/add-lib", mainColController.auth, mainColController.init, mainColController.addLib);
+    colRouter.post("/deleteLibByID", mainColController.auth, mainColController.init, mainColController.deleteLibByID);
+    colRouter.post("/getLibByID", mainColController.auth, mainColController.init, mainColController.getLibByID);
+    colRouter.post("/saveLib", mainColController.auth, mainColController.init, mainColController.saveLib);
+    /*colRouter.get("/editTemplate/:libID", mainColController.auth, mainColController.init, mainColController.editTemplate);
+    colRouter.post("/getLibByID", mainColController.auth, mainColController.init, mainColController.getLibByID);
+    colRouter.post("/saveLib", mainColController.auth, mainColController.init, mainColController.saveLib);
+    colRouter.post("/deleteLibByID", mainColController.auth, mainColController.init, mainColController.deleteLibByID);
+    colRouter.post("/add-lib", mainColController.auth, mainColController.init, mainColController.addLib);
+    colRouter.post("/updateBillsTemplateItem/:libID", mainColController.auth, mainColController.init, mainColController.updateBillsTemplateItem);*/
+    app.use("/mainTreeCol", colRouter);
+};

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

@@ -19,6 +19,8 @@ import EngineeringLibModel from "../models/engineering_lib_model";
 import STDLabourCoesModel from "../../common/std/std_labour_coes_model";
 import STDCalcProgramModel from "../../common/std/std_calc_program_model";
 const billsGuidanceFc = require('../../std_billsGuidance_lib/facade/facades');
+import mainColFacade from "../../main_col_lib/facade/main_col_facade";
+import billTemplateFacade from "../../bills_template_lib/facade/bills_template_facade";
 
 class CompilationController extends BaseController {
 
@@ -92,11 +94,14 @@ class CompilationController extends BaseController {
             };
 
             let compilationModel = new CompilationModel();
-            let result = await compilationModel.addValuation(id, section, insertData);
-
-            if (!result) {
+            let valuationId = await compilationModel.addValuation(id, section, insertData);
+            if (!valuationId) {
                 throw '新增计价规则失败';
             }
+            //添加标准工程专业
+            let engineeringLibModel = new EngineeringLibModel();
+            let stdEngs = await engineeringLibModel.addStdLib(valuationId);
+            console.log(stdEngs);
         } catch (error) {
             console.log(error);
             responseData.err = 1;
@@ -119,9 +124,9 @@ class CompilationController extends BaseController {
         let section = request.params.section;
 
         let compilationList = [];
+        let engineeringList = [];
         let valuationData = {};
         let valuationList = {};
-        let libCount = {};
         try {
             let compilationModel = new CompilationModel();
             compilationList = await compilationModel.getCompilationList();
@@ -134,19 +139,19 @@ class CompilationController extends BaseController {
 
             // 获取计价规则中对应的标准库数据
             let engineeringLibModel = new EngineeringLibModel();
-            libCount = await engineeringLibModel.getLibCount(valuationData);
+            engineeringList = await engineeringLibModel.getLibsByValuationID(valuationId);
+
         } catch (error) {
             console.log(error);
         }
 
         let renderData = {
             compilationList: compilationList,
-            engineeringList: EngineeringList,
+            engineeringList: engineeringList,
             selectedCompilation: selectedCompilation,
             valuationData: valuationData,
             valuationList: valuationList,
             valuationId: valuationId,
-            libCount: libCount,
             section: section,
             layout: 'users/views/layout/layout'
         };
@@ -161,35 +166,14 @@ class CompilationController extends BaseController {
      * @return {void}
      */
     async editEngineering(request, response) {
-        let engineering = parseInt(request.params.engineering);
+        let engineerID = request.params.engineerID;
         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 feeRateList = [];
-        let libData = {};
-        let billsTemplateData = [];
-        let valuationData = {};
-        let valuationList = {};
-        let artificialCoefficientList = [];
-        let calculationList = [];
-        let billsGuidanceList = [];
+        let compilationList = [],billList = [], rationList = [], gljList = [],feeRateList = [], libData = {}, billsTemplateData = [];
+        let valuationData = {}, valuationList = {}, artificialCoefficientList = [], calculationList = [], billsGuidanceList = [], mainTreeColList = [];
+        let billTemplateList = [];
         try {
             let compilationModel = new CompilationModel();
             compilationList = await compilationModel.getCompilationList();
@@ -216,7 +200,13 @@ class CompilationController extends BaseController {
 
             // 获取计算程序库
             let stdCalcProgramModel = new STDCalcProgramModel();
-            calculationList = await stdCalcProgramModel.getProgramList();
+            calculationList = await stdCalcProgramModel.getProgramList(selectedCompilation._id);
+
+            //获取列设置库
+             mainTreeColList = await mainColFacade.getColLibsByCompilationID(selectedCompilation._id);
+
+             //获取清单模板库
+            billTemplateList = await billTemplateFacade.getTemplateLibByCompilationID(selectedCompilation._id);
 
             // 获取对应的计价规则数据
             [valuationData, valuationList] = await compilationModel.getValuation(selectedCompilation._id, valuationId, section);
@@ -226,11 +216,11 @@ class CompilationController extends BaseController {
 
             // 获取对应专业工程下的标准库数据
             let engineeringLibModel = new EngineeringLibModel();
-            libData = await engineeringLibModel.getLib(valuationData.engineering_list, engineering);
+            libData = await engineeringLibModel.findDataByCondition({_id:engineerID});
 
             // 获取清单模板数据
             let billsTemplateModel = new BillsTemplateModel();
-            billsTemplateData = await billsTemplateModel.getTemplateData(valuationId, engineering);
+            billsTemplateData = await billsTemplateModel.getTemplateData(valuationId, libData.engineering);
 
             //获取清单指引数据
             billsGuidanceList = await billsGuidanceFc.getBillsGuideLibs({compilationId: selectedCompilation._id, $or: [{deleted: null}, {deleted: false}]});
@@ -242,7 +232,6 @@ class CompilationController extends BaseController {
         let renderData = {
             section: section,
             valuationId: valuationId,
-            engineeringInfo: engineeringInfo,
             compilationList: compilationList,
             selectedCompilation: selectedCompilation,
             libData: libData,
@@ -252,7 +241,8 @@ class CompilationController extends BaseController {
             artificialCoefficientList: JSON.stringify(artificialCoefficientList),
             feeRateList: JSON.stringify(feeRateList),
             billsTemplateData: JSON.stringify(billsTemplateData),
-            mainTreeCol: JSON.stringify(libData.main_tree_col),
+            billTemplateList:JSON.stringify(billTemplateList),
+            mainTreeColList: JSON.stringify(mainTreeColList),
             gljCol:JSON.stringify(libData.glj_col),
             calculationList: JSON.stringify(calculationList),
             billsGuidanceList: JSON.stringify(billsGuidanceList),
@@ -269,16 +259,16 @@ class CompilationController extends BaseController {
      * @return {void}
      */
     async saveEngineering(request, response) {
-        let valuationId = request.body.id;
+        let engineerId = request.body.id;
 
         try {
-            if (valuationId === '') {
+            if (engineerId === '') {
                 throw 'id参数错误';
             }
 
             // 先存入工程专业标准库表
             let engineeringLibModel = new EngineeringLibModel();
-            let result = await engineeringLibModel.addLib(valuationId, request.body);
+            let result = await engineeringLibModel.addLib(engineerId, request.body);
 
             if (!result) {
                 throw '保存失败';
@@ -291,6 +281,35 @@ class CompilationController extends BaseController {
         response.redirect(request.headers.referer);
     }
 
+
+    /**
+     * 保存工程专业信息-用于异步操作
+     * @param request
+     * @param response
+     * @returns {Promise.<void>}
+     */
+    async updateEngineer(request,response){
+        let result={
+            error:0
+        };
+        try {
+            let data = request.body.data;
+            data = JSON.parse(data);
+            if(data.id && data.updateData){
+                let engineeringLibModel = new EngineeringLibModel();
+                result.data = await engineeringLibModel.updateById(data.id,data.updateData);
+            }else {
+                throw new Error("提交数据有误");
+            }
+
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        response.json(result);
+    }
+
     /**
      * 保存计价规则
      *
@@ -307,7 +326,6 @@ class CompilationController extends BaseController {
 
             let compilationModel = new CompilationModel();
             let result = await compilationModel.saveValuation(valuationId, request.body);
-
             if (!result) {
                 throw '保存失败';
             }
@@ -336,9 +354,13 @@ class CompilationController extends BaseController {
                 throw '参数错误';
             }
 
+            //先删除对应的工程专业
+            let engineeringLibModel = new EngineeringLibModel();
+            await engineeringLibModel.deleteByValuationID(id);
+
+            //删除计价规则
             let compilationModel = new CompilationModel();
             let result = compilationModel.deleteValuation(selectedCompilation._id, id, section);
-
             if (!result) {
                 throw '删除失败';
             }

+ 0 - 1
modules/users/models/bills_template_model.js

@@ -27,7 +27,6 @@ class BillsTemplateModel extends BaseModel {
         // 筛选字段
         let field = {_id: 1, valuationId: 1, ID: 1, ParentID: 1, NextSiblingID: 1, code: 1, name: 1, unit: 1, flags: 1, type: 1,calcBase:1,feeRateID:1};
         let data = await this.findDataByCondition({valuationId: valuationId, engineering: engineering}, field, false);
-        console.log(data);
         return data === null ? [] : data;
     }
 

+ 6 - 7
modules/users/models/compilation_model.js

@@ -7,6 +7,7 @@
  */
 import mongoose from "mongoose";
 import BaseModel from "../../common/base/base_model";
+import  uuidV1  from 'uuid/v1';
 
 class CompilationModel extends BaseModel {
 
@@ -113,12 +114,10 @@ class CompilationModel extends BaseModel {
         }
 
         let insertData = {};
-        data.id = "12580";
+        data.id = uuidV1();
         insertData[section + '_valuation'] = data;
         let result = await this.db.addToSet(condition, insertData);
-        console.log(result);
-
-        return result.ok === undefined ? false : result.ok;
+        return result.ok === undefined ? false : data.id;
     }
 
     /**
@@ -132,7 +131,7 @@ class CompilationModel extends BaseModel {
         data = this._filterValuationData(data);
         let sectionString = data.section + "_valuation";
         let condition = {};
-        condition[sectionString + "._id"] = valuationId;
+        condition[sectionString + ".id"] = valuationId;
 
         let updateData = {};
         updateData[sectionString + ".$.name"] = data.name;
@@ -153,7 +152,7 @@ class CompilationModel extends BaseModel {
     async switchEnable(valuationId, section, enable) {
         let sectionString = section + "_valuation";
         let condition = {};
-        condition[sectionString + "._id"] = valuationId;
+        condition[sectionString + ".id"] = valuationId;
 
         let updateData = {};
         updateData[sectionString + ".$.enable"] = enable === "true";
@@ -237,7 +236,7 @@ class CompilationModel extends BaseModel {
         let condition = {_id: compilationId};
         let sectionString = section + '_valuation';
         let deleteData = {};
-        deleteData[sectionString] = {_id: valuationId};
+        deleteData[sectionString] = {id: valuationId};
 
         // 利用pull删除嵌套数据
         let result = await this.db.deleteSet(condition, deleteData);

+ 40 - 44
modules/users/models/engineering_lib_model.js

@@ -48,6 +48,36 @@ class EngineeringLibModel extends BaseModel {
         return this.findDataByCondition(condition);
     }
 
+    async getLibsByValuationID(valuationID){
+        return this.findDataByCondition({valuationID:valuationID},null,false);
+    }
+
+    async deleteByValuationID(valuationID){
+        return await this.db.delete({valuationID:valuationID});
+    }
+
+
+    //添加空的默认的所有标准库
+    /**
+     * @param valuationID
+     * @returns {Promise.<*>}
+     */
+    async addStdLib(valuationID){
+        let stdLibs = [];
+        for(let eng of EngineeringList){
+            let tem = {
+                glj_col:{showAdjustPrice:false},
+                valuationID:valuationID,
+                name:eng.name,
+                engineering:eng.value
+            };
+            stdLibs.push(tem);
+        }
+        let result = await this.db.create(stdLibs);
+        return result;
+    }
+
+
     /**
      * 新增标准库
      *
@@ -55,58 +85,23 @@ class EngineeringLibModel extends BaseModel {
      * @param {Object} data
      * @return {Promise}
      */
-    async addLib(valuationId, data) {
-        if (data.main_tree_col) {
-            data.main_tree_col = JSON.parse(data.main_tree_col);
-        } else {
-            data.main_tree_col = {
-                emptyRows: 3,
-                headRows: 0,
-                treeCol: 0,
-                headRowHeight: [],
-                cols:[]
-            }
-        }
+    async addLib(engineerId, data) {
         if(data.glj_col){
             data.glj_col =  JSON.parse(data.glj_col);
         }
-
         let result = false;
         data = this.filterLibData(data);
         try {
-            // 查找计价规则表中是否有对应工程专业标准库的数据
-            let compilationModel = new CompilationModel();
-            let engineeringLib = await compilationModel.getEngineeringLib(valuationId, data.section, data.engineering);
-            if (engineeringLib === null) {
-                // 不存在则插入
-                result = await this.db.create(data);
-                console.log(data);
-            } else {
+            let engineeringLib = await this.findDataByCondition({_id:engineerId});
+            if(engineeringLib){
+                // 存在则直接更新
                 delete data.id;
                 delete data.section;
-                delete data.engineering;
-                console.log(`data==============================================`);
-                console.log(data);
-                // 存在则直接更新
-                let condition = {_id: engineeringLib.engineering_id};
+                let condition = {_id: engineerId};
                 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 '新增编办数据中的专业工程失败!';
-                }
+            }else {
+                throw  new Error("找不到对应的工程专业");
             }
 
         } catch (error) {
@@ -159,8 +154,8 @@ class EngineeringLibModel extends BaseModel {
         // 判断人工系数
         data.artificial_lib = this._validLib(data.artificial_lib);
 
-        // 判断计算程序
-        data.program_lib = this._validLib(data.program_lib);
+        //计税方式组合
+        data.tax_group = this._validLib(data.tax_group);
 
         return data;
     }
@@ -184,6 +179,7 @@ class EngineeringLibModel extends BaseModel {
         return result;
     }
 
+
     /**
      * 获取对应标准库数量
      *

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

@@ -15,7 +15,7 @@ module.exports = function (app) {
     // action定义区域
     router.get('/', compilationController.auth, compilationController.init, compilationController.index);
     router.get('/valuation/:section/:id', compilationController.auth, compilationController.init, compilationController.editValuation);
-    router.get('/:section/:id/:engineering', compilationController.auth, compilationController.init, compilationController.editEngineering);
+    router.get('/:section/:id/:engineerID', compilationController.auth, compilationController.init, compilationController.editEngineering);
     router.get('/valuation/:section/delete/:id', compilationController.auth, compilationController.init, compilationController.deleteValuation);
     router.get('/template/:section/:id/:engineering', compilationController.auth, compilationController.init, compilationController.billsTemplate);
 
@@ -24,6 +24,7 @@ module.exports = function (app) {
     router.post('/setDescription', compilationController.auth, compilationController.init, compilationController.setDescription);
     router.post('/add-valuation', compilationController.auth, compilationController.init, compilationController.addValuation);
     router.post('/save-valuation', compilationController.auth, compilationController.init, compilationController.saveValuation);
+    router.post('/update-engineer', compilationController.auth, compilationController.init, compilationController.updateEngineer);
     router.post('/save-lib', compilationController.auth, compilationController.init, compilationController.saveEngineering);
     router.post('/valuation/:section/enable', compilationController.auth, compilationController.init, compilationController.enableSwitch);
     router.post('/template/:section/:id/:engineering/update', compilationController.auth, compilationController.init, compilationController.updateBillsTemplate);

+ 43 - 0
web/maintain/bill_template_lib/html/edit.html

@@ -0,0 +1,43 @@
+<nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0 second_header">
+    <ul class="nav nav-tabs" role="tablist">
+        <li class="nav-item">
+            <a class="nav-link active px-3" href="javascript: void(0);">清单模板</a>
+        </li>
+    </ul>
+</nav>
+
+<div class="main">
+    <div class="content" >
+        <div class=" col-lg-12 p-0">
+            <nav class="navbar sticky-top navbar-toggleable-md navbar-light bg-faded tools-bar">
+                <div class="collapse navbar-collapse" id="navbarNav">
+                    <div class="tools-btn btn-group align-top">
+                        <a href="" class="btn btn-sm"><i class="fa fa-files-o" aria-hidden="true"></i> 复制</a>
+                        <a href="" class="btn btn-sm"><i class="fa fa-scissors" aria-hidden="true"></i> 剪切</a>
+                        <a href="" class="btn btn-sm"><i class="fa fa-clipboard" aria-hidden="true"></i> 粘贴</a>
+                        <a href="javascript:void(0)" class="btn btn-sm" id="insert"><i class="fa fa-sign-in" aria-hidden="true"></i> 插入</a>
+                        <a href="javascript:void(0)" class="btn btn-sm" id="delete"><i class="fa fa-remove" aria-hidden="true"></i> 删除</a>
+                        <a href="javascript:void(0)" class="btn btn-sm" id="upLevel"><i class="fa fa-arrow-left" aria-hidden="true"></i> 升级</a>
+                        <a href="javascript:void(0)" class="btn btn-sm" id="downLevel"><i class="fa fa-arrow-right" aria-hidden="true"></i> 降级</a>
+                        <a href="javascript:void(0)" class="btn btn-sm" id="downMove"><i class="fa fa-arrow-down" aria-hidden="true"></i> 下移</a>
+                        <a href="javascript:void(0)" class="btn btn-sm" id="upMove"><i class="fa fa-arrow-up" aria-hidden="true"></i> 上移</a>
+                    </div>
+                </div>
+            </nav>
+            <div class="edit-spread" id="billsSpread"></div>
+
+        </div>
+    </div>
+</div>
+
+<script>
+    let billsTemplateData = '<%- billsTemplateData %>';
+    let billsFixedFlagList = '<%- billsFixedFlagList %>';
+    let billsTypeFlagList = '<%- billsTypeFlagList %>';
+    let updateUrl = '/billsTemplate/updateBillsTemplateItem/<%= libID%>';
+</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="/public/web/tree_sheet/tree_sheet_controller.js"></script>
+<script type="text/javascript" src="/public/web/common_ajax.js"></script>
+<script type="text/javascript" src="/web/maintain/bill_template_lib/js/bills_template_edit.js"></script>

+ 114 - 0
web/maintain/bill_template_lib/html/main.html

@@ -0,0 +1,114 @@
+<div class="main">
+    <div class="content">
+        <div class="container-fluid">
+            <div class="row">
+                <div class="col-md-8">
+                    <div class="warp-p2 mt-3">
+                        <table class="table table-hover table-bordered">
+                            <thead><tr><th>清单模板名称</th><th width="160">编办</th><th width="160">添加时间</th><th width="90">操作</th></tr></thead>
+                            <tbody id="showArea">
+                            <% for(let lib of templateLibs){ %>
+                            <tr class="libTr">
+                                <td id="<%= lib.ID%>"><a href="/billsTemplate/editTemplate/<%= lib.ID%>"><%= lib.name%></a></td>
+                                <td><%= lib.compilationName%></td>
+                                <td><%= moment(lib.createDate).format('YYYY-MM-DD')%></td>
+                                <td>
+                                    <a href="javacript:void(0);" onclick='getTemplateLib("<%= lib.ID%>")' title="编辑"><i class="fa fa-pencil-square-o"></i></a>
+                                    <a href="javacript:void(0);" onclick='showDeleteModal("<%= lib.ID%>")'class="text-danger" title="删除"><i class="fa fa-remove"></i></a>
+                                </td>
+                            </tr>
+                            <% } %>
+                            </tbody>
+                        </table>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+
+<!--弹出添加-->
+<div class="modal fade" id="add" data-backdrop="static" style="display: none;" aria-hidden="true">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">添加清单模板</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">×</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <form id="addTemplateForm" method="post" action="/billsTemplate/add-lib" enctype="application/x-www-form-urlencoded21">
+                    <div class="form-group">
+                        <label>清单模板名称</label>
+                        <input id="name" name="name" class="form-control" placeholder="输入清单模板名称" type="text">
+                        <small class="form-text text-danger" id="nameError" style="display: none">请输入模板名称。</small>
+                    </div>
+                    <div class="form-group">
+                        <label>编办名称</label>
+                        <select id="compilationSels" name="compilationId" class="form-control"></select>
+                    </div>
+                    <input type="hidden" name = "userAccount" value="<%= userAccount%>">
+                </form>
+            </div>
+            <div class="modal-footer">
+                <a id="addTemplate"  href="javascript:void(0);" class="btn btn-primary">新建</a>
+                <button type="button" id="cancelBtn" class="btn btn-secondary" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+<!--弹出编辑-->
+<div class="modal fade" id="edit" data-backdrop="static" style="display: none;" aria-hidden="true">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">编辑清单模板</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">×</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <form>
+                    <div class="form-group">
+                        <label>清单模板名称</label>
+                        <input id="renameText" class="form-control" placeholder="输入名称" type="text" value="">
+                        <small class="form-text text-danger" id="renameError" style="display: none">请输入列名称。</small>
+                        <input id="libID" type="hidden">
+                    </div>
+                </form>
+            </div>
+            <div class="modal-footer">
+                <a id="rename" href="javascript: void(0);" class="btn btn-primary" >确定</a>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+<!--弹出删除-->
+<div class="modal fade" id="del" data-backdrop="static" style="display: none;" aria-hidden="true">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">删除确认</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">×</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <h5 class="text-danger">删除后无法恢复,确认是否删除?</h5>
+                <input type="hidden" id="libID_del">
+                <input type="hidden" id="delCount">
+            </div>
+            <div class="modal-footer">
+                <a id="delete" href="javascript:void(0);" class="btn btn-danger" >确认</a>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+<script src="/web/maintain/bills_lib/scripts/bills_lib_ajax.js"></script>
+<script type="text/javascript" src="/web/maintain/bill_template_lib/js/bills_template.js"></script>

+ 69 - 0
web/maintain/bill_template_lib/js/bills_template.js

@@ -0,0 +1,69 @@
+/**
+ * Created by zhang on 2018/7/12.
+ */
+
+$(document).ready(function() {
+    $('#add').on('show.bs.modal', function () {
+        $('#compilationSels').empty();
+        mainAjax.getCompilationList();
+    });
+
+    // 保存按钮
+    $("#addTemplate").click(function() {
+        let name = $('#name').val();
+        if(name==''){
+            $("#nameError").show();
+            return;
+        }else {
+            $("#addTemplate").addClass("disabled");//防止重复提交
+            $("#addTemplateForm").submit();
+        }
+    });
+
+    $("#rename").click(function() {
+        let libID = $("#libID").val();
+        let name = $('#renameText').val();
+        if(libID!=''){
+            if(name ==''){
+                $("#renameError").show();
+                return;
+            }else {
+                CommonAjax.post("/billsTemplate/saveLib",{query:{ID:libID},data:{name:name}},function (data) {
+                    $("#"+libID).children("a").text(data.name);
+                    $("#edit").modal('hide');
+                });
+            }
+        }
+    });
+
+    $("#delete").click(function() {
+        let libID = $("#libID_del").val();
+        let delCount = parseInt($("#delCount").val());
+        delCount = delCount+1;
+        $("#delCount").val(delCount)
+        if(delCount == 3){
+           if(libID!=""){
+               CommonAjax.post("/billsTemplate/deleteLibByID",{ID:libID},function (data) {
+                   if(data.ok){
+                       $("#"+libID).parent(".libTr").remove();
+                   }
+                   $("#del").modal('hide');
+               });
+           }
+        }
+    });
+});
+
+function getTemplateLib (ID) {
+    CommonAjax.post("/billsTemplate/getLibByID",{libID:ID},function (data) {
+        $("#renameText").val(data.name);
+        $("#libID").val(ID);
+        $("#edit").modal({show:true});
+    });
+}
+
+function showDeleteModal(ID){
+    $("#libID_del").val(ID);
+    $("#delCount").val(0);
+    $("#del").modal({show:true});
+}

+ 508 - 0
web/maintain/bill_template_lib/js/bills_template_edit.js

@@ -0,0 +1,508 @@
+/**
+ * Created by zhang on 2018/7/13.
+ */
+
+
+let TEMPLATE_BILLS_SETTING = {
+    "emptyRows":1,
+    "headRows":1,
+    "headRowHeight":[35],
+    "treeCol": 1,
+    "cols":[{
+        "width":80,
+        "readOnly":false,
+        "head":{
+            "titleNames":["类别"],
+            "spanCols":[1],
+            "spanRows":[1],
+            "vAlign":[1],
+            "hAlign":[1],
+            "font":["Arial"]
+        },
+        "data":{
+            "field":"type",
+            "vAlign":0,
+            "hAlign":1,
+            "font":"Arail",
+        }
+    }, {
+        "width":200,
+        "readOnly":false,
+        "head":{
+            "titleNames":["编号"],
+            "spanCols":[1],
+            "spanRows":[1],
+            "vAlign":[1],
+            "hAlign":[1],
+            "font":["Arial"],
+        },
+        "data":{
+            "field":"code",
+            "vAlign":0,
+            "hAlign":3,
+            "font":"Arail",
+            "formatter": '@'
+        }
+    }, {
+        "width":300,
+        "readOnly":false,
+        "head":{
+            "titleNames":["名称"],
+            "spanCols":[1],
+            "spanRows":[1],
+            "vAlign":[1],
+            "hAlign":[1],
+            "font":["Arial"]
+        },
+        "data":{
+            "field":"name",
+            "vAlign":0,
+            "hAlign":3,
+            "font":"Arail"
+        }
+    }, {
+        "width":50,
+        "readOnly":false,
+        "head":{
+            "titleNames":["单位"],
+            "spanCols":[1],
+            "spanRows":[1],
+            "vAlign":[1],
+            "hAlign":[1],
+            "font":["Arial"]
+        },
+        "data":{
+            "field":"unit",
+            "vAlign":0,
+            "hAlign":1,
+            "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":250,
+        "readOnly":false,
+        "head":{
+            "titleNames":["计算基数"],
+            "spanCols":[1],
+            "spanRows":[1],
+            "vAlign":[1],
+            "hAlign":[1],
+            "font":["Arial"]
+        },
+        "data":{
+            "field":"calcBase",
+            "vAlign":0,
+            "hAlign":3,
+            "font":"Arail",
+        }
+    }, {
+        "width":50,
+        "readOnly":false,
+        "head":{
+            "titleNames":["费率ID"],
+            "spanCols":[1],
+            "spanRows":[1],
+            "vAlign":[1],
+            "hAlign":[1],
+            "font":["Arial"]
+        },
+        "data":{
+            "field":"feeRateID",
+            "type":'Number',
+            "vAlign":0,
+            "hAlign":1,
+            "font":"Arail"
+        }
+    }, {
+        "width":50,
+        "readOnly":true,
+        "head":{
+            "titleNames":["ID"],
+            "spanCols":[1],
+            "spanRows":[1],
+            "vAlign":[1],
+            "hAlign":[1],
+            "font":["Arial"]
+        },
+        "data":{
+            "field":"ID",
+            "vAlign":0,
+            "hAlign":1,
+            "font":"Arail"
+        }
+    }, {
+        "width":50,
+        "readOnly":true,
+        "head":{
+            "titleNames":["ParentID"],
+            "spanCols":[1],
+            "spanRows":[1],
+            "vAlign":[1],
+            "hAlign":[1],
+            "font":["Arial"]
+        },
+        "data":{
+            "field":"ParentID",
+            "vAlign":0,
+            "hAlign":1,
+            "font":"Arail"
+        }
+    }, {
+        "width":50,
+        "readOnly":true,
+        "head":{
+            "titleNames":["NextSiblingID"],
+            "spanCols":[1],
+            "spanRows":[1],
+            "vAlign":[1],
+            "hAlign":[1],
+            "font":["Arial"]
+        },
+        "data":{
+            "field":"NextSiblingID",
+            "vAlign":0,
+            "hAlign":1,
+            "font":"Arail"
+        }
+    }]
+};
+
+$(document).ready(function () {
+    autoFlashHeight();
+    let RefreshBaseActn = function (tree) {
+        /*  let showButton = function (show, btn) { 隐藏改成灰显
+         if (show) {
+         btn.show();
+         } else {
+         btn.hide();
+         }
+         };*/
+        let setButtonValid = function (valid, btn) {
+            if (valid) {
+                btn.removeClass('disabled');
+            } else {
+                btn.addClass('disabled');
+            }
+        };
+        setButtonValid(tree.selected && tree.selected.canUpLevel(), $('#upLevel'));
+        setButtonValid(tree.selected && tree.selected.canDownLevel(), $('#downLevel'));
+        setButtonValid(tree.selected && tree.selected.canUpMove(), $('#upMove'));
+        setButtonValid(tree.selected && tree.selected.canDownMove(), $('#downMove'));
+        setButtonValid(tree.selected ? true : false, $('#delete'));
+    };
+    let RefreshBillsData = function (datas) {
+        datas.forEach(function (data) {
+            let node = tree.findNode(data.data.ID);
+            if (node) {
+                $.extend(true, node.data, data.data);
+            }
+        });
+    };
+    let getNameValueComboCellType = function (datas) {
+        let comboItems = [];
+        for (let data of datas) {
+            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 getFixedFlagCellType = function () {
+        let billsFixedFlagData = JSON.parse(billsFixedFlagList);
+        return getNameValueComboCellType(billsFixedFlagData);
+    };
+    let getNameToValueMap = function (listString) {
+        let map = {};
+        let datas = JSON.parse(listString);
+        for(let data of datas){
+            map[data.name] = data.value;
+        }
+        return map;
+    };
+    let getTypeFlagCellType = function () {
+        let billsTypeFlagData = JSON.parse(billsTypeFlagList);
+        return getNameValueComboCellType(billsTypeFlagData);
+    };
+    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 getRealValue = function (value,map) {//中文到实际值的转换
+        if(value) value = value.replace(/[\s\r\n]/g, "");//去掉空格,回车等无用字符
+        if(map[value]!==undefined && map[value]!==null) value = map[value];
+        return value;
+    };
+    let setUpdateData = function (node,data,col,value,setting) {
+        let fieldName = setting.cols[col].data.field;
+        let valueType = setting.cols[col].data.type;
+        if(fieldName == 'type'){
+            value = getRealValue(value,typeMap);
+        }
+        if(fieldName == 'flagsIndex.fixed.flag'){
+            value = getRealValue(value,fixedFlagMap);
+        }
+        if (/flagsIndex/.test(fieldName)) {
+            data.data.flags = [];
+            let flagField = fieldName.split('.');
+            data.data.flags.push({fieldName: flagField[1],flag: value});
+        } else {
+            if(value && valueType == 'Number') value = parseInt(value);
+            setFee(data.data, fieldName, value);
+        }
+    };
+
+    billsTemplateData = billsTemplateData.replace(/\n/g, '\\n');
+    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 === 'type' && TEMPLATE_BILLS_SETTING.cols.indexOf(col) !== TEMPLATE_BILLS_SETTING.treeCol) {
+            col.data.cellType = getTypeFlagCellType();
+        } else 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 billsSpread = TREE_SHEET_HELPER.createNewSpread($('#billsSpread')[0]);
+    let controller = TREE_SHEET_CONTROLLER.createNew(tree, billsSpread.getActiveSheet(), TEMPLATE_BILLS_SETTING);
+    let fixedFlagMap = getNameToValueMap(billsFixedFlagList);
+    let typeMap = getNameToValueMap(billsTypeFlagList);
+    console.log(fixedFlagMap);
+    console.log(typeMap);
+    //format code
+    //billsSpread.getSheet(0).setFormatter(-1, 1, '@');
+    controller.bind('refreshBaseActn', RefreshBaseActn);
+
+    billsSpread.bind(GC.Spread.Sheets.Events.EditEnded, function (sender, info) {
+        var node = controller.tree.items[info.row];
+        var fieldName = controller.setting.cols[info.col].data.field;
+        var valueType = controller.setting.cols[info.col].data.type;
+        let value = info.editingText;
+        if(node){
+            var data = {type: 'update', data: {ID: node.getID()}};
+            if (/flagsIndex/.test(fieldName)) {
+                data.data.flags = [];
+                let flagField = fieldName.split('.');
+                data.data.flags.push({fieldName: flagField[1], flag: info.editingText});
+            } else {
+                if(value && valueType == 'Number') value = parseInt(info.editingText);
+                setFee(data.data, fieldName, value);
+            }
+            var updateData = [data];
+            CommonAjax.post(updateUrl, updateData, function (data) {
+                setFee(node.data, fieldName, value);
+                controller.refreshTreeNode([node], false);
+            }, function () {
+                controller.refreshTreeNode([node], false);
+            });
+        }else {
+            info.sheet.getCell(info.row,info.col).value("");
+        }
+
+    });
+    billsSpread.bind(GC.Spread.Sheets.Events.ClipboardPasted, function (e, info) {
+        console.log("ClipboardPasted");
+        var node, iRow, iCol, curRow, curCol, datas = [], data, fieldName,valueType,value, updateData;
+        for (iRow = 0; iRow < info.cellRange.rowCount; iRow ++) {
+            curRow = info.cellRange.row + iRow;
+            node = controller.tree.items[curRow];
+            if (node) {
+                data = {type: 'update', data: {ID: node.getID()}};
+                for (iCol = 0; iCol < info.cellRange.colCount; iCol++) {
+                    curCol = info.cellRange.col + iCol;
+                    value = info.sheet.getText(curRow, curCol);
+                    setUpdateData(node,data,curCol,value,controller.setting);
+                }
+                datas.push(data);
+            }
+        };
+        CommonAjax.post(updateUrl, datas, function (data) {
+            RefreshBillsData(data);
+            controller.showTreeData();
+        }, function () {
+            controller.showTreeData();
+        });
+    });
+    billsSpread.bind(GC.Spread.Sheets.Events.RangeChanged, function (e,info) {
+        let datas = [];
+        let changGroup = _.groupBy(info.changedCells,'row');
+        for(let row in changGroup){
+            let node = controller.tree.items[row];
+            if (node) {
+                let data = {type: 'update', data: {ID: node.getID()}};
+                for (let cell of changGroup[row]) {
+                    let value = info.sheet.getText(cell.row, cell.col);
+                    if(value=="") value = null;
+                    setUpdateData(node,data,cell.col,value,controller.setting);
+                }
+                datas.push(data);
+            }
+        }
+        CommonAjax.post(updateUrl, datas, function (data) {
+            RefreshBillsData(data);
+            controller.showTreeData();
+        }, function () {
+            controller.showTreeData();
+        });
+
+    });
+    tree.loadDatas(templateData);
+    controller.showTreeData();
+    let sel = billsSpread.getActiveSheet().getSelections()[0];
+    controller.setTreeSelected(tree.items[sel.row == -1?0:sel.row]);//初始化选中项
+    RefreshBaseActn(tree);
+    $('#insert').click(function () {
+        let me = this;
+        $(me).addClass('disabled');
+        var selected = controller.tree.selected, updateData;
+        if (selected) {
+            updateData = controller.tree.getInsertData(selected.getParentID(), selected.getNextSiblingID());
+        } else {
+            updateData = controller.tree.getInsertData();
+        }
+        if (updateData.length > 0) {
+            CommonAjax.post(updateUrl, updateData, function (data) {
+                controller.insert();
+                controller.showTreeData();
+                $(me).removeClass('disabled');
+            });
+        } else {
+            alert('新增节点失败, 请重试.');
+            $(me).removeClass('disabled');
+        }
+    });
+    $('#delete').click(function () {
+        let me = this;
+        $(me).addClass('disabled');
+        let selection = controller.sheet.getSelections()[0], updateData,deleteMap={},deleteNodes=[];
+        for(let i=0;i < selection.rowCount;i++){
+            let tem_node = controller.tree.items[selection.row+i];
+            if(i == 0){//第一个直接添加;
+                deleteMap[tem_node.getID()] = tem_node;
+                deleteNodes.push(tem_node);
+            }else {
+                setNodeToMapAndArray(tem_node,deleteMap,deleteNodes);
+            }
+        }
+
+        if (deleteNodes.length > 0) {
+            updateData = controller.tree.getDeleteDatas(deleteMap,deleteNodes);
+            CommonAjax.post(updateUrl, updateData, function (data) {
+                controller.m_delete(deleteNodes);
+                controller.showTreeData();
+                $(me).removeClass('disabled');
+            });
+        }
+        function setNodeToMapAndArray(node,map,array) {
+            let nodeID = node.getID();
+            if(map[nodeID]==undefined||map[nodeID]==null){
+                newMap(node,node.parent,map,array)
+            }
+            function newMap(node,parent,map,array) {
+                let nodeID =node.getID();
+                if(parent==null){//说明已经是最顶层了
+                    map[nodeID]=node;
+                    array.push(node);
+                }else {
+                    let parentID = parent.getID();
+                    if(map[parentID]==undefined||map[parentID]==null){
+                        newMap(node,parent.parent,map,array);
+                    }
+                }
+            }
+        }
+
+    });
+    $('#upLevel').click(function () {
+        let me = this;
+        $(me).addClass('disabled');
+        var selected = controller.tree.selected, updateData;
+        if (selected) {
+            updateData = selected.getUpLevelData();
+            CommonAjax.post(updateUrl, updateData, function (data) {
+                controller.upLevel();
+                controller.showTreeData();
+                $(me).removeClass('disabled');
+            });
+        }
+    });
+    $('#downLevel').click(function () {
+        let me = this;
+        $(me).addClass('disabled');
+        var selected = controller.tree.selected, updateData;
+        if (selected) {
+            updateData = selected.getDownLevelData();
+            CommonAjax.post(updateUrl, updateData, function (data) {
+                controller.downLevel();
+                controller.showTreeData();
+                $(me).removeClass('disabled');
+            });
+        }
+    });
+    $('#upMove').click(function () {
+        let me = this;
+        $(me).addClass('disabled');
+        var selected = controller.tree.selected, updateData;
+        if (selected) {
+            updateData = selected.getUpMoveData();
+            CommonAjax.post(updateUrl, updateData, function (data) {
+                controller.upMove();
+                controller.showTreeData();
+                $(me).removeClass('disabled');
+            });
+        }
+    });
+    $('#downMove').click(function () {
+        let me = this;
+        $(me).addClass('disabled');
+        var selected = controller.tree.selected, updateData;
+        if (selected) {
+            updateData = selected.getDownMoveData();
+            CommonAjax.post(updateUrl, updateData, function (data) {
+                controller.downMove();
+                controller.showTreeData();
+                $(me).removeClass('disabled');
+            });
+        }
+    });
+});

+ 2 - 2
web/maintain/bills_lib/scripts/bills_lib_ajax.js

@@ -6,7 +6,7 @@ var mainAjax = {
     getCompilationList: function () {
         $.ajax({
             type: 'post',
-            url: 'stdBillsEditor/getCompilationList',
+            url: '/stdBillsEditor/getCompilationList',
             dataType: 'json',
             success: function (result) {
                 //addoptions
@@ -23,7 +23,7 @@ var mainAjax = {
     getMaxNumber: function(billsLibId, field, callback){
         $.ajax({
             type: 'post',
-            url: 'stdBillsEditor/getMaxNumber',
+            url: '/stdBillsEditor/getMaxNumber',
             data: {data: JSON.stringify({billsLibId: billsLibId, field: field})},
             dataType: 'json',
             success: function(result){

+ 3 - 1
web/maintain/bills_lib/scripts/global.js

@@ -2,10 +2,12 @@
 function autoFlashHeight(){
     var headerHeight = $(".header").height();
     var toolsBar = $(".tools-bar").height();
-    $(".content").height($(window).height()-headerHeight);
+    var second_header = $(".second_header").height();
+    $(".content").height($(window).height()-headerHeight-second_header);
     $(".main-side").height($(window).height()-headerHeight-2);
     $(".main-content").height($(window).height()-headerHeight-2);
     $(".main-data").height($(window).height()-headerHeight-toolsBar-16);
+    $(".edit-spread").height($(window).height()-headerHeight-toolsBar-second_header-17);
 };
 $(window).resize(autoFlashHeight);
 /*全局自适应高度结束*/

+ 345 - 0
web/maintain/common/css/main.css

@@ -0,0 +1,345 @@
+/*building SAAS 0.1*/
+/*bootstrap 初始化*/
+body {
+    font-size: 0.9rem
+}
+.dropdown-menu {
+    font-size: 0.9rem
+}
+/*自定义css*/
+.header {
+    background: #e1e1e1
+}
+.header .header-logo {
+    background: #ff6501;
+    color: #fff;
+    float: left;
+    padding-top: .25rem;
+    padding-bottom: .25rem;
+    margin-right: 1rem;
+    font-size: 1.25rem;
+    line-height: inherit
+}
+.top-msg{
+    position: fixed;
+    top:0;
+    width:100%;
+    z-index: 999
+}
+.in-1{padding-left:0rem!important}
+.in-2{padding-left:1rem!important}
+.in-3{padding-left:1.5rem!important}
+.in-4{padding-left:2rem!important}
+.in-5{padding-left:2.5rem!important}
+.in-6{padding-left:3rem!important}
+.main {
+    position: relative;
+    background: #f7f7f9;
+}
+.main-nav {
+    position: absolute;
+    text-align: center;
+    z-index: 999;
+    padding: 2px 0 0 2px
+}
+.main-nav .nav a {
+    display: block;
+    width: 28px;
+    text-align: center;
+    line-height: 18px;
+    color: #999;
+    padding: 10px 0;
+    border-right: 1px solid #ccc;
+}
+.main-nav .nav a:hover {
+    background: #fff;
+    color: #333;
+    text-decoration: none;
+}
+.main-nav .nav a.active {
+    border: 1px solid #ccc;
+    border-right: 1px solid #fff;
+    background: #fff;
+    color: #333
+}
+.content {
+    background: #fff
+}
+.tools-btn {
+    height: 30px;
+    line-height: 30px;
+}
+.toolsbar .tools-btn.btn:hover {
+    background: #f7f7f9;
+}
+.main-side {
+    border-right: 1px solid #ccc;
+    overflow:hidden;
+}
+.main-side .tab-bar {
+    padding:5px 10px;
+    height:38px;
+    position:fixed;
+}
+.main-side .tab-content {
+    margin-top: 38px
+}
+.top-content, .fluid-content {
+    overflow: hidden;
+    border-bottom: 1px solid #ccc;
+}
+.warp-p2 {
+    padding: 2px
+}
+.bottom-content .nav,.top-content .nav {
+    background: #f7f7f9;
+    padding:0 0 0 2px
+}
+.bottom-content .nav-tabs .nav-link, .side-tabs .nav-tabs .nav-link,.top-content .nav-tabs .nav-link {
+    border-radius: 0;
+    padding: 0.2em 0.5em
+}
+.side-tabs .nav-tabs .nav-item {
+    z-index: 999
+}
+.side-tabs .nav-tabs {
+    border-bottom: none;
+    margin-bottom: -1px
+}
+.side-tabs .nav-tabs .nav-link {
+    border-radius: 0;
+    padding: 0em 0.5em;
+    line-height: 30px;
+    z-index: 999
+}
+.bottom-content .nav-tabs .nav-link.active {
+    border-top: 1px solid #f7f7f9
+}
+.side-tabs .nav-tabs .nav-link.active {
+    border-top: none;
+    border-bottom:1px solid #fff
+}
+.side-tabs a.active, .sub-nav a.active {
+    background: #ccc
+}
+.poj-manage {
+    background: #fff
+}
+.slide-sidebar {
+    border-left: 1px solid #E1E1E1;
+    box-shadow: 0px 15px 15px rgba(0, 0, 0, 0.1);
+    background: none repeat scroll 0% 0% #ffffff;
+    overflow: hidden;
+    position: absolute;
+    right: 0px;
+    top: 0;
+    z-index: 999;
+    width: 0px;
+}
+.new-msg {
+    -webkit-animation: tada 1s infinite .2s ease both;
+    -moz-animation: tada 1s infinite .2s ease both;
+}
+@-webkit-keyframes tada {
+    0% {
+        -webkit-transform: scale(1)
+    }
+    10%, 20% {
+        -webkit-transform: scale(0.9) rotate(-3deg)
+    }
+    30%, 50%, 70%, 90% {
+        -webkit-transform: scale(1.1) rotate(3deg)
+    }
+    40%, 60%, 80% {
+        -webkit-transform: scale(1.1) rotate(-3deg)
+    }
+    100% {
+        -webkit-transform: scale(1) rotate(0)
+    }
+}
+@-moz-keyframes tada {
+    0% {
+        -moz-transform: scale(1)
+    }
+    10%, 20% {
+        -moz-transform: scale(0.9) rotate(-3deg)
+    }
+    30%, 50%, 70%, 90% {
+        -moz-transform: scale(1.1) rotate(3deg)
+    }
+    40%, 60%, 80% {
+        -moz-transform: scale(1.1) rotate(-3deg)
+    }
+    100% {
+        -moz-transform: scale(1) rotate(0)
+    }
+}
+.has-danger {
+    -webkit-animation: shake 1s .2s ease both;
+    -moz-animation: shake 1s .2s ease both;
+    animation: shake 1s .2s ease both;
+}
+@-webkit-keyframes shake {
+    0%, 100% {
+        -webkit-transform: translateX(0);
+    }
+    10%, 30%, 50%, 70%, 90% {
+        -webkit-transform: translateX(-10px);
+    }
+    20%, 40%, 60%, 80% {
+        -webkit-transform: translateX(10px);
+    }
+}
+@-moz-keyframes shake {
+    0%, 100% {
+        -moz-transform: translateX(0);
+    }
+    10%, 30%, 50%, 70%, 90% {
+        -moz-transform: translateX(-10px);
+    }
+    20%, 40%, 60%, 80% {
+        -moz-transform: translateX(10px);
+    }
+}
+@keyframes shake {
+    0%, 100% {
+        transform: translateX(0);
+    }
+    10%, 30%, 50%, 70%, 90% {
+        transform: translateX(-10px);
+    }
+    20%, 40%, 60%, 80% {
+        transform: translateX(10px);
+    }
+}
+.bottom-content {
+    height: 370px;
+    overflow: hidden;
+}
+.bottom-content .tab-content .main-data-bottom{
+    height: 340px;
+    overflow: auto;
+}
+.form-signin {
+    max-width: 500px;
+    margin: 150px auto;
+}
+.poj-list, .side-content {
+    overflow: auto;
+}
+.poj-list span.poj-icon {
+    padding-right:10px;
+    color:#ccc
+}
+.print-toolsbar{
+    padding:5px
+}
+.print-toolsbar .panel {
+    display:inline-block;
+    vertical-align:top;
+    background:#f7f7f9
+}
+.print-toolsbar .panel .panel-foot{
+    text-align: center;
+    font-size: 12px
+}
+.print-list {
+    border-right:1px solid #ccc
+}
+.print-list .form-list {
+    overflow: auto
+}
+.print-list .list-tools{
+    height:50px;
+    padding:10px 0;
+    border-bottom:1px solid #f2f2f2
+}
+.pageContainer {
+    background: #ededed;
+    text-align: center
+}
+.pageContainer .page{
+    border:9px solid transparent;
+    display: inline-block;
+}
+.pageContainer .page img{
+    width:inherit;
+    height: inherit;
+}
+.codeList{
+    max-height: 200px;
+    overflow:auto;
+}
+.main-data-top,.main-data-bottom,.main-data{
+    overflow: hidden;
+}
+.modal-fixed-height {
+    height:400px;
+    overflow-y:auto;
+}
+.second_header{
+    background: #e1e1e1;
+}
+
+.input-group-addon{
+    padding: 6px 12px;
+    font-size: 14px;
+    font-weight: 400;
+    line-height: 1;
+    color: #555;
+    text-align: center;
+    background-color: #eee;
+    border: 1px solid #ccc;
+    border-radius: 4px;
+}
+
+.input-sm{
+    height: 30px;
+    padding: 5px 10px;
+    font-size: 12px;
+    line-height: 1.5;
+    border-radius: 3px;
+}
+
+.btn-default{
+    color: #333;
+    background-color: #fff;
+    border-color: #ccc;
+}
+.checkbox{
+    position: relative;
+    display: block;
+    margin-top: 10px;
+    margin-bottom: 10px;
+}
+input[type=checkbox]{
+    position: absolute;
+    margin-top: 5px;
+    margin-left: -20px;
+}
+.col-md-2{
+    position: relative;
+    min-height: 1px;
+    padding-right: 15px;
+    padding-left:15px;
+    width:16.66666667%
+}
+.checkbox label, .radio label {
+    min-height: 20px;
+    padding-left: 20px;
+    margin-bottom: 0;
+    font-weight: 400;
+    cursor: pointer;
+    width: 200px;
+}
+
+.close{
+    float: right;
+    font-size: 21px;
+    font-weight: 700;
+    line-height: 1;
+    color: #000;
+    text-shadow: 0 1px 0 #fff;
+    filter: alpha(opacity=20);
+    opacity: .2;
+}

File diff suppressed because it is too large
+ 46 - 0
web/maintain/common/html/edit_layout.html


+ 43 - 0
web/maintain/common/html/layout.html

@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title><%= title%>编辑器</title>
+    <link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
+    <link rel="stylesheet" href="/web/maintain/common/css/main.css">
+    <link rel="stylesheet" href="/lib/font-awesome/font-awesome.min.css">
+    <link rel="stylesheet" href="/lib/spreadjs/sheets/css/gc.spread.sheets.sc.css" type="text/css">
+</head>
+
+<body>
+<div class="header">
+    <nav class="navbar navbar-toggleable-lg navbar-light bg-faded p-0 ">
+        <span class="header-logo px-2"><%= title%>编辑器</span>
+        <div class="navbar-text"></div>
+    </nav>
+    <nav class="navbar navbar-toggleable-lg justify-content-between navbar-light p-0">
+        <ul class="nav navbar-nav px-1">
+            <li class="nav-item">
+                <a class="nav-link" href="javascript:void(0);" aria-haspopup="true" aria-expanded="false" data-toggle="modal" data-target="#add">新建<%= title%></a>
+            </li>
+        </ul>
+    </nav>
+</div>
+
+
+<!-- JS. -->
+<script src="/lib/jquery/jquery.min.js"></script>
+<script src="/lib/tether/tether.min.js"></script>
+<script src="/lib/bootstrap/bootstrap.min.js"></script>
+<script src="/public/web/common_ajax.js"></script>
+<script src="/web/maintain/bills_lib/scripts/global.js"></script>
+<script src="/web/maintain/bills_lib/scripts/tools.js"></script>
+<%- body %>
+</body>
+
+
+
+</html>

File diff suppressed because it is too large
+ 179 - 0
web/maintain/main_col_lib/html/main.html


+ 507 - 0
web/maintain/main_col_lib/js/main_col_lib.js

@@ -0,0 +1,507 @@
+/**
+ * Created by zhang on 2018/7/14.
+ */
+$(document).ready(function() {
+    $('#add').on('show.bs.modal', function () {
+        $('#compilationSels').empty();
+        mainAjax.getCompilationList();
+    });
+
+    // 保存按钮
+    $("#addMainCol").click(function() {
+        let name = $('#name').val();
+        if(name==''){
+            $("#nameError").show();
+            return;
+        }else {
+            $("#addMainCol").addClass("disabled");//防止重复提交
+            $("#addMainLibForm").submit();
+        }
+    });
+
+    //删除按钮
+    $("#delete").click(function() {
+        let libID = $("#libID_del").val();
+        let delCount = parseInt($("#delCount").val());
+        delCount = delCount+1;
+        $("#delCount").val(delCount)
+        if(delCount == 3){//连续点3次才做真删除
+            if(libID!=""){
+                CommonAjax.post("/mainTreeCol/deleteLibByID",{ID:libID},function (data) {
+                    if(data.ok){
+                        $("#"+libID).parent(".libTr").remove();
+                    }
+                    $("#del").modal('hide');
+                });
+            }
+        }
+    });
+
+});
+
+let colEditSpread = null;
+let mainTreeCol = null;
+
+function getMainColLib(ID) {
+    CommonAjax.post("/mainTreeCol/getLibByID",{libID:ID},function (data) {
+        console.log(data);
+        $("#renameText").val(data.name);
+        mainTreeCol = data.main_tree_col;
+        $("#libID").val(ID);
+        $("#set-column").modal({show:true});
+    });
+}
+
+
+function showDeleteModal(ID){
+    $("#libID_del").val(ID);
+    $("#delCount").val(0);
+    $("#del").modal({show:true});
+}
+
+/**
+ * Created by Mai on 2017/8/14.
+ */
+
+let ColSettingObj = {
+    colSetting: null,
+    DEFAULT_TITLE_STYLE: null,
+    DEFAULT_DATA_STYLE: null,
+    cellType: {
+        getText: null,
+        cellType: null,
+        readOnly: null,
+        checkBox: null
+    },
+    Rows: {data: 0, filedName: 0, getText: 1, wordWrap: 2, cellType: 3, width: 4, readOnly: 5, showHint: 6, visible: 7, customize: 8},
+    columnValueChanged: function (e, info) {
+        let that = ColSettingObj;
+        info.colList.forEach(function (iCol) {
+            info.sheet.setValue(that.colSetting.headRows + that.Rows.width, iCol, info.sheet.getColumnWidth(iCol), GC.Spread.Sheets.SheetArea.viewport);
+        });
+    },
+    valueChanged: function (e, info) {
+        let that = ColSettingObj;
+        if (info.row === that.colSetting.headRows + that.Rows.width) {
+            info.sheet.setColumnWidth(info.col, info.newValue, GC.Spread.Sheets.SheetArea.viewport);
+        }
+    },
+    selectionChanged: function (e, info) {
+        let that = ColSettingObj, sel = info.newSelections[0];
+        if (sel.row <= that.colSetting.headRows) {
+            $('.btn-toolbar').removeClass('disabled');
+            $('#font').val(info.sheet.getCell(sel.row, sel.col, GC.Spread.Sheets.SheetArea.viewport).font());
+        } else {
+            $('.btn-toolbar').addClass('disabled');
+        }
+    },
+    getCellStyle: function (font, hAlign, vAlign) {
+        var style = new GC.Spread.Sheets.Style();
+        style.font = font;
+        style.hAlign = hAlign;
+        style.vAlign = vAlign;
+        style.wordWrap = true;
+        return style;
+    },
+    getSettingItems: function (type, items) {
+        let events = MainTreeCol[type];
+        for (let prop in events) {
+            if (typeof(events[prop]) === 'function') {
+                items.push(type + '.' + prop);
+            }
+        }
+    },
+    initCellType: function () {
+        this.cellType.readOnly = new GC.Spread.Sheets.CellTypes.ComboBox();
+        let readOnlyItems = [true, false];
+        this.getSettingItems('readOnly', readOnlyItems);
+        this.cellType.readOnly.items(readOnlyItems);
+
+        this.cellType.getText = new GC.Spread.Sheets.CellTypes.ComboBox();
+        let getTextItems = [];
+        this.getSettingItems('getText', getTextItems);
+        this.cellType.getText.items(getTextItems);
+
+        this.cellType.cellType = new GC.Spread.Sheets.CellTypes.ComboBox();
+        let cellTypeItems = [];
+        this.getSettingItems('cellType', cellTypeItems)
+        this.cellType.cellType.items(cellTypeItems);
+
+        this.cellType.checkBox = new GC.Spread.Sheets.CellTypes.CheckBox();
+    },
+    initSheet: function (sheet, setting) {
+        let initColProperty = function (iRow, title) {
+            sheet.setText(setting.headRows + iRow, 0, title, GC.Spread.Sheets.SheetArea.rowHeader);
+            sheet.addSpan(setting.headRows + iRow, 0, 1, 2, GC.Spread.Sheets.SheetArea.rowHeader);
+        };
+
+        sheet.setColumnCount(2, GC.Spread.Sheets.SheetArea.rowHeader);
+        sheet.setColumnWidth(0, 80, GC.Spread.Sheets.SheetArea.rowHeader);
+        sheet.setColumnWidth(1, 70, GC.Spread.Sheets.SheetArea.rowHeader);
+        sheet.setRowCount(setting.headRows + this.Rows.customize + 1);
+
+        sheet.setText(setting.headRows + this.Rows.data, 0, 'Data', GC.Spread.Sheets.SheetArea.rowHeader);
+        sheet.setStyle(setting.headRows + this.Rows.data, -1, this.DEFAULT_DATA_STYLE);
+        sheet.addSpan(setting.headRows + this.Rows.data, 0, this.Rows.wordWrap + 1, 1, GC.Spread.Sheets.SheetArea.rowHeader);
+
+        sheet.setText(setting.headRows + this.Rows.filedName, 1, 'FieldName', GC.Spread.Sheets.SheetArea.rowHeader);
+        sheet.setText(setting.headRows + this.Rows.getText, 1, 'getText', GC.Spread.Sheets.SheetArea.rowHeader);
+        sheet.setText(setting.headRows + this.Rows.wordWrap, 1, 'wordWrap', GC.Spread.Sheets.SheetArea.rowHeader);
+
+        initColProperty(this.Rows.width, 'Width');
+        initColProperty(this.Rows.readOnly, 'ReadOnly');
+        initColProperty(this.Rows.showHint, 'ShowHint');
+        initColProperty(this.Rows.visible, 'Visible');
+        initColProperty(this.Rows.cellType, 'CellType');
+        initColProperty(this.Rows.customize, 'Customize');
+    },
+    initColSetting: function (setting) {
+        this.DEFAULT_TITLE_STYLE = this.getCellStyle('Arial', GC.Spread.Sheets.HorizontalAlign.center, GC.Spread.Sheets.VerticalAlign.center);
+        this.DEFAULT_DATA_STYLE = this.getCellStyle('Arial', GC.Spread.Sheets.HorizontalAlign.left, GC.Spread.Sheets.VerticalAlign.center);
+        this.initCellType();
+
+        $('#empty-rows').val(setting.emptyRows);
+        $('#col-count').val(setting.cols ? setting.cols.length : 0);
+        $('#header-row-count').val(setting.headRows);
+
+        colEditSpread = new GC.Spread.Sheets.Workbook($('#colEditSpread')[0], {sheetCount: 1});
+        colEditSpread.getActiveSheet().setRowCount(0);
+        colEditSpread.getActiveSheet().setColumnCount(0);
+        colEditSpread.options.tabStripVisible = false;
+        colEditSpread.bind(GC.Spread.Sheets.Events.ColumnWidthChanged, this.columnValueChanged);
+        colEditSpread.bind(GC.Spread.Sheets.Events.ValueChanged, this.valueChanged);
+        colEditSpread.bind(GC.Spread.Sheets.Events.SelectionChanged, this.selectionChanged);
+
+        colEditSpread.getActiveSheet().suspendPaint();
+
+        this.initSheet(colEditSpread.getActiveSheet(), setting);
+        this.setColCount(this.colSetting.cols.length);
+        this.setHeaderRowCount(this.colSetting.headRows);
+        // headerHeight
+        for (let iRow in this.colSetting.headRowHeight) {
+            colEditSpread.getActiveSheet().setRowHeight(iRow, this.colSetting.headRowHeight[iRow], GC.Spread.Sheets.SheetArea.viewport);
+        }
+
+        if (setting.treeCol >= 0) {
+            $('#is-tree')[0].checked = true;
+            $('#tree-col-div').removeClass('hidden');
+            $('#tree-col').val(setting.treeCol);
+        } else {
+            $('#is-tree')[0].checked = false;
+            $('#tree-col-div').addClass('hidden');
+        }
+
+        if (setting.cols) {
+            let sheet = colEditSpread.getActiveSheet(), iRow;
+            for (let iCol = 0; iCol < setting.cols.length; iCol++) {
+                let col = setting.cols[iCol], iRow = 0;
+                // header
+                for (let i in col.head.spanCols) {
+                    if (col.head.spanCols[i] !== 0) {
+                        let cell = sheet.getCell(iRow, iCol, GC.Spread.Sheets.SheetArea.viewport);
+                        cell.value(col.head.titleNames[i]).font(col.head.font[i]).hAlign(col.head.hAlign[i]).vAlign(col.head.vAlign[i]);
+                    }
+                    if (col.head.spanCols[i] > 1 || col.head.spanRows[i] > 1) {
+                        sheet.addSpan(iRow, iCol, col.head.spanRows[i], col.head.spanCols[i], GC.Spread.Sheets.SheetArea.viewport);
+                    }
+                    iRow += col.head.spanRows[i];
+                };
+                // data
+                // field
+                let cell = sheet.getCell(this.colSetting.headRows + this.Rows.data, iCol, GC.Spread.Sheets.SheetArea.viewport);
+                cell.value(col.data.field).font(col.data.font).hAlign(col.data.hAlign).vAlign(col.data.vAlign);
+                // getText
+                cell = sheet.getCell(this.colSetting.headRows + this.Rows.getText, iCol, GC.Spread.Sheets.SheetArea.viewport);
+                cell.cellType(this.cellType.getText).value(col.data.getText).hAlign(GC.Spread.Sheets.HorizontalAlign.right);
+                // wordWrap
+                cell = sheet.getCell(this.colSetting.headRows + this.Rows.wordWrap, iCol, GC.Spread.Sheets.SheetArea.viewport);
+                cell.cellType(this.cellType.checkBox).value(col.data.wordWrap).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+                // cellType
+                cell = sheet.getCell(this.colSetting.headRows + this.Rows.cellType, iCol, GC.Spread.Sheets.SheetArea.viewport);
+                cell.cellType(this.cellType.cellType).value(col.data.cellType).hAlign(GC.Spread.Sheets.HorizontalAlign.right);
+                // 列宽
+                sheet.setColumnWidth(iCol, col.width);
+                sheet.setValue(this.colSetting.headRows + this.Rows.width, iCol, sheet.getColumnWidth(iCol), GC.Spread.Sheets.SheetArea.viewport);
+                // readonly
+                cell = sheet.getCell(this.colSetting.headRows + this.Rows.readOnly, iCol, GC.Spread.Sheets.SheetArea.viewport);
+                cell.cellType(this.cellType.readOnly).value(col.readOnly).hAlign(GC.Spread.Sheets.HorizontalAlign.right);
+                // showHint
+                cell = sheet.getCell(this.colSetting.headRows + this.Rows.showHint, iCol, GC.Spread.Sheets.SheetArea.viewport);
+                cell.cellType(this.cellType.checkBox).value(col.showHint).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+                // visible
+                cell = sheet.getCell(this.colSetting.headRows + this.Rows.visible, iCol, GC.Spread.Sheets.SheetArea.viewport);
+                cell.cellType(this.cellType.checkBox).value(col.visible).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+                // customize
+                cell = sheet.getCell(this.colSetting.headRows + this.Rows.customize, iCol, GC.Spread.Sheets.SheetArea.viewport);
+                cell.cellType(this.cellType.checkBox).value(col.customize).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+            }
+        }
+
+        colEditSpread.getActiveSheet().resumePaint();
+
+        let cell = colEditSpread.getActiveSheet().getCell(0, 0, GC.Spread.Sheets.SheetArea.viewport);
+        if (cell) {
+            $('#font').val(cell.font());
+        }
+    },
+    setColCount: function (count) {
+        let sheet = colEditSpread.getActiveSheet();
+        let orgCount = sheet.getColumnCount();
+        sheet.setColumnCount(count);
+        for (let iCol = orgCount; iCol < count; iCol++) {
+            for (let iRow = 0; iRow < this.colSetting.headRows; iRow ++) {
+                sheet.setStyle(iRow, iCol, this.DEFAULT_TITLE_STYLE);
+            }
+            sheet.getCell(this.colSetting.headRows + this.Rows.getText, iCol).cellType(this.cellType.getText).hAlign(GC.Spread.Sheets.HorizontalAlign.right);
+            sheet.getCell(this.colSetting.headRows + this.Rows.wordWrap, iCol).cellType(this.cellType.checkBox).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+            sheet.getCell(this.colSetting.headRows + this.Rows.cellType, iCol).cellType(this.cellType.cellType).hAlign(GC.Spread.Sheets.HorizontalAlign.right);
+            sheet.setValue(this.colSetting.headRows + this.Rows.width, iCol, sheet.getColumnWidth(iCol), GC.Spread.Sheets.SheetArea.viewport);
+            sheet.getCell(this.colSetting.headRows + this.Rows.readOnly, iCol).cellType(this.cellType.readOnly).hAlign(GC.Spread.Sheets.HorizontalAlign.right);
+            sheet.setValue(this.colSetting.headRows + this.Rows.readOnly, iCol, false, GC.Spread.Sheets.SheetArea.viewport);
+            sheet.getCell(this.colSetting.headRows + this.Rows.showHint, iCol).cellType(this.cellType.checkBox).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+            sheet.getCell(this.colSetting.headRows + this.Rows.visible, iCol).cellType(this.cellType.checkBox).hAlign(GC.Spread.Sheets.HorizontalAlign.center).value(true);
+            sheet.getCell(this.colSetting.headRows + this.Rows.customize, iCol).cellType(this.cellType.checkBox).hAlign(GC.Spread.Sheets.HorizontalAlign.center).value(false);
+        }
+    },
+    setHeaderRowCount: function (count) {
+        let sheet = colEditSpread.getActiveSheet(), orgCount = this.colSetting.headRows;
+        if (count < orgCount) {
+            sheet.deleteRows(count, orgCount - count);
+        } else if (count > orgCount) {
+            sheet.addRows(orgCount, count - orgCount);
+            sheet.addSpan(0, 0, count, 1, GC.Spread.Sheets.SheetArea.rowHeader);
+            for (let iRow = orgCount; iRow < count; iRow++) {
+                sheet.setStyle(iRow, -1, this.DEFAULT_TITLE_STYLE);
+            }
+        }
+    },
+    getActualCellRange: function (cellRange, rowCount, columnCount) {
+        let spreadNS = GC.Spread.Sheets;
+        if (cellRange.row == -1 && cellRange.col == -1) {
+            return new spreadNS.Range(0, 0, rowCount, columnCount);
+        }
+        else if (cellRange.row == -1) {
+            return new spreadNS.Range(0, cellRange.col, rowCount, cellRange.colCount);
+        }
+        else if (cellRange.col == -1) {
+            return new spreadNS.Range(cellRange.row, 0, cellRange.rowCount, columnCount);
+        }
+
+        return cellRange;
+    },
+    // 批量操作Spread选择的单元格
+    controlSelectCells: function (spread, control) {
+        let sheet = colEditSpread.getActiveSheet();
+        let sel = sheet.getSelections(), i, j;
+
+        sel = this.getActualCellRange(sel[sel.length - 1], sheet.getRowCount(), sheet.getColumnCount());
+        for (i = 0; i < sel.rowCount; i++) {
+            for (j = 0; j < sel.colCount; j++) {
+                control(sheet.getCell(sel.row + i, sel.col + j));
+            }
+        }
+    },
+    generateColSetting: function () {
+        let setting = {}, sheet = colEditSpread.getActiveSheet();
+        setting.emptyRows = parseInt($('#empty-rows').val());
+        setting.headRows = parseInt($('#header-row-count').val());
+        if ($('#is-tree')[0].checked) {
+            setting.treeCol = parseInt($('#tree-col').val());
+        }
+        setting.headRowHeight = [];
+        for (let iRow = 0; iRow < setting.headRows; iRow++) {
+            setting.headRowHeight.push(sheet.getRowHeight(iRow, GC.Spread.Sheets.SheetArea.viewport));
+        };
+        setting.cols = [];
+        for (let iCol = 0; iCol < sheet.getColumnCount(); iCol++) {
+            let col = {};
+            col.width = sheet.getColumnWidth(iCol);
+            col.readOnly = sheet.getValue(setting.headRows + this.Rows.readOnly, iCol) || false;
+            if (sheet.getValue(setting.headRows + this.Rows.showHint, iCol)) {
+                col.showHint = sheet.getValue(setting.headRows + this.Rows.showHint, iCol) || false;
+            }
+            col.visible = sheet.getValue(setting.headRows + this.Rows.visible, iCol) || false;
+            col.customize = sheet.getValue(setting.headRows + this.Rows.customize, iCol) || false;
+
+            col.head = {};
+            col.head.titleNames = [];
+            col.head.spanCols = [];
+            col.head.spanRows = [];
+            col.head.vAlign = [];
+            col.head.hAlign = [];
+            col.head.font = [];
+            for (let iRow = 0; iRow < setting.headRows; iRow++) {
+                let cell = sheet.getCell(iRow, iCol);
+                col.head.titleNames.push(cell.text());
+                let span = sheet.getSpan(iRow, iCol);
+                if (span) {
+                    if (span.col === iCol && span.row === iRow) {
+                        col.head.spanCols.push(span.colCount);
+                        col.head.spanRows.push(span.rowCount);
+                    } else {
+                        col.head.spanCols.push(0);
+                        col.head.spanRows.push(1);
+                    }
+                } else {
+                    col.head.spanCols.push(1);
+                    col.head.spanRows.push(1);
+                }
+                col.head.vAlign.push(cell.vAlign());
+                col.head.hAlign.push(cell.hAlign());
+                col.head.font.push(cell.font());
+            }
+
+            col.data = {};
+            let cell = sheet.getCell(setting.headRows, iCol);
+            col.data.field = cell.text();
+            col.data.vAlign = cell.vAlign();
+            col.data.hAlign = cell.hAlign();
+            col.data.font = cell.font();
+            // getText
+            cell = sheet.getCell(setting.headRows + this.Rows.getText, iCol);
+            if (cell.text() !== '') {
+                col.data.getText = cell.text();
+            }
+            // wordWrap
+            col.data.wordWrap = sheet.getValue(setting.headRows + this.Rows.wordWrap, iCol) || false;
+            // cellType
+            cell = sheet.getCell(setting.headRows + this.Rows.cellType, iCol);
+            if (cell.text() !== '') {
+                col.data.cellType = cell.text();
+            }
+            setting.cols.push(col);
+        }
+        return setting;
+    }
+};
+
+$('#set-column').on('shown.bs.modal', function () {
+    if(colEditSpread) colEditSpread.destroy();
+    ColSettingObj.colSetting = mainTreeCol;
+    ColSettingObj.initColSetting(ColSettingObj.colSetting);
+});
+
+$('#set-glj-col').on('show.bs.modal', function () {
+    let glj_col_setting = JSON.parse($("#glj_col").val());
+    if(glj_col_setting.showAdjustPrice){
+        $('#adjustPrice_cb').prop('checked',true);
+    }else {
+        $('#adjustPrice_cb').prop('checked',false);
+    }
+});
+
+$('#set-glj-comf').click(function () {
+
+    let showAdjustPrice =  $('#adjustPrice_cb').prop('checked');
+    let glj_col_setting = {
+        showAdjustPrice :showAdjustPrice
+    };
+    $("#glj_col").val(JSON.stringify(glj_col_setting));
+});
+
+$('#col-count').change(function () {
+    ColSettingObj.setColCount(parseInt($(this).val()));
+});
+$('#header-row-count').change(function () {
+    ColSettingObj.setHeaderRowCount(parseInt($(this).val()));
+    ColSettingObj.colSetting.headRows = parseInt($(this).val());
+});
+$('#is-tree').click(function () {
+    if (this.checked) {
+        $('#tree-col-div').removeClass('hidden');
+    } else {
+        $('#tree-col-div').addClass('hidden');
+    }
+});
+$('#merge').click(function () {
+    let sheet = colEditSpread.getActiveSheet();
+    let sel = sheet.getSelections();
+
+    if (sel.length > 0) {
+        sel = ColSettingObj.getActualCellRange(sel[sel.length - 1], sheet.getRowCount(), sheet.getColumnCount());
+        if (sel.row + sel.rowCount > ColSettingObj.colSetting.headRows) {
+            alert('仅HeaderTitle部分可以合并单元格');
+        } else {
+            sheet.addSpan(sel.row, sel.col, sel.rowCount, sel.colCount);
+            //sheet.setTag(sel.row, sel.col, 1);
+        }
+    }
+});
+$('#unmerge').click(function () {
+    let sheet = colEditSpread.getActiveSheet();
+    let sel = sheet.getSelections();
+
+    if (sel.length > 0) {
+        sel = ColSettingObj.getActualCellRange(sel[sel.length - 1], sheet.getRowCount(), sheet.getColumnCount());
+        sheet.suspendPaint();
+        for (var i = 0; i < sel.rowCount; i++) {
+            for (var j = 0; j < sel.colCount; j++) {
+                sheet.removeSpan(i + sel.row, j + sel.col);
+            }
+        }
+        sheet.resumePaint();
+    }
+});
+$('#save-col-setting').click(function () {
+    ColSettingObj.colSetting = ColSettingObj.generateColSetting();
+    let mainTreeColString = JSON.stringify(ColSettingObj.colSetting);
+    let libID = $("#libID").val();
+    let name = $('#renameText').val();
+    if(libID!=''){
+        if(name ==''){
+            $("#renameError").show();
+            return;
+        }else {
+            CommonAjax.post("/mainTreeCol/saveLib",{query:{ID:libID},data:{name:name,main_tree_col:mainTreeColString}},function (data) {
+                $("#"+libID).text(data.name);
+                $('#set-column').modal('hide');
+            });
+        }
+    }
+
+
+    /*let billsTemplateTree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1});
+    billsTemplateTree.loadDatas(JSON.parse(billsTemplateData));
+    TREE_SHEET_HELPER.loadSheetHeader(ColSettingObj.colSetting, colSpread.getActiveSheet());
+    TREE_SHEET_HELPER.showTreeData(ColSettingObj.colSetting, colSpread.getActiveSheet(), billsTemplateTree);*/
+});
+
+$('#h-left').click(function () {
+    ColSettingObj.controlSelectCells(colEditSpread, function (cell) {
+        cell.hAlign(GC.Spread.Sheets.HorizontalAlign.left);
+    });
+});
+$('#h-center').click(function () {
+    ColSettingObj.controlSelectCells(colEditSpread, function (cell) {
+        cell.hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+    });
+});
+
+$('#h-right').click(function () {
+    ColSettingObj.controlSelectCells(colEditSpread, function (cell) {
+        cell.hAlign(GC.Spread.Sheets.HorizontalAlign.right);
+    });
+});
+
+$('#v-top').click(function () {
+    ColSettingObj.controlSelectCells(colEditSpread, function (cell) {
+        cell.vAlign(GC.Spread.Sheets.VerticalAlign.top);
+    });
+});
+$('#v-center').click(function () {
+    ColSettingObj.controlSelectCells(colEditSpread, function (cell) {
+        cell.vAlign(GC.Spread.Sheets.VerticalAlign.center);
+    });
+});
+$('#v-bottom').click(function () {
+    ColSettingObj.controlSelectCells(colEditSpread, function (cell) {
+        cell.vAlign(GC.Spread.Sheets.VerticalAlign.bottom);
+    });
+});
+
+$('#set-font').click(function () {
+    var sFont = $('#font').val();
+    ColSettingObj.controlSelectCells(colEditSpread, function (cell) {
+        cell.font(sFont);
+    });
+});

+ 228 - 0
web/maintain/main_col_lib/js/main_tree_col.js

@@ -0,0 +1,228 @@
+/**
+ * Created by Mai on 2017/7/25.
+ */
+
+let MainTreeCol = {
+    getText: {
+        subType: function (node) {
+
+        },
+        type: function (node) {
+            if (node.sourceType === projectObj.project.Bills.getSourceType()) {
+                return '';
+            } else if (node.sourceType === projectObj.project.Ration.getSourceType()) {
+                return '定';
+            } else if (node.sourceType === projectObj.project.VolumePrice.getSourceType()) {
+                return '量';
+            } else if (node.sourceType === projectObj.project.ration_glj.getSourceType()) {
+                return '主';
+            }
+        },
+        quantity:function (node) {
+            if(node.sourceType === projectObj.project.ration_glj.getSourceType()){
+                return gljOprObj.getTotalQuantity(node.data);
+            }else {
+                return node.data["quantity"];
+            }
+        },
+        code: function (node) {
+
+        },
+        //取费专业
+        calcProgramName: function (node) {
+
+        },
+        marketPrice: function (node) {
+
+        },
+        feeRate:function (node) {
+            
+        }
+
+    },
+    readOnly: {
+        bills: function (node) {
+            return node.sourceType === projectObj.project.Bills.getSourceType();
+        },
+        ration: function (node) {
+            return node.sourceType === projectObj.project.Ration.getSourceType();
+        },
+        glj: function (node) {
+            return node.sourceType == projectObj.project.ration_glj.getSourceType();
+        },
+        volumePrice: function (node) {
+            return node.sourceType === projectObj.project.VolumePrice.getSourceType();
+        },
+        non_bills: function (node) {
+            return node.sourceType !== projectObj.project.Bills.getSourceType();
+        },
+        non_ration: function (node) {
+            return node.sourceType !== projectObj.project.Ration.getSourceType();
+        },
+        non_volumePrice: function (node) {
+            return node.sourceType !== projectObj.project.Ration.getSourceType();
+        },
+        billsParent: function (node) {
+            return node.sourceType === projectObj.project.Bills.getSourceType() && node.source.children.length > 0;
+        },
+        leafBillsWithDetail: function (node) {
+            return (!MainTreeCol.readOnly.billsParent(node)) && (node.children.length > 0);
+        },
+        forCalcBase: function (node) {
+            // to do according to billsParentType
+            return MainTreeCol.readOnly.billsParent(node) || MainTreeCol.readOnly.non_bills(node)||MainTreeCol.readOnly.leafBillsWithDetail(node);
+        },
+        forUnitFee: function (node) {
+            return MainTreeCol.readOnly.ration(node) || MainTreeCol.readOnly.billsParent(node) || MainTreeCol.readOnly.leafBillsWithDetail(node);
+        },
+        forTotalFee: function (node) {
+            return MainTreeCol.readOnly.non_bills(node) || MainTreeCol.readOnly.billsParent(node) || (MainTreeCol.readOnly.leafBillsWithDetail(node));
+        },
+        forFeeRate:function (node) {
+            return MainTreeCol.readOnly.non_bills(node)||MainTreeCol.readOnly.billsParent(node)||MainTreeCol.readOnly.leafBillsWithDetail(node);
+        },
+        forQuantity:function (node) {
+            return MainTreeCol.readOnly.glj(node)||MainTreeCol.readOnly.billsParent(node)
+        },
+        forMarketPrice:function (node) {
+            return MainTreeCol.readOnly.non_volumePrice(node);
+        },
+        forContain:function (node) {
+            return MainTreeCol.readOnly.non_ration(node)&&!MainTreeCol.readOnly.glj(node);
+        },
+        forCode:function (node) {
+            return MainTreeCol.readOnly.glj(node)|| (node.sourceType === projectObj.project.Ration.getSourceType()&&node.data.type===rationType.gljRation);
+        },
+        forUnit:function (node) {
+            if(MainTreeCol.readOnly.bills(node)&&(node.data.type==billType.DXFY||node.data.type==billType.FB)){//在大项费用、分部行,计量单位只读。
+                return true;
+            }else {
+                return treeNodeTools.isRation(node);
+            }
+        },
+        forContentCharacter: function (node) {
+            return !MainTreeCol.readOnly.bills(node) || (node.data.type !== billType.BILL && node.data.type !== billType.FX);
+        },
+        forRuleText: function (node) {
+            if(MainTreeCol.readOnly.bills(node)){
+                if(node.data.type === billType.FX || (node.data.type === billType.BILL && node.source.children.length === 0)){
+                    return false;
+                }
+            }
+            return true;
+        }
+    },
+    cellType: {
+        unit: function () {
+            let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
+            combo.itemHeight(10).items(['m', 'm2', 'm3', 'km', 't', 'kg', '台班', '工日', '昼夜', '元', '项', '处', '个', '件',
+                '根', '组', '系统', '台', '套', '株', '丛', '缸', '支', '只', '块', '座', '对', '份', '樘', '攒', '榀']);
+            return combo;
+        },
+        feeRate: function () {
+            return feeRateObject.getFeeRateEditCellType();
+        },
+        calcBase: function () {
+            return calcBaseView.getCalcBaseCellType();
+        },
+        calcProgramName: function (node) {
+
+        },
+        //类别
+        subType: function (node) {
+
+        },
+        //是否分包
+        isSubcontract: function (node) {
+
+        },
+        isEstimate:function (node) {
+
+        }
+     },
+    getEvent: function (eventName) {
+        let names = eventName.split('.');
+        let event = this;
+        for (let name of names) {
+            if (event[name]) {
+                event = event[name];
+            } else {
+                return null;
+            }
+        }
+        if (event && Object.prototype.toString.apply(event) !== "[object Function]") {
+            return null;
+        } else {
+            return event;
+        }
+    },
+    getNumberFormatter: function (digit) {
+        switch (digit) {
+            case 1:
+                return '0.#';
+            case 2:
+                return '0.##';
+            case 3:
+                return '0.###';
+            case 4:
+                return '0.####';
+            case 5:
+                return '0.#####';
+            case 6:
+                return '0.######';
+            default:
+                return '0.##';
+        }
+    }
+};
+
+let colSettingObj = {
+    settingSpread: null,
+    checkBox: new GC.Spread.Sheets.CellTypes.CheckBox(),
+    loadSetting: function (sheet, setting) {
+        sheet.setColumnCount(setting.cols.length);
+        sheet.setRowCount(setting.headRows, GC.Spread.Sheets.SheetArea.colHeader);
+        sheet.setRowCount(1);
+        sheet.getRange(0, -1, 1, -1).cellType(this.checkBox).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+
+        setting.headRowHeight.forEach(function (rowHeight, index) {
+            sheet.setRowHeight(index, rowHeight, GC.Spread.Sheets.SheetArea.colHeader);
+        });
+        setting.cols.forEach(function (col, index) {
+            let i, iRow = 0, cell;
+            for (i = 0; i < col.head.spanCols.length; i++) {
+                if (col.head.spanCols[i] !== 0) {
+                    cell = sheet.getCell(iRow, index, GC.Spread.Sheets.SheetArea.colHeader);
+                    cell.value(col.head.titleNames[i]).font(col.head.font).hAlign(col.head.hAlign[i]).vAlign(col.head.vAlign[i]).wordWrap(true);
+                }
+                if (col.head.spanCols[i] > 1 || col.head.spanRows[i] > 1) {
+                    sheet.addSpan(iRow, index, col.head.spanRows[i], col.head.spanCols[i], GC.Spread.Sheets.SheetArea.colHeader);
+                }
+                iRow += col.head.spanRows[i];
+            };
+            sheet.setColumnWidth(index, col.width);
+            cell = sheet.getCell(0, index).value(col.visible);
+        });
+    },
+    initSettingSpread: function () {
+        this.settingSpread = SheetDataHelper.createNewSpread($('#col_setting_spread')[0], {sheetCount: 1});
+        this.settingSpread.options.showScrollTip = GC.Spread.Sheets.ShowScrollTip.horizontal;
+        this.loadSetting(this.settingSpread.getActiveSheet(), projectObj.project.projSetting.main_tree_col);
+    }
+};
+
+$('#column').on('shown.bs.modal', function () {
+    if (!colSettingObj.settingSpread) {
+        colSettingObj.initSettingSpread();
+    }
+});
+
+$('#column').on('hide.bs.modal', function () {
+    let sheet = colSettingObj.settingSpread.getActiveSheet();
+    for (let iCol = 0; iCol < sheet.getColumnCount(); iCol ++) {
+        projectObj.project.projSetting.main_tree_col.cols[iCol].visible = sheet.getValue(0, iCol);
+        projectObj.project.projSetting.mainGridSetting.cols[iCol].visible = sheet.getValue(0, iCol);
+    }
+    SheetDataHelper.refreshColumnVisible(projectObj.project.projSetting.mainGridSetting, projectObj.mainSpread.getActiveSheet());
+    projectObj.project.pushNow('editColSetting', projectObj.project.projSetting.moduleName, {projectID: projectObj.project.ID(), main_tree_col: projectObj.project.projSetting.main_tree_col});
+});

+ 176 - 5
web/users/js/compilation.js

@@ -73,6 +73,50 @@ $(document).ready(function() {
         }
     });
 
+    $("#addTaxGroupBtn").click(function () {
+        $('#groupEditType').val("add");
+        $("#taxType").val("");
+        $("#program_lib").val("");
+        $("#template_lib").val("");
+        $("#col_lib").val("");
+    });
+
+    //新增计税组合
+    $("#add-group").click(function() {
+        let taxMap = {"1":"一般计税","2":"简易计税" };
+        let actionType = $('#groupEditType').val();
+        let groupData = getTaxGroupData();
+        let groupIndex = getGroupIndex(groupData);//用来做重复判断
+        if(!_.isEmpty(groupData)){
+            //重复判断 todo
+            if($("input[data-id = "+groupIndex+"]").length <= 0){
+                let taxName = groupData.taxType?taxMap[groupData.taxType]:'';
+                let p_name = groupData.program_lib?groupData.program_lib.displayName:"";
+                let t_name = groupData.template_lib?groupData.template_lib.name:"";
+                let c_name = groupData.col_lib?groupData.col_lib.name:"";
+                let htmlString = "<tr class='taxGroup_tr'><td><span>"+taxName+"</span></td>" +
+                    "<td><span>"+p_name+"</span></td>" +
+                    "<td><span>"+t_name+"</span></td>" +
+                    "<td><span>"+c_name+"</span></td>" +
+                    "<td> <a class='btn btn-link btn-sm' style='padding: 0px' onclick='editTaxGroup(this)'> 编辑</a>/<a class='btn btn-link btn-sm ' style='padding: 0px' onclick='deleteTaxGroup(this)'>删除</a> " +
+                    "<input type='hidden' name='tax_group' data-id ='"+groupIndex+"' value='"+JSON.stringify(groupData)+"'>"+
+                    "</td>" +
+                    "</tr>";
+                if(actionType == "add"){
+                    $("#tax_group_tbody").append(htmlString);
+                }else if(actionType == "modify"){
+                    let oldIndex = $("#groupIndex").val();
+                    let parentTr = $("input[data-id = "+oldIndex+"]").parents(".taxGroup_tr");
+                    parentTr.after(htmlString);
+                    parentTr.remove();
+                }
+            }else {
+                alert("已存在相同的组合!");
+            }
+        }
+        $("#addTaxGroup").modal('hide');
+    });
+
     // 新增计价规则
     $("#add-valuation").click(function() {
         try {
@@ -148,7 +192,6 @@ $(document).ready(function() {
                 $("#add-compilation-title").text('添加计算程序');
                 break;
         }
-
         $("#addcompilation").modal('show');
     });
 
@@ -255,6 +298,7 @@ $(document).ready(function() {
 
     });
 
+
 });
 
 /**
@@ -270,8 +314,9 @@ function initCompilation() {
     let artificialCoefficientData = artificialCoefficientList === undefined ? [] : JSON.parse(artificialCoefficientList);
     let programData = programList === undefined ? [] : JSON.parse(programList);
     let billsGuidanceData = billsGuidanceList === undefined ? [] : JSON.parse(billsGuidanceList);
-
-    mainTreeCol = mainTreeCol !== '' ? mainTreeCol.replace(/\n/g, '\\n') : mainTreeCol;
+    let billTemplateData = billTemplateList == undefined ? [] : JSON.parse(billTemplateList);
+    let mainTreeColData= mainTreeColList == undefined ? [] : JSON.parse(mainTreeColList);
+    /*mainTreeCol = mainTreeCol !== '' ? mainTreeCol.replace(/\n/g, '\\n') : mainTreeCol;
     billsTemplateData = billsTemplateData.replace(/\n/g, '\\n');
 
     let mainTreeColObj = mainTreeCol === '' ? {} : JSON.parse(mainTreeCol);
@@ -284,7 +329,7 @@ function initCompilation() {
     if (mainTreeCol !== '' && mainTreeColObj.cols.length > 0) {
         TREE_SHEET_HELPER.loadSheetHeader(mainTreeColObj, colSpread.getActiveSheet());
         TREE_SHEET_HELPER.showTreeData(mainTreeColObj, colSpread.getActiveSheet(), billsTemplateTree);
-    }
+    }*/
 
     if (billListData.length <= 0 || rationLibData.length <= 0 || gljLibData.length <= 0) {
         return false;
@@ -341,11 +386,25 @@ function initCompilation() {
     // 计算程序标准库
     html = '';
     for(let tmp of programData) {
-        let tmpHtml = '<option value="' + tmp.id + '">' + tmp.name + '</option>';
+        let tmpHtml = '<option value="' + tmp.id + '">' + tmp.displayName + '</option>';
         html += tmpHtml;
     }
     $("select[name='program_lib']").children("option").first().after(html);
 
+    //模板库
+    html = '';
+    for(let tmp of billTemplateData) {
+        let tmpHtml = '<option value="' + tmp.ID + '">' + tmp.name + '</option>';
+        html += tmpHtml;
+    }
+    $("select[name='template_lib']").children("option").first().after(html);
+    //列设置
+    html = '';
+    for(let tmp of mainTreeColData) {
+        let tmpHtml = '<option value="' + tmp.ID + '">' + tmp.name + '</option>';
+        html += tmpHtml;
+    }
+    $("select[name='col_lib']").children("option").first().after(html);
 }
 
 /**
@@ -520,3 +579,115 @@ function switchChange(element) {
 
     return !currentStatus;
 }
+
+function editEngineerName(selector) {
+    let engineerName =  $(selector).prev("span").text();
+    let parentDiv = $(selector).parent("div");
+    parentDiv.next("div").find("input").val(engineerName);
+    parentDiv.hide();
+    parentDiv.next("div").show();
+}
+
+function confirmName(selector,engineerID) {
+    let inputDiv = $(selector).parents(".input_group_div");
+    let oldEngineerName =  inputDiv.prev("div").find("span").text();
+    let newEngineerName = $(selector).parent(".input-group-btn").prev("input").val();
+    if(newEngineerName === "" || newEngineerName == oldEngineerName||!engineerID){
+        inputDiv.prev("div").show();
+        inputDiv.hide();
+        return;
+    }
+
+    updateEngineer(engineerID,{name:newEngineerName},function () {
+        inputDiv.prev("div").find("span").text(newEngineerName);
+    });
+    inputDiv.prev("div").show();
+    inputDiv.hide();
+}
+
+function engineerVisibleChange(checkBox,engineerID) {
+    if(engineerID){
+        updateEngineer(engineerID,{visible:checkBox.checked});
+    }
+}
+
+function updateEngineer(engineerID,data,callback) {
+    CommonAjax.post('/compilation/update-engineer',{id:engineerID,updateData:data},function (data) {
+        if(callback){
+            callback();
+        }
+    })
+}
+
+function editTaxGroup(ele) {
+    $('#groupEditType').val("modify");
+    let groupData = $(ele).nextAll("input[name = 'tax_group']").val();
+    groupData = JSON.parse(groupData);
+    if(!_.isEmpty(groupData)){
+        $("#taxType").val(groupData.taxType?groupData.taxType:"");
+        $("#program_lib").val(groupData.program_lib?groupData.program_lib.id:"");
+        $("#template_lib").val(groupData.template_lib?groupData.template_lib.id:"");
+        $("#col_lib").val(groupData.col_lib?groupData.col_lib.id:"");
+    }else {
+        $("#taxType").val("");
+        $("#program_lib").val("");
+        $("#template_lib").val("");
+        $("#col_lib").val("");
+    }
+    $("#groupIndex").val(getGroupIndex(groupData));
+    $("#addTaxGroup").modal({show:true});
+}
+
+function deleteTaxGroup(ele) {
+    let parentTr = $(ele).parents(".taxGroup_tr");
+    parentTr.remove();
+}
+
+function getGroupIndex(groupData) {//用来做唯一标识
+    let index = "";
+    if(groupData){
+        if(groupData.taxType) index = index + groupData.taxType;
+        if(groupData.program_lib) index = index + groupData.program_lib.id;
+        if(groupData.template_lib) index = index + groupData.template_lib.id;
+        if(groupData.col_lib) index = index + groupData.col_lib.id;
+    }
+    return index;
+}
+function getTaxGroupData() {
+    let programData = programList === undefined ? [] : _.indexBy(JSON.parse(programList), 'id');
+    let billTemplateData = billTemplateList == undefined ? [] : _.indexBy(JSON.parse(billTemplateList),'ID');
+    let mainTreeColData= mainTreeColList == undefined ? [] :  _.indexBy(JSON.parse(mainTreeColList),'ID');
+    let groupData = {};
+    if($("#taxType").val() !==""){
+        groupData.taxType = $("#taxType").val();
+    }
+    if($("#program_lib").val() !==""){
+        let program =  programData[$("#program_lib").val()];
+        if(program){
+            groupData.program_lib = {
+                id:program.id,
+                name:program.name,
+                displayName:program.displayName
+            }
+        }
+    }
+    if($("#template_lib").val() !==""){
+        let template =  billTemplateData[$("#template_lib").val()];
+        if(template){
+            groupData.template_lib = {
+                id:template.ID,
+                name:template.name
+            }
+        }
+    }
+    if($("#col_lib").val() !==""){
+        let col =  mainTreeColData[$("#col_lib").val()];
+        if(col){
+            groupData.col_lib = {
+                id:col.ID,
+                name:col.name
+            }
+        }
+    }
+    return groupData;
+}

+ 22 - 14
web/users/views/compilation/add.html

@@ -3,6 +3,7 @@
     <div class="panel-title">
         <div class="title-main">
             <h2>
+                <span><%= selectedCompilation.name%></span>
                 <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>
@@ -29,7 +30,7 @@
                         <legend>
                             工程专业
                         </legend>
-                        <table class="table">
+                        <table class="table engineer_table">
                             <thead>
                             <tr>
                                 <th>工程名称</th>
@@ -38,24 +39,30 @@
                                 <th>人材机库</th>
                                 <th>费率标准</th>
                                 <th>人工系数</th>
+                                <th>前台显示</th>
                                 <th>操作</th>
                             </tr>
                             </thead>
                             <tbody>
                                 <% engineeringList.forEach(function(engineering) {%>
-                                <tr>
-                                    <td><%= engineering.name %></td>
-                                    <td><%= libCount !== null && libCount[engineering.value + ''] !== undefined ?
-                                        libCount[engineering.value + ''].bill_count : 0 %></td>
-                                    <td><%= libCount !== null && libCount[engineering.value + ''] !== undefined ?
-                                        libCount[engineering.value + ''].ration_count : 0 %></td>
-                                    <td><%= libCount !== null && libCount[engineering.value + ''] !== undefined ?
-                                        libCount[engineering.value + ''].glj_count : 0 %></td>
-                                    <td><%= libCount !== null && libCount[engineering.value + ''] !== undefined ?
-                                        libCount[engineering.value + ''].fee_count : 0 %></td>
-                                    <td><%= libCount !== null && libCount[engineering.value + ''] !== undefined ?
-                                        libCount[engineering.value + ''].artificial_count : 0 %></td>
-                                    <td><a href="/compilation/<%= section %>/<%= valuationId %>/<%= engineering.value %>">编辑</a></td>
+                                <tr >
+                                    <td>
+                                        <div><span><%= engineering.name %></span> <a onclick='editEngineerName(this)'><i class="glyphicon glyphicon-pencil"></i></a></div>
+                                        <div class="input-group input-group-sm input_group_div" style="width:200px;display: none">
+                                            <input class="form-control">
+                                            <div class="input-group-btn">
+                                                <button type="button" class="btn btn-success" onclick='confirmName(this,"<%= engineering._id.toString()%>")'>
+                                                    <span class="glyphicon glyphicon-ok"></span></button>
+                                            </div>
+                                        </div>
+                                    </td>
+                                    <td><%= engineering.bill_lib.length %></td>
+                                    <td><%= engineering.ration_lib.length %></td>
+                                    <td><%= engineering.glj_lib.length %></td>
+                                    <td><%= engineering.fee_lib.length %></td>
+                                    <td><%= engineering.artificial_lib.length %></td>
+                                    <td><label><input type="checkbox"  <% if (engineering.visible) { %>checked<% } %>  onclick='engineerVisibleChange(this,"<%= engineering._id.toString()%>")'> 显示</label></td>
+                                    <td><a href="/compilation/<%= section %>/<%= valuationId %>/<%= engineering._id.toString()%>">编辑</a></td>
                                 </tr>
                                 <% }) %>
                             </tbody>
@@ -68,5 +75,6 @@
         </div>
     </div>
 </div>
+<script type="text/javascript" src="/public/web/common_ajax.js"></script>
 <script type="text/javascript" src="/web/users/js/compilation.js"></script>
 <%include ../compilation/modal.html %>

+ 65 - 33
web/users/views/compilation/engineering.html

@@ -11,7 +11,7 @@
     <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>
+                <li role="presentation" class="active"><a href="javascript:void(0);"><%= libData.name %></a></li>
             </ul>
         </div>
         <div class="c-body">
@@ -89,7 +89,7 @@
                             </div>
                         </div>
                         <div class="row">
-                            <div class="form-group col-md-4">
+                            <div class="form-group col-md-3">
                                 <label>费率标准</label>
                                 <div class="fee-list">
                                     <% if (Object.keys(libData).length > 0 && libData.fee_lib.length > 0) { %>
@@ -106,7 +106,7 @@
                                 </div>
                                 <a href="#" class="btn btn-link btn-sm add-compilation" data-model="fee">添加</a>
                             </div>
-                            <div class="form-group col-md-4">
+                            <div class="form-group col-md-3">
                                 <label>人工系数</label>
                                 <div class="artificial-list">
                                     <% if (Object.keys(libData).length > 0 && libData.artificial_lib.length > 0) { %>
@@ -123,40 +123,70 @@
                                 </div>
                                 <a href="#" class="btn btn-link btn-sm add-compilation" data-model="artificial">添加</a>
                             </div>
-                            <div class="form-group col-md-4">
-                                <label>计算程序</label>
-                                <div class="program-list">
-                                    <% if (Object.keys(libData).length > 0 && libData.program_lib.length > 0) { %>
-                                    <% libData.program_lib.forEach(function (program, index){ %>
-                                    <p class="form-control-static">
-                                        <a class="pull-right text-danger remove-lib" data-model="program" title="移除" data-id="<%= program.id %>">
-                                            <span class="glyphicon glyphicon-remove"></span>
-                                        </a>
-                                        <input type="hidden" name="program_lib" data-id="<%= program.id %>" value="<%= JSON.stringify({id: program.id, name: program.name}) %>">
-                                        <% if (index === 0) {%><i class="glyphicon glyphicon-flag"></i>&nbsp;<% } %><%= program.name %>
-                                    </p>
-                                    <% }) %>
-                                    <% } %>
-                                </div>
-                                <a href="#" class="btn btn-link btn-sm add-compilation" data-model="program">添加</a>
-                            </div>
-                        </div>
                     </div>
                     <div class="col-md-12">
-                        <legend>清单模板 / 造价书列</legend>
-                        <a data-toggle="modal" data-target="#set-column" class="btn btn-primary btn-sm pull-right">设置</a>
-                        <a href="/compilation/template/<%= section %>/<%= valuationId %>/<%= engineeringInfo.id%>"
-                               data-toggle="modal" data-target="" class="btn btn-primary btn-sm pull-right"
-                               style="margin-right:5px">模板设置</a>
-                        <a data-toggle="modal" data-target="#set-glj-col" 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" style="height: 400px;"></div>
+                        <a data-toggle="modal" data-target="#set-glj-col" class="btn btn-primary btn-sm " style="margin-right:5px">人材机列</a>
+                    </div>
+                    <div class="col-md-12" style="padding-top:20px">
+                        <legend>计算程序/清单模板/列设置</legend>
+                        <a data-toggle="modal" data-target="#addTaxGroup" class="btn btn-link btn-sm " id="addTaxGroupBtn" style="margin-right:5px">添加</a>
+                        <table class="table engineer_table">
+                            <thead>
+                            <tr>
+                                <th>计税方式</th>
+                                <th>计算程序</th>
+                                <th>清单模板</th>
+                                <th>列设置</th>
+                                <th>操作</th>
+                            </tr>
+                            </thead>
+                            <tbody id="tax_group_tbody">
+                            <% if (Object.keys(libData).length > 0 && libData.tax_group.length > 0) { %>
+                            <% for(let tax of libData.tax_group) {%>
+                            <% let groupIndex = "";%>
+                            <tr class='taxGroup_tr'>
+                                <td>
+                                    <% if(tax.taxType === "1") { %>
+                                    <%  groupIndex = groupIndex + tax.taxType;%>
+                                    <span>一般计税</span>
+                                    <% } else if(tax.taxType === "2"){%>
+                                    <%  groupIndex = groupIndex + tax.taxType;%>
+                                    <span>简易计税</span>
+                                    <% } %>
+                                </td>
+                                <td>
+                                    <% if(tax.program_lib) { %>
+                                    <%  groupIndex = groupIndex + tax.program_lib.id;%>
+                                        <span><%= tax.program_lib.displayName%></span>
+                                    <% } %>
+                                </td>
+                                <td>
+                                    <% if(tax.template_lib) { %>
+                                    <%  groupIndex = groupIndex + tax.template_lib.id;%>
+                                    <span><%= tax.template_lib.name%></span>
+                                    <% } %>
+                                </td>
+                                <td>
+                                    <% if(tax.col_lib) { %>
+                                    <%  groupIndex = groupIndex + tax.col_lib.id;%>
+                                    <span><%= tax.col_lib.name%></span>
+                                    <% } %>
+                                </td>
+                                <td><a class='btn btn-link btn-sm ' style="padding: 0px" onclick='editTaxGroup(this)'>编辑</a>/<a class='btn btn-link btn-sm ' style="padding: 0px" onclick='deleteTaxGroup(this)'>删除</a>
+                                    <input type='hidden' name='tax_group' data-id ="<%= groupIndex%>" value="<%= JSON.stringify(tax) %>">
+                                </td>
+                            </tr>
+                            <% } %>
+                            <% } %>
+                            </tbody>
+                        </table>
                     </div>
                 </div>
                 <input type="hidden" name="glj_col" value="<%= gljCol %>" id="glj_col">
-                <input type="hidden" name="engineering" value="<%= engineeringInfo.id %>" id="engineering">
+                <input type="hidden" name="engineering" value="<%= libData.engineering %>" id="engineering">
                 <input type="hidden" name="section" value="<%= section %>" id="section">
-                <input type="hidden" name="id" value="<%= valuationId %>">
+                <input type="hidden" name="id" value="<%= libData._id.toString()%>">
+                </div>
             </form>
         </div>
     </div>
@@ -168,10 +198,12 @@
     let feeRateList = '<%- feeRateList %>';
     let artificialCoefficientList = '<%- artificialCoefficientList %>';
     let programList = '<%- calculationList %>';
-    let mainTreeCol = '<%- mainTreeCol %>';
     let billsTemplateData = '<%- billsTemplateData %>';
     let billsGuidanceList = '<%- billsGuidanceList %>';
-    let gljCol = '<%- gljCol %>';    let colSpread = null;
+    let gljCol = '<%- gljCol %>';
+    let billTemplateList = '<%- billTemplateList %>';
+    let mainTreeColList = '<%- mainTreeColList %>';
+    let colSpread = null;
     let colEditSpread = null;
 </script>
 <script type="text/javascript" src="/public/web/id_tree.js"></script>

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

@@ -71,16 +71,6 @@
                         </div>
                     </div>
                 </div>
-                <div class="form-group" id="program-area">
-                    <label>计算程序</label>
-                    <div class="row">
-                        <div class="col-xs-12">
-                            <select class="form-control" name="program_lib">
-                                <option value="">请选择计算程序</option>
-                            </select>
-                        </div>
-                    </div>
-                </div>
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
@@ -242,4 +232,66 @@
 </div>
 
 
+<!-- 弹窗计税组合 -->
+<div class="modal fade" id="addTaxGroup" tabindex="-1" role="dialog">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                <h4 class="modal-title" >添加计税组合</h4>
+                <input type="hidden" id="groupEditType" value="">
+                <input type="hidden" id="groupIndex" value="">
+            </div>
+            <div class="modal-body">
+                <div class="form-group" id="tax-area">
+                    <label>计税方式</label>
+                    <div class="row">
+                        <div class="col-xs-12">
+                            <select class="form-control" name="taxType" id ="taxType" >
+                                <option value="">请选择计税方式</option>
+                                <option value=1>一般计税</option>
+                                <option value=2>简易计税</option>
+                            </select>
+                        </div>
+                    </div>
+                </div>
+                <div class="form-group" id="program-area">
+                    <label>计算程序</label>
+                    <div class="row">
+                        <div class="col-xs-12">
+                            <select class="form-control" name="program_lib" id="program_lib">
+                                <option value="">请选择计算程序</option>
+                            </select>
+                        </div>
+                    </div>
+                </div>
+                <div class="form-group" id="template-area">
+                    <label>清单模板</label>
+                    <div class="row">
+                        <div class="col-xs-12">
+                            <select class="form-control" name="template_lib" id="template_lib">
+                                <option value="">请选择清单模板</option>
+                            </select>
+                        </div>
+                    </div>
+                </div>
+                <div class="form-group" id="col-area">
+                    <label>列设置</label>
+                    <div class="row">
+                        <div class="col-xs-12">
+                            <select class="form-control" name="col_lib" id = "col_lib">
+                                <option value="">请选择列设置</option>
+                            </select>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-primary" id="add-group">确定添加</button>
+            </div>
+        </div>
+    </div>
+</div>
+
 <script type="text/javascript" src="/web/users/js/col_setting.js"></script>

+ 26 - 6
web/users/views/tool/index.html

@@ -9,37 +9,57 @@
             <div class="col-xs-6 mb-30 ">
                 <div class="c-body">
                     <h2>清单规则编辑器
-                        <a id="billsLib" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a></h2>
+                        <a id="billsLib" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a>
+                    </h2>
                 </div>
             </div>
             <div class="col-xs-6 mb-30 ">
                 <div class="c-body">
                     <h2>定额编辑器
-                        <a id="rationLib" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a></h2>
+                        <a id="rationLib" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a>
+                    </h2>
                 </div>
             </div>
             <div class="col-xs-6 mb-30 ">
                 <div class="c-body">
                     <h2>报表模板
-                        <a id="rptTemplate" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a></h2>
+                        <a id="rptTemplate" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a>
+                    </h2>
                 </div>
             </div>
             <div class="col-xs-6 mb-30 ">
                 <div class="c-body">
                     <h2>人材机库
-                        <a id="gljLib" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a></h2>
+                        <a id="gljLib" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a>
+                    </h2>
                 </div>
             </div>
             <div class="col-xs-6 mb-30 ">
                 <div class="c-body">
                     <h2>清单指引编辑器
-                        <a id="billsGuidanceLib" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a></h2>
+                        <a id="billsGuidanceLib" href="javascript:void(0);" class="btn btn-primary pull-right">进入</a>
+                    </h2>
                 </div>
             </div>
             <div class="col-xs-6 mb-30 ">
                 <div class="c-body">
                     <h2>清除项目残留数据
-                        <a href="javascript:void(0);" id="clearJunkBtn" class="btn btn-primary pull-right">清除</a></h2>
+                        <a id="clearJunkBtn" href="javascript:void(0);" class="btn btn-primary pull-right">清除</a>
+                    </h2>
+                </div>
+            </div>
+            <div class="col-xs-6 mb-30 ">
+                <div class="c-body">
+                    <h2>清单模板编辑器
+                        <a id="billTemplate" href="/billsTemplate/main" target="_blank" class="btn btn-primary pull-right">进入</a>
+                    </h2>
+                </div>
+            </div>
+            <div class="col-xs-6 mb-30 ">
+                <div class="c-body">
+                    <h2>列设置
+                        <a id="mainTreeCol" href="/mainTreeCol/main" target="_blank" class="btn btn-primary pull-right">进入</a>
+                    </h2>
                 </div>
             </div>
         </div>