Browse Source

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

TonyKang 7 years ago
parent
commit
0ee1adc0c2

+ 2 - 2
logs/log4js.json

@@ -16,7 +16,7 @@
     "default": { "appenders": ["console"], "level": "debug"},
     "logInfo":{ "appenders": ["logInfo","console"], "level": "debug"},
     "logDebug":{ "appenders": ["logDebug","console"], "level": "debug"},
-    "logWarn":{ "appenders": ["logWarn"], "level": "debug"},
-    "logErr":{ "appenders": ["logErr"], "level": "debug"}
+    "logWarn":{ "appenders": ["logWarn","console"], "level": "debug"},
+    "logErr":{ "appenders": ["logErr","console"], "level": "debug"}
   }
 }

+ 2 - 24
modules/ration_repository/models/coe.js

@@ -2,30 +2,8 @@
  * Created by CSL on 2017/5/3.
  * 系数表。
  */
-
-var mongoose = require("mongoose");
-var dbm = require("../../../config/db/db_manager");
-var db = dbm.getCfgConnection("scConstruct");
-var counter = require('../../../public/counter/counter');
-
-var coeSchema = mongoose.Schema({
-    coeType: String,                // 系数类型,指作用范围:
-                                    // 单个(如:111量0.001)、人工类、材料类、机械类、全部(如:定额×0.925)。
-    gljCode: String,                  // 要调整的工料机Code(当coeType=0时有效)
-    operator: String,               // 运算符(*、+、-、=)
-    amount: String,                 // 调整的量
-    _id: false
-});
-
-var coeListSchema = mongoose.Schema({
-    libID: Number,                      // 所属定额定ID
-    ID: Number,                         // 系数ID(流水号ID)
-    name: String,                       // 名称
-    content: String,                    // 说明
-    coes: [coeSchema]
-}, {versionKey: false});
-
-var coeListModel = db.model("std_ration_lib_coe_list",coeListSchema, "std_ration_lib_coe_list")
+let counter = require('../../../public/counter/counter');
+import {coeListModel} from './schemas';
 
 var coeListDAO = function(){};
 

+ 0 - 1
modules/ration_repository/models/glj_repository.js

@@ -2,7 +2,6 @@
  * Created by Tony on 2017/5/4.
  * 工料机的总库,根据不同定额库分类,参考原gljList表
  */
-
 var mongoose = require("mongoose");
 var dbm = require("../../../config/db/db_manager");
 var db = dbm.getCfgConnection("scConstruct");

+ 5 - 43
modules/ration_repository/models/ration_item.js

@@ -1,52 +1,14 @@
 /**
  * Created by Tony on 2017/4/28.
  */
-var mongoose = require("mongoose");
-var dbm = require("../../../config/db/db_manager");
-var db = dbm.getCfgConnection("scConstruct");
-var async = require("async");
-var Schema = mongoose.Schema;
 
-var rationGljItemSchema = mongoose.Schema({
-    gljId: Number,
-    consumeAmt: Number,
-    proportion: Number //配合比,暂时无需使用,默认0
-}, { _id: false });
-
-var rationAssItemSchema = mongoose.Schema({
-    name: String,
-    assistID: Number,
-    assistCode: String,
-    stdValue: String,
-    stepValue: String,
-    decimal: Number,
-    carryBit: String,
-    minValue: String,
-    maxValue: String
-}, { _id: false });
-
-var rationItemSchema = mongoose.Schema({
-    ID:Number,
-    code: String,
-    name: String,
-    unit: String,
-    labourPrice: Number,
-    materialPrice: Number,
-    machinePrice: Number,
-    basePrice: Number,
-    sectionId: Number,
-    rationRepId: Number,
-    caption: String,
-    feeType: Number,
-    rationGljList: [rationGljItemSchema],
-    rationCoeList: Array,
-    rationAssList: [rationAssItemSchema]
-});
-var rationItemModel = db.model("std_ration_lib_ration_items",rationItemSchema, "std_ration_lib_ration_items")
-var counter = require('../../../public/counter/counter');
-let gljDao = require('./glj_repository');
+let async = require("async");
 let moment = require('moment');
+let counter = require('../../../public/counter/counter');
+let gljDao = require('./glj_repository');
 let rationRepositoryDao = require('./repository_map');
