refactor: update usePreviewAssets.ts

This commit is contained in:
2026-08-18 01:04:50 +08:00
parent 5e377d18a4
commit 4f308926bd
@@ -0,0 +1,106 @@
/**
* 预览素材加载 Hook
* 根据选中的素材 ID 列表,批量获取素材详情(含 file_url、duration 等)
* 供前端预览播放器使用
*/
import { useState, useEffect, useCallback, useRef } from "react"
import type { AssetItem } from "@/api/assets"
/** 批量获取素材详情的 API 路径 */
const ASSETS_BATCH_URL = "/assets/batch"
/**
* 通过 ID 列表批量获取素材
* 优先使用批量接口,失败则回退为逐个获取
*/
async function fetchAssetsByIds(ids: string[]): Promise<AssetItem[]> {
if (!ids.length) return []
try {
// 尝试批量接口
const { default: apiClient } = await import("@/api/client")
const response = await apiClient.post(ASSETS_BATCH_URL, { ids })
const items: AssetItem[] = response.data?.items || response.data || []
if (items.length > 0) return items
} catch {
// 批量接口不存在,回退为逐个获取
}
// 回退:逐个获取
try {
const { default: apiClient } = await import("@/api/client")
const results = await Promise.allSettled(
ids.map((id) => apiClient.get(`/assets/${id}`)),
)
return results
.filter(
(r): r is PromiseFulfilledResult<{ data: AssetItem }> =>
r.status === "fulfilled" && r.value?.data,
)
.map((r) => r.value.data)
} catch {
return []
}
}
interface UsePreviewAssetsReturn {
/** 加载后的素材列表 */
assets: AssetItem[]
/** 是否正在加载 */
loading: boolean
/** 是否已就绪(加载完成) */
ready: boolean
/** 手动触发重新加载 */
reload: () => void
}
/**
* usePreviewAssets — 加载选中素材的视频文件信息
*/
export function usePreviewAssets(
assetIds: string[],
enabled: boolean,
): UsePreviewAssetsReturn {
const [assets, setAssets] = useState<AssetItem[]>([])
const [loading, setLoading] = useState(false)
const [ready, setReady] = useState(false)
const requestIdRef = useRef(0)
const load = useCallback(async () => {
if (!assetIds.length || !enabled) {
setAssets([])
setReady(false)
return
}
const thisRequestId = ++requestIdRef.current
setLoading(true)
setReady(false)
try {
const result = await fetchAssetsByIds(assetIds)
// 防止竞态:只保留最新请求的结果
if (requestIdRef.current === thisRequestId) {
setAssets(result)
setReady(result.length > 0)
}
} catch {
if (requestIdRef.current === thisRequestId) {
setAssets([])
setReady(false)
}
} finally {
if (requestIdRef.current === thisRequestId) {
setLoading(false)
}
}
}, [assetIds, enabled])
useEffect(() => {
load()
}, [load])
return { assets, loading, ready, reload: load }
}
export default usePreviewAssets