Files
UHD_Media_Tool/apps/web/app/api/episode-mapping.ts
T

76 lines
2.9 KiB
TypeScript

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<unknown>(`/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<unknown>(`/media-entities/${v.entityId}/episode-mapping-rules`, v.body)
: v.op === "update"
? await api.patch<unknown>(`/episode-mapping-rules/${v.id}`, v.body)
: await api.del<unknown>(`/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) });
},
});
}