浏览代码

feature:
1. 添加了定时清理上传完成但没有归属的项目文档

eyes4 5 月之前
父节点
当前提交
9fe40fc5ff

+ 1 - 0
base-lib/src/core-models/BpmnWork.ts

@@ -25,6 +25,7 @@ export class BpmnWork extends Model {
     declare status: number;
     declare case_id: string;
     declare show_in_my_works: boolean;
+    declare form: any;
 
     static table_name = 'tb_bpmn_work';
 

+ 6 - 0
base-lib/src/core-models/PrjFile.ts

@@ -18,6 +18,7 @@ export class PrjFile extends Model {
     declare creator_id: string;
     declare uploaded: boolean;
     declare size: number;
+    declare associate_work_id: string;
     declare archived: boolean;
     declare req_upload_time: string;
 
@@ -93,6 +94,11 @@ export class PrjFile extends Model {
             comment: '文件大小(Bytes)',
             defaultValue: 0
         },
+        associate_work_id: {
+            type: DataTypes.STRING,
+            allowNull: true,
+            comment: '相关工单id, 工作表单中的附件在表单提交前会先上传到oss,表单提交后,要将此id写入到dependent_id中'
+        },
         archived: {
             type: DataTypes.BOOLEAN,
             allowNull: false,

+ 2 - 2
pmr-biz-manager/readme.md

@@ -186,7 +186,7 @@ preventComplete: true
         "id": "task_request_task",
         "executionId": "task_request_task_8b0c71a536",
         "user_id": "admin",
-        "check_type": 1
+        "check_type": 1  //>>>>>>>>>>>这里是表单提交的内容
       }
     },
     "variables": {
@@ -212,7 +212,7 @@ preventComplete: true
         "messageId": "smq.mid-2a55e1a76c",
         "timestamp": 1717127830563
       },
-      "check_type": 1
+      "check_type": 1 
     }
 }
 ```

+ 42 - 0
pmr-biz-manager/src/app.ts

@@ -137,6 +137,48 @@ new ServiceApp().start(new MyRouter('@src/routes', guards), Models).then(async (
         await task_delay_rate_daily();
     });
 
+
+    schedule.scheduleJob('0 * * * *', async function () {
+        let oss = Oss.get_instance('pmr-doc');
+        // 清除项目文档记录表中,超过时间仍未上传完成的文档记录
+        let records = await PrjFile.findAll({
+            where: {
+                req_upload_time: {
+                    [Op.lt]: dayjs().subtract(2, 'hour').format('YYYY-MM-DD HH:mm:ss')
+                },
+                uploaded: false
+            },
+            raw: true
+        });
+        for (let record of records) {
+            try {
+                await oss.remove_object(oss.bucket, record.id);
+                await PrjFile.destroy({where: {id: record.id}});
+            } catch (e) {
+                Logger.error(e);
+            }
+
+        }
+        // 清除没有归属的项目文档
+        let files = await PrjFile.findAll({
+            where: {
+                req_upload_time: {
+                    [Op.lt]: dayjs().subtract(1, 'hour').format('YYYY-MM-DD HH:mm:ss')
+                },
+                dependent_id: null
+            }
+        });
+        for (let file of files) {
+            try{
+                await oss.remove_object(oss.bucket, file.id);
+                await PrjFile.destroy({where: {id: file.id}});
+            } catch (e) {
+                Logger.error(e);
+            }
+
+        }
+    });
+
     // 每天8:30检查任务和工作项是否有临近过期的,有的话生成提醒工作
     schedule.scheduleJob('30 8 * * *', async function () {
         let config = await Config.findOne({where: {id: '1'}});

+ 11 - 0
pmr-biz-manager/src/bpmn/flow_engine.ts

@@ -286,6 +286,17 @@ export class FlowEngine extends EventEmitter {
 
                     return false;
                 },
+                // 将流程表单中的文件与工作项进行关联,不关联的文件会被定期清理。没有关联是因为表单中的文件上传完成后,有可能表单最终没有提交。
+                associate_files: async (files: IFiles[], dependent_id: string) => {
+                    for (let file of files) {
+                        await PrjFile.update({
+                            dependent_id: dependent_id
+                        }, {
+                            where: {id: file.id},
+                            returning: false
+                        })
+                    }
+                },
                 // 归档任务交付物文档
                 place_on_outcome: async (suffix: string, category_id?: string, _memo?: string) => {
                     console.log('$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$' + self._task_id);

+ 1 - 1
pmr-biz-manager/src/routes/api/prj/doc/get_list.ts

@@ -74,7 +74,7 @@ function get_list(json: IRequest, _params: IMethodParams, _cached_data: ICachedD
                 left join ${PrjFileCategory.table_name} category on prj_file.category_id = category.id
                 left join ${PrjInfo.table_name} prj on prj_file.prj_id = prj.id
                 left join ${AcsUserInfo.table_name} creator on creator.id = prj_file.creator_id
-                where 1=1 
+                where prj_file.uploaded_at is not null and prj_file.dependent_id is not null 
             `;
             let replacements: ISQLReplacements = {};
             if (data.filename !== undefined) {

+ 2 - 1
pmr-biz-manager/src/routes/api/prj/doc/upload.ts

@@ -41,7 +41,8 @@ function get_upload_url(json: IRequest, params: IMethodParams, cached_data: ICac
                 req_upload_time: dayjs(),
                 id: object_name,
                 filename: data.filename,
-                creator_id: cached_data.user_id
+                creator_id: cached_data.user_id,
+                dependent_id: data.prj_id
             }, {transaction: t});
 
             let oss = Oss.get_instance('pmr-doc');

