From cb5088115ad824b8c62ac298f7c2008c9db3259e Mon Sep 17 00:00:00 2001 From: Stev_Wang <304865932@qq.com> Date: Sat, 27 Dec 2025 21:12:05 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=F0=9F=90=9B=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=8E=A9=E5=AE=B6=E5=92=8C=E7=AE=A1=E7=90=86=E5=91=98=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E5=90=8E=E5=88=B7=E6=96=B0=E8=87=AA=E5=8A=A8=E9=80=80?= =?UTF-8?q?=E5=87=BA=E7=9A=84bug=E4=BC=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/AdminAuthRoute.tsx | 3 +- frontend/src/components/AdminLayout.tsx | 5 +- frontend/src/components/PlayerAuthRoute.tsx | 19 +++- frontend/src/components/PlayerLayout.tsx | 82 +++++++++++------ frontend/src/main.tsx | 6 +- frontend/src/pages/admin/AdminDashboard.tsx | 8 +- frontend/src/pages/admin/AdminLogin.tsx | 7 +- frontend/src/pages/player/PlayerDashboard.tsx | 53 ++++++----- frontend/src/pages/player/PlayerLogin.tsx | 6 +- frontend/src/stores/authStore.ts | 90 +++++++++++++++---- frontend/src/theme/index.ts | 2 +- 11 files changed, 195 insertions(+), 86 deletions(-) diff --git a/frontend/src/components/AdminAuthRoute.tsx b/frontend/src/components/AdminAuthRoute.tsx index 21d4b8e..3b3c9ed 100644 --- a/frontend/src/components/AdminAuthRoute.tsx +++ b/frontend/src/components/AdminAuthRoute.tsx @@ -3,8 +3,9 @@ import { useAuthStore } from '../stores/authStore'; const AdminAuthRoute = () => { const isAuthenticated = useAuthStore((state) => state.isAuthenticated); + const authType = useAuthStore((state) => state.authType); - if (!isAuthenticated) { + if (!isAuthenticated || authType !== 'admin') { return ; } diff --git a/frontend/src/components/AdminLayout.tsx b/frontend/src/components/AdminLayout.tsx index 28ae72c..66013fc 100644 --- a/frontend/src/components/AdminLayout.tsx +++ b/frontend/src/components/AdminLayout.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { Layout, Menu, Button, theme } from 'antd'; +import { Layout, Menu, Button, theme, App } from 'antd'; import { MenuFoldOutlined, MenuUnfoldOutlined, @@ -10,7 +10,6 @@ import { import { Outlet, useNavigate, useLocation } from 'react-router-dom'; import { useAuthStore } from '../stores/authStore'; import { adminAuthService } from '../services/adminAuthService'; -import { message } from 'antd'; const { Header, Sider, Content, Footer } = Layout; @@ -23,11 +22,11 @@ const AdminLayout = () => { const location = useLocation(); const adminUser = useAuthStore((state) => state.adminUser); const logout = useAuthStore((state) => state.logout); + const { message } = App.useApp(); const handleLogout = async () => { try { await adminAuthService.logout(); - localStorage.removeItem('adminToken'); logout(); message.success('登出成功'); navigate('/admin/login'); diff --git a/frontend/src/components/PlayerAuthRoute.tsx b/frontend/src/components/PlayerAuthRoute.tsx index 826b99b..807b957 100644 --- a/frontend/src/components/PlayerAuthRoute.tsx +++ b/frontend/src/components/PlayerAuthRoute.tsx @@ -3,8 +3,25 @@ import { useAuthStore } from '../stores/authStore'; const PlayerAuthRoute = () => { const isAuthenticated = useAuthStore((state) => state.isAuthenticated); + const authType = useAuthStore((state) => state.authType); + const setAuth = useAuthStore((state) => state.setAuth); - if (!isAuthenticated) { + // 检查是否有playerToken + const playerToken = localStorage.getItem('playerToken'); + const playerUserStr = localStorage.getItem('playerUser'); + + // 如果有playerToken但authType不是player,说明需要重新加载玩家认证 + if (playerToken && playerUserStr && authType !== 'player') { + try { + const playerUser = JSON.parse(playerUserStr); + setAuth(playerUser, playerToken, 'player'); + } catch (e) { + console.error('解析playerUser失败:', e); + } + } + + // 如果没有playerToken,重定向到登录页 + if (!playerToken) { return ; } diff --git a/frontend/src/components/PlayerLayout.tsx b/frontend/src/components/PlayerLayout.tsx index 3155a3d..a0d6f44 100644 --- a/frontend/src/components/PlayerLayout.tsx +++ b/frontend/src/components/PlayerLayout.tsx @@ -1,4 +1,4 @@ -import { Layout, Menu, Button, Dropdown, theme } from 'antd'; +import { Layout, Menu, Button, Dropdown, theme, App } from 'antd'; import { HomeOutlined, UserOutlined, @@ -6,7 +6,6 @@ import { DownOutlined, } from '@ant-design/icons'; import { Outlet, useNavigate, useLocation } from 'react-router-dom'; -import { message } from 'antd'; import { playerAuthService } from '../services/playerAuthService'; const { Header, Content, Footer } = Layout; @@ -17,11 +16,11 @@ const PlayerLayout = () => { } = theme.useToken(); const navigate = useNavigate(); const location = useLocation(); + const { message } = App.useApp(); const handleLogout = async () => { try { await playerAuthService.logout(); - localStorage.removeItem('playerToken'); message.success('登出成功'); navigate('/player/login'); } catch (error) { @@ -57,40 +56,67 @@ const PlayerLayout = () => { style={{ display: 'flex', alignItems: 'center', - justifyContent: 'space-between', - background: colorBgLayout, - padding: '0 24px', + justifyContent: 'center', + background: '#001529', + padding: '0', + height: 64, }} > + {/* 导航条内容容器 */}
- 梦幻西游玩家服务中心 -
- navigate(key)} - /> - - - + 梦幻西游玩家服务中心 + + + {/* 导航菜单位 */} +
+ navigate(key)} + /> +
+ + {/* 个人中心菜单位 */} + + + + - + + + , ); diff --git a/frontend/src/pages/admin/AdminDashboard.tsx b/frontend/src/pages/admin/AdminDashboard.tsx index 6fe69ca..a354852 100644 --- a/frontend/src/pages/admin/AdminDashboard.tsx +++ b/frontend/src/pages/admin/AdminDashboard.tsx @@ -17,7 +17,7 @@ const AdminDashboard = () => { title="总用户数" value={11280} prefix={} - valueStyle={{ color: '#3f8600' }} + styles={{ content: { color: '#3f8600' } }} /> @@ -27,7 +27,7 @@ const AdminDashboard = () => { title="今日订单" value={93} prefix={} - valueStyle={{ color: '#cf1322' }} + styles={{ content: { color: '#cf1322' } }} /> @@ -38,7 +38,7 @@ const AdminDashboard = () => { value={11280} prefix={} precision={2} - valueStyle={{ color: '#1890ff' }} + styles={{ content: { color: '#1890ff' } }} /> @@ -48,7 +48,7 @@ const AdminDashboard = () => { title="活动参与" value={93} prefix={} - valueStyle={{ color: '#722ed1' }} + styles={{ content: { color: '#722ed1' } }} /> diff --git a/frontend/src/pages/admin/AdminLogin.tsx b/frontend/src/pages/admin/AdminLogin.tsx index 02eae1e..1a8e62b 100644 --- a/frontend/src/pages/admin/AdminLogin.tsx +++ b/frontend/src/pages/admin/AdminLogin.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { Form, Input, Button, Card, message } from 'antd'; +import { Form, Input, Button, Card, App } from 'antd'; import { UserOutlined, LockOutlined } from '@ant-design/icons'; import { useNavigate } from 'react-router-dom'; import { adminAuthService, type LoginRequest } from '../../services/adminAuthService'; @@ -9,6 +9,7 @@ const AdminLogin = () => { const [loading, setLoading] = useState(false); const navigate = useNavigate(); const setAuth = useAuthStore((state) => state.setAuth); + const { message } = App.useApp(); const onFinish = async (values: LoginRequest) => { setLoading(true); @@ -20,9 +21,9 @@ const AdminLogin = () => { username: response.username, role: response.role, }, - response.accessToken + response.accessToken, + 'admin' ); - localStorage.setItem('adminToken', response.accessToken); message.success('登录成功'); navigate('/admin/dashboard'); } catch (error) { diff --git a/frontend/src/pages/player/PlayerDashboard.tsx b/frontend/src/pages/player/PlayerDashboard.tsx index 79a528e..ad1adca 100644 --- a/frontend/src/pages/player/PlayerDashboard.tsx +++ b/frontend/src/pages/player/PlayerDashboard.tsx @@ -1,4 +1,4 @@ -import { Card, Row, Col, Statistic, List, Avatar, Button } from 'antd'; +import { Card, Row, Col, Statistic, Avatar, Button } from 'antd'; import { TrophyOutlined, GiftOutlined, @@ -36,7 +36,7 @@ const PlayerDashboard = () => { value={100} suffix="级" prefix={} - valueStyle={{ color: '#3f8600' }} + styles={{ content: { color: '#3f8600' } }} /> @@ -47,7 +47,7 @@ const PlayerDashboard = () => { value={12800} prefix={} precision={2} - valueStyle={{ color: '#cf1322' }} + styles={{ content: { color: '#cf1322' } }} /> @@ -58,7 +58,7 @@ const PlayerDashboard = () => { value={365} suffix="小时" prefix={} - valueStyle={{ color: '#1890ff' }} + styles={{ content: { color: '#1890ff' } }} /> @@ -68,7 +68,7 @@ const PlayerDashboard = () => { title="成就点数" value={2560} prefix={} - valueStyle={{ color: '#722ed1' }} + styles={{ content: { color: '#722ed1' } }} /> @@ -76,24 +76,33 @@ const PlayerDashboard = () => { - ( - - } />} - title={item.title} - description={ -
-

{item.description}

- {item.time} -
- } +
+ {notices.map((item, index) => ( +
+ } + style={{ marginRight: 12, flexShrink: 0 }} /> - - )} - /> +
+
+ {item.title} +
+
+ {item.description} +
+ {item.time} +
+
+ ))} +
diff --git a/frontend/src/pages/player/PlayerLogin.tsx b/frontend/src/pages/player/PlayerLogin.tsx index 2811bcb..730597e 100644 --- a/frontend/src/pages/player/PlayerLogin.tsx +++ b/frontend/src/pages/player/PlayerLogin.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { Form, Input, Button, Card, message } from 'antd'; +import { Form, Input, Button, Card, App } from 'antd'; import { UserOutlined, LockOutlined } from '@ant-design/icons'; import { useNavigate } from 'react-router-dom'; import { playerAuthService, type LoginRequest } from '../../services/playerAuthService'; @@ -9,17 +9,17 @@ const PlayerLogin = () => { const [loading, setLoading] = useState(false); const navigate = useNavigate(); const setAuth = useAuthStore((state) => state.setAuth); + const { message } = App.useApp(); const onFinish = async (values: LoginRequest) => { setLoading(true); try { const response = await playerAuthService.login(values); - localStorage.setItem('playerToken', response.accessToken); setAuth({ id: response.userId, username: response.username, role: response.role, - }, response.accessToken); + }, response.accessToken, 'player'); message.success('登录成功'); navigate('/player/dashboard'); } catch (error) { diff --git a/frontend/src/stores/authStore.ts b/frontend/src/stores/authStore.ts index cf946ca..11dc3d2 100644 --- a/frontend/src/stores/authStore.ts +++ b/frontend/src/stores/authStore.ts @@ -6,28 +6,82 @@ interface AdminUser { role: string; } +type AuthType = 'admin' | 'player'; + interface AuthState { isAuthenticated: boolean; adminUser: AdminUser | null; token: string | null; - setAuth: (user: AdminUser, token: string) => void; + authType: AuthType | null; + setAuth: (user: AdminUser, token: string, type: AuthType) => void; logout: () => void; } -export const useAuthStore = create((set) => ({ - isAuthenticated: false, - adminUser: null, - token: null, - setAuth: (user, token) => - set({ - isAuthenticated: true, - adminUser: user, - token, - }), - logout: () => - set({ - isAuthenticated: false, - adminUser: null, - token: null, - }), -})); +export const useAuthStore = create((set) => { + // 初始化时从localStorage加载 + const savedAdminToken = localStorage.getItem('adminToken'); + const savedPlayerToken = localStorage.getItem('playerToken'); + const savedAdminUserStr = localStorage.getItem('adminUser'); + const savedPlayerUserStr = localStorage.getItem('playerUser'); + + let savedUser: AdminUser | null = null; + let savedToken: string | null = null; + let savedAuthType: AuthType | null = null; + + // 优先加载管理员认证 + if (savedAdminToken && savedAdminUserStr) { + try { + savedUser = JSON.parse(savedAdminUserStr); + savedToken = savedAdminToken; + savedAuthType = 'admin'; + } catch (e) { + console.error('解析adminUser失败:', e); + } + } + // 如果没有管理员认证,则加载玩家认证 + if (!savedToken && savedPlayerToken && savedPlayerUserStr) { + try { + savedUser = JSON.parse(savedPlayerUserStr); + savedToken = savedPlayerToken; + savedAuthType = 'player'; + } catch (e) { + console.error('解析playerUser失败:', e); + } + } + + return { + isAuthenticated: !!savedToken, + adminUser: savedUser, + token: savedToken, + authType: savedAuthType, + setAuth: (user, token, type) => { + // 根据类型保存到不同的localStorage key + if (type === 'admin') { + localStorage.setItem('adminToken', token); + localStorage.setItem('adminUser', JSON.stringify(user)); + } else { + localStorage.setItem('playerToken', token); + localStorage.setItem('playerUser', JSON.stringify(user)); + } + set({ + isAuthenticated: true, + adminUser: user, + token, + authType: type, + }); + }, + logout: () => { + // 清除所有认证数据 + localStorage.removeItem('adminToken'); + localStorage.removeItem('adminUser'); + localStorage.removeItem('playerToken'); + localStorage.removeItem('playerUser'); + set({ + isAuthenticated: false, + adminUser: null, + token: null, + authType: null, + }); + }, + }; +}); diff --git a/frontend/src/theme/index.ts b/frontend/src/theme/index.ts index 98a21d6..5a5b22d 100644 --- a/frontend/src/theme/index.ts +++ b/frontend/src/theme/index.ts @@ -16,7 +16,7 @@ export const appTheme: ThemeConfig = { fontSize: 14, // 圆角 - borderRadius: 6, + borderRadius: 3, }, components: {