Browse Source

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

Tony Kang 1 month atrás
parent
commit
9ad6accb0d

+ 151 - 18
app/controller/spss_controller.js

@@ -129,20 +129,28 @@ module.exports = app => {
         }
         async _filterOrder(tender, order) {
             const stages = await this._getValidStages(tender.id);
-            return { type: 'stage', stage: this.ctx.helper._.find(stages, { order }), filter: `第${order}期` };
+            const stage = this.ctx.helper._.find(stages, { order });
+            if (stage) await this.ctx.service.stage.doCheckStage(stage);
+            return { type: 'stage', stage, filter: `第${order}期` };
         }
         async _filterMonth(tender, month) {
             const stages = await this._getValidStages(tender.id);
-            return { type: 'stage', stage: this.ctx.helper._.find(stages, { s_time: month }), filter: month };
+            const stage = this.ctx.helper._.find(stages, { s_time: month });
+            if (stage) await this.ctx.service.stage.doCheckStage(stage);
+            return { type: 'stage', stage, filter: month };
         }
         async _filterFinal(tender) {
             const stages = await this._getValidStages(tender.id);
-            return { type: 'stage', stage: stages[0], filter: `第${stages[0].order}期` };
+            const stage = stages[0];
+            if (stage) await this.ctx.service.stage.doCheckStage(stage);
+            return { type: 'stage', stage, filter: `第${stage.order}期` };
         }
         async _filterCheckedFinal(tender) {
             const stages = await this._getValidStages(tender.id);
             const checkedStages = stages.filter(x => { return x.status === status.checked; });
-            return { type: 'stage', stage: checkedStages[0], filter: `第${checkedStages[0].order}期` };
+            const stage = checkedStages[0];
+            if (stage) await this.ctx.service.stage.doCheckStage(stage);
+            return { type: 'stage', stage, filter: `第${stage.order}期` };
         }
         async _filterOrderZone(tender, zone) {
             let [iBegin, iEnd] = zone.split(':');
@@ -199,6 +207,7 @@ module.exports = app => {
                     return;
             }
         }
