import React, { useState } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { useQuery } from '@tanstack/react-query'; import { Typography, Tabs, Button, Row, Col, Card, Statistic, Tag, Descriptions, Empty, message, Spin } from 'antd'; import { CalendarOutlined, TrophyOutlined, UserOutlined, FileTextOutlined, CloudUploadOutlined, CopyOutlined, CheckOutlined } from '@ant-design/icons'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import rehypeRaw from 'rehype-raw'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'; import dayjs from 'dayjs'; import { getCompetitionDetail, getProjects, getMyCompetitionEnrollment, enrollCompetition } from '../../api'; import ProjectSubmission from './ProjectSubmission'; import { useAuth } from '../../context/AuthContext'; const { Title, Paragraph } = Typography; const CodeBlock = ({ inline, className, children, ...props }) => { const [copied, setCopied] = useState(false); const match = /language-(\w+)/.exec(className || ''); const codeString = String(children).replace(/\n$/, ''); const handleCopy = () => { navigator.clipboard.writeText(codeString); setCopied(true); message.success('代码已复制'); setTimeout(() => setCopied(false), 2000); }; return !inline && match ? (
{copied ? : } {copied ? '已复制' : '复制'}
{codeString}
) : ( {children} ); }; const CompetitionDetail = () => { const { id } = useParams(); const navigate = useNavigate(); const { user, showLoginModal } = useAuth(); const [activeTab, setActiveTab] = useState('details'); const [submissionModalVisible, setSubmissionModalVisible] = useState(false); const [editingProject, setEditingProject] = useState(null); // Fetch competition details const { data: competition, isLoading: loadingDetail } = useQuery({ queryKey: ['competition', id], queryFn: () => getCompetitionDetail(id) }); // Fetch projects (for leaderboard/display) const { data: projects } = useQuery({ queryKey: ['projects', id], queryFn: () => getProjects({ competition: id, status: 'submitted' }) }); // Check enrollment status const { data: enrollment, refetch: refetchEnrollment } = useQuery({ queryKey: ['enrollment', id], queryFn: () => getMyCompetitionEnrollment(id), enabled: !!user, retry: false }); const handleEnroll = async () => { if (!user) { showLoginModal(); return; } try { await enrollCompetition(id, { role: 'contestant' }); message.success('报名申请已提交,请等待审核'); refetchEnrollment(); } catch (error) { message.error(error.response?.data?.detail || '报名失败'); } }; if (loadingDetail) return ; if (!competition) return ; const isContestant = enrollment?.role === 'contestant' && enrollment?.status === 'approved'; const items = [ { key: 'details', label: '比赛详情', children: (
{competition.status_display} {dayjs(competition.start_time).format('YYYY-MM-DD')} {dayjs(competition.end_time).format('YYYY-MM-DD')} 比赛简介
, h1: (props) =>

, h2: (props) =>

, h3: (props) =>

, a: (props) => , blockquote: (props) =>
, table: (props) => , th: (props) =>
, td: (props) => , }} > {competition.description} 规则说明
, h1: (props) =>

, h2: (props) =>

, h3: (props) =>

, a: (props) => , blockquote: (props) =>
, table: (props) => , th: (props) =>
, td: (props) => , }} > {competition.rule_description} 参赛条件
, h1: (props) =>

, h2: (props) =>

, h3: (props) =>

, a: (props) => , blockquote: (props) =>
, table: (props) => , th: (props) => } actions={[ ]} > } /> ))} {(!projects?.results || projects.results.length === 0) && ( )} ) }, { key: 'leaderboard', label: '排行榜', children: ( {/* Leaderboard Logic: sort by final_score descending */} {projects?.results?.sort((a, b) => b.final_score - a.final_score).map((project, index) => (
#{index + 1}
{project.title}
{project.contestant_info?.nickname}
{project.final_score}
))}
) } ]; return (
{competition.title}
{enrollment ? ( ) : ( )} {isContestant && ( )}
{submissionModalVisible && ( { setSubmissionModalVisible(false); setEditingProject(null); }} onSuccess={() => { setSubmissionModalVisible(false); setEditingProject(null); // Refetch projects }} /> )}
); }; export default CompetitionDetail;
, td: (props) => , }} > {competition.condition_description} ) }, { key: 'projects', label: '参赛项目', children: ( {projects?.results?.map(project => (