/** * 成品 / 视频相关 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 } }