Преглед изворни кода

Merge branch 'dev' of http://192.168.1.41:3000/maixinrong/Calculation into dev

laiguoran пре 4 година
родитељ
комит
25677ec00a

+ 63 - 0
app/controller/revise_controller.js

@@ -889,6 +889,69 @@ module.exports = app => {
                 ctx.redirect('/tender/' + ctx.tender.id + '/revise/info');
             }
         }
+
+        async compare(ctx) {
+            const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
+            if (!revise) throw '台账修订数据有误';
+
+            const renderData = {
+                revise,
+                measureType,
+                jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.revise.compare),
+            };
+            await this.layout('revise/compare.ejs', renderData);
+        }
+
+        async _loadDataByFilter(ctx, filter) {
+            switch(filter) {
+                case 'bills': return await ctx.service.ledger.getAllDataByCondition({where: {tender_id: ctx.tender.id} });
+                case 'pos': return await ctx.service.pos.getAllDataByCondition({where: {tid: ctx.tender.id} });
+                case 'reviseBills': return await ctx.service.reviseBills.getAllDataByCondition({where: {tender_id: ctx.tender.id}});
+                case 'revisePos': return await ctx.service.revisePos.getAllDataByCondition({where: {tid: ctx.tender.id}});
+            }
+        }
+
+        async loadData(ctx) {
+            try {
+                const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
+                if (!revise) throw '台账修订数据有误';
+
+                const data = JSON.parse(ctx.request.body.data);
+                const filter = data.filter ? data.filter.split(';') : [];
+
+                const responseData = { err: 0, msg: '', data: {} };
+                for (const f of filter) {
+                    if (!f) continue;
+                    responseData.data[f] = await this._loadDataByFilter(ctx, f);
+                }
+                ctx.body = responseData;
+            } catch (err) {
+                this.ctx.helper.log(err);
+                this.ajaxErrorBody(err, '加载数据错误,请刷新页面重试');
+            }
+        }
+
+        async gather(ctx) {
+            const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
+            if (!revise) throw '台账修订数据有误';
+
+            const renderData = {
+                revise,
+                jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.revise.gather),
+            };
+            await this.layout('revise/gather.ejs', renderData);
+        }
+
+        async bwtz(ctx) {
+            const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
+            if (!revise) throw '台账修订数据有误';
+
+            const renderData = {
+                revise,
+                jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.revise.bwtz),
+            };
+            await this.layout('revise/bwtz.ejs', renderData);
+        }
     }
 
     return ReviseController;

+ 58 - 14
app/public/css/main.css

@@ -90,6 +90,51 @@ font-size: .875rem;
 .group-tab .btn-light.active{
   cursor: default;
 }
+.text-info-50{
+  color: #bee5eb;
+}
+.text-danger-50{
+  color: #ed969e;
+}
+.text-success-50{
+  color: #c3e6cb;
+}
+.text-primary-50{
+  color: #cce5ff;
+}
+.text-secondary-50{
+  color: #dcdcdc;
+}
+.bg-info-50{
+  background-color: #d0f6fd;
+}
+.bg-danger-50{
+  background-color: #f8d7da;
+}
+.bg-success-50{
+  background-color: #d4edda;
+}
+.bg-primary-50{
+  background-color: #cce5ff;
+}
+.bg-secondary-50{
+  background-color: #dcdcdc;
+}
+.border-info-50{
+  border:1px solid #9be6f4;
+}
+.border-danger-50{
+  border:1px solid #f5c6cb;
+}
+.border-success-50{
+  border:1px solid #c3e6cb;
+}
+.border-primary-50{
+  border:1px solid #b8daff;
+}
+.border-secondary-50{
+  border:1px solid #ccc;
+}
 /*在谷歌下移除input[number]的上下箭头*/
 input.nospin[type='number']::-webkit-outer-spin-button,
 input.nospin[type='number']::-webkit-inner-spin-button{
@@ -108,23 +153,23 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
 /*滚动条*/
 /* 滚动条 */
 /*水平滚动条的样式*/
-/*::-webkit-scrollbar-thumb:horizontal {
+/*::-webkit-scrollbar-thumb:horizontal { 
 	width: 5px;
 	background-color: #e9ecef;
 	-webkit-border-radius: 0;
 }*/
 /*滚动条的背景颜色,滚动条的圆角宽度*/
 /*::-webkit-scrollbar-track-piece {
-	background-color: #efefef;
-	-webkit-border-radius: 0;
+	background-color: #efefef; 
+	-webkit-border-radius: 0; 
 }*/
 /*滚动条的宽度,滚动条的高度*/
 /*::-webkit-scrollbar {
-	width: 14px;
-	height: 14px;
+	width: 14px; 
+	height: 14px; 
 }*/
 /*垂直滚动条的样式*/
-/*::-webkit-scrollbar-thumb:vertical {
+/*::-webkit-scrollbar-thumb:vertical { 
 	height: 50px;
 	background-color: #e9ecef;
 	-webkit-border-radius: 0;
@@ -133,7 +178,7 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
 	border: 1px solid #ced4da;
 }*/
 /*滚动条的hover样式*/
-/*::-webkit-scrollbar-thumb:hover {
+/*::-webkit-scrollbar-thumb:hover { 
 	height: 50px;
 	background-color: #ced4da;
 	-webkit-border-radius: 0;
@@ -156,7 +201,7 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
   margin-top:-3px;
 }
 .sjs-bottom{
-  height:400px;
+  height:250px;
 }
 .sjs-bottom-2{
   height:360px;
@@ -705,7 +750,7 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
   font-size: 14px
 }
 .bd-toc {
-
+  
     position: sticky;
     top:3rem;
     height: calc(100vh - 10rem);
@@ -860,7 +905,7 @@ body{
   line-height: 30px;
 }
 .panel-title > .title-main .btn.pull-right {
-    margin: 5px 0 0 0
+    margin: 5px 0 0 0 
 }
 .panel-content{
   padding-top:35px;
@@ -1083,7 +1128,7 @@ a.maintain-icon .fa{
     }
 }
 
-a.maintain-icon:hover .fa{
+a.maintain-icon:hover .fa{ 
     animation-iteration-count:0
 }
 /*审批列表*/
@@ -1150,6 +1195,5 @@ overflow-y: auto;
   display: none;
 }
 .list-table tr:hover .att-file-btn{
-  display: block;
-}
-
+  display: inline-block;
+}

