diff --git a/package-lock.json b/package-lock.json index 34fab69..4edd5b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "js-cookie": "^3.0.5", "lucide-react": "^0.546.0", "motion": "^12.23.24", + "nprogress": "^0.2.0", "qrcode": "^1.5.4", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -4094,6 +4095,12 @@ "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", "license": "MIT" }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==", + "license": "MIT" + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", diff --git a/package.json b/package.json index 75981ee..c4a3e9b 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,6 @@ }, "dependencies": { "@ant-design/icons": "^6.1.1", - "@google/genai": "^1.29.0", "@reduxjs/toolkit": "^2.11.2", "@tailwindcss/vite": "^4.1.14", "@vitejs/plugin-react": "^5.0.4", @@ -24,6 +23,7 @@ "js-cookie": "^3.0.5", "lucide-react": "^0.546.0", "motion": "^12.23.24", + "nprogress": "^0.2.0", "qrcode": "^1.5.4", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/src/App.tsx b/src/App.tsx index 26ceabf..fe37bc5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,5 +3,6 @@ import { RouterProvider } from 'react-router-dom'; import { router } from './router'; export default function App() { - return ; + + return ; } diff --git a/src/api/request.ts b/src/api/request.ts index 98fcf48..be6396e 100644 --- a/src/api/request.ts +++ b/src/api/request.ts @@ -2,9 +2,10 @@ import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'ax import envConfig from '../../env'; import Cookies from 'js-cookie'; import { message } from 'antd'; -import store from '../store'; -import { logout } from '../store/userSlice'; +// 🔥 删掉这两行!!! +// import store from '../store'; +// import { logout } from '../store/userSlice'; const API_BASE_URL = envConfig.baseURL; @@ -13,19 +14,15 @@ const api = axios.create({ timeout: 20000, headers: { 'Content-Type': 'application/json', - }, withCredentials: true, }); // 请求拦截器:自动添加token -// 请求拦截器 api.interceptors.request.use( (config: InternalAxiosRequestConfig) => { - // 从 localStorage 获取 token const token = localStorage.getItem('token'); if (token && config.headers) { - // 将 token 添加到请求头 config.headers['Authorization'] = `Bearer ${token}`; } return config; @@ -38,43 +35,23 @@ api.interceptors.request.use( // 响应拦截器 api.interceptors.response.use( (response: AxiosResponse) => { - // 处理成功响应 - const { data } = response; - // 如果后端规范定义了 code,可以在这里统一处理 - // if (data.code !== 200) { - // message.error(data.message || '请求失败'); - // return Promise.reject(new Error(data.message || 'Error')); - // } - return data; + return response.data; }, - (error: AxiosError) => { - // 处理错误响应 - if (error.response) { - switch (error.response.status) { - case 401: - // 未授权,清除本地信息并跳转到登录页 - localStorage.removeItem('token'); - localStorage.removeItem('isAuthenticated'); - localStorage.removeItem('user'); - store.dispatch(logout()); - window.location.href = '/login'; - message.error('会话已过期,请重新登录'); - break; - case 403: - message.error('拒绝访问:权限不足'); - break; - case 404: - message.error('资源不存在'); - break; - case 500: - message.error('服务器内部错误'); - break; - default: - message.error(error.message || '网络错误'); - } - } else { - message.error('连接服务器失败'); + async (error: AxiosError) => { // 👈 加 async + if (error.response?.status === 401) { + localStorage.removeItem('token'); + localStorage.removeItem('isAuthenticated'); + localStorage.removeItem('user'); + + // 🔥 🔥 🔥 在这里动态导入!!! + const store = await import('../store'); + const { logout } = await import('../store/userSlice'); + + store.default.dispatch(logout()); + window.location.href = '/login'; + message.error('会话已过期,请重新登录'); } + return Promise.reject(error); } ); diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index b461810..0fc63fc 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -9,7 +9,8 @@ import { ConfigProvider, theme, Breadcrumb, - Badge + Badge, + message } from 'antd'; import { DashboardOutlined, @@ -26,6 +27,8 @@ import { } from '@ant-design/icons'; import { MOCK_USER } from '../constants'; import logo from '../assets/logo.png'; +import { useSelector } from 'react-redux'; +import { RootState } from '../store'; const { Header, Sider, Content } = Layout; export default function AppLayout() { @@ -33,10 +36,7 @@ export default function AppLayout() { const [time, setTime] = useState(new Date().toLocaleString()); const navigate = useNavigate(); const location = useLocation(); - - // 从 localStorage 获取真实用户信息 - const userJson = localStorage.getItem('user'); - const user = userJson ? JSON.parse(userJson) : MOCK_USER; + const { userInfo } = useSelector((state: RootState) => state.user); useEffect(() => { const timer = setInterval(() => setTime(new Date().toLocaleString()), 1000); @@ -61,7 +61,7 @@ export default function AppLayout() { { key: '/serialNumGenerate', icon: , label: '序列号生成', roles: ['admin'] }, ]; - const filteredMenu = menuItems.filter(item => item.roles.includes(user.role)); + const filteredMenu = menuItems.filter(item => item.roles.includes(userInfo.role)); const currentPathLabel = menuItems.find(i => i.key === location.pathname)?.label || '概览控制台'; @@ -85,6 +85,7 @@ export default function AppLayout() { } }} > +
@@ -100,11 +101,7 @@ export default function AppLayout() { items={filteredMenu} onClick={({ key }) => navigate(key)} /> - {!collapsed && ( -
- 当前权限: {user.role === 'admin' ? '系统管理员' : user.role === 'operator' ? '操作员' : '观察员'} -
- )} +
@@ -127,8 +124,7 @@ export default function AppLayout() {
{time} - {user.name} - } /> + {userInfo.username}