以下代碼都為部分核心代碼
一.根據不同的登錄用戶,返回不同的權限列表?,以下是三種不同用戶限權列表
const pression = {
//超級管理員BigAdmin: [{key: "screen",icon: "FileOutlined",label: "數據圖表",},{key: "users",icon: "UserOutlined",label: "用戶列表",},{key: "food",icon: "PieChartOutlined",label: "食譜",},{key: "discuss",icon: "CommentOutlined",label: "評論",}],
//普通管理員Admin: [{key: "screen",icon: "FileOutlined",label: "數據圖表",},{key: "food",icon: "PieChartOutlined",label: "食譜",}, {key: "discuss",icon: "CommentOutlined",label: "評論",}],
//普通用戶commont: [{key: "screen",icon: "FileOutlined",label: "數據圖表",}]}
二.實現動態菜單
用戶登錄后先將權限列表存入本地瀏覽器,再跳轉到系統頁面,并在首次加載時候獲取本地權限列表數據,進行動態渲染
//假如登錄的是超級管理員,對應的權限列表應如下,這里使用了ant design的菜單組件,為了方便所以使用符合該菜單組件的數據結構BigAdmin: [{key: "screen",icon: "FileOutlined",label: "數據圖表",},{key: "users",icon: "UserOutlined",label: "用戶列表",},{key: "food",icon: "PieChartOutlined",label: "食譜",},{key: "discuss",icon: "CommentOutlined",label: "評論",}],
//-----------------import * as Icons from '@ant-design/icons';//--自定義組件將字符串轉化為對應的組件---------
const ICONFONT = (props: any) => {const { icon } = props//動態菜單不能確定需要那些icon,全部引入作為Iconsreturn React.createElement(Icons[icon])
}const [Enums, setenum] = useState<any>()const AdminInfo = useSelector((state: any) => state.AdminStore.AdminInfo)
useEffect(() => {
//登錄后,系統首頁獲取本地權限列表,因為這里使用了ant design的icon,需要將字符串轉化為對應的組件,這里封裝的自定義組件let items = JSON.parse(JSON.stringify(AdminInfo.pression))items.map((item: any) => {item.icon = item.icon && <ICONFONT icon={item.icon}></ICONFONT>})setenum([...items])}, [])//在菜單組件中使用<Menu selectedKeys={['screen']} mode="inline" items={Enums} onClick={chooose} />
三.實現動態路由?
先把動態路由和靜態路由分離出來,在路由配置文件中,這里需要進行動態添加的路由為?path: "/backstage"下的子路由,需要給他一個name,后續方便查找
//這里也很重要,頁面加載時候,先判斷本地是否存入了權限列表
import { Admin } from "@/utils/local"
//獲取本地存儲的信息
const rs = Admin.get_Admin()//路由懶加載
const lazyComponent = (Component: FC) => {return <Suspense fallback={Skeletons}><Component /></Suspense>
}//靜態路由
const routers = [{path: '/',element: <Navigate to="/home" />},{path: "/",element: <App />,children: [{path: "/home",element: lazyComponent(Home),},{path: "/category",element: lazyComponent(About),children: [{path: "/category",element: <Navigate to={'/category/mainfood'}></Navigate>},{path: "mainfood",element: lazyComponent(Mainfood)},{path: "bake",element: lazyComponent(Bake)},{path: "beverage",element: lazyComponent(Beverage)},{path: "soup",element: lazyComponent(Soup)}]}, {path: "/user",element: lazyComponent(Test),}, {path: "/edituser",element: lazyComponent(EeditUser)},{path: "/editfood",element: lazyComponent(Edit_Food)}]},{path: "/detaile/:id",element: lazyComponent(Datile)},{path: "/login",element: <Login></Login>},{
//需要動態添加的路由在此處path: "/backstage",element: lazyComponent(Back),name: "back",children: [{path: "/backstage",element: <Navigate to="/backstage/screen"></Navigate>},{path: "screen",element: lazyComponent(Screen)},]},{path: "*",element: <Error></Error>}
]//準備需要添加的動態路由,將添加到 path: "/backstage"的子路由下,
//這里的id必須必須填寫,而且必須唯一,
//如:id:'4-2',4表示在一級路由下索引為4的路由,2表示在該路由下子路由的索引
const dtRoute = [{path: "users",element: lazyComponent(Users),id: '4-2'},{path: "food",id: '4-3',element: lazyComponent(Food)},{path: "discuss",id: '4-4',element: lazyComponent(Discuss)}
]
定義一個動態添加路由的函數
const dtRoute = [{path: "users",element: lazyComponent(Users),id: '4-2'},{path: "food",id: '4-3',element: lazyComponent(Food)},{path: "discuss",id: '4-4',element: lazyComponent(Discuss)}
]const route = createBrowserRouter(routers)//這里需要導出函數,在登錄后調用,pression即為后端返回的列表
export function addrouter(pression: any[]) {
//找到需要動態添加的路由,name為back,即為之前的path:"/backstage"路由const baseRouter = route.routes.find((rt: any) => rt.name === "back")console.log(baseRouter)if (pression.length !== 0) {//判斷傳入的權限列表是否在動態路由之中,有則追加進去for (const use of pression) {for (const rt of dtRoute) {if (rt.path === use.key) {baseRouter?.children?.push(rt)} else {}}}} else {
//如果傳入的為空表示,退出登錄,更新路由,這里取的最前兩個靜態路由,即刪除動態路由baseRouter?.children?.splice(2)}
}//這里之前已提到,
import { Admin } from "@/utils/local"
const rs = Admin.get_Admin()
//-------頁面刷新時候會重新執行路由文件---訪問其它動態路由的時候會丟失找不到,
//因為動態路由只在登錄的時候進行了添加,而頁面刷新會讓整個路由重新執行,而不會重新動態添加--
//所以刷新的時候要判斷本地是否存儲了動態路由信息,并再次添加
if (rs) {addrouter(rs.pression)
}
在redux中使用動態添加路由的函數
import { createSlice } from "@reduxjs/toolkit";
import { Admin } from "@/utils/local";
import { Admin_Loing } from '@/apis/admin/admin'
import { message } from "antd"
import type { AppDispatch } from "../index"//導入動態添加路由的函數
import { addrouter } from "@/router"
const AdminStore = createSlice({name: "RootStore",initialState: {AdminInfo: Admin.get_Admin() || {pression: [],user: {}}},reducers: {//定義登錄方法,需要在登錄后動態添加路由Login: (state, { payload }) => {state.AdminInfo = payloadAdmin.set_Admin(payload)
//調用動態添加路由的函數,并傳入登錄后傳來的權限列表addrouter(payload.pression)},GoOut: (state) => {state.AdminInfo = {pression: [],user: {}}Admin.remove_Admin()addrouter([])},},
})//導出Login
export const { Login, GoOut } = AdminStore.actions//,登錄是異步的,所以定義異步登錄方法
const axios_admin_login = (data: any) => {return async (dispatch: AppDispatch) => {const res = await Admin_Loing(data)if (res.status == 200) {
//登錄成功后調用Login,并傳入包含權限列表的數據dispatch(Login(res.data))message.success("登錄成功")return true} else {return false}}
}
//最后導出異步登錄,在登錄界面使用
export { axios_admin_login }
export default AdminStore.reducer