feat(selection): 支持选股结果服务端分页

This commit is contained in:
yuxuanhui
2026-08-10 11:09:23 +08:00
parent ed7bdda515
commit 3af97bf65d
16 changed files with 431 additions and 63 deletions
@@ -20,7 +20,7 @@ vi.mock("@/features/selection/api/selection.query", () => ({
vi.mock("@tanstack/react-router", () => ({
useNavigate: () => routerNavigate,
useSearch: () => ({ page: 1, pageSize: 5 }),
useSearch: () => ({ page: 1, pageSize: 5, search: "", category: "all" }),
}))
const selectedResult: SelectionResults = {
@@ -34,9 +34,12 @@ const selectedResult: SelectionResults = {
failures: [],
finished_at: "2026-08-08T09:02:00+08:00",
market_sync_batch_id: "market-run-1",
page: 1,
page_size: 5,
run_id: "run-1",
selected_stock_count: 1,
signal_count: 2,
signals_total: 2,
signals: [
{
category: "zhixing_b1_original_b1",
@@ -142,7 +145,12 @@ describe("SelectionResultsPage", () => {
ts_code: `00000${index + 1}.SZ`,
}))
useSelectionResults.mockReturnValue({
data: { ...selectedResult, signal_count: signals.length, signals },
data: {
...selectedResult,
signal_count: signals.length,
signals,
signals_total: signals.length,
},
isError: false,
isPending: false,
})
@@ -262,7 +270,10 @@ describe("SelectionResultsPage", () => {
expect(screen.getByText("策略执行中")).toBeInTheDocument()
expect(screen.getByRole("button", { name: "执行中" })).toBeDisabled()
expect(useSelectionRun).toHaveBeenCalledWith("run-1")
expect(useSelectionRun).toHaveBeenCalledWith("run-1", {
page: 1,
pageSize: 5,
})
})
it("renders query failures explicitly", () => {
@@ -5,6 +5,7 @@ import {
RefreshCw,
Search,
} from "lucide-react"
import { useSearch } from "@tanstack/react-router"
import { useState } from "react"
import { PageLayout } from "@/app/layout/page-layout"
@@ -15,6 +16,7 @@ import {
} from "@/features/selection/api/selection.query"
import type {
SelectionResults,
SelectionResultsQuery,
SelectionRunStatus,
} from "@/features/selection/api/selection.types"
import { Badge } from "@/shared/ui/badge"
@@ -54,12 +56,23 @@ export function SelectionResultsPage() {
const [targetTradeDate, setTargetTradeDate] = useState<string | null>(null)
const [activeRunId, setActiveRunId] = useState<string | null>(null)
const [rerunDialogOpen, setRerunDialogOpen] = useState(false)
const search = useSearch({ from: "/_workspace/selection" })
const resultQuery: SelectionResultsQuery = {
page: search.page,
pageSize: search.pageSize,
...(search.search ? { search: search.search } : {}),
...(search.category !== "all" ? { category: search.category } : {}),
}
const results = useSelectionResults(STRATEGY, targetTradeDate || undefined)
const results = useSelectionResults(
STRATEGY,
targetTradeDate || undefined,
resultQuery,
)
const persistedRunningRunId =
results.data?.status === "running" ? results.data.run_id : null
const polledRunId = activeRunId ?? persistedRunningRunId
const activeRun = useSelectionRun(polledRunId)
const activeRun = useSelectionRun(polledRunId, resultQuery)
const trigger = useTriggerSelectionRun()
const selectedTargetTradeDate =
@@ -420,7 +433,9 @@ function ResultState({ result }: { result: SelectionResults }) {
{result.signal_count === 0 ? (
<NoSignalState />
) : (
<SelectionResultsWorkbench result={result} />
<div className="min-h-[420px] shrink-0">
<SelectionResultsWorkbench result={result} />
</div>
)}
{result.failures.length > 0 ? <FailureList result={result} /> : null}
</div>