@steedos-labs/plugin-workflow 3.0.58 → 3.0.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/designer/dist/amis-renderer/amis-renderer.js +1 -1
  2. package/designer/dist/assets/{index-0cQynRDB.js → index-D5-hZ3Ut.js} +199 -159
  3. package/designer/dist/index.html +1 -1
  4. package/main/default/manager/instance_tasks_manager.js +36 -32
  5. package/main/default/manager/push_manager.js +63 -63
  6. package/main/default/manager/uuflowManagerForInitApproval.js +192 -98
  7. package/main/default/manager/uuflow_manager.js +31 -32
  8. package/main/default/objectTranslations/instances.en/instances.en.objectTranslation.yml +9 -0
  9. package/main/default/objectTranslations/instances.zh-CN/instances.zh-CN.objectTranslation.yml +9 -0
  10. package/main/default/objects/instance_tasks/buttons/instance_new.button.js +3 -0
  11. package/main/default/objects/instance_tasks/buttons/instance_new.button.yml +1 -1
  12. package/main/default/objects/instances/buttons/instance_cc.button.yml +1 -0
  13. package/main/default/objects/instances/buttons/instance_delete.button.yml +1 -1
  14. package/main/default/objects/instances/buttons/instance_distribute.button.yml +2 -1
  15. package/main/default/objects/instances/buttons/instance_export.button.js +1 -6
  16. package/main/default/objects/instances/buttons/instance_export.button.yml +12 -9
  17. package/main/default/objects/instances/buttons/instance_forward.button.yml +2 -1
  18. package/main/default/objects/instances/buttons/instance_new.button.js +3 -0
  19. package/main/default/objects/instances/buttons/instance_reassign.button.yml +2 -1
  20. package/main/default/objects/instances/buttons/instance_relocate.button.yml +3 -1
  21. package/main/default/objects/instances/buttons/instance_return.button.yml +1 -0
  22. package/main/default/objects/instances/buttons/instance_terminate.button.yml +1 -0
  23. package/main/default/objects/instances/listviews/monitor.listview.yml +13 -0
  24. package/main/default/objects/instances/listviews/outbox.listview.yml +36 -0
  25. package/main/default/routes/api_workflow_instance_terminate.router.js +26 -27
  26. package/main/default/routes/api_workflow_nav.router.js +65 -55
  27. package/main/default/routes/api_workflow_reassign.router.js +20 -17
  28. package/main/default/routes/api_workflow_redirect.router.js +11 -1
  29. package/main/default/routes/api_workflow_relocate.router.js +9 -4
  30. package/package.json +1 -1
  31. package/public/amis-renderer/amis-renderer.js +1 -1
  32. package/src/instance_record_queue.js +142 -12
  33. package/src/rests/badgeRecalcExecute.js +7 -11
