Prechádzať zdrojové kódy

Merge branch 'master' of http://192.168.1.41:3000/maixinrong/Calculation

TonyKang 5 rokov pred
rodič
commit
c45a01d471

+ 15 - 2
app/controller/stage_extra_controller.js

@@ -99,7 +99,13 @@ module.exports = app => {
          * @returns {Promise<void>}
          */
         async loadBonus (ctx) {
-
+            try {
+                const data = await ctx.service.stageBonus.getEndStageData(ctx.stage.order);
+                ctx.body = {err: 0, msg: '', data: data};
+            } catch (error) {
+                ctx.helper.log(error);
+                ctx.body = this.ajaxErrorBody(error, '获取甲供材料数据失败,请刷新');
+            }
         }
 
         /**
@@ -108,7 +114,14 @@ module.exports = app => {
          * @returns {Promise<void>}
          */
         async updateBonus (ctx) {
-
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const result = await ctx.service.stageBonus.updateDatas(data);
+                ctx.body = { err: 0, msg: '', data: result };
+            } catch (error) {
+                ctx.helper.log(error);
+                ctx.body = this.ajaxErrorBody(error, '提交甲供材料数据失败,请重试');
+            }
         }
 
         /**

+ 1 - 1
app/lib/analysis_excel.js

@@ -302,7 +302,7 @@ class AnalysisExcelTree {
         this.colHeaderMatch = {
             code: {value: ['项目节编号', '预算项目节'], type: colDefineType.match},
             b_code: {value: ['清单子目号', '清单编号', '子目号'], type: colDefineType.match},
-            pos: {value: ['部位明细'], type: colDefineType.match},
+            pos: {value: ['计量单元'], type: colDefineType.match},
             name: {value: ['名称'], type: colDefineType.match},
             unit: {value: ['单位'], type: colDefineType.match},
             quantity: {value: ['清单数量'], type: colDefineType.match},

+ 1 - 1
app/lib/export_excel.js

@@ -41,7 +41,7 @@ class exportLedger2Excel extends exportExcel {
     constructor(ctx) {
         super(ctx);
         this.setting = {
-            header: ['项目节编号', '清单子目号', '部位明细', '名称', '单位', '清单数量', '设计数量1', '设计数量2', '单价', '合价', '图号', '备注'],
+            header: ['项目节编号', '清单子目号', '计量单元', '名称', '单位', '清单数量', '设计数量1', '设计数量2', '单价', '合价', '图号', '备注'],
             width: [100, 70, 70, 300, 60, 80, 80, 80, 80, 80, 100, 100],
             hAlign: ['left', 'left', 'left', 'left','center', 'right', 'right', 'right', 'right', 'right', 'left', 'left'],
         };

BIN
app/public/files/template/ledger/导入分项清单EXCEL格式.xls


+ 1 - 17
app/public/js/ledger.js

@@ -1322,23 +1322,7 @@ $(document).ready(function() {
                 return !readOnly;
             }
         };
-        billsContextMenuOptions.items.sprImport = '-----------';
     }
-    billsContextMenuOptions.items.exportExcel = {
-        name: '导出表格数据',
-        icon: 'fa-file-excel-o',
-        callback: function (key, opt) {
-            const fileName = $('.text-truncate').attr('data-original-title') + '.xlsx';
-            SpreadExcelObj.exportSpread2XlsxWithHeader(ledgerSpread, fileName);
-        },
-        visible: function (key, opt) {
-            try {
-                return is_debug;
-            } catch (err) {
-                return false;
-            }
-        }
-    };
     $.contextMenu(billsContextMenuOptions);
 
     const posSearch = $.posSearch({selector: '#pos-search', searchSpread: posSpread});
@@ -2550,7 +2534,7 @@ $(document).ready(function() {
             cols: [
                 {title: '项目节编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 100, formatter: '@'},
                 {title: '清单子目号', colSpan: '1', rowSpan: '1', field: 'b_code', hAlign: 0, width: 70, formatter: '@'},
-                {title: '部位明细', colSpan: '1', rowSpan: '1', field: 'pos_code', hAlign: 1, width: 70, formatter: '@'},
+                {title: '计量单元', colSpan: '1', rowSpan: '1', field: 'pos_code', hAlign: 1, width: 70, formatter: '@'},
                 {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 300, formatter: '@'},
                 {title: '单位', colSpan: '1', rowSpan: '1', field: 'unit', hAlign: 1, width: 60, formatter: '@'},
                 {title: '清单数量', colSpan: '1', rowSpan: '1', field: 'quantity', hAlign: 2, width: 80, type: 'Number'},

+ 365 - 9
app/public/js/se_bonus.js

@@ -8,16 +8,23 @@
  * @version
  */
 
