瀏覽代碼

金额汇总、台账汇总、计量汇总,暂存结果相关

MaiXinRong 1 周之前
父節點
當前提交
88e7209fbf

+ 46 - 6
app/controller/spss_controller.js

@@ -30,8 +30,10 @@ module.exports = app => {
         async info(ctx) {
             try {
                 const categoryData = await this.ctx.service.category.getAllCategory(this.ctx.subProject);
+                const stashList = await this.ctx.service.spssStash.getSpssStashList(this.ctx.subProject.id, 'gather_info');
                 const renderData = {
                     categoryData,
+                    stashList,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.spss.gatherInfo)
                 };
                 await this.layout('spss/gather_info.ejs', renderData, 'spss/gather_info_modal.ejs');
@@ -43,11 +45,13 @@ module.exports = app => {
         async gatherLedger(ctx) {
             try {
                 const categoryData = await this.ctx.service.category.getAllCategory(this.ctx.subProject);
+                const stashList = await this.ctx.service.spssStash.getSpssStashList(this.ctx.subProject.id, 'gather_ledger');
                 const renderData = {
                     categoryData,
+                    stashList,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.spss.gatherLedger)
                 };
-                await this.layout('spss/gather_ledger.ejs', renderData, 'spss/spss_select_modal.ejs');
+                await this.layout('spss/gather_ledger.ejs', renderData, 'spss/spss_modal.ejs');
             } catch (err) {
                 ctx.helper.log(err);
             }
@@ -56,11 +60,13 @@ module.exports = app => {
         async gatherStage(ctx) {
             try {
                 const categoryData = await this.ctx.service.category.getAllCategory(this.ctx.subProject);
+                const stashList = await this.ctx.service.spssStash.getSpssStashList(this.ctx.subProject.id, 'gather_stage');
                 const renderData = {
                     categoryData,
+                    stashList,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.spss.gatherStage)
                 };
-                await this.layout('spss/gather_stage.ejs', renderData, 'spss/spss_select_modal.ejs');
+                await this.layout('spss/gather_stage.ejs', renderData, 'spss/spss_modal.ejs');
             } catch (err) {
                 ctx.helper.log(err);
             }
@@ -69,11 +75,13 @@ module.exports = app => {
         async gatherStageExtra(ctx) {
             try {
                 const categoryData = await this.ctx.service.category.getAllCategory(this.ctx.subProject);
+                const stashList = await this.ctx.service.spssStash.getSpssStashList(this.ctx.subProject.id, 'gather_stage_extra');
                 const renderData = {
                     categoryData,
+                    stashList,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.spss.gatherStageExtra)
                 };
-                await this.layout('spss/gather_stage_extra.ejs', renderData, 'spss/spss_select_modal.ejs');
+                await this.layout('spss/gather_stage_extra.ejs', renderData, 'spss/spss_modal.ejs');
             } catch (err) {
                 ctx.helper.log(err);
             }
@@ -82,11 +90,13 @@ module.exports = app => {
         async gatherStagePay(ctx) {
             try {
                 const categoryData = await this.ctx.service.category.getAllCategory(this.ctx.subProject);
+                const stashList = await this.ctx.service.spssStash.getSpssStashList(this.ctx.subProject.id, 'gather_stage_pay');
                 const renderData = {
                     categoryData,
+                    stashList,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.spss.gatherStagePay)
                 };
-                await this.layout('spss/gather_stage_pay.ejs', renderData, 'spss/spss_select_modal.ejs');
+                await this.layout('spss/gather_stage_pay.ejs', renderData, 'spss/spss_modal.ejs');
             } catch(err) {
                 ctx.log(err);
             }
@@ -95,11 +105,13 @@ module.exports = app => {
         async compareLedger(ctx) {
             try {
                 const categoryData = await this.ctx.service.category.getAllCategory(this.ctx.subProject);
+                const stashList = await this.ctx.service.spssStash.getSpssStashList(this.ctx.subProject.id, 'compare_ledger');
                 const renderData = {
                     categoryData,
+                    stashList,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.spss.compareLedger)
                 };
-                await this.layout('spss/compare_ledger.ejs', renderData, 'spss/spss_select_modal.ejs');
+                await this.layout('spss/compare_ledger.ejs', renderData, 'spss/spss_modal.ejs');
             } catch (err) {
                 ctx.helper.log(err);
             }
@@ -108,11 +120,13 @@ module.exports = app => {
         async compareStage(ctx) {
             try {
                 const categoryData = await this.ctx.service.category.getAllCategory(this.ctx.subProject);
+                const stashList = await this.ctx.service.spssStash.getSpssStashList(this.ctx.subProject.id, 'compare_stage');
                 const renderData = {
                     categoryData,
+                    stashList,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.spss.compareStage),
                 };
-                await this.layout('spss/compare_stage.ejs', renderData, 'spss/spss_select_modal.ejs');
+                await this.layout('spss/compare_stage.ejs', renderData, 'spss/spss_modal.ejs');
             } catch (err) {
                 ctx.helper.log(err);
             }
@@ -704,6 +718,32 @@ module.exports = app => {
                 ctx.body = this.ajaxErrorBody(err, '查询数据错误');
             }
         }
+
+        async stash(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const responseData = { err: 0, msg: '', data: [] };
+                if (!data.type || !data.action) throw '参数错误';
+
+                switch (data.action) {
+                    case 'load':
+                        responseData.data = await this.ctx.service.spssStash.getSpssStash(data.id);
+                        break;
+                    case 'list':
+                        responseData.data = await this.ctx.service.spssStash.getSpssStashList(this.ctx.subProject.id, data.type);
+                        break;
+                    case 'add':
+                        await this.ctx.service.spssStash.addSpssStash(data.type, data.select, data.result);
+                        responseData.data = await this.ctx.service.spssStash.getSpssStashList(this.ctx.subProject.id, data.type);
+                        break;
+                    default: throw '未知操作';
+                }
+                ctx.body = responseData;
+            } catch (err) {
+                ctx.log(err);
+                ctx.ajaxErrorBody(err, '暂存数据错误');
+            }
+        }
     }
 
     return SpssController;

+ 5 - 4
app/public/js/path_tree.js

@@ -1002,24 +1002,25 @@ const createNewPathTree = function (type, setting) {
             }
         };
 
-        _getDefaultNodeData(node) {
+        _getDefaultNodeData(node, filter) {
             const result = {};
             for (const prop in node) {
                 if (['children', 'visible', 'expanded'].indexOf(prop) >= 0) continue;
+                if (filter && filter(prop)) continue;
                 result[prop] = node[prop];
             }
             return result;
         }
 
-        getDefaultData(node) {
+        getDefaultData(node, filter) {
             if (node instanceof Array) {
                 const arr = [];
                 for (const n of node) {
-                    arr.push(this._getDefaultNodeData(n));
+                    arr.push(this._getDefaultNodeData(n, filter));
                 }
                 return arr;
             } else {
-                this._getDefaultNodeData(node);
+                this._getDefaultNodeData(node, filter);
             }
         }
 

+ 49 - 0
app/public/js/shares/spss_stash.js

@@ -0,0 +1,49 @@
+const SpssStash = function(setting){
+    let init = false;
+
+    const refreshStashListHtml = function(list) {
+        const html = [];
+        for (const [i, l] of list.entries()) {
+            html.push('<tr class="text-center">');
+            html.push(`<td>${i+1}</td>`);
+            html.push(`<td>${moment(l.create_time).format('YYYY-MM-DD HH:mm:ss')}</td>`);
+            html.push(`<td>${l.user_name}</td>`);
+            html.push(`<td><button name="load-spss-stash" class="btn btn-sm btn-primary" sid="${l.id}">载入</button></td>`);
+            html.push('</tr>');
+        }
+        $('#spss-stash-list').html(html.join(''));
+    };
+
+    const showStash = async function() {
+        if (!init) {
+            const list = await postDataAsync(setting.url, { type: setting.type, action: 'list' });
+            refreshStashListHtml(list);
+            init = true;
+        }
+        $('#spss-stash').modal('show');
+    };
+
+    $('#spss-stash-add').click(() => {
+        const data = setting.getCurStashData();
+        if (!data) return;
+
+        data.type = setting.type;
+        data.action = 'add';
+        postData(setting.url, data, function(result) {
+            refreshStashListHtml(result);
+        });
+    });
+
+    $('body').on('click', '[name=load-spss-stash]', function() {
+        const id = this.getAttribute('sid');
+        if (!id) {
+            toastr.warning('数据错误,请刷新页面后重试');
+            return;
+        }
+
+        postData(setting.url, { type: setting.type, action: 'load', id: id }, function(result) {
+            setting.loadStashData(result);
+        });
+    });
+    return { showStash }
+};

+ 7 - 1
app/public/js/shares/tenders2tree.js

@@ -108,5 +108,11 @@ const Tender2Tree = (function () {
         tenderTree.sortTreeNode(true);
         return tenderTree;
     }
-    return { convert }
+
+    function getNewConvertTree () {
+        tenderTree = createNewPathTree('gather', treeSetting);
+        tenderTree.clearDatas();
+        return tenderTree;
+    }
+    return { convert, getNewConvertTree }
 })();

+ 39 - 1
app/public/js/spss_gather_ledger.js

@@ -3,6 +3,7 @@ const posCompareField = ['quantity'];
 
 $(document).ready(() => {
     autoFlashHeight();
+    let isCache = false, selectTenders = [];
     const billsSpreadSetting = {
         cols: [
             {title: '项目节编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 185, formatter: '@', cellType: 'tree'},
@@ -162,7 +163,6 @@ $(document).ready(() => {
     const posSpreadObj = {
         loadCurPosData: function () {
             const node = SpreadJsObj.getSelectObject(billsSheet);
-            console.log(node);
             if (node) {
                 SpreadJsObj.loadSheetData(posSheet, 'data', node.pos || []);
             } else {
@@ -178,6 +178,7 @@ $(document).ready(() => {
         afterSelect: function(select) {
             const data = { filter: 'ledger', tender: select };
             postData(`/sp/${spid}/spss/load`, data, function(result) {
+                isCache = false;
                 billsTreeSpreadObj.rebuildSpreadSetting(result);
                 SpreadJsObj.reLoadSheetHeader(billsSheet);
                 SpreadJsObj.reLoadSheetHeader(posSheet);
@@ -196,6 +197,7 @@ $(document).ready(() => {
                 const posSetting = { id: 'id', ledgerId: 'lid' };
                 const tenders = [];
                 for (const t of result) {
+                    selectTenders.push({ id: t.id, name: t.name, stage_filter: t.stage_filter });
                     const tender = {
                         billsTree: createNewPathTree('ledger', tenderTreeSetting),
                         pos: new PosData(posSetting),
@@ -210,6 +212,8 @@ $(document).ready(() => {
                 treeCalc.calculateAll(billsTree);
                 SpreadJsObj.loadSheetData(billsSheet, SpreadJsObj.DataType.Tree, billsTree, true);
                 posSpreadObj.loadCurPosData();
+
+                $('#stash-hint').html(`当前显示:${moment(data.create_time).format('YYYY-MM-DD HH:mm:ss')} (${data.user_name})`);
             });
         },
     });
@@ -298,4 +302,38 @@ $(document).ready(() => {
             posSpread.refresh();
         }
     });
+
+    const spssStash = SpssStash({
+        type: 'gather_ledger',
+        url: `/sp/${spid}/spss/stash`,
+        getCurStashData: function() {
+            if (!billsTree || billsTree.nodes.length === 0) {
+                toastr.warning('当前无数据可暂存,请先汇总标段后,再操作');
+                return null;
+            }
+            if (isCache) {
+                toastr.warning('当前数据为暂存数据,请勿重复保存');
+                return null;
+            }
+
+            const data = { result: { bills: billsTree.getDefaultData(billsTree.nodes) } };
+            data.select = selectTenders;
+            return data;
+        },
+        loadStashData: function(data) {
+            isCache = true;
+
+            billsTreeSpreadObj.rebuildSpreadSetting(data.spss_select);
+            SpreadJsObj.reLoadSheetHeader(billsSheet);
+            SpreadJsObj.reLoadSheetHeader(posSheet);
+
+            billsTree.clearDatas();
+            billsTree.loadDatas(data.spss_result.bills);
+            SpreadJsObj.loadSheetData(billsSheet, SpreadJsObj.DataType.Tree, billsTree, true);
+            posSpreadObj.loadCurPosData();
+
+            $('#stash-hint').html(`当前显示:${moment(data.create_time).format('YYYY-MM-DD HH:mm:ss')} (${data.user_name})`);
+        }
+    });
+    $('#stash').click(() => { spssStash.showStash(); });
 });

+ 41 - 1
app/public/js/spss_gather_stage.js

@@ -11,6 +11,7 @@ const posCompareField = [
 
 $(document).ready(() => {
     autoFlashHeight();
+    let isCache = false, selectTenders = [];
     const billsSpreadSetting = {
         cols: [
             {title: '项目节编号', colSpan: '1', rowSpan: '3', field: 'code', hAlign: 0, width: 185, formatter: '@', cellType: 'tree'},
@@ -208,7 +209,6 @@ $(document).ready(() => {
         loadCurPosData: function () {
             const node = SpreadJsObj.getSelectObject(billsSheet);
             if (node) {
-                console.log(node.pos);
                 SpreadJsObj.loadSheetData(posSheet, 'data', node.pos || []);
             } else {
                 SpreadJsObj.loadSheetData(posSheet, 'data', []);
@@ -223,6 +223,7 @@ $(document).ready(() => {
         afterSelect: function(select) {
             const data = { filter: 'stage', tender: select };
             postData(`/sp/${spid}/spss/load`, data, function(result) {
+                isCache = false;
                 billsTreeSpreadObj.rebuildSpreadSetting(result);
                 SpreadJsObj.reLoadSheetHeader(billsSheet, true);
                 SpreadJsObj.reLoadSheetHeader(posSheet, true);
@@ -266,6 +267,7 @@ $(document).ready(() => {
                 };
                 const tenders = [];
                 for (const t of result) {
+                    selectTenders.push({ id: t.id, name: t.name, stage_filter: t.stage_filter });
                     const tender = {
                         billsTree: createNewPathTree('ledger', tenderTreeSetting),
                         pos: new PosData(posSetting),
@@ -377,4 +379,42 @@ $(document).ready(() => {
             posSpread.refresh();
         }
     });
+
+    const spssStash = SpssStash({
+        type: 'gather_stage',
+        url: `/sp/${spid}/spss/stash`,
+        getCurStashData: function() {
+            if (!billsTree || billsTree.nodes.length === 0) {
+                toastr.warning('当前无数据可暂存,请先汇总标段后,再操作');
+                return null;
+            }
+            if (isCache) {
+                toastr.warning('当前数据为暂存数据,请勿重复保存');
+                return null;
+            }
+
+            const data = { result: { bills: billsTree.getDefaultData(billsTree.nodes) } };
+            data.select = selectTenders;
+            return data;
+        },
+        loadStashData: function(data) {
+            isCache = true;
+
+            billsTreeSpreadObj.rebuildSpreadSetting(data.spss_select);
+            SpreadJsObj.reLoadSheetHeader(billsSheet, true);
+            SpreadJsObj.reLoadSheetHeader(posSheet, true);
+
+            billsTree.clearDatas();
+            billsTree.loadDatas(data.spss_result.bills);
+            billsTree.count = data.spss_select.length;
+            billsTreeSpreadObj.loadShowData();
+            SpreadJsObj.loadSheetData(billsSheet, SpreadJsObj.DataType.Tree, billsTree, true);
+            SpreadJsObj.locateRow(billsSheet, 0);
+            posSpreadObj.loadCurPosData();
+            SpreadJsObj.locateRow(posSheet, 0);
+
+            $('#stash-hint').html(`当前显示:${moment(data.create_time).format('YYYY-MM-DD HH:mm:ss')} (${data.user_name})`);
+        }
+    });
+    $('#stash').click(() => { spssStash.showStash(); });
 });

+ 51 - 0
app/public/js/spss_gather_stage_extra.js

@@ -163,6 +163,8 @@ $(document).ready(() => {
     const stageExtra = {
         seType: 'jgcl',
         seData: 'cur',
+        tenderCount: 0,
+        selectTenders: [],
         jgcl: [],
         yjcl: [],
         bonus: createNewPathTree('gather', {id: 'tree_id', pid: 'tree_pid', order: 'order', level: 'level', rootId: -1, fullPath: 'full_path', calcFields: ['tp']}),
@@ -316,6 +318,7 @@ $(document).ready(() => {
         },
         gatherStageExtraData(tenders) {
             this.tenderCount = tenders.length;
+            this.selectTenders = tenders.map(t => { return { id: t.id, name: t.name, stage_filter: t.stage_filter }; });
             this.gatherJgcl(tenders);
             this.gatherYjcl(tenders);
             this.gatherBonus(tenders);
@@ -411,6 +414,16 @@ $(document).ready(() => {
             }
             this.loadSheetData();
         },
+        loadStashData(data) {
+            this.tenderCount = data.spss_select.length;
+            this.selectTenders = data.spss_select;
+            this.jgcl = data.spss_result.jgcl;
+            this.yjcl = data.spss_result.yjcl;
+            this.bonus.loadDatas(data.spss_result.bonus);
+            this.other.loadDatas(data.spss_result.other);
+            this.safeProd = data.spss_result.safeProd;
+            this.tempLand.loadDatas(data.spss_result.tempLand);
+        }
     };
     stageExtra.loadSheetData();
 
@@ -469,4 +482,42 @@ $(document).ready(() => {
             dataSpread.refresh();
         }
     });
+
+    const spssStash = SpssStash({
+        type: 'gather_stage_extra',
+        url: `/sp/${spid}/spss/stash`,
+        getCurStashData: function() {
+            if (stageExtra.tenderCount === 0) {
+                toastr.warning('当前无数据可暂存,请先汇总标段后,再操作');
+                return null;
+            }
+            if (stageExtra.isCache) {
+                toastr.warning('当前数据为暂存数据,请勿重复保存');
+                return null;
+            }
+
+            const data = {
+                result: {
+                    jgcl: stageExtra.jgcl,
+                    yjcl: stageExtra.yjcl,
+                    bonus: stageExtra.other.getDefaultData(stageExtra.bonus.nodes),
+                    other: stageExtra.bonus.getDefaultData(stageExtra.other.nodes),
+                    safeProd: stageExtra.safeProd,
+                    tempLand: stageExtra.tempLand.getDefaultData(stageExtra.tempLand.nodes),
+                },
+                select: stageExtra.selectTenders
+            };
+            return data;
+        },
+        loadStashData: function(data) {
+            stageExtra.loadStashData(data);
+            stageExtra.rebuildSpreadSetting(data.spss_select);
+            SpreadJsObj.reLoadSheetHeader(dataSheet, true);
+            stageExtra.loadShowData(true);
+            stageExtra.loadSheetData();
+
+            $('#stash-hint').html(`当前显示:${moment(data.create_time).format('YYYY-MM-DD HH:mm:ss')} (${data.user_name})`);
+        }
+    });
+    $('#stash').click(() => { spssStash.showStash(); });
 });

+ 36 - 1
app/public/js/spss_gather_stage_info.js

@@ -71,6 +71,7 @@ $(document).ready(() => {
 
     const infoObj = {
         tenders: [],
+        isCache: false,
         rebuildInfoTree: function(categoryLevel) {
             infoTree = Tender2Tree.convert(category, this.tenders, null, null, function(node, tender) {
                 node.measure_type_str = tender.info.measure_type_str;
@@ -95,13 +96,23 @@ $(document).ready(() => {
             treeCalc.calculateAll(infoTree);
         },
         refreshInfoTree: function(categoryLevel) {
+            if (this.isCache) return;
+
             this.rebuildInfoTree(categoryLevel);
             SpreadJsObj.loadSheetData(infoSheet, SpreadJsObj.DataType.Tree, infoTree, true);
         },
         loadTenders: function(tenders) {
+            this.isCache = false;
             this.tenders = tenders;
             const categoryLevel = infoCate.getCategoryLevel();
             this.refreshInfoTree(categoryLevel);
+        },
+        loadStashData: function(data) {
+            this.isCache = true;
+            this.tenders = data.spss_select;
+            infoTree = Tender2Tree.getNewConvertTree();
+            infoTree.loadDatas(data.spss_result);
+            SpreadJsObj.loadSheetData(infoSheet, SpreadJsObj.DataType.Tree, infoTree, true);
         }
     };
 
@@ -349,5 +360,29 @@ $(document).ready(() => {
     });
     $('#spss-info-col-set').click(() => {
         customColSet.show(colSetSetting);
-    })
+    });
+
+    const spssStash = SpssStash({
+        type: 'gather_stage_info',
+        url: `/sp/${spid}/spss/stash`,
+        getCurStashData: function() {
+            if (!infoTree || infoTree.nodes.length === 0) {
+                toastr.warning('当前无数据可暂存,请先汇总标段后,再操作');
+                return null;
+            }
+            if (infoObj.isCache) {
+                toastr.warning('当前数据为暂存数据,请勿重复保存');
+                return null;
+            }
+
+            const data = { result: infoTree.getDefaultData(infoTree.nodes) };
+            data.select = infoObj.tenders.map(t => { return { id: t.id, name: t.name, stage_filter: t.stage_filter } });
+            return data;
+        },
+        loadStashData: function(data) {
+            infoObj.loadStashData(data);
+            $('#stash-hint').html(`当前显示:${moment(data.create_time).format('YYYY-MM-DD HH:mm:ss')} (${data.user_name})`);
+        }
+    });
+    $('#stash').click(() => { spssStash.showStash(); });
 });

+ 38 - 0
app/public/js/spss_gather_stage_pay.js

@@ -32,9 +32,13 @@ $(document).ready(() => {
     const payGather = {
         pays: [],
         seData: 'cur',
+        tenderCount: 0,
+        selectTenders: [],
         gatherPays(tenders) {
             this.pays = [];
+            this.selectTenders = [];
             for (const [i, t] of tenders.entries()) {
+                this.selectTenders.push({ id: t.id, name: t.name, stage_filter: t.stage_filter });
                 const endfix = '_' + (i + 1);
                 for (const data of t.pay) {
                     if (!data.name) data.name = '';
@@ -56,6 +60,7 @@ $(document).ready(() => {
             }
         },
         gatherStageExtraData(tenders) {
+            this.isCache = false;
             this.tenderCount = tenders.length;
             this.gatherPays(tenders);
         },
@@ -108,6 +113,13 @@ $(document).ready(() => {
             }
             this.loadSheetData();
         },
+        loadStashData(data) {
+            this.isCache = true;
+            this.tenderCount = data.spss_select.length;
+            this.selectTenders = data.spss_select;
+            this.rebuildSpreadSetting(data.spss_select);
+            this.pays = data.spss_result.pays;
+        }
     };
     payGather.loadSheetData();
 
@@ -157,4 +169,30 @@ $(document).ready(() => {
             paySpread.refresh();
         }
     });
+
+    const spssStash = SpssStash({
+        type: 'gather_stage_pay',
+        url: `/sp/${spid}/spss/stash`,
+        getCurStashData: function() {
+            if (payGather.pays.length === 0) {
+                toastr.warning('当前无数据可暂存,请先汇总标段后,再操作');
+                return null;
+            }
+            if (payGather.isCache) {
+                toastr.warning('当前数据为暂存数据,请勿重复保存');
+                return null;
+            }
+
+            const data = { result: { pays: payGather.pays }, select: payGather.selectTenders };
+            return data;
+        },
+        loadStashData: function(data) {
+            payGather.loadStashData(data);
+            SpreadJsObj.reLoadSheetHeader(paySheet, true);
+            payGather.loadShowData(true);
+            payGather.loadSheetData();
+            $('#stash-hint').html(`当前显示:${moment(data.create_time).format('YYYY-MM-DD HH:mm:ss')} (${data.user_name})`);
+        }
+    });
+    $('#stash').click(() => { spssStash.showStash(); });
 });

+ 1 - 0
app/router.js

@@ -303,6 +303,7 @@ module.exports = app => {
     app.get('/sp/:id/spss/compare/ledger', sessionAuth, subProjectCheck, 'spssController.compareLedger');
     app.get('/sp/:id/spss/compare/stage', sessionAuth, subProjectCheck, 'spssController.compareStage');
     app.post('/sp/:id/spss/load', sessionAuth, subProjectCheck, 'spssController.load');
+    app.post('/sp/:id/spss/stash', sessionAuth, subProjectCheck, 'spssController.stash');
 
     // **标段合同管理 todo 接入项目内部
     // app.get('/sp/:id/contract', sessionAuth, subProjectCheck, 'contractController.index');

+ 63 - 0
app/service/spss_stash.js

@@ -0,0 +1,63 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date 2025/12/05
+ * @version
+ */
+
+const maxStashCount = 5;
+
+module.exports = app => {
+
+    class SpssStash extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'spss_stash';
+        }
+
+        async getSpssStashList(spid, spssType) {
+            const result = await this.getAllDataByCondition({
+                where: { spid, spss_type: spssType },
+                columns: [ 'id', 'user_id', 'user_name', 'create_time' ],
+                orders: [['create_time', 'desc']],
+            });
+            if (result.length > maxStashCount) {
+                const id = [...result].reverse().slice(0, result.length - maxStashCount).map(x => { return x.id; });
+                await this.db.delete(this.tableName, { id });
+                return result.slice(0, maxStashCount);
+            }
+            return result;
+        }
+
+        async getSpssStash(id) {
+            const data = await this.getDataById(id);
+            data.spss_select = JSON.parse(data.spss_select);
+            data.spss_result = JSON.parse(data.spss_result);
+            return data;
+        }
+
+        async addSpssStash(type, select, result) {
+            const data = {
+                id: this.uuid.v4(), spid: this.ctx.subProject.id,
+                user_id: this.ctx.session.sessionUser.accountId, user_name: this.ctx.session.sessionUser.name,
+                spss_type: type,
+                spss_select: JSON.stringify(select),
+                spss_result: JSON.stringify(result),
+            };
+            await this.db.insert(this.tableName, data);
+        }
+
+    }
+
+    return SpssStash;
+};

+ 4 - 0
app/view/spss/compare_ledger.ejs

@@ -26,6 +26,10 @@
                     </div>
                 </div>
             </div>
+            <div class="ml-auto">
+                <span id="stash-hint" class="text-warning"></span>
+                <button class="btn btn-primary btn-sm mr-2" id="stash">暂存结果</button>
+            </div>
         </div>
     </div>
     <div class="content-wrap">

+ 5 - 1
app/view/spss/compare_stage.ejs

@@ -3,7 +3,7 @@
     <div class="panel-title">
         <div class="title-main d-flex">
             <% include ../tender/list_sub_mini_menu.ejs %>
-            <div class="title-main  d-flex justify-content-between">
+            <div class="title-main d-flex justify-content-between">
                 <div>
                     <div class="d-inline-block mr-2">
                         <!--展开/收起-->
@@ -55,6 +55,10 @@
                     </div>
                 </div>
             </div>
+            <div class="ml-auto">
+                <span id="stash-hint" class="text-warning"></span>
+                <button class="btn btn-primary btn-sm mr-2" id="stash">暂存结果</button>
+            </div>
         </div>
     </div>
     <div class="content-wrap">

+ 5 - 1
app/view/spss/gather_info.ejs

@@ -3,7 +3,7 @@
     <div class="panel-title">
         <div class="title-main d-flex">
             <% include ../tender/list_sub_mini_menu.ejs %>
-            <div class="title-main  d-flex justify-content-between">
+            <div class="title-main d-flex justify-content-between">
                 <div>
                     <div class="d-inline-block mr-2">
                         <div class="btn-group">
@@ -26,6 +26,10 @@
                     </div>
                 </div>
             </div>
+            <div class="ml-auto">
+                <span id="stash-hint" class="text-warning"></span>
+                <button class="btn btn-primary btn-sm mr-2" id="stash">暂存结果</button>
+            </div>
         </div>
     </div>
     <div class="content-wrap">

+ 1 - 0
app/view/spss/gather_info_modal.ejs

@@ -1,5 +1,6 @@
 <% include ./spss_select_modal.ejs %>
 <% include ../shares/col_set_modal.ejs %>
+<% include ./spss_stash_modal.ejs %>
 <div class="modal fade" id="info-cate" data-backdrop="static">
     <div class="modal-dialog" role="document">
         <div class="modal-content">

+ 4 - 3
app/view/spss/gather_ledger.ejs

@@ -25,9 +25,10 @@
                         <button class="btn btn-sm btn-primary" id="gather-select">汇总标段</button>
                     </div>
                 </div>
-                <div class="">
-
-                </div>
+            </div>
+            <div class="ml-auto">
+                <span id="stash-hint" class="text-warning"></span>
+                <button class="btn btn-primary btn-sm mr-2" id="stash">暂存结果</button>
             </div>
         </div>
     </div>

+ 4 - 3
app/view/spss/gather_stage.ejs

@@ -61,9 +61,10 @@
                         </div>
                     </div>
                 </div>
-                <div class="">
-
-                </div>
+            </div>
+            <div class="ml-auto">
+                <span id="stash-hint" class="text-warning"></span>
+                <button class="btn btn-primary btn-sm mr-2" id="stash">暂存结果</button>
             </div>
         </div>
     </div>

+ 4 - 0
app/view/spss/gather_stage_extra.ejs

@@ -31,6 +31,10 @@
                     </div>
                 </div>
             </div>
+            <div class="ml-auto">
+                <span id="stash-hint" class="text-warning"></span>
+                <button class="btn btn-primary btn-sm mr-2" id="stash">暂存结果</button>
+            </div>
         </div>
     </div>
     <div class="content-wrap">

+ 4 - 0
app/view/spss/gather_stage_pay.ejs

@@ -31,6 +31,10 @@
                     </div>
                 </div>
             </div>
+            <div class="ml-auto">
+                <span id="stash-hint" class="text-warning"></span>
+                <button class="btn btn-primary btn-sm mr-2" id="stash">暂存结果</button>
+            </div>
         </div>
     </div>
     <div class="content-wrap">

+ 2 - 0
app/view/spss/spss_modal.ejs

@@ -0,0 +1,2 @@
+<% include ./spss_select_modal.ejs %>
+<% include ./spss_stash_modal.ejs %>

+ 24 - 0
app/view/spss/spss_stash_modal.ejs

@@ -0,0 +1,24 @@
+<div class="modal fade" id="spss-stash" data-backdrop="static">
+    <div class="modal-dialog modal-lx" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">暂存结果</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <h5>可用数据 </h5>
+                <table class="table table-sm table-bordered">
+                    <thead><tr class="text-center"><th>序号</th><th>创建时间</th><th>创建人</th><th>操作</th></tr></thead>
+                    <tbody id="spss-stash-list">
+                    </tbody>
+                </table>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
+                <button class="btn btn-sm btn-primary" id="spss-stash-add">新增暂存</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 14 - 0
config/web.js

@@ -2032,6 +2032,7 @@ const JsFiles = {
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
                     '/public/js/file-saver/FileSaver.js',
+                    '/public/js/moment/moment.min.js',
                     '/public/js/datepicker/datepicker.min.js', '/public/js/datepicker/datepicker.zh.js',
                     '/public/js/ztree/jquery.ztree.core.js', '/public/js/ztree/jquery.ztree.exedit.js',
                 ],
@@ -2045,6 +2046,7 @@ const JsFiles = {
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
                     '/public/js/shares/tenders2tree.js',
+                    '/public/js/shares/spss_stash.js',
                     '/public/js/spss_gather_stage_info.js',
                 ],
                 mergeFile: 'spss_gather_stage_info',
@@ -2056,6 +2058,7 @@ const JsFiles = {
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
                     '/public/js/file-saver/FileSaver.js',
+                    '/public/js/moment/moment.min.js',
                     '/public/js/datepicker/datepicker.min.js', '/public/js/datepicker/datepicker.zh.js',
                 ],
                 mergeFiles: [
@@ -2068,6 +2071,7 @@ const JsFiles = {
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
                     '/public/js/shares/tenders2tree.js',
+                    '/public/js/shares/spss_stash.js',
                     '/public/js/spss_gather_ledger.js',
                 ],
                 mergeFile: 'spss_gather_ledger',
@@ -2079,6 +2083,7 @@ const JsFiles = {
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
                     '/public/js/file-saver/FileSaver.js',
+                    '/public/js/moment/moment.min.js',
                     '/public/js/datepicker/datepicker.min.js', '/public/js/datepicker/datepicker.zh.js',
                 ],
                 mergeFiles: [
@@ -2091,6 +2096,7 @@ const JsFiles = {
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
                     '/public/js/shares/tenders2tree.js',
+                    '/public/js/shares/spss_stash.js',
                     '/public/js/spss_gather_stage.js',
                 ],
                 mergeFile: 'spss_gather_stage',
@@ -2102,6 +2108,7 @@ const JsFiles = {
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
                     '/public/js/file-saver/FileSaver.js',
+                    '/public/js/moment/moment.min.js',
                     '/public/js/datepicker/datepicker.min.js', '/public/js/datepicker/datepicker.zh.js',
                 ],
                 mergeFiles: [
@@ -2114,6 +2121,7 @@ const JsFiles = {
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
                     '/public/js/shares/tenders2tree.js',
+                    '/public/js/shares/spss_stash.js',
                     '/public/js/spss_gather_stage_extra.js',
                 ],
                 mergeFile: 'spss_gather_stage_extra',
@@ -2124,6 +2132,7 @@ const JsFiles = {
                     '/public/js/spreadjs/sheets/v11/interop/gc.spread.excelio.11.2.2.min.js',
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
+                    '/public/js/moment/moment.min.js',
                     '/public/js/file-saver/FileSaver.js',
                     '/public/js/datepicker/datepicker.min.js', '/public/js/datepicker/datepicker.zh.js',
                 ],
@@ -2137,6 +2146,7 @@ const JsFiles = {
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
                     '/public/js/shares/tenders2tree.js',
+                    '/public/js/shares/spss_stash.js',
                     '/public/js/spss_gather_stage_pay.js',
                 ],
                 mergeFile: 'spss_gather_stage_pay',
@@ -2147,6 +2157,7 @@ const JsFiles = {
                     '/public/js/spreadjs/sheets/v11/interop/gc.spread.excelio.11.2.2.min.js',
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
+                    '/public/js/moment/moment.min.js',
                     '/public/js/file-saver/FileSaver.js',
                     '/public/js/datepicker/datepicker.min.js', '/public/js/datepicker/datepicker.zh.js',
                 ],
@@ -2160,6 +2171,7 @@ const JsFiles = {
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
                     '/public/js/shares/tenders2tree.js',
+                    '/public/js/shares/spss_stash.js',
                     '/public/js/spss_compare_ledger.js',
                 ],
                 mergeFile: 'spss_compare_ledger',
@@ -2170,6 +2182,7 @@ const JsFiles = {
                     '/public/js/spreadjs/sheets/v11/interop/gc.spread.excelio.11.2.2.min.js',
                     '/public/js/decimal.min.js',
                     '/public/js/math.min.js',
+                    '/public/js/moment/moment.min.js',
                     '/public/js/file-saver/FileSaver.js',
                     '/public/js/datepicker/datepicker.min.js', '/public/js/datepicker/datepicker.zh.js',
                 ],
@@ -2183,6 +2196,7 @@ const JsFiles = {
                     '/public/js/zh_calc.js',
                     '/public/js/path_tree.js',
                     '/public/js/shares/tenders2tree.js',
+                    '/public/js/shares/spss_stash.js',
                     '/public/js/spss_compare_stage.js',
                 ],
                 mergeFile: 'spss_compare_stage',

+ 12 - 0
sql/update.sql

@@ -122,6 +122,18 @@ ADD COLUMN `safe_payment` varchar(255) NOT NULL DEFAULT '' COMMENT '安全计量
 ALTER TABLE `zh_budget`
 ADD COLUMN `final_type` varchar(50) NOT NULL DEFAULT 'code_name' COMMENT '决算汇总规则' AFTER `final_id`;
 
+CREATE TABLE `zh_spss_stash`  (
+  `id` varchar(36) NOT NULL COMMENT 'uuid',
+  `spid` varchar(36) NOT NULL COMMENT '子项目id(zh_sub_project.id)',
+  `user_id` integer(11) NOT NULL COMMENT '创建用户id',
+  `user_name` varchar(20) NOT NULL DEFAULT '' COMMENT '创建人姓名',
+  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `spss_type` varchar(20) NOT NULL COMMENT '汇总对比类型',
+  `spss_select` varchar(1000) NOT NULL COMMENT '汇总对比选择',
+  `spss_result` json NULL COMMENT '汇总对比结果',
+  PRIMARY KEY (`id`)
+);
+
 ------------------------------------
 -- 表数据
 ------------------------------------