MaiXinRong 1 рік тому
батько
коміт
9b4b809bdd

+ 10 - 2
app/controller/payment_controller.js

@@ -387,7 +387,7 @@ module.exports = app => {
                 const content = [];
                 // 获取当前报表人
                 const rptAudit = await ctx.service.paymentRptAudit.getDataByCondition({ td_id: ctx.detail.id, uid: ctx.session.sessionUser.accountId });
-                if (report_json.items[0].interact_cells.length > 0) {
+                if (report_json && report_json.items[0].interact_cells.length > 0) {
                     for (const [i, cell] of report_json.items[0].interact_cells.entries()) {
                         cell.index = i;
                     }
@@ -1189,7 +1189,15 @@ module.exports = app => {
                 for (const f of filter) {
                     switch (f) {
                         case 'bills':
-                            responseData.data.bills = await ctx.service.paymentSafeBills.getAllDataByCondition({ where: {detail_id: ctx.params.did }});
+                            responseData.data.bills = ctx.detail.readOnly
+                                ? await ctx.service.paymentSafeBills.getReadData(ctx.detail)
+                                : await ctx.service.paymentSafeBills.getEditData(ctx.detail);
+                            break;
+                        case 'billsCompare':
+                            responseData.data[f] = await ctx.service.paymentSafeBills.getCompareData(ctx.detail);
+                            break;
+                        case 'auditFlow':
+                            responseData.data[f] = await ctx.service.paymentDetailAudit.getViewFlow(ctx.detail);
                             break;
                         default:
                             responseData.data[f] = [];

+ 1 - 1
app/middleware/payment_detail_check.js

@@ -79,7 +79,7 @@ module.exports = options => {
             });
             detail.readOnly = !((detail.status === status.uncheck || detail.status === status.checkNo) && accountId === detail.uid);
             if (detail.readOnly && detail.type === paymentConst.modes_value_object.safe) {
-                if ((detail.status === status.checking || detail.status === status.checkNoPre) && detail.curAuditor && detail.curAuditor === accountId) {
+                if ((detail.status === status.checking || detail.status === status.checkNoPre) && detail.curAuditor && detail.curAuditor.aid === accountId) {
                     detail.readOnly = false;
                 }
             }

+ 3 - 0
app/public/js/global.js

@@ -1201,6 +1201,9 @@ const spreadColor = {
         pause: '#f2f2f2',
         yf_without: '#d6d8db',
         cur_add: '#FFFFE1',
+    },
+    safe: {
+        differ: '#F2DEDE',
     }
 };
 

+ 62 - 11
app/public/js/payment_compare.js

@@ -9,23 +9,21 @@ $(document).ready(function() {
                 pid: 'tree_pid',
                 order: 'tree_order',
                 level: 'tree_level',
+                isLeaf: 'tree_is_leaf',
+                fullPath: 'tree_full_path',
                 rootId: -1,
-                autoExpand: 3,
-                markExpandKey: 'bills-expand',
-                markExpandSubKey: window.location.pathname.split('/')[2],
-                calcFields: ['cur_tp', 'pre_tp', 'end_tp'],
             };
             this.spreadSetting = {
                 baseCols: [
-                    {title: '编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 70, formatter: '@'},
+                    {title: '编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 230, formatter: '@', cellType: 'tree'},
                     {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 185, formatter: '@'},
                     {title: '规格', colSpan: '1', rowSpan: '2', field: 'spec', hAlign: 0, width: 150, formatter: '@'},
                     {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 50, formatter: '@', cellType: 'unit'},
                     {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
                 ],
                 extraCols: [
-                    {title: '%s|数量', colSpan: '2|1', rowSpan: '1|1', field: '{%s}_qty{%d}', hAlign: 2, width: 60, type: 'Number', },
-                    {title: '|金额', colSpan: '|1', rowSpan: '|1', field: '{%s}_tp{%d}', hAlign: 2, width: 60, type: 'Number', },
+                    {title: '%s|数量', colSpan: '2|1', rowSpan: '1|1', field: 'qty_{%d}', hAlign: 2, width: 60, type: 'Number', },
+                    {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'tp_{%d}', hAlign: 2, width: 60, type: 'Number', },
                 ],
                 emptyRows: 3,
                 headRows: 2,
@@ -33,6 +31,19 @@ $(document).ready(function() {
                 defaultRowHeight: 21,
                 headerFont: '12px 微软雅黑',
                 font: '12px 微软雅黑',
+                readOnly: true,
+            };
+            this.spreadSetting.getColor = function (sheet, data, row, col, defaultColor) {
+                function checkDiffer(data) {
+                    const fieldSufs = sheet.zh_setting.fieldSufs;
+                    if (fieldSufs.length <= 1) return false;
+                    const base = data['qty_' + fieldSufs[0]];
+                    for (let i = 1; i< fieldSufs.length; i++) {
+                        const compare = data['qty_' + fieldSufs[i]];
+                        if ((base || compare) && (compare!== base)) return true;
+                    }
+                }
+                return checkDiffer(data) ? spreadColor.safe.differ : defaultColor;
             };
             this.tree = createNewPathTree('ledger', this.treeSetting);
             this.ckBillsSpread = window.location.pathname + '-billsSelect';
@@ -41,19 +52,59 @@ $(document).ready(function() {
         }
         refreshSpreadSetting(roles) {
             this.spreadSetting.cols = [];
+            this.spreadSetting.fieldSufs = [];
             for (const col of this.spreadSetting.baseCols) {
                 this.spreadSetting.cols.push(col);
             }
-            // todo 根据参与审批的人加载数据
+            for (const role of roles) {
+                this.spreadSetting.fieldSufs.push(role.order);
+                for (const ec of this.spreadSetting.extraCols) {
+                    const col = JSON.parse(JSON.stringify(ec));
+                    col.title = _.replace(col.title, '%s', role.name);
+                    col.field = _.replace(col.field, '{%d}', role.order);
+                    this.spreadSetting.cols.push(col);
+                }
+            }
         }
         initSpread(roles = []) {
             this.refreshSpreadSetting(roles);
             SpreadJsObj.initSheet(this.sheet, this.spreadSetting);
         }
-        loadData(datas, roles, history) {
+        analysisCompareData(datas, roles){
+            const findHis = function (role, history) {
+                let his = null;
+                for (const h of history) {
+                    if (h.times < role.times || (h.times === role.times && h.order <= role.order)) {
+                        his = h;
+                    } else {
+                        break;
+                    }
+                }
+                return his;
+            };
+            for (const d of datas) {
+                if (!d.tree_is_leaf) continue;
+                d.cur_his.sort((x, y) => { return x.times === y.times ? x.order - y.order : x.times - y.times; });
+                for (const r of roles) {
+                    if (r.latest) {
+                        d[`qty_${r.order}`] = d.cur_qty;
+                        d[`tp_${r.order}`] = d.cur_tp;
+                    } else {
+                        const rHis = findHis(r, d.cur_his);
+                        if (rHis) {
+                            d[`qty_${r.order}`] = rHis.qty;
+                            d[`tp_${r.order}`] = rHis.tp;
+                        }
+                    }
+                }
+            }
+        }
+        loadData(datas, roles) {
             // todo 整理数据
             this.initSpread(roles);
+            this.analysisCompareData(datas, roles);
             this.tree.loadDatas(datas);
+            this.tree.setting.calcFields = roles.map(x => { return `tp_${x.order}`});
             treeCalc.calculateAll(this.tree);
             SpreadJsObj.loadSheetData(this.sheet, SpreadJsObj.DataType.Tree, this.tree);
             SpreadJsObj.loadTopAndSelect(this.sheet, this.ckBillsSpread);
@@ -62,8 +113,8 @@ $(document).ready(function() {
     const billsObj = new BillsObj();
 
     // 加载安全生产费数据
-    postData('load', { filter: 'bills;audit;history' }, function(result) {
-        billsObj.loadData(result.bills);
+    postData('load', { filter: 'billsCompare;auditFlow' }, function(result) {
+        billsObj.loadData(result.billsCompare, result.auditFlow);
     });
 
     // 导航Menu

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

@@ -74,7 +74,6 @@ const tenderListSpec = (function(){
         // 上一流程审批时间
         html.push('<td style="width: 8%">');
         if (!node.cid && node.pre_flow) {
-            if (node.name === '123456677') console.log(node.pre_flow);
             html.push(node.pre_flow.name + ' ' + moment(node.pre_flow.time).format('YYYY-MM-DD'));
         }
         html.push('</td>');

+ 8 - 5
app/service/payment_detail.js

@@ -141,7 +141,11 @@ module.exports = app => {
                     throw '新增支付审批数据失败';
                 }
                 // 初始化安全生产费
-                await this.ctx.service.paymentSafeBills.init(newDetail, transaction);
+                if (preDetail) {
+                    await this.ctx.service.paymentSafeBills.initByPre(newDetail, preDetail, transaction);
+                } else {
+                    await this.ctx.service.paymentSafeBills.init(newDetail, transaction);
+                }
 
                 // 存在上一期时,复制上一期审批流程
                 if (preDetail) {
@@ -163,11 +167,9 @@ module.exports = app => {
         async addDetail(trInfo, code, s_time) {
             switch (trInfo.type) {
                 case paymentConst.modes_value_object.form:
-                    this.addFormDetail(trInfo, code, s_time);
-                    break;
+                    return this.addFormDetail(trInfo, code, s_time);
                 case paymentConst.modes_value_object.safe:
-                    this.addSafeDetail(trInfo, code, s_time);
-                    break;
+                    return this.addSafeDetail(trInfo, code, s_time);
                 default:
                     throw '未知类型,新建失败';
             }
@@ -249,6 +251,7 @@ module.exports = app => {
             try {
                 await transaction.delete(this.ctx.service.paymentDetailAudit.tableName, { td_id: id });
                 await transaction.delete(this.ctx.service.paymentRptAudit.tableName, { td_id: id });
+                await transaction.delete(this.ctx.service.paymentSafeBills.tableName, { detail_id: id });
                 await transaction.delete(this.tableName, { id });
                 await transaction.commit();
                 return true;

+ 54 - 1
app/service/payment_detail_audit.js

@@ -91,6 +91,41 @@ module.exports = app => {
         }
 
         /**
+         * 安全生产费-审核比较专用,它用不可修改
+         * @param detail
+         * @returns {Promise<Array>}
+         */
+        async getViewFlow(detail) {
+            const result = [];
+            const user = await this.ctx.service.projectAccount.getDataById(detail.uid);
+            if (detail.status === auditConst.status.uncheck) {
+                if (detail.readOnly) return result;
+                result.push({
+                    aid: user.id, name: user.name, company: user.company, role: user.role, mobile: user.mobile, telephone: user.telephone,
+                    times: 1, order: 0, status: auditConst.status.uncheck
+                });
+            } else {
+                result.push({
+                    aid: user.id, name: user.name, company: user.company, role: user.role, mobile: user.mobile, telephone: user.telephone,
+                    times: detail.curTimes, order: 0, status: auditConst.status.uncheck, latest: detail.readOnly,
+                });
+
+                const sql = `SELECT pda.aid, pa.name, pa.company, pa.role, pa.mobile, pa.telephone, pda.times, pda.order, pda.status, pda.opinion, pda.begin_time, pda.end_time` +
+                    `  FROM ${this.tableName} pda LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON pda.aid = pa.id` +
+                    '  WHERE pda.td_id = ? AND pda.times = ?';
+                const flow = await this.db.query(sql, [detail.id, detail.curTimes]);
+                flow.forEach(x => {
+                    if (x.status === auditConst.status.checked) result.push(x);
+                    if (x.status === auditConst.status.checking && !detail.readOnly) {
+                        x.latest = true;
+                        result.push(x);
+                    }
+                });
+            }
+            return result;
+        }
+
+        /**
          * 获取 当前审核人
          *
          * @param {Number} materialId - 支付审批表单详情id
@@ -354,6 +389,10 @@ module.exports = app => {
                     await this.ctx.service.paymentRptAudit.updateSignTime(transaction, rptAudit.id);
                 }
                 await transaction.update(this.ctx.service.paymentDetail.tableName, updateDetailData);
+                // 安全生产费存储相关
+                await this.ctx.service.paymentSafeBills.auditCache(transaction, detailId, {
+                    user_id: this.ctx.detail.uid, times, order: 0,
+                });
                 // 判断用户是否有权限查看支付审批,没有则自动加入到权限中
                 const auditList = await this.getAllDataByCondition({ where: { td_id: detailId, times } });
                 const rptAuditList = await this.ctx.service.paymentRptAudit.getAllDataByCondition({ where: { td_id: detailId } });
@@ -418,6 +457,10 @@ module.exports = app => {
                     // 同步 期信息
                     updateDetailData.status = checkData.checkType;
                 }
+                // 安全生产费存储相关
+                await this.ctx.service.paymentSafeBills.auditCache(transaction, detailId, {
+                    user_id: audit.id, times: audit.times, order: audit.order,
+                });
                 await transaction.update(this.ctx.service.paymentDetail.tableName, updateDetailData);
                 await transaction.commit();
             } catch (err) {
@@ -455,7 +498,9 @@ module.exports = app => {
                 await transaction.update(this.tableName, { id: audit.id, status: checkData.checkType, opinion: checkData.opinion, end_time: time });
                 // 清空所有签名数据
                 let report_json = JSON.parse(this.ctx.detail.report_json);
-                report_json = await this.ctx.service.paymentDetail.clearAllSignatureData(report_json);
+                if (report_json) {
+                    report_json = await this.ctx.service.paymentDetail.clearAllSignatureData(report_json);
+                }
                 const detailUpdateData = {
                     id: detailId, status: checkData.checkType,
                     times: times + 1,
@@ -478,6 +523,10 @@ module.exports = app => {
                 });
                 // 拷贝新一次审核流程列表
                 await transaction.insert(this.tableName, auditors);
+                // 安全生产费存储相关
+                await this.ctx.service.paymentSafeBills.auditCache(transaction, detailId, {
+                    user_id: audit.id, times: audit.times, order: audit.order,
+                });
 
                 await transaction.commit();
             } catch (err) {
@@ -522,6 +571,10 @@ module.exports = app => {
                 await transaction.insert(this.tableName, newAuditors);
                 // 清除本人的签章
                 await this.ctx.service.paymentRptAudit.clearSignatureMsg(transaction, detailId, audit.aid);
+                // 安全生产费存储相关
+                await this.ctx.service.paymentSafeBills.auditCache(transaction, detailId, {
+                    user_id: audit.id, times: audit.times, order: audit.order,
+                });
                 await transaction.commit();
             } catch (error) {
                 await transaction.rollback();

+ 79 - 5
app/service/payment_safe_bills.js

@@ -13,13 +13,17 @@ const billsUtils = require('../lib/bills_utils');
 const SafeBillsFields = {
     textFields: ['b_code', 'name', 'unit', 'spec', 'invoice_code', 'memo'],
     calcFields: ['unit_price', 'cur_qty', 'cur_tp', 'end_qty', 'end_tp'],
-    fixedFields: ['safe_id', 'tender_id', 'pre_qty', 'pre_tp', 'cur_read_qty', 'cur_read_tp', 'cur_his_qty', 'cur_his_tp', 'add_user_id', 'add_time'],
-    treeFields: ['detail_id', 'tree_id', 'tree_pid', 'tree_level', 'tree_order', 'tree_full_path', 'tree_is_leaf'],
+    fixedFields: ['safe_id', 'tender_id', 'pre_qty', 'pre_tp', 'cur_read_qty', 'cur_read_tp', 'cur_his', 'add_user_id', 'add_time'],
+    treeFields: ['id', 'detail_id', 'tree_id', 'tree_pid', 'tree_level', 'tree_order', 'tree_full_path', 'tree_is_leaf'],
 };
+SafeBillsFields.editQueryFields = [...SafeBillsFields.treeFields, ...SafeBillsFields.textFields, ...SafeBillsFields.calcFields];
+SafeBillsFields.readQueryFields = [...SafeBillsFields.treeFields, ...SafeBillsFields.textFields, 'unit_price', 'pre_qty', 'pre_tp', 'cur_read_qty', 'cur_read_tp'];
+SafeBillsFields.compareQueryFields = [...SafeBillsFields.treeFields, ...SafeBillsFields.textFields, 'unit_price', 'cur_his', 'cur_qty', 'cur_tp'];
+SafeBillsFields.preQueryFields = [...SafeBillsFields.treeFields, ...SafeBillsFields.textFields, 'tender_id', 'unit_price', 'end_qty', 'end_tp', 'add_user_id', 'add_time', 'update_user_id', 'update_time'];
 
 module.exports = app => {
 
-    class Ledger extends app.BaseTreeService {
+    class PaymentSafeBills extends app.BaseTreeService {
 
         /**
          * 构造函数
@@ -59,6 +63,39 @@ module.exports = app => {
             data.add_user_id = this.ctx.session.sessionUser.accountId;
         }
 
+        async getEditData(detail) {
+            return await this.getAllDataByCondition({
+                where: { detail_id: detail.id },
+                columns: SafeBillsFields.editQueryFields
+            });
+        }
+
+        async getReadData(detail) {
+            const helper = this.ctx.helper;
+            const result = await this.getAllDataByCondition({
+                where: { detail_id: detail.id },
+                columns: SafeBillsFields.readQueryFields
+            });
+            result.forEach(x => {
+                x.cur_qty = x.cur_read_qty;
+                x.cur_tp = x.cur_read_tp;
+                x.end_qty = helper.add(x.pre_qty, x.cur_qty);
+                x.end_tp = helper.add(x.pre_tp, x.cur_tp);
+            });
+            return result;
+        }
+
+        async getCompareData(detail) {
+            const result = await this.getAllDataByCondition({
+                where: { detail_id: detail.id },
+                columns: SafeBillsFields.compareQueryFields
+            });
+            result.forEach(x => {
+                x.cur_his = x.cur_his ? JSON.parse(x.cur_his) : [];
+            });
+            return result;
+        }
+
         async init(detail, transaction) {
             if (!detail || !transaction) throw '安全生产费数据错误';
 
@@ -73,6 +110,27 @@ module.exports = app => {
             return operate.affectedRows === insertData.length;
         }
 
+        async initByPre(detail, preDetail, transaction) {
+            if (!detail || !preDetail || !transaction) throw '安全生产费数据错误';
+
+            const preBills = await this.getAllDataByCondition({
+                where: { detail_id: preDetail.id },
+                columns: SafeBillsFields.preQueryFields
+            });
+            const insertData = [];
+            for (const bills of preBills) {
+                //const bills = JSON.parse(JSON.stringify(b));
+                bills.id = this.uuid.v4();
+                bills.detail_id = detail.id;
+                delete bills.invoice_code;
+                bills.pre_qty = bills.end_qty;
+                bills.pre_tp = bills.end_tp;
+                insertData.push(bills);
+            }
+            const operate = await transaction.insert(this.tableName, insertData);
+            return operate.affectedRows === insertData.length;
+        }
+
         /**
          * 新增数据(供内部或其他service类调用, controller不可直接使用)
          * @param {Array|Object} data - 新增数据
@@ -426,7 +484,6 @@ module.exports = app => {
                     nData.end_qty = helper.add(nData.cur_qty, oData.pre_qty);
                     nData.end_tp = helper.add(nData.cur_tp, oData.pre_tp);
                 }
-                console.log(nData);
                 for (const field of SafeBillsFields.textFields) {
                     if (row[field] !== undefined) nData[field] = row[field];
                 }
@@ -436,7 +493,24 @@ module.exports = app => {
             await this.db.updateRows(this.tableName, updateData);
             return { update: updateData };
         }
+
+        async auditCache(transaction, detailId, auditInfo) {
+            const leaf = await this.getAllDataByCondition({ where: { detail_id: detailId, tree_is_leaf: true} });
+            const updateData = [];
+            for (const l of leaf) {
+                if (l.cur_read_qty !== l.cur_qty || l.cur_read_tp !== l.cur_tp) {
+                    const data = { id: l.id, cur_read_qty: l.cur_qty, cur_read_tp: l.cur_tp };
+                    const his = l.cur_his ? JSON.parse(l.cur_his) : [];
+                    his.push({ ...auditInfo, qty: l.cur_qty, tp: l.cur_tp });
+                    data.cur_his = JSON.stringify(his);
+                    data.cur_read_qty = l.cur_qty;
+                    data.cur_read_tp = l.cur_tp;
+                    updateData.push(data);
+                }
+            }
+            if (updateData.length > 0) await transaction.updateRows(this.tableName, updateData);
+        }
     }
 
-    return Ledger;
+    return PaymentSafeBills;
 };

+ 1 - 0
app/service/report.js

@@ -483,6 +483,7 @@ module.exports = app => {
                         Result = await fjHelper.getChangeProgressData(params.tender_id, params.stage_id);
                         break;
                     default:
+                        Result = {};
                         break;
                 }
                 for (const d in Result) {

+ 3 - 1
app/view/payment_safe/index.ejs

@@ -18,6 +18,7 @@
                         </div>
                     </div>
                 </div>
+                <% if (ctx.detail.uid === ctx.session.sessionUser.accountId) { %>
                 <div class="d-inline-block">
                     <a href="javascript: void(0);" name="base-opr" type="add" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="新增"><i class="fa fa-plus" aria-hidden="true"></i></a>
                     <a href="javascript: void(0);" name="base-opr" type="delete" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="删除"><i class="fa fa-remove" aria-hidden="true"></i></a>
@@ -26,6 +27,7 @@
                     <a href="javascript: void(0);" name="base-opr" type="down-move" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a>
                     <a href="javascript: void(0);" name="base-opr" type="up-move" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a>
                 </div>
+                <% } %>
             </div>
             <div class="ml-auto">
                 <% include ../payment/audit_btn.ejs %>
@@ -177,6 +179,6 @@
     </div>
 </div>
 <script>
-    const readOnly = false;
+    const readOnly = <%- ctx.detail.readOnly %>;
     const stdBills = JSON.parse(unescape('<%- escape(JSON.stringify(stdBills)) %>'));
 </script>