From 1e5ea1879b251ded4bc7c156e3bcbf4a8b13ec67 Mon Sep 17 00:00:00 2001 From: wuxichen <17301714657@163.com> Date: Mon, 20 Oct 2025 14:05:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B5=81=E5=BC=8F=E5=B8=83=E5=B1=80?= =?UTF-8?q?=E7=82=B9=E5=87=BB=E4=B8=80=E7=BA=A7=E8=8F=9C=E5=8D=95=E5=AE=9A?= =?UTF-8?q?=E4=BD=8D=E5=88=B0=E5=AD=90=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/proxy.ts | 2 +- config/routes.ts | 34 +++++++++++- src/app.tsx | 114 ++++++++++++---------------------------- src/utils/menuUtils.ts | 97 ---------------------------------- src/utils/menuUtils.tsx | 69 ++++++++++++++++++++++++ 5 files changed, 138 insertions(+), 178 deletions(-) delete mode 100644 src/utils/menuUtils.ts create mode 100644 src/utils/menuUtils.tsx diff --git a/config/proxy.ts b/config/proxy.ts index a3cb75d..09ea6cd 100644 --- a/config/proxy.ts +++ b/config/proxy.ts @@ -17,7 +17,7 @@ export default { // 要代理的地址 // http://192.168.1.231:48080 伟强 // https://petshy.tashowz.com/ - target: 'http://192.168.1.231:48080/', + target: 'https://petshy.tashowz.com/', // 配置了这个可以从 http 代理到 https // 依赖 origin 的功能可能需要这个,比如 cookie changeOrigin: true, diff --git a/config/routes.ts b/config/routes.ts index 7da7247..0a2c3b5 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -40,11 +40,43 @@ export default [ routes: [ { name: '订单管理', - path: '/trade', + path: '/trade/order', component: './trade/order/index', }, ], }, + + { + path: '/prod1', + name: '商品管理1', + routes: [ + { + path: '', // 空路径,匹配 /prod + redirect: 'list', // 相对路径重定向 + }, + { + name: '商品1', + path: '/prod1/list', + component: './prod/list/index', + }, + { + name: '类目管理', + path: '/prod1/category', + component: './prod/category/index', + }, + ], + }, + // { + // path: "/system", + // name: "系统管理", + // routes: [ + // { + // name: "商品管理", + // path: "/system/menu", + // component: "./system/menu/index", + // }, + // ], + // }, { component: '404', layout: false, diff --git a/src/app.tsx b/src/app.tsx index 3e49ab9..5435b7d 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -19,6 +19,8 @@ import '@ant-design/v5-patch-for-react-19'; import { useDictStore } from '@/hooks/stores/dict'; import { getAccessToken, getTenantId } from '@/utils/auth'; import { CACHE_KEY, useCache } from './hooks/web/useCache'; +import type { MenuVO } from './services/system/menu'; +import { loopMenuItem } from './utils/menuUtils'; const isDev = process.env.NODE_ENV === 'development'; const isDevOrTest = isDev || process.env.CI; @@ -26,6 +28,8 @@ const loginPath = '/user/login'; // 全局存储菜单数据和路由映射 +const dynamicRoutesAdded = false; +// 标记是否已添加动态路由 /** * @see https://umijs.org/docs/api/runtime-config#getinitialstate * */ @@ -33,6 +37,7 @@ export async function getInitialState(): Promise<{ settings?: Partial; currentUser?: UserInfoVO; loading?: boolean; + menus?: MenuVO[]; fetchUserInfo?: () => Promise; }> { const { wsCache } = useCache(); @@ -70,12 +75,14 @@ export async function getInitialState(): Promise<{ ) { const currentUser = wsCache.get(CACHE_KEY.USER); if (getAccessToken() && !currentUser) { - fetchUserInfo(); + await fetchUserInfo(); } + const menus = wsCache.get(CACHE_KEY.ROLE_ROUTERS); console.log(111); return { fetchUserInfo, currentUser, + menus, settings: defaultSettings as Partial, }; } @@ -227,87 +234,36 @@ export const request: RequestConfig = { return searchParams.toString(); }, }; -// umi 4 使用 modifyRoutes -export function patchClientRoutes({ routes }: { routes: any }) { + +// Umi 4 支持异步的 patchClientRoutes +export async function patchClientRoutes({ routes }: any) { const { wsCache } = useCache(); - const globalMenus = wsCache.get(CACHE_KEY.ROLE_ROUTERS); + + // 先尝试从缓存获取 + let menus = wsCache.get(CACHE_KEY.ROLE_ROUTERS); + + // 如果缓存没有,且有 token,则获取 + if (!menus && getAccessToken()) { + try { + const data = await getInfo(); + wsCache.set(CACHE_KEY.USER, data); + wsCache.set(CACHE_KEY.ROLE_ROUTERS, data.menus); + menus = data.menus; + } catch (error) { + console.error('获取菜单失败:', error); + return; + } + } + + if (!menus || menus.length === 0) { + return; + } const routerIndex = routes.findIndex((item: any) => item.path === '/'); const parentId = routes[routerIndex].id; - if (globalMenus) { - routes[routerIndex].routes.push(...loopMenuItem(globalMenus, parentId)); + if (menus) { + const r = loopMenuItem(menus, parentId); + console.log(r, routes); + routes[routerIndex].routes.push(...r); } } - -const loopMenuItem = (menus: any[], pId: number | string): any[] => { - return menus.flatMap((item) => { - let Component: React.ComponentType | null = null; - // console.log(findFirstLeafRoute(item), 'item'); - if (item.component && item.component.length > 0) { - // 防止配置了路由,但本地暂未添加对应的页面,产生的错误 - Component = React.lazy(() => { - const importComponent = () => import(`@/pages/${item.component}`); - const import404 = () => import('@/pages/404'); - return importComponent().catch(import404); - }); - } - if (item.children && item.children.length > 0) { - return [ - { - path: item.path, - name: item.name, - // icon: item.icon, - id: item.id, - parentId: pId, - - children: [ - { - path: item.url, - element: , - }, - ...loopMenuItem(item.children, item.menuID), - ], - }, - ]; - } else { - // console.log(findFirstLeafRoute(newItem)); - return [ - { - path: item.path, - name: item.name, - // icon: item.icon, - id: item.menuID, - parentId: pId, - redirect: '/system/tenant/list', - element: ( - } - > - {Component && } - - ), - children: [], // 添加缺失的 children 属性 - }, - ]; - } - }); -}; - -const _findFirstLeafRoute = (menuItem: any, parent = '/'): string | null => { - // 如果没有子菜单,返回当前路径 - - if (!menuItem.children || menuItem.children.length === 0) { - return parent + menuItem.path; - } - - // 递归查找第一个叶子节点 - for (const child of menuItem.children) { - // const leafRoute = findFirstLeafRoute(child, menuItem.path + "/"); - const leafRoute = _findFirstLeafRoute(child, `${menuItem.path}/`); - if (leafRoute) { - return leafRoute; - } - } - - return null; -}; diff --git a/src/utils/menuUtils.ts b/src/utils/menuUtils.ts deleted file mode 100644 index fd62235..0000000 --- a/src/utils/menuUtils.ts +++ /dev/null @@ -1,97 +0,0 @@ -// src/utils/menuUtils.ts -import { MenuVO } from "@/services/system/menu"; -import type { MenuDataItem } from "@ant-design/pro-components"; -// src/utils/menuUtils.ts - -// src/utils/menuUtils.ts -// src/utils/route.ts -export function transformMenuToRoutes(menuData: MenuVO[]): any[] { - return menuData.map((item) => ({ - path: item.path, - name: item.name, - icon: item.icon, - component: item.component, - routes: item.children ? transformMenuToRoutes(item.children) : undefined, - })); -} - -// src/utils/route.ts -export function transformBackendMenuToFlatRoutes(menuData: any[]) { - const flatRoutes: any[] = []; - - function processMenu(items: any[], parentRouteId = "ant-design-pro-layout") { - items.forEach((item) => { - const currentRouteId = `route-${item.id}`; - - // 处理路径 - 如果是子路由,需要组合完整路径 - let fullPath = item.path; - if (item.parentId !== 0 && !item.path.startsWith("/")) { - // 子路由需要相对路径 - fullPath = item.path; - } - - const route: any = { - id: currentRouteId, - path: fullPath, - name: item.name, - parentId: parentRouteId, - }; - - // 添加图标(如果不是 # 的话) - if (item.icon && item.icon !== "#") { - route.icon = item.icon; - } - - // 添加组件路径 - if (item.component) { - // 转换组件路径为动态导入格式 - route.component = item.component; - } - - // 其他属性 - if (!item.visible) { - route.hideInMenu = true; - } - - flatRoutes.push(route); - - // 递归处理子菜单 - if (item.children && item.children.length > 0) { - processMenu(item.children, currentRouteId); - } - }); - } - - processMenu(menuData); - return flatRoutes; -} - -export function transformMenuData(menuData: any[]) { - const transformItem = (item: any, parentPath = "") => { - const fullPath = item.path.startsWith("/") - ? item.path - : `${parentPath}/${item.path}`; - const result: any = { - path: fullPath, - name: item.name, - key: `${item.id}`, - }; - if (item.icon && item.icon !== "#") { - result.icon = item.icon; - } - - if (!item.visible) { - result.hideInMenu = true; - } - - if (item.children && item.children.length > 0) { - result.children = item.children.map((child: any) => - transformItem(child, fullPath) - ); - } - - return; - result; - }; - return menuData.map((item) => transformItem(item)); -} diff --git a/src/utils/menuUtils.tsx b/src/utils/menuUtils.tsx new file mode 100644 index 0000000..b76ecd6 --- /dev/null +++ b/src/utils/menuUtils.tsx @@ -0,0 +1,69 @@ +import { Navigate } from '@umijs/max'; +import { Spin } from 'antd'; +import React from 'react'; + +export const loopMenuItem = (menus: any[], pId: number | string): any[] => { + // console.log(menus, "menus"); + return menus.flatMap((item) => { + let Component: React.ComponentType | null = null; + if (item.component && item.component.length > 0) { + // 防止配置了路由,但本地暂未添加对应的页面,产生的错误 + Component = React.lazy(() => { + const importComponent = () => import(`@/pages/${item.component}`); + const import404 = () => import('@/pages/404'); + return importComponent().catch(import404); + }); + } + if (item.children && item.children.length > 0) { + return [ + { + path: item.path, + name: item.name, + // icon: item.icon, + id: item.id, + parentId: pId, + children: [ + { + path: item.path, + element: ( + + ), + }, + ...loopMenuItem(item.children, item.menuID), + ], + }, + ]; + } else { + return [ + { + path: item.path, + name: item.name, + // icon: item.icon, + id: item.menuID, + parentId: pId, + element: ( + } + > + {Component && } + + ), + children: [], // 添加缺失的 children 属性 + }, + ]; + } + }); +}; + +function getFirstLeafPath(menus: any[], parentPath: string): string { + const firstMenu = menus[0]; + const currentPath = `${parentPath}/${firstMenu.path}`; + if (firstMenu.children && firstMenu.children.length > 0) { + return getFirstLeafPath(firstMenu.children, currentPath); + } else { + return currentPath; + } +}