From 9864c3778169f5e69aa983490ef0a8f08ece4768 Mon Sep 17 00:00:00 2001 From: zouluping Date: Wed, 21 Jan 2026 10:59:12 +0800 Subject: [PATCH] =?UTF-8?q?feature:=20=E5=89=8D=E7=AB=AF=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=99=A8=E6=94=AF=E6=8C=81=E9=85=8D=E7=BD=AE?= =?UTF-8?q?schema?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/composition/use-modal.tsx | 66 +++- .../flow-content/workflow/lib/index.ts | 1 + .../flow-content/workflow/src/mock-data.ts | 59 +-- .../packages/flow-designer/package.json | 2 +- .../flow-designer/src/assets/images/index.ts | 1 + .../src/assets/images/method-invoke.jpg | Bin 0 -> 2606 bytes .../src/components/builtin-nodes/index.ts | 2 + .../builtin-nodes/loop/node-definition.ts | 21 +- .../builtin-nodes/method-invoke/index.ts | 1 + .../method-invoke/node-definition.ts | 59 +++ .../method-invoke/node.component.vue | 75 ++++ .../method-invoke/property-config.ts | 33 ++ .../builtin-nodes/start/property-config.ts | 2 + .../composition/use-flow-property-panel.tsx | 18 +- .../composition/use-node-property-panel.tsx | 30 +- .../node-debug-drawer.component.vue | 2 +- .../components/trial-run/chat-debug.vue | 7 +- .../trial-run/composables/use-input-params.ts | 355 ++++++------------ .../trial-run/composables/use-trial-run.ts | 6 +- .../components/trial-run/param-input.vue | 131 ++++++- .../components/trial-run/trial-run.vue | 5 +- .../toolbar/components/trial-run/types.ts | 7 +- .../flow-designer/src/hooks/node.utils.ts | 31 +- .../flow-designer/src/hooks/use-edge-types.ts | 2 +- .../hooks/use-flow-metadata-from-backend.ts | 9 +- .../src/hooks/use-vue-flow-data-converter.ts | 61 ++- .../lib/components/common-edge.vue | 2 +- .../lib/composition/use-type-details.ts | 59 +++ .../basic-type-selector/index.ts | 7 + .../src/basic-type-selector.component.tsx | 56 +++ .../src/basic-type-selector.props.ts | 14 + .../src/basic-type-selector.scss | 7 + .../form-materials/enum-input-help/index.ts | 7 + .../src/enum-input-help.component.tsx | 164 ++++++++ .../src/enum-input-help.props.ts | 9 + .../enum-input-help/src/enum-input-help.scss | 108 ++++++ .../flow-devkit/lib/form-materials/index.ts | 5 + .../src/input-params.component.tsx | 2 +- .../src/schema/input-params.schema.json | 2 +- .../src/composition/constants.ts | 10 + .../src/composition/index.ts | 5 + .../src/composition/type.ts | 15 + .../src/composition/use-columns-style.ts | 22 ++ .../src/composition/use-data.ts | 207 ++++++++++ .../src/composition/use-details.tsx | 116 ++++++ .../src/json-schema-editor.component.tsx | 334 ++++++++++++---- .../src/json-schema-editor.props.ts | 14 + .../src/json-schema-editor.scss | 100 ++++- .../src/schema/json-schema-editor.schema.json | 20 + .../method-invoke-express/index.ts | 13 + .../src/components/index.ts | 1 + .../src/components/method-type-select.scss | 0 .../src/components/method-type-select.tsx | 4 +- .../src/method-invoke-express.component.tsx | 337 +++++++++++++++++ .../src/method-invoke-express.props.ts | 21 ++ .../src/method-invoke-express.scss | 100 +++++ .../schema/method-invoke-express.schema.json | 24 ++ .../param-tag-list/src/param-tag-list.scss | 26 +- .../src/type-selector.component.tsx | 3 + .../src/components/index.ts | 1 - .../src/composition/use-const-tab.tsx | 6 +- .../src/composition/use-method-invoke-tab.tsx | 274 ++------------ .../src/composition/use-modal.tsx | 17 +- .../src/composition/use-value-expression.tsx | 40 +- .../src/composition/use-var-tab.tsx | 288 +++++++++----- .../schema/value-expression-input.schema.json | 2 +- .../src/value-expression-input.component.tsx | 54 ++- .../src/value-expression-input.scss | 103 ----- .../packages/flow-devkit/lib/index.ts | 2 + .../lib/third-party/tdesign-exports.ts | 22 +- .../lib/types/builtin-node-type.ts | 2 + .../composition/types.ts => types/common.ts} | 7 +- .../flow-devkit/lib/types/flow-metadata.ts | 20 +- .../flow-devkit/lib/types/flow-registry.ts | 11 + .../packages/flow-devkit/lib/types/index.ts | 3 + .../flow-devkit/lib/types/input-help.ts | 27 ++ .../flow-devkit/lib/types/json-schema.ts | 24 ++ .../flow-devkit/lib/types/node-definition.ts | 7 + .../flow-devkit/lib/types/value-express.ts | 8 +- .../packages/flow-devkit/lib/utils/index.ts | 2 + .../flow-devkit/lib/utils/input-help.ts | 29 ++ .../flow-devkit/lib/utils/json-schema.ts | 235 ++++++++++++ .../flow-devkit/lib/utils/param-validate.ts | 74 +++- .../flow-devkit/lib/utils/parameter.ts | 12 +- .../packages/flow-devkit/lib/utils/uuid.ts | 3 +- .../flow-devkit/lib/utils/validate.ts | 37 +- .../flow-devkit/lib/utils/value-express.ts | 175 ++++++++- .../packages/flow-devkit/package.json | 2 +- 88 files changed, 3290 insertions(+), 997 deletions(-) create mode 100644 ai-flow-front/packages/flow-designer/src/assets/images/method-invoke.jpg create mode 100644 ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/index.ts create mode 100644 ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/node-definition.ts create mode 100644 ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/node.component.vue create mode 100644 ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/property-config.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/basic-type-selector/index.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/basic-type-selector/src/basic-type-selector.component.tsx create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/basic-type-selector/src/basic-type-selector.props.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/basic-type-selector/src/basic-type-selector.scss create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/enum-input-help/index.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/enum-input-help/src/enum-input-help.component.tsx create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/enum-input-help/src/enum-input-help.props.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/enum-input-help/src/enum-input-help.scss create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/json-schema-editor/src/composition/constants.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/json-schema-editor/src/composition/index.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/json-schema-editor/src/composition/type.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/json-schema-editor/src/composition/use-columns-style.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/json-schema-editor/src/composition/use-data.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/json-schema-editor/src/composition/use-details.tsx create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/method-invoke-express/index.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/method-invoke-express/src/components/index.ts rename ai-flow-front/packages/flow-devkit/lib/form-materials/{value-expression-input => method-invoke-express}/src/components/method-type-select.scss (100%) rename ai-flow-front/packages/flow-devkit/lib/form-materials/{value-expression-input => method-invoke-express}/src/components/method-type-select.tsx (98%) create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/method-invoke-express/src/method-invoke-express.component.tsx create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/method-invoke-express/src/method-invoke-express.props.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/method-invoke-express/src/method-invoke-express.scss create mode 100644 ai-flow-front/packages/flow-devkit/lib/form-materials/method-invoke-express/src/schema/method-invoke-express.schema.json rename ai-flow-front/packages/flow-devkit/lib/{form-materials/value-expression-input/src/composition/types.ts => types/common.ts} (40%) create mode 100644 ai-flow-front/packages/flow-devkit/lib/types/input-help.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/types/json-schema.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/utils/input-help.ts create mode 100644 ai-flow-front/packages/flow-devkit/lib/utils/json-schema.ts diff --git a/ai-flow-front/packages/flow-content/workflow/lib/components/editors/agent-selector/src/composition/use-modal.tsx b/ai-flow-front/packages/flow-content/workflow/lib/components/editors/agent-selector/src/composition/use-modal.tsx index b4d3daa..eec4a7c 100644 --- a/ai-flow-front/packages/flow-content/workflow/lib/components/editors/agent-selector/src/composition/use-modal.tsx +++ b/ai-flow-front/packages/flow-content/workflow/lib/components/editors/agent-selector/src/composition/use-modal.tsx @@ -42,6 +42,7 @@ export function useModal( const treeGridComponentInstance = ref(); const dataGridRef = ref(); const agentFilterValue = ref(''); + let agentDataTotal = 0; function closeModal(): void { if (modalInstance.value) { @@ -75,19 +76,21 @@ export function useModal( * 智能体名称筛选处理 */ const onAgentFilterChange = (value: string) => { + agentFilterValue.value = value; + if (!value || value.trim() === '') { - filteredAgentData.value = [...agentData.value]; + fetchAgentList(currentTagId.value, ''); } else { const filterValue = value.toLowerCase().trim(); - filteredAgentData.value = agentData.value.filter((item: any) => - item.agentName && item.agentName.toLowerCase().includes(filterValue) - ); + pagination.value = { + ...pagination.value, + index: 1 + }; + fetchAgentList(currentTagId.value, filterValue); } - // 更新表格数据源并清除选中状态 if (dataGridRef.value) { - dataGridRef.value.updateDataSource(filteredAgentData.value); dataGridRef.value.clearSelection?.(); // 清除表格的选中状态 } @@ -202,6 +205,11 @@ export function useModal( // 清空筛选框和选中状态 agentFilterValue.value = ''; selectedData.value = []; + // 更新分页配置 + pagination.value = { + ...pagination.value, + index: 1 + }; // 获取该分类下的智能体列表 fetchAgentList(tagId); @@ -210,28 +218,64 @@ export function useModal( // 当前选中的tagId const currentTagId = ref(null); + /** + * 获取当前语言 + */ + const getCurrentLang = () => { + const langKey = localStorage.getItem('languageCode'); + if(langKey === 'zh-CHS') return 'cafMlcchs'; + if(langKey === 'en') return 'cafMlcen'; + if(langKey === 'zh-CHT') return 'cafMlccht'; + return 'cafMlcchs'; + } + /** * 获取智能体列表 */ - const fetchAgentList = async (tagId: string | null) => { + const fetchAgentList = async (tagId: string | null, agentName: string | null = null) => { try { const requestData: any = { startDateTime: "", endDateTime: "", orderCondition: "createdOn", orderType: "desc", - tagId: tagId + tagId: tagId, + agentName: agentName, + page: pagination.value.index - 1, + pageSize: pagination.value.size }; const res = await post('/runtime/sys/v1.0/aiAgentBuilder/authFilter/agent', requestData); - - if (!res || !Array.isArray(res)) { + if (!res) { agentData.value = []; return; } + // 更新分页配置 + pagination.value = { + ...pagination.value, + total: res.pagination.totalCount + }; + + agentDataTotal = res.pagination.totalCount; + + // 只展示canEdit为false的智能体 - agentData.value = res.filter((agent: any) => agent.canEdit === false); + // agentData.value = res.resultList.filter((agent: any) => agent.canEdit === false).map((agent: any) => { + // const currentLang = getCurrentLang(); + // return { + // ...agent, + // agentName: agent.agentNameI18n?.[currentLang] || '' + // }; + // }); + agentData.value = res.resultList.map((agent: any) => { + const currentLang = getCurrentLang(); + return { + ...agent, + agentName: agent.agentNameI18n?.[currentLang] || '', + disabled: agent.canEdit + }; + }); // 应用筛选 if (!agentFilterValue.value || agentFilterValue.value.trim() === '') { diff --git a/ai-flow-front/packages/flow-content/workflow/lib/index.ts b/ai-flow-front/packages/flow-content/workflow/lib/index.ts index 025725b..2d0c606 100644 --- a/ai-flow-front/packages/flow-content/workflow/lib/index.ts +++ b/ai-flow-front/packages/flow-content/workflow/lib/index.ts @@ -118,6 +118,7 @@ export const FLOW_REGISTRY: FlowRegistry = { BuiltinNodeType.Loop, BuiltinNodeType.VariableDef, BuiltinNodeType.VariableAssign, + BuiltinNodeType.MethodInvoke, BuiltinNodeType.End, ], }], diff --git a/ai-flow-front/packages/flow-content/workflow/src/mock-data.ts b/ai-flow-front/packages/flow-content/workflow/src/mock-data.ts index 2a97d3e..dbec913 100644 --- a/ai-flow-front/packages/flow-content/workflow/src/mock-data.ts +++ b/ai-flow-front/packages/flow-content/workflow/src/mock-data.ts @@ -34,42 +34,7 @@ export const MOCK_FLOW_METADATA: FlowMetadata = { inputPorts: [], outputPorts: [], graphMeta: { - position: { x: 80, y: 150 }, - }, - extension: {}, - }, { - id: 'llm', - kind: 'LLMClient', - code: 'llm', - name: '大模型', - description: '', - inputParams: [{ - code: 'question', - type: { - source: 'default', - typeId: 'string', - typeCode: 'String', - typeName: 'String', - }, - valueExpr: { - kind: 'nodeVariable', - nodeCode: 'start', - variable: 'keyword', - }, - }], - outputParams: [{ - code: 'result', - type: { - source: 'default', - typeId: 'string', - typeCode: 'String', - typeName: 'String', - }, - }], - inputPorts: [], - outputPorts: [], - graphMeta: { - position: { x: 450, y: 150 }, + position: { x: 0, y: 0 }, }, extension: {}, }, { @@ -79,34 +44,16 @@ export const MOCK_FLOW_METADATA: FlowMetadata = { name: '结束', description: '', inputParams: [], - outputParams: [{ - code: 'outline', - type: { - source: 'default', - typeId: 'string', - typeCode: 'String', - typeName: 'String', - }, - valueExpr: { - kind: 'nodeVariable', - nodeCode: 'llm', - variable: 'result', - }, - }], + outputParams: [], inputPorts: [], outputPorts: [], graphMeta: { - position: { x: 850, y: 150 }, + position: { x: 1000, y: 0 }, }, extension: {}, }], edges: [{ sourceNodeId: 'start', - targetNodeId: 'llm', - sourcePort: 'output', - targetPort: 'input', - }, { - sourceNodeId: 'llm', targetNodeId: 'end', sourcePort: 'output', targetPort: 'input', diff --git a/ai-flow-front/packages/flow-designer/package.json b/ai-flow-front/packages/flow-designer/package.json index d9e004d..0f42dcb 100644 --- a/ai-flow-front/packages/flow-designer/package.json +++ b/ai-flow-front/packages/flow-designer/package.json @@ -1,6 +1,6 @@ { "name": "@farris/flow-designer", - "version": "0.0.5", + "version": "0.0.6", "license": "Apache-2.0", "private": true, "type": "module", diff --git a/ai-flow-front/packages/flow-designer/src/assets/images/index.ts b/ai-flow-front/packages/flow-designer/src/assets/images/index.ts index 578e093..6fd7f54 100644 --- a/ai-flow-front/packages/flow-designer/src/assets/images/index.ts +++ b/ai-flow-front/packages/flow-designer/src/assets/images/index.ts @@ -4,3 +4,4 @@ export { default as selectorIcon } from './icon-selector.jpg'; export { default as loopIcon } from './icon-loop.jpg'; export { default as variableDefIcon } from './icon-variable-def.jpg'; export { default as variableAssignIcon } from './icon-variable-assign.jpg'; +export { default as methodInvokeIcon } from './method-invoke.jpg'; diff --git a/ai-flow-front/packages/flow-designer/src/assets/images/method-invoke.jpg b/ai-flow-front/packages/flow-designer/src/assets/images/method-invoke.jpg new file mode 100644 index 0000000000000000000000000000000000000000..782339fad366fd7268668c0df4bd5cbc79f8cd64 GIT binary patch literal 2606 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 Nqo9QCcGw^4{|{{AqLcst literal 0 HcmV?d00001 diff --git a/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/index.ts b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/index.ts index a9828cc..e2441d8 100644 --- a/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/index.ts +++ b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/index.ts @@ -4,6 +4,7 @@ import { SELECTOR_NODE } from './selector'; import { LOOP_NODE } from './loop'; import { VARIABLE_DEF_NODE } from './variable-def'; import { VARIABLE_ASSIGN_NODE } from './variable-assign'; +import { METHOD_INVOKE_NODE } from './method-invoke'; export const BUILTIN_NODES = [ START_NODE, @@ -12,4 +13,5 @@ export const BUILTIN_NODES = [ LOOP_NODE, VARIABLE_DEF_NODE, VARIABLE_ASSIGN_NODE, + METHOD_INVOKE_NODE, ]; diff --git a/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/loop/node-definition.ts b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/loop/node-definition.ts index fa53239..9482ff0 100644 --- a/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/loop/node-definition.ts +++ b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/loop/node-definition.ts @@ -1,6 +1,6 @@ import { markRaw } from 'vue'; -import type { NodeDefinition, Parameter, TypeRefer } from '@farris/flow-devkit'; -import { BasicTypeRefer, BuiltinNodeType, ValidateUtils } from '@farris/flow-devkit'; +import type { NodeDefinition, Parameter, TypeRefer, JsonSchema } from '@farris/flow-devkit'; +import { BasicTypeRefer, BuiltinNodeType, ValidateUtils, ValueExpressUtils } from '@farris/flow-devkit'; import { loopIcon } from '@flow-designer/assets/images'; import SubFlowNode from './node.component.vue'; import { NodeProperty } from './property-config'; @@ -12,7 +12,7 @@ export const LOOP_NODE: NodeDefinition = { description: '根据循环数组,循环执行一段逻辑', icon: loopIcon, isSubFlowContainer: true, - debuggable: false, // @todo 单节点调试功能暂不支持识别`inputParams`之外的输入参数,后续需要支持通过回调方法自定义输入参数 + debuggable: false, ports: [ { id: 'input', @@ -46,12 +46,25 @@ export const LOOP_NODE: NodeDefinition = { writable: false, }; const itemCode = nodeData.iterableVariable || 'item'; - const itemType = (nodeData.iterableExprType as TypeRefer)?.genericTypes?.[0]; + let itemType: TypeRefer | undefined = undefined; + let itemSchema: JsonSchema | undefined = undefined; + if (ValueExpressUtils.isNodeVariableExpr(nodeData.iterableExpr)) { + const valueExpressType = ValueExpressUtils.unwrapValueExpressType( + ValueExpressUtils.getValueExpressType(nodeData.iterableExpr, nodeData) + ); + if (valueExpressType) { + itemType = valueExpressType.type; + itemSchema = valueExpressType.schema; + } + } else { + itemType = (nodeData.iterableExprType as TypeRefer)?.genericTypes?.[0]; + } const item = { id: `${nodeData.id}_item`, code: itemCode, name: `${itemCode} (in items)`, type: itemType, + schema: itemSchema, writable: false, } as Parameter; return [item, index, ...nodeData.outputParams]; diff --git a/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/index.ts b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/index.ts new file mode 100644 index 0000000..218a7bd --- /dev/null +++ b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/index.ts @@ -0,0 +1 @@ +export * from './node-definition'; diff --git a/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/node-definition.ts b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/node-definition.ts new file mode 100644 index 0000000..20239c4 --- /dev/null +++ b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/node-definition.ts @@ -0,0 +1,59 @@ +import { markRaw } from 'vue'; +import type { NodeDefinition, MethodInvokeExpr } from '@farris/flow-devkit'; +import { BuiltinNodeType, ValueExpressUtils, ParameterUtils, useTypeDetails } from '@farris/flow-devkit'; +import { methodInvokeIcon } from '@flow-designer/assets/images'; +import MethodInvokeComponent from './node.component.vue'; +import { NodeProperty } from './property-config'; + +export const METHOD_INVOKE_NODE: NodeDefinition = { + metadata: { + type: BuiltinNodeType.MethodInvoke, + label: '函数调用', + description: '用于调用一个函数', + icon: methodInvokeIcon, + debuggable: true, + ports: [ + { + id: 'input', + position: 'left', + type: 'target', + }, + { + id: 'output', + position: 'right', + type: 'source', + } + ] + }, + component: markRaw(MethodInvokeComponent), + getPropertyPanelConfig: (nodeData) => { + const config = new NodeProperty(); + return config.getPropertyConfig(nodeData); + }, + validator: (nodeData) => { + if (!ValueExpressUtils.isMethodInvokeExpr(nodeData.express)) { + return { errors: [{ message: "函数名不可为空" }] }; + } + }, + getOutputParams: (nodeData) => { + const express = nodeData.express as MethodInvokeExpr; + const returnType = ValueExpressUtils.getReturnTypeByMethodInvokeExpr(express); + if (!returnType || ParameterUtils.isVoid(returnType)) { + return []; + } + const { loadType } = useTypeDetails(); + loadType(returnType); + return [{ + id: `${nodeData.id}_returnValue`, + code: `returnValue`, + type: returnType, + description: `函数的返回值`, + readOnly: true, + }]; + }, + getDebugParams: (nodeData) => { + const express = nodeData.express as MethodInvokeExpr; + const method = ValueExpressUtils.getMethodTypeByMethodInvokeExpr(express); + return method?.parameters || []; + }, +}; diff --git a/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/node.component.vue b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/node.component.vue new file mode 100644 index 0000000..7362c49 --- /dev/null +++ b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/node.component.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/property-config.ts b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/property-config.ts new file mode 100644 index 0000000..0169a18 --- /dev/null +++ b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/method-invoke/property-config.ts @@ -0,0 +1,33 @@ +import { BaseControlProperty, type NodeData } from '@farris/flow-devkit'; + +export class NodeProperty extends BaseControlProperty { + + public getPropertyConfig(nodeData: NodeData) { + this.propertyConfig.categories['basic'] = { + hideTitle: true, + title: "基本信息", + description: "Basic Information", + properties: { + name: { + type: "object", + editor: { + type: 'fvf-node-header', + nodeData, + }, + } + } + }; + this.propertyConfig.categories['express'] = { + title: "调用配置", + properties: { + express: { + type: "object", + editor: { + type: 'fvf-method-invoke-express', + } + } + } + }; + return this.propertyConfig; + } +} diff --git a/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/start/property-config.ts b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/start/property-config.ts index 1e223b6..57886ca 100644 --- a/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/start/property-config.ts +++ b/ai-flow-front/packages/flow-designer/src/components/builtin-nodes/start/property-config.ts @@ -24,6 +24,8 @@ export class NodeProperty extends BaseControlProperty { type: "array", editor: { type: 'fvf-json-schema-editor', + canEditName: true, + canEditInputHelp: true, } } } diff --git a/ai-flow-front/packages/flow-designer/src/components/flow-view/composition/use-flow-property-panel.tsx b/ai-flow-front/packages/flow-designer/src/components/flow-view/composition/use-flow-property-panel.tsx index 2aa0d73..9bd9269 100644 --- a/ai-flow-front/packages/flow-designer/src/components/flow-view/composition/use-flow-property-panel.tsx +++ b/ai-flow-front/packages/flow-designer/src/components/flow-view/composition/use-flow-property-panel.tsx @@ -5,6 +5,8 @@ import type { PropertyCategory, PropertyPanelConfig } from '@farris/flow-devkit' import css from '../flow-view.module.scss'; +const PROPERTY_PANEL_DEFAULT_WIDTH = 300; + export function useFlowPropertyPanel() { const flowRegistry = inject(FLOW_REGISTRY_KEY); @@ -67,7 +69,7 @@ export function useFlowPropertyPanel() { return panelShowMode.value === 'panel'; }); - const leftPanelWidth = ref(300); + const leftPanelWidth = ref(PROPERTY_PANEL_DEFAULT_WIDTH); const leftPanelStyle = computed(() => ({ display: shouldShowPropertyPanel.value ? undefined : 'none', @@ -79,7 +81,21 @@ export function useFlowPropertyPanel() { categories: {}, }; + function setPanelWidth(newValue: number): void { + leftPanelWidth.value = newValue; + } + + function updatePanelWidth(): void { + const defaultWidth = flowRegistry?.value?.flowPropertyPanelDefaultWidth; + if (typeof defaultWidth === 'number' && defaultWidth > 0) { + setPanelWidth(defaultWidth); + return; + } + setPanelWidth(PROPERTY_PANEL_DEFAULT_WIDTH); + } + function updatePropertyPanel(forceUpdate = true): void { + updatePanelWidth(); const propertyConfig = getPropertyPanelConfig.value?.(propertyData.value) || defaultPropertyPanelConfig; propertyConfig.type = 'object'; propertyConfig.categories = Object.assign({ _basic_: defaultPropertyCategory }, propertyConfig.categories); diff --git a/ai-flow-front/packages/flow-designer/src/components/flow-view/composition/use-node-property-panel.tsx b/ai-flow-front/packages/flow-designer/src/components/flow-view/composition/use-node-property-panel.tsx index e3df291..6aeb2c2 100644 --- a/ai-flow-front/packages/flow-designer/src/components/flow-view/composition/use-node-property-panel.tsx +++ b/ai-flow-front/packages/flow-designer/src/components/flow-view/composition/use-node-property-panel.tsx @@ -1,11 +1,11 @@ -import { computed, ref, watch, provide, type CSSProperties, defineComponent, type PropType, type Ref } from 'vue'; +import { computed, ref, watch, provide, inject, type CSSProperties, defineComponent, type PropType, type Ref } from 'vue'; import { FlowPropertyPanel, type PanelShowMode } from '@flow-designer/components/property-panel'; import { useVueFlow, type GraphNode } from '@vue-flow/core'; import { nodeRegistry, PROPERTY_PANEL_KEY, provideNodeVariables } from '@farris/flow-devkit'; import type { NodeDefinition, NodeMetadata, FlowNodeInstance, NodeData } from '@farris/flow-devkit'; import { NODE_RENDER_SCENE_KEY, USE_NODE_ID_KEY, USE_NODE_DATA_KEY } from '@farris/flow-devkit'; import type { UseNodePropertyPanel } from './types'; -import { useFloatPanelLayout } from '@flow-designer/hooks'; +import { useFloatPanelLayout, FLOW_REGISTRY_KEY } from '@flow-designer/hooks'; import styles from '../flow-view.module.scss'; @@ -38,6 +38,8 @@ const NodeContextProvider = defineComponent({ }, }); +const PROPERTY_PANEL_DEFAULT_WIDTH = 450; + export function useNodePropertyPanel(): UseNodePropertyPanel { const { @@ -45,6 +47,7 @@ export function useNodePropertyPanel(): UseNodePropertyPanel { nodes: allNodes, onNodeClick, } = useVueFlow(); + const flowRegistry = inject(FLOW_REGISTRY_KEY); const isShow = ref(true); const propertyPanelInstance = ref(); @@ -94,7 +97,28 @@ export function useNodePropertyPanel(): UseNodePropertyPanel { return typeof getPropertyPanelConfig === 'function'; }); + const rightPanelWidth = ref(PROPERTY_PANEL_DEFAULT_WIDTH); + + function setPanelWidth(newValue: number): void { + rightPanelWidth.value = newValue; + } + + function updatePanelWidth(): void { + const nodeLevelDefaultWidth = selectedNodeDefinition.value?.propertyPanelDefaultWidth; + if (typeof nodeLevelDefaultWidth === 'number' && nodeLevelDefaultWidth > 0) { + setPanelWidth(nodeLevelDefaultWidth); + return; + } + const flowLevelDefaultWidth = flowRegistry?.value?.nodePropertyPanelDefaultWidth; + if (typeof flowLevelDefaultWidth === 'number' && flowLevelDefaultWidth > 0) { + setPanelWidth(flowLevelDefaultWidth); + return; + } + setPanelWidth(PROPERTY_PANEL_DEFAULT_WIDTH); + } + function updatePropertyPanel(forceUpdate = true): void { + updatePanelWidth(); const nodeId = selectedNode.value?.id; const nodeData = selectedNode.value?.data; const getPropertyPanelConfig = selectedNodeDefinition.value?.getPropertyPanelConfig; @@ -138,8 +162,6 @@ export function useNodePropertyPanel(): UseNodePropertyPanel { return panelShowMode.value === 'panel'; }); - const rightPanelWidth = ref(450); - const PANEL_ID = 'NodePropertyPanel'; const { currentRightFloatPanelId } = useFloatPanelLayout(); function renderCurrentPanel() { diff --git a/ai-flow-front/packages/flow-designer/src/components/node-debug-drawer/node-debug-drawer.component.vue b/ai-flow-front/packages/flow-designer/src/components/node-debug-drawer/node-debug-drawer.component.vue index 44195e4..c514b3e 100644 --- a/ai-flow-front/packages/flow-designer/src/components/node-debug-drawer/node-debug-drawer.component.vue +++ b/ai-flow-front/packages/flow-designer/src/components/node-debug-drawer/node-debug-drawer.component.vue @@ -334,7 +334,7 @@ onUnmounted(() => { .tab-item { flex: 1; text-align: center; - padding: 0 14px 7px 14px; + padding: 4px 14px 3px 14px; cursor: pointer; font-size: 14px; font-weight: 400; diff --git a/ai-flow-front/packages/flow-designer/src/components/toolbar/components/trial-run/chat-debug.vue b/ai-flow-front/packages/flow-designer/src/components/toolbar/components/trial-run/chat-debug.vue index 6bac968..2d0d193 100644 --- a/ai-flow-front/packages/flow-designer/src/components/toolbar/components/trial-run/chat-debug.vue +++ b/ai-flow-front/packages/flow-designer/src/components/toolbar/components/trial-run/chat-debug.vue @@ -111,7 +111,7 @@