fix: 🐛 修复玩家和管理员登录后刷新自动退出的bug优
This commit is contained in:
@@ -3,8 +3,9 @@ import { useAuthStore } from '../stores/authStore';
|
|||||||
|
|
||||||
const AdminAuthRoute = () => {
|
const AdminAuthRoute = () => {
|
||||||
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
||||||
|
const authType = useAuthStore((state) => state.authType);
|
||||||
|
|
||||||
if (!isAuthenticated) {
|
if (!isAuthenticated || authType !== 'admin') {
|
||||||
return <Navigate to="/admin/login" replace />;
|
return <Navigate to="/admin/login" replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Layout, Menu, Button, theme } from 'antd';
|
import { Layout, Menu, Button, theme, App } from 'antd';
|
||||||
import {
|
import {
|
||||||
MenuFoldOutlined,
|
MenuFoldOutlined,
|
||||||
MenuUnfoldOutlined,
|
MenuUnfoldOutlined,
|
||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
|
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
|
||||||
import { useAuthStore } from '../stores/authStore';
|
import { useAuthStore } from '../stores/authStore';
|
||||||
import { adminAuthService } from '../services/adminAuthService';
|
import { adminAuthService } from '../services/adminAuthService';
|
||||||
import { message } from 'antd';
|
|
||||||
|
|
||||||
const { Header, Sider, Content, Footer } = Layout;
|
const { Header, Sider, Content, Footer } = Layout;
|
||||||
|
|
||||||
@@ -23,11 +22,11 @@ const AdminLayout = () => {
|
|||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const adminUser = useAuthStore((state) => state.adminUser);
|
const adminUser = useAuthStore((state) => state.adminUser);
|
||||||
const logout = useAuthStore((state) => state.logout);
|
const logout = useAuthStore((state) => state.logout);
|
||||||
|
const { message } = App.useApp();
|
||||||
|
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
try {
|
try {
|
||||||
await adminAuthService.logout();
|
await adminAuthService.logout();
|
||||||
localStorage.removeItem('adminToken');
|
|
||||||
logout();
|
logout();
|
||||||
message.success('登出成功');
|
message.success('登出成功');
|
||||||
navigate('/admin/login');
|
navigate('/admin/login');
|
||||||
|
|||||||
@@ -3,8 +3,25 @@ import { useAuthStore } from '../stores/authStore';
|
|||||||
|
|
||||||
const PlayerAuthRoute = () => {
|
const PlayerAuthRoute = () => {
|
||||||
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
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 <Navigate to="/player/login" replace />;
|
return <Navigate to="/player/login" replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Layout, Menu, Button, Dropdown, theme } from 'antd';
|
import { Layout, Menu, Button, Dropdown, theme, App } from 'antd';
|
||||||
import {
|
import {
|
||||||
HomeOutlined,
|
HomeOutlined,
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
DownOutlined,
|
DownOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
|
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
|
||||||
import { message } from 'antd';
|
|
||||||
import { playerAuthService } from '../services/playerAuthService';
|
import { playerAuthService } from '../services/playerAuthService';
|
||||||
|
|
||||||
const { Header, Content, Footer } = Layout;
|
const { Header, Content, Footer } = Layout;
|
||||||
@@ -17,11 +16,11 @@ const PlayerLayout = () => {
|
|||||||
} = theme.useToken();
|
} = theme.useToken();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const { message } = App.useApp();
|
||||||
|
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
try {
|
try {
|
||||||
await playerAuthService.logout();
|
await playerAuthService.logout();
|
||||||
localStorage.removeItem('playerToken');
|
|
||||||
message.success('登出成功');
|
message.success('登出成功');
|
||||||
navigate('/player/login');
|
navigate('/player/login');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -57,40 +56,67 @@ const PlayerLayout = () => {
|
|||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'center',
|
||||||
background: colorBgLayout,
|
background: '#001529',
|
||||||
padding: '0 24px',
|
padding: '0',
|
||||||
|
height: 64,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{/* 导航条内容容器 */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
color: 'white',
|
|
||||||
fontSize: '20px',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
gap: 12,
|
width: '100%',
|
||||||
|
maxWidth: 1200,
|
||||||
|
padding: '0 24px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>梦幻西游玩家服务中心</span>
|
{/* LOGO标题位 */}
|
||||||
</div>
|
<div
|
||||||
<Menu
|
style={{
|
||||||
theme="dark"
|
color: '#ffffff',
|
||||||
mode="horizontal"
|
fontSize: '20px',
|
||||||
selectedKeys={[location.pathname]}
|
fontWeight: 'bold',
|
||||||
items={menuItems}
|
display: 'flex',
|
||||||
style={{ flex: 1, minWidth: 0, justifyContent: 'center' }}
|
alignItems: 'center',
|
||||||
onClick={({ key }) => navigate(key)}
|
gap: 12,
|
||||||
/>
|
flexShrink: 0,
|
||||||
<Dropdown menu={{ items: userMenuItems }} placement="bottomRight">
|
}}
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
style={{ color: 'white' }}
|
|
||||||
icon={<DownOutlined />}
|
|
||||||
>
|
>
|
||||||
个人中心
|
<span>梦幻西游玩家服务中心</span>
|
||||||
</Button>
|
</div>
|
||||||
</Dropdown>
|
|
||||||
|
{/* 导航菜单位 */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
margin: '0 24px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Menu
|
||||||
|
theme="dark"
|
||||||
|
mode="horizontal"
|
||||||
|
selectedKeys={[location.pathname]}
|
||||||
|
items={menuItems}
|
||||||
|
style={{ flex: 1, minWidth: 0, justifyContent: 'center', background: 'transparent' }}
|
||||||
|
onClick={({ key }) => navigate(key)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 个人中心菜单位 */}
|
||||||
|
<Dropdown menu={{ items: userMenuItems }} placement="bottomRight">
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
style={{ color: '#ffffff', flexShrink: 0 }}
|
||||||
|
icon={<DownOutlined />}
|
||||||
|
>
|
||||||
|
个人中心
|
||||||
|
</Button>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
</Header>
|
</Header>
|
||||||
<Content
|
<Content
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { StrictMode } from 'react';
|
import { StrictMode } from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { RouterProvider } from 'react-router-dom';
|
import { RouterProvider } from 'react-router-dom';
|
||||||
import { ConfigProvider, theme } from 'antd';
|
import { ConfigProvider, App, theme } from 'antd';
|
||||||
import zhCN from 'antd/locale/zh_CN';
|
import zhCN from 'antd/locale/zh_CN';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import router from './router';
|
import router from './router';
|
||||||
@@ -16,7 +16,9 @@ createRoot(document.getElementById('root')!).render(
|
|||||||
...appTheme,
|
...appTheme,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RouterProvider router={router} />
|
<App>
|
||||||
|
<RouterProvider router={router} />
|
||||||
|
</App>
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const AdminDashboard = () => {
|
|||||||
title="总用户数"
|
title="总用户数"
|
||||||
value={11280}
|
value={11280}
|
||||||
prefix={<UserOutlined />}
|
prefix={<UserOutlined />}
|
||||||
valueStyle={{ color: '#3f8600' }}
|
styles={{ content: { color: '#3f8600' } }}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -27,7 +27,7 @@ const AdminDashboard = () => {
|
|||||||
title="今日订单"
|
title="今日订单"
|
||||||
value={93}
|
value={93}
|
||||||
prefix={<ShoppingOutlined />}
|
prefix={<ShoppingOutlined />}
|
||||||
valueStyle={{ color: '#cf1322' }}
|
styles={{ content: { color: '#cf1322' } }}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -38,7 +38,7 @@ const AdminDashboard = () => {
|
|||||||
value={11280}
|
value={11280}
|
||||||
prefix={<DollarOutlined />}
|
prefix={<DollarOutlined />}
|
||||||
precision={2}
|
precision={2}
|
||||||
valueStyle={{ color: '#1890ff' }}
|
styles={{ content: { color: '#1890ff' } }}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -48,7 +48,7 @@ const AdminDashboard = () => {
|
|||||||
title="活动参与"
|
title="活动参与"
|
||||||
value={93}
|
value={93}
|
||||||
prefix={<TrophyOutlined />}
|
prefix={<TrophyOutlined />}
|
||||||
valueStyle={{ color: '#722ed1' }}
|
styles={{ content: { color: '#722ed1' } }}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from 'react';
|
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 { UserOutlined, LockOutlined } from '@ant-design/icons';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { adminAuthService, type LoginRequest } from '../../services/adminAuthService';
|
import { adminAuthService, type LoginRequest } from '../../services/adminAuthService';
|
||||||
@@ -9,6 +9,7 @@ const AdminLogin = () => {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const setAuth = useAuthStore((state) => state.setAuth);
|
const setAuth = useAuthStore((state) => state.setAuth);
|
||||||
|
const { message } = App.useApp();
|
||||||
|
|
||||||
const onFinish = async (values: LoginRequest) => {
|
const onFinish = async (values: LoginRequest) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -20,9 +21,9 @@ const AdminLogin = () => {
|
|||||||
username: response.username,
|
username: response.username,
|
||||||
role: response.role,
|
role: response.role,
|
||||||
},
|
},
|
||||||
response.accessToken
|
response.accessToken,
|
||||||
|
'admin'
|
||||||
);
|
);
|
||||||
localStorage.setItem('adminToken', response.accessToken);
|
|
||||||
message.success('登录成功');
|
message.success('登录成功');
|
||||||
navigate('/admin/dashboard');
|
navigate('/admin/dashboard');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Card, Row, Col, Statistic, List, Avatar, Button } from 'antd';
|
import { Card, Row, Col, Statistic, Avatar, Button } from 'antd';
|
||||||
import {
|
import {
|
||||||
TrophyOutlined,
|
TrophyOutlined,
|
||||||
GiftOutlined,
|
GiftOutlined,
|
||||||
@@ -36,7 +36,7 @@ const PlayerDashboard = () => {
|
|||||||
value={100}
|
value={100}
|
||||||
suffix="级"
|
suffix="级"
|
||||||
prefix={<StarOutlined />}
|
prefix={<StarOutlined />}
|
||||||
valueStyle={{ color: '#3f8600' }}
|
styles={{ content: { color: '#3f8600' } }}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -47,7 +47,7 @@ const PlayerDashboard = () => {
|
|||||||
value={12800}
|
value={12800}
|
||||||
prefix={<GiftOutlined />}
|
prefix={<GiftOutlined />}
|
||||||
precision={2}
|
precision={2}
|
||||||
valueStyle={{ color: '#cf1322' }}
|
styles={{ content: { color: '#cf1322' } }}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -58,7 +58,7 @@ const PlayerDashboard = () => {
|
|||||||
value={365}
|
value={365}
|
||||||
suffix="小时"
|
suffix="小时"
|
||||||
prefix={<ClockCircleOutlined />}
|
prefix={<ClockCircleOutlined />}
|
||||||
valueStyle={{ color: '#1890ff' }}
|
styles={{ content: { color: '#1890ff' } }}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -68,7 +68,7 @@ const PlayerDashboard = () => {
|
|||||||
title="成就点数"
|
title="成就点数"
|
||||||
value={2560}
|
value={2560}
|
||||||
prefix={<TrophyOutlined />}
|
prefix={<TrophyOutlined />}
|
||||||
valueStyle={{ color: '#722ed1' }}
|
styles={{ content: { color: '#722ed1' } }}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -76,24 +76,33 @@ const PlayerDashboard = () => {
|
|||||||
<Row gutter={16} style={{ marginTop: 24 }}>
|
<Row gutter={16} style={{ marginTop: 24 }}>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Card title="系统公告">
|
<Card title="系统公告">
|
||||||
<List
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||||
itemLayout="horizontal"
|
{notices.map((item, index) => (
|
||||||
dataSource={notices}
|
<div
|
||||||
renderItem={(item) => (
|
key={index}
|
||||||
<List.Item>
|
style={{
|
||||||
<List.Item.Meta
|
display: 'flex',
|
||||||
avatar={<Avatar icon={<TrophyOutlined />} />}
|
alignItems: 'flex-start',
|
||||||
title={item.title}
|
padding: '12px 0',
|
||||||
description={
|
borderBottom: index !== notices.length - 1 ? '1px solid #f0f0f0' : 'none',
|
||||||
<div>
|
}}
|
||||||
<p>{item.description}</p>
|
>
|
||||||
<small style={{ color: '#999' }}>{item.time}</small>
|
<Avatar
|
||||||
</div>
|
icon={<TrophyOutlined />}
|
||||||
}
|
style={{ marginRight: 12, flexShrink: 0 }}
|
||||||
/>
|
/>
|
||||||
</List.Item>
|
<div style={{ flex: 1 }}>
|
||||||
)}
|
<div style={{ fontSize: 16, fontWeight: 500, marginBottom: 4 }}>
|
||||||
/>
|
{item.title}
|
||||||
|
</div>
|
||||||
|
<div style={{ color: '#666', marginBottom: 4 }}>
|
||||||
|
{item.description}
|
||||||
|
</div>
|
||||||
|
<small style={{ color: '#999' }}>{item.time}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from 'react';
|
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 { UserOutlined, LockOutlined } from '@ant-design/icons';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { playerAuthService, type LoginRequest } from '../../services/playerAuthService';
|
import { playerAuthService, type LoginRequest } from '../../services/playerAuthService';
|
||||||
@@ -9,17 +9,17 @@ const PlayerLogin = () => {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const setAuth = useAuthStore((state) => state.setAuth);
|
const setAuth = useAuthStore((state) => state.setAuth);
|
||||||
|
const { message } = App.useApp();
|
||||||
|
|
||||||
const onFinish = async (values: LoginRequest) => {
|
const onFinish = async (values: LoginRequest) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await playerAuthService.login(values);
|
const response = await playerAuthService.login(values);
|
||||||
localStorage.setItem('playerToken', response.accessToken);
|
|
||||||
setAuth({
|
setAuth({
|
||||||
id: response.userId,
|
id: response.userId,
|
||||||
username: response.username,
|
username: response.username,
|
||||||
role: response.role,
|
role: response.role,
|
||||||
}, response.accessToken);
|
}, response.accessToken, 'player');
|
||||||
message.success('登录成功');
|
message.success('登录成功');
|
||||||
navigate('/player/dashboard');
|
navigate('/player/dashboard');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -6,28 +6,82 @@ interface AdminUser {
|
|||||||
role: string;
|
role: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AuthType = 'admin' | 'player';
|
||||||
|
|
||||||
interface AuthState {
|
interface AuthState {
|
||||||
isAuthenticated: boolean;
|
isAuthenticated: boolean;
|
||||||
adminUser: AdminUser | null;
|
adminUser: AdminUser | null;
|
||||||
token: string | null;
|
token: string | null;
|
||||||
setAuth: (user: AdminUser, token: string) => void;
|
authType: AuthType | null;
|
||||||
|
setAuth: (user: AdminUser, token: string, type: AuthType) => void;
|
||||||
logout: () => void;
|
logout: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAuthStore = create<AuthState>((set) => ({
|
export const useAuthStore = create<AuthState>((set) => {
|
||||||
isAuthenticated: false,
|
// 初始化时从localStorage加载
|
||||||
adminUser: null,
|
const savedAdminToken = localStorage.getItem('adminToken');
|
||||||
token: null,
|
const savedPlayerToken = localStorage.getItem('playerToken');
|
||||||
setAuth: (user, token) =>
|
const savedAdminUserStr = localStorage.getItem('adminUser');
|
||||||
set({
|
const savedPlayerUserStr = localStorage.getItem('playerUser');
|
||||||
isAuthenticated: true,
|
|
||||||
adminUser: user,
|
let savedUser: AdminUser | null = null;
|
||||||
token,
|
let savedToken: string | null = null;
|
||||||
}),
|
let savedAuthType: AuthType | null = null;
|
||||||
logout: () =>
|
|
||||||
set({
|
// 优先加载管理员认证
|
||||||
isAuthenticated: false,
|
if (savedAdminToken && savedAdminUserStr) {
|
||||||
adminUser: null,
|
try {
|
||||||
token: null,
|
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,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const appTheme: ThemeConfig = {
|
|||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
|
|
||||||
// 圆角
|
// 圆角
|
||||||
borderRadius: 6,
|
borderRadius: 3,
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
|
|||||||
Reference in New Issue
Block a user