feat(assets): 上传即入库——批量上传队列化(并发3)+真实进度+刷新不丢 #1557

Merged
auto-approve-bot merged 1 commits from feat/upload-instant-assets into develop 2026-08-30 17:56:04 +08:00
Owner

背景

批量上传视频后素材库很久才显示:①直传阶段只有内存乐观卡片、刷新即丢,服务端 complete 后才有记录;②10 路并发直传瓜分上行带宽;③直传完还要等 worker 转码约 3 分钟才可见。

前端改造(本 PR),后端配合在 /upload/direct/prepare 预创建 status=uploading 的 asset 并返回 asset_id(后端任务并行,前端对旧返回做降级兼容)。

改动

API 层(api/assets)

  • DirectUploadPrepareResult 新增可选 asset_id(后端预建素材 id;旧后端不返回 → 降级为原行为)
  • 新增 prepareDirectUploadHandle():把直传拆为 prepare → transfer(OSS, onProgress) → complete 三段,支持队列调度与失败重试;uploadAssetDirect() 旧签名保留为「一次性完成」封装,配音库/克隆音色等既有调用方零改动

useAssetUpload 重写(队列式批量)

  • 多文件入队,OSS 直传并发限制 3(inFlightRef 计数 + claimedRef 防止同一任务被多个 pump 重复认领),其余排队,前序完成自动拉起
  • 每文件独立状态机:preparing → uploading(真实 XHR 进度) → ingesting → done/error
  • prepare 拿到 asset_id 后立即 invalidate 素材列表,卡片以「上传中」态出现在网格(服务端记录为准,刷新页面不丢);complete 后转「转码中」,轮询到 ready 可播放
  • 失败卡片可重试(重新 prepare+transfer)、可移除;duplicated 去重提示逻辑不变

UI

  • 删除阻塞式单文件进度弹窗 UploadProgressModal,新增 UploadQueuePanel:每文件独立进度条/状态/重试/移除/清空已完成
  • AssetUploadZone 多文件拖入即入队,文案显示「上传中…(进行 N 个,排队 M 个)」
  • AssetCard:上传中遮罩显示真实百分比 + 进度条;转码中遮罩与上传中区分
  • useAssetsData:列表存在 uploading/ingesting/processing/pending 素材时每 3s 轮询(refetchInterval 动态求值),全部就绪自动停止;status 全量参数不变

不改动

去重逻辑、单文件/配音上传流程、上传弹窗交互、素材筛选/播放、clips 提交链路。

测试

  • 新增 useAssetUpload.test.tsx 3 用例:5 文件并发不超过 3 且全部完成/刷新列表、传输失败重试成功、duplicated 去重标记
  • tsc / ESLint 0 warning / prettier / 全量单测 607 passed

验收(依赖后端 prepare 返回 asset_id 上线后端到端完整;旧后端下队列/并发/进度/重试仍生效,仅卡片即时出现降级为 complete 后出现)

拖入 5 个视频 → 素材库立刻出现 5 张「上传中」卡片显示真实进度 → 刷新不消失 → 传完依次变「转码中」→ 完成可播放;同时直传不超过 3 路;去重提示正常。

