Browse Source

Merge branch 'dev' of http://192.168.1.41:3000/maixinrong/Calculation into dev

TonyKang 4 years ago
parent
commit
d39e760e1c
43 changed files with 604 additions and 502 deletions
  1. 1 2
      app/base/base_bills_service.js
  2. 2 2
      app/base/base_controller.js
  3. 4 1
      app/base/base_service.js
  4. 19 18
      app/controller/advance_controller.js
  5. 39 53
      app/controller/change_controller.js
  6. 9 10
      app/controller/deal_bills_controller.js
  7. 0 45
      app/controller/ledger_controller.js
  8. 19 19
      app/controller/material_controller.js
  9. 8 5
      app/controller/profile_controller.js
  10. 30 3
      app/controller/schedule_controller.js
  11. 6 4
      app/controller/sign_controller.js
  12. 2 2
      app/controller/spss_controller.js
  13. 78 115
      app/controller/stage_controller.js
  14. 22 31
      app/controller/stage_extra_controller.js
  15. 14 11
      app/controller/tender_controller.js
  16. 2 0
      app/controller/wap_controller.js
  17. 14 0
      app/extend/helper.js
  18. 2 2
      app/middleware/tender_check.js
  19. 2 2
      app/middleware/uncheck_tender_check.js
  20. BIN
      app/public/files/template/ledger/导入分项清单EXCEL格式.xlsx
  21. 13 3
      app/public/js/change_information_set.js
  22. 2 2
      app/public/js/revise.js
  23. 47 21
      app/public/js/schedule_stage_tp.js
  24. 1 1
      app/public/js/se_bonus.js
  25. 27 4
      app/public/js/shenpi.js
  26. 36 0
      app/service/change_audit_list.js
  27. 1 1
      app/service/ledger_revise.js
  28. 1 0
      app/service/report.js
  29. 1 1
      app/service/revise_bills.js
  30. 120 105
      app/service/rpt_gather_memory.js
  31. 8 0
      app/service/schedule_ledger_month.js
  32. 3 0
      app/service/tender.js
  33. 3 3
      app/view/layout/menu.ejs
  34. 0 2
      app/view/ledger/bwtz.ejs
  35. 1 1
      app/view/schedule/plan_modal.ejs
  36. 4 0
      app/view/schedule/stage_tp.ejs
  37. 13 13
      app/view/schedule/stage_tp_modal.ejs
  38. 0 2
      app/view/stage/bwtz.ejs
  39. 1 1
      app/view/stage_extra/bonus_modal.ejs
  40. 26 4
      app/view/tender/shenpi.ejs
  41. 1 0
      config/config.default.js
  42. 3 13
      db_script/stage-change-final.js
  43. 19 0
      sql/update.sql

+ 1 - 2
app/base/base_bills_service.js

@@ -17,7 +17,6 @@ const upFields = ['unit_price'];
 const qtyFields = ['sgfh_qty', 'sjcl_qty', 'qtcl_qty', 'quantity', 'deal_qty', 'dgn_qty1', 'dgn_qty2'];
 const tpFields = ['sgfh_tp', 'sjcl_tp', 'qtcl_tp', 'total_price', 'deal_tp'];
 const measureType = require('../const/tender').measureType;
