瀏覽代碼

1. 汇总对比,合同支付,台账对比,计量对比,暂存数据相关
2. 汇总对比,报表数据相关

MaiXinRong 4 天之前
父節點
當前提交
3cb02e4c1e

+ 1 - 1
app/base/base_controller.js

@@ -11,7 +11,7 @@ const moment = require('moment');
 const messageType = require('../const/message_type');
 const Controller = require('egg').Controller;
 const maintainConst = require('../const/maintain');
-const otherProjectController = ['setting', 'file', 'profile'];
+const otherProjectController = ['setting', 'file', 'profile', 'devTest'];
 
 class BaseController extends Controller {
 

+ 11 - 11
app/const/source_type.js

@@ -1,17 +1,17 @@
 'use strict';
 
 const sourceTypeData = [
-    { id: 1, name: '标段&期', key: 'tender' },
-    { id: 10, name: '预付款', key: 'advance' },
-    { id: 20, name: '变更令', key: 'change' },
-    { id: 21, name: '变更方案', key: 'change_plan' },
-    { id: 22, name: '变更立项', key: 'change_project' },
-    { id: 23, name: '变更申请', key: 'change_apply' },
-    { id: 30, name: '材料调差', key: 'material' },
-    { id: 100, name: '支付审批', key: 'payment' },
-    { id: 101, name: '安全生产费', key: 'payment_safe' },
-    { id: 200, name: '动态投资', key: 'budget' },
-    { id: 300, name: '合同管理', key: 'contract_management' },
+    { id: 1, name: '标段&期', key: 'tender', params: { tender_id: 1, stage_id: 1 } },
+    { id: 10, name: '预付款', key: 'advance', params: { advance_id: 1 } },
+    { id: 20, name: '变更令', key: 'change', params: { change_id: 'uuid' } },
+    { id: 21, name: '变更方案', key: 'change_plan', params: { change_plan_id: 1 } },
+    { id: 22, name: '变更立项', key: 'change_project', params: { change_project_id: 1 } },
+    { id: 23, name: '变更申请', key: 'change_apply', params: { change_apply_id: 1 } },
+    { id: 30, name: '材料调差', key: 'material', params: { material_id: 1 } },
+    { id: 100, name: '支付审批', key: 'payment', params: { tender_id: 1, detail_id: 1 } },
+    { id: 101, name: '安全生产费', key: 'payment_safe', params: { tender_id: 1, detail_id: 1 } },
+    { id: 200, name: '动态投资', key: 'budget', params: { sp_id: 'uuid', budget_id: 1 } },
+    { id: 300, name: '合同管理', key: 'contract_management', params: {} },
     // { id: 301, name: '标段合同', key: 'tender_contract' },
 ];
 

+ 29 - 0
app/controller/spss_controller.js

@@ -744,6 +744,35 @@ module.exports = app => {
                 ctx.ajaxErrorBody(err, '暂存数据错误');
             }
         }
+
+        async test(ctx) {
+            try {
+                const sourceType = require('../const/source_type');
+                await this.layout('spss/dev_test.ejs', { sourceType });
+            } catch (err) {
+                ctx.helper.log(err);
+            }
+        }
+
+        async _testLoadReport(data) {
+            const reportData = await this.ctx.service.report.getReportData(data.source_type, data.params, data.source_filters);
+            this.ctx.body = { err: 0, msg: '', data: reportData };
+        }
+        async testLoad(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data.type && !data.detail) throw '参数错误';
+                switch(data.type) {
+                    case 'report':
+                        await this._testLoadReport(data.detail);
+                        break;
+                    default: throw '未知参数';
+                }
+            } catch (err) {
+                ctx.log(err);
+                ctx.ajaxErrorBody(err, '查询数据错误');
+            }
+        }
     }
 
     return SpssController;

+ 138 - 0
app/lib/rm/spss.js

