feat(condition): 编辑器支持表达式判断——判断方式切换 + 出口条件就地编辑 + 表达式调试
- ConditionNode 增 judgeMode/conditions(SERVICE 缺省,旧定义天然兼容);DefEdgeJson/DefNodeJson 透传 condition/judgeMode - convert.ts 双向透传:CONDITION 分支首边带 condition,序列化顺序=分支顺序(求值优先级保序) - ConditionDrawer 判断方式 Radio(服务/表达式);ConditionBox 表达式模式分支头部条件输入(序号即优先级) - validate.ts 镜像校验:表达式模式每出口条件必填(语法由后端发布期拦) - Routers 页加「表达式调试」Modal(/admin/router/eval,与线上同一求值核心) - addBranch/removeBranch 同步维护 conditions 占位
This commit is contained in:
@@ -43,15 +43,19 @@ export function toContentJson(model: EditorModel): DefJson {
|
||||
* 条件分支(2026-09-24)无 JOIN 语义:分支尾不互连,隐式汇合到容器后继——cursor 置 null 后
|
||||
* 下一个节点(或 END)只接收各分支尾的连线;firstEdgeName 只作用于分支首边(出口名)。
|
||||
* walk 返回"尾集合"(普通序列=末节点,末尾含条件分支=各分支尾)。
|
||||
* firstEdgeCondition(2026-10-10):EXPRESSION 模式分支首边的条件表达式,与出口名同位写入。
|
||||
*/
|
||||
const walk = (items: EditorItem[], prev: string, firstEdgeName?: string): string[] => {
|
||||
const walk = (items: EditorItem[], prev: string, firstEdgeName?: string,
|
||||
firstEdgeCondition?: string): string[] => {
|
||||
let cursor: string | null = prev;
|
||||
let pending: string[] = [];
|
||||
let first = true;
|
||||
const linkTo = (toId: string): void => {
|
||||
if (cursor !== null) {
|
||||
if (first && firstEdgeName) {
|
||||
edges.push({ from: cursor, to: toId, name: firstEdgeName });
|
||||
const e: DefEdgeJson = { from: cursor, to: toId, name: firstEdgeName };
|
||||
if (firstEdgeCondition !== undefined) e.condition = firstEdgeCondition;
|
||||
edges.push(e);
|
||||
} else {
|
||||
edges.push({ from: cursor, to: toId });
|
||||
}
|
||||
@@ -102,16 +106,21 @@ export function toContentJson(model: EditorModel): DefJson {
|
||||
}
|
||||
if (item.kind === "condition") {
|
||||
const condId = `${item.uid}c`;
|
||||
nodes.push({
|
||||
const node: DefNodeJson = {
|
||||
id: condId,
|
||||
type: "CONDITION",
|
||||
name: item.name || "条件判断",
|
||||
routerKey: item.routerKey || "",
|
||||
});
|
||||
};
|
||||
// SERVICE 是后端缺省,不写字段保持最小 JSON;EXPRESSION 显式携带
|
||||
if (item.judgeMode === "EXPRESSION") node.judgeMode = "EXPRESSION";
|
||||
nodes.push(node);
|
||||
linkTo(condId);
|
||||
const tails: string[] = [];
|
||||
const expression = item.judgeMode === "EXPRESSION";
|
||||
item.branches.forEach((branch, bi) => {
|
||||
tails.push(...walk(branch, condId, item.outlets[bi]));
|
||||
const cond = expression ? (item.conditions || [])[bi] || "" : undefined;
|
||||
tails.push(...walk(branch, condId, item.outlets[bi], cond));
|
||||
});
|
||||
cursor = null;
|
||||
pending = tails;
|
||||
@@ -311,12 +320,19 @@ export function fromContentJson(def: any): ParsedDef {
|
||||
// uid 复用 JSON id 并剥掉生成态的 "c" 尾缀:uid+"c" 是本编辑器的 JSON id 生成约定,
|
||||
// 剥尾保证"图→树→图→树→图"的 id 收敛(否则每轮追加一个 c,往返不幂等)
|
||||
const uidRaw = condId.endsWith("c") ? condId.slice(0, -1) : condId;
|
||||
// 出口条件反解(2026-10-10):EXPRESSION 模式出边 condition 与 outlets 同位
|
||||
const conditions = heads.map((head) => {
|
||||
const e = edges.find((x) => x.from === condId && x.to === head);
|
||||
return e && e.condition ? String(e.condition) : "";
|
||||
});
|
||||
return {
|
||||
item: {
|
||||
uid: UsedIds.take(uidRaw),
|
||||
kind: "condition",
|
||||
name: n.name || "条件判断",
|
||||
routerKey: n.routerKey || "",
|
||||
judgeMode: n.judgeMode === "EXPRESSION" ? "EXPRESSION" : "SERVICE",
|
||||
conditions,
|
||||
outlets,
|
||||
branches: branches.map((b) => (b.length ? b : [createApproval()])),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user