feat(episode-mapping): 映射规则接口与模拟预览、待处理确认 / 忽略、作品页集数映射分区与订阅摘要
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
fe597187dd
commit
45a114263b
26 files changed
+2770
-9
No files matched your search
@@ -15,6 +15,7 @@ import { PageHeader } from "~/components/console/page-header.tsx";
|
||||
import { StatusBadge } from "~/components/console/status-badge.tsx";
|
||||
import { TechInfo } from "~/components/console/tech-info.tsx";
|
||||
import { useListPagination } from "~/components/console/use-list-pagination.ts";
|
||||
import { EpisodeDecision } from "~/components/episode-mapping/decision.tsx";
|
||||
import { EntityPicker, type PickedEntity } from "~/components/library/identity-entity-picker.tsx";
|
||||
import { DECISION_KIND, DECISION_STATUS, opts, SEVERITY } from "~/components/library/labels.ts";
|
||||
import { Chip, relTime, Tone } from "~/components/library/parts.tsx";
|
||||
@@ -363,6 +364,8 @@ function DismissButton({ d }: { d: Decision }) {
|
||||
function DecisionCard({ d }: { d: Decision }) {
|
||||
const open = OPEN.includes(d.status);
|
||||
const identity = IDENTITY_KINDS.includes(d.kind);
|
||||
// 集数待确认:证据与「确认 / 修改 / 忽略」由 EpisodeDecision 渲染
|
||||
const episode = d.kind === "episode_mapping";
|
||||
// 身份类:手动 TMDB / 选本地作品两个选项并进「指定作品」
|
||||
const options = d.options.filter(
|
||||
(o) =>
|
||||
@@ -383,11 +386,16 @@ function DecisionCard({ d }: { d: Decision }) {
|
||||
{d.summary ? (
|
||||
<p className="mt-1 text-caption break-words text-muted-foreground">{humanizeReason(d.summary)}</p>
|
||||
) : null}
|
||||
<GroupReleases d={d} />
|
||||
{episode ? null : <GroupReleases d={d} />}
|
||||
{episode ? (
|
||||
<div className="mt-3">
|
||||
<EpisodeDecision d={d} open={open} />
|
||||
</div>
|
||||
) : null}
|
||||
<div className="mt-3">
|
||||
<Evidence d={d} />
|
||||
</div>
|
||||
{open ? (
|
||||
{open && !episode ? (
|
||||
<div className="mt-3 flex flex-wrap items-center gap-2">
|
||||
{identity ? <AssignWorkButton d={d} /> : null}
|
||||
{options.map((o) => (
|
||||
@@ -404,7 +412,7 @@ function DecisionCard({ d }: { d: Decision }) {
|
||||
</Link>
|
||||
) : null}
|
||||
</div>
|
||||
) : (
|
||||
) : open ? null : (
|
||||
<p className="mt-3 text-meta text-muted-foreground">
|
||||
{d.resolvedBy ? `${actorText(d.resolvedBy)} ` : ""}于 {formatDateTime(d.resolvedAt)}
|
||||
{resolution?.optionKey
|
||||
|
||||
@@ -48,6 +48,7 @@ import { PaginatedList } from "~/components/console/paginated-list.tsx";
|
||||
import { StatusBadge } from "~/components/console/status-badge.tsx";
|
||||
import { TechInfo } from "~/components/console/tech-info.tsx";
|
||||
import { DROPPED_STATUS, droppedReason, PURPOSE_LABEL } from "~/components/downloads/plan-format.ts";
|
||||
import { EpisodeMappingPanel } from "~/components/episode-mapping/mapping-panel.tsx";
|
||||
import { evidenceLabel, FieldLockDialog, IdentityDialog, MergeDialog } from "~/components/library/entity-dialogs.tsx";
|
||||
import {
|
||||
CONTENT_TYPE,
|
||||
@@ -1215,6 +1216,7 @@ export default function LibraryDetailPage() {
|
||||
{e.kind !== "movie" ? <EpisodesPanel detail={d} units={entity.data?.contentUnits ?? []} /> : null}
|
||||
{e.kind === "movie" ? <MovieVersionsPanel entityId={e.id} /> : null}
|
||||
<SlotsPanel detail={d} units={entity.data?.contentUnits ?? []} />
|
||||
{e.kind === "series" || e.kind === "variety" ? <EpisodeMappingPanel entityId={e.id} /> : null}
|
||||
<div className="grid gap-5 xl:grid-cols-2">
|
||||
<IdentityPanel detail={d} />
|
||||
<MetadataPanel detail={d} entity={entity.data} />
|
||||
|
||||
@@ -12,6 +12,7 @@ import { ErrorState, LoadingState } from "~/components/console/empty-state.tsx";
|
||||
import { KvList } from "~/components/console/kv-list.tsx";
|
||||
import { consolePath } from "~/components/console/nav.ts";
|
||||
import { StatusBadge } from "~/components/console/status-badge.tsx";
|
||||
import { SubscriptionMappingSummary } from "~/components/episode-mapping/subscription-summary.tsx";
|
||||
import { PRIORITY, SEASON_SCOPE, SUB_MODE, SUB_ORIGIN, SUB_STATUS } from "~/components/library/labels.ts";
|
||||
import { CoverPlaceholder, Panel, relTime, Tone } from "~/components/library/parts.tsx";
|
||||
import { SlotsPanel } from "~/components/library/subscriptions-slots.tsx";
|
||||
@@ -215,6 +216,10 @@ export default function SubscriptionDetailPage() {
|
||||
|
||||
{sub.mediaEntityId ? <SlotPanel sub={sub} cov={cov} item={item} canFill={tracking} /> : null}
|
||||
|
||||
{sub.mediaEntityId && sub.mediaKind !== "movie" ? (
|
||||
<SubscriptionMappingSummary entityId={sub.mediaEntityId} seasonUnitId={sub.seasonUnitId} />
|
||||
) : null}
|
||||
|
||||
<div className="grid gap-5 lg:grid-cols-2">
|
||||
<Panel title="订阅信息">
|
||||
<KvList
|
||||
|
||||
Reference in new issue
Block a user