Просмотр исходного кода

台账修订,错误列表相关

MaiXinRong 5 лет назад
Родитель
Сommit
5588f86959

+ 3 - 4
app/controller/revise_controller.js

@@ -776,7 +776,7 @@ module.exports = app => {
             }
         }
         /**
-         * 上报(post)
+         * 上报(ajax-post)
          *
          * @param ctx
          * @return {Promise<void>}
@@ -794,11 +794,10 @@ module.exports = app => {
 
                 await ctx.service.reviseAudit.start(revise, revise.times);
 
-                ctx.redirect('/tender/' + ctx.tender.id + '/revise/info');
+                ctx.body = {err: 0, msg: '', data: {}};
             } catch (err) {
                 this.log(err);
-                this.postError(err, '上报失败');
-                ctx.redirect('/tender/' + ctx.tender.id + '/revise/info');
+                ctx.body = this.ajaxErrorBody(err, '上报失败');
             }
         }
         /**

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

@@ -32,7 +32,7 @@ function autoFlashHeight(){
     $(".sjs-sh-4").height($(window).height()-cHeader-sBar4-92+55);
     $(".sjs-sh-5").height($(window).height()-cHeader-sBar5-92+55);
     for (const sh of $('.sjs-sh')) {
-        $(sh).height($(window).height()-cHeader-getObjHeight($('.sjs-bar', sh.parent))-92+55);
+        $(sh).height($(window).height()-cHeader-getObjHeight($('.sjs-bar', sh.parentNode))-92+55);
     }
 };
 $(window).resize(autoFlashHeight);

+ 1 - 26
app/public/js/ledger.js

@@ -56,30 +56,6 @@ $(document).ready(function() {
     });
     const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);
 
-
-    const showSideTools = function (show) {
-        const left = $('#left-view'), right = $('#right-view'), parent = left.parent();
-        if (show) {
-            right.show();
-            autoFlashHeight();
-            /**
-             * right.show()后, parent被撑开成2倍left.height, 导致parent.width减少了10px
-             * 第一次left.width调整后,parent的缩回left.height, 此时parent.width又增加了10px
-             * 故需要通过最终的parent.width再计算一次left.width
-             *
-             * Q: 为什么不通过先计算left.width的宽度,以避免计算两次left.width?
-             * A: 右侧工具栏不一定显示,当右侧工具栏显示过一次后,就必须使用parent和right来计算left.width
-             *
-             */
-                //left.css('width', parent.width() - right.outerWidth());
-                //left.css('width', parent.width() - right.outerWidth());
-            const percent = 100 - right.outerWidth() /parent.width() * 100;
-            left.css('width', percent + '%');
-        } else {
-            left.width(parent.width());
-            right.hide();
-        }
-    };
     const errorList = $.cs_errorList({
         tabSelector: '#error-list-tab',
         selector: '#error-list',
@@ -92,7 +68,6 @@ $(document).ready(function() {
             ledgerSpread.refresh();
             if (posSpread) posSpread.refresh();
         },
-        showSideTools: showSideTools,
     });
 
     $.subMenu({
@@ -2623,7 +2598,7 @@ $(document).ready(function() {
                     for (const field of checkFields) {
                         checkData[field] = b[field] ? b[field] : 0;
                     }
-                    for (p of pr) {
+                    for (const p of pr) {
                         for (const field of checkFields) {
                             calcData[field] = ZhCalc.add(calcData[field], p[field]);
                         }

+ 0 - 225
app/public/js/ledger_search.js

@@ -1,225 +0,0 @@
-'use strict';
-
-/**
- * 台账搜索相关
- * 多个页面均使用:
- * 0好台账:台账分解、台账审批、台账修订、部位台账
- * 期计量:计量台账、部位台账
- *
- * 搜索基于spreadjs,请放在gc.spread.sheets.all.10.0.1.min.js/spreadjs_zh.js之后
- *
- * @author Mai
- * @date
- * @version
- */
-
-(function($){
-    $.posSearch = function (setting) {
-        if (!setting.selector || !setting.searchSpread) return;
-        const searchHtml =
-            '                                <div class="ml-2">\n' +
-            '                                    <div class="input-group input-group-sm">\n' +
-            '                                        <input type="text" class="form-control" placeholder="输入名称查找" id="pos-keyword">\n' +
-            '                                        <div class="input-group-append">\n' +
-            '                                            <span class="input-group-text" id="pos-search-hint">结果:0</span>\n' +
-            '                                        </div>\n' +
-            '                                        <div class="input-group-append" >\n' +
-            '                                            <button class="btn btn-outline-secondary" type="button" title="上一个" id="search-pre-pos"><i class="fa fa-angle-double-left"></i></button>\n' +
-            '                                            <button class="btn btn-outline-secondary" type="button" title="下一个" id="search-next-pos"><i class="fa fa-angle-double-right"></i></button>\n' +
-            '                                        </div>\n' +
-            '                                    </div>\n' +
-            '                                </div>\n';
-        $(setting.selector).html(searchHtml);
-        const sheet = setting.searchSpread.getActiveSheet();
-        const searchObj = (function () {
-            let resultArr = [];
-            const search = function (keyword) {
-                if (keyword && keyword !== '') {
-                    resultArr = [];
-                    const sortData = sheet.zh_data;
-                    if (sortData) {
-                        for (let i = 0, iLength = sortData.length; i < iLength; i++) {
-                            const sd = sortData[i];
-                            if (sd.name && sd.name.indexOf(keyword) > -1) {
-                                resultArr.push({index: i, data: sd});
-                            }
-                        }
-                    }
-                } else {
-                    resultArr = [];
-                }
-                $('#pos-search-hint').html('结果:' + resultArr.length);
-            };
-            const searchAndLocate = function (keyword) {
-                search(keyword);
-                if (resultArr.length > 0) {
-                    const sel = sheet.getSelections()[0];
-                    const curRow = sel ? sel.row : 0;
-                    const pos = resultArr[0];
-                    if (pos.index !== curRow) {
-                        sheet.setSelection(pos.index, sel ? sel.col : 0, 1, 1);
-                        sheet.getParent().focus();
-                        sheet.showRow(pos.index, spreadNS.VerticalPosition.center);
-                    }
-                }
-            };
-            const locateNext = function () {
-                if (resultArr.length > 0) {
-                    const sel = sheet.getSelections()[0];
-                    const curRow = sel ? sel.row : 0;
-                    let next = _.find(resultArr, function (d) {
-                        return d.index > curRow;
-                    });
-                    if (!next) next = resultArr[0];
-                    if (next.index !== curRow) {
-                        sheet.setSelection(next.index, sel ? sel.col : 0, 1, 1);
-                        sheet.getParent().focus();
-                        sheet.showRow(next.index, spreadNS.VerticalPosition.center);
-                    }
-                }
-            };
-            const locatePre = function () {
-                if (resultArr.length > 0) {
-                    const sel = sheet.getSelections()[0];
-                    const curRow = sel ? sel.row : 0;
-                    let next = _.findLast(resultArr, function (d) {
-                        return d.index < curRow;
-                    });
-                    if (!next) next = resultArr[resultArr.length - 1];
-                    if (next.index !== curRow) {
-                        sheet.setSelection(next.index, sel ? sel.col : 0, 1, 1);
-                        sheet.getParent().focus();
-                        sheet.showRow(next.index, spreadNS.VerticalPosition.center);
-                    }
-                }
-            };
-            return {search, searchAndLocate, locateNext, locatePre};
-        })();
-        // $('#pos-keyword').bind('input propertychange', function () {
-        //     posSearch.search(this.value);
-        // });
-        $('#pos-keyword').bind('keydown', function(e){
-            if (e.keyCode == 13) searchObj.searchAndLocate(this.value);
-        });
-        $('#search-pre-pos').click(function () {
-            searchObj.locatePre();
-        });
-        $('#search-next-pos').click(function () {
-            searchObj.locateNext();
-        });
-        return searchObj;
-    };
-    $.billsSearch = function (setting) {
-        if (!setting.selector || !setting.searchSpread || !setting.resultSpreadSetting) return;
-        if (!setting.searchRangeStr) setting.searchRangeStr = '项目节编号/清单编号/名称';
-        const resultId = setting.id + '-search-result';
-        const obj = $(setting.selector);
-        obj.html(
-            '                        <div class="sjs-bar">\n' +
-            '                            <div class="input-group input-group-sm pb-1">\n' +
-            '                                <div class="input-group-prepend">\n' +
-            (setting.searchOver ? '                                    <div class="input-group-text"><input type="radio" name="searchType" id="over"> 超计</div>\n' : '') +
-            (setting.searchEmpty ? '                                    <div class="input-group-text"><input type="radio" name="searchType" id="empty"> 漏计</div>\n' : '') +
-            '                                </div>' +
-            '                                <input id="searchKeyword" type="text" class="form-control" placeholder="可查找 ' + setting.searchRangeStr + '" aria-label="Recipient\'s username" aria-describedby="button-addon2">\n' +
-            '                                <div class="input-group-append">\n' +
-            '                                    <button class="btn btn-outline-secondary" type="button"">搜索</button>\n' +
-            '                                </div>\n' +
-            '                            </div>\n' +
-            '                        </div>\n' +
-            '                        <div id="' + resultId + '" class="sjs-sh">\n' +
-            '                        </div>'
-        );
-        autoFlashHeight();
-        const resultSpread = SpreadJsObj.createNewSpread($('#' + resultId)[0]);
-        SpreadJsObj.initSheet(resultSpread.getActiveSheet(), setting.resultSpreadSetting);
-        SpreadJsObj.forbiddenSpreadContextMenu('#' + resultId, resultSpread);
-        const searchSheet = setting.searchSpread.getActiveSheet();
-        let searchResult = [];
-        const searchBills = function () {
-            const keyword = $('#searchKeyword', obj).val();
-            searchResult = [];
-            const sortData = SpreadJsObj.getSortData(searchSheet);
-            for (const node of sortData) {
-                if ((node.code && node.code.indexOf(keyword) > -1) ||
-                    node.b_code && node.b_code.indexOf(keyword) > -1 ||
-                    node.name && node.name.indexOf(keyword) > -1) {
-                    const data = JSON.parse(JSON.stringify(node));
-                    data.visible = true;
-                    searchResult.push(data);
-                }
-            }
-            SpreadJsObj.loadSheetData(resultSpread.getActiveSheet(), 'data', searchResult);
-        };
-        const calculateCompletePercent = function (searchResult) {
-            if (!searchResult) return;
-            for (const sr of searchResult) {
-                const base = ZhCalc.add(sr.total_price, sr.end_qc_tp);
-                sr.complete_percent = base !== 0 ? ZhCalc.mul(ZhCalc.div(sr.end_gather_tp, base), 100, 2) : 0;
-            }
-        };
-        const searchOver = function () {
-            searchResult = [];
-            const sortData = SpreadJsObj.getSortData(searchSheet);
-            for (const node of sortData) {
-                if (node.children && node.children.length > 0) continue;
-                if (setting.checkOver && setting.checkOver(node)) {
-                    const data = JSON.parse(JSON.stringify(node));
-                    data.visible = true;
-                    searchResult.push(data);
-                }
-            }
-            calculateCompletePercent(searchResult);
-            SpreadJsObj.loadSheetData(resultSpread.getActiveSheet(), 'data', searchResult);
-        };
-        const searchEmpty = function () {
-            searchResult = [];
-            const sortData = SpreadJsObj.getSortData(searchSheet);
-            for (const node of sortData) {
-                if (node.children && node.children.length > 0) continue;
-                if (setting.checkEmpty && setting.checkEmpty(node)) {
-                    const data = JSON.parse(JSON.stringify(node));
-                    data.visible = true;
-                    searchResult.push(data);
-                }
-            }
-            calculateCompletePercent(searchResult);
-            SpreadJsObj.loadSheetData(resultSpread.getActiveSheet(), 'data', searchResult);
-        };
-        const searchLess = function () {
-            searchResult = [];
-            const sortData = SpreadJsObj.getSortData(searchSheet);
-            for (const node of sortData) {
-                if (node.children && node.children.length > 0) continue;
-                if (setting.checkLess && setting.checkLess(node)) {
-                    const data = JSON.parse(JSON.stringify(node));
-                    data.visible = true;
-                    searchResult.push(data);
-                }
-            }
-            calculateCompletePercent(searchResult);
-            SpreadJsObj.loadSheetData(resultSpread.getActiveSheet(), 'data', searchResult);
-        };
-
-        $('input', obj).bind('keydown', function (e) {
-            if (e.keyCode == 13) searchBills();
-        });
-        $('button', obj).bind('click', () => {searchBills()});
-        $('#over', obj).bind('change', () => {searchOver()});
-        $('#empty', obj).bind('change', () => {searchLess()});
-        resultSpread.getActiveSheet().bind(spreadNS.Events.CellDoubleClick, function (e, info) {
-            const sheet = info.sheet;
-            const data = sheet.zh_data;
-            if (!data) { return }
-
-            const curBills = data[info.row];
-            if (!curBills) { return }
-
-            SpreadJsObj.locateTreeNode(searchSheet, curBills.ledger_id, true);
-            if (setting.afterLocated) {
-                setting.afterLocated();
-            }
-        });
-        return {spread: resultSpread};
-    };
-})(jQuery);

+ 71 - 24
app/public/js/revise.js

@@ -34,6 +34,20 @@ $(document).ready(() => {
 
     const posSearch = $.posSearch({selector: '#pos-search', searchSpread: posSpread});
 
+    const errorList = $.cs_errorList({
+        tabSelector: '#error-list-tab',
+        selector: '#error-list',
+        relaSpread: billsSpread,
+        storeKey: 'revise-error-' + window.location.pathname.split('/')[2] + '-' + window.location.pathname.split('/')[4],
+        afterLocated:  function () {
+            posSpreadObj.loadCurPosData();
+        },
+        afterShow: function () {
+            billsSpread.refresh();
+            if (posSpread) posSpread.refresh();
+        },
+    });
+
     // 初始化 节点树结构
     const treeSetting = {
         id: 'ledger_id',
@@ -1940,29 +1954,6 @@ $(document).ready(() => {
         }
     });
 
-    const showSideTools = function (show) {
-        const left = $('#left-view'), right = $('#right-view'), parent = left.parent();
-        if (show) {
-            right.show();
-            autoFlashHeight();
-            /**
-             * right.show()后, parent被撑开成2倍left.height, 导致parent.width减少了10px
-             * 第一次left.width调整后,parent的缩回left.height, 此时parent.width又增加了10px
-             * 故需要通过最终的parent.width再计算一次left.width
-             *
-             * Q: 为什么不通过先计算left.width的宽度,以避免计算两次left.width?
-             * A: 右侧工具栏不一定显示,当右侧工具栏显示过一次后,就必须使用parent和right来计算left.width
-             *
-             */
-                //left.css('width', parent.width() - right.outerWidth());
-                //left.css('width', parent.width() - right.outerWidth());
-            const percent = 100 - right.outerWidth() /parent.width() * 100;
-            left.css('width', percent + '%');
-        } else {
-            left.width(parent.width());
-            right.hide();
-        }
-    };
     $('#content-tab').addClass('active');
     $('#xd-content').addClass('active');
     showSideTools(true);
@@ -2109,7 +2100,7 @@ $(document).ready(() => {
             } else if (tab.attr('content') === '#bg-bills') {
                 bgBills.loadData();
                 bgBills.spread.refresh();
-            } else if (tab.attr('content') === '#search' && !searchLedger) {
+            } else if (tab.attr('content') === '#search') {
                 if (!searchLedger) {
                     searchLedger = $.billsSearch({
                         selector: '#search',
@@ -2137,6 +2128,8 @@ $(document).ready(() => {
                     });
                 }
                 searchLedger.spread.refresh();
+            } else if (tab.attr('content') === '#error-list') {
+                errorList.spread.refresh();
             }
         }
         else {// 收起工具栏
@@ -2186,5 +2179,59 @@ $(document).ready(() => {
             }
         });
     })('a[name=showLevel]', billsSheet);
+
+    const dataChecker = DataChecker({
+        loadUrl: window.location.pathname + '/load',
+        loadData: {},
+        checkFun: function (data, progress) {
+            billsTree.loadDatas(data.bills);
+            treeCalc.calculateAll(billsTree);
+            SpreadJsObj.loadSheetData(billsSheet, 'tree', billsTree);
+
+            pos.loadDatas(data.pos);
+            posSpreadObj.loadCurPosData();
+
+            const checkFields = ['sgfh_qty', 'qtcl_qty', 'sjcl_qty', 'quantity'], result = [];
+            const iLen = data.bills.length;
+            for (const [i, b] of data.bills.entries()) {
+                const pr = _.filter(data.pos, {lid: b.id});
+                if (pr && pr.length > 0) {
+                    const checkData = {}, calcData = {};
+                    for (const field of checkFields) {
+                        checkData[field] = b[field] ? b[field] : 0;
+                    }
+                    for (const p of pr) {
+                        for (const field of checkFields) {
+                            calcData[field] = ZhCalc.add(calcData[field], p[field]);
+                        }
+                    }
+                    for (const field of checkFields) {
+                        calcData[field] = calcData[field] ? calcData[field] : 0;
+                    }
+                    if (!_.isMatch(checkData, calcData)) {
+                        result.push({
+                            ledger_id: b.ledger_id,
+                            b_code: b.b_code,
+                            name: b.name,
+                            serialNo: billsTree.getNodeIndex(billsTree.getItems(b.ledger_id)) + 1,
+                            error: {checkData: checkData, calcData: calcData}
+                        })
+                    }
+                    progress(parseInt((i+1)/iLen*100));
+                }
+            }
+            return result;
+        },
+        errorList: errorList,
+    });
+    $('[name=revise-start]').submit(function (e) {
+        if (checkAuditorFrom()) {
+            $(this).parent().parent().parent().modal('hide');
+            const formData = new FormData();
+            dataChecker.checkAndPost(this.action, formData);
+            $('#hide-all').hide();
+        }
+        return false;
+    });
 });
 

+ 244 - 2
app/public/js/shares/cs_tools.js

@@ -1,16 +1,49 @@
 'use strict';
 
 /**
+ * cs_errorList:错误列表
+ * 使用范围:
+ *    台账分解(原报)、台账修订(原报)、计量台账(所有角色)
  *
+ * posSearch & billsSearch:台账搜索相关
+ * 使用范围:
+ *    0号台账:台账分解、台账审批、台账修订、部位台账;
+ *    期计量:计量台账、部位台账
+ *
+ * 所有工具均基于spreadjs,请放在gc.spread.sheets.all.10.0.1.min.js/spreadjs_zh.js之后
  *
  * @author Mai
  * @date
  * @version
  */
 
+const showSideTools = function (show) {
+    const left = $('#left-view'), right = $('#right-view'), parent = left.parent();
+    if (show) {
+        right.show();
+        autoFlashHeight();
+        /**
+         * right.show()后, parent被撑开成2倍left.height, 导致parent.width减少了10px
+         * 第一次left.width调整后,parent的缩回left.height, 此时parent.width又增加了10px
+         * 故需要通过最终的parent.width再计算一次left.width
+         *
+         * Q: 为什么不通过先计算left.width的宽度,以避免计算两次left.width?
+         * A: 右侧工具栏不一定显示,当右侧工具栏显示过一次后,就必须使用parent和right来计算left.width
+         *
+         */
+            //left.css('width', parent.width() - right.outerWidth());
+            //left.css('width', parent.width() - right.outerWidth());
+        const percent = 100 - right.outerWidth() /parent.width() * 100;
+        left.css('width', percent + '%');
+    } else {
+        left.width(parent.width());
+        right.hide();
+    }
+};
+
 (function($){
     /**
-     *
+     * 错误列表
      * @param setting
      * {
      *      tabSelector: 'a[content=#error-list]',
@@ -86,10 +119,219 @@
             tab.addClass('active');
             $('.tab-content .tab-pane').removeClass('active');
             tabPanel.addClass('active');
-            setting.showSideTools(true);
+            showSideTools(true);
             spread.refresh();
             if (setting.afterShow) setting.afterShow();
         };
         return {spread: spread, loadErrorData: loadErrorData, show: showErrorList};
     };
+
+    $.posSearch = function (setting) {
+        if (!setting.selector || !setting.searchSpread) return;
+        const searchHtml =
+            '                                <div class="ml-2">\n' +
+            '                                    <div class="input-group input-group-sm">\n' +
+            '                                        <input type="text" class="form-control" placeholder="输入名称查找" id="pos-keyword">\n' +
+            '                                        <div class="input-group-append">\n' +
+            '                                            <span class="input-group-text" id="pos-search-hint">结果:0</span>\n' +
+            '                                        </div>\n' +
+            '                                        <div class="input-group-append" >\n' +
+            '                                            <button class="btn btn-outline-secondary" type="button" title="上一个" id="search-pre-pos"><i class="fa fa-angle-double-left"></i></button>\n' +
+            '                                            <button class="btn btn-outline-secondary" type="button" title="下一个" id="search-next-pos"><i class="fa fa-angle-double-right"></i></button>\n' +
+            '                                        </div>\n' +
+            '                                    </div>\n' +
+            '                                </div>\n';
+        $(setting.selector).html(searchHtml);
+        const sheet = setting.searchSpread.getActiveSheet();
+        const searchObj = (function () {
+            let resultArr = [];
+            const search = function (keyword) {
+                if (keyword && keyword !== '') {
+                    resultArr = [];
+                    const sortData = sheet.zh_data;
+                    if (sortData) {
+                        for (let i = 0, iLength = sortData.length; i < iLength; i++) {
+                            const sd = sortData[i];
+                            if (sd.name && sd.name.indexOf(keyword) > -1) {
+                                resultArr.push({index: i, data: sd});
+                            }
+                        }
+                    }
+                } else {
+                    resultArr = [];
+                }
+                $('#pos-search-hint').html('结果:' + resultArr.length);
+            };
+            const searchAndLocate = function (keyword) {
+                search(keyword);
+                if (resultArr.length > 0) {
+                    const sel = sheet.getSelections()[0];
+                    const curRow = sel ? sel.row : 0;
+                    const pos = resultArr[0];
+                    if (pos.index !== curRow) {
+                        sheet.setSelection(pos.index, sel ? sel.col : 0, 1, 1);
+                        sheet.getParent().focus();
+                        sheet.showRow(pos.index, spreadNS.VerticalPosition.center);
+                    }
+                }
+            };
+            const locateNext = function () {
+                if (resultArr.length > 0) {
+                    const sel = sheet.getSelections()[0];
+                    const curRow = sel ? sel.row : 0;
+                    let next = _.find(resultArr, function (d) {
+                        return d.index > curRow;
+                    });
+                    if (!next) next = resultArr[0];
+                    if (next.index !== curRow) {
+                        sheet.setSelection(next.index, sel ? sel.col : 0, 1, 1);
+                        sheet.getParent().focus();
+                        sheet.showRow(next.index, spreadNS.VerticalPosition.center);
+                    }
+                }
+            };
+            const locatePre = function () {
+                if (resultArr.length > 0) {
+                    const sel = sheet.getSelections()[0];
+                    const curRow = sel ? sel.row : 0;
+                    let next = _.findLast(resultArr, function (d) {
+                        return d.index < curRow;
+                    });
+                    if (!next) next = resultArr[resultArr.length - 1];
+                    if (next.index !== curRow) {
+                        sheet.setSelection(next.index, sel ? sel.col : 0, 1, 1);
+                        sheet.getParent().focus();
+                        sheet.showRow(next.index, spreadNS.VerticalPosition.center);
+                    }
+                }
+            };
+            return {search, searchAndLocate, locateNext, locatePre};
+        })();
+        // $('#pos-keyword').bind('input propertychange', function () {
+        //     posSearch.search(this.value);
+        // });
+        $('#pos-keyword').bind('keydown', function(e){
+            if (e.keyCode == 13) searchObj.searchAndLocate(this.value);
+        });
+        $('#search-pre-pos').click(function () {
+            searchObj.locatePre();
+        });
+        $('#search-next-pos').click(function () {
+            searchObj.locateNext();
+        });
+        return searchObj;
+    };
+    $.billsSearch = function (setting) {
+        if (!setting.selector || !setting.searchSpread || !setting.resultSpreadSetting) return;
+        if (!setting.searchRangeStr) setting.searchRangeStr = '项目节编号/清单编号/名称';
+        const resultId = setting.id + '-search-result';
+        const obj = $(setting.selector);
+        obj.html(
+            '                        <div class="sjs-bar">\n' +
+            '                            <div class="input-group input-group-sm pb-1">\n' +
+            '                                <div class="input-group-prepend">\n' +
+            (setting.searchOver ? '                                    <div class="input-group-text"><input type="radio" name="searchType" id="over"> 超计</div>\n' : '') +
+            (setting.searchEmpty ? '                                    <div class="input-group-text"><input type="radio" name="searchType" id="empty"> 漏计</div>\n' : '') +
+            '                                </div>' +
+            '                                <input id="searchKeyword" type="text" class="form-control" placeholder="可查找 ' + setting.searchRangeStr + '" aria-label="Recipient\'s username" aria-describedby="button-addon2">\n' +
+            '                                <div class="input-group-append">\n' +
+            '                                    <button class="btn btn-outline-secondary" type="button"">搜索</button>\n' +
+            '                                </div>\n' +
+            '                            </div>\n' +
+            '                        </div>\n' +
+            '                        <div id="' + resultId + '" class="sjs-sh">\n' +
+            '                        </div>'
+        );
+        autoFlashHeight();
+        const resultSpread = SpreadJsObj.createNewSpread($('#' + resultId)[0]);
+        SpreadJsObj.initSheet(resultSpread.getActiveSheet(), setting.resultSpreadSetting);
+        SpreadJsObj.forbiddenSpreadContextMenu('#' + resultId, resultSpread);
+        const searchSheet = setting.searchSpread.getActiveSheet();
+        let searchResult = [];
+        const searchBills = function () {
+            const keyword = $('#searchKeyword', obj).val();
+            searchResult = [];
+            const sortData = SpreadJsObj.getSortData(searchSheet);
+            for (const node of sortData) {
+                if ((node.code && node.code.indexOf(keyword) > -1) ||
+                    node.b_code && node.b_code.indexOf(keyword) > -1 ||
+                    node.name && node.name.indexOf(keyword) > -1) {
+                    const data = JSON.parse(JSON.stringify(node));
+                    data.visible = true;
+                    searchResult.push(data);
+                }
+            }
+            SpreadJsObj.loadSheetData(resultSpread.getActiveSheet(), 'data', searchResult);
+        };
+        const calculateCompletePercent = function (searchResult) {
+            if (!searchResult) return;
+            for (const sr of searchResult) {
+                const base = ZhCalc.add(sr.total_price, sr.end_qc_tp);
+                sr.complete_percent = base !== 0 ? ZhCalc.mul(ZhCalc.div(sr.end_gather_tp, base), 100, 2) : 0;
+            }
+        };
+        const searchOver = function () {
+            searchResult = [];
+            const sortData = SpreadJsObj.getSortData(searchSheet);
+            for (const node of sortData) {
+                if (node.children && node.children.length > 0) continue;
+                if (setting.checkOver && setting.checkOver(node)) {
+                    const data = JSON.parse(JSON.stringify(node));
+                    data.visible = true;
+                    searchResult.push(data);
+                }
+            }
+            calculateCompletePercent(searchResult);
+            SpreadJsObj.loadSheetData(resultSpread.getActiveSheet(), 'data', searchResult);
+        };
+        const searchEmpty = function () {
+            searchResult = [];
+            const sortData = SpreadJsObj.getSortData(searchSheet);
+            for (const node of sortData) {
+                if (node.children && node.children.length > 0) continue;
+                if (setting.checkEmpty && setting.checkEmpty(node)) {
+                    const data = JSON.parse(JSON.stringify(node));
+                    data.visible = true;
+                    searchResult.push(data);
+                }
+            }
+            calculateCompletePercent(searchResult);
+            SpreadJsObj.loadSheetData(resultSpread.getActiveSheet(), 'data', searchResult);
+        };
+        const searchLess = function () {
+            searchResult = [];
+            const sortData = SpreadJsObj.getSortData(searchSheet);
+            for (const node of sortData) {
+                if (node.children && node.children.length > 0) continue;
+                if (setting.checkLess && setting.checkLess(node)) {
+                    const data = JSON.parse(JSON.stringify(node));
+                    data.visible = true;
+                    searchResult.push(data);
+                }
+            }
+            calculateCompletePercent(searchResult);
+            SpreadJsObj.loadSheetData(resultSpread.getActiveSheet(), 'data', searchResult);
+        };
+
+        $('input', obj).bind('keydown', function (e) {
+            if (e.keyCode == 13) searchBills();
+        });
+        $('button', obj).bind('click', () => {searchBills()});
+        $('#over', obj).bind('change', () => {searchOver()});
+        $('#empty', obj).bind('change', () => {searchLess()});
+        resultSpread.getActiveSheet().bind(spreadNS.Events.CellDoubleClick, function (e, info) {
+            const sheet = info.sheet;
+            const data = sheet.zh_data;
+            if (!data) { return }
+
+            const curBills = data[info.row];
+            if (!curBills) { return }
+
+            SpreadJsObj.locateTreeNode(searchSheet, curBills.ledger_id, true);
+            if (setting.afterLocated) {
+                setting.afterLocated();
+            }
+        });
+        return {spread: resultSpread};
+    };
 })(jQuery);

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

@@ -170,6 +170,8 @@
                         <div id="bg-bills-spread" class="sjs-sh">
                         </div>
                     </div>
+                    <div id="error-list" class="tab-pane">
+                    </div>
                 </div>
             </div>
         </div>
@@ -195,6 +197,9 @@
                 <li class="nav-item">
                     <a class="nav-link" content="#bg-bills" href="javascript: void(0);">变更清单</a>
                 </li>
+                <li class="nav-item">
+                    <a class="nav-link" content="#error-list" id="error-list-tab" href="javascript: void(0);" style="display: none;">错误列表</a>
+                </li>
             </ul>
         </div>
     </div>

+ 4 - 2
app/view/revise/info_modal.ejs

@@ -80,7 +80,7 @@
                     </div>
                 </div>
             </div>
-            <form class="modal-footer" method="post" action="/tender/<%- ctx.tender.id %>/revise/audit/start" onsubmit="return checkAuditorFrom()">
+            <form class="modal-footer" method="post" action="/tender/<%- ctx.tender.id %>/revise/audit/start" name="revise-start">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
                 <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
                 <button class="btn btn-primary btn-sm" type="submit">确认上报</button>
@@ -191,7 +191,7 @@
                     </div>
                 </div>
             </div>
-            <form class="modal-footer" action="/tender/<%- ctx.tender.id %>/revise/audit/start" method="post" onsubmit="return checkAuditorFrom()">
+            <form class="modal-footer" action="/tender/<%- ctx.tender.id %>/revise/audit/start" method="post" name="revise-start">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
                 <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
                 <button type="submit" class="btn btn-primary btn-sm">确认上报</button>
@@ -569,6 +569,7 @@
 <% include ../shares/merge_peg_modal.ejs %>
 <% include ../shares/import_excel_modal.ejs %>
 <% include ../shares/delete_hint_modal.ejs %>
+<% include ../shares/check_data_modal.ejs %>
 <script>
     <% if (ctx.session.sessionUser.accountId === revise.uid && (revise.status === audit.status.uncheck || revise.status === audit.status.checkNo)) { %>
     const accountList = JSON.parse('<%- JSON.stringify(accountList) %>');
@@ -689,6 +690,7 @@
             return false;
         }
         $('#hide-all').show();
+        return true;
     }
 
     // texterea换行

+ 6 - 4
app/view/shares/check_data_modal.ejs

@@ -60,8 +60,10 @@
             $('.progress-bar').attr('aria-valuenow', percent).width(percent + '%').html(percent + '%');
         }
         const addProgress = function (percent) {
-            const oldPercent = parseInt($('.progress-bar').attr('aria-valuenow'));
-            progress(oldPercent + percent);
+            if (percent % 2 === 0) {
+                const oldPercent = parseInt($('.progress-bar').attr('aria-valuenow'));
+                progress(oldPercent + percent/2);
+            }
         }
         const checkAndPost = async function (postUrl, postForm) {
             progress(0);
@@ -75,8 +77,8 @@
                     $('#check-error-hint').modal('show');
                     setting.errorList.loadErrorData(result);
                 } else {
-                    postDataWithFile(postUrl, postForm, function (data) {
-                        if (data.url) window.location.href = data.url;
+                    postDataWithFile(postUrl, postForm, function () {
+                        window.location.reload();
                     });
                 }
             }, 1000);

+ 8 - 10
config/web.js

@@ -136,14 +136,13 @@ const JsFiles = {
                     "/public/js/math.min.js",
                     "/public/js/file-saver/FileSaver.js",
                     "/public/js/shares/export_excel.js",
-                    "/public/js/shares/cs_tools.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/ledger_search.js",
+                    "/public/js/shares/cs_tools.js",
                     "/public/js/shares/merge_peg.js",
                     "/public/js/zh_calc.js",
                     "/public/js/path_tree.js",
@@ -157,14 +156,13 @@ const JsFiles = {
                 files: [
                     "/public/js/spreadjs/sheets/v11/gc.spread.sheets.all.11.2.2.min.js",
                     "/public/js/decimal.min.js",
-                    "/public/js/shares/cs_tools.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/ledger_search.js",
+                    "/public/js/shares/cs_tools.js",
                     "/public/js/zh_calc.js",
                     "/public/js/path_tree.js",
                     "/public/js/ledger_audit.js",
@@ -184,7 +182,7 @@ const JsFiles = {
                     "/public/js/div_resizer.js",
                     "/public/js/spreadjs_rela/spreadjs_zh.js",
                     "/public/js/shares/sjs_setting.js",
-                    "/public/js/ledger_search.js",
+                    "/public/js/shares/cs_tools.js",
                     "/public/js/zh_calc.js",
                     "/public/js/path_tree.js",
                     "/public/js/shares/bills_pos_convert.js",
@@ -220,7 +218,7 @@ const JsFiles = {
                     "/public/js/sub_menu.js",
                     "/public/js/div_resizer.js",
                     "/public/js/spreadjs_rela/spreadjs_zh.js",
-                    "/public/js/ledger_search.js",
+                    "/public/js/shares/cs_tools.js",
                     "/public/js/zh_calc.js",
                     "/public/js/path_tree.js",
                     "/public/js/std_lib.js",
@@ -243,7 +241,7 @@ const JsFiles = {
                     "/public/js/div_resizer.js",
                     "/public/js/spreadjs_rela/spreadjs_zh.js",
                     "/public/js/shares/sjs_setting.js",
-                    "/public/js/ledger_search.js",
+                    "/public/js/shares/cs_tools.js",
                     "/public/js/shares/merge_peg.js",
                     "/public/js/zh_calc.js",
                     "/public/js/path_tree.js",
@@ -262,7 +260,7 @@ const JsFiles = {
                     "/public/js/div_resizer.js",
                     "/public/js/spreadjs_rela/spreadjs_zh.js",
                     "/public/js/shares/sjs_setting.js",
-                    "/public/js/ledger_search.js",
+                    "/public/js/shares/cs_tools.js",
                     "/public/js/zh_calc.js",
                     "/public/js/path_tree.js",
                     "/public/js/revise_history.js",
@@ -284,7 +282,7 @@ const JsFiles = {
                     "/public/js/msg_box.js",
                     "/public/js/spreadjs_rela/spreadjs_zh.js",
                     "/public/js/shares/sjs_setting.js",
-                    "/public/js/ledger_search.js",
+                    "/public/js/shares/cs_tools.js",
                     "/public/js/shares/merge_peg.js",
                     "/public/js/zh_calc.js",
                     "/public/js/path_tree.js",
@@ -338,7 +336,7 @@ const JsFiles = {
                     "/public/js/div_resizer.js",
                     "/public/js/spreadjs_rela/spreadjs_zh.js",
                     "/public/js/shares/sjs_setting.js",
-                    "/public/js/ledger_search.js",
+                    "/public/js/shares/cs_tools.js",
                     "/public/js/zh_calc.js",
                     "/public/js/path_tree.js",
                     "/public/js/shares/bills_pos_convert.js",