import type { ReactNode } from "react";
import { Tag } from "antd";
import { Check, CircleAlert } from "lucide-react";
import { Link } from "react-router";
import type { ProjectDetail, ProjectShot, ShotArtifact, ShotRevision, WorkflowStep } from "@/services/api/projects";
export type ShortDramaWorkflowStage = "story" | "assets" | "storyboard" | "previz" | "video" | "delivery";
export const workflowStages: Array<{ key: ShortDramaWorkflowStage; label: string; shortLabel: string }> = [
{ key: "story", label: "剧情与章节", shortLabel: "剧情" },
{ key: "assets", label: "资产拆分", shortLabel: "资产" },
{ key: "storyboard", label: "分镜脚本", shortLabel: "分镜" },
{ key: "previz", label: "黑白动作预演", shortLabel: "预演" },
{ key: "video", label: "视频生成", shortLabel: "视频" },
{ key: "delivery", label: "交付与打包", shortLabel: "交付" },
];
export function WorkflowStageLink({ href, active, step, index, label, shortLabel }: { href: string; active: boolean; step?: WorkflowStep; index: number; label: string; shortLabel: string }) {
const completed = step?.status === "completed" || step?.status === "skipped";
const failed = step?.status === "failed";
return (
{completed ? : failed ? : index + 1}
{shortLabel}
{label}
);
}
export function StageHeading({ eyebrow, title, description }: { eyebrow: string; title: string; description: string }) {
return
{eyebrow}
{title}
{description}
;
}
export function MetricCard({ icon, label, value }: { icon: ReactNode; label: string; value: string }) {
return ;
}
export function ArtifactStatus({ artifact, compact = false }: { artifact?: ShotArtifact; compact?: boolean }) {
if (!artifact) return 待生成;
const color = artifact.status === "ready" ? "green" : artifact.status === "failed" ? "red" : artifact.status === "stale" ? "orange" : "blue";
const label = artifact.status === "ready" ? "已生成" : artifact.status === "failed" ? "失败" : artifact.status === "stale" ? "已过期" : "生成中";
return {label};
}
export function currentRevision(detail: ProjectDetail, shot?: ProjectShot): ShotRevision | undefined {
if (!shot) return undefined;
const revisions = detail.shotRevisions || [];
return revisions.find((item) => item.id === shot.currentRevisionId)
|| revisions.filter((item) => item.shotId === shot.id).slice().sort((left, right) => right.version - left.version)[0];
}
export function currentArtifact(detail: ProjectDetail, shotId: string, type: string) {
const artifacts = (detail.shotArtifacts || []).filter((item) => item.shotId === shotId && item.type === type).slice().sort((left, right) => right.version - left.version);
return artifacts.find((item) => item.selected) || artifacts[0];
}
export function artifactTypeForStage(stage: ShortDramaWorkflowStage) {
if (stage === "video") return "video";
if (stage === "previz") return "action_board";
return "storyboard";
}
export function assetCategoryLabel(category: string) {
return ({ character: "角色", environment: "场景", wardrobe: "服饰", accessory: "配饰", prop: "道具", weapon: "武器", style: "画风" } as Record)[category] || category || "其他";
}
export function formatDuration(durationMs: number) {
if (durationMs < 60_000) return `${Math.round(durationMs / 100) / 10}s`;
const minutes = Math.floor(durationMs / 60_000);
const seconds = Math.round((durationMs % 60_000) / 1000);
return `${minutes}m ${seconds}s`;
}
export function stageActionLabel(step?: WorkflowStep) {
if (!step || step.status === "pending") return "等待上一步";
if (step.status === "running" || step.status === "review") return "完成阶段";
if (step.status === "completed") return "重新打开";
if (step.status === "failed") return "重新开始";
return "开始阶段";
}