Browse Source

多期比较,查找定位

MaiXinRong 1 month ago
parent
commit
6bc5b4fbfa

+ 1 - 0
app/public/js/gcl_gather.js

@@ -134,6 +134,7 @@ const gclGatherModel = (function () {
      */
     function newGclNode(node) {
         const gcl = {
+            id: node.id,
             b_code: node.b_code,
             name: node.name,
             unit: node.unit,

+ 189 - 1
app/public/js/measure_compare.js

@@ -267,7 +267,7 @@ function calculateStagePosData(datas) {
 }
 
 $(document).ready(() => {
-    let spec;
+    let spec, ledgerSearch, gclSearch;
     autoFlashHeight();
     initSpreadSettingWithRoles([]);
     const billsSpread = SpreadJsObj.createNewSpread($('#bills-spread')[0]);
@@ -334,6 +334,25 @@ $(document).ready(() => {
             leafXmjSpread.refresh();
         }
     });
+    // 工具栏resizer
+    $.divResizer({
+        select: '#tz-right-spr',
+        callback: function () {
+            billsSpread.refresh();
+            posSpread.refresh();
+            window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
+            if (ledgerSearch) ledgerSearch.spread.refresh();
+        }
+    });
+    $.divResizer({
+        select: '#gcl-right-spr',
+        callback: function () {
+            gclSpread.refresh();
+            leafXmjSpread.refresh();
+            window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
+            if (gclSearch) gclSearch.spread.refresh();
+        }
+    });
 
     const cTree = createNewPathTree('master', {
         id: 'ledger_id',
@@ -517,6 +536,175 @@ $(document).ready(() => {
         });
     })('a[name=showLevel]', billsSheet);
 
+    // 展开收起工具栏
+    const showTzSideTools = function (show) {
+        const left = $('#tz-left-view'), right = $('#tz-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 showGclSideTools = function (show) {
+        const left = $('#gcl-left-view'), right = $('#gcl-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();
+        }
+    };
+    $('a', '#tz-side-menu').bind('click', function (e) {
+        e.preventDefault();
+        const tab = $(this), tabPanel = $(tab.attr('content'));
+        // 展开工具栏、切换标签
+        if (!tab.hasClass('active')) {
+            // const close = $('.active', '#side-menu').length === 0;
+            $('a', '#tz-side-menu').removeClass('active');
+            $('.tab-content .tab-select-show.tab-pane.active').removeClass('active');
+            tab.addClass('active');
+            tabPanel.addClass('active');
+            // $('.tab-content .tab-pane').removeClass('active');
+            showTzSideTools(tab.hasClass('active'));
+            if (tab.attr('content') === '#tz-search') {
+                if (!ledgerSearch) {
+                    ledgerSearch = $.ledgerSearch({
+                        selector: '#tz-search',
+                        ledger: { billsTree: cTree, pos: cPos },
+                        resultSpreadSetting: {
+                            cols: [
+                                {title: '项目节编号', field: 'code', hAlign: 0, width: 90, formatter: '@'},
+                                {title: '清单编号', field: 'b_code', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '名称', field: 'name', width: 150, hAlign: 0, formatter: '@'},
+                                {title: '单位', field: 'unit', width: 50, hAlign: 1, formatter: '@'},
+                                {title: '单价', field: 'unit_price', hAlign: 2, width: 50},
+                            ],
+                            emptyRows: 0,
+                            headRows: 1,
+                            headRowHeight: [32],
+                            headColWidth: [30],
+                            defaultRowHeight: 21,
+                            headerFont: '12px 微软雅黑',
+                            font: '12px 微软雅黑',
+                            selectedBackColor: '#fffacd',
+                            readOnly: true,
+                        },
+                        locate: function(cur) {
+                            if (!cur.lid) return;
+
+                            SpreadJsObj.locateTreeNode(billsSheet, cur.lid, true);
+                            loadPosData();
+                            if (cur.pid && cur.pid !== -1) {
+                                const pIndex = posSheet.zh_data.findIndex(x => { return x.id === cur.pid; });
+                                SpreadJsObj.locateRow(posSheet, pIndex);
+                            }
+                        },
+                    });
+                }
+                ledgerSearch.spread.refresh();
+            }
+        } else { // 收起工具栏
+            tab.removeClass('active');
+            tabPanel.removeClass('active');
+            showTzSideTools(tab.hasClass('active'));
+        }
+        billsSpread.refresh();
+        posSpread.refresh();
+    });
+    $('a', '#gcl-side-menu').bind('click', function (e) {
+        e.preventDefault();
+        const tab = $(this), tabPanel = $(tab.attr('content'));
+        // 展开工具栏、切换标签
+        if (!tab.hasClass('active')) {
+            // const close = $('.active', '#side-menu').length === 0;
+            $('a', '#gcl-side-menu').removeClass('active');
+            $('.tab-content .tab-select-show.tab-pane.active').removeClass('active');
+            tab.addClass('active');
+            tabPanel.addClass('active');
+            // $('.tab-content .tab-pane').removeClass('active');
+            showGclSideTools(tab.hasClass('active'));
+            if (tab.attr('content') === '#gcl-search') {
+                if (!gclSearch) {
+                    gclSearch = $.gclSearch({
+                        selector: '#gcl-search',
+                        gcl: { bills: gclGatherData, getBillsXmj: function(node){ return node.leafXmjs; } },
+                        searchField: { bills: ['b_code', 'name'], xmj: ['code', 'dwgc', 'fbgc', 'fxgc', 'jldy', 'bwmx'], },
+                        resultSpreadSetting: {
+                            cols: [
+                                {title: '清单编号', field: 'b_code', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '项目节编号', field: 'code', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '名称', field: 'name', width: 120, hAlign: 0, formatter: '@'},
+                                {title: '单位', field: 'unit', width: 50, hAlign: 1, formatter: '@'},
+                                {title: '单价', field: 'unit_price', hAlign: 2, width: 50},
+                                {title: '单位工程', colSpan: '1', rowSpan: '2', field: 'dwgc', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '分部工程', colSpan: '1', rowSpan: '2', field: 'fbgc', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '分项工程', colSpan: '1', rowSpan: '2', field: 'fxgc', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '细目', colSpan: '1', rowSpan: '2', field: 'jldy', hAlign: 0, width: 80, formatter: '@'},
+                                {title: '计量单元', colSpan: '1', rowSpan: '2', field: 'bwmx', hAlign: 0, width: 80, formatter: '@'},
+                            ],
+                            emptyRows: 0,
+                            headRows: 1,
+                            headRowHeight: [32],
+                            headColWidth: [30],
+                            defaultRowHeight: 21,
+                            headerFont: '12px 微软雅黑',
+                            font: '12px 微软雅黑',
+                            selectedBackColor: '#fffacd',
+                            readOnly: true,
+                        },
+                        locate: function(cur) {
+                            if (!cur.bid) return;
+
+                            const bIndex = gclSheet.zh_data.findIndex(x => { return x.id === cur.bid; });
+                            SpreadJsObj.locateRow(gclSheet, bIndex);
+                            loadLeafXmjData();
+                            if (cur.xid && cur.xid !== -1) {
+                                const xIndex = leafXmjSheet.zh_data.findIndex(x => { return x.id === cur.xid; });
+                                SpreadJsObj.locateRow(leafXmjSheet, xIndex);
+                            }
+                        },
+                    });
+                }
+                gclSearch.spread.refresh();
+            }
+        } else { // 收起工具栏
+            tab.removeClass('active');
+            tabPanel.removeClass('active');
+            showGclSideTools(tab.hasClass('active'));
+        }
+        gclSpread.refresh();
+        leafXmjSpread.refresh();
+    });
+
     $('#exportExcel').click(function () {
         const exportLedger = function () {
             const data = [];

+ 105 - 3
app/public/js/shares/cs_tools.js

@@ -803,7 +803,6 @@ const showSelectTab = function(select, spread, afterShow) {
         autoFlashHeight();
         const resultSpread = SpreadJsObj.createNewSpread($('#' + resultId)[0]);
         SpreadJsObj.initSheet(resultSpread.getActiveSheet(), setting.resultSpreadSetting);
-        const searchSheet = setting.searchSpread.getActiveSheet();
         let searchResult = [];
         const defaultCheck = function(node, keyword) {
             const keyNum = _.toNumber(keyword);
@@ -814,7 +813,7 @@ const showSelectTab = function(select, spread, afterShow) {
         };
         const getCheckFun = function (key) {
             const cs = setting.customSearch.find(function (x) {return x.key === key});
-            return cs ? [cs.billsCheck, cs.posCheck] : [null, null];
+            return cs ? [cs.billsCheck || cs.check, cs.posCheck] : [null, null];
         };
         const search = function () {
             const filter = $('#search-filter').val();
@@ -864,7 +863,7 @@ const showSelectTab = function(select, spread, afterShow) {
                             convertData[col.field] = node[col.field];
                         }
                     }
-                    searchResult.push(data);
+                    searchResult.push(convertData);
                 }
                 const posRange = ledger.pos ? ledger.pos.getLedgerPos(node.id) : ledger.getLedgerPos(node);
                 if (!posRange || posRange.length === 0) continue;
@@ -911,6 +910,109 @@ const showSelectTab = function(select, spread, afterShow) {
         });
         return {spread: resultSpread};
     };
+    $.gclSearch = function(setting) {
+        if (!setting.selector || !setting.gcl || !setting.resultSpreadSetting) return;
+        if (!setting.gcl.bills) return;
+        if (!setting.gcl.xmj && !setting.gcl.getBillsXmj) return;
+        if (!setting.searchRangeStr) setting.searchRangeStr = '清单编号/名称/项目节编号/单位/分部/分项工程/细目/计量单元';
+        if (!setting.keyId) setting.keyId = 'ledger_id';
+        const gcl = setting.gcl;
+        const resultId = setting.id + '-search-result';
+        const obj = $(setting.selector);
+        let filter = [];
+        if (setting.searchOver || setting.searchEmpty) {
+            filter.push('<select class="input-group-text" id="search-filter">');
+            filter.push('<option value="">清单</option>');
+            if (setting.customSearch) {
+                for (const cs of setting.customSearch) {
+                    if (cs.valid) filter.push('<option value="' + cs.key + '">' + cs.title + '</option>');
+                }
+            }
+            filter.push('</select>');
+        }
+        obj.html(
+            '                        <div class="sjs-bar">\n' +
+            '                            <div class="input-group input-group-sm pb-1">\n' +
+            '                                <div class="input-group-prepend">\n' +
+            filter.join('') +
+            '                                </div>' +
+            '                                <input id="searchKeyword" type="text" class="form-control" autocomplete="off" 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);
+        let searchResult = [];
+        const defaultCheck = function(node, keyword, fields) {
+            for (const f of fields) {
+                if (node[f] && node[f].indexOf(keyword) > -1) return true;
+            }
+            return false;
+        };
+        const getCheckFun = function (key) {
+            const cs = setting.customSearch.find(function (x) {return x.key === key});
+            return cs ? [cs.billsCheck, cs.xmjCheck] : [null, null];
+        };
+        const search = function () {
+            const filter = $('#search-filter').val();
+            const [billsCheck, xmjCheck] = filter ? getCheckFun(filter) : [null, null];
+            searchCustom(billsCheck || defaultCheck, xmjCheck || defaultCheck);
+        };
+        const searchCustom = function (billsCheckFun, xmjCheckFun) {
+            const keyword = $('#searchKeyword', obj).val();
+
+            searchResult = [];
+            for (const node of gcl.bills) {
+                if (billsCheckFun(node, keyword, setting.searchField.bills)) {
+                    const convertData = { bid: node.id, xid: -1 };
+                    for (const col of setting.resultSpreadSetting.cols) {
+                        convertData[col.field] = node[col.field];
+                    }
+                    searchResult.push(convertData);
+                }
+                const xmjRange = gcl.xmj ? gcl.xmj.getBillsXmj(node.id) : gcl.getBillsXmj(node);
+                if (!xmjRange || xmjRange.length === 0) continue;
+                for (const x of xmjRange) {
+                    if (xmjCheckFun(x, keyword, setting.searchField.xmj)) {
+                        const convertData = { bid: node.id, xid: x.id };
+                        for (const col of setting.resultSpreadSetting.cols) {
+                            convertData[col.field] = x[col.field];
+                        }
+                        searchResult.push(convertData);
+                    }
+                }
+            }
+            // calculateSum();
+            SpreadJsObj.loadSheetData(resultSpread.getActiveSheet(), 'data', searchResult);
+        };
+        const calculateSum = function () {
+            if (!searchResult || searchResult.length === 0 || !setting.calcSum) return;
+
+            const sum = setting.calcSum(searchResult);
+            if (sum) searchResult.unshift(sum);
+        };
+
+        $('input', obj).bind('keydown', function (e) {
+            if (e.keyCode == 13) search();
+        });
+        $('button', obj).bind('click', () => {search()});
+        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;
+            setting.locate(curBills);
+        });
+        return {spread: resultSpread};
+    };
 
     $.xmjSearch = function (setting) {
         if (!setting.selector || !setting.searchSpread) return;

+ 68 - 26
app/view/measure/compare.ejs

@@ -64,42 +64,84 @@
         <div class="c-body">
             <div class="tab-content" id="compareType">
                 <div class="tab-pane" id="tz">
-                    <div class="sjs-height-1" id="bills-spread">
-                    </div>
-                    <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">
-                                    <a class="nav-link active" data-toggle="tab" href="#xmujie" role="tab">计量单元</a>
-                                </li>
-                            </ul>
+                    <div class="content-wrap row pr-46" style="background: #e4e7ea;">
+                        <div class="c-header p-0 col-12">
                         </div>
-                        <div class="tab-content">
-                            <div class="tab-pane active" id="xmujie">
-                                <div class="sp-wrap" id="pos-spread">
+                        <div class="row w-100 sub-content">
+                            <div class="c-body" id="tz-left-view" style="width: 100%">
+                                <div class="sjs-height-1" id="bills-spread">
+                                </div>
+                                <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">
+                                                <a class="nav-link active" data-toggle="tab" href="#xmujie" role="tab">计量单元</a>
+                                            </li>
+                                        </ul>
+                                    </div>
+                                    <div class="tab-content">
+                                        <div class="tab-pane active" id="xmujie">
+                                            <div class="sp-wrap" id="pos-spread">
+                                            </div>
+                                        </div>
+                                    </div>
                                 </div>
                             </div>
+                            <div class="c-body" id="tz-right-view" style="display: none; width: 33%;">
+                                <div class="resize-x" id="right-spr" r-Type="width" div1="#tz-left-view" div2="#tz-right-view" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
+                                <div class="tab-content">
+                                    <div id="tz-search" class="tab-pane"></div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="side-menu side-memu-tz">
+                            <ul class="nav flex-column right-nav" id="tz-side-menu">
+                                <li>
+                                    <a class="nav-link" content="#tz-search" href="javascript: void(0);">查找定位</a>
+                                </li>
+                            </ul>
                         </div>
                     </div>
                 </div>
                 <div class="tab-pane active" id="gcl">
-                    <div class="sjs-height-1" id="gcl-spread">
-                    </div>
-                    <div class="bcontent-wrap" id="leafxmj-bottom">
-                        <div id="gcl-resize" class="resize-y" r-Type="height" div1="#gcl-spread" div2="#leafxmj-bottom" store-id="compare-stages-gcl" store-version="1.0.0" min="100"></div>
-                        <div class="bc-bar mb-1">
-                            <ul class="nav nav-tabs">
-                                <li class="nav-item">
-                                    <a class="nav-link active" data-toggle="tab" href="#xmujie" role="tab">所属项目节</a>
-                                </li>
-                            </ul>
+                    <div class="content-wrap row pr-46" style="background: #e4e7ea;">
+                        <div class="c-header p-0 col-12">
                         </div>
-                        <div class="tab-content">
-                            <div class="tab-pane active">
-                                <div class="sp-wrap" id="leaf-xmj-spread">
+                        <div class="row w-100 sub-content">
+                            <div class="c-body" id="gcl-left-view" style="width: 100%">
+                                <div class="sjs-height-1" id="gcl-spread">
+                                </div>
+                                <div class="bcontent-wrap" id="leafxmj-bottom">
+                                    <div id="gcl-resize" class="resize-y" r-Type="height" div1="#gcl-spread" div2="#leafxmj-bottom" store-id="compare-stages-gcl" store-version="1.0.0" min="100"></div>
+                                    <div class="bc-bar mb-1">
+                                        <ul class="nav nav-tabs">
+                                            <li class="nav-item">
+                                                <a class="nav-link active" data-toggle="tab" href="#xmujie" role="tab">所属项目节</a>
+                                            </li>
+                                        </ul>
+                                    </div>
+                                    <div class="tab-content">
+                                        <div class="tab-pane active">
+                                            <div class="sp-wrap" id="leaf-xmj-spread">
+                                            </div>
+                                        </div>
+                                    </div>
                                 </div>
                             </div>
+                            <div class="c-body" id="gcl-right-view" style="display: none; width: 33%;">
+                                <div class="resize-x" id="right-spr" r-Type="width" div1="#gcl-left-view" div2="#gcl-right-view" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
+                                <div class="tab-content">
+                                    <div id="gcl-search" class="tab-pane"></div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="side-menu gcl-side-memu">
+                            <ul class="nav flex-column right-nav" id="gcl-side-menu">
+                                <li>
+                                    <a class="nav-link" content="#gcl-search" href="javascript: void(0);">查找定位</a>
+                                </li>
+                            </ul>
                         </div>
                     </div>
                 </div>

+ 1 - 0
config/web.js

@@ -754,6 +754,7 @@ const JsFiles = {
                     '/public/js/shares/sjs_setting.js',
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
+                    '/public/js/shares/cs_tools.js',
                     '/public/js/gcl_gather.js',
                     '/public/js/measure_compare.js',
                 ],