From c74bd5f70145f047696d063b60fcdc4c8e65a28a Mon Sep 17 00:00:00 2001 From: kang Date: Mon, 13 Jul 2026 10:23:44 +0800 Subject: [PATCH] =?UTF-8?q?feat(hall):=20=E4=BC=98=E5=8C=96=E6=A1=8C?= =?UTF-8?q?=E9=9D=A2=E7=AB=AF=E6=8A=95=E6=B3=A8=E8=A1=A8=E6=A0=BC=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E4=B8=8E=E5=9B=BD=E9=99=85=E5=8C=96=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/hall/hall-betting-grid.tsx | 160 ++++++++++++------------ src/hooks/use-token-refresh.ts | 8 +- src/i18n/locales/en/player.json | 17 ++- src/i18n/locales/ne/player.json | 22 +++- src/i18n/locales/zh/player.json | 16 ++- src/stores/error-store.ts | 4 +- 6 files changed, 136 insertions(+), 91 deletions(-) diff --git a/src/features/hall/hall-betting-grid.tsx b/src/features/hall/hall-betting-grid.tsx index d75469c..21973b8 100644 --- a/src/features/hall/hall-betting-grid.tsx +++ b/src/features/hall/hall-betting-grid.tsx @@ -1628,14 +1628,15 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot } ) : null} -
+
+
@@ -1727,8 +1728,12 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot } ...current, [column.key]: checked === true, }))} - aria-label={`${playColumnHeaderLabel(column.play, playCategory(column.play.play_code), column.digitSlot, t)} 同步本列金额`} - title="同步本列金额" + aria-label={t("hall.table.syncColumnAmount", { + column: playColumnHeaderLabel(column.play, playCategory(column.play.play_code), column.digitSlot, t), + })} + title={t("hall.table.syncColumnAmount", { + column: playColumnHeaderLabel(column.play, playCategory(column.play.play_code), column.digitSlot, t), + })} className="mx-auto mt-1 size-3.5" /> @@ -1745,15 +1750,15 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot } event.currentTarget.value = ""; }} className="mx-auto mt-1 h-5 w-full rounded border border-[#d7e1f3] bg-white px-0.5 text-[10px] font-semibold text-[#304f86]" - aria-label="全选种类" - title="统一设置所有行的种类" + aria-label={t("hall.table.selectAllTypes")} + title={t("hall.table.setAllTypes")} > - - - - - - {activeCategory === "D4" ? : null} + + + + + + {activeCategory === "D4" ? : null} ) : null} @@ -1770,7 +1775,7 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot } checked={checked} disabled={tableDisabled} onCheckedChange={(next) => toggleProviderColumn(provider.code, next === true)} - aria-label={`全选 ${provider.name}`} + aria-label={t("hall.table.selectAllProvider", { provider: provider.name })} className="mx-auto mt-1 border-slate-500 bg-white data-checked:border-slate-800 data-checked:bg-slate-800" /> @@ -1816,74 +1821,63 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot } ))}
- {!isMobile ? ( - - ) : null}
+
+ + {!isMobile ? ( + + ) : null}
- {!isMobile ? ( -
- - {t("hall.table.draftTotal")} - - - {formatMinorAsCurrency(debouncedSummary.actual, currencyCode)} - -
- ) : null} - {sealedBetUi ? (

{t("hall.table.sealedHint")}

) : null} - {!isMobile ? ( - - ) : null} {isMobile ? ( @@ -2140,13 +2134,13 @@ const DraftRowItem = memo(function DraftRowItem({ disabled={tableDisabled} onChange={(event) => updateRowSelectionType(row.id, event.target.value as DraftRow["selectionType"])} className="h-8 w-full rounded-md border border-[#e1e8f3] bg-white px-1 text-[10px] font-semibold text-[#304f86]" - aria-label={`第 ${index + 1} 行种类`} + aria-label={t("hall.table.selectionTypeForRow", { row: index + 1 })} > - - - - - {activeCategory === "D4" ? : null} + + + + + {activeCategory === "D4" ? : null} ) : null} diff --git a/src/hooks/use-token-refresh.ts b/src/hooks/use-token-refresh.ts index 81cbb58..81c779a 100644 --- a/src/hooks/use-token-refresh.ts +++ b/src/hooks/use-token-refresh.ts @@ -1,4 +1,5 @@ import { useCallback, useEffect, useRef } from "react"; +import { useTranslation } from "react-i18next"; import { parseJwtExp } from "@/lib/jwt-payload"; import { usePlayerSessionStore } from "@/stores/player-session-store"; @@ -39,6 +40,7 @@ export function useTokenRefresh(): { const setBearerToken = usePlayerSessionStore((state) => state.setBearerToken); const setServerError = useErrorStore((state) => state.setServerError); const clearServerError = useErrorStore((state) => state.clearServerError); + const { t } = useTranslation("player"); const refreshTimerRef = useRef(null); const retryCountRef = useRef(0); @@ -89,7 +91,7 @@ export function useTokenRefresh(): { */ const refreshToken = useCallback(async (): Promise => { if (retryCountRef.current >= MAX_RETRY) { - setServerError(true, "Token 刷新失败,请返回主站重新进入"); + setServerError(true, t("token.refreshFailed")); return; } @@ -102,10 +104,10 @@ export function useTokenRefresh(): { if (pendingRefreshRef.current !== attemptId) return; retryCountRef.current += 1; if (retryCountRef.current >= MAX_RETRY) { - setServerError(true, "Token 刷新失败,请返回主站重新进入"); + setServerError(true, t("token.refreshFailed")); } }, REFRESH_RESPONSE_TIMEOUT_MS); - }, [clearServerError, requestParentRefresh, setServerError]); + }, [clearServerError, requestParentRefresh, setServerError, t]); /** * 监听主站 postMessage 发送的新 Token diff --git a/src/i18n/locales/en/player.json b/src/i18n/locales/en/player.json index e9b4666..29882da 100644 --- a/src/i18n/locales/en/player.json +++ b/src/i18n/locales/en/player.json @@ -68,7 +68,8 @@ "warning": "Login expiring soon", "remaining": "Remaining {{time}}", "autoRenewing": "Auto-renewing...", - "renewNow": "Renew now" + "renewNow": "Renew now", + "refreshFailed": "Token refresh failed. Please return to the main site and enter again." }, "serverError": { "title": "Server error", @@ -235,6 +236,19 @@ "number": "Number", "selectionType": "Type", "rowTotal": "Row Total", + "selectAllTypes": "Select all types", + "setAllTypes": "Set the type for every row", + "selectAll": "Select all", + "syncColumnAmount": "Sync amount for {{column}}", + "selectAllProvider": "Select all {{provider}}", + "selectionTypeForRow": "Type for row {{row}}", + "selectionTypes": { + "straight": "Straight", + "reverse": "Reverse", + "full_cover": "Full cover", + "full_play": "Full play", + "half_play": "Half play" + }, "stake": "Stake Amount", "rebate": "Commission / Rebate", "actual": "Actual Deduction", @@ -456,6 +470,7 @@ "wallet": "Main-site wallet player (transfers & wallet ledger)" }, "creditAvailableAfter": "Available credit after", + "creditReleasedAmount": "Released credit {{amount}}", "creditPaymentRecordOnly": "Billing payment record only; not counted in available credit", "totalRecords": "{{total}} records", "emptyLogs": "No wallet logs", diff --git a/src/i18n/locales/ne/player.json b/src/i18n/locales/ne/player.json index 96aaf2d..577e979 100644 --- a/src/i18n/locales/ne/player.json +++ b/src/i18n/locales/ne/player.json @@ -68,7 +68,8 @@ "warning": "लगइन समाप्त हुन लागेको छ", "remaining": "बाँकी {{time}}", "autoRenewing": "स्वचालित नवीकरण हुँदैछ...", - "renewNow": "अहिले नवीकरण" + "renewNow": "अहिले नवीकरण", + "refreshFailed": "टोकन नवीकरण असफल भयो। कृपया मुख्य साइटमा फर्केर फेरि प्रवेश गर्नुहोस्।" }, "serverError": { "title": "सर्भर त्रुटि", @@ -233,6 +234,21 @@ "table": { "no": "नं.", "number": "नम्बर", + "selectionType": "प्रकार", + "rowTotal": "पंक्ति जम्मा", + "selectAllTypes": "सबै प्रकार छान्नुहोस्", + "setAllTypes": "सबै पंक्तिको प्रकार सेट गर्नुहोस्", + "selectAll": "सबै छान्नुहोस्", + "syncColumnAmount": "{{column}} को रकम मिलाउनुहोस्", + "selectAllProvider": "सबै {{provider}} छान्नुहोस्", + "selectionTypeForRow": "पंक्ति {{row}} को प्रकार", + "selectionTypes": { + "straight": "स्ट्रेट", + "reverse": "रिभर्स", + "full_cover": "पूर्ण कभर", + "full_play": "पूर्ण खेल", + "half_play": "आधा खेल" + }, "stake": "बेट रकम", "rebate": "कमिशन / रिबेट", "actual": "वास्तविक कट्टा", @@ -242,6 +258,9 @@ "totalBet": "जम्मा", "totalRebate": "रिबेट", "actualTotal": "अनुमानित कट्टा", + "orderSummary": "अर्डर सारांश", + "lineCount": "लाइनहरू", + "providerCount": "खुलाउने कम्पनीहरू", "sealedHint": "बन्द: यो तालिका लक छ। कृपया अर्को इश्यू पर्खनुहोस्।", "previewing": "पूर्वावलोकन...", "submitBet": "बेट पेश गर्नुहोस्", @@ -451,6 +470,7 @@ "wallet": "मुख्य साइट वालेट खेलाडी" }, "creditAvailableAfter": "पछि उपलब्ध क्रेडिट", + "creditReleasedAmount": "मुक्त क्रेडिट {{amount}}", "creditPaymentRecordOnly": "बिलिङ भुक्तानी रेकर्ड मात्र; उपलब्ध क्रेडिटमा गणना हुँदैन", "emptyCreditLogs": "क्रेडिट लेनदेन छैन", "creditFlow": { diff --git a/src/i18n/locales/zh/player.json b/src/i18n/locales/zh/player.json index ed4247c..9a03def 100644 --- a/src/i18n/locales/zh/player.json +++ b/src/i18n/locales/zh/player.json @@ -68,7 +68,8 @@ "warning": "登录即将过期", "remaining": "剩余 {{time}}", "autoRenewing": "正在自动续签...", - "renewNow": "立即续签" + "renewNow": "立即续签", + "refreshFailed": "Token 刷新失败,请返回主站重新进入" }, "serverError": { "title": "服务器错误", @@ -234,6 +235,19 @@ "number": "号码", "selectionType": "种类", "rowTotal": "本行合计", + "selectAllTypes": "全选种类", + "setAllTypes": "统一设置所有行的种类", + "selectAll": "全选", + "syncColumnAmount": "同步 {{column}} 本列金额", + "selectAllProvider": "全选 {{provider}}", + "selectionTypeForRow": "第 {{row}} 行种类", + "selectionTypes": { + "straight": "正字", + "reverse": "来回", + "full_cover": "全保", + "full_play": "全打", + "half_play": "半打" + }, "stake": "下注金额", "rebate": "佣金 / 回水", "actual": "实扣金额", diff --git a/src/stores/error-store.ts b/src/stores/error-store.ts index fab27dc..47aae5d 100644 --- a/src/stores/error-store.ts +++ b/src/stores/error-store.ts @@ -31,7 +31,7 @@ export const useErrorStore = create((set, get) => ({ // 首屏与 SSR 一致为 false;真实离线状态由 useNetworkStatus 在 mount 后同步 isOffline: false, isServerError: false, - serverErrorMessage: "服务器暂时不可用,请稍后重试", + serverErrorMessage: "", currentErrorType: null, // Actions @@ -51,7 +51,7 @@ export const useErrorStore = create((set, get) => ({ setServerError: (isError: boolean, message?: string) => { set({ isServerError: isError, - serverErrorMessage: message || "服务器暂时不可用,请稍后重试", + serverErrorMessage: message ?? "", }); // 更新当前错误类型 - 服务器错误优先级更高 if (isError) {