4.8 KiB
4.8 KiB
id, title, phase, deps, status, created
| id | title | phase | deps | status | created | |
|---|---|---|---|---|---|---|
| T-692 | 商品套图原图拖放重复项修复 | 7 |
|
DONE | 2026-07-23 |
问题 / 背景
T-691 为使参考图可以拖到第一位,给每个 QListWidgetItem 添加了 Qt.ItemIsDropEnabled 并继续调用 QListWidget.InternalMove 的默认 dropEvent。在图标列表中,拖到已有图片上会变成“投放到该项”的模型插入/复制语义,而非单纯的行移动;同一商品原图 ID 因此短暂出现两次。
ProductOriginalList 随后把重复的 asset_ids() 传给 image_studio.reorder_original_assets()。服务层的唯一性校验正确阻止了 SQLite 写入,显示“商品原图排序不能包含重复图片”,但用户无法完成主图调整。
方案
1. 受控单项内部移动
- 真实原图项恢复为可选择、可勾选、可拖动,不再用
ItemIsDropEnabled把“拖到图片上”交给 Qt 默认复制式模型处理。 ProductOriginalList自行管理内部拖拽源:开始拖拽时记录当前原图项及其 asset ID;拖放时只接受来源为当前列表、且排序未锁定的单项移动。- 根据 drop 坐标和目标缩略图中心计算插入行;使用
takeItem()+insertItem()移动同一个QListWidgetItem,不调用 Qt 默认super().dropEvent()的内部复制路径。 - 只在移动后最终
asset_ids与移动前不同、ID 数量与集合数量一致时发出一次orderChanged;异常、无效位置、跨列表、锁定状态或重复 ID 一律不写库。
2. 既有行为保持
- 外部文件 URL 拖入继续发送
filesDropped并导入图片;剪贴板、勾选、预览、删除、悬停删除和主图样式不变。 - 生成中、拉取 URL 或图片下载未完成时继续拒绝内部排序;完成后可重新拖放。
- 成功排序仍复用
reorder_originals()与 SQLite 单事务服务,刷新后首项显示“主图”;服务层的重复 ID 校验保留为最后防线。
3. 自动回归
- 为列表内部移动增加无需系统原生拖放平台的 Qt 单元回归:第二项移动到首项前后,列表顺序唯一且只发一次
orderChanged。 - 覆盖向下移动、原地 drop、无拖拽源、锁定状态、外部 URL 拖入和重复 ID 防御;项目级回归验证最终排序同步到 SQLite,首项更新为主图。
验收要点
- 将任意参考图拖到第一张位置后,列表仅保留每张图片一次,参考图成为“主图”,不再出现重复图片错误。
- 向其它位置拖动同样只移动原项,不复制项;原地释放不写库、不提示成功。
orderChanged只携带唯一 asset ID 顺序;服务层仍拒绝任何异常重复输入。- 外部图片拖入、生成锁定和拉取锁定语义不变。
- 自动验证:
py -3.10 -m unittest tests.test_product_suite_gui tests.test_image_studio tests.test_product_suitepy -3.10 -m unittest discover -s testspy -3.10 -m ruff check app tests main.pypy -3.10 -m compileall app main.pygit diff --check
边界(不改什么)
- 不改 SQLite schema、图片文件、已生成 job 的主图/参考图快照、提示词、cmhub、Shopee CDP 或①至⑤模块。
- 不放宽
reorder_original_assets()的重复 ID 校验,不改变外部文件导入来源和原图上限。 - 不实现跨商品、跨任务或多项拖放;本任务只处理当前列表单张原图的可靠排序。
执行记录
- 2026-07-23 完成。
- 移除 T-691 对真实原图项追加的
ItemIsDropEnabled,避免 Qt 将拖到缩略图上的动作走默认复制/插入路径。ProductOriginalList现在在startDrag()记录单一拖拽项,在内部dragEnter/dragMove/drop中只接受本列表来源的移动。 - 内部 drop 不再调用
super().dropEvent():按目标缩略图和坐标计算插入行,以takeItem()+insertItem()移动原QListWidgetItem;移动前后均检查 asset ID 唯一性,仅顺序实际变化时发送一次orderChanged。原地释放、无拖拽源、跨列表和已存在异常重复 ID 都不回写排序。 - 外部文件 URL 拖入继续只发送
filesDropped;拉取或生成中的锁定逻辑、SQLite 服务层重复 ID 最后防线、主图刷新样式和历史 job 快照均未改动。已同步docs/04-architecture.md与docs/routes.md。 - 新增 GUI 回归覆盖第二张移到第一张、向后移动、原地释放、无拖拽源和已有重复 ID 防御;现有项目级测试继续验证 SQLite 排序、主图标签和外部文件导入隔离。
- 验证通过:
py -3.10 -m unittest tests.test_product_suite_gui tests.test_image_studio tests.test_product_suite(108项)、py -3.10 -m unittest discover -s tests(675项)、py -3.10 -m ruff check app tests main.py、py -3.10 -m compileall app main.py、git diff --check。离屏 PySide6 有字体目录/插件告警,但无测试失败。