Browse Source

Merge remote-tracking branch 'remotes/origin/dev' into uat

MaiXinRong 4 years atrás
parent
commit
d3721bf4b2

+ 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 };

+ 10 - 2
app/controller/schedule_controller.js

@@ -84,6 +84,7 @@ module.exports = app => {
             let nextSlmList = [];
             let endSlmList = [];
             let yearSlmList = [];
+            let curYearStageData = [];
             if (ctx.params.order && scheduleStage.length > 0) {
                 curScheduleStage = _.find(scheduleStage, { order: parseInt(ctx.params.order) });
             }
@@ -103,9 +104,15 @@ module.exports = app => {
                     return item.yearmonth.indexOf(curScheduleStage.yearmonth.split('-')[0]) !== -1;
                 }), 'yearmonth');
                 yearSlmList = await ctx.service.scheduleLedgerMonth.getConllectionList(tender.id, yearConllection);
+                // 获取本年完成计量数据
+                const stageList = _.filter(stageOrderList, function(item) {
+                    return item.s_time.indexOf(curScheduleStage.yearmonth.split('-')[0]) !== -1;
+                });
+                const stageIdList = _.map(_.filter(stageList, function(item) {
+                    return _.find(newSS, { order: item.order });
+                }), 'id');
+                curYearStageData = await ctx.service.stageBills.getStagesData(ctx.tender.id, stageIdList.join(','));
             }
-            // 获取本年完成计量数据
-
             const renderData = {
                 tender: tender.data,
                 tenderInfo: tender.info,
@@ -119,6 +126,7 @@ module.exports = app => {
                 nextSlmList,
                 endSlmList,
                 yearSlmList,
+                curYearStageData,
                 scheduleLedgerList: await this._getSelectedLedgerList(ctx),
                 jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.schedule.stageTp),
             };

+ 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 };

+ 19 - 10
app/public/js/schedule_stage_tp.js

