From e1ef4c1a70d2648c0700eed92b265693c981c455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?cls=5F=E5=AE=81=E6=B3=A2=E6=9C=AC=E6=9C=BA?= <908705107@qq.com> Date: Mon, 22 Jun 2026 06:34:53 +0800 Subject: [PATCH] feat: improve workflow observability and lighten admin frontend --- .../ai_platform/services/workflow_service.py | 116 ++++++++- .../src/api/ai-platform/ai-platform.ts | 9 + web/apps/web-ele/src/api/core/index.ts | 19 -- web/apps/web-ele/src/locales/index.ts | 28 ++- web/apps/web-ele/src/router/access.ts | 14 -- web/apps/web-ele/src/router/light-menu.ts | 52 ++-- .../src/views/_core/page-render/index.vue | 102 +++++++- .../components/RunLogTimeline.vue | 97 +++++++- .../workflow/editor/components/Panel.vue | 67 ----- .../ai-platform/workflow/editor/index.vue | 235 +----------------- .../workflow/shared/workflowNodeTypes.ts | 37 --- 11 files changed, 360 insertions(+), 416 deletions(-) diff --git a/backend-fastapi/ai_platform/services/workflow_service.py b/backend-fastapi/ai_platform/services/workflow_service.py index be7b11e..17f7db5 100644 --- a/backend-fastapi/ai_platform/services/workflow_service.py +++ b/backend-fastapi/ai_platform/services/workflow_service.py @@ -226,6 +226,7 @@ def _make_execution_log_entry( **extra: Any, ) -> dict: extra.setdefault('timestamp', datetime.now().isoformat()) + events = extra.pop('events', None) metadata = dict(extra.pop('metadata', {}) or {}) event_type = _execution_log_event_type(extra.get('status')) collaboration = _node_collaboration_metadata(node_map, node_id, node_type) @@ -249,19 +250,106 @@ def _make_execution_log_entry( error=extra.get('error'), ) metadata['communication']['timestamp'] = extra.get('timestamp') - return { + entry = { 'node_id': node_id, 'node_type': node_type, 'node_label': _node_label_from_map(node_map, node_id), 'metadata': metadata, **extra, } + if events: + entry['events'] = events + return entry + + +def _event_log_status(event_type: str, event: Dict[str, Any]) -> str: + if event_type == 'error': + return 'failed' + if event_type == 'waiting_input': + return 'waiting' + if event_type in ('start', 'node_start', 'parallel_start'): + return 'running' + status = event.get('status') or 'completed' + if status == 'success': + return 'completed' + if status == 'failed': + return 'failed' + return status + + +def _make_stream_event_log_entry(event: Dict[str, Any]) -> Optional[dict]: + event_type = event.get('type') + if not event_type or event_type == 'llm_chunk': + return None + + event_data = copy.deepcopy(event) + timestamp = event_data.get('timestamp') or datetime.now().isoformat() + event_data.setdefault('timestamp', timestamp) + communication = dict(event_data.get('communication') or {}) + communication.setdefault('event', event_type) + communication.setdefault('timestamp', timestamp) + + node_id = str(event_data.get('node_id') or event_data.get('run_id') or 'workflow') + node_type = str(event_data.get('node_type') or 'workflow') + node_label = ( + event_data.get('node_label') + or event_data.get('workflow_name') + or communication.get('message') + or event_type + ) + output = event_data.get('outputs') + if output is None: + output = event_data.get('content') or event_data.get('message') + error = event_data.get('error_message') or event_data.get('error') + + return { + 'type': event_type, + 'node_id': node_id, + 'node_type': node_type, + 'node_label': str(node_label), + 'status': _event_log_status(event_type, event_data), + 'timestamp': timestamp, + 'elapsed_time': event_data.get('elapsed_time'), + 'tokens_used': event_data.get('tokens_used') or 0, + 'output': output, + 'error': error, + 'event': event_data, + 'events': [event_data], + 'metadata': { + 'stream_event': True, + 'collaboration': event_data.get('collaboration') or {}, + 'communication': communication, + }, + } + + +def _log_timestamp(log: Dict[str, Any]) -> str: + metadata = log.get('metadata') or {} + communication = metadata.get('communication') or {} + return log.get('timestamp') or communication.get('timestamp') or '' + + +def _merge_execution_logs(node_logs: List[dict], event_logs: List[dict]) -> List[dict]: + base_logs = [ + log for log in (node_logs or []) + if not (log.get('metadata') or {}).get('stream_event') + ] + merged = base_logs + list(event_logs or []) + return sorted( + merged, + key=lambda item: (_log_timestamp(item), 0 if item.get('metadata', {}).get('stream_event') else 1), + ) def _node_result_metadata(result: NodeResult) -> dict: return dict(result.metadata or {}) +def _node_result_events(result: NodeResult) -> List[Dict[str, Any]]: + events = getattr(result, 'events', None) or [] + return copy.deepcopy(events) if events else [] + + def _event_collaboration_metadata( node_map: Dict[str, Any], node_id: str, @@ -842,6 +930,7 @@ class AIWorkflowService: elapsed_time=elapsed, tokens_used=result.tokens_used, metadata=_node_result_metadata(result), + events=_node_result_events(result), inputs=copy.deepcopy(node_inputs), target_node_id=target_node_id, )) @@ -1024,6 +1113,7 @@ class AIWorkflowService: elapsed_time=elapsed, tokens_used=result.tokens_used, metadata=_node_result_metadata(result), + events=_node_result_events(result), inputs=copy.deepcopy(node_inputs), branch=branch_id, branch_label=branch_labels.get(branch_id, branch_id), @@ -1252,6 +1342,7 @@ class AIWorkflowService: elapsed_time=elapsed, tokens_used=result.tokens_used, metadata=_node_result_metadata(result), + events=_node_result_events(result), branch=branch_id, branch_label=branch_labels.get(branch_id, branch_id), )) @@ -1545,6 +1636,7 @@ class AIWorkflowService: elapsed_time=elapsed, tokens_used=result.tokens_used, metadata=_node_result_metadata(result), + events=_node_result_events(result), loop_iteration=iteration, )) @@ -1593,7 +1685,10 @@ class AIWorkflowService: current_id, node_type, status='waiting', + output=result.output, elapsed_time=elapsed, + metadata=_node_result_metadata(result), + events=_node_result_events(result), loop_iteration=iteration, )) @@ -1733,15 +1828,20 @@ class AIWorkflowService: ) self._db.add(run) await self._db.flush() + event_logs: List[dict] = [] try: # 使用异步生成器执行工作流 async for event in self._execute_workflow_stream(workflow, inputs, run, conversation_history, use_draft): yield event + event_log = _make_stream_event_log_entry(event) + if event_log: + event_logs.append(event_log) + run.execution_log = _merge_execution_logs(run.execution_log or [], event_logs) # 在关键事件后提交数据库状态 event_type = event.get('type') - if event_type in ('node_complete', 'waiting_input', 'complete', 'error'): + if event_log or event_type in ('node_complete', 'waiting_input', 'complete', 'error'): await self._db.commit() # 更新运行记录 @@ -1771,13 +1871,19 @@ class AIWorkflowService: await self._db.commit() # 发送错误事件给前端 - yield { + error_event = { 'type': 'error', 'message': str(e), 'error_message': str(e), 'run_id': run.id, 'workflow_id': workflow.id, } + error_log = _make_stream_event_log_entry(error_event) + if error_log: + event_logs.append(error_log) + run.execution_log = _merge_execution_logs(run.execution_log or [], event_logs) + await self._db.commit() + yield error_event async def _execute_workflow_stream( self, @@ -2026,6 +2132,7 @@ class AIWorkflowService: output=result.output, elapsed_time=elapsed, metadata=_node_result_metadata(result), + events=_node_result_events(result), inputs=copy.deepcopy(node_inputs), target_node_id=target_node_id, ) @@ -2067,6 +2174,7 @@ class AIWorkflowService: elapsed_time=elapsed, tokens_used=result.tokens_used, metadata=_node_result_metadata(result), + events=_node_result_events(result), inputs=copy.deepcopy(node_inputs), target_node_id=target_node_id, ) @@ -2557,6 +2665,7 @@ class AIWorkflowService: output=result.output, elapsed_time=elapsed, metadata=_node_result_metadata(result), + events=_node_result_events(result), target_node_id=target_node_id, ) logs.append(log_entry) @@ -2595,6 +2704,7 @@ class AIWorkflowService: elapsed_time=elapsed, tokens_used=result.tokens_used, metadata=_node_result_metadata(result), + events=_node_result_events(result), target_node_id=target_node_id, ) logs.append(log_entry) diff --git a/web/apps/web-ele/src/api/ai-platform/ai-platform.ts b/web/apps/web-ele/src/api/ai-platform/ai-platform.ts index 85cf632..4cba581 100644 --- a/web/apps/web-ele/src/api/ai-platform/ai-platform.ts +++ b/web/apps/web-ele/src/api/ai-platform/ai-platform.ts @@ -271,6 +271,14 @@ export interface WorkflowListItem { } /** 工作流运行记录 */ +export interface WorkflowRunEvent { + type?: string; + content?: string; + message?: string; + message_type?: string; + [key: string]: any; +} + export interface ExecutionLogEntry { node_id: string; node_type: string; @@ -285,6 +293,7 @@ export interface ExecutionLogEntry { branch?: string; branch_label?: string; metadata?: Record; + events?: WorkflowRunEvent[]; } export interface WorkflowRunListItem { diff --git a/web/apps/web-ele/src/api/core/index.ts b/web/apps/web-ele/src/api/core/index.ts index ec6a5ef..1da3078 100644 --- a/web/apps/web-ele/src/api/core/index.ts +++ b/web/apps/web-ele/src/api/core/index.ts @@ -1,22 +1,3 @@ -export * from '../online-dev/form-data-api'; -export * from '../online-dev/form-manager'; -// 注意: login-log 模块请直接导入以避免 PaginatedResponse 类型冲突 -// import { getLoginLogListApi, ... } from '#/api/core/login-log'; -// 注意: ai-platform 模块请直接导入以避免类型冲突 -// import { ... } from '#/api/core/ai-platform'; -export * from '../online-dev/screen-design'; -export * from './application'; export * from './auth'; -export * from './data-source'; -export * from './database-connection'; -export * from './database-manager'; -export * from './dept'; -export * from './dict'; -export * from './menu'; export * from './oauth'; -export * from './permission'; -export * from './post'; -export * from './role'; -export * from './scheduler'; -export * from './server-monitor'; export * from './user'; diff --git a/web/apps/web-ele/src/locales/index.ts b/web/apps/web-ele/src/locales/index.ts index cf60370..f58e0d8 100644 --- a/web/apps/web-ele/src/locales/index.ts +++ b/web/apps/web-ele/src/locales/index.ts @@ -22,7 +22,33 @@ import zhTwLocale from 'element-plus/es/locale/lang/zh-tw'; const elementLocale = ref(defaultLocale); -const modules = import.meta.glob('./langs/**/*.json'); +const modules = import.meta.glob([ + './langs/**/account-settings.json', + './langs/**/ai-platform.json', + './langs/**/announcement.json', + './langs/**/authentication.json', + './langs/**/chat.json', + './langs/**/common.json', + './langs/**/core.json', + './langs/**/database-connection.json', + './langs/**/database-manager.json', + './langs/**/dept.json', + './langs/**/dict.json', + './langs/**/file-manager.json', + './langs/**/menu-title.json', + './langs/**/menu.json', + './langs/**/message.json', + './langs/**/page.json', + './langs/**/permission.json', + './langs/**/post.json', + './langs/**/role.json', + './langs/**/system.json', + './langs/**/system-config.json', + './langs/**/ui.json', + './langs/**/user-avatar.json', + './langs/**/user.json', + './langs/**/workflow.json', +]); const localesMap = loadLocalesMapFromDir( /\.\/langs\/([^/]+)\/(.*)\.json$/, diff --git a/web/apps/web-ele/src/router/access.ts b/web/apps/web-ele/src/router/access.ts index 44d3642..d41bb64 100644 --- a/web/apps/web-ele/src/router/access.ts +++ b/web/apps/web-ele/src/router/access.ts @@ -175,27 +175,13 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) { '../views/_core/agent-chat/**/*.vue', '../views/_core/announcement/index.vue', '../views/_core/announcement/list.vue', - '../views/_core/application/index.vue', '../views/_core/authentication/login.vue', - '../views/_core/chat/**/*.vue', - '../views/_core/database-monitor/**/*.vue', - '../views/_core/dept/index.vue', - '../views/_core/dict/index.vue', '../views/_core/fallback/**/*.vue', - '../views/_core/file-manager/index.vue', - '../views/_core/file-preview/index.vue', - '../views/_core/login-log/index.vue', '../views/_core/menu/index.vue', '../views/_core/message/index.vue', - '../views/_core/org-chart/index.vue', '../views/_core/page-render/index.vue', '../views/_core/permission/index.vue', - '../views/_core/post/index.vue', '../views/_core/role/index.vue', - '../views/_core/redis-monitor/**/*.vue', - '../views/_core/server-monitor/index.vue', - '../views/_core/system-config/index.vue', - '../views/_core/ui-config/index.vue', '../views/_core/user/index.vue', '../views/ai-platform/agent/editor/index.vue', '../views/ai-platform/agent/index.vue', diff --git a/web/apps/web-ele/src/router/light-menu.ts b/web/apps/web-ele/src/router/light-menu.ts index eab9d5c..b89b491 100644 --- a/web/apps/web-ele/src/router/light-menu.ts +++ b/web/apps/web-ele/src/router/light-menu.ts @@ -1,50 +1,42 @@ export const LIGHT_MENU_NAMES = new Set([ 'AccountSettings', - 'Application', - 'ControlCenter', 'AIAgent', + 'AIAgentEditor', + 'AgentChat', 'AIKnowledgeDetail', + 'AIKnowledgeLegacyDetailRedirect', + 'AIKnowledgeLegacyRedirect', 'AIModelConfig', 'AIPlatform', 'AIWorkflow', + 'AIWorkflowEditor', 'AIWorkflowRuns', 'AnnouncementList', 'AnnouncementManage', 'CodexAgentChat', - 'FileManager', 'Message', 'MessageCenter', 'MessageList', 'KnowledgeBase', - 'LoginLog', - 'OrgNode', - 'DatabaseMonitor', - 'RedisMonitor', - 'ServerMonitor', - 'StartChat', - 'SystemDept', - 'SystemDict', - 'SystemFileManager', - 'SystemLoginLog', 'SystemManagement', - 'SystemOrgChart', - 'SystemTools', - 'SystemConfig', - 'SystemConfigManager', - 'SystemMonitoring', 'SystemMenu', 'SystemPermission', - 'SystemPost', 'SystemRole', - 'UIConfig', - 'UIConfigManager', + 'PageRenderMainHome', + 'SubAppAIAgentEditor', + 'SubAppAgentChat', + 'SubAppAIKnowledgeDetail', + 'SubAppAIKnowledgeLegacyDetailRedirect', + 'SubAppAIKnowledgeLegacyRedirect', + 'SubAppAIModelConfig', + 'SubAppAIWorkflowEditor', + 'SubAppAIWorkflowRuns', 'UserManagement', 'userCenter', 'userSettings', ]); const LIGHT_ROUTE_PATH_PREFIXES = [ - '/control-center', '/ai-platform/agent', '/ai-platform/knowledge', '/ai-platform/knowledge-base', @@ -52,30 +44,14 @@ const LIGHT_ROUTE_PATH_PREFIXES = [ '/ai-platform/workflow', '/ai-platform/workflow-runs', '/agent-chat', - '/application', - '/chat', '/message/list', '/message/announcement', '/message/announcement-list', '/page-render/main_home', - '/monitor', - '/core/ui-config', - '/system-config', - '/system/dept', - '/system/dict', - '/system/file-manager', - '/system/login-log', - '/system/org-chart', - '/system/post', - '/system/config', '/system/menu', '/system/new-permission', '/system/role', - '/system/ui-config', '/system/user', - '/tool/dict', - '/tool/file', - '/log/login-log', '/user-center', ]; diff --git a/web/apps/web-ele/src/views/_core/page-render/index.vue b/web/apps/web-ele/src/views/_core/page-render/index.vue index 926e7a2..7161299 100644 --- a/web/apps/web-ele/src/views/_core/page-render/index.vue +++ b/web/apps/web-ele/src/views/_core/page-render/index.vue @@ -1,7 +1,8 @@ @@ -104,6 +175,26 @@ function getLogDetail(log: ExecutionLogEntry) { > {{ getLogDetail(log) }} +
+
+ 运行事件 +
+
+ + {{ getEventTypeLabel(event.type || event.event?.type) }} + + + {{ getEventSummary(event) }} + +
+
diff --git a/web/apps/web-ele/src/views/ai-platform/workflow/editor/components/Panel.vue b/web/apps/web-ele/src/views/ai-platform/workflow/editor/components/Panel.vue index 63469e5..6b55860 100644 --- a/web/apps/web-ele/src/views/ai-platform/workflow/editor/components/Panel.vue +++ b/web/apps/web-ele/src/views/ai-platform/workflow/editor/components/Panel.vue @@ -54,79 +54,12 @@ const components: Record = { ), // 循环节点 loop: defineAsyncComponent(() => import('../panels/LoopPanel.vue')), - // 表单节点 - form_basic_info: defineAsyncComponent( - () => import('../panels/FormBasicInfoPanel.vue'), - ), - form_database_design: defineAsyncComponent( - () => import('../panels/FormDatabaseDesignPanel.vue'), - ), - form_database_create: defineAsyncComponent( - () => import('../panels/FormDatabaseCreatePanel.vue'), - ), - form_ui_design: defineAsyncComponent( - () => import('../panels/FormUIDesignPanel.vue'), - ), - form_list_design: defineAsyncComponent( - () => import('../panels/FormListDesignPanel.vue'), - ), - form_create: defineAsyncComponent( - () => import('../panels/FormCreatePanel.vue'), - ), - form_publish: defineAsyncComponent( - () => import('../panels/FormPublishPanel.vue'), - ), - // 应用节点 - app_create: defineAsyncComponent( - () => import('../panels/AppCreatePanel.vue'), - ), - app_design: defineAsyncComponent( - () => import('../panels/AppDesignPanel.vue'), - ), - app_settings: defineAsyncComponent( - () => import('../panels/AppSettingsPanel.vue'), - ), - app_update: defineAsyncComponent( - () => import('../panels/AppUpdatePanel.vue'), - ), - // 仪表盘节点 - dashboard_basic_info: defineAsyncComponent( - () => import('../panels/DashboardBasicInfoPanel.vue'), - ), - dashboard_design: defineAsyncComponent( - () => import('../panels/DashboardDesignPanel.vue'), - ), - dashboard_create: defineAsyncComponent( - () => import('../panels/DashboardCreatePanel.vue'), - ), - dashboard_publish: defineAsyncComponent( - () => import('../panels/DashboardPublishPanel.vue'), - ), // 系统总结节点 system_summary: defineAsyncComponent( () => import('../panels/SystemSummaryPanel.vue'), ), // 子流程节点 subflow: defineAsyncComponent(() => import('../panels/SubflowPanel.vue')), - // 表单数据节点 - form_data_create: defineAsyncComponent( - () => import('../panels/FormDataPanel.vue'), - ), - form_data_read: defineAsyncComponent( - () => import('../panels/FormDataPanel.vue'), - ), - form_data_update: defineAsyncComponent( - () => import('../panels/FormDataPanel.vue'), - ), - form_data_delete: defineAsyncComponent( - () => import('../panels/FormDataPanel.vue'), - ), - form_data_list: defineAsyncComponent( - () => import('../panels/FormDataPanel.vue'), - ), - form_schema_to_llm: defineAsyncComponent( - () => import('../panels/FormDataPanel.vue'), - ), // Text-to-SQL 节点 text_to_sql: defineAsyncComponent( () => import('../panels/TextToSqlPanel.vue'), diff --git a/web/apps/web-ele/src/views/ai-platform/workflow/editor/index.vue b/web/apps/web-ele/src/views/ai-platform/workflow/editor/index.vue index c70e285..bd73db7 100644 --- a/web/apps/web-ele/src/views/ai-platform/workflow/editor/index.vue +++ b/web/apps/web-ele/src/views/ai-platform/workflow/editor/index.vue @@ -27,14 +27,11 @@ import { Database, DatabaseBackup, DatabaseZap, - FilePlus, - FileText, Fullscreen, GitBranch, GitFork, Globe, HelpCircle, - LayoutDashboard, LayoutTemplate, ListChecks, Map, @@ -45,13 +42,9 @@ import { Plus, Redo2, RefreshCw, - Save, Search, - Send, - Settings, Snowflake, Square, - TableProperties, Trash2, Undo2, Upload, @@ -84,32 +77,16 @@ import ContextMenu from './components/ContextMenu.vue'; import Panel from './components/Panel.vue'; import VersionHistoryPanel from './components/VersionHistoryPanel.vue'; import AddButtonEdge from './edges/AddButtonEdge.vue'; -import AppCreateNode from './nodes/AppCreateNode.vue'; -import AppDesignNode from './nodes/AppDesignNode.vue'; -import AppSettingsNode from './nodes/AppSettingsNode.vue'; -import AppUpdateNode from './nodes/AppUpdateNode.vue'; import ChoiceNode from './nodes/ChoiceNode.vue'; import CodeNode from './nodes/CodeNode.vue'; import ConditionNode from './nodes/ConditionNode.vue'; import ConfirmNode from './nodes/ConfirmNode.vue'; -import DashboardBasicInfoNode from './nodes/DashboardBasicInfoNode.vue'; -import DashboardCreateNode from './nodes/DashboardCreateNode.vue'; -import DashboardDesignNode from './nodes/DashboardDesignNode.vue'; -import DashboardPublishNode from './nodes/DashboardPublishNode.vue'; import DbDeleteNode from './nodes/DbDeleteNode.vue'; import DbInsertNode from './nodes/DbInsertNode.vue'; import DbQueryNode from './nodes/DbQueryNode.vue'; import DbSqlNode from './nodes/DbSqlNode.vue'; import DbUpdateNode from './nodes/DbUpdateNode.vue'; import EndNode from './nodes/EndNode.vue'; -import FormBasicInfoNode from './nodes/FormBasicInfoNode.vue'; -import FormCreateNode from './nodes/FormCreateNode.vue'; -import FormDatabaseCreateNode from './nodes/FormDatabaseCreateNode.vue'; -import FormDatabaseDesignNode from './nodes/FormDatabaseDesignNode.vue'; -import FormDataNode from './nodes/FormDataNode.vue'; -import FormListDesignNode from './nodes/FormListDesignNode.vue'; -import FormPublishNode from './nodes/FormPublishNode.vue'; -import FormUIDesignNode from './nodes/FormUIDesignNode.vue'; import HttpNode from './nodes/HttpNode.vue'; import IntentNode from './nodes/IntentNode.vue'; import KnowledgeRetrievalNode from './nodes/KnowledgeRetrievalNode.vue'; @@ -184,35 +161,10 @@ const nodeTypes = { snowflake_cortex_analyst: markRaw(SnowflakeCortexAnalystNode), // 循环节点 loop: markRaw(LoopNode), - // 表单节点 - form_basic_info: markRaw(FormBasicInfoNode), - form_database_design: markRaw(FormDatabaseDesignNode), - form_database_create: markRaw(FormDatabaseCreateNode), - form_ui_design: markRaw(FormUIDesignNode), - form_list_design: markRaw(FormListDesignNode), - form_create: markRaw(FormCreateNode), - form_publish: markRaw(FormPublishNode), - // 应用管理节点 - app_create: markRaw(AppCreateNode), - app_design: markRaw(AppDesignNode), - app_settings: markRaw(AppSettingsNode), - app_update: markRaw(AppUpdateNode), - // 仪表盘节点 - dashboard_basic_info: markRaw(DashboardBasicInfoNode), - dashboard_design: markRaw(DashboardDesignNode), - dashboard_create: markRaw(DashboardCreateNode), - dashboard_publish: markRaw(DashboardPublishNode), // 系统总结节点 system_summary: markRaw(SystemSummaryNode), // 子流程节点 subflow: markRaw(SubflowNode), - // 表单数据节点 - form_data_create: markRaw(FormDataNode), - form_data_read: markRaw(FormDataNode), - form_data_update: markRaw(FormDataNode), - form_data_delete: markRaw(FormDataNode), - form_data_list: markRaw(FormDataNode), - form_schema_to_llm: markRaw(FormDataNode), // Text-to-SQL 节点 text_to_sql: markRaw(TextToSqlNode), // 知识库节点 @@ -390,94 +342,6 @@ const nodeCategories = computed(() => [ }, ], }, - { - name: $t('ai-platform.workflow.editor.categories.formDesign'), - nodes: [ - { - type: 'form_basic_info', - label: getNodeLabel('form_basic_info'), - icon: 'FileText', - color: 'purple', - }, - { - type: 'form_database_design', - label: getNodeLabel('form_database_design'), - icon: 'Database', - color: 'purple', - }, - { - type: 'form_database_create', - label: getNodeLabel('form_database_create'), - icon: 'DatabaseZap', - color: 'purple', - }, - { - type: 'form_ui_design', - label: getNodeLabel('form_ui_design'), - icon: 'LayoutTemplate', - color: 'purple', - }, - { - type: 'form_list_design', - label: getNodeLabel('form_list_design'), - icon: 'TableProperties', - color: 'purple', - }, - { - type: 'form_create', - label: getNodeLabel('form_create'), - icon: 'FilePlus', - color: 'purple', - }, - { - type: 'form_publish', - label: getNodeLabel('form_publish'), - icon: 'Send', - color: 'purple', - }, - ], - }, - { - name: $t('ai-platform.workflow.editor.categories.formData'), - nodes: [ - { - type: 'form_data_create', - label: getNodeLabel('form_data_create'), - icon: 'FilePlus', - color: 'green', - }, - { - type: 'form_data_read', - label: getNodeLabel('form_data_read'), - icon: 'FileText', - color: 'blue', - }, - { - type: 'form_data_update', - label: getNodeLabel('form_data_update'), - icon: 'FileText', - color: 'orange', - }, - { - type: 'form_data_delete', - label: getNodeLabel('form_data_delete'), - icon: 'Trash2', - color: 'red', - }, - { - type: 'form_data_list', - label: getNodeLabel('form_data_list'), - icon: 'Search', - color: 'blue', - }, - { - type: 'form_schema_to_llm', - label: getNodeLabel('form_schema_to_llm'), - icon: 'Code', - color: 'purple', - }, - ], - }, { name: $t('ai-platform.workflow.editor.categories.dialog'), nodes: [ @@ -587,6 +451,12 @@ const nodeCategories = computed(() => [ icon: 'Workflow', color: 'purple', }, + { + type: 'system_summary', + label: getNodeLabel('system_summary'), + icon: 'ClipboardCheck', + color: 'purple', + }, { type: 'end', label: getNodeLabel('end'), @@ -612,72 +482,6 @@ const nodeCategories = computed(() => [ }, ], }, - { - name: $t('ai-platform.workflow.editor.categories.appManage'), - nodes: [ - { - type: 'app_create', - label: getNodeLabel('app_create'), - icon: 'LayoutTemplate', - color: 'indigo', - }, - { - type: 'app_design', - label: getNodeLabel('app_design'), - icon: 'LayoutDashboard', - color: 'indigo', - }, - { - type: 'app_settings', - label: getNodeLabel('app_settings'), - icon: 'Settings', - color: 'indigo', - }, - { - type: 'app_update', - label: getNodeLabel('app_update'), - icon: 'Save', - color: 'indigo', - }, - ], - }, - { - name: $t('ai-platform.workflow.editor.categories.dashboard'), - icon: 'LayoutDashboard', - color: 'cyan', - nodes: [ - { - type: 'dashboard_basic_info', - label: getNodeLabel('dashboard_basic_info'), - icon: 'FileText', - color: 'cyan', - }, - { - type: 'dashboard_design', - label: getNodeLabel('dashboard_design'), - icon: 'LayoutDashboard', - color: 'cyan', - }, - { - type: 'dashboard_create', - label: getNodeLabel('dashboard_create'), - icon: 'FilePlus', - color: 'cyan', - }, - { - type: 'dashboard_publish', - label: getNodeLabel('dashboard_publish'), - icon: 'Upload', - color: 'cyan', - }, - { - type: 'system_summary', - label: getNodeLabel('system_summary'), - icon: 'ClipboardCheck', - color: 'cyan', - }, - ], - }, { name: $t('ai-platform.workflow.editor.categories.knowledge'), nodes: [ @@ -720,17 +524,6 @@ const iconComponents: Record = { // 循环节点图标 RefreshCw, CornerDownLeft, - // 表单节点图标 - FileText, - TableProperties, - Send, - // 应用节点图标 - LayoutDashboard, - Settings, - Save, - // 仪表盘节点图标 - FilePlus, - Upload, // 系统总结节点图标 ClipboardCheck, // 子流程节点图标 @@ -741,21 +534,7 @@ const iconComponents: Record = { // 过滤后的节点分类 const filteredNodeCategories = computed(() => { - // 首先根据工作流类型过滤分类 - let categories = nodeCategories.value; - - // 如果是通用类型,排除表单设计、应用管理、仪表盘分组 - if (workflow.value?.workflow_type === 'general') { - const excludeNames = new Set([ - $t('ai-platform.workflow.editor.categories.appManage'), - $t('ai-platform.workflow.editor.categories.dashboard'), - $t('ai-platform.workflow.editor.categories.formDesign'), - ]); - categories = nodeCategories.value.filter( - (category: { name: string; nodes: any[] }) => - !excludeNames.has(category.name), - ); - } + const categories = nodeCategories.value; // 再根据搜索关键词过滤 if (!nodeSearchQuery.value.trim()) { diff --git a/web/apps/web-ele/src/views/ai-platform/workflow/shared/workflowNodeTypes.ts b/web/apps/web-ele/src/views/ai-platform/workflow/shared/workflowNodeTypes.ts index 1bdfce5..c497f63 100644 --- a/web/apps/web-ele/src/views/ai-platform/workflow/shared/workflowNodeTypes.ts +++ b/web/apps/web-ele/src/views/ai-platform/workflow/shared/workflowNodeTypes.ts @@ -1,32 +1,16 @@ import { markRaw } from 'vue'; import AddButtonEdge from '../editor/edges/AddButtonEdge.vue'; -import AppCreateNode from '../editor/nodes/AppCreateNode.vue'; -import AppDesignNode from '../editor/nodes/AppDesignNode.vue'; -import AppSettingsNode from '../editor/nodes/AppSettingsNode.vue'; -import AppUpdateNode from '../editor/nodes/AppUpdateNode.vue'; import ChoiceNode from '../editor/nodes/ChoiceNode.vue'; import CodeNode from '../editor/nodes/CodeNode.vue'; import ConditionNode from '../editor/nodes/ConditionNode.vue'; import ConfirmNode from '../editor/nodes/ConfirmNode.vue'; -import DashboardBasicInfoNode from '../editor/nodes/DashboardBasicInfoNode.vue'; -import DashboardCreateNode from '../editor/nodes/DashboardCreateNode.vue'; -import DashboardDesignNode from '../editor/nodes/DashboardDesignNode.vue'; -import DashboardPublishNode from '../editor/nodes/DashboardPublishNode.vue'; import DbDeleteNode from '../editor/nodes/DbDeleteNode.vue'; import DbInsertNode from '../editor/nodes/DbInsertNode.vue'; import DbQueryNode from '../editor/nodes/DbQueryNode.vue'; import DbSqlNode from '../editor/nodes/DbSqlNode.vue'; import DbUpdateNode from '../editor/nodes/DbUpdateNode.vue'; import EndNode from '../editor/nodes/EndNode.vue'; -import FormBasicInfoNode from '../editor/nodes/FormBasicInfoNode.vue'; -import FormCreateNode from '../editor/nodes/FormCreateNode.vue'; -import FormDatabaseCreateNode from '../editor/nodes/FormDatabaseCreateNode.vue'; -import FormDatabaseDesignNode from '../editor/nodes/FormDatabaseDesignNode.vue'; -import FormDataNode from '../editor/nodes/FormDataNode.vue'; -import FormListDesignNode from '../editor/nodes/FormListDesignNode.vue'; -import FormPublishNode from '../editor/nodes/FormPublishNode.vue'; -import FormUIDesignNode from '../editor/nodes/FormUIDesignNode.vue'; import HttpNode from '../editor/nodes/HttpNode.vue'; import IntentNode from '../editor/nodes/IntentNode.vue'; import KnowledgeRetrievalNode from '../editor/nodes/KnowledgeRetrievalNode.vue'; @@ -67,29 +51,8 @@ export const workflowNodeTypes = { snowflake_cortex_llm: markRaw(SnowflakeCortexLLMNode), snowflake_cortex_analyst: markRaw(SnowflakeCortexAnalystNode), loop: markRaw(LoopNode), - form_basic_info: markRaw(FormBasicInfoNode), - form_database_design: markRaw(FormDatabaseDesignNode), - form_database_create: markRaw(FormDatabaseCreateNode), - form_ui_design: markRaw(FormUIDesignNode), - form_list_design: markRaw(FormListDesignNode), - form_create: markRaw(FormCreateNode), - form_publish: markRaw(FormPublishNode), - app_create: markRaw(AppCreateNode), - app_design: markRaw(AppDesignNode), - app_settings: markRaw(AppSettingsNode), - app_update: markRaw(AppUpdateNode), - dashboard_basic_info: markRaw(DashboardBasicInfoNode), - dashboard_design: markRaw(DashboardDesignNode), - dashboard_create: markRaw(DashboardCreateNode), - dashboard_publish: markRaw(DashboardPublishNode), system_summary: markRaw(SystemSummaryNode), subflow: markRaw(SubflowNode), - form_data_create: markRaw(FormDataNode), - form_data_read: markRaw(FormDataNode), - form_data_update: markRaw(FormDataNode), - form_data_delete: markRaw(FormDataNode), - form_data_list: markRaw(FormDataNode), - form_schema_to_llm: markRaw(FormDataNode), text_to_sql: markRaw(TextToSqlNode), knowledge_retrieval: markRaw(KnowledgeRetrievalNode), };