# INBOX > 本轮任务:K100 后台剧集多选上传(分片 + 断点续传 + 进度展示)。**[已处理]** > 开工前置:先读 `AGENTS.md`、`CODING_STANDARDS.md`、`GIT_WORKFLOW.md` 本文件,再读 > `ReelShortWeb/src/utils/uploader.ts`、`src/api/admin/media.ts`、`src/views/contentManagement/EpisodeManagementView.vue`。 ### Codex 回执(K100) - ReelShortWeb 分支:`feature/episode-batch-upload` → `--no-ff` 合入 `develop` 并 push - 提交:`feat(admin): 剧集多选分片上传与断点续传` - 门禁:`pnpm lint:eslint` 零错误;`pnpm build:dev` 成功 - 未验证:PM 手工多选/暂停/刷新续传/批量建集(8080+3005) - 风险:续传需重选相同本地文件;暂停不 abort 进行中分片 ## 现状(已勘察,不要重复排查) - 后端分片上传已具备且不改:`POST /admin/media/upload/init` → `POST /admin/media/upload/chunk` → `POST /admin/media/upload/complete`;断点查询 `GET /admin/media/upload/{uploadId}` 返回 `receivedChunks/totalChunks/chunkSize/percent/status/assetId/url`。 - 前端已有 `src/utils/uploader.ts`:`uploadFile()` 分片并发 3、`resumeUpload()` 按服务端已收片数续传、 `probeVideoDuration()` 探测时长。**这两个函数已可用,本次在其上做批量队列 UI**。 - 当前剧集管理 `EpisodeManagementView.vue` 只有一个 `el-upload` 单文件入口(`http-request="uploadVideo"`), **不支持多选、没有进度条、没有断点续传入口**,`onSession` 也没有落盘。 ## 目标 在剧集管理页提供「批量上传」:一次选多个视频 → 队列分片上传 → 每个文件独立进度 → 失败可重试 → 刷新/重进页面能续传 → 上传完成后批量创建分集。 ## A. 上传队列(新建 `src/views/contentManagement/upload/useUploadQueue.ts`) 1. 输入:`File[]` + `dramaId` + 可选 `bizType` 2. 每项状态机:`waiting → uploading → merging → done / failed / paused`;对外暴露 `items`、`overallPercent`、 `start()`、`pause()`、`retry(id)`、`retryAll()`、`remove(id)`、`clear()` 3. 队列并发:同时最多 2 个文件上传(文件内分片并发沿用 `uploadFile` 的 3) 4. 进度:文件内 `onProgress` 回调更新单项百分比;总进度 = 各文件字节加权,不是简单平均 5. 失败隔离:单文件失败不影响其它文件,错误原因记在该项 `error` 6. 暂停语义(本轮简化,不做 abort):暂停后不再派发新任务,已在传的分片让其完成 7. 上传完成后 `completeUploadApi` 拿到 `assetId/url/durationSec` 写回该项 ## B. 断点续传(关键) 1. 上传开始(拿到 `uploadId`)即写入 `localStorage`:键 `reel_upload_sessions`, 值数组项含 `{ uploadId, fileName, fileSize, lastModified, dramaId, bizType, createdAt }` 2. 页面进入时读取该键,过滤 `dramaId` 匹配且 24 小时内的会话,弹出提示「发现 N 个未完成上传,是否续传」 3. 续传前用 `file.name + size + lastModified` 匹配本地重新选择的文件; **文件匹配不上(换机器/改名)则不自动续传,提示后由用户手动重选** 4. 续传走现有 `resumeUpload(file, uploadId)`;`GET /admin/media/upload/{uploadId}` 返回 404 或已 completed 的会话要从 localStorage 清理 5. 上传成功、用户移除、用户放弃续传三种情况都要清理对应记录 ## C. 批量创建分集 1. 上传完成列表提供「批量创建分集」按钮 2. 默认值:按文件名自然排序(去扩展名后再比较,`第2集` 排在 `第10集` 之前); 集号 = 该剧当前最大集号 + 1 起顺延;标题取文件名去扩展名;是否免费沿用现有新建默认值 3. 弹窗内每行可改:集号、标题、是否免费;冲突集号在提交前本地校验并标红 4. 提交:逐条调用现有 `createEpisodeApi`(`src/api/admin/episode.ts`), 逐条显示成功/失败,失败的保留在弹窗内可重试;全部结束后刷新剧集列表 5. **不新增后端接口**,契约不动 ## D. 组件拆分(红线:单文件 ≤ 500 行) - `src/views/contentManagement/upload/BatchUploadDialog.vue`:多选、队列列表、总进度、暂停/重试/移除 - `src/views/contentManagement/upload/UploadTaskRow.vue`:单行(文件名、大小、进度条、状态、操作) - `src/views/contentManagement/upload/CreateEpisodesDialog.vue`:批量建分集表单 - `src/views/contentManagement/upload/useUploadQueue.ts`:队列逻辑(纯逻辑单元,不写 UI) - `EpisodeManagementView.vue` 只加一个「批量上传」入口按钮,并保持原单文件上传入口可用 ## E. 细节要求 - 文件类型白名单:`mp4/mov/mkv/webm`(`accept="video/*"` + `before-upload` 二次校验) - 单文件大小上限从现有常量取值,超限直接标红不入队 - 所有文案走 `src/locales/zh-CN.ts` / `en.ts`,禁止硬编码中文 - 进度与错误展示用项目现有样式变量,不新引入 UI 依赖 - 上传期间:关闭页面前用 `beforeunload` 提示存在未完成上传 ## F. 门禁 - `pnpm lint:eslint` 零错误 - `pnpm build:dev` 构建成功 - 手工验证(PM 会复核):本地起 8080 + 3005,多选 3 个视频 → 三条并行进度 → 中途暂停 → 刷新页面 → 出现续传提示 → 续传完成 → 批量建分集成功 ## Git - ReelShortWeb:从 `develop` 拉 `feature/episode-batch-upload` → 提交 `feat(admin): 剧集多选分片上传与断点续传` → `--no-ff` 合回 `develop` 并 push - 作者 `Zhou Weidong <502333560@qq.com>`;禁止 `git add -A`;源码首行 `// Author: fruit.com.cn` ## 约束 - 先写计划 `docs/plans/2026-10-21-K100-episode-batch-upload.md`,再改代码 - 每跑一个命令,把「命令 + 原始输出 + 解读」追加到 `docs/plans/PROGRESS.md` - 不改 FruitServer、不改 ReelShort 客户端、不改接口契约 - 禁止 `git add -A`;不要操作真机 - 完成后停住等 PM 验收,回执需贴门禁原始输出