feat(hall): 优化桌面端投注表格布局与国际化文本支持
Some checks failed
lotteryfront CI / build (push) Has been cancelled
Some checks failed
lotteryfront CI / build (push) Has been cancelled
This commit is contained in:
@@ -1628,14 +1628,15 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<div
|
<div className={cn("min-w-0", !isMobile && "flex items-start gap-3")}>
|
||||||
className={cn(
|
<div
|
||||||
"overflow-hidden border border-[#e6edf8] bg-white transition-opacity",
|
className={cn(
|
||||||
isMobile ? "rounded-lg" : "rounded-xl shadow-[0_8px_24px_rgba(15,23,42,0.05)]",
|
"min-w-0 flex-1 overflow-hidden border border-[#e6edf8] bg-white transition-opacity",
|
||||||
tableDisabled && "opacity-55",
|
isMobile ? "rounded-lg" : "rounded-xl shadow-[0_8px_24px_rgba(15,23,42,0.05)]",
|
||||||
showWideTableHint && "player-table-scroll-wrap",
|
tableDisabled && "opacity-55",
|
||||||
)}
|
showWideTableHint && "player-table-scroll-wrap",
|
||||||
>
|
)}
|
||||||
|
>
|
||||||
<div className="mb-3 overflow-x-auto rounded border border-[#dae3f3] shadow-sm">
|
<div className="mb-3 overflow-x-auto rounded border border-[#dae3f3] shadow-sm">
|
||||||
<table className="w-full border-collapse text-center text-[11px] tabular-nums">
|
<table className="w-full border-collapse text-center text-[11px] tabular-nums">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -1727,8 +1728,12 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
|||||||
...current,
|
...current,
|
||||||
[column.key]: checked === true,
|
[column.key]: checked === true,
|
||||||
}))}
|
}))}
|
||||||
aria-label={`${playColumnHeaderLabel(column.play, playCategory(column.play.play_code), column.digitSlot, t)} 同步本列金额`}
|
aria-label={t("hall.table.syncColumnAmount", {
|
||||||
title="同步本列金额"
|
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"
|
className="mx-auto mt-1 size-3.5"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
@@ -1745,15 +1750,15 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
|||||||
event.currentTarget.value = "";
|
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]"
|
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="全选种类"
|
aria-label={t("hall.table.selectAllTypes")}
|
||||||
title="统一设置所有行的种类"
|
title={t("hall.table.setAllTypes")}
|
||||||
>
|
>
|
||||||
<option value="">全选</option>
|
<option value="">{t("hall.table.selectAll")}</option>
|
||||||
<option value="straight">正字</option>
|
<option value="straight">{t("hall.table.selectionTypes.straight")}</option>
|
||||||
<option value="reverse">来回</option>
|
<option value="reverse">{t("hall.table.selectionTypes.reverse")}</option>
|
||||||
<option value="full_cover">全保</option>
|
<option value="full_cover">{t("hall.table.selectionTypes.full_cover")}</option>
|
||||||
<option value="full_play">全打</option>
|
<option value="full_play">{t("hall.table.selectionTypes.full_play")}</option>
|
||||||
{activeCategory === "D4" ? <option value="half_play">半打</option> : null}
|
{activeCategory === "D4" ? <option value="half_play">{t("hall.table.selectionTypes.half_play")}</option> : null}
|
||||||
</select>
|
</select>
|
||||||
</th>
|
</th>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -1770,7 +1775,7 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
|||||||
checked={checked}
|
checked={checked}
|
||||||
disabled={tableDisabled}
|
disabled={tableDisabled}
|
||||||
onCheckedChange={(next) => toggleProviderColumn(provider.code, next === true)}
|
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"
|
className="mx-auto mt-1 border-slate-500 bg-white data-checked:border-slate-800 data-checked:bg-slate-800"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
@@ -1816,74 +1821,63 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
|||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{!isMobile ? (
|
|
||||||
<aside className="min-w-[12rem] flex-1 border-l border-[#e6edf8] bg-[#f8fbff] px-4 py-4 text-[#304f86]">
|
|
||||||
<p className="text-xs font-black">{t("hall.table.orderSummary", { defaultValue: "Order summary" })}</p>
|
|
||||||
<dl className="mt-5 space-y-4">
|
|
||||||
<div className="flex items-center justify-between gap-3">
|
|
||||||
<dt className="text-xs text-slate-500">{t("hall.table.lineCount", { defaultValue: "Lines" })}</dt>
|
|
||||||
<dd className="font-mono text-base font-black tabular-nums">{draftEntries.length}</dd>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center justify-between gap-3">
|
|
||||||
<dt className="text-xs text-slate-500">{t("hall.table.providerCount", { defaultValue: "Providers" })}</dt>
|
|
||||||
<dd className="font-mono text-base font-black tabular-nums">{selectedProviderCount}</dd>
|
|
||||||
</div>
|
|
||||||
<div className="border-t border-[#dce6f5] pt-4">
|
|
||||||
<dt className="text-xs text-slate-500">{t("hall.table.actualTotal")}</dt>
|
|
||||||
<dd className="mt-1 text-lg font-black tabular-nums text-[#0b3f96]">
|
|
||||||
{formatMinorAsCurrency(submitActualMinor, currencyCode)}
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
</dl>
|
|
||||||
</aside>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{!isMobile ? (
|
||||||
|
<aside className="sticky top-3 z-20 w-64 shrink-0 self-start rounded-xl border border-[#e6edf8] bg-[#f8fbff] px-4 py-4 text-[#304f86] shadow-[0_8px_24px_rgba(15,23,42,0.05)]">
|
||||||
|
<p className="text-xs font-black">{t("hall.table.orderSummary", { defaultValue: "Order summary" })}</p>
|
||||||
|
<dl className="mt-5 space-y-4">
|
||||||
|
<div className="flex items-center justify-between gap-3">
|
||||||
|
<dt className="text-xs text-slate-500">{t("hall.table.lineCount", { defaultValue: "Lines" })}</dt>
|
||||||
|
<dd className="font-mono text-base font-black tabular-nums">{draftEntries.length}</dd>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between gap-3">
|
||||||
|
<dt className="text-xs text-slate-500">{t("hall.table.providerCount", { defaultValue: "Providers" })}</dt>
|
||||||
|
<dd className="font-mono text-base font-black tabular-nums">{selectedProviderCount}</dd>
|
||||||
|
</div>
|
||||||
|
<div className="border-t border-[#dce6f5] pt-4">
|
||||||
|
<dt className="text-xs text-slate-500">{t("hall.table.actualTotal")}</dt>
|
||||||
|
<dd className="mt-1 text-lg font-black tabular-nums text-[#0b3f96]">
|
||||||
|
{formatMinorAsCurrency(submitActualMinor, currencyCode)}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
disabled={!canSubmit || previewLoading}
|
||||||
|
onClick={() => void handlePreview()}
|
||||||
|
className={cn(
|
||||||
|
"mt-6 h-11 w-full gap-2 rounded-lg border-0 text-sm font-bold text-white",
|
||||||
|
!isBettable
|
||||||
|
? "bg-slate-500 shadow-none hover:bg-slate-500 disabled:opacity-100"
|
||||||
|
: "bg-[#e5002c] shadow-[0_8px_20px_rgba(229,0,44,0.26)] hover:bg-[#d10028]",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{!isBettable ? (
|
||||||
|
<Lock className="size-4 shrink-0" aria-hidden />
|
||||||
|
) : (
|
||||||
|
<Ticket className="size-4 shrink-0" aria-hidden />
|
||||||
|
)}
|
||||||
|
{previewLoading
|
||||||
|
? t("hall.table.previewing")
|
||||||
|
: !isBettable
|
||||||
|
? t("hall.closed.title")
|
||||||
|
: availableMinor < submitActualMinor
|
||||||
|
? t("hall.table.insufficientBalance")
|
||||||
|
: t("hall.table.submitBet")}
|
||||||
|
</Button>
|
||||||
|
</aside>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isMobile ? (
|
|
||||||
<div className="flex items-center justify-between rounded-xl border border-[#e9eef7] bg-[#f8fbff] px-3 py-2.5 text-sm shadow-[0_6px_20px_rgba(15,23,42,0.04)]">
|
|
||||||
<span className="text-xs font-medium text-slate-500">
|
|
||||||
{t("hall.table.draftTotal")}
|
|
||||||
</span>
|
|
||||||
<span className="text-base font-black tabular-nums text-[#0b3f96]">
|
|
||||||
{formatMinorAsCurrency(debouncedSummary.actual, currencyCode)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{sealedBetUi ? (
|
{sealedBetUi ? (
|
||||||
<p className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-600">
|
<p className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-600">
|
||||||
{t("hall.table.sealedHint")}
|
{t("hall.table.sealedHint")}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{!isMobile ? (
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
disabled={!canSubmit || previewLoading}
|
|
||||||
onClick={() => void handlePreview()}
|
|
||||||
className={cn(
|
|
||||||
"h-12 w-full gap-2 rounded-xl border-0 text-base font-bold text-white",
|
|
||||||
!isBettable
|
|
||||||
? "bg-slate-500 shadow-none hover:bg-slate-500 disabled:opacity-100"
|
|
||||||
: "bg-[#e5002c] shadow-[0_8px_20px_rgba(229,0,44,0.26)] hover:bg-[#d10028]",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{!isBettable ? (
|
|
||||||
<Lock className="size-5 shrink-0" aria-hidden />
|
|
||||||
) : (
|
|
||||||
<Ticket className="size-5 shrink-0" aria-hidden />
|
|
||||||
)}
|
|
||||||
{previewLoading
|
|
||||||
? t("hall.table.previewing")
|
|
||||||
: !isBettable
|
|
||||||
? t("hall.closed.title")
|
|
||||||
: availableMinor < submitActualMinor
|
|
||||||
? t("hall.table.insufficientBalance")
|
|
||||||
: t("hall.table.submitBet")}
|
|
||||||
</Button>
|
|
||||||
) : null}
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
@@ -2140,13 +2134,13 @@ const DraftRowItem = memo(function DraftRowItem({
|
|||||||
disabled={tableDisabled}
|
disabled={tableDisabled}
|
||||||
onChange={(event) => updateRowSelectionType(row.id, event.target.value as DraftRow["selectionType"])}
|
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]"
|
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 })}
|
||||||
>
|
>
|
||||||
<option value="straight">正字</option>
|
<option value="straight">{t("hall.table.selectionTypes.straight")}</option>
|
||||||
<option value="reverse">来回</option>
|
<option value="reverse">{t("hall.table.selectionTypes.reverse")}</option>
|
||||||
<option value="full_cover">全保</option>
|
<option value="full_cover">{t("hall.table.selectionTypes.full_cover")}</option>
|
||||||
<option value="full_play">全打</option>
|
<option value="full_play">{t("hall.table.selectionTypes.full_play")}</option>
|
||||||
{activeCategory === "D4" ? <option value="half_play">半打</option> : null}
|
{activeCategory === "D4" ? <option value="half_play">{t("hall.table.selectionTypes.half_play")}</option> : null}
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useCallback, useEffect, useRef } from "react";
|
import { useCallback, useEffect, useRef } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { parseJwtExp } from "@/lib/jwt-payload";
|
import { parseJwtExp } from "@/lib/jwt-payload";
|
||||||
import { usePlayerSessionStore } from "@/stores/player-session-store";
|
import { usePlayerSessionStore } from "@/stores/player-session-store";
|
||||||
@@ -39,6 +40,7 @@ export function useTokenRefresh(): {
|
|||||||
const setBearerToken = usePlayerSessionStore((state) => state.setBearerToken);
|
const setBearerToken = usePlayerSessionStore((state) => state.setBearerToken);
|
||||||
const setServerError = useErrorStore((state) => state.setServerError);
|
const setServerError = useErrorStore((state) => state.setServerError);
|
||||||
const clearServerError = useErrorStore((state) => state.clearServerError);
|
const clearServerError = useErrorStore((state) => state.clearServerError);
|
||||||
|
const { t } = useTranslation("player");
|
||||||
|
|
||||||
const refreshTimerRef = useRef<NodeJS.Timeout | null>(null);
|
const refreshTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
const retryCountRef = useRef(0);
|
const retryCountRef = useRef(0);
|
||||||
@@ -89,7 +91,7 @@ export function useTokenRefresh(): {
|
|||||||
*/
|
*/
|
||||||
const refreshToken = useCallback(async (): Promise<void> => {
|
const refreshToken = useCallback(async (): Promise<void> => {
|
||||||
if (retryCountRef.current >= MAX_RETRY) {
|
if (retryCountRef.current >= MAX_RETRY) {
|
||||||
setServerError(true, "Token 刷新失败,请返回主站重新进入");
|
setServerError(true, t("token.refreshFailed"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,10 +104,10 @@ export function useTokenRefresh(): {
|
|||||||
if (pendingRefreshRef.current !== attemptId) return;
|
if (pendingRefreshRef.current !== attemptId) return;
|
||||||
retryCountRef.current += 1;
|
retryCountRef.current += 1;
|
||||||
if (retryCountRef.current >= MAX_RETRY) {
|
if (retryCountRef.current >= MAX_RETRY) {
|
||||||
setServerError(true, "Token 刷新失败,请返回主站重新进入");
|
setServerError(true, t("token.refreshFailed"));
|
||||||
}
|
}
|
||||||
}, REFRESH_RESPONSE_TIMEOUT_MS);
|
}, REFRESH_RESPONSE_TIMEOUT_MS);
|
||||||
}, [clearServerError, requestParentRefresh, setServerError]);
|
}, [clearServerError, requestParentRefresh, setServerError, t]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听主站 postMessage 发送的新 Token
|
* 监听主站 postMessage 发送的新 Token
|
||||||
|
|||||||
@@ -68,7 +68,8 @@
|
|||||||
"warning": "Login expiring soon",
|
"warning": "Login expiring soon",
|
||||||
"remaining": "Remaining {{time}}",
|
"remaining": "Remaining {{time}}",
|
||||||
"autoRenewing": "Auto-renewing...",
|
"autoRenewing": "Auto-renewing...",
|
||||||
"renewNow": "Renew now"
|
"renewNow": "Renew now",
|
||||||
|
"refreshFailed": "Token refresh failed. Please return to the main site and enter again."
|
||||||
},
|
},
|
||||||
"serverError": {
|
"serverError": {
|
||||||
"title": "Server error",
|
"title": "Server error",
|
||||||
@@ -235,6 +236,19 @@
|
|||||||
"number": "Number",
|
"number": "Number",
|
||||||
"selectionType": "Type",
|
"selectionType": "Type",
|
||||||
"rowTotal": "Row Total",
|
"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",
|
"stake": "Stake Amount",
|
||||||
"rebate": "Commission / Rebate",
|
"rebate": "Commission / Rebate",
|
||||||
"actual": "Actual Deduction",
|
"actual": "Actual Deduction",
|
||||||
@@ -456,6 +470,7 @@
|
|||||||
"wallet": "Main-site wallet player (transfers & wallet ledger)"
|
"wallet": "Main-site wallet player (transfers & wallet ledger)"
|
||||||
},
|
},
|
||||||
"creditAvailableAfter": "Available credit after",
|
"creditAvailableAfter": "Available credit after",
|
||||||
|
"creditReleasedAmount": "Released credit {{amount}}",
|
||||||
"creditPaymentRecordOnly": "Billing payment record only; not counted in available credit",
|
"creditPaymentRecordOnly": "Billing payment record only; not counted in available credit",
|
||||||
"totalRecords": "{{total}} records",
|
"totalRecords": "{{total}} records",
|
||||||
"emptyLogs": "No wallet logs",
|
"emptyLogs": "No wallet logs",
|
||||||
|
|||||||
@@ -68,7 +68,8 @@
|
|||||||
"warning": "लगइन समाप्त हुन लागेको छ",
|
"warning": "लगइन समाप्त हुन लागेको छ",
|
||||||
"remaining": "बाँकी {{time}}",
|
"remaining": "बाँकी {{time}}",
|
||||||
"autoRenewing": "स्वचालित नवीकरण हुँदैछ...",
|
"autoRenewing": "स्वचालित नवीकरण हुँदैछ...",
|
||||||
"renewNow": "अहिले नवीकरण"
|
"renewNow": "अहिले नवीकरण",
|
||||||
|
"refreshFailed": "टोकन नवीकरण असफल भयो। कृपया मुख्य साइटमा फर्केर फेरि प्रवेश गर्नुहोस्।"
|
||||||
},
|
},
|
||||||
"serverError": {
|
"serverError": {
|
||||||
"title": "सर्भर त्रुटि",
|
"title": "सर्भर त्रुटि",
|
||||||
@@ -233,6 +234,21 @@
|
|||||||
"table": {
|
"table": {
|
||||||
"no": "नं.",
|
"no": "नं.",
|
||||||
"number": "नम्बर",
|
"number": "नम्बर",
|
||||||
|
"selectionType": "प्रकार",
|
||||||
|
"rowTotal": "पंक्ति जम्मा",
|
||||||
|
"selectAllTypes": "सबै प्रकार छान्नुहोस्",
|
||||||
|
"setAllTypes": "सबै पंक्तिको प्रकार सेट गर्नुहोस्",
|
||||||
|
"selectAll": "सबै छान्नुहोस्",
|
||||||
|
"syncColumnAmount": "{{column}} को रकम मिलाउनुहोस्",
|
||||||
|
"selectAllProvider": "सबै {{provider}} छान्नुहोस्",
|
||||||
|
"selectionTypeForRow": "पंक्ति {{row}} को प्रकार",
|
||||||
|
"selectionTypes": {
|
||||||
|
"straight": "स्ट्रेट",
|
||||||
|
"reverse": "रिभर्स",
|
||||||
|
"full_cover": "पूर्ण कभर",
|
||||||
|
"full_play": "पूर्ण खेल",
|
||||||
|
"half_play": "आधा खेल"
|
||||||
|
},
|
||||||
"stake": "बेट रकम",
|
"stake": "बेट रकम",
|
||||||
"rebate": "कमिशन / रिबेट",
|
"rebate": "कमिशन / रिबेट",
|
||||||
"actual": "वास्तविक कट्टा",
|
"actual": "वास्तविक कट्टा",
|
||||||
@@ -242,6 +258,9 @@
|
|||||||
"totalBet": "जम्मा",
|
"totalBet": "जम्मा",
|
||||||
"totalRebate": "रिबेट",
|
"totalRebate": "रिबेट",
|
||||||
"actualTotal": "अनुमानित कट्टा",
|
"actualTotal": "अनुमानित कट्टा",
|
||||||
|
"orderSummary": "अर्डर सारांश",
|
||||||
|
"lineCount": "लाइनहरू",
|
||||||
|
"providerCount": "खुलाउने कम्पनीहरू",
|
||||||
"sealedHint": "बन्द: यो तालिका लक छ। कृपया अर्को इश्यू पर्खनुहोस्।",
|
"sealedHint": "बन्द: यो तालिका लक छ। कृपया अर्को इश्यू पर्खनुहोस्।",
|
||||||
"previewing": "पूर्वावलोकन...",
|
"previewing": "पूर्वावलोकन...",
|
||||||
"submitBet": "बेट पेश गर्नुहोस्",
|
"submitBet": "बेट पेश गर्नुहोस्",
|
||||||
@@ -451,6 +470,7 @@
|
|||||||
"wallet": "मुख्य साइट वालेट खेलाडी"
|
"wallet": "मुख्य साइट वालेट खेलाडी"
|
||||||
},
|
},
|
||||||
"creditAvailableAfter": "पछि उपलब्ध क्रेडिट",
|
"creditAvailableAfter": "पछि उपलब्ध क्रेडिट",
|
||||||
|
"creditReleasedAmount": "मुक्त क्रेडिट {{amount}}",
|
||||||
"creditPaymentRecordOnly": "बिलिङ भुक्तानी रेकर्ड मात्र; उपलब्ध क्रेडिटमा गणना हुँदैन",
|
"creditPaymentRecordOnly": "बिलिङ भुक्तानी रेकर्ड मात्र; उपलब्ध क्रेडिटमा गणना हुँदैन",
|
||||||
"emptyCreditLogs": "क्रेडिट लेनदेन छैन",
|
"emptyCreditLogs": "क्रेडिट लेनदेन छैन",
|
||||||
"creditFlow": {
|
"creditFlow": {
|
||||||
|
|||||||
@@ -68,7 +68,8 @@
|
|||||||
"warning": "登录即将过期",
|
"warning": "登录即将过期",
|
||||||
"remaining": "剩余 {{time}}",
|
"remaining": "剩余 {{time}}",
|
||||||
"autoRenewing": "正在自动续签...",
|
"autoRenewing": "正在自动续签...",
|
||||||
"renewNow": "立即续签"
|
"renewNow": "立即续签",
|
||||||
|
"refreshFailed": "Token 刷新失败,请返回主站重新进入"
|
||||||
},
|
},
|
||||||
"serverError": {
|
"serverError": {
|
||||||
"title": "服务器错误",
|
"title": "服务器错误",
|
||||||
@@ -234,6 +235,19 @@
|
|||||||
"number": "号码",
|
"number": "号码",
|
||||||
"selectionType": "种类",
|
"selectionType": "种类",
|
||||||
"rowTotal": "本行合计",
|
"rowTotal": "本行合计",
|
||||||
|
"selectAllTypes": "全选种类",
|
||||||
|
"setAllTypes": "统一设置所有行的种类",
|
||||||
|
"selectAll": "全选",
|
||||||
|
"syncColumnAmount": "同步 {{column}} 本列金额",
|
||||||
|
"selectAllProvider": "全选 {{provider}}",
|
||||||
|
"selectionTypeForRow": "第 {{row}} 行种类",
|
||||||
|
"selectionTypes": {
|
||||||
|
"straight": "正字",
|
||||||
|
"reverse": "来回",
|
||||||
|
"full_cover": "全保",
|
||||||
|
"full_play": "全打",
|
||||||
|
"half_play": "半打"
|
||||||
|
},
|
||||||
"stake": "下注金额",
|
"stake": "下注金额",
|
||||||
"rebate": "佣金 / 回水",
|
"rebate": "佣金 / 回水",
|
||||||
"actual": "实扣金额",
|
"actual": "实扣金额",
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export const useErrorStore = create<ErrorState>((set, get) => ({
|
|||||||
// 首屏与 SSR 一致为 false;真实离线状态由 useNetworkStatus 在 mount 后同步
|
// 首屏与 SSR 一致为 false;真实离线状态由 useNetworkStatus 在 mount 后同步
|
||||||
isOffline: false,
|
isOffline: false,
|
||||||
isServerError: false,
|
isServerError: false,
|
||||||
serverErrorMessage: "服务器暂时不可用,请稍后重试",
|
serverErrorMessage: "",
|
||||||
currentErrorType: null,
|
currentErrorType: null,
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
@@ -51,7 +51,7 @@ export const useErrorStore = create<ErrorState>((set, get) => ({
|
|||||||
setServerError: (isError: boolean, message?: string) => {
|
setServerError: (isError: boolean, message?: string) => {
|
||||||
set({
|
set({
|
||||||
isServerError: isError,
|
isServerError: isError,
|
||||||
serverErrorMessage: message || "服务器暂时不可用,请稍后重试",
|
serverErrorMessage: message ?? "",
|
||||||
});
|
});
|
||||||
// 更新当前错误类型 - 服务器错误优先级更高
|
// 更新当前错误类型 - 服务器错误优先级更高
|
||||||
if (isError) {
|
if (isError) {
|
||||||
|
|||||||
Reference in New Issue
Block a user