Files
flow-center-front/src/views/flow/admin/def-editor/components/ConditionDrawer.vue
T

208 lines
7.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
// 条件分支配置抽屉(2026-09-24):结构与 NotifyDrawer 同源(本地表单 + 确定回写)。
// 管节点名与判断方式(2026-10-10 二选一:服务/表达式);出口命名/条件表达式/分支编排 ConditionBox 就地做。
import { computed, inject, reactive, watch } from "vue";
import { Message } from "view-ui-plus";
import { ConditionNode, EDITOR_CTX, JudgeMode } 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: "",
// 2026-10-12 SERVICE 收口:新建缺省翻转为表达式(主路径);存量归一化见 syncFromNode(勿动)
judgeMode: "EXPRESSION" as JudgeMode,
});
function syncFromNode(): void {
const n = props.node;
if (!n) return;
form.name = n.name;
form.routerKey = n.routerKey || "";
form.judgeMode = n.judgeMode === "EXPRESSION" ? "EXPRESSION" : "SERVICE";
}
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};返回出口名即分支走向`;
});
/** 切换判断方式:表达式模式下 conditions 补齐占位(与 outlets 同位) */
function switchJudgeMode(mode: JudgeMode): void {
form.judgeMode = mode;
const n = props.node;
if (n && mode === "EXPRESSION") {
n.conditions = n.conditions || [];
while (n.conditions.length < n.outlets.length) n.conditions.push("");
}
}
function onOk(): void {
const n = props.node;
if (!n) {
emit("update:modelValue", false);
return;
}
if (!form.name.trim()) {
Message.warning("节点名称不能为空");
return;
}
if (form.judgeMode === "SERVICE" && !form.routerKey) {
Message.warning("请选择判断服务(未配置的判断服务运行到该节点会挂起)");
return;
}
n.name = form.name.trim();
n.routerKey = form.judgeMode === "SERVICE" ? form.routerKey : "";
n.judgeMode = form.judgeMode;
if (form.judgeMode === "EXPRESSION") {
n.conditions = n.conditions || [];
while (n.conditions.length < n.outlets.length) n.conditions.push("");
}
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>
<RadioGroup :model-value="form.judgeMode" @on-change="switchJudgeMode">
<Radio label="SERVICE">服务(外部判断接口)</Radio>
<Radio label="EXPRESSION">表达式</Radio>
</RadioGroup>
<div class="hint">
简单条件用表达式在编辑器内闭环;复杂判断(查库/调外部系统)沿用注册的判断服务
</div>
</div>
<div v-if="form.judgeMode === 'SERVICE'" 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 class="hint">
仅当判断依赖流程到达时点的实时业务数据时使用;简单条件请用"表达式"(apply 时 formData
自带判断数据)。判断端点与登记由
<code>yh-flow-callback-spring-boot-starter</code>(流程中心接入件)自动完成,见《子应用接入流程中心规范》§6.6。
</div>
</div>
<div v-else class="fld">
<label>表达式说明</label>
<div class="hint">
每个出口在分支列头部就地填写 AviatorScript 条件(如 amount &gt; 1000);按分支顺序取
首个为真的出口。变量=表单字段 + 内置(schId/bizType/bizId/submitterId/instanceId 等)。
变量未提供或条件全不为真时流程挂起(不配默认出口),可在"条件路由"页调试表达式
</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>