@@ -5,20 +5,23 @@ amis_schema: |-
5
5
  "body": [
6
6
  {
7
7
  "type": "dropdown-button",
8
- "label": "导出",
8
+ "label": "${'CustomAction.instances.instance_export' | t}",
9
9
  "id": "u:instance_export",
10
10
  "level": "default",
11
11
  "icon": "fa fa-download",
12
+ "tooltip": "选择流程后可导出为Excel",
13
+ "tooltipPlacement": "top",
14
+ "align": "right",
12
15
  "buttons": [
13
16
  {
14
17
  "type": "button",
15
- "label": "本月",
18
+ "label": "${'CustomLabels.instance_export_this_month' | t}",
16
19
  "onEvent": {
17
20
  "click": {
18
21
  "actions": [
19
22
  {
20
23
  "actionType": "custom",
21
- "script": "var spaceId = event.data.context.tenantId; var flowId = event.data.flowId; if(spaceId && flowId){ var timezoneoffset = new Date().getTimezoneOffset(); var url = Steedos.absoluteUrl('/api/workflow/export/instances?space_id=' + spaceId + '&flow_id=' + flowId + '&type=0&timezoneoffset=' + timezoneoffset); window.open(url, '_blank'); } else { window.toastr && window.toastr.warning('请先选择流程'); }"
24
+ "script": "var spaceId = event.data.context.tenantId; var flowIds = []; if (event.data.flowId && sessionStorage.getItem('flowId')) { flowIds = [event.data.flowId]; } else { var sf = event.data.monitorExportFlowIds; if (!sf) { sf = event.data.__searchable__flow; } if (sf) { flowIds = Array.isArray(sf) ? sf.slice() : [sf]; } } flowIds = flowIds.filter(function(id) { return !!id; }); if (flowIds.length === 0) { event.context.env.notify('warning', t('CustomLabels.instance_export_msg_no_flow')); } else if (flowIds.length > 5) { event.context.env.notify('warning', t('CustomLabels.instance_export_msg_max_flow')); } else { var tz = new Date().getTimezoneOffset(); flowIds.forEach(function(fid) { window.open(Steedos.absoluteUrl('/api/workflow/export/instances?space_id=' + spaceId + '&flow_id=' + fid + '&type=0&timezoneoffset=' + tz), '_blank'); }); }"
22
25
  }
23
26
  ]
24
27
  }
@@ -26,13 +29,13 @@ amis_schema: |-
26
29
  },
27
30
  {
28
31
  "type": "button",
29
- "label": "上月",
32
+ "label": "${'CustomLabels.instance_export_last_month' | t}",
30
33
  "onEvent": {
31
34
  "click": {
32
35
  "actions": [
33
36
  {
34
37
  "actionType": "custom",
35
- "script": "var spaceId = event.data.context.tenantId; var flowId = event.data.flowId; if(spaceId && flowId){ var timezoneoffset = new Date().getTimezoneOffset(); var url = Steedos.absoluteUrl('/api/workflow/export/instances?space_id=' + spaceId + '&flow_id=' + flowId + '&type=1&timezoneoffset=' + timezoneoffset); window.open(url, '_blank'); } else { window.toastr && window.toastr.warning('请先选择流程'); }"
38
+ "script": "var spaceId = event.data.context.tenantId; var flowIds = []; if (event.data.flowId && sessionStorage.getItem('flowId')) { flowIds = [event.data.flowId]; } else { var sf = event.data.monitorExportFlowIds; if (!sf) { sf = event.data.__searchable__flow; } if (sf) { flowIds = Array.isArray(sf) ? sf.slice() : [sf]; } } flowIds = flowIds.filter(function(id) { return !!id; }); if (flowIds.length === 0) { event.context.env.notify('warning', t('CustomLabels.instance_export_msg_no_flow')); } else if (flowIds.length > 5) { event.context.env.notify('warning', t('CustomLabels.instance_export_msg_max_flow')); } else { var tz = new Date().getTimezoneOffset(); flowIds.forEach(function(fid) { window.open(Steedos.absoluteUrl('/api/workflow/export/instances?space_id=' + spaceId + '&flow_id=' + fid + '&type=1&timezoneoffset=' + tz), '_blank'); }); }"
36
39
  }
37
40
  ]
38
41
  }
@@ -40,13 +43,13 @@ amis_schema: |-
40
43
  },
41
44
  {
42
45
  "type": "button",
43
- "label": "本年度",
46
+ "label": "${'CustomLabels.instance_export_this_year' | t}",
44
47
  "onEvent": {
45
48
  "click": {
46
49
  "actions": [
47
50
  {
48
51
  "actionType": "custom",
49
- "script": "var spaceId = event.data.context.tenantId; var flowId = event.data.flowId; if(spaceId && flowId){ var timezoneoffset = new Date().getTimezoneOffset(); var url = Steedos.absoluteUrl('/api/workflow/export/instances?space_id=' + spaceId + '&flow_id=' + flowId + '&type=2&timezoneoffset=' + timezoneoffset); window.open(url, '_blank'); } else { window.toastr && window.toastr.warning('请先选择流程'); }"
52
+ "script": "var spaceId = event.data.context.tenantId; var flowIds = []; if (event.data.flowId && sessionStorage.getItem('flowId')) { flowIds = [event.data.flowId]; } else { var sf = event.data.monitorExportFlowIds; if (!sf) { sf = event.data.__searchable__flow; } if (sf) { flowIds = Array.isArray(sf) ? sf.slice() : [sf]; } } flowIds = flowIds.filter(function(id) { return !!id; }); if (flowIds.length === 0) { event.context.env.notify('warning', t('CustomLabels.instance_export_msg_no_flow')); } else if (flowIds.length > 5) { event.context.env.notify('warning', t('CustomLabels.instance_export_msg_max_flow')); } else { var tz = new Date().getTimezoneOffset(); flowIds.forEach(function(fid) { window.open(Steedos.absoluteUrl('/api/workflow/export/instances?space_id=' + spaceId + '&flow_id=' + fid + '&type=2&timezoneoffset=' + tz), '_blank'); }); }"
50
53
  }
51
54
  ]
52
55
  }
@@ -54,13 +57,13 @@ amis_schema: |-
54
57
  },
55
58
  {
56
59
  "type": "button",
57
- "label": "所有",
60
+ "label": "${'CustomLabels.instance_export_all' | t}",
58
61
  "onEvent": {
59
62
  "click": {
60
63
  "actions": [
61
64
  {
62
65
  "actionType": "custom",
63
- "script": "var spaceId = event.data.context.tenantId; var flowId = event.data.flowId; if(spaceId && flowId){ var timezoneoffset = new Date().getTimezoneOffset(); var url = Steedos.absoluteUrl('/api/workflow/export/instances?space_id=' + spaceId + '&flow_id=' + flowId + '&type=3&timezoneoffset=' + timezoneoffset); window.open(url, '_blank'); } else { window.toastr && window.toastr.warning('请先选择流程'); }"
66
+ "script": "var spaceId = event.data.context.tenantId; var flowIds = []; if (event.data.flowId && sessionStorage.getItem('flowId')) { flowIds = [event.data.flowId]; } else { var sf = event.data.monitorExportFlowIds; if (!sf) { sf = event.data.__searchable__flow; } if (sf) { flowIds = Array.isArray(sf) ? sf.slice() : [sf]; } } flowIds = flowIds.filter(function(id) { return !!id; }); if (flowIds.length === 0) { event.context.env.notify('warning', t('CustomLabels.instance_export_msg_no_flow')); } else if (flowIds.length > 5) { event.context.env.notify('warning', t('CustomLabels.instance_export_msg_max_flow')); } else { var tz = new Date().getTimezoneOffset(); flowIds.forEach(function(fid) { window.open(Steedos.absoluteUrl('/api/workflow/export/instances?space_id=' + spaceId + '&flow_id=' + fid + '&type=3&timezoneoffset=' + tz), '_blank'); }); }"
64
67
  }
65
68
  ]
66
69
  }
@@ -14,6 +14,7 @@ amis_schema: |-
14
14
  "actionType": "dialog",
15
15
  "dialog": {
16
16
  "type": "dialog",
17
+ "className": "instance-action-dialog",
17
18
  "title": {
18
19
  "type": "tpl",
19
20
  "id": "u:4733f85da58b",
@@ -144,7 +145,7 @@ amis_schema: |-
144
145
  "weight": 0
145
146
  }
146
147
  },
147
- "hiddenOn": "!( record.state != \"draft\" )"
148
+ "hiddenOn": "!( record.state != \"draft\" ) || (window.Builder && window.Builder.settings && window.Builder.settings.STEEDOS_PUBLIC_WORKFLOW_READONLY === 'true')"
148
149
  }
149
150
  ],
150
151
  "regions": [
@@ -11,6 +11,9 @@ module.exports = {
11
11
  if(data && data._isRelated){
12
12
  return false;
13
13
  }
14
+ if (typeof Builder !== 'undefined' && Builder.settings && Builder.settings.STEEDOS_PUBLIC_WORKFLOW_READONLY === 'true'){
15
+ return false;
16
+ }
14
17
  return true;
15
18
  }
16
19
  }
@@ -17,7 +17,7 @@ amis_schema: |-
17
17
  "type": "button",
18
18
  "label": "转签核",
19
19
  "id": "u:instance_reassign",
20
- "hiddenOn": "!(this.record.box === 'monitor' && this.record.state == 'pending' && this.record.flowPermissions.includes('admin'))",
20
+ "hiddenOn": "!(this.record.box === 'monitor' && this.record.state == 'pending' && this.record.flowPermissions.includes('admin')) || (window.Builder && window.Builder.settings && window.Builder.settings.STEEDOS_PUBLIC_WORKFLOW_READONLY === 'true')",
21
21
  "onEvent": {
22
22
  "click": {
23
23
  "weight": 0,
@@ -27,6 +27,7 @@ amis_schema: |-
27
27
  "actionType": "dialog",
28
28
  "dialog": {
29
29
  "type": "dialog",
30
+ "className": "instance-action-dialog",
30
31
  "title": "转签核",
31
32
  "body": [
32
33
  {
@@ -16,7 +16,7 @@ amis_schema: |-
16
16
  {
17
17
  "type": "button",
18
18
  "label": "${'CustomAction.instances.instance_relocate' | t}",
19
- "hiddenOn": "!(this.record.box === 'monitor' && this.record.state != 'draft' && this.record.flowPermissions.includes('admin'))",
19
+ "hiddenOn": "!(this.record.box === 'monitor' && this.record.state != 'draft' && this.record.flowPermissions.includes('admin')) || (window.Builder && window.Builder.settings && window.Builder.settings.STEEDOS_PUBLIC_WORKFLOW_READONLY === 'true')",
20
20
  "onEvent": {
21
21
  "click": {
22
22
  "weight": 0,
@@ -24,6 +24,7 @@ amis_schema: |-
24
24
  {
25
25
  "dialog": {
26
26
  "type": "dialog",
27
+ "className": "instance-action-dialog",
27
28
  "title": "${'instance_action_instance_relocate_dialog_title' | t}",
28
29
  "body": [
29
30
  {
@@ -50,6 +51,7 @@ amis_schema: |-
50
51
  "id": "u:ee15214c1808",
51
52
  "multiple": false,
52
53
  "required": true,
54
+ "searchable": true,
53
55
  "source": "${stepsOption}",
54
56
  "onEvent": {
55
57
  "change": {
@@ -15,6 +15,7 @@ amis_schema: |-
15
15
  "actionType": "dialog",
16
16
  "dialog": {
17
17
  "type": "dialog",
18
+ "className": "instance-action-dialog",
18
19
  "title": "退回",
19
20
  "body": [
20
21
  {
@@ -15,6 +15,7 @@ amis_schema: |-
15
15
  "actionType": "dialog",
16
16
  "dialog": {
17
17
  "type": "dialog",
18
+ "className": "instance-action-dialog",
18
19
  "title": "${'CustomLabels.instance_action_terminate_dialog_title' | t}",
19
20
  "body": [
20
21
  {
@@ -23,6 +23,19 @@ filters: !!js/function |
23
23
  });
24
24
  return result.filter;
25
25
  }
26
+ requestAdaptor: |-
27
+ var searchFlow = selfData.__searchable__flow;
28
+ var flowIds = [];
29
+ if (searchFlow) {
30
+ flowIds = Array.isArray(searchFlow) ? searchFlow.slice() : [searchFlow];
31
+ }
32
+ flowIds = flowIds.filter(function(id) { return !!id; });
33
+ try {
34
+ window.postMessage({
35
+ type: 'page.dataProvider.setData',
36
+ data: { monitorExportFlowIds: flowIds.length > 0 ? flowIds : '' }
37
+ }, '*');
38
+ } catch(e) {}
26
39
  sort: [['submit_date','desc']]
27
40
  searchable_fields:
28
41
  - field: flow
@@ -0,0 +1,36 @@
1
+ name: outbox
2
+ label: 已审批
3
+ columns:
4
+ - field: name
5
+ wrap: true
6
+ width: 300
7
+ - submitter_name
8
+ - submit_date
9
+ - flow_name
10
+ - current_step_name
11
+ - modified
12
+ mobile_columns:
13
+ - name
14
+ - flow_name
15
+ - current_step_name
16
+ - submitter_name
17
+ - modified
18
+ filter_scope: space
19
+ filters: !!js/function |
20
+ function(filters, data){
21
+ var result = Steedos.authRequest(`/api/workflow/v2/\${data.listName}/filter?app=\${data.appId}&additionalFilters=\${data.additionalFilters || ""}`, {
22
+ type: 'get', async: false
23
+ });
24
+ return result.filter;
25
+ }
26
+ sort: [['modified','desc']]
27
+ searchable_fields:
28
+ - field: flow
29
+ - field: name
30
+ - field: submitter_name
31
+ - field: applicant_organization_name
32
+ - field: submit_date
33
+ - field: instance_state
34
+ extra_columns:
35
+ - extras
36
+ disableSwitch: true
@@ -24,7 +24,7 @@ router.post("/api/workflow/v2/instance/terminate", requireAuthentication, async
24
24
  try {
25
25
  const userSession = req.user;
26
26
  const { terminate_reason, instance_id } = req.body;
27
-
27
+
28
28
  if (!terminate_reason) {
29
29
  throw new Error("还未填写强制结束申请单的理由,操作失败");
30
30
  }
@@ -67,9 +67,9 @@ router.post("/api/workflow/v2/instance/terminate", requireAuthentication, async
67
67
 
68
68
  // Check permissions
69
69
  const permissions = await PermissionManager.getFlowPermissions(flow_id, current_user);
70
- const hasPermission = permissions.includes("admin") ||
71
- space.admins.includes(current_user) ||
72
- instance.submitter === current_user ||
70
+ const hasPermission = permissions.includes("admin") ||
71
+ space.admins.includes(current_user) ||
72
+ instance.submitter === current_user ||
73
73
  instance.applicant === current_user;
74
74
  if (!hasPermission) {
75
75
  throw new Error("无权终止此申请单");
@@ -147,7 +147,7 @@ router.post("/api/workflow/v2/instance/terminate", requireAuthentication, async
147
147
  const old_inbox_users = instance.inbox_users || [];
148
148
  const old_cc_users = instance.cc_users || [];
149
149
  const old_outbox_users = instance.outbox_users || [];
150
-
150
+
151
151
  const tempUsers = [];
152
152
  instance_trace.approves.forEach(approve => {
153
153
  tempUsers.push(approve.user);
@@ -167,6 +167,7 @@ router.post("/api/workflow/v2/instance/terminate", requireAuthentication, async
167
167
 
168
168
  // Update instance
169
169
  const instancesCollection = await getCollection('instances');
170
+
170
171
  const result = await instancesCollection.updateOne(
171
172
  { _id: instance_id },
172
173
  { $set: setObj }
@@ -178,30 +179,28 @@ router.post("/api/workflow/v2/instance/terminate", requireAuthentication, async
178
179
 
179
180
  // Send notifications
180
181
  const updatedInstance = await UUFlowManager.getInstance(instance_id);
181
- await pushManager.send_instance_notification(
182
- "submit_terminate_applicant",
183
- updatedInstance,
184
- terminate_reason,
185
- current_user_info
186
- );
187
-
188
- // Notify all involved users
182
+
183
+ // Send notifications + webhook (并行)
189
184
  const usersToNotify = _.uniq([...old_inbox_users, ...old_cc_users]);
190
- await Promise.all(
191
- usersToNotify.map(user_id =>
185
+ await Promise.all([
186
+ pushManager.send_instance_notification(
187
+ "submit_terminate_applicant",
188
+ updatedInstance,
189
+ terminate_reason,
190
+ current_user_info
191
+ ),
192
+ ...usersToNotify.map(user_id =>
192
193
  pushManager.send_message_to_specifyUser("terminate_approval", user_id)
194
+ ),
195
+ pushManager.triggerWebhook(
196
+ updatedInstance.flow,
197
+ updatedInstance,
198
+ {},
199
+ "terminate",
200
+ current_user,
201
+ []
193
202
  )
194
- );
195
-
196
- // Trigger webhook
197
- await pushManager.triggerWebhook(
198
- updatedInstance.flow,
199
- updatedInstance,
200
- {},
201
- "terminate",
202
- current_user,
203
- []
204
- );
203
+ ]);
205
204
  }
206
205
 
207
206
  res.status(200).send({});
@@ -213,4 +212,4 @@ router.post("/api/workflow/v2/instance/terminate", requireAuthentication, async
213
212
  }
214
213
  });
215
214
 
216
- exports.default = router;
215
+ exports.default = router;
@@ -290,18 +290,22 @@ router.get('/api/:appId/workflow/nav', requireAuthentication, async function (re
290
290
  currentUrl = currentUrl.substring(currentUrl.indexOf("/app"));
291
291
  let userSession = req.user;
292
292
  const { appId } = req.params;
293
+ const isWorkflowReadonly = process.env.STEEDOS_PUBLIC_WORKFLOW_READONLY === 'true';
294
+
293
295
  // const s1 = new Date().getTime();
294
- let inboxResult = await getCategoriesInbox(userSession, req, currentUrl);
296
+ let inboxResult = isWorkflowReadonly ? { schema: [], count: 0 } : await getCategoriesInbox(userSession, req, currentUrl);
295
297
  // console.log(`inboxResult time`, new Date().getTime() - s1);
296
298
  // const s2 = new Date().getTime();
297
299
  let monitorResult = await getCategoriesMonitor(userSession, req, currentUrl)
298
300
  // console.log(`monitorResult time`, new Date().getTime() - s2);
299
301
  // const s3 = new Date().getTime();
300
- let draftCount = await getDraftCount(userSession,req);
302
+ let draftCount = isWorkflowReadonly ? 0 : await getDraftCount(userSession,req);
301
303
  // console.log(`getDraftCount time`, new Date().getTime() - s3);
302
-
303
- var options = [
304
- {
304
+
305
+ var options = [];
306
+
307
+ if (!isWorkflowReadonly) {
308
+ options.push({
305
309
  "label": t('inbox', {}, userSession.language),
306
310
  "icon": "fa fa-download",
307
311
  "tag":inboxResult.count,
@@ -312,17 +316,21 @@ router.get('/api/:appId/workflow/nav', requireAuthentication, async function (re
312
316
  },
313
317
  "value": `/app/${appId}/instance_tasks/view/none?side_object=instance_tasks&side_listview_id=inbox&additionalFilters=`,
314
318
  "children": inboxResult.schema
319
+ });
320
+ }
321
+
322
+ options.push({
323
+ "label": t('outbox', {}, userSession.language),
324
+ "options":{
325
+ "level":1,
326
+ "to": `/app/${appId}/instance_tasks/view/none?side_object=instance_tasks&side_listview_id=outbox&additionalFilters=`
315
327
  },
316
- {
317
- "label": t('outbox', {}, userSession.language),
318
- "options":{
319
- "level":1,
320
- "to": `/app/${appId}/instance_tasks/view/none?side_object=instance_tasks&side_listview_id=outbox&additionalFilters=`
321
- },
322
- "value": `/app/${appId}/instance_tasks/view/none?side_object=instance_tasks&side_listview_id=outbox&additionalFilters=`,
323
- "icon": "fa fa-check"
324
- },
325
- {
328
+ "value": `/app/${appId}/instance_tasks/view/none?side_object=instance_tasks&side_listview_id=outbox&additionalFilters=`,
329
+ "icon": "fa fa-check"
330
+ });
331
+
332
+ if (monitorResult.hasFlowsPer) {
333
+ options.push({
326
334
  "label": t('monitor', {}, userSession.language),
327
335
  "icon": "fa fa-eye",
328
336
  "options":{
@@ -331,49 +339,51 @@ router.get('/api/:appId/workflow/nav', requireAuthentication, async function (re
331
339
  },
332
340
  "value": `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=monitor&additionalFilters=`,
333
341
  "children": monitorResult.schema,
334
- "unfolded": monitorResult.monitorIsUnfolded,
335
- "visible": monitorResult.hasFlowsPer
336
- },
337
- {
338
- "label": t('myfile', {}, userSession.language),
339
- "icon": "fa fa-folder",
342
+ "unfolded": monitorResult.monitorIsUnfolded
343
+ });
344
+ }
345
+
346
+ const myfileChildren = [];
347
+ if (!isWorkflowReadonly) {
348
+ myfileChildren.push({
349
+ "label": t('draft', {}, userSession.language),
340
350
  "options":{
341
351
  "level":1,
342
- // "to": `/app/${appId}/instance_tasks/grid/inbox`
352
+ "to": `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=draft&additionalFilters=`
343
353
  },
344
- "unfolded": true,
345
- "children": [
346
- {
347
- "label": t('draft', {}, userSession.language),
348
- "options":{
349
- "level":1,
350
- "to": `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=draft&additionalFilters=`
351
- },
352
- "value": `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=draft&additionalFilters=`,
353
- "icon": "fa fa-pencil",
354
- "tag": draftCount
355
- },
356
- {
357
- "label": t('pending', {}, userSession.language),
358
- "options":{
359
- "level":1,
360
- "to": `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=pending&additionalFilters=`,
361
- },
362
- "value": `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=pending&additionalFilters=`,
363
- "icon": "fa fa-hourglass-half"
364
- },
365
- {
366
- "label": t('completed', {}, userSession.language),
367
- "options":{
368
- "level":1,
369
- "to": `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=completed&additionalFilters=`,
370
- },
371
- "value": `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=completed&additionalFilters=`,
372
- "icon": "fa fa-check-square"
373
- }
374
- ]
375
- }
376
- ];
354
+ "value": `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=draft&additionalFilters=`,
355
+ "icon": "fa fa-pencil",
356
+ "tag": draftCount
357
+ });
358
+ myfileChildren.push({
359
+ "label": t('pending', {}, userSession.language),
360
+ "options":{
361
+ "level":1,
362
+ "to": `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=pending&additionalFilters=`,
363
+ },
364
+ "value": `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=pending&additionalFilters=`,
365
+ "icon": "fa fa-hourglass-half"
366
+ });
367
+ }
368
+ myfileChildren.push({
369
+ "label": t('completed', {}, userSession.language),
370
+ "options":{
371
+ "level":1,
372
+ "to": `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=completed&additionalFilters=`,
373
+ },
374
+ "value": `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=completed&additionalFilters=`,
375
+ "icon": "fa fa-check-square"
376
+ });
377
+
378
+ options.push({
379
+ "label": t('myfile', {}, userSession.language),
380
+ "icon": "fa fa-folder",
381
+ "options":{
382
+ "level":1,
383
+ },
384
+ "unfolded": true,
385
+ "children": myfileChildren
386
+ });
377
387
  res.status(200).send({
378
388
  data: {
379
389
  options:options
@@ -3,7 +3,7 @@
3
3
  * @Date: 2022-12-24 14:38:27
4
4
  * @LastEditors: 孙浩林 sunhaolin@steedos.com
5
5
  * @LastEditTime: 2025-10-08 14:50:07
6
- * @Description:
6
+ * @Description:
7
7
  */
8
8
  'use strict';
9
9
  // @ts-check
@@ -49,10 +49,12 @@ router.post('/api/workflow/reassign', requireAuthentication, async function (req
49
49
  const spaceUsersCollection = await getCollection('space_users');
50
50
  const organizationsCollection = await getCollection('organizations');
51
51
 
52
- for (const instance_from_client of hashData['Instances']) {
52
+ for (const instance_from_client of hashData['Instances']) {
53
53
  var _users, approve_users_handlers, assignee_appr, current_space_user, current_user_organization, i, inbox_users, inbox_users_from_client, ins, instance, instance_id, last_trace, last_trace_from_client, new_inbox_users, not_in_inbox_users, now, permissions, r, reassign_reason, setObj, space, space_id;
54
54
  instance_id = instance_from_client['_id'];
55
+
55
56
  instance = await UUFlowManager.getInstance(instance_id);
57
+
56
58
  space_id = instance.space;
57
59
  // 验证instance为审核中状态
58
60
  await UUFlowManager.isInstancePending(instance);
@@ -66,7 +68,7 @@ router.post('/api/workflow/reassign', requireAuthentication, async function (req
66
68
  }
67
69
  // 验证login user_id对该流程有管理申请单的权限
68
70
  permissions = await PermissionManager.getFlowPermissions(instance.flow, current_user);
69
-
71
+
70
72
  if ((!permissions.includes("admin")) && !is_space_admin) {
71
73
  throw new Error("用户没有对当前流程的管理权限");
72
74
  }
@@ -191,6 +193,7 @@ router.post('/api/workflow/reassign', requireAuthentication, async function (req
191
193
  last_trace.approves.push(new_appr);
192
194
  newApproveIds.push(new_appr._id)
193
195
  };
196
+
194
197
  instance.outbox_users.push(current_user);
195
198
  instance.outbox_users = instance.outbox_users.concat(approve_users_handlers);
196
199
  setObj.outbox_users = _.uniq(instance.outbox_users);
@@ -213,25 +216,25 @@ router.post('/api/workflow/reassign', requireAuthentication, async function (req
213
216
 
214
217
  if (r) {
215
218
  ins = await UUFlowManager.getInstance(instance_id);
216
- // 给被删除的inbox_users 和 当前用户 发送push
217
- await pushManager.send_message_current_user(current_user_info);
218
- for (const user_id of not_in_inbox_users) {
219
- if (user_id !== current_user) {
220
- await pushManager.send_message_to_specifyUser("current_user", user_id);
221
- }
222
- };
219
+
223
220
  // 提取instances.outbox_users数组和填单人、申请人
224
221
  _users = new Array;
225
222
  _users.push(ins.applicant);
226
223
  _users.push(ins.submitter);
227
224
  _users = _.uniq(_users.concat(ins.outbox_users));
228
- for (const user_id of _users) {
229
- await pushManager.send_message_to_specifyUser("current_user", user_id);
230
- };
231
- // 给新加入的inbox_users发送push message
232
- await pushManager.send_instance_notification("reassign_new_inbox_users", ins, reassign_reason, current_user_info);
233
- // 如果已经配置webhook并已激活则触发
234
- await pushManager.triggerWebhook(ins.flow, ins, {}, 'reassign', current_user, ins.inbox_users);
225
+
226
+ // 所有通知+webhook 并行
227
+ await Promise.all([
228
+ pushManager.send_message_current_user(current_user_info),
229
+ ...not_in_inbox_users
230
+ .filter(user_id => user_id !== current_user)
231
+ .map(user_id => pushManager.send_message_to_specifyUser("current_user", user_id)),
232
+ ..._users.map(user_id =>
233
+ pushManager.send_message_to_specifyUser("current_user", user_id)
234
+ ),
235
+ pushManager.send_instance_notification("reassign_new_inbox_users", ins, reassign_reason, current_user_info),
236
+ pushManager.triggerWebhook(ins.flow, ins, {}, 'reassign', current_user, ins.inbox_users)
237
+ ]);
235
238
  }
236
239
  };
237
240
 
@@ -30,7 +30,17 @@ router.get('/api/workflow/instances/redirect/:insId', requireAuthentication, asy
30
30
  if(ins.submitter === userId){
31
31
  redirectUrl = `/app/approve_workflow/instances/view/${insId}?side_object=instance_tasks&side_listview_id=${ins.state === 'completed' ? 'completed' : 'pending'}`
32
32
  }else{
33
- redirectUrl = `/app/approve_workflow/instance_tasks/view/${insId}?side_object=instance_tasks&side_listview_id=outbox`
33
+ const tasks2 = await db.instance_tasks.find({
34
+ instance: insId,
35
+ is_finished: true,
36
+ handler: userId,
37
+ space: spaceId
38
+ }, {_id: 1}).toArray();
39
+ if(tasks2.length > 0){
40
+ redirectUrl = `/app/approve_workflow/instance_tasks/view/${tasks2[0]._id}?side_object=instance_tasks&side_listview_id=outbox`
41
+ }else{
42
+ redirectUrl = `/app/approve_workflow/instances/view/${insId}?side_object=instance_tasks&side_listview_id=outbox`
43
+ }
34
44
  }
35
45
  }
36
46
 
@@ -1,6 +1,6 @@
1
1
  /*
2
- * @Author: sunhaolin@hotoa.com
3
- * @Date: 2022-03-26 10:49:51
2
+ * @Author: sunhaolin@hotoa.com
3
+ * @Date: 2022-03-26 10:49:51
4
4
  * @Last Modified by: sunhaolin@hotoa.com
5
5
  * @Last Modified time: 2022-03-26 10:53:33
6
6
  */
@@ -18,7 +18,7 @@ const afterHook = require('./afterHook');
18
18
  * body {
19
19
  * Instances: [
20
20
  * {
21
- *
21
+ *
22
22
  * }
23
23
  * ]
24
24
  * }
@@ -35,9 +35,12 @@ router.post('/api/workflow/relocate', requireAuthentication, afterHook, async fu
35
35
  const instance_from_client = hashData['Instances'][0];
36
36
  // beforeEnd
37
37
  const insId = instance_from_client._id;
38
+
38
39
  const instanceDoc = (await objectql.getObject('instances').find({ filters: [['_id', '=', insId]], fields: ['flow', 'flow_version'] }))[0];
40
+
39
41
  const flowId = instanceDoc.flow;
40
42
  const flowDoc = await objectql.getObject('flows').findOne(flowId);
43
+
41
44
  const next_step_id = instance_from_client["relocate_next_step"];
42
45
  const next_step = getStep(instanceDoc, flowDoc, next_step_id);
43
46
  const next_step_type = next_step["step_type"];
@@ -46,10 +49,12 @@ router.post('/api/workflow/relocate', requireAuthentication, afterHook, async fu
46
49
  }
47
50
 
48
51
  await UUFlowManager.relocate(instance_from_client, userSession)
52
+
49
53
  // afterEnd
50
54
  if (next_step_type === 'end') {
51
55
  await excuteTriggers({ when: 'afterEnd', userId, flowId, insId });
52
56
  }
57
+
53
58
  res.status(200).send({});
54
59
 
55
60
  } catch (e) {
@@ -58,4 +63,4 @@ router.post('/api/workflow/relocate', requireAuthentication, afterHook, async fu
58
63
  });
59
64
  }
60
65
  });
61
- exports.default = router;
66
+ exports.default = router;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steedos-labs/plugin-workflow",
3
- "version": "3.0.58",
3
+ "version": "3.0.60",
4
4
  "main": "package.service.js",
5
5
  "license": "MIT",
6
6
  "files": [