|
@@ -8,13 +8,18 @@
|
|
|
* @version
|
|
|
*/
|
|
|
|
|
|
-const Service = require('egg').Service;
|
|
|
const StageIm = require('../lib/stage_im');
|
|
|
const imType = require('../const/tender').imType;
|
|
|
const audit = require('../const/audit');
|
|
|
+// const path = require('path');
|
|
|
+// const fs = require('fs');
|
|
|
+
|
|
|
+const stageImTz = 'mem_stage_im_tz';
|
|
|
+const stageImTzBills = 'mem_stage_im_tz_bills';
|
|
|
+const stageImZl = 'mem_stage_im_zl';
|
|
|
|
|
|
module.exports = app => {
|
|
|
- class ReportMemory extends Service {
|
|
|
+ class ReportMemory extends app.BaseService {
|
|
|
|
|
|
/**
|
|
|
* 构造函数
|
|
@@ -24,69 +29,117 @@ module.exports = app => {
|
|
|
*/
|
|
|
constructor(ctx) {
|
|
|
super(ctx);
|
|
|
- this.db = this.app.mysql;
|
|
|
- this.cache = this.app.redis;
|
|
|
- this._ = this.app._;
|
|
|
+ this.tableName = 'report_memory';
|
|
|
// 需要缓存的数据
|
|
|
this.stageImData = null;
|
|
|
}
|
|
|
|
|
|
async _checkTender(tid) {
|
|
|
+ if (this.ctx.tender) return;
|
|
|
const tender = await this.ctx.service.tender.getTender(tid);
|
|
|
tender.info = await this.ctx.service.tenderInfo.getTenderInfo(tid);
|
|
|
this.ctx.tender = tender;
|
|
|
}
|
|
|
|
|
|
async _checkStage(sid) {
|
|
|
- const status = audit.stage.status;
|
|
|
- const stage = await this.ctx.service.stage.getDataById(sid);
|
|
|
- stage.auditors = await this.ctx.service.stageAudit.getAuditors(stage.id, stage.times);
|
|
|
- stage.curAuditor = await this.ctx.service.stageAudit.getCurAuditor(stage.id, stage.times);
|
|
|
-
|
|
|
- const accountId = this.ctx.session.sessionUser.accountId, auditorIds = this._.map(stage.auditors, 'aid'), shareIds = [];
|
|
|
- if (accountId === stage.user_id) { // 原报
|
|
|
- if (stage.curAuditor) {
|
|
|
- stage.readOnly = stage.curAuditor.aid !== accountId;
|
|
|
- } else {
|
|
|
- stage.readOnly = stage.status !== status.uncheck && stage.status !== status.checkNo;
|
|
|
- }
|
|
|
- stage.curTimes = stage.times;
|
|
|
- if (stage.status === status.uncheck || stage.status === status.checkNo) {
|
|
|
- stage.curOrder = 0;
|
|
|
- } else if (stage.status === status.checked) {
|
|
|
- stage.curOrder = this._.max(this._.map(stage.auditors, 'order'));
|
|
|
- } else {
|
|
|
- stage.curOrder = stage.curAuditor.aid === accountId ? stage.curAuditor.order : stage.curAuditor.order - 1;
|
|
|
- }
|
|
|
- } else if (auditorIds.indexOf(accountId) !== -1) { // 审批人
|
|
|
- if (stage.status === status.uncheck) {
|
|
|
- throw '您无权查看该数据';
|
|
|
- }
|
|
|
- stage.curTimes = stage.status === status.checkNo ? stage.times - 1 : stage.times;
|
|
|
- if (stage.status === status.checked) {
|
|
|
- stage.curOrder = this._.max(this._.map(stage.auditors, 'order'));
|
|
|
- } else if (stage.status === status.checkNo) {
|
|
|
- const audit = await this.service.stageAudit.getDataByCondition({
|
|
|
- sid: stage.id, times: stage.times - 1, status: status.checkNo
|
|
|
- });
|
|
|
- stage.curOrder = audit.order;
|
|
|
- } else {
|
|
|
- stage.curOrder = accountId === stage.curAuditor.aid ? stage.curAuditor.order : stage.curAuditor.order - 1;
|
|
|
- }
|
|
|
- } else if (shareIds.indexOf(accountId) !== -1) { // 分享人
|
|
|
- if (stage.status === status.uncheck) {
|
|
|
- throw '您无权查看该数据';
|
|
|
+ if (!this.ctx.stage) {
|
|
|
+ const status = audit.stage.status;
|
|
|
+ const stage = await this.ctx.service.stage.getDataById(sid);
|
|
|
+ stage.auditors = await this.ctx.service.stageAudit.getAuditors(stage.id, stage.times);
|
|
|
+ stage.curAuditor = await this.ctx.service.stageAudit.getCurAuditor(stage.id, stage.times);
|
|
|
+
|
|
|
+ const accountId = this.ctx.session.sessionUser.accountId, auditorIds = this._.map(stage.auditors, 'aid'), shareIds = [];
|
|
|
+ if (accountId === stage.user_id) { // 原报
|
|
|
+ if (stage.curAuditor) {
|
|
|
+ stage.readOnly = stage.curAuditor.aid !== accountId;
|
|
|
+ } else {
|
|
|
+ stage.readOnly = stage.status !== status.uncheck && stage.status !== status.checkNo;
|
|
|
+ }
|
|
|
+ stage.curTimes = stage.times;
|
|
|
+ if (stage.status === status.uncheck || stage.status === status.checkNo) {
|
|
|
+ stage.curOrder = 0;
|
|
|
+ } else if (stage.status === status.checked) {
|
|
|
+ stage.curOrder = this._.max(this._.map(stage.auditors, 'order'));
|
|
|
+ } else {
|
|
|
+ stage.curOrder = stage.curAuditor.aid === accountId ? stage.curAuditor.order : stage.curAuditor.order - 1;
|
|
|
+ }
|
|
|
+ } else if (auditorIds.indexOf(accountId) !== -1) { // 审批人
|
|
|
+ if (stage.status === status.uncheck) {
|
|
|
+ throw '您无权查看该数据';
|
|
|
+ }
|
|
|
+ stage.curTimes = stage.status === status.checkNo ? stage.times - 1 : stage.times;
|
|
|
+ if (stage.status === status.checked) {
|
|
|
+ stage.curOrder = this._.max(this._.map(stage.auditors, 'order'));
|
|
|
+ } else if (stage.status === status.checkNo) {
|
|
|
+ const audit = await this.service.stageAudit.getDataByCondition({
|
|
|
+ sid: stage.id, times: stage.times - 1, status: status.checkNo
|
|
|
+ });
|
|
|
+ stage.curOrder = audit.order;
|
|
|
+ } else {
|
|
|
+ stage.curOrder = accountId === stage.curAuditor.aid ? stage.curAuditor.order : stage.curAuditor.order - 1;
|
|
|
+ }
|
|
|
+ } else if (shareIds.indexOf(accountId) !== -1) { // 分享人
|
|
|
+ if (stage.status === status.uncheck) {
|
|
|
+ throw '您无权查看该数据';
|
|
|
+ }
|
|
|
+ stage.curTimes = stage.status === status.checkNo ? stage.times - 1 : stage.times;
|
|
|
+ stage.curOrder = stage.status === status.checked ? this._.max(this._.map(stage.auditors, 'order')) : stage.curAuditor.order - 1;
|
|
|
}
|
|
|
- stage.curTimes = stage.status === status.checkNo ? stage.times - 1 : stage.times;
|
|
|
- stage.curOrder = stage.status === status.checked ? this._.max(this._.map(stage.auditors, 'order')) : stage.curAuditor.order - 1;
|
|
|
+
|
|
|
+ this.ctx.stage = stage;
|
|
|
+ this.ctx.stage.cacheTime = this.ctx.stage.readOnly ? (this.ctx.stage.cache_time_r).getTime(): (this.ctx.stage.cache_time_l).getTime();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // build-time: 162-384ms, redis-cache: 0-41ms, mysql + IO: 116-146ms
|
|
|
+ // 一定程度上算是大Value缓存,数据多了以后:
|
|
|
+ // 1. 达到redis内存阈值时,数据会swap到磁盘,此时将消耗IO时间
|
|
|
+ // 2. redis单独服务器
|
|
|
+ // 3. redis集群
|
|
|
+ async _getReportMemoryCache(name, tid, sid, time) {
|
|
|
+ // redis
|
|
|
+ const cacheKey = name + '-t' + tid + (sid ? '-s' + sid : '') + (time ? '-' + time : '');
|
|
|
+ const data = await this.cache.get(cacheKey);
|
|
|
+ if (data) {
|
|
|
+ return eval(data);
|
|
|
+ } else {
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
- this.ctx.stage = stage;
|
|
|
+ // mysql + IO
|
|
|
+ // const rm = await this.getDataByCondition({
|
|
|
+ // tid: tid, sid: sid, name: name, time: time
|
|
|
+ // });
|
|
|
+ // if (rm && rm.file) {
|
|
|
+ // const file = path.join(this.ctx.app.config.filePath, 'report', 'cache', rm.file);
|
|
|
+ // if (fs.existsSync(file)) {
|
|
|
+ // const data = await fs.readFileSync(file, 'utf8');
|
|
|
+ // return eval(data);
|
|
|
+ // } else {
|
|
|
+ // return null;
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ }
|
|
|
+
|
|
|
+ async _setReportMemoryCache(name, tid, sid, time, data) {
|
|
|
+ // redis
|
|
|
+ const cacheKey = name + '-t' + tid + (sid ? '-s' + sid : '') + (time ? '-' + time : '');
|
|
|
+ this.cache.set(cacheKey, JSON.stringify(data), 'EX', this.ctx.app.config.cacheTime);
|
|
|
+
|
|
|
+ // mysql + IO
|
|
|
+ // const file = path.join('report', 'cache', 'rm' + (new Date()).getTime() + '.json');
|
|
|
+ // await this.ctx.helper.saveBufferFile(JSON.stringify(data), path.join(this.ctx.app.config.filePath, file));
|
|
|
+ // const rm = await this.getDataByCondition({
|
|
|
+ // tid: tid, sid: sid, name: name, time: time
|
|
|
+ // });
|
|
|
+ // if (rm) {
|
|
|
+ // await this.db.update(this.tableName, {id: rm.id, file: file});
|
|
|
+ // } else {
|
|
|
+ // await this.db.insert(this.tableName, {tid: tid, sid: sid, name: name, time: time, file: file});
|
|
|
+ // }
|
|
|
}
|
|
|
|
|
|
async _generateStageIm(tid, sid, isTz = true) {
|
|
|
- await this._checkTender(tid);
|
|
|
- await this._checkStage(sid);
|
|
|
if (isTz && this.ctx.stage.im_type !== imType.tz.value) {
|
|
|
throw '您查看的报表跟设置不符,请查看“总量控制”的报表';
|
|
|
} else if (!isTz && this.ctx.stage.im_type === imType.tz.value) {
|
|
@@ -97,6 +150,10 @@ module.exports = app => {
|
|
|
this.stageImData.main = stageIm.ImData;
|
|
|
if (isTz) {
|
|
|
this.stageImData.bills = stageIm.ImBillsData;
|
|
|
+ await this._setReportMemoryCache(stageImTz, tid, sid, this.ctx.stage.cacheTime, this.stageImData.main);
|
|
|
+ await this._setReportMemoryCache(stageImTzBills, tid, sid, this.ctx.stage.cacheTime, this.stageImData.bills);
|
|
|
+ } else {
|
|
|
+ await this._setReportMemoryCache(stageImZl, tid, sid, this.ctx.stage.cacheTime, this.stageImData.main);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -125,6 +182,15 @@ module.exports = app => {
|
|
|
}
|
|
|
|
|
|
async getStageImTzData(tid, sid) {
|
|
|
+ await this._checkTender(tid);
|
|
|
+ await this._checkStage(sid);
|
|
|
+ const cache = await this._getReportMemoryCache('mem_stage_im_tz', tid, sid, this.ctx.stage.cacheTime);
|
|
|
+ if (cache) {
|
|
|
+ //console.log('cache');
|
|
|
+ return cache;
|
|
|
+ }
|
|
|
+
|
|
|
+ //console.log('build');
|
|
|
if (!this.stageImData) {
|
|
|
this.stageImData = {};
|
|
|
try {
|
|
@@ -141,6 +207,11 @@ module.exports = app => {
|
|
|
}
|
|
|
|
|
|
async getStageImTzBillsData(tid, sid) {
|
|
|
+ await this._checkTender(tid);
|
|
|
+ await this._checkStage(sid);
|
|
|
+ const cache = await this._getReportMemoryCache('mem_stage_im_tz_bills', tid, sid, this.ctx.stage.cacheTime);
|
|
|
+ if (cache) return cache;
|
|
|
+
|
|
|
if (!this.stageImData) {
|
|
|
this.stageImData = {};
|
|
|
try {
|
|
@@ -157,6 +228,11 @@ module.exports = app => {
|
|
|
}
|
|
|
|
|
|
async getStageImZlData(tid, sid) {
|
|
|
+ await this._checkTender(tid);
|
|
|
+ await this._checkStage(sid);
|
|
|
+ const cache = await this._getReportMemoryCache('mem_stage_im_zl', tid, sid, this.ctx.stage.cacheTime);
|
|
|
+ if (cache) return cache;
|
|
|
+
|
|
|
this.stageImData = {};
|
|
|
try {
|
|
|
await this._generateStageIm(tid, sid, false);
|