feat(web): 完善选股详情图表与案例图

This commit is contained in:
yuxuanhui
2026-09-01 13:37:19 +08:00
parent 9145fe4b2c
commit feb8fd4feb
27 changed files with 788 additions and 25 deletions
@@ -4,7 +4,11 @@ const requestJson = vi.hoisted(() => vi.fn())
vi.mock("@/shared/api/request-json", () => ({ requestJson }))
import { getSelectionResults, getSelectionRun } from "./selection.api"
import {
getSelectionChart,
getSelectionResults,
getSelectionRun,
} from "./selection.api"
describe("selection API adapters", () => {
beforeEach(() => {
@@ -47,4 +51,18 @@ describe("selection API adapters", () => {
expect(params.has("category")).toBe(false)
expect(params.has("sort")).toBe(false)
})
it("requests a stock chart with an encoded code and target date", async () => {
await getSelectionChart("600601.SH", "2026-08-08")
const [input, init] = requestJson.mock.calls[0] as [
string,
{ signal?: AbortSignal },
]
expect(input).toContain("/api/v1/selection/stocks/600601.SH/chart?")
expect(
new URL(input, "http://localhost").searchParams.get("target_trade_date"),
).toBe("2026-08-08")
expect(init).toEqual({ signal: undefined })
})
})
@@ -1,6 +1,7 @@
import { requestJson } from "@/shared/api/request-json"
import type {
SelectionChart,
SelectionResults,
SelectionResultsQuery,
SelectionRunAccepted,
@@ -8,6 +9,20 @@ import type {
SelectionStrategy,
} from "./selection.types"
export function getSelectionChart(
tsCode: string,
targetTradeDate: string,
signal?: AbortSignal,
) {
const params = new URLSearchParams({
target_trade_date: targetTradeDate,
})
return requestJson<SelectionChart>(
`/api/v1/selection/stocks/${encodeURIComponent(tsCode)}/chart?${params.toString()}`,
{ signal },
)
}
export function getSelectionResults(
strategy: SelectionStrategy,
targetTradeDate?: string,
@@ -7,6 +7,7 @@ import {
import { useEffect } from "react"
import {
getSelectionChart,
getSelectionResults,
getSelectionRun,
triggerSelectionRun,
@@ -17,6 +18,12 @@ import type {
SelectionStrategy,
} from "./selection.types"
export const selectionChartQueryKey = (
tsCode?: string,
targetTradeDate?: string,
) =>
["selection", "chart", tsCode ?? "none", targetTradeDate ?? "none"] as const
export const selectionResultsQueryKey = (
strategy: SelectionStrategy,
targetTradeDate?: string,
@@ -61,6 +68,15 @@ export function useSelectionResults(
})
}
export function useSelectionChart(tsCode?: string, targetTradeDate?: string) {
return useQuery({
enabled: Boolean(tsCode && targetTradeDate),
queryFn: ({ signal }) =>
getSelectionChart(tsCode ?? "", targetTradeDate ?? "", signal),
queryKey: selectionChartQueryKey(tsCode, targetTradeDate),
})
}
export function useSelectionRun(
runId: string | null,
resultQuery: SelectionResultsQuery = { page: 1, pageSize: 10 },
@@ -58,6 +58,26 @@ export interface SelectionStockResult {
signals: SelectionSignal[]
}
export interface SelectionChartPoint {
trade_date: string
open: number | null
high: number | null
low: number | null
close: number | null
volume: number | null
k: number | null
d: number | null
j: number | null
}
export interface SelectionChart {
ts_code: string
name: string
target_trade_date: string
source_adj: "qfq"
points: SelectionChartPoint[]
}
export interface SelectionPatternScore {
status: "matched" | "below_threshold" | "failed"
value: number | null