refactor(layout, i18n, admin): 优化布局结构与多语言支持
调整 AdminShell 组件的子组件顺序,提升代码可读性。更新 admin-breadcrumb 组件,简化导航标签翻译逻辑,确保多语言支持的一致性。重构 admin-language-switcher 组件,优化语言切换的用户体验,增强界面交互性。更新多语言配置,新增登录界面的副标题,提升用户体验。
This commit is contained in:
@@ -51,34 +51,16 @@ import type {
|
||||
OddsVersionDetail,
|
||||
} from "@/types/api/admin-config";
|
||||
|
||||
import { ConfigWorkflowSection } from "@/modules/config/config-workflow-section";
|
||||
import {
|
||||
inferRebatePercentFromDimension,
|
||||
rateToPercentUi,
|
||||
} from "@/modules/config/doc/odds-rebate-rates";
|
||||
import { PRIZE_SCOPE_ORDER } from "@/modules/config/doc/prize-scopes";
|
||||
|
||||
const SETTLEMENT_GROUP = "settlement";
|
||||
const APPLY_REBATE_TO_PAYOUT_KEY = "settlement.apply_rebate_to_payout";
|
||||
|
||||
function rateToPercentUi(rateStr: string): string {
|
||||
const n = Number.parseFloat(rateStr);
|
||||
if (!Number.isFinite(n)) {
|
||||
return "0.00";
|
||||
}
|
||||
return (Math.round(n * 10000) / 100).toFixed(2);
|
||||
}
|
||||
|
||||
function inferPercentFrom(dim: 2 | 3 | 4, rows: OddsItemRow[], typeList: AdminPlayTypeRow[]): string {
|
||||
const codes = typeList
|
||||
.filter((t) => (t.dimension ?? 2) === dim)
|
||||
.map((t) => t.play_code)
|
||||
.sort((a, b) => a.localeCompare(b));
|
||||
const scope = PRIZE_SCOPE_ORDER[0];
|
||||
for (const code of codes) {
|
||||
const hit = rows.find((r) => r.play_code === code && r.prize_scope === scope);
|
||||
if (hit) {
|
||||
return rateToPercentUi(String(hit.rebate_rate));
|
||||
}
|
||||
}
|
||||
return "0";
|
||||
}
|
||||
|
||||
function dimensionDistinctPrimaryScopePercents(
|
||||
dim: 2 | 3 | 4,
|
||||
rows: OddsItemRow[],
|
||||
@@ -101,6 +83,8 @@ function dimensionDistinctPrimaryScopePercents(
|
||||
|
||||
type RebateConfigDocScreenProps = {
|
||||
embedded?: boolean;
|
||||
/** 合并页第 3 步卡片 */
|
||||
mergedSection?: boolean;
|
||||
workspace?: OddsConfigWorkspace;
|
||||
versionId?: string;
|
||||
onVersionIdChange?: (id: string) => void;
|
||||
@@ -108,6 +92,7 @@ type RebateConfigDocScreenProps = {
|
||||
|
||||
export function RebateConfigDocScreen({
|
||||
embedded = false,
|
||||
mergedSection = false,
|
||||
workspace,
|
||||
versionId: controlledVersionId,
|
||||
onVersionIdChange,
|
||||
@@ -205,9 +190,9 @@ export function RebateConfigDocScreen({
|
||||
if (!workspace) {
|
||||
return;
|
||||
}
|
||||
setP2(inferPercentFrom(2, workspace.draftRows, workspace.types));
|
||||
setP3(inferPercentFrom(3, workspace.draftRows, workspace.types));
|
||||
setP4(inferPercentFrom(4, workspace.draftRows, workspace.types));
|
||||
setP2(inferRebatePercentFromDimension(2, workspace.draftRows, workspace.types));
|
||||
setP3(inferRebatePercentFromDimension(3, workspace.draftRows, workspace.types));
|
||||
setP4(inferRebatePercentFromDimension(4, workspace.draftRows, workspace.types));
|
||||
}, [workspace?.draftRows, workspace?.types, workspace]);
|
||||
|
||||
async function handleWinEnjoyChange(checked: boolean): Promise<void> {
|
||||
@@ -236,9 +221,9 @@ export function RebateConfigDocScreen({
|
||||
const rows = d.items.map((it) => ({ ...it }));
|
||||
setDetail(d);
|
||||
setDraftRows(rows);
|
||||
setP2(inferPercentFrom(2, rows, typeList));
|
||||
setP3(inferPercentFrom(3, rows, typeList));
|
||||
setP4(inferPercentFrom(4, rows, typeList));
|
||||
setP2(inferRebatePercentFromDimension(2, rows, typeList));
|
||||
setP3(inferRebatePercentFromDimension(3, rows, typeList));
|
||||
setP4(inferRebatePercentFromDimension(4, rows, typeList));
|
||||
} catch (e) {
|
||||
toast.error(e instanceof LotteryApiBizError ? e.message : t("errors.loadFailed", { ns: "common" }));
|
||||
setDetail(null);
|
||||
@@ -357,9 +342,9 @@ export function RebateConfigDocScreen({
|
||||
setDetail(d);
|
||||
setDraftRows(rows);
|
||||
}
|
||||
setP2(inferPercentFrom(2, rows, resolvedTypes));
|
||||
setP3(inferPercentFrom(3, rows, resolvedTypes));
|
||||
setP4(inferPercentFrom(4, rows, resolvedTypes));
|
||||
setP2(inferRebatePercentFromDimension(2, rows, resolvedTypes));
|
||||
setP3(inferRebatePercentFromDimension(3, rows, resolvedTypes));
|
||||
setP4(inferRebatePercentFromDimension(4, rows, resolvedTypes));
|
||||
toast.success(t("versionActions.saveDraft", { ns: "config" }));
|
||||
void (workspace?.refreshList() ?? refreshList());
|
||||
} catch (e) {
|
||||
@@ -383,9 +368,9 @@ export function RebateConfigDocScreen({
|
||||
setDetail(d);
|
||||
setDraftRows(rows);
|
||||
}
|
||||
setP2(inferPercentFrom(2, rows, resolvedTypes));
|
||||
setP3(inferPercentFrom(3, rows, resolvedTypes));
|
||||
setP4(inferPercentFrom(4, rows, resolvedTypes));
|
||||
setP2(inferRebatePercentFromDimension(2, rows, resolvedTypes));
|
||||
setP3(inferRebatePercentFromDimension(3, rows, resolvedTypes));
|
||||
setP4(inferRebatePercentFromDimension(4, rows, resolvedTypes));
|
||||
toast.success(t("rebate.publishSuccess", { ns: "config" }));
|
||||
void (workspace?.refreshList() ?? refreshList());
|
||||
setSelectedId(String(d.id));
|
||||
@@ -414,9 +399,9 @@ export function RebateConfigDocScreen({
|
||||
setDetail(d);
|
||||
setDraftRows(rows);
|
||||
}
|
||||
setP2(inferPercentFrom(2, rows, resolvedTypes));
|
||||
setP3(inferPercentFrom(3, rows, resolvedTypes));
|
||||
setP4(inferPercentFrom(4, rows, resolvedTypes));
|
||||
setP2(inferRebatePercentFromDimension(2, rows, resolvedTypes));
|
||||
setP3(inferRebatePercentFromDimension(3, rows, resolvedTypes));
|
||||
setP4(inferRebatePercentFromDimension(4, rows, resolvedTypes));
|
||||
} catch (e) {
|
||||
toast.error(e instanceof LotteryApiBizError ? e.message : t("rebate.createDraftFailed", { ns: "config" }));
|
||||
} finally {
|
||||
@@ -457,9 +442,9 @@ export function RebateConfigDocScreen({
|
||||
setDetail(d);
|
||||
setDraftRows(rows);
|
||||
}
|
||||
setP2(inferPercentFrom(2, rows, resolvedTypes));
|
||||
setP3(inferPercentFrom(3, rows, resolvedTypes));
|
||||
setP4(inferPercentFrom(4, rows, resolvedTypes));
|
||||
setP2(inferRebatePercentFromDimension(2, rows, resolvedTypes));
|
||||
setP3(inferRebatePercentFromDimension(3, rows, resolvedTypes));
|
||||
setP4(inferRebatePercentFromDimension(4, rows, resolvedTypes));
|
||||
setRollbackOpen(false);
|
||||
setRollbackTarget(null);
|
||||
} catch (e) {
|
||||
@@ -658,6 +643,23 @@ export function RebateConfigDocScreen({
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
if (embedded && mergedSection) {
|
||||
return (
|
||||
<>
|
||||
<ConfigWorkflowSection
|
||||
step={3}
|
||||
title={t("nav.items.rebate", { ns: "config" })}
|
||||
description={t("rebate.sectionHint", { ns: "config" })}
|
||||
contentClassName="space-y-5"
|
||||
>
|
||||
{fieldsBlock}
|
||||
</ConfigWorkflowSection>
|
||||
{rollbackDialog}
|
||||
<ConfirmDialog />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (embedded) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
|
||||
Reference in New Issue
Block a user