refactor: 优化管理端配置页紧凑布局与时间展示

This commit is contained in:
2026-05-20 16:57:47 +08:00
parent 08a11a1589
commit 6ecbaf5fb4
13 changed files with 93 additions and 97 deletions

View File

@@ -407,7 +407,11 @@ export function OddsConfigDocScreen() {
key={t.id}
type="button"
variant={catTab === t.id ? "default" : "outline"}
className={cn(catTab === t.id && "shadow-sm")}
size="xs"
className={cn(
"h-7 rounded-full px-3 text-xs font-medium",
catTab === t.id ? "shadow-sm" : "bg-white text-slate-900",
)}
onClick={() => setCatTab(t.id)}
>
{t.label}
@@ -427,7 +431,7 @@ export function OddsConfigDocScreen() {
type="button"
variant={resolvedPlayCode === t.play_code ? "secondary" : "outline"}
className={cn(
"h-9 border-slate-300 px-5 text-[18px] font-medium",
"h-8 rounded-full border-slate-300 px-4 text-sm font-medium",
resolvedPlayCode === t.play_code
? "border-slate-950 bg-slate-950 text-white shadow-sm hover:bg-slate-900"
: "bg-white text-slate-900 hover:border-slate-400 hover:bg-slate-50",
@@ -470,20 +474,25 @@ export function OddsConfigDocScreen() {
</div>
{detail ? (
<p className="text-sm text-muted-foreground">
{t("odds.activeVersionPrefix", { ns: "config" })}
{activeHead ? (
<>
v{activeHead.version_no}
{activeHead.effective_at ? ` · ${formatDt(activeHead.effective_at)}` : ""}
</>
) : (
"—"
)}
{!isDraft ? (
<span className="text-amber-600 dark:text-amber-400"> - {t("odds.readOnlyHint", { ns: "config" })}</span>
) : null}
</p>
<div className="space-y-1 text-sm">
<p className="text-muted-foreground">
{t("odds.activeVersionPrefix", { ns: "config" })}
{activeHead ? (
<>
v{activeHead.version_no}
{activeHead.effective_at ? ` · ${formatDt(activeHead.effective_at)}` : ""}
</>
) : (
"—"
)}
{!isDraft ? (
<span className="text-amber-600 dark:text-amber-400">
{" "}
- {t("odds.readOnlyHint", { ns: "config" })}
</span>
) : null}
</p>
</div>
) : null}
{error ? <p className="text-sm text-destructive">{error}</p> : null}

View File

@@ -37,6 +37,7 @@ import {
import { ConfigReadonlyValue } from "@/modules/config/config-readonly-value";
import { ConfigVersionActions } from "@/modules/config/config-version-actions";
import { ConfigVersionSwitcher } from "@/modules/config/config-version-switcher";
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
import { LotteryApiBizError } from "@/types/api/errors";
import type {
ConfigVersionSummary,
@@ -129,6 +130,7 @@ function buildPlayConfigSavePayload(
export function PlayConfigDocScreen() {
const { t } = useTranslation(["config", "adminUsers", "common"]);
const formatDt = useAdminDateTimeFormatter();
const [list, setList] = useState<ConfigVersionSummary[]>([]);
const [selectedId, setSelectedId] = useState("");
const [detail, setDetail] = useState<PlayConfigVersionDetail | null>(null);
@@ -408,7 +410,7 @@ export function PlayConfigDocScreen() {
{activeHead ? (
<>
{t("play.activeVersion", { ns: "config", version: activeHead.version_no })}
{activeHead.effective_at ? ` · ${activeHead.effective_at}` : ""}
{activeHead.effective_at ? ` · ${formatDt(activeHead.effective_at)}` : ""}
</>
) : null}
{!isDraft ? (
@@ -425,9 +427,6 @@ export function PlayConfigDocScreen() {
<div className="mb-3 flex flex-wrap items-center justify-between gap-2">
<div>
<p className="text-sm font-medium">{t("play.batchSwitchesTitle", { ns: "config" })}</p>
<p className="text-xs text-muted-foreground">
{t("play.batchSwitchesDesc", { ns: "config" })}
</p>
</div>
{!isDraft ? (
<span className="text-xs text-amber-600 dark:text-amber-400">

View File

@@ -377,9 +377,6 @@ export function RebateConfigDocScreen() {
<Label htmlFor="win-enjoy" className="font-medium leading-snug">
{t("rebate.winEnjoy.label", { ns: "config" })}
</Label>
<p className="text-sm text-muted-foreground">
{t("rebate.winEnjoy.description", { ns: "config" })}
</p>
</div>
</div>

View File

@@ -364,7 +364,7 @@ export function RiskCapDocScreen() {
{detail ? (
<p className="text-sm text-muted-foreground">
{t("riskCap.effectiveAt", { ns: "config", value: detail.effective_at ? formatDt(detail.effective_at) : "—" })} · {t("riskCap.note", { ns: "config", value: detail.reason ?? "—" })}
{t("riskCap.effectiveAt", { ns: "config", value: detail.effective_at ? formatDt(detail.effective_at) : "—" })}
{!isDraft ? (
<span className="text-amber-600 dark:text-amber-400"> - {t("riskCap.readOnlyHint", { ns: "config" })}</span>
) : null}
@@ -376,9 +376,6 @@ export function RiskCapDocScreen() {
<section className="space-y-3 rounded-lg border bg-muted/20 p-4">
<h3 className="text-sm font-medium">{t("riskCap.defaultCap.title", { ns: "config" })}</h3>
<p className="text-sm text-muted-foreground">
{t("riskCap.defaultCap.description", { ns: "config" })}
</p>
<div className="flex flex-wrap items-end gap-2">
<div className="grid gap-1">
<Label htmlFor="default-cap">{t("riskCap.defaultCap.fieldLabel", { ns: "config" })}</Label>
@@ -503,9 +500,6 @@ export function RiskCapDocScreen() {
<section className="space-y-3">
<h3 className="text-sm font-medium">{t("riskCap.occupancy.title", { ns: "config" })}</h3>
<p className="text-sm text-muted-foreground">
{t("riskCap.occupancy.description", { ns: "config" })}
</p>
<div className="flex flex-wrap gap-3 items-end">
<div className="grid gap-1">
<Label htmlFor="occ-search">{t("riskCap.occupancy.searchLabel", { ns: "config" })}</Label>

View File

@@ -115,9 +115,6 @@ export function WalletConfigDocScreen() {
<CardTitle>{t("wallet.title", { ns: "config" })}</CardTitle>
</CardHeader>
<CardContent className="space-y-6">
<p className="text-sm text-muted-foreground">
{t("wallet.description", { ns: "config" })}
</p>
<div className="grid gap-6 sm:grid-cols-2">
<div className="space-y-2">
<Label htmlFor="in-min">{t("wallet.fields.inMin", { ns: "config" })}</Label>
@@ -131,9 +128,6 @@ export function WalletConfigDocScreen() {
onChange={(e) => handleChange("inMin", e.target.value)}
disabled={loading || saving}
/>
<p className="text-xs text-muted-foreground">
{t("wallet.hints.inMin", { ns: "config" })}
</p>
</div>
<div className="space-y-2">
<Label htmlFor="in-max">{t("wallet.fields.inMax", { ns: "config" })}</Label>
@@ -147,9 +141,6 @@ export function WalletConfigDocScreen() {
onChange={(e) => handleChange("inMax", e.target.value)}
disabled={loading || saving}
/>
<p className="text-xs text-muted-foreground">
{t("wallet.hints.inMax", { ns: "config" })}
</p>
</div>
<div className="space-y-2">
<Label htmlFor="out-min">{t("wallet.fields.outMin", { ns: "config" })}</Label>
@@ -163,9 +154,6 @@ export function WalletConfigDocScreen() {
onChange={(e) => handleChange("outMin", e.target.value)}
disabled={loading || saving}
/>
<p className="text-xs text-muted-foreground">
{t("wallet.hints.outMin", { ns: "config" })}
</p>
</div>
<div className="space-y-2">
<Label htmlFor="out-max">{t("wallet.fields.outMax", { ns: "config" })}</Label>
@@ -179,9 +167,6 @@ export function WalletConfigDocScreen() {
onChange={(e) => handleChange("outMax", e.target.value)}
disabled={loading || saving}
/>
<p className="text-xs text-muted-foreground">
{t("wallet.hints.outMax", { ns: "config" })}
</p>
</div>
</div>
<div className="flex items-center gap-4">