Files
UHD_Media_Tool/docs/design/file-manager-v2.md
T
rootandClaude Opus 5.5 abc69886ea feat(contracts,server,web): files G6–G8 fields and identify S-7 contract
- G6: FileRoot.pendingCount/pendingPartial for download roots (same rule as the
  unidentified filter, recursive, cached 5 min, invalidated by files.changed)
- G7: FileEntry.parsedHint from parseReleasePath (file + parent dirs); the web
  subline uses it and no longer parses names itself
- G8: FileIdentifyCandidate.posterUrl (TMDB poster_path via adapter and
  catalog.lookup, local entities from metadata.posterPath); thumbnails in the
  identify panel
- S-7 contract: FilesIdentifyResult.remoteTaskId/remotePending,
  MediaServerInventory.partial, EventType identify.completed with
  IdentifyCompletedPayload; identify panel (useIdentifyLive) and organize wizard
  merge remote results by root + path, buffering events that beat the response

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-28 20:09:29 +08:00

25 KiB
Raw Blame History

文件管理 v2(对照 MP 逐功能 + 按我们的逻辑重整前端)

基础:docs/plan/06-file-manager-spec.md(下称"规格 06",后端 17 个 /files 端点已实现);行为账本 docs/porting/moviepilot-filemanager.md(痛点 P1–P12)。 上游:MoviePilot-Frontend 17b9d51 —— views/reorganize/FileBrowserView.vue、components/filebrowser/{FileBrowser,FileToolbar,FileNavigator,FileList}.vue、components/dialog/{ReorganizeDialog,FileRenameDialog,ScrapeDialog,MediaInfoDialog,FileNewFolderDialog,ProgressDialog}.vue、cards/MediaInfoCard.vue、cards/DirectoryCard.vue(覆盖模式)、locales/zh-CN.ts。只参考行为,不抄源码/模板/文案(GPLv3)。 本文只改前端信息架构与交互,加少量后端缺口(§15)。IA-3 已取消"身份与元数据"页,这直接影响整理向导(§6.1)。

0. 结论

  • MP 文件管理共 52 个功能点(§2)。我们已有 37 个(一致 7、更好 10、做法不同 20),缺 12 个(v2 补 8、不做 4),另 3 个不适用(网盘存储、多数据源、类型/类别分目录开关)。
  • 缺口集中在整理对话框和周边:最小体积、覆盖策略、目标目录、TMDB 候选就地建作品、整理后刷新元数据、已有整理记录提示/重新整理、批量刮削、模板推荐名、hover 行内操作、上一级按钮、目录树折叠;预览缺统计和"只看问题"。
  • 布局定稿:桌面左树右表(树可折叠)+ 右侧详情抽屉;移动端单栏 + 面包屑 + 底部操作栏。整理只保留一个向导,下载详情和整理记录都用它(去掉 downloads/organize-dialog.tsx)。
  • 拆分:契约 0.5 d → 后端 2.5 d / 前端 5 d 并行 → 测试截图 1 d,合计约 9 人日(§16)。

1. 现状盘点(代码 + qa-v02 截图)