@@ -22,6 +22,7 @@ $(function () {
         level: 'level',
         rootId: -1,
         fullPath: 'full_path',
+        calcFields: ['plan_gcl', 'plan_tp', 'next_plan_gcl', 'next_plan_tp', 'end_plan_gcl', 'end_plan_tp', 'year_plan_gcl', 'year_plan_tp'],
     };
     const ledgerTree = createNewPathTree('filter', treeSetting);
 
@@ -38,8 +39,8 @@ $(function () {
         {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'end_gather_tp', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '本年计划完成|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'year_plan_gcl', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'year_plan_tp', hAlign: 2, width: 70, type: 'Number', readOnly: true},
-        {title: '本年累计完成|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'dgn_qty1', hAlign: 2, width: 70, type: 'Number', readOnly: true},
-        {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 70, type: 'Number', readOnly: true},
+        {title: '本年累计完成|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'year_contract_qty', hAlign: 2, width: 70, type: 'Number', readOnly: true},
+        {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'year_gather_tp', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '本月计划完成|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'plan_gcl', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'plan_tp', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '本期完成计量|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 70, type: 'Number', readOnly: true},
@@ -70,9 +71,11 @@ $(function () {
 
     if (curScheduleStage && curScheduleStage.order) {
         postData('/tender/' + getTenderId() + '/measure/stage/' + curScheduleStage.order + '/load', { filter: 'ledger' }, function (data) {
-            const calcList = ['contract_qty', 'end_gather_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp',
+            const calcList = ['year_contract_qty', 'year_gather_tp',
+                'contract_qty', 'end_gather_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp',
                 'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp', 'end_contract_tp', 'end_qc_tp', 'end_gather_tp', 'end_correct_tp'];
             const showList = ['plan_gcl', 'plan_tp', 'next_plan_gcl', 'next_plan_tp', 'end_plan_gcl', 'end_plan_tp', 'year_plan_gcl', 'year_plan_tp',
+                'year_contract_qty', 'year_gather_tp',
                 'contract_qty', 'end_gather_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'ledger_id', 'ledger_pid', 'order', 'level', 'tender_id', 'full_path',
                 'code', 'name', 'unit', 'dgn_qty1', 'dgn_qty2', 'dgn_price', 'quantity', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp',
                 'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp', 'end_contract_tp', 'end_qc_tp', 'end_gather_tp', 'end_correct_tp'];
@@ -85,7 +88,7 @@ $(function () {
                 fullPath: 'full_path',
                 calcFields: calcList,
             };
-            baseLedgerTreeSetting.updateFields = ['contract_qty', 'end_gather_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'postil', 'used', 'contract_expr'];
+            baseLedgerTreeSetting.updateFields = ['year_contract_qty', 'year_gather_tp', 'contract_qty', 'end_gather_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'postil', 'used', 'contract_expr'];
             baseLedgerTreeSetting.calcFun = function (node) {
                 if (!node.children || node.children.length === 0) {
                     node.pre_gather_qty = ZhCalc.add(node.pre_contract_qty, node.pre_qc_qty);
@@ -113,11 +116,9 @@ $(function () {
                 node.dgn_price = ZhCalc.round(ZhCalc.div(node.total_price, node.dgn_qty1), 2);
             };
             const baseLedgerTree = createNewPathTree('base', baseLedgerTreeSetting);
-            const newLedgerList = setMonthToLedger(data.ledgerData, slmList, nextSlmList, endSlmList, yearSlmList);
-            console.log(newLedgerList);
+            const newLedgerList = setMonthToLedger(data.ledgerData, slmList, nextSlmList, endSlmList, yearSlmList, curYearStageData);
             baseLedgerTree.loadDatas(newLedgerList);
             treeCalc.calculateAll(baseLedgerTree);
-            console.log(baseLedgerTree);
             for (const d of baseLedgerTree.nodes) {
                 if (!d.b_code) {
                     const one = _.find(selectedLedgerList, function (item) {
@@ -128,9 +129,8 @@ $(function () {
                     }
                 }
             }
-            console.log(ledgerTree);
             ledgerTree.sortTreeNode(true);
-            // console.log(ledgerTree);
+            treeCalc.calculateAll(ledgerTree);
             SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Tree, ledgerTree);
         }, null, true);
     }
@@ -267,7 +267,7 @@ function setLeafData(tree) {
     return newtree;
 }
 
-function setMonthToLedger(ledgerList, slm, nextSlm, endSlm, yearSlm) {
+function setMonthToLedger(ledgerList, slm, nextSlm, endSlm, yearSlm, yearLedgerData) {
     if (slm.length > 0) {
         for(const s of slm) {
             const index = _.findIndex(ledgerList, { 'ledger_id': s.lid });
@@ -304,6 +304,15 @@ function setMonthToLedger(ledgerList, slm, nextSlm, endSlm, yearSlm) {
             }
         }
     }
+    if (yearLedgerData.length > 0) {
+        for (const yl of yearLedgerData) {
+            const index = _.findIndex(ledgerList, {'id': yl.lid});
+            if (index && index !== -1) {
+                ledgerList[index].year_contract_qty = ZhCalc.add(yl.contract_qty, yl.qc_qty);
+                ledgerList[index].year_gather_tp = ZhCalc.add(yl.contract_tp, yl.qc_tp);
+            }
+        }
+    }
     return ledgerList;
 }
 const is_numeric = (value) => {

+ 24 - 28
app/view/report/rpt_all_popup.ejs

@@ -534,12 +534,27 @@
         }
         //3. 把标段挂上去
         let tmpCacheArr = []; //这个临时用来储存相应标段节点挂接信息
+        let _createTenderItem = function (tender) {
+            let rst = {
+                name: tender.name,
+                id : -1,
+                cid : -1,
+                tender_id: tender.id,
+                last_stage: tender.lastStage.order,
+                last_stage_id: tender.lastStage.id,
+                report_id: zTreeOprObj.currentNode.refId,
+                signature: '',
+                items: [],
+                isParent: false
+            }
+            return rst;
+        }
         let _putTender = function (catLv, tender, parentItems) {
             if (tender.lastStage !== undefined && tender.lastStage !== null) {
                 if (hasCat) {
                     let isSorted = false;
                     for (let sCat of sortedCat) {
-                        if (sCat.id === tender.category[catLv].cid && sCat.level > 0) {
+                        if (sCat.level <= tender.category.length && sCat.level > 0 && sCat.id === tender.category[catLv].cid) {
                             isSorted = true;
                             break;
                         }
@@ -547,49 +562,30 @@
                     if (isSorted) {
                         for (const item of parentItems) {
                             if (item.cid === tender.category[catLv].cid && item.id === tender.category[catLv].value) {
-                                if (item.items.length > 0) {
+                                if (item.items.length > 0 && tender.category.length > (catLv + 1)) {
                                     //递归循环
                                     _putTender(catLv + 1, tender, item.items);
                                 } else {
                                     //就是这个了
-                                    let tdItem = {
-                                        name: tender.name,
-                                        id : -1,
-                                        cid : -1,
-                                        tender_id: tender.id,
-                                        last_stage: tender.lastStage.order,
-                                        last_stage_id: tender.lastStage.id,
-                                        report_id: zTreeOprObj.currentNode.refId,
-                                        signature: '',
-                                        items: [],
-                                        isParent: false
-                                    }; //标段节点
-                                    //
+                                    let tdItem = _createTenderItem(tender); //标段节点
                                     tmpCacheArr.push([item, tdItem]);
                                 }
                             }
                         }
+                    } else {
+                        //超界了
+                        //let tdItem = _createTenderItem(tender); //标段节点
+                        //tmpCacheArr.push([item, tdItem]);
                     }
                 } else {
                     // 没有设置category
-                    let tdItem = {
-                        name: tender.name,
-                        id : -1,
-                        cid : -1,
-                        tender_id: tender.id,
-                        last_stage: tender.lastStage.order,
-                        last_stage_id: tender.lastStage.id,
-                        report_id: zTreeOprObj.currentNode.refId,
-                        signature: '',
-                        items: [],
-                        isParent: false
-                    }; //标段节点
-                    //
+                    let tdItem = _createTenderItem(tender); //标段节点
                     tmpCacheArr.push([null, tdItem]);
                 }
             }
         }
         for (const tender of tenders) {
+            //console.log('tender.name: ' + tender.name);
             _putTender(0, tender, treeCache);
         }
         if (hasCat) {

+ 1 - 0
app/view/schedule/stage_tp.ejs

@@ -62,4 +62,5 @@
     const nextSlmList = JSON.parse('<%- JSON.stringify(nextSlmList) %>');
     const endSlmList = JSON.parse('<%- JSON.stringify(endSlmList) %>');
     const yearSlmList = JSON.parse('<%- JSON.stringify(yearSlmList) %>');
+    const curYearStageData = JSON.parse('<%- JSON.stringify(curYearStageData) %>');
 </script>

+ 0 - 1
config/config.default.js

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