feat: 本次提交更新内容如下
store 和 router 封装完毕
This commit is contained in:
@@ -8,7 +8,8 @@
|
||||
"axios": "^1.6.7",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.20.0"
|
||||
"react-router-dom": "^6.20.0",
|
||||
"zustand": "^5.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.0.14",
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
import React from "react";
|
||||
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
||||
import AppRouter from "@/router";
|
||||
import { Button } from "antd";
|
||||
import { Button as MobileButton } from "antd-mobile";
|
||||
import Home from "./pages/Home";
|
||||
import About from "./pages/About";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/about" element={<About />} />
|
||||
</Routes>
|
||||
<>
|
||||
<AppRouter />
|
||||
<div style={{ margin: 16 }}>
|
||||
<Button type="primary">Antd 按钮</Button>
|
||||
<MobileButton color="primary">Antd-Mobile 按钮</MobileButton>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import axios, { AxiosInstance, AxiosRequestConfig, Method, AxiosResponse } from 'axios';
|
||||
import { Toast } from 'antd-mobile';
|
||||
|
||||
const DEBOUNCE_GAP = 1000;
|
||||
const debounceMap = new Map<string, number>();
|
||||
@@ -22,14 +23,28 @@ instance.interceptors.request.use(config => {
|
||||
|
||||
instance.interceptors.response.use(
|
||||
(res: AxiosResponse) => {
|
||||
if (res.data && (res.data.code === 200 || res.data.success)) {
|
||||
const { code, success, msg } = res.data || {};
|
||||
if (code === 200 || success) {
|
||||
return res.data.data ?? res.data;
|
||||
}
|
||||
window?.alert?.(res.data?.msg || '接口错误');
|
||||
return Promise.reject(res.data?.msg || '接口错误');
|
||||
// 业务错误统一提示
|
||||
Toast.show({ content: msg || '接口错误', position: 'top' });
|
||||
// 分类处理
|
||||
if (code === 401) {
|
||||
// 未登录或登录失效
|
||||
// 可跳转登录页或清除 token
|
||||
localStorage.removeItem('token');
|
||||
} else if (code === 403) {
|
||||
// 无权限
|
||||
// 可做特殊处理
|
||||
} else if (code === 500) {
|
||||
// 服务端异常
|
||||
}
|
||||
return Promise.reject(msg || '接口错误');
|
||||
},
|
||||
err => {
|
||||
window?.alert?.(err.message || '网络异常');
|
||||
// 网络错误、超时等
|
||||
Toast.show({ content: err.message || '网络异常', position: 'top' });
|
||||
return Promise.reject(err);
|
||||
}
|
||||
);
|
||||
@@ -44,6 +59,7 @@ export function request(
|
||||
const now = Date.now();
|
||||
const last = debounceMap.get(key) || 0;
|
||||
if (now - last < DEBOUNCE_GAP) {
|
||||
Toast.show({ content: '请求过于频繁,请稍后再试', position: 'top' });
|
||||
return Promise.reject('请求过于频繁,请稍后再试');
|
||||
}
|
||||
debounceMap.set(key, now);
|
||||
|
||||
34
nkebao/src/router/index.tsx
Normal file
34
nkebao/src/router/index.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import React from "react";
|
||||
import { BrowserRouter, useRoutes } from "react-router-dom";
|
||||
import homeRoutes from "./module/home";
|
||||
import aboutRoutes from "./module/about";
|
||||
import PermissionRoute from "./permissionRoute";
|
||||
|
||||
function wrapWithPermission(route) {
|
||||
if (route.auth) {
|
||||
return {
|
||||
...route,
|
||||
element: (
|
||||
<PermissionRoute requiredRole={route.requiredRole}>
|
||||
{route.element}
|
||||
</PermissionRoute>
|
||||
),
|
||||
};
|
||||
}
|
||||
return route;
|
||||
}
|
||||
|
||||
const routes = [
|
||||
...homeRoutes.map(wrapWithPermission),
|
||||
...aboutRoutes.map(wrapWithPermission),
|
||||
];
|
||||
|
||||
const AppRoutes = () => useRoutes(routes);
|
||||
|
||||
const AppRouter: React.FC = () => (
|
||||
<BrowserRouter>
|
||||
<AppRoutes />
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
export default AppRouter;
|
||||
10
nkebao/src/router/module/about.tsx
Normal file
10
nkebao/src/router/module/about.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import About from "@/pages/About";
|
||||
|
||||
const aboutRoutes = [
|
||||
{
|
||||
path: "/about",
|
||||
element: <About />,
|
||||
},
|
||||
];
|
||||
|
||||
export default aboutRoutes;
|
||||
17
nkebao/src/router/module/home.tsx
Normal file
17
nkebao/src/router/module/home.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import Home from "@/pages/Home";
|
||||
|
||||
const homeRoutes = [
|
||||
{
|
||||
path: "/",
|
||||
element: <Home />,
|
||||
auth: false, // 不需要权限
|
||||
},
|
||||
{
|
||||
path: "/dashboard",
|
||||
element: <Dashboard />,
|
||||
auth: true, // 需要登录
|
||||
requiredRole: "admin", // 需要 admin 角色
|
||||
},
|
||||
];
|
||||
|
||||
export default homeRoutes;
|
||||
28
nkebao/src/router/permissionRoute.tsx
Normal file
28
nkebao/src/router/permissionRoute.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
import { Navigate, useLocation } from "react-router-dom";
|
||||
import { useUserStore } from "@/store/module/user"; // 假设你用 zustand 管理用户状态
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
requiredRole?: string; // 可选:需要的角色
|
||||
}
|
||||
|
||||
const PermissionRoute: React.FC<Props> = ({ children, requiredRole }) => {
|
||||
const user = useUserStore((state) => state.user);
|
||||
const location = useLocation();
|
||||
|
||||
// 未登录
|
||||
if (!user) {
|
||||
return <Navigate to="/login" state={{ from: location }} replace />;
|
||||
}
|
||||
|
||||
// 有角色要求但不满足
|
||||
if (requiredRole && user.role !== requiredRole) {
|
||||
return <Navigate to="/403" replace />;
|
||||
}
|
||||
|
||||
// 通过
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
export default PermissionRoute;
|
||||
2
nkebao/src/store/index.ts
Normal file
2
nkebao/src/store/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './module/user';
|
||||
// 未来可继续合并其他模块
|
||||
20
nkebao/src/store/module/user.ts
Normal file
20
nkebao/src/store/module/user.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
// src/store/user.ts
|
||||
import { create } from 'zustand';
|
||||
|
||||
export interface User {
|
||||
name: string;
|
||||
role: string;
|
||||
token: string;
|
||||
}
|
||||
|
||||
interface UserState {
|
||||
user: User | null;
|
||||
setUser: (user: User) => void;
|
||||
clearUser: () => void;
|
||||
}
|
||||
|
||||
export const useUserStore = create<UserState>((set) => ({
|
||||
user: null,
|
||||
setUser: (user) => set({ user }),
|
||||
clearUser: () => set({ user: null }),
|
||||
}));
|
||||
Reference in New Issue
Block a user