feat(web): 按原型调整响应式研究工作台
This commit is contained in:
@@ -1,124 +0,0 @@
|
||||
import {
|
||||
BarChart3,
|
||||
BrainCircuit,
|
||||
ClipboardCheck,
|
||||
LayoutDashboard,
|
||||
Search,
|
||||
} from "lucide-react"
|
||||
|
||||
import { Avatar, AvatarFallback } from "@/shared/ui/avatar"
|
||||
import { Button } from "@/shared/ui/button"
|
||||
import { Input } from "@/shared/ui/input"
|
||||
import { Separator } from "@/shared/ui/separator"
|
||||
|
||||
interface HomeShellProps {
|
||||
children: React.ReactNode
|
||||
activeSection?: "home" | "selection"
|
||||
}
|
||||
|
||||
const navigation = [
|
||||
{
|
||||
label: "首页",
|
||||
icon: LayoutDashboard,
|
||||
section: "home" as const,
|
||||
path: "/" as const,
|
||||
},
|
||||
{ label: "行情数据", icon: BarChart3, section: null, path: null },
|
||||
{ label: "同步任务", icon: ClipboardCheck, section: null, path: null },
|
||||
{
|
||||
label: "选股策略",
|
||||
icon: BrainCircuit,
|
||||
section: "selection" as const,
|
||||
path: "/selection" as const,
|
||||
},
|
||||
]
|
||||
|
||||
export function HomeShell({
|
||||
activeSection = "home",
|
||||
children,
|
||||
}: HomeShellProps) {
|
||||
return (
|
||||
<div className="flex min-h-screen bg-muted/30 text-foreground">
|
||||
<aside className="flex w-20 shrink-0 flex-col border-r bg-card px-3 py-5 md:w-64 md:px-5">
|
||||
<div className="flex items-center gap-3 px-1 md:px-2">
|
||||
<div className="flex size-9 items-center justify-center rounded-xl bg-primary text-primary-foreground shadow-sm">
|
||||
<BarChart3 className="size-5" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="hidden min-w-0 md:block">
|
||||
<p className="truncate text-sm font-semibold tracking-wide">
|
||||
知行量化
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">研究工作台</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator className="my-6" />
|
||||
|
||||
<nav aria-label="主导航" className="space-y-1">
|
||||
{navigation.map((item) => {
|
||||
const Icon = item.icon
|
||||
const active = item.section === activeSection
|
||||
const content = (
|
||||
<>
|
||||
<Icon className="size-4 shrink-0" aria-hidden="true" />
|
||||
<span className="hidden md:inline">{item.label}</span>
|
||||
</>
|
||||
)
|
||||
if (item.path) {
|
||||
return (
|
||||
<Button
|
||||
key={item.label}
|
||||
className="w-full justify-start gap-3 px-2 md:px-3"
|
||||
render={<a href={item.path} />}
|
||||
variant={active ? "secondary" : "ghost"}
|
||||
aria-current={active ? "page" : undefined}
|
||||
>
|
||||
{content}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Button
|
||||
key={item.label}
|
||||
className="w-full justify-start gap-3 px-2 md:px-3"
|
||||
disabled
|
||||
variant="ghost"
|
||||
>
|
||||
{content}
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
</nav>
|
||||
|
||||
<div className="mt-auto hidden rounded-xl bg-muted/60 p-4 md:block">
|
||||
<p className="text-xs font-medium">数据研究空间</p>
|
||||
<p className="mt-1 text-xs leading-5 text-muted-foreground">
|
||||
从市场数据概览开始,掌握当前研究基础。
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
<header className="flex h-16 items-center justify-between gap-4 border-b bg-card/80 px-4 backdrop-blur md:px-8">
|
||||
<div className="relative w-full max-w-md">
|
||||
<Search
|
||||
className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<Input
|
||||
aria-label="搜索"
|
||||
className="h-9 bg-muted/40 pl-9"
|
||||
placeholder="搜索股票、数据或功能"
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
<Avatar aria-label="用户头像">
|
||||
<AvatarFallback>研</AvatarFallback>
|
||||
</Avatar>
|
||||
</header>
|
||||
|
||||
<main className="mx-auto w-full max-w-7xl p-4 md:p-8">{children}</main>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -51,20 +51,13 @@ describe("HomePage", () => {
|
||||
})
|
||||
})
|
||||
|
||||
it("renders the management shell and partial overview", () => {
|
||||
it("renders the overview card with the partial overview", () => {
|
||||
render(<HomePage />)
|
||||
|
||||
expect(screen.getByRole("heading", { name: "首页" })).toBeInTheDocument()
|
||||
expect(screen.getByText("市场数据概览")).toBeInTheDocument()
|
||||
expect(screen.getByText("部分更新")).toBeInTheDocument()
|
||||
expect(screen.getByText("当前目标股票池")).toBeInTheDocument()
|
||||
expect(screen.getByText("33.33%")).toBeInTheDocument()
|
||||
expect(screen.getByRole("button", { name: "行情数据" })).toBeDisabled()
|
||||
expect(screen.getByRole("button", { name: "同步任务" })).toBeDisabled()
|
||||
expect(screen.getByRole("link", { name: "选股策略" })).toHaveAttribute(
|
||||
"href",
|
||||
"/selection",
|
||||
)
|
||||
})
|
||||
|
||||
it("opens and closes the accessible failed-stock dialog", () => {
|
||||
@@ -142,7 +135,7 @@ describe("HomePage", () => {
|
||||
expect(screen.queryByRole("dialog")).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("keeps the shell and explains the no-data state", () => {
|
||||
it("explains the no-data state", () => {
|
||||
useHomeOverview.mockReturnValue({
|
||||
data: { status: "no_data", stock_pool_count: 7, latest_update: null },
|
||||
isError: false,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { AlertTriangle, Database, RefreshCw } from "lucide-react"
|
||||
import { useState } from "react"
|
||||
|
||||
import { PageLayout } from "@/app/layout/page-layout"
|
||||
import { useHomeOverview } from "@/features/home/api/home.query"
|
||||
import { Button } from "@/shared/ui/button"
|
||||
import {
|
||||
@@ -13,7 +14,6 @@ import {
|
||||
import { Skeleton } from "@/shared/ui/skeleton"
|
||||
|
||||
import { FailedStocksDialog } from "../components/failed-stocks-dialog"
|
||||
import { HomeShell } from "../components/home-shell"
|
||||
import { MarketDataOverviewCard } from "../components/market-data-overview-card"
|
||||
|
||||
export function HomePage() {
|
||||
@@ -22,16 +22,8 @@ export function HomePage() {
|
||||
const update = overview.data?.latest_update
|
||||
|
||||
return (
|
||||
<HomeShell activeSection="home">
|
||||
<div className="space-y-8">
|
||||
<section className="space-y-2">
|
||||
<p className="text-sm font-medium text-primary">欢迎回到知行量化</p>
|
||||
<h1 className="text-3xl font-semibold tracking-tight">首页</h1>
|
||||
<p className="max-w-2xl text-muted-foreground">
|
||||
从当前目标股票池和市场数据同步状态开始,快速判断研究数据是否准备就绪。
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<PageLayout>
|
||||
<div className="mx-auto w-full max-w-6xl space-y-6">
|
||||
{overview.isPending ? <OverviewLoading /> : null}
|
||||
|
||||
{overview.isError ? (
|
||||
@@ -60,7 +52,7 @@ export function HomePage() {
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</HomeShell>
|
||||
</PageLayout>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user