瀏覽代碼

1. 期计量,审核比较,显示本期计量
2. 期计量,审核比较,选择比较人

MaiXinRong 6 年之前
父節點
當前提交
0706408abb

+ 34 - 0
app/const/spread.js

@@ -170,6 +170,39 @@ const stageGather = {
         font: '10pt 微软雅黑',
     }
 };
+const stageCompare = {
+    ledger: {
+        baseCols: [
+            {title: '项目节编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 150, formatter: '@', cellType: 'tree'},
+            {title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 80, formatter: '@'},
+            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 230, formatter: '@'},
+            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 50, formatter: '@'},
+            {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
+        ],
+        extraCols: [
+            {title: '%s|数量', colSpan: '2|1', rowSpan: '1|1', field: 'gather_qty%s', hAlign: 2, width: 60, formatter: '@'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'gather_tp%s', hAlign: 2, width: 60, formatter: '@'},
+        ],
+        emptyRows: 3,
+        headRows: 2,
+        headRowHeight: [40, 40],
+        defaultRowHeight: 21,
+        readOnly: true,
+    },
+    pos: {
+        baseCols: [
+            {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@'},
+        ],
+        extraCols: [
+            {title: '%s数量', colSpan: '1', rowSpan: '1', field: 'quantity%s', hAlign: 2, width: 60, formatter: '@'},
+        ],
+        emptyRows: 3,
+        headRows: 1,
+        headRowHeight: [40],
+        defaultRowHeight: 21,
+        readOnly: true,
+    }
+};
 
 // 计量台账 - cols需要二次计算得到
 const measure = {
@@ -217,6 +250,7 @@ module.exports = {
     ledgerPosSpread,
     stage,
     stageGather,
+    stageCompare,
     filterCols: {
         tzWithoutCols,
         dgnCols,

+ 118 - 3
app/controller/stage_controller.js

@@ -106,6 +106,8 @@ module.exports = app => {
                 tid: ctx.tender.id,
                 order: stageOrder,
             });
+            ctx.stage.auditors = await ctx.service.stageAudit.getAuditors(ctx.stage.id, ctx.stage.times);
+            ctx.stage.curAuditor = await ctx.service.stageAudit.getCurAuditor(ctx.stage.id, ctx.stage.times);
         }
 
         /**
@@ -201,7 +203,7 @@ module.exports = app => {
                 await this.layout('stage/detail.ejs', renderData, 'stage/detail_modal.ejs');
             } catch (err) {
                 this.log(err);
-                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage');
+                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage/' + ctx.params.order);
             }
         }
 
@@ -412,6 +414,75 @@ module.exports = app => {
             }
         }
 
+        // 审批相关
+        /**
+         * 添加审批人
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async addAudit(ctx) {
+            try {
+                await this._getStage(ctx);
+                const data = JSON.parse(ctx.request.body.data);
+                const id = data.auditorId;
+                if (isNaN(id) || id <= 0) {
+                    throw '参数错误';
+                }
+
+                const result = await ctx.service.stageAudit.addAuditor(ctx.stage.id, id);
+                if (!result) {
+                    throw '添加审核人失败';
+                }
+
+                const audit = await ctx.service.stageAudit.getAuditor(ctx.stage.id, id);
+                ctx.body = {err: 0, msg: '', data: audit};
+            } catch (err) {
+                this.log(err);
+                ctx.body = {err: 1, msg: err.toString(), data: null};
+            }
+        }
+        /**
+         * 移除审批人
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async deleteAudit(ctx) {
+            try {
+                await this._getStage(ctx);
+                const data = JSON.parse(ctx.request.body.data);
+                const id = data.auditorId instanceof Number ? data.auditorId : this.app._.toNumber(data.auditorId);
+                if (isNaN(id) || id <= 0) {
+                    throw '参数错误';
+                }
+
+                const result = await ctx.service.stageAudit.deleteAuditor(ctx.stage.id, id, ctx.stage.times);
+                if (!result) {
+                    throw '移除审核人失败';
+                }
+
+                const auditors = await ctx.service.stageAudit.getAuditors(ctx.stage.id);
+                ctx.body = {err: 0, msg: '', data: auditors};
+            } catch (err) {
+                ctx.body = {err: 1, msg: err.toString(), data: null};
+            }
+        }
+        /**
+         * 上报
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async startAudit(ctx) {
+
+        }
+        /**
+         * 审批
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async checkAudit(ctx) {
+
+        }
+
         _getGatherSpreadSetting() {
             const _ = this.app._;
             function removeFieldCols(setting, cols) {
@@ -465,7 +536,7 @@ module.exports = app => {
                 await this.layout('stage/gather.ejs', renderData);
             } catch (err) {
                 this.log(err);
-                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage');
+                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage/' + ctx.params.order);
             }
         }
 
@@ -475,13 +546,57 @@ module.exports = app => {
          * @returns {Promise<void>}
          */
         async compare(ctx) {
+            function getCompareSpreadSetting () {
+                function setColFormat(cols, field, formatter) {
+                    const filterCols = cols.filter(function (c) {
+                        return c.field.search(field) !== -1;
+                    });
+                    for (const col of filterCols) {
+                        col.formatter = formatter;
+                    }
+                }
+                const tpFormatter = ctx.helper.getNumberFormatter(ctx.tender.info.decimal.tp);
+                const upFormatter = ctx.helper.getNumberFormatter(2);
+                const ledger = JSON.parse(JSON.stringify(spreadConst.stageCompare.ledger));
+                setColFormat(ledger.baseCols, 'unit_price', upFormatter);
+                setColFormat(ledger.extraCols, 'total_price', tpFormatter);
+                setColFormat(ledger.extraCols, 'tp', tpFormatter);
+
+                const pos = JSON.parse(JSON.stringify(spreadConst.stageCompare.pos));
+                return [ledger, pos];
+            };
             try {
                 await this._getStage(ctx);
                 const renderData = this._getDefaultRenderData(ctx);
+                [renderData.ledgerSpread, renderData.posSpread] = getCompareSpreadSetting();
+                renderData.ledger = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1);
+                renderData.orgStageLedger = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, 0);
+                renderData.pos = await ctx.service.pos.getPosData({tid: ctx.tender.id});
+                renderData.orgStagePos = await ctx.service.stagePos.getAuditorStageData(ctx.tender.id,
+                    ctx.stage.id, ctx.stage.times, ctx.stage.curAuditor ? ctx.stage.curAuditor.order : 0);
+                renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.compare);
                 await this.layout('stage/compare.ejs', renderData, 'stage/compare_modal.ejs');
             } catch (err) {
                 this.log(err);
-                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage');
+                ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage/' + ctx.params.order);
+            }
+        }
+
+        async compareAuditor(ctx) {
+            try {
+                await this._getStage(ctx);
+                const data = JSON.parse(ctx.request.body.data);
+                const result = [];
+                for (const order of data.auditors) {
+                    const data = { order: order, bills: [], pos: [] };
+                    data.bills = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, order);
+                    data.pos = await ctx.service.stagePos.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, order);
+                    result.push(data);
+                }
+                ctx.body = {err: 0, msg: '', data: result};
+            } catch (err) {
+                this.log(err);
+                ctx.body = {err: 1, msg: err.toString(), data: null};
             }
         }
 

+ 11 - 11
app/public/js/gcl_gather.js

