video-shuoshan/web/src/store/assetLibrary.ts
seaislee1209 da9a1413c3 v0.18.0 素材库多类型支持 + @ 引用改为单素材
对齐火山 API 文档(Asset URI 小写、HEIC/HEIF、DeleteAsset)
素材库支持视频/音频上传(按类型分三区显示、前端校验、拖拽上传)
@ 引用从素材组改为单个素材(搜索返回具体素材、即时数量/时长检查)
ffmpeg 视频封面帧提取 + 音频时长读取(Celery 异步)
生产级安全修复(跨团队校验、异常信息脱敏、下载大小限制)
2026-04-04 17:36:35 +08:00

80 lines
2.2 KiB
TypeScript

import { create } from 'zustand';
import { assetsApi } from '../lib/api';
import type { AssetGroup, AssetSearchResult } from '../types';
import { showToast } from '../components/Toast';
interface AssetLibraryState {
groups: AssetGroup[];
loading: boolean;
total: number;
page: number;
searchResults: AssetSearchResult[];
searching: boolean;
loadGroups: (page?: number) => Promise<void>;
searchAssets: (query: string) => Promise<void>;
createGroup: (name: string, file: File | null) => Promise<AssetGroup | null>;
pollAssetStatus: (assetId: number) => void;
}
export const useAssetLibraryStore = create<AssetLibraryState>((set) => ({
groups: [],
loading: false,
total: 0,
page: 1,
searchResults: [],
searching: false,
loadGroups: async (page = 1) => {
set({ loading: true });
try {
const { data } = await assetsApi.getGroups({ page, page_size: 20 });
set({ groups: data.results, total: data.total, page, loading: false });
} catch {
set({ loading: false });
}
},
searchAssets: async (query: string) => {
set({ searching: true });
try {
const { data } = await assetsApi.search(query);
set({ searchResults: data.results, searching: false });
} catch {
set({ searching: false });
}
},
createGroup: async (name: string, file: File | null) => {
const formData = new FormData();
formData.append('name', name);
if (file) formData.append('file', file);
try {
const { data } = await assetsApi.createGroup(formData);
showToast('角色创建成功');
return data;
} catch {
showToast('创建失败,请重试');
return null;
}
},
pollAssetStatus: (assetId: number) => {
const poll = async () => {
try {
const { data } = await assetsApi.pollStatus(assetId);
if (data.status === 'processing') {
setTimeout(poll, 3000);
} else if (data.status === 'active') {
showToast('素材处理完成');
} else if (data.status === 'failed') {
showToast(data.error_message || '素材处理失败');
}
} catch {
setTimeout(poll, 3000);
}
};
setTimeout(poll, 3000);
},
}));