feat: 重构管理端列表与风控/结算导航,新增表格导出和结算审核确认
This commit is contained in:
@@ -33,6 +33,12 @@ import {
|
||||
PRD_PAYOUT_REVIEW,
|
||||
} from "./draw-prd";
|
||||
|
||||
function drawStatusText(status: string, t: (key: string) => string): string {
|
||||
const key = `statusOptions.${status}`;
|
||||
const translated = t(key);
|
||||
return translated === key ? status : translated;
|
||||
}
|
||||
|
||||
function Field({ label, children }: { label: string; children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="grid gap-1 sm:grid-cols-[10rem_1fr] sm:items-start">
|
||||
@@ -114,12 +120,16 @@ export function DrawDetailConsole({ drawId }: { drawId: string }) {
|
||||
<CardTitle className="text-xl">{data.draw_no}</CardTitle>
|
||||
<p className="mt-1 text-sm text-muted-foreground">{t("drawDetail")}</p>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<DrawStatusBadge status={data.status} label={data.status} />
|
||||
<div className="flex flex-col items-end gap-1 text-right">
|
||||
<DrawStatusBadge
|
||||
status={data.hall_preview_status}
|
||||
label={t("hallPreviewStatus", { status: data.hall_preview_status })}
|
||||
status={data.status}
|
||||
label={drawStatusText(data.status, t)}
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("hallPreviewStatus", {
|
||||
status: drawStatusText(data.hall_preview_status, t),
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { getAdminDrawFinanceSummary } from "@/api/admin-draws";
|
||||
import { postAdminRunDrawSettlement } from "@/api/admin-settlement";
|
||||
import { Button, buttonVariants } from "@/components/ui/button";
|
||||
import { AdminTableExportButton } from "@/components/admin/admin-table-export-button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import {
|
||||
Table,
|
||||
@@ -156,7 +157,14 @@ export function DrawFinanceConsole({ drawId }: { drawId: string }): React.ReactE
|
||||
<p className="text-muted-foreground text-sm">{t("noSettlementBatches")}</p>
|
||||
) : (
|
||||
<div className="overflow-x-auto rounded-md border">
|
||||
<Table>
|
||||
<div className="admin-table-toolbar">
|
||||
<AdminTableExportButton
|
||||
tableId={`draw-finance-table-${drawId}`}
|
||||
filename={`期号收支-${data.draw_no}`}
|
||||
sheetName="期号收支"
|
||||
/>
|
||||
</div>
|
||||
<Table id={`draw-finance-table-${drawId}`}>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-20">ID</TableHead>
|
||||
|
||||
@@ -12,6 +12,10 @@ const segments = [
|
||||
{ suffix: "/results", key: "results", label: "subnav.results" },
|
||||
{ suffix: "/finance", key: "finance", label: "subnav.finance" },
|
||||
{ suffix: "/review", key: "review", label: "subnav.review" },
|
||||
{ suffix: "/risk/occupancy", key: "riskOccupancy", label: "subnav.riskOccupancy" },
|
||||
{ suffix: "/risk/hot", key: "riskHot", label: "subnav.riskHot" },
|
||||
{ suffix: "/risk/sold-out", key: "riskSoldOut", label: "subnav.riskSoldOut" },
|
||||
{ suffix: "/risk/pools", key: "riskPools", label: "subnav.riskPools" },
|
||||
] as const;
|
||||
|
||||
function isReviewTabActive(pathname: string, base: string): boolean {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { toast } from "sonner";
|
||||
|
||||
import { getAdminDraws, postAdminGenerateDrawPlan } from "@/api/admin-draws";
|
||||
import { Button, buttonVariants } from "@/components/ui/button";
|
||||
import { AdminTableExportButton } from "@/components/admin/admin-table-export-button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { AdminListPaginationFooter } from "@/components/admin/admin-list-pagination-footer";
|
||||
import { Input } from "@/components/ui/input";
|
||||
@@ -140,60 +141,66 @@ export function DrawsIndexConsole() {
|
||||
}, [load]);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<CardTitle className="text-lg">{t("statusListTitle")}</CardTitle>
|
||||
<Card className="admin-list-card">
|
||||
<CardHeader className="admin-list-header flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<CardTitle className="admin-list-title">{t("statusListTitle")}</CardTitle>
|
||||
{canManageDraw ? (
|
||||
<Button type="button" onClick={() => void generatePlan()} disabled={generating}>
|
||||
{generating ? t("generating") : t("generatePlan")}
|
||||
</Button>
|
||||
) : null}
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{/* Grid:桌面端标签一行 / 控件一行,避免 flex+items-end 与各列实际高度不一致;移动端单列自上而下 */}
|
||||
<div
|
||||
className="grid max-w-full gap-x-6 gap-y-3 sm:grid-cols-[minmax(0,12rem)_minmax(0,11rem)_auto] sm:gap-y-1.5"
|
||||
>
|
||||
<Label htmlFor="draw-filter-no">
|
||||
{t("drawNo")}
|
||||
</Label>
|
||||
<Input
|
||||
id="draw-filter-no"
|
||||
placeholder={t("fuzzyDrawNo")}
|
||||
value={draftDrawNo}
|
||||
className="w-full min-w-0 sm:w-full"
|
||||
onChange={(e) => setDraftDrawNo(e.target.value)}
|
||||
/>
|
||||
<Label htmlFor="draw-filter-status">
|
||||
{t("status")}
|
||||
</Label>
|
||||
<div className="min-w-0">
|
||||
<Select
|
||||
modal={false}
|
||||
value={
|
||||
draftStatus === "" ||
|
||||
!DRAW_STATUS_OPTIONS.some((o) => o.value === draftStatus)
|
||||
? DRAW_FILTER_ALL
|
||||
: draftStatus
|
||||
}
|
||||
onValueChange={(v) =>
|
||||
setDraftStatus(v == null || v === DRAW_FILTER_ALL ? "" : String(v))
|
||||
}
|
||||
>
|
||||
<SelectTrigger id="draw-filter-status" className="h-8 w-full min-w-0 sm:w-44">
|
||||
<SelectValue>{drawStatusTriggerLabel}</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent align="start" sideOffset={6}>
|
||||
<SelectItem value={DRAW_FILTER_ALL}>{t("statusOptions.all")}</SelectItem>
|
||||
{DRAW_STATUS_OPTIONS.map((o) => (
|
||||
<SelectItem key={o.value} value={o.value}>
|
||||
{t(o.label)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<CardContent className="admin-list-content">
|
||||
<div className="admin-list-toolbar">
|
||||
<div className="admin-list-field xl:min-w-0">
|
||||
<Label htmlFor="draw-filter-no" className="sm:w-10 sm:shrink-0">
|
||||
{t("drawNo")}
|
||||
</Label>
|
||||
<Input
|
||||
id="draw-filter-no"
|
||||
placeholder={t("fuzzyDrawNo")}
|
||||
value={draftDrawNo}
|
||||
className="w-full sm:w-[16rem] xl:w-[20rem]"
|
||||
onChange={(e) => setDraftDrawNo(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="[grid-area:act] flex flex-wrap gap-2">
|
||||
<div className="admin-list-field">
|
||||
<Label htmlFor="draw-filter-status" className="sm:w-10 sm:shrink-0">
|
||||
{t("status")}
|
||||
</Label>
|
||||
<div className="min-w-0">
|
||||
<Select
|
||||
modal={false}
|
||||
value={
|
||||
draftStatus === "" ||
|
||||
!DRAW_STATUS_OPTIONS.some((o) => o.value === draftStatus)
|
||||
? DRAW_FILTER_ALL
|
||||
: draftStatus
|
||||
}
|
||||
onValueChange={(v) =>
|
||||
setDraftStatus(v == null || v === DRAW_FILTER_ALL ? "" : String(v))
|
||||
}
|
||||
>
|
||||
<SelectTrigger id="draw-filter-status" className="h-8 w-full sm:w-44">
|
||||
<SelectValue>{drawStatusTriggerLabel}</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent align="start" sideOffset={6}>
|
||||
<SelectItem value={DRAW_FILTER_ALL}>{t("statusOptions.all")}</SelectItem>
|
||||
{DRAW_STATUS_OPTIONS.map((o) => (
|
||||
<SelectItem key={o.value} value={o.value}>
|
||||
{t(o.label)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="admin-list-actions">
|
||||
<AdminTableExportButton
|
||||
tableId="draws-index-table"
|
||||
filename="期号列表"
|
||||
sheetName="期号列表"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
@@ -224,8 +231,8 @@ export function DrawsIndexConsole() {
|
||||
<p className="text-sm text-destructive">{error}</p>
|
||||
) : null}
|
||||
|
||||
<div className="rounded-lg border border-border">
|
||||
<Table>
|
||||
<div className="admin-table-shell">
|
||||
<Table id="draws-index-table">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>{t("drawNo")}</TableHead>
|
||||
|
||||
Reference in New Issue
Block a user