feat(flow): 优化条件编辑界面和节点样式,增强用户体验

This commit is contained in:
zhanghao 2026-08-21 15:36:01 +08:00
parent d733ea8525
commit d8e1168020
3 changed files with 51 additions and 46 deletions

View File

@ -100,23 +100,25 @@
</el-select> </el-select>
</template> </template>
</el-input> </el-input>
<el-input v-else model-value="" readonly :disabled="!requiresComparison(item.condition)" placeholder="请选择比较变量"> <div v-else class="reference-field">
<template #prepend> <el-select
<el-select v-model="item.type" class="value-type" @change="resetCompareValue(item)"> v-model="item.type"
class="value-type"
:disabled="!requiresComparison(item.condition)"
@change="resetCompareValue(item)"
>
<el-option label="输入" value="input" /> <el-option label="输入" value="input" />
<el-option label="引用" value="quote" /> <el-option label="引用" value="quote" />
</el-select> </el-select>
</template>
<template #append>
<el-cascader <el-cascader
v-model="item.quote" v-model="item.quote"
:disabled="!requiresComparison(item.condition)" :disabled="!requiresComparison(item.condition)"
:options="quoteOptions" :options="quoteOptions"
:show-all-levels="false" :show-all-levels="false"
placeholder="请选择"
@visible-change="(visible) => refreshQuoteOptions(visible, item, 'quote')" @visible-change="(visible) => refreshQuoteOptions(visible, item, 'quote')"
/> />
</template> </div>
</el-input>
</el-form-item> </el-form-item>
</div> </div>
@ -262,14 +264,10 @@ const refreshQuoteOptions = (visible, item, field) => {
}; };
/** /**
* 校验并保存条件。先清理已删除条件的连线,再写入条件和锚点集合。 * 将当前分支配置写回画布节点。
* 新条件锚点的位置由 switch.vue 渲染摘要后自动测量并补齐。 * 即使表单校验失败也要写回,这样关闭抽屉后用户刚填的错误配置仍会保留在节点上。
*/ */
const validateAndSave = async () => { const persistConditions = () => {
const valid = await formRef.value?.validate().then(() => true).catch(() => false);
if (!valid) return;
try {
const conditions = JSON.parse(JSON.stringify(formData.nodeParams)); const conditions = JSON.parse(JSON.stringify(formData.nodeParams));
const activeIds = new Set(conditions.map((condition) => condition.id)); const activeIds = new Set(conditions.map((condition) => condition.id));
const removedIds = originalConditionIds.value.filter((id) => !activeIds.has(id)); const removedIds = originalConditionIds.value.filter((id) => !activeIds.has(id));
@ -284,7 +282,18 @@ const validateAndSave = async () => {
nodeParams: conditions, nodeParams: conditions,
anchor, anchor,
}); });
emit("save-success"); };
/**
* 校验并保存条件。校验失败时仍关闭抽屉,但向父组件发 save-error,
* 由 ParamsDrawer 标记画布节点为错误状态,并让试运行阶段继续拦截。
*/
const validateAndSave = async () => {
const valid = await formRef.value?.validate().then(() => true).catch(() => false);
try {
persistConditions();
emit(valid ? "save-success" : "save-error");
} catch { } catch {
emit("save-error"); emit("save-error");
} }
@ -402,12 +411,4 @@ defineExpose({ validateAndSave });
margin-bottom: 18px; margin-bottom: 18px;
} }
:deep(.el-input-group__append) {
width: 120px;
padding: 0;
}
:deep(.el-input-group__append .el-cascader) {
width: 100%;
}
</style> </style>

View File

@ -3,7 +3,7 @@
* 作用范围:仅服务于流程设计器模块;条件编辑由 SwitchNodeParams 组件独立负责。 * 作用范围:仅服务于流程设计器模块;条件编辑由 SwitchNodeParams 组件独立负责。
--> -->
<template> <template>
<div class="node__container" ref="switchRef"> <div class="node__container" :class="props.model.id" ref="switchRef">
<NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef"> <NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef">
<template #input> <template #input>
<JsonViewer :value="inputJsonData" copyable boxed sort theme="light" /> <JsonViewer :value="inputJsonData" copyable boxed sort theme="light" />
@ -241,7 +241,7 @@ defineExpose({ closePopover });
border-left: 4px solid var(--node-accent, #b7791f); border-left: 4px solid var(--node-accent, #b7791f);
border-radius: 8px; border-radius: 8px;
background: #fff; background: #fff;
box-shadow: 0 8px 24px rgba(31, 41, 55, 0.09); // box-shadow: 0 8px 24px rgba(31, 41, 55, 0.09);
box-sizing: border-box; box-sizing: border-box;
cursor: default; cursor: default;
} }

View File

@ -301,7 +301,11 @@ onMounted(() => bindComponent(componentRef.value));
box-shadow: 0 0 0 2px rgba(47, 128, 237, 0.2), 0 10px 26px rgba(31, 41, 55, 0.12); box-shadow: 0 0 0 2px rgba(47, 128, 237, 0.2), 0 10px 26px rgba(31, 41, 55, 0.12);
} }
&--selected.flow-node-shell--branch :deep(.node__container), &--selected.flow-node-shell--branch :deep(.node__container) {
border-color: #2f80ed;
box-shadow: none;
}
&--selected.flow-node-shell--loop :deep(.group__container), &--selected.flow-node-shell--loop :deep(.group__container),
&--selected.flow-node-shell--selectArea :deep(.group__container) { &--selected.flow-node-shell--selectArea :deep(.group__container) {
border-color: #2f80ed; border-color: #2f80ed;