a25aa7baed
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Check push changed paths (push) Successful in 16s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 27s
CI/CD Pipeline / Build Staging API Image (push) Successful in 28s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 30s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m1s
CI/CD Pipeline / Frontend Unit Tests (push) Failing after 2m49s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m56s
CI/CD Pipeline / Integration Tests (push) Successful in 4m0s
CI/CD Pipeline / Validate - Style (push) Successful in 4m23s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m7s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m9s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 6m48s
CI/CD Pipeline / Validate - Security (push) Successful in 9m39s
CI/CD Pipeline / Unit Tests (push) Successful in 9m40s
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Failing after 27h59m57s
CI/CD Pipeline / Build Production Web Image (push) Failing after 28h0m1s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Failing after 28h8m54s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 28h9m45s
CI/CD Pipeline / PR Build Web Image (push) Failing after 28h9m7s
CI/CD Pipeline / PR Build API Image (push) Failing after 28h9m7s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 27h59m23s
CI/CD Pipeline / Build Production API Image (push) Failing after 27h59m24s
CI/CD Pipeline / CI Gate (push) Failing after 27h59m23s
CI/CD Pipeline / Canary Release to Production (push) Failing after 27h59m19s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Failing after 28h8m16s
CI/CD Pipeline / Retag skipped Staging API Image (push) Failing after 28h8m17s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 28h9m8s
CI/CD Pipeline / Frontend Lint (push) Failing after 28h9m4s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
119 lines
3.7 KiB
TypeScript
119 lines
3.7 KiB
TypeScript
/**
|
||
* 片段 CRUD + 批量操作 API
|
||
*/
|
||
import apiClient from "../client"
|
||
import type {
|
||
EditPlanClip,
|
||
EditPlanClipListParams,
|
||
EditPlanClipListResponse,
|
||
CreateEditPlanClipRequest,
|
||
UpdateEditPlanClipRequest,
|
||
ClipReorderItem,
|
||
ClipReorderResponse,
|
||
ClipBatchDeleteResponse,
|
||
ClipsFromAssetsResponse,
|
||
} from "./types"
|
||
|
||
/** 获取片段列表 */
|
||
export async function getEditPlanClips(
|
||
templateId: string,
|
||
params?: EditPlanClipListParams,
|
||
): Promise<EditPlanClipListResponse> {
|
||
const response = await apiClient.get<EditPlanClipListResponse>(
|
||
`/templates/${templateId}/editor/clips`,
|
||
{ params },
|
||
)
|
||
return response.data
|
||
}
|
||
|
||
/** 获取单个片段详情 */
|
||
export async function getEditPlanClip(templateId: string, clipId: string): Promise<EditPlanClip> {
|
||
const response = await apiClient.get<EditPlanClip>(
|
||
`/templates/${templateId}/editor/clips/${clipId}`,
|
||
)
|
||
return response.data
|
||
}
|
||
|
||
/** 创建片段 */
|
||
export async function createEditPlanClip(
|
||
templateId: string,
|
||
data: CreateEditPlanClipRequest,
|
||
): Promise<EditPlanClip> {
|
||
const response = await apiClient.post<EditPlanClip>(`/templates/${templateId}/editor/clips`, data)
|
||
return response.data
|
||
}
|
||
|
||
/** 更新片段 */
|
||
export async function updateEditPlanClip(
|
||
templateId: string,
|
||
clipId: string,
|
||
data: UpdateEditPlanClipRequest,
|
||
): Promise<EditPlanClip> {
|
||
const response = await apiClient.put<EditPlanClip>(
|
||
`/templates/${templateId}/editor/clips/${clipId}`,
|
||
data,
|
||
)
|
||
return response.data
|
||
}
|
||
|
||
/** 删除片段 */
|
||
export async function deleteEditPlanClip(templateId: string, clipId: string): Promise<void> {
|
||
await apiClient.delete(`/templates/${templateId}/editor/clips/${clipId}`)
|
||
}
|
||
|
||
/** 片段重排序(拖拽排序后一次性提交) */
|
||
export async function reorderEditPlanClips(
|
||
templateId: string,
|
||
items: ClipReorderItem[],
|
||
): Promise<ClipReorderResponse> {
|
||
const response = await apiClient.post<ClipReorderResponse>(
|
||
`/templates/${templateId}/editor/clips/reorder`,
|
||
{ items },
|
||
)
|
||
return response.data
|
||
}
|
||
|
||
/** 批量删除片段 */
|
||
export async function batchDeleteEditPlanClips(
|
||
templateId: string,
|
||
clipIds: string[],
|
||
): Promise<ClipBatchDeleteResponse> {
|
||
const response = await apiClient.post<ClipBatchDeleteResponse>(
|
||
`/templates/${templateId}/editor/clips/batch-delete`,
|
||
{ clip_ids: clipIds },
|
||
)
|
||
return response.data
|
||
}
|
||
|
||
/**
|
||
* 从素材批量创建片段(追加到时间线末尾)。
|
||
* #1921 修复:templateId 为空时调用新端点 POST /clips/from-assets,避免拼出双斜杠
|
||
* `/templates//editor/clips/from-assets` 导致 404;有 templateId 时保持原路径向后兼容。
|
||
*/
|
||
export async function createClipsFromAssets(
|
||
templateId: string | undefined | null,
|
||
assetIds: string[],
|
||
clipType = "main",
|
||
requiredClipsCount?: number,
|
||
opts?: { signal?: AbortSignal; silentErrorToast?: boolean },
|
||
): Promise<ClipsFromAssetsResponse> {
|
||
const body: Record<string, unknown> = {
|
||
asset_ids: assetIds,
|
||
clip_type: clipType,
|
||
}
|
||
if (requiredClipsCount !== undefined) {
|
||
body.required_clips_count = requiredClipsCount
|
||
}
|
||
// 新端点(#1921):templateId 为空时,body 不传 template_id,由后端兜底创建默认模板
|
||
const hasTid = !!templateId
|
||
const url = hasTid ? `/templates/${templateId}/editor/clips/from-assets` : "/clips/from-assets"
|
||
// from-assets 后端会调用 MediaKit 智能选片(最长 60s),单独延长超时
|
||
const response = await apiClient.post<ClipsFromAssetsResponse>(url, body, {
|
||
timeout: 60000,
|
||
signal: opts?.signal,
|
||
// _silentErrorToast 由 api/client.ts 响应拦截器读取(抑制全局错误 toast,#1777)
|
||
...(opts?.silentErrorToast ? ({ _silentErrorToast: true } as Record<string, unknown>) : {}),
|
||
})
|
||
return response.data
|
||
}
|