3.4 KiB
3.4 KiB
id, title, phase, deps, status, created
| id | title | phase | deps | status | created | |
|---|---|---|---|---|---|---|
| T-692 | 商品套图原图拖放重复项修复 | 7 |
|
TODO | 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 校验,不改变外部文件导入来源和原图上限。 - 不实现跨商品、跨任务或多项拖放;本任务只处理当前列表单张原图的可靠排序。
执行记录
- 待实现。