diff --git a/web/apps/web-ele/src/locales/index.ts b/web/apps/web-ele/src/locales/index.ts index 97c448d..9e61954 100644 --- a/web/apps/web-ele/src/locales/index.ts +++ b/web/apps/web-ele/src/locales/index.ts @@ -8,54 +8,54 @@ import { ref } from 'vue'; import { $t, - setupI18n as coreSetup, - getSystemLanguage, i18n, loadLocalesMapFromDir, + setupI18n as coreSetup, } from '@vben/locales'; -import { preferences } from '@vben/preferences'; import dayjs from 'dayjs'; +import 'dayjs/locale/zh-cn'; import defaultLocale from 'element-plus/es/locale/lang/zh-cn'; +const APP_LOCALE: SupportedLanguagesType = 'zh-CN'; const elementLocale = ref(defaultLocale); const baseModules = import.meta.glob([ - './langs/*/about.json', - './langs/*/authentication.json', - './langs/*/common.json', - './langs/*/menu-title.json', - './langs/*/page.json', - './langs/*/ui.json', + './langs/zh-CN/about.json', + './langs/zh-CN/authentication.json', + './langs/zh-CN/common.json', + './langs/zh-CN/menu-title.json', + './langs/zh-CN/page.json', + './langs/zh-CN/ui.json', ]); const businessModules = import.meta.glob([ - './langs/*/account-settings.json', - './langs/*/api-token.json', - './langs/*/ai-platform.json', - './langs/*/announcement.json', - './langs/*/application.json', - './langs/*/chat.json', - './langs/*/dept.json', - './langs/*/dashboard-design.json', - './langs/*/dingtalk-sync.json', - './langs/*/dict.json', - './langs/*/feishu-sync.json', - './langs/*/file-manager.json', - './langs/*/loginLog.json', - './langs/*/menu.json', - './langs/*/message.json', - './langs/*/org-chart.json', - './langs/*/page-manager.json', - './langs/*/permission.json', - './langs/*/post.json', - './langs/*/role.json', - './langs/*/system-config.json', - './langs/*/system.json', - './langs/*/ui-config.json', - './langs/*/user-avatar.json', - './langs/*/user.json', - './langs/*/wecom-sync.json', + './langs/zh-CN/account-settings.json', + './langs/zh-CN/api-token.json', + './langs/zh-CN/ai-platform.json', + './langs/zh-CN/announcement.json', + './langs/zh-CN/application.json', + './langs/zh-CN/chat.json', + './langs/zh-CN/dept.json', + './langs/zh-CN/dashboard-design.json', + './langs/zh-CN/dingtalk-sync.json', + './langs/zh-CN/dict.json', + './langs/zh-CN/feishu-sync.json', + './langs/zh-CN/file-manager.json', + './langs/zh-CN/loginLog.json', + './langs/zh-CN/menu.json', + './langs/zh-CN/message.json', + './langs/zh-CN/org-chart.json', + './langs/zh-CN/page-manager.json', + './langs/zh-CN/permission.json', + './langs/zh-CN/post.json', + './langs/zh-CN/role.json', + './langs/zh-CN/system-config.json', + './langs/zh-CN/system.json', + './langs/zh-CN/ui-config.json', + './langs/zh-CN/user-avatar.json', + './langs/zh-CN/user.json', + './langs/zh-CN/wecom-sync.json', ]); const baseLocalesMap = loadLocalesMapFromDir( @@ -70,11 +70,6 @@ const businessLocalesMap = loadLocalesMapFromDir( const loadedBusinessLocales = new Set(); -/** - * 加载应用特有的语言包 - * 这里也可以改造为从服务端获取翻译数据 - * @param lang - */ async function loadMessages(lang: SupportedLanguagesType) { const [appLocaleMessages] = await Promise.all([ baseLocalesMap[lang]?.(), @@ -84,8 +79,7 @@ async function loadMessages(lang: SupportedLanguagesType) { } function getActualLocale(): SupportedLanguagesType { - const locale = preferences.app.locale; - return locale === 'auto' ? getSystemLanguage() : locale; + return APP_LOCALE; } async function loadBusinessMessages(lang = getActualLocale()) { @@ -100,76 +94,25 @@ async function loadBusinessMessages(lang = getActualLocale()) { loadedBusinessLocales.add(lang); } -/** - * 加载第三方组件库的语言包 - * @param lang - */ async function loadThirdPartyMessage(lang: SupportedLanguagesType) { await Promise.all([loadElementLocale(lang), loadDayjsLocale(lang)]); } -/** - * 加载dayjs的语言包 - * @param lang - */ async function loadDayjsLocale(lang: SupportedLanguagesType) { - let locale; - switch (lang) { - case 'en-US': { - locale = await import('dayjs/locale/en'); - break; - } - case 'zh-CN': { - locale = await import('dayjs/locale/zh-cn'); - break; - } - case 'zh-TW': { - locale = await import('dayjs/locale/zh-tw'); - break; - } - // 默认使用英语 - default: { - locale = await import('dayjs/locale/en'); - } - } - if (locale) { - dayjs.locale(locale); - } else { - console.error(`Failed to load dayjs locale for ${lang}`); + if (lang === APP_LOCALE) { + dayjs.locale('zh-cn'); } } -/** - * 加载element-plus的语言包 - * @param lang - */ async function loadElementLocale(lang: SupportedLanguagesType) { - switch (lang) { - case 'en-US': { - elementLocale.value = ( - await import('element-plus/es/locale/lang/en') - ).default; - break; - } - case 'zh-CN': { - elementLocale.value = defaultLocale; - break; - } - case 'zh-TW': { - elementLocale.value = ( - await import('element-plus/es/locale/lang/zh-tw') - ).default; - break; - } + if (lang === APP_LOCALE) { + elementLocale.value = defaultLocale; } } async function setupI18n(app: App, options: LocaleSetupOptions = {}) { - // 如果是跟随系统,获取系统语言 - const actualLocale = getActualLocale(); - await coreSetup(app, { - defaultLocale: actualLocale, + defaultLocale: getActualLocale(), loadMessages, missingWarn: !import.meta.env.PROD, ...options, diff --git a/web/apps/web-ele/src/router/access.ts b/web/apps/web-ele/src/router/access.ts index 8ab3ea5..f4ea804 100644 --- a/web/apps/web-ele/src/router/access.ts +++ b/web/apps/web-ele/src/router/access.ts @@ -13,6 +13,67 @@ import { useAppContextStore } from '#/store/app-context'; const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue'); +function normalizeViewPath(path: string) { + const normalizedPath = path.replace(/^(\.\/|\.\.\/)+/, ''); + const viewPath = normalizedPath.startsWith('/') + ? normalizedPath + : `/${normalizedPath}`; + return viewPath.replace(/^\/views/, ''); +} + +function hasPageComponent( + component: string | undefined, + pageMap: ComponentRecordType, + layoutMap: ComponentRecordType, +) { + if (!component) return true; + if (layoutMap[component]) return true; + + const normalizedPath = normalizeViewPath(component); + const pageKey = normalizedPath.endsWith('.vue') + ? normalizedPath + : `${normalizedPath}.vue`; + + return Boolean(pageMap[pageKey]); +} + +function normalizePageMap(pageMap: ComponentRecordType) { + return Object.fromEntries( + Object.entries(pageMap).map(([key, value]) => [ + normalizeViewPath(key), + value, + ]), + ) as ComponentRecordType; +} + +function filterAvailableRoutes( + routes: T[], + pageMap: ComponentRecordType, + layoutMap: ComponentRecordType, +): T[] { + return routes + .map((route) => { + const children = route.children + ? filterAvailableRoutes(route.children, pageMap, layoutMap) + : undefined; + + if (!route.component && route.children && !children?.length) { + return undefined; + } + + if (!hasPageComponent(route.component, pageMap, layoutMap)) { + if (!children?.length) return undefined; + + const groupRoute = { ...route, children }; + delete groupRoute.component; + return groupRoute; + } + + return children ? { ...route, children } : route; + }) + .filter(Boolean) as T[]; +} + async function generateAccess(options: GenerateMenuAndRoutesOptions) { const pageMap: ComponentRecordType = import.meta.glob([ '../views/_core/agent-chat/**/*.vue', @@ -54,7 +115,11 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) { const layoutMap: ComponentRecordType = { BasicLayout, IFrameView, + Layout: BasicLayout, + 'Layout.vue': BasicLayout, + '/Layout.vue': BasicLayout, }; + const routePageMap = normalizePageMap(pageMap); return await generateAccessible(preferences.app.accessMode, { ...options, @@ -72,11 +137,13 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) { // 如果是子应用模式,传递 appCode 过滤应用专属菜单 if (appContextStore.appCode) { - return await getAllMenusApi(appContextStore.appCode); + const menus = await getAllMenusApi(appContextStore.appCode); + return filterAvailableRoutes(menus, routePageMap, layoutMap); } // 主应用模式,不传参数 - return await getAllMenusApi(); + const menus = await getAllMenusApi(); + return filterAvailableRoutes(menus, routePageMap, layoutMap); }, // 可以指定没有权限跳转403页面 forbiddenComponent,