|
|
@@ -0,0 +1,112 @@
|
|
|
+'use strict';
|
|
|
+
|
|
|
+const PermissionCheck = require('../const/account_permission').PermissionCheck;
|
|
|
+
|
|
|
+// 安全、质量巡检共用附件阶段及操作权限规则。
|
|
|
+class InspectionAttachment {
|
|
|
+ constructor(ctx, type) {
|
|
|
+ if (!['safe', 'quality'].includes(type)) throw '无效的巡检类型';
|
|
|
+ this.ctx = ctx;
|
|
|
+ this.inspectionService = ctx.service[type + 'Inspection'];
|
|
|
+ this.auditService = ctx.service[type + 'InspectionAudit'];
|
|
|
+ this.attachmentService = ctx.service[type + 'InspectionAtt'];
|
|
|
+ }
|
|
|
+
|
|
|
+ getFileStage(file) {
|
|
|
+ // 尚未回填的历史数据与数据库迁移后的规则保持一致。
|
|
|
+ return file.flow_stage === null || file.flow_stage === undefined || Number(file.flow_stage) === 0 ? 1 : Number(file.flow_stage);
|
|
|
+ }
|
|
|
+
|
|
|
+ getUploadStage(inspection) {
|
|
|
+ if (inspection.flow_version === 1) return [1, 2, 3].includes(inspection.flow_stage) ? inspection.flow_stage : 0;
|
|
|
+ // 旧流程只有上报、整改,完成后的补传归入整改阶段。
|
|
|
+ if ([3, 12].includes(inspection.status)) return 2;
|
|
|
+ return [1, 2, 5, 6].includes(inspection.status) ? 1 : 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ canUpload(inspection, records) {
|
|
|
+ if (!inspection || inspection.status === 4 || !this.getUploadStage(inspection)) return false;
|
|
|
+ if (inspection.flow_version !== 1) return Boolean(inspection.filePermission);
|
|
|
+ // 页面和上传入口沿用中间件已计算的权限;事务内传入最新审批记录后重新校验。
|
|
|
+ if (!records && typeof inspection.canUpload === 'boolean') return inspection.canUpload;
|
|
|
+ const uid = this.ctx.session.sessionUser.accountId;
|
|
|
+ if ([1, 3, 5].includes(inspection.status)) return inspection.uid === uid;
|
|
|
+ const current = (records || inspection.auditors || []).filter(record => !record.is_old && record.times === inspection.times
|
|
|
+ && record.flow_stage === inspection.flow_stage && record.stage_round === inspection.stage_round);
|
|
|
+ if (inspection.flow_stage === 2) {
|
|
|
+ current.sort((a, b) => a.audit_order - b.audit_order || a.order - b.order || a.id - b.id);
|
|
|
+ const active = current.find(record => [1, 12].includes(record.status));
|
|
|
+ return inspection.status === 12 && Boolean(active && active.aid === uid && active.status === 12);
|
|
|
+ }
|
|
|
+ return [2, 6].includes(inspection.status) && current.some(record => record.aid === uid && record.status === 2);
|
|
|
+ }
|
|
|
+
|
|
|
+ canDeleteFile(file, inspection, records) {
|
|
|
+ if (!file || !inspection || file.tid !== inspection.tid || file.qiid !== inspection.id) return false;
|
|
|
+ if (file.uid !== this.ctx.session.sessionUser.accountId || !this.canUpload(inspection, records)) return false;
|
|
|
+ if (this.getFileStage(file) !== this.getUploadStage(inspection)) return false;
|
|
|
+ return inspection.status !== 3 || Boolean(file.extra_upload) || PermissionCheck.delFile(this.ctx.session.sessionUser.permission);
|
|
|
+ }
|
|
|
+
|
|
|
+ async getFiles(qiid) {
|
|
|
+ if (this.ctx.inspection) this.ctx.inspection.canUploadAttachments = this.canUpload(this.ctx.inspection);
|
|
|
+ const files = await this.attachmentService.getAllAtt(this.ctx.tender.id, qiid);
|
|
|
+ return files.map(file => Object.assign(file, {
|
|
|
+ flow_stage: this.getFileStage(file),
|
|
|
+ stageName: ['', '上报', '整改', '批复'][this.getFileStage(file)] || '未知阶段',
|
|
|
+ canDelete: this.canDeleteFile(file, this.ctx.inspection),
|
|
|
+ }));
|
|
|
+ }
|
|
|
+
|
|
|
+ async saveFiles(files, flowContext) {
|
|
|
+ const transaction = await this.attachmentService.beginTransaction();
|
|
|
+ try {
|
|
|
+ const { current } = await this.getCurrentContext(transaction, flowContext);
|
|
|
+ if (!files.length) throw '请选择附件';
|
|
|
+ const payload = files.map(file => Object.assign({}, file, {
|
|
|
+ tid: current.tid, qiid: current.id, uid: this.ctx.session.sessionUser.accountId,
|
|
|
+ flow_stage: this.getUploadStage(current), extra_upload: current.status === 3,
|
|
|
+ }));
|
|
|
+ const result = await this.attachmentService.saveFileMsgToDb(payload, transaction);
|
|
|
+ await transaction.commit();
|
|
|
+ return result;
|
|
|
+ } catch (err) {
|
|
|
+ await transaction.rollback();
|
|
|
+ throw err;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async deleteFile(id, flowContext) {
|
|
|
+ id = Number(id);
|
|
|
+ if (!Number.isSafeInteger(id) || id <= 0) throw '无效的附件';
|
|
|
+ const transaction = await this.attachmentService.beginTransaction();
|
|
|
+ try {
|
|
|
+ const { current, records } = await this.getCurrentContext(transaction, flowContext);
|
|
|
+ const file = await this.attachmentService.getMaterialFileById(id, transaction);
|
|
|
+ if (!this.canDeleteFile(file, current, records)) throw '只能删除本人在当前阶段上传的附件';
|
|
|
+ await this.ctx.app.fujianOss.delete(this.ctx.app.config.fujianOssFolder + file.filepath);
|
|
|
+ await this.attachmentService.delete(id, transaction);
|
|
|
+ await transaction.commit();
|
|
|
+ } catch (err) {
|
|
|
+ await transaction.rollback();
|
|
|
+ throw err;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async getCurrentContext(transaction, flowContext) {
|
|
|
+ const { ctx } = this;
|
|
|
+ const rows = await this.inspectionService.getAllDataForUpdate({ id: ctx.inspection.id, tid: ctx.tender.id }, transaction);
|
|
|
+ const current = rows[0];
|
|
|
+ if (!current) throw '巡检不存在';
|
|
|
+ const fields = ['flow_version', 'flow_stage', 'stage_round', 'times', 'status'];
|
|
|
+ if (!flowContext || fields.some(key => Number(flowContext[key]) !== Number(current[key]) || Number(ctx.inspection[key]) !== Number(current[key]))) {
|
|
|
+ throw '流程已更新,请刷新后操作附件';
|
|
|
+ }
|
|
|
+ current.filePermission = ctx.inspection.filePermission;
|
|
|
+ const records = await this.auditService.getAllDataByCondition({ where: { qiid: current.id, times: current.times, is_old: 0 } }, transaction);
|
|
|
+ if (!this.canUpload(current, records)) throw '当前不可操作附件';
|
|
|
+ return { current, records };
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+module.exports = InspectionAttachment;
|