diff --git a/src/components/game/TimerDisplay.tsx b/src/components/game/TimerDisplay.tsx index c384d09..47988a2 100644 --- a/src/components/game/TimerDisplay.tsx +++ b/src/components/game/TimerDisplay.tsx @@ -1,29 +1,85 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useRef, useCallback } from 'react'; import { useGameStore } from '../../store/gameStore'; +import { invoke } from '@tauri-apps/api/core'; export default function TimerDisplay() { const config = useGameStore((s) => s.config); const currentColor = useGameStore((s) => s.currentColor); const status = useGameStore((s) => s.status); - const [time, setTime] = useState(config.timeLimitSecs); + const refreshBoard = useGameStore((s) => s.refreshBoard); + + const [blackTime, setBlackTime] = useState(config.timeLimitSecs); + const [whiteTime, setWhiteTime] = useState(config.timeLimitSecs); + const lastColorRef = useRef(currentColor); + const hasTimedOutRef = useRef(false); + + // 初始化/重置时钟 + useEffect(() => { + setBlackTime(config.timeLimitSecs); + setWhiteTime(config.timeLimitSecs); + hasTimedOutRef.current = false; + lastColorRef.current = 'Black'; + }, [config.timeLimitSecs, status === 'waiting' ? status : null]); + + const handleTimeout = useCallback(async () => { + if (hasTimedOutRef.current) return; + hasTimedOutRef.current = true; + try { + await invoke('resign'); + await refreshBoard(); + } catch { + // 忽略错误 + } + }, [refreshBoard]); useEffect(() => { if (!config.useTimer || status !== 'playing') return; - setTime(config.timeLimitSecs); + const timer = setInterval(() => { - setTime((t) => { - if (t <= 1) { clearInterval(timer); return 0; } - return t - 1; - }); + if (currentColor === 'Black') { + setBlackTime((t) => { + if (t <= 1) { + clearInterval(timer); + handleTimeout(); + return 0; + } + return t - 1; + }); + } else { + setWhiteTime((t) => { + if (t <= 1) { + clearInterval(timer); + handleTimeout(); + return 0; + } + return t - 1; + }); + } }, 1000); + + lastColorRef.current = currentColor; + return () => clearInterval(timer); - }, [currentColor, config.useTimer, config.timeLimitSecs, status]); + }, [currentColor, config.useTimer, status, handleTimeout]); if (!config.useTimer) return null; + const displayTime = currentColor === 'Black' ? blackTime : whiteTime; + const isWarning = displayTime <= 10; + return ( -
- {Math.floor(time / 60)}:{(time % 60).toString().padStart(2, '0')} +
+
+ {Math.floor(displayTime / 60)}:{(displayTime % 60).toString().padStart(2, '0')} +
+
+ + 黑: {Math.floor(blackTime / 60)}:{String(blackTime % 60).padStart(2, '0')} + + + 白: {Math.floor(whiteTime / 60)}:{String(whiteTime % 60).padStart(2, '0')} + +
); }