2026-08-09 09:34:46 +08:00
|
|
|
import {
|
|
|
|
|
useMutation,
|
|
|
|
|
useQuery,
|
|
|
|
|
useQueryClient,
|
|
|
|
|
type QueryClient,
|
|
|
|
|
} from "@tanstack/react-query"
|
|
|
|
|
import { useEffect } from "react"
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
getSelectionResults,
|
|
|
|
|
getSelectionRun,
|
|
|
|
|
triggerSelectionRun,
|
|
|
|
|
} from "./selection.api"
|
2026-08-10 11:09:23 +08:00
|
|
|
import type {
|
|
|
|
|
SelectionResultsQuery,
|
|
|
|
|
SelectionRunRequest,
|
|
|
|
|
SelectionStrategy,
|
|
|
|
|
} from "./selection.types"
|
2026-08-09 09:34:46 +08:00
|
|
|
|
|
|
|
|
export const selectionResultsQueryKey = (
|
|
|
|
|
strategy: SelectionStrategy,
|
|
|
|
|
targetTradeDate?: string,
|
2026-08-10 11:09:23 +08:00
|
|
|
query: SelectionResultsQuery = { page: 1, pageSize: 10 },
|
|
|
|
|
) =>
|
|
|
|
|
[
|
|
|
|
|
"selection",
|
|
|
|
|
"results",
|
|
|
|
|
strategy,
|
|
|
|
|
targetTradeDate,
|
|
|
|
|
query.page,
|
|
|
|
|
query.pageSize,
|
|
|
|
|
query.search ?? "",
|
|
|
|
|
query.category ?? "all",
|
|
|
|
|
] as const
|
2026-08-09 09:34:46 +08:00
|
|
|
|
2026-08-10 11:09:23 +08:00
|
|
|
export const selectionRunQueryKey = (
|
|
|
|
|
runId: string,
|
|
|
|
|
query: SelectionResultsQuery = { page: 1, pageSize: 10 },
|
|
|
|
|
) =>
|
|
|
|
|
[
|
|
|
|
|
"selection",
|
|
|
|
|
"runs",
|
|
|
|
|
runId,
|
|
|
|
|
query.page,
|
|
|
|
|
query.pageSize,
|
|
|
|
|
query.search ?? "",
|
|
|
|
|
query.category ?? "all",
|
|
|
|
|
] as const
|
2026-08-09 09:34:46 +08:00
|
|
|
|
|
|
|
|
export function useSelectionResults(
|
|
|
|
|
strategy: SelectionStrategy,
|
|
|
|
|
targetTradeDate?: string,
|
2026-08-10 11:09:23 +08:00
|
|
|
query: SelectionResultsQuery = { page: 1, pageSize: 10 },
|
2026-08-09 09:34:46 +08:00
|
|
|
) {
|
|
|
|
|
return useQuery({
|
|
|
|
|
queryFn: ({ signal }) =>
|
2026-08-10 11:09:23 +08:00
|
|
|
getSelectionResults(strategy, targetTradeDate, query, signal),
|
|
|
|
|
queryKey: selectionResultsQueryKey(strategy, targetTradeDate, query),
|
2026-08-09 09:34:46 +08:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-10 11:09:23 +08:00
|
|
|
export function useSelectionRun(
|
|
|
|
|
runId: string | null,
|
|
|
|
|
resultQuery: SelectionResultsQuery = { page: 1, pageSize: 10 },
|
|
|
|
|
) {
|
2026-08-09 09:34:46 +08:00
|
|
|
const queryClient = useQueryClient()
|
|
|
|
|
const query = useQuery({
|
|
|
|
|
enabled: Boolean(runId),
|
2026-08-10 11:09:23 +08:00
|
|
|
queryFn: ({ signal }) => getSelectionRun(runId ?? "", resultQuery, signal),
|
|
|
|
|
queryKey: selectionRunQueryKey(runId ?? "none", resultQuery),
|
2026-08-09 09:34:46 +08:00
|
|
|
refetchInterval: (query) =>
|
|
|
|
|
query.state.data?.status === "running" ? 1500 : false,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const result = query.data
|
|
|
|
|
if (!runId || !result || result.status === "running") return
|
|
|
|
|
|
|
|
|
|
void invalidateSelectionResults(queryClient, result.strategy)
|
|
|
|
|
}, [query.data, queryClient, runId])
|
|
|
|
|
|
|
|
|
|
return query
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useTriggerSelectionRun() {
|
|
|
|
|
const queryClient = useQueryClient()
|
|
|
|
|
|
|
|
|
|
return useMutation({
|
|
|
|
|
mutationFn: ({
|
|
|
|
|
request,
|
|
|
|
|
signal,
|
|
|
|
|
}: {
|
|
|
|
|
request: SelectionRunRequest
|
|
|
|
|
signal?: AbortSignal
|
|
|
|
|
}) => triggerSelectionRun(request, signal),
|
|
|
|
|
onSuccess: (_accepted, { request }) => {
|
|
|
|
|
void invalidateSelectionResults(queryClient, request.strategy)
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function invalidateSelectionResults(
|
|
|
|
|
queryClient: QueryClient,
|
|
|
|
|
strategy: SelectionStrategy,
|
|
|
|
|
) {
|
|
|
|
|
return queryClient.invalidateQueries({
|
|
|
|
|
queryKey: ["selection", "results", strategy],
|
|
|
|
|
})
|
|
|
|
|
}
|