Files
xiaoxia-saas/apps/web/src/api/templates.ts
T
CI Bot d2ea8ba579
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 47s
CI/CD Pipeline / Frontend Lint (push) Failing after 58s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 58s
CI/CD Pipeline / Production Browser E2E (pull_request) Failing after 1513h42m38s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 1513h42m38s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 1513h42m39s
CI/CD Pipeline / Build Production Web Image (pull_request) Failing after 1513h42m39s
CI/CD Pipeline / Build Production Worker Image (pull_request) Failing after 1513h42m40s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 1513h42m40s
CI/CD Pipeline / Build Production API Image (pull_request) Failing after 1513h42m40s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 1513h42m40s
CI/CD Pipeline / Production Browser E2E (push) Failing after 1513h43m42s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 1513h43m45s
CI/CD Pipeline / Staging API Integration Tests (push) Failing after 1513h43m42s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1513h43m42s
CI/CD Pipeline / Build Production API Image (push) Failing after 1513h43m46s
CI/CD Pipeline / Build Staging Worker Image (push) Failing after 1513h43m46s
CI/CD Pipeline / Deploy Production (push) Failing after 1513h43m44s
CI/CD Pipeline / Build Staging API Image (push) Failing after 1513h43m46s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Failing after 1513h43m44s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 1514h14m20s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 1514h14m21s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 1514h14m22s
CI/CD Pipeline / Unit Tests (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Failing after 1514h15m27s
CI/CD Pipeline / Build Staging Web Image (push) Failing after 1514h15m28s
fix: TemplateItem 类型 estimated_duration 字段对齐后端 API
- TemplateItem 新增 estimated_duration 字段,匹配后端实际返回字段名
- target_duration 标记为 deprecated,保留向后兼容
- TemplateLibrary 两处引用改为 estimated_duration ?? target_duration 回退
- 新增 mode/user_id 可选字段,description/clip_count/is_active 改 optional

修复模板卡片时长显示 NaN 问题(根因:前端读 target_duration 但后端返回 estimated_duration)
2026-07-15 13:45:22 +08:00

179 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 模板相关 API
* 对接后端模板管理接口:
* - GET /api/v1/templates — 模板列表(分页/筛选)
* - GET /api/v1/templates/{id} — 模板详情
* - POST /api/v1/templates/{id}/copy — 复制模板
* - POST /api/v1/templates/{id}/generate — 从模板生成剪辑计划
* - POST /api/v1/templates/{id}/toggle-favorite — 收藏/取消收藏
*/
import apiClient from "./client";
import type { TitleConfig, SubtitleConfig, BgmConfig } from "./editingPlanner";
import type { EditPlanConfig } from "./editPlans";
/* ──────────── 类型定义 ──────────── */
/** 模板条目(后端 TemplateResponse) */
export interface TemplateItem {
id: string;
user_id?: string;
name: string;
description?: string;
mode?: string;
category: string;
tags?: string[];
/** 预估时长(后端字段名 estimated_duration) */
estimated_duration?: number;
/** @deprecated 后端已改名为 estimated_duration,保留兼容 */
target_duration?: number;
clip_count?: number;
/** 使用次数 */
usage_count?: number;
thumbnail_url?: string;
preview_url?: string;
is_active?: boolean;
is_favorite?: boolean;
/** 素材规则(片段配置) */
segments?: TemplateSegment[];
/** 字幕样式 */
subtitle_config?: SubtitleConfig;
/** BGM 配置 */
bgm_config?: BgmConfig;
/** 标题配置 */
title_config?: TitleConfig;
/** 视频比例 */
aspect_ratio?: string;
created_at?: string;
updated_at?: string;
}
/** 模板片段(素材规则) */
export interface TemplateSegment {
id?: string;
segment_order: number;
duration_min: number;
duration_max: number;
material_type: string | null;
description?: string;
}
/** 模板列表查询参数 */
export interface TemplateListParams {
page?: number;
page_size?: number;
category?: string;
tags?: string;
keyword?: string;
/** 时长筛选(秒):short < 30, medium 30-120, long > 120 */
duration_range?: "short" | "medium" | "long";
}
/** 模板列表分页响应 */
export interface TemplateListResponse {
items: TemplateItem[];
total: number;
page: number;
page_size: number;
}
/** 从模板生成剪辑计划请求 */
export interface GenerateFromTemplateRequest {
asset_ids?: string[];
name?: string;
config?: EditPlanConfig;
}
/** 从模板生成剪辑计划响应 */
export interface GenerateFromTemplateResponse {
plan_id: string;
template_id: string;
status: string;
name: string;
}
/** 复制模板响应 */
export interface CopyTemplateResponse {
id: string;
name: string;
source_template_id: string;
}
/* ──────────── API 函数 ──────────── */
/** 获取模板列表(支持分页和筛选) */
export const getTemplates = async (
params?: TemplateListParams,
): Promise<TemplateListResponse> => {
const { data } = await apiClient.get<TemplateListResponse>("/templates", {
params,
});
return data;
};
/** 获取模板列表(兼容旧接口,返回数组) */
export const getTemplatesList = async (): Promise<TemplateItem[]> => {
const response = await apiClient.get("/templates");
return response.data.items || response.data || [];
};
/** 获取单个模板详情 */
export const getTemplate = async (
templateId: string,
): Promise<TemplateItem> => {
const response = await apiClient.get(`/templates/${templateId}`);
return response.data;
};
/** 收藏 / 取消收藏模板 */
export const toggleFavoriteTemplate = async (
templateId: string,
): Promise<{ is_favorite: boolean }> => {
const response = await apiClient.post(
`/templates/${templateId}/toggle-favorite`,
);
return response.data;
};
/** 复制模板(创建副本到我的模板) */
export const copyTemplate = async (
templateId: string,
): Promise<CopyTemplateResponse> => {
const response = await apiClient.post<CopyTemplateResponse>(
`/templates/${templateId}/copy`,
);
return response.data;
};
/** 从模板生成剪辑计划 */
export const generateFromTemplate = async (
templateId: string,
data?: GenerateFromTemplateRequest,
): Promise<GenerateFromTemplateResponse> => {
const response = await apiClient.post<GenerateFromTemplateResponse>(
`/templates/${templateId}/generate`,
data,
);
return response.data;
};
/* ──────────── 常量 ──────────── */
/** 模板分类选项 */
export const TEMPLATE_CATEGORY_OPTIONS = [
{ value: "", label: "全部分类" },
{ value: "口播", label: "口播" },
{ value: "种草", label: "种草" },
{ value: "产品", label: "产品" },
{ value: "品牌", label: "品牌" },
{ value: "混剪", label: "混剪" },
{ value: "Vlog", label: "Vlog" },
];
/** 时长筛选选项 */
export const TEMPLATE_DURATION_OPTIONS = [
{ value: "", label: "全部时长" },
{ value: "short", label: "30秒以内" },
{ value: "medium", label: "30秒-2分钟" },
{ value: "long", label: "2分钟以上" },
];