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

68 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: T-582
title: 修复①导入 Excel 失败通知弹窗偶发只显示一半(延迟一拍弹窗)
phase: 7
deps: []
status: DONE
created: 2026-07-10
---
## 问题 / 背景
用户反馈:①采集导入 Excel 后的通知弹窗**偶发只显示一半、显示不全**。**界面本身不卡死**——导入通常很快、无可感知冻结,纯粹是弹窗画不全。「偶尔」也排除纯 HiDPI 缩放(那会稳定半截),更像绘制时序竞态。
已核代码事实:
- 当前 `CollectTab.import_excel()` **成功导入后没有完成弹窗**,只是在 `refresh_tasks()` 后调用 `_set_status("导入完成...")` 更新左下角状态栏。因此本任务不得新增“导入成功”弹窗,否则会变成新需求。
- 当前导入失败路径在 `except` 中写 run log / 诊断日志后直接调用 `_show_error(safe_error)`;`_show_error()` 立即执行 `QMessageBox.warning(self, "导入采集", str(message))`。
- 失败弹窗可能在同一调用栈内、界面刷新/状态更新还未完成时立即进入模态 `exec()`,首帧几何/内容没算稳 → 偶发只画一半。修法不是“把导入改慢/改 worker”,而是“让通知弹窗晚一拍,等当前事件循环先把待处理绘制冲刷完”。
范围收敛:本任务**只修①导入 Excel 失败通知弹窗**,不建统一弹窗 helper、不重构其它 `QMessageBox` 调用点、不改导入线程模型(导入 worker 化不在本任务)。
## 方案(改哪个文件、改成什么)
### 1. 让导入失败通知弹窗晚一拍弹(`app/gui/tabs/collect.py`)
- 把 `_show_error(message)` 改为:先同步更新状态栏 `_set_status(str(message), level="danger" 或现有口径)`;再用 `QTimer.singleShot(0, lambda: QMessageBox.warning(...))` 延迟显示导入失败通知。
- 这样导入失败路径原有 run log、diagnostic log、状态栏错误信息仍在当前调用栈完成;真正的模态弹窗等当前事件循环下一拍再打开,降低首帧绘制不完整概率。
- 只改 `_show_error()` 这一处导入失败通知;不改 `import_excel()` 成功路径,不新增导入成功弹窗。
- 不改 `_show_account_guide()`:它属于采集前账号就绪引导,不是导入 Excel 完成链路;本任务不外扩到采集链路。
- 不改 `QMessageBox.question` / 删除批次确认等需要立即返回用户选择的确认类弹窗。
### 2. 本任务不做 HiDPI 全局设置
- 先不在 `app/gui/__init__.py` 增加 `QGuiApplication.setHighDpiScaleFactorRoundingPolicy(...)`。该设置影响全局窗口缩放,且当前问题是“偶发”,优先按事件循环时序修复。
- 如果后续能稳定复现 HiDPI 缩放导致的弹窗裁切,再另立任务处理全局缩放策略。
## 验收要点
- `excel.import_tasks()` 抛异常时,导入失败通知经 `QTimer.singleShot(0, ...)` 延迟显示;单测 mock `QTimer.singleShot` 断言被调用,不真正弹窗。
- `excel.import_tasks()` 抛异常时,不再在同一调用栈直接调用 `QMessageBox.warning`;可通过 mock `QMessageBox.warning` 断言在执行 `singleShot` 回调前未被直接调用。
- 导入失败既有行为不回归:run log 标记 failed、诊断日志写入、状态栏显示脱敏错误文案、`_show_error` 的窗口标题/正文仍为中文导入失败提示。
- 导入成功路径不新增 `QMessageBox`;仍然刷新列表、更新 summary、写状态栏“导入完成...”。
- 未改动导入链路以外的弹窗调用点(`git diff` 范围仅 `app/gui/tabs/collect.py` + 对应 `tests/test_gui.py`)。
- 验证命令(unittest,不引入 pytest;GUI 测试用 offscreen):
- `py -3.10 -m unittest tests.test_gui`
- `python -m ruff check app tests main.py`
- `py -3.10 -m compileall app main.py`
- `py -3.10 -m unittest discover -s tests`
- `git diff --check`
## 边界(不改什么)
- 不建统一弹窗 helper、不收敛/替换其它模块的 `QMessageBox` 调用。
- 不把①导入改成 worker 线程(如后续要治界面卡死另立任务/backlog)。
- 不新增导入成功弹窗;成功导入仍只用状态栏提示。
- 不改 `_show_account_guide()` 账号未就绪弹窗;它属于采集链路,不属于导入 Excel 链路。
- 不做 HiDPI 全局缩放策略调整。
- 不改弹窗文案/业务语义、不改 `excel.import_tasks` 解析入库逻辑。
- 不改 CDP/DB/AI/cmhub、主窗口尺寸逻辑。
## 执行记录
- 2026-07-10:已实现 `_show_error()` 延迟弹出导入失败通知:状态栏仍同步显示错误,`QMessageBox.warning(self, "导入采集", text)` 改为经 `QTimer.singleShot(0, ...)` 下一拍执行,降低刷新/绘制同栈内立即弹模态框导致首帧显示不完整的概率。
- 2026-07-10:未改导入成功路径;成功导入仍只刷新列表、更新 summary、状态栏显示“导入完成...”,不新增成功弹窗。未改 `_show_account_guide()`、删除批次确认框、HiDPI 全局设置、导入解析入库逻辑。
- 2026-07-10:补 `tests/test_gui.py`:成功导入断言不会调用 `QTimer.singleShot` 和弹窗;导入异常时断言 `QTimer.singleShot(0, callback)` 被调用、回调执行前不直接弹窗、run log/脱敏错误/弹窗标题正文不回归。
- 当前工作区验证通过:
- `py -3.10 -m unittest tests.test_gui.GuiTests.test_collect_tab_import_button_imports_excel_and_refreshes_tasks tests.test_gui.GuiTests.test_collect_tab_import_error_dialog_is_delayed_one_event_loop tests.test_gui.GuiTests.test_collect_tab_import_excel_writes_diagnostic_run_log`
- `python -m ruff check app tests main.py`
- `py -3.10 -m compileall app main.py`
- `git diff --check`(仅输出当前工作区既有 CRLF 提示,无空白错误)
- 当前工作区直接运行 `py -3.10 -m unittest tests.test_gui` 失败 2 项,原因是本任务开始前已有未提交改动把默认封面提示词从 `papa1` 改成「默认」,导致两个旧断言仍期望 `papa1`;该提示词改名不属于 T-582,本次未处理、未提交。提交后需用干净 worktree 验证本次提交本身。
- 提交后在干净 worktree `D:\chengma\cmshopee_verify_t582` 验证本次 T-582 提交:`python -m ruff check app tests main.py` 通过,`py -3.10 -m compileall app main.py` 通过,`git diff --check` 通过,`py -3.10 -m unittest tests.test_gui` 通过 145 项,`py -3.10 -m unittest discover -s tests` 通过 325 项。