浏览代码

合同支付,附件相关

MaiXinRong 3 年之前
父节点
当前提交
b6c522adb6

+ 49 - 87
app/controller/stage_controller.js

@@ -855,19 +855,14 @@ module.exports = app => {
             try {
                 await this._getStageAuditViewData(ctx);
                 const renderData = await this._getDefaultRenderData(ctx);
-                const dealPay = await ctx.service.stagePay.getStagePays(ctx.stage);
+                renderData.dealPay = await ctx.service.stagePay.getStagePays(ctx.stage);
+                const payAtt = await ctx.service.payAtt.getStageData({ sid: ctx.stage.id });
+                console.log(payAtt);
                 // 附件不取下载地址
-                for (const index in dealPay) {
-                    if (dealPay[index].attachment !== null) {
-                        const attachments = JSON.parse(dealPay[index].attachment);
-                        for (const att_index in attachments) {
-                            delete attachments[att_index].filepath;
-                            attachments[att_index].username = (await ctx.service.projectAccount.getAccountInfoById(attachments[att_index].uid)).name;
-                        }
-                        dealPay[index].attachment = attachments;
-                    }
+                for (const dp of renderData.dealPay) {
+                    dp.attachment = payAtt.filter(x => { return x.pid === dp.pid });
+                    console.log(dp.attachment);
                 }
-                renderData.dealPay = dealPay;
                 renderData.calcBase = await ctx.service.stage.getStagePayCalcBase(ctx.stage, ctx.tender.info);
                 renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.pay);
                 renderData.whiteList = this.ctx.app.config.multipart.whitelist;
@@ -879,17 +874,13 @@ module.exports = app => {
                 }
 
                 // 用户有无权限上传和删除附件
-                renderData.uploadPermission = (!(ctx.stage.readOnly || ctx.stage.revising) && ((ctx.stage.status === auditConst.status.uncheck || ctx.stage.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ctx.stage.user_id) ||
-                    (ctx.stage.status === auditConst.status.checkNoPre && ctx.session.sessionUser.accountId === ctx.stage.curAuditor.aid) ||
-                    (ctx.stage.status === auditConst.status.checking && ctx.stage.curAuditor && ctx.stage.curAuditor.aid === ctx.session.sessionUser.accountId)) ||
-                    (ctx.tender.isTourist && ctx.tender.touristPermission.file);
+                renderData.uploadPermission = !ctx.tender.isTourist || ctx.tender.touristPermission.file;
 
                 if (!ctx.stage.readOnly || ctx.tender.isTourist) {
                     // 计算 本期金额
                     const payCalculator = new PayCalculator(ctx, ctx.stage, ctx.tender.info);
                     await payCalculator.calculateAll(renderData.dealPay);
                     await this._updateStageCache(ctx, payCalculator);
-                    // renderData.calcBase = payCalculator.bases;
                 }
                 await this.layout('stage/pay.ejs', renderData, 'stage/pay_modal.ejs');
             } catch (err) {
@@ -1736,6 +1727,7 @@ module.exports = app => {
             }
 
         }
+
         /**
          * 合同支付上传附件
          * @param {Object} ctx - egg全局变量
@@ -1749,9 +1741,6 @@ module.exports = app => {
             };
             let stream;
             try {
-                // this._checkStageCanModify(ctx);
-                this._checkStageCanModifyRe(ctx);
-
                 const parts = ctx.multipart({ autoFields: true });
                 const files = [];
                 let index = 0;
@@ -1774,23 +1763,22 @@ module.exports = app => {
                     await sendToWormhole(stream);
                     // 插入到stage_pay对应的附件列表中
                     const attData = {
+                        tid: this.ctx.tender.id,
+                        sid: this.ctx.stage.id,
+                        uid: ctx.session.sessionUser.accountId,
+                        pid: parts.field.pay_id,
                         filename: fileInfo.name,
                         fileext: fileInfo.ext,
                         filesize: Array.isArray(parts.field.size) ? parts.field.size[index] : parts.field.size,
                         filepath: path.join(dirName, fileName),
-                        uid: ctx.session.sessionUser.accountId,
                         in_time: moment(create_time * 1000).format('YYYY-MM-DD'),
+                        renew: this.ctx.stage.status === auditConst.status.checked,
                     };
-                    const result = await ctx.service.stagePay.saveAtt(parts.field.pay_id, attData);
-                    if (!result) {
-                        throw '导入数据库保存失败';
-                    }
-                    delete attData.filepath;
                     attData.username = ctx.session.sessionUser.name;
                     files.length !== 0 ? files.unshift(attData) : files.push(attData);
                     ++index;
                 }
-                responseData.data = files;
+                responseData.data = await ctx.service.payAtt.addFiles(files);
             } catch (err) {
                 this.log(err);
                 // 失败需要消耗掉stream 以防卡死
@@ -1810,38 +1798,33 @@ module.exports = app => {
          * @return {void}
          */
         async payDownloadFile(ctx) {
-            const id = ctx.params.pid;
-            const index = ctx.params.index;
-            if (id && index) {
-                try {
-                    const payInfo = await ctx.service.stagePay.getDataById(id);
-                    if (payInfo !== undefined && payInfo.attachment !== null) {
-                        const fileInfo = JSON.parse(payInfo.attachment)[index];
-                        const fileName = path.join(this.app.baseDir, fileInfo.filepath);
-                        // 解决中文无法下载问题
-                        const userAgent = (ctx.request.header['user-agent'] || '').toLowerCase();
-                        let disposition = '';
-                        if (userAgent.indexOf('msie') >= 0 || userAgent.indexOf('chrome') >= 0) {
-                            disposition = 'attachment; filename=' + encodeURIComponent(fileInfo.filename + fileInfo.fileext);
-                        } else if (userAgent.indexOf('firefox') >= 0) {
-                            disposition = 'attachment; filename*="utf8\'\'' + encodeURIComponent(fileInfo.filename + fileInfo.fileext) + '"';
-                        } else {
-                            /* safari等其他非主流浏览器只能自求多福了 */
-                            disposition = 'attachment; filename=' + new Buffer(fileInfo.filename + fileInfo.fileext).toString('binary');
-                        }
-                        ctx.response.set({
-                            'Content-Type': 'application/octet-stream',
-                            'Content-Disposition': disposition,
-                            'Content-Length': fileInfo.filesize,
-                        });
-                        ctx.body = await fs.createReadStream(fileName);
-                    } else {
-                        throw '不存在该文件';
-                    }
-                } catch (err) {
-                    this.log(err);
-                    this.setMessage(err.toString(), this.messageType.ERROR);
+            const id = ctx.params.id;
+            try {
+                if (!id) throw '数据错误';
+                const fileInfo = ctx.service.payAtt.getDataById(id);
+                if (!fileInfo) throw '不存在该文件';
+
+                const fileName = path.join(this.app.baseDir, fileInfo.filepath);
+                // 解决中文无法下载问题
+                const userAgent = (ctx.request.header['user-agent'] || '').toLowerCase();
+                let disposition = '';
+                if (userAgent.indexOf('msie') >= 0 || userAgent.indexOf('chrome') >= 0) {
+                    disposition = 'attachment; filename=' + encodeURIComponent(fileInfo.filename + fileInfo.fileext);
+                } else if (userAgent.indexOf('firefox') >= 0) {
+                    disposition = 'attachment; filename*="utf8\'\'' + encodeURIComponent(fileInfo.filename + fileInfo.fileext) + '"';
+                } else {
+                    /* safari等其他非主流浏览器只能自求多福了 */
+                    disposition = 'attachment; filename=' + new Buffer(fileInfo.filename + fileInfo.fileext).toString('binary');
                 }
+                ctx.response.set({
+                    'Content-Type': 'application/octet-stream',
+                    'Content-Disposition': disposition,
+                    'Content-Length': fileInfo.filesize,
+                });
+                ctx.body = await fs.createReadStream(fileName);
+            } catch (err) {
+                this.log(err);
+                this.setMessage(err.toString(), this.messageType.ERROR);
             }
         }
 
@@ -1851,41 +1834,20 @@ module.exports = app => {
          * @return {void}
          */
         async payDeleteFile(ctx) {
-            const responseData = {
-                err: 0,
-                msg: '',
-                data: '',
-            };
             try {
-                // this._checkStageCanModify(ctx);
-                this._checkStageCanModifyRe(ctx);
-
                 const data = JSON.parse(ctx.request.body.data);
-                const payInfo = await ctx.service.stagePay.getDataById(data.id);
-                if (payInfo !== undefined) {
-                    const fileInfo = JSON.parse(payInfo.attachment)[data.index];
-                    // 先删除文件
-                    await fs.unlinkSync(path.join(this.app.baseDir, fileInfo.filepath));
-                    // 再删除数据库
-                    const attachment = JSON.parse(payInfo.attachment);
-                    attachment.splice(data.index, 1);
-                    const result = await ctx.service.stagePay.deleteAtt(data.id, attachment);
-                    responseData.data = '';
-                } else {
-                    throw '不存在该文件';
-                }
+                const fileInfo = await ctx.service.payAtt.getDataById(data.id);
+                if (!fileInfo) throw '不存在该文件';
 
-                // if (data.tid === undefined || data.uci === undefined || data.uc === undefined || data.ac === undefined) {
-                //     throw '参数有误';
-                // }
-                // const [addCompany, selectCompany] = await ctx.service.changeCompany.setCompanyList(data);
-                // responseData.data = { add: addCompany, select: selectCompany };
+                const result = await ctx.service.payAtt.delFiles(data.id);
+                if (fs.existsSync(path.join(ctx.app.baseDir, fileInfo.filepath))) {
+                    await fs.unlinkSync(path.join(ctx.app.baseDir, fileInfo.filepath));
+                }
+                ctx.body = { err: 0, msg: '', data: result };
             } catch (err) {
-                responseData.err = 1;
-                responseData.msg = err;
+                ctx.log(err);
+                ctx.ajaxErrorBody(err, '删除文件错误');
             }
-
-            ctx.body = responseData;
         }
 
 

+ 11 - 26
app/public/js/stage_pay.js

@@ -33,12 +33,12 @@ function makeAttTable(payNode) {
     const id = payNode.id, attachment = payNode.attachment;
     let html = '';
     if (attachment !== null) {
-        for (const [index, att] of attachment.entries()) {
-            const delhtml = uploadPermission && (parseInt(att.uid) === userID || payNode.uid === userID || (payNode.uid === -1 && userID === stage.user_id))
-                ? '<a class="delete-att text-danger" href="javascript:void(0);" data-payid="'+ id +'" data-attindex="'+ index +'" title="删除"><i class="fa fa-remove "></i></a>'
+        for (const att of attachment) {
+            const delhtml = uploadPermission && parseInt(att.uid) === userID && (att.renew || stage.status !== auditConst.status.checked)
+                ? '<a class="delete-att text-danger" href="javascript:void(0);" data-fileid="'+ att.id +'" title="删除"><i class="fa fa-remove "></i></a>'
                 : '';
             html += '<tr><td style="width: 200px">' + att.filename + att.fileext + '</td><td>' + att.username + '</td><td>' + att.in_time + '</td>' +
-                '<td><a href="/tender/'+ tender.id + '/measure/stage/' + tender.ledger_times +'/pay/download/file/'+ id +'/'+ index +'" title="下载"><i class="fa fa-download "></i></a> ' +
+                '<td><a href="/tender/'+ tender.id + '/measure/stage/' + tender.ledger_times +'/pay/download/file/'+ att.id +'" title="下载"><i class="fa fa-download "></i></a> ' +
                 delhtml +
                 '</td></tr>';
         }
@@ -1194,8 +1194,7 @@ $(document).ready(() => {
         const files = this.files;
         const select = SpreadJsObj.getSelectObject(paySpread.getActiveSheet());
         const formData = new FormData();
-        // const sizes = [];
-        formData.append('pay_id', select.id);
+        formData.append('pay_id', select.pid);
         for (const file of files) {
             if (file === undefined) {
                 toast('未选择上传文件!', 'error');
@@ -1211,21 +1210,13 @@ $(document).ready(() => {
                 toast('只能上传指定格式的附件!', 'error');
                 return false;
             }
-            // sizes.push(filesize);
             formData.append('size', filesize);
             formData.append('file[]', file);
         }
-        // formData.append('size', sizes.join(','));
         postDataWithFile('/tender/' + tender.id + '/measure/stage/' + stage.order + '/pay/upload/file', formData, function (data) {
-            if (select.attachment === null) {
-                select.attachment = data;
-            } else {
-                select.attachment = data.concat(select.attachment);
-            }
+            select.attachment = data;
             makeAttTable(select);
-            const index = dealPay.indexOf(select);
-            dealPay.splice(index, 1, select);
-            SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
+            SpreadJsObj.reLoadRowData(paySpread.getActiveSheet(), dealPay.indexOf(select));
         }, function () {
             toast('附件上传失败', 'error');
         });
@@ -1234,19 +1225,13 @@ $(document).ready(() => {
 
     // 删除附件
     $('body').on('click', '.delete-att' ,function () {
-        const id = $(this).attr('data-payid');
-        const index = $(this).attr('data-attindex');
-        const data = {
-            id,
-            index,
-        };
+        const id = $(this).attr('data-fileid');
+        const data = { id };
         const select = SpreadJsObj.getSelectObject(paySpread.getActiveSheet());
         postData('/tender/' + tender.id + '/measure/stage/' + stage.order + '/pay/delete/file', data, function (result) {
-            select.attachment.splice(index, 1);
+            select.attachment = result;
             makeAttTable(select);
-            const pay_index = dealPay.indexOf(select);
-            dealPay.splice(pay_index, 1, select);
-            SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
+            SpreadJsObj.reLoadRowData(paySpread.getActiveSheet(), dealPay.indexOf(select));
         });
     })
 });

+ 51 - 0
app/service/pay_att.js

@@ -0,0 +1,51 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+module.exports = app => {
+    class PayAtt extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'pay_attachment';
+        }
+
+        async getStageData(condition) {
+            const files = await this.getAllDataByCondition({
+                where: condition,
+                orders: [['id', 'desc']]
+            });
+            for (const f of files) {
+                delete f.filepath;
+            }
+            return files;
+        }
+
+        async addFiles(files) {
+            await this.db.insert(this.tableName, files);
+            return await this.getStageData({ sid: files[0].sid, pid: files[0].pid });
+        }
+
+        async delFiles(fileId) {
+            const fileInfo = await this.getDataById(fileId);
+            if (!fileInfo) throw '不存在该文件';
+            if (fileInfo.uid !== this.ctx.session.sessionUser.accountId) throw '您无权删除该文件';
+
+            await this.db.delete(this.tableName, { id: fileId });
+            return await this.getStageData({ sid: fileInfo.sid, pid: fileInfo.pid });
+        }
+    }
+
+    return PayAtt;
+};

+ 7 - 0
app/service/stage_detail_att.js

@@ -9,6 +9,8 @@
  */
 
 const ImTypeConst = require('../const/tender').imType;
+const path = require('path');
+const fs = require('fs');
 
 module.exports = app => {
     class StageDetailAtt extends app.BaseService {
@@ -120,10 +122,15 @@ module.exports = app => {
 
             const index = detailAtt.attachment.findIndex(x => { return x.file_id === fileId });
             if (index < 0) throw '不存在改文件';
+            const att = detailAtt[index];
             if (detailAtt.attachment[index].uid !== this.ctx.session.sessionUser.accountId) throw '您无权删除该文件';
 
             detailAtt.attachment.splice(index, 1);
             await this.db.update(this.tableName, { id: detailAtt.id, attachment: JSON.stringify(detailAtt.attachment) });
+
+            if (fs.existsSync(path.join(this.ctx.app.baseDir, att.filepath))) {
+                await fs.unlinkSync(path.join(this.ctx.app.baseDir, att.filepath));
+            }
             await this._complete4Output(detailAtt);
             return detailAtt;
         }

+ 4 - 33
app/service/stage_pay.js

@@ -287,9 +287,9 @@ module.exports = app => {
             if (!stage || !transaction || !times || order === undefined) {
                 throw '数据错误';
             }
-            const sql = 'INSERT INTO ?? (`tid`, `sid`, `pid`, `stimes`, `sorder`, `name`, `tp`, `expr`, `pause`, `attachment`,' +
+            const sql = 'INSERT INTO ?? (`tid`, `sid`, `pid`, `stimes`, `sorder`, `name`, `tp`, `expr`, `pause`,' +
                         '    `pre_tp`, `end_tp`, `pre_used`, `pre_finish`, `start_stage_order`) ' +
-                        '  SELECT SP.`tid`, SP.`sid`, SP.`pid`, ?, ?, SP.name, SP.`tp`, SP.`expr`, SP.`pause`, SP.`attachment`,' +
+                        '  SELECT SP.`tid`, SP.`sid`, SP.`pid`, ?, ?, SP.name, SP.`tp`, SP.`expr`, SP.`pause`,' +
                         '     SP.`pre_tp`, SP.`end_tp`, SP.`pre_used`, SP.`pre_finish`, SP.`start_stage_order` ' +
                         '  FROM ?? As SP, ?? As P ' +
                         '  WHERE SP.`sid` = ? AND SP.`stimes` = ? AND SP.`sorder` = ? And SP.`pid` = P.`id` And P.`valid`';
@@ -316,9 +316,9 @@ module.exports = app => {
          * @returns {Promise<*>}
          */
         async copyStagePays4DeleteTimes(stage, times, order, copyTimes, copyOrder, transaction) {
-            const sql = 'INSERT INTO ?? (`tid`, `sid`, `pid`, `stimes`, `sorder`, `name`, `tp`, `expr`, `pause`, `attachment`,' +
+            const sql = 'INSERT INTO ?? (`tid`, `sid`, `pid`, `stimes`, `sorder`, `name`, `tp`, `expr`, `pause`,' +
                 '    `pre_tp`, `end_tp`, `pre_used`, `pre_finish`, `start_stage_order`) ' +
-                '  SELECT SP.`tid`, SP.`sid`, SP.`pid`, ?, ?, SP.name, SP.`tp`, SP.`expr`, SP.`pause`, SP.`attachment`,' +
+                '  SELECT SP.`tid`, SP.`sid`, SP.`pid`, ?, ?, SP.name, SP.`tp`, SP.`expr`, SP.`pause`,' +
                 '     SP.`pre_tp`, SP.`end_tp`, SP.`pre_used`, SP.`pre_finish`, SP.`start_stage_order` ' +
                 '  FROM ?? As SP, ?? As P ' +
                 '  WHERE SP.`sid` = ? AND SP.`stimes` = ? AND SP.`sorder` = ? And SP.`pid` = P.`id` And P.`valid`';
@@ -326,35 +326,6 @@ module.exports = app => {
                 stage.id, copyTimes, copyOrder];
             return await transaction.query(sql, sqlParam);
         }
-
-        /**
-         * 保存附件
-         * @param data
-         * @returns {Promise<void>}
-         */
-        async saveAtt(id, att) {
-            // 获取attachment
-            const info = await this.getDataById(id);
-            let attachment = null;
-            if (info.attachment !== null && JSON.parse(info.attachment).length !== 0) {
-                attachment = JSON.parse(info.attachment);
-                attachment.unshift(att);
-            } else {
-                attachment = new Array(att);
-            }
-            const result = await this.db.update(this.tableName, { id, attachment: JSON.stringify(attachment) });
-            return result.affectedRows === 1;
-        }
-
-        /**
-         * 删除附件
-         * @param data
-         * @returns {Promise<void>}
-         */
-        async deleteAtt(id, attachment) {
-            const result = await this.db.update(this.tableName, { id, attachment: JSON.stringify(attachment) });
-            return result.affectedRows === 1;
-        }
     }
 
     return StagePay;

+ 1 - 0
app/view/stage/pay.ejs

@@ -68,4 +68,5 @@
     const preContractTp = <%- (pre.contract_tp || 0) %>;
     const preQcTp = <%- (pre.qc_tp || 0) %>;
     const preGatherTp = <%- (pre.gather_tp || 0) %>;
+    const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
 </script>

+ 67 - 0
db_script/pay_att.js

@@ -0,0 +1,67 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+const audit = require('../app/const/audit');
+
+const mysql = require('mysql');
+const config = process.argv[2];
+console.log(config);
+const mysqlOptions = require(`../config/config.${config}`)({ baseDir: __dirname + '/app', root: __dirname, name: 'calc' }).mysql;
+
+console.log(mysqlOptions);
+const pool = mysql.createPool(mysqlOptions.client);
+
+const querySql = async function (sql, sqlParam) {
+    return new Promise(function (resolve, reject) {
+        pool.getConnection(function (err, conn) {
+            if (err) {
+                reject(err);
+            } else {
+                conn.query(sql, sqlParam, function (err, rows, fields) {
+                    //释放连接
+                    conn.release();
+                    //传递Promise回调对象
+                    resolve({"err": err, "rows": rows, "fields": fields});
+                });
+            }
+        });
+    });
+};
+
+const doComplete = async function () {
+    try {
+        const tenders = await querySql('Select * From zh_tender where ledger_status = ?', [audit.ledger.status.checked]);
+        for (const t of tenders.rows) {
+            const stages = await querySql('Select * From zh_stage where tid = ?', [t.id]);
+            for (const s of stages.rows) {
+                console.log('处理标段: ' + t.name + ' 期: ' + s.order);
+                const auditors = await querySql('Select * From zh_stage_audit where sid = ? and times = ? order by `order`', [s.id, s.times ? s.times : 1]);
+                const curAuditor = auditors.rows.find(x => { return x.status === audit.stage.status.checking});
+                const order = curAuditor ? curAuditor.order : (auditors.rows.length > 0 ? auditors.rows.length : 0);
+                const latestStagePay = await querySql('Select * From zh_stage_pay where sid = ? and stimes = ? and sorder = ?', [s.id, s.times ? s.times : 1, order]);
+                const insertData = [];
+                for (const lsp of latestStagePay.rows) {
+                    if (!lsp.attachment) continue;
+
+                    const attachment = JSON.parse(lsp.attachment);
+                    for (const a of attachment) {
+                        insertData.unshift([t.id, s.id, lsp.pid, a.uid, a.filename, a.fileext, a.filesize, a.filepath, a.in_time, a.username || '']);
+                    }
+                }
+                const result = await querySql('Insert Into zh_pay_attachment (tid, sid, pid, uid, filename, fileext, filesize, filepath, in_time, username ) Values ?', [insertData]);
+            }
+        }
+        await querySql("Update zh_pay_attachment att Left Join zh_project_account acc On att.uid = acc.id Set att.username = acc.name Where att.username = ''");
+        pool.end();
+    } catch(err) {
+        console.log(err);
+    }
+};
+
+doComplete();