feat: 优化工作流参数编辑与告警交互

- 新增 ParamTokenEditor,支持参数选择插入、token 高亮、整段删除与光标避让

- 参数候选改为动态监测,未映射参数可选择并在下拉与输入框顶部告警

- 接入知识库/搜索引擎/LLM/动态代码/HTTP Body 及 SQL、查询数据自定义节点

- 优化 Http 节点布局并补充参数解析工具与单测
This commit is contained in:
2026-02-28 21:37:49 +08:00
parent 59c95a3b06
commit 4ef17da6f4
13 changed files with 1465 additions and 120 deletions

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import NodeWrapper from '../core/NodeWrapper.svelte';
import {type Node, type NodeProps, useSvelteFlow} from '@xyflow/svelte';
import {type Node, type NodeProps, useNodesData, useSvelteFlow} from '@xyflow/svelte';
import {Button, Chosen, Heading, Input, Select, Textarea} from '../base';
import RefParameterList from '../core/RefParameterList.svelte';
import {getCurrentNodeId} from '#components/utils/NodeUtils';
@@ -8,6 +8,7 @@
import {getOptions} from '../utils/NodeUtils';
import OutputDefList from '../core/OutputDefList.svelte';
import {fillParameterId} from '../utils/useAddParameter.svelte.js';
import ParamTokenEditor from '../core/ParamTokenEditor.svelte';
const { data, ...rest }: {
data: NodeProps['data'],
@@ -15,9 +16,13 @@
} = $props();
const currentNodeId = getCurrentNodeId();
let currentNode = useNodesData(currentNodeId);
const { addParameter } = useAddParameter();
const flowInstance = useSvelteFlow();
const { updateNodeData: updateNodeDataInner } = flowInstance;
const editorParameters = $derived.by(() => {
return (currentNode?.current?.data?.parameters as Array<any>) || data.parameters || [];
});
const updateNodeData = (data: Record<string, any>) => {
updateNodeDataInner(currentNodeId, data);
@@ -104,19 +109,47 @@
{#if form.type === 'input'}
<div class="setting-title">{form.label}</div>
<div class="setting-item">
<Input
placeholder={form.placeholder}
style="width: 100%"
value={data[form.name] || form.defaultValue}
{...form.attrs}
onchange={(e)=>{
{#if form.templateSupport}
<ParamTokenEditor
mode="input"
placeholder={form.placeholder}
style="width: 100%"
value={data[form.name] || form.defaultValue}
parameters={editorParameters}
{...form.attrs}
oninput={(e)=>{
updateNodeDataByEvent(form.name,e)
}}
/>
/>
{:else}
<Input
placeholder={form.placeholder}
style="width: 100%"
value={data[form.name] || form.defaultValue}
{...form.attrs}
onchange={(e)=>{
updateNodeDataByEvent(form.name,e)
}}
/>
{/if}
</div>
{:else if form.type === 'textarea'}
<div class="setting-title">{form.label}</div>
<div class="setting-item">
{#if form.templateSupport}
<ParamTokenEditor
mode="textarea"
rows={3}
placeholder={form.placeholder}
style="width: 100%"
value={data[form.name] || form.defaultValue}
parameters={editorParameters}
{...form.attrs}
oninput={(e)=>{
updateNodeDataByEvent(form.name,e)
}}
/>
{:else}
<Textarea
rows={3}
placeholder={form.placeholder}
@@ -127,6 +160,7 @@
updateNodeDataByEvent(form.name,e)
}}
/>
{/if}
</div>
{:else if form.type === 'slider'}
<div class="setting-title">{form.label}</div>
@@ -246,5 +280,3 @@
}
</style>