+const isPre = function (data) {
+    return data.sid !== stageId;
+};
 const spreadSetting = { 
     cols: [
-        {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 185, formatter: '@'},
-        {title: '金额', colSpan: '1', rowSpan: '1', field: 'e_type', hAlign: 1, width: 80, formatter: '@'},
-        {title: '本期金额', colSpan: '1', rowSpan: '1', field: 'quantity', hAlign: 2, width: 100, type: 'Number'},
-        {title: '截止本期金额', colSpan: '1', rowSpan: '1', field: 'total_price', hAlign: 2, width: 100, type: 'Number', readOnly: true},
-        {title: '时间', colSpan: '1', rowSpan: '1', field: 'total_price', hAlign: 2, width: 100, type: 'Number'},
-        {title: '编号', colSpan: '1', rowSpan: '1', field: 'total_price', hAlign: 2, width: 100, type: 'Number'},
-        {title: '依据材料证明', colSpan: '1', rowSpan: '1', field: 'total_price', hAlign: 2, width: 100, type: 'Number'},
-        {title: '备注', colSpan: '1', rowSpan: '1', field: 'memo', hAlign: 0, width: 150, formatter: '@', cellType: 'ellipsisAutoTip'}
+        {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 235, formatter: '@', readOnly: isPre, },
+        {title: '金额', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 2, width: 100, type: 'Number', readOnly: isPre, },
+        {title: '时间', colSpan: '1', rowSpan: '1', field: 'real_time', hAlign: 1, width: 150, formatter: '@', readOnly: isPre, },
+        {title: '编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 150, formatter: '@', readOnly: isPre, },
+        {title: '依据材料证明', colSpan: '1', rowSpan: '1', field: 'proof', hAlign: 0, width: 180, formatter: '@', readOnly: isPre, },
+        {
+            title: '计量期', colSpan: '1', rowSpan: '1', field: 'sorder', hAlign: 1, width: 100, formatter: '@',
+            getValue: function (data) {
+                return '第' + data.sorder + '期';
+            }, readOnly: true,
+        },
+        {title: '备注', colSpan: '1', rowSpan: '1', field: 'memo', hAlign: 0, width: 180, formatter: '@', cellType: 'ellipsisAutoTip', readOnly: isPre, }
     ],
     emptyRows: 3,
     headRows: 1,
@@ -30,6 +37,7 @@ $(document).ready(() => {
     autoFlashHeight();
     const bonusSpread = SpreadJsObj.createNewSpread($('#bonus-spread')[0]);
     const bonusSheet = bonusSpread.getActiveSheet();
+    spreadSetting.readOnly = readOnly;
     SpreadJsObj.initSheet(bonusSheet, spreadSetting);
 
     $.subMenu({
@@ -48,5 +56,353 @@ $(document).ready(() => {
             autoFlashHeight();
             bonusSpread.refresh();
         }
-    }); 
+    });
+
+    class Bonus {
+        constructor () {
+            this.data = [];
+        }
+        resortData() {
+            this.data.sort(function (a, b) {
+                return a.sorder !== b.sorder ? a.sorder - b.sorder : a.order - b.order;
+            });
+        }
+        loadDatas(datas) {
+            this.data = datas;
+            this.resortData();
+        }
+        loadUpdateData(updateData) {
+            if (updateData.add) {
+                for (const a of updateData.add) {
+                    this.data.push(a);
+                }
+            }
+            if (updateData.update) {
+                for (const u of updateData.update) {
+                    const d = this.data.find(function (x) {
+                        return u.id === x.id;
+                    });
+                    if (d) {
+                        _.assign(d, u);
+                    } else {
+                        this.data.push(d);
+                    }
+                }
+            }
+            if (updateData.del) {
+                _.remove(this.data, function (d) {
+                    return updateData.del.indexOf(d.id) >= 0;
+                });
+            }
+            this.resortData();
+        }
+        getCurStageNewOrder() {
+            const cur = this.data.filter(function (x) {
+                return x.sid === stageId;
+            });
+            return cur && cur.length > 0 ? cur.length + 1 : 1;
+        }
+        checkCurFirst(bonusData) {
+            const cur = this.data.filter(function (x) {
+                return x.sid === stageId;
+            });
+            return cur.indexOf(bonusData) === 0;
+        }
+        checkCurLast(bonusData) {
+            const cur = this.data.filter(function (x) {
+                return x.sid === stageId;
+            });
+            return cur.indexOf(bonusData) === cur.length - 1;
+        }
+    }
+    const bonusObj = new Bonus();
+
+    postData(window.location.pathname + '/load', null, function (result) {
+        bonusObj.loadDatas(result);
+        SpreadJsObj.loadSheetData(bonusSheet, SpreadJsObj.DataType.Data, bonusObj.data);
+    });
+
+    if (!readOnly) {
+        const bonusOprObj = {
+            /**
+             * 删除按钮响应事件
+             * @param sheet
+             */
+            deletePress: function (sheet) {
+                if (!sheet.zh_setting || readOnly) return;
+
+                const sortData = sheet.zh_data;
+                const datas = [];
+                const sels = sheet.getSelections();
+                if (!sels || !sels[0]) return;
+                const hint = {
+                    name: {type: 'warning', msg: '名称不能为空,如需删除甲供材料请使用右键删除'},
+                };
+
+                for (let iRow = sels[0].row; iRow < sels[0].row + sels[0].rowCount; iRow++) {
+                    let bDel = false;
+                    const node = sortData[iRow];
+                    if (node) {
+                        const data = {id: node.id};
+                        for (let iCol = sels[0].col; iCol < sels[0].col + sels[0].colCount; iCol++) {
+                            const colSetting = sheet.zh_setting.cols[iCol];
+                            if (colSetting.field === 'name') {
+                                toastMessageUniq(hint.name);
+                                return;
+                            }
+                            const style = sheet.getStyle(iRow, iCol);
+                            if (!style.locked) {
+                                const colSetting = sheet.zh_setting.cols[iCol];
+                                data[colSetting.field] = null;
+                                bDel = true;
+                            }
+                        }
+                        if (bDel) {
+                            datas.push(data);
+                        }
+                    }
+                }
+                if (datas.length > 0) {
+                    postData(window.location.pathname + '/update', {updateType: 'update', updateData: datas}, function (result) {
+                        bonusObj.loadUpdateData(result);
+                        SpreadJsObj.reLoadSheetData(bonusSheet);
+                    }, function () {
+                        SpreadJsObj.reLoadSheetData(bonusSheet);
+                    });
+                }
+            },
+            delete: function () {
+                const sheet = bonusSheet;
+                if (!sheet.zh_setting || readOnly) return;
+
+                const sortData = sheet.zh_data;
+                const datas = [];
+                const sels = sheet.getSelections();
+                if (!sels || !sels[0]) return;
+                const hint = {
+                    isOld: {type: 'warning', msg: '本项为往期数据,不可删除'},
+                    invalidDel: {type: 'warning', msg: '本项不是您新增的,只有原报和新增人可删除'},
+                };
+
+                for (let iRow = sels[0].row, iLen = sels[0].row + sels[0].rowCount; iRow < iLen; iRow++) {
+                    const node = sortData[iRow];
+                    if (node.sid !== stageID) {
+                        toastMessageUniq(hint.isOld);
+                        continue;
+                    } else {
+                        if (node.uid !== userID || stageUserId !== userID) {
+                            toastMessageUniq(hint.invalidDel);
+                            continue;
+                        }
+                        datas.push(node.id);
+                    }
+                }
+                if (datas.length > 0) {
+                    postData(window.location.pathname + '/update', {del: datas}, function (result) {
+                        bonusObj.loadUpdateData(result);
+                        SpreadJsObj.reLoadSheetData(sheet);
+                    }, function () {
+                        SpreadJsObj.reLoadSheetData(sheet);
+                    });
+                }
+            },
+            editEnded: function (e, info) {
+                if (!info.sheet.zh_setting || !info.sheet.zh_data) return;
+
+                const node = info.sheet.zh_data[info.row];
+                const col = info.sheet.zh_setting.cols[info.col];
+                const data = {};
+
+                if (node) {
+                    data.update = {};
+                    data.update.id = node.id;
+
+                    const oldValue = node ? node[col.field] : null;
+                    const newValue = trimInvalidChar(info.editingText);
+                    if (oldValue == info.editingText || ((!oldValue || oldValue === '') && (newValue === ''))) {
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        return;
+                    }
+                    data.update[col.field] = newValue;
+                } else {
+                    if (col.field !== 'name') {
+                        toastr.warning('新增奖罚金,请先输入名称');
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        return;
+                    }
+                    data.add = {};
+                    data.add.order = bonusObj.getCurStageNewOrder();
+                    data.add.name = trimInvalidChar(info.editingText);
+                }
+
+                postData(window.location.pathname + '/update', data, function (result) {
+                    bonusObj.loadUpdateData(result);
+                    SpreadJsObj.reLoadSheetData(info.sheet);
+                }, function () {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                });
+            },
+            clipboardPasting(e, info) {
+                const setting = info.sheet.zh_setting, sortData = info.sheet.zh_data;
+                info.cancel = true;
+
+                if (!setting || !sortData) return;
+                const pasteData = info.pasteData.html
+                    ? SpreadJsObj.analysisPasteHtml(info.pasteData.html)
+                    : (info.pasteData.text === ''
+                        ? SpreadJsObj.Clipboard.getAnalysisPasteText()
+                        : SpreadJsObj.analysisPasteText(info.pasteData.text));
+                const hint = {
+                    name: {type: 'warning', msg: '奖罚金名称不可为空,已过滤'},
+                    tp: {type: 'warning', msg: '输入的 金额 非法,已过滤'},
+                };
+
+                const uDatas = [], iDatas = [], maxOrder = bonusObj.getCurStageNewOrder();
+                for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
+                    const curRow = info.cellRange.row + iRow;
+                    const node = sortData[curRow];
+
+                    let bPaste = false;
+                    const data = {};
+                    for (let iCol = 0; iCol < info.cellRange.colCount; iCol++) {
+                        const curCol = info.cellRange.col + iCol;
+                        const colSetting = setting.cols[curCol];
+                        const value = trimInvalidChar(pasteData[iRow][iCol]);
+
+                        if (colSetting.field === 'name' && (!value || value === '')) {
+                            toastMessageUniq(hint.name);
+                            break;
+                        }
+                        if (colSetting.type === 'Number') {
+                            const num = _.toNumber(value);
+                            if (num) {
+                                data[colSetting.field] = num;
+                                bPaste = true;
+                            }
+                        } else {
+                            data[colSetting.field] = value;
+                            bPaste = true;
+                        }
+                    }
+                    if (bPaste) {
+                        if (node) {
+                            data.id = node.id;
+                            uDatas.push(data);
+                        } else {
+                            data.order = maxOrder + iRow;
+                            iDatas.push(data);
+                        }
+                    }
+                }
+                const updateData = {};
+                if (uDatas.length > 0) updateData.update = uDatas;
+                if (iDatas.length > 0) updateData.add = iDatas;
+                if (uDatas.length > 0 || iDatas.length > 0) {
+                    postData(window.location.pathname + '/update', updateData, function (result) {
+                        bonusObj.loadUpdateData(result);
+                        SpreadJsObj.reLoadSheetData(info.sheet);
+                    });
+                } else {
+                    SpreadJsObj.reLoadSheetData(info.sheet);
+                }
+            },
+            upMove: function () {
+                const sheet = bonusSheet;
+                const sels = sheet.getSelections(), sortData = sheet.zh_data;
+                const node = sortData[sels[0].row];
+                const preNode = sortData[sels[0].row - 1];
+                const data = [
+                    {id: node.id, order: preNode.order},
+                    {id: preNode.id, order: node.order}
+                ];
+                postData(window.location.pathname + '/update', {update: data}, function (result) {
+                    bonusObj.loadUpdateData(result);
+                    SpreadJsObj.reLoadRowsData(sheet, [sels[0].row, sels[0].row - 1]);
+                    sheet.setSelection(sels[0].row - 1, sels[0].col, sels[0].rowCount, sels[0].colCount);
+                });
+            },
+            downMove: function () {
+                const sheet = bonusSheet;
+                const sels = sheet.getSelections(), sortData = sheet.zh_data;
+                const node = sortData[sels[0].row];
+                const nextNode = sortData[sels[0].row + 1];
+                const data = [
+                    {id: node.id, order: nextNode.order},
+                    {id: nextNode.id, order: node.order}
+                ];
+                postData(window.location.pathname + '/update', {update: data}, function (result) {
+                    bonusObj.loadUpdateData(result);
+                    SpreadJsObj.reLoadRowsData(sheet, [sels[0].row, sels[0].row + 1]);
+                    sheet.setSelection(sels[0].row + 1, sels[0].col, sels[0].rowCount, sels[0].colCount);
+                });
+            }
+        };
+        bonusSheet.bind(spreadNS.Events.EditEnded, bonusOprObj.editEnded);
+        bonusSheet.bind(spreadNS.Events.ClipboardPasting, bonusOprObj.clipboardPasting);
+        SpreadJsObj.addDeleteBind(bonusSpread, bonusOprObj.deletePress);
+        $.contextMenu({
+            selector: '#bonus-spread',
+            build: function ($trigger, e) {
+                const target = SpreadJsObj.safeRightClickSelection($trigger, e, bonusSpread);
+                return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
+            },
+            items: {
+                del: {
+                    name: '删除',
+                    icon: 'fa-remove',
+                    callback: function (key, opt) {
+                        bonusOprObj.delete();
+                    },
+                    disabled: function (key, opt) {
+                        const sels = bonusSheet.getSelections();
+                        if (!sels || !sels[0]) return true;
+
+                        const row = sels[0].row;
+                        const node = bonusObj.data[row];
+                        return node === undefined || node === null || node.sid !== stageId;
+                    },
+                    visible: function (key, opt) {
+                        return !readOnly;
+                    }
+                },
+                sprDel: '------------',
+                upMove: {
+                    name: '上移',
+                    icon: 'fa-arrow-up',
+                    callback: function (key, opt) {
+                        bonusOprObj.upMove();
+                    },
+                    disabled: function (key, opt) {
+                        const sels = bonusSheet.getSelections();
+                        if (!sels || !sels[0] || sels[0].row === 0) return true;
+
+                        const row = sels[0].row;
+                        const node = bonusObj.data[row];
+                        return node === undefined || node === null || node.sid !== stageId || bonusObj.checkCurFirst(node);
+                    },
+                    visible: function (key, opt) {
+                        return !readOnly;
+                    }
+                },
+                downMove: {
+                    name: '下移',
+                    icon: 'fa-arrow-down',
+                    callback: function (key, opt) {
+                        bonusOprObj.downMove();
+                    },
+                    disabled: function (key, opt) {
+                        const sels = bonusSheet.getSelections();
+                        if (!sels || !sels[0] || sels[0].row >= bonusObj.data.length - 1) return true;
+
+                        const row = sels[0].row;
+                        const node = bonusObj.data[row];
+                        return node === undefined || node === null || node.sid !== stageId || bonusObj.checkCurLast(node);
+                    },
+                    visible: function (key, opt) {
+                        return !readOnly;
+                    }
+                }
+            },
+        });
+    }
 });

