import React, { useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { Card, Button, Typography, Space, message, Tag, Row, Col, Avatar, Descriptions, Progress, Table, Spin, } from 'antd' import { ArrowLeftOutlined, UserOutlined, CheckCircleOutlined, CloseCircleOutlined, } from '@ant-design/icons' import * as questionApi from '../api/question' import type { UserDetailStats } from '../api/question' import styles from './UserDetail.module.less' const { Title, Text } = Typography const UserDetail: React.FC = () => { const navigate = useNavigate() const { id } = useParams<{ id: string }>() const [loading, setLoading] = useState(false) const [userDetail, setUserDetail] = useState(null) // 加载用户详情 const loadUserDetail = async () => { if (!id) return try { setLoading(true) const res = await questionApi.getUserDetailStats(Number(id)) if (res.success && res.data) { setUserDetail(res.data) } } catch (error: any) { console.error('加载用户详情失败:', error) if (error.response?.status === 403) { message.error('无权访问') navigate('/user-management') } else if (error.response?.status === 401) { message.error('请先登录') navigate('/login') } else { message.error('加载用户详情失败') } } finally { setLoading(false) } } useEffect(() => { loadUserDetail() }, [id]) // 格式化日期 const formatDate = (dateStr?: string) => { if (!dateStr) return '-' return new Date(dateStr).toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', }) } // 获取用户类型显示文本 const getUserTypeText = (type?: string) => { if (!type) return '未设置' return type === 'ordinary-person' ? '普通涉密人员' : '保密管理人员' } if (loading) { return (
) } if (!userDetail) { return null } const { user_info, type_stats } = userDetail return (
{/* 返回按钮 */} {/* 用户信息卡片 */}
} className={styles.avatar} />
{user_info.nickname || user_info.username} @{user_info.username} {getUserTypeText(user_info.user_type)}
{/* 统计卡片 */}
总答题数 {user_info.total_answers}
答对数 {user_info.correct_count}
答错数 {user_info.wrong_count}
正确率 = 80 ? '#52c41a' : user_info.accuracy >= 60 ? '#1890ff' : '#faad14', }} > {user_info.accuracy.toFixed(1)}%
{/* 正确率进度条 */}
答题准确率 = 80 ? '#52c41a' : user_info.accuracy >= 60 ? '#1890ff' : '#faad14' } strokeWidth={12} format={(percent) => `${percent?.toFixed(1)}%`} />
{/* 详细信息 */} {user_info.username} {user_info.nickname || '-'} {getUserTypeText(user_info.user_type)} {user_info.total_answers} {user_info.correct_count} {user_info.wrong_count} {formatDate(user_info.created_at)} {formatDate(user_info.last_answer_at)} {/* 题型统计 */} {type_stats.length > 0 && ( {text}, }, { title: '答题数', dataIndex: 'total_answers', key: 'total_answers', align: 'center', sorter: (a, b) => a.total_answers - b.total_answers, }, { title: '答对数', dataIndex: 'correct_count', key: 'correct_count', align: 'center', render: (val: number) => {val}, }, { title: '答错数', key: 'wrong_count', align: 'center', render: (_, record) => ( {record.total_answers - record.correct_count} ), }, { title: '正确率', dataIndex: 'accuracy', key: 'accuracy', align: 'center', sorter: (a, b) => a.accuracy - b.accuracy, render: (val: number) => ( = 80 ? 'success' : val >= 60 ? 'processing' : 'warning'}> {val.toFixed(1)}% ), }, ]} /> )} ) } export default UserDetail