import React,{ useState, useCallback, useEffect } from 'react'; import { useQuery } from '@tanstack/react-query'; import { useSearchParams, useNavigate } from "react-router"; import dayjs from 'dayjs'; import { message } from 'antd'; import { useSocketClient } from './hooks/useSocketClient.ts'; import { ClassroomDataAPI } from '../../api/classroom_data.ts'; import { ClassroomStatus } from '../../../share/types_stock.ts'; import type { QuizState } from './types.ts'; import type { AnswerRecord, Answer } from './types.ts'; import { useAuth } from "../../hooks.tsx"; // 答题卡页面 export default function ExamCard() { const { user } = useAuth(); const navigate = useNavigate(); const [searchParams] = useSearchParams(); const classroom = searchParams.get('classroom'); const { socketRoom: { joinRoom, leaveRoom, client }, answerManagement, // lastMessage, } = useSocketClient(classroom as string); const [currentDate, setCurrentDate] = useState(''); const [currentPrice, setCurrentPrice] = useState('0'); const [holdingStock, setHoldingStock] = useState('0'); const [holdingCash, setHoldingCash] = useState('0'); const [isStarted, setIsStarted] = useState(false); const [answerRecords, setAnswerRecords] = useState([]); const { data: classroomData, isLoading } = useQuery({ queryKey: ['classroom', classroom], queryFn: async () => { if (!classroom) return null; const response = await ClassroomDataAPI.getClassroomDatas({ classroom_no: classroom }); if (!response.data?.length) { message.error('获取教室数据失败'); return null; } return response.data[0] || null; }, enabled: !!classroom }); // 初始化答题卡数据 const initExamCard = useCallback(async () => { if (!classroom || !user?.username) { // globalThis.location.href = '/exam'; navigate('/mobile') return; } if (classroomData && classroomData.status !== ClassroomStatus.OPEN) { message.error('该教室已关闭'); // globalThis.location.href = '/exam'; navigate('/mobile') return; } // 获取当前问题并更新状态 const question = await answerManagement.getCurrentQuestion(classroom); setCurrentDate(question.date); setCurrentPrice(String(question.price)); setIsStarted(true); // 获取用户回答记录 if (user?.id) { try { const answers = await answerManagement.getUserAnswers(classroom, String(user.id)); if (answers && answers.length > 0) { const lastAnswer = answers[answers.length - 1]; setHoldingStock(lastAnswer.holdingStock); setHoldingCash(lastAnswer.holdingCash); const records = answers.map((answer: Answer, index: number): AnswerRecord => ({ date: answer.date, price: String(answer.price || '0'), holdingStock: answer.holdingStock, holdingCash: answer.holdingCash, profitAmount: answer.profitAmount || 0, profitPercent: answer.profitPercent || 0, index: index + 1 })); setAnswerRecords(records); } } catch (error) { console.error('获取用户回答记录失败:', error); } } }, [classroom, user, classroomData, answerManagement]); // 加入/离开房间 useEffect(() => { if (!classroom) return; joinRoom(classroom); initExamCard(); return () => { leaveRoom(classroom); }; }, [classroom, joinRoom, leaveRoom]); // // 处理房间消息 // useEffect(() => { // if (!lastMessage?.message) return; // const { type } = lastMessage.message; // // 只处理重开消息的UI重置 // if (type === 'restart') { // setCurrentDate(''); // setCurrentPrice('0'); // setHoldingStock('0'); // setHoldingCash('0'); // setIsStarted(false); // setAnswerRecords([]); // } // }, [lastMessage]); // 处理选择A(持股) const handleChooseA = useCallback(async () => { setHoldingStock('1'); setHoldingCash('0'); if (classroom && user?.username && currentDate) { const answer = { date: currentDate, holdingStock: '1', holdingCash: '0', userId: String(user.id), price: currentPrice }; try { await answerManagement.storeAnswer( classroom as string, currentDate, String(user.id), answer, (answers) => { const records = answers.map((answer: Answer, index: number): AnswerRecord => ({ date: answer.date, price: String(answer.price || '0'), holdingStock: answer.holdingStock, holdingCash: answer.holdingCash, profitAmount: answer.profitAmount || 0, profitPercent: answer.profitPercent || 0, index: index + 1 })); setAnswerRecords(records); } ); } catch (error) { message.error('提交答案失败'); } } }, [classroom, user, currentDate, currentPrice, answerManagement]); const handleChooseB = useCallback(async () => { setHoldingStock('0'); setHoldingCash('1'); if (classroom && user?.username && currentDate) { const answer = { date: currentDate, holdingStock: '0', holdingCash: '1', userId: String(user.id), price: currentPrice }; try { await answerManagement.storeAnswer( classroom as string, currentDate, String(user.id), answer, (answers) => { const records = answers.map((answer: Answer, index: number): AnswerRecord => ({ date: answer.date, price: String(answer.price || '0'), holdingStock: answer.holdingStock, holdingCash: answer.holdingCash, profitAmount: answer.profitAmount || 0, profitPercent: answer.profitPercent || 0, index: index + 1 })); setAnswerRecords(records); } ); } catch (error) { message.error('提交答案失败'); } } }, [classroom, user, currentDate, currentPrice, answerManagement]); // 监听当前问题变化 useEffect(() => { if (!client ) return; const handleQuestionUpdate = (question:QuizState ) => { setCurrentDate(question.date); setCurrentPrice(String(question.price)); setIsStarted(true); }; client.on('exam:question', handleQuestionUpdate); return () => { client.off('exam:question', handleQuestionUpdate); }; }, [client]); // 监听重开 useEffect(() => { if (!client ) return; const handleCleaned = () => { setCurrentDate(''); setCurrentPrice('0'); setHoldingStock('0'); setHoldingCash('0'); setIsStarted(false); setAnswerRecords([]); }; client.on('exam:cleaned', handleCleaned); return () => { client.off('exam:cleaned', handleCleaned); }; }, [client]); if (isLoading || !classroomData) { return
加载中...
; } return (
{/* 选择区域 */}

持股选A, 持币选B

{isStarted ? ( <> 日期: {currentDate} 价格: {currentPrice} ) : (
等待训练开始...
训练日期: {dayjs(classroomData.training_date).format('YYYY-MM-DD')}
)}
{/* 选择按钮 */}
{isStarted ? '开始' : '等待'}
{/* 信息显示 */}
昵称: {user?.username || '未知用户'}
代码: {classroomData.code}
{/* 表格头部 */}
训练日期
持股
持币
价格
收益(元)
盈亏率
{/* 表格内容 */}
{[...answerRecords].reverse().map((record: AnswerRecord) => (
{record.index}
{dayjs(record.date).format('YYYY-MM-DD')}
{record.holdingStock}
{record.holdingCash}
{record.price}
= 0 ? 'text-red-500' : 'text-green-500'}> {record.profitAmount.toFixed(2)}
= 0 ? 'text-red-500' : 'text-green-500'}> {record.profitPercent.toFixed(2)}%
{record.index}
))}
); }