MaiXinRong 5 år sedan
förälder
incheckning
a47fb33ab5

+ 39 - 1
app/controller/measure_controller.js

@@ -181,7 +181,12 @@ module.exports = app => {
                     tender: ctx.tender.data,
                     tenderMenu: this.menu.tenderMenu,
                     preUrl: '/tender/' + ctx.tender.id,
-                }
+                };
+                renderData.stages = await ctx.service.stage.getAllDataByCondition({
+                    where: {tid: ctx.tender.id, status: auditConst.status.checked},
+                    orders: [['order', 'asc']],
+                });
+                renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.measure.compare);
                 await this.layout('measure/compare.ejs', renderData, 'measure/compare_modal.ejs');
             } catch (err) {
                 this.log(err);
@@ -190,6 +195,39 @@ module.exports = app => {
         }
 
         /**
+         * 多期比较 - 获取数据(Ajax)
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async loadCompareData(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const result = {
+                    main: null,
+                    stages: []
+                };
+                if (data.main) {
+                    result.main = {};
+                    result.main.ledger = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1);
+                    result.main.pos = await ctx.service.pos.getPosData({tid: ctx.tender.id});
+                }
+                if (data.stages) {
+                    for (const order of data.stages) {
+                        const data = { order: order, bills: [], pos: [] };
+                        const stage = await this.ctx.service.stage.getDataByCondition({tid: ctx.tender.id, order: order});
+                        data.bills = await ctx.service.stageBills.getLastestStageData(ctx.tender.id, stage.id);
+                        data.pos = await ctx.service.stagePos.getLastestStageData(ctx.tender.id, stage.id);
+                        result.stages.push(data);
+                    }
+                }
+                ctx.body = {err: 0, msg: '', data: result};
+            } catch (err) {
+                this.log(err);
+                ctx.body = this.ajaxErrorBody(err, '获取数据错误');
+            }
+        }
+
+        /**
          * 删除期(Post)
          * @param ctx
          * @returns {Promise<void>}

+ 241 - 0
app/public/js/measure_compare.js

@@ -0,0 +1,241 @@
+'use strict';
+
+/**
+ * 多期比较
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+const billsSpreadSetting = {
+    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: '@', cellType: 'unit'},
+        {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
+        {title: '台账|数量', colSpan: '2|1', rowSpan: '1|1', field: 'quantity', hAlign: 2, width: 60, formatter: '@'},
+        {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 60, formatter: '@'},
+    ],
+    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,
+};
+const posSpreadSetting = {
+    baseCols: [
+        {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@'},
+        {title: '台账数量', colSpan: '1', rowSpan: '1', field: 'quantity', hAlign: 2, width: 60},
+    ],
+    extraCols: [
+        {title: '%s数量', colSpan: '1', rowSpan: '1', field: 'gather_qty%s', hAlign: 2, width: 60},
+    ],
+    emptyRows: 3,
+    headRows: 1,
+    headRowHeight: [40],
+    defaultRowHeight: 21,
+    readOnly: true,
+};
+function initSpreadSettingWithRoles(compareRoles) {
+    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]);
+        }
+    }
+    const fieldSufs = [], roles = [], trs = $('tr[stage-id]');
+    for (let r of compareRoles) {
+        if (r > 0) {
+            const tr = trs[r-1];
+            if (tr) {
+                fieldSufs.push(r + '');
+                roles.push(tr.children[0].textContent);
+            }
+        }
+    }
+    setSpreadSettingCols(billsSpreadSetting, fieldSufs, roles);
+    setSpreadSettingCols(posSpreadSetting, fieldSufs, roles);
+}
+function calculateStageLedgerData(datas) {
+    for (const d of datas) {
+        d.gather_qty = ZhCalc.add(d.contract_qty, d.qc_qty);
+        d.gather_tp = ZhCalc.add(d.contract_tp, d.qc_tp);
+    }
+}
+function calculateStagePosData(datas) {
+    for (const d of datas) {
+        d.gather_qty = ZhCalc.add(d.contract_qty, d.qc_qty);
+    }
+}
+
+$(document).ready(() => {
+    autoFlashHeight();
+    initSpreadSettingWithRoles([]);
+    const billsSpread = SpreadJsObj.createNewSpread($('#bills-spread')[0]);
+    const billsSheet = billsSpread.getActiveSheet();
+    SpreadJsObj.initSheet(billsSheet, billsSpreadSetting);
+    const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);
+    const posSheet = posSpread.getActiveSheet();
+    SpreadJsObj.initSheet(posSheet, posSpreadSetting);
+
+    $.subMenu({
+        menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
+        toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
+        //key: 'measure.compare.memu.1.0.0',
+        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();
+            posSpread.refresh();
+        }
+    });
+    // 上下窗口resizer
+    $.divResizer({
+        select: '#main-resize',
+        callback: function () {
+            billsSpread.refresh();
+            let bcontent = $(".bcontent-wrap").length > 0 ? $(".bcontent-wrap").height() : 0;
+            $(".sp-wrap").height(bcontent-40);
+            posSpread.refresh();
+        }
+    });
+
+    const cTree = createNewPathTree('master', {
+        id: 'ledger_id',
+        pid: 'ledger_pid',
+        order: 'order',
+        level: 'level',
+        rootId: -1,
+        keys: ['id', 'tender_id', 'ledger_id'],
+        masterId: 'id',
+        minorId: 'lid',
+        calcFields: [],
+    });
+    const cPos = new MasterPosData({
+        id: 'id', ledgerId: 'lid', masterId: 'id', minorId: 'pid',
+        calcFun: function (pos) {
+            pos.gather_qty = ZhCalc.add(pos.contract_qty, pos.qc_qty);
+        }
+    });
+
+    postData(window.location.pathname + '/load', {main: true}, function (result) {
+        cTree.loadDatas(result.main.ledger);
+        cPos.loadDatas(result.main.pos);
+        SpreadJsObj.loadSheetData(billsSheet, SpreadJsObj.DataType.Tree, cTree);
+        loadPosData(0);
+    });
+    function loadPosData(iRow) {
+        const node = iRow ? billsSheet.zh_tree.nodes[iRow] : SpreadJsObj.getSelectObject(billsSheet);
+        if (node) {
+            SpreadJsObj.loadSheetData(posSheet, SpreadJsObj.DataType.Data, cPos.getLedgerPos(node.id));
+        } else {
+            SpreadJsObj.loadSheetData(posSheet, SpreadJsObj.DataType.Data, []);
+        }
+        SpreadJsObj.resetTopAndSelect(posSheet);
+    }
+    billsSheet.bind(spreadNS.Events.SelectionChanged, function (e, info) {
+        if (info.newSelections) {
+            const iNewRow = info.newSelections[0].row;
+            if (info.oldSelections) {
+                const iOldRow = info.oldSelections[0].row;
+                if (iNewRow !== iOldRow) {
+                    loadPosData(iNewRow);
+                }
+            } else {
+                loadPosData(iNewRow);
+            }
+        }
+    });
+    $('#select-qi-ok').click(function () {
+        function refreshView () {
+            const compareStages = [];
+            for (let order = 0, iLength = trs.length; order < iLength; order++) {
+                const tr = trs[order];
+                if ($('input', tr)[0].checked) {
+                    compareStages.push(order + 1);
+                }
+            }
+            //setLocalCache(cCacheKey, compareStages.join(','));
+            initSpreadSettingWithRoles(compareStages);
+            SpreadJsObj.initSheet(billsSheet, billsSpreadSetting);
+            treeCalc.calculateAll(cTree);
+            SpreadJsObj.loadSheetData(billsSheet, SpreadJsObj.DataType.Tree, cTree);
+            SpreadJsObj.initSheet(posSheet, posSpreadSetting);
+            loadPosData();
+        }
+        let loadData = [], showData = [], trs = $('tr[stage-id]');
+        for (let order = 0, iLength = trs.length; order < iLength; order++) {
+            const tr = trs[order];
+            if ($('input[type=checkbox]', tr)[0].checked) {
+                if (!cTree.minorData[order + 1]) {
+                    loadData.push(order + 1);
+                }
+                showData.push(order + 1);
+            }
+        }
+        if (loadData.length > 0) {
+            postData(window.location.pathname + '/load', {stages: loadData}, function (result) {
+                for (const aData of result.stages) {
+                    calculateStageLedgerData(aData.bills);
+                    cTree.loadMinorData(aData.bills, aData.order + '', ['gather_qty', 'gather_tp'], ['gather_tp']);
+                    treeCalc.calculateAll(cTree);
+                    calculateStagePosData(aData.pos);
+                    cPos.loadMinorData(aData.pos, aData.order + '', ['gather_qty']);
+                }
+                refreshView();
+                $('#select-qi').modal('hide');
+            });
+        } else {
+            refreshView();
+            $('#select-qi').modal('hide');
+        }
+    });
+    (function (select, sheet) {
+        if (!sheet.zh_tree) return;
+        $(select).click(function () {
+            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;
+            }
+        });
+    })('a[name=showLevel]', billsSheet);
+});

+ 1 - 0
app/router.js

@@ -134,6 +134,7 @@ module.exports = app => {
     app.get('/tender/:id/measure/gather', sessionAuth, tenderCheck, 'measureController.gather');
     // 计量台账 -- 审核比较
     app.get('/tender/:id/measure/compare', sessionAuth, tenderCheck, 'measureController.compare');
+    app.post('/tender/:id/measure/compare/load', sessionAuth, tenderCheck, 'measureController.loadCompareData');
 
     // 期计量详细
     // 本期计量台账

+ 1 - 1
app/view/ledger/audit.ejs

@@ -20,7 +20,7 @@
                 </div>
             </div>
             <div></div>
-            <div>
+            <div class="ml-auto">
                 <% if (tender.ledger_status === auditConst.status.checkNo) { %>
                     <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm pull-right text-dark">退回意见</a>
                 <% } else if (tender.ledger_status === auditConst.status.checking) { %>

+ 24 - 23
app/view/measure/compare.ejs

@@ -3,10 +3,28 @@
     <div class="panel-title">
         <div class="title-main d-flex">
             <% include ../tender/tender_sub_mini_menu.ejs %>
-            <h2>期审核比较</h2>
             <div>
-                <button href="#cate-set" class="btn btn-sm btn-light" data-toggle="modal" data-target="#select-qi"><i class="fa fa-clone"></i> 选择比较期</button>
+                <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>
+                        </div>
+                    </div>
+                </div>
+                <div class="d-inline-block">
+                    <button href="#cate-set" class="btn btn-sm btn-light text-primary" data-toggle="modal" data-target="#select-qi"><i class="fa fa-clone"></i> 选择比较期</button>
+                </div>
             </div>
+            <div class="ml-auto"></div>
         </div>
     </div>
     <div class="content-wrap">
@@ -14,7 +32,8 @@
         <div class="c-body">
             <div class="sjs-height-1" id="bills-spread">
             </div>
-            <div class="bcontent-wrap">
+            <div class="bcontent-wrap" id="main-bottom">
+                <div id="main-resize" class="resize-y"  r-Type="height" div1="#bills-spread" div2="#main-bottom" store-id="compare-main" store-version="1.0.0" min="100"></div>
                 <div class="bc-bar mb-1">
                     <ul class="nav nav-tabs">
                         <li class="nav-item">
@@ -24,29 +43,11 @@
                 </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>
-<script src="/public/js/sub_menu.js"></script>
-<script>
-    $.subMenu({
-        menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
-        toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
-        //key: 'measure.compare.memu.1.0.0',
-        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();
-        }
-    });
-</script>
+</div>

+ 4 - 4
app/view/measure/compare_modal.ejs

@@ -8,14 +8,14 @@
             <div class="modal-body">
                 <table class="table table-sm">
                     <tr><th>期</th><th width="90">选择</th></tr>
-                    <tr><td>1期</td><td><input type="checkbox"></td></tr>
-                    <tr><td>2期</td><td><input type="checkbox"></td></tr>
-                    <tr><td>3期</td><td><input type="checkbox"></td></tr>
+                    <% for (const s of stages) { %>
+                    <tr stage-id="<%- s.id %>"><td><%- s.order %>期</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>

+ 28 - 24
app/view/stage/compare.ejs

@@ -3,32 +3,36 @@
     <div class="panel-title">
         <div class="title-main d-flex">
             <% include ./stage_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>
-                    </div>
-                </div>
-            </div>
             <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 text-primary" for="customCheckDisabled">显示本期计量</label>
+                <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>
+                        </div>
                     </div>
-                </a>
-                <% 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 class="d-inline-block">
+                    <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 text-primary" for="customCheckDisabled">显示本期计量</label>
+                        </div>
+                    </a>
+                </div>
+                <div class="d-inline-block">
+                    <% 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>

+ 18 - 1
config/web.js

@@ -243,7 +243,24 @@ const JsFiles = {
                 ],
                 mergeFile: 'stage_compare',
             }
-        }
+        },
+        measure: {
+            compare: {
+                files: [
+                    "/public/js/spreadjs/sheets/gc.spread.sheets.all.10.0.1.min.js",
+                    "/public/js/decimal.min.js",
+                ],
+                mergeFiles: [
+                    "/public/js/sub_menu.js",
+                    "/public/js/div_resizer.js",
+                    "/public/js/spreadjs_rela/spreadjs_zh.js",
+                    "/public/js/zh_calc.js",
+                    "/public/js/path_tree.js",
+                    "/public/js/measure_compare.js"
+                ],
+                mergeFile: 'measure_compare',
+            }
+        },
     }
 
 };