Browse Source

合同支付附件内容

laiguoran 5 years ago
parent
commit
99eb838c5e

+ 149 - 1
app/controller/stage_controller.js

@@ -519,7 +519,19 @@ module.exports = app => {
             try {
                 await this._getStageAuditViewData(ctx);
                 const renderData = await this._getDefaultRenderData(ctx);
-                renderData.dealPay = await ctx.service.stagePay.getStagePays(ctx.stage);
+                const dealPay = await ctx.service.stagePay.getStagePays(ctx.stage);
+                // 附件不取下载地址
+                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;
+                    }
+                }
+                renderData.dealPay = dealPay;
                 // if (dealPay && dealPay.length > 0) {
                 //     renderData.dealPay = dealPay;
                 // } else {
@@ -529,6 +541,7 @@ module.exports = app => {
                 // }
                 renderData.calcBase = await ctx.service.stage.getStagePayCalcBase();
                 renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.pay);
+                renderData.whiteList = this.ctx.app.config.multipart.whitelist;
 
                 // 计算 本期金额
                 const payCalculator = new PayCalculator(this.ctx, this.ctx.tender.info.decimal);
@@ -1155,6 +1168,141 @@ module.exports = app => {
             }
             ctx.body = responseData;
         }
+
+        /**
+         * 合同支付上传附件
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async payUploadFile(ctx) {
+            const responseData = {
+                err: 0,
+                msg: '',
+                data: [],
+            };
+            let stream;
+            try {
+                stream = await ctx.getFileStream();
+                const create_time = Date.parse(new Date()) / 1000;
+                const fileInfo = path.parse(stream.filename);
+                const dirName = 'app/public/upload/pay/' + moment().format('YYYYMMDD');
+                const fileName = 'pay' + create_time + fileInfo.ext;
+
+                // 判断文件夹是否存在,不存在则直接创建文件夹
+                if (!fs.existsSync(path.join(this.app.baseDir, dirName))) {
+                    await fs.mkdirSync(path.join(this.app.baseDir, dirName));
+                }
+                // 保存文件
+                await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
+                // 插入到stage_pay对应的附件列表中
+                const attData = {
+                    filename: fileInfo.name,
+                    fileext: fileInfo.ext,
+                    filesize: stream.fields.size,
+                    filepath: path.join(dirName, fileName),
+                    uid: ctx.session.sessionUser.accountId,
+                    in_time: moment(create_time * 1000).format('YYYY-MM-DD'),
+                };
+                const result = await ctx.service.stagePay.saveAtt(stream.fields.pay_id, attData);
+                if (!result) {
+                    throw '导入数据库保存失败';
+                }
+                delete attData.filepath
+                attData.username = ctx.session.sessionUser.name;
+                responseData.data = attData;
+            } catch (err) {
+                this.log(err);
+                // 失败需要消耗掉stream 以防卡死
+                if (stream) {
+                    await sendToWormhole(stream);
+                }
+                this.setMessage(err.toString(), this.messageType.ERROR);
+                responseData.err = 1;
+                responseData.msg = err.toString();
+            }
+            ctx.body = responseData;
+        }
+
+        /**
+         * 合同支付下载附件
+         * @param {Object} ctx - egg全局变量
+         * @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);
+                }
+            }
+        }
+
+        /**
+         * 合同支付删除附件
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async payDeleteFile(ctx) {
+            const responseData = {
+                err: 0,
+                msg: '',
+                data: '',
+            };
+            try {
+                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 '不存在该文件';
+                }
+
+                // 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 };
+            } catch (err) {
+                responseData.err = 1;
+                responseData.msg = err;
+            }
+
+            ctx.body = responseData;
+        }
     }
 
     return StageController;

+ 0 - 5
app/public/js/stage.js

@@ -1268,7 +1268,6 @@ $(document).ready(() => {
         postDataWithFile('/tender/' + tender.id + '/measure/stage/' + tender.ledger_times + '/upload/file', formData, function (data) {
             $('#upload').modal('hide');
             // 插入到attData中
-            console.log(data);
             attData.unshift(data);
             // 重新生成LIst
             getAllList();
@@ -1288,7 +1287,6 @@ $(document).ready(() => {
         const att = attData.find(function (item) {
             return item.id === parseInt(fid);
         });
-        console.log(att);
         $('#edit-att').hide();
         $('#show-att').show();
         if (att !== undefined) {
@@ -1299,8 +1297,6 @@ $(document).ready(() => {
             $('#show-att tr').eq(3).children('td').eq(0).text(att.username);
             $('#show-att tr').eq(3).children('td').eq(1).text(att.in_time);
             $('#show-att tr').eq(4).children('td').text(att.remark);
-            console.log(userID);
-            console.log(att.uid);
             if (parseInt(userID) === att.uid) {
                 $('#btn-att').show();
                 $('#btn-att a').eq(1).show();
@@ -1431,7 +1427,6 @@ $(document).ready(() => {
         const totalPageNum = $('#totalPage').text();
         const lastPageNum = $('#currentPage').text();
         const status = $(this).attr('content');
-        console.log(totalPageNum,lastPageNum,status);
         if (status === 'pre' && lastPageNum > 1) {
             getAllList(parseInt(lastPageNum)-1);
         } else if (status === 'next' && lastPageNum < totalPageNum) {

+ 71 - 2
app/public/js/stage_pay.js

@@ -28,6 +28,19 @@ function loadUpdateDealPays(newPay, fields) {
     }
 }
 
+function makeAttTable(id, attachment) {
+    let html = '';
+    if (attachment !== null) {
+        for (const [index, att] of attachment.entries()) {
+            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> ' +
+                '<a class="delete-att text-danger" href="javascript:void(0);" data-payid="'+ id +'" data-attindex="'+ index +'" title="删除"><i class="fa fa-remove "></i></a>' +
+                '</td></tr>';
+        }
+    }
+    $('#pay-attList').html(html);
+}
+
 $(document).ready(() => {
     autoFlashHeight();
 
@@ -55,6 +68,7 @@ $(document).ready(() => {
         pos: SpreadJsObj.getObjPos($('#pay-spread')[0]),
     };
     paySpreadSetting.imageClick = function (data) {
+        makeAttTable(data.id, data.attachment);
         $('#file').modal('show');
     };
     paySpreadSetting.getColor = function (data, col, defaultColor) {
@@ -75,7 +89,7 @@ $(document).ready(() => {
     const payCol = {
         getValue: {
             attachment: function (data) {
-                return data.attchement ? data.attachement.length : 0;
+                return data.attachment ? data.attachment.length : 0;
             },
             state: function (data) {
                 const value = [];
@@ -735,4 +749,59 @@ $(document).ready(() => {
             $('#deadline').modal('hide');
         });
     });
-});
+
+    // 上传附件
+    $('#upload-file-btn').click(function () {
+        const file = $('#upload-file')[0];
+        if (file.files[0] === undefined) {
+            toast('未选择上传文件!', 'error');
+            return false;
+        }
+        const filesize = file.files[0].size;
+        if (filesize > 10 * 1024 * 1024) {
+            toast('文件大小过大!', 'error');
+            return false;
+        }
+        const fileext = '.' + file.files[0].name.toLowerCase().split('.').splice(-1)[0];
+        if (whiteList.indexOf(fileext) === -1) {
+            toast('只能上传指定格式的附件!', 'error');
+            return false;
+        }
+        const select = SpreadJsObj.getSelectObject(paySpread.getActiveSheet());
+        const formData = new FormData();
+        formData.append('pay_id', select.id);
+        formData.append('size', filesize);
+        formData.append('file', file.files[0]);
+        postDataWithFile('/tender/' + tender.id + '/measure/stage/' + tender.ledger_times + '/pay/upload/file', formData, function (data) {
+            if (select.attachment === null) {
+                select.attachment = new Array(data);
+            } else {
+                select.attachment.unshift(data);
+            }
+            makeAttTable(select.id, select.attachment);
+            const index = dealPay.indexOf(select);
+            dealPay.splice(index, 1, select);
+            SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
+        }, function () {
+            toast('附件上传失败', 'error');
+        });
+        $('#upload-file').val('');
+    });
+
+    // 删除附件
+    $('body').on('click', '.delete-att' ,function () {
+        const id = $(this).attr('data-payid');
+        const index = $(this).attr('data-attindex');
+        const data = {
+            id,
+            index,
+        };
+        const select = SpreadJsObj.getSelectObject(paySpread.getActiveSheet());
+        postData('/tender/' + tender.id + '/measure/stage/' + tender.ledger_times + '/pay/delete/file', data, function (result) {
+            select.attachment.splice(index, 1);
+            makeAttTable(id, select.attachment);
+            dealPay.splice(index, 1, select);
+            SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
+        });
+    })
+});

+ 1 - 0
app/public/upload/pay/page.html

@@ -0,0 +1 @@
+当前页存变更令附件

+ 6 - 3
app/router.js

@@ -103,8 +103,8 @@ module.exports = app => {
     app.post('/tender/:id/ledger/revise/cancel', sessionAuth, tenderCheck, 'ledgerController.cancelRevise');
     app.post('/tender/:id/ledger/revise/save', sessionAuth, tenderCheck, 'ledgerController.saveRevise');
     app.get('/tender/:id/ledger/revise/info', sessionAuth, tenderCheck, 'ledgerController.reviseInfo');
-    //app.post('/tender/:id/ledger/revise/audit/', sessionAuth, tenderCheck, 'ledgerController.reviseStatus');
-    //app.get('/tender/:id/ledger/index', sessionAuth, 'ledgerController.index');
+    // app.post('/tender/:id/ledger/revise/audit/', sessionAuth, tenderCheck, 'ledgerController.reviseStatus');
+    // app.get('/tender/:id/ledger/index', sessionAuth, 'ledgerController.index');
 
     // 台账审批相关
     app.get('/tender/:id/ledger/audit', sessionAuth, tenderCheck, 'ledgerAuditController.index');
@@ -135,7 +135,7 @@ module.exports = app => {
     app.post('/tender/:id/measure/stage/:order/pos', sessionAuth, tenderCheck, stageCheck, 'stageController.getStagePosData');
     app.post('/tender/:id/measure/stage/:order/update', sessionAuth, tenderCheck, stageCheck, 'stageController.updateStageData');
     app.post('/tender/:id/measure/stage/:order/valid-change', sessionAuth, tenderCheck, stageCheck, 'stageController.searchValidChange');
-    app.post('/tender/:id/measure/stage/:order/use-change',sessionAuth, tenderCheck, stageCheck, 'stageController.useChange');
+    app.post('/tender/:id/measure/stage/:order/use-change', sessionAuth, tenderCheck, stageCheck, 'stageController.useChange');
     // 中间计量
     app.get('/tender/:id/measure/stage/:order/detail', sessionAuth, tenderCheck, stageCheck, 'stageController.detail');
     app.post('/tender/:id/measure/stage/:order/detail/build', sessionAuth, tenderCheck, stageCheck, 'stageController.buildDetailData');
@@ -150,6 +150,9 @@ module.exports = app => {
     app.get('/tender/:id/measure/stage/:order/pay', sessionAuth, tenderCheck, stageCheck, 'stageController.pay');
     app.post('/tender/:id/measure/stage/:order/pay/detail', sessionAuth, tenderCheck, stageCheck, 'stageController.chapterDetail');
     app.post('/tender/:id/measure/stage/:order/pay/save', sessionAuth, tenderCheck, stageCheck, 'stageController.savePayData');
+    app.post('/tender/:id/measure/stage/:order/pay/upload/file', sessionAuth, tenderCheck, stageCheck, 'stageController.payUploadFile');
+    app.get('/tender/:id/measure/stage/:order/pay/download/file/:pid/:index', sessionAuth, 'stageController.payDownloadFile');
+    app.post('/tender/:id/measure/stage/:order/pay/delete/file', sessionAuth, 'stageController.payDeleteFile');
     // 变更令
     app.get('/tender/:id/measure/stage/:order/change', sessionAuth, tenderCheck, stageCheck, 'stageController.change');
     app.post('/tender/:id/measure/stage/:order/change/detail', sessionAuth, tenderCheck, stageCheck, 'stageController.changeDetail');

+ 29 - 0
app/service/stage_pay.js

@@ -253,6 +253,35 @@ module.exports = app => {
                 stage.id, stage.curTimes, stage.curOrder];
             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;

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

@@ -52,9 +52,11 @@
 <img src="/public/images/file_clip.png" id="rela-file-icon" />
 <img src="/public/images/file_clip_hover.png" id="rela-file-hover" />
 <script>
+    const tender = JSON.parse('<%- JSON.stringify(tender) %>');
     const stage = JSON.parse('<%- JSON.stringify(ctx.stage) %>');
     const readOnly = <%- stage.readOnly %>;
     const dealPay = JSON.parse('<%- JSON.stringify(dealPay) %>');
     const calcBase = JSON.parse('<%- JSON.stringify(calcBase) %>');
     const decimal = JSON.parse('<%- JSON.stringify(ctx.tender.info.decimal) %>');
-</script>
+    const whiteList = JSON.parse('<%- JSON.stringify(whiteList) %>');
+</script>

+ 14 - 8
app/view/stage/pay_modal.ejs

@@ -77,21 +77,27 @@
             <div class="modal-body">
                 <div class="form-group">
                     <label for="formGroupExampleInput">大小限制:10MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
-                    <input type="file" class="form-control">
+                    <input type="file" class="form-control" id="upload-file">
                 </div>
-                <div class="modal-height-500">
-                    <table class="table table-sm table-bordered">
+                <div class="modal-height-500" style="overflow:auto;">
+                    <table class="table table-sm table-bordered" style="word-break:break-all; table-layout: fixed">
                         <thead>
-                        <tr><th>文件名</th><th>上传人</th><th>上传时间</th><th>操作</th></tr>
+                        <tr><th width="240">文件名</th><th>上传人</th><th>上传时间</th><th width="40">操作</th></tr>
                         </thead>
-                        <tr><td>XXXX.jpg</td><td>张三</td><td>2018-01-01</td><td><a href="#" target="_blank" title="下载"><i class="fa fa-download "></i></a> <a class="text-danger" href="#" target="_blank" title="删除"><i class="fa fa-remove "></i></a></td></tr>
-                        <tr><td>YYYY.jpg</td><td>李四</td><td>2018-01-01</td><td><a href="#" target="_blank" title="下载"><i class="fa fa-download "></i></a></td></tr>
+                        <tbody id="pay-attList">
+                        <tr>
+                            <td>XXXX.jpg</td><td>张三</td><td>2018-01-01</td><td><a href="#" target="_blank" title="下载"><i class="fa fa-download "></i></a> <a class="text-danger" href="#" target="_blank" title="删除"><i class="fa fa-remove "></i></a></td>
+                        </tr>
+                        <tr>
+                            <td>YYYY.jpg</td><td>李四</td><td>2018-01-01</td><td><a href="#" target="_blank" title="下载"><i class="fa fa-download "></i></a></td>
+                        </tr>
+                        </tbody>
                     </table>
                 </div>
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-primary" >确定</button>
+                <button type="button" class="btn btn-primary" id="upload-file-btn">确定</button>
             </div>
         </div>
     </div>
@@ -117,4 +123,4 @@
         </div>
     </div>
 </div>
-<% include ./audit_modal.ejs %>
+<% include ./audit_modal.ejs %>

+ 2 - 0
config/config.default.js

@@ -119,6 +119,8 @@ module.exports = appInfo => {
     // 压缩设置
     config.gzip = {
         threshold: 2048,
+        // 下载的url要用正则忽略
+        ignore: /(\w*)\/download\/file(\w*)/ig,
     };
 
     config.customLogger = {