diff --git a/backend-fastapi/core/menu/service.py b/backend-fastapi/core/menu/service.py index 4099965..1a8e44a 100644 --- a/backend-fastapi/core/menu/service.py +++ b/backend-fastapi/core/menu/service.py @@ -17,8 +17,33 @@ from core.menu.schema import MenuCreate, MenuUpdate menu_cache = CacheManager(prefix="menu:") # 缓存key -MENU_TREE_CACHE_KEY = "tree" -USER_ROUTE_CACHE_PREFIX = "user_route:" +MENU_TREE_CACHE_KEY = "tree:ai_agent_admin" +USER_ROUTE_CACHE_PREFIX = "user_route:ai_agent_admin:" + +AI_AGENT_ADMIN_MENU_NAMES = { + "AIPlatform", + "AIAgent", + "AIWorkflow", + "KnowledgeBase", + "Codex", + "SystemConfigManager", + "SystemManagement", + "SystemPermission", + "UserManagement", + "SystemMenu", + "SystemRole", + "Message", + "AnnouncementList", + "AnnouncementManage", + "userCenter", + "userSettings", + "LoginLog", +} + + +def _filter_ai_agent_admin_menus(menus: List[Menu]) -> List[Menu]: + """Keep only the lightweight admin and AI modules for this product.""" + return [menu for menu in menus if menu.name in AI_AGENT_ADMIN_MENU_NAMES] class MenuService(BaseService[Menu, MenuCreate, MenuUpdate]): @@ -239,7 +264,7 @@ class MenuService(BaseService[Menu, MenuCreate, MenuUpdate]): Menu.is_deleted == False # noqa: E712 ).order_by(Menu.order) ) - return list(result.scalars().all()) + return _filter_ai_agent_admin_menus(list(result.scalars().all())) @classmethod async def build_tree( @@ -613,6 +638,8 @@ class MenuService(BaseService[Menu, MenuCreate, MenuUpdate]): ).order_by(Menu.order) ) menus = list(result.scalars().all()) + + menus = _filter_ai_agent_admin_menus(menus) # 构建路由树,传递 application_code 用于添加路径前缀 # 开发模式使用 /app-dev/{code} 前缀,正常模式使用 /app/{code} 前缀 diff --git a/web/apps/web-ele/src/components/ai-chat-panel/DesignPreviewDialog.vue b/web/apps/web-ele/src/components/ai-chat-panel/DesignPreviewDialog.vue index 4c354da..f4bc01e 100644 --- a/web/apps/web-ele/src/components/ai-chat-panel/DesignPreviewDialog.vue +++ b/web/apps/web-ele/src/components/ai-chat-panel/DesignPreviewDialog.vue @@ -3,10 +3,27 @@ import type { DesignPreviewData } from './types'; import { computed, ref, watch } from 'vue'; -import { ElButton, ElDialog, ElInput, ElMessage } from 'element-plus'; +import { Check, Copy, X } from '@vben/icons'; + +import { + ElButton, + ElDescriptions, + ElDescriptionsItem, + ElDialog, + ElDivider, + ElInput, + ElMessage, + ElScrollbar, + ElTag, +} from 'element-plus'; const props = defineProps<{ + basicInfo?: Record; + data?: Record; + design?: DesignPreviewData | Record; preview?: DesignPreviewData; + publishData?: Record; + settings?: Record; title?: string; visible: boolean; }>(); @@ -19,15 +36,56 @@ const emit = defineEmits<{ const draftText = ref('{}'); -const dialogTitle = computed( - () => props.preview?.title || props.title || '确认内容', -); +const sourceData = computed(() => { + return ( + props.preview || + props.design || + props.basicInfo || + props.settings || + props.publishData || + props.data || + {} + ); +}); + +const payload = computed(() => { + const source = sourceData.value as Record; + if ('data' in source && source.data && typeof source.data === 'object') { + return source.data; + } + return source; +}); + +const dialogTitle = computed(() => { + const source = sourceData.value as Record; + return source.title || props.title || 'AI 方案确认'; +}); + +const summaryItems = computed(() => { + const source = payload.value as Record; + const keys = ['name', 'title', 'description', 'code', 'type', 'category']; + return keys + .filter((key) => source[key] !== undefined && source[key] !== null) + .map((key) => ({ key, value: String(source[key]) })); +}); + +const fieldItems = computed(() => { + const source = payload.value as Record; + const fields = source.form_fields || source.fields || source.schema?.fields; + return Array.isArray(fields) ? fields.slice(0, 12) : []; +}); + +const tableItems = computed(() => { + const source = payload.value as Record; + const tables = source.table_configs || source.tables || source.data_sources; + return Array.isArray(tables) ? tables.slice(0, 8) : []; +}); watch( - () => [props.visible, props.preview] as const, + () => [props.visible, sourceData.value] as const, () => { if (props.visible) { - draftText.value = JSON.stringify(props.preview?.data || {}, null, 2); + draftText.value = JSON.stringify(payload.value || {}, null, 2); } }, { immediate: true }, @@ -48,6 +106,11 @@ function handleConfirm() { } } +async function copyJson() { + await navigator.clipboard?.writeText(draftText.value); + ElMessage.success('已复制'); +} + function handleVisibleChange(visible: boolean) { if (!visible) handleClose(); } @@ -57,25 +120,160 @@ function handleVisibleChange(visible: boolean) { -
-
- {{ preview?.type || 'design_preview' }} -
- +
+
+
方案概要
+ + + {{ item.value }} + + +
当前方案未提供概要字段
+ + + + + + +
+ +
+
+ 结构化数据 + 复制 +
+ + + +
+ + + diff --git a/web/apps/web-ele/src/locales/index.ts b/web/apps/web-ele/src/locales/index.ts index b5c0da7..a7a8adc 100644 --- a/web/apps/web-ele/src/locales/index.ts +++ b/web/apps/web-ele/src/locales/index.ts @@ -28,7 +28,6 @@ const modules = import.meta.glob([ './langs/*/announcement.json', './langs/*/apiToken.json', './langs/*/authentication.json', - './langs/*/chat.json', './langs/*/common.json', './langs/*/loginLog.json', './langs/*/menu.json', @@ -40,6 +39,7 @@ const modules = import.meta.glob([ './langs/*/system-config.json', './langs/*/system.json', './langs/*/ui.json', + './langs/*/ui-config.json', './langs/*/user-avatar.json', './langs/*/user.json', ]); diff --git a/web/apps/web-ele/src/router/access.ts b/web/apps/web-ele/src/router/access.ts index 140df6e..72cb7f1 100644 --- a/web/apps/web-ele/src/router/access.ts +++ b/web/apps/web-ele/src/router/access.ts @@ -22,16 +22,14 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) { '../views/_core/announcement/index.vue', '../views/_core/announcement/list.vue', '../views/_core/authentication/**/*.vue', - '../views/_core/chat/**/*.vue', '../views/_core/fallback/**/*.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/mobile-signature/index.vue', '../views/_core/permission/index.vue', '../views/_core/role/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/routes/core.ts b/web/apps/web-ele/src/router/routes/core.ts index 82fb730..1f33cc0 100644 --- a/web/apps/web-ele/src/router/routes/core.ts +++ b/web/apps/web-ele/src/router/routes/core.ts @@ -97,28 +97,6 @@ const coreRoutes: RouteRecordRaw[] = [ title: 'OAuth Callback', }, }, - { - name: 'MobileSignature', - path: '/mobile-signature/:token', - component: () => import('#/views/_core/mobile-signature/index.vue'), - meta: { - hideInBreadcrumb: true, - hideInMenu: true, - hideInTab: true, - title: 'Mobile Signature', - }, - }, - { - name: 'FilePreview', - path: '/file-preview/:id', - component: () => import('#/views/_core/file-preview/index.vue'), - meta: { - hideInBreadcrumb: true, - hideInMenu: true, - hideInTab: true, - title: 'File Preview', - }, - }, ]; export { coreRoutes, fallbackNotFoundRoute }; diff --git a/web/apps/web-ele/src/router/routes/index.ts b/web/apps/web-ele/src/router/routes/index.ts index 7814928..af4f85c 100644 --- a/web/apps/web-ele/src/router/routes/index.ts +++ b/web/apps/web-ele/src/router/routes/index.ts @@ -41,16 +41,14 @@ const componentKeys: string[] = Object.keys( '../../views/_core/announcement/index.vue', '../../views/_core/announcement/list.vue', '../../views/_core/authentication/**/*.vue', - '../../views/_core/chat/**/*.vue', '../../views/_core/fallback/**/*.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/mobile-signature/index.vue', '../../views/_core/permission/index.vue', '../../views/_core/role/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/views/ai-platform/knowledge/detail/index.vue b/web/apps/web-ele/src/views/ai-platform/knowledge/detail/index.vue index 6916bff..8fa5837 100644 --- a/web/apps/web-ele/src/views/ai-platform/knowledge/detail/index.vue +++ b/web/apps/web-ele/src/views/ai-platform/knowledge/detail/index.vue @@ -291,9 +291,12 @@ async function handlePreviewDoc(doc: KnowledgeDocumentListItem) { docPreviewUrlList.value = [url]; docPreviewVisible.value = true; } else { - const ext = getDocFileExt(doc); - const query = new URLSearchParams({ name: doc.name || '', ext }); - window.open(`/file-preview/${doc.file_id}?${query.toString()}`, '_blank'); + try { + const url = await getFileUrl(doc.file_id); + window.open(url, '_blank'); + } catch { + ElMessage.error($t('ai-platform.knowledge.chunkPreview.error')); + } } } diff --git a/web/apps/web-ele/src/views/ai-platform/workflow-runs/index.vue b/web/apps/web-ele/src/views/ai-platform/workflow-runs/index.vue index 9544061..29bbc6d 100644 --- a/web/apps/web-ele/src/views/ai-platform/workflow-runs/index.vue +++ b/web/apps/web-ele/src/views/ai-platform/workflow-runs/index.vue @@ -1,29 +1,16 @@ -
- -
- + + + + + + diff --git a/web/apps/web-ele/src/views/ai-platform/workflow/editor/panels/FormDataPanel.vue b/web/apps/web-ele/src/views/ai-platform/workflow/editor/panels/FormDataPanel.vue index 91e5982..5807da4 100644 --- a/web/apps/web-ele/src/views/ai-platform/workflow/editor/panels/FormDataPanel.vue +++ b/web/apps/web-ele/src/views/ai-platform/workflow/editor/panels/FormDataPanel.vue @@ -1,5 +1,5 @@