@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.
- package/AI_PLUGIN_GUIDE.md +939 -0
- package/README.md +24 -1
- package/main/default/applications/approve_workflow.app.yml +160 -3
- package/main/default/manager/handlers_manager.js +1 -1
- package/main/default/manager/instance_number_rules.js +84 -0
- package/main/default/manager/instance_tasks_manager.js +79 -1
- package/main/default/manager/uuflow_manager.js +53 -45
- package/main/default/objects/flows/buttons/design_form_layout.button.js +1 -3
- package/main/default/objects/flows/flows.object.yml +4 -3
- package/main/default/objects/instances/buttons/instance_reassign.button.yml +5 -4
- package/main/default/pages/instance_detail.page.amis.json +2 -100
- package/main/default/pages/instance_tasks_detail.page.amis.json +0 -100
- package/main/default/pages/page_instance_view.page.amis.json +1 -1
- package/main/default/routes/api_auto_number.router.js +233 -0
- package/main/default/routes/api_files.router.js +21 -0
- package/main/default/routes/api_have_read.router.js +20 -2
- package/main/default/routes/api_workflow_chart.router.js +23 -3
- package/main/default/routes/api_workflow_instance_upgrade.router.js +5 -0
- package/main/default/routes/api_workflow_nav.router.js +160 -136
- package/main/default/routes/api_workflow_next_step.router.js +111 -30
- package/main/default/routes/flow_form_design.ejs +16 -1
- package/main/default/services/instance.service.js +10 -1
- package/package.json +1 -1
- package/public/workflow/index.css +208 -10
- package/main/default/pages/instance_tasks_list.page.amis.json +0 -330
- package/main/default/pages/instance_tasks_list.page.yml +0 -12
- package/main/default/pages/instances_list.page.amis.json +0 -327
- 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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
lodash.each(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
tag:
|
|
79
|
-
options:{
|
|
80
|
-
level:
|
|
81
|
-
value:
|
|
82
|
-
name: '
|
|
83
|
-
to:
|
|
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:
|
|
86
|
-
unfolded:
|
|
114
|
+
value: categoryValue,
|
|
115
|
+
unfolded: categoryIsUnfolded
|
|
87
116
|
})
|
|
88
117
|
})
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
141
|
-
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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:
|
|
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
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
-
|
|
202
|
-
label:
|
|
203
|
-
|
|
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:
|
|
206
|
-
value:
|
|
207
|
-
name: '
|
|
208
|
-
to:
|
|
246
|
+
level: 2,
|
|
247
|
+
value: v[0].category__expand && v[0].category__expand._id,
|
|
248
|
+
name: 'category',
|
|
249
|
+
to: categoryValue,
|
|
209
250
|
},
|
|
210
|
-
value:
|
|
211
|
-
unfolded:
|
|
251
|
+
value: categoryValue,
|
|
252
|
+
unfolded: categoryIsUnfolded
|
|
212
253
|
})
|
|
213
254
|
})
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
-
|
|
153
|
-
for (const nextStep of nextSteps) {
|
|
154
|
+
const conditionResults = await Promise.all(nextSteps.map(async (nextStep) => {
|
|
154
155
|
if (nextStep.step_type == "condition") {
|
|
155
|
-
|
|
156
|
-
|
|
156
|
+
let currentJudge = judge;
|
|
157
|
+
if (!currentJudge && nextStep.step_type == 'sign') {
|
|
158
|
+
currentJudge = 'approved';
|
|
157
159
|
}
|
|
158
|
-
|
|
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
|
-
|
|
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
|
-
|
|
171
|
-
|
|
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
|
-
|
|
177
|
+
return nextStepsAfterSkipStep.filter(s => currentStep.id != s.id);
|
|
183
178
|
} else {
|
|
184
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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]] });
|