diff --git a/apps/web-antd/src/router/access.ts b/apps/web-antd/src/router/access.ts index 06cf3829..6990ba8b 100644 --- a/apps/web-antd/src/router/access.ts +++ b/apps/web-antd/src/router/access.ts @@ -19,6 +19,170 @@ import { localMenuList } from './routes/local'; const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue'); const NotFoundComponent = () => import('#/views/_core/fallback/not-found.vue'); +/** + * 后台路由转vben路由 + * @param menuList 后台菜单 + * @param parentPath 上级目录 + * @returns vben路由 + */ +function backMenuToVbenMenu( + menuList: Menu[], + parentPath = '', +): RouteRecordStringComponent[] { + const resultList: RouteRecordStringComponent[] = []; + menuList.forEach((menu) => { + // 根目录为菜单形式 + // 固定有一个children children为当前菜单 + if (menu.path === '/' && menu.children && menu.children.length === 1) { + if (!menu.children || !menu.children[0]) { + return; + } + + // 需要处理根目录为内嵌的情况 不会带InnerLink + if (/^https?:\/\//.test(menu.children[0].path)) { + menu.children[0].component = 'InnerLink'; + menu.children[0].path = menu.children[0].path + .replaceAll(/^https?:\/\//g, '') + .replaceAll('/#/', '') + .replaceAll('#', '') + .replaceAll(/[?&]/g, ''); + } + + // 取子路径作为父级路径 + const path = menu.children[0].path; + // 取子菜单的meta作为当前菜单的meta + menu.meta = menu.children[0].meta; + // 由于在一级路由 父级路径需要加上/ + menu.path = `/${path}`; + menu.component = 'RootMenu'; + // 将子路径设置为'' + menu.children[0].path = ''; + } + + // 外链: http开头 & 组件为Layout || ParentView + // 正则判断是否为http://或者https://开头 + if ( + /^https?:\/\//.test(menu.path) && + (menu.component === 'Layout' || menu.component === 'ParentView') + ) { + menu.component = 'Link'; + } + + // 内嵌iframe 组件为InnerLink + if (menu.meta?.link && menu.component === 'InnerLink') { + menu.component = 'IFrameView'; + } + + /** + * 拼接path + * menu.path为''(根目录路由) 则不拼接 + */ + if (parentPath && menu.path) { + menu.path = `${parentPath}/${menu.path}`; + } + + // 创建vben路由对象 + const vbenRoute: RouteRecordStringComponent = { + component: menu.component, + meta: { + // 当前路由不在菜单显示 但是可以通过链接访问 + // 不可访问的路由由后端控制隐藏(不返回对应路由) + hideInMenu: menu.hidden, + icon: menu.meta?.icon, + keepAlive: !menu.meta?.noCache, + title: menu.meta?.title, + }, + name: menu.name, + path: menu.path, + }; + + // 添加路由参数信息 + if (menu.query) { + try { + const query = JSON.parse(menu.query); + vbenRoute.meta && (vbenRoute.meta.query = query); + } catch { + console.error('错误的路由参数类型, 必须为[json]格式'); + } + } + + /** + * 处理不同组件 + */ + switch (menu.component) { + /** + * iframe内嵌 + */ + case 'IFrameView': { + vbenRoute.component = 'IFrameView'; + if (vbenRoute.meta) { + vbenRoute.meta.iframeSrc = menu.meta.link; + } + /** + * 需要判断特殊情况 比如vue的hash是带#的 + * 比如链接 aaa.com/#/bbb path会转换为 aaa/com/#/bbb + * 比如链接 aaa.com/?bbb=xxx + * 需要去除# 否则无法被添加到路由 + */ + vbenRoute.path = vbenRoute.path + // 替换https:// 或者 http:// + .replaceAll(/^https?:\/\//g, '') + .replaceAll('/#/', '') + .replaceAll('#', '') + .replaceAll(/[?&]/g, ''); + break; + } + case 'Layout': { + vbenRoute.component = 'BasicLayout'; + break; + } + /** + * 外链 新窗口打开 + */ + case 'Link': { + if (vbenRoute.meta) { + vbenRoute.meta.link = menu.meta.link; + } + vbenRoute.component = 'BasicLayout'; + break; + } + /** + * 三级以上菜单 父级component为ParentView + * 不能为layout 会套两层BasicLayout + */ + case 'ParentView': { + vbenRoute.component = ''; + break; + } + /** + * 根目录菜单 + */ + case 'RootMenu': { + if (vbenRoute.meta) { + vbenRoute.meta.hideChildrenInMenu = true; + } + vbenRoute.component = 'BasicLayout'; + break; + } + /** + * 其他自定义组件 如system/user/index 拼接/ + */ + default: { + vbenRoute.component = `/${menu.component}`; + break; + } + } + + // children处理 + if (menu.children && menu.children.length > 0) { + vbenRoute.children = backMenuToVbenMenu(menu.children, menu.path); + } + // 添加 + resultList.push(vbenRoute); + }); + return resultList; +} + async function generateAccess(options: GenerateMenuAndRoutesOptions) { const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue'); @@ -28,156 +192,6 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) { NotFoundComponent, }; - /** - * 后台路由转vben路由 - * - * todo 需要重构 - * @param menuList 后台菜单 - * @param parentPath 上级目录 - * @returns vben路由 - */ - function backMenuToVbenMenu( - menuList: Menu[], - parentPath = '', - ): RouteRecordStringComponent[] { - const resultList: RouteRecordStringComponent[] = []; - menuList.forEach((menu) => { - // 根目录为菜单形式 - // 固定有一个children children为当前菜单 - if (menu.path === '/' && menu.children && menu.children.length === 1) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - menu.meta = menu.children[0]!.meta; - /** - * todo 先写死 后续再优化 - */ - menu.path = '/root_menu'; - menu.component = 'RootMenu'; - } - // 外链: http开头 & 组件为Layout || ParentView - // 正则判断是否为http://或者https://开头 - if ( - /^https?:\/\//.test(menu.path) && - (menu.component === 'Layout' || menu.component === 'ParentView') - ) { - menu.component = 'Link'; - } - // 内嵌iframe 组件为InnerLink - if (menu.meta?.link && menu.component === 'InnerLink') { - menu.component = 'IFrameView'; - } - - // path - if (parentPath) { - menu.path = `${parentPath}/${menu.path}`; - } - - const vbenRoute: RouteRecordStringComponent = { - component: menu.component, - meta: { - // 当前路由不在菜单显示 但是可以通过链接访问 - // 不可访问的路由由后端控制隐藏(不返回对应路由) - hideInMenu: menu.hidden, - icon: menu.meta?.icon, - keepAlive: !menu.meta?.noCache, - title: menu.meta?.title, - }, - name: menu.name, - path: menu.path, - }; - - // 添加路由参数信息 - if (menu.query) { - try { - const query = JSON.parse(menu.query); - vbenRoute.meta && (vbenRoute.meta.query = query); - } catch { - console.error('错误的路由参数类型, 必须为[json]格式'); - } - } - - /** - * 处理不同组件 - */ - switch (menu.component) { - case 'Layout': { - vbenRoute.component = 'BasicLayout'; - break; - } - /** - * iframe内嵌 - */ - case 'IFrameView': { - vbenRoute.component = 'IFrameView'; - if (vbenRoute.meta) { - vbenRoute.meta.iframeSrc = menu.meta.link; - } - /** - * 需要判断特殊情况 比如vue的hash是带#的 - * 比如链接 aaa.com/#/bbb path会转换为 aaa/com/#/bbb - * 比如链接 aaa.com/?bbb=xxx - * 需要去除# 否则无法被添加到路由 - */ - /** - * todo 不优雅 考虑别的方案 - */ - if (vbenRoute.path.includes('/#/')) { - vbenRoute.path = vbenRoute.path.replace('/#/', ''); - } - if (vbenRoute.path.includes('#')) { - vbenRoute.path = vbenRoute.path.replace('#', ''); - } - if (vbenRoute.path.includes('?') || vbenRoute.path.includes('&')) { - vbenRoute.path = vbenRoute.path.replace('?', ''); - vbenRoute.path = vbenRoute.path.replace('&', ''); - } - break; - } - /** - * 外链 新窗口打开 - */ - case 'Link': { - if (vbenRoute.meta) { - vbenRoute.meta.link = menu.meta.link; - } - vbenRoute.component = 'BasicLayout'; - break; - } - /** - * 根目录菜单 - */ - case 'RootMenu': { - if (vbenRoute.meta) { - vbenRoute.meta.hideChildrenInMenu = true; - } - vbenRoute.component = 'BasicLayout'; - break; - } - /** - * 不能为layout 会套两层BasicLayout - */ - case 'ParentView': { - vbenRoute.component = ''; - break; - } - /** - * 其他自定义组件 如system/user/index 拼接/ - */ - default: { - vbenRoute.component = `/${menu.component}`; - break; - } - } - - // children处理 - if (menu.children && menu.children.length > 0) { - vbenRoute.children = backMenuToVbenMenu(menu.children, menu.path); - } - - resultList.push(vbenRoute); - }); - return resultList; - } - return await generateAccessible(preferences.app.accessMode, { ...options, fetchMenuListAsync: async () => {