安全移除勾选的本地任务记录 #108

Closed
opened 2026-08-10 17:01:23 +08:00 by ila · 4 comments
Owner

基本信息

  • 类型:需求
  • 父级大工单:#1
  • 所属 MVP / 版本:#2
  • 阶段:PDD 任务列表交互完善

要解决什么

PDD 任务表已经支持按稳定任务编号批量勾选,但没有从普通列表移除不再需要查看的本地记录的入口。直接物理删除 pdd_tasks 会通过外键级联删除执行记录和 Outbox,丢失审计、防重复领取和崩溃恢复依据,也会违反“已完成任务永久保留”的基线。

需要在“重新上报”右边增加“删除”按钮,使符合安全条件的勾选记录不再显示,同时仍在 SQLite 中保留完整历史。

做什么 / 不做什么

  • 做:
    • 在“重新上报”右边增加“删除”按钮,按表格勾选集批量操作。
    • 使用软删除:给本地任务增加可空的移除时间,普通列表和计数默认排除已移除记录。
    • 只允许移除 succeeded、failed、cancelled 终态任务。
    • 存在未发送、发送中或发送失败 Outbox 的任务禁止移除。
    • 任一执行记录的 irreversible_action_at 有值时禁止移除。
    • 执行前使用窗口居中的确认对话框说明数量和影响;安全取消为默认路径并支持 Escape。
    • 成功后清空对应勾选、刷新当前筛选结果,并在页面状态区反馈结果。
  • 不做:
    • 不物理删除 pdd_tasks、task_runs 或 outbox_events。
    • 不删除或修改 Admin 端任务。
    • 不允许移除待执行、执行中、结果待提交、等待重试或需要人工处理的任务。
    • 不增加恢复已移除记录的界面,不改 PDD 自动化、领取或提交协议。

怎么做

  • 在 client/src/db_schema.py 追加新版本迁移,为 pdd_tasks 增加可空的 removed_at 字段;不得修改已发布迁移。
  • 在 client/src/task_repository.py 增加批量安全移除方法:使用一个事务按稳定 remote_task_id 校验全部记录,任一记录不满足条件时整体拒绝,不做部分修改;更新 removed_at 而不执行 DELETE。
  • list_tasks() 和 count_tasks() 默认只返回 removed_at IS NULL;稳定任务编号唯一约束和历史记录继续保留,避免相同 Admin 任务被当成新任务再次插入。
  • 在 client/src/pdd_ui.py 增加 Fluent 删除按钮、信号、勾选启用状态和无障碍名称。
  • 在 client/src/pdd_ui_event.py 增加居中确认、后台执行、错误反馈和刷新;Worker 通过 QObject + moveToThread 执行数据库操作,不从工作线程访问 QWidget。
  • 同步更新 docs/client/03-data-model.md、docs/client/05-ui-specification.md 及相关测试。文档明确“删除”只表示从普通列表移除,本地审计数据仍永久保留。
  • 现有工作区可能包含用户修改,实施时只改本工单范围并保留无关改动。

验收标准

  • 未勾选任务时“删除”按钮禁用;勾选一条或多条后启用。
  • 点击删除显示位于主窗口中央的确认对话框,正文包含勾选数量,取消、Escape 和关闭按钮均不修改数据。
  • 符合条件的终态任务确认后从当前列表消失,重启 Client 后仍不出现在普通列表。
  • 被移除任务、执行记录和 Outbox 在 SQLite 中仍完整存在,remote_task_id 唯一性仍有效。
  • 待执行、执行中、结果待提交、等待重试、需要人工处理、存在未完成 Outbox 或进入不可逆阶段的任务不能被移除,并给出中文原因。
  • 批量操作采用全有或全无:任一任务不满足条件时,所有勾选任务均保持不变。
  • 删除操作不请求 Admin,不操作 Android 设备,不改变任务状态和 Outbox 状态。
  • SQLite 首次建库和从上一已发布版本迁移均通过,相关专项及 Client 全量测试通过。

怎么验证

从 client/ 执行:

C:/Python310/python.exe -m pytest test/test_db.py test/test_task_repository.py test/test_pdd_ui.py test/test_pdd_ui_event.py -q
C:/Python310/python.exe -m pytest test -q
C:/Python310/python.exe -m py_compile src/db_schema.py src/task_repository.py src/pdd_ui.py src/pdd_ui_event.py

离屏界面冒烟:

$env:QT_QPA_PLATFORM="offscreen"
C:/Python310/python.exe -c "from src.ui_main import MainWindow; from PyQt5.QtWidgets import QApplication; app=QApplication([]); w=MainWindow(); print('OK'); app.quit()"
Remove-Item Env:QT_QPA_PLATFORM

手工验证至少覆盖:单条、多条、取消、混合合法/非法记录、未发送 Outbox、不可逆采购记录、重启后列表状态。不得执行真实下单。

风险和回退

  • 风险:查询漏加 removed_at IS NULL 会让已移除记录重新出现;迁移或批量校验错误可能隐藏不应移除的任务。
  • 控制:只做软删除、单事务全量校验、保留外键子记录,并覆盖上一版本迁移与重启测试。
  • 回退:回退界面和 Repository 过滤逻辑即可重新显示记录;不得删除新字段或重建数据库。
