diff --git a/apps/jingrow/frontend/src/core/features/flows/AIAgentFlowBuilder.vue b/apps/jingrow/frontend/src/core/features/flows/AIAgentFlowBuilder.vue
index fc97f16..6fb5e13 100644
--- a/apps/jingrow/frontend/src/core/features/flows/AIAgentFlowBuilder.vue
+++ b/apps/jingrow/frontend/src/core/features/flows/AIAgentFlowBuilder.vue
@@ -9,7 +9,7 @@ import { useFlowStore } from './store/flowStore.js';
import { flowExecutor } from './executors/flowExecutor.js';
import NodePalette from './components/Sidebar/NodePalette.vue';
import ExecutionResults from './components/ExecutionResults.vue';
-import { getNodeComponents, getNodeMetadataByType } from './utils/nodeMetadata.js';
+import { getNodeComponents, getNodeMetadataByType, preloadNodeMetadata } from './utils/nodeMetadata.js';
import { t } from '@/shared/i18n'
// Props
@@ -136,8 +136,24 @@ const onPaneReady = () => {
}
};
-// 自动化获取所有节点组件,使用markRaw避免响应式
-const nodeTypes = markRaw(getNodeComponents());
+// 节点组件映射(响应式)
+const nodeTypes = ref({});
+const nodeTypesLoaded = ref(false);
+
+// 预加载节点元数据
+onMounted(async () => {
+ await preloadNodeMetadata();
+ // 更新节点组件映射
+ const components = getNodeComponents();
+ nodeTypes.value = markRaw(components);
+ nodeTypesLoaded.value = true;
+
+ // 节点元数据加载完成后,再初始化流程数据
+ nextTick(async () => {
+ initFlowData();
+ store.saveToHistory();
+ });
+});
// 获取节点颜色函数
const getNodeColor = (nodeType) => {
@@ -325,11 +341,6 @@ const onKeyDown = (event) => {
// 生命周期
onMounted(() => {
- nextTick(async () => {
- // 初始化流程数据
- initFlowData();
- store.saveToHistory();
- });
// 暴露 teleport 目标到全局,供节点组件使用
window.nodePropertyTeleportTarget = {
@@ -617,6 +628,7 @@ const showBubbleTip = (msg, type = '') => {
{
+
+
+
@@ -1219,4 +1239,29 @@ const showBubbleTip = (msg, type = '') => {
.ai-agent-flow-builder.fullscreen .bubble-tip-global {
z-index: 100000;
}
+
+/* 加载提示样式 */
+.loading-container {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ min-height: 400px;
+}
+
+.loading-spinner {
+ text-align: center;
+ color: #6b7280;
+}
+
+.loading-spinner i {
+ font-size: 24px;
+ margin-bottom: 12px;
+ display: block;
+}
+
+.loading-spinner p {
+ margin: 0;
+ font-size: 14px;
+}
\ No newline at end of file
diff --git a/apps/jingrow/frontend/src/core/features/flows/utils/nodeMetadata.js b/apps/jingrow/frontend/src/core/features/flows/utils/nodeMetadata.js
index 2e123b4..bddcbf4 100644
--- a/apps/jingrow/frontend/src/core/features/flows/utils/nodeMetadata.js
+++ b/apps/jingrow/frontend/src/core/features/flows/utils/nodeMetadata.js
@@ -16,29 +16,27 @@ function resolveComponent(componentType) {
return COMPONENT_MAP[componentType] || GenericNode
}
-// 发现所有节点的元数据(从本地JSON文件)
-function discoverNodeMetadata() {
- // 使用 import.meta.glob 获取所有节点JSON文件
- // 注意:Vite 要求以 './' 或 '/' 开头,别名在 glob 中不可用
- // 从当前文件路径 ../../../../../../../ 指向到项目根,再进入 apps/jingrow/nodes 目录(core 比原 features 深一层)
- const modulesNew = import.meta.glob('../../../../../../../../apps/jingrow/jingrow/ai/pagetype/local_ai_agent/nodes/**/*.json', { eager: true })
+// 发现所有节点的元数据(从API获取)
+async function discoverNodeMetadata() {
+ try {
+ const response = await fetch('/jingrow/node-definitions/metadata');
- const metadataMap = {}
-
- Object.keys(modulesNew).forEach(path => {
- try {
- const module = modulesNew[path]
- const data = module.default || module
-
- // 检查是否有 metadata 字段
- if (data && typeof data === 'object' && data.metadata && data.metadata.type) {
- metadataMap[data.metadata.type] = data.metadata
- }
- } catch (error) {
- // 静默失败,避免污染控制台
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
- })
- return metadataMap
+
+ const result = await response.json();
+
+ if (result.success && result.data) {
+ return result.data;
+ } else {
+ console.warn('获取节点元数据失败:', result);
+ return {};
+ }
+ } catch (error) {
+ console.error('获取节点元数据失败:', error);
+ return {};
+ }
}
// 自动生成节点分组
@@ -60,36 +58,65 @@ function generateNodeGroups(metadataMap) {
return Object.values(groupMap)
}
-// 节点元数据映射(同步初始化)
-const NODE_METADATA_MAP = {}
-const LOCAL_METADATA = discoverNodeMetadata()
+// 节点元数据映射(异步初始化)
+let NODE_METADATA_MAP = {}
+let NODE_GROUPS = []
+let isInitialized = false
-// 构建最终的元数据映射
-Object.keys(LOCAL_METADATA).forEach(type => {
- const metadata = LOCAL_METADATA[type]
- NODE_METADATA_MAP[type] = {
- ...metadata,
- component: resolveComponent(metadata.component_type)
+// 初始化节点元数据
+async function initializeNodeMetadata() {
+ if (isInitialized) return
+
+ try {
+ const LOCAL_METADATA = await discoverNodeMetadata()
+
+ // 构建最终的元数据映射
+ NODE_METADATA_MAP = {}
+ Object.keys(LOCAL_METADATA).forEach(type => {
+ const metadata = LOCAL_METADATA[type]
+ NODE_METADATA_MAP[type] = {
+ ...metadata,
+ component: resolveComponent(metadata.component)
+ }
+ })
+
+ // 自动生成节点分组
+ NODE_GROUPS = generateNodeGroups(NODE_METADATA_MAP)
+ isInitialized = true
+ } catch (error) {
+ console.error('初始化节点元数据失败:', error)
+ NODE_METADATA_MAP = {}
+ NODE_GROUPS = []
}
-})
+}
-// 自动生成节点分组
-const NODE_GROUPS = generateNodeGroups(NODE_METADATA_MAP)
-
-// 导出函数
+// 导出函数(保持同步接口)
export function getNodeMetadataByType(type) {
+ if (!isInitialized) {
+ // 如果还没初始化,返回null,组件会处理这种情况
+ return null
+ }
return NODE_METADATA_MAP[type]
}
export function getAllNodeTypes() {
+ if (!isInitialized) {
+ return []
+ }
return Object.values(NODE_METADATA_MAP)
}
export function getNodeGroups() {
+ if (!isInitialized) {
+ return []
+ }
return NODE_GROUPS
}
export function getNodeComponents() {
+ if (!isInitialized) {
+ return {}
+ }
const components = {}
Object.keys(NODE_METADATA_MAP).forEach(type => {
if (NODE_METADATA_MAP[type].component) {
@@ -99,5 +126,10 @@ export function getNodeComponents() {
return components
}
+// 预加载函数
+export async function preloadNodeMetadata() {
+ await initializeNodeMetadata()
+}
+
// 导出常量
export { NODE_METADATA_MAP, NODE_GROUPS }
\ No newline at end of file
diff --git a/apps/jingrow/frontend/src/core/features/flows/utils/schemaLoader.js b/apps/jingrow/frontend/src/core/features/flows/utils/schemaLoader.js
index 2b1dfc0..9001e1b 100644
--- a/apps/jingrow/frontend/src/core/features/flows/utils/schemaLoader.js
+++ b/apps/jingrow/frontend/src/core/features/flows/utils/schemaLoader.js
@@ -4,29 +4,20 @@
* @returns {Promise