import { keepPreviousData, useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { EpisodeMappingPreview, type EpisodeMappingPreviewInput, type EpisodeMappingRuleCreate, EpisodeMappingRuleList, type EpisodeMappingRuleUpdate, EpisodeMappingRuleWriteResult, } from "@umt/contracts"; import { api } from "~/lib/api.ts"; import { decisionKeys } from "./decisions.ts"; import { getParsed, libraryKeys, parseOrThrow } from "./library.ts"; // 集数映射:作品的规则列表 / 增改停删(写入后服务端按作品重算)/ 模拟预览(纯读)。 export const episodeMappingKeys = { all: ["episode-mapping"] as const, rules: (entityId: string) => ["episode-mapping", "rules", entityId] as const, preview: (entityId: string, input: EpisodeMappingPreviewInput) => ["episode-mapping", "preview", entityId, input] as const, }; export function useEpisodeMappingRules(entityId: string | undefined) { return useQuery({ queryKey: episodeMappingKeys.rules(entityId ?? ""), enabled: !!entityId, queryFn: ({ signal }) => getParsed(EpisodeMappingRuleList, `/media-entities/${entityId}/episode-mapping-rules`, undefined, signal), }); } export function useEpisodeMappingPreview( entityId: string | null | undefined, input: EpisodeMappingPreviewInput, enabled = true, ) { return useQuery({ queryKey: episodeMappingKeys.preview(entityId ?? "", input), enabled: !!entityId && enabled, placeholderData: keepPreviousData, queryFn: async () => parseOrThrow( EpisodeMappingPreview, await api.post(`/media-entities/${entityId}/episode-mapping/preview`, input), "/media-entities/{id}/episode-mapping/preview", ), }); } type WriteVars = | { op: "create"; entityId: string; body: EpisodeMappingRuleCreate } | { op: "update"; id: string; body: EpisodeMappingRuleUpdate } | { op: "delete"; id: string }; /** 规则写入:成功后刷新规则、预览、待处理与作品详情(季集可能变了) */ export function useEpisodeMappingWrite(entityId: string) { const qc = useQueryClient(); return useMutation({ mutationFn: async (v: WriteVars) => { const data = v.op === "create" ? await api.post(`/media-entities/${v.entityId}/episode-mapping-rules`, v.body) : v.op === "update" ? await api.patch(`/episode-mapping-rules/${v.id}`, v.body) : await api.del(`/episode-mapping-rules/${v.id}`); return parseOrThrow(EpisodeMappingRuleWriteResult, data, "/episode-mapping-rules"); }, onSuccess: () => { void qc.invalidateQueries({ queryKey: episodeMappingKeys.all }); void qc.invalidateQueries({ queryKey: decisionKeys.all }); void qc.invalidateQueries({ queryKey: libraryKeys.detail(entityId) }); void qc.invalidateQueries({ queryKey: libraryKeys.entity(entityId) }); }, }); }