镜像自地址
https://github.com/lhly/cloud-drive-renamer.git
已同步 2026-10-20 05:37:47 +08:00
更新 package.json、manifest.json 和版本常量文件中的版本号至 1.0.4。 新增冲突检测与对话框优化的详细设计规格文档和实现计划文档,为后续功能开发做准备。
6.4 KiB
6.4 KiB
批量重命名冲突误报修复与冲突弹窗优化设计
背景
当前批量重命名在执行前会先进行冲突检测,并在检测到冲突时通过浏览器原生 prompt() 让用户选择处理方式。现有实现存在两个问题:
- 误报冲突:未发生改名的文件仍然参与外部重名检测,阿里云盘适配器只按文件名匹配,不排除自身,导致“与自己重名”被误判为冲突。
- 交互能力不足:原生
prompt()无法展示结构化冲突详情,也无法承载滚动列表、说明文本、危险操作强调等 UI。
目标
- 修复“未改名文件被误判冲突”的问题。
- 保持真实冲突检测不变:
- 批量内部生成相同目标名仍应识别。
- 当前目录已存在其他同名文件仍应识别。
- 将原生冲突弹窗升级为扩展内自定义对话框。
- 在对话框中显示可滚动的冲突明细,至少包含:原文件名、目标文件名、冲突类型。
- 删除误导性的“强制覆盖”选项,改为用户可安全理解的“取消本次执行”。
非目标
- 不改动批量执行器的核心重命名流程。
- 不新增“手动编辑每个冲突项”的复杂交互。
- 不重构所有 confirm/alert,仅替换冲突处理相关弹窗。
方案对比
方案 A:仅在适配器层排除自身
- 做法:扩展
checkNameConflict接口,额外传入当前文件 ID,在适配器层排除自己。 - 优点:语义最准确,冲突判断在数据源层完成。
- 缺点:需要修改平台接口和多个适配器,改动面更大;对“未改名文件直接应跳过检测”这一业务规则表达不够直接。
方案 B:执行前仅对“实际会改名”的任务做冲突检测(推荐)
- 做法:在
handleExecute()中先根据newName !== file.name过滤出真正需要改名的文件,再对这些任务执行冲突检测和后续执行计划构建。 - 优点:
- 直接匹配产品语义:“没改名就不应参与改名冲突检测”。
- 改动范围小,平台接口无需变动。
- 与现有
skipUnchanged行为一致,避免检测和执行语义不一致。
- 缺点:如果未来需要对“未改名文件”做别的预检查,需要单独扩展逻辑。
方案 C:保留现有检测范围,但在冲突结果合并后剔除 unchanged 自冲突
- 做法:检测后再根据
newName === oldName把相关冲突结果清理掉。 - 优点:改动集中。
- 缺点:是事后修补,逻辑绕,不如方案 B 清晰。
采用方案:B。
详细设计
1. 冲突检测修复
在 FileSelectorPanel.handleExecute() 中新增“候选任务”概念:
- 从
selectedFiles和newNames派生出renameCandidates。 - 只有
newName !== file.name的候选项才参与:- 冲突检测
- 冲突解决
- 执行计划
- 当候选项为空时,继续沿用现有
no_rename_needed提示。
这样可以保证:
- 预览、冲突检测、执行三者都只关注实际要改名的文件。
- 不再出现“预览里没显示,但执行阶段又报冲突”的割裂体验。
2. 冲突详情数据模型
在 conflict-detector.ts 中补充冲突详情结构,面向 UI 传递:
- 文件 ID
- 原文件名
- 目标文件名
- 冲突类型:
DUPLICATE_IN_BATCHNAME_EXISTS
- 相关冲突文件名列表(若适用)
新增一个将 Map<string, ConflictResult> + 文件列表 + 新名称列表整理为 UI 明细数组的辅助函数,供对话框渲染使用。
3. 冲突对话框 UI
新增一个 Lit 组件,例如 conflict-resolution-dialog,风格对齐现有 rename-dialog / progress-dialog:
布局
- 标题:检测到 N 个文件名冲突
- 说明:提示用户先查看冲突详情,再选择处理方式
- 可滚动详情区域:
- 每项显示
- 原文件名
- 箭头/目标文件名
- 冲突类型标签
- 若为批量内部冲突,可显示“同批次重复目标名”及相关文件名
- 每项显示
- 底部操作区:
- 自动添加编号(主按钮,推荐)
- 跳过冲突文件
- 取消本次执行
交互
- 点击遮罩或取消本次执行:返回
null - 点击“自动添加编号”或“跳过冲突文件”:返回对应
ConflictResolution - 移除
ConflictResolution.OVERWRITE及相关误导文案,避免让用户误以为扩展具备删除/覆盖网盘同名文件的能力
4. 集成方式
在 file-selector-panel.ts 中以状态驱动方式集成:
- 增加对话框开关与冲突详情状态。
handleExecute()检测到冲突时:- 先保存待执行上下文
- 打开冲突对话框
- 等用户选择后再继续执行
- 为减少侵入,可将“等待用户选择”封装成
Promise<ConflictResolution | null>,由对话框按钮事件 resolve。
5. 国际化
为三套语言文案新增/补充分组 key:
- 对话框标题、说明、副标题
- 按钮文案
- 冲突类型标签
- 明细字段标签:原文件名、目标文件名、冲突文件
- 取消执行提示文案
测试策略
单元测试
FileSelectorPanel.handleExecute()相关行为:- 当部分文件未变化时,仅变化文件参与冲突检测。
- 未变化文件不会触发误报冲突。
conflict-detector:- 批量内部重复名仍可正确生成冲突详情。
- 冲突详情整理函数输出正确。
- 冲突对话框组件:
- 渲染冲突条目
- 点击不同按钮返回对应 resolution
回归验证
- 真实替换场景:仅 7 个变化文件,无重复时不弹冲突框。
- 存在真实重名时:弹窗能列出冲突文件,并能按选择继续处理。
风险与缓解
- 风险: 改成异步自定义对话框后,执行流程可能被打断。
- 缓解: 用
Promise封装选择流程,保持handleExecute()线性。
- 缓解: 用
- 风险: 新增文案导致多语言缺失。
- 缓解: 同步更新
zh_CN/zh_TW/en。
- 缓解: 同步更新
- 风险: 冲突数量统计与 UI 列表不一致。
- 缓解: 统一由冲突详情数组派生数量,而不是重复计算。
成功标准
- 用户给出的样例不再出现“检测到 2 个冲突”的误报。
- 真正冲突时会显示自定义对话框,而不是浏览器原生 prompt。
- 对话框中能滚动查看冲突文件列表。
- 自动加序号 / 跳过 两种处理策略继续可用,且可以安全取消本次执行。