feat: 增强钱包 API 与玩家会话管理
- 新增钱包 API 函数:getWalletLogs(获取钱包日志)、postWalletTransferIn(充值)及 postWalletTransferOut(提现) - 更新钱包相关类型定义,提升类型安全性 - 改进玩家会话管理:若当前无玩家资料,则自动拉取玩家信息 - 增强入口网关对过期会话的错误处理能力 - 更新 UI 组件,以适配新的结构与功能
This commit is contained in:
@@ -4,7 +4,8 @@ import axios, {
|
||||
type AxiosResponse,
|
||||
} from "axios";
|
||||
|
||||
import { withPlayerAuthHeader } from "@/lib/lottery-auth";
|
||||
import { setPlayerBearerToken, withPlayerAuthHeader } from "@/lib/lottery-auth";
|
||||
import { clearPersistedPlayerBearerToken } from "@/lib/player-session";
|
||||
import { withLotteryLocaleHeaders } from "@/lib/lottery-locale";
|
||||
import {
|
||||
LotteryApiBizError,
|
||||
@@ -23,6 +24,25 @@ export const lotteryHttp = axios.create({
|
||||
headers: { Accept: "application/json" },
|
||||
});
|
||||
|
||||
/** 站内接口 401:清本地会话并回入口,与 {@link EntryGate} `session=expired` 衔接 */
|
||||
lotteryHttp.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error: unknown) => {
|
||||
if (
|
||||
isAxiosError(error) &&
|
||||
error.response?.status === 401 &&
|
||||
typeof window !== "undefined"
|
||||
) {
|
||||
clearPersistedPlayerBearerToken();
|
||||
setPlayerBearerToken(null);
|
||||
if (window.location.pathname !== "/") {
|
||||
window.location.replace("/?session=expired");
|
||||
}
|
||||
}
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* 对 **payload**(通常是 `response.data`)校验信封并成功时返回 `data`;
|
||||
* `code !== 0` 抛 {@link LotteryApiBizError}。
|
||||
|
||||
37
src/lib/money.ts
Normal file
37
src/lib/money.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 与后端约定:金额存最小货币单位(如 NPR 2 位小数 → 分);展示时除以 10^decimals。
|
||||
*/
|
||||
|
||||
const DEFAULT_DECIMAL_PLACES = 2;
|
||||
|
||||
export function formatMinorAsCurrency(
|
||||
minor: number | string,
|
||||
currencyCode: string,
|
||||
decimalPlaces = DEFAULT_DECIMAL_PLACES,
|
||||
): string {
|
||||
const n = typeof minor === "string" ? Number(minor) : minor;
|
||||
if (!Number.isFinite(n)) return `${currencyCode} —`;
|
||||
const divisor = 10 ** decimalPlaces;
|
||||
const major = n / divisor;
|
||||
return `${currencyCode} ${major.toLocaleString(undefined, {
|
||||
minimumFractionDigits: decimalPlaces,
|
||||
maximumFractionDigits: decimalPlaces,
|
||||
})}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户输入如 `1000` 或 `1000.5` → 最小货币单位整数。
|
||||
*/
|
||||
export function parseDecimalInputToMinor(
|
||||
raw: string,
|
||||
decimalPlaces = DEFAULT_DECIMAL_PLACES,
|
||||
): number | null {
|
||||
const cleaned = raw.replace(/,/g, "").trim();
|
||||
if (cleaned === "") return null;
|
||||
const n = Number(cleaned);
|
||||
if (!Number.isFinite(n) || n < 0) return null;
|
||||
const factor = 10 ** decimalPlaces;
|
||||
const minor = Math.round(n * factor);
|
||||
if (!Number.isSafeInteger(minor)) return null;
|
||||
return minor;
|
||||
}
|
||||
43
src/lib/wallet-api-error.ts
Normal file
43
src/lib/wallet-api-error.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { isAxiosError } from "axios";
|
||||
|
||||
import { LotteryApiBizError } from "@/types/api/errors";
|
||||
|
||||
/** 钱包 / 转账 API 对用户展示的中文说明(优先业务码,其次 HTTP) */
|
||||
export function formatWalletClientError(error: unknown): string {
|
||||
if (error instanceof LotteryApiBizError) {
|
||||
const m = WALLET_CODE_MESSAGES[error.code];
|
||||
if (m) return m;
|
||||
if (error.message.trim()) return error.message;
|
||||
}
|
||||
if (isAxiosError(error)) {
|
||||
if (error.response?.status === 401) {
|
||||
return "登录已失效,请返回重新进入。";
|
||||
}
|
||||
if (error.response?.status === 409) {
|
||||
return "转账处理中,请稍后刷新;若长时间未到账请联系客服。";
|
||||
}
|
||||
if (!error.response) {
|
||||
return "网络异常,请检查连接后重试。";
|
||||
}
|
||||
if (error.code === "ECONNABORTED") {
|
||||
return "请求超时,请稍后重试。";
|
||||
}
|
||||
}
|
||||
if (error instanceof Error && error.message.trim()) {
|
||||
return error.message;
|
||||
}
|
||||
return "请求失败,请稍后重试。";
|
||||
}
|
||||
|
||||
const WALLET_CODE_MESSAGES: Record<number, string> = {
|
||||
1001: "彩票钱包余额不足,请转入或减少转出金额。",
|
||||
1002: "转账处理中,请稍后在本页刷新余额;若长时间未到账请联系客服。",
|
||||
1003: "金额超出单笔或每日限额,请调整金额。",
|
||||
1004: "当前已暂停转入,请稍后再试或联系客服。",
|
||||
1005: "币种无效或未开通。",
|
||||
1006: "当前已暂停转出,请稍后再试或联系客服。",
|
||||
1007: "彩票钱包已冻结,暂无法划转。",
|
||||
1008: "金额格式不正确。",
|
||||
1009: "主站未能完成本次划转,请稍后重试。",
|
||||
1010: "请勿用同一幂等键发起不同金额的转账。",
|
||||
};
|
||||
Reference in New Issue
Block a user