## 背景 批量上传视频后素材库很久才显示:①直传阶段只有内存乐观卡片、刷新即丢,服务端 complete 后才有记录;②10 路并发直传瓜分上行带宽;③直传完还要等 worker 转码约 3 分钟才可见。 **前端改造(本 PR)**,后端配合在 `/upload/direct/prepare` 预创建 `status=uploading` 的 asset 并返回 `asset_id`(后端任务并行,前端对旧返回做降级兼容)。 ## 改动 ### API 层(api/assets) - `DirectUploadPrepareResult` 新增可选 `asset_id`(后端预建素材 id;旧后端不返回 → 降级为原行为) - 新增 `prepareDirectUploadHandle()`:把直传拆为 prepare → transfer(OSS, onProgress) → complete 三段,支持队列调度与失败重试;`uploadAssetDirect()` 旧签名保留为「一次性完成」封装,**配音库/克隆音色等既有调用方零改动** ### useAssetUpload 重写(队列式批量) - 多文件入队,**OSS 直传并发限制 3**(inFlightRef 计数 + claimedRef 防止同一任务被多个 pump 重复认领),其余排队,前序完成自动拉起 - 每文件独立状态机:`preparing → uploading(真实 XHR 进度) → ingesting → done/error` - prepare 拿到 asset_id 后**立即 invalidate 素材列表**,卡片以「上传中」态出现在网格(服务端记录为准,**刷新页面不丢**);complete 后转「转码中」,轮询到 ready 可播放 - 失败卡片可**重试**(重新 prepare+transfer)、可移除;`duplicated` 去重提示逻辑不变 ### UI - 删除阻塞式单文件进度弹窗 `UploadProgressModal`,新增 `UploadQueuePanel`:每文件独立进度条/状态/重试/移除/清空已完成 - `AssetUploadZone` 多文件拖入即入队,文案显示「上传中…(进行 N 个,排队 M 个)」 - `AssetCard`:上传中遮罩显示**真实百分比 + 进度条**;转码中遮罩与上传中区分 - `useAssetsData`:列表存在 uploading/ingesting/processing/pending 素材时每 3s 轮询(refetchInterval 动态求值),全部就绪自动停止;status 全量参数不变 ### 不改动 去重逻辑、单文件/配音上传流程、上传弹窗交互、素材筛选/播放、clips 提交链路。 ## 测试 - 新增 `useAssetUpload.test.tsx` 3 用例:5 文件并发不超过 3 且全部完成/刷新列表、传输失败重试成功、duplicated 去重标记 - tsc ✅ / ESLint 0 warning ✅ / prettier ✅ / 全量单测 607 passed ✅ ## 验收(依赖后端 prepare 返回 asset_id 上线后端到端完整;旧后端下队列/并发/进度/重试仍生效,仅卡片即时出现降级为 complete 后出现) 拖入 5 个视频 → 素材库立刻出现 5 张「上传中」卡片显示真实进度 → 刷新不消失 → 传完依次变「转码中」→ 完成可播放;同时直传不超过 3 路;去重提示正常。
xiaoxia added 1 commit 2026-08-30 17:38:44 +08:00
feat(assets): 上传即入库——批量上传队列化(并发3)+真实进度+刷新不丢
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m7s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m21s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m38s
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 5m13s
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m7s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m11s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m11s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 3m16s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 3m44s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 4m43s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m8s
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 2m38s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 3m37s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 3m55s
f8bae5a15f
- API 层:prepareDirectUpload 返回新增可选 asset_id(后端 prepare 预建
  status=uploading 的素材记录,旧后端不返回则降级为原行为);新增
  prepareDirectUploadHandle 拆分为 prepare/transfer/complete 三段,
  支持队列调度与失败重试;uploadAssetDirect 旧签名保留,配音/克隆等
  既有调用方零改动
- useAssetUpload 重写为队列式批量管理:多文件入队,OSS 直传并发限制 3
  (inFlightRef + claimedRef 防重复认领),其余排队;每个文件独立
  状态机 preparing→uploading(真实进度)→ingesting→done/error;
  prepare 拿到 asset_id 立即 invalidate 列表,卡片以「上传中」态出现在
  网格(服务端记录为准,刷新不丢);失败可重试、可移除、可清空已完成;
  duplicated 去重提示不变
- 上传 UI:删除阻塞式 UploadProgressModal,新增 UploadQueuePanel
  (每文件独立进度条/状态/重试/移除);AssetUploadZone 支持多文件入队,
  文案显示进行中/排队数量;AssetCard 上传中遮罩显示真实百分比+进度条,
  转码中遮罩与上传中区分
- useAssetsData:列表存在 uploading/ingesting/processing/pending 素材时
  每 3s 轮询(refetchInterval 函数动态求值),全部就绪自动停止;
  status 全量参数保持不变
- 不动:去重逻辑、单文件/配音上传流程、上传弹窗交互、素材筛选/播放

🚀 预览环境已部署

