feat: 集成玩家余额 WebSocket 监听并增强风控预警处理
新增 PlayerBalanceWsListener,用于处理玩家余额的实时更新。 引入 RiskWarningWsEvent 类型,并更新 HallBettingGrid 以支持实时风控预警处理。 增强 cellRiskState 方法,新增 warning 状态支持,提升风控管理能力。 更新英文、尼泊尔语及中文翻译,新增玩家余额更新相关文案。
This commit is contained in:
80
src/hooks/use-player-balance-ws.ts
Normal file
80
src/hooks/use-player-balance-ws.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { getLotteryEcho } from "@/lib/lottery-echo";
|
||||
import { useActivePlayerCurrency } from "@/hooks/use-active-player-currency";
|
||||
import { usePlayerSessionStore } from "@/stores/player-session-store";
|
||||
|
||||
type BalanceUpdateWsEvent = {
|
||||
player_id?: number;
|
||||
currency_code?: string;
|
||||
balance_minor?: number;
|
||||
change_minor?: number;
|
||||
change_formatted?: string;
|
||||
reason?: string;
|
||||
};
|
||||
|
||||
const REASON_I18N_KEY: Record<string, string> = {
|
||||
transfer_in: "wallet.wsReason.transferIn",
|
||||
transfer_out: "wallet.wsReason.transferOut",
|
||||
bet: "wallet.wsReason.bet",
|
||||
prize: "wallet.wsReason.prize",
|
||||
refund: "wallet.wsReason.refund",
|
||||
};
|
||||
|
||||
/**
|
||||
* 订阅 `player.{id}` 私有频道的 `balance.update`,刷新余额并 Toast。
|
||||
*/
|
||||
export function usePlayerBalanceWs(): void {
|
||||
const { t } = useTranslation("player");
|
||||
const playerId = usePlayerSessionStore((state) => state.profile?.id);
|
||||
const bearerToken = usePlayerSessionStore((state) => state.bearerToken);
|
||||
const { activeCurrency } = useActivePlayerCurrency();
|
||||
|
||||
useEffect(() => {
|
||||
if (!playerId || !bearerToken) {
|
||||
return;
|
||||
}
|
||||
|
||||
const echo = getLotteryEcho();
|
||||
if (!echo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const channelName = `player.${playerId}`;
|
||||
const channel = echo.channel(channelName);
|
||||
|
||||
const onBalanceUpdate = (evt: BalanceUpdateWsEvent): void => {
|
||||
const currency = evt.currency_code?.trim().toUpperCase();
|
||||
if (currency && currency !== activeCurrency.toUpperCase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.dispatchEvent(new Event("lottery-wallet-refresh"));
|
||||
|
||||
const changeLabel =
|
||||
typeof evt.change_formatted === "string" && evt.change_formatted !== ""
|
||||
? evt.change_formatted
|
||||
: evt.change_minor != null
|
||||
? String(evt.change_minor)
|
||||
: "";
|
||||
|
||||
const reasonKey =
|
||||
evt.reason && REASON_I18N_KEY[evt.reason]
|
||||
? REASON_I18N_KEY[evt.reason]
|
||||
: "wallet.wsReason.unknown";
|
||||
const reasonLabel = t(reasonKey);
|
||||
|
||||
toast.message(t("wallet.wsBalanceUpdated", { change: changeLabel, reason: reasonLabel }));
|
||||
};
|
||||
|
||||
channel.listen(".balance.update", onBalanceUpdate);
|
||||
|
||||
return () => {
|
||||
channel.stopListening(".balance.update");
|
||||
};
|
||||
}, [activeCurrency, bearerToken, playerId, t]);
|
||||
}
|
||||
Reference in New Issue
Block a user