feat: 增强投注结果弹窗与投注网格功能

更新 HallBetResultDialog:根据成功与失败数量显示不同的结果图标与标题。
优化 HallBettingGrid:新增 place trace ID 管理机制,更好地处理投注提交流程,并防止重复扣费。
增强注单详情页面:针对临时状态中的注单自动刷新,提升用户体验。
新增多语言翻译:补充投注结果与状态相关文案,支持更完善的用户反馈。
This commit is contained in:
2026-05-26 14:50:21 +08:00
parent d768a3f6ba
commit 51b2a36cc5
11 changed files with 257 additions and 90 deletions

View File

@@ -2,7 +2,7 @@
import { isAxiosError } from "axios";
import { Loader2 } from "lucide-react";
import { useMemo, useState, type ReactNode } from "react";
import { useMemo, useRef, useState, type ReactNode } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
@@ -149,6 +149,7 @@ export function TransferInPanel({
const [amountText, setAmountText] = useState("");
const [submitting, setSubmitting] = useState(false);
const [localError, setLocalError] = useState<string | null>(null);
const idempotentKeyRef = useRef<string | null>(null);
const tid = `${idPrefix}in-amount`;
const parsedMinor = useMemo(
@@ -159,25 +160,31 @@ export function TransferInPanel({
parsedMinor != null ? lotteryMinor + parsedMinor : lotteryMinor;
const submit = async () => {
if (submitting) {
return;
}
setLocalError(null);
if (parsedMinor == null || parsedMinor < 1) {
setLocalError(t("wallet.invalidAmount"));
return;
}
if (idempotentKeyRef.current === null) {
idempotentKeyRef.current = randomIdempotentKey();
}
setSubmitting(true);
try {
await postWalletTransferIn({
amount: parsedMinor,
currency,
idempotent_key: randomIdempotentKey(),
idempotent_key: idempotentKeyRef.current,
});
idempotentKeyRef.current = null;
toast.success(t("wallet.successIn"));
setAmountText("");
await onSuccess();
emitWalletRefresh();
} catch (e) {
if (await handleTransferMaybePending(e, onSuccess, t)) {
setLocalError(formatWalletClientError(e, t));
return;
}
setLocalError(formatWalletClientError(e, t));
@@ -270,6 +277,7 @@ export function TransferOutPanel({
const [amountText, setAmountText] = useState("");
const [submitting, setSubmitting] = useState(false);
const [localError, setLocalError] = useState<string | null>(null);
const idempotentKeyRef = useRef<string | null>(null);
const tid = `${idPrefix}out-amount`;
const parsedMinor = useMemo(
@@ -288,6 +296,9 @@ export function TransferOutPanel({
};
const submit = async () => {
if (submitting) {
return;
}
setLocalError(null);
if (parsedMinor == null || parsedMinor < 1) {
setLocalError(t("wallet.invalidAmount"));
@@ -297,20 +308,23 @@ export function TransferOutPanel({
setLocalError(t("wallet.outExceeds"));
return;
}
if (idempotentKeyRef.current === null) {
idempotentKeyRef.current = randomIdempotentKey();
}
setSubmitting(true);
try {
await postWalletTransferOut({
amount: parsedMinor,
currency,
idempotent_key: randomIdempotentKey(),
idempotent_key: idempotentKeyRef.current,
});
idempotentKeyRef.current = null;
toast.success(t("wallet.successOut"));
setAmountText("");
await onSuccess();
emitWalletRefresh();
} catch (e) {
if (await handleTransferMaybePending(e, onSuccess, t)) {
setLocalError(formatWalletClientError(e, t));
return;
}
setLocalError(formatWalletClientError(e, t));