2026-06-24 f4bd1f3c89d906131495a0aca5aaf82966378510
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple;
 
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.bpm.enums.definition.*;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.flowable.bpmn.model.IOParameter;
import org.hibernate.validator.constraints.URL;
 
import java.util.List;
import java.util.Map;
import java.util.Set;
 
@Schema(description = "管理后台 - 仿钉钉流程设计模型节点 VO")
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class BpmSimpleModelNodeVO {
 
    @Schema(description = "模型节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "StartEvent_1")
    @NotEmpty(message = "模型节点编号不能为空")
    private String id;
 
    @Schema(description = "模型节点类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
    @NotNull(message = "模型节点类型不能为空")
    @InEnum(BpmSimpleModelNodeTypeEnum.class)
    private Integer type;
 
    @Schema(description = "模型节点名称", example = "领导审批")
    private String name;
 
    @Schema(description = "节点展示内容", example = "指定成员: 芋道源码")
    private String showText;
 
    @Schema(description = "子节点")
    private BpmSimpleModelNodeVO childNode; // 补充说明:在该模型下,子节点有且仅有一个,不会有多个
 
    @Schema(description = "候选人策略", example = "30")
    @InEnum(BpmTaskCandidateStrategyEnum.class)
    private Integer candidateStrategy; // 用于审批,抄送节点
 
    @Schema(description = "候选人参数")
    private String candidateParam; // 用于审批,抄送节点
 
    @Schema(description = "审批节点类型", example = "1")
    @InEnum(BpmUserTaskApproveTypeEnum.class)
    private Integer approveType; // 用于审批节点
 
    @Schema(description = "多人审批方式", example = "1")
    @InEnum(BpmUserTaskApproveMethodEnum.class)
    private Integer approveMethod; // 用于审批节点
 
    @Schema(description = "通过比例", example = "100")
    private Integer approveRatio; // 通过比例,当多人审批方式为:多人会签(按通过比例) 需要设置
 
    @Schema(description = "表单权限", example = "[]")
    private List<Map<String, String>> fieldsPermission;
 
    @Schema(description = "操作按钮设置", example = "[]")
    private List<OperationButtonSetting> buttonsSetting;  // 用于审批节点
 
    @Schema(description = "是否需要签名", example = "false")
    private Boolean signEnable;
 
    @Schema(description = "是否填写审批意见", example = "false")
    private Boolean reasonRequire;
 
    @Schema(description = "跳过表达式", example = "{true}")
    private String skipExpression;  // 用于审批节点
 
    /**
     * 审批节点拒绝处理
     */
    private RejectHandler rejectHandler;
 
    /**
     * 审批节点超时处理
     */
    private TimeoutHandler timeoutHandler;
 
    @Schema(description = "审批节点的审批人与发起人相同时,对应的处理类型", example = "1")
    @InEnum(BpmUserTaskAssignStartUserHandlerTypeEnum.class)
    private Integer assignStartUserHandlerType;
 
    /**
     * 空处理策略
     */
    private AssignEmptyHandler assignEmptyHandler;
 
    /**
     * 创建任务监听器
     */
    private ListenerHandler taskCreateListener;
    /**
     * 指派任务监听器
     */
    private ListenerHandler taskAssignListener;
    /**
     * 完成任务监听器
     */
    private ListenerHandler taskCompleteListener;
 
    @Schema(description = "延迟器设置", example = "{}")
    private DelaySetting delaySetting;
 
    @Schema(description = "条件节点")
    private List<BpmSimpleModelNodeVO> conditionNodes; // 补充说明:有且仅有条件、并行、包容分支会使用
 
    /**
     * 条件节点设置
     */
    private ConditionSetting conditionSetting; // 仅用于条件节点 BpmSimpleModelNodeTypeEnum.CONDITION_NODE
 
    @Schema(description = "路由分支组", example = "[]")
    private List<RouterSetting> routerGroups;
 
    @Schema(description = "路由分支默认分支 ID", example = "Flow_xxx", hidden = true) // 由后端生成(不从前端传递),所以 hidden = true
    @JsonIgnore
    private String routerDefaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTER_BRANCH_NODE
 
    /**
     * 触发器节点设置
     */
    private TriggerSetting triggerSetting;
 
    @Schema(description = "附加节点 Id", example = "UserTask_xxx", hidden = true) // 由后端生成(不从前端传递),所以 hidden = true
    @JsonIgnore
    private String attachNodeId; // 目前用于触发器节点(HTTP 回调)。需要 UserTask 和 ReceiveTask(附加节点) 来完成
 
    /**
     * 子流程设置
     */
    private ChildProcessSetting childProcessSetting;
 
    @Schema(description = "任务监听器")
    @Valid
    @Data
    public static class ListenerHandler {
 
        @Schema(description = "是否开启任务监听器", example = "false")
        @NotNull(message = "是否开启任务监听器不能为空")
        private Boolean enable;
 
        @Schema(description = "请求路径", example = "http://xxxxx")
        private String path;
 
        @Schema(description = "请求头", example = "[]")
        private List<HttpRequestParam> header;
 
        @Schema(description = "请求体", example = "[]")
        private List<HttpRequestParam> body;
 
    }
 
    @Schema(description = "HTTP 请求参数设置")
    @Data
    public static class HttpRequestParam {
 
        @Schema(description = "值类型", example = "1")
        @InEnum(BpmHttpRequestParamTypeEnum.class)
        @NotNull(message = "值类型不能为空")
        private Integer type;
 
        @Schema(description = "键", example = "xxx")
        @NotEmpty(message = "键不能为空")
        private String key;
 
        @Schema(description = "值", example = "xxx")
        @NotEmpty(message = "值不能为空")
        private String value;
 
    }
 
    @Schema(description = "审批节点拒绝处理策略")
    @Data
    public static class RejectHandler {
 
        @Schema(description = "拒绝处理类型", example = "1")
        @InEnum(BpmUserTaskRejectHandlerTypeEnum.class)
        private Integer type;
 
        @Schema(description = "任务拒绝后驳回的节点 Id", example = "Activity_1")
        private String returnNodeId;
    }
 
    @Schema(description = "审批节点超时处理策略")
    @Valid
    @Data
    public static class TimeoutHandler {
 
        @Schema(description = "是否开启超时处理", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
        @NotNull(message = "是否开启超时处理不能为空")
        private Boolean enable;
 
        @Schema(description = "任务超时未处理的行为", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
        @NotNull(message = "任务超时未处理的行为不能为空")
        @InEnum(BpmUserTaskTimeoutHandlerTypeEnum.class)
        private Integer type;
 
        @Schema(description = "超时时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "PT6H")
        @NotEmpty(message = "超时时间不能为空")
        private String timeDuration;
 
        @Schema(description = "最大提醒次数", example = "1")
        private Integer maxRemindCount;
    }
 
    @Schema(description = "空处理策略")
    @Data
    @Valid
    public static class AssignEmptyHandler {
 
        @Schema(description = "空处理类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
        @NotNull(message = "空处理类型不能为空")
        @InEnum(BpmUserTaskAssignEmptyHandlerTypeEnum.class)
        private Integer type;
 
        @Schema(description = "指定人员审批的用户编号数组", example = "1")
        private List<Long> userIds;
    }
 
    @Schema(description = "操作按钮设置")
    @Data
    @Valid
    public static class OperationButtonSetting {
 
        // TODO @jason:是不是按钮的标识?id 会和数据库的 id 自增有点模糊,key 标识会更合理一点点哈。
        @Schema(description = "按钮 Id", example = "1")
        private Integer id;
 
        @Schema(description = "显示名称", example = "审批")
        private String displayName;
 
        @Schema(description = "是否启用", example = "true")
        private Boolean enable;
    }
 
    @Schema(description = "条件设置")
    @Data
    @Valid
    // 仅用于条件节点 BpmSimpleModelNodeTypeEnum.CONDITION_NODE
    public static class ConditionSetting {
 
        @Schema(description = "条件类型", example = "1")
        @InEnum(BpmSimpleModeConditionTypeEnum.class)
        private Integer conditionType;
 
        @Schema(description = "条件表达式", example = "${day>3}")
        private String conditionExpression;
 
        @Schema(description = "是否默认条件", example = "true")
        private Boolean defaultFlow;
 
        /**
         * 条件组
         */
        private ConditionGroups conditionGroups;
    }
 
    @Schema(description = "条件组")
    @Data
    @Valid
    public static class ConditionGroups {
 
        @Schema(description = "条件组下的条件关系是否为与关系", example = "true")
        @NotNull(message = "条件关系不能为空")
        private Boolean and;
 
        @Schema(description = "条件组下的条件", example = "[]")
        @NotEmpty(message = "条件不能为空")
        private List<Condition> conditions;
    }
 
    @Schema(description = "条件")
    @Data
    @Valid
    public static class Condition {
 
        @Schema(description = "条件下的规则关系是否为与关系", example = "true")
        @NotNull(message = "规则关系不能为空")
        private Boolean and;
 
        @Schema(description = "条件下的规则", example = "[]")
        @NotEmpty(message = "规则不能为空")
        private List<ConditionRule> rules;
    }
 
    @Schema(description = "条件规则")
    @Data
    @Valid
    public static class ConditionRule {
 
        @Schema(description = "运行符号", example = "==")
        @NotEmpty(message = "运行符号不能为空")
        private String opCode;
 
        @Schema(description = "运算符左边的值,例如某个流程变量", example = "startUserId")
        @NotEmpty(message = "运算符左边的值不能为空")
        private String leftSide;
 
        @Schema(description = "运算符右边的值", example = "1")
        @NotEmpty(message = "运算符右边的值不能为空")
        private String rightSide;
    }
 
    @Schema(description = "延迟器")
    @Data
    @Valid
    public static class DelaySetting {
 
        @Schema(description = "延迟时间类型", example = "1")
        @NotNull(message = "延迟时间类型不能为空")
        @InEnum(BpmDelayTimerTypeEnum.class)
        private Integer delayType;
 
        @Schema(description = "延迟时间表达式", example = "PT1H,2025-01-01T00:00:00")
        @NotEmpty(message = "延迟时间表达式不能为空")
        private String delayTime;
    }
 
    @Schema(description = "路由分支")
    @Data
    @Valid
    public static class RouterSetting {
 
        @Schema(description = "节点 Id", example = "Activity_xxx") // 跳转到该节点
        @NotEmpty(message = "节点 Id 不能为空")
        private String nodeId;
 
        @Schema(description = "条件类型", example = "1")
        @InEnum(BpmSimpleModeConditionTypeEnum.class)
        @NotNull(message = "条件类型不能为空")
        private Integer conditionType;
 
        @Schema(description = "条件表达式", example = "${day>3}")
        private String conditionExpression;
 
        @Schema(description = "条件组", example = "{}")
        private ConditionGroups conditionGroups;
    }
 
    @Schema(description = "触发器节点配置")
    @Data
    @Valid
    public static class TriggerSetting {
 
        @Schema(description = "触发器类型", example = "1")
        @InEnum(BpmTriggerTypeEnum.class)
        @NotNull(message = "触发器类型不能为空")
        private Integer type;
 
        /**
         * http 请求触发器设置
         */
        @Valid
        private HttpRequestTriggerSetting httpRequestSetting;
 
        /**
         * 流程表单触发器设置
         */
        private List<FormTriggerSetting> formSettings;
 
        @Schema(description = "http 请求触发器设置", example = "{}")
        @Data
        public static class HttpRequestTriggerSetting {
 
            @Schema(description = "请求路径", example = "http://127.0.0.1")
            @NotEmpty(message = "请求 URL 不能为空")
            @URL(message = "请求 URL 格式不正确")
            private String url;
 
            @Schema(description = "请求头参数设置", example = "[]")
            @Valid
            private List<HttpRequestParam> header;
 
            @Schema(description = "请求头参数设置", example = "[]")
            @Valid
            private List<HttpRequestParam> body;
 
            /**
             * 请求返回处理设置,用于修改流程表单值
             * <p>
             * key:表示要修改的流程表单字段名(name)
             * value:接口返回的字段名
             */
            @Schema(description = "请求返回处理设置", example = "[]")
            private List<KeyValue<String, String>> response;
 
            /**
             * Http 回调请求,需要指定回调任务 Key,用于回调执行
             */
            @Schema(description = "回调任务 Key", example = "xxx", hidden = true)
            private String callbackTaskDefineKey;
 
        }
 
        @Schema(description = "流程表单触发器设置", example = "{}")
        @Data
        public static class FormTriggerSetting {
 
            @Schema(description = "条件类型", example = "1")
            @InEnum(BpmSimpleModeConditionTypeEnum.class)
            private Integer conditionType;
 
            @Schema(description = "条件表达式", example = "${day>3}")
            private String conditionExpression;
 
            @Schema(description = "条件组", example = "{}")
            private ConditionGroups conditionGroups;
 
            @Schema(description = "修改的表单字段", example = "{}")
            private Map<String, Object> updateFormFields;
 
            @Schema(description = "删除表单字段", example = "[]")
            private Set<String> deleteFields;
        }
    }
 
    @Schema(description = "子流程节点配置")
    @Data
    @Valid
    public static class ChildProcessSetting {
 
        @Schema(description = "被调用流程", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxx")
        @NotEmpty(message = "被调用流程不能为空")
        private String calledProcessDefinitionKey;
 
        @Schema(description = "被调用流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxx")
        @NotEmpty(message = "被调用流程名称不能为空")
        private String calledProcessDefinitionName;
 
        @Schema(description = "是否异步", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
        @NotNull(message = "是否异步不能为空")
        private Boolean async;
 
        @Schema(description = "输入参数(主->子)", example = "[]")
        private List<IOParameter> inVariables;
 
        @Schema(description = "输出参数(子->主)", example = "[]")
        private List<IOParameter> outVariables;
 
        @Schema(description = "是否自动跳过子流程发起节点", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
        @NotNull(message = "是否自动跳过子流程发起节点不能为空")
        private Boolean skipStartUserNode;
 
        @Schema(description = "子流程发起人配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
        @NotNull(message = "子流程发起人配置不能为空")
        private StartUserSetting startUserSetting;
 
        @Schema(description = "超时设置", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
        private TimeoutSetting timeoutSetting;
 
        @Schema(description = "多实例设置", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
        private MultiInstanceSetting multiInstanceSetting;
 
        @Schema(description = "子流程发起人配置")
        @Data
        @Valid
        public static class StartUserSetting {
 
            @Schema(description = "子流程发起人类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
            @NotNull(message = "子流程发起人类型")
            @InEnum(BpmChildProcessStartUserTypeEnum.class)
            private Integer type;
 
            @Schema(description = "表单", example = "xxx")
            private String formField;
 
            @Schema(description = "当子流程发起人为空时类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
            @NotNull(message = "当子流程发起人为空时类型不能为空")
            @InEnum(BpmChildProcessStartUserEmptyTypeEnum.class)
            private Integer emptyType;
 
        }
 
        @Schema(description = "超时设置")
        @Data
        @Valid
        public static class TimeoutSetting {
 
            @Schema(description = "是否开启超时设置", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
            @NotNull(message = "是否开启超时设置不能为空")
            private Boolean enable;
 
            @Schema(description = "时间类型", example = "1")
            @InEnum(BpmDelayTimerTypeEnum.class)
            private Integer type;
 
            @Schema(description = "时间表达式", example = "PT1H,2025-01-01T00:00:00")
            private String timeExpression;
 
        }
 
        @Schema(description = "多实例设置")
        @Data
        @Valid
        public static class MultiInstanceSetting {
 
            @Schema(description = "是否开启多实例", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
            @NotNull(message = "是否开启多实例不能为空")
            private Boolean enable;
 
            @Schema(description = "是否串行", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
            @NotNull(message = "是否串行不能为空")
            private Boolean sequential;
 
            @Schema(description = "完成比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
            @NotNull(message = "完成比例不能为空")
            private Integer approveRatio;
 
            @Schema(description = "多实例来源类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
            @NotNull(message = "多实例来源类型不能为空")
            @InEnum(BpmChildProcessMultiInstanceSourceTypeEnum.class)
            private Integer sourceType;
 
            @Schema(description = "多实例来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
            @NotNull(message = "多实例来源不能为空")
            private String source;
 
        }
 
    }
}