blob: 0ecaaf454448dce302cc59304b78e457a8c3c98c [file] [log] [blame]
Raverafc93da2025-06-15 18:12:49 +08001import React, { useState, useEffect } from 'react';
2import { Card, Button, Descriptions, Avatar, Tag, Space, message } from 'antd';
3import { UserOutlined, LogoutOutlined, ReloadOutlined } from '@ant-design/icons';
4import { getUserInfo, getAuthToken, isLoggedIn, saveAuthInfo, createAuthenticatedRequest } from '../../utils/auth';
5import LogoutButton from '../../components/LogoutButton/LogoutButton';
6import './TestDashboard.css';
7
8const TestDashboard = () => {
9 const [userInfo, setUserInfo] = useState(null);
10 const [token, setToken] = useState(null);
11 const [loading, setLoading] = useState(false);
12 const [jwtTestLoading, setJwtTestLoading] = useState(false);
13
14 useEffect(() => {
15 // 检查用户是否已登录
16 if (!isLoggedIn()) {
17 window.location.href = '/';
18 return;
19 }
20
21 // 获取用户信息和token
22 const authToken = getAuthToken();
23 const authUserInfo = getUserInfo();
24
25 setToken(authToken);
26 setUserInfo(authUserInfo);
27 }, []);
28
29 const handleRefreshProfile = async () => {
30 if (!token) {
31 message.error('未找到认证token');
32 return;
33 }
34
35 setLoading(true);
36 try {
37 const response = await fetch('http://10.126.59.25:8082/profile', createAuthenticatedRequest());
38
39 const result = await response.json();
40
41 if (result.success) {
42 setUserInfo(result.user);
43 // 更新存储的用户信息,保持原有的存储方式(localStorage或sessionStorage)
44 const isRemembered = localStorage.getItem('authToken');
45 saveAuthInfo(token, result.user, !!isRemembered);
46 message.success('用户信息刷新成功');
47 } else {
48 message.error(`获取用户信息失败: ${result.message}`);
49 }
50 } catch (error) {
51 console.error('刷新用户信息失败:', error);
52 message.error('网络连接失败');
53 } finally {
54 setLoading(false);
55 }
56 };
57
58 const handleLogout = async () => {
59 if (!token) {
60 // 清除存储并跳转
61 localStorage.removeItem('authToken');
62 localStorage.removeItem('userInfo');
63 sessionStorage.removeItem('authToken');
64 sessionStorage.removeItem('userInfo');
65 window.location.href = '/';
66 return;
67 }
68
69 try {
70 const response = await fetch('http://10.126.59.25:8082/logout', {
71 method: 'POST',
72 headers: {
73 'Authorization': `Bearer ${token}`,
74 'Content-Type': 'application/json',
75 }
76 });
77
78 const result = await response.json();
79
80 if (result.success) {
81 message.success('退出登录成功');
82 } else {
83 message.warning(`退出登录: ${result.message}`);
84 }
85 } catch (error) {
86 console.error('退出登录请求失败:', error);
87 message.warning('网络请求失败,但将清除本地数据');
88 } finally {
89 // 无论请求成功与否,都清除本地存储并跳转
90 localStorage.removeItem('authToken');
91 localStorage.removeItem('userInfo');
92 sessionStorage.removeItem('authToken');
93 sessionStorage.removeItem('userInfo');
94 window.location.href = '/';
95 }
96 };
97
98 const handleTestJWT = async () => {
99 if (!token) {
100 message.error('未找到认证token');
101 return;
102 }
103
104 setJwtTestLoading(true);
105 try {
106 const response = await fetch('http://10.126.59.25:8082/test-jwt', {
107 method: 'POST',
108 headers: {
109 'Authorization': `Bearer ${token}`,
110 'Content-Type': 'application/json',
111 },
112 body: JSON.stringify({
113 token: token, // 可选:在请求体中也发送token进行额外验证
114 test_purpose: 'frontend_jwt_test'
115 })
116 });
117
118 const result = await response.json();
119
120 if (result.success) {
121 message.success(`JWT令牌验证成功!用户: ${result.user.username}`);
122 console.log('JWT验证详细结果:', result);
123
124 // 如果有额外的token验证结果,也显示出来
125 if (result.additional_token_verification) {
126 console.log('额外token验证:', result.additional_token_verification);
127 }
128 } else {
129 message.error(`JWT令牌验证失败: ${result.message}`);
130 }
131 } catch (error) {
132 console.error('JWT令牌验证失败:', error);
133 message.error('网络连接失败');
134 } finally {
135 setJwtTestLoading(false);
136 }
137 };
138
139 const getRoleColor = (role) => {
140 switch (role) {
141 case 'superadmin':
142 return 'red';
143 case 'admin':
144 return 'orange';
145 case 'user':
146 default:
147 return 'blue';
148 }
149 };
150
151 const getStatusColor = (status) => {
152 switch (status) {
153 case 'active':
154 return 'green';
155 case 'banned':
156 return 'red';
157 case 'muted':
158 return 'orange';
159 default:
160 return 'default';
161 }
162 };
163
164 if (!userInfo) {
165 return (
166 <div className="test-dashboard">
167 <div className="loading-container">
168 <div className="spinner"></div>
169 <p>加载用户信息中...</p>
170 </div>
171 </div>
172 );
173 }
174
175 return (
176 <div className="test-dashboard">
177 <div className="dashboard-header">
178 <h1>测试仪表板</h1>
179 <p>登录成功!以下是从后端返回的用户信息:</p>
180 </div>
181
182 <div className="dashboard-content">
183 <Card
184 title={
185 <Space>
186 <Avatar size={40} icon={<UserOutlined />} src={userInfo.avatar} />
187 <span>用户信息</span>
188 </Space>
189 }
190 extra={
191 <Space>
192 <Button
193 type="primary"
194 icon={<ReloadOutlined />}
195 loading={loading}
196 onClick={handleRefreshProfile}
197 >
198 刷新信息
199 </Button>
200 <LogoutButton onLogout={() => window.location.href = '/'} />
201 </Space>
202 }
203 className="user-info-card"
204 >
205 <Descriptions column={2} bordered>
206 <Descriptions.Item label="用户ID">{userInfo.id}</Descriptions.Item>
207 <Descriptions.Item label="用户名">{userInfo.username}</Descriptions.Item>
208 <Descriptions.Item label="邮箱">{userInfo.email}</Descriptions.Item>
209 <Descriptions.Item label="角色">
210 <Tag color={getRoleColor(userInfo.role)}>
211 {userInfo.role}
212 </Tag>
213 </Descriptions.Item>
214 <Descriptions.Item label="账号状态">
215 <Tag color={getStatusColor(userInfo.status)}>
216 {userInfo.status}
217 </Tag>
218 </Descriptions.Item>
219 <Descriptions.Item label="个人简介" span={2}>
220 {userInfo.bio || '暂无个人简介'}
221 </Descriptions.Item>
222 <Descriptions.Item label="创建时间">
223 {userInfo.created_at ? new Date(userInfo.created_at).toLocaleString() : '未知'}
224 </Descriptions.Item>
225 <Descriptions.Item label="更新时间">
226 {userInfo.updated_at ? new Date(userInfo.updated_at).toLocaleString() : '未知'}
227 </Descriptions.Item>
228 </Descriptions>
229 </Card>
230
231 <Card title="登录状态信息" className="login-status-card">
232 <div className="login-status-display">
233 <Descriptions column={1} bordered>
234 <Descriptions.Item label="登录方式">
235 <Tag color={localStorage.getItem('authToken') ? 'green' : 'blue'}>
236 {localStorage.getItem('authToken') ? '记住我登录 (持久化)' : '普通登录 (会话)'}
237 </Tag>
238 </Descriptions.Item>
239 <Descriptions.Item label="Token存储位置">
240 {localStorage.getItem('authToken') ? 'localStorage (浏览器关闭后仍保持登录)' : 'sessionStorage (浏览器关闭后需重新登录)'}
241 </Descriptions.Item>
242 <Descriptions.Item label="记住的登录信息">
243 {localStorage.getItem('rememberMe') === 'true' ?
244 `已保存邮箱: ${localStorage.getItem('rememberedEmail') || '无'}` :
245 '未保存登录信息'
246 }
247 </Descriptions.Item>
248 </Descriptions>
249 </div>
250 </Card>
251
252 <Card title="Token信息" className="token-info-card">
253 <div className="token-display">
254 <p><strong>认证Token:</strong></p>
255 <div className="token-text">
256 {token ? `${token.substring(0, 50)}...` : '未找到token'}
257 </div>
258 <p className="token-note">
259 * Token已被安全截断显示,完整token存储在浏览器存储中
260 </p>
261 </div>
262 </Card>
263
264 <Card title="API测试" className="api-test-card">
265 <Space direction="vertical" style={{ width: '100%' }}>
266 <p>您可以使用以下按钮测试不同的API接口:</p>
267 <Space wrap>
268 <Button onClick={handleRefreshProfile} loading={loading}>
269 测试 GET /profile
270 </Button>
271 <Button onClick={handleLogout}>
272 测试 POST /logout
273 </Button>
274 <Button
275 onClick={handleTestJWT}
276 loading={jwtTestLoading}
277 type="primary"
278 >
279 测试 POST /test-jwt
280 </Button>
281 <Button
282 type="dashed"
283 onClick={() => window.open('http://10.126.59.25:8082/health', '_blank')}
284 >
285 测试 GET /health
286 </Button>
287 </Space>
288 </Space>
289 </Card>
290 </div>
291 </div>
292 );
293};
294
295export default TestDashboard;