Spaces:
Running
Running
Update pages/GameRandom.tsx
Browse files- pages/GameRandom.tsx +20 -12
pages/GameRandom.tsx
CHANGED
|
@@ -32,7 +32,7 @@ export const GameRandom: React.FC = () => {
|
|
| 32 |
const [rewardType, setRewardType] = useState<'DRAW_COUNT' | 'ITEM' | 'ACHIEVEMENT'>('DRAW_COUNT');
|
| 33 |
const [rewardId, setRewardId] = useState(''); // Achievement ID or Item Name
|
| 34 |
const [rewardCount, setRewardCount] = useState(1);
|
| 35 |
-
|
| 36 |
|
| 37 |
const timerRef = useRef<any>(null);
|
| 38 |
const speedRef = useRef<number>(50);
|
|
@@ -48,7 +48,7 @@ export const GameRandom: React.FC = () => {
|
|
| 48 |
// Clear picked IDs when mode changes to avoid ID confusion
|
| 49 |
useEffect(() => {
|
| 50 |
setPickedIds(new Set());
|
| 51 |
-
}, [mode]);
|
| 52 |
|
| 53 |
const loadData = async () => {
|
| 54 |
if (!homeroomClass) return setLoading(false);
|
|
@@ -92,7 +92,7 @@ export const GameRandom: React.FC = () => {
|
|
| 92 |
baseList = baseList.filter(s => !excludedStudentIds.has(s._id || String(s.id)));
|
| 93 |
}
|
| 94 |
|
| 95 |
-
//
|
| 96 |
if (avoidRepeat) {
|
| 97 |
baseList = baseList.filter(item => !pickedIds.has(mode === 'TEAM' ? item.id : (item._id || String(item.id))));
|
| 98 |
}
|
|
@@ -104,7 +104,11 @@ export const GameRandom: React.FC = () => {
|
|
| 104 |
const list = getTargetList();
|
| 105 |
if (list.length === 0) {
|
| 106 |
if (avoidRepeat && pickedIds.size > 0) {
|
| 107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
}
|
| 109 |
return alert('当前范围内没有可选对象');
|
| 110 |
}
|
|
@@ -156,8 +160,9 @@ export const GameRandom: React.FC = () => {
|
|
| 156 |
setIsRunning(false);
|
| 157 |
};
|
| 158 |
|
| 159 |
-
|
| 160 |
-
|
|
|
|
| 161 |
setShowResultModal(false);
|
| 162 |
return;
|
| 163 |
}
|
|
@@ -200,7 +205,7 @@ export const GameRandom: React.FC = () => {
|
|
| 200 |
}
|
| 201 |
});
|
| 202 |
await Promise.all(promises);
|
| 203 |
-
|
| 204 |
} catch (e) {
|
| 205 |
console.error(e);
|
| 206 |
alert('发放失败');
|
|
@@ -227,6 +232,7 @@ export const GameRandom: React.FC = () => {
|
|
| 227 |
{isFullscreen ? <Minimize size={20}/> : <Maximize size={20}/>}
|
| 228 |
<span className="text-xs font-bold hidden sm:inline">{isFullscreen ? '退出全屏' : '全屏模式'}</span>
|
| 229 |
</button>
|
|
|
|
| 230 |
{/* Header Config */}
|
| 231 |
<div className="bg-white p-4 shadow-sm border-b border-gray-200 z-10 flex flex-wrap gap-4 items-center justify-between shrink-0 pr-36">
|
| 232 |
<div className="flex flex-wrap gap-4 items-center">
|
|
@@ -247,15 +253,15 @@ export const GameRandom: React.FC = () => {
|
|
| 247 |
|
| 248 |
{/* Avoid Repeat Logic */}
|
| 249 |
<div className={`flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors ${avoidRepeat ? 'bg-indigo-50 border-indigo-200' : 'bg-gray-50 border-gray-200'}`}>
|
| 250 |
-
<div className="flex items-center gap-2">
|
| 251 |
<input type="checkbox" id="avoidRepeat" checked={avoidRepeat} onChange={e => setAvoidRepeat(e.target.checked)} className="w-4 h-4 text-indigo-600 rounded focus:ring-indigo-500 cursor-pointer"/>
|
| 252 |
-
<label htmlFor="avoidRepeat" className={`text-sm font-bold cursor-pointer ${avoidRepeat ? 'text-indigo-700' : 'text-gray-600'}`}>不重复</label>
|
| 253 |
</div>
|
| 254 |
{avoidRepeat && pickedIds.size > 0 && (
|
| 255 |
<>
|
| 256 |
<div className="w-px h-4 bg-indigo-200 mx-1"></div>
|
| 257 |
<span className="text-xs text-indigo-500 font-mono">已点{pickedIds.size}</span>
|
| 258 |
-
<button onClick={() => setPickedIds(new Set())} className="text-indigo-400 hover:text-indigo-700 p-1 rounded-full hover:bg-indigo-100" title="重置记录">
|
| 259 |
<RotateCcw size={14}/>
|
| 260 |
</button>
|
| 261 |
</>
|
|
@@ -290,6 +296,7 @@ export const GameRandom: React.FC = () => {
|
|
| 290 |
</div>
|
| 291 |
</div>
|
| 292 |
</div>
|
|
|
|
| 293 |
{/* Grid Area */}
|
| 294 |
<div className="flex-1 overflow-y-auto p-6 custom-scrollbar bg-slate-50">
|
| 295 |
<div className={`grid gap-4 transition-all pb-24 ${mode==='STUDENT' ? (isFullscreen ? 'grid-cols-6 sm:grid-cols-8 md:grid-cols-10 lg:grid-cols-12' : 'grid-cols-4 sm:grid-cols-6 md:grid-cols-8 lg:grid-cols-10') : 'grid-cols-2 md:grid-cols-3 lg:grid-cols-4'}`}>
|
|
@@ -325,6 +332,7 @@ export const GameRandom: React.FC = () => {
|
|
| 325 |
})}
|
| 326 |
</div>
|
| 327 |
</div>
|
|
|
|
| 328 |
{/* Start Button */}
|
| 329 |
<div className="absolute bottom-0 left-0 right-0 p-6 flex justify-center bg-white/90 backdrop-blur-sm border-t border-gray-200 z-10 shadow-[0_-4px_10px_-1px_rgba(0,0,0,0.1)]">
|
| 330 |
<button
|
|
@@ -389,12 +397,12 @@ export const GameRandom: React.FC = () => {
|
|
| 389 |
{/* @ts-ignore */}
|
| 390 |
<div className="text-gray-400 mb-8">{mode==='STUDENT' ? `座号: ${selectedResult.seatNo || '-'}` : `${selectedResult.members.length} 位成员`}</div>
|
| 391 |
<div className="grid grid-cols-2 gap-4 mb-4">
|
| 392 |
-
<button onClick={() =>
|
| 393 |
<CheckCircle size={32} className="mb-1"/>
|
| 394 |
回答正确
|
| 395 |
<span className="text-xs font-normal opacity-80 mt-1">发放奖励</span>
|
| 396 |
</button>
|
| 397 |
-
<button onClick={() =>
|
| 398 |
<XCircle size={32} className="mb-1"/>
|
| 399 |
回答错误
|
| 400 |
<span className="text-xs font-normal opacity-80 mt-1">无奖励</span>
|
|
|
|
| 32 |
const [rewardType, setRewardType] = useState<'DRAW_COUNT' | 'ITEM' | 'ACHIEVEMENT'>('DRAW_COUNT');
|
| 33 |
const [rewardId, setRewardId] = useState(''); // Achievement ID or Item Name
|
| 34 |
const [rewardCount, setRewardCount] = useState(1);
|
| 35 |
+
// Removed explicit enableReward state dependency for immediate actions to avoid async bugs
|
| 36 |
|
| 37 |
const timerRef = useRef<any>(null);
|
| 38 |
const speedRef = useRef<number>(50);
|
|
|
|
| 48 |
// Clear picked IDs when mode changes to avoid ID confusion
|
| 49 |
useEffect(() => {
|
| 50 |
setPickedIds(new Set());
|
| 51 |
+
}, [mode, scopeTeamId]);
|
| 52 |
|
| 53 |
const loadData = async () => {
|
| 54 |
if (!homeroomClass) return setLoading(false);
|
|
|
|
| 92 |
baseList = baseList.filter(s => !excludedStudentIds.has(s._id || String(s.id)));
|
| 93 |
}
|
| 94 |
|
| 95 |
+
// Filter out previously picked if mode is on
|
| 96 |
if (avoidRepeat) {
|
| 97 |
baseList = baseList.filter(item => !pickedIds.has(mode === 'TEAM' ? item.id : (item._id || String(item.id))));
|
| 98 |
}
|
|
|
|
| 104 |
const list = getTargetList();
|
| 105 |
if (list.length === 0) {
|
| 106 |
if (avoidRepeat && pickedIds.size > 0) {
|
| 107 |
+
if (confirm('本轮所有候选对象已全部点完!是否重置记录并重新开始?')) {
|
| 108 |
+
setPickedIds(new Set());
|
| 109 |
+
// Logic to restart immediately after reset could go here, but let's just reset first
|
| 110 |
+
}
|
| 111 |
+
return;
|
| 112 |
}
|
| 113 |
return alert('当前范围内没有可选对象');
|
| 114 |
}
|
|
|
|
| 160 |
setIsRunning(false);
|
| 161 |
};
|
| 162 |
|
| 163 |
+
// Fixed: Pass `shouldReward` directly to avoid async state issues
|
| 164 |
+
const handleGrantReward = async (shouldReward: boolean) => {
|
| 165 |
+
if (!selectedResult || !shouldReward) {
|
| 166 |
setShowResultModal(false);
|
| 167 |
return;
|
| 168 |
}
|
|
|
|
| 205 |
}
|
| 206 |
});
|
| 207 |
await Promise.all(promises);
|
| 208 |
+
// Optional: Show success toast
|
| 209 |
} catch (e) {
|
| 210 |
console.error(e);
|
| 211 |
alert('发放失败');
|
|
|
|
| 232 |
{isFullscreen ? <Minimize size={20}/> : <Maximize size={20}/>}
|
| 233 |
<span className="text-xs font-bold hidden sm:inline">{isFullscreen ? '退出全屏' : '全屏模式'}</span>
|
| 234 |
</button>
|
| 235 |
+
|
| 236 |
{/* Header Config */}
|
| 237 |
<div className="bg-white p-4 shadow-sm border-b border-gray-200 z-10 flex flex-wrap gap-4 items-center justify-between shrink-0 pr-36">
|
| 238 |
<div className="flex flex-wrap gap-4 items-center">
|
|
|
|
| 253 |
|
| 254 |
{/* Avoid Repeat Logic */}
|
| 255 |
<div className={`flex items-center gap-2 px-3 py-2 rounded-lg border transition-colors ${avoidRepeat ? 'bg-indigo-50 border-indigo-200' : 'bg-gray-50 border-gray-200'}`}>
|
| 256 |
+
<div className="flex items-center gap-2" title="开启后,已点过的学生/小组不会再次被选中">
|
| 257 |
<input type="checkbox" id="avoidRepeat" checked={avoidRepeat} onChange={e => setAvoidRepeat(e.target.checked)} className="w-4 h-4 text-indigo-600 rounded focus:ring-indigo-500 cursor-pointer"/>
|
| 258 |
+
<label htmlFor="avoidRepeat" className={`text-sm font-bold cursor-pointer select-none ${avoidRepeat ? 'text-indigo-700' : 'text-gray-600'}`}>不重复</label>
|
| 259 |
</div>
|
| 260 |
{avoidRepeat && pickedIds.size > 0 && (
|
| 261 |
<>
|
| 262 |
<div className="w-px h-4 bg-indigo-200 mx-1"></div>
|
| 263 |
<span className="text-xs text-indigo-500 font-mono">已点{pickedIds.size}</span>
|
| 264 |
+
<button onClick={() => setPickedIds(new Set())} className="text-indigo-400 hover:text-indigo-700 p-1 rounded-full hover:bg-indigo-100 transition-colors" title="重置记录">
|
| 265 |
<RotateCcw size={14}/>
|
| 266 |
</button>
|
| 267 |
</>
|
|
|
|
| 296 |
</div>
|
| 297 |
</div>
|
| 298 |
</div>
|
| 299 |
+
|
| 300 |
{/* Grid Area */}
|
| 301 |
<div className="flex-1 overflow-y-auto p-6 custom-scrollbar bg-slate-50">
|
| 302 |
<div className={`grid gap-4 transition-all pb-24 ${mode==='STUDENT' ? (isFullscreen ? 'grid-cols-6 sm:grid-cols-8 md:grid-cols-10 lg:grid-cols-12' : 'grid-cols-4 sm:grid-cols-6 md:grid-cols-8 lg:grid-cols-10') : 'grid-cols-2 md:grid-cols-3 lg:grid-cols-4'}`}>
|
|
|
|
| 332 |
})}
|
| 333 |
</div>
|
| 334 |
</div>
|
| 335 |
+
|
| 336 |
{/* Start Button */}
|
| 337 |
<div className="absolute bottom-0 left-0 right-0 p-6 flex justify-center bg-white/90 backdrop-blur-sm border-t border-gray-200 z-10 shadow-[0_-4px_10px_-1px_rgba(0,0,0,0.1)]">
|
| 338 |
<button
|
|
|
|
| 397 |
{/* @ts-ignore */}
|
| 398 |
<div className="text-gray-400 mb-8">{mode==='STUDENT' ? `座号: ${selectedResult.seatNo || '-'}` : `${selectedResult.members.length} 位成员`}</div>
|
| 399 |
<div className="grid grid-cols-2 gap-4 mb-4">
|
| 400 |
+
<button onClick={() => handleGrantReward(true)} className="bg-green-500 hover:bg-green-600 text-white py-4 rounded-2xl font-bold text-lg flex flex-col items-center justify-center shadow-md transition-transform hover:-translate-y-1">
|
| 401 |
<CheckCircle size={32} className="mb-1"/>
|
| 402 |
回答正确
|
| 403 |
<span className="text-xs font-normal opacity-80 mt-1">发放奖励</span>
|
| 404 |
</button>
|
| 405 |
+
<button onClick={() => handleGrantReward(false)} className="bg-gray-100 hover:bg-gray-200 text-gray-600 py-4 rounded-2xl font-bold text-lg flex flex-col items-center justify-center shadow-sm transition-transform hover:-translate-y-1">
|
| 406 |
<XCircle size={32} className="mb-1"/>
|
| 407 |
回答错误
|
| 408 |
<span className="text-xs font-normal opacity-80 mt-1">无奖励</span>
|