浏览代码

1. 本期计量台账,列设置
2. 菜单调整
3. 中间计量,生成规则
4. 中间计量,生成规则,高级设置

MaiXinRong 6 年之前
父节点
当前提交
ee3e90e9ae

+ 2 - 2
app.js

@@ -69,7 +69,7 @@ module.exports = app => {
         app.jsFiles[c] = {};
         for (const a in controller) {
             const action = controller[a];
-            if (app.config.min) {
+            if (app.config.min && action.mergeFiles && action.mergeFile.length > 0) {
                 const minFileName = JsFiles.webPath + action.mergeFile + '.' + app.config.version + '.min.js';
                 let code = '';
                 for (const f of action.mergeFiles) {
@@ -78,7 +78,7 @@ module.exports = app => {
                 fs.writeFileSync(app.baseDir + '/app' + minFileName, Uglyfy.minify(code, {mangle: true}).code);
                 app.jsFiles[c][a] = action.files.concat([minFileName]);
             } else {
-                app.jsFiles[c][a] = action.files.concat(action.mergeFiles);
+                app.jsFiles[c][a] = action.files.concat(action.mergeFiles || []);
             }
         }
     }

+ 3 - 1
app/base/base_service.js

@@ -189,6 +189,8 @@ class BaseService extends Service {
         return list;
     }
 
-
+    round(value, decimal) {
+        this.ctx.helper.round(value, decimal);
+    }
 }
 module.exports = BaseService;

+ 7 - 1
app/const/tender.js

@@ -54,7 +54,12 @@ const measureType = {
     gcl: {
         value: 2, name: '工程量清单模式', title: ' 工程量清单', hint: ' 仅需要工程量清单,详细台帐在计量过程中逐步添加,最终组成完整台帐。',
     },
-}
+};
+
+const imType = {
+    zl: { value: 0, name: '总量控制' },
+    tz: { value: 1, name: '0号台账' },
+};
 
 const typeString = [];
 typeString[type.TJ] = '土建标';
@@ -70,4 +75,5 @@ module.exports = {
     progressTableCol,
     manageTableCol,
     measureType,
+    imType,
 };

+ 18 - 3
app/const/tender_info.js

@@ -8,7 +8,7 @@
  * @version
  */
 
-const parseInfo = ['deal_info', 'construction_unit', 'tech_param', 'decimal', 'deal_param', 'display'];
+const parseInfo = ['deal_info', 'construction_unit', 'tech_param', 'decimal', 'precision', 'deal_param', 'display'];
 const defaultInfo = {
     // 合同信息
     deal_info: {
@@ -60,11 +60,26 @@ const defaultInfo = {
         qty: 3,
         tp: 2,
         deal: false,
-        dealQty: 3,
         dealTp: 2,
         pay: false,
         payTp: 0,
     },
+    precision: {
+        t: { unit: 't', value: 3 },
+        km: { unit: 'km', value: 3 },
+        m: { unit: 'm', value: 3 },
+        m2: { unit: 'm2', value: 2 },
+        m3: { unit: 'm3', value: 2 },
+        kg: { unit: 'kg', value: 2 },
+        ge: { unit: '个', value: 0 },
+        tai: { unit: '台', value: 0 },
+        tao: { unit: '套', value: 0 },
+        ke: { unit: '棵', value: 0 },
+        zu: { unit: '组', value: 0 },
+        zonge: { unit: '总额', value: 0},
+        xitong: { unit: '系统', value: 0 },
+        other: { value: 3 },
+    },
     // 合同参数
     deal_param: {
         contractPrice: 0,
@@ -83,4 +98,4 @@ const defaultInfo = {
 module.exports = {
     parseInfo,
     defaultInfo,
-}
+};

+ 0 - 6
app/controller/ledger_controller.js

@@ -64,19 +64,13 @@ module.exports = app => {
                 });
                 col.formatter = formatter;
             }
-            const qtyFormatter = this.ctx.helper.getNumberFormatter(this.ctx.tender.info.decimal.qty);
             const tpFormatter = this.ctx.helper.getNumberFormatter(this.ctx.tender.info.decimal.tp);
             const upFormatter = this.ctx.helper.getNumberFormatter(2);
             const ledger = JSON.parse(JSON.stringify(spreadConst.ledgerSpread));
-            setColFormat(ledger.cols, 'quantity', qtyFormatter);
-            setColFormat(ledger.cols, 'dgn_qty1', qtyFormatter);
-            setColFormat(ledger.cols, 'dgn_qty2', qtyFormatter);
-            setColFormat(ledger.cols, 'deal_qty', qtyFormatter);
             setColFormat(ledger.cols, 'unit_price', upFormatter);
             setColFormat(ledger.cols, 'total_price', tpFormatter);
             setColFormat(ledger.cols, 'deal_tp', tpFormatter);
             const pos = JSON.parse(JSON.stringify(spreadConst.ledgerPosSpread));
-            setColFormat(pos.cols, 'quantity', qtyFormatter);
 
             const tender = this.ctx.tender;
             if (this._ledgerReadOnly(tender.data)) {

+ 74 - 6
app/controller/stage_controller.js

@@ -11,7 +11,8 @@
 const moment = require('moment');
 const auditConst = require('../const/audit');
 const spreadConst = require('../const/spread');
-const measureType = require('../const/tender').measureType;
+const tenderConst = require('../const/tender');
+const measureType = tenderConst.measureType;
 
 module.exports = app => {
     class StageController extends app.BaseController {
@@ -70,18 +71,13 @@ module.exports = app => {
                     col.formatter = formatter;
                 }
             }
-            const qtyFormatter = this.ctx.helper.getNumberFormatter(this.ctx.tender.info.decimal.qty);
             const tpFormatter = this.ctx.helper.getNumberFormatter(this.ctx.tender.info.decimal.tp);
             const upFormatter = this.ctx.helper.getNumberFormatter(2);
             const ledger = JSON.parse(JSON.stringify(spreadConst.stage.ledger));
-            setColFormat(ledger.cols, 'quantity', qtyFormatter);
-            setColFormat(ledger.cols, 'qty', qtyFormatter);
             setColFormat(ledger.cols, 'unit_price', upFormatter);
             setColFormat(ledger.cols, 'total_price', tpFormatter);
             setColFormat(ledger.cols, 'tp', tpFormatter);
             const pos = JSON.parse(JSON.stringify(spreadConst.stage.pos));
-            setColFormat(pos.cols, 'quantity', qtyFormatter);
-            setColFormat(pos.cols, 'qty', qtyFormatter);
             const tender = this.ctx.tender, stage = this.ctx.stage;
             if (this._stageReadOnly(stage)) {
                 ledger.readOnly = true;
@@ -199,6 +195,8 @@ module.exports = app => {
             try {
                 await this._getStage(ctx);
                 const renderData = this._getDefaultRenderData(ctx);
+                renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.detail);
+                renderData.imType = tenderConst.imType;
                 await this.layout('stage/detail.ejs', renderData, 'stage/detail_modal.ejs');
             } catch (err) {
                 this.log(err);
@@ -207,6 +205,76 @@ module.exports = app => {
         }
 
         /**
+         * 设置中间计量生成规则,并生成中间计量数据
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async buildDetailData (ctx) {
+            try {
+                await this._getStage(ctx);
+                // 检查登录用户,是否可操作
+                if (ctx.session.sessionUser.accountId === ctx.stage.user_id) {
+                    if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) {
+                        throw '该计量期当前您无权操作';
+                    }
+                }
+
+                const data = JSON.parse(ctx.request.body.data);
+                await ctx.service.stage.buildDetailData(ctx.tender.id, ctx.stage.order, data);
+
+                ctx.redirect('/tender/'+ ctx.tender.id + '/measure/stage/' + ctx.stage.order + '/detail');
+            } catch (err) {
+                this.log(err);
+                ctx.body = {err: 1, msg: err.toString(), data: null};
+            }
+        }
+
+        /**
+         * 加载数据
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async loadDetailRelaData(ctx) {
+            try {
+                await this._getStage(ctx);
+                const data = JSON.parse(ctx.request.body.data);
+                // 加载台账数据
+                if (data.loadType === 'ledger') {
+                    const ledgerData = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1);
+                    ctx.body = {err: 0, msg: '', data: ledgerData };
+                }
+            } catch (err) {
+                this.log(err);
+                ctx.body = {err: 1, msg: err.toString(), data: null};
+            }
+        }
+
+        /**
+         * 中间计量,生成规则,高级设置
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async setAdvancedConfig(ctx) {
+            try {
+                await this._getStage(ctx);
+                // 检查登录用户,是否可操作
+                if (ctx.session.sessionUser.accountId === ctx.stage.user_id) {
+                    if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) {
+                        throw '该计量期当前您无权操作';
+                    }
+                }
+
+                const data = JSON.parse(ctx.request.body.data);
+                await ctx.service.stage.update(data, { id: ctx.stage.id });
+
+                ctx.body = {err: 0, msg: '', data: this.ctx.stage};
+            } catch (err) {
+                this.log(err);
+                ctx.body = {err: 1, msg: err.toString(), data: null};
+            }
+        }
+
+        /**
          * 合同支付
          * @param ctx
          * @returns {Promise<void>}

+ 46 - 1
app/extend/helper.js

@@ -10,6 +10,7 @@
 const zeroRange = 0.0000000001;
 const fs = require('fs');
 const streamToArray = require('stream-to-array');
+const _ = require('lodash');
 module.exports = {
 
     /**
@@ -368,5 +369,49 @@ module.exports = {
             pre += "#"
         }
         return pre;
-    }
+    },
+
+    /**
+     * 根据单位查找对应的清单精度
+     * @param {tenderInfo.precision} list - 清单精度列表
+     * @param {String} unit - 单位
+     * @returns {number}
+     */
+    findPrecision(list, unit) {
+        if (unit) {
+            for (const p in list) {
+                if (list[p].unit && list[p].unit === unit) {
+                    return list[p];
+                }
+            }
+        }
+        return list.other;
+    },
+
+    /**
+     * 检查数据中的精度
+     * @param {Object} Obj - 检查的数据
+     * @param {Array} fields - 检查的属性
+     * @param {Number} precision - 精度
+     * @constructor
+     */
+    checkFieldPrecision(Obj, fields, precision) {
+        if (Obj) {
+            for (const field of fields) {
+                if (Obj[field]) {
+                    Obj[field] = this.round(Obj[field], precision);
+                }
+            }
+        }
+    },
+
+    /**
+     * 四舍五入(统一,方便以后万一需要置换)
+     * @param {Number} value - 舍入的数字
+     * @param {Number} decimal - 要保留的小数位数
+     * @returns {*}
+     */
+    round(value, decimal) {
+        return _.round(value, decimal);
+    },
 };

文件差异内容过多而无法显示
+ 2 - 2
app/public/css/bootstrap/bootstrap.min.css


二进制
app/public/images/example/jiliangmoshi.png


+ 13 - 0
app/public/js/cookies.js

@@ -24,4 +24,17 @@ let Cookies = {
         // 截取字符串返回
         return decodeURI(document.cookie.substring(start, end));
     },
+    set: function (name, value, time) {
+        const exDate = new Date();
+        exDate.setTime(exDate.getTime() + time * 1);
+        document.cookie = name + "=" + encodeURI(value) + ";expires=" + exDate.toGMTString();
+    },
+    del: function (name) {
+        const exDate = new Date();
+        exDate.setTime(exDate.getTime() - 1);
+        const cVal = this.get(name);
+        if (cVal != null) {
+            document.cookie = name + "=" + cVal + ";expires=" + exDate.toGMTString();
+        }
+    }
 };

+ 4 - 2
app/public/js/ledger.js

@@ -610,7 +610,7 @@ $(document).ready(function() {
                     toast('父节点不可插入部位明细', 'error');
                     info.cancel = true;
                     return;
-                } else if (info.editingText !== '' && node.code || node.code !== '') {
+                } else if (info.editingText !== '' && node.code && node.code !== '') {
                     toast('项目节不可插入部位明细', 'error');
                     info.cancel = true;
                     return;
@@ -629,7 +629,7 @@ $(document).ready(function() {
                     } else if (!position) {
                         if (info.editingText !== '') {
                             data.updateType = 'add';
-                            data.updateData = {name: info.editingText, lid: node.id, tid: tender.id};
+                            data.updateData = { name: info.editingText, lid: node.id, tid: tender.id };
                         } else {
                             return;
                         }
@@ -646,6 +646,7 @@ $(document).ready(function() {
                 }
                 postData('/tender/' + getTenderId() + '/pos/update', data, function (result) {
                     pos.updateDatas(result.pos);
+                    posOperationObj.loadCurPosData();
                     ledgerTree.loadPostData(result.ledger, function (loadResult) {
                         treeOperationObj.refreshTree(ledgerSpread.getActiveSheet(), loadResult);
                     });
@@ -773,6 +774,7 @@ $(document).ready(function() {
                 }
                 postData('/tender/' + getTenderId() + '/pos/update', data, function (result) {
                     pos.updateDatas(result.pos);
+                    posOperationObj.loadCurPosData();
                     ledgerTree.loadPostData(result.ledger, function (loadResult) {
                         treeOperationObj.refreshTree(ledgerSpread.getActiveSheet(), loadResult);
                     });

+ 38 - 1
app/public/js/spreadjs_rela/spreadjs_zh.js

@@ -24,6 +24,8 @@ const SpreadJsObj = {
         spread.options.cutCopyIndicatorVisible = false;
         spread.options.allowCopyPasteExcelStyle = false;
         spread.options.allowUserDragDrop = false;
+        spread.options.allowUserEditFormula = false;
+        spread.getActiveSheet().options.clipBoardOptions = GC.Spread.Sheets.ClipboardPasteOptions.values;//设置粘贴时只粘贴值
         spread.getActiveSheet().setRowCount(3);
         return spread;
     },
@@ -169,12 +171,15 @@ const SpreadJsObj = {
             const colSpan = col.colSpan ? col.colSpan.split('|'): ['1'], rowSpan = col.rowSpan ? col.rowSpan.split('|'): ['1'];
             for (let i = 0; i < title.length; i++) {
                 const cell = sheet.getCell(i, iCol, spreadNS.SheetArea.colHeader);
-                cell.text(title[i]);
+                cell.text(title[i]).wordWrap(true);
                 if ((colSpan[i] !== '' && colSpan[i] !== '1') || (rowSpan[i] !== '' && rowSpan[i] !== '1')) {
                     sheet.addSpan(i, iCol, parseInt(rowSpan[i]), parseInt(colSpan[i]), spreadNS.SheetArea.colHeader);
                 }
             }
             sheet.setColumnWidth(iCol, col.width);
+            if (col.visible !== undefined && col.visible !== null) {
+                sheet.setColumnVisible(iCol, col.visible);
+            }
         }
         sheet.rowOutlines.direction(spreadNS.Outlines.OutlineDirection.backward);
         sheet.showRowOutline(false);
@@ -237,6 +242,11 @@ const SpreadJsObj = {
                         sheet.extendCellType.tip = self.CellType.getTipCellType();
                     }
                     sheet.getRange(-1, j, -1, 1).cellType(sheet.extendCellType.tip);
+                } else if (col.cellType === 'checkbox') {
+                    if (!sheet.extendCellType.checkbox) {
+                        sheet.extendCellType.checkbox = new spreadNS.CellTypes.CheckBox();
+                    }
+                    sheet.getRange(-1, j, -1, 1).cellType(sheet.extendCellType.checkbox);
                 }
                 if (col.formatter) {
                     sheet.getRange(-1, j, -1, 1).formatter(col.formatter);
@@ -436,6 +446,33 @@ const SpreadJsObj = {
             }
         }
     },
+    /**
+     * 刷新列显示
+     * @param sheet
+     */
+    refreshColumnVisible: function (sheet) {
+        if(sheet.zh_setting) {
+            sheet.zh_setting.cols.forEach(function (col, index) {
+                if (col.visible !== undefined && col.visible !== null) {
+                    sheet.setColumnVisible(index, col.visible);
+                }
+            });
+        }
+    },
+    resetFieldReadOnly: function (sheet, field, readonly) {
+        const fields = field instanceof Array ? field : [field];
+        if (sheet.zh_setting) {
+            sheet.zh_setting.cols.forEach(function (col, i) {
+                if (fields.indexOf(col.field) !== -1) {
+                    col.readOnly = readonly;
+                    sheet.getRange(-1, i, -1, 1).locked(col.readOnly || sheet.zh_setting.readOnly || false);
+                    console.log(sheet.getCell(1, 0).locked());
+                    console.log(sheet.getCell(1, 0).text());
+                    console.log(sheet.getCell(1, 1).text());
+                }
+            });
+        }
+    },
 
     CellType: {
         /**

+ 65 - 0
app/public/js/stage.js

@@ -11,10 +11,48 @@ function checkTzMeasureType () {
     return tender.measure_type === measureType.tz.value;
 }
 
+/**
+ * 从cookie中读取缓存的列显示设置,没有则取默认
+ * @returns {*[]}
+ */
+function customColDisplay () {
+    const defaultSetting = [
+        { title: '签约合同', fields: ['deal_qty', 'deal_tp'], visible: true },
+        { title: '施工图复核', fields: ['quantity', 'total_price'], visible: true },
+        { title: '本期计量合同', fields: ['contract_qty', 'contract_tp'], visible: true },
+        { title: '本期数量变更', fields: ['qc_qty', 'qc_tp', 'qc_bgl'], visible: true },
+        { title: '本期完成计量', fields: ['gather_qty', 'gather_tp'], visible: true },
+        { title: '截止本期计量合同', fields: ['end_contract_qty', 'end_contract_tp'], visible: true },
+        { title: '截止本期数量变更', fields: ['end_qc_qty', 'end_qc_tp', 'end_qc_bgl'], visible: true },
+        { title: '截止本期完成计量', fields: ['end_gather_qty', 'end_gather_tp'], visible: true },
+        { title: '图册号', fields: ['drawing_code'], visible: true },
+        { title: '累计完成率(%)', fields: ['percent'], visible: true },
+        { title: '备注', fields: ['memo'], visible: true },
+    ];
+    const settingStr = Cookies.get('stage-col-visible');
+    return settingStr ? JSON.parse(settingStr) : defaultSetting;
+}
+
+/**
+ * 根据列显示设置,调整setting中的列是否显示
+ * @param setting
+ * @param customDisplay
+ */
+function customizeStageTreeSetting(setting, customDisplay) {
+    for (const cd of customDisplay) {
+        for (const c of setting.cols) {
+            if (cd.fields.indexOf(c.field) !== -1) {
+                c.visible = cd.visible;
+            }
+        }
+    }
+}
+
 $(document).ready(() => {
     autoFlashHeight();
     // 初始化 台账 spread
     const slSpread = SpreadJsObj.createNewSpread($('#stage-ledger')[0]);
+    customizeStageTreeSetting(ledgerSpreadSetting, customColDisplay());
     SpreadJsObj.initSheet(slSpread.getActiveSheet(), ledgerSpreadSetting);
     const stageTreeSetting = {
         id: 'ledger_id',
@@ -434,4 +472,31 @@ $(document).ready(() => {
     spSpread.bind(spreadNS.Events.ClipboardPasting, stagePosSpreadObj.clipboardPasting);
     spSpread.bind(spreadNS.Events.ClipboardPasted, stagePosSpreadObj.clipboardPasted);
     SpreadJsObj.addDeleteBind(spSpread, stagePosSpreadObj.deletePress);
+
+    $('#row-view').on('show.bs.modal', function () {
+        const html = [], customDisplay = customColDisplay();
+        for (const cd of customDisplay) {
+            html.push('<tr>');
+            html.push('<td>', cd.title, '</td>');
+            html.push('<td>', '<input type="checkbox"' + (cd.visible ? ' checked=""' : '') + '>', '</td>');
+            html.push('</tr>');
+        }
+        $('#row-view-list').html(html.join(''));
+    });
+    $('#row-view-ok').click(function () {
+        const customDisplay = customColDisplay();
+        const cvl = $('#row-view-list').children();
+        for (const cv of cvl) {
+            const title = $(cv).children()[0].innerHTML;
+            const check = $('input', cv)[0].checked;
+            const cd = customDisplay.find(function (c) {
+                return c.title === title;
+            });
+            cd.visible = check;
+        }
+        customizeStageTreeSetting(ledgerSpreadSetting, customDisplay);
+        SpreadJsObj.refreshColumnVisible(slSpread.getActiveSheet());
+        Cookies.set('stage-col-visible', JSON.stringify(customDisplay), 7*24*60*60*1000);
+        $('#row-view').modal('hide');
+    });
 });

+ 219 - 0
app/public/js/stage_detail.js

@@ -0,0 +1,219 @@
+'use strict';
+
+/**
+ * 期 - 中间计量
+ *
+ * @author Mai
+ * @date 2019/1/16
+ * @version
+ */
+
+$(document).ready(() => {
+    let gsSpread, gsTree;
+
+    let gatherComfirmPopover = {
+        reBind: function (obj, eventName, fun) {
+            obj.unbind(eventName);
+            obj.bind(eventName, fun);
+        },
+        check: function (pos, hint, okCallback) {
+            const comfirmObj = $('#gather-confirm'), hintObj = $('#gather-confirm-hint');
+            const okObj = $('#gather-confirm-ok'), cancelObj = $('#gather-confirm-cancel');
+            this.reBind(cancelObj, 'click', function () {
+                comfirmObj.hide();
+            });
+            this.reBind(okObj, 'click', function () {
+                okCallback();
+                comfirmObj.hide();
+            });
+            hintObj.text(hint);
+            comfirmObj.css("top", pos.y).css("left", pos.x).show();
+        }
+    };
+
+    // 选择中间计量模式
+    $('div[name="im-type"]').click(function () {
+        function chooseType(obj) {
+            obj.style.cursor = 'default';
+            $(obj).children().addClass('text-primary');
+            $('h5', obj).prepend('<i class="fa fa-check pull-right"></i>');
+        }
+        function validType(obj) {
+            obj.style.cursor = 'pointer';
+            $(obj).children().removeClass('text-primary');
+            $('i', obj).remove();
+        }
+        if (this.style.cursor === 'pointer') {
+            const typeArr = $('div[name="im-type"]');
+            for (const t of typeArr) {
+                if ($(t).attr('im-type') === $(this).attr('im-type')) {
+                    chooseType(t);
+                } else {
+                    validType(t)
+                }
+            }
+        }
+    });
+    // 提交 中间计量模式
+    $('#choose-ok').click(() => {
+        const chooseType = _.find($('div[name="im-type"]', '#im-type'), function (it) {
+            return it.style.cursor !== 'pointer';
+        });
+        const data = {
+            im_type: parseInt($(chooseType).attr('im-type')),
+            im_pre: $('#im-pre').val(),
+        };
+        postData(window.location.pathname + '/build', data, function (result) {
+            stage.im_type = data.im_type;
+            stage.im_pre = data.im_pre;
+            $('#choose').modal('hide');
+            // 加载生成数据
+        });
+    });
+    // 拉取树结构信息
+    $('#choose2').on('shown.bs.modal', function () {
+        if (!gsSpread) {
+            gsSpread = SpreadJsObj.createNewSpread($('#im-gather-spread')[0]);
+            SpreadJsObj.initSheet(gsSpread.getActiveSheet(), {
+                cols: [
+                    {title: '计量\n汇总', colSpan: '1', rowSpan: '1', field: 'check', hAlign: 1, width: 50, formatter: '@', readOnly: true, cellType: 'checkbox'},
+                    {title: '项目节编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 150, formatter: '@', readOnly: true, cellType: 'tree'},
+                    {title: '清单编号', colSpan: '1', rowSpan: '1', field: 'b_code', hAlign: 0, width: 80, formatter: '@', readOnly: true},
+                    {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@', readOnly: true},
+                    {title: '单位', colSpan: '1', rowSpan: '1', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: true},
+                ],
+                headRows: 1,
+                emptyRows: 0,
+                headRowHeight: [40],
+                defaultRowHeight: 21,
+            });
+            gsSpread.bind(spreadNS.Events.ButtonClicked, function (e, info) {
+                function checkParent(node) {
+                    const parent = gsTree.getParent(node);
+                    if (parent) {
+                        return parent.check ? parent.check : checkParent(parent);
+                    } else {
+                        return false;
+                    }
+                }
+
+                function checkChildren(node) {
+                    for (const child of node.children) {
+                        if (child.check) {
+                            return true;
+                        } else if (checkChildren(child)) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+
+                if (!$('#im-gather-check')[0].checked) { return; }
+
+                const sheet = info.sheet, cellType = sheet.getCellType(info.row, info.col);
+                if (cellType instanceof GC.Spread.Sheets.CellTypes.CheckBox) {
+                    if (sheet.isEditing()) {
+                        sheet.endEdit(true);
+                    }
+                }
+
+                if (info.sheet.zh_setting) {
+                    const col = info.sheet.zh_setting.cols[info.col];
+                    if (col.field !== 'check') {
+                        return;
+                    }
+
+                    const sortData = info.sheet.zh_dataType === 'tree' ? info.sheet.zh_tree.nodes : info.sheet.zh_data;
+                    const node = sortData[info.row];
+                    if (!node.check) {
+                        if (checkParent(node)) {
+                            const rect = info.sheet.getCellRect(info.row, info.col);
+                            gatherComfirmPopover.check({
+                                x: rect.x + rect.width / 2 + 25,
+                                y: rect.y + rect.height / 2 + 3,
+                            }, '父项已勾选,继续将取消父项勾选。', function () {
+                                node.check = true;
+                                const parents = gsTree.getFullPathNodes(gsTree.getParent(node).full_path);
+                                const rows = [gsTree.nodes.indexOf(node)];
+                                for (const p of parents) {
+                                    if (p.check) {
+                                        p.check = false;
+                                        rows.push(gsTree.nodes.indexOf(p));
+                                    }
+                                }
+                                SpreadJsObj.reLoadRowsData(info.sheet, rows);
+                            });
+                        } else if (checkChildren(node)) {
+                            const rect = info.sheet.getCellRect(info.row, info.col);
+                            gatherComfirmPopover.check({
+                                x: rect.x + rect.width / 2 + 25,
+                                y: rect.y + rect.height / 2 + 3,
+                            }, '子项已勾选,继续将取消子项勾选。', function () {
+                                node.check = true;
+                                const posterity = gsTree.getPosterity(node);
+                                const rows = [gsTree.nodes.indexOf(node)];
+                                for (const p of posterity) {
+                                    if (p.check) {
+                                        rows.push(gsTree.nodes.indexOf(p));
+                                        p.check = false;
+                                    }
+                                }
+                                SpreadJsObj.reLoadRowsData(info.sheet, rows);
+                            });
+                        } else {
+                            node.check = true;
+                            SpreadJsObj.reLoadRowsData(info.sheet, [gsTree.nodes.indexOf(node)]);
+                        }
+                    } else {
+                        node.check = false;
+                        SpreadJsObj.reLoadRowsData(info.sheet, [gsTree.nodes.indexOf(node)]);
+                    }
+                }
+            });
+        }
+        if (!gsTree) {
+            postData(window.location.pathname + '/load', { loadType: 'ledger' }, function (data) {
+                gsTree = createNewPathTree('base', {
+                    id: 'ledger_id',
+                    pid: 'ledger_pid',
+                    order: 'order',
+                    level: 'level',
+                    rootId: -1,
+                    keys: ['id', 'tender_id', 'ledger_id'],
+                });
+                const gatherNodes = stage.im_gather_node ? _.map(stage.im_gather_node.split(','), _.toNumber) : [];
+                for (const node of data) {
+                    node.check = gatherNodes.indexOf(node.id) !== -1;
+                }
+                gsTree.loadDatas(data);
+                SpreadJsObj.loadSheetData(gsSpread.getActiveSheet(), 'tree', gsTree);
+                SpreadJsObj.resetFieldReadOnly(gsSpread.getActiveSheet, 'check', !$('#im-gather-check')[0].checked);
+            });
+        } else {
+            const gatherNodes = stage.im_gather_node ? _.map(stage.im_gather_node.split(','), _.toNumber) : [];
+            for (const node of gsTree.datas) {
+                node.check = gatherNodes.indexOf(node.id) !== -1;
+            }
+            SpreadJsObj.resetFieldReadOnly(gsSpread.getActiveSheet(), 'check', !$('#im-gather-check')[0].checked);
+        }
+    });
+    // 提交 高级设置
+    $('#choose2-ok').click(() => {
+        if (!gsTree) { return; }
+        const nodes = [];
+        for (const node of gsTree.datas) {
+            if (node.check) {
+                nodes.push(node.id);
+            }
+        }
+        const data = {
+            im_gather: $('#im-gather-check')[0].checked,
+            im_gather_node: nodes.join(','),
+        };
+        postData(window.location.pathname + '/adv', data, function (result) {
+            stage.im_gather = data.im_gather;
+            stage.im_gather_node = data.im_gather_node;
+            $('#choose2').modal('hide');
+        });
+    });
+});

+ 136 - 55
app/public/js/tender.js

@@ -61,19 +61,32 @@ function loadCommonProperty () {
     $('#start-date').val(property.tech_param.startDate);
     $('#plan-end-date').val(property.tech_param.planEndDate);
 }
-// 计算参
+// 小数位
 function loadCalculateProperty () {
-    // 小数位数
-    $('#decimal-qty').val(property.decimal.qty);
+    $('#decimal-up').val(property.decimal.up);
     $('#decimal-tp').val(property.decimal.tp);
-    $('#decimal-deal')[0].checked = property.decimal.deal;
-    $('#decimal-deal-qty').val(property.decimal.dealQty);
-    $('#decimal-deal-tp').val(property.decimal.dealTp);
     $('#decimal-pay')[0].checked = property.decimal.pay;
-    $('#decimal-pay-qty').val(property.decimal.payQty);
     $('#decimal-pay-tp').val(property.decimal.payTp);
-
-    // 合同参数
+}
+// 清单精度
+function loadPrecisionProperty () {
+    $('#unit-t').val(property.precision.t.value);
+    $('#unit-km').val(property.precision.km.value);
+    $('#unit-m').val(property.precision.m.value);
+    $('#unit-m2').val(property.precision.m2.value);
+    $('#unit-m3').val(property.precision.m3.value);
+    $('#unit-kg').val(property.precision.kg.value);
+    $('#unit-ge').val(property.precision.ge.value);
+    $('#unit-tai').val(property.precision.tai.value);
+    $('#unit-tao').val(property.precision.tao.value);
+    $('#unit-ke').val(property.precision.ke.value);
+    $('#unit-zu').val(property.precision.zu.value);
+    $('#unit-zonge').val(property.precision.zonge.value);
+    $('#unit-xitong').val(property.precision.xitong.value);
+    $('#unit-other').val(property.precision.other.value);
+}
+// 合同参数
+function loadDealProperty () {
     $('#contract-price').val(property.deal_param.contractPrice);
     $('#zan-lie-price').val(property.deal_param.zanLiePrice);
     $('#c-zl').val(property.deal_param.contractPrice - property.deal_param.zanLiePrice);
@@ -101,6 +114,8 @@ function loadTenderProperty() {
     // 加载属性
     loadCommonProperty();
     loadCalculateProperty();
+    loadPrecisionProperty();
+    loadDealProperty();
     loadDisplayProperty();
     // 设置只读
     setReadOnly('#shuxing', true);
@@ -138,20 +153,20 @@ $(document).ready(function() {
      * 属性
      */
     // 编辑
-    $('#edit-agi').click(() => {
-        setReadOnly('#v-pills-agi', false);
-        $('#post-agi').parent().show();
-        $('#edit-agi').parent().hide();
+    $('#edit-1').click(() => {
+        setReadOnly('#v-pills-1', false);
+        $('#post-1').parent().show();
+        $('#edit-1').parent().hide();
     });
     // 取消
-    $('#cancel-agi').click(() => {
-        setReadOnly('#v-pills-agi', true);
+    $('#cancel-1').click(() => {
+        setReadOnly('#v-pills-1', true);
         loadCommonProperty();
-        $('#post-agi').parent().hide();
-        $('#edit-agi').parent().show();
+        $('#post-1').parent().hide();
+        $('#edit-1').parent().show();
     });
     // 提交
-    $('#post-agi').click(() => {
+    $('#post-1').click(() => {
         const prop = {
             deal_info: {
                 buildName: $('#build-name').val(),
@@ -199,12 +214,12 @@ $(document).ready(function() {
         const tenderId = window.location.pathname.split('/')[2];
         console.log(prop);
         postData('/tender/' + tenderId + '/save', prop, function (data) {
-            setReadOnly('#v-pills-agi', true);
+            setReadOnly('#v-pills-1', true);
             property.deal_info = data.deal_info;
             property.construction_unit = data.construction_unit;
             property.tech_param = data.tech_param;
-            $('#post-agi').parent().hide();
-            $('#edit-agi').parent().show();
+            $('#post-1').parent().hide();
+            $('#edit-1').parent().show();
         });
     });
 
@@ -212,31 +227,99 @@ $(document).ready(function() {
      * 计算参数
       */
     // 编辑
-    $('#edit-count').click(() => {
-        setReadOnly('#v-pills-count', false);
-        $('#post-count').parent().show();
-        $('#edit-count').parent().hide();
+    $('#edit-2').click(() => {
+        setReadOnly('#v-pills-2', false);
+        $('#post-2').parent().show();
+        $('#edit-2').parent().hide();
     });
     // 取消
-    $('#cancel-count').click(() => {
-        setReadOnly('#v-pills-count', true);
-        loadCommonProperty();
-        $('#post-count').parent().hide();
-        $('#edit-count').parent().show();
+    $('#cancel-2').click(() => {
+        setReadOnly('#v-pills-2', true);
+        loadCalculateProperty();
+        $('#post-2').parent().hide();
+        $('#edit-2').parent().show();
     });
     // 提交
-    $('#post-count').click(() => {
+    $('#post-2').click(() => {
         const prop = {
             decimal: {
-                qty: _.toNumber($('#decimal-qty').val()),
+                up: _.toNumber($('#decimal-up').val()),
                 tp: _.toNumber($('#decimal-tp').val()),
-                deal: $('#decimal-deal')[0].checked,
-                dealQty: _.toNumber($('#decimal-deal-qty').val()),
-                dealTp: _.toNumber($('#decimal-deal-tp').val()),
                 pay: $('#decimal-pay')[0].checked,
-                payQty: _.toNumber($('#decimal-pay-qty').val()),
                 payTp: _.toNumber($('#decimal-pay-tp').val()),
-            },
+            }
+        };
+        const tenderId = window.location.pathname.split('/')[2];
+        console.log(prop);
+        postData('/tender/' + tenderId + '/save', prop, function (data) {
+            setReadOnly('#v-pills-2', true);
+            property.decimal = data.decimal;
+            $('#post-2').parent().hide();
+            $('#edit-2').parent().show();
+        });
+    });
+
+    /**
+     * 清单精度
+     */
+    // 编辑
+    $('#edit-3').click(() => {
+        setReadOnly('#v-pills-3', false);
+        $('#post-3').parent().show();
+        $('#edit-3').parent().hide();
+    });
+    // 取消
+    $('#cancel-3').click(() => {
+        setReadOnly('#v-pills-3', true);
+        loadPrecisionProperty();
+        $('#post-3').parent().hide();
+        $('#edit-3').parent().show();
+    });
+    // 提交
+    $('#post-3').click(() => {
+        const prop = { precision: JSON.parse(JSON.stringify(property.precision)) };
+        prop.precision.t.value = _.toNumber($('#unit-t').val());
+        prop.precision.km.value = _.toNumber($('#unit-km').val());
+        prop.precision.m.value = _.toNumber($('#unit-m').val());
+        prop.precision.m2.value = _.toNumber($('#unit-m2').val());
+        prop.precision.m3.value = _.toNumber($('#unit-m3').val());
+        prop.precision.kg.value = _.toNumber($('#unit-kg').val());
+        prop.precision.ge.value = _.toNumber($('#unit-ge').val());
+        prop.precision.tai.value = _.toNumber($('#unit-tai').val());
+        prop.precision.tao.value = _.toNumber($('#unit-tao').val());
+        prop.precision.ke.value = _.toNumber($('#unit-ke').val());
+        prop.precision.zu.value = _.toNumber($('#unit-zu').val());
+        prop.precision.zonge.value = _.toNumber($('#unit-zonge').val());
+        prop.precision.xitong.value = _.toNumber($('#unit-xitong').val());
+        prop.precision.other.value = _.toNumber($('#unit-other').val());
+        const tenderId = window.location.pathname.split('/')[2];
+        postData('/tender/' + tenderId + '/save', prop, function (data) {
+            setReadOnly('#v-pills-count', true);
+            property.precision = data.precision;
+            $('#post-3').parent().hide();
+            $('#edit-3').parent().show();
+        });
+    });
+
+    /**
+     * 合同参数
+     */
+    // 编辑
+    $('#edit-4').click(() => {
+        setReadOnly('#v-pills-4', false);
+        $('#post-4').parent().show();
+        $('#edit-4').parent().hide();
+    });
+    // 取消
+    $('#cancel-4').click(() => {
+        setReadOnly('#v-pills-4', true);
+        loadDealProperty();
+        $('#post-4').parent().hide();
+        $('#edit-4').parent().show();
+    });
+    // 提交
+    $('#post-4').click(() => {
+        const prop = {
             deal_param: {
                 contractPrice: _.toNumber($('#contract-price').val()),
                 zanLiePrice: _.toNumber($('#zan-lie-price').val()),
@@ -245,13 +328,11 @@ $(document).ready(function() {
             }
         };
         const tenderId = window.location.pathname.split('/')[2];
-        console.log(prop);
         postData('/tender/' + tenderId + '/save', prop, function (data) {
-            setReadOnly('#v-pills-count', true);
-            property.decimal = data.decimal;
+            setReadOnly('#v-pills-4', true);
             property.deal_param = data.deal_param;
-            $('#post-count').parent().hide();
-            $('#edit-count').parent().show();
+            $('#post-4').parent().hide();
+            $('#edit-4').parent().show();
         });
     });
 
@@ -259,20 +340,20 @@ $(document).ready(function() {
      * 显示设置
      */
     // 编辑
-    $('#edit-display').click(() => {
-        setReadOnly('#v-pills-display', false);
-        $('#post-display').parent().show();
-        $('#edit-display').parent().hide();
+    $('#edit-5').click(() => {
+        setReadOnly('#v-pills-5', false);
+        $('#post-5').parent().show();
+        $('#edit-5').parent().hide();
     });
     // 取消
-    $('#cancel-display').click(() => {
-        setReadOnly('#v-pills-display', true);
-        loadCommonProperty();
-        $('#post-display').parent().hide();
-        $('#edit-display').parent().show();
+    $('#cancel-5').click(() => {
+        setReadOnly('#v-pills-5', true);
+        loadDisplayProperty();
+        $('#post-5').parent().hide();
+        $('#edit-5').parent().show();
     });
     // 提交
-    $('#post-display').click(() => {
+    $('#post-5').click(() => {
         const prop = {
             display: {
                 ledger: { dgnQty: $('#ledger-dgn-qty')[0].checked, },
@@ -281,10 +362,10 @@ $(document).ready(function() {
         const tenderId = window.location.pathname.split('/')[2];
         console.log(prop);
         postData('/tender/' + tenderId + '/save', prop, function (data) {
-            setReadOnly('#v-pills-display', true);
+            setReadOnly('#v-pills-5', true);
             property.display = data.display;
-            $('#post-display').parent().hide();
-            $('#edit-display').parent().show();
+            $('#post-5').parent().hide();
+            $('#edit-5').parent().show();
         });
     });
 

+ 3 - 0
app/router.js

@@ -115,6 +115,9 @@ module.exports = app => {
     app.post('/tender/:id/measure/stage/:order/update', sessionAuth, tenderCheck, 'stageController.updateStageData');
     // 中间计量
     app.get('/tender/:id/measure/stage/:order/detail', sessionAuth, tenderCheck, 'stageController.detail');
+    app.post('/tender/:id/measure/stage/:order/detail/build', sessionAuth, tenderCheck, 'stageController.buildDetailData');
+    app.post('/tender/:id/measure/stage/:order/detail/adv', sessionAuth, tenderCheck, 'stageController.setAdvancedConfig');
+    app.post('/tender/:id/measure/stage/:order/detail/load', sessionAuth, tenderCheck, 'stageController.loadDetailRelaData');
     // 合同支付
     app.get('/tender/:id/measure/stage/:order/pay', sessionAuth, tenderCheck, 'stageController.pay');
     // 变更令

+ 9 - 0
app/service/ledger.js

@@ -23,6 +23,7 @@ const keyFields = {
 // 以下字段仅可通过树结构操作改变,不可直接通过update方式从接口提交,发现时过滤
 const readOnlyFields = ['id', 'tender_id', 'ledger_id', 'ledger_pid', 'order', 'level', 'full_path', 'is_leaf'];
 const calcFields = ['quantity', 'unit_price', 'total_price', 'deal_qty', 'deal_tp'];
+const qtyFields = ['quantity', 'deal_qty', 'dgn_qty1', 'dgn_qty2'];
 const zeroRange = 0.0000000001;
 const rootId = -1;
 const keyPre = 'tender_node_maxId:';
@@ -1517,6 +1518,8 @@ module.exports = app => {
                     let updateData;
                     if (this._checkCalcField(row)) {
                         const calcData = this.ctx.helper.updateObj(updateNode, row);
+                        const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, updateNode.unit);
+                        this.ctx.helper.checkFieldPrecision(calcData, qtyFields, precision.value);
                         if (updateNode.is_leaf) {
                             calcData.total_price = calcData.quantity * calcData.unit_price;
                             calcData.deal_tp = calcData.deal_qty * calcData.unit_price;
@@ -1646,6 +1649,8 @@ module.exports = app => {
                         unit_price: data[i].price,
                     };
                     qd.full_path = selectData.full_path + '.' + qd.ledger_id;
+                    const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, qd.unit);
+                    this.ctx.helper.checkPrecision(qd, qtyFields, precision.value);
                     const insertResult = await this.transaction.insert(this.tableName, qd);
                     newIds.push(insertResult.insertId);
                     await this.ctx.service.pos.insertLedgerPosData(this.transaction, tenderId, insertResult.insertId, data[i].pos);
@@ -1713,6 +1718,8 @@ module.exports = app => {
                         unit_price: data[i].price,
                     };
                     qd.full_path = parentData.full_path + '.' + qd.ledger_id;
+                    const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, qd.unit);
+                    this.ctx.helper.checkPrecision(qd, qtyFields, precision.value);
                     const insertResult = await this.transaction.insert(this.tableName, qd);
                     newIds.push(insertResult.insertId);
                     await this.ctx.service.pos.insertLedgerPosData(this.transaction, tenderId, insertResult.insertId, data[i].pos);
@@ -1789,6 +1796,8 @@ module.exports = app => {
                 memo: node.memo,
                 drawing_code: node.drawing_code,
             };
+            const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, data.unit);
+            this.ctx.helper.checkPrecision(data, qtyFields, precision.value);
             const result = await transaction.insert(this.tableName, data);
             if (node.children && node.children.length > 0) {
                 for (const child of node.children) {

+ 15 - 3
app/service/pos.js

@@ -46,21 +46,29 @@ module.exports = app => {
                     data.updateData.add_stage = 0;
                     data.updateData.add_times = 0;
                     data.updateData.add_user = this.ctx.session.sessionUser.accountId;
+                    if (data.quantity) {
+                        const bills = await this.ctx.service.ledger.getDataById(data.lid);
+                        const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
+                        data.quantity = this._.round(data.quantity, precision.value);
+                    }
                     const addRst = await transaction.insert(this.tableName, data.updateData);
                     data.updateData.id = addRst.insertId;
                 } else if (data.updateType === 'update') {
                     const datas = data.updateData instanceof Array ? data.updateData : [data.updateData];
                     result.ledger.update = [];
                     const orgPos = await this.getPosData({tid: tid, id: this._.map(datas, 'id')});
-                    console.log(datas);
                     for (const d of datas) {
                         const op = this._.find(orgPos, function (p) { return p.id = d.id; });
+                        if (d.quantity) {
+                            const bills = await this.ctx.service.ledger.getDataById(op.lid);
+                            const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
+                            d.quantity = this._.round(d.quantity, precision.value);
+                        }
                         await transaction.update(this.tableName, d, {tid: tid, id: d.id});
                         if (d.quantity && op && (result.ledger.update.indexOf(op.lid) === -1)) {
                             result.ledger.update.push(op.lid);
                         }
                     }
-                    console.log(result.ledger.update);
                     for (const lid of result.ledger.update) {
                         await this.ctx.service.ledger.calc(tid, lid, transaction);
                     }
@@ -127,6 +135,8 @@ module.exports = app => {
          * @returns {Promise<void>}
          */
         async insertLedgerPosData(transaction, tid, lid, data) {
+            const bills = await this.ctx.service.ledger.getDataById(lid);
+            const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
             for (const d of data) {
                 d.tid = tid;
                 d.lid = lid;
@@ -134,10 +144,12 @@ module.exports = app => {
                 d.add_stage = 0;
                 d.add_times = 0;
                 d.add_user = this.ctx.session.sessionUser.accountId;
+                if (d.quantity) {
+                    d.quantity = this._.round(d.quantity, precision.value);
+                }
             }
             await transaction.insert(this.tableName, data);
         }
-
     }
 
     return Pos;

+ 19 - 0
app/service/stage.js

@@ -81,6 +81,25 @@ module.exports = app => {
                 period: period,
             }, { where: { tid: tenderId, order: order } });
         }
+
+        /**
+         * 设置 中间计量 生成规则,并生成数据
+         * @param {Number} tenderId - 标段id
+         * @param {Number} order - 期序号
+         * @param {Number} data - 中间计量生成规则
+         * @returns {Promise<void>}
+         */
+        async buildDetailData(tenderId, order, data) {
+            const conn = await this.db.beginTransaction();
+            try {
+                await conn.update(this.tableName, { im_type: data.im_type, im_pre: data.im_pre }, { where: { tid: tenderId, order: order } });
+                // to do 生成中间计量数据
+                await conn.commit();
+            } catch (err) {
+                await conn.rollback();
+                throw err;
+            }
+        }
     }
 
     return Stage;

+ 10 - 2
app/service/stage_bills.js

@@ -93,12 +93,14 @@ module.exports = app => {
                 order: this.ctx.stage.curAuditor ? this.ctx.stage.curAuditor.order : 0,
                 said: this.ctx.session.sessionUser.accountId,
             };
+
+            const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, updateNode.unit);
             if (insertData.contract_qty) {
-                d.contract_qty = insertData.contract_qty;
+                d.contract_qty = this.round(insertData.contract_qty, precision.value);
                 d.contract_tp = d.contract_qty * ledgerData.unit_price;
             }
             if (insertData.qc_qty) {
-                d.qc_qty = insertData.qc_qty;
+                d.qc_qty = this.round(insertData.qc_qty, precision.value);
                 d.qc_tp = d.qc_qty * ledgerData.unit_price;
             }
             if (insertData.postil) {
@@ -120,10 +122,13 @@ module.exports = app => {
                 for (const d of datas) {
                     const stageBills = await this.getLastestStageData(this.ctx.tender.id, this.ctx.stage.id, d.lid);
                     const ledgerBills = await this.ctx.service.ledger.getDataById(d.lid);
+                    const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, ledgerBills.unit);
                     if (d.contract_qty !== undefined) {
+                        d.contract_qty = this.round(d.contract_qty, precision.value);
                         d.contract_tp = d.contract_qty * ledgerBills.unit_price;
                     }
                     if (d.qc_qty !== undefined) {
+                        d.qc_qty = this.round(d.qc_qty, precision.value);
                         d.qc_tp = d.qc_qty * ledgerBills.unit_price;
                     }
                     console.log(d);
@@ -164,11 +169,14 @@ module.exports = app => {
             console.log(posGather);
             if (!posGather) { return; }
 
+            const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, ledgerBills.unit);
             // 计算
             if (posGather.contract_qty !== undefined) {
+                posGather.contract_qty = this.round(posGather.contract_qty, precision.value);
                 posGather.contract_tp = posGather.contract_qty * ledgerBills.unit_price;
             }
             if (posGather.qc_qty !== undefined) {
+                posGather.qc_qty = this.round(posGather.qc_qty, precision.value);
                 posGather.qc_tp = posGather.qc_qty * ledgerBills.unit_price;
             }
             if (stageBills) {

+ 14 - 2
app/service/stage_pos.js

@@ -21,6 +21,7 @@ module.exports = app => {
         constructor(ctx) {
             super(ctx);
             this.tableName = 'stage_pos';
+            this.qtyFields = ['contract_qty', 'qc_qty']
         }
 
         /**
@@ -86,6 +87,8 @@ module.exports = app => {
          * @private
          */
         async _addStagePosData(transaction, data) {
+            const bills = await this.ctx.service.ledger.getDataById(data.lid);
+            const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
             const  result = {};
             // 在主表pos中新增数据
             const p = JSON.parse(JSON.stringify(data.updateData));
@@ -96,6 +99,9 @@ module.exports = app => {
             if (p.contract_qty) { delete p.contract_qty; }
             if (p.qc_qty) { delete p.qc_qty; }
             if (p.postil) { delete p.postil; }
+            if (p.quantity) {
+                p.quantity = this.round(p.quantity, precision.value);
+            }
             const addRst = await transaction.insert(this.ctx.service.pos.tableName, data.updateData);
             p.id = addRst.insertId;
             result.pos = p.id;
@@ -115,8 +121,8 @@ module.exports = app => {
                     times: this.ctx.stage.times,
                     order: 0,
                 };
-                if (data.contract_qty) { ps.contract_qty = data.contract_qty; }
-                if (data.qc_qty) { ps.qc_qty = data.qc_qty; }
+                if (data.contract_qty) { ps.contract_qty = this.round(data.contract_qty, precision.value); }
+                if (data.qc_qty) { ps.qc_qty = this.round(data.qc_qty, precision.value); }
                 if (data.postil) { ps.postil = data.postil; }
                 await transaction.insert(ps);
                 await this.ctx.service.stageBills.calc(ctx.tender.id, ctx.stage.id, ps.lid, transaction);
@@ -134,12 +140,18 @@ module.exports = app => {
          * @private
          */
         async _updateStagePosData(transaction, data) {
+            let bills, precision;
             const result = {ledger: [], pos: [], stageUpdate: true};
             const datas = data instanceof Array ? data : [data];
             const orgStagePos = await this.getLastestStageData(this.ctx.tender.id, this.ctx.stage.id, this._.map(datas, 'pid'));
             const userOrder = this.ctx.stage.curAuditor ? this.ctx.stage.curAuditor.order : 0;
             for (const d of datas) {
+                if (!bills || bills.id !== data.lid) {
+                    bills = await this.ctx.service.ledger.getDataById(data.lid);
+                    precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
+                }
                 const osp = this._.find(orgStagePos, function (p) { return p.pid === d.pid; });
+                this.ctx.helper.checkFieldPrecision(d, this.qtyFields, precision.value);
                 if (osp && osp.times === this.ctx.stage.times && osp.order === userOrder) {
                     await transaction.update(this.tableName, d, {where: {id: osp.id}});
                 } else {

+ 1 - 1
app/service/tender_info.js

@@ -63,7 +63,7 @@ module.exports = app => {
                 info = await this.addTenderInfo(tenderId, this.ctx.session.sessionProject.id);
             }
             for (const pi of parseInfo) {
-                info[pi] = !info[pi] || info[pi] === '' ? defaultInfo[parseInfo] : JSON.parse(info[pi]);
+                info[pi] = !info[pi] || info[pi] === '' ? defaultInfo[pi] : JSON.parse(info[pi]);
             }
             return info;
         }

+ 5 - 3
app/view/ledger/explode.ejs

@@ -4,11 +4,13 @@
         <div class="title-main  d-flex justify-content-between"><!--工具-->
             <div>
                 <div class="btn-group">
-                    <a href="javascript:void(0)" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title=""
+                    <a href="javascript:void(0)" id="insert" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title=""
+                       data-original-title="插入"><i class="fa fa-sign-in" aria-hidden="true"></i></a>
+                    <a href="javascript:void(0)" id="copy" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title=""
                        data-original-title="复制"><i class="fa fa-files-o" aria-hidden="true"></i></a>
-                    <a href="javascript:void(0)" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title=""
+                    <a href="javascript:void(0)" id="cut" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title=""
                        data-original-title="剪切"><i class="fa fa-scissors" aria-hidden="true"></i></a>
-                    <a href="javascript:void(0)" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title=""
+                    <a href="javascript:void(0)" id="paste" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title=""
                        data-original-title="粘贴"><i class="fa fa-clipboard" aria-hidden="true"></i></a>
                     <a href="javascript:void(0)" id="delete" class="btn btn-sm" data-toggle="tooltip" data-placement="bottom" title=""
                        data-original-title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>

+ 1 - 1
app/view/stage/deal_modal.ejs

@@ -297,7 +297,7 @@
             <div class="modal-body">
                 <div class="form-group">
                     <label for="formGroupExampleInput">大小限制:10MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
-                    <input type="file" class="form-control">
+                    <input type="file" class="form-control-file">
                 </div>
                 <div class="modal-height-500">
                     <table class="table table-sm table-bordered">

+ 10 - 22
app/view/stage/detail.ejs

@@ -3,30 +3,11 @@
     <div class="panel-title">
         <div class="title-main d-flex justify-content-between">
             <div>
-                <div class="d-inline-block ml-3">
-                    <div class="input-group input-group-sm">
-                        <div class="input-group-prepend">
-                            <span class="input-group-text">前缀</span>
-                        </div>
-                        <input type="text" class="form-control m-0">
-                    </div>
-                </div>
-                <div class="d-inline-block ml-3">
+                <div class="d-inline-block">
                     <div class="form-group">
-                        <div class="form-check form-check-inline">
-                            <input class="form-check-input" name="inlineRadioOptions" id="inlineRadio1" value="option1" type="radio">
-                            <label class="form-check-label" for="inlineRadio1">总量控制</label>
-                        </div>
-                        <div class="form-check form-check-inline">
-                            <input class="form-check-input" name="inlineRadioOptions" id="inlineRadio2" value="option2" type="radio">
-                            <label class="form-check-label" for="inlineRadio2">0号台帐</label>
-                        </div>
-                        <button class="btn btn-sm btn-outline-primary">生成数据</button>
+                        <button class="btn btn-sm btn-light text-primary" href="#choose" data-toggle="modal" data-target="#choose">设置生成规则</button>
                     </div>
                 </div>
-                <div class="d-inline-block ml-3">
-                    <a href="#choose" data-toggle="modal" data-target="#choose" class="btn btn-primary btn-sm">计量汇总</a>
-                </div>
             </div>
             <div>
                 <!--上报-->
@@ -154,4 +135,11 @@
             </div>
         </div>
     </div>
-</div>
+</div>
+<script>
+    GC.Spread.Sheets.LicenseKey = "559432293813965#A0y3iTOzEDOzkjMyMDN9UTNiojIklkI1pjIEJCLi4TPB9mM5AFNTd4cvZ7SaJUVy3CWKtWYXx4VVhjMpp7dYNGdx2ia9sEVlZGOTh7NRlTUwkWR9wEV4gmbjBDZ4ElR8N7cGdHVvEWVBtCOwIGW0ZmeYVWVr3mI0IyUiwCMzETN8kzNzYTM0IicfJye&Qf35VfiEzRwEkI0IyQiwiIwEjL6ByUKBCZhVmcwNlI0IiTis7W0ICZyBlIsIyNyMzM5ADI5ADNwcTMwIjI0ICdyNkIsIibj9SbvNmL4N7bjRnch56ciojIz5GRiwiI8+Y9sWY9QmZ0Jyp96uL9v6L0wap9biY9qiq95q197Wr9g+89iojIh94Wiqi";
+</script>
+<script>
+    const stage = JSON.parse('<%- JSON.stringify(ctx.stage) %>');
+    const imType = JSON.parse('<%- JSON.stringify(imType) %>');
+</script>

+ 73 - 0
app/view/stage/detail_modal.ejs

@@ -1,3 +1,76 @@
+<!--设置生成规则-->
+<div class="modal fade" id="choose" data-backdrop="static">
+    <div class="modal-dialog " role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">设置中间计量生成规则</h5>
+            </div>
+            <div class="modal-body">
+                <div class="form-group">
+                    <label>中间计量模式 <a href="/public/images/example/jiliangmoshi.png" target="_blank" data-toggle="tooltip" data-placement="bottom" data-original-title="点击查看相关报表"><i class="fa fa-question-circle-o"></i></a></label>
+                    <div class="row" id="im-type">
+                        <% for (const iT in imType) { %>
+                        <% const t = imType[iT]; %>
+                        <div class="col-6">
+                            <div class="card border-primary" name="im-type" im-type="<%- t.value %>" <% if (ctx.stage.im_type !== t.value) { %> style="cursor:pointer;"<% } %>>
+                                <div class="card-body<% if (ctx.stage.im_type === t.value) { %> text-primary<% } %>">
+                                    <h5 class="card-title mb-0" im-type="<%- t.value %>">
+                                        <% if (ctx.stage.im_type === t.value) { %><i class="fa fa-check pull-right"></i><% } %>
+                                        <%- t.name %>
+                                    </h5>
+                                </div>
+                            </div>
+                        </div>
+                        <% }%>
+                    </div>
+                </div>
+                <div class="form-group">
+                    <label>中间计量表号前缀</label>
+                    <input type="text" class="form-control form-control-sm" value="<%- ctx.stage.im_pre ? ctx.stage.im_pre : '' %>" id="im-pre">
+                </div>
+                <div class="form-group">
+                    <label> </label>
+                    <a  href="#choose2" data-toggle="modal" data-target="#choose2">高级设置</a>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-primary" id="choose-ok">重新生成</button>
+            </div>
+        </div>
+    </div>
+</div>
+<!--设置生成规则2-->
+<div class="modal fade" id="choose2" data-backdrop="static">
+    <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">高级设置</h5>
+            </div>
+            <div class="modal-body">
+                <div class="custom-control custom-checkbox mb-2">
+                    <input type="checkbox" class="custom-control-input" id="im-gather-check" <% if (ctx.stage.im_gather) { %> checked="checked"<% } %>>
+                    <label class="custom-control-label" for="im-gather-check">汇总计量节点</label>
+                </div>
+                <div class="modal-height-500" id="im-gather-spread">
+                </div>
+                <div class="popover bs-popover-right" role="tooltip" id="gather-confirm" style="display: none">
+                    <div class="arrow" style="top:30px"></div>
+                    <div class="popover-body">
+                        <p id="gather-confirm-hint">父项已勾选,继续将取消父项勾选。</p>
+                        <p class="mb-0 d-flex justify-content-end">
+                            <button class="btn btn-sm btn-secondary" id="gather-confirm-cancel">取消</button>&nbsp;<button class="btn btn-sm btn-success" id="gather-confirm-ok">继续</button>
+                        </p>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-primary" id="choose2-ok">确定</button>
+            </div>
+        </div>
+    </div>
+</div>
 <!--添加草图-->
 <div class="modal fade" id="edit-img" data-backdrop="static">
     <div class="modal-dialog modal-lgx" role="document">

+ 5 - 2
app/view/stage/index.ejs

@@ -3,14 +3,17 @@
     <div class="panel-title">
         <div class="title-main d-flex justify-content-between">
             <div>
-                <div class="input-group input-group-sm ml-2 mt-2">
+                <div class="input-group input-group-sm mt-2">
                     <div class="input-group-prepend">
                         <span class="input-group-text" id="basic-addon1">表达式</span>
                     </div>
                     <input type="text" class="form-control m-0">
                 </div>
             </div>
-            <div>
+            <div class="ml-2">
+                <button href="#row-view" class="btn btn-sm btn-light" data-toggle="modal" data-target="#row-view"><i class="fa fa-table"></i> 列显示</button>
+            </div>
+            <div class="ml-auto">
                 <!--上报-->
                 <a href="#sub-sp" data-toggle="modal" data-target="#sub-sp" class="btn btn-primary btn-sm pull-right">上报审批</a>
                 <a href="#sub-sp2" data-toggle="modal" data-target="#sub-sp2" class="btn btn-primary btn-sm pull-right">重新上报</a>

+ 34 - 0
app/view/stage/modal.ejs

@@ -1,3 +1,37 @@
+<!--列设置-->
+<div class="modal fade" id="row-view" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">列显示</h5>
+            </div>
+            <div class="modal-body">
+                <table class="table table-bordered table-sm">
+                    <thead>
+                    <tr><th>列项</th><th width="90">显示</th></tr>
+                    </thead>
+                    <tbody id="row-view-list">
+                    <tr><td>签约合同</td><td><input type="checkbox" checked=""></td></tr>
+                    <tr><td>施工图复核</td><td><input type="checkbox" checked=""></td></tr>
+                    <tr><td>本期计量合同</td><td><input type="checkbox" checked=""></td></tr>
+                    <tr><td>本期数量变更</td><td><input type="checkbox" checked=""></td></tr>
+                    <tr><td>本期完成计量</td><td><input type="checkbox" checked=""></td></tr>
+                    <tr><td>截止本期合同计量</td><td><input type="checkbox"></td></tr>
+                    <tr><td>截止本期数量变更</td><td><input type="checkbox"></td></tr>
+                    <tr><td>截止本期完成计量</td><td><input type="checkbox" checked=""></td></tr>
+                    <tr><td>图册号</td><td><input type="checkbox" checked=""></td></tr>
+                    <tr><td>累计完成率(%)</td><td><input type="checkbox" checked=""></td></tr>
+                    <tr><td>备注</td><td><input type="checkbox" checked=""></td></tr>
+                    </tbody>
+                </table>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-primary" id="row-view-ok">确认</button>
+            </div>
+        </div>
+    </div>
+</div>
 <!--弹出调用变更令-->
 <div class="modal fade" id="use-bg" data-backdrop="static">
     <div class="modal-dialog modal-lgx" role="document">

+ 156 - 15
app/view/tender/detail.ejs

@@ -92,22 +92,24 @@
                     <div class="row my-3">
                         <div class="col-2">
                             <div class="nav flex-column nav-pills" >
-                                <a class="nav-link active" id="v-pills-agi-tab" data-toggle="pill" href="#v-pills-agi" role="tab">属性</a>
-                                <a class="nav-link" id="v-pills-count-tab" data-toggle="pill" href="#v-pills-count" role="tab">计算参数</a>
-                                <a class="nav-link" id="v-pills-display-tab" data-toggle="pill" href="#v-pills-display" role="tab">显示设置</a>
+                                <a class="nav-link active" data-toggle="pill" href="#v-pills-1" role="tab">标段属性</a>
+                                <a class="nav-link"  data-toggle="pill" href="#v-pills-2" role="tab">小数位数</a>
+                                <a class="nav-link"  data-toggle="pill" href="#v-pills-3" role="tab">清单精度</a>
+                                <a class="nav-link"  data-toggle="pill" href="#v-pills-4" role="tab">合同参数</a>
+                                <a class="nav-link"  data-toggle="pill" href="#v-pills-5" role="tab">显示设置</a>
                             </div>
                         </div>
                         <div class="col">
                             <div class="tab-content">
-                                <div class="tab-pane fade show active" id="v-pills-agi" role="tabpanel">
+                                <div class="tab-pane fade show active" id="v-pills-1" role="tabpanel">
                                     <!--操作-->
                                     <div class="d-flex justify-content-end mt-3">
                                         <div>
-                                            <button type="button" class="btn btn-sm btn-outline-primary" id="edit-agi"> 编辑</button>
+                                            <button type="button" class="btn btn-sm btn-outline-primary" id="edit-1"> 编辑</button>
                                         </div>
                                         <div style="display: none">
-                                            <button type="button" class="btn btn-sm btn-outline-success" id="post-agi"><i class="fa fa-check"></i> 提交</button>&nbsp;
-                                            <button type="button" class="btn btn-sm btn-outline-danger" id="cancel-agi"><i class="fa fa-close"></i> 取消</button>
+                                            <button type="button" class="btn btn-sm btn-outline-success" id="post-1"><i class="fa fa-check"></i> 提交</button>&nbsp;
+                                            <button type="button" class="btn btn-sm btn-outline-danger" id="cancel-1"><i class="fa fa-close"></i> 取消</button>
                                         </div>
                                     </div>
                                     <!--合同信息-->
@@ -370,15 +372,15 @@
                                         </div>
                                     </div>
                                 </div>
-                                <div class="tab-pane fade" id="v-pills-count" role="tabpanel" >
+                                <div class="tab-pane fade" id="v-pills-2" role="tabpanel" >
                                     <!--操作-->
                                     <div class="d-flex justify-content-end mt-3">
                                         <span>
-                                            <button type="button" class="btn btn-sm btn-outline-primary" id="edit-count">编辑</button>
+                                            <button type="button" class="btn btn-sm btn-outline-primary" id="edit-2">编辑</button>
                                         </span>
                                         <span style="display: none">
-                                            <button type="button" class="btn btn-sm btn-outline-success" id="post-count"><i class="fa fa-check"></i> 提交</button>&nbsp;
-                                            <button type="button" class="btn btn-sm btn-outline-danger" id="cancel-count"><i class="fa fa-close"></i>  取消</button>
+                                            <button type="button" class="btn btn-sm btn-outline-success" id="post-2"><i class="fa fa-check"></i> 提交</button>&nbsp;
+                                            <button type="button" class="btn btn-sm btn-outline-danger" id="cancel-2"><i class="fa fa-close"></i>  取消</button>
                                         </span>
                                     </div>
                                     <!--小数位数-->
@@ -397,6 +399,14 @@
                                             <div class="col-2">
                                                 <div class="input-group input-group-sm">
                                                     <div class="input-group-prepend">
+                                                        <span class="input-group-text">单价</span>
+                                                    </div>
+                                                    <input type="number" class="form-control" value="3" id="decimal-up" min="0" max="4">
+                                                </div>
+                                            </div>
+                                            <div class="col-2">
+                                                <div class="input-group input-group-sm">
+                                                    <div class="input-group-prepend">
                                                         <span class="input-group-text">金额</span>
                                                     </div>
                                                     <input type="number" class="form-control" value="2" id="decimal-tp" onchange="CalculateAllDealParam()"  min="0" max="4">
@@ -447,6 +457,137 @@
                                             </div>
                                         </div>
                                     </div>
+                                </div>
+                                <div class="tab-pane fade" id="v-pills-3" role="tabpanel" >
+                                    <!--操作-->
+                                    <div class="d-flex justify-content-end mt-3">
+                                        <button type="button" class="btn btn-sm btn-outline-primary" id="edit-3">编辑</button>
+                                    </div>
+                                    <div class="d-flex justify-content-end mt-3">
+                                        <button type="button" class="btn btn-sm btn-outline-success" id="post-3"><i class="fa fa-check"></i> 提交</button>&nbsp;
+                                        <button type="button" class="btn btn-sm btn-outline-danger" id="cancel-3"><i class="fa fa-close"></i>  取消</button>
+                                    </div>
+                                    <legend class="mt-3">清单精度</legend>
+                                    <!--默认显示-->
+                                    <div class="form-group">
+                                        <div class="col-2 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">t</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-t">
+                                            </div>
+                                        </div>
+                                        <div class="col-2 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">km</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-km">
+                                            </div>
+                                        </div>
+                                        <div class="col-2 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">m</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-m">
+                                            </div>
+                                        </div>
+                                        <div class="col-2 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">m2</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-m2">
+                                            </div>
+                                        </div>
+                                        <div class="col-2 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">m3</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-m3">
+                                            </div>
+                                        </div>
+                                        <div class="col-2 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">kg</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-kg">
+                                            </div>
+                                        </div>
+                                        <div class="col-2 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">个</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-ge">
+                                            </div>
+                                        </div>
+                                        <div class="col-2 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">台</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-tai">
+                                            </div>
+                                        </div>
+                                        <div class="col-2 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">套</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-tao">
+                                            </div>
+                                        </div>
+                                        <div class="col-2 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">棵</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-ke">
+                                            </div>
+                                        </div>
+                                        <div class="col-2 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">组</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-zu">
+                                            </div>
+                                        </div>
+                                        <div class="col-2 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">总额</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-zonge">
+                                            </div>
+                                        </div>
+                                        <div class="col-2 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">系统</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-xitong">
+                                            </div>
+                                        </div>
+                                        <div class="col-3 mb-3">
+                                            <div class="input-group input-group-sm">
+                                                <div class="input-group-prepend">
+                                                    <span class="input-group-text">其他未列单位</span>
+                                                </div>
+                                                <input class="form-control" type="number" min="0" max="6" value="3" id="unit-other">
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                                <div class="tab-pane fade" id="v-pills-4" role="tabpanel" >
+                                    <!--操作-->
+                                    <div class="d-flex justify-content-end mt-3"><button type="button" class="btn btn-sm btn-outline-primary">编辑</button></div>
+                                    <div class="d-flex justify-content-end mt-3"><button type="button" class="btn btn-sm btn-outline-success"><i class="fa fa-check"></i> 提交</button>&nbsp;<button type="button" class="btn btn-sm btn-outline-danger"><i class="fa fa-close"></i>  取消</button></div>
                                     <legend class="mt-3">合同参数</legend>
                                     <!--默认显示-->
                                     <div class="form-group">
@@ -493,15 +634,15 @@
                                         </div>
                                     </div>
                                 </div>
-                                <div class="tab-pane fade" id="v-pills-display" role="tabpanel" >
+                                <div class="tab-pane fade" id="v-pills-5" role="tabpanel" >
                                     <!--操作-->
                                     <div class="d-flex justify-content-end mt-3">
                                         <span>
-                                            <button type="button" class="btn btn-sm btn-outline-primary" id="edit-display">编辑</button>
+                                            <button type="button" class="btn btn-sm btn-outline-primary" id="edit-5">编辑</button>
                                         </span>
                                         <span style="display: none">
-                                            <button type="button" class="btn btn-sm btn-outline-success" id="post-display"><i class="fa fa-check"></i> 提交</button>&nbsp;
-                                            <button type="button" class="btn btn-sm btn-outline-danger" id="cancel-display"><i class="fa fa-close"></i>  取消</button>
+                                            <button type="button" class="btn btn-sm btn-outline-success" id="post-5"><i class="fa fa-check"></i> 提交</button>&nbsp;
+                                            <button type="button" class="btn btn-sm btn-outline-danger" id="cancel-5"><i class="fa fa-close"></i>  取消</button>
                                         </span>
                                     </div>
                                     <legend class="mt-3">台帐列显示</legend>

+ 18 - 5
config/menu.js

@@ -77,12 +77,12 @@ const tenderMenu = {
                 name: '期列表',
                 display: true,
                 url: '/measure/stage',
+            // }, {
+            //     name: '清单汇总',
+            //     display: true,
+            //     url: '/measure/gather',
             }, {
-                name: '清单汇总',
-                display: true,
-                url: '/measure/gather',
-            }, {
-                name: '审核比较',
+                name: '多期比较',
                 display: true,
                 url: '/measure/compare',
             },
@@ -180,6 +180,19 @@ const stageMenu = {
             },
         ],
     },
+    gather: {
+        name: '清单汇总',
+        display: false,
+        children: [
+            {
+                name: '清单汇总',
+                icon: '',
+                display: true,
+                url: '/gather',
+                class: ' class="ml-3"',
+            },
+        ],
+    },
     compare: {
         name: '审核比较',
         display: false,

+ 35 - 0
config/web.js

@@ -1,7 +1,31 @@
 'use strict';
 
 /**
+ * 前端所需js
  *
+ * {String} webPath: 记录 合并压缩后的 文件存放的路径
+ * {String[]} commonFiles: 所有页面通用的js包文件
+ * {Object} controller: 根据controller和action来区分不同的页面数据
+ *  -   files: 当前页面所需的js包文件
+ *  -   mergeFiles: 当前页面所需 合并压缩的 js文件
+ *  -   mergeFile: 合并压缩后 生成的js文件名
+ *
+ *  在app中运行合并压缩代码,运行后数据为app.jsFiles,示例(ledger)如下:
+ *  app.jsFiles = {
+ *      common: String[]
+ *      controller1: {
+ *          action1: String[]
+ *          action2: String[]
+ *      }
+ *  }
+ *
+ *  在Controller中使用时,需添加到renderData.jsFiles中,并调用Layout方法
+ *  没有该值时,Layout方法会自动加载app.jsFiles.common
+ *  有该值时,例如台账审核页面,renderData.jsFiles = app.jsFiles.ledger.audit = ['/public/js/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js', '/public/js/web/ledger_audit.min.1.0.0.js']
+ *  则layout方法会同时加载app.jsFiles.common与renderData.jsFiles
+ *  加载位置为head
+ *
+ *  如果页面无需合并压缩js文件,可以直接添加到JsFiles.controller.controller1.action1.files,也可以直接添加到调用的ejs模板中
  *
  * @author Mai
  * @date 2019/1/10
@@ -70,6 +94,17 @@ const JsFiles = {
                     "/public/js/stage.js",
                 ],
                 mergeFile: 'stage',
+            },
+            detail: {
+                files: [
+                    "/public/js/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js",
+                ],
+                mergeFiles: [
+                    "/public/js/spreadjs_rela/spreadjs_zh.js",
+                    "/public/js/path_tree.js",
+                    "/public/js/stage_detail.js",
+                ],
+                mergeFile: 'stage_detail',
             }
         }
     }