已实现:routes/console/files.tsx(911 行)、files.trash.tsx、components/files/*(DirTree、PathBreadcrumb、ContextMenu、FileList 分页+长按多选、FileDetail、dialogs、4 步 OrganizeWizard)。后端 modules/file-manager/* 覆盖 roots/list/stat/mkdir/rename/move/copy/organize/delete/trash/identify/scrape/probe/records/download。

截图暴露的问题:

  1. 名称列太窄(60/61):文件名截到 25 字符;"季集"列对未登记文件恒空,"状态"列留白过宽。
  2. 右键菜单 13 项(61):"刮削/打开作品/在整理记录中查看"对未登记文件只是灰显 + 副标题,菜单高过半屏。
  3. 向导第 1 步是卡片(66-1):每项约 130 px,6 个文件要滚两屏;"应用到同目录 3 项"每张卡都重复一次。
  4. 向导第 2 步只有"动作 + 目标库根"(66-2),MP 对话框里的最小体积、覆盖、目标目录、命名说明都没有。
  5. 预览(66-3)只有前后路径,没有总数/问题数,也不能只看问题。
  6. 远端候选(只在 TMDB 上的作品)提示"先在身份与元数据建立作品",但这个页已取消,这条路断了。
  7. 下载详情另有一个"手动整理"对话框(45):字段、预览样式和文件管理的向导都不一样。
  8. 移动端(ia1/files.mobile):页头说明文字 + 回收站按钮 + 三行工具栏,首屏只剩一半给列表。
  9. 前端没接 /files/records;推荐名是前端拼的 标题 (年份),没走命名模板。

2. MP 功能 → 我们现状 → v2 决定

状态:✓ 有 / ✓+ 有且更好 / ≠ 有但不同 / ✗ 无。决定:照抄 / 改(按我们逻辑)/ 不做。

# MP 功能点 我们 v2 决定
1 存储切换菜单(local/115/阿里/Alist/SMB/rclone) ≠ 左栏按"媒体库/下载目录"列登记目录 改:登记目录 = 库根 + 下载器路径映射,不接网盘(REQ §7.1.1)
2 初始位置 = 下载目录公共前缀,记住上次存储 ≠ 默认第一个在线库根 改:上次位置(localStorage)> 第一个下载目录 > 第一个库根。整理从下载目录开始
3 面包屑(桌面全段,移动端只显示存储名) ✓ 可拖放 照抄 + 移动端折叠成"…/父/当前"
4 "上一级"按钮 ✗ 只有 Backspace 照抄:工具栏加"上一级"
5 目录树懒加载、跟随当前路径展开 ✓ 保留
6 目录树显示/隐藏开关 ✗ 照抄:左栏可折叠,状态存 localStorage
7 可拖宽分隔条(存 localStorage) ✓ 保留
8 排序:名称/时间切换 ✓+ 名称/时间/大小/状态 + 升降 保留
9 过滤框(子串 / *? glob) ✓+ 服务端过滤 保留
10 过滤大小写开关 ✗ 不做:媒体文件名按不区分大小写匹配就够
11 刷新 ✓ 保留 + SSE 自动刷新
12 新建文件夹(工具栏 + PWA 悬浮按钮) ✓ 只读目录禁用 保留;移动端放进"更多"
13 虚拟滚动全量列表 ✓+ 游标分页 + 截断提示 保留
14 图标按扩展名映射 ≠ 按 fileKind 保留 fileKind(视频/字幕/NFO/图片/音频/其他)
15 行 = 名称 + 大小副行 ≠ 多列 改:名称副行放作品·季集,删"季集"列(§4.2)
16 桌面 hover 出 5 个行内按钮 ✗ 只有 ⋯ 改:hover 出 2 个主操作 + ⋯(§5.1)
17 移动端 ⋮ 菜单 ✓ 保留
18 选择模式开关(默认无复选框) ≠ 常驻复选框 保留常驻(桌面);移动端长按进入
19 批量:刮削 / 整理 / 删除 ≠ 整理/移动/复制/探测/删除 改:加批量刮削(按作品去重)
20 点文件进"文件视图"(缩略图/大小/时间/识别/下载) ✓+ 详情抽屉(资产/下载任务/绑定/媒体信息) 保留抽屉,加"整理记录"节
21 图片大图预览 ✓ 保留
22 下载任意文件 ≠ 仅非媒体 ≤ 20 MB 保留限制:视频不经浏览器
23 空态:过滤无结果 / 空目录 ✓+ 另有离线 / 截断 / 无权限 保留
24 进度弹窗(识别/删除/刮削/递归改名,SSE) ≠ toast + 后台任务 保留我们的:长操作不阻塞页面
25 识别 → 单结果只读媒体卡(海报/标题/季集/年份/简介/类型/类别/TMDB ID/来源/版本/分辨率/编码/制作组/原始串/识别词) ≠ 识别直接进向导 改:单项 → 识别卡片(解析 + Top5 候选),多项 → 向导(§7.1)
26 刮削对话框(类型/数据源/媒体 ID + 搜索) ≠ 仅已登记作品,字段级刷新 改:未登记不显示刮削;NFO 投影实现前不显示 NFO 选项(§7.2)
27 批量刮削(逐个串行,失败汇总) ✗ 改:按作品去重后逐个提交
28 重命名 + "自动识别名称" ≠ 前端拼建议名 改:推荐名走命名模板(§8)
29 递归重命名目录内媒体(一个失败即中止) ✗ 改:放进向导"原地按模板改名"模式,先预览(阶段 3)
30 删除确认"是否确认删除{name}?" ✓+ 回收站 + 引用检查 保留
31 新建目录对话框 ✓+ 名称校验 保留
32 整理:目的存储 — 不做:只有本机路径
33 整理方式 copy/move/link/softlink ≠ 复制/移动 保留两项;硬链接灰显"W5"
34 目的路径(自动 / 目录配置下拉 / 手输) ≠ 目标库根(契约有 targetDir,界面没有) 改:自动 / 指定库根 / 指定目录(§6.2)
35 按源路径推荐目标(/manual/target-path) ≠ 按作品绑定或类型 保留我们的:已绑定作品沿用原目录
36 媒体类型(自动/电影/剧集/音乐) ≠ 由作品决定 不单列:作品选择器按类型过滤
37 数据源(TMDB/豆瓣/Bangumi/…) — 不做:本地作品 + TMDB
38 媒体 ID + 名称搜索选择器 ≠ 只能选本地作品 改:搜本地 + TMDB,选 TMDB 就地建作品(G1)
39 剧集组 ✗ 不做:季集以本地内容单元为准
40 季 ✓+ 逐项 保留
41 集(如 1 或 1,2) ✓+ 逐项,支持 3-5 保留
42 集数定位 {ep} 模板 + 智能生成 ✗ 不做:解析器 + 逐项改集号覆盖同一需求
43 集数偏移(-10 / EP*2) ≠ 仅正整数 改:支持正负整数;不做乘法
44 指定 Part ✗ 不做(命名模板 part 变量来自解析)
45 最小文件大小(MB) ✗ 照抄:识别步骤按体积排除(G2)
46 按类型/按类别分目录 — 不做开关:目录结构由命名模板决定
47 整理后刮削 ✗ 改:"入库后刷新元数据",默认开(G5)
48 覆盖模式(从不/总是/按大小/仅保留最新,在目录配置) ≠ 恒不覆盖 → 冲突进待处理 改:向导内三选一(§6.2,G3)
49 检测到已有整理记录 → 重新整理(清旧目标) ✗ 改:识别步标"已登记/有 n 条记录";整理记录页"重新整理"开同一向导
50 预览:总/成功/失败统计、媒体信息、识别词详情、前后对照、分页 20 ≠ 按作品分组前后对照 改:加统计条 + "只看问题" + 目标路径分段着色(§6.3)
51 "加入整理队列"(后台)与"立即整理"两个按钮 ≠ 一律后台任务 保留一个"执行";执行后可关向导,列表自动刷新
52 键盘/拖拽/右键/隐藏文件开关 ✓+ MP 全无 保留

3. 信息架构

  • 位置:侧栏"整理"组(下载面板 / 整理记录 / 文件管理 / 媒体概览),路由 /console/files、/console/files/trash 不变。
  • 可浏览范围只有登记目录:库根(可写或只读登记)+ 下载器路径映射。根 / 永不出现。
  • 每行状态来自本地账本(资产位置、下载任务、临时文件规则),不需要逐个点识别:已登记 / 下载中 n% / 做种中(H&R 未满足)/ 临时文件 / 待识别 / 链接越界。
  • 与其他页的关系:
    从 到文件管理 从文件管理出去
    下载面板任务详情 "整理"打开同一向导;"在文件管理中打开"定位到内容路径 状态徽标"下载中"→ 任务详情
    整理记录 失败/重名拦截行"重新整理"打开向导(源路径按登记目录 hostPath 换算成 FileRef) 详情抽屉"整理记录"节 → 记录详情
    媒体概览作品详情 资产位置"在文件管理中打开" 已登记行 → 作品详情
    待处理 冲突事项"查看文件" 整理冲突进待处理

4. 页面布局定稿

4.1 桌面(≥ md):左树右表 + 详情抽屉

理由:① 库目录层级深(作品/季/文件),树 + 面包屑两种跳法都要;② 拖放移动需要常驻目标(树节点);③ MP 用户已习惯这个布局。单栏在窄屏用。

┌ PageHeader:文件管理            [回收站 n] ┐   ← 说明文字删掉,回收站带条数
├ 左栏 260px(可折叠/拖宽) ┬ 工具栏行 1:[⇤树] [↑上一级] 面包屑……  [刷新][新建目录]
│ 下载目录                 │ 工具栏行 2:搜索 | 全部 视频 待识别 已登记 下载中 临时 | 排序 ⇅ 隐藏文件
│  qB  · 待识别 12         ├──────────────────────────────────────────────
│ 媒体库                   │ ☐ 名称(副行)              状态      大小    修改时间  [hover 操作]
│  电影库 剩余 1.1 TB      │ …虚拟列表…
│   └ 目录树               ├ 状态栏:15/15 项 · 已选 1 · 400 MB        剩余 1.1 TB  只读
│ 回收站                   │           [浮动批量栏]
└──────────────────────────┴──────────────────────────────────────────────
  • 左栏顺序改为下载目录在前(整理从下载开始),每个登记目录显示健康点 + 剩余空间;下载目录额外显示"待识别 n"(G6,可选)。
  • 左栏折叠后只剩 44 px 图标条(登记目录图标 + 回收站)。
  • 详情抽屉(DetailSheet,右侧)不改布局,新增"整理记录"节。

4.2 列表列

列 内容
☐ 复选框;Shift 区间选
名称 主行文件名(truncate,hover 显示全名);副行:已登记 → 作品 (年) · S01E02 · 版本目标;待识别 → 解析结果灰字 The Last of Us · S01E01 · 1080p(来自列表时服务端的轻量解析,G7);目录 → 13 视频 · 0 已登记
状态 StatusBadge + 文字,固定 120 px
大小 文件大小;目录空
修改时间 相对时间,≥ lg 显示
操作 hover/聚焦显示(§5.1)

删除独立的"季集"列,把宽度让给名称(名称列最小 40%)。

5. 操作

5.1 行内 hover 操作(桌面)

按行状态只露 2 个 + ⋯:待识别视频/目录 → 整理 识别;已登记 → 重命名 打开作品;其他 → 重命名 移动到。

5.2 右键 / ⋯ 菜单(单项,最终顺序)

  1. 打开 / 详情 Enter
  2. ── 整理…(主操作,未登记视频或目录) · 识别 · 重命名 F2 · 移动到… · 复制到…
  3. ── 刷新元数据(仅已登记) · 探测(仅视频)
  4. ── 复制路径… · 打开作品(仅已登记) · 查看整理记录(仅有记录)
  5. ── 删除 Del

规则:不适用的项隐藏(未登记文件不出现刮削/打开作品/整理记录);被状态阻止的项灰显并在 tooltip 写原因("做种中,H&R 满足前不能改名")。单项菜单最多 11 项、常见 8 项。

多选菜单:整理 n 项… · 识别 · 移动到… · 复制到… · 探测 · 刷新元数据(按作品去重,仅含已登记时)· 删除 n 项。

5.3 浮动批量栏

已选 n · 大小 | 整理 | 移动 | 复制 | 更多(探测 / 刷新元数据 / 复制路径)| 删除 | ✕。任何按钮被阻止时灰显,tooltip 写第一条原因和涉及项数。

5.4 工具栏

⇤ 折叠树 · ↑ 上一级 · 面包屑 · 刷新 · 新建目录;第二行搜索、筛选 chips、排序 + 升降、隐藏文件开关。截断时在列表顶出黄条"目录过大,只读了前 20 000 项。用搜索或进入子目录"。

6. 整理向导重做

唯一入口组件 OrganizeWizard;来源三种:文件管理选中项、下载任务(内容路径)、整理记录(源路径)。Sheet 全高,3 步:① 文件与作品 → ② 选项 → ③ 预览并执行(原第 4 步"执行"并入 ③:执行后在原地显示每组结果)。

6.1 ① 文件与作品(表格,不再用卡片)

  • 顶部批量条:应用作品到选中(作品选择器)· 季 · 集号偏移 ±N · 最小体积 [100] MB(低于的项自动排除并计数,默认取设置"整理默认")· 统计 n 个视频 · m 项待定 · k 项已排除。
  • 表格按源目录分组,组头一行:目录名 + 应用到本组(把组内第一项作品复制到全组)。
  • 行列:☐ | 源文件(主行文件名,副行解析:标题·年·季集·分辨率·来源·组)| 作品(选择器)| 季 | 集 | 版本目标(默认自动)| 标记。
  • 标记:已登记(existing.assetId,再整理会改路径)、有 n 条整理记录(接 /files/records,对应 MP"检测到成功整理记录")、做种中·H&R 未满足(本行只能复制)。
  • 作品选择器:上半本地作品(识别候选 Top5,带等级高/中/低和理由),下半"TMDB 候选"。选 TMDB 候选 → 行标"将新建作品",执行时由后端建作品(G1),不再跳去已取消的身份页。
  • 未决项(无作品 / 集号格式错 / 剧集缺季)整行黄底,必须处理或排除才能下一步。

6.2 ② 选项(MP 手动整理字段的映射)

MP 字段 我们的字段 取值与默认
整理方式 整理方式 复制(默认,保留源文件,不影响做种)/ 移动(跨卷按复制→核验→删源;含 H&R 未满足项时禁用并写原因)/ 硬链接(灰显,W5)
目的存储 + 目的路径 目标 自动(默认:已绑定作品沿用原目录,否则按作品类型选库根)/ 指定库根(列可写库根 + 剩余空间)/ 指定目录(目录树选择器,写入 targetDir,不建路径绑定)
覆盖模式 目标已存在 跳过 / 交给待处理(默认)/ 按版本目标替换(新文件更好才替换,旧文件进回收站,G3)
智能重命名 + 类型/类别分目录 命名 只读说明:按命名模板(来源:作品覆盖 / 库根 / 全局)+"去设置"链接;另一选项"保留原文件名"(G4)。不提供临时模板,避免同一作品两套目录
季 / 集 / 集数偏移 在 ① 逐项设置 —
最小文件大小 在 ① 批量条 —
刮削元数据 入库后刷新元数据 默认开;字段级刷新,锁定字段不变(G5)。NFO/图片投影实现后再加"写 NFO"
(MP 自动带字幕) 附属文件 只读:同名字幕/NFO/图片随主文件一起处理(planImport 已支持),在 ③ 列出
类型 / 数据源 / 剧集组 / 集数定位 / Part / 复用历史识别 — 不做,理由见 §2

6.3 ③ 预览并执行

  • 统计条 n 组 · m 个文件 · 可执行 x · 冲突 y · 失败 z + 开关只看问题;按作品分组的卡片:组头 = 作品 + 状态(计划就绪 / 不能执行 + 原因)+ 文件数与总大小 + 整理方式;目标目录显示一次,段着色:作品根 / 季 / 文件名,已绑定段加标签沿用绑定。
  • 文件行:源(灰,只显示相对登记目录的路径)→ 目标(只显示文件名差异);附属文件缩进列在主文件下。
  • 组数 > 20 时分页(每页 20 组,对应 MP 预览分页)。
  • 底栏:返回修改 · 执行 n 组。执行后原地替换为每组结果(已提交 / 失败 + 原因),按钮变 查看整理记录(跳 /console/organize?ids=)和 完成。plan_stale 的组自动重新预览并提示"源文件在预览后有变化,已重新预览"。

6.4 移动端向导

全屏 Sheet;① 改为每项一张紧凑卡(文件名 + 作品 + 季/集一行),批量条收进"批量设置"折叠;②③ 单列。

7. 识别与刮削

7.1 识别

  • 单项:详情抽屉里的"识别"节(不另开弹窗):解析字段表(标题/年份/季集/分辨率/来源/发布组/类型)+ Top5 候选列表(海报缩略图 G8、标题年份、等级、理由),每个候选一个按钮 按此整理(打开向导并预填)。TMDB 不可用时显示 warnings 原文。
  • 多项:直接进向导 ①。
  • 识别只读,不写库(规格 06 §2.3.4 不变)。

7.2 刮削 → 界面叫"刷新元数据"

  • 只对已登记项出现;多选时按作品去重,提交 n 个作品,toast 汇总"已提交 n 个作品,锁定字段不变"。
  • 对话框:说明一句"按字段刷新,锁定的字段和路径不变" + 锁定字段列表(来自响应)+ 刷新。NFO/图片两项在后端返回 not_implemented 期间不显示(文案规则 8)。
  • 未登记文件:不出现该项;引导走"整理"。

8. 重命名

  • 对话框字段:新名称(默认选中主名不含扩展名)、按模板生成按钮、附属文件对照表(同名字幕/NFO/图片,默认一起改)、已登记/绑定目录的后果说明。
  • 按模板生成:调 G9(命名引擎按当前绑定与模板渲染),返回文件名或目录段;识别不可信时按钮旁提示"识别不可信,没有推荐名"。不再用前端拼接的 suggestName。
  • 目标名已存在:输入框下即时报"同名已存在,不会覆盖"(用当前列表判断,服务端仍 409)。
  • 做种中:菜单灰显,不进对话框。
  • 目录内批量按模板改名:阶段 3 做成向导模式"原地改名"(目标 = 当前目录,只预览改名对),替代 MP 的递归重命名。

9. 预览与下载

  • 图片(jpg/png/webp/gif):抽屉内缩略图,点开新窗口原图。文本(NFO/字幕/txt):抽屉内等宽预览,最多读前 256 KB,超出显示"只显示前 256 KB"。
  • 视频:不做播放器;显示探测摘要(分辨率/HDR/编码/音轨/字幕轨/时长/容器),未登记文件需点"探测"。
  • 下载:仅非媒体 ≤ 20 MB,按钮下载。

10. 回收站

  • 左栏底部入口 + 页头按钮都显示条数(回收站 3);页内列:名称 · 原位置(可点回到目录)· 删除时间 · 到期 · 关联资产(已退役作品链接)· 操作(还原 / 还原到…)。
  • 批量还原;清空回收站 仅管理员会话,需输入"清空"确认。
  • 原位置被占用:行内报错"原位置已被占用",按钮变 还原到…。

11. 键盘与拖拽

沿用现有:↑↓ Enter Backspace Space Shift 区间 Ctrl/⌘+A F2 Del / Esc。新增:Alt+↑ 上一级、Ctrl/⌘+Enter 对选中项打开整理向导、? 显示快捷键浮层。拖放不变:拖到树节点/面包屑段/列表中的目录 = 移动到(Alt 复制),松手先出预览,不直接执行;只接受可写库根。

12. 移动端(< md)

  • 页头只留标题,回收站进"更多"。工具栏一行:[目录](左侧 Sheet:登记目录 + 树)· 面包屑"…/父/当前" · [搜索](点开展开为整行输入)· [更多](排序、升降、隐藏文件、新建目录、回收站)。筛选 chips 第二行横滑。
  • 列表单列卡片:名称 + 状态徽标 + 副行;点击打开/详情,长按进入多选;多选底栏:整理 · 移动 · 删除 · 更多;详情用底部 Sheet。

13. 文案(按 glossary)

现在 改为 理由
根与目录 / 只读根不能新建目录 目录 / 只读目录,不能新建 glossary:可浏览目录叫"登记目录",不叫"根"
整理到… / 整理 n 项… 整理… / 整理 n 项 与批量栏一致
在整理记录中查看 查看整理记录 按钮 ≤ 6 字
刮削 刷新元数据 与作品详情同名;MP 用户看到 tooltip"即 MP 的刮削"
链接逃逸 链接越界 用户能懂
页头说明"已登记的库根与下载目录。删除先进回收站,改名同步更新资产。" 删除 事实已在状态栏和删除对话框里说
空目录描述"隐藏文件未显示。" "隐藏文件未显示"只在目录里确有点文件时出现 不写无依据的话

向导按钮:下一步 生成预览 返回修改 执行 n 组 查看整理记录 完成;对话框确认:移入回收站 永久删除 重命名 刷新 还原 还原到…。

14. 组件复用与新建

复用:PageHeader、DataTable(向导 ① 用 dense 分组模式,缺分组行就给 DataTable 加 groupBy,不另造表格)、FilterBar(工具栏第二行改用它承载搜索 + chips + 排序)、DetailSheet、ConfirmDialog、StatusBadge、EmptyState、KvList、Timeline(抽屉整理记录节)。

保留并收拢到 components/files/:DirTree、PathBreadcrumb、ContextMenu、FileList、FileDetail。

新建:

组件 用途
EntityPicker 本地作品 + TMDB 候选两段搜索选择;向导、识别卡片、下载任务共用
IdentifyPanel 抽屉"识别"节:解析表 + 候选 + 按此整理
PathSegments 目标路径分段着色 + 沿用绑定 标签;向导预览与重命名共用
DirPicker 基于 DirTree 的目录选择器(只列可写库根);移动/复制/向导"指定目录"共用
WizardBulkBar 向导 ① 批量条(作品/季/偏移/最小体积)

删除:components/downloads/organize-dialog.tsx(下载详情与整理记录页改开 OrganizeWizard,sources 传下载任务内容路径或记录源路径)。model.ts 的 suggestName 删除。

15. 后端缺口

# 缺口 说明 必需
G1 整理项接受外部候选 FilesOrganizeItem 加 external?: {provider:"tmdb", externalId, kind}(与 mediaEntityId 二选一);dryRun 标"将新建作品",执行时在同一事务建 media_entity + 外部身份(复用 identity-pool assign 的建实体逻辑) 是(身份页已取消)
G2 识别按体积过滤 FilesIdentifyRequest 加 minSizeBytes;FileIdentifyItem 加 size、excludedBySize 计数 是
G3 目标已存在策略 FilesOrganizeRequest 加 onConflict: "skip"|"decision"|"replace_if_better";替换走现有 replace_with_verify,旧文件进回收站 是
G4 命名方式 + 来源 请求加 naming: "template"|"keep";响应每组加 templateSource: "entity"|"root"|"global" 与目标路径 segments:[{text, role, bound}] 是
G5 入库后刷新元数据 请求加 refreshMetadata: boolean,执行成功后对每个作品排一次 refresh run 否(前端可在完成后调 /files/scrape)
G6 下载目录待识别计数 FileRoot 加 pendingCount(缓存 5 分钟) 否(C1-C 已做,另有 pendingPartial)
G7 列表轻量解析 待识别视频的 entry 加 parsedHint(标题·季集·分辨率,纯字符串解析,不查库) 否(C1-C 已做)
G8 候选海报 FileIdentifyCandidate 加 posterUrl 否(C1-C 已做)
G9 推荐名 POST /files/suggest-name {root,path} → 命名引擎渲染(依赖 naming-template.md §8 的引擎);不可信时返回 null + 原因 是(依赖命名引擎)

16. 实施拆分与估算

路 范围 估计
0 契约 G1–G4、G9 的 schema + api 注册 0.5 d
B1 后端 G1(建实体 + 事务)、G2、G3、G4;测试:外部候选 dryRun/执行、onConflict 三态、keep 命名、segments 2 d
B2 后端 G9(命名引擎就绪后接入)、G5–G8 可选项 0.5 d
F1 页面 左栏重排与折叠、上一级、列表列重排与副行、hover 操作、菜单隐藏规则、批量栏"更多"、移动端工具栏与页头、文案表 1.5 d
F2 向导 3 步重构、表格化 ①(DataTable groupBy)、EntityPicker、WizardBulkBar、② 选项表、③ 统计/只看问题/PathSegments/原地结果;下载详情与整理记录"重新整理"改用向导;删旧对话框 2.5 d
F3 周边 IdentifyPanel、重命名按模板、刷新元数据(批量去重、隐藏 NFO)、抽屉整理记录节、文本预览上限、回收站条数与批量还原、快捷键浮层 1 d
T 验收 model/向导单测;e2e:下载目录散文件 → 选 TMDB 候选 → 预览 → 执行 → 整理记录出现 → 行变"已登记";桌面/移动截图各 8 张 1 d

顺序:0 → (B1 ∥ F1) → F2(先用 mock 接 G1–G4)→ F3 → B2 → T。合计约 9 人日;F1 不依赖后端,可立刻开工。