@@ -0,0 +1,138 @@
+'use strict';
+
+/**
+ * 要求必须有ctx.subProject
+ * 如果不是子项目内部使用,需要先载入ctx.subProject再使用
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+class reportMemorySpss {
+    constructor(ctx) {
+        this.ctx = ctx;
+    }
+
+    async _loadTypeData(type) {
+        if (!this[type]) this[type] = await this.ctx.service.spssStash.getLatestSpssStash(this.ctx.subProject.id, type);
+    }
+
+    async getTypeTender(type) {
+        await this._loadTypeData(type);
+        return this[type] ? this[type].spss_select : [];
+    }
+
+    async getTyperBills(type) {
+        await this._loadTypeData(type);
+        return this[type] && this[type].spss_result ? this[type].spss_result.bills : [];
+
+    }
+    getBillsPosData(bills) {
+        const pos = [];
+        for (const b of bills) {
+            if (!b.pos || b.pos.length === 0) continue;
+            b.pos.forEach(x => { x.lid === b.ledger_id; });
+            pos.push(...b.pos);
+        }
+        return pos;
+    }
+    async getTypePos(type) {
+        await this._loadTypeData(type);
+        return this[type] && this[type].spss_result ? this.getBillsPosData(this[type].spss_result.bills) : [];
+    }
+
+    async getGatherStageInfoTender() {
+        return await this.getTypeTender('gather_stage_info');
+    }
+    async getGatherStageInfo() {
+        await this._loadTypeData('gather_stage_info');
+        return this.gather_stage_info.spss_result || [];
+    }
+
+    async getGatherLedgerTender() {
+        return await this.getTypeTender('gather_ledger');
+    }
+    async getGatherLedgerBills() {
+        return await this.getTyperBills('gather_ledger');
+    }
+    async getGatherLedgerPos() {
+        return await this.getTypePos('gather_ledger');
+    }
+
+    async getGatherStageTender() {
+        return await this.getTypeTender('gather_stage');
+    }
+    async getGatherStageBills() {
+        return await this.getTyperBills('gather_stage');
+    }
+    async getGatherStagePos() {
+        return await this.getTypePos('gather_stage');
+    }
+
+    async getGatherStageExtraTender() {
+        return await this.getTypeTender('gather_stage_extra');
+    }
+    async getGatherStageJgcl() {
+        const type = 'gather_stage_extra';
+        await this._loadTypeData(type);
+        return this[type] && this[type].spss_result ? this[type].spss_result.jgcl : [];
+    }
+    async getGatherStageYjcl() {
+        const type = 'gather_stage_extra';
+        await this._loadTypeData(type);
+        return this[type] && this[type].spss_result ? this[type].spss_result.yjcl : [];
+    }
+    async getGatherStageBonus() {
+        const type = 'gather_stage_extra';
+        await this._loadTypeData(type);
+        return this[type] && this[type].spss_result ? this[type].spss_result.bonus : [];
+    }
+    async getGatherStageOther() {
+        const type = 'gather_stage_extra';
+        await this._loadTypeData(type);
+        return this[type] && this[type].spss_result ? this[type].spss_result.other : [];
+    }
+    async getGatherStageSafeProd() {
+        const type = 'gather_stage_extra';
+        await this._loadTypeData(type);
+        return this[type] && this[type].spss_result ? this[type].spss_result.safeProd : [];
+    }
+    async getGatherStageTempLand() {
+        const type = 'gather_stage_extra';
+        await this._loadTypeData(type);
+        return this[type] && this[type].spss_result ? this[type].spss_result.tempLand : [];
+    }
+
+    async getGatherStagePayTender() {
+        return await this.getTypeTender('gather_stage_pay');
+    }
+    async getGatherStagePay() {
+        const type = 'gather_stage_pay';
+        await this._loadTypeData(type);
+        return this[type] && this[type].spss_result ? this[type].spss_result.pays : [];
+    }
+
+    async getCompareLedgerTender() {
+        return await this.getTypeTender('compare_ledger');
+    }
+    async getCompareLedgerBills() {
+        return await this.getTyperBills('compare_ledger');
+    }
+    async getCompareLedgerPos() {
+        return await this.getTypePos('compare_ledger');
+    }
+
+    async getCompareStageTender() {
+        return await this.getTypeTender('compare_stage');
+    }
+    async getCompareStageBills() {
+        return await this.getTyperBills('compare_stage');
+    }
+    async getCompareStagePos() {
+        return await this.getTypePos('compare_stage');
+    }
+
+}
+
+module.exports = reportMemorySpss;

+ 71 - 0
app/lib/rm/tender.js

@@ -18,6 +18,7 @@ const BudgetSource = require('./tender_budget');
 const MaterialSource = require('./tender_material');
 const FinancialSource = require('./tender_financial');
 const rptCustomData = require('../rptCustomData');
+const SpssSource = require('./spss');
 
 class rptMemPaymentSafe extends RptMemBase {
     constructor(ctx) {
@@ -217,6 +218,7 @@ class rptMemPaymentSafe extends RptMemBase {
 
     async getFlowData(params, key, fields, customDefine, customSelect) {
         const service = this.ctx.service;
+        const spssSource = new SpssSource(this.ctx);
         switch (filter) {
             case 'mem_custom_select':
                 return customSelect;
@@ -274,6 +276,75 @@ class rptMemPaymentSafe extends RptMemBase {
             //     return await service.rptGatherMemory.getMaterialBills(params.tender_id, params.material_order, memFieldKeys[filter]);
             // case 'mem_material_bills_gl':
             //     return await service.rptGatherMemory.getMaterialBillsGl(params.tender_id, params.material_order, memFieldKeys[filter]);
+            case 'mem_spss_gather_info_tender':
+                return await spssSource.getGatherStageInfoTender();
+                break;
+            case 'mem_spss_gather_info':
+                return await spssSource.getGatherStageInfo();
+                break;
+            case 'mem_spss_gather_ledger_tender':
+                return await spssSource.getGatherLedgerTender();
+                break;
+            case 'mem_spss_gather_ledger_bills':
+                return await spssSource.getGatherLedgerBills();
+                break;
+            case 'mem_spss_gather_ledger_pos':
+                return await spssSource.getGatherLedgerPos();
+                break;
+            case 'mem_spss_gather_stage_tender':
+                return await spssSource.getGatherStageTender();
+                break;
+            case 'mem_spss_gather_stage_bills':
+                return await spssSource.getGatherStageBills();
+                break;
+            case 'mem_spss_gather_stage_pos':
+                return await spssSource.getGatherStagePos();
+                break;
+            case 'mem_spss_gather_stage_extra_tender':
+                return await spssSource.getGatherStageExtraTender();
+                break;
+            case 'mem_spss_gather_stage_jgcl':
+                return await spssSource.getGatherStageJgcl();
+                break;
+            case 'mem_spss_gather_stage_yjcl':
+                return await spssSource.getGatherStageYjcl();
+                break;
+            case 'mem_spss_gather_stage_bonus':
+                return await spssSource.getGatherStageBonus();
+                break;
+            case 'mem_spss_gather_stage_other':
+                return await spssSource.getGatherStageOther();
+                break;
+            case 'mem_spss_gather_stage_safe_prod':
+                return await spssSource.getGatherStageSafeProd();
+                break;
+            case 'mem_spss_gather_stage_temp_land':
+                return await spssSource.getGatherStageTempLand();
+                break;
+            case 'mem_spss_gather_stage_pay_tender':
+                return await spssSource.getGatherStagePayTender();
+                break;
+            case 'mem_spss_gather_stage_pay':
+                return await spssSource.getGatherStagePay();
+                break;
+            case 'mem_spss_compare_ledger_tender':
+                return await spssSource.getCompareLedgerTender();
+                break;
+            case 'mem_spss_compare_ledger_bills':
+                return await spssSource.getCompareLedgerBills();
+                break;
+            case 'mem_spss_compare_ledger_pos':
+                return await spssSource.getCompareLedgerPos();
+                break;
+            case 'mem_spss_compare_stage_tender':
+                return await spssSource.getCompareStageTender();
+                break;
+            case 'mem_spss_compare_stage_bills':
+                return await spssSource.getCompareStageBills();
+                break;
+            case 'mem_spss_compare_stage_pos':
+                return await spssSource.getCompareStagePos();
+                break;
             default:
                 return [];
         }

+ 48 - 10
app/public/js/spss_compare_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'},
@@ -58,7 +59,7 @@ $(document).ready(() => {
         full_path: 'full_path',
         rootId: -1,
         keys: ['id', 'tender_id', 'ledger_id'],
-        calcFields: ['total_price_1', 'total_price_2', 'differ_tp'],
+        calcFields: ['total_price_1', 'total_price_2', 'differ_total_price'],
         // todo 判断同一清单时,是否应区分 清单是否含计量单元?
         // findNode: function(tree, node, parent, source) {
         //     const siblings = parent ? parent.children : tree.children;
@@ -125,6 +126,19 @@ $(document).ready(() => {
     const billsTree = createNewPathTree('compare', treeSetting);
 
     const billsTreeSpreadObj = {
+        rebuildSpreadSetting: function(tenders) {
+            selectTenders.length = 0;
+            for (const [i, t] of tenders.entries()) {
+                selectTenders.push({ id: t.id, name: t.name, stage_filter: t.stage_filter });
+                const fieldName = 'quantity_' + (i + 1);
+                const billsQty = billsSpreadSetting.cols.find(x => { return x.field === fieldName; });
+                billsQty.title = billsQty.formatTitle.replace('%s', t.name);
+                const posQty = posSpreadSetting.cols.find(x => { return x.field === fieldName; });
+                posQty.title = posQty.formatTitle.replace('%s', t.name);
+            }
+            SpreadJsObj.reLoadSheetHeader(billsSheet);
+            SpreadJsObj.reLoadSheetHeader(posSheet);
+        },
         selectionChanged: function (e, info) {
             if (info.newSelections) {
                 if (!info.oldSelections || info.newSelections[0].row !== info.oldSelections[0].row) {
@@ -152,6 +166,7 @@ $(document).ready(() => {
         afterSelect: function(select) {
             const data = { filter: 'ledger', tender: select };
             postData(`/sp/${spid}/spss/load`, data, function(result) {
+                isCache = false;
                 const tenderTreeSetting = {
                     id: 'ledger_id',
                     pid: 'ledger_pid',
@@ -162,13 +177,8 @@ $(document).ready(() => {
                     calcFields: ['total_price'],
                 };
                 const tenders = [];
-                for (const [i, t] of result.entries()) {
-                    const fieldName = 'quantity_' + (i + 1);
-                    const billsQty = billsSpreadSetting.cols.find(x => { return x.field === fieldName; });
-                    billsQty.title = billsQty.formatTitle.replace('%s', t.name);
-                    const posQty = posSpreadSetting.cols.find(x => { return x.field === fieldName; });
-                    posQty.title = posQty.formatTitle.replace('%s', t.name);
-
+                billsTreeSpreadObj.rebuildSpreadSetting(result);
+                for (const t of result) {
                     const tender = {
                         billsTree: createNewPathTree('ledger', tenderTreeSetting),
                         pos: new PosData({ id: 'id', ledgerId: 'lid', }),
@@ -177,8 +187,6 @@ $(document).ready(() => {
                     tender.pos.loadDatas(t.pos);
                     tenders.push(tender);
                 }
-                SpreadJsObj.reLoadSheetHeader(billsSheet);
-                SpreadJsObj.reLoadSheetHeader(posSheet);
 
                 billsTree.loadCompareData(tenders[0], tenders[1]);
                 treeCalc.calculateAll(billsTree);
@@ -271,4 +279,34 @@ $(document).ready(() => {
             posSpread.refresh();
         }
     });
+
+    const spssStash = SpssStash({
+        type: 'compare_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);
+            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(); });
 });

+ 52 - 9
app/public/js/spss_compare_stage.js

@@ -11,6 +11,7 @@ const posCompareField = [
 
 $(document).ready(() => {
     autoFlashHeight();
+    let isCache = false, selectTenders = [];
     const billsSpreadSetting = {
         cols: [
             {title: '项目节编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 185, formatter: '@', cellType: 'tree'},
@@ -139,6 +140,19 @@ $(document).ready(() => {
 
     const billsTreeSpreadObj = {
         compareData: '',
+        rebuildSpreadSetting: function(tenders) {
+            selectTenders.length = 0;
+            for (const [i, t] of tenders.entries()) {
+                selectTenders.push({ id: t.id, name: t.name, stage_filter: t.stage_filter });
+                const fieldName = 'compare_qty_' + (i + 1);
+                const billsQty = billsSpreadSetting.cols.find(x => { return x.field === fieldName; });
+                billsQty.title = billsQty.formatTitle.replace('%s', t.name);
+                const posQty = posSpreadSetting.cols.find(x => { return x.field === fieldName; });
+                posQty.title = posQty.formatTitle.replace('%s', t.name);
+            }
+            SpreadJsObj.reLoadSheetHeader(billsSheet);
+            SpreadJsObj.reLoadSheetHeader(posSheet);
+        },
         selectionChanged: function (e, info) {
             if (info.newSelections) {
                 if (!info.oldSelections || info.newSelections[0].row !== info.oldSelections[0].row) {
@@ -192,6 +206,7 @@ $(document).ready(() => {
         afterSelect: function(select) {
             const data = { filter: 'stage', tender: select };
             postData(`/sp/${spid}/spss/load`, data, function(result) {
+                isCache = false;
                 const tenderTreeSetting = {
                     id: 'ledger_id',
                     pid: 'ledger_pid',
@@ -228,13 +243,8 @@ $(document).ready(() => {
                     }
                 };
                 const tenders = [];
-                for (const [i, t] of result.entries()) {
-                    const fieldName = 'compare_qty_' + (i + 1);
-                    const billsQty = billsSpreadSetting.cols.find(x => { return x.field === fieldName; });
-                    billsQty.title = billsQty.formatTitle.replace('%s', t.name);
-                    const posQty = posSpreadSetting.cols.find(x => { return x.field === fieldName; });
-                    posQty.title = posQty.formatTitle.replace('%s', t.name);
-
+                billsTreeSpreadObj.rebuildSpreadSetting(result);
+                for (const t of result) {
                     const tender = {
                         billsTree: createNewPathTree('ledger', tenderTreeSetting),
                         pos: new PosData(tenderPosSetting),
@@ -245,8 +255,6 @@ $(document).ready(() => {
                     tender.pos.calculateAll();
                     tenders.push(tender);
                 }
-                SpreadJsObj.reLoadSheetHeader(billsSheet);
-                SpreadJsObj.reLoadSheetHeader(posSheet);
 
                 billsTree.loadCompareData(tenders[0], tenders[1]);
                 treeCalc.calculateAll(billsTree);
@@ -344,4 +352,39 @@ $(document).ready(() => {
             posSpread.refresh();
         }
     });
+
+    const spssStash = SpssStash({
+        type: 'compare_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);
+
+            billsTree.clearDatas();
+            billsTree.loadDatas(data.spss_result.bills);
+            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(); });
 });

+ 2 - 2
app/public/js/spss_gather_stage_pay.js

@@ -14,7 +14,7 @@ $(document).ready(() => {
             {title: '标段1|第1期', colSpan: '1|1', rowSpan: '1|1', field: 'show_tp1', hAlign: 2, width: 80, type: 'Number', formatTitle: '%s|%f', formatField: 'show_tp_%d'},
         ],
         endCols: [
-            {title: '合计', colSpan: '1', rowSpan: '2', field: 'sum_tp', hAlign: 2, width: 80, type: 'Number'},
+            {title: '合计', colSpan: '1', rowSpan: '2', field: 'show_sum_tp', hAlign: 2, width: 80, type: 'Number'},
         ],
         emptyRows: 0,
         headRows: 2,
@@ -85,7 +85,7 @@ $(document).ready(() => {
                 for (let i = 1; i<= this.tenderCount; i++) {
                     cl['show_tp_' + i] = cl[prefix + 'tp_' + i];
                 }
-                cl.sum_tp = cl['sum_' + prefix + 'tp'];
+                cl.show_sum_tp = cl['sum_' + prefix + 'tp'];
             }
             SpreadJsObj.reloadColData(paySheet, 2, this.tenderCount + 1);
         },

+ 3 - 1
app/router.js

@@ -304,6 +304,9 @@ module.exports = app => {
     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');
+    // 测试用
+    // app.get('/sp/:id/devTest', sessionAuth, projectManagerCheck, subProjectCheck, 'spssController.test');
+    // app.post('/sp/:id/devTest/load', sessionAuth, projectManagerCheck, subProjectCheck, 'spssController.testLoad');
 
     // **标段合同管理 todo 接入项目内部
     // app.get('/sp/:id/contract', sessionAuth, subProjectCheck, 'contractController.index');
@@ -1163,5 +1166,4 @@ module.exports = app => {
     app.get('/wx/work/:corpid/project', wxWorkAuth, 'wechatController.workProject');
     app.get('/wx/work/:corpid/test', wxWorkAuth, 'wechatController.workTest');
     app.get('/wx/tips', 'wechatController.tips');
-
 };

+ 72 - 2
app/service/report.js

@@ -11,6 +11,7 @@
 const BudgetSource = require('../lib/rm/tender_budget');
 const MaterialSource = require('../lib/rm/tender_material');
 const FinancialSource = require('../lib/rm/tender_financial');
+const SpssSource = require('../lib/rm/spss');
 
 const rptCustomData = require('../lib/rptCustomData');
 const bindData = {
@@ -20,7 +21,6 @@ const bindData = {
 };
 const sourceTypeConst = require('../const/source_type');
 
-
 module.exports = app => {
     class Report extends app.BaseService {
 
@@ -81,6 +81,7 @@ module.exports = app => {
             await service.tender.checkTender(params.tender_id);
             const materialSource = new MaterialSource(this.ctx);
             const financialSource = new FinancialSource(this.ctx);
+            const spssSource = new SpssSource(this.ctx);
             const rst = {};
             const runnableRst = [];
             const runnableKey = []; // 这个配合runnableRst用,未来考虑并行查询优化
@@ -617,6 +618,75 @@ module.exports = app => {
                     // case 'mem_material_bills_gl':
                     //     rst[filter] = await service.rptGatherMemory.getMaterialBillsGl(params.tender_id, params.material_order, memFieldKeys[filter]);
                     //     break;
+                    case 'mem_spss_gather_info_tender':
+                        rst[filter] =  await spssSource.getGatherStageInfoTender();
+                        break;
+                    case 'mem_spss_gather_info':
+                        rst[filter] =  await spssSource.getGatherStageInfo();
+                        break;
+                    case 'mem_spss_gather_ledger_tender':
+                        rst[filter] =  await spssSource.getGatherLedgerTender();
+                        break;
+                    case 'mem_spss_gather_ledger_bills':
+                        rst[filter] =  await spssSource.getGatherLedgerBills();
+                        break;
+                    case 'mem_spss_gather_ledger_pos':
+                        rst[filter] =  await spssSource.getGatherLedgerPos();
+                        break;
+                    case 'mem_spss_gather_stage_tender':
+                        rst[filter] =  await spssSource.getGatherStageTender();
+                        break;
+                    case 'mem_spss_gather_stage_bills':
+                        rst[filter] =  await spssSource.getGatherStageBills();
+                        break;
+                    case 'mem_spss_gather_stage_pos':
+                        rst[filter] =  await spssSource.getGatherStagePos();
+                        break;
+                    case 'mem_spss_gather_stage_extra_tender':
+                        rst[filter] =  await spssSource.getGatherStageExtraTender();
+                        break;
+                    case 'mem_spss_gather_stage_jgcl':
+                        rst[filter] =  await spssSource.getGatherStageJgcl();
+                        break;
+                    case 'mem_spss_gather_stage_yjcl':
+                        rst[filter] =  await spssSource.getGatherStageYjcl();
+                        break;
+                    case 'mem_spss_gather_stage_bonus':
+                        rst[filter] =  await spssSource.getGatherStageBonus();
+                        break;
+                    case 'mem_spss_gather_stage_other':
+                        rst[filter] =  await spssSource.getGatherStageOther();
+                        break;
+                    case 'mem_spss_gather_stage_safe_prod':
+                        rst[filter] =  await spssSource.getGatherStageSafeProd();
+                        break;
+                    case 'mem_spss_gather_stage_temp_land':
+                        rst[filter] =  await spssSource.getGatherStageTempLand();
+                        break;
+                    case 'mem_spss_gather_stage_pay_tender':
+                        rst[filter] =  await spssSource.getGatherStagePayTender();
+                        break;
+                    case 'mem_spss_gather_stage_pay':
+                        rst[filter] =  await spssSource.getGatherStagePay();
+                        break;
+                    case 'mem_spss_compare_ledger_tender':
+                        rst[filter] =  await spssSource.getCompareLedgerTender();
+                        break;
+                    case 'mem_spss_compare_ledger_bills':
+                        rst[filter] =  await spssSource.getCompareLedgerBills();
+                        break;
+                    case 'mem_spss_compare_ledger_pos':
+                        rst[filter] =  await spssSource.getCompareLedgerPos();
+                        break;
+                    case 'mem_spss_compare_stage_tender':
+                        rst[filter] =  await spssSource.getCompareStageTender();
+                        break;
+                    case 'mem_spss_compare_stage_bills':
+                        rst[filter] =  await spssSource.getCompareStageBills();
+                        break;
+                    case 'mem_spss_compare_stage_pos':
+                        rst[filter] =  await spssSource.getCompareStagePos();
+                        break;
                     default:
                         break;
                 }
@@ -729,7 +799,7 @@ module.exports = app => {
         async getReportData(source_type, params, sourceFilters, memFieldKeys, customDefine, customSelect) {
             this.clearReportCache();
             const sourceType = sourceTypeConst.sourceTypeData.find(x => { return x.id === source_type; });
-            if (!sourceType && !this[sourceType.key]) return {};
+            if (!sourceType || !this[sourceType.key]) return {};
 
             return await this[sourceType.key](params, sourceFilters, memFieldKeys, customDefine, customSelect);
         }

+ 13 - 0
app/service/spss_stash.js

@@ -46,6 +46,19 @@ module.exports = app => {
             return data;
         }
 
+        async getLatestSpssStash(spid, type) {
+            const data = await this.getAllDataByCondition({
+                where: { spid, spss_type: type },
+                orders: [['create_time', 'desc']],
+                limit: 1,
+                offset: 0,
+            });
+            if (data.length === 0) return { spss_select: [], spss_result: null };
+            data[0].spss_select = JSON.parse(data[0].spss_select);
+            data[0].spss_result = JSON.parse(data[0].spss_result);
+            return data[0];
+        }
+
         async addSpssStash(type, select, result) {
             const data = {
                 id: this.uuid.v4(), spid: this.ctx.subProject.id,

+ 3 - 3
app/service/stage_pos.js

@@ -176,7 +176,7 @@ module.exports = app => {
                     if (d.contract_qty !== undefined) ps.contract_qty = this.round(d.contract_qty, precision.value);
                     if (d.contract_expr !== undefined) ps.contract_expr = d.contract_expr;
                     if (d.postil!== undefined) ps.postil = d.postil;
-                    if (d.ex_stage_qty1 !== undefined) ps.ex_stage_qty1 = this.round(d.ex_stage_qty1, precision.value);
+                    if (d.ex_stage_qty1 !== undefined) ps.ex_stage_qty1 = this.round(d.ex_stage_qty1, precision.value) || 0;
                     insertPosStage.push(ps);
                     if ((d.contract_qty || d.ex_stage_qty1) && calcStageBills.indexOf(ps.lid) === -1) {
                         calcStageBills.push(ps.lid);
@@ -273,7 +273,7 @@ module.exports = app => {
                         if (d.postil !== undefined) {
                             sp.postil = d.postil;
                         }
-                        if (d.ex_stage_qty1 !== undefined) sp.ex_stage_qty1 = this.ctx.helper.round(d.ex_stage_qty1, precision.value);
+                        if (d.ex_stage_qty1 !== undefined) sp.ex_stage_qty1 = this.ctx.helper.round(d.ex_stage_qty1 || 0, precision.value) || 0;
                         updatePosStage.push(sp);
                     } else {
                         const sp = {
@@ -292,7 +292,7 @@ module.exports = app => {
                             sp.postil = d.postil === undefined && osp ? osp.postil : d.postil;
                         }
                         if (d.ex_stage_qty1 !== undefined) {
-                            sp.ex_stage_qty1 = this.ctx.helper.round(d.ex_stage_qty1, precision.value) || 0;
+                            sp.ex_stage_qty1 = this.ctx.helper.round(d.ex_stage_qty1 || 0, precision.value) || 0;
                         } else {
                             sp.ex_stage_qty1 = osp ? osp.ex_stage_qty1 || 0 : 0;
                         }

+ 64 - 0
app/view/spss/dev_test.ejs

@@ -0,0 +1,64 @@
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main d-flex">
+            <div class="title-main d-flex justify-content-between">
+                测试用模块
+            </div>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-body">
+            <div class="row mt-2 ml-2">
+                <div class="col-5">
+                    <div class="form-group">
+                        <h6>测试报表指标</h6>
+                        <div class="card p-2">
+                            <div class="d-flex m-1">
+                                <div class="input-group input-group-sm w-75">
+                                    <div class="input-group-prepend">
+                                        <span class="input-group-text">指定数据源</span>
+                                    </div>
+                                    <select class="form-control m-0" id="st-rpt-source-type">
+                                        <% for (const std of sourceType.sourceTypeData) { %>
+                                        <option value="<%- std.id %>" stParams="<%- JSON.stringify(std.params) %>"><%- std.name %></option>
+                                        <% } %>
+                                    </select>
+                                </div>
+                                <div class="ml-auto">
+                                    <button class="btn btn-sm btn-primary" id="st-rpt-check">查询</button>
+                                </div>
+                            </div>
+                            <div class="mt-1">
+                                <span>数据源 必须参数 <span class="text-danger">JSON</span>:</span>
+                                <textarea class="form-control form-control-sm mt-1" rows="6" id="st-rpt-params"></textarea>
+                            </div>
+                            <div class="mt-1">
+                                <div class="input-group input-group-sm">
+                                    <div class="input-group-prepend">
+                                        <span class="input-group-text">指标表</span>
+                                    </div>
+                                    <input class="form-control m-0" id="st-rpt-source-filters">
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script>
+    $('#st-rpt-check').click(function() {
+        const data = { type: 'report', detail: { source_type: parseInt($('#st-rpt-source-type').val()) } };
+        try {
+            data.detail.params = JSON.parse($('#st-rpt-params').val());
+        } catch (err) {
+            toastr.error('必须参数:不是有效的json数据,请检查');
+            return;
+        }
+        data.detail.source_filters = $('#st-rpt-source-filters').val().split(';');
+        postData('devTest/load', data, function(result) {
+            console.log(result);
+        })
+    });
+</script>