feat: 增强投注结果弹窗与投注网格功能
更新 HallBetResultDialog:根据成功与失败数量显示不同的结果图标与标题。 优化 HallBettingGrid:新增 place trace ID 管理机制,更好地处理投注提交流程,并防止重复扣费。 增强注单详情页面:针对临时状态中的注单自动刷新,提升用户体验。 新增多语言翻译:补充投注结果与状态相关文案,支持更完善的用户反馈。
This commit is contained in:
@@ -52,6 +52,13 @@ type TimelineRow = {
|
||||
time: string;
|
||||
};
|
||||
|
||||
const TRANSIENT_TICKET_STATUSES = new Set([
|
||||
"pending_confirm",
|
||||
"partial_pending_confirm",
|
||||
"pending_draw",
|
||||
"pending_payout",
|
||||
]);
|
||||
|
||||
type TicketItemDetailWithExtras = TicketItemDetailPayload & {
|
||||
timeline?: TimelineRow[];
|
||||
match_result?: {
|
||||
@@ -98,17 +105,23 @@ export function TicketOrderDetailScreen({ ticketNo }: { ticketNo: string }) {
|
||||
};
|
||||
}, [fromGroupKey, groupTickets, t]);
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setLoading(true);
|
||||
const load = useCallback(async (options?: { silent?: boolean }) => {
|
||||
if (!options?.silent) {
|
||||
setLoading(true);
|
||||
}
|
||||
setError(null);
|
||||
try {
|
||||
const row = await getTicketItemDetail(ticketNo);
|
||||
setData(row);
|
||||
} catch {
|
||||
setData(null);
|
||||
setError(t("orders.notFound"));
|
||||
if (!options?.silent) {
|
||||
setError(t("orders.notFound"));
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
if (!options?.silent) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
}, [ticketNo, t]);
|
||||
|
||||
@@ -118,6 +131,21 @@ export function TicketOrderDetailScreen({ ticketNo }: { ticketNo: string }) {
|
||||
});
|
||||
}, [load]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!data || !TRANSIENT_TICKET_STATUSES.has(data.status)) {
|
||||
return;
|
||||
}
|
||||
const refresh = () => void load({ silent: true });
|
||||
const intervalId = window.setInterval(refresh, 12_000);
|
||||
window.addEventListener("lottery-hall-refresh", refresh);
|
||||
window.addEventListener("lottery-wallet-refresh", refresh);
|
||||
return () => {
|
||||
window.clearInterval(intervalId);
|
||||
window.removeEventListener("lottery-hall-refresh", refresh);
|
||||
window.removeEventListener("lottery-wallet-refresh", refresh);
|
||||
};
|
||||
}, [data?.status, load]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<PlayerPanel
|
||||
|
||||
@@ -30,7 +30,18 @@ import { cn } from "@/lib/utils";
|
||||
import type { TicketItemListRow } from "@/types/api/ticket-items";
|
||||
|
||||
const ORDERS_PAGE_SIZE = 20;
|
||||
const STATUS_OPTIONS = ["pending_draw", "pending_payout", "settled_win", "settled_lose", "failed"] as const;
|
||||
const STATUS_OPTIONS = [
|
||||
"pending_confirm",
|
||||
"partial_pending_confirm",
|
||||
"placed",
|
||||
"pending_draw",
|
||||
"partial_failed",
|
||||
"pending_payout",
|
||||
"settled_win",
|
||||
"settled_lose",
|
||||
"failed",
|
||||
"refunded",
|
||||
] as const;
|
||||
|
||||
function parseYmd(value: string): Date | undefined {
|
||||
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
||||
@@ -141,6 +152,18 @@ export function TicketOrdersListScreen() {
|
||||
void fetchPage(1, false);
|
||||
}, [fetchPage, queryDrawNo, queryNumber, queryStatuses, fromDate, toDate]);
|
||||
|
||||
useEffect(() => {
|
||||
const refreshFromEvents = () => {
|
||||
void fetchPage(1, false);
|
||||
};
|
||||
window.addEventListener("lottery-hall-refresh", refreshFromEvents);
|
||||
window.addEventListener("lottery-wallet-refresh", refreshFromEvents);
|
||||
return () => {
|
||||
window.removeEventListener("lottery-hall-refresh", refreshFromEvents);
|
||||
window.removeEventListener("lottery-wallet-refresh", refreshFromEvents);
|
||||
};
|
||||
}, [fetchPage]);
|
||||
|
||||
useEffect(() => {
|
||||
const target = loadMoreRef.current;
|
||||
if (!target || loading || loadingMore || page >= lastPage) return;
|
||||
@@ -238,6 +261,9 @@ export function TicketOrdersListScreen() {
|
||||
}
|
||||
/>
|
||||
<PopoverContent align="start" className="w-auto border-[#dce7f7] p-2 shadow-[0_16px_40px_rgba(15,23,42,0.14)]">
|
||||
<p className="mb-2 px-1 text-[11px] leading-snug text-muted-foreground">
|
||||
{t("orders.dateRangeHint")}
|
||||
</p>
|
||||
<Calendar
|
||||
mode="range"
|
||||
month={calendarMonth}
|
||||
|
||||
Reference in New Issue
Block a user