-const math = require('mathjs');
 const billsUtils = require('../lib/bills_utils');
 
 class BaseBillsSerivce extends TreeService {
@@ -544,7 +543,7 @@ class BaseBillsSerivce extends TreeService {
     _calcExpr(data, field, expr, defaultValue, precision) {
         if (expr) {
             try {
-                data[field] = this.ctx.helper.round(math.eval(expr), precision.value);
+                data[field] = this.ctx.helper.round(this.ctx.helper.calcExpr(expr), precision.value);
             } catch (err) {
             }
         } else {

+ 2 - 2
app/base/base_controller.js

@@ -154,9 +154,9 @@ class BaseController extends Controller {
 
     ajaxErrorBody(error, msg) {
         if (error.stack) {
-            return {err: 2, msg: msg, data: null};
+            return {err: 4, msg: msg, data: null};
         } else {
-            return {err: 1, msg: error.toString(), data: null};
+            return {err: 3, msg: error.toString(), data: null};
         }
     }
 }

+ 4 - 1
app/base/base_service.js

@@ -45,7 +45,10 @@ class BaseService extends Service {
      * @return {String} - 返回表名
      */
     get tableName() {
-        return (this.depart > 0 && this.ctx.tender) ? this._table + '_' + (this.ctx.tender.id % this.depart) : this._table;
+        if (this.depart <= 0) return this._table;
+
+        if (!this.ctx.query_tender && !this.ctx.tender) throw '获取数据表错误';
+        return this._table + '_' + ((this.ctx.query_tender ? this.ctx.query_tender.id : this.ctx.tender.id) % this.depart);
     }
 
     /**

+ 19 - 18
app/controller/advance_controller.js

@@ -2,7 +2,6 @@
 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 => {
@@ -366,30 +365,33 @@ module.exports = app => {
             let stream;
             try {
                 // this._checkAdvanceFileCanModify(ctx);
-                const parts = this.ctx.multipart({
-                    autoFields: true,
-                });
+
                 const files = [];
-                const create_time = Date.parse(new Date()) / 1000;
                 let idx = 0;
+                const create_time = Date.parse(new Date()) / 1000;
                 const extra_upload = ctx.advance.status === auditConst.status.checked;
-                while ((stream = await parts()) !== undefined) {
-                    if (!stream.filename) {
-                        // 如果没有传入直接返回
-                        return;
+                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);
                     }
-                    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(parts.field.name)) {
-                        idx = parts.field.name.findIndex(name => name === file.name);
+                    if (Array.isArray(ctx.request.body.name)) {
+                        idx = ctx.request.body.name.findIndex(name => name === file.name);
                     } else {
                         idx = 'isString';
                     }
@@ -399,7 +401,7 @@ module.exports = app => {
                         tid: ctx.tender.id,
                         create_time: in_time,
                         filepath: file.filepath,
-                        filesize: ctx.helper.bytesToSize(idx === 'isString' ? parts.field.size : parts.field.size[idx]),
+                        filesize: ctx.helper.bytesToSize(idx === 'isString' ? ctx.request.body.size : ctx.request.body.size[idx]),
                         filename: file.name,
                         fileext: file.ext,
                         extra_upload,
@@ -412,7 +414,6 @@ 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 };
             }

+ 39 - 53
app/controller/change_controller.js

@@ -9,7 +9,6 @@
  */
 
 const moment = require('moment');
-const sendToWormhole = require('stream-wormhole');
 const fs = require('fs');
 const path = require('path');
 const audit = require('../const/audit');
@@ -746,6 +745,11 @@ module.exports = app => {
                         // 取所有工料表
                         responseData.data = await ctx.service.changeAuditList.getList(ctx.change.cid);
                         break;
+                    case 'remove_list':
+                        await ctx.service.changeAuditList.removeLedgerListDatas(data.updateData);
+                        // 取所有工料表
+                        responseData.data = await ctx.service.changeAuditList.getList(ctx.change.cid);
+                        break;
                     case 'info':
                         await ctx.service.change.saveInfo(data.updateData);
                         // 取所有工料表
@@ -984,66 +988,48 @@ module.exports = app => {
          * @return {void}
          */
         async uploadFile(ctx) {
-            const responseData = {
-                err: 0,
-                msg: '',
-                data: [],
-            };
-            let stream;
+            const responseData = { err: 0, msg: '', data: [], };
             try {
-                const parts = ctx.multipart({ autoFields: true });
-                const files = [];
-                let index = 0;
                 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 '导入数据库保存失败';
+                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);
                     }
-                    // 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 - 10
app/controller/deal_bills_controller.js

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

+ 0 - 45
app/controller/ledger_controller.js

@@ -553,51 +553,6 @@ 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,7 +17,6 @@ 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');
@@ -868,33 +867,35 @@ module.exports = app => {
          * @param {*} ctx 上下文
          */
         async upload(ctx) {
-            let stream;
             try {
                 await this._checkMaterialFileCanModify(ctx);
-                const parts = this.ctx.multipart({
-                    autoFields: true,
-                });
+
                 const files = [];
-                const create_time = Date.parse(new Date()) / 1000;
                 let idx = 0;
+                const create_time = Date.parse(new Date()) / 1000;
                 const extra_upload = ctx.material.status === auditConst.status.checked;
-                while ((stream = await parts()) !== undefined) {
-                    if (!stream.filename) {
-                        // 如果没有传入直接返回
-                        return;
+                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);
                     }
-                    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(parts.field.name)) {
-                        idx = parts.field.name.findIndex(name => name === file.name);
+                    if (Array.isArray(ctx.request.body.name)) {
+                        idx = ctx.request.body.name.findIndex(name => name === file.name);
                     } else {
                         idx = 'isString';
                     }
@@ -905,7 +906,7 @@ module.exports = app => {
                         s_order: ctx.params.order,
                         upload_time,
                         filepath: file.filepath,
-                        file_size: ctx.helper.bytesToSize(idx === 'isString' ? parts.field.size : parts.field.size[idx]),
+                        file_size: ctx.helper.bytesToSize(idx === 'isString' ? ctx.request.body.size : ctx.request.body.size[idx]),
                         file_name: file.name,
                         fileext: file.ext,
                         extra_upload,
@@ -918,7 +919,6 @@ 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 };
             }

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

+ 30 - 3
app/controller/schedule_controller.js

@@ -77,12 +77,35 @@ module.exports = app => {
             const tender = ctx.tender;
             const schedule = await ctx.service.schedule.getDataByCondition({ tid: tender.id });
             const scheduleMonth = await ctx.service.scheduleMonth.getAllDataByCondition({ where: { tid: tender.id }, orders: [['yearmonth', 'asc']] });
-            const stageOrderList = await ctx.service.stage.getAllDataByCondition({ columns: ['id', 'order'], where: { tid: tender.id } });
-            const scheduleStage = await ctx.service.scheduleStage.getAllDataByCondition({ where: { tid: tender.id } });
-            let curScheduleStage = scheduleStage.length > 0 ? scheduleStage[scheduleStage.length - 1] : null;
+            const stageOrderList = await ctx.service.stage.getAllDataByCondition({ columns: ['id', 's_time', 'order'], where: { tid: tender.id } });
+            const scheduleStage = await ctx.service.scheduleStage.getAllDataByCondition({ where: { tid: tender.id }, orders: [['order', 'desc']] });
+            let curScheduleStage = scheduleStage.length > 0 ? _.maxBy(scheduleStage, 'order') : null;
+            let slmList = [];
+            let nextSlmList = [];
+            let endSlmList = [];
+            let yearSlmList = [];
             if (ctx.params.order && scheduleStage.length > 0) {
                 curScheduleStage = _.find(scheduleStage, { order: parseInt(ctx.params.order) });
             }
+            if (curScheduleStage) {
+                const newSS = _.sortBy(scheduleStage, 'yearmonth');
+                const nowScheduleStage = _.findIndex(newSS, { yearmonth: curScheduleStage.yearmonth });
+                slmList = await ctx.service.scheduleLedgerMonth.getAllDataByCondition({ where: { tid: tender.id, yearmonth: curScheduleStage.yearmonth } });
+                const nextScheduleStage = nowScheduleStage >= 0 && nowScheduleStage + 1 <= newSS.length - 1 ? newSS[nowScheduleStage + 1] : null;
+                if (nextScheduleStage) nextSlmList = await ctx.service.scheduleLedgerMonth.getAllDataByCondition({ where: { tid: tender.id, yearmonth: nextScheduleStage.yearmonth } });
+                if (nowScheduleStage === 0) {
+                    endSlmList = slmList;
+                } else if (nowScheduleStage > 0) {
+                    const endYearmonthCollection = _.map(_.take(newSS, nowScheduleStage + 1), 'yearmonth');
+                    endSlmList = await ctx.service.scheduleLedgerMonth.getConllectionList(tender.id, endYearmonthCollection);
+                }
+                const yearConllection = _.map(_.filter(newSS, function(item) {
+                    return item.yearmonth.indexOf(curScheduleStage.yearmonth.split('-')[0]) !== -1;
+                }), 'yearmonth');
+                yearSlmList = await ctx.service.scheduleLedgerMonth.getConllectionList(tender.id, yearConllection);
+            }
+            // 获取本年完成计量数据
+
             const renderData = {
                 tender: tender.data,
                 tenderInfo: tender.info,
@@ -92,6 +115,10 @@ module.exports = app => {
                 stageOrderList,
                 scheduleStage,
                 curScheduleStage,
+                slmList,
+                nextSlmList,
+                endSlmList,
+                yearSlmList,
                 scheduleLedgerList: await this._getSelectedLedgerList(ctx),
                 jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.schedule.stageTp),
             };

+ 6 - 4
app/controller/sign_controller.js

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

+ 2 - 2
app/controller/spss_controller.js

@@ -31,10 +31,12 @@ module.exports = app => {
             if (!tender || tender.project_id !== this.ctx.session.sessionProject.id) {
                 throw '不存在该标段';
             }
+            this.ctx.query_tender = tender;
             const bills = await this.ctx.service.ledger.getData(tid);
             const pos = tender.measure_type === measureType.tz.value || includePos
                 ? await this.ctx.service.pos.getPosData({tid: tid})
                 : [];
+            this.ctx.query_tender = null;
 
             return { id: tid, name: tender.name, bills: bills, pos: pos };
         }
@@ -87,7 +89,6 @@ module.exports = app => {
         }
 
         async _getStageData(tid, sorder) {
-            console.log(tid);
             const data = await this._getTzData(tid, true);
             const stage = await this._checkStage(tid, sorder);
             const bills = await this.ctx.service.stageBills.getAuditorStageData(tid, stage.id, stage.curTimes, stage.curOrder);
@@ -173,7 +174,6 @@ module.exports = app => {
         async loadCompareStage(ctx) {
             try {
                 const data = JSON.parse(ctx.request.body.data);
-                console.log(data);
                 const responseData = {err: 0, msg: '', data: {}};
                 responseData.data.tender1 = await this._getStageData(data.tid1, data.sorder1);
                 responseData.data.tender2 = await this._getStageData(data.tid2, data.sorder2);

+ 78 - 115
app/controller/stage_controller.js

@@ -21,7 +21,6 @@ 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');
@@ -669,12 +668,16 @@ module.exports = app => {
             try {
                 this._checkStageCanModify(ctx);
 
-                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 };
+                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);
+                }
             } catch (err) {
                 this.log(err);
                 ctx.body = { err: 1, msg: err.toString(), data: null };
@@ -1316,68 +1319,46 @@ module.exports = app => {
                 msg: '',
                 data: [],
             };
-            let stream;
             try {
                 // this._checkStageCanModifyRe(ctx);
 
-                const parts = ctx.multipart({ autoFields: true });
-                const files = [];
                 let index = 0;
+                const files = [];
                 const extra_upload = ctx.stage.status === auditConst.status.checked;
-                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 '导入数据库保存失败';
+                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);
                     }
-                    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();
@@ -1511,42 +1492,34 @@ module.exports = app => {
                 msg: '',
                 data: [],
             };
-            let stream;
             try {
-                this._checkStageCanModifyRe(ctx);
-                stream = await ctx.getFileStream({ requireFile: false });
+                //this._checkStageCanModifyRe(ctx);
+
+                const file = ctx.request.files[0];
                 let fileData = {};
-                if (stream.filename !== undefined) {
+                if (file && file.filename !== undefined) {
                     const create_time = Date.parse(new Date()) / 1000;
-                    const fileInfo = path.parse(stream.filename);
+                    const fileInfo = path.parse(file.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.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
+                    await ctx.helper.copyFileSync(file.filepath, path.join(this.app.baseDir, dirName, fileName));
                     // 保存数据到att表
                     fileData = {
-                        filesize: stream.fields.size,
+                        filesize: ctx.request.body.size,
                         filepath: path.join(dirName, fileName),
                     };
                 }
-                const result = await ctx.service.stageAtt.updateByID(stream.fields, fileData);
+                const result = await ctx.service.stageAtt.updateByID(ctx.request.body, fileData);
                 if (!result) {
                     throw '导入数据库保存失败';
                 }
-                const attData = await ctx.service.stageAtt.getDataByFid(stream.fields.id);
+                const attData = await ctx.service.stageAtt.getDataByFid(ctx.request.body.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();
@@ -1605,55 +1578,45 @@ module.exports = app => {
                 msg: '',
                 data: [],
             };
-            let stream;
             try {
                 this._checkStageCanModify(ctx);
 
-                const parts = ctx.multipart({ autoFields: true });
-                const files = [];
                 let index = 0;
+                const files = [];
                 const create_time = Date.parse(new Date()) / 1000;
-                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 '导入数据库保存失败';
+                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);
                     }
-                    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();

+ 22 - 31
app/controller/stage_extra_controller.js

@@ -8,7 +8,6 @@
  * @version
  */
 const auditConst = require('../const/audit').stage;
-const sendToWormhole = require('stream-wormhole');
 const path = require('path');
 const moment = require('moment');
 const fs = require('fs');
@@ -198,37 +197,33 @@ module.exports = app => {
         }
 
         async uploadFile(ctx) {
-            let stream;
             try {
-                const parts = ctx.multipart({ autoFields: true });
-                let index = 0;
+                const bonus = await ctx.service.stageBonus.getStageDataById(ctx.request.body.bonus_id);
+                if (!bonus || bonus.sid !== ctx.stage.id) throw '该奖罚金,当前不允许上传附件';
                 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 '该奖罚金,当前不允许上传附件';
 
-                    const fileInfo = path.parse(stream.filename);
-                    const dirName = 'app/public/upload/extra/' + moment().format('YYYYMMDD');
-                    const fileName = create_time + '_' + index + fileInfo.ext;
+                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;
 
-                    // 保存文件
-                    await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
-                    await sendToWormhole(stream);
+                        await this.ctx.helper.recursiveMkdirSync(path.join(this.app.baseDir, dirName));
+                        await fs.copyFileSync(file.filepath, path.join(this.app.baseDir, dirName, fileName));
 
-                    // 插入到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;
+                        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);
+                    }
                 }
                 const result = await ctx.service.stageBonus.updateDatas({
                     update: [
@@ -242,10 +237,6 @@ 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, '上传附件失败,请重试');
             }
         }

+ 14 - 11
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 sendToWormhole = require('stream-wormhole');
+const fs = require('fs');
 
 module.exports = app => {
 
@@ -123,6 +123,7 @@ module.exports = app => {
                 const tenderList = await this.ctx.service.tender.getList('', userPermission);
 
                 for (const t of tenderList) {
+                    this.ctx.query_tender = t;
                     if (t.user_id === this.ctx.session.sessionUser.accountId && (
                         t.ledger_status === auditConst.ledger.status.checkNo || t.ledger_status === auditConst.ledger.status.uncheck)) {
                         const sum = await this.ctx.service.ledger.addUp({ tender_id: t.id/* , is_leaf: true*/ });
@@ -147,6 +148,7 @@ module.exports = app => {
                         await this._getLedgerAuditInfo(t);
                     }
                 }
+                this.ctx.query_tender = null;
                 const categoryData = await this.ctx.service.category.getAllCategory(this.ctx.session.sessionProject.id);
                 const valuations = await this.ctx.service.valuation.getProjectValidValuation(this.ctx.session.sessionProject.id);
                 const renderData = {
@@ -909,17 +911,18 @@ module.exports = app => {
          */
         async saveCooperateSign(ctx) {
             try {
-                const stream = await ctx.getFileStream();
                 const create_time = Date.parse(new Date()) / 1000;
-                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 };
+                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);
+                }
             } catch (err) {
                 this.log(err);
                 ctx.body = { err: 1, msg: err.toString(), data: null };

+ 2 - 0
app/controller/wap_controller.js

@@ -147,6 +147,7 @@ module.exports = app => {
 
                 const tenderList = await this.ctx.service.tender.getList('', userPermission);
                 for (const t of tenderList) {
+                    this.ctx.query_tender = t;
                     if (t.user_id === this.ctx.session.sessionUser.accountId && (
                         t.ledger_status === auditConst.ledger.status.checkNo || t.ledger_status === auditConst.ledger.status.uncheck)) {
                         const sum = await this.ctx.service.ledger.addUp({tender_id: t.id/*, is_leaf: true*/});
@@ -165,6 +166,7 @@ module.exports = app => {
                         await this.ctx.service.stage.checkStageGatherData(t.lastStage);
                     }
                 }
+                this.ctx.query_tender = null;
                 const categoryData = await this.ctx.service.category.getAllCategory(this.ctx.session.sessionProject.id);
                 const valuations = await this.ctx.service.valuation.getProjectValidValuation(this.ctx.session.sessionProject.id);
                 const renderData = {

+ 14 - 0
app/extend/helper.js

@@ -20,6 +20,7 @@ const SMS = require('../lib/sms');
 const WX = require('../lib/wechat');
 const timesLen = 100;
 const UAParser = require('ua-parser-js');
+const math = require('mathjs');
 
 module.exports = {
     _,
@@ -570,6 +571,14 @@ module.exports = {
         await this.saveBufferFile(buffer, fileName);
     },
 
+    async copyFileSync(source, target) {
+        const pathName = path.dirname(target);
+        if (!fs.existsSync(pathName)) {
+            await this.recursiveMkdirSync(pathName);
+        }
+        await fs.copyFileSync(source, target);
+    },
+
     /**
      * 检查code是否是指标模板数据
      * @param {String} code
@@ -1280,6 +1289,11 @@ module.exports = {
         return result;
     },
 
+    calcExpr(expr) {
+        const validExpr = expr.replace('=', '').replace('%', '/100');
+        return math.eval(validExpr);
+    },
+
     /**
      * 创建登录日志
      * @return {Boolean} 日志是否创建成功

+ 2 - 2
app/middleware/tender_check.js

@@ -94,9 +94,9 @@ module.exports = options => {
             }
             if (this.helper.isAjax(this.request)) {
                 if (err.stack) {
-                    this.body = {err: 2, msg: '标段数据未知错误', data: null};
+                    this.body = {err: 4, msg: '标段数据未知错误', data: null};
                 } else {
-                    this.body = {err: 1, msg: err.toString(), data: null};
+                    this.body = {err: 3, msg: err.toString(), data: null};
                 }
             } else {
                 if (this.helper.isWap(this.request)) {

+ 2 - 2
app/middleware/uncheck_tender_check.js

@@ -49,9 +49,9 @@ module.exports = options => {
             }
             if (this.helper.isAjax(this.request)) {
                 if (err.stack) {
-                    this.body = {err: 2, msg: '标段数据未知错误', data: null};
+                    this.body = {err: 4, msg: '标段数据未知错误', data: null};
                 } else {
-                    this.body = {err: 1, msg: err.toString(), data: null};
+                    this.body = {err: 3, msg: err.toString(), data: null};
                 }
             } else {
                 if (this.helper.isWap(this.request)) {

BIN
app/public/files/template/ledger/导入分项清单EXCEL格式.xlsx


+ 13 - 3
app/public/js/change_information_set.js

@@ -806,6 +806,7 @@ function tableDataRemake(changeListData) {
     $('#code-list').html('');
     // 根据已添加的清单显示
     if (changeList.length > 0 && changeList[0]) {
+        const removeList = [];
         for (const [index,clinfo] of changeList.entries()) {
             if (clinfo.lid != 0) {
                 let listinfo = changeListData.find(function (item) {
@@ -816,7 +817,8 @@ function tableDataRemake(changeListData) {
                     listinfo = changeListData[clinfo.lid - 1];
                     if (listinfo === undefined) {
                         toastr.warning('台账清单列表已不存在'+ clinfo.code +',已更新变更清单列表');
-                        changeList.splice(index, 1);
+                        // changeList.splice(index, 1);
+                        removeList.push(clinfo);
                         continue;
                     }
                     $('#table-list-select tr[data-index="'+ clinfo.lid +'"]').addClass('table-success');
@@ -835,7 +837,8 @@ function tableDataRemake(changeListData) {
                                 (leafInfo.bwmx !== undefined ? leafInfo.bwmx : (leafInfo.jldy !== undefined ? leafInfo.jldy : '')) + '*;*' + (leafInfo.quantity !== null ? leafInfo.quantity : 0);
                         } else {
                             toastr.warning('台账清单列表已不存在'+ clinfo.code +',已更新变更清单列表');
-                            changeList.splice(index, 1);
+                            // changeList.splice(index, 1);
+                            removeList.push(clinfo);
                             continue;
                         }
                     } else {
@@ -865,7 +868,8 @@ function tableDataRemake(changeListData) {
                                 (leafInfo.bwmx !== undefined ? leafInfo.bwmx : (leafInfo.jldy !== undefined ? leafInfo.jldy : '')) + '*;*' + (leafInfo.quantity !== null ? leafInfo.quantity : 0);
                         } else {
                             toastr.warning('台账清单列表已不存在'+ clinfo.code +',已更新变更清单列表');
-                            changeList.splice(index, 1);
+                            // changeList.splice(index, 1);
+                            removeList.push(clinfo);
                             continue;
                         }
                     } else {
@@ -882,6 +886,12 @@ function tableDataRemake(changeListData) {
                 }
             }
         }
+        if(removeList.length > 0) {
+            _.pullAll(changeList, removeList);
+            postData(window.location.pathname + '/save', { type:'remove_list', updateData: removeList }, function (result) {
+            }, function () {
+            });
+        }
     }
 }
 

+ 2 - 2
app/public/js/revise.js

@@ -1316,7 +1316,7 @@ $(document).ready(() => {
             } else {
                 $('#pos-expr').val('').attr('readOnly', true);
                 $('#pos-expr').removeAttr('data-row');
-            }            
+            }
         },
         /**
          * 加载计量单元 根据当前台账选择节点
@@ -1326,7 +1326,7 @@ $(document).ready(() => {
             if (node) {
                 const posData = pos.getLedgerPos(node.id) || [];
                 SpreadJsObj.loadSheetData(posSheet, 'data', posData);
-                posSheet.zh_setting.readOnly = readOnly || posData.length === 0;
+                posSheet.zh_setting.readOnly = readOnly || (node.used && posData.length === 0);
             } else {
                 SpreadJsObj.loadSheetData(posSheet, 'data', []);
                 posSheet.zh_setting.readOnly = true;

+ 47 - 21
app/public/js/schedule_stage_tp.js

@@ -32,20 +32,20 @@ $(function () {
         {title: '经济指标', colSpan: '1', rowSpan: '2', field: 'dgn_price', hAlign: 2, width: 60, 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: '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: 'end_plan_gcl', hAlign: 2, width: 70, type: 'Number', readOnly: true},
+        {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'end_plan_tp', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {title: '截止本期完成计量|工程量', colSpan: '2|1', rowSpan: '1|1', field: 'end_gather_qty', hAlign: 2, width: 70, type: 'Number', readOnly: true},
         {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: '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_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: '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: '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},
         {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'gather_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: 'next_plan_gcl', hAlign: 2, width: 70, type: 'Number', readOnly: true},
+        {title: '|金额(万元)', colSpan: '|1', rowSpan: '|1', field: 'next_plan_tp', hAlign: 2, width: 70, type: 'Number', readOnly: true},
     ];
 
     const ledgerSpreadSetting = {
@@ -70,9 +70,10 @@ $(function () {
 
     if (curScheduleStage && curScheduleStage.order) {
         postData('/tender/' + getTenderId() + '/measure/stage/' + curScheduleStage.order + '/load', { filter: 'ledger' }, function (data) {
-            const calcList = ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp',
+            const calcList = ['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 = ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'ledger_id', 'ledger_pid', 'order', 'level', 'tender_id', 'full_path',
+            const showList = ['plan_gcl', 'plan_tp', 'next_plan_gcl', 'next_plan_tp', 'end_plan_gcl', 'end_plan_tp', 'year_plan_gcl', 'year_plan_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'];
             const baseLedgerTreeSetting = {
@@ -84,7 +85,7 @@ $(function () {
                 fullPath: 'full_path',
                 calcFields: calcList,
             };
-            baseLedgerTreeSetting.updateFields = ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'postil', 'used', 'contract_expr'];
+            baseLedgerTreeSetting.updateFields = ['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);
@@ -112,8 +113,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.bills, data.slm);
-            baseLedgerTree.loadDatas(data.ledgerData);
+            const newLedgerList = setMonthToLedger(data.ledgerData, slmList, nextSlmList, endSlmList, yearSlmList);
+            console.log(newLedgerList);
+            baseLedgerTree.loadDatas(newLedgerList);
             treeCalc.calculateAll(baseLedgerTree);
             console.log(baseLedgerTree);
             for (const d of baseLedgerTree.nodes) {
@@ -197,7 +199,7 @@ $(function () {
             return;
         }
         const _self = $(this);
-        postData(window.location.pathname + '/save', {type: 'add_stage', postData: { yearmonth, order }}, function (result) {
+        postData('/tender/'+ getTenderId() + '/schedule/stage/save', {type: 'add_stage', postData: { yearmonth, order }}, function (result) {
             _self.addClass('disabled').attr('disabled', true);
             toastr.success('新增成功');
             setTimeout(function () {
@@ -265,16 +267,40 @@ function setLeafData(tree) {
     return newtree;
 }
 
-function setMonthToLedger(ledgerList, slm) {
+function setMonthToLedger(ledgerList, slm, nextSlm, endSlm, yearSlm) {
     if (slm.length > 0) {
         for(const s of slm) {
             const index = _.findIndex(ledgerList, { 'ledger_id': s.lid });
-            const canCalc = _.find(scheduleMonth, { 'yearmonth': s.yearmonth, 'stage_used': 1});
-            if (index && index !== -1 && canCalc) {
-                ledgerList[index][s.yearmonth + '_plan_tp'] = s.plan_tp;
-                ledgerList[index][s.yearmonth + '_plan_gcl'] = s.plan_gcl;
-                ledgerList[index][s.yearmonth + '_sj_tp'] = s.sj_tp;
-                ledgerList[index][s.yearmonth + '_sj_gcl'] = s.sj_gcl;
+            if (index && index !== -1) {
+                ledgerList[index].plan_tp = s.plan_tp;
+                ledgerList[index].plan_gcl = s.plan_gcl;
+            }
+        }
+    }
+    if (nextSlm.length > 0) {
+        for (const ns of nextSlm) {
+            const index = _.findIndex(ledgerList, {'ledger_id': ns.lid});
+            if (index && index !== -1) {
+                ledgerList[index].next_plan_tp = ns.plan_tp;
+                ledgerList[index].next_plan_gcl = ns.plan_gcl;
+            }
+        }
+    }
+    if (endSlm.length > 0) {
+        for (const es of endSlm) {
+            const index = _.findIndex(ledgerList, {'ledger_id': es.lid});
+            if (index && index !== -1) {
+                ledgerList[index].end_plan_tp = es.plan_tp;
+                ledgerList[index].end_plan_gcl = es.plan_gcl;
+            }
+        }
+    }
+    if (yearSlm.length > 0) {
+        for (const ys of yearSlm) {
+            const index = _.findIndex(ledgerList, {'ledger_id': ys.lid});
+            if (index && index !== -1) {
+                ledgerList[index].year_plan_tp = ys.plan_tp;
+                ledgerList[index].year_plan_gcl = ys.plan_gcl;
             }
         }
     }

+ 1 - 1
app/public/js/se_bonus.js

@@ -183,7 +183,7 @@ $(document).ready(() => {
                     toastr.error('仅支持office文档、图片、压缩包格式,请勿上传' + fileext + '格式文件。');
                     return false;
                 }
-                formData.append('size[]', file.size);
+                formData.append('size', file.size);
                 formData.append('file[]', file);
             }
             postDataWithFile('upload/file', formData, function (data) {

+ 27 - 4
app/public/js/shenpi.js

@@ -363,7 +363,19 @@ $(document).ready(function () {
                     _self.parents('ul').append('<li class="pl-3"><a href="javascript:void(0);" class="add-audit"><i class="fa fa-plus"></i> 添加流程</a></li>');
                 }
                 _self.parents('.spr-span').html('<span class="d-inline-block"></span>\n' +
-                    '<span class="d-inline-block"><span class="badge badge-light">'+ user.name +' <a href="javascript:void(0);" class="remove-audit btn-sm text-danger px-1" title="移除" data-id="'+ user.id +'"><i class="fa fa-remove"></i></a></span> </span>');
+                    '<span class="d-inline-block"><span class="badge badge-light">'+ user.name +' <span class="dropdown">\n' +
+                    '                                                            <a href="javascript:void(0);" class="btn-sm text-danger px-1" title="移除" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-remove"></i></a>\n' +
+                    '                                                            <div class="dropdown-menu">\n' +
+                    '                                                                <a class="dropdown-item" href="javascript:void(0);">确认移除审批人?</a>\n' +
+                    '                                                                <div class="dropdown-divider"></div>\n' +
+                    '                                                                <div class="px-2 py-1 text-center">\n' +
+                    '                                                                    <button class="remove-audit btn btn-sm btn-danger" data-id="' + user.id + '">移除</button>\n' +
+                    '                                                                    <button class="btn btn-sm btn-secondary">取消</button>\n' +
+                    '                                                                </div>\n' +
+                    '                                                            </div>\n' +
+                    '                                                        </span> ' +
+                    '                                            </span></span></span>\n');
+                    // <a href="javascript:void(0);" class="remove-audit btn-sm text-danger px-1" title="移除" data-id="'+ user.id +'"><i class="fa fa-remove"></i></a></span> </span>');
             });
         }
     });
@@ -425,8 +437,19 @@ $(document).ready(function () {
             '                                            <span class="col-auto">'+ i +'审</span>\n' +
             '                                            <span class="col-7 spr-span">\n' +
             '                                            <span class="d-inline-block"></span>\n' +
-            '                                            <span class="d-inline-block"><span class="badge badge-light">'+ audit.name +' <a href="javascript:void(0);" class="remove-audit btn-sm text-danger px-1" title="移除" data-id="'+ audit.audit_id +'"><i class="fa fa-remove"></i></a></span> </span>\n' +
-            '                                            </span>\n' +
+            '                                            <span class="d-inline-block"><span class="badge badge-light">'+ audit.name +' <span class="dropdown">\n' +
+            '                                                            <a href="javascript:void(0);" class="btn-sm text-danger px-1" title="移除" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-remove"></i></a>\n' +
+            '                                                            <div class="dropdown-menu">\n' +
+            '                                                                <a class="dropdown-item" href="javascript:void(0);">确认移除审批人?</a>\n' +
+            '                                                                <div class="dropdown-divider"></div>\n' +
+            '                                                                <div class="px-2 py-1 text-center">\n' +
+            '                                                                    <button class="remove-audit btn btn-sm btn-danger" data-id="' + audit.audit_id + '">移除</button>\n' +
+            '                                                                    <button class="btn btn-sm btn-secondary">取消</button>\n' +
+            '                                                                </div>\n' +
+            '                                                            </div>\n' +
+            '                                                        </span> ' +
+            // '<a href="javascript:void(0);" class="remove-audit btn-sm text-danger px-1" title="移除" data-id="'+ audit.audit_id +'"><i class="fa fa-remove"></i></a></span> </span>\n' +
+            '                                            </span></span></span>\n' +
             '                                        </li>';
     }
 
@@ -822,7 +845,7 @@ $(document).ready(function () {
         // 更新新的多人协同表格信息
         const newUidList = [];
         $('.stage_div ul li').each(function (k, v) {
-            const uid = $(v).find('a').data('id');
+            const uid = $(v).find('button').eq(0).data('id');
             if(uid) newUidList.push(uid);
         });
         const oldUidList = [];

+ 36 - 0
app/service/change_audit_list.js

@@ -183,6 +183,42 @@ module.exports = app => {
             }
         }
 
+        /**
+         * 台账数据清单 清除部分并重新算原设计总金额
+         * @param {Object} datas 内容
+         * @return {void}
+         */
+        async removeLedgerListDatas(datas) {
+            if (!this.ctx.tender || !this.ctx.change) {
+                throw '数据错误';
+            }
+            // 判断是否可修改
+            // 判断t_type是否为费用
+            const transaction = await this.db.beginTransaction();
+            try {
+                // 先删除原本的台账清单数据
+                // const sql = 'DELETE FROM ?? WHERE cid = ? and lid != "0"';
+                // const sqlParam = [this.tableName, this.ctx.change.cid];
+                // await transaction.query(sql, sqlParam);
+                // const insertDatas = [];
+                for (const data of datas) {
+                    // data.tid = this.ctx.tender.id;
+                    // data.cid = this.ctx.change.cid;
+                    // data.spamount = data.camount;
+                    // data.samount = '';
+                    // insertDatas.push(data);
+                    await transaction.delete(this.tableName, { id: data.id });
+                }
+                // if (insertDatas.length > 0) await transaction.insert(this.tableName, insertDatas);
+                await this.calcCamountSum(transaction);
+                await transaction.commit();
+                return true;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
         async calcCamountSum(transaction) {
             // const sql = 'SELECT SUM(ROUND(`camount`*`unit_price`, )) as total_price FROM ?? WHERE cid = ?';
             // const sqlParam = [this.tableName, this.change.cid];

+ 1 - 1
app/service/ledger_revise.js

@@ -142,7 +142,7 @@ module.exports = app => {
                     status: audit.status.uncheck,
                 });
             }
-            await transaction.insert(this.ctx.service.reviseAudit.tableName, newAuditors);
+            if (auditors) await transaction.insert(this.ctx.service.reviseAudit.tableName, newAuditors);
         }
 
         /**

+ 1 - 0
app/service/report.js

@@ -32,6 +32,7 @@ module.exports = app => {
 
         async getReportData(params, filters, memFieldKeys, customDefine, customSelect) {
             const service = this.ctx.service;
+            await service.tender.checkTender(params.tender_id);
             const rst = {};
             const runnableRst = [];
             const runnableKey = []; // 这个配合runnableRst用,未来考虑并行查询优化

+ 1 - 1
app/service/revise_bills.js

@@ -46,7 +46,7 @@ module.exports = app => {
          */
         async addReviseNode(tid, rid, lid, count) {
             if (!rid) return null;
-            return await this.addNodeBatch(tid, lid, {crid: rid, revise_calc: 1}, count);
+            return await this.addNodeBatch(tid, lid, {crid: rid, check_calc: 1}, count);
         }
 
         /**

+ 120 - 105
app/service/rpt_gather_memory.js

@@ -284,18 +284,33 @@ module.exports = app => {
                     const curStage = await this.ctx.service.stageBills.getAuditorStageData(tender.id,
                         stage.id, stage.curTimes, stage.curOrder);
                     this.ctx.helper.assignRelaData(billsData, [
-                        {data: curStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: '', relaId: 'lid'}
+                        {
+                            data: curStage,
+                            fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'],
+                            prefix: '',
+                            relaId: 'lid'
+                        }
                     ]);
                 } else {
                     const curStage = await this.ctx.service.stageBills.getLastestStageData(tender.id, stage.id);
                     this.ctx.helper.assignRelaData(billsData, [
-                        {data: curStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: '', relaId: 'lid'}
+                        {
+                            data: curStage,
+                            fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'],
+                            prefix: '',
+                            relaId: 'lid'
+                        }
                     ]);
                 }
                 if (hasPre) {
                     const preStage = stage.order > 1 ? await this.ctx.service.stageBillsFinal.getFinalData(tender, stage.order - 1) : [];
                     this.ctx.helper.assignRelaData(billsData, [
-                        {data: preStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: 'pre_', relaId: 'lid'}
+                        {
+                            data: preStage,
+                            fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'],
+                            prefix: 'pre_',
+                            relaId: 'lid'
+                        }
                     ]);
                 }
             }
@@ -304,7 +319,6 @@ module.exports = app => {
             this.resultTree.loadGatherTree(billsTree, function (gatherNode, sourceNode) {
                 gatherUtils.gatherStage(tender, gatherNode, sourceNode, completeData.prefix, helper);
             });
-
         }
 
         async _gatherStagesData(completeData, tender, stages) {
@@ -368,14 +382,20 @@ module.exports = app => {
                 if (stage.readOnly) {
                     const curStage = await this.ctx.service.stageBills.getAuditorStageData(tender.id,
                         stage.id, stage.curTimes, stage.curOrder);
-                    sumAssignRelaData(billsIndexData, [
-                        {data: curStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: '', relaId: 'lid'}
-                    ]);
+                    sumAssignRelaData(billsIndexData, [{
+                        data: curStage,
+                        fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'],
+                        prefix: '',
+                        relaId: 'lid'
+                    }]);
                 } else {
                     const curStage = await this.ctx.service.stageBills.getLastestStageData(tender.id, stage.id);
-                    sumAssignRelaData(billsIndexData, [
-                        {data: curStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: '', relaId: 'lid'}
-                    ]);
+                    sumAssignRelaData(billsIndexData, [{
+                        data: curStage,
+                        fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'],
+                        prefix: '',
+                        relaId: 'lid'
+                    }]);
                 }
             }
 
@@ -386,45 +406,39 @@ module.exports = app => {
             });
         }
 
-        async _gatherMonthData(sTender, completeData, month, hasPre) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+        async _gatherMonthData(tender, completeData, month, hasPre) {
             const stages = await this._getValidStages(tender.id);
             const stage = this.ctx.helper._.find(stages, {s_time: month});
             await this._gatherStageData(completeData, tender, stage, hasPre);
         }
 
-        async _gatherIndexData(sTender, completeData, index, hasPre) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+        async _gatherIndexData(tender, completeData, index, hasPre) {
             const stages = await this._getValidStages(tender.id);
             const stage = this.ctx.helper._.find(stages, {order: index});
             await this._gatherStageData(completeData, tender, stage, hasPre);
         }
 
-        async _gatherZoneData(sTender, completeData, zone) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+        async _gatherZoneData(tender, completeData, zone) {
             const stages = await this._getTimeZoneStages(tender, zone);
             await this._gatherStagesData(completeData, tender, stages);
         }
 
-        async _gatherIndexZoneData(sTender, completeData, stageZone) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+        async _gatherIndexZoneData(tender, completeData, stageZone) {
             const stages = await this._getOrderZoneStages(tender, stageZone);
             await this._gatherStagesData(completeData, tender, stages);
         }
 
-        async _gatherFinalData(sTender, completeData, hasPre) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+        async _gatherFinalData(tender, completeData, hasPre) {
             const stages = await this._getValidStages(tender.id);
             await this._gatherStageData(completeData, tender, stages[0], hasPre);
         }
 
-        async _gatherCheckedFinalData(sTender, completeData, hasPre) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+        async _gatherCheckedFinalData(tender, completeData, hasPre) {
             const stages = await this._getCheckedStages(tender.id);
             await this._gatherStageData(completeData, tender, stages[0], hasPre);
         }
 
-        async _gatherLedgerData(sTender, completeData) {
+        async _gatherLedgerData(tender, completeData) {
             const helper = this.ctx.helper;
             const billsTree = new Ledger.billsTree(this.ctx, {
                 id: 'ledger_id',
@@ -436,16 +450,15 @@ module.exports = app => {
                 stageId: 'id',
                 calcFields: ['deal_tp', 'total_price'],
             });
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
             const billsData = await this.ctx.service.ledger.getData(tender.id);
             billsTree.loadDatas(billsData);
             billsTree.calculateAll();
             this.resultTree.loadGatherTree(billsTree, function (gatherNode, sourceNode) {
                 gatherUtils.gatherLedger(tender, gatherNode, sourceNode, completeData.prefix, helper);
-            })
+            });
         }
 
-        async _gatherSpecialData(sTender, sKey) {
+        async _gatherSpecialData(tender, sKey) {
             const helper = this.ctx.helper;
             const billsTree = new Ledger.billsTree(this.ctx, {
                 id: 'ledger_id',
@@ -457,13 +470,12 @@ module.exports = app => {
                 stageId: 'id',
                 calcFields: ['deal_tp', 'total_price'],
             });
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
             const billsData = await this.ctx.service.ledger.getData(tender.id);
             billsTree.loadDatas(billsData);
             billsTree.calculateAll();
             this.resultTree.loadGatherTree(billsTree, function (gatherNode, sourceNode) {
                 gatherUtils.gatherSpecial(gatherNode, sourceNode, 'ts_' + sKey + '_', helper);
-            })
+            });
         }
 
         async getGatherStageBills(memFieldKeys, gsDefine, gsCustom) {
@@ -473,40 +485,46 @@ module.exports = app => {
             const gsSetting = JSON.parse(gsDefine.setting);
             let commonIndex = 0;
             const completeDatas = [];
-            for (const tender of gsCustom.tenders) {
-                const specialKey = this._checkSpecialTender(tender, gsSetting.special);
-                if (specialKey === '') {
-                    const completeData = {
-                        prefix: 't_' + commonIndex + '_',
-                    };
-                    completeDatas.push(completeData);
-                    switch (gsSetting.type) {
-                        case 'month':
-                            await this._gatherMonthData(tender, completeData, gsCustom.month, gsSetting.hasPre);
-                            break;
-                        case 'zone':
-                            await this._gatherZoneData(tender, completeData, gsCustom.zone);
-                            break;
-                        case 'final':
-                            await this._gatherFinalData(tender, completeData, gsSetting.hasPre);
-                            break;
-                        case 'checked-final':
-                            await this._gatherCheckedFinalData(tender, completeData, gsSetting.hasPre);
-                            break;
-                        case 'ledger':
-                            await this._gatherLedgerData(tender, completeData);
-                            break;
-                        case 'stage':
-                            await this._gatherIndexData(tender, completeData, gsCustom.stage, gsSetting.hasPre);
-                            break;
-                        case 'stage-zone':
-                            await this._gatherIndexZoneData(tender, completeData, gsCustom.stage_zone);
-                            break;
+            for (const t of gsCustom.tenders) {
+                const specialKey = this._checkSpecialTender(t, gsSetting.special);
+                const tender = await this.ctx.service.tender.getCheckTender(t.tid);
+                this.ctx.query_tender = tender;
+                try {
+                    if (specialKey === '') {
+                        const completeData = {
+                            prefix: 't_' + commonIndex + '_',
+                        };
+                        completeDatas.push(completeData);
+                        switch (gsSetting.type) {
+                            case 'month':
+                                await this._gatherMonthData(tender, completeData, gsCustom.month, gsSetting.hasPre);
+                                break;
+                            case 'zone':
+                                await this._gatherZoneData(tender, completeData, gsCustom.zone);
+                                break;
+                            case 'final':
+                                await this._gatherFinalData(tender, completeData, gsSetting.hasPre);
+                                break;
+                            case 'checked-final':
+                                await this._gatherCheckedFinalData(tender, completeData, gsSetting.hasPre);
+                                break;
+                            case 'ledger':
+                                await this._gatherLedgerData(tender, completeData);
+                                break;
+                            case 'stage':
+                                await this._gatherIndexData(tender, completeData, gsCustom.stage, gsSetting.hasPre);
+                                break;
+                            case 'stage-zone':
+                                await this._gatherIndexZoneData(tender, completeData, gsCustom.stage_zone);
+                                break;
+                        }
+                        commonIndex++;
+                    } else {
+                        await this._gatherSpecialData(tender, specialKey);
                     }
-                    commonIndex++;
-                } else {
-                    await this._gatherSpecialData(tender, specialKey);
+                } catch(err) {
                 }
+                this.ctx.query_tender = null;
             }
 
             this.resultTree.generateSortNodes();
@@ -580,8 +598,7 @@ module.exports = app => {
             info.gather_tp = helper.add(info.contract_tp, info.qc_tp);
         }
 
-        async _gatherMonthTenderInfo(sTender, index, month, hasPre) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+        async _gatherMonthTenderInfo(tender, index, month, hasPre) {
             const info = await this._getBaseTenderInfo(tender);
             const stages = await this._getValidStages(tender.id);
             const stage = this.ctx.helper._.find(stages, {s_time: month});
@@ -589,8 +606,7 @@ module.exports = app => {
             this.resultTenderInfo.push(info);
         }
 
-        async _gatherOrderTenderInfo(sTender, index, order, hasPre) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+        async _gatherOrderTenderInfo(tender, index, order, hasPre) {
             const info = await this._getBaseTenderInfo(tender);
             const stages = await this._getValidStages(tender.id);
             const stage = this.ctx.helper._.find(stages, {order: order});
@@ -598,47 +614,40 @@ module.exports = app => {
             this.resultTenderInfo.push(info);
         }
 
-        async _gatherZoneTenderInfo(sTender, index, zone) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+        async _gatherZoneTenderInfo(tender, index, zone) {
             const info = await this._getBaseTenderInfo(tender);
             const stages = await this._getTimeZoneStages(tender, zone);
             await this._getStagesTenderInfo(stages, info);
             this.resultTenderInfo.push(info);
         }
 
-        async _gatherOrderZoneTenderInfo(sTender, index, stageZone) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+        async _gatherOrderZoneTenderInfo(tender, index, stageZone) {
             const info = await this._getBaseTenderInfo(tender);
             const stages = await this._getOrderZoneStages(tender, stageZone);
             await this._getStagesTenderInfo(stages, info);
             this.resultTenderInfo.push(info);
         }
 
-        async _gatherFinalTenderInfo(sTender, index, hasPre) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+        async _gatherFinalTenderInfo(tender, index, hasPre) {
             const info = await this._getBaseTenderInfo(tender);
             const stages = await this._getValidStages(tender.id);
             await this._getStageTenderInfo(stages[0], info);
             this.resultTenderInfo.push(info);
         }
 
-        async _gatherCheckedFinalTenderInfo(sTender, index, hasPre) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+        async _gatherCheckedFinalTenderInfo(tender, index, hasPre) {
             const info = await this._getBaseTenderInfo(tender);
             const stages = await this._getCheckedStages(tender.id);
             await this._getStageTenderInfo(stages[0], info);
             this.resultTenderInfo.push(info);
         }
 
-        async _gatherLedgerTenderInfo(sTender, index) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+        async _gatherLedgerTenderInfo(tender, index) {
             const info = await this._getBaseTenderInfo(tender);
             this.resultTenderInfo.push(info);
         }
 
-        async _gatherSpecialTenderInfo(sTender, sKey) {
-            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
-
+        async _gatherSpecialTenderInfo(tender, sKey) {
             const info = await this._getBaseTenderInfo(tender);
             info.spec = sKey;
             this.resultTenderInfo.push(info);
@@ -651,36 +660,42 @@ module.exports = app => {
             this.resultTenderInfo = [];
             const gsSetting = JSON.parse(gsDefine.setting);
             let commonIndex = 0;
-            for (const tender of gsCustom.tenders) {
-                const specialKey = this._checkSpecialTender(tender, gsSetting.special);
-                if (specialKey === '') {
-                    switch (gsSetting.type) {
-                        case 'month':
-                            await this._gatherMonthTenderInfo(tender, commonIndex, gsCustom.month, gsSetting.hasPre);
-                            break;
-                        case 'zone':
-                            await this._gatherZoneTenderInfo(tender, commonIndex, gsCustom.zone);
-                            break;
-                        case 'final':
-                            await this._gatherFinalTenderInfo(tender, commonIndex, gsSetting.hasPre);
-                            break;
-                        case 'checked-final':
-                            await this._gatherCheckedFinalTenderInfo(tender, commonIndex, gsSetting.hasPre);
-                            break;
-                        case 'ledger':
-                            await this._gatherLedgerTenderInfo(tender, commonIndex);
-                            break;
-                        case 'stage':
-                            await this._gatherOrderTenderInfo(tender, commonIndex, gsCustom.stage, gsSetting.hasPre);
-                            break;
-                        case 'stage-zone':
-                            await this._gatherOrderZoneTenderInfo(tender, commonIndex, gsCustom.stage_zone);
-                            break;
+            for (const t of gsCustom.tenders) {
+                const specialKey = this._checkSpecialTender(t, gsSetting.special);
+                const tender = await this.ctx.service.tender.getCheckTender(t.tid);
+                this.ctx.query_tender = tender;
+                try {
+                    if (specialKey === '') {
+                        switch (gsSetting.type) {
+                            case 'month':
+                                await this._gatherMonthTenderInfo(tender, commonIndex, gsCustom.month, gsSetting.hasPre);
+                                break;
+                            case 'zone':
+                                await this._gatherZoneTenderInfo(tender, commonIndex, gsCustom.zone);
+                                break;
+                            case 'final':
+                                await this._gatherFinalTenderInfo(tender, commonIndex, gsSetting.hasPre);
+                                break;
+                            case 'checked-final':
+                                await this._gatherCheckedFinalTenderInfo(tender, commonIndex, gsSetting.hasPre);
+                                break;
+                            case 'ledger':
+                                await this._gatherLedgerTenderInfo(tender, commonIndex);
+                                break;
+                            case 'stage':
+                                await this._gatherOrderTenderInfo(tender, commonIndex, gsCustom.stage, gsSetting.hasPre);
+                                break;
+                            case 'stage-zone':
+                                await this._gatherOrderZoneTenderInfo(tender, commonIndex, gsCustom.stage_zone);
+                                break;
+                        }
+                        commonIndex++;
+                    } else {
+                        await this._gatherSpecialTenderInfo(tender, specialKey);
                     }
-                    commonIndex++;
-                } else {
-                    await this._gatherSpecialTenderInfo(tender, specialKey);
+                } catch (err) {
                 }
+                this.ctx.query_tender = null;
             }
             return this.resultTenderInfo;
         }

+ 8 - 0
app/service/schedule_ledger_month.js

@@ -114,6 +114,14 @@ module.exports = app => {
             };
             return await transaction.update(this.ctx.service.scheduleMonth.tableName, updateData, option);
         }
+
+        async getConllectionList(tid, yearmonthArray) {
+            const sql = 'SELECT tid, lid, SUM(`plan_gcl`) as plan_gcl, SUM(`plan_tp`) as plan_tp' +
+                ' FROM ?? WHERE `tid` = ? AND `yearmonth` in (?) GROUP BY `lid`';
+            const sqlParam = [this.tableName, tid, yearmonthArray];
+            const result = await this.db.query(sql, sqlParam);
+            return result;
+        }
     }
     return ScheduleLedgerMonth;
 };

+ 3 - 0
app/service/tender.js

@@ -269,6 +269,7 @@ module.exports = app => {
          * @return {Promise<boolean>} - 结果
          */
         async deleteTenderNoBackup(id) {
+            this.ctx.query_tender = await this.ctx.service.tender.getDataById(id);
             const transaction = await this.db.beginTransaction();
             try {
                 const tenderMsg = await this.getDataById(id);
@@ -331,10 +332,12 @@ module.exports = app => {
                 // 记录删除日志
                 await this.ctx.service.projectLog.addProjectLog(transaction, projectLogConst.type.tender, projectLogConst.status.delete, tenderMsg.name, id);
                 await transaction.commit();
+                this.ctx.query_tender = null;
                 return true;
             } catch (err) {
                 this.ctx.helper.log(err);
                 await transaction.rollback();
+                this.ctx.query_tender = null;
                 return false;
             }
         }

+ 3 - 3
app/view/layout/menu.ejs

@@ -29,9 +29,9 @@
         <ul class="nav nav-pills nav-stacked bg-nav">
             <li <% if (ctx.controllerName === 'setting') { %>class="active"<% } %>><a href="/setting/info" data-toggle="tooltip" data-placement="right" title="" data-original-title="项目信息"><i class="fa fa-cogs"></i><span>项目信息</span></a></li>
         </ul>
-        <div class="dropup mb-1 ml-1">
-            <a href="" class="btn btn-sm btn-light" data-toggle="dropdown" aria-haspopup="false" aria-expanded="false">
-                <%- ctx.session.sessionUser.name.substr(ctx.session.sessionUser.name.length > 2 ? ctx.session.sessionUser.name.length - 2 : 0) %>
+        <div class="dropup mb-1 ml-1 mr-1">
+            <a href="" class="btn btn-sm btn-light p-1 w-100" data-toggle="dropdown" aria-haspopup="false" aria-expanded="false">
+                <%- ctx.session.sessionUser.name.substr(ctx.session.sessionUser.name.length > 3 ? ctx.session.sessionUser.name.length - 3 : 0) %>
             </a>
             <div class="dropdown-menu">
                 <a href="/profile/info" class="dropdown-item">账号资料</a>

+ 0 - 2
app/view/ledger/bwtz.ejs

@@ -53,7 +53,6 @@
                                         </div>
                                     </a>
                                 </div>
-                                <% if (ctx.app.config.is_debug) {%>
                                 <div class="d-inline-block">
                                     <div class="input-group input-group-sm ml-2">
                                         <div class="input-group-prepend">
@@ -65,7 +64,6 @@
                                 <div class="d-inline-block ml-2">
                                     <div class="alert-warning p-1"><i class="fa Example of exclamation-circle fa-exclamation-circle "></i> 父项/子项任一符合,均显示</div>
                                 </div>
-                                <% } %>
                             </li>
                         </ul>
                     </div>

+ 1 - 1
app/view/schedule/plan_modal.ejs

@@ -33,7 +33,7 @@
                     <% for (const m of scheduleMonth) { %>
                     <tr>
                         <td><%- m.yearmonth %></td>
-                        <td><% if (m.stage_gcl_used === 0 && m.stage_tp_used) { %><label></label><input type="checkbox" value="<%- m.id %>"><% } %></td>
+                        <td><% if (m.stage_gcl_used === 0 && m.stage_tp_used === 0) { %><label></label><input type="checkbox" value="<%- m.id %>"><% } %></td>
                     </tr>
                     <% } %>
                 </table>

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

@@ -58,4 +58,8 @@
     const scheduleMonth = JSON.parse('<%- JSON.stringify(scheduleMonth) %>');
     const curScheduleStage = JSON.parse('<%- JSON.stringify(curScheduleStage) %>');
     const monthList = _.map(scheduleMonth, 'yearmonth');
+    const slmList = JSON.parse('<%- JSON.stringify(slmList) %>');
+    const nextSlmList = JSON.parse('<%- JSON.stringify(nextSlmList) %>');
+    const endSlmList = JSON.parse('<%- JSON.stringify(endSlmList) %>');
+    const yearSlmList = JSON.parse('<%- JSON.stringify(yearSlmList) %>');
 </script>

+ 13 - 13
app/view/schedule/stage_tp_modal.ejs

@@ -3,28 +3,28 @@
     <div class="modal-dialog" role="document">
         <div class="modal-content">
             <div class="modal-header">
-                <h5 class="modal-title">创建实际计量</h5>
+                <h5 class="modal-title">创建新计量进度</h5>
             </div>
             <div class="modal-body">
                 <div class="form-group">
-                    <label>计划进度月</label>
-                    <select class="form-control" id="month_list">
-                        <option value="0">选择计划进度月</option>
-                        <% for (const m of scheduleMonth) { %>
-                        <% if (!ctx.helper._.find(scheduleStage, { yearmonth: m.yearmonth })) { %>
-                        <option value="<%- m.yearmonth %>"><%- m.yearmonth.split('-')[0] %>年<%- parseInt(m.yearmonth.split('-')[1]) %>月 %></option>
-                        <% } %>
-                        <% } %>
-                    </select>
-                </div>
-                <div class="form-group">
                     <label>计量期</label>
                     <select class="form-control" id="stage_list">
                         <option value="0">选择计量期</option>
                         <% for (const so of stageOrderList) { %>
                         <% if (!ctx.helper._.find(scheduleStage, { order: so.order })) { %>
-                        <option value="<%- so.order %>">第<%- so.order %>期</option>
+                        <option value="<%- so.order %>">第<%- so.order %>期(<%- so.s_time %>)</option>
+                        <% } %>
                         <% } %>
+                    </select>
+                </div>
+                <div class="form-group">
+                    <label>计划进度月</label>
+                    <select class="form-control" id="month_list">
+                        <option value="0">选择计划进度月</option>
+                        <% for (const m of scheduleMonth) { %>
+                            <% if (!ctx.helper._.find(scheduleStage, { yearmonth: m.yearmonth })) { %>
+                                <option value="<%- m.yearmonth %>"><%- m.yearmonth.split('-')[0] %>年<%- parseInt(m.yearmonth.split('-')[1]) %>月 %></option>
+                            <% } %>
                         <% } %>
                     </select>
                 </div>

+ 0 - 2
app/view/stage/bwtz.ejs

@@ -65,7 +65,6 @@
                                         </div>
                                     </a>
                                 </div>
-                                <% if (ctx.app.config.is_debug) {%>
                                 <div class="d-inline-block">
                                     <div class="input-group input-group-sm ml-2">
                                         <div class="input-group-prepend">
@@ -77,7 +76,6 @@
                                 <div class="d-inline-block ml-2">
                                     <div class="alert-warning p-1"><i class="fa Example of exclamation-circle fa-exclamation-circle "></i> 父项/子项任一符合,均显示</div>
                                 </div>
-                                <% } %>
                             </li>
                         </ul>
                     </div>

+ 1 - 1
app/view/stage_extra/bonus_modal.ejs

@@ -9,7 +9,7 @@
                 <% if (!ctx.stage.readOnly) { %>
                 <div class="form-group" id="upload-file-panel">
                     <label for="formGroupExampleInput">大小限制:30MB,支持<span data-toggle="tooltip" data-placement="bottom" title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="rar,zip">压缩包格式</span></label>
-                    <input type="file" class="" id="upload-file" multiple onclick="file">
+                    <input type="file" class="" id="upload-file" multiple>
                 </div>
                 <% } %>
                 <div class="modal-height-500" style="overflow:auto;">

+ 26 - 4
app/view/tender/shenpi.ejs

@@ -40,8 +40,19 @@
                                             <span class="col-auto"><%- ctx.helper.transFormToChinese(i+1) %>审</span>
                                             <span class="col-7 spr-span">
                                                 <span class="d-inline-block"></span>
-                                                <span class="d-inline-block"><span class="badge badge-light"><%- audit.name %> <a href="javascript:void(0);" class="remove-audit btn-sm text-danger px-1" title="移除" data-id="<%- audit.audit_id %>"><i class="fa fa-remove"></i></a></span> </span>
-                                            </span>
+                                                <span class="d-inline-block"><span class="badge badge-light"><%- audit.name %> <span class="dropdown">
+                                                            <a href="javascript:void(0);" class="btn-sm text-danger px-1" title="移除" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-remove"></i></a>
+                                                            <div class="dropdown-menu">
+                                                                <a class="dropdown-item" href="javascript:void(0);">确认移除审批人?</a>
+                                                                <div class="dropdown-divider"></div>
+                                                                <div class="px-2 py-1 text-center">
+                                                                    <button class="remove-audit btn btn-sm btn-danger" data-id="<%- audit.audit_id %>">移除</button>
+                                                                    <button class="btn btn-sm btn-secondary">取消</button>
+                                                                </div>
+                                                            </div>
+                                                        </span>
+                                                        <!--<a href="javascript:void(0);" class="remove-audit btn-sm text-danger px-1" title="移除" ><i class="fa fa-remove"></i></a></span> </span>-->
+                                            </span></span></span>
                                         </li>
                                         <% } %>
                                         <li class="pl-3"><a href="javascript:void(0);" class="add-audit" ><i class="fa fa-plus"></i> 添加流程</a></li>
@@ -93,8 +104,19 @@
                                             <span class="col-auto">终审</span>
                                             <span class="col-7 spr-span">
                                             <span class="d-inline-block"></span>
-                                            <span class="d-inline-block"><span class="badge badge-light"><%- sp.audit.name %> <a href="javascript:void(0);" class="remove-audit btn-sm text-danger px-1" title="移除" data-id="<%- sp.audit.audit_id %>"><i class="fa fa-remove"></i></a></span> </span>
-                                            </span>
+                                            <span class="d-inline-block"><span class="badge badge-light"><%- sp.audit.name %> <span class="dropdown">
+                                                            <a href="javascript:void(0);" class="btn-sm text-danger px-1" title="移除" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-remove"></i></a>
+                                                            <div class="dropdown-menu">
+                                                                <a class="dropdown-item" href="javascript:void(0);">确认移除审批人?</a>
+                                                                <div class="dropdown-divider"></div>
+                                                                <div class="px-2 py-1 text-center">
+                                                                    <button class="remove-audit btn btn-sm btn-danger" data-id="<%- sp.audit.audit_id %>">移除</button>
+                                                                    <button class="btn btn-sm btn-secondary">取消</button>
+                                                                </div>
+                                                            </div>
+                                                        </span>
+                                                    <!--<a href="javascript:void(0);" class="remove-audit btn-sm text-danger px-1" title="移除" data-id=""><i class="fa fa-remove"></i></a></span> </span>-->
+                                            </span></span></span>
                                         </li>
                                         <% } else { %>
                                         <li class="d-flex justify-content-start mb-3">

+ 1 - 0
config/config.default.js

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

+ 3 - 13
db_script/stage-change-final.js

@@ -10,20 +10,10 @@
 const audit = require('../app/const/audit');
 
 const mysql = require('mysql');
+const config = process.argv.splice(2);
+const mysqlOptions = require(`../config/config.${config}`)({ baseDir: __dirname + '/app', root: __dirname, name: 'calc' }).mysql;
 
-const pool = mysql.createPool({
-    // host
-    host: '192.168.1.76',
-    // 端口号
-    port: '3306',
-    // 用户名
-    user: 'zh_dev',
-    // 密码
-    password: 'zongheng2019',
-    // 数据库名
-    database: 'calculation',
-    // database: 'calc_copy_pro',
-});
+const pool = mysql.createPool(mysqlOptions);
 
 const querySql = async function (sql, sqlParam) {
     return new Promise(function (resolve, reject) {

+ 19 - 0
sql/update.sql

@@ -23,3 +23,22 @@ ADD COLUMN `check_calc`  tinyint(1) NULL DEFAULT 1 COMMENT '是否检查计算'
 
 ALTER TABLE `zh_revise_bills`
 ADD COLUMN `check_calc`  tinyint(1) NULL DEFAULT 1 COMMENT '是否检查计算' AFTER `dagl_url`;
+
+-- ----------------------------
+-- Table structure for zh_project_log
+-- ----------------------------
+CREATE TABLE `zh_project_log` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `pid` int(11) NOT NULL COMMENT '操作项目',
+  `tid` int(11) NOT NULL COMMENT '操作标段',
+  `uid` int(11) NOT NULL COMMENT '操作人',
+  `type` tinyint(1) NOT NULL COMMENT '操作模块',
+  `status` tinyint(1) NOT NULL COMMENT '操作状态',
+  `msg` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '操作名称',
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
+  `os` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '系统信息',
+  `browser` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '浏览器信息',
+  `ip` varchar(45) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '操作人IP地址',
+  `address` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '操作人地址(接口获取)',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='项目操作日志';