dvc890 commited on
Commit
a39a43f
·
verified ·
1 Parent(s): f48b984

Update pages/GameLucky.tsx

Browse files
Files changed (1) hide show
  1. pages/GameLucky.tsx +49 -22
pages/GameLucky.tsx CHANGED
@@ -1,8 +1,9 @@
1
 
2
  import React, { useState, useEffect } from 'react';
 
3
  import { api } from '../services/api';
4
  import { LuckyDrawConfig, Student, LuckyPrize } from '../types';
5
- import { Gift, Settings, Loader2, Save, Trash2, X, UserCircle, RefreshCcw, HelpCircle } from 'lucide-react';
6
 
7
  const FlipCard = ({ index, prize, onFlip, isRevealed, activeIndex }: { index: number, prize: string, onFlip: (idx: number) => void, isRevealed: boolean, activeIndex: number | null }) => {
8
  const showBack = isRevealed && activeIndex === index;
@@ -35,6 +36,7 @@ export const GameLucky: React.FC = () => {
35
  const [students, setStudents] = useState<Student[]>([]);
36
  const [proxyStudentId, setProxyStudentId] = useState<string>('');
37
  const [isSettingsOpen, setIsSettingsOpen] = useState(false);
 
38
 
39
  const [drawResult, setDrawResult] = useState<{prize: string, rewardType?: string} | null>(null);
40
  const [activeCardIndex, setActiveCardIndex] = useState<number | null>(null);
@@ -133,13 +135,26 @@ export const GameLucky: React.FC = () => {
133
  if (loading) return <div className="h-full flex items-center justify-center"><Loader2 className="animate-spin text-blue-600"/></div>;
134
  if (!luckyConfig) return <div className="h-full flex items-center justify-center text-gray-400">配置加载失败</div>;
135
 
136
- return (
137
- <div className="flex-1 flex flex-col md:flex-row h-full overflow-hidden bg-gradient-to-br from-red-50 to-orange-50 relative">
138
- <div className="flex-1 overflow-y-auto p-4 md:p-8 custom-scrollbar">
139
- <div className={`grid gap-4 md:gap-6 w-full max-w-5xl mx-auto ${
140
- (luckyConfig.cardCount || 9) <= 4 ? 'grid-cols-2 md:grid-cols-3' :
141
- (luckyConfig.cardCount || 9) <= 6 ? 'grid-cols-2 md:grid-cols-3 lg:grid-cols-4' :
142
- 'grid-cols-3 md:grid-cols-4 lg:grid-cols-5'
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  }`}>
144
  {Array.from({ length: luckyConfig.cardCount || 9 }).map((_, i) => (
145
  <FlipCard
@@ -154,31 +169,37 @@ export const GameLucky: React.FC = () => {
154
  </div>
155
  </div>
156
 
157
- <div className="w-full md:w-80 bg-white border-l border-gray-200 shadow-xl flex flex-col shrink-0 z-20">
158
- <div className="p-6 border-b border-gray-100 bg-red-600 text-white relative overflow-hidden">
159
- <div className="relative z-10">
160
- <h3 className="text-xl font-bold flex items-center"><Gift className="mr-2"/> 幸运抽奖</h3>
161
- <p className="text-red-100 text-xs mt-1">班级专属奖池 | {currentClassName}</p>
 
 
 
162
  </div>
163
  <div className="absolute -right-4 -bottom-4 text-red-700 opacity-30"><Gift size={80}/></div>
164
  </div>
165
 
166
- <div className="p-6 flex-1 overflow-y-auto space-y-6">
167
- <div className="bg-gradient-to-r from-amber-50 to-orange-50 p-5 rounded-xl border border-orange-100 text-center">
168
- <p className="text-xs font-bold text-amber-700 uppercase tracking-wider mb-2">当前抽奖人</p>
169
- <div className="text-lg font-bold text-gray-800 truncate mb-4">
170
- {isTeacher && proxyStudentId ? (studentInfo?.name || '加载中...') : (isTeacher ? '未选择' : '我')}
 
 
171
  </div>
172
- <div className="border-t border-orange-200 pt-4">
 
173
  <p className="text-xs font-bold text-amber-700 uppercase tracking-wider mb-1">剩余次数</p>
174
- <p className={`text-4xl font-black ${studentInfo?.drawAttempts ? 'text-red-600' : 'text-gray-400'}`}>
175
  {studentInfo?.drawAttempts || 0}
176
  </p>
177
  </div>
178
  </div>
179
 
180
  {isTeacher && (
181
- <div className="space-y-4">
182
  <div>
183
  <label className="text-xs font-bold text-gray-500 uppercase block mb-1">选择代抽学生</label>
184
  <div className="relative">
@@ -204,8 +225,9 @@ export const GameLucky: React.FC = () => {
204
  </div>
205
  </div>
206
 
 
207
  {isSettingsOpen && (
208
- <div className="fixed inset-0 bg-black/60 z-[100] flex items-center justify-center p-4 backdrop-blur-sm">
209
  <div className="bg-white rounded-2xl w-full max-w-4xl h-[90vh] flex flex-col shadow-2xl animate-in zoom-in-95">
210
  <div className="p-6 border-b border-gray-100 flex justify-between items-center">
211
  <h3 className="text-xl font-bold text-gray-800">红包奖池配置 - {currentClassName}</h3>
@@ -299,4 +321,9 @@ export const GameLucky: React.FC = () => {
299
  )}
300
  </div>
301
  );
 
 
 
 
 
302
  };
 
1
 
2
  import React, { useState, useEffect } from 'react';
3
+ import { createPortal } from 'react-dom';
4
  import { api } from '../services/api';
5
  import { LuckyDrawConfig, Student, LuckyPrize } from '../types';
6
+ import { Gift, Settings, Loader2, Save, Trash2, X, UserCircle, RefreshCcw, HelpCircle, Maximize, Minimize } from 'lucide-react';
7
 
8
  const FlipCard = ({ index, prize, onFlip, isRevealed, activeIndex }: { index: number, prize: string, onFlip: (idx: number) => void, isRevealed: boolean, activeIndex: number | null }) => {
9
  const showBack = isRevealed && activeIndex === index;
 
36
  const [students, setStudents] = useState<Student[]>([]);
37
  const [proxyStudentId, setProxyStudentId] = useState<string>('');
38
  const [isSettingsOpen, setIsSettingsOpen] = useState(false);
39
+ const [isFullscreen, setIsFullscreen] = useState(false);
40
 
41
  const [drawResult, setDrawResult] = useState<{prize: string, rewardType?: string} | null>(null);
42
  const [activeCardIndex, setActiveCardIndex] = useState<number | null>(null);
 
135
  if (loading) return <div className="h-full flex items-center justify-center"><Loader2 className="animate-spin text-blue-600"/></div>;
136
  if (!luckyConfig) return <div className="h-full flex items-center justify-center text-gray-400">配置加载失败</div>;
137
 
138
+ const GameContent = (
139
+ <div className={`${isFullscreen ? 'fixed inset-0 z-[9999]' : 'h-full relative'} flex flex-col md:flex-row bg-gradient-to-br from-red-50 to-orange-50 overflow-hidden`}>
140
+ {/* Floating Fullscreen Button */}
141
+ <button
142
+ onClick={() => setIsFullscreen(!isFullscreen)}
143
+ className="absolute top-4 right-4 z-50 p-2 rounded-full bg-white/50 hover:bg-white backdrop-blur shadow-sm border transition-colors md:top-4 md:left-4 md:right-auto"
144
+ title={isFullscreen ? "退出全屏" : "全屏"}
145
+ >
146
+ {isFullscreen ? <Minimize size={20} className="text-gray-700"/> : <Maximize size={20} className="text-gray-700"/>}
147
+ </button>
148
+
149
+ {/* Left: Red Packet Grid */}
150
+ <div className="flex-1 overflow-y-auto p-4 md:p-8 custom-scrollbar order-1 md:order-1">
151
+ <div className={`grid gap-3 md:gap-6 w-full max-w-5xl mx-auto transition-all ${
152
+ // Mobile Grids (2 cols usually)
153
+ 'grid-cols-2 ' +
154
+ // Desktop Grids
155
+ ((luckyConfig.cardCount || 9) <= 4 ? 'md:grid-cols-3' :
156
+ (luckyConfig.cardCount || 9) <= 6 ? 'md:grid-cols-3 lg:grid-cols-4' :
157
+ 'md:grid-cols-4 lg:grid-cols-5')
158
  }`}>
159
  {Array.from({ length: luckyConfig.cardCount || 9 }).map((_, i) => (
160
  <FlipCard
 
169
  </div>
170
  </div>
171
 
172
+ {/* Right/Bottom: Controls */}
173
+ <div className="w-full md:w-80 bg-white border-t md:border-t-0 md:border-l border-gray-200 shadow-xl flex flex-col shrink-0 z-20 order-2 md:order-2">
174
+ <div className="p-4 md:p-6 border-b border-gray-100 bg-red-600 text-white relative overflow-hidden shrink-0">
175
+ <div className="relative z-10 flex justify-between items-center md:block">
176
+ <div>
177
+ <h3 className="text-lg md:text-xl font-bold flex items-center"><Gift className="mr-2"/> 幸运抽奖</h3>
178
+ <p className="text-red-100 text-xs mt-1">班级专属奖池 | {currentClassName}</p>
179
+ </div>
180
  </div>
181
  <div className="absolute -right-4 -bottom-4 text-red-700 opacity-30"><Gift size={80}/></div>
182
  </div>
183
 
184
+ <div className="p-4 md:p-6 flex-1 overflow-y-auto space-y-4 md:space-y-6">
185
+ <div className="bg-gradient-to-r from-amber-50 to-orange-50 p-4 rounded-xl border border-orange-100 text-center flex md:block justify-between items-center">
186
+ <div className="text-left md:text-center">
187
+ <p className="text-xs font-bold text-amber-700 uppercase tracking-wider mb-1 md:mb-2">当前抽奖人</p>
188
+ <div className="text-base md:text-lg font-bold text-gray-800 truncate">
189
+ {isTeacher && proxyStudentId ? (studentInfo?.name || '加载中...') : (isTeacher ? '未选择' : '我')}
190
+ </div>
191
  </div>
192
+ <div className="h-8 w-px bg-orange-200 md:hidden"></div>
193
+ <div className="text-right md:text-center md:border-t md:border-orange-200 md:pt-4">
194
  <p className="text-xs font-bold text-amber-700 uppercase tracking-wider mb-1">剩余次数</p>
195
+ <p className={`text-2xl md:text-4xl font-black ${studentInfo?.drawAttempts ? 'text-red-600' : 'text-gray-400'}`}>
196
  {studentInfo?.drawAttempts || 0}
197
  </p>
198
  </div>
199
  </div>
200
 
201
  {isTeacher && (
202
+ <div className="space-y-3 md:space-y-4">
203
  <div>
204
  <label className="text-xs font-bold text-gray-500 uppercase block mb-1">选择代抽学生</label>
205
  <div className="relative">
 
225
  </div>
226
  </div>
227
 
228
+ {/* Settings Modal */}
229
  {isSettingsOpen && (
230
+ <div className="fixed inset-0 bg-black/60 z-[1000] flex items-center justify-center p-4 backdrop-blur-sm">
231
  <div className="bg-white rounded-2xl w-full max-w-4xl h-[90vh] flex flex-col shadow-2xl animate-in zoom-in-95">
232
  <div className="p-6 border-b border-gray-100 flex justify-between items-center">
233
  <h3 className="text-xl font-bold text-gray-800">红包奖池配置 - {currentClassName}</h3>
 
321
  )}
322
  </div>
323
  );
324
+
325
+ if (isFullscreen) {
326
+ return createPortal(GameContent, document.body);
327
+ }
328
+ return GameContent;
329
  };