## 基本信息 - 类型:需求 - 父级大工单:#1 - 所属 MVP / 版本:#2 - 阶段:PDD 任务列表交互完善 ## 要解决什么 PDD 任务表已经支持按稳定任务编号批量勾选,但没有从普通列表移除不再需要查看的本地记录的入口。直接物理删除 `pdd_tasks` 会通过外键级联删除执行记录和 Outbox,丢失审计、防重复领取和崩溃恢复依据,也会违反“已完成任务永久保留”的基线。 需要在“重新上报”右边增加“删除”按钮,使符合安全条件的勾选记录不再显示,同时仍在 SQLite 中保留完整历史。 ## 做什么 / 不做什么 - 做: - 在“重新上报”右边增加“删除”按钮,按表格勾选集批量操作。 - 使用软删除:给本地任务增加可空的移除时间,普通列表和计数默认排除已移除记录。 - 只允许移除 `succeeded`、`failed`、`cancelled` 终态任务。 - 存在未发送、发送中或发送失败 Outbox 的任务禁止移除。 - 任一执行记录的 `irreversible_action_at` 有值时禁止移除。 - 执行前使用窗口居中的确认对话框说明数量和影响;安全取消为默认路径并支持 Escape。 - 成功后清空对应勾选、刷新当前筛选结果,并在页面状态区反馈结果。 - 不做: - 不物理删除 `pdd_tasks`、`task_runs` 或 `outbox_events`。 - 不删除或修改 Admin 端任务。 - 不允许移除待执行、执行中、结果待提交、等待重试或需要人工处理的任务。 - 不增加恢复已移除记录的界面,不改 PDD 自动化、领取或提交协议。 ## 怎么做 - 在 `client/src/db_schema.py` 追加新版本迁移,为 `pdd_tasks` 增加可空的 `removed_at` 字段;不得修改已发布迁移。 - 在 `client/src/task_repository.py` 增加批量安全移除方法:使用一个事务按稳定 `remote_task_id` 校验全部记录,任一记录不满足条件时整体拒绝,不做部分修改;更新 `removed_at` 而不执行 DELETE。 - `list_tasks()` 和 `count_tasks()` 默认只返回 `removed_at IS NULL`;稳定任务编号唯一约束和历史记录继续保留,避免相同 Admin 任务被当成新任务再次插入。 - 在 `client/src/pdd_ui.py` 增加 Fluent 删除按钮、信号、勾选启用状态和无障碍名称。 - 在 `client/src/pdd_ui_event.py` 增加居中确认、后台执行、错误反馈和刷新;Worker 通过 `QObject + moveToThread` 执行数据库操作,不从工作线程访问 QWidget。 - 同步更新 `docs/client/03-data-model.md`、`docs/client/05-ui-specification.md` 及相关测试。文档明确“删除”只表示从普通列表移除,本地审计数据仍永久保留。 - 现有工作区可能包含用户修改,实施时只改本工单范围并保留无关改动。 ## 验收标准 - [x] 未勾选任务时“删除”按钮禁用;勾选一条或多条后启用。 - [x] 点击删除显示位于主窗口中央的确认对话框,正文包含勾选数量,取消、Escape 和关闭按钮均不修改数据。 - [x] 符合条件的终态任务确认后从当前列表消失,重启 Client 后仍不出现在普通列表。 - [x] 被移除任务、执行记录和 Outbox 在 SQLite 中仍完整存在,`remote_task_id` 唯一性仍有效。 - [x] 待执行、执行中、结果待提交、等待重试、需要人工处理、存在未完成 Outbox 或进入不可逆阶段的任务不能被移除,并给出中文原因。 - [x] 批量操作采用全有或全无:任一任务不满足条件时,所有勾选任务均保持不变。 - [x] 删除操作不请求 Admin,不操作 Android 设备,不改变任务状态和 Outbox 状态。 - [x] SQLite 首次建库和从上一已发布版本迁移均通过,相关专项及 Client 全量测试通过。 ## 怎么验证 从 `client/` 执行: ```powershell C:/Python310/python.exe -m pytest test/test_db.py test/test_task_repository.py test/test_pdd_ui.py test/test_pdd_ui_event.py -q C:/Python310/python.exe -m pytest test -q C:/Python310/python.exe -m py_compile src/db_schema.py src/task_repository.py src/pdd_ui.py src/pdd_ui_event.py ``` 离屏界面冒烟: ```powershell $env:QT_QPA_PLATFORM="offscreen" C:/Python310/python.exe -c "from src.ui_main import MainWindow; from PyQt5.QtWidgets import QApplication; app=QApplication([]); w=MainWindow(); print('OK'); app.quit()" Remove-Item Env:QT_QPA_PLATFORM ``` 手工验证至少覆盖:单条、多条、取消、混合合法/非法记录、未发送 Outbox、不可逆采购记录、重启后列表状态。不得执行真实下单。 ## 风险和回退 - 风险:查询漏加 `removed_at IS NULL` 会让已移除记录重新出现;迁移或批量校验错误可能隐藏不应移除的任务。 - 控制:只做软删除、单事务全量校验、保留外键子记录,并覆盖上一版本迁移与重启测试。 - 回退:回退界面和 Repository 过滤逻辑即可重新显示记录;不得删除新字段或重建数据库。
Author
Owner

