feat(config): 重构配置模块导航与版本切换,新增版本删除能力
This commit is contained in:
@@ -4,6 +4,7 @@ import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import {
|
||||
deleteOddsVersion,
|
||||
getAdminPlayTypes,
|
||||
getOddsVersion,
|
||||
getOddsVersions,
|
||||
@@ -23,21 +24,7 @@ import {
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
} from "@/components/ui/sheet";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { ConfigVersionSwitcher } from "@/modules/config/config-version-switcher";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
|
||||
import { LotteryApiBizError } from "@/types/api/errors";
|
||||
@@ -91,7 +78,6 @@ export function OddsConfigDocScreen() {
|
||||
|
||||
const [rollbackOpen, setRollbackOpen] = useState(false);
|
||||
const [rollbackTarget, setRollbackTarget] = useState<ConfigVersionSummary | null>(null);
|
||||
const [historyOpen, setHistoryOpen] = useState(false);
|
||||
|
||||
const refreshTypes = useCallback(async () => {
|
||||
setLoadingTypes(true);
|
||||
@@ -332,6 +318,22 @@ export function OddsConfigDocScreen() {
|
||||
|
||||
const activeHead = list.find((x) => x.status === "active");
|
||||
|
||||
async function handleDeleteVersion(row: ConfigVersionSummary) {
|
||||
try {
|
||||
await deleteOddsVersion(row.id);
|
||||
toast.success("已删除该版本");
|
||||
await refreshList();
|
||||
} catch (e) {
|
||||
toast.error(e instanceof LotteryApiBizError ? e.message : "删除失败");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function requestRollback(row: ConfigVersionSummary) {
|
||||
setRollbackTarget(row);
|
||||
setRollbackOpen(true);
|
||||
}
|
||||
|
||||
const catTabs: { id: CatTab; label: string }[] = [
|
||||
{ id: "all", label: "全部" },
|
||||
{ id: "d4", label: "4D" },
|
||||
@@ -340,8 +342,6 @@ export function OddsConfigDocScreen() {
|
||||
{ id: "jackpot", label: "Jackpot" },
|
||||
];
|
||||
|
||||
const sortedHistory = useMemo(() => [...list].sort((a, b) => b.id - a.id), [list]);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader className="space-y-1">
|
||||
@@ -354,7 +354,6 @@ export function OddsConfigDocScreen() {
|
||||
<Button
|
||||
key={t.id}
|
||||
type="button"
|
||||
size="sm"
|
||||
variant={catTab === t.id ? "default" : "outline"}
|
||||
className={cn(catTab === t.id && "shadow-sm")}
|
||||
onClick={() => {
|
||||
@@ -377,7 +376,6 @@ export function OddsConfigDocScreen() {
|
||||
<Button
|
||||
key={t.play_code}
|
||||
type="button"
|
||||
size="sm"
|
||||
variant={resolvedPlayCode === t.play_code ? "secondary" : "outline"}
|
||||
onClick={() => setPlayCode(t.play_code)}
|
||||
>
|
||||
@@ -388,17 +386,28 @@ export function OddsConfigDocScreen() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ConfigVersionSwitcher
|
||||
versions={list}
|
||||
selectedId={selectedId}
|
||||
onSelectedIdChange={setSelectedId}
|
||||
loading={loadingList}
|
||||
sheetTitle="赔率配置版本"
|
||||
sheetDescription="选择版本在本页查看;非草稿版本可回滚为新建草稿。"
|
||||
onDeleteVersion={handleDeleteVersion}
|
||||
onRollbackVersion={requestRollback}
|
||||
rollbackBusy={saving}
|
||||
/>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
disabled={loadingList}
|
||||
onClick={() => void refreshList()}
|
||||
>
|
||||
刷新
|
||||
</Button>
|
||||
<Button type="button" size="sm" onClick={() => void handleNewDraft()} disabled={saving}>
|
||||
<Button type="button" onClick={() => void handleNewDraft()} disabled={saving}>
|
||||
新建草稿
|
||||
</Button>
|
||||
</div>
|
||||
@@ -483,59 +492,6 @@ export function OddsConfigDocScreen() {
|
||||
) : null}
|
||||
|
||||
<div className="flex flex-wrap gap-2 pt-2">
|
||||
<Button type="button" variant="outline" size="sm" onClick={() => setHistoryOpen(true)}>
|
||||
查看历史版本
|
||||
</Button>
|
||||
<Sheet open={historyOpen} onOpenChange={setHistoryOpen}>
|
||||
<SheetContent side="right" className="sm:max-w-lg flex flex-col">
|
||||
<SheetHeader>
|
||||
<SheetTitle>赔率版本历史</SheetTitle>
|
||||
<SheetDescription>选择一条历史版本执行回滚(克隆为新草稿)。</SheetDescription>
|
||||
</SheetHeader>
|
||||
<div className="flex-1 overflow-auto rounded-md border mt-4">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>版本</TableHead>
|
||||
<TableHead>状态</TableHead>
|
||||
<TableHead>时间</TableHead>
|
||||
<TableHead className="w-[100px]">操作</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{sortedHistory.map((v) => (
|
||||
<TableRow key={v.id}>
|
||||
<TableCell className="font-mono text-xs">v{v.version_no}</TableCell>
|
||||
<TableCell className="text-xs">
|
||||
{v.status === "active" ? "生效" : v.status === "draft" ? "草稿" : "归档"}
|
||||
</TableCell>
|
||||
<TableCell className="text-xs text-muted-foreground whitespace-nowrap">
|
||||
{v.updated_at ? formatDt(v.updated_at) : "—"}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-xs"
|
||||
disabled={saving || v.status === "draft"}
|
||||
onClick={() => {
|
||||
setRollbackTarget(v);
|
||||
setRollbackOpen(true);
|
||||
setHistoryOpen(false);
|
||||
}}
|
||||
>
|
||||
回滚
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
|
||||
<Button type="button" onClick={() => void handleSave()} disabled={!isDraft || saving || loadingDetail}>
|
||||
保存
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user