@steedos-labs/plugin-workflow 3.0.12 → 3.0.14

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 (28) hide show
  1. package/AI_PLUGIN_GUIDE.md +939 -0
  2. package/README.md +24 -1
  3. package/main/default/applications/approve_workflow.app.yml +160 -3
  4. package/main/default/manager/handlers_manager.js +1 -1
  5. package/main/default/manager/instance_number_rules.js +84 -0
  6. package/main/default/manager/instance_tasks_manager.js +79 -1
  7. package/main/default/manager/uuflow_manager.js +53 -45
  8. package/main/default/objects/flows/buttons/design_form_layout.button.js +1 -3
  9. package/main/default/objects/flows/flows.object.yml +4 -3
  10. package/main/default/objects/instances/buttons/instance_reassign.button.yml +5 -4
  11. package/main/default/pages/instance_detail.page.amis.json +2 -100
  12. package/main/default/pages/instance_tasks_detail.page.amis.json +0 -100
  13. package/main/default/pages/page_instance_view.page.amis.json +1 -1
  14. package/main/default/routes/api_auto_number.router.js +233 -0
  15. package/main/default/routes/api_files.router.js +21 -0
  16. package/main/default/routes/api_have_read.router.js +20 -2
  17. package/main/default/routes/api_workflow_chart.router.js +23 -3
  18. package/main/default/routes/api_workflow_instance_upgrade.router.js +5 -0
  19. package/main/default/routes/api_workflow_nav.router.js +160 -136
  20. package/main/default/routes/api_workflow_next_step.router.js +111 -30
  21. package/main/default/routes/flow_form_design.ejs +16 -1
  22. package/main/default/services/instance.service.js +10 -1
  23. package/package.json +1 -1
  24. package/public/workflow/index.css +208 -10
  25. package/main/default/pages/instance_tasks_list.page.amis.json +0 -330
  26. package/main/default/pages/instance_tasks_list.page.yml +0 -12
  27. package/main/default/pages/instances_list.page.amis.json +0 -327
  28. package/main/default/pages/instances_list.page.yml +0 -12
@@ -56,54 +56,67 @@ const getCategoriesInbox = async (userSession, req, currentUrl) => {
56
56
  fields: ['_id', 'flow', 'category','flow_name','category_name']
57
57
  }, userSession)
58
58
 
59
+ // Check environment variable to control category filtering
60
+ // Default is enabled (when not set or set to any value except 'false')
61
+ // Only the string 'false' will disable the filtering
62
+ const enableCategoryFilter = process.env.STEEDOS_WORKFLOW_ENABLE_CATEGORY_FILTER !== 'false';
63
+
59
64
  const output = [];
