- 在getPlayEffective接口中增加provider_code参数支持 - 优化接口调用时对currency和provider_code的传递逻辑 - hall-bet-preview-dialog新增previewLineKey方法,解决列表渲染key冲突问题 - 修改投注和结果弹窗中开注商标题的国际化调用方式 - hall-betting-grid中增加选中开注商的默认逻辑,接口调用时传递provider_code - 优化provider名称显示逻辑,完善开注商选择及摘要文本显示 - 订单详情页中显示开注商名称,提升显示准确性 - 补充i18n中开注商相关文案,支持多语言环境 - 更新PlayEffectiveOddsSlice和PlayEffectivePayload类型,加入provider_code字段支持
This commit is contained in:
@@ -11,7 +11,7 @@
|
|||||||
LOTTERY_API_UPSTREAM=http://127.0.0.1:8000
|
LOTTERY_API_UPSTREAM=http://127.0.0.1:8000
|
||||||
# 线上
|
# 线上
|
||||||
# LOTTERY_API_UPSTREAM=http://127.0.0.1:8000
|
# LOTTERY_API_UPSTREAM=http://127.0.0.1:8000
|
||||||
# LOTTERY_API_UPSTREAM=https://lotterylaravel.tanumo.com
|
# LOTTERY_API_UPSTREAM=https://lottery-api.cjdhr.top
|
||||||
|
|
||||||
# Next 开发:局域网 IP 访问(逗号分隔 host,无协议)
|
# Next 开发:局域网 IP 访问(逗号分隔 host,无协议)
|
||||||
# ALLOWED_DEV_ORIGINS=192.168.0.101
|
# ALLOWED_DEV_ORIGINS=192.168.0.101
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import type { PlayEffectivePayload } from "@/types/api/play-effective";
|
|||||||
export type GetPlayEffectiveParams = {
|
export type GetPlayEffectiveParams = {
|
||||||
/** 不传则后端取首个可下注币种(通常为 NPR) */
|
/** 不传则后端取首个可下注币种(通常为 NPR) */
|
||||||
currency?: string;
|
currency?: string;
|
||||||
|
/** 按开注商返回覆盖后的赔率;未传则返回通用赔率 */
|
||||||
|
provider_code?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,8 +19,13 @@ export function getPlayEffective(
|
|||||||
`/play/effective`,
|
`/play/effective`,
|
||||||
{
|
{
|
||||||
params:
|
params:
|
||||||
params?.currency !== undefined && params.currency !== ""
|
params
|
||||||
? { currency: params.currency }
|
? {
|
||||||
|
...(params.currency !== undefined && params.currency !== "" ? { currency: params.currency } : {}),
|
||||||
|
...(params.provider_code !== undefined && params.provider_code !== ""
|
||||||
|
? { provider_code: params.provider_code }
|
||||||
|
: {}),
|
||||||
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import {
|
|||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { formatMinorAsCurrency } from "@/lib/money";
|
import { formatMinorAsCurrency } from "@/lib/money";
|
||||||
import { playLabel } from "@/lib/play-labels";
|
import { playLabel } from "@/lib/play-labels";
|
||||||
import type { TicketPreviewData, TicketPreviewWarning } from "@/types/api/ticket";
|
import type { TicketPreviewData, TicketPreviewLine, TicketPreviewWarning } from "@/types/api/ticket";
|
||||||
|
|
||||||
type HallBetPreviewDialogProps = {
|
type HallBetPreviewDialogProps = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@@ -65,6 +65,16 @@ function providerLabel(providerName?: string | null, providerCode?: string | nul
|
|||||||
return providerName || providerCode || "-";
|
return providerName || providerCode || "-";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function previewLineKey(line: TicketPreviewLine, index: number): string {
|
||||||
|
return [
|
||||||
|
line.client_line_no,
|
||||||
|
line.provider_code ?? "provider",
|
||||||
|
line.play_code,
|
||||||
|
line.number,
|
||||||
|
index,
|
||||||
|
].join(":");
|
||||||
|
}
|
||||||
|
|
||||||
function SubmittingPanel() {
|
function SubmittingPanel() {
|
||||||
const { t } = useTranslation("player");
|
const { t } = useTranslation("player");
|
||||||
|
|
||||||
@@ -221,7 +231,7 @@ export function HallBetPreviewDialog({
|
|||||||
{t("orders.play")}
|
{t("orders.play")}
|
||||||
</th>
|
</th>
|
||||||
<th className="border-r border-[#dfe8f6] px-2 py-3 text-center font-black">
|
<th className="border-r border-[#dfe8f6] px-2 py-3 text-center font-black">
|
||||||
{t("hall.providers.title", { defaultValue: "开注商" })}
|
{t("hall.providers.title")}
|
||||||
</th>
|
</th>
|
||||||
<th className="border-r border-[#dfe8f6] px-2 py-3 text-center font-black">
|
<th className="border-r border-[#dfe8f6] px-2 py-3 text-center font-black">
|
||||||
{t("hall.preview.amount")}
|
{t("hall.preview.amount")}
|
||||||
@@ -238,8 +248,8 @@ export function HallBetPreviewDialog({
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{lines.map((ln) => (
|
{lines.map((ln, index) => (
|
||||||
<tr key={ln.client_line_no} className="border-t border-[#e8eef7] bg-white">
|
<tr key={previewLineKey(ln, index)} className="border-t border-[#e8eef7] bg-white">
|
||||||
<td className="border-r border-[#e8eef7] px-2 py-3 text-center">
|
<td className="border-r border-[#e8eef7] px-2 py-3 text-center">
|
||||||
<span className="inline-flex size-6 items-center justify-center rounded-full border border-[#dfe8f6] font-black text-[#304f86]">
|
<span className="inline-flex size-6 items-center justify-center rounded-full border border-[#dfe8f6] font-black text-[#304f86]">
|
||||||
{ln.client_line_no}
|
{ln.client_line_no}
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ export function HallBetResultDialog({
|
|||||||
{t("orders.play")}
|
{t("orders.play")}
|
||||||
</th>
|
</th>
|
||||||
<th className="border-r border-[#dfe8f6] px-2 py-2.5 text-center font-black">
|
<th className="border-r border-[#dfe8f6] px-2 py-2.5 text-center font-black">
|
||||||
{t("hall.providers.title", { defaultValue: "开注商" })}
|
{t("hall.providers.title")}
|
||||||
</th>
|
</th>
|
||||||
<th className="px-2 py-2.5 text-center font-black">
|
<th className="px-2 py-2.5 text-center font-black">
|
||||||
{t("hall.result.actualDeduct")}
|
{t("hall.result.actualDeduct")}
|
||||||
|
|||||||
@@ -482,12 +482,19 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
|||||||
}, []);
|
}, []);
|
||||||
const catalogSeqRef = useRef(0);
|
const catalogSeqRef = useRef(0);
|
||||||
const walletSeqRef = useRef(0);
|
const walletSeqRef = useRef(0);
|
||||||
|
const selectedCatalogProviderCode =
|
||||||
|
selectedProviderCodes[0] ??
|
||||||
|
betProviders.find((provider) => provider.is_default)?.code ??
|
||||||
|
betProviders[0]?.code;
|
||||||
|
|
||||||
const loadCatalog = useCallback(async () => {
|
const loadCatalog = useCallback(async () => {
|
||||||
const seq = ++catalogSeqRef.current;
|
const seq = ++catalogSeqRef.current;
|
||||||
setCatalogState({ kind: "loading" });
|
setCatalogState({ kind: "loading" });
|
||||||
try {
|
try {
|
||||||
const data = await getPlayEffective({ currency: currencyParam });
|
const data = await getPlayEffective({
|
||||||
|
currency: currencyParam,
|
||||||
|
provider_code: selectedCatalogProviderCode,
|
||||||
|
});
|
||||||
if (seq !== catalogSeqRef.current) return;
|
if (seq !== catalogSeqRef.current) return;
|
||||||
setCatalogState({ kind: "ok", data });
|
setCatalogState({ kind: "ok", data });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -495,7 +502,7 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
|||||||
const msg = e instanceof LotteryApiBizError ? e.message : t("hall.loadingError");
|
const msg = e instanceof LotteryApiBizError ? e.message : t("hall.loadingError");
|
||||||
setCatalogState({ kind: "error", message: msg });
|
setCatalogState({ kind: "error", message: msg });
|
||||||
}
|
}
|
||||||
}, [currencyParam, t]);
|
}, [currencyParam, selectedCatalogProviderCode, t]);
|
||||||
|
|
||||||
const refreshWallet = useCallback(async () => {
|
const refreshWallet = useCallback(async () => {
|
||||||
const seq = ++walletSeqRef.current;
|
const seq = ++walletSeqRef.current;
|
||||||
@@ -1257,14 +1264,13 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
|||||||
const providerSummaryText =
|
const providerSummaryText =
|
||||||
selectedProviderCodes.length > 0
|
selectedProviderCodes.length > 0
|
||||||
? t("hall.providers.summary", {
|
? t("hall.providers.summary", {
|
||||||
defaultValue: "已选 {{count}} 家,金额按每家公司计算",
|
|
||||||
count: providerSummaryCount,
|
count: providerSummaryCount,
|
||||||
})
|
})
|
||||||
: t("hall.providers.platformDefaultSummary", {
|
: implicitDefaultProvider
|
||||||
defaultValue: implicitDefaultProvider
|
? t("hall.providers.platformDefaultSummary", {
|
||||||
? `未选择时走平台默认(${implicitDefaultProvider.name})`
|
provider: implicitDefaultProvider.name,
|
||||||
: "未选择时走平台默认",
|
})
|
||||||
});
|
: t("hall.providers.platformDefaultSummaryNoProvider");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -1511,7 +1517,7 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
|||||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||||
<div className="flex flex-wrap items-center gap-1.5">
|
<div className="flex flex-wrap items-center gap-1.5">
|
||||||
<span className="mr-1 text-[11px] font-black text-[#304f86]">
|
<span className="mr-1 text-[11px] font-black text-[#304f86]">
|
||||||
{t("hall.providers.title", { defaultValue: "开注商" })}
|
{t("hall.providers.title")}
|
||||||
</span>
|
</span>
|
||||||
{!isMobile ? betProviders.map((provider) => {
|
{!isMobile ? betProviders.map((provider) => {
|
||||||
const checked = selectedProviderCodes.includes(provider.code);
|
const checked = selectedProviderCodes.includes(provider.code);
|
||||||
@@ -1544,11 +1550,9 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
|||||||
<span className="text-xs font-semibold text-[#58709d]">
|
<span className="text-xs font-semibold text-[#58709d]">
|
||||||
{selectedProviderNames.length > 0
|
{selectedProviderNames.length > 0
|
||||||
? selectedProviderNames.join(" / ")
|
? selectedProviderNames.join(" / ")
|
||||||
: t("hall.providers.platformDefault", {
|
: implicitDefaultProvider
|
||||||
defaultValue: implicitDefaultProvider
|
? t("hall.providers.platformDefault", { provider: implicitDefaultProvider.name })
|
||||||
? `平台默认(${implicitDefaultProvider.name})`
|
: t("hall.providers.platformDefaultNoProvider")}
|
||||||
: "平台默认",
|
|
||||||
})}
|
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ export function TicketOrderDetailScreen({ ticketNo }: { ticketNo: string }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-baseline justify-between gap-3">
|
<div className="flex items-baseline justify-between gap-3">
|
||||||
<span className="shrink-0 text-slate-500">
|
<span className="shrink-0 text-slate-500">
|
||||||
{t("hall.providers.title", { defaultValue: "开注商" })}
|
{t("hall.providers.title")}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-right font-black text-[#0b56b7]">
|
<span className="text-right font-black text-[#0b56b7]">
|
||||||
{providerLabel(data.provider_name, data.provider_code)}
|
{providerLabel(data.provider_name, data.provider_code)}
|
||||||
|
|||||||
@@ -169,6 +169,14 @@
|
|||||||
"updated": "Play configuration updated. The betting table has been refreshed.",
|
"updated": "Play configuration updated. The betting table has been refreshed.",
|
||||||
"oddsUpdated": "Odds updated. Please preview the ticket again."
|
"oddsUpdated": "Odds updated. Please preview the ticket again."
|
||||||
},
|
},
|
||||||
|
"providers": {
|
||||||
|
"title": "Bet provider",
|
||||||
|
"summary": "{{count}} selected. Amount is calculated per provider.",
|
||||||
|
"platformDefault": "Platform default ({{provider}})",
|
||||||
|
"platformDefaultNoProvider": "Platform default",
|
||||||
|
"platformDefaultSummary": "If none is selected, platform default is used ({{provider}}).",
|
||||||
|
"platformDefaultSummaryNoProvider": "If none is selected, platform default is used."
|
||||||
|
},
|
||||||
"jackpotBurst": {
|
"jackpotBurst": {
|
||||||
"title": "Jackpot Burst",
|
"title": "Jackpot Burst",
|
||||||
"subtitle": "Issue {{drawNo}} triggered a pool payout",
|
"subtitle": "Issue {{drawNo}} triggered a pool payout",
|
||||||
|
|||||||
@@ -169,6 +169,14 @@
|
|||||||
"updated": "प्ले कन्फिगरेसन अपडेट भयो। बेटिङ तालिका रिफ्रेस गरियो।",
|
"updated": "प्ले कन्फिगरेसन अपडेट भयो। बेटिङ तालिका रिफ्रेस गरियो।",
|
||||||
"oddsUpdated": "Odds अपडेट भयो। कृपया टिकट फेरि पूर्वावलोकन गर्नुहोस्।"
|
"oddsUpdated": "Odds अपडेट भयो। कृपया टिकट फेरि पूर्वावलोकन गर्नुहोस्।"
|
||||||
},
|
},
|
||||||
|
"providers": {
|
||||||
|
"title": "Bet provider",
|
||||||
|
"summary": "{{count}} चयन गरियो। रकम प्रत्येक provider अनुसार गणना हुन्छ।",
|
||||||
|
"platformDefault": "Platform default ({{provider}})",
|
||||||
|
"platformDefaultNoProvider": "Platform default",
|
||||||
|
"platformDefaultSummary": "कुनै चयन नभए platform default प्रयोग हुन्छ ({{provider}})।",
|
||||||
|
"platformDefaultSummaryNoProvider": "कुनै चयन नभए platform default प्रयोग हुन्छ।"
|
||||||
|
},
|
||||||
"jackpotBurst": {
|
"jackpotBurst": {
|
||||||
"title": "ज्याकपट बर्स्ट",
|
"title": "ज्याकपट बर्स्ट",
|
||||||
"subtitle": "इश्यू {{drawNo}} मा पूल payout ट्रिगर भयो",
|
"subtitle": "इश्यू {{drawNo}} मा पूल payout ट्रिगर भयो",
|
||||||
|
|||||||
@@ -168,6 +168,14 @@
|
|||||||
"updated": "玩法配置已更新,已刷新下注表格。",
|
"updated": "玩法配置已更新,已刷新下注表格。",
|
||||||
"oddsUpdated": "赔率已更新,请重新预览注单。"
|
"oddsUpdated": "赔率已更新,请重新预览注单。"
|
||||||
},
|
},
|
||||||
|
"providers": {
|
||||||
|
"title": "开注商",
|
||||||
|
"summary": "已选 {{count}} 家,金额按每家公司计算",
|
||||||
|
"platformDefault": "平台默认({{provider}})",
|
||||||
|
"platformDefaultNoProvider": "平台默认",
|
||||||
|
"platformDefaultSummary": "未选择时走平台默认({{provider}})",
|
||||||
|
"platformDefaultSummaryNoProvider": "未选择时走平台默认"
|
||||||
|
},
|
||||||
"jackpotBurst": {
|
"jackpotBurst": {
|
||||||
"title": "Jackpot 爆池",
|
"title": "Jackpot 爆池",
|
||||||
"subtitle": "期号 {{drawNo}} 触发奖池派发",
|
"subtitle": "期号 {{drawNo}} 触发奖池派发",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export type PlayEffectiveConfigSlice = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type PlayEffectiveOddsSlice = {
|
export type PlayEffectiveOddsSlice = {
|
||||||
|
provider_code?: string;
|
||||||
prize_scope: string;
|
prize_scope: string;
|
||||||
odds_value: number;
|
odds_value: number;
|
||||||
rebate_rate: string;
|
rebate_rate: string;
|
||||||
@@ -50,6 +51,7 @@ export type PlayEffectiveRiskCapRow = {
|
|||||||
|
|
||||||
export type PlayEffectivePayload = {
|
export type PlayEffectivePayload = {
|
||||||
currency_code: string;
|
currency_code: string;
|
||||||
|
provider_code?: string;
|
||||||
effective_versions: {
|
effective_versions: {
|
||||||
play_config: PlayEffectiveVersionHead;
|
play_config: PlayEffectiveVersionHead;
|
||||||
odds: PlayEffectiveVersionHead;
|
odds: PlayEffectiveVersionHead;
|
||||||
|
|||||||
Reference in New Issue
Block a user