refactor: 重构整体页面布局与样式,统一UI设计风格
- 重构PlayerAppShell,移除冗余头部导航与国际化依赖,统一页面背景与内边距 - 新增通用页面容器组件PlayerPanel,统一页面头部布局与样式 - 重构底部导航栏,调整图标、文案与样式,新增激活状态指示器 - 重构所有页面组件:大厅页、注单页、结果页、开奖面板等,统一使用新的UI组件与设计风格 - 优化状态标签、卡片、按钮等组件的视觉样式,统一配色与圆角规范 - 移除冗余依赖与注释代码,整理代码结构
This commit is contained in:
@@ -4,22 +4,14 @@ import Link from "next/link";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { getDrawResults } from "@/api/draw";
|
||||
import { JackpotResultsStrip } from "@/features/results/jackpot-results-strip";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { PlayerPanel } from "@/components/layout/player-panel";
|
||||
import { JackpotResultsStrip } from "@/features/results/jackpot-results-strip";
|
||||
import { formatLotteryInstant } from "@/lib/player-datetime";
|
||||
import type { DrawResultListItem } from "@/types/api/draw-results";
|
||||
|
||||
/** §4.6 历史列表 + 默认最新一期入口 */
|
||||
export function DrawResultsListScreen() {
|
||||
const [items, setItems] = useState<DrawResultListItem[] | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@@ -51,92 +43,93 @@ export function DrawResultsListScreen() {
|
||||
}, [fetchList]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<JackpotResultsStrip currencyCode="NPR" />
|
||||
<PlayerPanel title="Results" subtitle="Latest draw history" eyebrow="N lotto">
|
||||
<div className="space-y-4">
|
||||
<JackpotResultsStrip currencyCode="NPR" />
|
||||
|
||||
<div className="flex flex-col gap-2 sm:flex-row sm:items-end">
|
||||
<div className="flex flex-1 flex-col gap-1.5">
|
||||
<Label htmlFor="biz-date">按业务日筛选</Label>
|
||||
<Input
|
||||
id="biz-date"
|
||||
type="date"
|
||||
value={date}
|
||||
onChange={(e) => setDate(e.target.value)}
|
||||
className="max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
<Button type="button" variant="secondary" size="sm" onClick={() => void fetchList()}>
|
||||
应用
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{loading ? (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Skeleton className="h-6 w-32" />
|
||||
<Skeleton className="h-4 w-48" />
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<Skeleton className="h-24 w-full" />
|
||||
<Skeleton className="h-24 w-full" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : error ? (
|
||||
<Card className="border-destructive/40">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">开奖结果</CardTitle>
|
||||
<CardDescription>{error}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Button type="button" size="sm" onClick={() => void fetchList()}>
|
||||
重试
|
||||
<div className="rounded-xl border border-[#e6edf8] bg-[#f8fbff] p-3">
|
||||
<p className="mb-2 text-xs font-bold text-[#32518d]">Business Date</p>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
type="date"
|
||||
value={date}
|
||||
onChange={(e) => setDate(e.target.value)}
|
||||
className="h-10 rounded-lg border-[#dce7f7] bg-white text-sm"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
className="h-10 rounded-lg bg-[#07459f] px-4 text-white hover:bg-[#063b88]"
|
||||
onClick={() => void fetchList()}
|
||||
>
|
||||
Apply
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : items && items.length === 0 ? (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">开奖结果</CardTitle>
|
||||
<CardDescription>暂无开奖结果</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
) : (
|
||||
<div className="flex flex-col gap-3">
|
||||
{items?.map((row) => (
|
||||
<Card key={row.draw_no}>
|
||||
<CardHeader className="pb-2">
|
||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||
<CardTitle className="font-mono text-base">{row.draw_no}</CardTitle>
|
||||
<Link
|
||||
href={`/results/${encodeURIComponent(row.draw_no)}`}
|
||||
className="text-sm font-medium text-primary underline-offset-4 hover:underline"
|
||||
>
|
||||
查看详情 →
|
||||
</Link>
|
||||
</div>
|
||||
<CardDescription className="font-mono text-xs">
|
||||
开奖时间:
|
||||
{formatLotteryInstant(row.draw_time_iso ?? row.draw_time ?? null)}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="grid grid-cols-3 gap-2 text-center font-mono text-sm">
|
||||
<div className="rounded-md border bg-card py-2">
|
||||
<div className="text-[10px] uppercase text-muted-foreground">1st</div>
|
||||
<div className="font-semibold">{row.results["1st"]}</div>
|
||||
</div>
|
||||
<div className="rounded-md border bg-card py-2">
|
||||
<div className="text-[10px] uppercase text-muted-foreground">2nd</div>
|
||||
<div className="font-semibold">{row.results["2nd"]}</div>
|
||||
</div>
|
||||
<div className="rounded-md border bg-card py-2">
|
||||
<div className="text-[10px] uppercase text-muted-foreground">3rd</div>
|
||||
<div className="font-semibold">{row.results["3rd"]}</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{loading ? (
|
||||
<div className="space-y-3">
|
||||
<Skeleton className="h-28 rounded-xl" />
|
||||
<Skeleton className="h-28 rounded-xl" />
|
||||
<Skeleton className="h-28 rounded-xl" />
|
||||
</div>
|
||||
) : error ? (
|
||||
<div className="rounded-xl border border-red-200 bg-red-50 px-4 py-4 text-sm text-red-700">
|
||||
<p>{error}</p>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
className="mt-3 bg-[#e5002c] text-white hover:bg-[#d10028]"
|
||||
onClick={() => void fetchList()}
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
</div>
|
||||
) : items && items.length === 0 ? (
|
||||
<div className="rounded-xl border border-dashed border-[#dce7f7] bg-[#f8fbff] px-4 py-10 text-center text-sm text-slate-500">
|
||||
No results yet.
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{items?.map((row) => (
|
||||
<Link
|
||||
key={row.draw_no}
|
||||
href={`/results/${encodeURIComponent(row.draw_no)}`}
|
||||
className="block rounded-xl border border-[#e5edf8] bg-white p-3 shadow-[0_8px_24px_rgba(15,23,42,0.05)] transition-colors hover:border-[#b9ccf6]"
|
||||
>
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<p className="truncate font-mono text-sm font-black text-[#0b3f96]">
|
||||
{row.draw_no}
|
||||
</p>
|
||||
<p className="mt-1 text-[11px] text-slate-500">
|
||||
{formatLotteryInstant(row.draw_time_iso ?? row.draw_time ?? null)}
|
||||
</p>
|
||||
</div>
|
||||
<span className="shrink-0 rounded-full bg-[#f2f6ff] px-2.5 py-1 text-xs font-bold text-[#0b56b7]">
|
||||
Detail
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="mt-3 grid grid-cols-3 gap-2 text-center">
|
||||
{[
|
||||
["1st", row.results["1st"]],
|
||||
["2nd", row.results["2nd"]],
|
||||
["3rd", row.results["3rd"]],
|
||||
].map(([label, value]) => (
|
||||
<div key={label} className="rounded-lg border border-[#edf2f8] bg-[#f8fbff] py-2">
|
||||
<p className="text-[10px] font-bold uppercase text-[#7890b8]">{label}</p>
|
||||
<p className="mt-1 font-mono text-lg font-black tabular-nums text-[#e5002c]">
|
||||
{value}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</PlayerPanel>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user