NOTIFY(2026-09-23):编辑器抄送卡片+抽屉+画布 bpmn:ServiceTask 映射、工作台「抄送我的」页签、轨迹 kind=CC 行、示意图青框卡片 CONDITION(2026-09-24):ConditionBox 互斥分支容器(分支列出口名就地编辑、无 JOIN 语义分支尾隐式汇合)、ConditionDrawer 判断服务下拉(flw_router)、convert 双向序列化(CONDITION+命名出边、uid+c 尾缀往返收敛)、validate 镜像后端口径、画布 bpmn:ExclusiveGateway 映射、轨迹「系统判断→出口」行(失败挂起提示)、示意图紫菱形(SVG 与服务端 PNG 同配色)、管理面 flw_router 维护页(/admin/routers)与办件记录「重跑路由」入口 convert 往返 54 项全过、npm run build 通过
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
<script setup lang="ts">
|
||||
// 条件分支配置抽屉(2026-09-24):结构与 NotifyDrawer 同源(本地表单 + 确定回写)。
|
||||
// 只管节点名与判断服务(flw_router 下拉);出口命名/分支编排 ConditionBox 就地做。
|
||||
import { computed, inject, reactive, watch } from "vue";
|
||||
import { Message } from "view-ui-plus";
|
||||
import { ConditionNode, EDITOR_CTX } from "../model";
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean;
|
||||
node: ConditionNode | null;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
"update:modelValue": [boolean];
|
||||
/** 节点已删除(由抽屉内删除按钮触发),由外层关闭抽屉并重算校验 */
|
||||
removed: [];
|
||||
}>();
|
||||
|
||||
const ctx = inject(EDITOR_CTX)!;
|
||||
|
||||
const form = reactive({
|
||||
name: "",
|
||||
routerKey: "",
|
||||
});
|
||||
|
||||
function syncFromNode(): void {
|
||||
const n = props.node;
|
||||
if (!n) return;
|
||||
form.name = n.name;
|
||||
form.routerKey = n.routerKey || "";
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [props.modelValue, props.node?.uid],
|
||||
() => {
|
||||
if (props.modelValue) syncFromNode();
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
/** 判断服务下拉:仅启用中的注册(ctx.routers 由编辑器载入);当前值兜底防选项丢失 */
|
||||
const routerOptions = computed(() => {
|
||||
const list = ctx.routers
|
||||
.filter((r) => r.status === 1)
|
||||
.map((r) => ({ value: r.routerKey, label: `${r.name}(${r.routerKey})` }));
|
||||
if (form.routerKey && !list.some((o) => o.value === form.routerKey)) {
|
||||
list.unshift({ value: form.routerKey, label: `${form.routerKey}(未注册或已停用)` });
|
||||
}
|
||||
return list;
|
||||
});
|
||||
|
||||
const routerHint = computed(() => {
|
||||
if (!form.routerKey) return "";
|
||||
const r = ctx.routers.find((x) => x.routerKey === form.routerKey);
|
||||
if (!r) return `判断服务「${form.routerKey}」未注册或已停用,发布会被拦截`;
|
||||
return `调用 ${r.serviceKey}${r.path};返回出口名即分支走向`;
|
||||
});
|
||||
|
||||
function onOk(): void {
|
||||
const n = props.node;
|
||||
if (!n) {
|
||||
emit("update:modelValue", false);
|
||||
return;
|
||||
}
|
||||
if (!form.name.trim()) {
|
||||
Message.warning("节点名称不能为空");
|
||||
return;
|
||||
}
|
||||
if (!form.routerKey) {
|
||||
Message.warning("请选择判断服务(未配置的判断服务运行到该节点会挂起)");
|
||||
return;
|
||||
}
|
||||
n.name = form.name.trim();
|
||||
n.routerKey = form.routerKey;
|
||||
emit("update:modelValue", false);
|
||||
}
|
||||
|
||||
function onRemove(): void {
|
||||
if (props.node) ctx.removeNode(props.node.uid);
|
||||
emit("removed");
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Drawer
|
||||
:model-value="modelValue"
|
||||
title="配置条件分支"
|
||||
:width="430"
|
||||
:mask-closable="false"
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
>
|
||||
<Form :label-width="0" class="dw-form">
|
||||
<div class="fld">
|
||||
<label>节点名称</label>
|
||||
<Input v-model="form.name" placeholder="如:发文部门判断" :maxlength="30" />
|
||||
</div>
|
||||
|
||||
<div class="fld">
|
||||
<label>判断服务</label>
|
||||
<Select v-model="form.routerKey" filterable placeholder="请选择判断服务(flw_router 注册)">
|
||||
<Option v-for="o in routerOptions" :key="o.value" :value="o.value" :label="o.label" />
|
||||
</Select>
|
||||
<div v-if="routerHint" class="hint" :class="{ warn: routerHint.includes('拦截') }">
|
||||
{{ routerHint.includes("拦截") ? "⚠ " : "" }}{{ routerHint }}
|
||||
</div>
|
||||
<div v-else class="hint">
|
||||
判断逻辑由业务方实现:引擎运行到该节点时同步调用判断接口,按返回出口名走对应分支
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="fld">
|
||||
<label>出口与分支</label>
|
||||
<div class="hint">
|
||||
出口名在各分支列头部就地编辑(互斥分支,出口名即判断依据,必填且唯一);判断失败流程挂起,
|
||||
由管理端"重跑路由"恢复,不配默认出口
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
|
||||
<div class="dw-foot">
|
||||
<Poptip confirm title="删除该条件分支及其全部分支?" ok-text="删除" cancel-text="取消" transfer @on-ok="onRemove">
|
||||
<Button type="error" ghost>删除节点</Button>
|
||||
</Poptip>
|
||||
<span style="flex: 1" />
|
||||
<Button @click="emit('update:modelValue', false)">取消</Button>
|
||||
<Button type="primary" @click="onOk">确定</Button>
|
||||
</div>
|
||||
</Drawer>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.dw-form {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.fld {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.fld > label {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
}
|
||||
.hint {
|
||||
color: #808695;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.hint.warn {
|
||||
color: #ff9900;
|
||||
}
|
||||
.dw-foot {
|
||||
position: sticky;
|
||||
bottom: -16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 0;
|
||||
margin-top: 8px;
|
||||
background: #fff;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user