60
- const categoryGroups = lodash.groupBy(data, 'category_name');
61
- lodash.each(categoryGroups, (v, k)=>{
62
- let categoryBadge = 0;
63
- const flowGroups = lodash.groupBy(v, 'flow_name');
64
- const flows = [];
65
- const categoryValue = `/app/${appId}/instance_tasks/view/none?side_object=instance_tasks&side_listview_id=inbox&additionalFilters=['category','=',${v[0].category?"'" + v[0].category + "'":v[0].category}]&flowId=&categoryId=${v[0].category}`;
66
- let categoryIsUnfolded = false;
67
- lodash.each(flowGroups, (v2, k2)=>{
68
- const flowValue = `/app/${appId}/instance_tasks/view/none?side_object=instance_tasks&side_listview_id=inbox&additionalFilters=['flow','=','${v2[0].flow}']&flowId=${v2[0].flow}&categoryId=${v[0].category}`;
69
- let flowIsUnfolded = false;
70
- if(currentUrl == flowValue){
71
- flowIsUnfolded = true;
65
+
66
+ if (!enableCategoryFilter) {
67
+ // When category filtering is disabled, return empty array (no sub-navigation)
68
+ // Only box-level items will be shown
69
+ } else {
70
+ // Original logic with category grouping
71
+ const categoryGroups = lodash.groupBy(data, 'category_name');
72
+ lodash.each(categoryGroups, (v, k)=>{
73
+ let categoryBadge = 0;
74
+ const flowGroups = lodash.groupBy(v, 'flow_name');
75
+ const flows = [];
76
+ const categoryValue = `/app/${appId}/instance_tasks/view/none?side_object=instance_tasks&side_listview_id=inbox&additionalFilters=['category','=',${v[0].category?"'" + v[0].category + "'":v[0].category}]&flowId=&categoryId=${v[0].category}`;
77
+ let categoryIsUnfolded = false;
78
+ lodash.each(flowGroups, (v2, k2)=>{
79
+ const flowValue = `/app/${appId}/instance_tasks/view/none?side_object=instance_tasks&side_listview_id=inbox&additionalFilters=['flow','=','${v2[0].flow}']&flowId=${v2[0].flow}&categoryId=${v[0].category}`;
80
+ let flowIsUnfolded = false;
81
+ if(currentUrl == flowValue){
82
+ flowIsUnfolded = true;
83
+ categoryIsUnfolded = true;
84
+ }
85
+ categoryBadge += v2.length
86
+ flows.push({
87
+ label: k2,
88
+ flow_name: k2,
89
+ tag:v2.length,
90
+ options:{
91
+ level:3,
92
+ value: v2[0].flow,
93
+ name: 'flow',
94
+ to: flowValue,
95
+ },
96
+ value: flowValue,
97
+ unfolded: flowIsUnfolded
98
+ })
99
+ })
100
+ if(currentUrl == categoryValue){
72
101
  categoryIsUnfolded = true;
73
102
  }
74
- categoryBadge += v2.length
75
- flows.push({
76
- label: k2,
77
- flow_name: k2,
78
- tag:v2.length,
79
- options:{
80
- level:3,
81
- value: v2[0].flow,
82
- name: 'flow',
83
- to: flowValue,
103
+ output.push({
104
+ label: k == 'null' || k == 'undefined' || !k ? "未分类" : k,
105
+ children: flows,
106
+ category_name: k == 'null' || k == 'undefined' || !k ? "未分类" : k,
107
+ tag: v.length,
108
+ options: {
109
+ level: 2,
110
+ value: v[0].category,
111
+ name: 'category',
112
+ to: categoryValue,
84
113
  },
85
- value: flowValue,
86
- unfolded: flowIsUnfolded
114
+ value: categoryValue,
115
+ unfolded: categoryIsUnfolded
87
116
  })
88
117
  })
89
- if(currentUrl == categoryValue){
90
- categoryIsUnfolded = true;
91
- }
92
- output.push({
93
- label: k == 'null' || k == 'undefined' || !k ? "未分类" : k,
94
- children: flows,
95
- category_name: k == 'null' || k == 'undefined' || !k ? "未分类" : k,
96
- tag: v.length,
97
- options: {
98
- level: 2,
99
- value: v[0].category,
100
- name: 'category',
101
- to: categoryValue,
102
- },
103
- value: categoryValue,
104
- unfolded: categoryIsUnfolded
105
- })
106
- })
118
+ }
119
+
107
120
  return {
108
121
  schema: output,
109
122
  count: data.length,
@@ -121,119 +134,130 @@ const getCategoriesMonitor = async (userSession, req, currentUrl) => {
121
134
  let output = [];
122
135
  let monitorIsUnfolded = false;
123
136
 
137
+ // Check environment variable to control category filtering
138
+ // Default is enabled (when not set or set to any value except 'false')
139
+ // Only the string 'false' will disable the filtering
140
+ const enableCategoryFilter = process.env.STEEDOS_WORKFLOW_ENABLE_CATEGORY_FILTER !== 'false';
141
+
124
142
  try {
125
- // const sa = new Date().getTime();
126
- const apps = await objectql.getObject('apps').find({filters: ['space', '=', userSession.spaceId], fields: ['_id', 'code']});
127
- // console.log(`find apps`, new Date().getTime() - sa)
128
- const appsMap = new Map(Object.entries(lodash.keyBy(apps, '_id')));
129
- // const sc = new Date().getTime();
130
- const categories = await objectql.getObject('categories').find({filters: ["space", "=", `${userSession.spaceId}`], sort: "sort_no desc"})
131
- // console.log(`find categories`, new Date().getTime() - sc)
132
- for (const item of categories) {
133
- if(item.app){
134
- item.app__expand = appsMap.get(item.app)
135
- }else{
136
- item.app__expand = {}
143
+ let flows = [];
144
+
145
+ if (!enableCategoryFilter) {
146
+ // When category filtering is disabled, return empty array (no sub-navigation)
147
+ // Only box-level items will be shown
148
+ // Still need to check permissions for hasFlowsPer (used to control monitor box visibility)
149
+ if (!hasFlowsPer) {
150
+ const flowIds = await WorkflowManager.getMyAdminOrMonitorFlows(userSession.spaceId, userSession.userId);
151
+ hasFlowsPer = flowIds && flowIds.length > 0;
152
+ }
153
+ } else {
154
+ // Original logic with category grouping
155
+ const apps = await objectql.getObject('apps').find({filters: ['space', '=', userSession.spaceId], fields: ['_id', 'code']});
156
+ const appsMap = new Map(Object.entries(lodash.keyBy(apps, '_id')));
157
+ const categories = await objectql.getObject('categories').find({filters: ["space", "=", `${userSession.spaceId}`], sort: "sort_no desc"})
158
+ for (const item of categories) {
159
+ if (item.app) {
160
+ item.app__expand = appsMap.get(item.app)
161
+ } else {
162
+ item.app__expand = {}
163
+ }
137
164
  }
138
- }
139
165
 
140
- let currentAppCategories = [];
141
- if(appId == "approve_workflow"){
142
- currentAppCategories = categories;
143
- }else{
144
- currentAppCategories = lodash.filter(categories, (category) => {
145
- if(category.app__expand?.code == appId) return true;
146
- else return false;
147
- })
148
- if(currentAppCategories.length == 0) {
149
- //如果没有任何分类绑定该app,则该app显示所有分类(该规则为审批王规则)
166
+ let currentAppCategories = [];
167
+ if (appId == "approve_workflow") {
150
168
  currentAppCategories = categories;
169
+ } else {
170
+ currentAppCategories = lodash.filter(categories, (category) => {
171
+ if (category.app__expand?.code == appId) return true;
172
+ else return false;
173
+ })
174
+ if (currentAppCategories.length == 0) {
175
+ //如果没有任何分类绑定该app,则该app显示所有分类(该规则为审批王规则)
176
+ currentAppCategories = categories;
177
+ }
151
178
  }
152
- }
153
- let categoriesIds = lodash.map(currentAppCategories, '_id');
154
- // console.log(`getCategoriesMonitor categoriesIds`, categoriesIds)
155
- // console.log(`getCategoriesMonitor hasFlowsPer`, hasFlowsPer)
156
- let flows = [];
157
- if (!hasFlowsPer) {
158
- const flowIds = await WorkflowManager.getMyAdminOrMonitorFlows(userSession.spaceId, userSession.userId);
159
- hasFlowsPer = flowIds && flowIds.length > 0;
160
- if (hasFlowsPer) {
179
+ let categoriesIds = lodash.map(currentAppCategories, '_id');
180
+
181
+ if (!hasFlowsPer) {
182
+ const flowIds = await WorkflowManager.getMyAdminOrMonitorFlows(userSession.spaceId, userSession.userId);
183
+ hasFlowsPer = flowIds && flowIds.length > 0;
184
+ if (hasFlowsPer) {
185
+ flows = await objectql.getObject('flows').find({
186
+ filters: [["_id","in", flowIds],"and",["category","in", categoriesIds], "and", ["state", "=", "enabled"]],
187
+ fields: ['_id', 'name', 'category', 'sort_no'],
188
+ sort:"sort_no desc"
189
+ });
190
+ }
191
+ } else {
161
192
  flows = await objectql.getObject('flows').find({
162
- filters: [["_id","in", flowIds],"and",["category","in", categoriesIds], "and", ["state", "=", "enabled"]],
193
+ filters:[["space", "=", userSession.spaceId],["category","in", categoriesIds],["state", "=", "enabled"]],
163
194
  fields: ['_id', 'name', 'category', 'sort_no'],
164
195
  sort:"sort_no desc"
165
- });
196
+ })
166
197
  }
167
- } else {
168
- // const s1 = new Date().getTime();
169
- flows = await objectql.getObject('flows').find({
170
- filters:[["space", "=", userSession.spaceId],["category","in", categoriesIds],["state", "=", "enabled"]],
171
- fields: ['_id', 'name', 'category', 'sort_no'],
172
- sort:"sort_no desc"
173
- })
174
- // console.log(`find flows`, new Date().getTime() - s1)
175
- }
176
- if (flows.length > 0) {
177
- const categoriesMap = new Map(Object.entries(lodash.keyBy(categories, '_id')));
198
+
199
+ if (flows.length > 0) {
200
+ const categoriesMap = new Map(Object.entries(lodash.keyBy(categories, '_id')));
178
201
 
179
- for (const item of flows) {
180
- if(item.category){
181
- item.category__expand = categoriesMap.get(item.category)
182
- }else{
183
- item.category__expand = {}
202
+ for (const item of flows) {
203
+ if (item.category) {
204
+ item.category__expand = categoriesMap.get(item.category)
205
+ } else {
206
+ item.category__expand = {}
207
+ }
184
208
  }
185
- }
186
209
 
187
- const categoryGroups = lodash.groupBy(flows, 'category__expand.name');
188
- lodash.each(categoryGroups, (v, k) => {
189
- const flowGroups = lodash.groupBy(v, 'name');
190
- const flows = [];
191
- const categoryValue = `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=monitor&additionalFilters=['category','=',${v[0].category__expand?"'" + v[0].category__expand._id + "'":null}]&flowId=&categoryId=${v[0].category__expand && v[0].category__expand._id}`;
192
- let categoryIsUnfolded = false;
193
- lodash.each(flowGroups, (v2, k2) => {
194
- const flowValue = `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=monitor&additionalFilters=['flow','=','${v2[0]._id}']&flowId=${v2[0]._id}&categoryId=${v[0].category__expand && v[0].category__expand._id}`;
195
- let flowIsUnfolded = false;
196
- if(currentUrl == flowValue){
197
- flowIsUnfolded = true;
210
+ const categoryGroups = lodash.groupBy(flows, 'category__expand.name');
211
+ lodash.each(categoryGroups, (v, k) => {
212
+ const flowGroups = lodash.groupBy(v, 'name');
213
+ const flows = [];
214
+ const categoryValue = `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=monitor&additionalFilters=['category','=',${v[0].category__expand?"'" + v[0].category__expand._id + "'":null}]&flowId=&categoryId=${v[0].category__expand && v[0].category__expand._id}`;
215
+ let categoryIsUnfolded = false;
216
+ lodash.each(flowGroups, (v2, k2) => {
217
+ const flowValue = `/app/${appId}/instances/view/none?side_object=instances&side_listview_id=monitor&additionalFilters=['flow','=','${v2[0]._id}']&flowId=${v2[0]._id}&categoryId=${v[0].category__expand && v[0].category__expand._id}`;
218
+ let flowIsUnfolded = false;
219
+ if (currentUrl == flowValue) {
220
+ flowIsUnfolded = true;
221
+ categoryIsUnfolded = true;
222
+ monitorIsUnfolded = true;
223
+ }
224
+ flows.push({
225
+ label: k2,
226
+ flow_name: k2,
227
+ options: {
228
+ level: 3,
229
+ value: v2[0]._id,
230
+ name: 'flow',
231
+ to: flowValue,
232
+ },
233
+ value: flowValue,
234
+ unfolded: flowIsUnfolded
235
+ })
236
+ })
237
+ if (currentUrl == categoryValue) {
198
238
  categoryIsUnfolded = true;
199
239
  monitorIsUnfolded = true;
200
240
  }
201
- flows.push({
202
- label: k2,
203
- flow_name: k2,
241
+ output.push({
242
+ label: k == 'null' || k == 'undefined' || !k? "未分类" : k,
243
+ children: flows,
244
+ category_name: k == 'null' || k == 'undefined' || !k ? "未分类" : k,
204
245
  options: {
205
- level: 3,
206
- value: v2[0]._id,
207
- name: 'flow',
208
- to: flowValue,
246
+ level: 2,
247
+ value: v[0].category__expand && v[0].category__expand._id,
248
+ name: 'category',
249
+ to: categoryValue,
209
250
  },
210
- value: flowValue,
211
- unfolded: flowIsUnfolded
251
+ value: categoryValue,
252
+ unfolded: categoryIsUnfolded
212
253
  })
213
254
  })
214
- if(currentUrl == categoryValue){
215
- categoryIsUnfolded = true;
216
- monitorIsUnfolded = true;
217
- }
218
- output.push({
219
- label: k == 'null' || k == 'undefined' || !k? "未分类" : k,
220
- children: flows,
221
- category_name: k == 'null' || k == 'undefined' || !k ? "未分类" : k,
222
- options: {
223
- level: 2,
224
- value: v[0].category__expand && v[0].category__expand._id,
225
- name: 'category',
226
- to: categoryValue,
227
- },
228
- value: categoryValue,
229
- unfolded: categoryIsUnfolded
230
- })
231
- })
232
- output = lodash.sortBy(output, [function (o) {
233
- return lodash.findIndex(categories, (e) => {
234
- return e._id == o.options.value;
235
- });
236
- }]);
255
+ output = lodash.sortBy(output, [function (o) {
256
+ return lodash.findIndex(categories, (e) => {
257
+ return e._id == o.options.value;
258
+ });
259
+ }]);
260
+ }
237
261
  }
238
262
  } catch (error) {
239
263
  console.log(error)
@@ -11,6 +11,8 @@ const { requireAuthentication } = require("@steedos/auth");
11
11
  const _ = require('lodash');
12
12
  const objectql = require('@steedos/objectql');
13
13
  const UUFlowManager = require('../manager/uuflow_manager');
14
+ const HandlersManager = require('../manager/handlers_manager');
15
+ const WorkflowManager = require('../manager/workflow_manager');
14
16
 
15
17
  const getFlowVersion = (flow, flowVersionId) => {
16
18
  if (flow.current._id === flowVersionId) {
@@ -53,7 +55,7 @@ const isSkipStep = function (instance, step) {
53
55
  return _.includes(instance.skip_steps, step._id)
54
56
  }
55
57
 
56
- const getNextSteps = async (flow, flowVersionId, instance, currentStep, judge, autoFormDoc, fields, showSkipStep) => {
58
+ const getNextSteps = async (flow, flowVersionId, instance, currentStep, judge, autoFormDoc, fields, showSkipStep, userId) => {
57
59
  if (!currentStep)
58
60
  return;
59
61
 
@@ -149,42 +151,39 @@ const getNextSteps = async (flow, flowVersionId, instance, currentStep, judge, a
149
151
  //去除重复
150
152
  nextSteps = _.compact(_.uniqBy(nextSteps, 'id'));
151
153
 
152
- let condition_next_steps = [];
153
- for (const nextStep of nextSteps) {
154
+ const conditionResults = await Promise.all(nextSteps.map(async (nextStep) => {
154
155
  if (nextStep.step_type == "condition") {
155
- if (!judge && nextStep.step_type == 'sign') {
156
- judge = 'approved';
156
+ let currentJudge = judge;
157
+ if (!currentJudge && nextStep.step_type == 'sign') {
158
+ currentJudge = 'approved';
157
159
  }
158
- const conditionSteps = await getNextSteps(flow, flowVersionId, instance, nextStep, judge, autoFormDoc, fields, showSkipStep);
159
- condition_next_steps = condition_next_steps.concat(conditionSteps);
160
+ return await getNextSteps(flow, flowVersionId, instance, nextStep, currentJudge, autoFormDoc, fields, showSkipStep, userId);
160
161
  }
161
- }
162
+ return [];
163
+ }));
164
+ const condition_next_steps = _.flatten(conditionResults);
162
165
 
163
166
  nextSteps = nextSteps.concat(condition_next_steps);
164
167
 
165
- let rev_nextSteps = [];
166
-
167
- for (const nextStep of nextSteps) {
168
+ const skipStepPromises = nextSteps.map(async (nextStep) => {
168
169
  if (nextStep.step_type != "condition") {
169
170
  if (!showSkipStep && isSkipStep(instance, nextStep)) {
170
- if (!judge && nextStep.step_type == 'sign') {
171
- judge = 'approved';
172
- }
173
- let nextStepsAfterSkipStep = await getNextSteps(flow, flowVersionId, instance, nextStep, judge, autoFormDoc, fields, showSkipStep);
174
- let stepsWithOutCurrentStep = [];
175
- for (const s of nextStepsAfterSkipStep) {
176
- if (currentStep.id == s.id) {
177
- continue;
178
- }
179
- stepsWithOutCurrentStep.push(s);
171
+ let currentJudge = judge;
172
+ if (!currentJudge && nextStep.step_type == 'sign') {
173
+ currentJudge = 'approved';
180
174
  }
175
+ let nextStepsAfterSkipStep = await getNextSteps(flow, flowVersionId, instance, nextStep, currentJudge, autoFormDoc, fields, showSkipStep, userId);
181
176
  // 后续步骤不应包含当前步骤
182
- rev_nextSteps = rev_nextSteps.concat(stepsWithOutCurrentStep);
177
+ return nextStepsAfterSkipStep.filter(s => currentStep.id != s.id);
183
178
  } else {
184
- rev_nextSteps.push(nextStep);
179
+ return [nextStep];
185
180
  }
186
181
  }
187
- }
182
+ return [];
183
+ });
184
+
185
+ const nestedSteps = await Promise.all(skipStepPromises);
186
+ let rev_nextSteps = _.flatten(nestedSteps);
188
187
 
189
188
  //去除重复
190
189
  rev_nextSteps = _.compact(_.uniqBy(rev_nextSteps, 'id'));
@@ -193,17 +192,98 @@ const getNextSteps = async (flow, flowVersionId, instance, currentStep, judge, a
193
192
  if (currentStep.step_type == "counterSign" && rev_nextSteps.length > 1 && !currentStep.oneClickRejection) {
194
193
  rev_nextSteps = [];
195
194
  }
195
+
196
+ // 如果步骤的 always_enter_step (始终进入此步骤(默认选中,历史流程如果未配置,也是选中)) 值为false,那么需要运行脚本 enter_step_condition (步骤条件)
197
+ // 如结果中包含条件节点则需要继续计算条件节点下一步
198
+ const needRemoveSteps = {}, needAddSteps = {};
199
+ await Promise.all(rev_nextSteps.map(step =>
200
+ caculateNextStepsByEnterStepCondition(flow, flowVersionId, instance, step, autoFormDoc, fields, needRemoveSteps, needAddSteps, userId)
201
+ ));
202
+ if (!_.isEmpty(needRemoveSteps) && !_.isEmpty(needAddSteps)) {
203
+ for (const id in needAddSteps) {
204
+ if (Object.hasOwnProperty.call(needAddSteps, id)) {
205
+ const index = rev_nextSteps.findIndex(item => item.id == id)
206
+ if (-1 === index) {
207
+ rev_nextSteps.push(needAddSteps[id])
208
+ }
209
+ }
210
+ }
211
+ for (const id in needRemoveSteps) {
212
+ if (Object.hasOwnProperty.call(needRemoveSteps, id)) {
213
+ const index = rev_nextSteps.findIndex(item => item.id == id)
214
+ if (-1 != index) {
215
+ rev_nextSteps.splice(index, 1)
216
+ }
217
+ }
218
+ }
219
+ var conditionNextSteps = new Array();
220
+
221
+ for (const [idx, nextStep] of rev_nextSteps.entries()) {
222
+ if (nextStep.step_type == "condition") {
223
+ if(!judge && nextStep.step_type == 'sign'){
224
+ judge = 'approved'
225
+ }
226
+ conditionNextSteps = conditionNextSteps.concat(await getNextSteps(instance, nextStep, judge, autoFormDoc, fields, showSkipStep, userId));
227
+ // 移除条件节点
228
+ rev_nextSteps.splice(idx, 1)
229
+ }
230
+ }
231
+ rev_nextSteps = rev_nextSteps.concat(conditionNextSteps);
232
+ //去除重复
233
+ rev_nextSteps = _.compact(_.uniqBy(rev_nextSteps, 'id'));
234
+ }
235
+
196
236
  return rev_nextSteps;
197
237
  }
198
238
 
239
+ async function caculateNextStepsByEnterStepCondition(flow, flowVersionId, instance, step, autoFormDoc, fields, needRemoveSteps = {}, needAddSteps = {}, userId) {
240
+ if (false === step.always_enter_step) {
241
+ const stepId = step.id;
242
+ // 获取step处理人
243
+ const users = await HandlersManager.getHandlers(instance._id, stepId, userId);
244
+ const spaceId = instance.space;
245
+ const approvers = await Promise.all(users.map(user => WorkflowManager.getFormulaUserObject(spaceId, user)));
246
+
247
+ let enterStepCondition = step.enter_step_condition;
248
+ const fieldValues = await UUFlowManager.initFormulaValues(instance, autoFormDoc);
249
+ fieldValues.step = {
250
+ ...step,
251
+ approvers
252
+ };
253
+ fieldValues.loginUserId = userId; // 当前登录用户
254
+ if (!UUFlowManager.isAmisFormula(enterStepCondition)) {
255
+ throw new Error('Not Amis Formula, Contact Admin Please.')
256
+ }
257
+ let result = UUFlowManager.calculateConditionWithAmis(fieldValues, enterStepCondition);
258
+ if (false === result) {
259
+ needRemoveSteps[step.id] = step;
260
+ if (step.lines && step.lines.length > 0) {
261
+ const toStepIds = step.lines.map(function(s){ return s.to_step});
262
+ await Promise.all(toStepIds.map(async (stepId) => {
263
+ const s = getStep(flow, flowVersionId, stepId);
264
+ if (s) {
265
+ await caculateNextStepsByEnterStepCondition(flow, flowVersionId, instance, s, autoFormDoc, fields, needRemoveSteps, needAddSteps, userId);
266
+ }
267
+ }));
268
+ }
269
+ } else {
270
+ needAddSteps[step.id] = step;
271
+ }
272
+ } else {
273
+ needAddSteps[step.id] = step;
274
+ }
275
+ }
276
+
277
+
199
278
  router.post('/api/workflow/v2/nextStep', requireAuthentication, async function (req, res) {
200
279
  try {
201
280
  const userSession = req.user;
281
+ const { userId } = userSession;
202
282
  const { instanceId, flowId, step, judge, values, flowVersionId } = req.body;
203
283
  const flow = await objectql.getObject('flows').findOne(flowId);
204
284
  const instance = await objectql.getObject('instances').findOne(instanceId);
205
285
 
206
- const resNextSteps = await getNextSteps(flow, flowVersionId, instance, step, judge, values);
286
+ const resNextSteps = await getNextSteps(flow, flowVersionId, instance, step, judge, values, null, null, userId);
207
287
  res.status(200).send({
208
288
  'nextSteps': resNextSteps
209
289
  });
@@ -228,17 +308,18 @@ const calcSteps = async function(instance, flow, flowVersionId, formFields, valu
228
308
 
229
309
  _steps.push(step);
230
310
  try {
231
- var nextSteps = await getNextSteps(flow, flowVersionId, instance, step, judge, values);
232
- for (const nextStep of nextSteps) {
311
+ var nextSteps = await getNextSteps(flow, flowVersionId, instance, step, judge, values, null, null, instance.submitter);
312
+ const recursiveResults = await Promise.all(nextSteps.map(async (nextStep) => {
233
313
  try {
234
314
  if (!_.includes(track, nextStep._id)) {
235
- const __steps = await calcSteps(instance, flow, flowVersionId, formFields, values, nextStep, track.concat(_.map(_steps, '_id')));
236
- _steps = _steps.concat(__steps)
315
+ return await calcSteps(instance, flow, flowVersionId, formFields, values, nextStep, track.concat(_.map(_steps, '_id')));
237
316
  }
238
317
  } catch (e) {
239
318
  console.log(e)
240
319
  }
241
- }
320
+ return [];
321
+ }));
322
+ _steps = _steps.concat(_.flatten(recursiveResults));
242
323
  } catch (error) {
243
324
  console.log(error)
244
325
  }
@@ -302,7 +302,22 @@
302
302
  tpl.type = "input-text";
303
303
  }
304
304
  if(field.formula){
305
- tpl.value = `$${field.formula}`;
305
+ if(field.formula.startsWith('{') && (field.formula.endsWith('}') || field.formula.indexOf("}") > 0)){
306
+ // {申请人姓名}.organization.fullname 转换为 ${申请人姓名.organization.fullname}
307
+ // {申请人姓名.organization.fullname} 转换为 ${申请人姓名.organization.fullname}
308
+ if(field.formula.indexOf("}.") > 0){
309
+ // {申请人姓名}.organization.fullname
310
+ let formula = field.formula;
311
+ formula = formula.substring(1, formula.indexOf("}"));
312
+ tpl.value = `\${${formula}${field.formula.substring( field.formula.indexOf("}") + 1 )}}`;
313
+ } else {
314
+ // {申请人姓名.organization.fullname}
315
+ tpl.value = `$${field.formula}`;
316
+ }
317
+ }else{
318
+ // 替换掉所有双引号"
319
+ tpl.value = field.formula.replace(/"/g, '');
320
+ }
306
321
  }
307
322
  break;
308
323
  case "number":
@@ -283,7 +283,16 @@ module.exports = {
283
283
  },
284
284
  getAppCategoriesIds: {
285
285
  async handler(appId) {
286
- if(appId == "approve_workflow"){
286
+ // Check environment variable to control category filtering
287
+ // Default is enabled (when not set or set to any value except 'false')
288
+ // Only the string 'false' will disable the filtering
289
+ const enableCategoryFilter = process.env.STEEDOS_WORKFLOW_ENABLE_CATEGORY_FILTER !== 'false';
290
+
291
+ if (!enableCategoryFilter) {
292
+ return [];
293
+ }
294
+
295
+ if (appId == "approve_workflow") {
287
296
  return [];
288
297
  }
289
298
  const categories = await objectql.getObject('categories').directFind({ filters: [['app', '=', appId]] });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steedos-labs/plugin-workflow",
3
- "version": "3.0.12",
3
+ "version": "3.0.14",
4
4
  "main": "package.service.js",
5
5
  "license": "MIT",
6
6
  "scripts": {