feat: 提交流程中心后端代码
build / build-push (push) Successful in 28s

Spring Boot 流程引擎服务:流程定义/实例/任务、审批人解析、
回调分发、oapi 接口及单元测试。
保留远程 .gitea/workflows/build.yml 与 docker/Dockerfile,
新增 .gitignore 排除 target/ 构建产物。
This commit is contained in:
chenxing
2026-09-15 10:42:56 +08:00
parent 0296b2b5dd
commit c1103aeb29
65 changed files with 7119 additions and 0 deletions
@@ -0,0 +1,138 @@
package com.yunhai.flowcenter.engine;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yunhai.platform.apistd.BizException;
import com.yunhai.platform.utils.exception.ErrorCode;
import java.util.List;
/**
* 流程定义 JSON 模型(概览 §5.1 规范,一期 5 节点)。
* 序列化/反序列化统一走 {@link #parse(ObjectMapper, String)},未知属性忽略(向前兼容)。
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class FlowDefModel {
/** 节点类型(一期 5 种,二期按需扩展 NOTIFY/CONDITION) */
public static final String TYPE_START = "START";
public static final String TYPE_END = "END";
public static final String TYPE_APPROVAL = "APPROVAL";
public static final String TYPE_PARALLEL_SPLIT = "PARALLEL_SPLIT";
public static final String TYPE_PARALLEL_JOIN = "PARALLEL_JOIN";
/** 会签模式 */
public static final String COUNTERSIGN_ALL = "ALL";
public static final String COUNTERSIGN_ANY = "ANY";
/** 拒绝策略(一期仅 END_REJECTED) */
public static final String REJECT_END_REJECTED = "END_REJECTED";
/** 办理人类型(概览 §六:一期 DEPT_KEY/USERS;SUBMITTER_DEPT/FORM_FIELD 二期) */
public static final String ASSIGNEE_DEPT_KEY = "DEPT_KEY";
public static final String ASSIGNEE_USERS = "USERS";
public String code;
public String name;
public String start;
public List<Node> nodes;
public List<Edge> edges;
public Settings settings;
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Node {
public String id;
public String type;
public String name;
public Assignee assignee;
/** ALL(默认)|ANY */
public String countersign;
/** PARALLEL_JOIN 汇聚条件,一期仅 ALL */
public String waitFor;
/** 办理时限小时数(自然时间,任务 arrive_time + N 小时;可空) */
public Integer deadlineHours;
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Assignee {
/** DEPT_KEY | USERS */
public String type;
public String deptKey;
public List<Integer> userIds;
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Edge {
public String from;
public String to;
public String name;
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Settings {
public String rejectPolicy = REJECT_END_REJECTED;
public Urge urge = new Urge();
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Urge {
public Boolean enabled = true;
public Integer intervalHours = 24;
public Integer maxTimes = 3;
}
public static FlowDefModel parse(ObjectMapper objectMapper, String json) {
try {
FlowDefModel model = objectMapper.readValue(json, FlowDefModel.class);
if (model == null || model.nodes == null || model.edges == null) {
throw new BizException(ErrorCode.PARAM_ERROR, "流程定义 JSON 缺少 nodes/edges");
}
if (model.settings == null) {
model.settings = new Settings();
}
return model;
} catch (BizException e) {
throw e;
} catch (Exception e) {
throw new BizException(ErrorCode.PARAM_ERROR, "流程定义 JSON 不合法:" + e.getMessage());
}
}
public Node node(String nodeId) {
for (Node n : nodes) {
if (n.id != null && n.id.equals(nodeId)) {
return n;
}
}
return null;
}
public Node nodeById(String nodeId) {
Node n = node(nodeId);
if (n == null) {
throw new BizException(ErrorCode.PARAM_ERROR, "流程定义缺少节点:" + nodeId);
}
return n;
}
/** 出边集合(保持定义顺序) */
public List<Edge> outEdges(String nodeId) {
java.util.List<Edge> out = new java.util.ArrayList<>();
for (Edge e : edges) {
if (nodeId != null && nodeId.equals(e.from)) {
out.add(e);
}
}
return out;
}
public List<Edge> inEdges(String nodeId) {
java.util.List<Edge> in = new java.util.ArrayList<>();
for (Edge e : edges) {
if (nodeId != null && nodeId.equals(e.to)) {
in.add(e);
}
}
return in;
}
}