开始实施。先完成 SQLite v4 软删除迁移与仓储层原子安全校验,再接入任务列表“删除”按钮和后台线程,最后补充测试及 Client 基线文档。该改动沿用现有已确认的任务页布局,因此不另做 HTML 原型;确认框会显示准确数量、默认聚焦取消并支持 Esc。当前工作区已有的无关修改不纳入本工单。

开始实施。先完成 SQLite v4 软删除迁移与仓储层原子安全校验,再接入任务列表“删除”按钮和后台线程,最后补充测试及 Client 基线文档。该改动沿用现有已确认的任务页布局,因此不另做 HTML 原型;确认框会显示准确数量、默认聚焦取消并支持 Esc。当前工作区已有的无关修改不纳入本工单。
Author
Owner

实现和自动化验证已完成:

  • SQLite 升级到 v4,新增 pdd_tasks.removed_at 和可见列表索引;普通列表/计数默认排除已软隐藏记录。
  • Repository 在单个事务内按稳定任务编号校验整批记录:仅允许终态、所有 Outbox 已发送且从未进入不可逆阶段;任一失败则整批不修改。
  • 任务页新增“删除”按钮、准确数量确认框和独立 QObject + moveToThread Worker;成功后清除勾选并刷新,失败保留勾选并显示中文原因。
  • 删除不调用 Admin、不检查或操作 Android,不修改任务状态、执行记录和 Outbox。
  • 已同步 docs/client/03-data-model.md 与 05-ui-specification.md。

验证结果:专项测试 80 项通过;Client 全量测试 304 项通过;4 个修改模块 py_compile 通过;离屏主窗口冒烟输出 OK。测试仅有现有 PyQt/qfluentwidgets 弃用警告和离屏字体提示,未发现功能失败。接下来提交实现并归档任务。

实现和自动化验证已完成: - SQLite 升级到 v4,新增 `pdd_tasks.removed_at` 和可见列表索引;普通列表/计数默认排除已软隐藏记录。 - Repository 在单个事务内按稳定任务编号校验整批记录:仅允许终态、所有 Outbox 已发送且从未进入不可逆阶段;任一失败则整批不修改。 - 任务页新增“删除”按钮、准确数量确认框和独立 `QObject + moveToThread` Worker;成功后清除勾选并刷新,失败保留勾选并显示中文原因。 - 删除不调用 Admin、不检查或操作 Android,不修改任务状态、执行记录和 Outbox。 - 已同步 `docs/client/03-data-model.md` 与 `05-ui-specification.md`。 验证结果:专项测试 80 项通过;Client 全量测试 304 项通过;4 个修改模块 `py_compile` 通过;离屏主窗口冒烟输出 `OK`。测试仅有现有 PyQt/qfluentwidgets 弃用警告和离屏字体提示,未发现功能失败。接下来提交实现并归档任务。
Author
Owner

实施完成,等待用户验收

  • 实现提交:b272107 feat: 安全移除本地任务记录 (#108)
  • 归档提交:4c9bf38 docs: 归档任务 #108
  • 本地归档:docs/task/108-安全移除勾选的本地任务记录.md
  • 验证:专项 80 项、Client 全量 304 项、py_compile、git diff --check 和离屏主窗口冒烟均通过。
  • 未验证部分已如实写入归档:真实历史数据库人工升级重启、Windows 多 DPI/主题视觉检查、实际键鼠取消路径。

工单保持开启并标记为待验收。用户验收通过后再关闭本单,并同步 #2、#1 的任务清单;当前不提前修改父工单完成状态。

## 实施完成,等待用户验收 - 实现提交:`b272107` `feat: 安全移除本地任务记录 (#108)` - 归档提交:`4c9bf38` `docs: 归档任务 #108` - 本地归档:`docs/task/108-安全移除勾选的本地任务记录.md` - 验证:专项 80 项、Client 全量 304 项、`py_compile`、`git diff --check` 和离屏主窗口冒烟均通过。 - 未验证部分已如实写入归档:真实历史数据库人工升级重启、Windows 多 DPI/主题视觉检查、实际键鼠取消路径。 工单保持开启并标记为待验收。用户验收通过后再关闭本单,并同步 #2、#1 的任务清单;当前不提前修改父工单完成状态。
Author
Owner

用户已于 2026-08-11 明确验收通过。

  • 本地归档状态已更新为“已完成,用户验收通过”
  • 验收记录提交:eca9289
  • 本工单按项目流程关闭
用户已于 2026-08-11 明确验收通过。 - 本地归档状态已更新为“已完成,用户验收通过” - 验收记录提交:`eca9289` - 本工单按项目流程关闭
ila closed this issue 2026-08-11 10:58:26 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chengma/cmautobuy#108