/** * 成品 / 视频相关 API * 包含:列表查询、复核状态、批量下载 * 后端无 /products 路由,实际从 /generation/tasks 端点获取数据 */ import apiClient from "./client"; import { getGenerationTaskResults } from "./editPlans"; import type { GeneratedVideo } from "./editPlans"; /** 复核状态 */ export type ReviewStatus = "pending_review" | "approved" | "rejected"; /** 成品条目 */ export interface ProductItem { id: string; title: string; video_url?: string; thumbnail_url?: string; duration_seconds?: number; file_size?: number; resolution?: string; status: "processing" | "completed" | "failed"; /** 复核状态 */ review_status?: ReviewStatus; /** 所属项目 ID */ project_id?: string; /** 所属项目名称 */ project_name?: string; /** 查重率(百分比) */ duplicate_rate?: number; created_at?: string; updated_at?: string; } /** 列表查询参数 */ export interface ProductListParams { page?: number; page_size?: number; project_id?: string; review_status?: ReviewStatus | "all"; } /** 分页响应 */ export interface ProductListResponse { items: ProductItem[]; total: number; page: number; page_size: number; } /** 批量下载任务状态 */ export interface BatchDownloadStatus { job_id: string; status: "processing" | "completed" | "failed"; /** 完成后返回的下载 URL */ download_url?: string; /** 进度百分比 */ progress?: number; } /** * 将 generation task 数据映射为 ProductItem 格式 */ function mapTaskToProductItem(task: GeneratedVideo): ProductItem { return { id: task.id, title: task.name || "未命名视频", video_url: task.file_url, thumbnail_url: task.thumbnail_url, duration_seconds: task.duration, file_size: task.file_size, resolution: task.width && task.height ? `${task.width}x${task.height}` : undefined, status: task.status === "completed" ? "completed" : task.status === "failed" ? "failed" : "processing", review_status: task.review_status as ReviewStatus | undefined, project_id: task.project_id, created_at: task.created_at, updated_at: task.updated_at, }; } /** 获取成品列表(支持分页和筛选)— 实际从 generation tasks 获取 */ export const getProducts = async ( params?: ProductListParams, ): Promise => { const response = await apiClient.get("/generation/tasks", { params }); const tasks = response.data.items || response.data || []; return tasks.map(mapTaskToProductItem); }; /** 获取单个成品详情 — 通过 task ID 获取结果 */ export const getProduct = async (productId: string): Promise => { const response = await apiClient.get(`/generation/tasks/${productId}`); return mapTaskToProductItem(response.data); }; /** 删除成品 — 删除 generation task */ export const deleteProduct = async (productId: string): Promise => { await apiClient.delete(`/generation/tasks/${productId}`); }; /** 获取成品下载链接 — 从 generation task results 获取 */ export const getProductDownloadUrl = async ( productId: string, ): Promise<{ url: string; expires_at: string }> => { const videos = await getGenerationTaskResults(productId); const video = videos[0]; if (!video?.download_url) throw new Error("下载链接不可用"); return { url: video.download_url, expires_at: "" }; }; /** 更新复核状态 — TODO: 后端暂无对应端点,暂存本地状态 */ export const updateReviewStatus = async ( productId: string, status: ReviewStatus, ): Promise => { // 后端暂无 /generation/tasks/{id}/review 端点 // 暂时返回当前状态,后续可扩展 const product = await getProduct(productId); return { ...product, review_status: status }; }; /** 发起批量下载 — TODO: 后端暂无对应端点 */ export const batchDownload = async ( videoIds: string[], ): Promise<{ job_id: string }> => { // 后端暂无 /generation/tasks/batch-download 端点 // 暂时返回模拟 job_id,后续可扩展 console.warn("[batchDownload] 后端暂无批量下载端点", videoIds); return { job_id: `mock-${Date.now()}` }; }; /** 查询批量下载状态 — TODO: 后端暂无对应端点 */ export const getBatchDownloadStatus = async ( jobId: string, ): Promise => { // 后端暂无 /generation/tasks/batch-download/{jobId} 端点 // 暂时返回模拟状态,后续可扩展 console.warn("[getBatchDownloadStatus] 后端暂无批量下载状态端点", jobId); return { job_id: jobId, status: "processing", progress: 0 }; };