+ 25 - 7
app/public/css/main_s.css

@@ -94,28 +94,46 @@ font-size: .875rem;
   color: #bee5eb;
 }
 .text-danger-50{
-  color: #f5c6cb;
+  color: #ed969e;
 }
 .text-success-50{
   color: #c3e6cb;
 }
+.text-primary-50{
+  color: #cce5ff;
+}
+.text-secondary-50{
+  color: #dcdcdc;
+}
 .bg-info-50{
-  background-color: #bee5eb;
+  background-color: #d0f6fd;
 }
 .bg-danger-50{
-  background-color: #f5c6cb;
+  background-color: #f8d7da;
 }
 .bg-success-50{
-  background-color: #c3e6cb;
+  background-color: #d4edda;
+}
+.bg-primary-50{
+  background-color: #cce5ff;
+}
+.bg-secondary-50{
+  background-color: #dcdcdc;
 }
 .border-info-50{
-  border:1px solid #86cfda;
+  border:1px solid #9be6f4;
 }
 .border-danger-50{
-  border:1px solid #ed969e;
+  border:1px solid #f5c6cb;
 }
 .border-success-50{
-  border:1px solid #8fd19e;
+  border:1px solid #c3e6cb;
+}
+.border-primary-50{
+  border:1px solid #b8daff;
+}
+.border-secondary-50{
+  border:1px solid #ccc;
 }
 /*在谷歌下移除input[number]的上下箭头*/
 input.nospin[type='number']::-webkit-outer-spin-button,

+ 26 - 17
app/public/js/path_tree.js

@@ -1460,31 +1460,40 @@ const createNewPathTree = function (type, setting) {
             return this._newId++;
         }
 
