ExamIndex.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import React, { useState, useCallback, useEffect } from 'react';
  2. import { useQuery } from '@tanstack/react-query';
  3. import { useNavigate, useSearchParams } from "react-router";
  4. import dayjs from 'dayjs';
  5. import { message } from 'antd';
  6. import { Skeleton } from 'antd';
  7. // 昵称输入页面
  8. function ExamIndex() {
  9. const [nickname, setNickname] = useState('');
  10. const navigate = useNavigate();
  11. const [searchParams] = useSearchParams();
  12. const classroom = searchParams.get('classroom');
  13. const { data: classroomData, isLoading } = useQuery({
  14. queryKey: ['classroom', classroom],
  15. queryFn: async () => {
  16. if (!classroom) return null;
  17. const response = await fetch(`/api/v1/classroom?classroom_no=${classroom}`);
  18. const data = await response.json();
  19. if (!data.success) {
  20. message.error(data.message || '获取教室数据失败');
  21. return null;
  22. }
  23. return data.data?.[0] || null;
  24. },
  25. enabled: !!classroom
  26. });
  27. useEffect(() => {
  28. if (classroomData && classroomData.status !== "1") {
  29. message.error('该教室已关闭');
  30. }
  31. }, [classroomData]);
  32. const handleJoinTraining = useCallback(() => {
  33. if (!nickname.trim()) {
  34. message.error('请输入昵称');
  35. return;
  36. }
  37. if (!classroom) {
  38. message.error('教室号不能为空');
  39. return;
  40. }
  41. if (!classroomData) {
  42. message.error('教室不存在');
  43. return;
  44. }
  45. if (classroomData.status !== "1") {
  46. message.error('该教室已关闭');
  47. return;
  48. }
  49. // 将昵称和教室号作为参数传递到答题页
  50. navigate(`/exam/card?nickname=${encodeURIComponent(nickname)}&classroom=${classroom}`);
  51. }, [nickname, navigate, classroom, classroomData]);
  52. if (isLoading) {
  53. return (
  54. <div className="flex flex-col items-center justify-center min-h-screen p-4">
  55. <Skeleton active paragraph={{ rows: 4 }} />
  56. </div>
  57. );
  58. }
  59. return (
  60. <div className="flex flex-col items-center justify-center min-h-screen bg-gray-100 p-4">
  61. <div className="w-full max-w-md space-y-8">
  62. <div className="text-center">
  63. <h2 className="text-2xl font-bold text-gray-900">股票训练答题卡系统</h2>
  64. <p className="mt-2 text-gray-600">
  65. {classroom ? `教室号: ${classroom}` : '请输入昵称开始答题'}
  66. </p>
  67. {classroomData && (
  68. <div className="mt-2 text-sm text-gray-500">
  69. <p>训练日期: {dayjs(classroomData.training_date).format('YYYY-MM-DD')}</p>
  70. <p>代码: {classroomData.code}</p>
  71. </div>
  72. )}
  73. </div>
  74. <div className="mt-8">
  75. <input
  76. type="text"
  77. value={nickname}
  78. onChange={(e) => setNickname(e.target.value)}
  79. placeholder="请输入昵称"
  80. className="w-full px-4 py-3 text-base border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
  81. onKeyPress={(e) => e.key === 'Enter' && handleJoinTraining()}
  82. />
  83. </div>
  84. <button
  85. onClick={handleJoinTraining}
  86. disabled={!classroomData || classroomData.status !== "1"}
  87. className={`w-full px-8 py-3 text-base font-medium text-white rounded-lg focus:outline-none focus:ring-2 focus:ring-offset-2 transition-colors ${
  88. !classroomData || classroomData.status !== "1"
  89. ? 'bg-gray-400 cursor-not-allowed'
  90. : 'bg-blue-500 hover:bg-blue-600 focus:ring-blue-500'
  91. }`}
  92. >
  93. 开始答题
  94. </button>
  95. </div>
  96. </div>
  97. );
  98. }
  99. export default ExamIndex;