import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { AcquisitionSlot, type AcquisitionSlotCreate, type AcquisitionSlotUpdate, cursorPage, type SlotStatus, } from "@umt/contracts"; import { api } from "~/lib/api.ts"; import { getParsed, parseOrThrow } from "./library.ts"; // 收录目标 Slot:硬条件 / 软偏好 / 回退 / 升级阈值 / 完成条件(REQ §6.1) export const slotKeys = { all: ["slots"] as const, list: (f: SlotFilters) => ["slots", "list", f] as const, }; export type SlotFilters = { mediaEntityId?: string; status?: SlotStatus }; const Page = cursorPage(AcquisitionSlot); export function useSlots(filters: SlotFilters, enabled = true) { return useQuery({ queryKey: slotKeys.list(filters), enabled, queryFn: ({ signal }) => getParsed(Page, "/acquisition-slots", { ...filters, limit: 200 }, signal), }); } function useInvalidate() { const qc = useQueryClient(); return () => { void qc.invalidateQueries({ queryKey: slotKeys.all }); void qc.invalidateQueries({ queryKey: ["library"] }); }; } export function useCreateSlot() { const done = useInvalidate(); return useMutation({ mutationFn: (body: AcquisitionSlotCreate) => api.post("/acquisition-slots", body).then((d) => parseOrThrow(AcquisitionSlot, d, "/acquisition-slots")), onSuccess: done, }); } /** 规则修改带 expectedRevision(乐观并发);status 只由状态机推进 */ export function useUpdateSlot() { const done = useInvalidate(); return useMutation({ mutationFn: ({ id, ...body }: AcquisitionSlotUpdate & { id: string }) => api .patch(`/acquisition-slots/${id}`, body) .then((d) => parseOrThrow(AcquisitionSlot, d, "/acquisition-slots")), onSuccess: done, }); }