-        loadCompareNode(node, parent, loadFun) {
-            const siblings = parent ? parent.children : this.children;
-            let cur = siblings.find(function (x) {
-                return node.b_code
-                    ? x.b_code === node.b_code && x.name === node.name && x.unit === node.unit && x.unit_price === node.unit_price
-                    : x.code === node.code && x.name === node.name;
-            });
+        findCompareNode(node, parent) {
+            if (this.setting.findNode) {
+                return this.setting.findNode(this, node, parent);
+            } else {
+                const siblings = parent ? parent.children : this.children;
+                return siblings.find(function (x) {
+                    return node.b_code
+                        ? x.b_code === node.b_code && x.name === node.name && x.unit === node.unit && x.unit_price === node.unit_price
+                        : x.code === node.code && x.name === node.name;
+                });
+            }
+        }
+
+        loadCompareNode(source, node, parent, loadFun) {
+            let cur = this.findCompareNode(node, parent);
             if (!cur) {
+                const siblings = parent ? parent.children : this.children;
                 const id = this.newId;
                 cur = {
-                    id: id,
-                    pid: parent ? parent.id : this.setting.rootId,
-                    full_path: parent ? parent.full_path + '-' + id : '' + id,
-                    level: parent ? parent.level + 1 : 1,
-                    order: siblings.length + 1,
-                    children: [],
+                    children: [], pos: [],
                     code: node.code, b_code: node.b_code, name: node.name,
                     unit: node.unit, unit_price: node.unit_price,
                 };
+                cur[this.setting.id] = id;
+                cur[this.setting.pid] = parent ? parent[this.setting.id] : this.setting.rootId;
+                cur[this.setting.full_path] = parent ? parent[this.setting.full_path] + '-' + id : '' + id;
+                cur[this.setting.level] = parent ? parent[this.setting.level] + 1 : 1;
+                cur[this.setting.order] = siblings.length + 1;
                 siblings.push(cur);
                 this.datas.push(cur);
             }
-            loadFun(cur, node);
+            loadFun(cur, node, source);
             for (const c of node.children) {
-                this.loadCompareNode(c, cur, loadFun);
+                this.loadCompareNode(source, c, cur, loadFun);
             }
         }
     
@@ -1504,9 +1513,8 @@ const createNewPathTree = function (type, setting) {
     
         loadCompareTree(data, loadFun) {
             for (const c of data.billsTree.children) {
-                this.loadCompareNode(c, null, loadFun);
+                this.loadCompareNode(data, c, null, loadFun);
             }
-            // todo load Pos Data;
         }
     
         calculateDiffer() {
@@ -1528,6 +1536,7 @@ const createNewPathTree = function (type, setting) {
             }
             this.generateSortNodes();
             this.calculateDiffer();
+            if (this.setting.afterLoad) this.setting.afterLoad(this);
         }
     }
 

+ 398 - 0
app/public/js/revise_compare.js

@@ -0,0 +1,398 @@
+'use strict';
+
+/**
+ * 台账修订页面js
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+const billsCompareField = [
+    'code', 'b_code', 'name', 'unit', 'unit_price', 'dgn_qty1', 'dgn_qty2', 'dgn_price',
+    'sgfh_qty', 'sgfh_tp', 'sjcl_qty', 'sjcl_tp', 'qtcl_qty', 'qtcl_tp', 'quantity', 'total_price',
+    'deal_qty', 'deal_tp'
+];
+const posCompareField = [
+    'name', 'position', 'sgfh_qty', 'sjcl_qty', 'qtcl_qty', 'quantity'
+];
+const compareColor = {
+    add: '#D9EDF7'
+}
+
+$(document).ready(() => {
+    let searchLedger;
+    autoFlashHeight();
+    // 初始化spread
+    const billsSpread = SpreadJsObj.createNewSpread($('#bills-spread')[0]);
+    const billsSheet = billsSpread.getActiveSheet();
+    sjsSettingObj.setFxTreeStyle(billsSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
+    if (thousandth) sjsSettingObj.setTpThousandthFormat(billsSpreadSetting);
+    billsSpreadSetting.getColor = function (sheet, data, row, col, defaultColor) {
+        // 增
+        if (data.differ.indexOf('add') >= 0) return '#cce5ff';
+        // 删
+        if (data.differ.indexOf('del') >= 0) return '#DCDCDC';
+        // 结构变动
+        if (data.differ.indexOf('tree') >= 0) return '#d0f6fd';
+        // 修改计算或文字
+        if (data.differ.indexOf('calc') >= 0 || data.differ.indexOf('pos-add') >= 0 || data.differ.indexOf('pos-del') >= 0 || data.differ.indexOf('pos-calc') >= 0) return '#f8d7da';
+        if (data.differ.indexOf('info') >= 0 || data.differ.indexOf('pos-info') >= 0) return '#d4edda';
+        // 层次结构
+        if (data.level === 2) {
+            return '#C4CAFB';
+        } else if ((!data.b_code || data.b_code === '') && data.level > 2) {
+            return '#DFE8F9';
+        } else {
+            return defaultColor;
+        }
+    };
+    SpreadJsObj.initSheet(billsSheet, billsSpreadSetting);
+
+    const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);
+    const posSheet = posSpread.getActiveSheet();
+    sjsSettingObj.setGridSelectStyle(posSpreadSetting);
+    if (thousandth) sjsSettingObj.setTpThousandthFormat(posSpreadSetting);
+    posSpreadSetting.getColor = function (sheet, data, row, col, defaultColor) {
+        // 增
+        if (data.differ.indexOf('add') >= 0) return '#cce5ff';
+        // 删
+        if (data.differ.indexOf('del') >= 0) return '#DCDCDC';
+        // 修改计算或文字
+        if (data.differ.indexOf('calc') >= 0) return '#f8d7da';
+        if (data.differ.indexOf('info') >= 0) return '#d4edda';
+    };
+    SpreadJsObj.initSheet(posSheet, posSpreadSetting);
+
+    const posSearch = $.posSearch({selector: '#pos-search', searchSpread: posSpread});
+
+    // 初始化 节点树结构
+    const treeSetting = {
+        id: 'ledger_id',
+        pid: 'ledger_pid',
+        order: 'order',
+        level: 'level',
+        full_path: 'full_path',
+        rootId: -1,
+        keys: ['id', 'tender_id', 'ledger_id'],
+        calcFields: ['sgfh_tp', 'sjcl_tp', 'qtcl_tp', 'total_price'],
+        findNode: function (tree, node, parent) {
+            const sameId = tree.datas.find(x => {return x.id === node.id});
+            if (sameId) {
+                const pid = parent ? parent[tree.setting.id] : tree.setting.rootId;
+                if (sameId[tree.setting.pid] !== pid) {
+                    sameId.changeParent = true;
+                    sameId.org_parent = parent;
+                }
+                return sameId;
+            } else {
+                const siblings = parent ? parent.children : tree.children;
+                return siblings.find(function (x) {
+                    return node.b_code
+                        ? x.b_code === node.b_code && x.name === node.name && x.unit === node.unit && x.unit_price === node.unit_price
+                        : x.code === node.code && x.name === node.name;
+                });
+            }
+        },
+        loadInfo1: function (node, sourceNode, source) {
+            for (const f of billsCompareField) {
+                node['new_' + f] = sourceNode[f];
+            }
+            node.id = sourceNode.id;
+            node.isNew = true;
+            const posRange = source.pos.getLedgerPos(sourceNode.id);
+            if (posRange && posRange.length > 0) {
+                if (!node.pos) node.pos = [];
+                for (const p of posRange) {
+                    let nP = _.find(node.pos, {id: p.id});
+                    if (!nP) {
+                        nP = {id: p.id};
+                        node.pos.push(nP);
+                    }
+                    for (const f of posCompareField) {
+                        nP['new_' + f] = p[f];
+                    }
+                    nP.isNew = true;
+                }
+            }
+        },
+        loadInfo2: function (node, sourceNode, source) {
+            for (const f of billsCompareField) {
+                node['org_' + f] = sourceNode[f];
+            }
+            node.isOrg = true;
+            const posRange = source.pos.getLedgerPos(sourceNode.id);
+            if (posRange && posRange.length > 0) {
+                if (!node.pos) node.pos = [];
+                for (const p of posRange) {
+                    let nP = _.find(node.pos, {id: p.id});
+                    if (!nP) {
+                        nP = {id: p.id};
+                        node.pos.push(nP);
+                    }
+                    for (const f of posCompareField) {
+                        nP['org_' + f] = p[f];
+                    }
+                    nP.isOrg = true;
+                }
+            }
+        },
+        afterLoad: function (tree) {
+            for (const data of tree.datas) {
+                data.differ = [];
+                data.differ_str = [];
+                if (data.isNew && !data.isOrg) {
+                    data.differ.push('add');
+                    data.differ_str.push('增');
+                } else if (!data.isNew && data.isOrg) {
+                    data.differ.push('del');
+                    data.differ_str.push('删');
+                } else {
+                    if (data.changeParent) data.differ.push('tree');
+                    if (!data.children || data.children.length === 0) {
+                        const orgCalc = getCompare(data, compareFields.leafCalc, 'org_', 0);
+                        const newCalc = getCompare(data, compareFields.leafCalc, 'new_', 0);
+                        if (!_.isMatch(newCalc, orgCalc)) data.differ.push('calc');
+                    } else {
+                        const orgCalc = getCompare(data, compareFields.parentCalc, 'org_', 0);
+                        const newCalc = getCompare(data, compareFields.parentCalc, 'new_', 0);
+                        if (!_.isMatch(newCalc, orgCalc)) data.push('calc');
+                    }
+                    const orgInfo = getCompare(data, compareFields.info, 'org_', '');
+                    const newInfo = getCompare(data, compareFields.info, 'new_', '');
+                    if (!_.isMatch(newInfo, orgInfo)) data.differ.push('info');
+
+                    for (const p of data.pos) {
+                        p.differ = [];
+                        p.differ_str = [];
+                        if (p.isNew && !p.isOrg) {
+                            p.differ.push('add');
+                            if (data.differ.indexOf('pos-add') === -1) data.differ.push('pos-add');
+                            p.differ_str.push('增');
+                        } else if (!p.isNew && p.isOrg) {
+                            p.differ.push('del');
+                            if (data.differ.indexOf('pos-del') === -1) data.differ.push('pos-del');
+                            p.differ_str.push('删');
+                        } else {
+                            const orgPosCalc = getCompare(p, compareFields.posCalc, 'org_', 0);
+                            const newPosCalc = getCompare(p, compareFields.posCalc, 'new_', 0);
+                            if (!_.isMatch(orgPosCalc, newPosCalc)) {
+                                p.differ.push('calc');
+                                if (data.differ.indexOf('pos-calc') === -1) data.differ.push('pos-calc');
+                                p.differ_str.push('量改');
+                            }
+                            const orgPosInfo = getCompare(p, compareFields.posInfo, 'org_', 0);
+                            const newPosInfo = getCompare(p, compareFields.posInfo, 'new_', 0);
+                            if (!_.isMatch(orgPosInfo, newPosInfo)) {
+                                p.differ.push('info');
+                                if (data.differ.indexOf('pos-info') === -1) data.differ.push('pos-info');
+                                p.differ_str.push('文改');
+                            }
+                        }
+                    }
+                    if (data.differ.length > 0) data.differ_str.push('改');
+                }
+            }
+        }
+    };
+    if (!isTz) {
+        treeSetting.calcFields.push('deal_tp');
+    }
+    treeSetting.calcFun = function (node) {
+        node.dgn_price = ZhCalc.round(ZhCalc.div(node.total_price, node.dgn_qty1), 2);
+    };
+    const billsTree = createNewPathTree('compare', treeSetting);
+
+    // 清单 相关方法&绑定spreadjs事件
+    const billsTreeSpreadObj = {
+        selectionChanged: function (e, info) {
+            if (info.newSelections) {
+                if (!info.oldSelections || info.newSelections[0].row !== info.oldSelections[0].row) {
+                    posSpreadObj.loadCurPosData();
+                    posSearch.search($('#pos-keyword').val());
+                }
+            }
+        },
+    };
+    billsSpread.bind(spreadNS.Events.SelectionChanged, billsTreeSpreadObj.selectionChanged);
+
+    // 计量单元 相关方法&绑定spreadjs事件
+    const posSpreadObj = {
+        /**
+         * 加载计量单元 根据当前台账选择节点
+         */
+        loadCurPosData: function () {
+            const node = SpreadJsObj.getSelectObject(billsSheet);
+            if (node) {
+                SpreadJsObj.loadSheetData(posSheet, 'data', node.pos || []);
+            } else {
+                SpreadJsObj.loadSheetData(posSheet, 'data', []);
+            }
+        },
+    };
+
+    // 加载清单&计量单元数据
+    postData('/tender/' + window.location.pathname.split('/')[2] + '/revise/load', {filter: 'bills;pos;reviseBills;revisePos'}, function (result) {
+        const tenderTreeSetting = {
+            id: 'ledger_id',
+            pid: 'ledger_pid',
+            order: 'order',
+            level: 'level',
+            rootId: -1,
+            keys: ['id', 'tender_id', 'ledger_id'],
+            calcFields: ['deal_tp', 'sgfh_tp', 'sjcl_tp', 'qtcl_tp', 'total_price'],
+        };
+        const reviseLedger = {
+            billsTree: createNewPathTree('ledger', tenderTreeSetting),
+            pos: new PosData({ id: 'id', ledgerId: 'lid', }),
+        };
+        reviseLedger.billsTree.loadDatas(result.reviseBills);
+        reviseLedger.pos.loadDatas(result.revisePos);
+        const orgLedger = {
+            billsTree: createNewPathTree('ledger', tenderTreeSetting),
+            pos: new PosData({ id: 'id', ledgerId: 'lid', }),
+        };
+        orgLedger.billsTree.loadDatas(result.bills);
+        orgLedger.pos.loadDatas(result.pos);
+
+        billsTree.loadCompareData(reviseLedger, orgLedger);
+        SpreadJsObj.loadSheetData(billsSheet, SpreadJsObj.DataType.Tree, billsTree);
+
+        posSpreadObj.loadCurPosData();
+    }, null);
+    $.divResizer({
+        select: '#revise-resize',
+        callback: function () {
+            billsSpread.refresh();
+            let bcontent = $(".bcontent-wrap") ? $(".bcontent-wrap").height() : 0;
+            $(".sp-wrap").height(bcontent-30);
+            posSpread.refresh();
+        }
+    });
+
+    $.divResizer({
+        select: '#revise-right-spr',
+        callback: function () {
+            billsSpread.refresh();
+            if (posSpread) {
+                posSpread.refresh();
+            }
+            if (searchLedger) {
+                searchLedger.spread.refresh();
+            }
+        }
+    });
+    $.subMenu({
+        menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
+        toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
+        key: 'menu.1.0.0',
+        miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
+        callback: function (info) {
+            if (info.mini) {
+                $('.panel-title').addClass('fluid');
+                $('#sub-menu').removeClass('panel-sidebar');
+            } else {
+                $('.panel-title').removeClass('fluid');
+                $('#sub-menu').addClass('panel-sidebar');
+            }
+            autoFlashHeight();
+            billsSpread.refresh();
+            if (posSpread) {
+                posSpread.refresh();
+            }
+            if (searchLedger) {
+                searchLedger.spread.refresh();
+            }
+        }
+    });
+
+    // 展开收起标准节点
+    $('a', '#side-menu').bind('click', function (e) {
+        e.preventDefault();
+        const tab = $(this), tabPanel = $(tab.attr('content'));
+        // 展开工具栏、切换标签
+        if (!tab.hasClass('active')) {
+            const close = $('.active', '#side-menu').length === 0;
+            $('a', '#side-menu').removeClass('active');
+            tab.addClass('active');
+            $('.tab-content .tab-pane').removeClass('active');
+            tabPanel.addClass('active');
+            showSideTools(tab.hasClass('active'));
+            if (tab.attr('content') === '#search') {
+                if (!searchLedger) {
+                    searchLedger = $.billsSearch({
+                        selector: '#search',
+                        searchSpread: billsSpread,
+                        resultSpreadSetting: {
+                            cols: [
+                                {title: '项目节编号', field: 'code', hAlign: 0, width: 90, formatter: '@', readOnly: true},
+                                {title: '清单编号', field: 'b_code', hAlign: 0, width: 80, formatter: '@', readOnly: true},
+                                {title: '名称', field: 'name', width: 150, hAlign: 0, formatter: '@', readOnly: true},
+                                {title: '单位', field: 'unit', width: 50, hAlign: 1, formatter: '@', readOnly: true},
+                            ],
+                            emptyRows: 0,
+                            headRows: 1,
+                            headRowHeight: [32],
+                            headColWidth: [30],
+                            defaultRowHeight: 21,
+                            headerFont: '12px 微软雅黑',
+                            font: '12px 微软雅黑',
+                            selectedBackColor: '#fffacd',
+                        },
+                        afterLocated: function () {
+                            posSpreadObj.loadCurPosData();
+                        }
+                    });
+                }
+                searchLedger.spread.refresh();
+            }
+        }
+        else {// 收起工具栏
+            tab.removeClass('active');
+            tabPanel.removeClass('active');
+            showSideTools(tab.hasClass('active'));
+        }
+        billsSpread.refresh();
+        if (posSpread) {
+            posSpread.refresh();
+        }
+    });
+
+    // 显示层次
+    (function (select, sheet) {
+        $(select).click(function () {
+            if (!sheet.zh_tree) return;
+            const tag = $(this).attr('tag');
+            const tree = sheet.zh_tree;
+            switch (tag) {
+                case "1":
+                case "2":
+                case "3":
+                case "4":
+                case "5":
+                    tree.expandByLevel(parseInt(tag));
+                    SpreadJsObj.refreshTreeRowVisible(sheet);
+                    break;
+                case "last":
+                    tree.expandByCustom(() => { return true; });
+                    SpreadJsObj.refreshTreeRowVisible(sheet);
+                    break;
+                case "leafXmj":
+                    tree.expandToLeafXmj();
+                    SpreadJsObj.refreshTreeRowVisible(sheet);
+                    break;
+                case "differ":
+                    tree.expandByCustom(function (x) {
+                        const posterity = tree.getPosterity(x);
+                        if (posterity.length === 0) return x.differ.length > 0;
+                        for (const p of posterity) {
+                            if (p.differ.length > 0) return true;
+                        }
+                        return false;
+                    });
+                    SpreadJsObj.refreshTreeRowVisible(sheet);
+            }
+        });
+    })('a[name=showLevel]', billsSheet);
+});
+

