Files
cmshoppe/docs/tasks/T-691.md
T

4.9 KiB
Raw Blame History

id, title, phase, deps, status, created
id title phase deps status created
T-691 商品套图原图真实拖放排序修复 7
T-688
DONE 2026-07-23

问题 / 背景

商品套图的商品原图列表已显示“拖动到第一位即可设为主图”,但用户无法把参考图拖到第一张位置。列表开启了 QListWidget.InternalMove,真实原图项却只具备拖拽源标记,没有 Qt.ItemIsDropEnabled;拖到已有第一张图片时不是合法的内部放置目标,Qt 不会触发可用的排序结果和 orderChanged 回写。列表默认 drop action 仍为复制,也没有明确表达内部排序必须移动。

此前 T-688 的测试只直接调用 reorder_originals(),验证了 SQLite 排序持久化,未覆盖实际 Qt 拖放事件,因此没有发现界面手势失效。

拉取蝦皮主图尚未完全结束(含后台下载)或正在生成时,排序仍应锁定,这是既有并发保护,不属于本 bug;界面必须继续给出明确原因。

方案

1. 修复真实内部拖放条件

  • 创建真实商品原图项时,显式保留可选中、可勾选、可拖动并增加 Qt.ItemIsDropEnabled,使任意原图都能作为内部排序的放置目标。
  • 原图列表明确将内部 drop action 设为 Qt.MoveAction;外部本地文件 URL 拖入仍沿用既有导入路径,不能被内部排序逻辑误处理。
  • 内部 drop 只在 Qt 已接受移动后发出 orderChanged,避免无效 drop、锁定状态或外部拖入触发错误的数据库排序。

2. 保留安全边界与用户反馈

  • 生成中、拉取 URL 或拉取图片下载尚未完成时继续禁用原图内部排序;完成后自动恢复可拖放状态。
  • 排序成功继续复用 reorder_originals() 的单事务服务写入和“已更新商品原图顺序,第一张图片为主图”提示;第一项的主图文字、粗体和语义色按刷新后的顺序更新。
  • 不改历史 job 的 source_asset_id/reference_asset_ids 快照;排序只影响之后新建的生成轮次。

3. 自动回归

  • 增加 Qt 级回归,构造原图列表并模拟已接受的内部移动结果,验证第二张变为第一张时 orderChanged 只发出一次、顺序正确且服务层写回 SQLite。
  • 覆盖原图 item flags 含拖动/放置、默认 action 为移动、外部文件 URL 拖入仍仅走 filesDropped,以及拉取锁定时不触发排序。

验收要点

  • 非生成、非拉取状态下,用户可将任意参考图拖到第一张位置,刷新后该图显示“主图”,数据库 source_order 同步更新。
  • 拖到其它位置也可正常重排;无效 drop 不写数据库、不提示排序成功。
  • 外部图片拖入继续进入“添加商品原图”,不被当作内部排序。
  • 生成中或拉取未完成时仍不能排序,并保留中文原因提示;任务结束后可立即排序。
  • 自动验证:
    • py -3.10 -m unittest tests.test_product_suite_gui tests.test_image_studio tests.test_product_suite
    • py -3.10 -m unittest discover -s tests
    • py -3.10 -m ruff check app tests main.py
    • py -3.10 -m compileall app main.py
    • git diff --check

边界(不改什么)

  • 不改 SQLite schema、商品套图任务/历史轮次、提示词、cmhub 生图、下载并发或 Shopee CDP。
  • 不解除生成中或拉取未完成时的排序锁定,不增加新的主图选择按钮。
  • 不影响①至⑤模块及商品原图的删除、预览、勾选和外部文件导入语义。

执行记录

  • 2026-07-23 完成。
  • ProductOriginalList 明确使用 Qt.MoveAction 作为内部拖放默认动作;处理非 URL 的内部 drop 时会先强制移动语义,并且只在来源为当前原图列表、Qt 已接受移动后才发送 orderChanged。外部文件 URL 拖入仍直接走 filesDropped,不会触发排序。
  • _refresh_originals() 创建每张真实商品原图时显式附加 Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled,因此参考图和第一张主图都可作为拖放源和合法放置目标。排序仍复用既有 reorder_originals() 和 SQLite 单事务持久化,刷新后第一张继续按“主图”文字、粗体和语义色展示。
  • 拉取未完成及生成中的排序锁定未改;内部无效 drop 不会发送排序信号。已同步 docs/04-architecture.md 与 docs/routes.md。
  • 新增 GUI 回归:验证从项目刷新出的真实原图同时具备拖动/放置 flag,列表默认动作为移动;外部文件 URL drop 只触发导入、不触发排序。已有排序回归继续验证第二张变为第一张后的 SQLite 顺序、主图展示和成功提示。
  • 验证通过:py -3.10 -m unittest tests.test_product_suite_gui tests.test_image_studio tests.test_product_suite(107项)、py -3.10 -m unittest discover -s tests(674项)、py -3.10 -m ruff check app tests main.py、py -3.10 -m compileall app main.py、git diff --check。离屏 PySide6 有字体目录/插件告警,但无测试失败。