refactor(selection): update component descriptions and improve layout for stock detail panel
This commit is contained in:
@@ -1,15 +1,13 @@
|
||||
import { lazy, Suspense } from "react"
|
||||
import { Database, Search } from "lucide-react"
|
||||
import { Search } from "lucide-react"
|
||||
import { useSelectionChart } from "../api/selection.query"
|
||||
|
||||
import { Badge } from "@/shared/ui/badge"
|
||||
import { Card } from "@/shared/ui/card"
|
||||
|
||||
import type { SelectionStockResult } from "../api/selection.types"
|
||||
import { PatternScoreDetails } from "./pattern-score"
|
||||
import { categoryToneClass, getCategoryLabel } from "./selection-presentation"
|
||||
import { SignalDetails } from "./signal-details"
|
||||
import { PatternCaseImage } from "./pattern-case-image"
|
||||
import { getStockBasicMetrics } from "./selection-presentation"
|
||||
|
||||
const SelectionChart = lazy(() =>
|
||||
import("./selection-chart").then((module) => ({
|
||||
@@ -44,111 +42,95 @@ export function SignalDetailPanel({ stock }: SignalDetailPanelProps) {
|
||||
)
|
||||
}
|
||||
|
||||
const metricRows = [
|
||||
...getStockBasicMetrics(stock),
|
||||
{
|
||||
key: "target_trade_date",
|
||||
label: "目标交易日",
|
||||
value: stock.target_trade_date,
|
||||
},
|
||||
{ key: "strategy", label: "策略", value: "知行 B1" },
|
||||
]
|
||||
|
||||
return (
|
||||
<aside
|
||||
aria-label="当前股票详情"
|
||||
className="hidden min-h-0 overflow-auto rounded-md border border-border/80 bg-card p-3 md:block"
|
||||
className="hidden min-h-0 overflow-hidden rounded-md border border-border/80 bg-card md:flex"
|
||||
>
|
||||
<p className="text-[10px] font-bold tracking-[0.08em] text-muted-foreground uppercase">
|
||||
Selected stock
|
||||
</p>
|
||||
<div className="mt-2 flex items-start justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<h2 className="truncate text-xl font-semibold tracking-tight">
|
||||
{stock.name}
|
||||
</h2>
|
||||
<p className="font-mono text-xs text-muted-foreground">
|
||||
{stock.ts_code}
|
||||
</p>
|
||||
</div>
|
||||
<Database
|
||||
className="mt-1 size-4 shrink-0 text-muted-foreground"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<p className="mt-4 text-3xl font-semibold tabular-nums tracking-tight">
|
||||
¥ {stock.close.toFixed(2)}
|
||||
</p>
|
||||
|
||||
<div className="mt-3 flex flex-wrap gap-1">
|
||||
{stock.signals.map((signal) => (
|
||||
<Badge
|
||||
key={signal.category}
|
||||
className={categoryToneClass(signal.category)}
|
||||
variant="outline"
|
||||
>
|
||||
{getCategoryLabel(signal.category)}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<dl className="mt-4 divide-y divide-border/60 border-y border-border/60 text-xs">
|
||||
<div className="flex items-center justify-between gap-3 py-2.5">
|
||||
<dt className="text-muted-foreground">目标交易日</dt>
|
||||
<dd className="font-medium tabular-nums">
|
||||
{stock.target_trade_date}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-3 py-2.5">
|
||||
<dt className="text-muted-foreground">策略</dt>
|
||||
<dd className="font-medium">知行 B1</dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
<section className="mt-4" aria-labelledby="pattern-score-details">
|
||||
<section
|
||||
aria-labelledby="technical-chart"
|
||||
className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden p-3"
|
||||
>
|
||||
<h3
|
||||
className="mb-2 text-xs font-medium text-muted-foreground"
|
||||
id="pattern-score-details"
|
||||
>
|
||||
图形相似度评分
|
||||
</h3>
|
||||
<PatternScoreDetails score={stock.score} />
|
||||
</section>
|
||||
|
||||
<section className="mt-4" aria-labelledby="technical-chart">
|
||||
<h3
|
||||
className="mb-2 text-xs font-medium text-muted-foreground"
|
||||
className="mb-2 shrink-0 text-xs font-medium text-muted-foreground"
|
||||
id="technical-chart"
|
||||
>
|
||||
技术图表
|
||||
</h3>
|
||||
{chartQuery.isPending ? (
|
||||
<p className="text-xs text-muted-foreground">正在加载行情图表…</p>
|
||||
) : chartQuery.isError ? (
|
||||
<p className="text-xs text-destructive">行情图表暂时不可用。</p>
|
||||
) : chartQuery.data?.points.length ? (
|
||||
<Suspense
|
||||
fallback={
|
||||
<p className="text-xs text-muted-foreground">正在加载图表组件…</p>
|
||||
}
|
||||
>
|
||||
<SelectionChart chart={chartQuery.data} />
|
||||
</Suspense>
|
||||
) : (
|
||||
<p className="text-xs text-muted-foreground">暂无可用行情数据。</p>
|
||||
)}
|
||||
<div className="min-h-0 flex-1">
|
||||
{chartQuery.isPending ? (
|
||||
<p className="text-xs text-muted-foreground">正在加载行情图表…</p>
|
||||
) : chartQuery.isError ? (
|
||||
<p className="text-xs text-destructive">行情图表暂时不可用。</p>
|
||||
) : chartQuery.data?.points.length ? (
|
||||
<Suspense
|
||||
fallback={
|
||||
<p className="text-xs text-muted-foreground">
|
||||
正在加载图表组件…
|
||||
</p>
|
||||
}
|
||||
>
|
||||
<SelectionChart chart={chartQuery.data} />
|
||||
</Suspense>
|
||||
) : (
|
||||
<p className="text-xs text-muted-foreground">暂无可用行情数据。</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="shrink-0">
|
||||
<PatternCaseImage score={stock.score} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<PatternCaseImage score={stock.score} />
|
||||
|
||||
<section className="mt-4" aria-labelledby="signal-detail-metrics">
|
||||
<h3
|
||||
className="mb-2 text-xs font-medium text-muted-foreground"
|
||||
id="signal-detail-metrics"
|
||||
<section
|
||||
aria-labelledby="selected-stock-heading"
|
||||
className="flex w-50 shrink-0 flex-col overflow-auto border-l border-border/60 p-3"
|
||||
>
|
||||
<h2
|
||||
className="truncate text-base font-semibold tracking-tight"
|
||||
id="selected-stock-heading"
|
||||
>
|
||||
关键指标
|
||||
</h3>
|
||||
<div className="space-y-4">
|
||||
{stock.signals.map((signal) => (
|
||||
<section key={signal.category} className="space-y-2">
|
||||
<h4 className="text-xs font-medium text-foreground">
|
||||
{getCategoryLabel(signal.category)}
|
||||
</h4>
|
||||
<SignalDetails details={signal.details} />
|
||||
</section>
|
||||
{stock.name}
|
||||
</h2>
|
||||
<p className="font-mono text-xs text-muted-foreground">
|
||||
{stock.ts_code}
|
||||
</p>
|
||||
<p className="mt-3 text-2xl font-semibold tabular-nums tracking-tight">
|
||||
¥ {stock.close.toFixed(2)}
|
||||
</p>
|
||||
|
||||
<dl className="mt-3 divide-y divide-border/60 border-y border-border/60 text-xs">
|
||||
{metricRows.map((row) => (
|
||||
<div
|
||||
key={row.key}
|
||||
className="flex items-center justify-between gap-2 py-2"
|
||||
>
|
||||
<dt className="shrink-0 text-muted-foreground">{row.label}</dt>
|
||||
<dd className="min-w-0 truncate text-right font-medium tabular-nums">
|
||||
{row.value}
|
||||
</dd>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
<section className="mt-3" aria-labelledby="pattern-score-details">
|
||||
<h3
|
||||
className="mb-2 text-xs font-medium text-muted-foreground"
|
||||
id="pattern-score-details"
|
||||
>
|
||||
图形相似度评分
|
||||
</h3>
|
||||
<PatternScoreDetails score={stock.score} />
|
||||
</section>
|
||||
</section>
|
||||
</aside>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user