feat(selection): 支持选股结果服务端分页
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user