collabdocchat 1.2.13 → 2.0.0
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/README.md +219 -218
- package/index.html +2 -0
- package/install-and-start.bat +5 -0
- package/install-and-start.sh +5 -0
- package/package.json +9 -2
- package/scripts/pre-publish-check.js +213 -0
- package/scripts/start-app.js +15 -15
- package/server/index.js +38 -6
- package/server/middleware/cache.js +115 -0
- package/server/middleware/errorHandler.js +209 -0
- package/server/models/Document.js +66 -59
- package/server/models/File.js +49 -43
- package/server/models/Group.js +6 -0
- package/server/models/KnowledgeBase.js +254 -0
- package/server/models/Message.js +43 -0
- package/server/models/Task.js +87 -55
- package/server/models/User.js +67 -60
- package/server/models/Workflow.js +249 -0
- package/server/routes/ai.js +327 -0
- package/server/routes/audit.js +245 -210
- package/server/routes/backup.js +108 -0
- package/server/routes/chunked-upload.js +343 -0
- package/server/routes/export.js +440 -0
- package/server/routes/files.js +294 -218
- package/server/routes/groups.js +182 -0
- package/server/routes/knowledge.js +509 -0
- package/server/routes/tasks.js +257 -110
- package/server/routes/workflows.js +380 -0
- package/server/utils/backup.js +439 -0
- package/server/utils/cache.js +223 -0
- package/server/utils/workflow-engine.js +479 -0
- package/server/websocket/enhanced.js +509 -0
- package/server/websocket/index.js +233 -1
- package/src/components/knowledge-modal.js +485 -0
- package/src/components/optimized-poll-detail.js +724 -0
- package/src/main.js +5 -0
- package/src/pages/admin-dashboard.js +2248 -44
- package/src/pages/optimized-backup-view.js +616 -0
- package/src/pages/optimized-knowledge-view.js +803 -0
- package/src/pages/optimized-task-detail.js +843 -0
- package/src/pages/optimized-workflow-view.js +806 -0
- package/src/pages/simplified-workflows.js +651 -0
- package/src/pages/user-dashboard.js +677 -58
- package/src/services/api.js +65 -1
- package/src/services/auth.js +1 -1
- package/src/services/websocket.js +124 -16
- package/src/styles/collaboration-modern.js +708 -0
- package/src/styles/enhancements.css +392 -0
- package/src/styles/main.css +620 -1420
- package/src/styles/responsive.css +1000 -0
- package/src/styles/sidebar-fix.css +60 -0
- package/src/utils/ai-assistant.js +1398 -0
- package/src/utils/chat-enhancements.js +509 -0
- package/src/utils/collaboration-enhancer.js +1151 -0
- package/src/utils/feature-integrator.js +1724 -0
- package/src/utils/onboarding-guide.js +734 -0
- package/src/utils/performance.js +394 -0
- package/src/utils/permission-manager.js +890 -0
- package/src/utils/responsive-handler.js +491 -0
- package/src/utils/theme-manager.js +811 -0
- package/src/utils/ui-enhancements-loader.js +329 -0
- package/USAGE.md +0 -298
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
import { Workflow, WorkflowExecution, Approval } from '../models/Workflow.js';
|
|
2
|
+
import User from '../models/User.js';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
|
|
5
|
+
class WorkflowEngine {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.executionQueue = [];
|
|
8
|
+
this.isProcessing = false;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// 触发工作流
|
|
12
|
+
async triggerWorkflow(workflowId, triggerData, triggeredBy) {
|
|
13
|
+
const workflow = await Workflow.findById(workflowId);
|
|
14
|
+
|
|
15
|
+
if (!workflow) {
|
|
16
|
+
throw new Error('工作流不存在');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (workflow.status !== 'active') {
|
|
20
|
+
throw new Error('工作流未激活');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 检查触发条件
|
|
24
|
+
if (workflow.trigger.conditions && workflow.trigger.conditions.length > 0) {
|
|
25
|
+
const conditionsMet = this.checkConditions(workflow.trigger.conditions, triggerData);
|
|
26
|
+
if (!conditionsMet) {
|
|
27
|
+
console.log('触发条件不满足,跳过执行');
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 创建执行记录
|
|
33
|
+
const execution = new WorkflowExecution({
|
|
34
|
+
workflow: workflowId,
|
|
35
|
+
triggeredBy,
|
|
36
|
+
triggerType: workflow.trigger.type,
|
|
37
|
+
triggerData,
|
|
38
|
+
status: 'pending',
|
|
39
|
+
startedAt: new Date(),
|
|
40
|
+
steps: workflow.steps.map((step, index) => ({
|
|
41
|
+
stepIndex: index,
|
|
42
|
+
stepName: step.name,
|
|
43
|
+
status: 'pending'
|
|
44
|
+
}))
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
await execution.save();
|
|
48
|
+
|
|
49
|
+
// 添加到执行队列
|
|
50
|
+
this.executionQueue.push(execution._id);
|
|
51
|
+
|
|
52
|
+
// 开始处理队列
|
|
53
|
+
this.processQueue();
|
|
54
|
+
|
|
55
|
+
return execution;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 处理执行队列
|
|
59
|
+
async processQueue() {
|
|
60
|
+
if (this.isProcessing || this.executionQueue.length === 0) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.isProcessing = true;
|
|
65
|
+
|
|
66
|
+
while (this.executionQueue.length > 0) {
|
|
67
|
+
const executionId = this.executionQueue.shift();
|
|
68
|
+
try {
|
|
69
|
+
await this.executeWorkflow(executionId);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error('工作流执行失败:', error);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.isProcessing = false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 执行工作流
|
|
79
|
+
async executeWorkflow(executionId) {
|
|
80
|
+
const execution = await WorkflowExecution.findById(executionId)
|
|
81
|
+
.populate('workflow');
|
|
82
|
+
|
|
83
|
+
if (!execution) {
|
|
84
|
+
throw new Error('执行记录不存在');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const workflow = execution.workflow;
|
|
88
|
+
|
|
89
|
+
execution.status = 'running';
|
|
90
|
+
await execution.save();
|
|
91
|
+
|
|
92
|
+
this.addLog(execution, 'info', '工作流开始执行');
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
// 按顺序执行步骤
|
|
96
|
+
for (let i = 0; i < workflow.steps.length; i++) {
|
|
97
|
+
const step = workflow.steps[i];
|
|
98
|
+
execution.currentStep = i;
|
|
99
|
+
await execution.save();
|
|
100
|
+
|
|
101
|
+
// 检查步骤执行条件
|
|
102
|
+
if (step.executeIf && step.executeIf.length > 0) {
|
|
103
|
+
const shouldExecute = this.checkConditions(step.executeIf, execution.triggerData);
|
|
104
|
+
if (!shouldExecute) {
|
|
105
|
+
this.addLog(execution, 'info', `步骤 ${i + 1}: ${step.name} - 条件不满足,跳过`);
|
|
106
|
+
execution.steps[i].status = 'skipped';
|
|
107
|
+
await execution.save();
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.addLog(execution, 'info', `步骤 ${i + 1}: ${step.name} - 开始执行`);
|
|
113
|
+
execution.steps[i].status = 'running';
|
|
114
|
+
execution.steps[i].startedAt = new Date();
|
|
115
|
+
await execution.save();
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
const result = await this.executeStep(step, execution);
|
|
119
|
+
|
|
120
|
+
execution.steps[i].status = 'completed';
|
|
121
|
+
execution.steps[i].completedAt = new Date();
|
|
122
|
+
execution.steps[i].result = result;
|
|
123
|
+
await execution.save();
|
|
124
|
+
|
|
125
|
+
this.addLog(execution, 'info', `步骤 ${i + 1}: ${step.name} - 执行成功`);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
execution.steps[i].status = 'failed';
|
|
128
|
+
execution.steps[i].completedAt = new Date();
|
|
129
|
+
execution.steps[i].error = error.message;
|
|
130
|
+
await execution.save();
|
|
131
|
+
|
|
132
|
+
this.addLog(execution, 'error', `步骤 ${i + 1}: ${step.name} - 执行失败: ${error.message}`);
|
|
133
|
+
|
|
134
|
+
// 处理失败
|
|
135
|
+
if (step.onFailure === 'stop') {
|
|
136
|
+
throw error;
|
|
137
|
+
} else if (step.onFailure === 'retry' && step.retryCount > 0) {
|
|
138
|
+
// 重试逻辑
|
|
139
|
+
for (let retry = 0; retry < step.retryCount; retry++) {
|
|
140
|
+
this.addLog(execution, 'info', `步骤 ${i + 1}: ${step.name} - 重试 ${retry + 1}/${step.retryCount}`);
|
|
141
|
+
try {
|
|
142
|
+
const result = await this.executeStep(step, execution);
|
|
143
|
+
execution.steps[i].status = 'completed';
|
|
144
|
+
execution.steps[i].result = result;
|
|
145
|
+
await execution.save();
|
|
146
|
+
break;
|
|
147
|
+
} catch (retryError) {
|
|
148
|
+
if (retry === step.retryCount - 1) {
|
|
149
|
+
throw retryError;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// continue: 继续执行下一步
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 工作流执行完成
|
|
159
|
+
execution.status = 'completed';
|
|
160
|
+
execution.completedAt = new Date();
|
|
161
|
+
await execution.save();
|
|
162
|
+
|
|
163
|
+
// 更新工作流统计
|
|
164
|
+
await Workflow.findByIdAndUpdate(workflow._id, {
|
|
165
|
+
$inc: { 'stats.totalExecutions': 1, 'stats.successfulExecutions': 1 },
|
|
166
|
+
$set: { 'stats.lastExecutedAt': new Date() }
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
this.addLog(execution, 'info', '工作流执行完成');
|
|
170
|
+
} catch (error) {
|
|
171
|
+
execution.status = 'failed';
|
|
172
|
+
execution.completedAt = new Date();
|
|
173
|
+
execution.error = error.message;
|
|
174
|
+
await execution.save();
|
|
175
|
+
|
|
176
|
+
// 更新工作流统计
|
|
177
|
+
await Workflow.findByIdAndUpdate(workflow._id, {
|
|
178
|
+
$inc: { 'stats.totalExecutions': 1, 'stats.failedExecutions': 1 },
|
|
179
|
+
$set: { 'stats.lastExecutedAt': new Date() }
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
this.addLog(execution, 'error', `工作流执行失败: ${error.message}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// 执行单个步骤
|
|
187
|
+
async executeStep(step, execution) {
|
|
188
|
+
switch (step.type) {
|
|
189
|
+
case 'approval':
|
|
190
|
+
return await this.executeApprovalStep(step, execution);
|
|
191
|
+
case 'notification':
|
|
192
|
+
return await this.executeNotificationStep(step, execution);
|
|
193
|
+
case 'assignment':
|
|
194
|
+
return await this.executeAssignmentStep(step, execution);
|
|
195
|
+
case 'webhook':
|
|
196
|
+
return await this.executeWebhookStep(step, execution);
|
|
197
|
+
case 'delay':
|
|
198
|
+
return await this.executeDelayStep(step, execution);
|
|
199
|
+
case 'condition':
|
|
200
|
+
return await this.executeConditionStep(step, execution);
|
|
201
|
+
case 'script':
|
|
202
|
+
return await this.executeScriptStep(step, execution);
|
|
203
|
+
default:
|
|
204
|
+
throw new Error(`未知的步骤类型: ${step.type}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 执行审批步骤
|
|
209
|
+
async executeApprovalStep(step, execution) {
|
|
210
|
+
const { approvers, approvalType } = step.config;
|
|
211
|
+
|
|
212
|
+
if (!approvers || approvers.length === 0) {
|
|
213
|
+
throw new Error('未配置审批人');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// 创建审批记录
|
|
217
|
+
const approvals = await Promise.all(
|
|
218
|
+
approvers.map(approverId =>
|
|
219
|
+
new Approval({
|
|
220
|
+
execution: execution._id,
|
|
221
|
+
workflow: execution.workflow,
|
|
222
|
+
stepIndex: execution.currentStep,
|
|
223
|
+
approver: approverId,
|
|
224
|
+
status: 'pending'
|
|
225
|
+
}).save()
|
|
226
|
+
)
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
// 等待审批(这里简化处理,实际应该通过事件驱动)
|
|
230
|
+
// 在实际应用中,应该暂停执行,等待审批完成后继续
|
|
231
|
+
return {
|
|
232
|
+
type: 'approval',
|
|
233
|
+
approvals: approvals.map(a => a._id),
|
|
234
|
+
status: 'waiting'
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// 执行通知步骤
|
|
239
|
+
async executeNotificationStep(step, execution) {
|
|
240
|
+
const { notificationType, recipients, message } = step.config;
|
|
241
|
+
|
|
242
|
+
if (!recipients || recipients.length === 0) {
|
|
243
|
+
throw new Error('未配置通知接收人');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const users = await User.find({ _id: { $in: recipients } });
|
|
247
|
+
|
|
248
|
+
// 发送通知(这里简化处理)
|
|
249
|
+
for (const user of users) {
|
|
250
|
+
console.log(`发送${notificationType}通知给 ${user.username}: ${message}`);
|
|
251
|
+
// 实际应该调用通知服务
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
type: 'notification',
|
|
256
|
+
notificationType,
|
|
257
|
+
recipientCount: users.length,
|
|
258
|
+
message
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// 执行分配步骤
|
|
263
|
+
async executeAssignmentStep(step, execution) {
|
|
264
|
+
const { assignee } = step.config;
|
|
265
|
+
|
|
266
|
+
if (!assignee) {
|
|
267
|
+
throw new Error('未配置分配对象');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// 这里应该根据实际业务逻辑进行任务分配
|
|
271
|
+
return {
|
|
272
|
+
type: 'assignment',
|
|
273
|
+
assignee,
|
|
274
|
+
assignedAt: new Date()
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// 执行 Webhook 步骤
|
|
279
|
+
async executeWebhookStep(step, execution) {
|
|
280
|
+
const { url, method, headers, body } = step.config;
|
|
281
|
+
|
|
282
|
+
if (!url) {
|
|
283
|
+
throw new Error('未配置 Webhook URL');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const response = await axios({
|
|
287
|
+
method: method || 'POST',
|
|
288
|
+
url,
|
|
289
|
+
headers: headers || {},
|
|
290
|
+
data: body || execution.triggerData
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
type: 'webhook',
|
|
295
|
+
url,
|
|
296
|
+
method,
|
|
297
|
+
statusCode: response.status,
|
|
298
|
+
response: response.data
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// 执行延迟步骤
|
|
303
|
+
async executeDelayStep(step, execution) {
|
|
304
|
+
const { delayMinutes } = step.config;
|
|
305
|
+
|
|
306
|
+
if (!delayMinutes || delayMinutes <= 0) {
|
|
307
|
+
throw new Error('延迟时间配置无效');
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// 实际应该使用定时任务
|
|
311
|
+
await new Promise(resolve => setTimeout(resolve, delayMinutes * 60 * 1000));
|
|
312
|
+
|
|
313
|
+
return {
|
|
314
|
+
type: 'delay',
|
|
315
|
+
delayMinutes,
|
|
316
|
+
completedAt: new Date()
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// 执行条件步骤
|
|
321
|
+
async executeConditionStep(step, execution) {
|
|
322
|
+
const { conditions } = step.config;
|
|
323
|
+
|
|
324
|
+
if (!conditions || conditions.length === 0) {
|
|
325
|
+
throw new Error('未配置条件');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const result = this.checkConditions(conditions, execution.triggerData);
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
type: 'condition',
|
|
332
|
+
result,
|
|
333
|
+
conditions
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// 执行脚本步骤
|
|
338
|
+
async executeScriptStep(step, execution) {
|
|
339
|
+
const { script } = step.config;
|
|
340
|
+
|
|
341
|
+
if (!script) {
|
|
342
|
+
throw new Error('未配置脚本');
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// 注意:eval 有安全风险,生产环境应该使用沙箱环境
|
|
346
|
+
// 这里仅作示例
|
|
347
|
+
try {
|
|
348
|
+
const result = eval(script);
|
|
349
|
+
return {
|
|
350
|
+
type: 'script',
|
|
351
|
+
result
|
|
352
|
+
};
|
|
353
|
+
} catch (error) {
|
|
354
|
+
throw new Error(`脚本执行失败: ${error.message}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// 检查条件
|
|
359
|
+
checkConditions(conditions, data) {
|
|
360
|
+
return conditions.every(condition => {
|
|
361
|
+
const { field, operator, value } = condition;
|
|
362
|
+
const fieldValue = this.getFieldValue(data, field);
|
|
363
|
+
|
|
364
|
+
switch (operator) {
|
|
365
|
+
case 'equals':
|
|
366
|
+
return fieldValue === value;
|
|
367
|
+
case 'not_equals':
|
|
368
|
+
return fieldValue !== value;
|
|
369
|
+
case 'contains':
|
|
370
|
+
return String(fieldValue).includes(value);
|
|
371
|
+
case 'greater_than':
|
|
372
|
+
return fieldValue > value;
|
|
373
|
+
case 'less_than':
|
|
374
|
+
return fieldValue < value;
|
|
375
|
+
case 'in':
|
|
376
|
+
return Array.isArray(value) && value.includes(fieldValue);
|
|
377
|
+
case 'not_in':
|
|
378
|
+
return Array.isArray(value) && !value.includes(fieldValue);
|
|
379
|
+
default:
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// 获取字段值(支持嵌套)
|
|
386
|
+
getFieldValue(data, field) {
|
|
387
|
+
const keys = field.split('.');
|
|
388
|
+
let value = data;
|
|
389
|
+
for (const key of keys) {
|
|
390
|
+
if (value && typeof value === 'object') {
|
|
391
|
+
value = value[key];
|
|
392
|
+
} else {
|
|
393
|
+
return undefined;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return value;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// 添加日志
|
|
400
|
+
async addLog(execution, level, message, data = null) {
|
|
401
|
+
execution.logs.push({
|
|
402
|
+
timestamp: new Date(),
|
|
403
|
+
level,
|
|
404
|
+
message,
|
|
405
|
+
data
|
|
406
|
+
});
|
|
407
|
+
await execution.save();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// 处理审批决策
|
|
411
|
+
async handleApprovalDecision(approvalId, decision, comment, userId) {
|
|
412
|
+
const approval = await Approval.findById(approvalId)
|
|
413
|
+
.populate('execution')
|
|
414
|
+
.populate('workflow');
|
|
415
|
+
|
|
416
|
+
if (!approval) {
|
|
417
|
+
throw new Error('审批记录不存在');
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (approval.approver.toString() !== userId) {
|
|
421
|
+
throw new Error('无权处理此审批');
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (approval.status !== 'pending') {
|
|
425
|
+
throw new Error('审批已处理');
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
approval.status = decision;
|
|
429
|
+
approval.comment = comment;
|
|
430
|
+
approval.decidedAt = new Date();
|
|
431
|
+
await approval.save();
|
|
432
|
+
|
|
433
|
+
// 检查是否所有审批都已完成
|
|
434
|
+
const execution = approval.execution;
|
|
435
|
+
const workflow = approval.workflow;
|
|
436
|
+
const step = workflow.steps[approval.stepIndex];
|
|
437
|
+
|
|
438
|
+
const allApprovals = await Approval.find({
|
|
439
|
+
execution: execution._id,
|
|
440
|
+
stepIndex: approval.stepIndex
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
let shouldContinue = false;
|
|
444
|
+
|
|
445
|
+
if (step.config.approvalType === 'any') {
|
|
446
|
+
// 任意一人批准即可
|
|
447
|
+
shouldContinue = allApprovals.some(a => a.status === 'approved');
|
|
448
|
+
} else if (step.config.approvalType === 'all') {
|
|
449
|
+
// 所有人都需要批准
|
|
450
|
+
shouldContinue = allApprovals.every(a => a.status === 'approved');
|
|
451
|
+
} else if (step.config.approvalType === 'sequential') {
|
|
452
|
+
// 按顺序审批
|
|
453
|
+
const currentIndex = allApprovals.findIndex(a => a._id.toString() === approvalId);
|
|
454
|
+
if (decision === 'approved' && currentIndex < allApprovals.length - 1) {
|
|
455
|
+
// 继续下一个审批人
|
|
456
|
+
shouldContinue = false;
|
|
457
|
+
} else {
|
|
458
|
+
shouldContinue = decision === 'approved';
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (decision === 'rejected') {
|
|
463
|
+
// 审批被拒绝,工作流失败
|
|
464
|
+
execution.status = 'failed';
|
|
465
|
+
execution.error = '审批被拒绝';
|
|
466
|
+
await execution.save();
|
|
467
|
+
} else if (shouldContinue) {
|
|
468
|
+
// 审批通过,继续执行
|
|
469
|
+
// 这里应该触发继续执行工作流
|
|
470
|
+
this.executionQueue.push(execution._id);
|
|
471
|
+
this.processQueue();
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return approval;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
export default new WorkflowEngine();
|
|
479
|
+
|