inspection_attachment.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. 'use strict';
  2. const PermissionCheck = require('../const/account_permission').PermissionCheck;
  3. // 安全、质量巡检共用附件阶段及操作权限规则。
  4. class InspectionAttachment {
  5. constructor(ctx, type) {
  6. if (!['safe', 'quality'].includes(type)) throw '无效的巡检类型';
  7. this.ctx = ctx;
  8. this.inspectionService = ctx.service[type + 'Inspection'];
  9. this.auditService = ctx.service[type + 'InspectionAudit'];
  10. this.attachmentService = ctx.service[type + 'InspectionAtt'];
  11. }
  12. getFileStage(file) {
  13. // 尚未回填的历史数据与数据库迁移后的规则保持一致。
  14. return file.flow_stage === null || file.flow_stage === undefined || Number(file.flow_stage) === 0 ? 1 : Number(file.flow_stage);
  15. }
  16. getUploadStage(inspection) {
  17. if (inspection.flow_version === 1) return [1, 2, 3].includes(inspection.flow_stage) ? inspection.flow_stage : 0;
  18. // 旧流程只有上报、整改,完成后的补传归入整改阶段。
  19. if ([3, 12].includes(inspection.status)) return 2;
  20. return [1, 2, 5, 6].includes(inspection.status) ? 1 : 0;
  21. }
  22. canUpload(inspection, records) {
  23. if (!inspection || inspection.status === 4 || !this.getUploadStage(inspection)) return false;
  24. if (inspection.flow_version !== 1) return Boolean(inspection.filePermission);
  25. // 页面和上传入口沿用中间件已计算的权限;事务内传入最新审批记录后重新校验。
  26. if (!records && typeof inspection.canUpload === 'boolean') return inspection.canUpload;
  27. const uid = this.ctx.session.sessionUser.accountId;
  28. if ([1, 3, 5].includes(inspection.status)) return inspection.uid === uid;
  29. const current = (records || inspection.auditors || []).filter(record => !record.is_old && record.times === inspection.times
  30. && record.flow_stage === inspection.flow_stage && record.stage_round === inspection.stage_round);
  31. if (inspection.flow_stage === 2) {
  32. current.sort((a, b) => a.audit_order - b.audit_order || a.order - b.order || a.id - b.id);
  33. const active = current.find(record => [1, 12].includes(record.status));
  34. return inspection.status === 12 && Boolean(active && active.aid === uid && active.status === 12);
  35. }
  36. return [2, 6].includes(inspection.status) && current.some(record => record.aid === uid && record.status === 2);
  37. }
  38. canDeleteFile(file, inspection, records) {
  39. if (!file || !inspection || file.tid !== inspection.tid || file.qiid !== inspection.id) return false;
  40. if (file.uid !== this.ctx.session.sessionUser.accountId || !this.canUpload(inspection, records)) return false;
  41. if (this.getFileStage(file) !== this.getUploadStage(inspection)) return false;
  42. return inspection.status !== 3 || Boolean(file.extra_upload) || PermissionCheck.delFile(this.ctx.session.sessionUser.permission);
  43. }
  44. async getFiles(qiid) {
  45. if (this.ctx.inspection) this.ctx.inspection.canUploadAttachments = this.canUpload(this.ctx.inspection);
  46. const files = await this.attachmentService.getAllAtt(this.ctx.tender.id, qiid);
  47. return files.map(file => Object.assign(file, {
  48. flow_stage: this.getFileStage(file),
  49. stageName: ['', '上报', '整改', '批复'][this.getFileStage(file)] || '未知阶段',
  50. canDelete: this.canDeleteFile(file, this.ctx.inspection),
  51. }));
  52. }
  53. async saveFiles(files, flowContext) {
  54. const transaction = await this.attachmentService.beginTransaction();
  55. try {
  56. const { current } = await this.getCurrentContext(transaction, flowContext);
  57. if (!files.length) throw '请选择附件';
  58. const payload = files.map(file => Object.assign({}, file, {
  59. tid: current.tid, qiid: current.id, uid: this.ctx.session.sessionUser.accountId,
  60. flow_stage: this.getUploadStage(current), extra_upload: current.status === 3,
  61. }));
  62. const result = await this.attachmentService.saveFileMsgToDb(payload, transaction);
  63. await transaction.commit();
  64. return result;
  65. } catch (err) {
  66. await transaction.rollback();
  67. throw err;
  68. }
  69. }
  70. async deleteFile(id, flowContext) {
  71. id = Number(id);
  72. if (!Number.isSafeInteger(id) || id <= 0) throw '无效的附件';
  73. const transaction = await this.attachmentService.beginTransaction();
  74. try {
  75. const { current, records } = await this.getCurrentContext(transaction, flowContext);
  76. const file = await this.attachmentService.getMaterialFileById(id, transaction);
  77. if (!this.canDeleteFile(file, current, records)) throw '只能删除本人在当前阶段上传的附件';
  78. await this.ctx.app.fujianOss.delete(this.ctx.app.config.fujianOssFolder + file.filepath);
  79. await this.attachmentService.delete(id, transaction);
  80. await transaction.commit();
  81. } catch (err) {
  82. await transaction.rollback();
  83. throw err;
  84. }
  85. }
  86. async getCurrentContext(transaction, flowContext) {
  87. const { ctx } = this;
  88. const rows = await this.inspectionService.getAllDataForUpdate({ id: ctx.inspection.id, tid: ctx.tender.id }, transaction);
  89. const current = rows[0];
  90. if (!current) throw '巡检不存在';
  91. const fields = ['flow_version', 'flow_stage', 'stage_round', 'times', 'status'];
  92. if (!flowContext || fields.some(key => Number(flowContext[key]) !== Number(current[key]) || Number(ctx.inspection[key]) !== Number(current[key]))) {
  93. throw '流程已更新,请刷新后操作附件';
  94. }
  95. current.filePermission = ctx.inspection.filePermission;
  96. const records = await this.auditService.getAllDataByCondition({ where: { qiid: current.id, times: current.times, is_old: 0 } }, transaction);
  97. if (!this.canUpload(current, records)) throw '当前不可操作附件';
  98. return { current, records };
  99. }
  100. }
  101. module.exports = InspectionAttachment;