From 9eb60baa371786b0967d3cf4afc6f499f6bdd3d7 Mon Sep 17 00:00:00 2001 From: JianMiau Date: Mon, 15 Jun 2026 17:42:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9A=E8=A8=98=E5=88=86?= =?UTF-8?q?=E6=9D=BF=E8=AA=9E=E9=9F=B3=E6=94=B9=E7=82=BA=E5=A0=B1=E6=AF=94?= =?UTF-8?q?=E5=88=86=E3=80=81=E7=99=BC=E7=90=83=E5=8D=80=E3=80=81=E8=B3=BD?= =?UTF-8?q?=E6=9C=AB=E9=BB=9E=E8=88=87=E7=8D=B2=E5=8B=9D=E9=9A=8A=E4=BC=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 摘要: - 得分播報改為「比分(發球方先報)+ 發球者左右發球區」 - 發球方到賽末點(再得 1 分即獲勝)時,比分後加唸「賽末點」 - 賽末點得分獲勝時,整段改播「<獲勝隊伍> 贏得比賽」 - 發球區左右一律用實際球場方向,取消上方隊伍鏡像;畫面「發球區」顯示同步改為不鏡像,與語音一致 根本原因: - 現場記分需要即時聽到比分與發球位置,原本只唸「誰得分、誰發球」較不直覺 - 先前發球區對上方隊伍做鏡像,導致語音與實際球場方向相反 影響: - src/App.tsx:recordPoint 計算發球方比分、發球區、賽末點與獲勝隊伍,重整 voiceAnnouncement 欄位 - src/pages/ScoreboardPage.tsx:語音組字改為「X比Y(賽末點)」「OO左/右邊發球」、獲勝改播「贏得比賽」;發球區顯示移除鏡像;語音設定「播報誰得分」更名「播報比分」 修法: - 發球方分數先報;賽末點僅在發球方再得 1 分就獲勝時觸發;發球區統一用 getServiceCourt 實際方向 Co-Authored-By: Claude Opus 4.8 (1M context) --- src/App.tsx | 17 ++++++++++++----- src/pages/ScoreboardPage.tsx | 14 +++++++------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 9f219ab..414569c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -89,6 +89,7 @@ type VoiceAnnouncement = { opponentScore: number serverName: string serverCourt: 'left' | 'right' + matchPoint: boolean winnerTeamName: string | null } @@ -773,13 +774,18 @@ function App() { : getTeamDisplayName(rightTeam) : null - // 得分方接著發球,報分以發球方分數為先;左側隊伍的發球區需鏡像對應畫面。 + // 得分方接著發球,報分以發球方分數為先;發球區一律用實際球場左右,不做鏡像。 const servingScore = side === 'left' ? nextScoreState.scoreLeft : nextScoreState.scoreRight const opponentScore = side === 'left' ? nextScoreState.scoreRight : nextScoreState.scoreLeft - const serverCourt = - side === 'left' - ? getMirroredCourt(getServiceCourt(servingScore)) - : getServiceCourt(servingScore) + const serverCourt = getServiceCourt(servingScore) + // 只有發球方(剛得分那隊)再得 1 分就能贏,才算賽末點。 + const matchPoint = + !reachedTarget && + hasWonGame( + side === 'left' + ? { ...nextScoreState, scoreLeft: nextScoreState.scoreLeft + 1 } + : { ...nextScoreState, scoreRight: nextScoreState.scoreRight + 1 }, + ) setScoreHistory((current) => [...current, { pointLog, scoreState }]) setPointLog(nextPointLog) @@ -790,6 +796,7 @@ function App() { opponentScore, serverName: getNextServerName(nextScoreState, leftTeam, rightTeam, side), serverCourt, + matchPoint, winnerTeamName, }) diff --git a/src/pages/ScoreboardPage.tsx b/src/pages/ScoreboardPage.tsx index 54da9ba..3edf716 100644 --- a/src/pages/ScoreboardPage.tsx +++ b/src/pages/ScoreboardPage.tsx @@ -3,7 +3,6 @@ import { useEffect, useMemo, useRef, useState } from 'react' import { Link } from 'react-router-dom' import { getCourtAssignments, - getMirroredCourt, getReceivingPlayer, getServiceCourt, getServingPlayer, @@ -64,6 +63,7 @@ type ScoreboardPageProps = { opponentScore: number serverName: string serverCourt: 'left' | 'right' + matchPoint: boolean winnerTeamName: string | null } | null targetDate: string @@ -260,7 +260,11 @@ export function ScoreboardPage({ const parts: string[] = [] if (voiceSettings.announceScore) { - parts.push(`${voiceAnnouncement.servingScore}比${voiceAnnouncement.opponentScore}`) + parts.push( + `${voiceAnnouncement.servingScore}比${voiceAnnouncement.opponentScore}${ + voiceAnnouncement.matchPoint ? ' 賽末點' : '' + }`, + ) } if (voiceSettings.announceServer && voiceAnnouncement.serverName) { @@ -484,11 +488,7 @@ export function ScoreboardPage({ onSwapPlayers={() => onSwapTeamPlayers('left')} onSwapTeams={onSwapMatchup} score={scoreState.scoreLeft} - serviceCourt={ - scoreState.serving === 'left' && servingCourt - ? getMirroredCourt(servingCourt) - : null - } + serviceCourt={scoreState.serving === 'left' ? servingCourt : null} showServingPrompt={scoreState.serving === null} team={leftTeam} teamSlot="top"