+ 4 - 3
app/public/js/spreadjs_rela/spreadjs_zh.js

@@ -655,6 +655,7 @@ const SpreadJsObj = {
             });
             this.endMassOperation(sheet);
         } catch (err) {
+            console.log(err);
             this.endMassOperation(sheet);
         }
     },
@@ -1367,11 +1368,11 @@ const SpreadJsObj = {
                         const validWidth = $(window).width() - (pos.x + hitinfo.x + indent) - borderIndent;
                         const textWidth = this.getTextDisplayWidth(hitinfo, text, "9pt Arial");
                         if (validWidth >= maxHintWidth || textWidth <= validWidth) {
-                            $(div).text(text).css("top", pos.y + hitinfo.y + indent).css("left", pos.x + hitinfo.x + indent);
+                            $(div).html(text).css("top", pos.y + hitinfo.y + indent).css("left", pos.x + hitinfo.x + indent);
                         } else if (textWidth > maxHintWidth) {
-                            $(div).text(text).css("top", pos.y + hitinfo.y + indent).css("left", pos.x + hitinfo.x - indent - maxHintWidth);
+                            $(div).html(text).css("top", pos.y + hitinfo.y + indent).css("left", pos.x + hitinfo.x - indent - maxHintWidth);
                         } else {
-                            $(div).text(text).css("top", pos.y + hitinfo.y + indent).css("left", pos.x + hitinfo.x - indent - textWidth);
+                            $(div).html(text).css("top", pos.y + hitinfo.y + indent).css("left", pos.x + hitinfo.x - indent - textWidth);
                         }
                         this._toolTipElement = div;
                         $(div).show("fast");

+ 5 - 0
app/router.js

@@ -175,6 +175,11 @@ module.exports = app => {
     app.post('/tender/:id/revise/info/upload-excel/:ueType', sessionAuth, tenderCheck, uncheckTenderCheck, 'reviseController.uploadExcel');
     app.post('/tender/:id/revise/info/check', sessionAuth, tenderCheck, uncheckTenderCheck, 'reviseController.checkData');
 
+    app.get('/tender/:id/revise/compare', sessionAuth, tenderCheck, uncheckTenderCheck, reviseAuditCheck, 'reviseController.compare');
+    // app.get('/tender/:id/revise/gather', sessionAuth, tenderCheck, uncheckTenderCheck, reviseAuditCheck, 'reviseController.gather');
+    // app.get('/tender/:id/revise/bwtz', sessionAuth, tenderCheck, uncheckTenderCheck, reviseAuditCheck, 'reviseController.bwtz');
+    app.post('/tender/:id/revise/load', sessionAuth, tenderCheck, uncheckTenderCheck, reviseAuditCheck, 'reviseController.loadData');
+
     // 查看修订数据
     app.get('/tender/:id/revise/history', sessionAuth, tenderCheck, uncheckTenderCheck, 'reviseController.history');
     app.post('/tender/:id/revise/history/load', sessionAuth, tenderCheck, uncheckTenderCheck, 'reviseController.loadHistoryData');

+ 2 - 2
app/service/stage_pos.js

@@ -433,11 +433,11 @@ module.exports = app => {
             }
             const updateBillsStage = [], insertBillsStage = [], info = this.ctx.tender.info;
             for (const b of bills) {
-                const stageBills = await this.getLastestStageData(b.tender_id, this.ctx.stage.id, b.id);
+                const stageBills = await this.ctx.service.stageBills.getLastestStageData(b.tender_id, this.ctx.stage.id, b.id);
 
                 const posStage = await this.getLastestStageData2(b.tender_id, this.ctx.stage.id, {lid: b.id});
                 let contract_qty = 0;
-                const newPosRange = insertPosStage.filter(x => {return x.lid = b.id});
+                const newPosRange = insertPosStage.filter(x => {return x.lid === b.id});
                 for (const nps of newPosRange) {
                     contract_qty = this.ctx.helper.add(contract_qty, nps.contract_qty);
                 }

+ 195 - 0
app/view/revise/compare.ejs

@@ -0,0 +1,195 @@
+<% include ./sub_menu.ejs %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main  d-flex">
+            <% include ./sub_mini_menu.ejs %>
+            <div class="d-inline-block">
+                <div class="dropdown">
+                    <button class="btn btn-sm btn-light dropdown-toggle text-primary" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                        <i class="fa fa-list-ol"></i> 显示层级
+                    </button>
+                    <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
+                        <a class="dropdown-item" name="showLevel" tag="1" href="javascirpt: void(0);">第一层</a>
+                        <a class="dropdown-item" name="showLevel" tag="2" href="javascirpt: void(0);">第二层</a>
+                        <a class="dropdown-item" name="showLevel" tag="3" href="javascirpt: void(0);">第三层</a>
+                        <a class="dropdown-item" name="showLevel" tag="4" href="javascirpt: void(0);">第四层</a>
+                        <a class="dropdown-item" name="showLevel" tag="5" href="javascirpt: void(0);">第五层</a>
+                        <a class="dropdown-item" name="showLevel" tag="last" href="javascirpt: void(0);">最底层</a>
+                        <a class="dropdown-item" name="showLevel" tag="leafXmj" href="javascirpt: void(0);">只显示项目节</a>
+                        <a class="dropdown-item" name="showLevel" tag="differ" href="javascirpt: void(0);">只显示修订项</a>
+                    </div>
+                </div>
+            </div>
+            <div class="d-inline-block">
+                <span class=""><i class="fa fa-stop text-primary-50 border-primary-50 bg-primary-50"></i> 新增</span>
+                <span class="ml-2"><i class="fa fa-stop text-secondary-50 border-secondary-50 bg-secondary-50"></i> 删除</span>
+                <span class="ml-2"><i class="fa fa-stop text-info-50 border-info-50 bg-info-50"></i> 结构调整</span>
+                <span class="ml-2"><i class="fa fa-stop text-danger-50 border-danger-50 bg-danger-50"></i> 计算项修改</span>
+                <span class="ml-2"><i class="fa fa-stop text-success-50 border-success-50 bg-success-50"></i> 文字修改</span>
+            </div>
+        </div>
+    </div>
+    <div class="content-wrap row pr-46">
+        <div class="c-header p-0 col-12"></div>
+        <!--核心内容(两栏)-->
+        <div class="row w-100 sub-content">
+            <!--左栏-->
+            <div class="c-body" id="left-view" style="width: 100%">
+                <!--0号台账模式-->
+                <div class="sjs-height-1" style="overflow: hidden" id="bills-spread">
+                </div>
+                <% if (ctx.tender.data.measure_type === measureType.tz.value) { %>
+                <div class="bcontent-wrap">
+                    <div id="revise-resize" class="resize-y" id="top-spr" r-Type="height" div1=".sjs-height-1" div2=".bcontent-wrap" title="调整大小"><!--调整上下高度条--></div>
+                    <div class="bc-bar mb-1">
+                        <ul class="nav nav-tabs">
+                            <li class="nav-item">
+                                <a class="nav-link active" href="javascript:void(0)">计量单元</a>
+                            </li>
+                            <li>
+                                <div class="d-inline-block ml-2 mt-1">
+                                    <span class=""><i class="fa fa-stop text-primary-50 border-primary-50 bg-primary-50"></i> 新增</span>
+                                    <span class="ml-2"><i class="fa fa-stop text-secondary-50 border-secondary-50 bg-secondary-50"></i> 删除</span>
+                                    <span class="ml-2"><i class="fa fa-stop text-danger-50 border-danger-50 bg-danger-50"></i> 数量修改</span>
+                                    <span class="ml-2"><i class="fa fa-stop text-success-50 border-success-50 bg-success-50"></i> 文字修改</span>
+                                </div>
+                            </li>
+                            <li class="nav-item" id="pos-search">
+                            </li>
+                        </ul>
+                    </div>
+                    <div class="sp-wrap" id="pos-spread">
+                    </div>
+                </div>
+                <% } %>
+            </div>
+            <!--右栏-->
+            <div class="c-body" id="right-view" style="display: none; width: 33%;">
+                <div class="resize-x" id="revise-right-spr" r-Type="width" div1="#left-view" div2="#right-view" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
+                <div class="tab-content">
+                    <div id="search" class="tab-pane">
+                    </div>
+                </div>
+            </div>
+        </div>
+        <!--右侧菜单-->
+        <div class="side-menu">
+            <!--右侧菜单-->
+            <ul class="nav flex-column right-nav" id="side-menu">
+                <li class="nav-item">
+                    <a class="nav-link" content="#search" href="javascript: void(0);">查找定位</a>
+                </li>
+            </ul>
+        </div>
+    </div>
+</div>
+<script src="/public/js/moment/moment.min.js"></script>
+<script>
+    const isTz = <%- ctx.tender.data.measure_type === measureType.tz.value %>;
+    const thousandth = <%- ctx.tender.info.display.thousandth %>;
+    const decimal = JSON.parse('<%- JSON.stringify(ctx.tender.info.decimal) %>');
+    const compareFields = {
+        info: ['code', 'b_code', 'name', 'unit'],
+        leafCalc: ['unit_price', 'sgfh_qty', 'sgfh_tp', 'qtcl_qty', 'qtcl_tp', 'sjcl_qty', 'sjcl_tp', 'deal_qty', 'deal_tp', 'quantity', 'total_price'],
+        parentCalc: ['dgn_qty1', 'dgn_qty2',],
+        posInfo: ['name', 'position'],
+        posCalc: ['sgfh_qty', 'qtcl_qty', 'sjcl_qty'],
+    }
+    const getCompare = function (node, field, prefix, defaultValue) {
+        const result = {};
+        for (const f of field) {
+            result[f] = node[prefix + f] || defaultValue;
+        }
+        return result;
+    };
+    const billsSpreadSetting = {
+        cols: [
+            {title: '', colSpan: '1', rowSpan: '3', field: 'differ_str', hAlign: 1, width: 20, formatter: '@', cellType: 'tip', getTip: function (x) {
+                if (x.differ_str.indexOf('改') >= 0) {
+                    const differ_hint = [];
+                    if (x.differ.indexOf('tree') >= 0)
+                        differ_hint.push('结构调整(原父项:' + (x.org_parent.code || '') + (x.org_parent.b_code || 0) + ')');
+                    if (x.differ.indexOf('calc') >= 0) differ_hint.push('计算项修改');
+                    if (x.differ.indexOf('info') >= 0) differ_hint.push('文字修改');
+                    const pos_hint = [];
+                    if (x.differ.indexOf('pos-add') >= 0) pos_hint.push('增');
+                    if (x.differ.indexOf('pos-del') >= 0) pos_hint.push('删');
+                    if (x.differ.indexOf('pos-info') >= 0) pos_hint.push('文改');
+                    if (x.differ.indexOf('pos-calc') >= 0) pos_hint.push('量改');
+                    if (pos_hint.length > 0) differ_hint.push('计量单元: ' + pos_hint.join(','))
+                    return differ_hint.join('<br>');
+                } else {
+                    return '';
+                }
+                }},
+            {title: '修订台账|项目节编号', colSpan: '16|1', rowSpan: '1|2', field: 'new_code', hAlign: 0, width: 145, formatter: '@', cellType: 'tree'},
+            {title: '|清单编号', colSpan: '|1', rowSpan: '|2', field: 'new_b_code', hAlign: 0, width: 70, formatter: '@'},
+            {title: '|名称', colSpan: '|1', rowSpan: '|2', field: 'new_name', hAlign: 0, width: 185, formatter: '@'},
+            {title: '|单位', colSpan: '|1', rowSpan: '|2', field: 'new_unit', hAlign: 1, width: 50, formatter: '@'},
+            {title: '|单价', colSpan: '|1', rowSpan: '|2', field: 'new_unit_price', hAlign: 2, width: 60, type: 'Number'},
+            {title: '|项目节数量|数量1',  colSpan: '|2|1', rowSpan: '|1|1', field: 'new_dgn_qty1', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.dgnQty%>},
+            {title: '||数量2',  colSpan: '||1', rowSpan: '||1', field: 'new_dgn_qty2', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.dgnQty%>},
+            {title: '|经济指标',  colSpan: '|1', rowSpan: '|2', field: 'new_dgn_price', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.dgnQty%>},
+            {title: '|签约|数量', colSpan: '|2|1', rowSpan: '|1|1', field: 'new_deal_qty', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.data.measure_type === measureType.gcl.value%>},
+            {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'new_deal_tp', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.data.measure_type === measureType.gcl.value%>},
+            {title: '|设计量|数量', colSpan: '|2|1', rowSpan: '|1|1', field: 'new_sgfh_qty', hAlign: 2, width: 60, type: 'Number'},
+            {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'new_sgfh_tp', hAlign: 2, width: 60, type: 'Number'},
+            {title: '|设计错漏增减|数量', colSpan: '|2|1', rowSpan: '|1|1', field: 'new_sjcl_qty', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'new_sjcl_tp', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '|其他错漏增减|数量', colSpan: '|2|1', rowSpan: '|1|1', field: 'new_qtcl_qty', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'new_qtcl_tp', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '|台账小计|数量', colSpan: '|2|1', rowSpan: '|1|1', field: 'new_quantity', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'new_total_price', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '原台账|项目节编号', colSpan: '16|1', rowSpan: '1|2', field: 'org_code', hAlign: 0, width: 145, formatter: '@', cellType: 'tree'},
+            {title: '|清单编号', colSpan: '|1', rowSpan: '|2', field: 'org_b_code', hAlign: 0, width: 70, formatter: '@'},
+            {title: '|名称', colSpan: '|1', rowSpan: '|2', field: 'org_name', hAlign: 0, width: 185, formatter: '@'},
+            {title: '|单位', colSpan: '|1', rowSpan: '|2', field: 'org_unit', hAlign: 1, width: 50, formatter: '@', cellType: 'unit'},
+            {title: '|单价', colSpan: '|1', rowSpan: '|2', field: 'org_unit_price', hAlign: 2, width: 60, type: 'Number'},
+            {title: '|项目节数量|数量1',  colSpan: '|2|1', rowSpan: '|1|1', field: 'org_dgn_qty1', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.dgnQty%>},
+            {title: '||数量2',  colSpan: '||1', rowSpan: '||1', field: 'org_dgn_qty2', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.dgnQty%>},
+            {title: '|经济指标',  colSpan: '|1', rowSpan: '|2', field: 'org_dgn_price', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.dgnQty%>},
+            {title: '|签约|数量', colSpan: '|2|1', rowSpan: '|1|1', field: 'org_deal_qty', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.data.measure_type === measureType.gcl.value%>},
+            {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'org_deal_tp', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.data.measure_type === measureType.gcl.value%>},
+            {title: '|设计量|数量', colSpan: '|2|1', rowSpan: '|1|1', field: 'org_sgfh_qty', hAlign: 2, width: 60, type: 'Number'},
+            {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'org_sgfh_tp', hAlign: 2, width: 60, type: 'Number'},
+            {title: '|设计错漏增减|数量', colSpan: '|2|1', rowSpan: '|1|1', field: 'org_sjcl_qty', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'org_sjcl_tp', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '|其他错漏增减|数量', colSpan: '|2|1', rowSpan: '|1|1', field: 'org_qtcl_qty', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'org_qtcl_tp', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '|台账小计|数量', colSpan: '|2|1', rowSpan: '|1|1', field: 'org_quantity', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'org_total_price', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+        ],
+        emptyRows: 3,
+        headRows: 3,
+        headRowHeight: [25, 25, 25],
+        defaultRowHeight: 21,
+        headerFont: '12px 微软雅黑',
+        font: '12px 微软雅黑',
+        readOnly: true,
+    };
+    const posSpreadSetting = {
+        cols: [
+            {title: '', colSpan: '1', rowSpan: '3', field: 'differ_str', hAlign: 1, width: 60, formatter: '@'},
+            {title: '修改台账|计量单元', colSpan: '6|1', rowSpan: '1|2', field: 'new_name', hAlign: 0, width: 230, formatter: '@'},
+            {title: '|位置', colSpan: '|1', rowSpan: '|2', field: 'new_position', hAlign: 0, width: 60, formatter: '@'},
+            {title: '|台账数量|设计量', colSpan: '|4|1', rowSpan: '|1|1', field: 'new_sgfh_qty', hAlign: 2, width: 100, type: 'Number'},
+            {title: '||设计错漏增减', colSpan: '||1', rowSpan: '||1', field: 'new_sjcl_qty', hAlign: 2, width: 100, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '||其他错漏增减', colSpan: '||1', rowSpan: '||1', field: 'new_qtcl_qty', hAlign: 2, width: 100, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '||小计', colSpan: '||1', rowSpan: '||1', field: 'new_quantity', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '原台账|计量单元', colSpan: '6|1', rowSpan: '1|2', field: 'org_name', hAlign: 0, width: 230, formatter: '@'},
+            {title: '|位置', colSpan: '|1', rowSpan: '|2', field: 'org_position', hAlign: 0, width: 60, formatter: '@'},
+            {title: '|台账数量|设计量', colSpan: '|4|1', rowSpan: '|1|1', field: 'org_sgfh_qty', hAlign: 2, width: 100, type: 'Number'},
+            {title: '||设计错漏增减', colSpan: '||1', rowSpan: '||1', field: 'org_sjcl_qty', hAlign: 2, width: 100, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '||其他错漏增减', colSpan: '||1', rowSpan: '||1', field: 'org_qtcl_qty', hAlign: 2, width: 100, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+            {title: '||小计', colSpan: '||1', rowSpan: '||1', field: 'org_quantity', hAlign: 2, width: 60, type: 'Number', visible: <%- ctx.tender.info.display.ledger.clQty%>},
+        ],
+        emptyRows: 3,
+        headRows: 3,
+        headRowHeight: [25, 25, 25],
+        headColWidth: [30],
+        defaultRowHeight: 21,
+        headerFont: '12px 微软雅黑',
+        font: '12px 微软雅黑',
+        readOnly: true,
+    }
+</script>

+ 2 - 2
app/view/revise/info.ejs

@@ -1,8 +1,8 @@
-<% include ../tender/tender_sub_menu.ejs %>
+<% include ./sub_menu.ejs %>
 <div class="panel-content">
     <div class="panel-title">
         <div class="title-main  d-flex">
-            <% include ../tender/tender_sub_mini_menu.ejs %>
+            <% include ./sub_mini_menu.ejs %>
             <!--工具-->
             <% if ((revise.status === audit.status.uncheck || revise.status === audit.status.checkNo) && revise.uid === ctx.session.sessionUser.accountId) { %>
             <div>

+ 12 - 0
app/view/revise/sub_menu.ejs

@@ -0,0 +1,12 @@
+<div class="panel-sidebar" id="sub-menu">
+    <div class="sidebar-title" data-toggle="tooltip" data-placement="right" data-original-title="<%- revise.corder %># 台账修订"><%- revise.corder %># 台账修订</div>
+    <div class="scrollbar-auto">
+        <% include ./sub_menu_list.ejs %>
+        <div class="side-fold"><a href="javascript: void(0)" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu"><i class="fa fa-upload fa-rotate-270"></i></a></div>
+    </div>
+    <script>
+        new Vue({
+            el: '.scrollbar-auto',
+        });
+    </script>
+</div>

+ 5 - 0
app/view/revise/sub_menu_list.ejs

@@ -0,0 +1,5 @@
+<nav-menu title="返回" url="/tender/<%= ctx.tender.id %>/revise" tclass="text-primary" ml="1" icon="fa-chevron-left"></nav-menu>
+<nav-menu title="台账修订" url="/tender/<%= ctx.tender.id %>/revise/info" ml="3" active="<%= ctx.url.indexOf('revise/info') %>"></nav-menu>
+<nav-menu title="台账对比" url="/tender/<%= ctx.tender.id %>/revise/compare" ml="3" active="<%= ctx.url.indexOf('revise/compare') %>"></nav-menu>
+<!--<nav-menu title="清单汇总" url="/tender/<%= ctx.tender.id %>/revise/gather" ml="3" active="<%= ctx.url.indexOf('revise/gather') %>"></nav-menu>
+<nav-menu title="部位台账" url="/tender/<%= ctx.tender.id %>/revise/bwtz" ml="3" active="<%= ctx.url.indexOf('revise/bwtz') %>"></nav-menu>-->

+ 16 - 0
app/view/revise/sub_mini_menu.ejs

@@ -0,0 +1,16 @@
+<!--折起的菜单-->
+<div class="min-side" id="sub-mini-menu" style="display: none;">
+    <div id="sub-mini-hint" class="side-switch" data-container="body" data-toggle="popover" data-placement="bottom" data-content="这里打开收起的菜单栏"></div>
+    <div class="side-switch">
+        <i class="fa fa-bars"></i>
+    </div>
+    <div class="side-menu" id="mini-menu-list" style="display: none">
+        <% include ./sub_menu_list.ejs %>
+        <div class="side-fold"><a href="javascript: void(0);" data-toggle="tooltip" data-placement="top" data-original-title="展开侧栏" id="to-menu"><i class="fa fa-upload fa-rotate-90"></i></a></div>
+    </div>
+</div>
+<script>
+    new Vue({
+        el: '.side-menu',
+    });
+</script>

+ 20 - 0
config/web.js

@@ -212,6 +212,7 @@ const JsFiles = {
                     '/public/js/spreadjs/sheets/v11/gc.spread.sheets.all.11.2.2.min.js',
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
+                    '/public/js/component/menu.js',
                 ],
                 mergeFiles: [
                     '/public/js/sub_menu.js',
@@ -241,6 +242,25 @@ const JsFiles = {
                 ],
                 mergeFile: 'revise_history',
             },
+            compare: {
+                files: [
+                    '/public/js/spreadjs/sheets/v11/gc.spread.sheets.all.11.2.2.min.js',
+                    '/public/js/decimal.min.js',
+                    '/public/js/math.min.js',
+                    '/public/js/component/menu.js',
+                ],
+                mergeFiles: [
+                    '/public/js/sub_menu.js',
+                    '/public/js/div_resizer.js',
+                    '/public/js/spreadjs_rela/spreadjs_zh.js',
+                    '/public/js/shares/sjs_setting.js',
+                    '/public/js/shares/cs_tools.js',
+                    '/public/js/zh_calc.js',
+                    '/public/js/path_tree.js',
+                    '/public/js/revise_compare.js',
+                ],
+                mergeFile: 'revise_compare',
+            }
         },
         stage: {
             // 本期计量台账