Files
UHD_Media_Tool/apps/web/app/components/episode-mapping/subscription-summary.tsx
T

81 lines
3.2 KiB
TypeScript

import { ChevronRight, Info } from "lucide-react";
import { Link } from "react-router";
import { useEpisodeMappingPreview } from "~/api/episode-mapping.ts";
import { useEntityDetail } from "~/api/library.ts";
import { consolePath } from "~/components/console/nav.ts";
import { StatusBadge } from "~/components/console/status-badge.tsx";
import { Panel } from "~/components/library/parts.tsx";
import { absoluteGroups, groupMethodsText, mappingHref } from "./model.ts";
// 订阅详情的集数映射摘要 + 订阅表单的绝对集号提示(批次 4)。数据来自模拟预览(不带草稿 = 当前规则)。
/** 订阅的季:有季单元取它的季号,否则不按季过滤 */
function useSubscriptionSeason(entityId: string, seasonUnitId: string | null | undefined): number | null {
const entity = useEntityDetail(seasonUnitId ? entityId : undefined);
if (!seasonUnitId) return null;
return entity.data?.contentUnits.find((u) => u.id === seasonUnitId)?.seasonNumber ?? null;
}
export function SubscriptionMappingSummary({
entityId,
seasonUnitId,
}: {
entityId: string;
seasonUnitId?: string | null;
}) {
const season = useSubscriptionSeason(entityId, seasonUnitId);
const preview = useEpisodeMappingPreview(entityId, season != null ? { season } : {});
const p = preview.data;
if (!p?.applicable || (p.groups.length === 0 && p.seasons.seasons.length === 0)) return null;
const pending = p.groups.reduce((n, g) => n + g.pending, 0);
return (
<Panel
title="集数映射"
description={`${season != null ? `第 ${season} 季` : "全部季"}最近资源按发布组的识别方式`}
actions={
<Link
to={mappingHref(consolePath("library", entityId))}
className="inline-flex items-center text-meta text-muted-foreground hover:text-foreground hover:underline"
>
到作品页调整
<ChevronRight className="h-3 w-3" />
</Link>
}
>
{p.groups.length ? (
<ul className="space-y-1 text-caption text-foreground">
{p.groups.map((g) => (
<li key={g.releaseGroup ?? "-"}>{groupMethodsText(g)}</li>
))}
</ul>
) : (
<p className="text-caption text-muted-foreground">还没有绑定到这一季的资源。</p>
)}
{pending ? (
<div className="mt-2">
<StatusBadge tone="warning">待确认 {pending} 条</StatusBadge>
</div>
) : null}
</Panel>
);
}
/** 订阅表单:作品的近期资源里有发布组用绝对集号时提示一句,不阻塞 */
export function AbsoluteNumberingHint({ entityId }: { entityId: string | null }) {
const preview = useEpisodeMappingPreview(entityId, {});
const groups = absoluteGroups(preview.data);
if (!entityId || !groups.length) return null;
return (
<p className="flex items-start gap-1.5 text-meta text-muted-foreground">
<Info aria-hidden className="mt-0.5 h-3.5 w-3.5 shrink-0" />
<span>
{groups.map((g) => `「${g}」`).join("")}用的是绝对集号,已自动换算成季内集号;不对的话到
<Link className="mx-0.5 underline-offset-4 hover:underline" to={mappingHref(consolePath("library", entityId))}>
作品页的集数映射
</Link>
调整。
</span>
</p>
);
}