+import {rationItemModel} from './schemas';
+
 var rationItemDAO = function(){};
 
 rationItemDAO.prototype.getRationItemsBySection = function(sectionId,callback){

+ 4 - 19
modules/ration_repository/models/ration_section_tree.js

@@ -2,26 +2,11 @@
  * Created by Tony on 2017/4/21.
  */
 
-var mongoose = require("mongoose");
-var dbm = require("../../../config/db/db_manager");
-var chapterTreeDb = dbm.getCfgConnection("scConstruct");
-var async = require("async");
-var Schema = mongoose.Schema;
-let rationRepositoryDao = require('./repository_map');
+let async = require('async');
 let moment = require('moment');
-
-var rationChapterTreeSchema = new Schema({//章节树  //生成唯一id改为sectionID  改成string
-    rationRepId: Number,
-    ID:Number,
-    ParentID:Number,
-    NextSiblingID:Number,
-    name: String,
-    explanation: String,//说明
-    ruleText: String,//计算规则
-    isDeleted: Boolean
-});
-var rationChapterTreeModel = chapterTreeDb.model("std_ration_lib_ration_chapter_trees", rationChapterTreeSchema, "std_ration_lib_ration_chapter_trees");
-var counter = require('../../../public/counter/counter');
+let counter = require('../../../public/counter/counter');
+let rationRepositoryDao = require('./repository_map');
+import {rationChapterTreeModel} from './schemas';
 
 var rationChapterTreeDAO = function(){};
 

+ 30 - 36
modules/ration_repository/models/repository_map.js

@@ -2,38 +2,11 @@
  * Created by Tony on 2017/4/24.
  * 重新构造,不适宜生成多个定额库db,还是得统一在一个表
  */
-var mongoose = require('mongoose');
-var dbm = require("../../../config/db/db_manager");
 let async = require("async");
 let moment = require('moment');
+let counter = require('../../../public/counter/counter');
 import gljMapModel from "../../std_glj_lib/models/schemas";
-//var stringUtil = require('../../../public/stringUtil');
-var rationLibdb = dbm.getCfgConnection("scConstruct");
-var Schema = mongoose.Schema;
-
-let oprSchema = new Schema({
-        operateDate: String,
-        operator: String
-    },
-    {_id: false},
-    {versionKey: false});
-
-var RepositoryMapSchema = new Schema({
-    "ID": Number,
-    "dispName" : String,
-    "appType" : String, //如:"建筑" / "公路"
-    "compilationId": String, //编办
-    "compilationName": String,
-    "gljLib": Number,
-    "descr" : String,
-    "creator": String,
-    "createDate": String,
-    "recentOpr" :[oprSchema],
-    "deleted": Boolean
-},  {versionKey: false});
-var counter = require('../../../public/counter/counter');
-
-var rationRepository = rationLibdb.model("std_ration_lib_map", RepositoryMapSchema, "std_ration_lib_map");
+import {rationRepository, rationChapterTreeModel, rationItemModel} from './schemas';
 
 function createNewLibModel(rationLibObj){
     var rst = {};
@@ -232,14 +205,35 @@ rationRepositoryDao.prototype.deleteRationLib = function(oprtor, libId, callback
                            callback(err, '移除工料机库失败!');
                        }
                        else{
-                           //移除工料机库内被引用标记
-                           gljMapModel.update({ID: result[0].gljLib, deleted: false}, {$pull: {rationLibs: {ID: libId}}}, function (err) {
-                               if(err){
-                                   callback(err, '删除引用失败!');
-                               }
-                               else{
-                                   callback(null, '成功!');
+                           async.parallel([
+                               function (cb) {
+                                   //移除工料机库内被引用标记
+                                   gljMapModel.update({ID: result[0].gljLib, deleted: false}, {$pull: {rationLibs: {ID: libId}}}, function (err) {
+                                       if(err){
+                                           cb(err);
+                                       }
+                                       else{
+                                           cb(null);
+                                       }
+                                   });
+                               },
+                               //删除库下定额
+                               function (cb) {
+                                   rationItemModel.update({rationRepId: libId}, {$set: {isDeleted: true}}, {upsert: true, multi: true}, function (err) {
+                                       if(err)cb(err);
+                                       else cb(null);
+                                   });
+                               },
+                               //删除库下章节树
+                               function (cb) {
+                                   rationChapterTreeModel.update({rationRepId: libId}, {$set: {isDeleted: true}}, {upsert: true, multi: true}, function (err) {
+                                       if(err)cb(err);
+                                       else cb(null);
+                                   })
                                }
+                           ], function (err) {
+                               if(err) callback(err, 'fail');
+                               else callback(null, 'sc')
                            });
                        }
                    });

+ 106 - 0
modules/ration_repository/models/schemas.js

@@ -0,0 +1,106 @@
+/**
+ * Created by Zhong on 2017/9/13.
+ */
+import mongoose from "mongoose";
+let dbm = require("../../../config/db/db_manager");
+let db = dbm.getCfgConnection("scConstruct");
+let Schema = mongoose.Schema;
+
+let coeSchema = new Schema({
+    coeType: String,                // 系数类型,指作用范围:
+                                    // 单个(如:111量0.001)、人工类、材料类、机械类、全部(如:定额×0.925)。
+    gljCode: String,                  // 要调整的工料机Code(当coeType=0时有效)
+    operator: String,               // 运算符(*、+、-、=)
+    amount: String,                 // 调整的量
+    _id: false
+});
+
+let coeListSchema = new Schema({
+    libID: Number,                      // 所属定额定ID
+    ID: Number,                         // 系数ID(流水号ID)
+    name: String,                       // 名称
+    content: String,                    // 说明
+    coes: [coeSchema]
+}, {versionKey: false});
+
+
+let oprSchema = new Schema({
+        operateDate: String,
+        operator: String
+    },
+    {_id: false},
+    {versionKey: false});
+
+//定额库
+let RepositoryMapSchema = new Schema({
+    "ID": Number,
+    "dispName" : String,
+    "appType" : String, //如:"建筑" / "公路"
+    "compilationId": String, //编办
+    "compilationName": String,
+    "gljLib": Number,
+    "descr" : String,
+    "creator": String,
+    "createDate": String,
+    "recentOpr" :[oprSchema],
+    "deleted": Boolean
+},  {versionKey: false});
+
+//定额章节树
+let rationChapterTreeSchema = new Schema({
+    rationRepId: Number,
+    ID:Number,
+    ParentID:Number,
+    NextSiblingID:Number,
+    name: String,
+    explanation: String,//说明
+    ruleText: String,//计算规则
+    isDeleted: Boolean
+});
+
+//定额工料机
+let rationGljItemSchema = new Schema({
+    gljId: Number,
+    consumeAmt: Number,
+    proportion: Number //配合比,暂时无需使用,默认0
+}, { _id: false });
+
+//辅助定额调整
+let rationAssItemSchema = new Schema({
+    name: String,
+    assistID: Number,
+    assistCode: String,
+    stdValue: String,
+    stepValue: String,
+    decimal: Number,
+    carryBit: String,
+    minValue: String,
+    maxValue: String
+}, { _id: false });
+
+//定额
+var rationItemSchema = new Schema({
+    ID:Number,
+    code: String,
+    name: String,
+    unit: String,
+    labourPrice: Number,
+    materialPrice: Number,
+    machinePrice: Number,
+    basePrice: Number,
+    sectionId: Number,
+    rationRepId: Number,
+    caption: String,
+    feeType: Number,
+    rationGljList: [rationGljItemSchema],
+    rationCoeList: Array,
+    rationAssList: [rationAssItemSchema],
+    isDeleted: Boolean
+});
+
+let coeListModel = db.model("std_ration_lib_coe_list",coeListSchema, "std_ration_lib_coe_list")
+let rationRepository = db.model("std_ration_lib_map", RepositoryMapSchema, "std_ration_lib_map");
+let rationChapterTreeModel = db.model("std_ration_lib_ration_chapter_trees", rationChapterTreeSchema, "std_ration_lib_ration_chapter_trees");
+let rationItemModel = db.model("std_ration_lib_ration_items",rationItemSchema, "std_ration_lib_ration_items");
+
+export{coeListModel, rationRepository, rationChapterTreeModel, rationItemModel};

+ 42 - 2
modules/std_glj_lib/models/gljMapModel.js

@@ -2,6 +2,7 @@
  * Created by Zhong on 2017/8/11.
  */
 import gljMapModel from "./schemas";
+import {gljModel, gljClassModel} from "./schemas";
 import moment from "moment";
 import counter from "../../../public/counter/counter";
 import async from "async";
@@ -144,14 +145,53 @@ class GljMapDao extends OprDao{
                             callback(null, '此工料机库已被引用!');
                         }
                         else{
-                            gljMapModel.update({ID: libId, deleted: false}, {$set: {deleted: true}}, function (err) {
+                            async.parallel([
+                                function (cb) {
+                                    gljMapModel.update({ID: libId, deleted: false}, {$set: {deleted: true}}, function (err) {
+                                        if(err){
+                                            cb(err);
+                                        }
+                                        else{
+                                            cb(null);
+                                        }
+                                    });
+                                },
+                                function (cb) {
+                                    gljModel.update({repositoryId: libId}, {$set: {deleted: true}}, {upsert: true, multi: true}, function (err) {
+                                        if(err){
+                                            cb(err);
+                                        }
+                                        else{
+                                            cb(null);
+                                        }
+                                    });
+                                },
+                                function (cb) {
+                                    gljClassModel.update({repositoryId: libId}, {$set: {deleted: true}}, {upsert: true, multi: true}, function (err) {
+                                        if(err){
+                                            cb(err);
+                                        }
+                                        else{
+                                            cb(null);
+                                        }
+                                    })
+                                }
+                            ], function (err) {
                                 if(err){
                                     callback(err, '移除工料机库失败!');
                                 }
                                 else{
-                                   callback(null, '删除成功');
+                                    callback(null, '删除成功');
                                 }
                             });
+                           /* gljMapModel.update({ID: libId, deleted: false}, {$set: {deleted: true}}, function (err) {
+                                if(err){
+                                    callback(err, '移除工料机库失败!');
+                                }
+                                else{
+                                   callback(null, '删除成功');
+                                }
+                            });*/
                         }
                     }
                 });

+ 1 - 0
modules/std_glj_lib/models/gljModel.js

@@ -28,6 +28,7 @@ class GljDao  extends OprDao{
                             newClassObj.NextSiblingID = data.NextSiblingID;
                             newClassObj.Name = data.Name;
                             newClassObj.repositoryId = gljLibId;
+                            newClassObj.deleted = false;
                             gljClassModel.create(newClassObj, function(err){
                                 if(err)cb(err);
                                 else{

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

@@ -58,6 +58,8 @@ class EngineeringLibModel extends BaseModel {
     async addLib(valuationId, data) {
         if (data.main_tree_col) {
             data.main_tree_col = JSON.parse(data.main_tree_col);
+        } else {
+            delete data['main_tree_col'];
         }
 
         let result = false;

+ 0 - 11
modules/users/models/schemas/compilation.js

@@ -35,17 +35,6 @@ let childrenSchema = new Schema({
     // 类型
     type: {
         type: Number
-    },
-    // 列设置
-    main_tree_col: {
-        type: Schema.Types.Mixed,
-        default: {
-            "emptyRows":3,
-            "headRows":0,
-            "treeCol": 0,
-            "headRowHeight":[],
-            "cols":[]
-        }
     }
 });
 let modelSchema = {

+ 5 - 5
modules/users/models/schemas/engineering_lib.js

@@ -29,11 +29,11 @@ let modelSchema = {
     main_tree_col: {
         type: Schema.Types.Mixed,
         default: {
-            "emptyRows":3,
-            "headRows":0,
-            "treeCol": 0,
-            "headRowHeight":[],
-            "cols":[]
+            emptyRows: 3,
+            headRows: 0,
+            treeCol: 0,
+            headRowHeight: [],
+            cols:[]
         }
     },
     // 费率标准库

+ 91 - 2
public/web/sheet/sheet_data_helper.js

@@ -30,16 +30,36 @@ var __settingTemp = {
 };
 
 var SheetDataHelper = {
+    getObjPos: function (obj) {
+        let target = obj;
+        let pos = {x: obj.offsetLeft, y: obj.offsetTop};
+
+        target = obj.offsetParent;
+        while (target) {
+            pos.x += target.offsetLeft;
+            pos.y += target.offsetTop;
+            target = target.offsetParent;
+        }
+        return pos;
+    },
+    initSetting: function (obj, setting) {
+        setting.pos = this.getObjPos(obj);
+    },
     createNewSpread: function (obj) {
         var spread = new GC.Spread.Sheets.Workbook(obj, {sheetCount: 1});
         spread.options.tabStripVisible = false;
         spread.options.scrollbarMaxAlign = true;
         spread.options.cutCopyIndicatorVisible = false;
         spread.options.allowCopyPasteExcelStyle = false;
+        spread.options.allowUserDragDrop = false;
         spread.getActiveSheet().setRowCount(3);
         return spread;
     },
     loadSheetHeader: function (setting, sheet) {
+        if (setting.frozenCols) {
+            sheet.frozenColumnCount(setting.frozenCols);
+        }
+        sheet.setColumnCount(setting.cols.length);
         sheet.setRowCount(setting.headRows, GC.Spread.Sheets.SheetArea.colHeader);
         if (setting.headRowHeight) {
             setting.headRowHeight.forEach(function (rowHeight, index) {
@@ -53,7 +73,7 @@ var SheetDataHelper = {
                 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]);
+                        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);
@@ -82,12 +102,53 @@ var SheetDataHelper = {
         style.font = setting.data.font;
         style.hAlign = setting.data.hAlign;
         style.vAlign = setting.data.vAlign;
-        //style.wordWrap = setting.data.wordWrap;
+        style.wordWrap = setting.data.wordWrap;
         return style;
     },
     loadSheetData: function (setting, sheet, datas) {
         SheetDataHelper.protectdSheet(sheet);
 
+        let TipCellType = function () {};
+        TipCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
+        TipCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
+            return {
+                x: x,
+                y: y,
+                row: context.row,
+                col: context.col,
+                cellStyle: cellStyle,
+                cellRect: cellRect,
+                sheet: context.sheet,
+                sheetArea: context.sheetArea
+            };
+        };
+        TipCellType.prototype.processMouseEnter = function (hitinfo) {
+            let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
+            if (setting.pos && text && text !== '') {
+                if (!this._toolTipElement) {
+                    var div = document.createElement("div");
+                    $(div).css("position", "absolute")
+                        .css("border", "1px #C0C0C0 solid")
+                        .css("box-shadow", "1px 2px 5px rgba(0,0,0,0.4)")
+                        .css("font", "9pt Arial")
+                        .css("background", "white")
+                        .css("padding", 5);
+
+                    this._toolTipElement = div;
+                }
+                $(this._toolTipElement).text(text).css("top", setting.pos.y + hitinfo.y + 15).css("left", setting.pos.x + hitinfo.x + 15);
+                $(this._toolTipElement).hide();
+                document.body.insertBefore(this._toolTipElement, null);
+                $(this._toolTipElement).show("fast");
+            }
+        };
+        TipCellType.prototype.processMouseLeave = function (hininfo) {
+            if (this._toolTipElement) {
+                document.body.removeChild(this._toolTipElement);
+                this._toolTipElement = null;
+            }
+        }
+
         sheet.suspendPaint();
         sheet.suspendEvent();
 
@@ -98,9 +159,37 @@ var SheetDataHelper = {
         sheet.setRowCount(datas.length + setting.emptyRows, GC.Spread.Sheets.SheetArea.viewport);
         setting.cols.forEach(function (colSetting, iCol) {       
             sheet.setStyle(-1, iCol, SheetDataHelper.getSheetCellStyle(colSetting));
+            if (colSetting.showHint) {
+                sheet.getRange(-1, iCol, -1, 1).cellType(new TipCellType());
+            }
             datas.forEach(function (data, iRow) {
                 var cell = sheet.getCell(iRow, iCol, GC.Spread.Sheets.SheetArea.viewport);
+                var getFieldText2 = function () {
+                    var fields = colSetting.data.field.split('.'), iField, value = data;
+                    for (iField = 0; iField < fields.length; iField++) {
+                        if (value[fields[iField]]) {
+                            value = value[fields[iField]];
+                        } else {
+                            return '';
+                        }
+                    }
+                    return value;
+                };
                 cell.value(data[colSetting.data.field]);
+                if (colSetting.data.getText) {
+                    cell.value(colSetting.data.getText(data));
+                } else {
+                    cell.value(getFieldText2());
+                }
+                if (colSetting.readOnly) {
+                    if (Object.prototype.toString.apply(colSetting.readOnly) === "[object Function]") {
+                        cell.locked(colSetting.readOnly(node));
+                    } else {
+                        cell.locked(true);
+                    }
+                } else {
+                    cell.locked(false);
+                }
             });
         });
 

+ 4 - 0
public/web/tree_sheet/tree_sheet_controller.js

@@ -118,6 +118,9 @@ var TREE_SHEET_CONTROLLER = {
         }
 
         controller.prototype.setTreeSelected = function (node) {
+            if (this.event.beforeTreeSelectedChange) {
+                this.event.beforeTreeSelectedChange(this.tree.selected);
+            }
             this.tree.selected = node;
             if (this.event.refreshBaseActn) {
                 this.event.refreshBaseActn(this.tree);
@@ -135,6 +138,7 @@ var TREE_SHEET_CONTROLLER = {
     },
     eventName: {
         refreshBaseActn: 'refreshBaseActn',
+        beforeTreeSelectedChange: 'beforeTreeSelectedChange',
         treeSelectedChanged: 'treeSelectedChanged',
         cellDoubleClick: 'cellDoubleClick'
     }

+ 92 - 4
public/web/tree_sheet/tree_sheet_helper.js

@@ -3,6 +3,26 @@
  */
 
 var TREE_SHEET_HELPER = {
+    getObjPos: function (obj) {
+        let target = obj;
+        let pos = {x: obj.offsetLeft, y: obj.offsetTop};
+
+        target = obj.offsetParent;
+        while (target) {
+            pos.x += target.offsetLeft;
+            pos.y += target.offsetTop;
+            target = target.offsetParent;
+        }
+        return pos;
+    },
+    /**
+     * 初始化setting,需要提示单元格text时,必须先初始化setting
+     * @param obj
+     * @param setting
+     */
+    initSetting: function (obj, setting) {
+        setting.pos = this.getObjPos(obj);
+    },
     createNewSpread: function (obj) {
         var spread = new GC.Spread.Sheets.Workbook(obj, {sheetCount: 1});
         spread.options.tabStripVisible = false;
@@ -21,9 +41,15 @@ var TREE_SHEET_HELPER = {
         style.hAlign = setting.data.hAlign;
         style.vAlign = setting.data.vAlign;
         style.wordWrap = setting.data.wordWrap;
+        if (setting.data.formatter) {
+            style.formatter = setting.data.formatter;
+        }
         return style;
     },
     loadSheetHeader: function (setting, sheet) {
+        if (setting.frozenCols) {
+            sheet.frozenColumnCount(setting.frozenCols);
+        }
         sheet.setColumnCount(setting.cols.length);
         sheet.setRowCount(setting.headRows, GC.Spread.Sheets.SheetArea.colHeader);
         setting.headRowHeight.forEach(function (rowHeight, index) {
@@ -34,7 +60,7 @@ var TREE_SHEET_HELPER = {
             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(col.head.wordWrap);
+                    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);
@@ -104,15 +130,25 @@ var TREE_SHEET_HELPER = {
                     }
                     return data;
                 };
-                if (colSetting.data.getText) {
+                if (colSetting.data.getText && Object.prototype.toString.apply(colSetting.data.getText) === "[object Function]") {
                     cell.value(colSetting.data.getText(node));
                 } else {
                     cell.value(getFieldText2());
                 }
-                if (colSetting.data.cellType) {
+                if (colSetting.data.cellType && Object.prototype.toString.apply(colSetting.data.cellType) !== "[object String]") {
                     cell.cellType(colSetting.data.cellType);
                 }
+                if (colSetting.readOnly) {
+                    if (Object.prototype.toString.apply(colSetting.readOnly) === "[object Function]") {
+                        cell.locked(colSetting.readOnly(node));
+                    } else {
+                        cell.locked(true);
+                    }
+                } else {
+                    cell.locked(false);
+                }
             });
+            sheet.autoFitRow(node.serialNo());
             if (recursive) {
                 TREE_SHEET_HELPER.refreshTreeNodeData(setting, sheet, node.children, recursive);
             }
@@ -127,6 +163,14 @@ var TREE_SHEET_HELPER = {
         };
         TreeNodeCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
         TreeNodeCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
+            if (style.backColor) {
+                ctx.save();
+                ctx.fillStyle = style.backColor;
+                ctx.fillRect(x, y, w, h);
+                ctx.restore();
+            } else {
+                ctx.clearRect(x, y, w, h);
+            }
             // ������(x1, y1)���(��, ��), (x2, y2)�յ�(��, ��), ��ɫ
             var drawLine = function (canvas, x1, y1, x2, y2, color) {
                 ctx.save();
@@ -233,7 +277,7 @@ var TREE_SHEET_HELPER = {
                 cellRect: cellRect,
                 sheetArea: context.sheetArea
             };
-        }
+        };
         TreeNodeCellType.prototype.processMouseDown = function (hitinfo) {
             var offset = -1;
             var node = tree.items[hitinfo.row];
@@ -257,6 +301,47 @@ var TREE_SHEET_HELPER = {
             }
         };
 
+        let TipCellType = function () {};
+        TipCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
+        TipCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
+            return {
+                x: x,
+                y: y,
+                row: context.row,
+                col: context.col,
+                cellStyle: cellStyle,
+                cellRect: cellRect,
+                sheet: context.sheet,
+                sheetArea: context.sheetArea
+            };
+        };
+        TipCellType.prototype.processMouseEnter = function (hitinfo) {
+            let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
+            if (setting.pos && text && text !== '') {
+                if (!this._toolTipElement) {
+                    var div = document.createElement("div");
+                    $(div).css("position", "absolute")
+                        .css("border", "1px #C0C0C0 solid")
+                        .css("box-shadow", "1px 2px 5px rgba(0,0,0,0.4)")
+                        .css("font", "9pt Arial")
+                        .css("background", "white")
+                        .css("padding", 5);
+
+                    this._toolTipElement = div;
+                }
+                $(this._toolTipElement).text(text).css("top", setting.pos.y + hitinfo.y + 15).css("left", setting.pos.x + hitinfo.x + 15);
+                $(this._toolTipElement).hide();
+                document.body.insertBefore(this._toolTipElement, null);
+                $(this._toolTipElement).show("fast");
+            }
+        };
+        TipCellType.prototype.processMouseLeave = function (hininfo) {
+            if (this._toolTipElement) {
+                document.body.removeChild(this._toolTipElement);
+                this._toolTipElement = null;
+            }
+        }
+
         TREE_SHEET_HELPER.protectdSheet(sheet);
         TREE_SHEET_HELPER.massOperationSheet(sheet, function () {
             sheet.rowOutlines.direction(GC.Spread.Sheets.Outlines.OutlineDirection.backward);
@@ -267,6 +352,9 @@ var TREE_SHEET_HELPER = {
             sheet.setRowCount(tree.count() + setting.emptyRows, GC.Spread.Sheets.SheetArea.viewport);
             setting.cols.forEach(function (colSetting, iCol) {
                 sheet.setStyle(-1, iCol, TREE_SHEET_HELPER.getSheetCellStyle(colSetting));
+                if (colSetting.showHint) {
+                    sheet.getRange(-1, iCol, -1, 1).cellType(new TipCellType());
+                }
             });
             sheet.getRange(-1, setting.treeCol, -1, 1).cellType(new TreeNodeCellType());
             TREE_SHEET_HELPER.refreshTreeNodeData(setting, sheet, tree.roots, true);

+ 2 - 2
web/maintain/ration_repository/dinge.html

@@ -107,7 +107,7 @@
                                 <!--  <div class="m-2"><a href="javacript:void(0);" data-toggle="modal" data-target="#editTsm" title="编辑">编辑说明</a></div>-->
                                   <div class="main-content m-2">
                                       <h5>说明</h5>
-                                      <textarea id="explanationShow" class="form-control"   rows="7" style="background: white;"></textarea>
+                                      <textarea id="explanationShow" class="form-control" rows="35" style="background: white;"></textarea>
                                   </div>
                               </div>
                           </div>
@@ -117,7 +117,7 @@
                          <!--         <div class="m-2"><a href="javacript:void(0);" data-toggle="modal" data-target="#editTjs" title="编辑">编辑计算规则</a></div>-->
                                   <div class="main-content m-2">
                                       <h5>计算规则</h5>
-                                      <textarea id="ruleTextShow" class="form-control"   rows="7" style="background: white;"></textarea>
+                                      <textarea id="ruleTextShow" class="form-control"   rows="35" style="background: white;"></textarea>
                                   </div>
                               </div>
                           </div>

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

@@ -322,7 +322,7 @@ var rationOprObj = {
             if (!sheetCommonObj.chkIfEmpty(rObj, me.setting)) {
                 //addArr.push(rObj);
                 me.addRationItem = rObj;
-                if(rObj.code && rObj.code.trim().length > 0){
+                if(rObj.code && rObj.code.toString().trim().length > 0){
                     if(me.rationsCodes.indexOf(rObj.code) === -1){
                         addArr.push(rObj);
                         me.rationsCodes.push(rObj.code);
@@ -349,7 +349,7 @@ var rationOprObj = {
                         });
                     }*/
                 }
-                else if(rObj.code && rObj.code.trim().length === 0){
+                else if(rObj.code && rObj.code.toString.trim().length === 0){
                     me.workBook.getSheet(0).setValue(args.row, args.col, '');
                 }
             }

+ 5 - 5
web/maintain/ration_repository/js/ration_glj.js

@@ -12,10 +12,10 @@ var rationGLJOprObj = {
             {headerName:"编码",headerWidth:120,dataCode:"code", dataType: "String", formatter: "@"},
             {headerName:"名称",headerWidth:400,dataCode:"name", dataType: "String"},
             {headerName:"规格",headerWidth:120,dataCode:"specs", dataType: "String"},
-            {headerName:"单位",headerWidth:160,dataCode:"unit", dataType: "String"},
+            {headerName:"单位",headerWidth:160,dataCode:"unit", dataType: "String", hAlign: "center", vAlign: "center"},
             {headerName:"基价单价",headerWidth:160, dataCode:"basePrice", dataType: "Number", formatter:"0.00",  precision: 2},
             {headerName:"定额消耗",headerWidth:160, dataCode:"consumeAmt", dataType: "Number", formatter: "0.000", precision: 3},
-            {headerName:"类型",headerWidth:160,dataCode:"gljType", dataType: "String"}
+            {headerName:"类型",headerWidth:160,dataCode:"gljType", dataType: "String", hAlign: "center", vAlign: "center"}
         ],
         view:{
             comboBox:[],
@@ -249,7 +249,7 @@ var rationGLJOprObj = {
                 }
             }
         } else {
-            if(args.editingText && args.editingText.trim().length !== 0){
+            if(args.editingText && args.editingText.toString().trim().length !== 0){
                 let isExist = false;
                 for(let i = 0, len = cacheArr.length; i < len; i++){
                     if(cacheArr[i].code === args.editingText && i !== args.row){
@@ -267,7 +267,7 @@ var rationGLJOprObj = {
                         let rationRepId = storageUtil.getSessionCache("RationGrp","repositoryID");
                         let gljLibID = storageUtil.getSessionCache("gljLib", "repositoryID_" + rationRepId);
                         let codes = [];
-                        codes.push(args.editingText.trim());
+                        codes.push(args.editingText.toString().trim());
                         me.addGljItems(codes, gljLibID, args);
                     }
                     else if(args.row >= cacheArr.length){//新增
@@ -275,7 +275,7 @@ var rationGLJOprObj = {
                             let gljLibID = storageUtil.getSessionCache("gljLib", "repositoryID_" + rationRepId);
                             if (gljLibID) {
                                 var codes = [];
-                                codes.push(args.editingText.trim());
+                                codes.push(args.editingText.toString().trim());
                                 me.addGljItems(codes, gljLibID, args);
                             }
                     }

+ 58 - 11
web/users/js/col_setting.js

@@ -8,9 +8,11 @@ let ColSettingObj = {
     DEFAULT_DATA_STYLE: null,
     cellType: {
         getText: null,
-        readOnly: null
+        cellType: null,
+        readOnly: null,
+        checkBox: null
     },
-    Rows: {data: 0, filedName: 0, getText: 1, width: 2, readOnly: 3},
+    Rows: {data: 0, filedName: 0, getText: 1, wordWrap: 2, cellType: 3, width: 4, readOnly: 5, showHint: 6, visible: 7},
     columnValueChanged: function (e, info) {
         let that = ColSettingObj;
         info.colList.forEach(function (iCol) {
@@ -50,25 +52,36 @@ let ColSettingObj = {
 
         this.cellType.getText = new GC.Spread.Sheets.CellTypes.ComboBox();
         this.cellType.getText.items(['getText.type']);
+
+        this.cellType.cellType = new GC.Spread.Sheets.CellTypes.ComboBox();
+        this.cellType.cellType.items(['cellType.units']);
+
+        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.readOnly + 1);
+        sheet.setRowCount(setting.headRows + this.Rows.visible + 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, 2, 1, GC.Spread.Sheets.SheetArea.rowHeader);
+        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);
 
-        sheet.setText(setting.headRows + this.Rows.width, 0, 'width', GC.Spread.Sheets.SheetArea.rowHeader);
-        sheet.addSpan(setting.headRows + this.Rows.width, 0, 1, 2, GC.Spread.Sheets.SheetArea.rowHeader);
-
-        sheet.setText(setting.headRows + this.Rows.readOnly, 0, 'ReadOnly', GC.Spread.Sheets.SheetArea.rowHeader);
-        sheet.addSpan(setting.headRows + this.Rows.readOnly, 0, 1, 2, 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');
     },
     initColSetting: function (setting) {
         this.DEFAULT_TITLE_STYLE = this.getCellStyle('Arial', GC.Spread.Sheets.HorizontalAlign.center, GC.Spread.Sheets.VerticalAlign.center);
@@ -80,11 +93,15 @@ let ColSettingObj = {
         $('#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);
@@ -124,14 +141,29 @@ let ColSettingObj = {
                 // 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);
             }
         }
+
+        colEditSpread.getActiveSheet().resumePaint();
+
         let cell = colEditSpread.getActiveSheet().getCell(0, 0, GC.Spread.Sheets.SheetArea.viewport);
         if (cell) {
             $('#font').val(cell.font());
@@ -139,11 +171,20 @@ let ColSettingObj = {
     },
     setColCount: function (count) {
         let sheet = colEditSpread.getActiveSheet();
+        let orgCount = sheet.getColumnCount();
         sheet.setColumnCount(count);
-        for (let iCol = 0; iCol < sheet.getColumnCount(); iCol++) {
+        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, GC.Spread.Sheets.SheetArea.viewport).cellType(this.cellType.readOnly);
+            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);
         }
     },
     setHeaderRowCount: function (count) {
@@ -199,6 +240,10 @@ let ColSettingObj = {
             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.head = {};
             col.head.titleNames = [];
@@ -240,6 +285,8 @@ let ColSettingObj = {
                 col.data.getText = cell.text();
             }
             setting.cols.push(col);
+            // wordWrap
+            col.data.wordWrap = sheet.getValue(setting.headRows + this.Rows.wordWrap, iCol) || false;
         }
         return setting;
     }

+ 9 - 2
web/users/js/compilation.js

@@ -234,14 +234,21 @@ function initCompilation() {
     let rationLibData = rationList === undefined ? [] : JSON.parse(rationList);
     let gljLibData = gljList === undefined ? [] : JSON.parse(gljList);
     let feeLibData = feeRateList === undefined ? [] : JSON.parse(feeRateList);
+    mainTreeCol = mainTreeCol === '' ? '' : JSON.parse(mainTreeCol);
+
     let artificialCoefficientData = artificialCoefficientList === undefined ? [] : JSON.parse(artificialCoefficientList);
+    mainTreeCol = mainTreeCol.replace(/\n/g, '\\n');
+    billsTemplateData = billsTemplateData.replace(/\n/g, '\\n');
 
     // 初始化 造价书列设置
     colSpread = TREE_SHEET_HELPER.createNewSpread($('#main-tree-col')[0]);
     let billsTemplateTree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1});
+
     billsTemplateTree.loadDatas(JSON.parse(billsTemplateData));
-    TREE_SHEET_HELPER.loadSheetHeader(JSON.parse(mainTreeCol), colSpread.getActiveSheet());
-    TREE_SHEET_HELPER.showTreeData(JSON.parse(mainTreeCol), colSpread.getActiveSheet(), billsTemplateTree);
+    if (mainTreeCol !== '') {
+        TREE_SHEET_HELPER.loadSheetHeader(mainTreeCol, colSpread.getActiveSheet());
+        TREE_SHEET_HELPER.showTreeData(mainTreeCol, colSpread.getActiveSheet(), billsTemplateTree);
+    }
 
     if (billListData.length <= 0 || rationLibData.length <= 0 || gljLibData.length <= 0) {
         return false;

+ 88 - 0
web/users/js/main_tree_col.js

@@ -0,0 +1,88 @@
+/**
+ * Created by Mai on 2017/7/25.
+ */
+
+let MainTreeCol = {
+    getText: {
+        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 '主';
+            }
+        }
+    },
+    readOnly: {
+        bills: function (node) {
+            return node.sourceType === projectObj.project.Bills.getSourceType();
+        },
+        ration: function (node) {
+            return node.sourceType === projectObj.project.Ration.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;
+        },
+        forCalcBase: function (node) {
+            // to do according to billsParentType
+            return MainTreeCol.readOnly.billsParent && MainTreeCol.readOnly.non_bills;
+        }
+    },
+    cellType: {
+        unit: function () {
+            let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
+            combo.itemHeight(10).items(['m', 'm2', 'm3', 'km', 't', 'kg', '台班', '工日', '昼夜', '元', '项', '处', '个', '件',
+                '根', '组', '系统', '台', '套', '株', '丛', '缸', '支', '只', '块', '座', '对', '份', '樘', '攒', '榀']);
+            return combo;
+        }
+    },
+    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.##';
+        }
+    }
+};

+ 1 - 0
web/users/js/template.js

@@ -183,6 +183,7 @@ $(document).ready(function () {
         }
     }
 
+    billsTemplateData = billsTemplateData.replace('\n', '\\n');
     let templateData = JSON.parse(billsTemplateData);
     for (let data of templateData) {
         if (data.flags) {

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

@@ -163,7 +163,7 @@
                         </div>
                     </div>
                 </div>
-                <div id="colEditSpread">
+                <div id="colEditSpread" style="height: 300px">
                 </div>
             </div>
             <div class="modal-footer">