项目 详情
PR号 #1557
预览链接 https://pr-1557.preview.xiaoxiajianji.com
API环境 staging

💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。

🔄 每次提交新代码后预览环境会自动更新。

🗑️ PR 关闭或合并后,预览环境会自动清理。

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1557 | | 预览链接 | [https://pr-1557.preview.xiaoxiajianji.com](https://pr-1557.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
Collaborator

【阻塞级判定】

  • 是否存在阻塞级问题:否
  • 阻塞级问题数量:0 个

📊 审查概览

  • 整体评价:通过
  • 建议级问题数量:0 个

🔴 阻塞级问题(必须修复)

💡 改进建议(不阻塞合并)

良好实践

  1. [apps/web/src/api/assets/upload.ts] 模块化设计

    • 将上传逻辑拆分为 putToOSSprepareDirectUploadHandleuploadAssetDirect,实现了职责分离,既保留了向后兼容的简单调用方式,又提供了支持队列和重试的细粒度控制接口(Handle 模式)。
  2. [apps/web/src/api/assets/upload.ts] 错误处理完善

    • XMLHttpRequestonload 事件中,不仅检查了状态码,还尝试解析响应体中的错误信息(res.message),有助于排查上传失败原因。
  3. [apps/web/src/pages/assets/AssetLibrary.tsx] 性能优化

    • 使用 useMemo 缓存 uploadProgressMap,避免在每次渲染时重新创建 Map 对象,减少子组件不必要的重渲染。
  4. [apps/web/src/pages/assets/components/AssetCard.tsx] 状态互斥逻辑

    • 明确区分了“上传中”(前端状态)和“转码处理中”(后端状态)的遮罩显示逻辑(!isUploading),避免状态冲突导致 UI 混乱。

格式检查通过 | 逻辑审查通过 | 性能良好


🤖 由 AI 代码审查机器人自动生成 | 2026-08-30 09:43:58 | 模型:

### 【阻塞级判定】 - 是否存在阻塞级问题:否 - 阻塞级问题数量:0 个 ### 📊 审查概览 - 整体评价:通过 - 建议级问题数量:0 个 ### 🔴 阻塞级问题(必须修复) 无 ### 💡 改进建议(不阻塞合并) 无 ### ✅ 良好实践 1. **[apps/web/src/api/assets/upload.ts] 模块化设计** - 将上传逻辑拆分为 `putToOSS`、`prepareDirectUploadHandle` 和 `uploadAssetDirect`,实现了职责分离,既保留了向后兼容的简单调用方式,又提供了支持队列和重试的细粒度控制接口(Handle 模式)。 2. **[apps/web/src/api/assets/upload.ts] 错误处理完善** - 在 `XMLHttpRequest` 的 `onload` 事件中,不仅检查了状态码,还尝试解析响应体中的错误信息(`res.message`),有助于排查上传失败原因。 3. **[apps/web/src/pages/assets/AssetLibrary.tsx] 性能优化** - 使用 `useMemo` 缓存 `uploadProgressMap`,避免在每次渲染时重新创建 Map 对象,减少子组件不必要的重渲染。 4. **[apps/web/src/pages/assets/components/AssetCard.tsx] 状态互斥逻辑** - 明确区分了“上传中”(前端状态)和“转码处理中”(后端状态)的遮罩显示逻辑(`!isUploading`),避免状态冲突导致 UI 混乱。 --- ✅ 格式检查通过 | ✅ 逻辑审查通过 | ✅ 性能良好 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-08-30 09:43:58 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
auto-approve-bot approved these changes 2026-08-30 17:55:31 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot approved these changes 2026-08-30 17:55:31 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot merged commit 5c45629495 into develop 2026-08-30 17:56:04 +08:00
auto-approve-bot deleted branch feat/upload-instant-assets 2026-08-30 17:56:05 +08:00

🗑️ 预览环境已清理

PR #1557 已关闭或合并,对应的预览环境已被清理。

如有需要,可以重新打开 PR 来重新生成预览环境。

🗑️ **预览环境已清理** PR #1557 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Sign in to join this conversation.