功能:自動選隊排除「那個」、選隊面板顯示每人今日場次
摘要:
- 記分板「自動選擇」時排除名字為「那個」的球員,手動仍可勾選
- 結算完成(上傳或不上傳)時幫上場 4 人各記一場,輪空不計
- 選球員面板每位球員名字旁顯示「今日 N 場」徽章
根本原因:
- 名單裡的「那個」是佔位用名字,自動選擇會把它當一般球員排進場
- 現場排下一場時沒有依據看誰打得多、誰打得少,容易分配不均
影響:
- src/App.tsx:新增 playCounts state 與 localStorage 持久化(跨日自動歸零)、recordPlayedMatch() 於 skipUpload 與 uploadSettledMatch 成功時計數、傳 playCounts 給記分板
- src/pages/ScoreboardPage.tsx:新增 AUTO_PICK_EXCLUDED_NAMES 常數過濾自動選擇、選隊 modal 每列加「今日 N 場」徽章
- src/App.css:徽章樣式與選項改三欄 grid(含手機版縮小字級)
修法:
- 自動選擇先以排除名單過濾 selectablePlayers 再洗牌取 4 位
- 場次以 {date, counts} 存 localStorage,載入時日期非當天即歸零
- 計數以 activeMatchup 兩隊為準,isPlaceholder 的輪空欄位跳過
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+61
@@ -48,6 +48,7 @@ const STORAGE_KEYS = {
|
||||
areaA: 'badminton-scoreboard::area-a',
|
||||
areaB: 'badminton-scoreboard::area-b',
|
||||
history: 'badminton-scoreboard::history',
|
||||
playCounts: 'badminton-scoreboard::play-counts',
|
||||
} as const
|
||||
|
||||
const defaultAreaA = ['柏威', '建喵', 'Yuki', '阿釧']
|
||||
@@ -137,6 +138,10 @@ function App() {
|
||||
const [history, setHistory] = useState<MatchHistoryItem[]>(() =>
|
||||
loadStoredHistory(STORAGE_KEYS.history),
|
||||
)
|
||||
// 當天每位球員打過的場次(結算一次算一場),跨日自動歸零。
|
||||
const [playCounts, setPlayCounts] = useState<Record<string, number>>(() =>
|
||||
loadStoredPlayCounts(STORAGE_KEYS.playCounts),
|
||||
)
|
||||
const [settlement, setSettlement] = useState<SettlementState>({
|
||||
error: '',
|
||||
open: false,
|
||||
@@ -176,6 +181,13 @@ function App() {
|
||||
window.localStorage.setItem(STORAGE_KEYS.history, JSON.stringify(history))
|
||||
}, [history])
|
||||
|
||||
useEffect(() => {
|
||||
window.localStorage.setItem(
|
||||
STORAGE_KEYS.playCounts,
|
||||
JSON.stringify({ date: formatDateInputValue(), counts: playCounts }),
|
||||
)
|
||||
}, [playCounts])
|
||||
|
||||
useEffect(() => {
|
||||
if (loadStatus !== 'loaded' || !loadMessage) {
|
||||
return
|
||||
@@ -895,8 +907,31 @@ function App() {
|
||||
}))
|
||||
}
|
||||
|
||||
// 結算完成時幫這場上場的球員各記一場(輪空不計)。
|
||||
const recordPlayedMatch = () => {
|
||||
if (!leftTeam || !rightTeam) {
|
||||
return
|
||||
}
|
||||
|
||||
const playedNames = [leftTeam, rightTeam].flatMap((team) => [
|
||||
team.isPlaceholderA ? null : team.playerA,
|
||||
team.isPlaceholderB ? null : team.playerB,
|
||||
])
|
||||
|
||||
setPlayCounts((current) => {
|
||||
const next = { ...current }
|
||||
playedNames.forEach((name) => {
|
||||
if (name) {
|
||||
next[name] = (next[name] ?? 0) + 1
|
||||
}
|
||||
})
|
||||
return next
|
||||
})
|
||||
}
|
||||
|
||||
const skipUpload = () => {
|
||||
void finalizeLiveRoom().finally(() => {
|
||||
recordPlayedMatch()
|
||||
setSettlement({
|
||||
error: '',
|
||||
open: false,
|
||||
@@ -946,6 +981,7 @@ function App() {
|
||||
}
|
||||
|
||||
setHistory((current) => [historyItem, ...current])
|
||||
recordPlayedMatch()
|
||||
await finalizeLiveRoom()
|
||||
setSettlement({
|
||||
error: '',
|
||||
@@ -1081,6 +1117,7 @@ function App() {
|
||||
nextMatchSignal={nextMatchSignal}
|
||||
rightTeam={rightTeam}
|
||||
scoreState={scoreState}
|
||||
playCounts={playCounts}
|
||||
selectedGroup={selectedGroup}
|
||||
streakAnnouncement={streakAnnouncement}
|
||||
victoryAnnouncement={victoryAnnouncement}
|
||||
@@ -1264,6 +1301,30 @@ function loadStoredHistory(storageKey: string) {
|
||||
}
|
||||
}
|
||||
|
||||
// 讀取當天的球員場次紀錄,日期不是今天就重新歸零。
|
||||
function loadStoredPlayCounts(storageKey: string): Record<string, number> {
|
||||
const value = window.localStorage.getItem(storageKey)
|
||||
|
||||
if (!value) {
|
||||
return {}
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(value) as {
|
||||
date?: string
|
||||
counts?: Record<string, number>
|
||||
}
|
||||
|
||||
if (parsed.date !== formatDateInputValue() || !parsed.counts) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return parsed.counts
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
function buildLiveRoomPayload({
|
||||
groupId,
|
||||
leftTeam,
|
||||
|
||||
Reference in New Issue
Block a user