From 2d798bf8a6a7c38e220a2b462a609e754a525bc7 Mon Sep 17 00:00:00 2001 From: Xiaoxia AI Date: Mon, 22 Jun 2026 22:09:41 +0800 Subject: [PATCH] fix(web): allow batch asset uploads --- .../web/src/pages/workspace/ProjectAssets.tsx | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/apps/web/src/pages/workspace/ProjectAssets.tsx b/apps/web/src/pages/workspace/ProjectAssets.tsx index c52f2f1f0..f0950f79e 100644 --- a/apps/web/src/pages/workspace/ProjectAssets.tsx +++ b/apps/web/src/pages/workspace/ProjectAssets.tsx @@ -90,7 +90,7 @@ const ProjectAssets: React.FC = () => { const workspaceId = routedWorkspaceId || storedWorkspaceId || resolvedWorkspaceId; const [libraryId, setLibraryId] = useState(''); const [createLibraryOpen, setCreateLibraryOpen] = useState(false); - const [uploading, setUploading] = useState(false); + const [activeUploadCount, setActiveUploadCount] = useState(0); const [ingestJobId, setIngestJobId] = useState(''); const [classificationJobId, setClassificationJobId] = useState(''); const [classifyingAssetId, setClassifyingAssetId] = useState(''); @@ -102,6 +102,7 @@ const ProjectAssets: React.FC = () => { const [batchJobIds, setBatchJobIds] = useState([]); const [batchFailedIds, setBatchFailedIds] = useState([]); const [form] = Form.useForm(); + const uploading = activeUploadCount > 0; useEffect(() => { if (projectId && routedWorkspaceId) { @@ -172,12 +173,10 @@ const ProjectAssets: React.FC = () => { useEffect(() => { const status = ingestJobQuery.data?.status; if (status === 'completed') { - setUploading(false); assetsQuery.refetch(); message.success('素材导入完成,已自动发起分类'); } if (status === 'failed') { - setUploading(false); message.error(ingestJobQuery.data?.error_message || '素材导入失败'); } }, [ingestJobQuery.data?.status, assetsQuery]); @@ -413,25 +412,33 @@ const ProjectAssets: React.FC = () => { const customUpload = async (options: any) => { const { file, onSuccess, onError } = options; - if (!libraryId) { - message.warning('请先选择或创建素材库'); + const uploadFile = file as File; + if (!workspaceId) { + message.warning('正在恢复工作空间上下文,请稍后再上传'); + onError(new Error('Missing workspace context')); return; } + if (!libraryId) { + message.warning('请先选择或创建素材库'); + onError(new Error('Missing asset library')); + return; + } + setActiveUploadCount((count) => count + 1); try { - setUploading(true); const formData = new FormData(); - formData.append('file', file); + formData.append('file', uploadFile); formData.append('workspace_id', workspaceId); formData.append('project_id', projectId); formData.append('library_id', libraryId); const result = await uploadAsset(formData); setIngestJobId(result.ingest_job_id); onSuccess(result); - message.info('文件已上传,正在导入处理中'); + message.info(`${uploadFile.name} 已上传,正在导入处理中`); } catch (error) { - setUploading(false); onError(error); - message.error((error as any).response?.data?.detail || '上传失败'); + message.error((error as any).response?.data?.detail || `${uploadFile.name} 上传失败`); + } finally { + setActiveUploadCount((count) => Math.max(0, count - 1)); } }; @@ -527,10 +534,12 @@ const ProjectAssets: React.FC = () => { )} - +

-

点击或拖拽文件到这里上传素材

-

支持视频、音频、图片文件;上传后自动进入导入任务

+

点击或拖拽文件到这里批量上传素材

+

+ 支持一次选择多个视频、音频、图片文件;上传中 {uploading ? `(${activeUploadCount} 个文件处理中)` : '自动进入导入任务'} +

{filteredAssets.length ? (