+
         async _loadStageData(tender, stage) {
             const bills = await this.ctx.service.ledger.getAllDataByCondition({
                 columns: ['id', 'ledger_id', 'ledger_pid', 'level', 'full_path', 'is_leaf', 'order', 'code', 'b_code', 'name', 'unit', 'unit_price', 'quantity', 'total_price'],
@@ -210,7 +219,6 @@ module.exports = app => {
             });
             if (!stage) return [bills, pos];
 
-            await this.ctx.service.stage.doCheckStage(stage);
             const curStage = stage.readOnly
                 ? await this.ctx.service.stageBills.getAuditorStageData2(tender.id, stage.id, stage.curTimes, stage.curOrder)
                 : await this.ctx.service.stageBills.getLastestStageData2(tender.id, stage.id);
@@ -306,23 +314,147 @@ module.exports = app => {
                 ? await this._loadStageData(tender, filter.stage)
                 : await this._loadStagesData(tender, filter.stages, filter.preStage, filter.endStage);
         }
-        async _loadJgclData(tender, stages) {
 
+        async _loadStageJgclData(tender, stage) {
+            if (!stage) return [];
+
+            const data = await this.ctx.service.stageJgcl.getStageData(stage);
+            const preData = stage.preCheckedStage ? await this.ctx.service.stageJgcl.getEndStageData(stage.tid, stage.preCheckedStage.order) : [];
+            for (const d of data) {
+                const pd = this.ctx.helper._.find(preData, {uuid: d.uuid});
+                if (pd) {
+                    d.pre_arrive_qty = pd.arrive_qty;
+                    d.pre_arrive_tp = pd.arrive_tp;
+                    d.pre_deduct_qty = pd.deduct_qty;
+                    d.pre_deduct_tp = pd.deduct_tp;
+                }
+                d.end_arrive_qty = this.ctx.helper.add(d.pre_arrive_qty, d.arrive_qty);
+                d.end_arrive_tp = this.ctx.helper.add(d.pre_arrive_tp, d.arrive_tp);
+                d.end_deduct_qty = this.ctx.helper.add(d.pre_deduct_qty, d.deduct_qty);
+                d.end_deduct_tp = this.ctx.helper.add(d.pre_deduct_tp, d.deduct_tp);
+            }
+            return data;
+        }
+        async _loadStagesJgclData(tender, stages, preStage, endStage) {
+            // todo
+            return [];
+        }
+        async _loadJgclData(tender, filter) {
+            return filter.type === 'stage'
+                ? await this._loadStageJgclData(tender, filter.stage)
+                : await this._loadStagesJgclData(tender, filter.stages, filter.preStage, filter.endStage);
         };
-        async _loadYjclData(tender, stages) {
 
+        async _loadStageYgclData(tender, stage) {
+            if (!stage) return [];
+
+            const data = await this.ctx.service.stageYjcl.getStageData(stage);
+            for (const d of data) {
+                d.end_qty = this.ctx.helper.add(d.pre_qty, d.qty);
+                d.end_tp = this.ctx.helper.add(d.pre_tp, d.tp);
+            }
+            return data;
+        }
+        async _loadStagesYgclData(tender, stages, preStage, endStage) {
+            // todo
+            return [];
+        }
+        async _loadYjclData(tender, filter) {
+            return filter.type === 'stage'
+                ? await this._loadStageYgclData(tender, filter.stage)
+                : await this._loadStagesYgclData(tender, filter.stages, filter.preStage, filter.endStage);
         };
-        async _loadBonusData(tender, stages) {
 
+        async _loadStageBonusData(tender, stage) {
+            if (!stage) return [];
+
+            const data = await this.ctx.service.stageBonus.getEndStageData(tender.id, stage.order);
+            return data;
+        }
+        async _loadStagesBonusData(tender, stages, preStage, endStage) {
+            // todo
+            return [];
+        }
+        async _loadBonusData(tender, filter) {
+            return filter.type === 'stage'
+                ? await this._loadStageBonusData(tender, filter.stage)
+                : await this._loadStagesBonusData(tender, filter.stages, filter.preStage, filter.endStage);
         };
-        async _loadSafeProdData(tender, stages) {
 
+        async _loadStageSafeProdData(tender, stage) {
+            if (!stage) return [];
+
+            const data = await this.ctx.service.stageSafeProd.getStageData(stage);
+            const preData = stage.preCheckedStage ? await this.ctx.service.stageSafeProd.getEndStageData(stage.tid, stage.preCheckedStage.order) : [];
+            for (const d of data) {
+                const pd = this.ctx.helper._.find(preData, {uuid: d.uuid});
+                if (pd) {
+                    d.pre_qty = pd.qty;
+                    d.pre_tp = pd.tp;
+                }
+                d.end_qty = this.ctx.helper.add(d.pre_qty, d.qty);
+                d.end_tp = this.ctx.helper.add(d.pre_tp, d.tp);
+            }
+            return data;
+        }
+        async _loadStagesSafeProdData(tender, stages, preStage, endStage) {
+            // todo
+            return [];
+        }
+        async _loadSafeProdData(tender, filter) {
+            return filter.type === 'stage'
+                ? await this._loadStageSafeProdData(tender, filter.stage)
+                : await this._loadStagesSafeProdData(tender, filter.stages, filter.preStage, filter.endStage);
         };
-        async _loadTempLandData(tender, stages) {
 
+        async _loadStageTempLandData(tender, stage) {
+            if (!stage) return [];
+
+            const data = await this.ctx.service.stageTempLand.getStageData(stage);
+            const preData = stage.preCheckedStage ? await this.ctx.service.stageTempLand.getEndStageData(stage.tid, stage.preCheckedStage.order) : [];
+            for (const d of data) {
+                const pd = this.ctx.helper._.find(preData, {uuid: d.uuid});
+                if (pd) {
+                    d.pre_qty = pd.qty;
+                    d.pre_tp = pd.tp;
+                }
+                d.end_qty = this.ctx.helper.add(d.pre_qty, d.qty);
+                d.end_tp = this.ctx.helper.add(d.pre_tp, d.tp);
+            }
+            return data;
+        }
+        async _loadStagesTempLandData(tender, stages, preStage, endStage) {
+            // todo
+            return [];
+        }
+        async _loadTempLandData(tender, filter) {
+            return filter.type === 'stage'
+                ? await this._loadStageTempLandData(tender, filter.stage)
+                : await this._loadStagesTempLandData(tender, filter.stages, filter.preStage, filter.endStage);
         };
-        async _loadOtherData(tender, stages) {
 
+        async _loadStageOtherData(tender, stage) {
+            if (!stage) return [];
+
+            const data = await this.ctx.service.stageOther.getStageData(stage);
+            const preData = stage.preCheckedStage ? await this.ctx.service.stageOther.getEndStageData(stage.tid, stage.preCheckedStage.order) : [];
+            for (const d of data) {
+                const pd = this.ctx.helper._.find(preData, {uuid: d.uuid});
+                if (pd) {
+                    d.pre_tp = pd.tp;
+                }
+                d.end_tp = this.ctx.helper.add(d.pre_tp, d.tp);
+            }
+            return data;
+        }
+        async _loadStagesOtherData(tender, stages, preStage, endStage) {
+            // todo
+            return [];
+        }
+        async _loadOtherData(tender, filter) {
+            return filter.type === 'stage'
+                ? await this._loadStageOtherData(tender, filter.stage)
+                : await this._loadStagesOtherData(tender, filter.stages, filter.preStage, filter.endStage);
         };
         async _loadTenderData(tid, filter, stageInfo) {
             this.ctx.tender = null;
@@ -356,37 +488,38 @@ module.exports = app => {
                             stageFilter = await this._filterStages(tender, stageInfo);
                             result.filter = stageFilter.filter;
                         }
-                        result.jgcl = await this._loadYjclData(tender, stageFilter);
+                        result.yjcl = await this._loadYjclData(tender, stageFilter);
                         break;
                     case 'bonus':
                         if (!stageFilter) {
                             stageFilter = await this._filterStages(tender, stageInfo);
                             result.filter = stageFilter.filter;
                         }
-                        result.jgcl = await this._loadBonusData(tender, stageFilter);
+                        result.bonus = await this._loadBonusData(tender, stageFilter);
                         break;
                     case 'safeProd':
                         if (!stageFilter) {
                             stageFilter = await this._filterStages(tender, stageInfo);
                             result.filter = stageFilter.filter;
                         }
-                        result.jgcl = await this._loadSafeProdData(tender, stageFilter);
+                        result.safeProd = await this._loadSafeProdData(tender, stageFilter);
                         break;
                     case 'tempLand':
                         if (!stageFilter) {
                             stageFilter = await this._filterStages(tender, stageInfo);
                             result.filter = stageFilter.filter;
                         }
-                        result.jgcl = await this._loadTempLandData(tender, stageFilter);
+                        result.tempLand = await this._loadTempLandData(tender, stageFilter);
                         break;
                     case 'other':
                         if (!stageFilter) {
                             stageFilter = await this._filterStages(tender, stageInfo);
                             result.filter = stageFilter.filter;
                         }
-                        result.jgcl = await this._loadOtherData(tender, stageFilter);
+                        result.other = await this._loadOtherData(tender, stageFilter);
                         break;
-                    default: throw '查询的数据类型未定义';
+                    default:
+                        throw '查询的数据类型未定义';
                 }
             }
             return result;
@@ -395,7 +528,7 @@ module.exports = app => {
         async load(ctx) {
             try {
                 const data = JSON.parse(ctx.request.body.data);
-                const filter = data.filter.split(',');
+                const filter = data.filter.split(';');
                 const result = [];
                 for (const t of data.tender) {
                     result.push(await this._loadTenderData(t.tid, filter, t.stageInfo));

+ 3 - 0
app/public/js/shares/tender_select_multi.js

@@ -3,6 +3,9 @@ const TenderSelectMulti = function (setting) {
     if (setting.type === 'gather' && setting.dataType === 'stage') {
         $('#tsm-stage-info').show();
     }
+    if (setting.zoneValid === false) {
+        $('[stage-type=zone]').hide();
+    }
     $('[name=tsm-source]').click(function() {
         $('[name=gather-type]').hide();
         const type = this.value;

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

@@ -405,7 +405,7 @@ const SpreadJsObj = {
         sheet.extendRowHeader = {};
         sheet.extendColHeader = {};
         this._initSheetDeafult(sheet);
-        this._initSheetHeader(sheet);
+        this._initSheetHeader(sheet, true);
         sheet.setRowCount(sheet.zh_setting.emptyRows);
         sheet.zh_setting.rowHeader && sheet.zh_setting.rowHeader.forEach(function (col, j) {
             self._defineRowHeader(sheet, j, col);

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

@@ -0,0 +1,451 @@
+$(document).ready(() => {
+    autoFlashHeight();
+    $('#data-spread').height($('.sjs-height-0').height() - $('.nav-tabs').height() - 16);
+    const spreadSetting = {
+        jgcl: {
+            cols: [
+                {title: '名称', colSpan: '1', rowSpan: '4', field: 'name', hAlign: 0, width: 200, formatter: '@'},
+                {title: '单位', colSpan: '1', rowSpan: '4', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
+                {title: '单价', colSpan: '1', rowSpan: '4', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
+                {title: '合计||到场|数量', colSpan: '4||2|1', rowSpan: '2||1|1', field: 'sum_arrive_qty', hAlign: 2, width: 80, type: 'Number'},
+                {title: '|||金额', colSpan: '|||1', rowSpan: '|||1', field: 'sum_arrive_tp', hAlign: 2, width: 80, type: 'Number'},
+                {title: '||扣回|数量', colSpan: '||2|1', rowSpan: '||1|1', field: 'sum_deduct_qty', hAlign: 2, width: 80, type: 'Number'},
+                {title: '|||金额', colSpan: '|||1', rowSpan: '|||1', field: 'sum_deduct_qty', hAlign: 2, width: 80, type: 'Number'},
+            ],
+            baseCols: [
+                {title: '名称', colSpan: '1', rowSpan: '4', field: 'name', hAlign: 0, width: 200, formatter: '@'},
+                {title: '单位', colSpan: '1', rowSpan: '4', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
+                {title: '单价', colSpan: '1', rowSpan: '4', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
+            ],
+            extraCols: [
+                {title: '标段1|第一期|到场|数量', colSpan: '4|4|2|1', rowSpan: '1|1|1|1', field: 'sum_arrive_qty', hAlign: 2, width: 80, type: 'Number', formatField: 'gather_arrive_qty_%d', formatTitle: '%s|%f|到场|数量'},
+                {title: '|||金额', colSpan: '|||1', rowSpan: '|||1', field: 'sum_arrive_tp', hAlign: 2, width: 80, type: 'Number', formatField: 'gather_arrive_tp_%d'},
+                {title: '||扣回|数量', colSpan: '||2|1', rowSpan: '||1|1', field: 'sum_deduct_qty', hAlign: 2, width: 80, type: 'Number', formatField: 'gather_deduct_tp_%d'},
+                {title: '|||金额', colSpan: '|||1', rowSpan: '|||1', field: 'sum_deduct_qty', hAlign: 2, width: 80, type: 'Number', formatField: 'gather_deduct_tp_%d'},
+            ],
+            endCols: [
+                {title: '合计||到场|数量', colSpan: '4||2|1', rowSpan: '2||1|1', field: 'sum_arrive_qty', hAlign: 2, width: 80, type: 'Number'},
+                {title: '|||金额', colSpan: '|||1', rowSpan: '|||1', field: 'sum_arrive_tp', hAlign: 2, width: 80, type: 'Number'},
+                {title: '||扣回|数量', colSpan: '||2|1', rowSpan: '||1|1', field: 'sum_deduct_qty', hAlign: 2, width: 80, type: 'Number'},
+                {title: '|||金额', colSpan: '|||1', rowSpan: '|||1', field: 'sum_deduct_qty', hAlign: 2, width: 80, type: 'Number'},
+            ],
+            emptyRows: 0,
+            headRows: 4,
+            headRowHeight: [32, 25, 25, 25],
+            defaultRowHeight: 21,
+            headerFont: '12px 微软雅黑',
+            font: '12px 微软雅黑',
+            readOnly: true,
+        },
+        yjcl: {
+            cols: [
+                {title: '名称', colSpan: '1', rowSpan: '3', field: 'name', hAlign: 0, width: 200, formatter: '@'},
+                {title: '单位', colSpan: '1', rowSpan: '3', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
+                {title: '单价', colSpan: '1', rowSpan: '3', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
+                {title: '合计||数量', colSpan: '2||1', rowSpan: '2||1', field: 'sum_qty', hAlign: 2, width: 80, type: 'Number' },
+                {title: '||金额', colSpan: '|1', rowSpan: '|1', field: 'sum_tp', hAlign: 2, width: 80, type: 'Number'},
+            ],
+            baseCols: [
+                {title: '名称', colSpan: '1', rowSpan: '3', field: 'name', hAlign: 0, width: 200, formatter: '@'},
+                {title: '单位', colSpan: '1', rowSpan: '3', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
+                {title: '单价', colSpan: '1', rowSpan: '3', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
+            ],
+            extraCols: [
+                {title: '标段1|第1期|数量', colSpan: '2|2|1', rowSpan: '1|1|1', field: 'gather_qty_1', hAlign: 2, width: 80, type: 'Number', formatField: 'gather_qty_%d', formatTitle: '%s|%f|数量' },
+                {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'gather_tp_1', hAlign: 2, width: 80, type: 'Number', formatField: 'gather_tp_%d'},
+            ],
+            endCols: [
+                {title: '合计||数量', colSpan: '2||1', rowSpan: '2||1', field: 'sum_qty', hAlign: 2, width: 80, type: 'Number' },
+                {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'sum_tp', hAlign: 2, width: 80, type: 'Number'},
+            ],
+            emptyRows: 0,
+            headRows: 3,
+            headRowHeight: [32, 25, 25],
+            defaultRowHeight: 21,
+            headerFont: '12px 微软雅黑',
+            font: '12px 微软雅黑',
+            readOnly: true,
+        },
+        bonus: {
+            cols: [
+                {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 320, formatter: '@'},
+                {title: '汇总', colSpan: '1', rowSpan: '1', field: 'filter', hAlign: 1, width: 100, formatter: '@'},
+                {title: '类型', colSpan: '1', rowSpan: '1', field: 'b_type', hAlign: 1, width: 80, formatter: '@'},
+                {title: '金额', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 1, width: 80, formatter: '@'},
+                {title: '时间', colSpan: '1', rowSpan: '1', field: 'real_time', hAlign: 1, width: 80, formatter: '@'},
+            ],
+            emptyRows: 0,
+            headRows: 1,
+            headRowHeight: [32],
+            defaultRowHeight: 21,
+            headerFont: '12px 微软雅黑',
+            font: '12px 微软雅黑',
+            readOnly: true,
+        },
+        safeProd: {
+            cols: [
+                {title: '名称', colSpan: '1', rowSpan: '3', field: 'name', hAlign: 0, width: 200, formatter: '@'},
+                {title: '单位', colSpan: '1', rowSpan: '3', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
+                {title: '单价', colSpan: '1', rowSpan: '3', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
+                {title: '合计||数量', colSpan: '2||1', rowSpan: '2||1', field: 'sum_qty', hAlign: 2, width: 80, type: 'Number' },
+                {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'sum_tp', hAlign: 2, width: 80, type: 'Number'},
+            ],
+            baseCols: [
+                {title: '名称', colSpan: '1', rowSpan: '3', field: 'name', hAlign: 0, width: 200, formatter: '@'},
+                {title: '单位', colSpan: '1', rowSpan: '3', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
+                {title: '单价', colSpan: '1', rowSpan: '3', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
+            ],
+            extraCols: [
+                {title: '标段1|第1期|数量', colSpan: '2|2|1', rowSpan: '1|1|1', field: 'gather_qty_1', hAlign: 2, width: 80, type: 'Number', formatField: 'gather_qty_%d', formatTitle: '%s|%f|数量' },
+                {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'gather_tp_1', hAlign: 2, width: 80, type: 'Number', formatField: 'gather_tp_%d'},
+            ],
+            endCols: [
+                {title: '合计||数量', colSpan: '2||1', rowSpan: '2||1', field: 'sum_qty', hAlign: 2, width: 80, type: 'Number' },
+                {title: '||金额', colSpan: '||1', rowSpan: '||1', field: 'sum_tp', hAlign: 2, width: 80, type: 'Number'},
+            ],
+            emptyRows: 0,
+            headRows: 3,
+            headRowHeight: [32, 25, 25],
+            defaultRowHeight: 21,
+            headerFont: '12px 微软雅黑',
+            font: '12px 微软雅黑',
+            readOnly: true,
+        },
+        tempLand: {
+            cols: [
+                {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 320, formatter: '@'},
+                {title: '汇总', colSpan: '1', rowSpan: '2', field: 'filter', hAlign: 1, width: 100, formatter: '@'},
+                {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 80, formatter: '@'},
+                {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
+                {title: '本期|数量', colSpan: '2|1', rowSpan: '1|1', field: 'qty', hAlign: 1, width: 80, formatter: '@'},
+                {title: '|数量', colSpan: '|1', rowSpan: '|1', field: 'tp', hAlign: 1, width: 80, formatter: '@'},
+                {title: '截止本期|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_qty', hAlign: 1, width: 80, formatter: '@'},
+                {title: '|数量', colSpan: '|1', rowSpan: '|1', field: 'end_tp', hAlign: 1, width: 80, formatter: '@'},
+            ],
+            emptyRows: 0,
+            headRows: 2,
+            headRowHeight: [25, 25],
+            defaultRowHeight: 21,
+            headerFont: '12px 微软雅黑',
+            font: '12px 微软雅黑',
+            readOnly: true,
+        },
+        other: {
+            cols: [
+                {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 320, formatter: '@'},
+                {title: '汇总', colSpan: '1', rowSpan: '1', field: 'filter', hAlign: 1, width: 100, formatter: '@'},
+                {title: '类型', colSpan: '1', rowSpan: '1', field: 'o_type', hAlign: 1, width: 80, formatter: '@'},
+                {title: '金额', colSpan: '1', rowSpan: '1', field: 'total_price', hAlign: 1, width: 80, formatter: '@'},
+                {title: '本期', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 1, width: 80, formatter: '@'},
+                {title: '截止本期', colSpan: '1', rowSpan: '1', field: 'end_tp', hAlign: 1, width: 80, formatter: '@'},
+                {title: '时间', colSpan: '1', rowSpan: '1', field: 'real_time', hAlign: 1, width: 80, formatter: '@'},
+            ],
+            emptyRows: 0,
+            headRows: 1,
+            headRowHeight: [32],
+            defaultRowHeight: 21,
+            headerFont: '12px 微软雅黑',
+            font: '12px 微软雅黑',
+            readOnly: true,
+        },
+    };
+
+    const dataSpread = SpreadJsObj.createNewSpread($('#data-spread')[0]);
+    const dataSheet = dataSpread.getActiveSheet();
+    const stageExtra = {
+        seType: 'jgcl',
+        seData: 'cur',
+        jgcl: [],
+        yjcl: [],
+        bonus: [],
+        other: [],
+        safeProd: [],
+        tempLand: [],
+        gatherJgcl(tenders) {
+            this.jgcl = [];
+            for (const [i, t] of tenders.entries()) {
+                const endfix = '_' + (i + 1);
+                for (const data of t.jgcl) {
+                    if (!data.unit) data.unit = '';
+                    if (!data.unit_price) data.unit_price = 0;
+                    let cl = this.jgcl.find(x => { return x.name === data.name && x.unit === data.unit && x.unit_price === data.unit_price; });
+                    if (!cl) {
+                        cl = { name: data.name || '', unit: data.unit || '', unit_price: data.unit_price || 0 };
+                        this.jgcl.push(cl);
+                    }
+                    cl['arrive_qty' + endfix] = ZhCalc.add(cl['arrive_qty' + endfix], data.arrive_qty);
+                    cl['arrive_tp' + endfix] = ZhCalc.add(cl['arrive_tp' + endfix], data.arrive_tp);
+                    cl['deduct_qty' + endfix] = ZhCalc.add(cl['deduct_qty' + endfix], data.deduct_qty);
+                    cl['deduct_tp' + endfix] = ZhCalc.add(cl['deduct_tp' + endfix], data.deduct_tp);
+                    cl['end_arrive_qty' + endfix] = ZhCalc.add(cl['end_arrive_qty' + endfix], data.end_arrive_qty);
+                    cl['end_arrive_tp' + endfix] = ZhCalc.add(cl['end_arrive_tp' + endfix], data.end_arrive_tp);
+                    cl['end_deduct_qty' + endfix] = ZhCalc.add(cl['end_deduct_qty' + endfix], data.end_deduct_qty);
+                    cl['end_deduct_tp' + endfix] = ZhCalc.add(cl['end_deduct_tp' + endfix], data.end_deduct_tp);
+
+                    cl['sum_arrive_qty'] = ZhCalc.add(cl['sum_arrive_qty'], data.arrive_qty);
+                    cl['sum_arrive_tp'] = ZhCalc.add(cl['sum_arrive_tp'], data.arrive_tp);
+                    cl['sum_deduct_qty'] = ZhCalc.add(cl['sum_deduct_qty'], data.deduct_qty);
+                    cl['sum_deduct_tp'] = ZhCalc.add(cl['sum_deduct_tp'], data.deduct_tp);
+                    cl['sum_end_arrive_qty'] = ZhCalc.add(cl['sum_end_arrive_qty'], data.end_arrive_qty);
+                    cl['sum_end_arrive_tp'] = ZhCalc.add(cl['sum_end_arrive_tp'], data.end_arrive_tp);
+                    cl['sum_end_deduct_qty'] = ZhCalc.add(cl['sum_end_deduct_qty'], data.end_deduct_qty);
+                    cl['sum_end_deduct_tp'] = ZhCalc.add(cl['sum_end_deduct_tp'], data.end_deduct_tp);
+                }
+            }
+        },
+        gatherYjcl(tenders) {
+            this.yjcl = [];
+            for (const [i, t] of tenders.entries()) {
+                const endfix = '_' + (i + 1);
+                for (const data of t.yjcl) {
+                    if (!data.unit) data.unit = '';
+                    if (!data.spec) data.spec = '';
+                    if (!data.unit_price) data.unit_price = 0;
+                    let cl = this.yjcl.find(x => { return x.name === data.name && x.spec === data.spec && x.unit === data.unit && x.unit_price === data.unit_price; });
+                    if (!cl) {
+                        cl = { name: data.name || '', spec: data.spec, unit: data.unit || '', unit_price: data.unit_price || 0 };
+                        this.yjcl.push(cl);
+                    }
+                    cl['arrive_qty' + endfix] = ZhCalc.add(cl['arrive_qty' + endfix], data.arrive_qty);
+                    cl['arrive_tp' + endfix] = ZhCalc.add(cl['arrive_tp' + endfix], data.arrive_tp);
+                    cl['qty' + endfix] = ZhCalc.add(cl['qty' + endfix], data.qty);
+                    cl['tp' + endfix] = ZhCalc.add(cl['tp' + endfix], data.tp);
+                    cl['end_qty' + endfix] = ZhCalc.add(cl['end_qty' + endfix], data.end_qty);
+                    cl['end_tp' + endfix] = ZhCalc.add(cl['end_tp' + endfix], data.end_tp);
+
+                    cl['sum_arrive_qty'] = ZhCalc.add(cl['sum_arrive_qty'], data.arrive_qty);
+                    cl['sum_arrive_tp'] = ZhCalc.add(cl['sum_arrive_tp'], data.arrive_tp);
+                    cl['sum_qty'] = ZhCalc.add(cl['sum_qty'], data.qty);
+                    cl['sum_tp'] = ZhCalc.add(cl['sum_tp'], data.tp);
+                    cl['sum_end_qty'] = ZhCalc.add(cl['sum_end_qty'], data.end_qty);
+                    cl['sum_end_tp'] = ZhCalc.add(cl['sum_end_tp'], data.end_tp);
+                }
+            }
+        },
+        gatherBonus(tenders) {
+            this.bonus = [];
+            for (const [i, t] of tenders.entries()) {
+                this.bonus.push({ tid: t.id, name: t.name, filter: t.filter });
+                this.bonus.push(...t.bonus);
+            }
+        },
+        gatherOther(tenders) {
+            this.other = [];
+            for (const [i, t] of tenders.entries()) {
+                this.other.push({ tid: t.id, name: t.name, filter: t.filter });
+                this.other.push(...t.other);
+            }
+        },
+        gatherSafeProd(tenders) {
+            this.safeProd = [];
+            for (const [i, t] of tenders.entries()) {
+                const endfix = '_' + (i + 1);
+                for (const data of t.safeProd) {
+                    if (!data.unit) data.unit = '';
+                    if (!data.unit_price) data.unit_price = 0;
+                    let sp = this.safeProd.find(x => { return x.name === data.name && x.unit === data.unit && x.unit_price === data.unit_price; });
+                    if (!sp) {
+                        sp = { name: data.name || '', unit: data.unit || '', unit_price: data.unit_price || 0 };
+                        this.safeProd.push(sp);
+                    }
+                    sp['quantity' + endfix] = ZhCalc.add(sp['quantity' + endfix], data.quantity);
+                    sp['total_price' + endfix] = ZhCalc.add(sp['total_price' + endfix], data.total_price);
+                    sp['qty' + endfix] = ZhCalc.add(sp['qty' + endfix], data.qty);
+                    sp['tp' + endfix] = ZhCalc.add(sp['tp' + endfix], data.tp);
+                    sp['end_qty' + endfix] = ZhCalc.add(sp['end_qty' + endfix], data.end_qty);
+                    sp['end_tp' + endfix] = ZhCalc.add(sp['end_tp' + endfix], data.end_tp);
+
+                    sp['sum_quantity'] = ZhCalc.add(sp['sum_quantity'], data.quantity);
+                    sp['sum_total_price'] = ZhCalc.add(sp['sum_total_price'], data.total_price);
+                    sp['sum_qty'] = ZhCalc.add(sp['sum_qty'], data.qty);
+                    sp['sum_tp'] = ZhCalc.add(sp['sum_tp'], data.tp);
+                    sp['sum_end_qty'] = ZhCalc.add(sp['sum_end_qty'], data.end_qty);
+                    sp['sum_end_tp'] = ZhCalc.add(sp['sum_end_tp'], data.end_tp);
+                }
+            }
+        },
+        gatherTempLand(tenders) {
+            this.tempLand = [];
+            for (const [i, t] of tenders.entries()) {
+                this.tempLand.push({ tid: t.id, name: t.name, filter: t.filter });
+                this.tempLand.push(...t.tempLand);
+                // const endfix = '_' + (i + 1);
+                // for (const data of t.tempLand) {
+                //     if (!data.unit) data.unit = '';
+                //     if (!data.unit_price) data.unit_price = 0;
+                //     let tl = this.tempLand.find(x => { return x.name === data.name && x.unit === data.unit && x.unit_price === data.unit_price; });
+                //     if (!tl) {
+                //         tl = { name: data.name || '', unit: data.unit || '', unit_price: data.unit_price || 0 };
+                //         this.tempLand.push(tl);
+                //     }
+                //     tl['quantity' + endfix] = ZhCalc.add(tl['quantity' + endfix], data.quantity);
+                //     tl['total_price' + endfix] = ZhCalc.add(tl['total_price' + endfix], data.total_price);
+                //     tl['qty' + endfix] = ZhCalc.add(tl['qty' + endfix], data.qty);
+                //     tl['tp' + endfix] = ZhCalc.add(tl['tp' + endfix], data.tp);
+                //     tl['end_qty' + endfix] = ZhCalc.add(tl['end_qty' + endfix], data.end_qty);
+                //     tl['end_tp' + endfix] = ZhCalc.add(tl['end_tp' + endfix], data.end_tp);
+                //
+                //     tl['sum_quantity'] = ZhCalc.add(tl['sum_quantity'], data.quantity);
+                //     tl['sum_total_price'] = ZhCalc.add(tl['sum_total_price'], data.total_price);
+                //     tl['sum_qty'] = ZhCalc.add(tl['sum_qty'], data.qty);
+                //     tl['sum_tp'] = ZhCalc.add(tl['sum_tp'], data.tp);
+                //     tl['sum_end_qty'] = ZhCalc.add(tl['sum_end_qty'], data.end_qty);
+                //     tl['sum_end_tp'] = ZhCalc.add(tl['sum_end_tp'], data.end_tp);
+                // }
+            }
+        },
+        gatherStageExtraData(tenders) {
+            this.tenderCount = tenders.length;
+            this.gatherJgcl(tenders);
+            this.gatherYjcl(tenders);
+            this.gatherBonus(tenders);
+            this.gatherOther(tenders);
+            this.gatherSafeProd(tenders);
+            this.gatherTempLand(tenders);
+        },
+        rebuildSpreadSetting(tenders) {
+            spreadSetting.jgcl.cols = [...spreadSetting.jgcl.baseCols];
+            spreadSetting.yjcl.cols = [...spreadSetting.yjcl.baseCols];
+            spreadSetting.safeProd.cols = [...spreadSetting.safeProd.baseCols];
+            const pushExtraCols = function(spreadSetting) {
+                for (const [i, tender] of tenders.entries()) {
+                    for (const col of spreadSetting.extraCols) {
+                        const newCol = JSON.parse(JSON.stringify(col));
+                        if (newCol.formatTitle) newCol.title = newCol.formatTitle.replace('%s', tender.name).replace('%f', tender.filter);
+                        if (newCol.formatField) newCol.field = newCol.formatField.replace('%d', i + 1);
+                        spreadSetting.cols.push(newCol);
+                    }
+                }
+            };
+            pushExtraCols(spreadSetting.jgcl);
+            pushExtraCols(spreadSetting.yjcl);
+            pushExtraCols(spreadSetting.safeProd);
+            spreadSetting.jgcl.cols.push(...spreadSetting.jgcl.endCols);
+            spreadSetting.yjcl.cols.push(...spreadSetting.yjcl.endCols);
+            spreadSetting.safeProd.cols.push(...spreadSetting.safeProd.endCols);
+        },
+        loadJgclShowData(field) {
+            const prefix = field === 'end' ? 'end_' : '';
+            for (const cl of this.jgcl) {
+                for (let i = 1; i<= this.tenderCount; i++) {
+                    cl['gather_arrive_qty_' + i] = cl[prefix + 'arrive_qty_' + i];
+                    cl['gather_arrive_tp_' + i] = cl[prefix + 'arrive_tp_' + i];
+                    cl['gather_deduct_qty_' + i] = cl[prefix + 'deduct_qty_' + i];
+                    cl['gather_deduct_tp_' + i] = cl[prefix + 'deduct_tp_' + i];
+                }
+                cl.sum_arrive_qty = cl['sum_' + prefix + 'arrive_qty'];
+                cl.sum_arrive_tp = cl['sum_' + prefix + 'arrive_tp'];
+                cl.sum_deduct_qty = cl['sum_' + prefix + 'deduct_qty'];
+                cl.sum_deduct_tp = cl['sum_' + prefix + 'deduct_tp'];
+            }
+            if (this.seType === 'jgcl') SpreadJsObj.reloadColData(dataSheet, 3, 4*this.tenderCount);
+        },
+        loadYjclShowData(field) {
+            const prefix = field === 'end' ? 'end_' : '';
+            for (const cl of this.yjcl) {
+                for (let i = 1; i<= this.tenderCount; i++) {
+                    cl['gather_qty_' + i] = cl[prefix + 'qty_' + i];
+                    cl['gather_tp_' + i] = cl[prefix + 'tp_' + i];
+                }
+                cl.sum_qty = cl['sum_' + prefix + 'qty'];
+                cl.sum_tp = cl['sum_' + prefix + 'tp'];
+            }
+            if (this.seType === 'yjcl') SpreadJsObj.reloadColData(dataSheet, 3, 2*this.tenderCount);
+        },
+        loadSafeProdShowData(field) {
+            const prefix = field === 'end' ? 'end_' : '';
+            for (const sp of this.safeProd) {
+                for (let i = 1; i<= this.tenderCount; i++) {
+                    sp['gather_qty_' + i] = sp[prefix + 'qty_' + i];
+                    sp['gather_tp_' + i] = sp[prefix + 'tp_' + i];
+                }
+                sp.sum_qty = sp['sum_' + prefix + 'qty'];
+                sp.sum_tp = sp['sum_' + prefix + 'tp'];
+            }
+            if (this.seType === 'safeProd') SpreadJsObj.reloadColData(dataSheet, 3, 2*this.tenderCount);
+        },
+        loadShowData() {
+            const field = $('[name=compare-data]:checked').val();
+            if (field === this.seData) return;
+            this.seData = field;
+            this.loadJgclShowData(field);
+            this.loadYjclShowData(field);
+            this.loadSafeProdShowData(field);
+        },
+        refreshShowData() {
+            const field = $('[name=compare-data]:checked').val();
+            if (field === this.seData) return;
+
+            this.loadShowData();
+        },
+        loadSheetData() {
+            SpreadJsObj.initSheet(dataSheet, spreadSetting[this.seType]);
+            SpreadJsObj.loadSheetData(dataSheet, SpreadJsObj.DataType.Data, this[this.seType]);
+            SpreadJsObj.locateRow(dataSheet, 0);
+        },
+        refreshStageExtraData(type) {
+            if (type) {
+                if (this.seType === type) return;
+                this.seType = type;
+            }
+            this.loadSheetData();
+        },
+    };
+    stageExtra.loadSheetData();
+
+    const tenderSelect = TenderSelectMulti({
+        title: '汇总标段',
+        type: 'gather',
+        dataType: 'stage',
+        zoneValid: false,
+        afterSelect: function(select) {
+            const data = { filter: 'jgcl;yjcl;bonus;other;safeProd;tempLand', tender: select };
+            postData(`/sp/${spid}/spss/load`, data, function(result) {
+                stageExtra.rebuildSpreadSetting(result);
+                stageExtra.gatherStageExtraData(result);
+                SpreadJsObj.reLoadSheetHeader(dataSheet, true);
+                stageExtra.loadShowData();
+                stageExtra.loadSheetData();
+            });
+        },
+    });
+    $('#gather-select').click(tenderSelect.showSelect);
+
+    $('[name=compare-data]').click(function() {
+        stageExtra.refreshShowData();
+    });
+    $('.nav-item').click(function() {
+        const dataType = $(this).attr('data-type');
+        stageExtra.refreshStageExtraData(dataType);
+    });
+
+    $('#export-excel').click(function() {
+        const sheets = [];
+        sheets.push({ name: '甲供材料', setting: spreadSetting.jgcl, data: stageExtra.jgcl });
+        sheets.push({ name: '永久材料', setting: spreadSetting.yjcl, data: stageExtra.yjcl });
+        sheets.push({ name: '奖罚金', setting: spreadSetting.bonus, data: stageExtra.bonus });
+        sheets.push({ name: '安全生产', setting: spreadSetting.safeProd, data: stageExtra.safeProd });
+        sheets.push({ name: '临时占地', setting: spreadSetting.tempLand, data: stageExtra.tempLand });
+        sheets.push({ name: '其他', setting: spreadSetting.other, data: stageExtra.other });
+        SpreadExcelObj.exportSimpleXlsxSheets(sheets, "计量汇总-其他台账.xlsx");
+    });
+    $.subMenu({
+        menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
+        toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
+        key: 'menu.1.0.0',
+        miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
+        callback: function (info) {
+            if (info.mini) {
+                $('.panel-title').addClass('fluid');
+                $('#sub-menu').removeClass('panel-sidebar');
+                $('.c-body table thead').css('left', '56px');
+            } else {
+                $('.panel-title').removeClass('fluid');
+                $('#sub-menu').addClass('panel-sidebar');
+                $('.c-body table thead').css('left', '176px');
+            }
+            autoFlashHeight();
+            dataSpread.refresh();
+        }
+    });
+});

+ 1 - 1
app/view/spss/gather_stage.ejs

@@ -8,7 +8,7 @@
                     <div class="d-inline-block">
                         <div class="btn-group btn-group-toggle group-tab">
                             <a href="/sp/<%- ctx.subProject.id %>/spss/gather/stage" class="btn btn-sm btn-light active">计量台账 </a>
-                            <a href="/sp/<%- ctx.subProject.id %>/spss/gather/se" class="btn btn-sm btn-light">其他台账 </a>
+                            <a href="/sp/<%- ctx.subProject.id %>/spss/gather/stage/extra" class="btn btn-sm btn-light">其他台账 </a>
                         </div>
                     </div>
                     <div class="d-inline-block mr-2">

+ 24 - 18
app/view/spss/gather_stage_extra.ejs

@@ -8,35 +8,41 @@
                     <div class="d-inline-block">
                         <div class="btn-group btn-group-toggle group-tab" data-toggle="buttons">
                             <a href="/sp/<%- ctx.subProject.id %>/spss/gather/stage" class="btn btn-sm btn-light">计量台账 </a>
-                            <a href="/sp/<%- ctx.subProject.id %>/spss/gather/se" class="btn btn-sm btn-light active">其他台账 </a>
-                        </div>
-                    </div>
-                    <div class="d-inline-block mr-2">
-                        <!--展开/收起-->
-                        <div class="btn-group">
-                            <button type="button" class="btn btn-sm btn-light text-primary dropdown-toggle" data-toggle="dropdown" id="zhankai" aria-expanded="false">显示层级</button>
-                            <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
-                                <a class="dropdown-item" name="showLevel" tag="1" href="javascript:void(0);">第一层</a>
-                                <a class="dropdown-item" name="showLevel" tag="2" href="javascript:void(0);">第二层</a>
-                                <a class="dropdown-item" name="showLevel" tag="3" href="javascript:void(0);">第三层</a>
-                                <a class="dropdown-item" name="showLevel" tag="4" href="javascript:void(0);">第四层</a>
-                                <a class="dropdown-item" name="showLevel" tag="5" href="javascript:void(0);">第五层</a>
-                                <a class="dropdown-item" name="showLevel" tag="last" href="javascript:void(0);">最底层</a>
-                                <a class="dropdown-item" name="showLevel" tag="leafXmj" href="javascript:void(0);">只显示项目节</a>
-                            </div>
+                            <a href="/sp/<%- ctx.subProject.id %>/spss/gather/stage/extra" class="btn btn-sm btn-light active">其他台账 </a>
                         </div>
                     </div>
                     <div class="d-inline-block">
-                        <button class="btn btn-primary btn-sm mr-2">导出Excel</button>
+                        <button class="btn btn-primary btn-sm mr-2" id="export-excel">导出Excel</button>
                         <button class="btn btn-sm btn-primary" id="gather-select">汇总标段</button>
                     </div>
+                    <div class="d-inline-block ml-2">
+                        <span>汇总数据:</span>
+                        <div class="d-inline-block" style="vertical-align: middle">
+                            <div class="form-check form-check-inline">
+                                <input class="form-check-input pt-1" type="radio" id="radio_cur" value="contract" name="compare-data" checked="checked">
+                                <label class="form-check-label" for="radio_cur">本期</label>
+                            </div>
+                            <div class="form-check form-check-inline">
+                                <input class="form-check-input" type="radio" id="radio_end" value="end" name="compare-data">
+                                <label class="form-check-label" for="radio_end">截止本期</label>
+                            </div>
+                        </div>
+                    </div>
                 </div>
             </div>
         </div>
     </div>
     <div class="content-wrap">
         <div class="sjs-height-0" style="background-color: #fff">
-            <div class="c-body">
+            <nav class="nav nav-tabs my-2" role="tablist">
+                <a class="nav-item nav-link px-3 active" href="javascript: void(0)" data-toggle="tab" data-type="jgcl" role="tab" aria-selected="true">甲供材料</a>
+                <a class="nav-item nav-link px-3" href="javascript: void(0)" data-toggle="tab" data-type="yjcl" role="tab" aria-selected="false">永久材料</a>
+                <a class="nav-item nav-link px-3" href="javascript: void(0)" data-toggle="tab" data-type="bonus" role="tab" aria-selected="false">奖罚金</a>
+                <a class="nav-item nav-link px-3" href="javascript: void(0)" data-toggle="tab" data-type="safeProd" role="tab" aria-selected="false">安全生产</a>
+                <a class="nav-item nav-link px-3" href="javascript: void(0)" data-toggle="tab" data-type="tempLand" role="tab" aria-selected="false">临时占地</a>
+                <a class="nav-item nav-link px-3" href="javascript: void(0)" data-toggle="tab" data-type="other" role="tab" aria-selected="false">其他</a>
+            </nav>
+            <div id="data-spread">
             </div>
         </div>
     </div>

+ 6 - 6
app/view/spss/spss_select_modal.ejs

@@ -9,27 +9,27 @@
                     <div class="form-row align-items-center mb-2">
                         <div class="col-auto"><span class="form-check-label">计量类型:</span></div>
                         <div class="col-auto">
-                            <div class="form-check form-check-inline">
+                            <div class="form-check form-check-inline" stage-type="stage">
                                 <input class="form-check-input" type="radio" id="tsm-source-stage" value="stage" name="tsm-source">
                                 <label class="form-check-label" for="tsm-source-stage">指定期</label>
                             </div>
-                            <div class="form-check form-check-inline">
+                            <div class="form-check form-check-inline" stage-type="stage">
                                 <input class="form-check-input" type="radio" id="tsm-source-final" value="final" name="tsm-source">
                                 <label class="form-check-label" for="tsm-source-final">最新期</label>
                             </div>
-                            <div class="form-check form-check-inline">
+                            <div class="form-check form-check-inline" stage-type="stage">
                                 <input class="form-check-input" type="radio" id="tsm-source-check-final" value="checked-final" checked="" name="tsm-source">
                                 <label class="form-check-label" for="tsm-source-check-final">最新审批完成期</label>
                             </div>
-                            <div class="form-check form-check-inline">
+                            <div class="form-check form-check-inline" stage-type="zone">
                                 <input class="form-check-input" type="radio" id="tsm-source-stage-zone" value="stage-zone" name="tsm-source">
                                 <label class="form-check-label" for="tsm-source-stage-zone">期区间</label>
                             </div>
-                            <div class="form-check form-check-inline">
+                            <div class="form-check form-check-inline" stage-type="stage">
                                 <input class="form-check-input" type="radio" id="tsm-source-month" value="month" name="tsm-source">
                                 <label class="form-check-label" for="tsm-source-month">指定月</label>
                             </div>
-                            <div class="form-check form-check-inline">
+                            <div class="form-check form-check-inline" stage-type="zone">
                                 <input class="form-check-input" type="radio" id="tsm-source-zone" value="zone" name="tsm-source">
                                 <label class="form-check-label" for="tsm-source-zone">月区间</label>
                             </div>