+ 5 - 0
pmr-biz-manager/src/routes/api/prj/outcome/upload.ts

@@ -41,6 +41,11 @@ function statusGuard(json: IRequest, cached_data: ICachedData): Promise<void> {
 
         let prj_info = await PrjInfo.findOne({where: {id: task.prj_id}, raw: true});
         if (!prj_info) return reject(Resp.gen_err(Resp.ResourceNotFound, '项目不存在。'));
+
+        if (prj_info.phase_id === 'created' || prj_info.phase_id === 'reject_plan') {
+            return reject(Resp.gen_err(Resp.InvalidFlow, '项目计划尚未申核,不允许上传交付文档。'));
+        }
+
         let result = await if_project_task_manageable_in_current_phase(false, prj_info.id, prj_info.phase_id, '上传交付文档');
         if (!result.manageable)
             return reject(result.error);

+ 18 - 0
pmr-biz-manager/src/routes/api/prj/work/submit.ts

@@ -1,6 +1,7 @@
 import {IApiProcessor, ICachedData, IMethodParams, IRequest} from "@core/Defined";
 import {Resp} from "@util/Resp";
 import {BpmnWork} from "@core-models/BpmnWork";
+import {PrjFile} from "@core-models/PrjFile";
 import {FlowEngine, IScriptResult} from "@src/bpmn/flow_engine";
 import {WorkItemStatus} from "@src/utils/define";
 
@@ -31,6 +32,23 @@ function submit(json: IRequest, params: IMethodParams, cached_data: ICachedData)
                     }
 
                     await engine.signal(work.activity_id, data.id, cached_data.user_id, {...data.form_data});
+                    // 将此工作项相关的表单中的上传文件的dependent_id设置为此工作项的id
+                    if (work.form?.schema?.properties && data.form_data) {
+                        // 遍历对象properties中的字段
+                        for (let key in work.form.schema.properties) {
+                            let item = work.form.schema.properties[key];
+                            if (item.type === 'upload') {
+                                let files = data.form_data[key];
+                                for (let file of files) {
+                                    // await PrjFile.update({dependent_id: work.id}, {where: {associate_work_id: work.id}});
+                                    await PrjFile.update({dependent_id: work.id}, {where: {id: file.id}});
+                                }
+                            }
+                        }
+
+                    }
+
+
                 }
             }
             resolve();

+ 2 - 4
pmr-biz-manager/src/routes/api/prj/work/upload_file.ts

@@ -2,10 +2,8 @@ import {IApiProcessor, ICachedData, IMethodParams, IRequest} from "@core/Defined
 import {Resp} from "@util/Resp";
 import {Oss} from "@util/Oss";
 import {IdGen} from "@util/IdGen";
-import {PrjInfo} from "@core-models/PrjInfo";
 import dayjs from "dayjs";
 import {PrjFile} from "@core-models/PrjFile";
-import {PrjFileCategory} from "@core-models/PrjFileCategory";
 import {BpmnWork} from "@core-models/BpmnWork";
 
 interface IData {
@@ -42,7 +40,7 @@ function get_upload_url(json: IRequest, params: IMethodParams, cached_data: ICac
                 id: object_name,
                 filename: data.filename,
                 creator_id: cached_data.user_id,
-                dependent_id: data.work_id
+                associate_work_id: data.work_id
             }, {transaction: t});
 
             let oss = Oss.get_instance('pmr-doc');
@@ -57,7 +55,7 @@ function get_upload_url(json: IRequest, params: IMethodParams, cached_data: ICac
 }
 
 /// 检查工作项是否存在
-function exists_guard(json: IRequest, cached_data: ICachedData): Promise<void> {
+function exists_guard(json: IRequest, _cached_data: ICachedData): Promise<void> {
     return new Promise<void>(async (resolve, reject) => {
         let data = <IData>json.data;
         let work = await BpmnWork.findOne({where: {id: data.work_id}, raw: true});