Trim legacy workflow node runtime metadata
This commit is contained in:
-19
@@ -474,25 +474,6 @@ const availableNodes = computed(() => {
|
||||
];
|
||||
break;
|
||||
}
|
||||
case 'text_to_sql': {
|
||||
const textToSqlOutputVar =
|
||||
node.data.output_variable || 'text_to_sql_result';
|
||||
variables = [
|
||||
{
|
||||
key: `${textToSqlOutputVar}_sql`,
|
||||
label: $t(
|
||||
'ai-platform.workflow.editor.variableSelector.generatedSqlStatement',
|
||||
),
|
||||
},
|
||||
{
|
||||
key: `${textToSqlOutputVar}_thought`,
|
||||
label: $t(
|
||||
'ai-platform.workflow.editor.variableSelector.sqlThought',
|
||||
),
|
||||
},
|
||||
];
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// 其他未知节点类型,尝试从 output_variable 获取
|
||||
if (node.data.output_variable) {
|
||||
|
||||
@@ -10,8 +10,13 @@ import { ElTooltip } from 'element-plus';
|
||||
|
||||
import NodeResultCard from '../components/NodeResultCard.vue';
|
||||
|
||||
type NodeColorConfig = {
|
||||
headerBg: string;
|
||||
iconBg: string;
|
||||
iconColor: string;
|
||||
};
|
||||
|
||||
const props = defineProps<{
|
||||
// 新增:完整的执行结果(用于节点下方展示)
|
||||
executionResult?: NodeExecutionResult;
|
||||
executionStatus?: {
|
||||
elapsed_time?: number;
|
||||
@@ -29,12 +34,120 @@ const props = defineProps<{
|
||||
}>();
|
||||
|
||||
const addButtonRef = ref<HTMLElement | null>(null);
|
||||
const onNodeAddClick = inject<
|
||||
(nodeId: string, position: { x: number; y: number }) => void
|
||||
>('onNodeAddClick');
|
||||
|
||||
// 从父组件注入的添加节点函数
|
||||
const onNodeAddClick =
|
||||
inject<(nodeId: string, position: { x: number; y: number }) => void>(
|
||||
'onNodeAddClick',
|
||||
);
|
||||
const nodeColorConfigs: Record<string, NodeColorConfig> = {
|
||||
start: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-emerald-50 to-green-50 dark:from-emerald-950 dark:to-green-950',
|
||||
iconBg: 'bg-emerald-200 dark:bg-emerald-800',
|
||||
iconColor: 'text-emerald-600 dark:text-emerald-400',
|
||||
},
|
||||
end: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-rose-50 to-red-50 dark:from-rose-950 dark:to-red-950',
|
||||
iconBg: 'bg-rose-200 dark:bg-rose-800',
|
||||
iconColor: 'text-rose-600 dark:text-rose-400',
|
||||
},
|
||||
condition: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-amber-50 to-yellow-50 dark:from-amber-950 dark:to-yellow-950',
|
||||
iconBg: 'bg-amber-200 dark:bg-amber-800',
|
||||
iconColor: 'text-amber-600 dark:text-amber-400',
|
||||
},
|
||||
parallel: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-cyan-50 to-sky-50 dark:from-cyan-950 dark:to-sky-950',
|
||||
iconBg: 'bg-cyan-200 dark:bg-cyan-800',
|
||||
iconColor: 'text-cyan-600 dark:text-cyan-400',
|
||||
},
|
||||
merge: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-slate-50 to-gray-100 dark:from-slate-900 dark:to-gray-900',
|
||||
iconBg: 'bg-slate-300 dark:bg-slate-700',
|
||||
iconColor: 'text-slate-600 dark:text-slate-400',
|
||||
},
|
||||
llm: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-violet-50 to-purple-50 dark:from-violet-950 dark:to-purple-950',
|
||||
iconBg: 'bg-violet-200 dark:bg-violet-800',
|
||||
iconColor: 'text-violet-600 dark:text-violet-400',
|
||||
},
|
||||
intent: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-fuchsia-50 to-pink-50 dark:from-fuchsia-950 dark:to-pink-950',
|
||||
iconBg: 'bg-fuchsia-200 dark:bg-fuchsia-800',
|
||||
iconColor: 'text-fuchsia-600 dark:text-fuchsia-400',
|
||||
},
|
||||
code: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-orange-50 to-amber-50 dark:from-orange-950 dark:to-amber-950',
|
||||
iconBg: 'bg-orange-200 dark:bg-orange-800',
|
||||
iconColor: 'text-orange-600 dark:text-orange-400',
|
||||
},
|
||||
template: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-teal-50 to-emerald-50 dark:from-teal-950 dark:to-emerald-950',
|
||||
iconBg: 'bg-teal-200 dark:bg-teal-800',
|
||||
iconColor: 'text-teal-600 dark:text-teal-400',
|
||||
},
|
||||
http: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-blue-950 dark:to-indigo-950',
|
||||
iconBg: 'bg-blue-200 dark:bg-blue-800',
|
||||
iconColor: 'text-blue-600 dark:text-blue-400',
|
||||
},
|
||||
question: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-sky-50 to-blue-50 dark:from-sky-950 dark:to-blue-950',
|
||||
iconBg: 'bg-sky-200 dark:bg-sky-800',
|
||||
iconColor: 'text-sky-600 dark:text-sky-400',
|
||||
},
|
||||
choice: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-lime-50 to-green-50 dark:from-lime-950 dark:to-green-950',
|
||||
iconBg: 'bg-lime-200 dark:bg-lime-800',
|
||||
iconColor: 'text-lime-600 dark:text-lime-400',
|
||||
},
|
||||
message: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-pink-50 to-rose-50 dark:from-pink-950 dark:to-rose-950',
|
||||
iconBg: 'bg-pink-200 dark:bg-pink-800',
|
||||
iconColor: 'text-pink-600 dark:text-pink-400',
|
||||
},
|
||||
confirm: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-orange-50 to-red-50 dark:from-orange-950 dark:to-red-950',
|
||||
iconBg: 'bg-orange-200 dark:bg-orange-800',
|
||||
iconColor: 'text-orange-600 dark:text-orange-400',
|
||||
},
|
||||
loop: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-blue-50 to-cyan-50 dark:from-blue-950 dark:to-cyan-950',
|
||||
iconBg: 'bg-blue-200 dark:bg-blue-800',
|
||||
iconColor: 'text-blue-600 dark:text-blue-400',
|
||||
},
|
||||
subflow: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-indigo-50 to-purple-50 dark:from-indigo-950 dark:to-purple-950',
|
||||
iconBg: 'bg-indigo-200 dark:bg-indigo-800',
|
||||
iconColor: 'text-indigo-600 dark:text-indigo-400',
|
||||
},
|
||||
knowledge_retrieval: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-teal-50 to-cyan-50 dark:from-teal-950 dark:to-cyan-950',
|
||||
iconBg: 'bg-teal-200 dark:bg-teal-800',
|
||||
iconColor: 'text-teal-600 dark:text-teal-400',
|
||||
},
|
||||
};
|
||||
|
||||
const defaultNodeColorConfig: NodeColorConfig = {
|
||||
headerBg: 'bg-gradient-to-r from-card to-muted',
|
||||
iconBg: 'bg-card border border-border',
|
||||
iconColor: 'text-primary',
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
const rect = addButtonRef.value?.getBoundingClientRect();
|
||||
@@ -43,190 +156,13 @@ const handleClick = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 节点类型配色 - 支持 dark 模式,使用 Tailwind dark: 前缀
|
||||
const nodeColorConfig = computed(() => {
|
||||
const configs: Record<
|
||||
string,
|
||||
{ headerBg: string; iconBg: string; iconColor: string }
|
||||
> = {
|
||||
// 流程控制
|
||||
start: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-emerald-50 to-green-50 dark:from-emerald-950 dark:to-green-950',
|
||||
iconBg: 'bg-emerald-200 dark:bg-emerald-800',
|
||||
iconColor: 'text-emerald-600 dark:text-emerald-400',
|
||||
},
|
||||
end: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-rose-50 to-red-50 dark:from-rose-950 dark:to-red-950',
|
||||
iconBg: 'bg-rose-200 dark:bg-rose-800',
|
||||
iconColor: 'text-rose-600 dark:text-rose-400',
|
||||
},
|
||||
condition: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-amber-50 to-yellow-50 dark:from-amber-950 dark:to-yellow-950',
|
||||
iconBg: 'bg-amber-200 dark:bg-amber-800',
|
||||
iconColor: 'text-amber-600 dark:text-amber-400',
|
||||
},
|
||||
parallel: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-cyan-50 to-sky-50 dark:from-cyan-950 dark:to-sky-950',
|
||||
iconBg: 'bg-cyan-200 dark:bg-cyan-800',
|
||||
iconColor: 'text-cyan-600 dark:text-cyan-400',
|
||||
},
|
||||
merge: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-slate-50 to-gray-100 dark:from-slate-900 dark:to-gray-900',
|
||||
iconBg: 'bg-slate-300 dark:bg-slate-700',
|
||||
iconColor: 'text-slate-600 dark:text-slate-400',
|
||||
},
|
||||
|
||||
// AI 相关
|
||||
llm: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-violet-50 to-purple-50 dark:from-violet-950 dark:to-purple-950',
|
||||
iconBg: 'bg-violet-200 dark:bg-violet-800',
|
||||
iconColor: 'text-violet-600 dark:text-violet-400',
|
||||
},
|
||||
intent: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-fuchsia-50 to-pink-50 dark:from-fuchsia-950 dark:to-pink-950',
|
||||
iconBg: 'bg-fuchsia-200 dark:bg-fuchsia-800',
|
||||
iconColor: 'text-fuchsia-600 dark:text-fuchsia-400',
|
||||
},
|
||||
|
||||
// 代码和模板
|
||||
code: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-orange-50 to-amber-50 dark:from-orange-950 dark:to-amber-950',
|
||||
iconBg: 'bg-orange-200 dark:bg-orange-800',
|
||||
iconColor: 'text-orange-600 dark:text-orange-400',
|
||||
},
|
||||
template: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-teal-50 to-emerald-50 dark:from-teal-950 dark:to-emerald-950',
|
||||
iconBg: 'bg-teal-200 dark:bg-teal-800',
|
||||
iconColor: 'text-teal-600 dark:text-teal-400',
|
||||
},
|
||||
|
||||
// HTTP
|
||||
http: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-blue-950 dark:to-indigo-950',
|
||||
iconBg: 'bg-blue-200 dark:bg-blue-800',
|
||||
iconColor: 'text-blue-600 dark:text-blue-400',
|
||||
},
|
||||
|
||||
// 数据库
|
||||
db_query: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-indigo-50 to-blue-50 dark:from-indigo-950 dark:to-blue-950',
|
||||
iconBg: 'bg-indigo-200 dark:bg-indigo-800',
|
||||
iconColor: 'text-indigo-600 dark:text-indigo-400',
|
||||
},
|
||||
db_insert: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-green-50 to-emerald-50 dark:from-green-950 dark:to-emerald-950',
|
||||
iconBg: 'bg-green-200 dark:bg-green-800',
|
||||
iconColor: 'text-green-600 dark:text-green-400',
|
||||
},
|
||||
db_update: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-yellow-50 to-amber-50 dark:from-yellow-950 dark:to-amber-950',
|
||||
iconBg: 'bg-yellow-200 dark:bg-yellow-800',
|
||||
iconColor: 'text-yellow-600 dark:text-yellow-400',
|
||||
},
|
||||
db_delete: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-red-50 to-rose-50 dark:from-red-950 dark:to-rose-950',
|
||||
iconBg: 'bg-red-200 dark:bg-red-800',
|
||||
iconColor: 'text-red-600 dark:text-red-400',
|
||||
},
|
||||
db_sql: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-purple-50 to-violet-50 dark:from-purple-950 dark:to-violet-950',
|
||||
iconBg: 'bg-purple-200 dark:bg-purple-800',
|
||||
iconColor: 'text-purple-600 dark:text-purple-400',
|
||||
},
|
||||
|
||||
// Text-to-SQL
|
||||
text_to_sql: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-cyan-50 to-teal-50 dark:from-cyan-950 dark:to-teal-950',
|
||||
iconBg: 'bg-cyan-200 dark:bg-cyan-800',
|
||||
iconColor: 'text-cyan-600 dark:text-cyan-400',
|
||||
},
|
||||
|
||||
// 对话流
|
||||
question: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-sky-50 to-blue-50 dark:from-sky-950 dark:to-blue-950',
|
||||
iconBg: 'bg-sky-200 dark:bg-sky-800',
|
||||
iconColor: 'text-sky-600 dark:text-sky-400',
|
||||
},
|
||||
choice: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-lime-50 to-green-50 dark:from-lime-950 dark:to-green-950',
|
||||
iconBg: 'bg-lime-200 dark:bg-lime-800',
|
||||
iconColor: 'text-lime-600 dark:text-lime-400',
|
||||
},
|
||||
message: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-pink-50 to-rose-50 dark:from-pink-950 dark:to-rose-950',
|
||||
iconBg: 'bg-pink-200 dark:bg-pink-800',
|
||||
iconColor: 'text-pink-600 dark:text-pink-400',
|
||||
},
|
||||
confirm: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-orange-50 to-red-50 dark:from-orange-950 dark:to-red-950',
|
||||
iconBg: 'bg-orange-200 dark:bg-orange-800',
|
||||
iconColor: 'text-orange-600 dark:text-orange-400',
|
||||
},
|
||||
|
||||
// Snowflake
|
||||
snowflake_cortex_llm: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-cyan-50 to-blue-50 dark:from-cyan-950 dark:to-blue-950',
|
||||
iconBg: 'bg-cyan-200 dark:bg-cyan-800',
|
||||
iconColor: 'text-cyan-600 dark:text-cyan-400',
|
||||
},
|
||||
snowflake_cortex_analyst: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-blue-50 to-cyan-50 dark:from-blue-950 dark:to-cyan-950',
|
||||
iconBg: 'bg-blue-200 dark:bg-blue-800',
|
||||
iconColor: 'text-blue-600 dark:text-blue-400',
|
||||
},
|
||||
|
||||
// 子流程
|
||||
subflow: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-indigo-50 to-purple-50 dark:from-indigo-950 dark:to-purple-950',
|
||||
iconBg: 'bg-indigo-200 dark:bg-indigo-800',
|
||||
iconColor: 'text-indigo-600 dark:text-indigo-400',
|
||||
},
|
||||
|
||||
// 知识库
|
||||
knowledge_retrieval: {
|
||||
headerBg:
|
||||
'bg-gradient-to-r from-teal-50 to-cyan-50 dark:from-teal-950 dark:to-cyan-950',
|
||||
iconBg: 'bg-teal-200 dark:bg-teal-800',
|
||||
iconColor: 'text-teal-600 dark:text-teal-400',
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
configs[props.nodeType || ''] || {
|
||||
headerBg: 'bg-gradient-to-r from-card to-muted',
|
||||
iconBg: 'bg-card border border-border',
|
||||
iconColor: 'text-primary',
|
||||
}
|
||||
);
|
||||
});
|
||||
const nodeColorConfig = computed(
|
||||
() => nodeColorConfigs[props.nodeType || ''] || defaultNodeColorConfig,
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col">
|
||||
<!-- 节点主体 -->
|
||||
<div
|
||||
class="bg-card group relative w-[280px] max-w-[280px] rounded-xl border shadow-sm transition-all duration-200 hover:shadow-md"
|
||||
:class="[
|
||||
@@ -243,7 +179,6 @@ const nodeColorConfig = computed(() => {
|
||||
!selected && !executionStatus?.status ? 'border-border' : '',
|
||||
]"
|
||||
>
|
||||
<!-- Status Badge (Absolute Top Right) -->
|
||||
<div
|
||||
v-if="executionStatus"
|
||||
class="absolute -top-3 right-4 z-20 flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] shadow-sm"
|
||||
@@ -280,10 +215,11 @@ const nodeColorConfig = computed(() => {
|
||||
/>
|
||||
|
||||
<span v-if="executionStatus.status === 'running'">Running...</span>
|
||||
<span v-else-if="executionStatus.elapsed_time !== undefined">{{ executionStatus.elapsed_time }}ms</span>
|
||||
<span v-else-if="executionStatus.elapsed_time !== undefined">
|
||||
{{ executionStatus.elapsed_time }}ms
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Header -->
|
||||
<div
|
||||
class="border-border/50 flex items-center gap-3 rounded-t-xl border-b px-4 py-3"
|
||||
:class="nodeColorConfig.headerBg"
|
||||
@@ -302,7 +238,6 @@ const nodeColorConfig = computed(() => {
|
||||
<slot name="desc"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Token Usage -->
|
||||
<div
|
||||
v-if="executionStatus?.tokens_used"
|
||||
class="text-muted-foreground bg-muted border-border flex items-center rounded border px-1.5 py-0.5 text-[10px]"
|
||||
@@ -314,40 +249,34 @@ const nodeColorConfig = computed(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Body -->
|
||||
<div class="text-muted-foreground min-w-0 space-y-2 overflow-hidden p-4 text-xs">
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
||||
<!-- Input Handles (Left) -->
|
||||
<div v-if="inputs && inputs.length > 0">
|
||||
<Handle
|
||||
v-for="(input, index) in inputs"
|
||||
:key="input.id"
|
||||
type="target"
|
||||
:position="Position.Left"
|
||||
:id="input.id"
|
||||
:key="input.id"
|
||||
class="!bg-primary !z-20 !h-3 !w-3 !border-2 !border-white transition-transform hover:scale-125"
|
||||
:position="Position.Left"
|
||||
:style="{ top: `${((index + 1) * 100) / (inputs.length + 1)}%` }"
|
||||
type="target"
|
||||
/>
|
||||
</div>
|
||||
<!-- Default single input if not specified but needed logic can be handled in parent -->
|
||||
|
||||
<!-- Output Handles (Right) -->
|
||||
<div v-if="outputs && outputs.length > 0">
|
||||
<Handle
|
||||
v-for="(output, index) in outputs"
|
||||
:key="output.id"
|
||||
type="source"
|
||||
:position="Position.Right"
|
||||
:id="output.id"
|
||||
:key="output.id"
|
||||
class="!bg-primary !z-20 !h-3 !w-3 !border-2 !border-white transition-transform hover:scale-125"
|
||||
:position="Position.Right"
|
||||
:style="{ top: `${((index + 1) * 100) / (outputs.length + 1)}%` }"
|
||||
type="source"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 悬停时显示的添加按钮 - 放在节点更右侧,不覆盖 Handle -->
|
||||
<!-- 分支类型节点(condition/intent/parallel/choice)不显示通用添加按钮,需要从具体分支 Handle 拖线 -->
|
||||
<div
|
||||
v-if="
|
||||
nodeType !== 'end' &&
|
||||
@@ -357,25 +286,23 @@ const nodeColorConfig = computed(() => {
|
||||
"
|
||||
ref="addButtonRef"
|
||||
class="bg-primary hover:bg-primary/90 absolute -right-8 top-1/2 flex size-6 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full text-white opacity-0 shadow-md transition-opacity hover:scale-110 group-hover:opacity-100"
|
||||
title="{{ $t('ai-platform.workflow.nodes.common.addNextNode') }}"
|
||||
:title="$t('ai-platform.workflow.nodes.common.addNextNode')"
|
||||
@click.stop="handleClick"
|
||||
>
|
||||
<Plus class="pointer-events-none size-3.5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 节点下方的执行结果卡片(独立显示,不在节点内部) -->
|
||||
<NodeResultCard
|
||||
v-if="executionResult"
|
||||
:result="executionResult"
|
||||
:node-type="nodeType"
|
||||
:result="executionResult"
|
||||
class="mt-3"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 自定义 Handle 样式 */
|
||||
:deep(.vue-flow__handle) {
|
||||
z-index: 20;
|
||||
width: 10px;
|
||||
@@ -383,7 +310,6 @@ const nodeColorConfig = computed(() => {
|
||||
background: hsl(var(--primary));
|
||||
}
|
||||
|
||||
/* 运行中边框呼吸动画 */
|
||||
@keyframes pulse-border {
|
||||
0%,
|
||||
100% {
|
||||
|
||||
Reference in New Issue
Block a user