Browse Source

还原附件上传代码

MaiXinRong 4 years ago
parent
commit
aa8271920a

+ 18 - 19
app/controller/advance_controller.js

@@ -2,6 +2,7 @@
 const accountGroup = require('../const/account_group').group;
 const auditConst = require('../const/audit').advance;
 const shenpiConst = require('../const/shenpi');
+const sendToWormhole = require('stream-wormhole');
 const path = require('path');
 const fs = require('fs');
 module.exports = app => {
@@ -365,33 +366,30 @@ module.exports = app => {
             let stream;
             try {
                 // this._checkAdvanceFileCanModify(ctx);
-
+                const parts = this.ctx.multipart({
+                    autoFields: true,
+                });
                 const files = [];
-                let idx = 0;
                 const create_time = Date.parse(new Date()) / 1000;
+                let idx = 0;
                 const extra_upload = ctx.advance.status === auditConst.status.checked;
-                for (const file of ctx.request.files) {
-                    // 如果没有传入直接返回
-                    if (!file.filename) return;
-                    try {
-                        const fileInfo = path.parse(file.filename);
-                        const filepath = `public/upload/${this.ctx.tender.id.toString()}/yfk/fujian_${create_time + idx.toString() + fileInfo.ext}`;
-                        await this.ctx.helper.recursiveMkdirSync(path.dirname(path.join(this.app.baseDir, 'app', filepath)));
-                        await fs.copyFileSync(file.filepath, path.resolve(this.app.baseDir, 'app', filepath));
-                        files.push({
-                            filepath, name: file.filename, ext: fileInfo.ext
-                        });
-                    } finally {
-                        await fs.unlinkSync(file.filepath);
+                while ((stream = await parts()) !== undefined) {
+                    if (!stream.filename) {
+                        // 如果没有传入直接返回
+                        return;
                     }
+                    const fileInfo = path.parse(stream.filename);
+                    const filepath = `public/upload/${this.ctx.tender.id.toString()}/yfk/fujian_${create_time + idx.toString() + fileInfo.ext}`;
+                    await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, 'app', filepath));
+                    files.push({ filepath, name: stream.filename, ext: fileInfo.ext });
                     ++idx;
+                    stream && (await sendToWormhole(stream));
                 }
-
                 const in_time = new Date();
                 const payload = files.map(file => {
                     let idx;
-                    if (Array.isArray(ctx.request.body.name)) {
-                        idx = ctx.request.body.name.findIndex(name => name === file.name);
+                    if (Array.isArray(parts.field.name)) {
+                        idx = parts.field.name.findIndex(name => name === file.name);
                     } else {
                         idx = 'isString';
                     }
@@ -401,7 +399,7 @@ module.exports = app => {
                         tid: ctx.tender.id,
                         create_time: in_time,
                         filepath: file.filepath,
-                        filesize: ctx.helper.bytesToSize(idx === 'isString' ? ctx.request.body.size : ctx.request.body.size[idx]),
+                        filesize: ctx.helper.bytesToSize(idx === 'isString' ? parts.field.size : parts.field.size[idx]),
                         filename: file.name,
                         fileext: file.ext,
                         extra_upload,
@@ -414,6 +412,7 @@ module.exports = app => {
                 const data = await ctx.service.advanceFile.getAdvanceFiles({ vid: ctx.advance.id });
                 ctx.body = { err: 0, msg: '', data };
             } catch (err) {
+                stream && (await sendToWormhole(stream));
                 this.log(err);
                 ctx.body = { err: 1, msg: err.toString(), data: null };
             }

+ 53 - 34
app/controller/change_controller.js

@@ -9,6 +9,7 @@
  */
 
 const moment = require('moment');
+const sendToWormhole = require('stream-wormhole');
 const fs = require('fs');
 const path = require('path');
 const audit = require('../const/audit');
@@ -988,48 +989,66 @@ module.exports = app => {
          * @return {void}
          */
         async uploadFile(ctx) {
-            const responseData = { err: 0, msg: '', data: [], };
+            const responseData = {
+                err: 0,
+                msg: '',
+                data: [],
+            };
+            let stream;
             try {
-                const change = await ctx.service.change.getDataByCondition({ cid: ctx.params.cid });
-                const extra_upload = change.status === audit.flow.status.checked;
+                const parts = ctx.multipart({ autoFields: true });
                 const files = [];
-
                 let index = 0;
-                for (const file of ctx.request.files) {
-                    if (!file.filename) throw '请选择上传的文件!';
-                    try {
-                        const fileInfo = path.parse(file.filename);
-                        const create_time = Date.parse(new Date()) / 1000;
-                        const filepath = `app/public/upload/change/fujian_${create_time + index.toString() + fileInfo.ext}`;
-
-                        await this.ctx.helper.recursiveMkdirSync(path.dirname(path.resolve(this.app.baseDir, filepath)));
-                        await fs.copyFileSync(file.filepath, path.resolve(this.app.baseDir, filepath));
-
-                        const fileData = {
-                            in_time: create_time,
-                            filename: fileInfo.name,
-                            fileext: fileInfo.ext,
-                            filesize: Array.isArray(ctx.request.body.size) ? ctx.request.body.size[index] : ctx.request.body.size,
-                            uid: ctx.session.sessionUser.accountId,
-                            filepath,
-                            extra_upload
-                        };
-                        const result = await ctx.service.changeAtt.save(ctx.request.body, fileData, ctx.session.sessionUser.accountId);
-                        if (!result) {
-                            throw '导入数据库保存失败';
-                        }
-                        fileData.uid = ctx.session.sessionUser.accountId;
-                        fileData.id = result.insertId;
-                        delete fileData.filepath;
-                        files.push(fileData);
-                        ++index;
-                    } finally {
-                        await fs.unlinkSync(file.filepath);
+                const change = await ctx.service.change.getDataByCondition({ cid: ctx.params.cid });
+                const extra_upload = change.status === audit.flow.status.checked;
+                while ((stream = await parts()) !== undefined) {
+                    // 判断用户是否选择上传文件
+                    if (!stream.filename) {
+                        throw '请选择上传的文件!';
+                    }
+                    // const create_time = Date.parse(new Date()) / 1000;
+                    // const fileInfo = path.parse(stream.filename);
+                    // const dirName = 'app/public/upload/changes/' + moment().format('YYYYMMDD');
+                    // const fileName = 'changes' + create_time + '_' + index + 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));
+                    const fileInfo = path.parse(stream.filename);
+                    const create_time = Date.parse(new Date()) / 1000;
+                    const filepath = `app/public/upload/change/fujian_${create_time + index.toString() + fileInfo.ext}`;
+                    await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, filepath));
+                    await sendToWormhole(stream);
+                    // 保存数据到att表
+                    const fileData = {
+                        in_time: create_time,
+                        filename: fileInfo.name,
+                        fileext: fileInfo.ext,
+                        filesize: Array.isArray(parts.field.size) ? parts.field.size[index] : parts.field.size,
+                        filepath,
+                        extra_upload,
+                    };
+                    const result = await ctx.service.changeAtt.save(parts.field, fileData, ctx.session.sessionUser.accountId);
+                    if (!result) {
+                        throw '导入数据库保存失败';
                     }
+                    // fileData.in_time = moment(create_time * 1000).format('YYYY-MM-DD');
+                    // fileData.filesize = await ctx.helper.bytesToSize(fileData.filesize);
+                    fileData.uid = ctx.session.sessionUser.accountId;
+                    fileData.id = result.insertId;
+                    delete fileData.filepath;
+                    files.push(fileData);
+                    ++index;
                 }
                 responseData.data = files;
             } catch (err) {
                 this.log(err);
+                // 失败需要消耗掉stream 以防卡死
+                if (stream) {
+                    await sendToWormhole(stream);
+                }
                 this.setMessage(err.toString(), this.messageType.ERROR);
             }
             ctx.body = responseData;

+ 9 - 8
app/controller/deal_bills_controller.js

@@ -12,6 +12,7 @@ const fs = require('fs');
 const path = require('path');
 const excel = require('node-xlsx');
 const xlsx = require('js-xlsx');
+const sendToWormhole = require('stream-wormhole');
 const loadExcelType = {
     display: 1,
     actual: 2,
@@ -72,19 +73,15 @@ module.exports = app => {
          * @return {Promise<void>}
          */
         async loadExcel(ctx) {
+            let stream;
             try {
                 await this.checkPermisision(ctx);
-
-                const file = ctx.request.files[0];
+                stream = await ctx.getFileStream();
                 const create_time = Date.parse(new Date()) / 1000;
-                const fileInfo = path.parse(file.filename);
+                const fileInfo = path.parse(stream.filename);
                 const fileName = this.app.config.filePath + '/cache/deal_bills/uploads/' + 'deal_bills' + create_time + fileInfo.ext;
                 // 保存文件
-                try {
-                    await ctx.helper.copyFileSync(file.filepath, fileName);
-                } finally {
-                    await fs.unlinkSync(file.filepath);
-                }
+                await ctx.helper.saveStreamFile(stream, fileName);
                 if (loadType === loadExcelType.display) {
                     const wb = xlsx.readFile(fileName);
                     const name = wb.SheetNames[0];
@@ -115,6 +112,10 @@ module.exports = app => {
                 ctx.body = {err: 0, msg: '', data: dealBills};
             } catch (err) {
                 this.log(err);
+                // 失败需要消耗掉stream 以防卡死
+                if (stream) {
+                    await sendToWormhole(stream);
+                }
                 this.ajaxErrorBody(err, '导入数据失败');
             }
         }

+ 45 - 0
app/controller/ledger_controller.js

@@ -553,6 +553,51 @@ module.exports = app => {
                 ctx.body = { err: 1, msg: err.toString(), data: null };
             }
         }
+        // async uploadExcel(ctx) {
+        //     let stream;
+        //     try {
+        //         const responseData = { err: 0, msg: '', data: {}, };
+
+        //         // 保存文件
+        //         stream = await ctx.getFileStream();
+        //         const create_time = Date.parse(new Date());
+        //         const fileInfo = path.parse(stream.filename);
+        //         const fileName = this.app.config.filePath + '/cache/ledger/uploads/' + create_time + fileInfo.ext;
+        //         await ctx.helper.saveStreamFile(stream, fileName);
+
+        //         // 读取excel
+        //         console.log(ctx.query);
+        //         const name = ctx.query.sheetName;
+        //         if (!name) throw '未选择需要导入的工作簿';
+        //         const wb = xlsx.readFile(fileName);
+        //         const sheetData = {
+        //             rows: xlsx.utils.sheet_to_json(wb.Sheets[name], {header: 1}),
+        //             merge: wb.Sheets[name]["!merges"],
+        //         };
+        //         if (!sheetData.rows) throw '读取工作簿数据错误';
+
+        //         const ueType = ctx.query.ueType;
+        //         switch (ueType) {
+        //             case 'tz':
+        //                 const templateId = await this.ctx.service.valuation.getValuationTemplate(
+        //                     this.ctx.tender.data.valuation, this.ctx.tender.data.measure_type);
+        //                 responseData.data = await ctx.service.ledger.importExcel(templateId, sheetData);
+        //                 break;
+        //             case 'gcl2xmj':
+        //                 responseData.data = await ctx.service.ledger.importGclExcel(ctx.tender.id, sheetData);
+        //                 break;
+        //             default:
+        //                 throw '数据错误';
+        //         }
+        //         ctx.body = responseData;
+        //     } catch (err) {
+        //         console.log(err);
+        //         this.log(err);
+        //         // 失败需要消耗掉stream 以防卡死
+        //         if (stream) await sendToWormhole(stream);
+        //         ctx.body = {err: 1, msg: err.toString(), data: null};
+        //     }
+        // }
 
         /**
          * 填设计量(Ajax)

+ 19 - 19
app/controller/material_controller.js

@@ -17,6 +17,7 @@ const accountGroup = require('../const/account_group').group;
 const materialConst = require('../const/material');
 const shenpiConst = require('../const/shenpi');
 const MaterialCalculator = require('../lib/material_calc');
+const sendToWormhole = require('stream-wormhole');
 const fs = require('fs');
 const path = require('path');
 const _ = require('lodash');
@@ -867,35 +868,33 @@ module.exports = app => {
          * @param {*} ctx 上下文
          */
         async upload(ctx) {
+            let stream;
             try {
                 await this._checkMaterialFileCanModify(ctx);
-
+                const parts = this.ctx.multipart({
+                    autoFields: true,
+                });
                 const files = [];
-                let idx = 0;
                 const create_time = Date.parse(new Date()) / 1000;
+                let idx = 0;
                 const extra_upload = ctx.material.status === auditConst.status.checked;
-                for (const file of ctx.request.files) {
-                    // 如果没有传入直接返回
-                    if (!file.filename) return;
-                    try {
-                        const fileInfo = path.parse(file.filename);
-                        const filepath = `public/upload/${this.ctx.tender.id.toString()}/tc/fujian_${create_time + idx.toString() + fileInfo.ext}`;
-                        await this.ctx.helper.recursiveMkdirSync(path.dirname(path.join(this.app.baseDir, 'app', filepath)));
-                        await fs.copyFileSync(file.filepath, path.resolve(this.app.baseDir, 'app', filepath));
-                        files.push({
-                            filepath, name: file.filename, ext: fileInfo.ext
-                        });
-                    } finally {
-                        await fs.unlinkSync(file.filepath);
+                while ((stream = await parts()) !== undefined) {
+                    if (!stream.filename) {
+                        // 如果没有传入直接返回
+                        return;
                     }
+                    const fileInfo = path.parse(stream.filename);
+                    // const filepath = path.join('public/upload', this.ctx.tender.id.toString(), 'tc', 'fujian_' + create_time + fileInfo.ext);
+                    const filepath = `public/upload/${this.ctx.tender.id.toString()}/tc/fujian_${create_time + idx.toString() + fileInfo.ext}`;
+                    await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, 'app', filepath));
+                    files.push({ filepath, name: stream.filename, ext: fileInfo.ext });
                     ++idx;
                 }
-
                 const upload_time = this.ctx.helper.dateTran(new Date());
                 const payload = files.map(file => {
                     let idx;
-                    if (Array.isArray(ctx.request.body.name)) {
-                        idx = ctx.request.body.name.findIndex(name => name === file.name);
+                    if (Array.isArray(parts.field.name)) {
+                        idx = parts.field.name.findIndex(name => name === file.name);
                     } else {
                         idx = 'isString';
                     }
@@ -906,7 +905,7 @@ module.exports = app => {
                         s_order: ctx.params.order,
                         upload_time,
                         filepath: file.filepath,
-                        file_size: ctx.helper.bytesToSize(idx === 'isString' ? ctx.request.body.size : ctx.request.body.size[idx]),
+                        file_size: ctx.helper.bytesToSize(idx === 'isString' ? parts.field.size : parts.field.size[idx]),
                         file_name: file.name,
                         fileext: file.ext,
                         extra_upload,
@@ -919,6 +918,7 @@ module.exports = app => {
                 const data = await ctx.service.materialFile.getAllMaterialFiles(ctx.tender.id);
                 ctx.body = { err: 0, msg: '', data };
             } catch (err) {
+                stream && (await sendToWormhole(stream));
                 this.log(err);
                 ctx.body = { err: 1, msg: err.toString(), data: null };
             }

+ 5 - 8
app/controller/profile_controller.js

@@ -13,8 +13,8 @@ const profileMenu = require('../../config/menu').profileMenu;
 const smsTypeConst = require('../const/sms_type');
 const qr = require('qr-image');
 const path = require('path');
+const sendToWormhole = require('stream-wormhole');
 const loginWay = require('../const/setting').loginWay;
-const fs = require('fs');
 
 module.exports = app => {
 
@@ -322,16 +322,13 @@ module.exports = app => {
                 err: 0, msg: '', data: null,
             };
             try {
+                const stream = await ctx.getFileStream();
                 const create_time = Date.parse(new Date()) / 1000;
-                const file = ctx.request.files[0];
-                const fileInfo = path.parse(file.filename);
+                const fileInfo = path.parse(stream.filename);
                 const dirName = 'public/upload/sign';
                 const fileName = moment().format('YYYYMMDD') + '_sign_' + create_time + fileInfo.ext;
-                try {
-                    await ctx.helper.copyFileSync(file.filepath, path.join(this.app.baseDir, 'app', dirName, fileName));
-                } finally {
-                    await fs.unlinkSync(file.filepath);
-                }
+                await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, 'app', dirName, fileName));
+                await sendToWormhole(stream);
                 const result = await ctx.service.projectAccount.update({ sign_path: fileName }, { id: ctx.session.sessionUser.accountId });
                 if (result) {
                     responseData.data = { sign_path: fileName };

+ 4 - 6
app/controller/sign_controller.js

@@ -9,6 +9,7 @@
  */
 const moment = require('moment');
 const path = require('path');
+const sendToWormhole = require('stream-wormhole');
 const fs = require('fs');
 
 module.exports = app => {
@@ -48,15 +49,12 @@ module.exports = app => {
          */
         async save(ctx) {
             try {
-                const file = ctx.request.files[0];
+                const stream = await ctx.getFileStream({ requireFile: false });
                 const create_time = Date.parse(new Date()) / 1000;
                 const dirName = 'app/public/upload/sign/';
                 const fileName = moment().format('YYYYMMDD') + '_sign_' + create_time + '.png';
-                try {
-                    await ctx.helper.copyFileSync(file.filepath, path.join(this.app.baseDir, dirName, fileName));
-                } finally {
-                    await fs.unlinkSync(file.filepath);
-                }
+                await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
+                await sendToWormhole(stream);
 
                 const result = await ctx.service.projectAccount.update({ sign_path: fileName }, { id: stream.fields.id });
                 if (result) {

+ 115 - 78
app/controller/stage_controller.js

@@ -21,6 +21,7 @@ const measureType = tenderConst.measureType;
 const path = require('path');
 const PayCalculator = require('../lib/pay_calc');
 const accountGroup = require('../const/account_group').group;
+const sendToWormhole = require('stream-wormhole');
 const billsPosConvert = require('../lib/bills_pos_convert');
 const fs = require('fs');
 const stdConst = require('../const/standard');
@@ -668,16 +669,12 @@ module.exports = app => {
             try {
                 this._checkStageCanModify(ctx);
 
-                const file = ctx.request.files[0];
-                try {
-                    const create_time = Date.parse(new Date()) / 1000;
-                    const fileInfo = path.parse(file.filename);
-                    const fileName = path.join('public/upload', this.ctx.tender.id.toString(), 'im', 'calcImg_' + create_time + fileInfo.ext);
-                    await ctx.helper.copyFileSync(file.filepath, path.join(this.app.baseDir, 'app', fileName));
-                    ctx.body = { err: 0, msg: '', data: fileName };
-                } finally {
-                    await fs.unlinkSync(file.filepath);
-                }
+                const stream = await ctx.getFileStream();
+                const create_time = Date.parse(new Date()) / 1000;
+                const fileInfo = path.parse(stream.filename);
+                const fileName = path.join('public/upload', this.ctx.tender.id.toString(), 'im', 'calcImg_' + create_time + fileInfo.ext);
+                await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, 'app', fileName));
+                ctx.body = { err: 0, msg: '', data: fileName };
             } catch (err) {
                 this.log(err);
                 ctx.body = { err: 1, msg: err.toString(), data: null };
@@ -1319,46 +1316,68 @@ module.exports = app => {
                 msg: '',
                 data: [],
             };
+            let stream;
             try {
                 // this._checkStageCanModifyRe(ctx);
 
-                let index = 0;
+                const parts = ctx.multipart({ autoFields: true });
                 const files = [];
+                let index = 0;
                 const extra_upload = ctx.stage.status === auditConst.status.checked;
-                for (const file of ctx.request.files) {
-                    if (!file.filename) throw '请选择上传的文件!';
-                    try {
-                        const fileInfo = path.parse(file.filename);
-                        const create_time = Date.parse(new Date()) / 1000;
-                        const filepath = `app/public/upload/${this.ctx.tender.id}/stage/fujian_${create_time + index.toString() + fileInfo.ext}`;
-                        await this.ctx.helper.recursiveMkdirSync(path.dirname(path.join(this.app.baseDir, filepath)));
-                        await fs.copyFileSync(file.filepath, path.resolve(this.app.baseDir, filepath));
-
-                        const fileData = {
-                            tid: ctx.params.id,
-                            sid: ctx.params.order,
-                            in_time: create_time,
-                            filename: fileInfo.name,
-                            fileext: fileInfo.ext,
-                            filesize: Array.isArray(ctx.request.body.size) ? ctx.request.body.size[index] : ctx.request.body.size,
-                            filepath,
-                            extra_upload,
-                        };
-                        const result = await ctx.service.stageAtt.save(ctx.request.body, fileData, ctx.session.sessionUser.accountId);
-                        if (!result) {
-                            throw '导入数据库保存失败';
-                        }
-                        const attData = await ctx.service.stageAtt.getDataByFid(result.insertId);
-                        attData.in_time = moment(create_time * 1000).format('YYYY-MM-DD');
-                        files.length !== 0 ? files.unshift(attData) : files.push(attData);
-                        ++index;
-                    } finally {
-                        await fs.unlinkSync(file.filepath);
+                while ((stream = await parts()) !== undefined) {
+                    // 判断用户是否选择上传文件
+                    if (!stream.filename) {
+                        throw '请选择上传的文件!';
+                    }
+                    // const dirName = 'app/public/upload/stage/' + moment().format('YYYYMMDD');
+                    // 判断文件夹是否存在,不存在则直接创建文件夹
+                    // if (!fs.existsSync(path.join(this.app.baseDir, dirName))) {
+                    //     await fs.mkdirSync(path.join(this.app.baseDir, dirName));
+                    // }
+                    const fileInfo = path.parse(stream.filename);
+                    const create_time = Date.parse(new Date()) / 1000;
+                    const filepath = `app/public/upload/${this.ctx.tender.id}/stage/fujian_${create_time + index.toString() + fileInfo.ext}`;
+                    await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, filepath));
+                    // console.log(await fs.existsSync(path.resolve(this.app.baseDir, 'app', filepath)));
+                    // const fileInfo = path.parse(stream.filename);
+                    // const fileName = 'stage' + create_time + '_' + index + fileInfo.ext;
+                    // 保存文件
+                    // await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, dirName, fileName));
+
+                    if (stream) {
+                        await sendToWormhole(stream);
+                    }
+
+                    // 保存数据到att表
+                    const fileData = {
+                        tid: ctx.params.id,
+                        sid: ctx.params.order,
+                        in_time: create_time,
+                        filename: fileInfo.name,
+                        fileext: fileInfo.ext,
+                        filesize: Array.isArray(parts.field.size) ? parts.field.size[index] : parts.field.size,
+                        filepath,
+                        extra_upload,
+                    };
+                    // if (ctx.reUploadPermission) {
+                    //     fileData.re_upload = 1;
+                    // }
+                    const result = await ctx.service.stageAtt.save(parts.field, fileData, ctx.session.sessionUser.accountId);
+                    if (!result) {
+                        throw '导入数据库保存失败';
                     }
+                    const attData = await ctx.service.stageAtt.getDataByFid(result.insertId);
+                    attData.in_time = moment(create_time * 1000).format('YYYY-MM-DD');
+                    files.length !== 0 ? files.unshift(attData) : files.push(attData);
+                    ++index;
                 }
                 responseData.data = files;
             } 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();
@@ -1492,34 +1511,42 @@ module.exports = app => {
                 msg: '',
                 data: [],
             };
+            let stream;
             try {
-                //this._checkStageCanModifyRe(ctx);
-
-                const file = ctx.request.files[0];
+                this._checkStageCanModifyRe(ctx);
+                stream = await ctx.getFileStream({ requireFile: false });
                 let fileData = {};
-                if (file && file.filename !== undefined) {
+                if (stream.filename !== undefined) {
                     const create_time = Date.parse(new Date()) / 1000;
-                    const fileInfo = path.parse(file.filename);
+                    const fileInfo = path.parse(stream.filename);
                     const dirName = 'app/public/upload/stage/' + moment().format('YYYYMMDD');
                     const fileName = 'stage' + 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.copyFileSync(file.filepath, path.join(this.app.baseDir, dirName, fileName));
+                    await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
                     // 保存数据到att表
                     fileData = {
-                        filesize: ctx.request.body.size,
+                        filesize: stream.fields.size,
                         filepath: path.join(dirName, fileName),
                     };
                 }
-                const result = await ctx.service.stageAtt.updateByID(ctx.request.body, fileData);
+                const result = await ctx.service.stageAtt.updateByID(stream.fields, fileData);
                 if (!result) {
                     throw '导入数据库保存失败';
                 }
-                const attData = await ctx.service.stageAtt.getDataByFid(ctx.request.body.id);
+                const attData = await ctx.service.stageAtt.getDataByFid(stream.fields.id);
                 attData.in_time = moment(attData.in_time * 1000).format('YYYY-MM-DD');
                 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();
@@ -1578,45 +1605,55 @@ module.exports = app => {
                 msg: '',
                 data: [],
             };
+            let stream;
             try {
                 this._checkStageCanModify(ctx);
 
-                let index = 0;
+                const parts = ctx.multipart({ autoFields: true });
                 const files = [];
+                let index = 0;
                 const create_time = Date.parse(new Date()) / 1000;
-                for (const file of ctx.request.files) {
-                    if (!file.filename) throw '请选择上传的文件!';
-                    try {
-                        const fileInfo = path.parse(file.filename);
-                        const dirName = 'app/public/upload/pay/' + moment().format('YYYYMMDD');
-                        const fileName = 'pay' + create_time + '_' + index + fileInfo.ext;
-
-                        await this.ctx.helper.recursiveMkdirSync(path.join(this.app.baseDir, dirName));
-                        await fs.copyFileSync(file.filepath, path.resolve(this.app.baseDir, dirName, fileName));
-
-                        const attData = {
-                            filename: fileInfo.name,
-                            fileext: fileInfo.ext,
-                            filesize: Array.isArray(ctx.request.body.size) ? ctx.request.body.size[index] : ctx.request.body.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(ctx.request.body.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;
-                    } finally {
-                        await fs.unlinkSync(file.filepath);
+                while ((stream = await parts()) !== undefined) {
+                    // 判断用户是否选择上传文件
+                    if (!stream.filename) {
+                        throw '请选择上传的文件!';
                     }
+                    const fileInfo = path.parse(stream.filename);
+                    const dirName = 'app/public/upload/pay/' + moment().format('YYYYMMDD');
+                    const fileName = 'pay' + create_time + '_' + index + 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));
+                    await sendToWormhole(stream);
+                    // 插入到stage_pay对应的附件列表中
+                    const attData = {
+                        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'),
+                    };
+                    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;
             } 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();

+ 31 - 22
app/controller/stage_extra_controller.js

@@ -8,6 +8,7 @@
  * @version
  */
 const auditConst = require('../const/audit').stage;
+const sendToWormhole = require('stream-wormhole');
 const path = require('path');
 const moment = require('moment');
 const fs = require('fs');
@@ -197,33 +198,37 @@ module.exports = app => {
         }
 
         async uploadFile(ctx) {
+            let stream;
             try {
-                const bonus = await ctx.service.stageBonus.getStageDataById(ctx.request.body.bonus_id);
-                if (!bonus || bonus.sid !== ctx.stage.id) throw '该奖罚金,当前不允许上传附件';
+                const parts = ctx.multipart({ autoFields: true });
+                let index = 0;
                 const create_time = Date.parse(new Date()) / 1000;
+                let bonus;
+                while ((stream = await parts()) !== undefined) {
+                    if (!stream.filename) {
+                        throw '未发现上传文件!';
+                    }
+                    if (!bonus) bonus = await ctx.service.stageBonus.getStageDataById(parts.field.bonus_id);
+                    if (!bonus || bonus.sid !== ctx.stage.id) throw '该奖罚金,当前不允许上传附件';
 
-                let index = 0;
-                for (const file of ctx.request.files) {
-                    try {
-                        const fileInfo = path.parse(file.filename);
-                        const dirName = 'app/public/upload/extra/' + moment().format('YYYYMMDD');
-                        const fileName = create_time + '_' + index + fileInfo.ext;
+                    const fileInfo = path.parse(stream.filename);
+                    const dirName = 'app/public/upload/extra/' + moment().format('YYYYMMDD');
+                    const fileName = create_time + '_' + index + fileInfo.ext;
 
-                        await this.ctx.helper.recursiveMkdirSync(path.join(this.app.baseDir, dirName));
-                        await fs.copyFileSync(file.filepath, path.join(this.app.baseDir, dirName, fileName));
+                    // 保存文件
+                    await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
+                    await sendToWormhole(stream);
 
-                        bonus.proof_file.push({
-                            filename: fileInfo.name,
-                            fileext: fileInfo.ext,
-                            filesize: Array.isArray(ctx.request.body.size) ? ctx.request.body.size[index] : ctx.request.body.size,
-                            filepath: path.join(dirName, fileName),
-                            uid: ctx.session.sessionUser.accountId,
-                            in_time: moment(create_time * 1000).format('YYYY-MM-DD'),
-                        });
-                        ++index;
-                    } finally {
-                        await fs.unlinkSync(file.filepath);
-                    }
+                    // 插入到stage_pay对应的附件列表中
+                    bonus.proof_file.push({
+                        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'),
+                    });
+                    ++index;
                 }
                 const result = await ctx.service.stageBonus.updateDatas({
                     update: [
@@ -237,6 +242,10 @@ module.exports = app => {
                 ctx.body = {err: 0, msg: '', data: bonus.proof_file};
             } catch (error) {
                 ctx.helper.log(error);
+                // 失败需要消耗掉stream 以防卡死
+                if (stream) {
+                    await sendToWormhole(stream);
+                }
                 ctx.body = this.ajaxErrorBody(error, '上传附件失败,请重试');
             }
         }

+ 11 - 12
app/controller/tender_controller.js

@@ -19,7 +19,7 @@ const accountPermission = require('../const/account_permission');
 const measureType = require('../const/tender').measureType;
 const billsPosConvert = require('../lib/bills_pos_convert');
 const path = require('path');
-const fs = require('fs');
+const sendToWormhole = require('stream-wormhole');
 
 module.exports = app => {
 
@@ -911,18 +911,17 @@ module.exports = app => {
          */
         async saveCooperateSign(ctx) {
             try {
+                const stream = await ctx.getFileStream();
                 const create_time = Date.parse(new Date()) / 1000;
-                const id = ctx.request.body.id;
-                const file = ctx.request.files[0];
-                try {
-                    const fileInfo = path.parse(file.filename);
-                    const fileName = path.join('public/upload', ctx.tender.id.toString(), 'sign', 'signImg_' + create_time + fileInfo.ext);
-                    await this.ctx.helper.copyFileSync(file.filepath, path.join(this.app.baseDir, 'app', fileName));
-                    await ctx.service.ledgerCooperation.saveSign(id, fileName);
-                    ctx.body = { err: 0, msg: '', data: fileName };
-                } finally {
-                    await fs.unlinkSync(file.filepath);
-                }
+                const id = stream.fields.id;
+                const fileInfo = path.parse(stream.filename);
+                const fileName = path.join('public/upload', ctx.tender.id.toString(), 'sign', 'signImg_' + create_time + fileInfo.ext);
+                await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, 'app', fileName));
+                if (stream) {
+                    await sendToWormhole(stream);
+                }
+                await ctx.service.ledgerCooperation.saveSign(id, fileName);
+                ctx.body = { err: 0, msg: '', data: fileName };
             } catch (err) {
                 this.log(err);
                 ctx.body = { err: 1, msg: err.toString(), data: null };

+ 0 - 1
config/config.default.js

@@ -122,7 +122,6 @@ module.exports = appInfo => {
             '.zip', '.rar', '.7z', ''],
         fileSize: '30mb',
         fields: '15',
-        mode: 'file',
     };
 
     // 是否压缩替换前端js