@@ -28,15 +28,15 @@ const gclGatherModel = (function () {
     gsTreeSetting.calcFields = ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp', 'end_contract_tp', 'end_qc_tp', 'end_gather_tp'];
     gsTreeSetting.calcFun = function (node) {
         if (node.children && node.children.length === 0) {
-            node.gather_qty = _.toNumber(node.contract_qty) + _.toNumber(node.qc_qty);
-            node.end_contract_qty = _.toNumber(node.pre_contract_qty) + _.toNumber(node.contract_qty);
-            node.end_qc_qty = _.toNumber(node.pre_qc_qty) + _.toNumber(node.qc_qty);
-            node.end_gather_qty = _.toNumber(node.pre_gather_qty) + _.toNumber(node.gather_qty);
+            node.gather_qty = _.add(node.contract_qty, node.qc_qty);
+            node.end_contract_qty = _.add(node.pre_contract_qty, node.contract_qty);
+            node.end_qc_qty = _.add(node.pre_qc_qty, node.qc_qty);
+            node.end_gather_qty = _.add(node.pre_gather_qty, node.gather_qty);
         }
-        node.gather_tp = _.toNumber(node.contract_tp) + _.toNumber(node.qc_tp);
-        node.end_contract_tp = _.toNumber(node.pre_contract_tp) + _.toNumber(node.contract_tp);
-        node.end_qc_tp = _.toNumber(node.pre_qc_tp) + _.toNumber(node.qc_tp);
-        node.end_gather_tp = _.toNumber(node.pre_gather_tp) + _.toNumber(node.gather_tp);
+        node.gather_tp = _.add(node.contract_tp, node.qc_tp);
+        node.end_contract_tp = _.add(node.pre_contract_tp, node.contract_tp);
+        node.end_qc_tp = _.add(node.pre_qc_tp, node.qc_tp);
+        node.end_gather_tp = _.add(node.pre_gather_tp, node.gather_tp);
         if (checkZero(node.dgn_qty1)) {
             node.dgn_price = _.round(node.total_price/node.dgn_qty1, 2);
         } else {
@@ -46,11 +46,11 @@ const gclGatherModel = (function () {
     const gsTree = createNewPathTree('stage', gsTreeSetting);
     // 初始化 部位明细
     const posSetting = {
-        id: 'id', masterId: 'lid',
+        id: 'id', ledgerId: 'lid',
         updateFields: ['contract_qty', 'qc_qty'],
     };
     posSetting.calcFun = function (pos) {
-        pos.gather_qty = _.toNumber(pos.contract_qty) + _.toNumber(pos.qc_qty);
+        pos.gather_qty = _.add(pos.contract_qty, pos.qc_qty);
     };
     const gsPos = new StagePosData(posSetting);
 
@@ -291,7 +291,7 @@ const gclGatherModel = (function () {
         const gcl = getGclNode(node);
         gatherfields(gcl, node, ledgerGatherFields);
         const cacheLeafXmj = getCacheLeafXmj(leafXmj);
-        const posRange = gsPos.getMasterRange(node.id);
+        const posRange = gsPos.getLedgerPos(node.id);
         const detail = posRange && posRange.length > 0 ? posRange : [node];
         for (const d of detail) {
             const dx = _.assign(cacheLeafXmj);

+ 3 - 3
app/public/js/ledger.js

@@ -86,7 +86,7 @@ $(document).ready(function() {
             setObjEnable($('#up-move'), valid && node && node.order > 1);
             setObjEnable($('#down-move'), valid && node && !tree.isLastSibling(node));
             if (checkTzMeasureType()) {
-                const posRange = node ? pos.getMasterRange(node.id) : [];
+                const posRange = node ? pos.getLedgerPos(node.id) : [];
                 setObjEnable($('#up-level'), valid && node && tree.getParent(node) && (!posRange || posRange.length === 0));
             } else {
                 setObjEnable($('#up-level'), valid && node && tree.getParent(node));
@@ -584,7 +584,7 @@ $(document).ready(function() {
         loadCurPosData: function () {
             const node = treeOperationObj.getSelectNode(ledgerSpread.getActiveSheet());
             if (node) {
-                const posData = pos.masterRange[itemsPre + node.id] || [];
+                const posData = pos.ledgerPos[itemsPre + node.id] || [];
                 SpreadJsObj.loadSheetData(posSpread.getActiveSheet(), 'data', posData);
             } else {
                 SpreadJsObj.loadSheetData(posSpread.getActiveSheet(), 'data', []);
@@ -615,7 +615,7 @@ $(document).ready(function() {
                     info.cancel = true;
                     return;
                 }
-                const curPosData = pos.getMasterRange(node.id);
+                const curPosData = pos.getLedgerPos(node.id);
                 const position = curPosData ? curPosData[info.row] : null;
                 const col = info.sheet.zh_setting.cols[info.col];
                 const data = {};

+ 2 - 2
app/public/js/ledger_audit.js

@@ -34,7 +34,7 @@ $(document).ready(() => {
 
     // 初始化 部位明细
     const pos = new PosData({
-        id: 'id', masterId: 'lid',
+        id: 'id', ledgerId: 'lid',
     });
     const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);
 
@@ -57,7 +57,7 @@ $(document).ready(() => {
         }
 
         if (node) {
-            const posData = pos.masterRange[itemsPre + node.id] || [];
+            const posData = pos.ledgerPos[itemsPre + node.id] || [];
             SpreadJsObj.loadSheetData(posSpread.getActiveSheet(), 'data', posData);
         } else {
             SpreadJsObj.loadSheetData(posSpread.getActiveSheet(), 'data', []);

+ 168 - 22
app/public/js/path_tree.js

@@ -18,7 +18,7 @@ class PosData {
         // 以key为索引
         this.items = {};
         // 以分类id为索引的有序
-        this.masterRange = {};
+        this.ledgerPos = {};
         // pos设置
         this.setting = setting;
     }
@@ -33,11 +33,11 @@ class PosData {
             const key = itemsPre + data[this.setting.id];
             this.items[key] = data;
 
-            const masterKey = itemsPre + data[this.setting.masterId];
-            if (!this.masterRange[masterKey]) {
-                this.masterRange[masterKey] = [];
+            const masterKey = itemsPre + data[this.setting.ledgerId];
+            if (!this.ledgerPos[masterKey]) {
+                this.ledgerPos[masterKey] = [];
             }
-            this.masterRange[masterKey].push(data);
+            this.ledgerPos[masterKey].push(data);
         }
     }
 
@@ -53,11 +53,11 @@ class PosData {
                 this.datas.push(d);
                 this.items[key] = d;
 
-                const masterKey = itemsPre + d[this.setting.masterId];
-                if (!this.masterRange[masterKey]) {
-                    this.masterRange[masterKey] = [];
+                const masterKey = itemsPre + d[this.setting.ledgerId];
+                if (!this.ledgerPos[masterKey]) {
+                    this.ledgerPos[masterKey] = [];
                 }
-                this.masterRange[masterKey].push(d);
+                this.ledgerPos[masterKey].push(d);
             } else {
                 const pos = this.items[key];
                 for (const prop in d) {
@@ -78,11 +78,11 @@ class PosData {
             this.datas.splice(this.datas.indexOf(d), 1);
             const key = itemsPre + d[this.setting.id];
             delete this.items[key];
-            const masterKey = itemsPre + d[this.setting.masterId];
-            const range = this.masterRange[masterKey];
+            const masterKey = itemsPre + d[this.setting.ledgerId];
+            const range = this.ledgerPos[masterKey];
             range.splice(range.indexOf(d), 1);
             if (range.length === 0) {
-                delete this.masterRange[masterKey];
+                delete this.ledgerPos[masterKey];
             }
         }
     }
@@ -93,8 +93,8 @@ class PosData {
      */
     removeDatasByMasterId (mid) {
         const masterKey = itemsPre + mid;
-        const range = this.masterRange(mid);
-        delete this.masterRange[masterKey];
+        const range = this.ledgerPos(mid);
+        delete this.ledgerPos[masterKey];
         for (const r of range) {
             this.datas.splice(this.datas.indexOf(r), 1);
             const key = itemsPre + r[this.setting.id];
@@ -106,8 +106,18 @@ class PosData {
         return this.items[itemsPre + id];
     }
 
-    getMasterRange(mid) {
-        return this.masterRange[itemsPre + mid];
+    getLedgerPos(mid) {
+        return this.ledgerPos[itemsPre + mid];
+    }
+
+    /**
+     * 计算全部
+     */
+    calculateAll() {
+        if (!this.setting.calcFun) { return; }
+        for (const pos of this.datas) {
+            this.setting.calcFun(pos);
+        }
     }
 }
 
@@ -140,13 +150,68 @@ class StagePosData extends PosData {
     loadCurStageData(datas) {
         this.loadStageData(datas, '', this.setting.updateFields);
     }
+}
 
-    calculateAll() {
-        if (!this.setting.calcFun) { return; }
-        for (const pos of this.datas) {
-            this.setting.calcFun(pos);
+class MasterPosData extends PosData {
+    /**
+     * 构造函数
+     * @param {id|Number, masterId|Number} setting
+     */
+    constructor (setting) {
+        super(setting);
+        // 关联索引
+        this.masterItems = {};
+    }
+    /**
+     * 加载主数据
+     * @param datas
+     */
+    loadDatas (datas) {
+        super.loadDatas(datas);
+        // 清空旧数据
+        this.masterItems = {};
+        // minor数据缓存
+        this.minorData = {};
+        // 加载全部数据
+        for (const data of this.datas) {
+            const keyName = itemsPre + data[this.setting.masterId];
+            this.masterItems[keyName] = data;
         }
     }
+    /**
+     * 根据关联id,查找节点
+     * @param id
+     * @returns {*}
+     */
+    getMasterItems(id) {
+        return this.masterItems[itemsPre + id];
+    }
+    /**
+     * 加载关联数据
+     *
+     * @param {Array|Object}datas - 需要关联的数据
+     * @param {String} fieldPre - 关联字段前缀(关联结果)
+     * @param {Array} fields - 关联字段
+     * @returns {Array}
+     */
+    loadMinorData(datas, fieldSuf, fields) {
+        if (!datas) { return; }
+        datas = datas instanceof Array ? datas : [datas];
+        this.minorData[fieldSuf] = datas;
+        const loadedData = [];
+        for (const data of datas) {
+            let node = this.getMasterItems(data[this.setting.minorId]);
+            if (node) {
+                for (const prop of fields) {
+                    if (data[prop] !== undefined) {
+                        node[prop + fieldSuf] = data[prop];
+                    }
+                }
+                loadedData.push(node);
+            }
+        }
+        return loadedData;
+    }
 }
 
 const itemsPre = 'id_';
@@ -910,6 +975,83 @@ const createNewPathTree = function (type, setting) {
         }
     }
 
+    class MasterTree extends FxTree {
+        /**
+         * 构造函数
+         */
+        constructor (setting) {
+            super(setting);
+            // 关联索引
+            this.masterItems = {};
+        }
+        /**
+         * 加载数据(初始化), 并给数据添加部分树结构必须数据
+         * @param datas
+         */
+        loadDatas (datas) {
+            super.loadDatas(datas);
+            // 清空旧数据
+            this.masterItems = {};
+            // minor数据缓存
+            this.minorData = {};
+            // 加载全部数据
+            for (const data of this.datas) {
+                const keyName = itemsPre + data[this.setting.masterId];
+                this.masterItems[keyName] = data;
+            }
+        }
+
+        /**
+         * 根据关联id,查找节点
+         * @param id
+         * @returns {*}
+         */
+        getMasterItems(id) {
+            return this.masterItems[itemsPre + id];
+        }
+        /**
+         * 加载关联数据
+         *
+         * @param {Array|Object}datas - 需要关联的数据
+         * @param {String} fieldPre - 关联字段前缀(关联结果)
+         * @param {Array} fields - 关联字段
+         * @returns {Array}
+         */
+        loadMinorData(datas, fieldSuf, fields) {
+            if (!datas) { return; }
+            datas = datas instanceof Array ? datas : [datas];
+            this.minorData[fieldSuf] = datas;
+            const loadedData = [];
+            for (const data of datas) {
+                let node = this.getMasterItems(data[this.setting.minorId]);
+                if (node) {
+                    for (const prop of fields) {
+                        if (data[prop] !== undefined) {
+                            node[prop + fieldSuf] = data[prop];
+                        }
+                    }
+                    loadedData.push(node);
+                }
+            }
+            return loadedData;
+        }
+
+        /**
+         * 展开至最底层项目节
+         */
+        expandByCalcFields() {
+            const self = this;
+            this.expandByCustom(function (node) {
+                for (const field of self.setting.calcFields) {
+                    if (node[field]) {
+                        return true;
+                    }
+                }
+                return false;
+            })
+        }
+    }
+
     if (type === 'base') {
         return new BaseTree(setting);
     } else if (type === 'stage') {
@@ -918,6 +1060,8 @@ const createNewPathTree = function (type, setting) {
         return new LedgerTree(setting);
     } else if (type === 'measure') {
         return new MeasureTree(setting);
+    } else if (type === 'master') {
+        return new MasterTree(setting);
     }
 };
 
@@ -935,14 +1079,16 @@ const treeCalc = {
                     } else {
                         result[field] = x[field] ? x[field] : undefined;
                     }
-                }
+                };
                 for (const cf of tree.setting.calcFields) {
-                    fieldCalc(cf);
+                    result[cf] = _.round(_.add(rst[cf], x[cf]), 8);
+                    //fieldCalc(cf);
                 }
                 return result;
             });
             // 汇总子项
             for (const cf of tree.setting.calcFields) {
+                //node[cf] = _.sumBy(node.children, cf);
                 if (gather[cf]) {
                     node[cf] = gather[cf];
                 } else {

+ 24 - 0
app/public/js/spreadjs_rela/spreadjs_zh.js

@@ -508,6 +508,30 @@ const SpreadJsObj = {
             });
         }
     },
+    /**
+     * 刷新行显示
+     * @param sheet
+     */
+    refreshTreeRowVisible: function (sheet) {
+        this.beginMassOperation(sheet);
+        if (sheet.zh_tree) {
+            for (const iRow in sheet.zh_tree.nodes) {
+                const node = sheet.zh_tree.nodes[iRow];
+                if (node.visible !== undefined && node.visible !== null) {
+                    sheet.setRowVisible(iRow, node.visible);
+                } else {
+                    sheet.setRowVisible(iRow, true);
+                }
+            }
+        }
+        this.endMassOperation(sheet);
+    },
+    /**
+     * 刷新列是否只读
+     * @param sheet
+     * @param field
+     * @param readonly
+     */
     resetFieldReadOnly: function (sheet, field, readonly) {
         const fields = field instanceof Array ? field : [field];
         if (sheet.zh_setting) {

+ 14 - 14
app/public/js/stage.js

@@ -68,15 +68,15 @@ $(document).ready(() => {
     stageTreeSetting.calcFields = ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp', 'end_contract_tp', 'end_qc_tp', 'end_gather_tp'];
     stageTreeSetting.calcFun = function (node) {
         if (node.children && node.children.length === 0) {
-            node.gather_qty = _.toNumber(node.contract_qty) + _.toNumber(node.qc_qty);
-            node.end_contract_qty = _.toNumber(node.pre_contract_qty) + _.toNumber(node.contract_qty);
-            node.end_qc_qty = _.toNumber(node.pre_qc_qty) + _.toNumber(node.qc_qty);
-            node.end_gather_qty = _.toNumber(node.pre_gather_qty) + _.toNumber(node.gather_qty);
+            node.gather_qty = _.add(node.contract_qty, node.qc_qty);
+            node.end_contract_qty = _.add(node.pre_contract_qty, node.contract_qty);
+            node.end_qc_qty = _.add(node.pre_qc_qty, node.qc_qty);
+            node.end_gather_qty = _.add(node.pre_gather_qty, node.gather_qty);
         }
-        node.gather_tp = _.toNumber(node.contract_tp) + _.toNumber(node.qc_tp);
-        node.end_contract_tp = _.toNumber(node.pre_contract_tp) + _.toNumber(node.contract_tp);
-        node.end_qc_tp = _.toNumber(node.pre_qc_tp) + _.toNumber(node.qc_tp);
-        node.end_gather_tp = _.toNumber(node.pre_gather_tp) + _.toNumber(node.gather_tp);
+        node.gather_tp = _.add(node.contract_tp, node.qc_tp);
+        node.end_contract_tp = _.add(node.pre_contract_tp, node.contract_tp);
+        node.end_qc_tp = _.add(node.pre_qc_tp, node.qc_tp);
+        node.end_gather_tp = _.add(node.pre_gather_tp, node.gather_tp);
         if (checkZero(node.dgn_qty1)) {
             node.dgn_price = _.round(node.total_price/node.dgn_qty1, 2);
         } else {
@@ -94,11 +94,11 @@ $(document).ready(() => {
 
     // 初始化 部位明细
     const stagePosSetting = {
-        id: 'id', masterId: 'lid',
+        id: 'id', ledgerId: 'lid',
         updateFields: ['contract_qty', 'qc_qty'],
     };
     stagePosSetting.calcFun = function (pos) {
-        pos.gather_qty = _.toNumber(pos.contract_qty) + _.toNumber(pos.qc_qty);
+        pos.gather_qty = _.add(pos.contract_qty, pos.qc_qty);
     };
     const stagePos = new StagePosData(stagePosSetting);
     const spSpread = SpreadJsObj.createNewSpread($('#stage-pos')[0]);
@@ -125,7 +125,7 @@ $(document).ready(() => {
                     info.cancel = true;
                     return;
                 } else {
-                    const nodePos = stagePos.getMasterRange(node.id);
+                    const nodePos = stagePos.getLedgerPos(node.id);
                     if (nodePos && nodePos.length > 0) {
                         toast('该清单有部位明细,请在部位明细处计量', 'error');
                         info.cancel = true;
@@ -166,7 +166,7 @@ $(document).ready(() => {
                     const node = sortData[iRow];
                     if (node) {
                         if (node.children && node.children.length > 0) { continue; }
-                        const nodePos = stagePos.getMasterRange(node.id);
+                        const nodePos = stagePos.getLedgerPos(node.id);
                         if (nodePos && nodePos.length > 0) { continue; }
 
                         const data = { lid: node.id };
@@ -213,7 +213,7 @@ $(document).ready(() => {
                         filterNodes.push(node);
                         continue;
                     }
-                    const nodePos = stagePos.getMasterRange(node.id);
+                    const nodePos = stagePos.getLedgerPos(node.id);
                     if (nodePos && nodePos.length > 0) {
                         filterNodes.push(node);
                         continue;
@@ -252,7 +252,7 @@ $(document).ready(() => {
         loadCurPosData: function () {
             const node = SpreadJsObj.getSelectObject(slSpread.getActiveSheet());
             if (node) {
-                const posData = stagePos.masterRange[itemsPre + node.id] || [];
+                const posData = stagePos.ledgerPos[itemsPre + node.id] || [];
                 SpreadJsObj.loadSheetData(spSpread.getActiveSheet(), 'data', posData);
             } else {
                 SpreadJsObj.loadSheetData(spSpread.getActiveSheet(), 'data', []);

+ 63 - 0
app/public/js/stage_audit.js

@@ -0,0 +1,63 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date 2019/2/27
+ * @version
+ */
+
+$(document).ready(function () {
+    // 获取审核相关url
+    function getUrlPre () {
+        const path = window.location.pathname.split('/');
+        return _.take(path, 6).join('/');
+    }
+
+    // 搜索审批人
+    $('#searchAccount').click(() => {
+        const data = {
+            keyword: $('#searchName').val(),
+        };
+        postData('/search/user', data, (data) => {
+            const resultDiv = $('#searchResult');
+            $('h5>span', resultDiv).text(data.name);
+            $('#addAuditor').attr('auditorId', data.id);
+            $('h6', resultDiv).text(data.role);
+            $('p', resultDiv).text(data.company);
+            resultDiv.show();
+        }, () => {
+            $('#searchResult').hide();
+        });
+    });
+    // 添加审批人
+    $('#addAuditor').click(() => {
+        postData(getUrlPre() + '/audit/add', { auditorId: $('#addAuditor').attr('auditorId') }, (data) => {
+            const html = [];
+            html.push('<li class="list-group-item" auditorId="'+ data.aid +'"><a href="javascript: void(0)" class="text-danger pull-right">移除</a>');
+            html.push('<span>');
+            html.push(data.order + ' ');
+            html.push(data.name + ' ');
+            html.push('</span>');
+            html.push('<small class="text-muted">');
+            html.push(data.role);
+            html.push('</small></li>');
+            $('#auditors').append(html.join(''));
+        });
+    });
+    // 删除审批人
+    $('li>a', '#auditors').bind('click', function () {
+        const li = $(this).parent();
+        const data = {
+            auditorId: parseInt(li.attr('auditorId')),
+        };
+        postData(getUrlPre() + '/audit/delete', data, (result) => {
+            li.remove();
+            for (const rst of result) {
+                const aLi = $('li[auditorId=' + rst.aid + ']');
+                $('span', aLi).text(rst.order + ' ' + rst.name + ' ');
+            }
+        });
+    });
+});

+ 158 - 0
app/public/js/stage_compare.js

@@ -0,0 +1,158 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+$(document).ready(function () {
+    autoFlashHeight();
+    // 根据设置整理Spread设置
+    function setSpreadSettingCols(setting, fieldSufs, Roles) {
+        function addExtraCols(fieldSuf, Role) {
+            for (const ec of setting.extraCols) {
+                const col = JSON.parse(JSON.stringify(ec));
+                col.title = _.replace(col.title, '%s', Role);
+                col.field = _.replace(col.field, '%s', fieldSuf);
+                setting.cols.push(col);
+            }
+        }
+        setting.cols = [];
+        for (const col of setting.baseCols) {
+            setting.cols.push(col);
+        }
+        for (const index in fieldSufs) {
+            addExtraCols(fieldSufs[index], Roles[index]);
+        }
+    }
+    setSpreadSettingCols(ledgerSpreadSetting, ['0'], ['原报']);
+    setSpreadSettingCols(posSpreadSetting, ['0'], ['原报']);
+
+    function calculateStageLedgerData(datas) {
+        for (const d of datas) {
+            d.gather_qty = _.add(d.contract_qty, d.qc_qty);
+            d.gather_tp = _.add(d.contract_tp, d.qc_tp);
+        }
+    }
+    function calculateStagePosData(datas) {
+        for (const d of datas) {
+            d.gather_qty = _.add(d.contract_qty, d.qc_qty);
+            d.gather_tp = _.add(d.contract_tp, d.qc_tp);
+        }
+    }
+
+    // 初始化台账
+    const ledgerSpread = SpreadJsObj.createNewSpread($('#ledger-spread')[0]);
+    SpreadJsObj.initSheet(ledgerSpread.getActiveSheet(), ledgerSpreadSetting);
+    // 初始化部位
+    const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);
+    SpreadJsObj.initSheet(posSpread.getActiveSheet(), posSpreadSetting);
+    // 加载 台账树结构 数据
+    const scTreeSetting = {
+        id: 'ledger_id',
+        pid: 'ledger_pid',
+        order: 'order',
+        level: 'level',
+        rootId: -1,
+        keys: ['id', 'tender_id', 'ledger_id'],
+        masterId: 'id',
+        minorId: 'lid',
+    }
+    //scTreeSetting.updateFields = ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'];
+    scTreeSetting.calcFields = ['gather_tp0'];
+    const scTree = createNewPathTree('master', scTreeSetting);
+    scTree.loadDatas(ledger);
+    calculateStageLedgerData(orgStageLedger);
+    scTree.loadMinorData(orgStageLedger, '0', ['gather_qty', 'gather_tp']);
+    treeCalc.calculateAll(scTree);
+    scTree.expandByCalcFields();
+    SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Tree, scTree);
+    // 加载 部位 数据
+    const scPosSetting = {
+        id: 'id', ledgerId: 'lid', masterId: 'id', minorId: 'pid',
+        updateFields: ['contract_qty', 'qc_qty'],
+    };
+    scPosSetting.calcFun = function (pos) {
+        pos.gather_qty = _.add(pos.contract_qty, pos.qc_qty);
+    };
+    const scPos = new MasterPosData(scPosSetting);
+    scPos.loadDatas(pos);
+    calculateStagePosData(orgStagePos);
+    scPos.loadMinorData(orgStagePos, '0', ['gather_qty']);
+
+    // 获取项目节数据
+    function loadPosData(iRow) {
+        const node = ledgerSpread.getActiveSheet().zh_tree.nodes[iRow];
+        if (node) {
+            SpreadJsObj.loadSheetData(posSpread.getActiveSheet(), SpreadJsObj.DataType.Data, scPos.getLedgerPos(node.id));
+        } else {
+            SpreadJsObj.loadSheetData(posSpread.getActiveSheet(), SpreadJsObj.DataType.Data, []);
+        }
+    }
+    loadPosData(0);
+    // 切换清单行,读取所属项目节数据
+    ledgerSpread.getActiveSheet().bind(spreadNS.Events.SelectionChanged, function (e, info) {
+        const iOldRow = info.oldSelections[0].row, iNewRow = info.newSelections[0].row;
+        if (iNewRow !== iOldRow) {
+            loadPosData(iNewRow);
+        }
+    });
+    // 显示本期计量
+    $('#customCheckDisabled').click(function () {
+        if (this.checked) {
+            scTree.expandByCalcFields();
+        } else {
+            scTree.expandByLevel(20);
+        }
+        SpreadJsObj.refreshTreeRowVisible(ledgerSpread.getActiveSheet());
+    });
+    // 选择比较人
+    $('#select-qi-ok').click(function () {
+        function refreshView () {
+            scTreeSetting.calcFields = [];
+            const fieldSufs = ['0'], roles = ['原报'], trs = $('tr[auditorId]');
+            for (let order = 0, iLength = trs.length; order < iLength; order++) {
+                fieldSufs.push(order + '');
+                roles.push(tr.children()[0].text);
+                scTreeSetting.calcFields.push('gather_tp' + order);
+            }
+            setSpreadSettingCols(ledgerSpreadSetting, fieldSufs, roles);
+            SpreadJsObj.initSheet(ledgerSpread.getActiveSheet(), ledgerSpreadSetting);
+            treeCalc.calculateAll(scTree);
+            scTree.expandByCalcFields();
+            SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Tree, scTree);
+            setSpreadSettingCols(posSpreadSetting, fieldSufs, roles);
+            SpreadJsObj.initSheet(posSpread.getActiveSheet(), posSpreadSetting);
+            loadPosData(0);
+        }
+        let loadData = [], showData = [], trs = $('tr[auditorId]');
+        for (let order = 0, iLength = trs.length; order < iLength; order++) {
+            const tr = trs[order];
+            if ($('input[type=check]', tr)[0].checked) {
+                if (!scTree.minorData[tr]) {
+                    loadData.push(order + 1);
+                }
+                showData.push(order + 1);
+            }
+        }
+        if (loadData.length > 0) {
+            postData(window.location.pathname + '/load', {auditors: loadData}, function (result) {
+                for (const aData of result) {
+                    calculateStageLedgerData(aData.bills);
+                    scTree.loadMinorData(aData.bills, aData.order + '', ['gather_qty', 'gather_tp']);
+                    treeCalc.calculateAll(scTree);
+                    calculateStagePosData(aData.pos);
+                    scPos.loadMinorData(aData.pos, aData.order + '', ['gather_qty']);
+                }
+                refreshView();
+                $('#select-qi').modal('hide');
+            });
+        } else {
+            refreshView();
+            $('#select-qi').modal('hide');
+        }
+    });
+});

+ 1 - 1
app/public/js/stage_detail.js

@@ -241,7 +241,7 @@ $(document).ready(() => {
                 node.check = gatherNodes.indexOf(node.id) !== -1;
             }
             gsTree.expandByLevel(4);
-            SpreadJsObj.loadSheetData(gsSpread.getActiveSheet(), 'tree', gsTree);
+            SpreadJsObj.refreshTreeRowVisible(gsSpread.getActiveSheet());
             SpreadJsObj.resetFieldReadOnly(gsSpread.getActiveSheet, 'check', !$('#im-gather-check')[0].checked);
         } else {
             const gsTree = stageIm.getGsTree();

+ 19 - 0
app/public/js/stage_gather.js

@@ -29,9 +29,27 @@ $(document).ready(function () {
             SpreadJsObj.loadSheetData(leafXmjSpread.getActiveSheet(), SpreadJsObj.DataType.Data, []);
         }
     }
+    // 超计显示
+    function checkOverRange() {
+        const sheet = gclSpread.getActiveSheet();
+        const bQty = $('#customRadio1')[0].checked, bDealQty = $('#customRadio2')[0].checked;
+        SpreadJsObj.beginMassOperation(sheet);
+        for (let iRow = 0, iLength = sheet.getRowCount(); iRow < iLength; iRow++) {
+            const node = sheet.zh_data[iRow];
+            if (node) {
+                const bOverRangeQty = node.quantity ? node.end_gather_qty > node.quantity : node.end_gather_qty;
+                const bOverRangeDealQty = node.deal_qty ? node.end_gather_qty > node.deal_qty : node.end_gather_qty;
+                const bOverRange = bQty ? bOverRangeQty : (bDealQty ? bOverRangeDealQty : bOverRangeQty || bOverRangeDealQty);
+                const color = bOverRange ? '#f8d7da' : '';
+                sheet.getRange(iRow, -1, 1, -1).backColor(color);
+            }
+        }
+        SpreadJsObj.endMassOperation(sheet);
+    }
     // 加载清单数据
     SpreadJsObj.loadSheetData(gclSpread.getActiveSheet(), SpreadJsObj.DataType.Data, gclGatherData);
     loadLeafXmjData(0);
+    checkOverRange();
     // 切换清单行,读取所属项目节数据
     gclSpread.getActiveSheet().bind(spreadNS.Events.SelectionChanged, function (e, info) {
         const iOldRow = info.oldSelections[0].row, iNewRow = info.newSelections[0].row;
@@ -39,4 +57,5 @@ $(document).ready(function () {
             loadLeafXmjData(iNewRow);
         }
     });
+    $('.custom-radio').click(checkOverRange);
 });

+ 6 - 1
app/router.js

@@ -125,13 +125,18 @@ module.exports = app => {
     app.get('/tender/:id/measure/stage/:order/pay', sessionAuth, tenderCheck, 'stageController.pay');
     // 变更令
     app.get('/tender/:id/measure/stage/:order/change', sessionAuth, tenderCheck, 'stageController.change');
+    // 审批
+    app.post('/tender/:id/measure/stage/:order/audit/add', sessionAuth, tenderCheck, 'stageController.addAudit');
+    app.post('/tender/:id/measure/stage/:order/audit/delete', sessionAuth, tenderCheck, 'stageController.deleteAudit');
+    app.post('/tender/:id/measure/stage/:order/audit/start', sessionAuth, tenderCheck, 'stageController.startAudit');
+    app.post('/tender/:id/measure/stage/:order/audit/check', sessionAuth, tenderCheck, 'stageController.checkAudit');
     // 清单汇总
     app.get('/tender/:id/measure/stage/:order/gather', sessionAuth, tenderCheck, 'stageController.gather');
     // 审核比较
     app.get('/tender/:id/measure/stage/:order/compare', sessionAuth, tenderCheck, 'stageController.compare');
+    app.post('/tender/:id/measure/stage/:order/compare/load', sessionAuth, tenderCheck, 'stageController.compareAuditor');
     // 报表
     app.get('/tender/:id/measure/stage/:order/report', sessionAuth, tenderCheck, 'stageController.report');
-
     // 变更管理
     app.get('/tender/:id/change', sessionAuth, tenderCheck, 'changeController.index');
     app.get('/tender/:id/change/status/:status', sessionAuth, tenderCheck, 'changeController.status');

+ 267 - 0
app/service/stage_audit.js

@@ -0,0 +1,267 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date 2019/2/27
+ * @version
+ */
+
+const auditConst = require('../const/audit').flow;
+
+module.exports = app => {
+    class StageAudit extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'stage_audit';
+        }
+
+        /**
+         * 获取 审核人信息
+         *
+         * @param {Number} stageId - 期id
+         * @param {Number} auditorId - 审核人id
+         * @param {Number} times - 第几次审批
+         * @returns {Promise<*>}
+         */
+        async getAuditor(stageId, auditorId, times = 1) {
+            const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
+                'FROM ?? AS la, ?? AS pa ' +
+                'WHERE la.`sid` = ? and la.`aid` = ? and la.`times` = ?' +
+                '    and la.`aid` = pa.`id`';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, auditorId, times];
+            return await this.db.queryOne(sql, sqlParam);
+        }
+
+        /**
+         * 获取 审核列表信息
+         *
+         * @param {Number} stageId - 期id
+         * @param {Number} times - 第几次审批
+         * @returns {Promise<*>}
+         */
+        async getAuditors(stageId, times = 1) {
+            const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
+                'FROM ?? AS la, ?? AS pa ' +
+                'WHERE la.`sid` = ? and la.`times` = ? and la.`aid` = pa.`id`';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, times];
+            return await this.db.query(sql, sqlParam);
+        }
+
+        /**
+         * 获取 当前审核人
+         *
+         * @param {Number} stageId - 期id
+         * @param {Number} times - 第几次审批
+         * @returns {Promise<*>}
+         */
+        async getCurAuditor(stageId, times = 1) {
+            const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
+                'FROM ?? AS la, ?? AS pa ' +
+                'WHERE la.`sid` = ? and la.`status` = ? and la.`times` = ?' +
+                '    and la.`aid` = pa.`id`';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, auditConst.status.checking, times];
+            return await this.db.queryOne(sql, sqlParam);
+        }
+
+        /**
+         * 获取 最新审核顺序
+         *
+         * @param {Number} stageId - 期id
+         * @param {Number} times - 第几次审批
+         * @returns {Promise<number>}
+         */
+        async getNewOrder(stageId, times = 1) {
+            const sql = 'SELECT Max(??) As max_order FROM ?? Where `sid` = ? and `times` = ?';
+            const sqlParam = ['order', this.tableName, stageId, times];
+            const result = await this.db.queryOne(sql, sqlParam);
+            return result && result.max_order ? result.max_order + 1 : 1;
+        }
+
+        /**
+         * 新增审核人
+         *
+         * @param {Number} stageId - 期id
+         * @param {Number} auditorId - 审核人id
+         * @param {Number} times - 第几次审批
+         * @returns {Promise<number>}
+         */
+        async addAuditor(stageId, auditorId, times = 1) {
+            const newOrder = await this.getNewOrder(stageId, times);
+            const data = {
+                tid: this.ctx.tender.id,
+                sid: stageId,
+                aid: auditorId,
+                times: times,
+                order: newOrder,
+                status: auditConst.status.uncheck,
+            };
+            const result = await this.db.insert(this.tableName, data);
+            return result.effectRows = 1;
+        }
+
+        /**
+         * 移除审核人时,同步其后审核人order
+         * @param transaction - 事务
+         * @param {Number} stageId - 标段id
+         * @param {Number} auditorId - 审核人id
+         * @param {Number} times - 第几次审批
+         * @returns {Promise<*>}
+         * @private
+         */
+        async _syncOrderByDelete(transaction, stageId, order, times) {
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('sid', {
+                value: stageId,
+                operate: '='
+            });
+            this.sqlBuilder.setAndWhere('order', {
+                value: order,
+                operate: '>=',
+            });
+            this.sqlBuilder.setAndWhere('times', {
+                value: times,
+                operate: '=',
+            });
+            this.sqlBuilder.setUpdateData('order', {
+                value: 1,
+                selfOperate: '-',
+            });
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
+            const data = await transaction.query(sql, sqlParam);
+
+            return data;
+        }
+
+        /**
+         * 移除审核人
+         *
+         * @param {Number} stageId - 期id
+         * @param {Number} auditorId - 审核人id
+         * @param {Number} times - 第几次审批
+         * @returns {Promise<boolean>}
+         */
+        async deleteAuditor(stageId, auditorId, times = 1) {
+            console.log('delete-1');
+            const transaction = await this.db.beginTransaction();
+            try {
+                const condition = {sid: stageId, aid: auditorId, times: times};
+                const auditor = await this.getDataByCondition(condition);
+                if (!auditor) {
+                    throw '该审核人不存在';
+                }
+                await this._syncOrderByDelete(transaction, stageId, auditor.order, times);
+                await transaction.delete(this.tableName, condition);
+                await transaction.commit();
+            } catch(err) {
+                await transaction.rollback();
+                throw err;
+            }
+            return true;
+        }
+
+        /**
+         * 开始审批
+         *
+         * @param {Number} stageId - 期id
+         * @param {Number} times - 第几次审批
+         * @returns {Promise<boolean>}
+         */
+        async start(stageId, times = 1) {
+            const audit = await this.getDataByCondition({sid: stageId, times: times, order: 1});
+            if (!audit) {
+                throw '审核人信息错误';
+            }
+
+            const transaction = await this.db.beginTransaction();
+            try {
+                await transaction.update(this.tableName, {id: audit.id, status: auditConst.status.checking, begin_time: new Date()});
+                await transaction.update(this.ctx.service.stage.tableName, {id: stageId, status: auditConst.status.checking});
+                // todo 更新标段stage状态
+                //await transaction.update(this.ctx.service.stage.tableName, {id: stageId, status: auditConst.status.checking});
+                await transaction.commit();
+            } catch(err) {
+                await transaction.rollback();
+                throw err;
+            }
+            return true;
+        }
+
+        /**
+         * 审批
+         * @param {Number} stageId - 标段id
+         * @param {auditConst.status.checked|auditConst.status.checkNo} checkType - 审批结果
+         * @param {Number} times - 第几次审批
+         * @returns {Promise<void>}
+         */
+        async check(stageId, checkType, opinion, times = 1) {
+            if (checkType !== auditConst.status.checked && checkType !== auditConst.status.checkNo) {
+                throw '提交数据错误';
+            }
+
+            const transaction = await this.db.beginTransaction();
+            try {
+                // 整理当前流程审核人状态更新
+                const time = new Date();
+                const audit = await this.getDataByCondition({sid: stageId, times: times, status: auditConst.status.checking});
+                if (!audit) {
+                    throw '审核数据错误';
+                }
+                // 更新当前审核流程
+                await transaction.update(this.tableName, {id: audit.id, status: checkType, opinion: opinion, end_time: time});
+                if (checkType === auditConst.status.checked) {
+                    const nextAudit = await this.getDataByCondition({sid: stageId, times: times, order: audit.order + 1});
+                    // 无下一审核人表示,审核结束
+                    if (nextAudit) {
+                        await transaction.update(this.tableName, {id: nextAudit.id, status: auditConst.status.checking, begin_time: time});
+                    } else {
+                        // 同步 期信息
+                        await transaction.update(this.ctx.service.stage.tableName, {id: stageId, status: checkType});
+                    }
+                } else {
+                    // 同步 期信息
+                    await transaction.update(this.ctx.service.stage.tableName, {id: stageId, times: times+1, status: checkType});
+                    // 拷贝新一次审核流程列表
+                    const auditors = await this.getAllDataByCondition({
+                        where: {sid: stageId, times: times},
+                        columns: ['tid', 'sid', 'aid', 'order']
+                    });
+                    for (const a of auditors) {
+                        a.times = times + 1;
+                        a.status = auditConst.status.uncheck;
+                    }
+                    await transaction.insert(this.tableName, auditors);
+                }
+
+                await transaction.commit();
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        /**
+         * 获取审核人需要审核的标段列表
+         *
+         * @param auditorId
+         * @returns {Promise<*>}
+         */
+        async getAuditStage(auditorId) {
+            const sql = 'SELECT la.`aid`, la.`times`, la.`order`, la.`begin_time`, la.`tid`, la.`sid`, s.`order`, t.`name`, t.`project_id`, t.`type`, t.`user_id` ' +
+                'FROM ?? AS la, ?? AS s, ?? As t ' +
+                'WHERE la.`aid` = ? and la.`status` = ?' +
+                '    and la.`sid` = s.`id` and la.`tid` = t.`id`';
+            const sqlParam = [this.tableName, this.ctx.service.stage.tableName, this.ctx.service.tender.tableName, auditorId, auditConst.status.checking];
+            return await this.db.query(sql, sqlParam);
+        }
+    }
+
+    return StageAudit;
+};

+ 276 - 0
app/view/stage/audit_modal.ejs

@@ -0,0 +1,276 @@
+<!--上报审批-->
+<% if (ctx.stage.status === auditConst.status.uncheck) { %>
+<!--上报审批-->
+<div class="modal fade" id="sub-sp" 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>搜索审批人</label>
+                    <div class="input-group">
+                        <input class="form-control" placeholder="请输入姓名进行检索" type="text" id="searchName">
+                        <div class="input-group-append">
+                            <button class="btn btn-outline-secondary" type="button" id="searchAccount"><i class="fa fa-search"></i></button>
+                        </div>
+                    </div>
+                </div>
+                <div class="card border-primary" id="searchResult" style="display: none">
+                    <div class="card-body">
+                        <h5 class="card-title">
+                            <a href="javascript: void(0)" class="btn btn-primary btn-sm pull-right" id="addAuditor">添加</a>
+                            <span>张三</span>
+                        </h5>
+                        <h6 class="card-subtitle mb-2 text-muted">监理</h6>
+                        <p class="card-text">XXXXX公司</p>
+                    </div>
+                </div>
+                <div class="card mt-3">
+                    <div class="card-header">
+                        审批流程
+                    </div>
+                    <ul class="list-group list-group-flush" id="auditors">
+                        <% for (let i = 0, iLen = stage.auditors.length; i < iLen; i++) { %>
+                        <li class="list-group-item" auditorId="<%- stage.auditors[i].aid %>">
+                            <a href="javascript: void(0)" class="text-danger pull-right">移除</a>
+                            <%- stage.auditors[i].order %> <%- stage.auditors[i].name %>
+                            <small class="text-muted"><%- stage.auditors[i].role %></small>
+                        </li>
+                        <% } %>
+                    </ul>
+                </div>
+            </div>
+            <form class="modal-footer" method="post" action="<%- preUrl %>/start">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                <button class="btn btn-primary" type="submit">确认上报</button>
+            </form>
+        </div>
+    </div>
+</div>
+<% } %>
+<!--重新上报-->
+<div class="modal fade" id="sub-sp2" 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="card mt-3">
+                    <ul class="list-group list-group-flush">
+                        <li class="list-group-item">
+                            <span class="text-success pull-right">上报</span>
+                            <h5 class="card-title"><i class="fa fa-play-circle fa-rotate-90 text-success"></i> 布尔 <small class="text-muted">施工</small></h5>
+                            <p class="card-text">2017-11-25</p>
+                        </li>
+                        <li class="list-group-item">
+                            <span class="text-success pull-right">审批通过</span>
+                            <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 张三 <small class="text-muted">监理</small></h5>
+                            <p class="card-text">审批意见。2017-11-25</p>
+                        </li>
+                        <li class="list-group-item">
+                            <span class="text-success pull-right">审批通过</span>
+                            <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 王五 <small class="text-muted">监理</small></h5>
+                            <p class="card-text">审批通过。2017-11-26</p>
+                        </li>
+                        <li class="list-group-item">
+                            <span class="text-warning pull-right">审批退回</span>
+                            <h5 class="card-title"><i class="fa fa-stop-circle text-warning"></i> 李四 <small class="text-muted">监理</small></h5>
+                            <p class="card-text">审批退回,审批意见文本。2017-11-27</p>
+                        </li>
+                    </ul>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-primary">确认上报</button>
+            </div>
+        </div>
+    </div>
+</div>
+<!--审批流程/结果-->
+<div class="modal fade" id="sp-list" 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="row">
+                    <div class="col-4">
+                        <div class="card mt-3">
+                            <ul class="list-group list-group-flush">
+                                <li class="list-group-item"><i class="fa fa fa-play-circle fa-rotate-90"></i> 布尔  <small class="text-muted">施工</small></li>
+                                <li class="list-group-item"><i class="fa fa-chevron-circle-down"></i> 张三  <small class="text-muted">监理</small></li>
+                                <li class="list-group-item"><i class="fa fa-chevron-circle-down"></i> 王五 <small class="text-muted">监理</small></li>
+                                <li class="list-group-item"><i class="fa fa fa-stop-circle"></i> 李四 <small class="text-muted">监理</small></li>
+                            </ul>
+                        </div>
+                    </div>
+                    <div class="col-8 modal-height-500" style="overflow: auto">
+                        <div class="card mt-3">
+                            <ul class="list-group list-group-flush">
+                                <li class="list-group-item">
+                                    <span class="text-success pull-right">上报</span>
+                                    <h5 class="card-title"><i class="fa fa-play-circle fa-rotate-90 text-success"></i> 布尔 <small class="text-muted">施工</small></h5>
+                                    <p class="card-text">2017-11-25</p>
+                                </li>
+                                <li class="list-group-item">
+                                    <span class="text-success pull-right">审批通过</span>
+                                    <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 张三 <small class="text-muted">监理</small></h5>
+                                    <p class="card-text">审批意见。2017-11-25</p>
+                                </li>
+                                <li class="list-group-item">
+                                    <span class="text-success pull-right">审批通过</span>
+                                    <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 王五 <small class="text-muted">监理</small></h5>
+                                    <p class="card-text">审批通过。2017-11-26</p>
+                                </li>
+                                <li class="list-group-item">
+                                    <span class="text-warning pull-right">审批退回 布尔</span>
+                                    <h5 class="card-title"><i class="fa fa-stop-circle text-warning"></i> 李四 <small class="text-muted">监理</small></h5>
+                                    <p class="card-text">审批退回,审批意见文本。2017-11-27</p>
+                                </li>
+                            </ul>
+                        </div>
+                        <!--退回原报重新上报-->
+                        <div class="card mt-3">
+                            <ul class="list-group list-group-flush">
+                                <li class="list-group-item">
+                                    <span class="text-success pull-right">重新上报</span>
+                                    <h5 class="card-title"><i class="fa fa-play-circle fa-rotate-90 text-success"></i> 布尔 <small class="text-muted">施工</small></h5>
+                                    <p class="card-text">2017-12-01</p>
+                                </li>
+                                <li class="list-group-item">
+                                    <span class="text-success pull-right">审批通过</span>
+                                    <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 张三 <small class="text-muted">监理</small></h5>
+                                    <p class="card-text">审批通过 2017-12-02</p>
+                                </li>
+                                <li class="list-group-item">
+                                    <span class="text-warning pull-right">审批退回 张三</span>
+                                    <h5 class="card-title"><i class="fa fa-chevron-circle-down text-warning"></i> 王五 <small class="text-muted">监理</small></h5>
+                                    <p class="card-text">审批退回 2017-12-02</p>
+                                </li>
+                                <!--王五退回上一审批人 张三,张三重新审批-->
+                                <li class="list-group-item">
+                                    <span class="pull-right">审批中</span>
+                                    <h5 class="card-title"><i class="fa fa-chevron-circle-down"></i> 张三 <small class="text-muted">监理</small></h5>
+                                    <p class="card-text"></p>
+                                </li>
+                                <li class="list-group-item">
+                                    <h5 class="card-title"><i class="fa fa-stop-circle"></i> 李四 <small class="text-muted">监理</small></h5>
+                                </li>
+                            </ul>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
+<!--审批通过-->
+<div class="modal fade" id="sp-done" 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="card mt-3">
+                    <ul class="list-group list-group-flush">
+                        <li class="list-group-item">
+                            <span class="text-success pull-right">上报</span>
+                            <h5 class="card-title"><i class="fa fa-play-circle fa-rotate-90 text-success"></i> 布尔 <small class="text-muted">施工</small></h5>
+                            <p class="card-text">2017-11-25</p>
+                        </li>
+                        <li class="list-group-item">
+                            <span class="text-success pull-right">审批通过</span>
+                            <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 张三 <small class="text-muted">监理</small></h5>
+                            <p class="card-text">审批意见。2018-01-01</p>
+                        </li>
+                        <li class="list-group-item">
+                            <span class="text-success pull-right">审批通过</span>
+                            <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 王五 <small class="text-muted">监理</small></h5>
+                            <p class="card-text">审批意见。2018-01-01</p>
+                        </li>
+                        <li class="list-group-item">
+                            <span class="text-warning pull-right">审批退回 王五</span>
+                            <h5 class="card-title"><i class="fa fa-stop-circle text-warning"></i> 李四 <small class="text-muted">监理</small></h5>
+                            <p class="card-text">审批意见。2018-01-01</p>
+                        </li>
+                        <li class="list-group-item">
+                            <span class="pull-right">审批中</span>
+                            <h5 class="card-title"><i class="fa fa-chevron-circle-down"></i> 王五 <small class="text-muted">监理</small></h5>
+                            <div class="form-group">
+                                <label>审批意见<b class="text-danger">*</b></label>
+                                <textarea class="form-control" ></textarea>
+                            </div>
+                        </li>
+                        <li class="list-group-item">
+                            <h5 class="card-title"><i class="fa fa-stop-circle"></i> 李四 <small class="text-muted">监理</small></h5>
+                        </li>
+                    </ul>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-success" >确认通过</button>
+            </div>
+        </div>
+    </div>
+</div>
+<!--审批退回-->
+<div class="modal fade" id="sp-back" 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="card mt-3">
+                    <ul class="list-group list-group-flush">
+                        <li class="list-group-item">
+                            <span class="text-success pull-right">上报</span>
+                            <h5 class="card-title"><i class="fa fa-play-circle fa-rotate-90 text-success"></i> 布尔 <small class="text-muted">施工</small></h5>
+                            <p class="card-text">2017-11-25</p>
+                        </li>
+                        <li class="list-group-item">
+                            <span class="text-success pull-right">审批通过</span>
+                            <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 张三 <small class="text-muted">监理</small></h5>
+                            <p class="card-text">审批意见。2018-01-01</p>
+                        </li>
+                        <li class="list-group-item">
+                            <span class="pull-right">审批中</span>
+                            <h5 class="card-title"><i class="fa fa-chevron-circle-down"></i> 王五 <small class="text-muted">监理</small></h5>
+                            <div class="form-group">
+                                <label>审批意见<b class="text-danger">*</b></label>
+                                <textarea class="form-control" ></textarea>
+                            </div>
+                            <div class="alert alert-warning"><div class="form-check form-check-inline">
+                                    <input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1">
+                                    <label class="form-check-label" for="inlineRadio1">退回上报 布尔</label>
+                                </div>
+                                <div class="form-check form-check-inline">
+                                    <input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio2" value="option2">
+                                    <label class="form-check-label" for="inlineRadio2">退回上一审批人 张三</label>
+                                </div></data-min-view>
+                        </li>
+                        <li class="list-group-item">
+                            <h5 class="card-title"><i class="fa fa-stop-circle"></i> 李四 <small class="text-muted">监理</small></h5>
+                        </li>
+                    </ul>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-warning" >确认退回</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 19 - 6
app/view/stage/compare.ejs

@@ -2,22 +2,23 @@
 <div class="panel-content">
     <div class="panel-title">
         <div class="title-main d-flex justify-content-between">
-            <h2>审核比较</h2>
             <div>
                 <a class="btn btn-sm btn-light">
                     <div class="custom-control custom-checkbox">
                         <input type="checkbox" class="custom-control-input" id="customCheckDisabled" checked="">
-                        <label class="custom-control-label" for="customCheckDisabled">显示本期计量</label>
+                        <label class="custom-control-label text-primary" for="customCheckDisabled">显示本期计量</label>
                     </div>
                 </a>
-                <button href="#cate-set" class="btn btn-sm btn-light" data-toggle="modal" data-target="#select-qi"><i class="fa fa-users"></i> 选择比较人</button>
+                <% if (ctx.stage.status !== auditConst.status.uncheck) { %>
+                <button href="#cate-set" class="btn btn-sm btn-light text-primary" data-toggle="modal" data-target="#select-qi"><i class="fa fa-users"></i> 选择比较人</button>
+                <% } %>
             </div>
         </div>
     </div>
     <div class="content-wrap">
         <div class="c-header p-0"></div>
         <div class="c-body">
-            <div class="sjs-height-1" id="bills-spread">
+            <div class="sjs-height-1" id="ledger-spread">
             </div>
             <div class="bcontent-wrap">
                 <div class="bc-bar mb-1">
@@ -29,11 +30,23 @@
                 </div>
                 <div class="tab-content">
                     <div class="tab-pane active" id="xmujie">
-                        <div class="sp-wrap" id="bills-spread2">
+                        <div class="sp-wrap" id="pos-spread">
                         </div>
                     </div>
                 </div>
             </div>
         </div>
     </div>
-</div>
+</div>
+<script>
+    GC.Spread.Sheets.LicenseKey = "559432293813965#A0y3iTOzEDOzkjMyMDN9UTNiojIklkI1pjIEJCLi4TPB9mM5AFNTd4cvZ7SaJUVy3CWKtWYXx4VVhjMpp7dYNGdx2ia9sEVlZGOTh7NRlTUwkWR9wEV4gmbjBDZ4ElR8N7cGdHVvEWVBtCOwIGW0ZmeYVWVr3mI0IyUiwCMzETN8kzNzYTM0IicfJye&Qf35VfiEzRwEkI0IyQiwiIwEjL6ByUKBCZhVmcwNlI0IiTis7W0ICZyBlIsIyNyMzM5ADI5ADNwcTMwIjI0ICdyNkIsIibj9SbvNmL4N7bjRnch56ciojIz5GRiwiI8+Y9sWY9QmZ0Jyp96uL9v6L0wap9biY9qiq95q197Wr9g+89iojIh94Wiqi";
+</script>
+<script>
+    //const auditors = JSON.parse(<%- JSON.stringify(ctx.stage.auditors) %>);
+    const ledgerSpreadSetting = JSON.parse('<%- JSON.stringify(ledgerSpread) %>');
+    const posSpreadSetting = JSON.parse('<%- JSON.stringify(posSpread) %>');
+    const ledger = JSON.parse('<%- JSON.stringify(ledger) %>');
+    const orgStageLedger = JSON.parse('<%- JSON.stringify(orgStageLedger) %>');
+    const pos = JSON.parse('<%- JSON.stringify(pos) %>');
+    const orgStagePos = JSON.parse('<%- JSON.stringify(orgStagePos) %>');
+</script>

+ 9 - 4
app/view/stage/compare_modal.ejs

@@ -1,3 +1,4 @@
+<% if (ctx.stage.status !== auditConst.status.uncheck) { %>
 <!--选择比较期-->
 <div class="modal fade" id="select-qi" data-backdrop="static">
     <div class="modal-dialog" role="document">
@@ -8,14 +9,18 @@
             <div class="modal-body">
                 <table class="table table-sm">
                     <tr><th>审批人</th><th width="90">选择</th></tr>
-                    <tr><td>王五</td><td><input type="checkbox"></td></tr>
-                    <tr><td>李四</td><td><input type="checkbox"></td></tr>
+                    <% for (const a of ctx.stage.auditors) { %>
+                    <% if (a.status === auditConst.status.checked) { %>
+                    <tr><td>a.name</td><td><input type="checkbox"></td></tr>
+                    <% } %>
+                    <% } %>
                 </table>
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-primary" >确认</button>
+                <button type="button" class="btn btn-primary" id="select-qi-ok">确认</button>
             </div>
         </div>
     </div>
-</div>
+</div>
+<% } %>

+ 2 - 1
app/view/stage/detail_modal.ejs

@@ -119,4 +119,5 @@
             </div>
         </div>
     </div>
-</div>
+</div>
+<% include ./audit_modal.ejs %>

+ 2 - 269
app/view/stage/modal.ejs

@@ -188,274 +188,6 @@
         </div>
     </div>
 </div>
-<!--上报审批-->
-<div class="modal fade" id="sub-sp" 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>搜索审批人</label>
-                    <div class="input-group">
-                        <input class="form-control" placeholder="请输入姓名进行检索" type="text">
-                        <div class="input-group-append">
-                            <button class="btn btn-outline-secondary" type="button"><i class="fa fa-search"></i></button>
-                        </div>
-                    </div>
-                </div>
-                <div class="card border-primary">
-                    <div class="card-body">
-                        <h5 class="card-title">
-                            <a href="#" class="btn btn-primary btn-sm pull-right">添加</a>张三
-                        </h5>
-                        <h6 class="card-subtitle mb-2 text-muted">监理</h6>
-                        <p class="card-text">XXXXX公司</p>
-                    </div>
-                </div>
-                <div class="card mt-3">
-                    <div class="card-header">
-                        审批流程
-                    </div>
-                    <ul class="list-group list-group-flush">
-                        <li class="list-group-item"><i class="fa fa fa-play-circle fa-rotate-90"></i> 布尔  <small class="text-muted">施工</small></li>
-                        <li class="list-group-item"><a href="" class="text-danger pull-right">移除</a><i class="fa fa-chevron-circle-down"></i> 张三  <small class="text-muted">监理</small></li>
-                        <li class="list-group-item"><a href="" class="text-danger pull-right">移除</a><i class="fa fa-chevron-circle-down"></i> 王五 <small class="text-muted">监理</small></li>
-                        <li class="list-group-item"><a href="" class="text-danger pull-right">移除</a><i class="fa fa fa-stop-circle"></i> 李四 <small class="text-muted">监理</small></li>
-                    </ul>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-primary">确认上报</button>
-            </div>
-        </div>
-    </div>
-</div>
-<!--重新上报-->
-<div class="modal fade" id="sub-sp2" 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="card mt-3">
-                    <ul class="list-group list-group-flush">
-                        <li class="list-group-item">
-                            <span class="text-success pull-right">上报</span>
-                            <h5 class="card-title"><i class="fa fa-play-circle fa-rotate-90 text-success"></i> 布尔 <small class="text-muted">施工</small></h5>
-                            <p class="card-text">2017-11-25</p>
-                        </li>
-                        <li class="list-group-item">
-                            <span class="text-success pull-right">审批通过</span>
-                            <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 张三 <small class="text-muted">监理</small></h5>
-                            <p class="card-text">审批意见。2017-11-25</p>
-                        </li>
-                        <li class="list-group-item">
-                            <span class="text-success pull-right">审批通过</span>
-                            <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 王五 <small class="text-muted">监理</small></h5>
-                            <p class="card-text">审批通过。2017-11-26</p>
-                        </li>
-                        <li class="list-group-item">
-                            <span class="text-warning pull-right">审批退回</span>
-                            <h5 class="card-title"><i class="fa fa-stop-circle text-warning"></i> 李四 <small class="text-muted">监理</small></h5>
-                            <p class="card-text">审批退回,审批意见文本。2017-11-27</p>
-                        </li>
-                    </ul>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-primary">确认上报</button>
-            </div>
-        </div>
-    </div>
-</div>
-<!--审批流程/结果-->
-<div class="modal fade" id="sp-list" 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="row">
-                    <div class="col-4">
-                        <div class="card mt-3">
-                            <ul class="list-group list-group-flush">
-                                <li class="list-group-item"><i class="fa fa fa-play-circle fa-rotate-90"></i> 布尔  <small class="text-muted">施工</small></li>
-                                <li class="list-group-item"><i class="fa fa-chevron-circle-down"></i> 张三  <small class="text-muted">监理</small></li>
-                                <li class="list-group-item"><i class="fa fa-chevron-circle-down"></i> 王五 <small class="text-muted">监理</small></li>
-                                <li class="list-group-item"><i class="fa fa fa-stop-circle"></i> 李四 <small class="text-muted">监理</small></li>
-                            </ul>
-                        </div>
-                    </div>
-                    <div class="col-8 modal-height-500" style="overflow: auto">
-                        <div class="card mt-3">
-                            <ul class="list-group list-group-flush">
-                                <li class="list-group-item">
-                                    <span class="text-success pull-right">上报</span>
-                                    <h5 class="card-title"><i class="fa fa-play-circle fa-rotate-90 text-success"></i> 布尔 <small class="text-muted">施工</small></h5>
-                                    <p class="card-text">2017-11-25</p>
-                                </li>
-                                <li class="list-group-item">
-                                    <span class="text-success pull-right">审批通过</span>
-                                    <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 张三 <small class="text-muted">监理</small></h5>
-                                    <p class="card-text">审批意见。2017-11-25</p>
-                                </li>
-                                <li class="list-group-item">
-                                    <span class="text-success pull-right">审批通过</span>
-                                    <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 王五 <small class="text-muted">监理</small></h5>
-                                    <p class="card-text">审批通过。2017-11-26</p>
-                                </li>
-                                <li class="list-group-item">
-                                    <span class="text-warning pull-right">审批退回 布尔</span>
-                                    <h5 class="card-title"><i class="fa fa-stop-circle text-warning"></i> 李四 <small class="text-muted">监理</small></h5>
-                                    <p class="card-text">审批退回,审批意见文本。2017-11-27</p>
-                                </li>
-                            </ul>
-                        </div>
-                        <!--退回原报重新上报-->
-                        <div class="card mt-3">
-                            <ul class="list-group list-group-flush">
-                                <li class="list-group-item">
-                                    <span class="text-success pull-right">重新上报</span>
-                                    <h5 class="card-title"><i class="fa fa-play-circle fa-rotate-90 text-success"></i> 布尔 <small class="text-muted">施工</small></h5>
-                                    <p class="card-text">2017-12-01</p>
-                                </li>
-                                <li class="list-group-item">
-                                    <span class="text-success pull-right">审批通过</span>
-                                    <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 张三 <small class="text-muted">监理</small></h5>
-                                    <p class="card-text">审批通过 2017-12-02</p>
-                                </li>
-                                <li class="list-group-item">
-                                    <span class="text-warning pull-right">审批退回 张三</span>
-                                    <h5 class="card-title"><i class="fa fa-chevron-circle-down text-warning"></i> 王五 <small class="text-muted">监理</small></h5>
-                                    <p class="card-text">审批退回 2017-12-02</p>
-                                </li>
-                                <!--王五退回上一审批人 张三,张三重新审批-->
-                                <li class="list-group-item">
-                                    <span class="pull-right">审批中</span>
-                                    <h5 class="card-title"><i class="fa fa-chevron-circle-down"></i> 张三 <small class="text-muted">监理</small></h5>
-                                    <p class="card-text"></p>
-                                </li>
-                                <li class="list-group-item">
-                                    <h5 class="card-title"><i class="fa fa-stop-circle"></i> 李四 <small class="text-muted">监理</small></h5>
-                                </li>
-                            </ul>
-                        </div>
-                    </div>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-            </div>
-        </div>
-    </div>
-</div>
-<!--审批通过-->
-<div class="modal fade" id="sp-done" 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="card mt-3">
-                    <ul class="list-group list-group-flush">
-                        <li class="list-group-item">
-                            <span class="text-success pull-right">上报</span>
-                            <h5 class="card-title"><i class="fa fa-play-circle fa-rotate-90 text-success"></i> 布尔 <small class="text-muted">施工</small></h5>
-                            <p class="card-text">2017-11-25</p>
-                        </li>
-                        <li class="list-group-item">
-                            <span class="text-success pull-right">审批通过</span>
-                            <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 张三 <small class="text-muted">监理</small></h5>
-                            <p class="card-text">审批意见。2018-01-01</p>
-                        </li>
-                        <li class="list-group-item">
-                            <span class="text-success pull-right">审批通过</span>
-                            <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 王五 <small class="text-muted">监理</small></h5>
-                            <p class="card-text">审批意见。2018-01-01</p>
-                        </li>
-                        <li class="list-group-item">
-                            <span class="text-warning pull-right">审批退回 王五</span>
-                            <h5 class="card-title"><i class="fa fa-stop-circle text-warning"></i> 李四 <small class="text-muted">监理</small></h5>
-                            <p class="card-text">审批意见。2018-01-01</p>
-                        </li>
-                        <li class="list-group-item">
-                            <span class="pull-right">审批中</span>
-                            <h5 class="card-title"><i class="fa fa-chevron-circle-down"></i> 王五 <small class="text-muted">监理</small></h5>
-                            <div class="form-group">
-                                <label>审批意见<b class="text-danger">*</b></label>
-                                <textarea class="form-control" ></textarea>
-                            </div>
-                        </li>
-                        <li class="list-group-item">
-                            <h5 class="card-title"><i class="fa fa-stop-circle"></i> 李四 <small class="text-muted">监理</small></h5>
-                        </li>
-                    </ul>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-success" >确认通过</button>
-            </div>
-        </div>
-    </div>
-</div>
-<!--审批退回-->
-<div class="modal fade" id="sp-back" 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="card mt-3">
-                    <ul class="list-group list-group-flush">
-                        <li class="list-group-item">
-                            <span class="text-success pull-right">上报</span>
-                            <h5 class="card-title"><i class="fa fa-play-circle fa-rotate-90 text-success"></i> 布尔 <small class="text-muted">施工</small></h5>
-                            <p class="card-text">2017-11-25</p>
-                        </li>
-                        <li class="list-group-item">
-                            <span class="text-success pull-right">审批通过</span>
-                            <h5 class="card-title"><i class="fa fa-chevron-circle-down text-success"></i> 张三 <small class="text-muted">监理</small></h5>
-                            <p class="card-text">审批意见。2018-01-01</p>
-                        </li>
-                        <li class="list-group-item">
-                            <span class="pull-right">审批中</span>
-                            <h5 class="card-title"><i class="fa fa-chevron-circle-down"></i> 王五 <small class="text-muted">监理</small></h5>
-                            <div class="form-group">
-                                <label>审批意见<b class="text-danger">*</b></label>
-                                <textarea class="form-control" ></textarea>
-                            </div>
-                            <div class="alert alert-warning"><div class="form-check form-check-inline">
-                                    <input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1">
-                                    <label class="form-check-label" for="inlineRadio1">退回上报 布尔</label>
-                                </div>
-                                <div class="form-check form-check-inline">
-                                    <input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio2" value="option2">
-                                    <label class="form-check-label" for="inlineRadio2">退回上一审批人 张三</label>
-                                </div></data-min-view>
-                        </li>
-                        <li class="list-group-item">
-                            <h5 class="card-title"><i class="fa fa-stop-circle"></i> 李四 <small class="text-muted">监理</small></h5>
-                        </li>
-                    </ul>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-warning" >确认退回</button>
-            </div>
-        </div>
-    </div>
-</div>
 <!--添加草图-->
 <div class="modal fade" id="edit-img" data-backdrop="static">
     <div class="modal-dialog modal-lgx" role="document">
@@ -506,4 +238,5 @@
             </div>
         </div>
     </div>
-</div>
+</div>
+<% include ./audit_modal.ejs %>

+ 2 - 150
app/view/stage/pay_modal.ejs

@@ -1,152 +1,3 @@
-<!--上报审批-->
-<div class="modal fade" id="sub-sp" 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>搜索审批人</label>
-                    <div class="input-group">
-                        <input class="form-control" placeholder="请输入姓名进行检索" type="text">
-                        <div class="input-group-append">
-                            <button class="btn btn-outline-secondary" type="button"><i class="fa fa-search"></i></button>
-                        </div>
-                    </div>
-                </div>
-                <div class="card border-primary">
-                    <div class="card-body">
-                        <h5 class="card-title">
-                            <a href="#" class="btn btn-primary btn-sm pull-right">添加</a>张三
-                        </h5>
-                        <h6 class="card-subtitle mb-2 text-muted">监理</h6>
-                        <p class="card-text">XXXXX公司</p>
-                    </div>
-                </div>
-                <div class="card mt-3">
-                    <div class="card-header">
-                        审批流程
-                    </div>
-                    <ul class="list-group list-group-flush">
-                        <li class="list-group-item"><a href="" class="text-danger pull-right">移除</a>1 张三  <small class="text-muted">监理</small></li>
-                        <li class="list-group-item"><a href="" class="text-danger pull-right">移除</a>2 王五 <small class="text-muted">监理</small></li>
-                        <li class="list-group-item"><a href="" class="text-danger pull-right">移除</a>3 李四 <small class="text-muted">监理</small></li>
-                    </ul>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-primary">确认上报</button>
-            </div>
-        </div>
-    </div>
-</div>
-<!--审批流程/结果-->
-<div class="modal fade" id="sp-list" 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="card mt-3">
-                    <ul class="list-group list-group-flush">
-                        <li class="list-group-item">
-                            <span class="text-success pull-right">审批通过</span>
-                            <h5 class="card-title">1 张三 <small class="text-muted">监理</small></h5>
-                            <p class="card-text">审批意见。2018-01-01</p>
-                        </li>
-                        <li class="list-group-item">
-                            <span class="text-warning pull-right">审批中</span>
-                            <h5 class="card-title">2 王五 <small class="text-muted">监理</small></h5>
-                            <p class="card-text"></p>
-                        </li>
-                        <li class="list-group-item">
-                            <h5 class="card-title">3 李四 <small class="text-muted">监理</small></h5>
-                        </li>
-                    </ul>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-            </div>
-        </div>
-    </div>
-</div>
-<!--审批通过-->
-<div class="modal fade" id="sp-done" 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="card mt-3">
-                    <ul class="list-group list-group-flush">
-                        <li class="list-group-item">
-                            <span class="text-success pull-right">审批通过</span>
-                            <h5 class="card-title">1 张三 <small class="text-muted">监理</small></h5>
-                            <p class="card-text">审批意见。2018-01-01</p>
-                        </li>
-                        <li class="list-group-item">
-                            <span class="text-warning pull-right">审批中</span>
-                            <h5 class="card-title">2 王五 <small class="text-muted">监理</small></h5>
-                            <div class="form-group">
-                                <label>审批意见<b class="text-danger">*</b></label>
-                                <textarea class="form-control" ></textarea>
-                            </div>
-                        </li>
-                        <li class="list-group-item">
-                            <h5 class="card-title">3 李四 <small class="text-muted">监理</small></h5>
-                        </li>
-                    </ul>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-success" >确认通过</button>
-            </div>
-        </div>
-    </div>
-</div>
-<!--审批退回-->
-<div class="modal fade" id="sp-back" 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="card mt-3">
-                    <ul class="list-group list-group-flush">
-                        <li class="list-group-item">
-                            <span class="text-success pull-right">审批通过</span>
-                            <h5 class="card-title">1 张三 <small class="text-muted">监理</small></h5>
-                            <p class="card-text">审批意见。2018-01-01</p>
-                        </li>
-                        <li class="list-group-item">
-                            <span class="text-warning pull-right">审批中</span>
-                            <h5 class="card-title">2 王五 <small class="text-muted">监理</small></h5>
-                            <div class="form-group">
-                                <label>审批意见<b class="text-danger">*</b></label>
-                                <textarea class="form-control" ></textarea>
-                            </div>
-                            <div class="alert alert-warning">审批退回,将直接退回给上报人。</data-min-view>
-                        </li>
-                        <li class="list-group-item">
-                            <h5 class="card-title">3 李四 <small class="text-muted">监理</small></h5>
-                        </li>
-                    </ul>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-warning" >确认退回</button>
-            </div>
-        </div>
-    </div>
-</div>
 <!--章节设置-->
 <div class="modal fade" id="zjset" data-backdrop="static">
     <div class="modal-dialog" role="document">
@@ -272,4 +123,5 @@
             </div>
         </div>
     </div>
-</div>
+</div>
+<% include ./audit_modal.ejs %>

+ 13 - 0
config/web.js

@@ -92,6 +92,7 @@ const JsFiles = {
                     "/public/js/spreadjs_rela/spreadjs_zh.js",
                     "/public/js/path_tree.js",
                     "/public/js/stage.js",
+                    "/public/js/stage_audit.js",
                 ],
                 mergeFile: 'stage',
             },
@@ -106,6 +107,7 @@ const JsFiles = {
                     "/public/js/path_tree.js",
                     "/public/js/stage_im.js",
                     "/public/js/stage_detail.js",
+                    "/public/js/stage_audit.js",
                 ],
                 mergeFile: 'stage_detail',
             },
@@ -120,6 +122,17 @@ const JsFiles = {
                     "/public/js/stage_gather.js",
                 ],
                 mergeFile: 'stage_gather',
+            },
+            compare: {
+                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_compare.js",
+                ],
+                mergeFile: 'stage_compare',
             }
         }
     }