import React, { useState, useEffect } from 'react'; import { useSearchParams } from 'react-router'; import { Table, Button, message, Input, QRCode, Modal, Tabs } from 'antd'; import type { GetProp, TableProps } from 'antd'; import dayjs from 'dayjs'; import { useExamCurrentQuestion, useExamRoomMessages, useExamAnswerSubmission, useExamSocketRoom } from './hooks/useSocketClient.ts'; import type { Answer, CumulativeResult } from './types.ts'; type ColumnType = GetProp[number] // 当前答题情况组件 - 添加移动端响应式样式 function CurrentAnswers({ answers, columns }: { answers: Answer[], columns: any[] }) { return (
`${record.userId}-${record.date}`} pagination={false} scroll={{ x: true }} /> ); } // 每日统计组件 - 添加移动端响应式样式 function DailyStatistics({ dailyAnswers, columns }: { dailyAnswers: {[key: string]: Answer[]}, columns: any[] }) { return (
({ date }))} rowKey="date" pagination={false} scroll={{ x: true }} /> ); } // 累计结果组件 - 添加移动端响应式样式 function CumulativeResults({ results, columns }: { results: CumulativeResult[], columns: any[] }) { return (
); } // 二维码组件 - 保持原样 function QRCodeSection({ classroom }: { classroom: string }) { return (
扫码参与训练
); } export default function ExamAdmin() { const [searchParams] = useSearchParams(); const classroom = searchParams.get('classroom'); const { connected } = useExamSocketRoom(classroom); const {currentQuestion} = useExamCurrentQuestion(classroom); const lastMessage = useExamRoomMessages(classroom); const { submitAnswer } = useExamAnswerSubmission(classroom); const [answers, setAnswers] = useState([]); const [dailyAnswers, setDailyAnswers] = useState<{[key: string]: Answer[]}>({}); const [currentDate, setCurrentDate] = useState(''); const [currentPrice, setCurrentPrice] = useState('0'); const [mark, setMark] = useState(''); const [activeTab, setActiveTab] = useState('current'); // 更新答案状态 useEffect(() => { if (lastMessage?.message.type === 'answer') { const answer = lastMessage.message.content; setAnswers(prev => [...prev, answer]); } }, [lastMessage]); // 更新每日答题情况 useEffect(() => { if (currentDate && answers.length > 0) { setDailyAnswers(prev => ({ ...prev, [currentDate]: answers })); } }, [currentDate, answers]); useEffect(() => { if (currentQuestion) { setCurrentDate(currentQuestion.date); setCurrentPrice(String(currentQuestion.price)); } }, [currentQuestion]); // 结算函数 const handleSettlement = async () => { if (!classroom || answers.length === 0) return; try { await submitAnswer(currentDate, 'system', { date: currentDate, price: currentPrice, holdingStock: '0', holdingCash: '1', userId: 'system' }); message.success('结算成功'); } catch (error) { console.error('结算失败:', error); message.error('结算失败'); } }; // 提交函数 const handleSubmit = async () => { if (!classroom || answers.length === 0) return; try { message.success('答案提交成功'); setAnswers([]); } catch (error: any) { console.error('提交答案失败:', error); message.error(error?.message || '提交答案失败'); } }; // 重新开始 const handleRestart = async () => { try { setAnswers([]); setDailyAnswers({}); setCurrentDate(''); setCurrentPrice('0'); message.success('已重新开始'); } catch (error) { console.error('重新开始失败:', error); message.error('重新开始失败'); } }; const columns = [ { title: '昵称', dataIndex: 'userId', key: 'userId', }, { title: '日期', dataIndex: 'date', key: 'date', render: (text: string) => text ? dayjs(text).format('YYYY-MM-DD') : '-', }, { title: '持股', dataIndex: 'holdingStock', key: 'holdingStock', }, { title: '持币', dataIndex: 'holdingCash', key: 'holdingCash', }, { title: '价格', dataIndex: 'price', key: 'price', render: (text: string | undefined) => text ? parseFloat(text).toFixed(2) : '-', }, { title: '收益(元)', dataIndex: 'profitAmount', key: 'profitAmount', render: (text: number | undefined) => text !== undefined ? text.toFixed(2) : '-', }, { title: '盈亏率', dataIndex: 'profitPercent', key: 'profitPercent', render: (text: number | undefined) => text !== undefined ? `${text.toFixed(2)}%` : '-', } ]; const resultColumns: ColumnType[] = [ { title: '昵称', dataIndex: 'userId', key: 'userId', }, { title: '累计盈亏(元)', dataIndex: 'totalProfitAmount', key: 'totalProfitAmount', render: (text: number | undefined) => text !== undefined ? text.toFixed(2) : '-', }, { title: '累计盈亏率', dataIndex: 'totalProfitPercent', key: 'totalProfitPercent', render: (text: number | undefined) => text !== undefined ? `${text.toFixed(2)}%` : '-', }, ]; const dailyAnswersColumns = [ { title: '日期', dataIndex: 'date', key: 'date', render: (text: string) => dayjs(text).format('YYYY-MM-DD'), }, { title: '答题人数', key: 'count', render: (_: any, record: { date: string }) => dailyAnswers[record.date]?.length || 0, }, { title: '持股人数', key: 'holdingStockCount', render: (_: any, record: { date: string }) => dailyAnswers[record.date]?.filter((a: any) => a.holdingStock === '1').length || 0, }, { title: '持币人数', key: 'holdingCashCount', render: (_: any, record: { date: string }) => dailyAnswers[record.date]?.filter((a: any) => a.holdingCash === '1').length || 0, } ]; // 计算累计结果 const calculateCumulativeResults = (dailyAnswers: {[key: string]: Answer[]}): CumulativeResult[] => { const userResults = new Map(); const sortedDates = Object.keys(dailyAnswers).sort((a: string, b: string) => new Date(a).getTime() - new Date(b).getTime() ); sortedDates.forEach(date => { const answers = dailyAnswers[date] || []; answers.forEach((answer: Answer) => { const userId = answer.userId; const profitAmount = answer.profitAmount || 0; const profitPercent = answer.profitPercent || 0; if (!userResults.has(userId)) { userResults.set(userId, { userId, totalProfitAmount: 0, totalProfitPercent: 0 }); } const currentResult = userResults.get(userId)!; currentResult.totalProfitAmount += profitAmount; currentResult.totalProfitPercent += profitPercent; userResults.set(userId, currentResult); }); }); return Array.from(userResults.values()); }; const items = [ { key: 'current', label: '当前答题情况', children: , }, { key: 'daily', label: '每日答题统计', children: , }, { key: 'cumulative', label: '累计结果', children: , }, ]; return (

答题卡管理

教室号: {classroom}
当前日期: {currentDate}
当前价格: {currentPrice}
Socket状态: {connected ? '已连接' : '未连接'}
{/* 主要内容区域 */}
{/* 底部按钮组 - 移动端优化布局 */}
setMark(e.target.value)} placeholder="标记" className="col-span-2" />
{/* 二维码区域 */}
); }