diff --git a/backend-fastapi/db_init.json b/backend-fastapi/db_init.json index e5a05f5..2eda9de 100644 --- a/backend-fastapi/db_init.json +++ b/backend-fastapi/db_init.json @@ -13990,11 +13990,49 @@ "id": "725fb629-8f27-4738-a335-42159dc2b9bb", "minH": 2, "minW": 6, - "type": "approval-center", + "type": "quick-links", "props": { - "title": "审批中心", - "showMore": true, - "routePrefix": "/app/workflow_center" + "title": "AI 协作", + "columns": 3, + "rows": 2, + "menus": [ + { + "id": "ai-agent", + "title": "智能体", + "icon": "lucide:square-user", + "path": "/ai-platform/agent", + "bgColor": "" + }, + { + "id": "ai-workflow", + "title": "流程编排", + "icon": "lucide:workflow", + "path": "/ai-platform/workflow", + "bgColor": "" + }, + { + "id": "ai-knowledge", + "title": "知识库", + "icon": "lucide:library-big", + "path": "/ai-platform/knowledge-base", + "bgColor": "" + }, + { + "id": "ai-model", + "title": "模型配置", + "icon": "lucide:settings", + "path": "/ai-platform/model", + "bgColor": "" + }, + { + "id": "codex", + "title": "Codex", + "icon": "lucide:code", + "path": "/agent-chat/codex", + "bgColor": "" + }, + null + ] }, "style": { "backgroundColor": "", @@ -14014,7 +14052,7 @@ "titleAlign": "left", "titleFontWeight": "normal" }, - "title": "审批中心" + "title": "AI 协作" }, { "h": 3, @@ -14027,9 +14065,53 @@ "minW": 6, "type": "my-apps", "props": { - "title": "我的应用", - "maxCount": 8, - "showMore": false + "title": "基础管理", + "maxCount": 6, + "showMore": false, + "apps": [ + { + "id": "system-user", + "code": "system-user", + "name": "用户管理", + "icon": "lucide:users", + "path": "/system/user" + }, + { + "id": "system-role", + "code": "system-role", + "name": "角色权限", + "icon": "lucide:shield-check", + "path": "/system/role" + }, + { + "id": "system-permission", + "code": "system-permission", + "name": "权限管理", + "icon": "lucide:key-round", + "path": "/system/new-permission" + }, + { + "id": "system-menu", + "code": "system-menu", + "name": "菜单管理", + "icon": "lucide:menu", + "path": "/system/menu" + }, + { + "id": "announcement", + "code": "announcement", + "name": "公告管理", + "icon": "lucide:megaphone", + "path": "/message/announcement" + }, + { + "id": "message-list", + "code": "message-list", + "name": "消息中心", + "icon": "lucide:message-square-text", + "path": "/message/list" + } + ] }, "style": { "backgroundColor": "", @@ -14049,7 +14131,7 @@ "titleAlign": "left", "titleFontWeight": "normal" }, - "title": "我的应用" + "title": "基础管理" }, { "h": 6, diff --git a/web/apps/web-ele/src/components/dashboard-design/components/WidgetRenderer.vue b/web/apps/web-ele/src/components/dashboard-design/components/WidgetRenderer.vue index 94b0cf2..6c51d68 100644 --- a/web/apps/web-ele/src/components/dashboard-design/components/WidgetRenderer.vue +++ b/web/apps/web-ele/src/components/dashboard-design/components/WidgetRenderer.vue @@ -38,6 +38,10 @@ const widgetComponents: Record< 'announcement-list': defineAsyncComponent( () => import('./widgets/AnnouncementList.vue'), ), + 'approval-center': defineAsyncComponent( + () => import('./widgets/ApprovalCenter.vue'), + ), + 'my-apps': defineAsyncComponent(() => import('./widgets/MyApps.vue')), 'notice-list': defineAsyncComponent(() => import('./widgets/NoticeList.vue')), 'quick-links': defineAsyncComponent(() => import('./widgets/QuickLinks.vue')), 'server-monitor': defineAsyncComponent( diff --git a/web/apps/web-ele/src/components/dashboard-design/components/widgets/MyApps.vue b/web/apps/web-ele/src/components/dashboard-design/components/widgets/MyApps.vue index 65a8780..e3eaba6 100644 --- a/web/apps/web-ele/src/components/dashboard-design/components/widgets/MyApps.vue +++ b/web/apps/web-ele/src/components/dashboard-design/components/widgets/MyApps.vue @@ -15,18 +15,34 @@ const props = defineProps<{ widget: DashboardWidget; }>(); +type AppLink = Pick & { + path?: string; +}; + // 应用列表 -const appList = ref([]); +const appList = ref([]); const loading = ref(false); +const configuredApps = computed(() => props.widget.props.apps || []); + // 最大显示数量 const maxCount = computed(() => props.widget.props.maxCount || 8); // 显示的应用列表 -const displayApps = computed(() => appList.value.slice(0, maxCount.value)); +const displayApps = computed(() => + (configuredApps.value.length > 0 ? configuredApps.value : appList.value).slice( + 0, + maxCount.value, + ), +); // 加载已发布的应用列表 const loadApps = async () => { + if (configuredApps.value.length > 0) { + appList.value = configuredApps.value; + return; + } + loading.value = true; try { const res = await getApplicationListApi({ @@ -43,8 +59,13 @@ const loadApps = async () => { }; // 点击应用 -const handleClick = (app: ApplicationListItem) => { - window.open(`${window.location.origin}/app/${app.code}`, '_blank'); +const handleClick = (app: AppLink) => { + const path = app.path || `/app/${app.code}`; + if (path.startsWith('http://') || path.startsWith('https://')) { + window.open(path, '_blank'); + return; + } + window.open(`${window.location.origin}${path}`, '_blank'); }; // 点击更多 diff --git a/web/apps/web-ele/src/locales/langs/zh-CN/dashboard-design.json b/web/apps/web-ele/src/locales/langs/zh-CN/dashboard-design.json index aba7b85..ef78bac 100644 --- a/web/apps/web-ele/src/locales/langs/zh-CN/dashboard-design.json +++ b/web/apps/web-ele/src/locales/langs/zh-CN/dashboard-design.json @@ -61,6 +61,22 @@ "evening": "晚上好" } }, + "approvalCenter": { + "initiated": "我发起的", + "pending": "我的待办", + "handling": "我的在办", + "signing": "我的待签", + "handled": "我的已办", + "copy": "抄送我的", + "start": "发起流程", + "more": "更多", + "config": "审批中心配置", + "routePrefix": "路由前缀" + }, + "myApps": { + "more": "更多", + "noData": "暂无应用" + }, "serverMonitor": { "core": "核", "thread": "线程", diff --git a/web/apps/web-ele/src/preferences.ts b/web/apps/web-ele/src/preferences.ts index 110ab8d..f85eb34 100644 --- a/web/apps/web-ele/src/preferences.ts +++ b/web/apps/web-ele/src/preferences.ts @@ -16,7 +16,7 @@ export const overridesPreferences = defineOverridesPreferences({ enablePreferences: false, accessMode: 'mixed', authPageLayout: 'panel-center', - defaultHomePath: '/control-center', + defaultHomePath: '/page-render/main_home', layout: 'header-sidebar-nav', }, shortcutKeys: { diff --git a/web/apps/web-ele/src/router/access.ts b/web/apps/web-ele/src/router/access.ts index a26e20b..83fb253 100644 --- a/web/apps/web-ele/src/router/access.ts +++ b/web/apps/web-ele/src/router/access.ts @@ -79,8 +79,8 @@ function normalizeBackendRoute< if (route.name !== 'ControlCenter') return route; const normalized = { ...route }; - normalized.path = '/control-center'; - normalized.component = '_core/control-center/index'; + normalized.path = '/page-render/main_home'; + normalized.component = 'online-dev/page-render/index'; normalized.query = undefined; return normalized; } @@ -138,7 +138,6 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) { '../views/_core/announcement/index.vue', '../views/_core/announcement/list.vue', '../views/_core/authentication/login.vue', - '../views/_core/control-center/index.vue', '../views/_core/authentication/oauth-callback.vue', '../views/_core/fallback/**/*.vue', '../views/_core/file-preview/index.vue', @@ -156,6 +155,7 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) { '../views/ai-platform/workflow/editor/index.vue', '../views/ai-platform/workflow/index.vue', '../views/ai-platform/workflow-runs/index.vue', + '../views/online-dev/page-render/index.vue', ]); const layoutMap: ComponentRecordType = { diff --git a/web/apps/web-ele/src/router/guard.ts b/web/apps/web-ele/src/router/guard.ts index 4c943cf..34f2f17 100644 --- a/web/apps/web-ele/src/router/guard.ts +++ b/web/apps/web-ele/src/router/guard.ts @@ -191,7 +191,7 @@ function setupAccessGuard(router: Router) { if (to.path === subAppRootPath) { const defaultHome = - preferences.app.defaultHomePath || '/control-center'; + preferences.app.defaultHomePath || '/page-render/main_home'; // 确保路径包含子应用前缀 const subAppTargetPath = defaultHome.startsWith(subAppRootPath) ? defaultHome diff --git a/web/apps/web-ele/src/router/routes/modules/ai-platform.ts b/web/apps/web-ele/src/router/routes/modules/ai-platform.ts index 7e98bda..9be5185 100644 --- a/web/apps/web-ele/src/router/routes/modules/ai-platform.ts +++ b/web/apps/web-ele/src/router/routes/modules/ai-platform.ts @@ -1,20 +1,11 @@ import type { RouteRecordRaw } from 'vue-router'; const routes: RouteRecordRaw[] = [ - { - meta: { - hideInMenu: true, - title: '控制中心', - }, - name: 'ControlCenterStatic', - path: '/control-center', - component: () => import('#/views/_core/control-center/index.vue'), - }, { meta: { hideInMenu: true }, - name: 'LegacyMainHomeRedirect', - path: '/page-render/main_home', - redirect: '/control-center', + name: 'ControlCenterLegacyRedirect', + path: '/control-center', + redirect: '/page-render/main_home', }, { meta: { hideInMenu: true }, diff --git a/web/apps/web-ele/src/views/_core/control-center/index.vue b/web/apps/web-ele/src/views/_core/control-center/index.vue deleted file mode 100644 index 7171534..0000000 --- a/web/apps/web-ele/src/views/_core/control-center/index.vue +++ /dev/null @@ -1,222 +0,0 @@ - - - diff --git a/web/apps/web-ele/src/views/_core/menu/modules/menu-form.vue b/web/apps/web-ele/src/views/_core/menu/modules/menu-form.vue index 780a2c8..8b167d2 100644 --- a/web/apps/web-ele/src/views/_core/menu/modules/menu-form.vue +++ b/web/apps/web-ele/src/views/_core/menu/modules/menu-form.vue @@ -99,7 +99,6 @@ const componentKeys: string[] = Object.keys( '../../../_core/announcement/list.vue', '../../../_core/authentication/login.vue', '../../../_core/authentication/oauth-callback.vue', - '../../../_core/control-center/index.vue', '../../../_core/fallback/**/*.vue', '../../../_core/menu/index.vue', '../../../_core/permission/index.vue', @@ -114,13 +113,15 @@ const componentKeys: string[] = Object.keys( '../../../ai-platform/workflow/editor/index.vue', '../../../ai-platform/workflow/index.vue', '../../../ai-platform/workflow-runs/index.vue', + '../../../online-dev/page-render/index.vue', ]), ) .filter((item) => !item.includes('/modules/')) .map((v) => { const path = v .replace('../../../_core/', '/_core/') - .replace('../../../ai-platform/', '/ai-platform/'); + .replace('../../../ai-platform/', '/ai-platform/') + .replace('../../../online-dev/', '/online-dev/'); return path.endsWith('.vue') ? path.slice(0, -4) : path; }); diff --git a/web/apps/web-ele/src/views/_core/ui-config/modules/app-settings-form.vue b/web/apps/web-ele/src/views/_core/ui-config/modules/app-settings-form.vue index 3935696..1486fdb 100644 --- a/web/apps/web-ele/src/views/_core/ui-config/modules/app-settings-form.vue +++ b/web/apps/web-ele/src/views/_core/ui-config/modules/app-settings-form.vue @@ -53,7 +53,7 @@ const appDynamicTitle = ref(true); const appWatermark = ref(false); const appWatermarkContent = ref(''); const appEnableCheckUpdates = ref(true); -const appDefaultHomePath = ref('/control-center'); +const appDefaultHomePath = ref('/page-render/main_home'); const appEnablePreferences = ref(true); const footerEnable = ref(true); @@ -106,7 +106,7 @@ function getDefaultConfig() { defaultHomePath: overrides.app?.defaultHomePath || preferences.app.defaultHomePath || - '/control-center', + '/page-render/main_home', enablePreferences: overrides.app?.enablePreferences ?? true, }, footer: { @@ -233,7 +233,7 @@ async function loadConfig() { // 获取带子应用前缀的首页路径 function getDefaultHomePathWithPrefix(): string { - const path = appDefaultHomePath.value || '/control-center'; + const path = appDefaultHomePath.value || '/page-render/main_home'; const appCode = appContextStore.appCode; // 如果是子应用模式且路径不包含子应用前缀,自动添加 if (appCode && !path.startsWith(`/app/${appCode}`)) { diff --git a/web/apps/web-ele/src/views/online-dev/page-render/index.vue b/web/apps/web-ele/src/views/online-dev/page-render/index.vue index e894949..4788b38 100644 --- a/web/apps/web-ele/src/views/online-dev/page-render/index.vue +++ b/web/apps/web-ele/src/views/online-dev/page-render/index.vue @@ -15,139 +15,6 @@ const pageConfig = ref(''); const pageName = ref(''); const pageCode = ref(''); -type QuickLink = null | { - bgColor: string; - icon: string; - id: string; - path: string; - title: string; -}; - -const MAIN_HOME_AI_LINKS: QuickLink[] = [ - { - bgColor: '', - icon: 'lucide:square-user', - id: 'ai-agent', - path: '/ai-platform/agent', - title: '智能体', - }, - { - bgColor: '', - icon: 'lucide:workflow', - id: 'ai-workflow', - path: '/ai-platform/workflow', - title: '流程编排', - }, - { - bgColor: '', - icon: 'lucide:library-big', - id: 'ai-knowledge', - path: '/ai-platform/knowledge-base', - title: '知识库', - }, - { - bgColor: '', - icon: 'lucide:settings', - id: 'ai-model', - path: '/ai-platform/model', - title: '模型配置', - }, - { - bgColor: '', - icon: 'lucide:code', - id: 'codex', - path: '/agent-chat/codex', - title: 'Codex', - }, - null, -]; - -const MAIN_HOME_ADMIN_LINKS: QuickLink[] = [ - { - bgColor: '', - icon: 'lucide:users', - id: 'system-user', - path: '/system/user', - title: '用户管理', - }, - { - bgColor: '', - icon: 'lucide:shield-check', - id: 'system-role', - path: '/system/role', - title: '角色权限', - }, - { - bgColor: '', - icon: 'lucide:key-round', - id: 'system-permission', - path: '/system/new-permission', - title: '权限管理', - }, - { - bgColor: '', - icon: 'lucide:menu', - id: 'system-menu', - path: '/system/menu', - title: '菜单管理', - }, - { - bgColor: '', - icon: 'lucide:megaphone', - id: 'announcement', - path: '/message/announcement', - title: '公告管理', - }, - { - bgColor: '', - icon: 'lucide:message-square-text', - id: 'message-list', - path: '/message/list', - title: '消息中心', - }, -]; - -function toQuickLinksWidget( - widget: Record, - title: string, - menus: QuickLink[], -) { - return { - ...widget, - title, - type: 'quick-links', - props: { - ...widget.props, - columns: 3, - menus, - rows: 2, - title, - }, - }; -} - -function normalizeMainHomeConfig(config: Record) { - if (pageCode.value !== 'main_home' || !Array.isArray(config.widgets)) { - return config; - } - - return { - ...config, - widgets: config.widgets.map((widget: Record) => { - if (widget.type === 'approval-center') { - return toQuickLinksWidget(widget, 'AI 协作', MAIN_HOME_AI_LINKS); - } - if (widget.type === 'my-apps') { - return toQuickLinksWidget(widget, '基础管理', MAIN_HOME_ADMIN_LINKS); - } - if (widget.type === 'quick-links') { - return toQuickLinksWidget(widget, '快捷入口', MAIN_HOME_AI_LINKS); - } - return widget; - }), - }; -} - function getPageCode(): string { if (route.query.pageCode) { return route.query.pageCode as string; @@ -179,11 +46,10 @@ async function loadPageData() { try { const page = await getPageByCodeApi(code); pageName.value = page.name; - const config = + pageConfig.value = page.page_config && Object.keys(page.page_config).length > 0 - ? normalizeMainHomeConfig(page.page_config) - : null; - pageConfig.value = config ? JSON.stringify(config) : ''; + ? JSON.stringify(page.page_config) + : ''; } catch (error: any) { ElMessage.error(error?.message || '加载页面失败'); } finally {