refactor: update usePreviewAssets.ts
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user