perf: lighten routes and improve ai runtime events
This commit is contained in:
@@ -139,6 +139,9 @@ const getStepLabel = (step: ReasoningStep) => {
|
|||||||
if (step.status === 'running') {
|
if (step.status === 'running') {
|
||||||
return '执行中';
|
return '执行中';
|
||||||
}
|
}
|
||||||
|
if (step.status === 'failed') {
|
||||||
|
return '执行失败';
|
||||||
|
}
|
||||||
return '已完成';
|
return '已完成';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,6 +172,9 @@ const getStepColor = (step: ReasoningStep) => {
|
|||||||
if (step.status === 'running') {
|
if (step.status === 'running') {
|
||||||
return 'text-blue-500';
|
return 'text-blue-500';
|
||||||
}
|
}
|
||||||
|
if (step.status === 'failed') {
|
||||||
|
return 'text-red-500';
|
||||||
|
}
|
||||||
return 'text-emerald-500';
|
return 'text-emerald-500';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,8 +83,8 @@ export interface ReasoningStep {
|
|||||||
target?: Record<string, any>;
|
target?: Record<string, any>;
|
||||||
};
|
};
|
||||||
output?: any;
|
output?: any;
|
||||||
/** 步骤状态:running 执行中,completed 已完成 */
|
/** 步骤状态:running 执行中,completed 已完成,failed 执行失败 */
|
||||||
status?: 'completed' | 'running';
|
status?: 'completed' | 'failed' | 'running';
|
||||||
timestamp?: string;
|
timestamp?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -214,6 +214,18 @@ export function useEventHandler(config: EventHandlerConfig) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getStreamErrorMessage = (event: StreamEvent) =>
|
||||||
|
event.error_message ||
|
||||||
|
event.message ||
|
||||||
|
event.error ||
|
||||||
|
event.content ||
|
||||||
|
'执行失败';
|
||||||
|
|
||||||
|
const isSuccessEvent = (event: StreamEvent) =>
|
||||||
|
!event.error_message &&
|
||||||
|
!event.error &&
|
||||||
|
(!event.status || event.status === 'success' || event.status === 'completed');
|
||||||
|
|
||||||
/** 处理流式事件 */
|
/** 处理流式事件 */
|
||||||
const handleStreamEvent = (event: StreamEvent, msgId: string) => {
|
const handleStreamEvent = (event: StreamEvent, msgId: string) => {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
@@ -357,18 +369,19 @@ export function useEventHandler(config: EventHandlerConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'error': {
|
case 'error': {
|
||||||
|
const errorMessage = getStreamErrorMessage(event);
|
||||||
currentSteps.value.push({
|
currentSteps.value.push({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
content: event.message || event.content || '执行失败',
|
content: errorMessage,
|
||||||
node_id: event.node_id,
|
node_id: event.node_id,
|
||||||
node_type: event.node_type,
|
node_type: event.node_type,
|
||||||
...buildReasoningMeta(event),
|
...buildReasoningMeta(event),
|
||||||
status: 'completed',
|
status: 'failed',
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
updateAssistantMessage(msgId, {
|
updateAssistantMessage(msgId, {
|
||||||
status: 'failed',
|
status: 'failed',
|
||||||
error_message: event.message || event.content || '执行失败',
|
error_message: errorMessage,
|
||||||
reasoning_steps: [...currentSteps.value],
|
reasoning_steps: [...currentSteps.value],
|
||||||
});
|
});
|
||||||
running.value = false;
|
running.value = false;
|
||||||
@@ -535,25 +548,30 @@ export function useEventHandler(config: EventHandlerConfig) {
|
|||||||
event.node_type,
|
event.node_type,
|
||||||
event.node_label,
|
event.node_label,
|
||||||
);
|
);
|
||||||
|
const nodeSucceeded = isSuccessEvent(event);
|
||||||
|
const nodeStatus = nodeSucceeded ? 'completed' : 'failed';
|
||||||
|
const nodeContent = nodeSucceeded
|
||||||
|
? completeLabel
|
||||||
|
: `${completeLabel || event.node_id || '节点'}:${getStreamErrorMessage(event)}`;
|
||||||
if (existingIndex === -1) {
|
if (existingIndex === -1) {
|
||||||
currentSteps.value.push({
|
currentSteps.value.push({
|
||||||
type: 'node_complete',
|
type: 'node_complete',
|
||||||
content: completeLabel,
|
content: nodeContent,
|
||||||
node_id: event.node_id,
|
node_id: event.node_id,
|
||||||
node_type: event.node_type,
|
node_type: event.node_type,
|
||||||
...buildReasoningMeta(event),
|
...buildReasoningMeta(event),
|
||||||
output: event.outputs,
|
output: event.outputs,
|
||||||
status: 'completed',
|
status: nodeStatus,
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
currentSteps.value[existingIndex] = {
|
currentSteps.value[existingIndex] = {
|
||||||
...currentSteps.value[existingIndex]!,
|
...currentSteps.value[existingIndex]!,
|
||||||
type: 'node_complete',
|
type: 'node_complete',
|
||||||
content: completeLabel,
|
content: nodeContent,
|
||||||
...buildReasoningMeta(event),
|
...buildReasoningMeta(event),
|
||||||
output: event.outputs,
|
output: event.outputs,
|
||||||
status: 'completed',
|
status: nodeStatus,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
updateAssistantMessage(msgId, {
|
updateAssistantMessage(msgId, {
|
||||||
|
|||||||
@@ -165,18 +165,12 @@ export class ZqTableApi<T extends Record<string, any> = any> {
|
|||||||
|
|
||||||
// 核心数据加载逻辑
|
// 核心数据加载逻辑
|
||||||
async reload(params: Record<string, any> = {}) {
|
async reload(params: Record<string, any> = {}) {
|
||||||
console.log('[ZqTable] reload called, state:', this.state?.gridOptions);
|
|
||||||
const { proxyConfig } = this.state?.gridOptions || {};
|
const { proxyConfig } = this.state?.gridOptions || {};
|
||||||
if (!proxyConfig?.ajax?.query) {
|
if (!proxyConfig?.ajax?.query) {
|
||||||
console.warn(
|
|
||||||
'[ZqTable] No ajax.query configured, proxyConfig:',
|
|
||||||
proxyConfig,
|
|
||||||
);
|
|
||||||
this.setLoading(false);
|
this.setLoading(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[ZqTable] Starting data load...');
|
|
||||||
this.setLoading(true);
|
this.setLoading(true);
|
||||||
try {
|
try {
|
||||||
// 1. 获取表单数据(带超时保护)
|
// 1. 获取表单数据(带超时保护)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { preferences } from '@vben/preferences';
|
|||||||
|
|
||||||
import { getAllMenusApi } from '#/api/core/menu';
|
import { getAllMenusApi } from '#/api/core/menu';
|
||||||
import { BasicLayout, IFrameView } from '#/layouts';
|
import { BasicLayout, IFrameView } from '#/layouts';
|
||||||
import { $t } from '#/locales';
|
|
||||||
import { useAppContextStore } from '#/store/app-context';
|
import { useAppContextStore } from '#/store/app-context';
|
||||||
|
|
||||||
import { isLightMenuName } from './light-menu';
|
import { isLightMenuName } from './light-menu';
|
||||||
@@ -194,8 +193,6 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) {
|
|||||||
'../views/ai-platform/workflow/editor/index.vue',
|
'../views/ai-platform/workflow/editor/index.vue',
|
||||||
'../views/ai-platform/workflow/index.vue',
|
'../views/ai-platform/workflow/index.vue',
|
||||||
'../views/ai-platform/workflow-runs/index.vue',
|
'../views/ai-platform/workflow-runs/index.vue',
|
||||||
'../views/dashboard/analytics/index.vue',
|
|
||||||
'../views/dashboard/workspace/index.vue',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const layoutMap: ComponentRecordType = {
|
const layoutMap: ComponentRecordType = {
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
export const LIGHT_MENU_NAMES = new Set([
|
export const LIGHT_MENU_NAMES = new Set([
|
||||||
'ControlCenter',
|
'ControlCenter',
|
||||||
'Dashboard',
|
|
||||||
'DashboardAnalytics',
|
|
||||||
'DashboardWorkspace',
|
|
||||||
'AIAgent',
|
'AIAgent',
|
||||||
'AIKnowledgeDetail',
|
'AIKnowledgeDetail',
|
||||||
'AIModelConfig',
|
'AIModelConfig',
|
||||||
@@ -26,7 +23,6 @@ export const LIGHT_MENU_NAMES = new Set([
|
|||||||
|
|
||||||
const LIGHT_ROUTE_PATH_PREFIXES = [
|
const LIGHT_ROUTE_PATH_PREFIXES = [
|
||||||
'/control-center',
|
'/control-center',
|
||||||
'/dashboard',
|
|
||||||
'/ai-platform/agent',
|
'/ai-platform/agent',
|
||||||
'/ai-platform/knowledge',
|
'/ai-platform/knowledge',
|
||||||
'/ai-platform/knowledge-base',
|
'/ai-platform/knowledge-base',
|
||||||
|
|||||||
@@ -11,20 +11,32 @@ type WindowWithIdleCallback = Window & {
|
|||||||
) => IdleCallbackHandle;
|
) => IdleCallbackHandle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type NavigatorWithConnection = Navigator & {
|
||||||
|
connection?: {
|
||||||
|
effectiveType?: string;
|
||||||
|
saveData?: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
let prefetched = false;
|
let prefetched = false;
|
||||||
|
|
||||||
const criticalPrefetchTasks = [
|
const corePrefetchTasks = [
|
||||||
() => import('#/views/_core/agent-chat/index.vue'),
|
() => import('#/views/_core/user/index.vue'),
|
||||||
() => import('#/views/ai-platform/workflow-runs/index.vue'),
|
() => import('#/views/_core/menu/index.vue'),
|
||||||
() => import('#/components/ai-chat-panel/AiChatPanel.vue'),
|
() => import('#/views/_core/role/index.vue'),
|
||||||
() => import('#/views/ai-platform/workflow-runs/modules/detail-dialog.vue'),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const deferredPrefetchTasks = [
|
const aiInteractivePrefetchTasks = [
|
||||||
|
() => import('#/views/_core/agent-chat/index.vue'),
|
||||||
|
() => import('#/components/ai-chat-panel/AiChatPanel.vue'),
|
||||||
|
];
|
||||||
|
|
||||||
|
const aiManagementPrefetchTasks = [
|
||||||
() => import('#/views/ai-platform/agent/index.vue'),
|
() => import('#/views/ai-platform/agent/index.vue'),
|
||||||
() => import('#/views/ai-platform/workflow/index.vue'),
|
() => import('#/views/ai-platform/workflow/index.vue'),
|
||||||
() => import('#/views/ai-platform/model/index.vue'),
|
() => import('#/views/ai-platform/model/index.vue'),
|
||||||
() => import('#/views/ai-platform/knowledge/index.vue'),
|
() => import('#/views/ai-platform/knowledge/index.vue'),
|
||||||
|
() => import('#/views/ai-platform/workflow-runs/index.vue'),
|
||||||
];
|
];
|
||||||
|
|
||||||
function scheduleIdle(callback: () => void) {
|
function scheduleIdle(callback: () => void) {
|
||||||
@@ -38,6 +50,28 @@ function scheduleIdle(callback: () => void) {
|
|||||||
window.setTimeout(callback, 1200);
|
window.setTimeout(callback, 1200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function canPrefetch() {
|
||||||
|
if (typeof document !== 'undefined' && document.visibilityState !== 'visible') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const connection = (navigator as NavigatorWithConnection).connection;
|
||||||
|
if (connection?.saveData) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !/(^|-)2g$/.test(connection?.effectiveType || '');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runTasksSequentially(tasks: Array<() => Promise<unknown>>) {
|
||||||
|
for (const task of tasks) {
|
||||||
|
if (!canPrefetch()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await task().catch(() => undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function prefetchAiPlatformPages() {
|
function prefetchAiPlatformPages() {
|
||||||
if (prefetched || typeof window === 'undefined') {
|
if (prefetched || typeof window === 'undefined') {
|
||||||
return;
|
return;
|
||||||
@@ -45,11 +79,22 @@ function prefetchAiPlatformPages() {
|
|||||||
|
|
||||||
prefetched = true;
|
prefetched = true;
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
void Promise.allSettled(criticalPrefetchTasks.map((task) => task()));
|
|
||||||
}, 300);
|
|
||||||
scheduleIdle(() => {
|
scheduleIdle(() => {
|
||||||
void Promise.allSettled(deferredPrefetchTasks.map((task) => task()));
|
void runTasksSequentially(corePrefetchTasks);
|
||||||
});
|
});
|
||||||
|
}, 800);
|
||||||
|
|
||||||
|
window.setTimeout(() => {
|
||||||
|
scheduleIdle(() => {
|
||||||
|
void runTasksSequentially(aiInteractivePrefetchTasks);
|
||||||
|
});
|
||||||
|
}, 4000);
|
||||||
|
|
||||||
|
window.setTimeout(() => {
|
||||||
|
scheduleIdle(() => {
|
||||||
|
void runTasksSequentially(aiManagementPrefetchTasks);
|
||||||
|
});
|
||||||
|
}, 9000);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { prefetchAiPlatformPages };
|
export { prefetchAiPlatformPages };
|
||||||
|
|||||||
@@ -32,6 +32,24 @@ const coreRoutes: RouteRecordRaw[] = [
|
|||||||
redirect: preferences.app.defaultHomePath,
|
redirect: preferences.app.defaultHomePath,
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
meta: { hideInMenu: true, title: '控制中心' },
|
||||||
|
name: 'DashboardLegacyRedirect',
|
||||||
|
path: '/dashboard',
|
||||||
|
redirect: '/page-render/main_home',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
meta: { hideInMenu: true, title: '控制中心' },
|
||||||
|
name: 'DashboardAnalyticsLegacyRedirect',
|
||||||
|
path: '/dashboard/analytics',
|
||||||
|
redirect: '/page-render/main_home',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
meta: { hideInMenu: true, title: '控制中心' },
|
||||||
|
name: 'DashboardWorkspaceLegacyRedirect',
|
||||||
|
path: '/dashboard/workspace',
|
||||||
|
redirect: '/page-render/main_home',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
component: AuthPageLayout,
|
component: AuthPageLayout,
|
||||||
meta: {
|
meta: {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { mergeRouteModules, traverseTreeValues } from '@vben/utils';
|
|||||||
|
|
||||||
import { coreRoutes, fallbackNotFoundRoute } from './core';
|
import { coreRoutes, fallbackNotFoundRoute } from './core';
|
||||||
import aiPlatformRoutes from './modules/ai-platform';
|
import aiPlatformRoutes from './modules/ai-platform';
|
||||||
import dashboardRoutes from './modules/dashboard';
|
|
||||||
|
|
||||||
// 有需要可以自行打开注释,并创建文件夹
|
// 有需要可以自行打开注释,并创建文件夹
|
||||||
// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });
|
// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });
|
||||||
@@ -13,7 +12,6 @@ import dashboardRoutes from './modules/dashboard';
|
|||||||
/** 动态路由 */
|
/** 动态路由 */
|
||||||
const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules({
|
const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules({
|
||||||
'./modules/ai-platform.ts': { default: aiPlatformRoutes },
|
'./modules/ai-platform.ts': { default: aiPlatformRoutes },
|
||||||
'./modules/dashboard.ts': { default: dashboardRoutes },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 外部路由列表,访问这些页面可以不需要Layout,可能用于内嵌在别的系统(不会显示在菜单中) */
|
/** 外部路由列表,访问这些页面可以不需要Layout,可能用于内嵌在别的系统(不会显示在菜单中) */
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { RouteRecordRaw } from 'vue-router';
|
|||||||
|
|
||||||
const routes: RouteRecordRaw[] = [
|
const routes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
meta: { hideInMenu: true },
|
meta: { hideInMenu: true, title: '控制中心' },
|
||||||
name: 'ControlCenterLegacyRedirect',
|
name: 'ControlCenterLegacyRedirect',
|
||||||
path: '/control-center',
|
path: '/control-center',
|
||||||
redirect: '/page-render/main_home',
|
redirect: '/page-render/main_home',
|
||||||
@@ -17,13 +17,13 @@ const routes: RouteRecordRaw[] = [
|
|||||||
component: () => import('#/views/_core/page-render/index.vue'),
|
component: () => import('#/views/_core/page-render/index.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
meta: { hideInMenu: true },
|
meta: { hideInMenu: true, title: '知识库' },
|
||||||
name: 'AIKnowledgeLegacyRedirect',
|
name: 'AIKnowledgeLegacyRedirect',
|
||||||
path: '/ai-platform/knowledge',
|
path: '/ai-platform/knowledge',
|
||||||
redirect: '/ai-platform/knowledge-base',
|
redirect: '/ai-platform/knowledge-base',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
meta: { hideInMenu: true },
|
meta: { hideInMenu: true, title: '知识库' },
|
||||||
name: 'SubAppAIKnowledgeLegacyRedirect',
|
name: 'SubAppAIKnowledgeLegacyRedirect',
|
||||||
path: '/app/:appCode/ai-platform/knowledge',
|
path: '/app/:appCode/ai-platform/knowledge',
|
||||||
redirect: (to) => `/app/${to.params.appCode}/ai-platform/knowledge-base`,
|
redirect: (to) => `/app/${to.params.appCode}/ai-platform/knowledge-base`,
|
||||||
@@ -65,13 +65,13 @@ const routes: RouteRecordRaw[] = [
|
|||||||
component: () => import('#/views/ai-platform/model/index.vue'),
|
component: () => import('#/views/ai-platform/model/index.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
meta: { hideInMenu: true },
|
meta: { hideInMenu: true, title: '知识库详情' },
|
||||||
name: 'AIKnowledgeLegacyDetailRedirect',
|
name: 'AIKnowledgeLegacyDetailRedirect',
|
||||||
path: '/ai-platform/knowledge/detail/:id',
|
path: '/ai-platform/knowledge/detail/:id',
|
||||||
redirect: (to) => `/ai-platform/knowledge-base/detail/${to.params.id}`,
|
redirect: (to) => `/ai-platform/knowledge-base/detail/${to.params.id}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
meta: { hideInMenu: true },
|
meta: { hideInMenu: true, title: '知识库详情' },
|
||||||
name: 'SubAppAIKnowledgeLegacyDetailRedirect',
|
name: 'SubAppAIKnowledgeLegacyDetailRedirect',
|
||||||
path: '/app/:appCode/ai-platform/knowledge/detail/:id',
|
path: '/app/:appCode/ai-platform/knowledge/detail/:id',
|
||||||
redirect: (to) =>
|
redirect: (to) =>
|
||||||
|
|||||||
@@ -98,6 +98,11 @@ const getStreamErrorMessage = (
|
|||||||
event?.content ||
|
event?.content ||
|
||||||
$t('ai-platform.workflow.editor.chatPanel.execFailed');
|
$t('ai-platform.workflow.editor.chatPanel.execFailed');
|
||||||
|
|
||||||
|
const isSuccessEvent = (event: WorkflowStreamEvent) =>
|
||||||
|
!event.error_message &&
|
||||||
|
!event.error &&
|
||||||
|
(!event.status || event.status === 'success' || event.status === 'completed');
|
||||||
|
|
||||||
// 发送消息
|
// 发送消息
|
||||||
const handleSend = (text: string) => {
|
const handleSend = (text: string) => {
|
||||||
if (!text || running.value) return;
|
if (!text || running.value) return;
|
||||||
@@ -448,15 +453,20 @@ const handleStreamEvent = (event: WorkflowStreamEvent, msgId: string) => {
|
|||||||
event.node_type,
|
event.node_type,
|
||||||
event.node_label,
|
event.node_label,
|
||||||
);
|
);
|
||||||
|
const nodeSucceeded = isSuccessEvent(event);
|
||||||
|
const nodeStatus = nodeSucceeded ? 'completed' : 'failed';
|
||||||
|
const nodeContent = nodeSucceeded
|
||||||
|
? nodeLabel
|
||||||
|
: `${nodeLabel || event.node_id || '节点'}:${getStreamErrorMessage(event)}`;
|
||||||
if (existingIndex === -1) {
|
if (existingIndex === -1) {
|
||||||
// 如果没有找到对应的 start,添加新的 complete 步骤
|
// 如果没有找到对应的 start,添加新的 complete 步骤
|
||||||
currentSteps.value.push({
|
currentSteps.value.push({
|
||||||
type: 'node_complete',
|
type: 'node_complete',
|
||||||
content: nodeLabel,
|
content: nodeContent,
|
||||||
node_id: event.node_id,
|
node_id: event.node_id,
|
||||||
node_type: event.node_type,
|
node_type: event.node_type,
|
||||||
output: event.outputs,
|
output: event.outputs,
|
||||||
status: 'completed',
|
status: nodeStatus,
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -464,9 +474,9 @@ const handleStreamEvent = (event: WorkflowStreamEvent, msgId: string) => {
|
|||||||
currentSteps.value[existingIndex] = {
|
currentSteps.value[existingIndex] = {
|
||||||
...currentSteps.value[existingIndex],
|
...currentSteps.value[existingIndex],
|
||||||
type: 'node_complete',
|
type: 'node_complete',
|
||||||
content: nodeLabel,
|
content: nodeContent,
|
||||||
output: event.outputs,
|
output: event.outputs,
|
||||||
status: 'completed',
|
status: nodeStatus,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
updateAssistantMessage(msgId, {
|
updateAssistantMessage(msgId, {
|
||||||
|
|||||||
@@ -296,7 +296,10 @@ const handleRun = () => {
|
|||||||
// 更新节点完成状态(包含输出数据)
|
// 更新节点完成状态(包含输出数据)
|
||||||
const state = nodeStates.value.get(event.node_id || '');
|
const state = nodeStates.value.get(event.node_id || '');
|
||||||
if (state) {
|
if (state) {
|
||||||
state.status = event.status === 'success' ? 'success' : 'failed';
|
state.status =
|
||||||
|
event.status === 'success' || event.status === 'completed'
|
||||||
|
? 'success'
|
||||||
|
: 'failed';
|
||||||
state.elapsed_time = event.elapsed_time;
|
state.elapsed_time = event.elapsed_time;
|
||||||
state.tokens_used = event.tokens_used;
|
state.tokens_used = event.tokens_used;
|
||||||
state.error_message = event.error_message;
|
state.error_message = event.error_message;
|
||||||
|
|||||||
@@ -151,10 +151,6 @@ watch(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (orphanedChildren.length > 0) {
|
if (orphanedChildren.length > 0) {
|
||||||
console.log(
|
|
||||||
'[Loop Delete] Cascade deleting orphaned children:',
|
|
||||||
orphanedChildren.map((n) => n.id),
|
|
||||||
);
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
removeNodes(orphanedChildren.map((n) => n.id));
|
removeNodes(orphanedChildren.map((n) => n.id));
|
||||||
});
|
});
|
||||||
@@ -483,10 +479,6 @@ const handleChildNodeDrag = (changes: any[]) => {
|
|||||||
// 查找被删除节点的子节点(在节点被删除前,子节点的 parentNode 仍然指向它)
|
// 查找被删除节点的子节点(在节点被删除前,子节点的 parentNode 仍然指向它)
|
||||||
const childNodes = nodes.value.filter((n) => n.parentNode === change.id);
|
const childNodes = nodes.value.filter((n) => n.parentNode === change.id);
|
||||||
if (childNodes.length > 0) {
|
if (childNodes.length > 0) {
|
||||||
console.log(
|
|
||||||
'[Loop Delete] Found child nodes to delete:',
|
|
||||||
childNodes.map((n) => n.id),
|
|
||||||
);
|
|
||||||
for (const child of childNodes) {
|
for (const child of childNodes) {
|
||||||
childNodesToDelete.push(child.id);
|
childNodesToDelete.push(child.id);
|
||||||
}
|
}
|
||||||
@@ -1095,26 +1087,6 @@ const onDrop = (event: DragEvent) => {
|
|||||||
position.y < nodeY + nodeHeight;
|
position.y < nodeY + nodeHeight;
|
||||||
const isInside = isInsideX && isInsideY;
|
const isInside = isInsideX && isInsideY;
|
||||||
|
|
||||||
console.log('[Loop Drop Check]', {
|
|
||||||
dropPosition: position,
|
|
||||||
loopNode: {
|
|
||||||
id: node.id,
|
|
||||||
x: nodeX,
|
|
||||||
y: nodeY,
|
|
||||||
width: nodeWidth,
|
|
||||||
height: nodeHeight,
|
|
||||||
},
|
|
||||||
bounds: {
|
|
||||||
left: nodeX,
|
|
||||||
right: nodeX + nodeWidth,
|
|
||||||
top: nodeY + loopHeaderHeight,
|
|
||||||
bottom: nodeY + nodeHeight,
|
|
||||||
},
|
|
||||||
isInsideX,
|
|
||||||
isInsideY,
|
|
||||||
isInside,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isInside) {
|
if (isInside) {
|
||||||
parentNodeId = node.id;
|
parentNodeId = node.id;
|
||||||
// 计算相对于父节点的位置(子节点位置是相对于父节点左上角的)
|
// 计算相对于父节点的位置(子节点位置是相对于父节点左上角的)
|
||||||
@@ -1126,7 +1098,6 @@ const onDrop = (event: DragEvent) => {
|
|||||||
x: Math.min(Math.max(20, relX), nodeWidth - 280), // 限制在容器宽度内
|
x: Math.min(Math.max(20, relX), nodeWidth - 280), // 限制在容器宽度内
|
||||||
y: Math.min(Math.max(loopHeaderHeight, relY), nodeHeight - 50), // 限制在容器高度内
|
y: Math.min(Math.max(loopHeaderHeight, relY), nodeHeight - 50), // 限制在容器高度内
|
||||||
};
|
};
|
||||||
console.log('[Loop Child Position]', { relativePosition, relX, relY });
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user