+ 1 - 1
app/public/js/se_jgcl.js

@@ -57,7 +57,7 @@ $(document).ready(() => {
     });
 
     class Jgcl {
-        constructor (setting) {
+        constructor () {
             this.data = [];
         }
         resortData() {

+ 1 - 1
app/public/js/tender_list_info.js

@@ -344,7 +344,7 @@ function getTenderTreeHtml () {
         const html = [];
         html.push('<table class="table table-hover table-bordered" style="margin-top: 25px">');
         html.push('<thead style="position: fixed;left:56px;top: 34px">', '<tr>');
-        html.push('<th>', '名称', '</th>');
+        html.push('<th>', '标段名称', '</th>');
         html.push('<th>', '计量模式', '</th>');
         html.push('<th>', '计量期数', '</th>');
         html.push('<th>', '审批状态', '</th>');

+ 2 - 1
app/public/js/tender_list_manage.js

@@ -255,6 +255,7 @@ function initTenderTree () {
             tenderTree.push(t);
         }
     }
+    console.log(tenderTree);
 }
 function recursiveGetTenderNodeHtml (node, arr, pid) {
     const html = [];
@@ -303,7 +304,7 @@ function getTenderTreeHeaderHtml() {
     const html = [];
     html.push('<table class="table table-hover table-bordered" style="margin-top: 25px">');
     html.push('<thead style="position: fixed;left:56px;top: 34px">', '<tr>');
-    html.push('<th>', '名称', '</th>');
+    html.push('<th>', '标段名称', '</th>');
     html.push('<th>', '创建人', '</th>');
     html.push('<th>', '创建时间', '</th>');
     html.push('<th>', '完成期数', '</th>');

+ 1 - 1
app/public/js/tender_list_progress.js

@@ -330,7 +330,7 @@ function getTenderTreeHtml () {
         const html = [];
         html.push('<table class="table table-hover table-bordered" style="margin-top: 25px">');
         html.push('<thead style="position: fixed;left:56px;top: 34px">', '<tr>');;
-        html.push('<th width="60%">', '名称', '</th>');
+        html.push('<th width="60%">', '标段名称', '</th>');
         html.push('<th width="120">', '计量期数', '</th>');
         html.push('<th width="10%">', '总价 <i class="fa fa-question-circle text-primary"  data-placement="bottom" data-toggle="tooltip" data-original-title="0号台账+截止本期数量变更"></i>', '</th>');
         html.push('<th>', '截止上期完成/本期完成/未完成', '</th>');

+ 4 - 0
app/router.js

@@ -200,7 +200,11 @@ module.exports = app => {
     app.post('/tender/:id/measure/stage/:order/extra/jgcl/load', sessionAuth, tenderCheck, stageCheck, 'stageExtraController.loadJgcl');
     app.post('/tender/:id/measure/stage/:order/extra/jgcl/update', sessionAuth, tenderCheck, stageCheck, 'stageExtraController.updateJgcl');
     app.get('/tender/:id/measure/stage/:order/extra/bonus', sessionAuth, tenderCheck, stageCheck, 'stageExtraController.bonus');
+    app.post('/tender/:id/measure/stage/:order/extra/bonus/load', sessionAuth, tenderCheck, stageCheck, 'stageExtraController.loadBonus');
+    app.post('/tender/:id/measure/stage/:order/extra/bonus/update', sessionAuth, tenderCheck, stageCheck, 'stageExtraController.updateBonus');
     app.get('/tender/:id/measure/stage/:order/extra/other', sessionAuth, tenderCheck, stageCheck, 'stageExtraController.other');
+    app.post('/tender/:id/measure/stage/:order/extra/other/load', sessionAuth, tenderCheck, stageCheck, 'stageExtraController.loadOther');
+    app.post('/tender/:id/measure/stage/:order/extra/other/update', sessionAuth, tenderCheck, stageCheck, 'stageExtraController.updateOther');
 
     // 报表
     app.get('/tender/:id/report', sessionAuth, tenderCheck, 'reportController.index');

+ 2 - 0
app/service/pay.js

@@ -44,6 +44,7 @@ module.exports = app => {
                     p.cstimes = 0;
                     p.csorder = 0;
                     p.csaorder = 0;
+                    if (p.minus === null) p.minus = false;
                 }
                 let result;
                 if (transaction) {
@@ -53,6 +54,7 @@ module.exports = app => {
                 }
                 return result.affectedRows === pays.length;
             } catch(error) {
+                this.ctx.helper.log(error);
                 throw '项目的默认合同支付数据有误';
             }
         }

+ 20 - 1
app/service/stage_audit.js

@@ -213,6 +213,7 @@ module.exports = app => {
                 // 复制一份下一审核人数据
                 await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, 1, transaction);
                 await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction);
+                await this.ctx.service.stageBonus.updateHistory(this.ctx.stage, transaction);
                 // 更新期数据
                 const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
                 await transaction.update(this.ctx.service.stage.tableName, {
@@ -258,7 +259,6 @@ module.exports = app => {
 
             const transaction = await this.db.beginTransaction();
             try {
-                console.log(checkData.opinion);
                 await transaction.update(this.tableName, {id: audit.id, status: checkData.checkType, opinion: checkData.opinion, end_time: time});
                 // 计算并合同支付最终数据
                 const yfPay = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
@@ -267,6 +267,7 @@ module.exports = app => {
                     // 复制一份下一审核人数据
                     await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, nextAudit.order, transaction);
                     await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction);
+                    await this.ctx.service.stageBonus.updateHistory(this.ctx.stage, transaction);
                     // 流程至下一审批人
                     await transaction.update(this.tableName, {id: nextAudit.id, status: auditConst.status.checking, begin_time: time});
                     // 同步 期信息
@@ -363,6 +364,8 @@ module.exports = app => {
 
             const transaction = await this.db.beginTransaction();
             try {
+                // 计算并合同支付最终数据
+                const yfPay = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
                 await transaction.update(this.tableName, {id: audit.id, status: checkData.checkType, opinion: checkData.opinion, end_time: time});
                 // 同步 期信息
                 await transaction.update(this.ctx.service.stage.tableName, {
@@ -370,6 +373,7 @@ module.exports = app => {
                     contract_tp: tpData.contract_tp,
                     qc_tp: tpData.qc_tp,
                     times: times + 1,
+                    yf_tp: yfPay.tp,
                     cache_time_r: this.ctx.stage.cache_time_l,
                 });
                 // 拷贝新一次审核流程列表
@@ -379,6 +383,7 @@ module.exports = app => {
                 // 复制一份最新数据给原报
                 await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times + 1, 0, transaction);
                 await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction);
+                await this.ctx.service.stageBonus.updateHistory(this.ctx.stage, transaction);
 
                 // 添加短信通知-审批退回提醒功能
                 const mobile_array = [];
@@ -430,8 +435,20 @@ module.exports = app => {
             });
             const preAuditor = auditors2[auditorIndex - 1];
 
+            const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
             const transaction = await this.db.beginTransaction();
             try {
+                // 计算并合同支付最终数据
+                const yfPay = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
+                // 同步 期信息
+                await transaction.update(this.ctx.service.stage.tableName, {
+                    id: stageId,
+                    contract_tp: tpData.contract_tp,
+                    qc_tp: tpData.qc_tp,
+                    times: times + 1,
+                    yf_tp: yfPay.tp,
+                    cache_time_r: this.ctx.stage.cache_time_l,
+                });
                 await transaction.update(this.tableName, {id: audit.id, status: checkData.checkType, opinion: checkData.opinion, end_time: time});
                 // 顺移气候审核人流程顺序
                 this.initSqlBuilder();
@@ -457,6 +474,7 @@ module.exports = app => {
                 // 复制一份最新数据给下一人
                 await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 1, transaction);
                 await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction);
+                await this.ctx.service.stageBonus.updateHistory(this.ctx.stage, transaction);
 
                 // 同步 期信息
                 await transaction.update(this.ctx.service.stage.tableName, {
@@ -665,6 +683,7 @@ module.exports = app => {
                 await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 1, transaction);
                 await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 2, transaction);
                 await this.ctx.service.stageJgcl.updateHistory(this.ctx.stage, transaction);
+                await this.ctx.service.stageBonus.updateHistory(this.ctx.stage, transaction);
 
                 // 本期结束
                 // 生成截止本期数据 final数据

+ 146 - 0
app/service/stage_bonus.js

@@ -0,0 +1,146 @@
+'use strict';
+
+/**
+ *  奖罚金
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+module.exports = app => {
+    class StageBonus extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'stage_bonus';
+        }
+
+        async getStageData(sid) {
+            const data = await this.getAllDataByCondition({where: { sid: sid }});
+            return data;
+        }
+
+        async getPreStageData(sorder) {
+            const sql = 'SELECT * From ' + this.tableName + ' WHERE sorder < ? And tid = ?';
+            const sqlParam = [sorder, this.ctx.tender.id];
+            const data = await this.db.query(sql, sqlParam);
+            return data;
+        }
+
+        async getEndStageData(sorder) {
+            const sql = 'SELECT * From ' + this.tableName + ' WHERE sorder <= ? And tid = ?';
+            const sqlParam = [sorder, this.ctx.tender.id];
+            const data = await this.db.query(sql, sqlParam);
+            return data;
+        }
+
+        async _addDatas(data) {
+            const datas = data instanceof Array ? data : [data];
+            const insertData = [];
+            for (const d of datas) {
+                if (!d.name || !d.order) throw '新增甲供材料,提交的数据错误';
+                const nd = {
+                    id: this.uuid.v4(),
+                    tid: this.ctx.tender.id,
+                    sid: this.ctx.stage.id,
+                    sorder: this.ctx.stage.order,
+                    uid: this.ctx.session.sessionUser.accountId,
+                    create_time: new Date(),
+                    name: d.name,
+                    order: d.order,
+                };
+                nd.tp = d.tp ? this.ctx.helper.round(d.to, this.ctx.tender.info.decimal.tp) : 0;
+                nd.code = d.code ? d.code: null;
+                nd.proof = d.proof ? d.proof : null;
+                nd.real_time = d.real_time ? d.real_time : null;
+                nd.memo = d.memo ? d.memo : null;
+                insertData.push(nd);
+            }
+            await this.db.insert(this.tableName, insertData);
+            return insertData;
+        }
+
+        async _delDatas (data) {
+            const datas = data instanceof Array ? data : [data];
+            const orgDatas = await this.getAllDataByCondition({sid: this.ctx.stage.id, id: this.ctx.helper._.map(datas, 'id')});
+            for (const od of orgDatas) {
+                if (od.sid !== this.ctx.stage.id) throw '非本期新增数据,不可删除';
+            }
+            await this.db.delete(this.tableName, {id: datas});
+            return datas;
+        }
+
+        async _updateDatas (data) {
+            const datas = data instanceof Array ? data : [data];
+            const orgDatas = await this.getAllDataByCondition({sid: this.ctx.stage.id, id: this.ctx.helper._.map(datas, 'id')});
+
+            const uDatas = [];
+            for (const d of datas) {
+                const od = this.ctx.helper._.find(orgDatas, {id: d.id});
+                if (!od) continue;
+
+                const nd = {id: od.id};
+                if (d.name) nd.name = d.name;
+                if (d.tp) nd.tp = this.ctx.helper.round(d.tp, this.ctx.tender.info.decimal.tp);
+                if (d.code) nd.code = d.code;
+                if (d.proof) nd.proof = d.proof;
+                if (d.real_time) nd.real_time = d.real_time;
+                if (d.memo) nd.memo = d.memo;
+                if (d.order) nd.order = d.order;
+                uDatas.push(nd);
+            }
+            if (uDatas.length > 0) {
+                await this.db.updateRows(this.tableName, uDatas);
+                return uDatas;
+            } else {
+                return [];
+            }
+        }
+
+        async updateDatas(data) {
+            const result = {add: [], del: [], update: []};
+            try {
+                if (data.add) {
+                    result.add = await this._addDatas(data.add);
+                }
+                if (data.update) {
+                    result.update = await this._updateDatas(data.update);
+                }
+                if (data.del) {
+                    result.del = await this._delDatas(data.del);
+                }
+                return result;
+            } catch (err) {
+                if (err) result.err = err;
+                return result;
+            }
+        }
+
+        async updateHistory(stage, transaction) {
+            const datas = await this.getStageData(stage.id);
+            if (datas.length === 0) return;
+
+            const filter = {stimes: this.ctx.stage.curTimes, sorder: this.ctx.stage.curOrder};
+            const updateDatas = [];
+            for (const d of datas) {
+                const history = d.shistory && d.shistory !== '' ? JSON.parse(d.shistory) : [];
+                const his = this.ctx.helper._.find(datas, filter);
+                if (his) {
+                    his.tp = d.tp;
+                } else {
+                    history.push({ stimes: this.ctx.stage.curTimes, sorder: this.ctx.stage.curOrder, tp: d.tp });
+                }
+                updateDatas.push({ id: d.id, shistory: JSON.stringify(history) });
+            }
+            await transaction.updateRows(this.tableName, updateDatas);
+        }
+    }
+
+    return StageBonus;
+};

+ 1 - 5
app/service/stage_jgcl.js

@@ -8,10 +8,6 @@
  * @version
  */
 
-
-const timesLen = require('../const/audit').stage.timesLen;
-const payConst = require('../const/deal_pay');
-
 module.exports = app => {
     class StageJgcl extends app.BaseService {
         /**
@@ -108,7 +104,7 @@ module.exports = app => {
 
                 const nd = {id: od.id};
                 if (d.name) nd.name = d.name;
-                if (od.sid === od.add_sid) {
+                if (od.pre_used === null || od.pre_used === undefined || od.pre_used === 0) {
                     if (d.unit) nd.unit = d.unit;
                     nd.unit_price = d.unit_price ? this.ctx.helper.round(d.unit_price, info.decimal.up) : od.unit_price;
                 }

+ 1 - 1
app/view/ledger/explode_modal.ejs

@@ -33,7 +33,7 @@
             <div class="modal-body">
                 <div class="form-group">
                     <label for="exampleFormControlFile1">Excel模板</label>
-                    <div class="form-control form-control-plaintext"><a id="downloadDealTemplate" href="/tender/<%- ctx.tender.id %>/deal/download/签约清单导入格式.xls" class="btn btn-sm btn-link">下载模板</a></div>
+                    <div class="form-control form-control-plaintext"><a id="downloadDealTemplate" href="/tender/<%- ctx.tender.id %>/deal/download/签约清单导入格式.xls" class="btn btn-sm btn-link">下载示例</a></div>
                 </div>
                 <div class="form-group">
                     <label for="exampleFormControlFile1">上传签约清单Excel文件</label>

+ 1 - 1
app/view/ledger/gather.ejs

@@ -6,7 +6,7 @@
             <div>
                 <a class="btn btn-sm btn-light">
                     <div class="custom-control custom-checkbox">
-                        <input type="checkbox" class="custom-control-input" id="compare-tag">
+                        <input type="checkbox" class="custom-control-input" id="compare-tag" checked="checked">
                         <label class="custom-control-label text-primary" for="compare-tag">签约-台账≠0</label>
                     </div>
                 </a>

+ 6 - 1
app/view/stage_extra/bonus.ejs

@@ -16,4 +16,9 @@
             </div>
         </div>
     </div>
-</div>
+</div>
+<script>
+    const stageId = <%- ctx.stage.id %>;
+    const stageUserId = <%- ctx.stage.user_id %>;
+    const readOnly = <%- ctx.stage.readOnly %>;
+</script>

+ 0 - 2
config/web.js

@@ -373,7 +373,6 @@ const JsFiles = {
                     "/public/js/sub_menu.js",
                     "/public/js/spreadjs_rela/spreadjs_zh.js",
                     "/public/js/zh_calc.js",
-                    "/public/js/path_tree.js",
                     "/public/js/se_jgcl.js",
                 ],
                 mergeFile: 'se_jgcl',
@@ -387,7 +386,6 @@ const JsFiles = {
                     "/public/js/sub_menu.js",
                     "/public/js/spreadjs_rela/spreadjs_zh.js",
                     "/public/js/zh_calc.js",
-                    "/public/js/path_tree.js",
                     "/public/js/se_bonus.js",
                 ],
                 mergeFile: 'se_bonus',