Browse Source

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

laiguoran 3 năm trước cách đây
mục cha
commit
2edf2ea7d3

+ 5 - 2
app/controller/revise_controller.js

@@ -461,7 +461,8 @@ module.exports = app => {
                         }
                     }
                 }
-                ctx.body = { err: 0, msg: '', data: { bills: reviseBills, pos: revisePos } };
+                const ledgerTags = await this.ctx.service.ledgerTag.getDatas(ctx.tender.id);
+                ctx.body = { err: 0, msg: '', data: { bills: reviseBills, pos: revisePos, tags: ledgerTags } };
             } catch (err) {
                 ctx.helper.log(err);
                 this.ajaxErrorBody(err, '加载台账修订数据错误');
@@ -1011,8 +1012,10 @@ module.exports = app => {
                 case 'dealBills': return await ctx.service.dealBills.getAllDataByCondition({where: {tender_id: ctx.tender.id}});
                 case 'spec':
                     const spec = {zlj: stdConst.zlj, jrg: stdConst.jrg};
-                    spec.zlj.deal_bills_tp = ctx.tender.info.deal_param.zanLiePrice;;
+                    spec.zlj.deal_bills_tp = ctx.tender.info.deal_param.zanLiePrice;
                     return spec;
+                case 'tags':
+                    return await this.ctx.service.ledgerTag.getDatas(ctx.tender.id);
             }
         }
 

+ 20 - 8
app/controller/tender_controller.js

