feat: initialize zhixing-web with React, React Router, and Tailwind CSS
- Set up the main application structure with App component and routing. - Implemented global state management for UI theme using Zustand. - Created API utilities for fetching system status. - Developed system status page with responsive design and theme toggle. - Added testing setup with Vitest and initial tests for system status page. - Configured TypeScript with appropriate settings for the application. - Integrated Tailwind CSS for styling and responsive design. - Established Vite configuration for development and testing environments.
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
import { requestJson } from "@/shared/api/request-json"
|
||||
|
||||
import type { SystemStatus } from "./system.types"
|
||||
|
||||
export function getSystemStatus(signal?: AbortSignal) {
|
||||
return requestJson<SystemStatus>("/api/v1/system/status", { signal })
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
|
||||
import { getSystemStatus } from "./system.api"
|
||||
|
||||
export const systemStatusQueryKey = ["system", "status"] as const
|
||||
|
||||
export function useSystemStatus() {
|
||||
return useQuery({
|
||||
queryFn: ({ signal }) => getSystemStatus(signal),
|
||||
queryKey: systemStatusQueryKey,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface SystemStatus {
|
||||
environment: string
|
||||
service: string
|
||||
status: "ok"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { render, screen } from "@testing-library/react"
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest"
|
||||
|
||||
import { SystemStatusPage } from "./system-status-page"
|
||||
|
||||
const useSystemStatus = vi.fn()
|
||||
|
||||
vi.mock("@/features/system/api/system.query", () => ({
|
||||
useSystemStatus: () => useSystemStatus(),
|
||||
}))
|
||||
|
||||
describe("SystemStatusPage", () => {
|
||||
beforeEach(() => {
|
||||
useSystemStatus.mockReturnValue({
|
||||
data: {
|
||||
environment: "test",
|
||||
service: "Zhixing Server",
|
||||
status: "ok",
|
||||
},
|
||||
isError: false,
|
||||
isPending: false,
|
||||
})
|
||||
})
|
||||
|
||||
it("renders the connected backend state", () => {
|
||||
render(<SystemStatusPage />)
|
||||
|
||||
expect(screen.getByText("运行正常")).toBeInTheDocument()
|
||||
expect(screen.getByText("test")).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,76 @@
|
||||
import { Activity, Moon, Sun } from "lucide-react"
|
||||
|
||||
import { useSystemStatus } from "@/features/system/api/system.query"
|
||||
import { useUiStore } from "@/shared/config/ui-store"
|
||||
import { Badge } from "@/shared/ui/badge"
|
||||
import { Button } from "@/shared/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/shared/ui/card"
|
||||
|
||||
export function SystemStatusPage() {
|
||||
const status = useSystemStatus()
|
||||
const theme = useUiStore((state) => state.theme)
|
||||
const toggleTheme = useUiStore((state) => state.toggleTheme)
|
||||
|
||||
const statusLabel = status.isPending
|
||||
? "正在连接"
|
||||
: status.isError
|
||||
? "连接异常"
|
||||
: "运行正常"
|
||||
|
||||
return (
|
||||
<main className="flex min-h-screen items-center justify-center bg-background p-6 text-foreground">
|
||||
<Card className="w-full max-w-xl">
|
||||
<CardHeader className="flex-row items-start justify-between gap-4">
|
||||
<div className="space-y-1.5">
|
||||
<CardTitle className="flex items-center gap-2 text-2xl">
|
||||
<Activity className="size-6 text-primary" aria-hidden="true" />
|
||||
Zhixing System
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
量化系统开发环境已完成最小链路连接。
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Button
|
||||
aria-label="切换主题"
|
||||
onClick={toggleTheme}
|
||||
size="icon"
|
||||
variant="outline"
|
||||
>
|
||||
{theme === "dark" ? (
|
||||
<Sun aria-hidden="true" />
|
||||
) : (
|
||||
<Moon aria-hidden="true" />
|
||||
)}
|
||||
</Button>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex items-center justify-between rounded-lg border bg-muted/40 p-4">
|
||||
<div>
|
||||
<p className="font-medium">后端服务</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{status.data?.service ?? "Zhixing Server"}
|
||||
</p>
|
||||
</div>
|
||||
<Badge variant={status.isError ? "destructive" : "default"}>
|
||||
{statusLabel}
|
||||
</Badge>
|
||||
</div>
|
||||
{status.data ? (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
当前环境:
|
||||
<span className="font-medium text-foreground">
|
||||
{status.data.environment}
|
||||
</span>
|
||||
</p>
|
||||
) : null}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user