@@ -400,6 +400,16 @@ module.exports = app => {
                 const lastStage = stages.length > 0 ? stages[0] : null; // await ctx.service.stage.getLastestStage(ctx.tender.id);
                 if (lastStage) {
                     await this.ctx.service.stage.checkStageGatherData(lastStage);
+
+                    if ((!bCalcTp) && tender.measure_type === measureType.gcl.value) {
+                        bCalcTp = lastStage.status !== auditConst.stage.status.checked && !lastStage.readOnly;
+                    }
+                    if (bCalcTp) {
+                        const sum = await this.ctx.service.ledger.addUp({ tender_id: tender.id/* , is_leaf: true*/ });
+                        tender.total_price = sum.total_price;
+                        tender.deal_tp = sum.deal_tp;
+                    }
+
                     tender.gather_tp = ctx.helper.add(lastStage.contract_tp, lastStage.qc_tp);
                     tender.end_contract_tp = ctx.helper.add(lastStage.contract_tp, lastStage.pre_contract_tp);
                     tender.end_qc_tp = ctx.helper.add(lastStage.qc_tp, lastStage.pre_qc_tp);
@@ -435,10 +445,13 @@ module.exports = app => {
                         const times = lastStage.status === auditConst.stage.status.checkNo ? lastStage.times - 1 : lastStage.times;
                         lastStage.auditors = await ctx.service.stageAudit.getFinalAuditGroup(lastStage.id, times);
                     }
-                    if ((!bCalcTp) && tender.measure_type === measureType.gcl.value) {
-                        bCalcTp = lastStage.status !== auditConst.stage.status.checked && !lastStage.readOnly;
-                    }
                 } else {
+                    if (bCalcTp) {
+                        const sum = await this.ctx.service.ledger.addUp({ tender_id: tender.id/* , is_leaf: true*/ });
+                        tender.total_price = sum.total_price;
+                        tender.deal_tp = sum.deal_tp;
+                    }
+
                     if (tender.ledger_status !== auditConst.ledger.status.uncheck) {
                         const status_name = await this.ctx.service.ledgerAudit.getStatusName(tender.id, tender.ledger_times);
                         tender.status_users = status_name ? status_name.name : '';
@@ -449,11 +462,7 @@ module.exports = app => {
                         tender.status_users = status_name ? status_name.name : '';
                     }
                 }
-                if (bCalcTp) {
-                    const sum = await this.ctx.service.ledger.addUp({ tender_id: tender.id/* , is_leaf: true*/ });
-                    tender.total_price = sum.total_price;
-                    tender.deal_tp = sum.deal_tp;
-                }
+
                 const tiModel = new tenderInfoModel(ctx);
                 const gclChapter = await tiModel.gatherChapter();
 
@@ -1144,6 +1153,9 @@ module.exports = app => {
                 if (ctx.stage) {
                     const isAuditor = ctx.stage.users.indexOf(this.ctx.session.sessionUser.accountId) >= 0;
                     if (!isAuditor && !isValidTourist) throw '您无权进行该操作';
+                } else if (ctx.revise) {
+                    const isAuditor = ctx.revise.reviseUsers.indexOf(this.ctx.session.sessionUser.accountId) >= 0;
+                    if (!isAuditor && !isValidTourist) throw '您无权进行该操作';
                 } else {
                     const isAuditor = ctx.tender.ledgerUsers.indexOf(this.ctx.session.sessionUser.accountId) >= 0;
                     if (!isAuditor && !isValidTourist) throw '您无权进行该操作';

+ 11 - 1
app/middleware/revise_check.js

@@ -8,6 +8,7 @@
  * @version
  */
 
+const auditConst = require('../const/audit').revise;
 module.exports = options => {
     /**
      * 标段校验 中间件
@@ -20,7 +21,16 @@ module.exports = options => {
     return function* reviseAuditCheck(next) {
         try {
             // 获取revise
-            this.revise = yield this.service.ledgerRevise.getLastestRevise(this.tender.id);
+            const revise = yield this.service.ledgerRevise.getLastestRevise(this.tender.id);
+            if (!revise) throw '台账修订数据有误';
+            revise.reviseUsers = [revise.uid];
+            if (revise.status !== auditConst.status.uncheck) {
+                const times = revise.status === auditConst.status.checkNo ? revise.times - 1 : revise.times;
+                const auditors = yield this.service.reviseAudit.getAuditors(revise.id, times);
+                const auditorsId = this.helper._.map(auditors, 'audit_id');
+                revise.reviseUsers.push(...auditorsId);
+            }
+            this.revise = revise;
             yield next;
         } catch (err) {
             // 输出错误到日志

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

@@ -640,6 +640,7 @@ $(document).ready(() => {
     const stdXmjSetting = {
         selector: '#std-xmj',
         stdType: 'xmj',
+        libs: stdChapters,
         treeSetting: {
             id: 'chapter_id',
             pid: 'pid',
@@ -672,6 +673,7 @@ $(document).ready(() => {
     const stdGclSetting = {
         selector: '#std-gcl',
         stdType: 'gcl',
+        libs: stdBills,
         treeSetting: {
             id: 'bill_id',
             pid: 'pid',
@@ -714,10 +716,10 @@ $(document).ready(() => {
             tabPanel.addClass('active');
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#std-xmj') {
-                if (!stdXmj) stdXmj = new stdLib(stdXmjSetting);
+                if (!stdXmj) stdXmj = $.stdLib(stdXmjSetting);
                 stdXmj.spread.refresh();
             } else if (tab.attr('content') === '#std-gcl') {
-                if (!stdGcl) stdGcl = new stdLib(stdGclSetting);
+                if (!stdGcl) stdGcl = $.stdLib(stdGclSetting);
                 stdGcl.spread.refresh();
             } else if (tab.attr('content') === '#search') {
                 if (!searchBudget) {

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

@@ -2378,6 +2378,7 @@ $(document).ready(() => {
     const stdXmjSetting = {
         selector: '#std-xmj',
         stdType: 'xmj',
+        libs: stdChapters,
         treeSetting: {
             id: 'chapter_id',
             pid: 'pid',
@@ -2409,6 +2410,7 @@ $(document).ready(() => {
     const stdGclSetting = {
         selector: '#std-gcl',
         stdType: 'gcl',
+        libs: stdBills,
         treeSetting: {
             id: 'bill_id',
             pid: 'pid',
@@ -2451,12 +2453,12 @@ $(document).ready(() => {
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#std-xmj') {
                 if (!stdXmj) {
-                    stdXmj = new stdLib(stdXmjSetting);
+                    stdXmj = $.stdLib(stdXmjSetting);
                 }
                 stdXmj.spread.refresh();
             } else if (tab.attr('content') === '#std-gcl') {
                 if (!stdGcl) {
-                    stdGcl = new stdLib(stdGclSetting);
+                    stdGcl = $.stdLib(stdGclSetting);
                 }
                 stdGcl.spread.refresh();
             } else if (tab.attr('content') === '#deal-bills') {

+ 6 - 5
app/public/js/ledger.js

@@ -414,6 +414,7 @@ $(document).ready(function() {
                         self.refreshTree(sheet, refreshNode);
                         self.refreshOperationValid(sheet);
                         posOperationObj.loadCurPosData();
+                        billsTag.afterDeleteBills(refreshNode.delete);
                     });
                 });
             }
@@ -2309,6 +2310,7 @@ $(document).ready(function() {
     const stdXmjSetting = {
         selector: '#std-xmj',
         stdType: 'xmj',
+        libs: stdChapters,
         treeSetting: {
             id: 'chapter_id',
             pid: 'pid',
@@ -2340,6 +2342,7 @@ $(document).ready(function() {
     const stdGclSetting = {
         selector: '#std-gcl',
         stdType: 'gcl',
+        libs: stdBills,
         treeSetting: {
             id: 'bill_id',
             pid: 'pid',
@@ -2383,14 +2386,12 @@ $(document).ready(function() {
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#std-xmj') {
                 if (!stdXmj) {
-                    stdXmj = new stdLib(stdXmjSetting);
-                    //stdXmj.loadLib($('select', '#std-xmj').val());
+                    stdXmj = $.stdLib(stdXmjSetting);
                 }
                 stdXmj.spread.refresh();
             } else if (tab.attr('content') === '#std-gcl') {
                 if (!stdGcl) {
-                    stdGcl = new stdLib(stdGclSetting);
-                    //stdGcl.loadLib($('select', '#std-gcl').val());
+                    stdGcl = $.stdLib(stdGclSetting);
                 }
                 stdGcl.spread.refresh();
             } else if (tab.attr('content') === '#deal-bills') {
@@ -2453,7 +2454,7 @@ $(document).ready(function() {
             } else if (tab.attr('content') === '#check-list') {
                 checkList.spread.refresh();
             } else if (tab.attr('content') === '#fujian') {
-              $('#showAttachment').hide()
+              $('#showAttachment').hide();
               const node = SpreadJsObj.getSelectObject(ledgerSpread.getActiveSheet());
               getNodeList(node.id);
               getAllList();

+ 69 - 3
app/public/js/revise.js

@@ -57,6 +57,37 @@ $(document).ready(() => {
     const billsSheet = billsSpread.getActiveSheet();
     sjsSettingObj.setFxTreeStyle(billsSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
     if (thousandth) sjsSettingObj.setTpThousandthFormat(billsSpreadSetting);
+
+    billsSpreadSetting.headColWidth = [50];
+    billsSpreadSetting.rowHeader = [
+        {
+            rowHeaderType: 'tag',
+            setting: {
+                indent: 14,
+                tagSize: 0.8,
+                tagFont: '8px 微软雅黑',
+                getColor: function (index, data) {
+                    if (!data) return;
+                    return billsTag.getBillsTagsColor(data.id);
+                },
+                getTagHtml: function (index, data) {
+                    if (!data) return;
+                    const getHtml = function (list) {
+                        if (!list || list.length === 0) return '';
+                        const html = [];
+                        for (const l of list) {
+                            html.push('<div class="row mr-1">');
+                            html.push(`<div class="col-auto pr-1 ${l.tagClass}">`, '<i class="fa fa-tag"></i>', '</div>');
+                            html.push('<div class="col p-0">', '<p>', l.comment, '</p>', '</div>');
+                            html.push('</div>');
+                        }
+                        return html.join('');
+                    };
+                    return getHtml(billsTag.getBillsTagsInfo(data.id));
+                }
+            },
+        },
+    ];
     SpreadJsObj.initSheet(billsSheet, billsSpreadSetting);
     const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);
     const posSheet = posSpread.getActiveSheet();
@@ -66,6 +97,21 @@ $(document).ready(() => {
 
     const posSearch = $.posSearch({selector: '#pos-search', searchSpread: posSpread});
 
+    const billsTag = $.billsTag({
+        selector: '#bills-tag',
+        relaSpread: billsSpread,
+        updateUrl: window.location.pathname + '/tag',
+        afterModify: function (nodes) {
+            SpreadJsObj.repaintNodesRowHeader(billsSpread.getActiveSheet(), nodes);
+        },
+        afterLocated:  function () {
+            posSpreadObj.loadCurPosData();
+        },
+        afterShow: function () {
+            billsSpread.refresh();
+            if (posSpread) posSpread.refresh();
+        },
+    });
     const errorList = $.cs_errorList({
         tabSelector: '#error-list-tab',
         selector: '#error-list',
@@ -293,6 +339,7 @@ $(document).ready(() => {
                     const rows = [];
                     for (const u of data.update) {
                         rows.push(tree.nodes.indexOf(u));
+                        billsTag.refreshBillsTagView(u);
                     }
                     SpreadJsObj.reLoadRowsData(sheet, rows);
                 }
@@ -391,6 +438,7 @@ $(document).ready(() => {
                             sheet.setSelection(sel.row, sel.col, 1, sel.colCount);
                         }
                         self.refreshOperationValid(sheet);
+                        billsTag.afterDeleteBills(refreshData.delete);
                     });
                 });
             } else {
@@ -1009,6 +1057,7 @@ $(document).ready(() => {
             .keyup((e) => {if (e.keyCode === 13) item.batchInsert($input[0], root);})
             .on('input', function () {this.value = this.value.replace(/[^\d]/g, '');});
     };
+    const addTag = newTag({ledgerSheet: billsSpread.getActiveSheet(), billsTag});
     const billsContextMenuOptions = {
         selector: '#bills-spread',
         build: function ($trigger, e) {
@@ -1304,7 +1353,19 @@ $(document).ready(() => {
                 tenderSelect.showSelect(SpreadJsObj.getSelectObject(billsSheet));
             }
         };
+        billsContextMenuOptions.items.sprImport = '----';
     }
+    billsContextMenuOptions.items.tag = {
+        name: '书签',
+        callback: function (key, opt, menu, e) {
+            const node = SpreadJsObj.getSelectObject(billsSpread.getActiveSheet());
+            addTag.do(node);
+        },
+        disabled: function (key, opt) {
+            const node = SpreadJsObj.getSelectObject(billsSpread.getActiveSheet());
+            return !node;
+        }
+    };
     billsContextMenuOptions.items.sprTag = '----';
     billsContextMenuOptions.items.showLast = {
         name: '显示至最底层',
@@ -1865,6 +1926,10 @@ $(document).ready(() => {
     postData(window.location.pathname + '/load', {}, function (result) {
         billsTree.loadDatas(result.bills);
         treeCalc.calculateAll(billsTree);
+        for (const t of result.tags) {
+            t.node = billsTree.datas.find(x => {return x.id === t.lid});
+        }
+        billsTag.loadDatas(result.tags);
         SpreadJsObj.loadSheetData(billsSheet, SpreadJsObj.DataType.Tree, billsTree);
         SpreadJsObj.loadTopAndSelect(billsSheet, ckBillsSpread);
 
@@ -2123,7 +2188,6 @@ $(document).ready(() => {
                         posSheet.getCell(0, i + 2 - 1, spreadNS.SheetArea.colHeader).text('清单' + i);
                     }
                 }
-                SpreadJsObj.beginMassOperation(billsSheet);
                 for (let iRow = 0; iRow < pasteData.length; iRow++) {
                     const curRow = iRow + info.cellRange.row;
                     pasteData[iRow].forEach((value, iCol) => {
@@ -2441,6 +2505,7 @@ $(document).ready(() => {
     const stdXmjSetting = {
         selector: '#std-xmj',
         stdType: 'xmj',
+        libs: stdChapters,
         treeSetting: {
             id: 'chapter_id',
             pid: 'pid',
@@ -2472,6 +2537,7 @@ $(document).ready(() => {
     const stdGclSetting = {
         selector: '#std-gcl',
         stdType: 'gcl',
+        libs: stdBills,
         treeSetting: {
             id: 'bill_id',
             pid: 'pid',
@@ -2514,12 +2580,12 @@ $(document).ready(() => {
             showSideTools(tab.hasClass('active'));
             if (tab.attr('content') === '#std-xmj') {
                 if (!stdXmj) {
-                    stdXmj = new stdLib(stdXmjSetting);
+                    stdXmj = $.stdLib(stdXmjSetting);
                 }
                 stdXmj.spread.refresh();
             } else if (tab.attr('content') === '#std-gcl') {
                 if (!stdGcl) {
-                    stdGcl = new stdLib(stdGclSetting);
+                    stdGcl = $.stdLib(stdGclSetting);
                 }
                 stdGcl.spread.refresh();
             } else if (tab.attr('content') === '#deal-bills') {

+ 233 - 1
app/public/js/shares/cs_tools.js

@@ -783,6 +783,7 @@ const showSelectTab = function(select, spread, afterShow) {
             billsTags = [];
             billsIndexes = {};
             for (const d of datas) {
+                if (!d.node) continue;
                 billsTags.push(d);
                 _addToBillsIndex(d);
             }
@@ -851,6 +852,18 @@ const showSelectTab = function(select, spread, afterShow) {
             }) : undefined;
         };
 
+        const afterDeleteBills = function (nodes) {
+            for (const node of nodes) {
+                const bi = billsIndexes[node.id];
+                delete billsIndexes[node.id];
+                for (const biTag of bi) {
+                    const delTag = billsTags.find(x => {return x.id === biTag.id});
+                    billsTags.splice(billsTags.indexOf(delTag), 1);
+                    $('#bills-tag-' + delTag.id).remove();
+                }
+            }
+        };
+
         $('body').on('click', '[name=bills-tag-locate]', function () {
             const lid = parseInt(this.getAttribute('lid'));
             SpreadJsObj.locateTreeNode(setting.relaSpread.getActiveSheet(), lid);
@@ -935,7 +948,7 @@ const showSelectTab = function(select, spread, afterShow) {
         $('#bills-tag-search').bind('click', () => {searchTagsAndShow();});
         $('#bills-tag-keyword').bind('keydown', e => {if (e.keyCode === 13) searchTagsAndShow();});
 
-        return { loadDatas, updateDatasAndShow, show, getBillsTagsColor, getBillsTagsInfo, refreshBillsTagView, }
+        return { loadDatas, updateDatasAndShow, show, getBillsTagsColor, getBillsTagsInfo, refreshBillsTagView, afterDeleteBills }
     };
 
     $.sumLoadMiss = function (setting) {
@@ -1074,4 +1087,223 @@ const showSelectTab = function(select, spread, afterShow) {
             };
         }
     };
+
+    $.stdLib = function (setting) {
+        if (!setting.selector) return;
+        const obj = $(setting.selector);
+        const stdLibHtml = setting.libs.map(l => {
+            return `<option value="${l.id}" >${l.name}</option>`;
+        });
+        const relaSelect = {
+            showLevel: `std-${setting.stdType}-sl`,
+            searchText: `std-${setting.stdType}-st`,
+            searchResult: `std-${setting.stdType}-sr`,
+            searchPre: `std-${setting.stdType}-sp`,
+            searchNext: `std-${setting.stdType}-sn`,
+            searchClose: `std-${setting.stdType}-sc`,
+        };
+        obj.html(
+            '<div class="sjs-bar d-flex">\n' +
+            '    <div class="dropdown mr-1">\n' +
+            '        <button class="btn btn-sm btn-light dropdown-toggle text-primary" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">\n' +
+            '             <i class="fa fa-list-ol"></i> 显示层级\n' +
+            '        </button>\n' +
+            '        <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">\n' +
+            `            <a class="dropdown-item" href="javascript: void(0);" tag="1" name="${relaSelect.showLevel}">第一层</a>\n` +
+            `            <a class="dropdown-item" href="javascript: void(0);" tag="2" name="${relaSelect.showLevel}">第二层</a>\n` +
+            `            <a class="dropdown-item" href="javascript: void(0);" tag="3" name="${relaSelect.showLevel}">第三层</a>\n` +
+            `            <a class="dropdown-item" href="javascript: void(0);" tag="4" name="${relaSelect.showLevel}">第四层</a>\n` +
+            `            <a class="dropdown-item" href="javascript: void(0);" tag="5" name="${relaSelect.showLevel}">第五层</a>\n` +
+            `            <a class="dropdown-item" href="javascript: void(0);" tag="last" name="${relaSelect.showLevel}">最底层</a>\n` +
+            '        </div>\n' +
+            '    </div>' +
+            `    <div class=input-group input-group-sm pr-1"><select class="form-control form-control-sm">${stdLibHtml.join('')}</select></div>\n` +
+            '    <div class="ml-1">\n' +
+            '        <div class="dropdown">\n' +
+            '            <button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">\n' +
+            '                <i class="fa fa-search"></i>\n' +
+            '            </button>\n' +
+            '            <div class="dropdown-menu dropdown-menu-right">\n' +
+            '                <div class="px-2 border-primary border-1 d-flex" style="width: 300px">\n' +
+            '                    <div class="d-inline-block">\n' +
+            '                        <div class="input-group input-group-sm mr-1">' +
+            `                            <input type="text" class="form-control" placeholder="输入编号/名称查找" id="${relaSelect.searchText}">\n` +
+            `                            <div class="input-group-append" ><span class="input-group-text" id="${relaSelect.searchResult}">结果:0</span></div>\n` +
+            '                            <div class="input-group-append" >\n' +
+            `                                <button class="btn btn-outline-secondary" type="button" title="上一个" id="${relaSelect.searchPre}"><i class="fa fa-angle-double-left"></i></button>\n` +
+            `                                <button class="btn btn-outline-secondary" type="button" title="下一个" id="${relaSelect.searchNext}"><i class="fa fa-angle-double-right"></i></button>\n` +
+            '                            </div>\n' +
+            '                        </div>\n' +
+            '                    </div>\n' +
+            `                    <div class="d-inline-block"><button class="btn btn-light text-danger btn-sm ml-1" type="button" id="${relaSelect.searchClose}"><i class="fa fa-remove"></i></button></div>\n` +
+            '                </div>\n' +
+            '            </div>\n' +
+            '        </div>\n' +
+            '    </div>' +
+            '</div>\n' +
+            `<div id="std-${setting.stdType}-spread" class="sjs-sh"></div>\n`
+        );
+        autoFlashHeight();
+        const pathTree = createNewPathTree('base', setting.treeSetting);
+
+        const spreadSetting = {
+            cols: [
+                {title: '名称', field: 'name', hAlign: 0, width: 180, formatter: '@'},
+                {title: '单位', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
+            ],
+            treeCol: 0,
+            emptyRows: 0,
+            headRows: 1,
+            headRowHeight: [32],
+            defaultRowHeight: 21,
+            headerFont: '12px 微软雅黑',
+            font: '12px 微软雅黑',
+            headColWidth: [30],
+            selectedBackColor: '#fffacd',
+            readOnly: true,
+            stdType: setting.stdType,
+        };
+        spreadSetting.cols.unshift(setting.stdType === 'xmj'
+            ? {title: '项目节编号', field: 'code', hAlign: 0, width: 150, formatter: '@', cellType: 'tree'}
+            : {title: '清单编号', field: 'b_code', hAlign: 0, width: 150, formatter: '@', cellType: 'tree'});
+
+        const spread = SpreadJsObj.createNewSpread($(`#std-${setting.stdType}-spread`)[0]);
+        const sheet = spread.getActiveSheet();
+        SpreadJsObj.initSheet(sheet, spreadSetting);
+
+
+        if (setting.cellDoubleClick) sheet.bind(spreadNS.Events.CellDoubleClick, setting.cellDoubleClick);
+        sheet.bind(spreadNS.Events.SelectionChanged, function (e, info) {
+            if (!info.oldSelections || !info.oldSelections[0] || info.newSelections[0].row !== info.oldSelections[0].row) {
+                SpreadJsObj.saveTopAndSelect(info.sheet, cacheKey.node);
+            }
+        });
+        sheet.bind(spreadNS.Events.TopRowChanged, function (e, info) {
+            SpreadJsObj.saveTopAndSelect(info.sheet, cacheKey.node);
+        });
+
+        const cacheLib = [];
+        const cacheKey = {
+            lib: setting.page + '-' + setting.tid + '-' + setting.stdType,
+        };
+
+        $('select', setting.selector).change(function () {
+            loadLib(parseInt(this.value), true);
+        });
+        (function (select, sheet) {
+            $(select).click(function () {
+                if (!sheet.zh_tree) return;
+                const tag = $(this).attr('tag');
+                const tree = sheet.zh_tree;
+                setTimeout(() => {
+                    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;
+                    }
+                }, 100);
+            });
+        })(`a[name=${relaSelect.showLevel}]`, sheet);
+
+        const loadLib = function(listId, reload = false) {
+            cacheKey.node = cacheLib.lib + '-' + listId;
+            const locateMemory = function () {
+                if (!reload) {
+                    SpreadJsObj.loadTopAndSelect(sheet, cacheKey.node);
+                } else {
+                    removeLocalCache(cacheKey.node);
+                }
+            };
+            const cacheData = cacheLib.find(function (lib) {
+                return lib.id === listId;
+            });
+            if (cacheData) {
+                pathTree.loadDatas(cacheData.data);
+                SpreadJsObj.loadSheetData(sheet, 'tree', pathTree);
+                locateMemory();
+                setLocalCache(cacheKey.lib, listId);
+            } else {
+                postData(`/std-lib/get-data`, {stdType: setting.stdType, list_id: listId}, function (data) {
+                    cacheLib.push({id: listId, data: data});
+                    pathTree.loadDatas(data);
+                    SpreadJsObj.loadSheetData(sheet, 'tree', pathTree);
+                    locateMemory();
+                    setLocalCache(cacheKey.lib, listId);
+                });
+            }
+        };
+
+        const _loadCacheLib = function() {
+            let libId = getLocalCache(cacheKey.lib);
+            if (libId) {
+                $('select', setting.selector).val(libId);
+                loadLib(parseInt(libId));
+            } else {
+                loadLib(parseInt($('select', setting.selector).val()));
+            }
+        };
+        _loadCacheLib();
+
+        const searchObj = {
+            result: [],
+            cur: 0,
+            searchStdNode: function() {
+                const keyword = $(`#${relaSelect.searchText}`).val();
+                searchObj.result = keyword ? pathTree.nodes.filter(x => {
+                    return x.code.indexOf(keyword) >= 0 || x.b_code.indexOf(keyword) >= 0 || x.name.indexOf(keyword) >= 0;
+                }) : [];
+                // searchObj.result = [];
+                // for (const x of pathTree.nodes) {
+                //     if (x.code.indexOf(keyword) >= 0 || x.b_code.indexOf(keyword) >= 0 || x.name.indexOf(keyword) >= 0) {
+                //         searchObj.result.push(x);
+                //     }
+                // }
+                $(`#${relaSelect.searchResult}`)[0].innerText = `结果:${searchObj.result.length}`;
+                searchObj.cur = 0;
+                if (searchObj.result.length > 0) {
+                    SpreadJsObj.locateTreeNode(sheet, pathTree.getNodeKey(searchObj.result[searchObj.cur]));
+                }
+            },
+            searchPre: function () {
+                if (searchObj.result.length <= 1) return;
+                searchObj.cur = searchObj.cur === 0 ? searchObj.result.length - 1 : this.cur - 1;
+                SpreadJsObj.locateTreeNode(sheet, pathTree.getNodeKey(searchObj.result[searchObj.cur]), true);
+            },
+            searchNext: function () {
+                if (searchObj.result.length <= 1) return;
+                searchObj.cur = searchObj.cur === searchObj.result.length - 1 ? 0 : searchObj.cur + 1;
+                SpreadJsObj.locateTreeNode(sheet, pathTree.getNodeKey(searchObj.result[searchObj.cur]), true);
+            },
+            clear: function () {
+                $(`#${relaSelect.searchText}`).val('');
+                $(`#${relaSelect.searchResult}`)[0].innerText = `结果:${0}`;
+                searchObj.result = [];
+                searchObj.cur = 0;
+            }
+        };
+        $(`#${relaSelect.searchText}`).change(searchObj.searchStdNode);
+        $(`#${relaSelect.searchPre}`).click(function (e) {
+            searchObj.searchPre();
+            e.stopPropagation();
+        });
+        $(`#${relaSelect.searchNext}`).click(function (e) {
+            searchObj.searchNext();
+            e.stopPropagation();
+        });
+        $(`#${relaSelect.searchClose}`).click(function (e) {
+            searchObj.clear();
+            e.stopPropagation();
+        });
+
+        return { spread }
+    };
 })(jQuery);

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

@@ -972,7 +972,6 @@ const SpreadJsObj = {
         if (!html || html === '') return result;
     },
     transposePasteData: function (data) {
-        console.log(data);
         const result = [];
         const rowCount = data.length, colCount = data.reduce((r, x) => { return r ? Math.max(r, x.length) : x.length; });
         for (let c = 0; c < colCount; c++) {

+ 1 - 0
app/router.js

@@ -553,6 +553,7 @@ module.exports = app => {
 
     // 书签
     app.post('/tender/:id/ledger/tag', sessionAuth, tenderCheck, uncheckTenderCheck, 'tenderController.billsTag');
+    app.post('/tender/:id/revise/info/tag', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, 'tenderController.billsTag');
     app.post('/tender/:id/measure/stage/:order/tag', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'tenderController.billsTag');
 
     // 总分包

+ 2 - 2
app/service/ledger_tag.js

@@ -12,7 +12,7 @@ const validField = ['lid', 'share', 'color', 'comment'];
 
 module.exports = app => {
 
-    class StageBillsDgn extends app.BaseService {
+    class LedgerTag extends app.BaseService {
         /**
          * 构造函数
          *
@@ -98,5 +98,5 @@ module.exports = app => {
         }
     }
 
-    return StageBillsDgn;
+    return LedgerTag;
 };

+ 2 - 22
app/view/budget/detail.ejs

@@ -67,31 +67,9 @@
                         </div>
                     </div>
                     <div id="std-xmj" class="tab-pane tab-select-show">
-                        <div class="sjs-bar-2">
-                            <div class="pb-1">
-                                <select class="form-control form-control-sm">
-                                    <% for (const [i, c] of stdChapters.entries()) { %>
-                                    <option value="<%- c.id %>" <%- (i===0 ? ' selected' : '') %>><%- c.name %></option>
-                                    <% } %>
-                                </select>
-                            </div>
-                        </div>
-                        <div id="std-xmj-spread" class="sjs-sh-2">
-                        </div>
                     </div>
                     <% if (needGcl) { %>
                     <div id="std-gcl" class="tab-pane tab-select-show">
-                        <div class="sjs-bar-3">
-                            <div class="pb-1">
-                                <select class="form-control form-control-sm">
-                                    <% for (const [i, b] of stdBills.entries()) { %>
-                                    <option value="<%- b.id %>" <%- (i===0 ? ' selected' : '') %>><%- b.name %></option>
-                                    <% } %>
-                                </select>
-                            </div>
-                        </div>
-                        <div id="std-gcl-spread" class="sjs-sh-3">
-                        </div>
                     </div>
                     <% } %>
                 </div>
@@ -115,6 +93,8 @@
     </div>
 </div>
 <script>
+    const stdChapters = JSON.parse(unescape('<%- escape(JSON.stringify(stdChapters)) %>'));
+    const stdBills = JSON.parse(unescape('<%- escape(JSON.stringify(stdBills)) %>'));
     const readOnly = <%- ctx.budget.readOnly %>;
     const needGcl = <%- needGcl %>;
     const spreadSetting = JSON.parse('<%- JSON.stringify(spreadSetting) %>');

+ 2 - 22
app/view/change/revise.ejs

@@ -95,30 +95,8 @@
                     <div id="search" class="tab-pane">
                     </div>
                     <div id="std-xmj" class="tab-pane">
-                        <div class="sjs-bar">
-                            <div class="pb-1">
-                                <select class="form-control form-control-sm">
-                                    <% for (const c of stdChapters) { %>
-                                    <option value="<%- c.id %>" <% if (stdChapters.indexOf(c) === 0) { %>selected<% } %>><%- c.name %></option>
-                                    <% } %>
-                                </select>
-                            </div>
-                        </div>
-                        <div id="std-xmj-spread" class="sjs-sh">
-                        </div>
                     </div>
                     <div id="std-gcl" class="tab-pane">
-                        <div class="sjs-bar">
-                            <div class="pb-1">
-                                <select class="form-control form-control-sm">
-                                    <% for (const b of stdBills) { %>
-                                    <option value="<%- b.id %>" <% if (stdBills.indexOf(b) === 0) { %>selected<% } %>><%- b.name %></option>
-                                    <% } %>
-                                </select>
-                            </div>
-                        </div>
-                        <div id="std-gcl-spread" class="sjs-sh">
-                        </div>
                     </div>
                     <div id="deal-bills" class="tab-pane">
                         <div class="sjs-bar">
@@ -164,6 +142,8 @@
     </div>
 </div>
 <script>
+    const stdChapters = JSON.parse(unescape('<%- escape(JSON.stringify(stdChapters)) %>'));
+    const stdBills = JSON.parse(unescape('<%- escape(JSON.stringify(stdBills)) %>'));
     const readOnly = <%- readOnly %>;
     const isTz = <%- ctx.tender.data.measure_type === measureType.tz.value %>;
     const billsSpreadSetting = JSON.parse('<%- JSON.stringify(ledgerSpread) %>');

+ 2 - 22
app/view/ledger/explode.ejs

@@ -109,30 +109,8 @@
                     <div id="search" class="tab-pane tab-select-show">
                     </div>
                     <div id="std-xmj" class="tab-pane tab-select-show">
-                        <div class="sjs-bar-2">
-                            <div class="pb-1">
-                                <select class="form-control form-control-sm">
-                                    <% for (const c of stdChapters) { %>
-                                    <option value="<%- c.id %>" <% if (stdChapters.indexOf(c) === 0) { %>selected<% } %>><%- c.name %></option>
-                                    <% } %>
-                                </select>
-                            </div>
-                        </div>
-                        <div id="std-xmj-spread" class="sjs-sh-2">
-                        </div>
                     </div>
                     <div id="std-gcl" class="tab-pane tab-select-show">
-                        <div class="sjs-bar-3">
-                            <div class="pb-1">
-                                <select class="form-control form-control-sm">
-                                    <% for (const b of stdBills) { %>
-                                    <option value="<%- b.id %>" <% if (stdBills.indexOf(b) === 0) { %>selected<% } %>><%- b.name %></option>
-                                    <% } %>
-                                </select>
-                            </div>
-                        </div>
-                        <div id="std-gcl-spread" class="sjs-sh-3">
-                        </div>
                     </div>
                     <div id="deal-bills" class="tab-pane tab-select-show">
                         <div class="sjs-bar-4">
@@ -327,6 +305,8 @@
         key: 'ledger-pos',
         colWidth: true,
     };
+    const stdChapters = JSON.parse(unescape('<%- escape(JSON.stringify(stdChapters)) %>'));
+    const stdBills = JSON.parse(unescape('<%- escape(JSON.stringify(stdBills)) %>'));
     $('.sp-list-btn').click(function () {
         const type = $(this).data('type')
         if (type === 'hide') {

+ 7 - 22
app/view/revise/info.ejs

@@ -139,30 +139,8 @@
                     <div id="search" class="tab-pane">
                     </div>
                     <div id="std-xmj" class="tab-pane">
-                        <div class="sjs-bar">
-                            <div class="pb-1">
-                                <select class="form-control form-control-sm">
-                                    <% for (const c of stdChapters) { %>
-                                    <option value="<%- c.id %>" <% if (stdChapters.indexOf(c) === 0) { %>selected<% } %>><%- c.name %></option>
-                                    <% } %>
-                                </select>
-                            </div>
-                        </div>
-                        <div id="std-xmj-spread" class="sjs-sh">
-                        </div>
                     </div>
                     <div id="std-gcl" class="tab-pane">
-                        <div class="sjs-bar">
-                            <div class="pb-1">
-                                <select class="form-control form-control-sm">
-                                    <% for (const b of stdBills) { %>
-                                    <option value="<%- b.id %>" <% if (stdBills.indexOf(b) === 0) { %>selected<% } %>><%- b.name %></option>
-                                    <% } %>
-                                </select>
-                            </div>
-                        </div>
-                        <div id="std-gcl-spread" class="sjs-sh">
-                        </div>
                     </div>
                     <div id="deal-bills" class="tab-pane">
                         <div class="sjs-bar">
@@ -179,6 +157,8 @@
                         <div id="bg-bills-spread" class="sjs-sh">
                         </div>
                     </div>
+                    <div id="bills-tag" class="tab-pane tab-select-show">
+                    </div>
                     <div id="error-list" class="tab-pane">
                     </div>
                     <div id="check-list" class="tab-pane">
@@ -211,6 +191,9 @@
                     <a class="nav-link" content="#bg-bills" href="javascript: void(0);">变更清单</a>
                 </li>
                 <li class="nav-item">
+                    <a class="nav-link" content="#bills-tag" 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>
                 <li class="nav-item">
@@ -225,6 +208,8 @@
 </div>
 <script src="/public/js/moment/moment.min.js"></script>
 <script>
+    const stdChapters = JSON.parse(unescape('<%- escape(JSON.stringify(stdChapters)) %>'));
+    const stdBills = JSON.parse(unescape('<%- escape(JSON.stringify(stdBills)) %>'));
     const readOnly = <%- readOnly %>;
     const isTz = <%- ctx.tender.data.measure_type === measureType.tz.value %>;
     const billsSpreadSetting = JSON.parse('<%- JSON.stringify(ledgerSpread) %>');

+ 1 - 0
app/view/revise/info_modal.ejs

@@ -727,6 +727,7 @@
     <% include ../shares/delete_hint_modal.ejs %>
     <% include ../shares/check_data_modal.ejs %>
     <% include ../shares/check_modal2.ejs %>
+<% include ../shares/new_tag_modal.ejs %>
     <% include ../shares/tender_select_modal.ejs %>
     <% if(ctx.session.sessionUser.accountId === revise.uid && (revise.status === auditConst.status.uncheck || revise.status === auditConst.status.checkNo)) { %>
     <script>

+ 1 - 0
config/web.js

@@ -234,6 +234,7 @@ const JsFiles = {
                     '/public/js/shares/sjs_setting.js',
                     '/public/js/shares/cs_tools.js',
                     '/public/js/shares/merge_peg.js',
+                    '/public/js/shares/new_tag.js',
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
                     '/public/js/std_lib.js',