From eb29bcd8b7825659199740fb3c5ed84d290555c0 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Tue, 4 Aug 2026 21:36:52 +0800 Subject: [PATCH] docs(tasks): define T-304 polling UI boundary --- docs/tasks/T-304.md | 86 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 docs/tasks/T-304.md diff --git a/docs/tasks/T-304.md b/docs/tasks/T-304.md new file mode 100644 index 0000000..4082214 --- /dev/null +++ b/docs/tasks/T-304.md @@ -0,0 +1,86 @@ +--- +id: T-304 +title: 定时轮询、会话边界与采购工具主界面 +phase: 3 +deps: [T-303, T-006] +status: TODO +created: 2026-08-04 +vikunja_task_id: 37 +context_ref: 526af1e +work_branch: task/t-304-polling-session-ui +needs_device: false +needs_human_review: true +write_paths: + - docs/tasks/T-304.md + - client/src/cmbuyer_client/app.py + - client/src/cmbuyer_client/polling/** + - client/src/cmbuyer_client/ui/** + - client/tests/test_app.py + - client/tests/polling/** + - client/tests/ui/** + - docs/api.md + - docs/06-tasks.md +--- + + +## 问题 / 背景 + +T-006 已确认采购工具双 Tab 原型,T-303 将提供唯一的 HTTP、本地恢复、DPAPI 与单实例底座。T-304 把原型转换为可测试的原生 PySide6 主界面和定时轮询协调器,但在真实单趟执行器接入前不得领取真实任务,避免形成无人消费的 active claim。 + +## 关联需求与交互 + +- 功能:F-005、F-008、F-012、F-013。 +- 用户故事:US-003、US-004、US-007。 +- 依赖:T-303、T-006;T-302/T-301/T-203/T-204 由 T-303 传递满足。 +- 实现已确认的“采购工具”固定双 Tab:默认“采购执行”,另一个为“配置”。 +- 不接入真机选择、事件、围栏、提交或付款;T-305 才注入受控单趟执行器。 + +## 方案 + +1. 使用 `QMainWindow + QTabWidget` 建立不可关闭的固定 Tab,使用稳定 page id 而非显示索引;Tab 切换保留内部状态、选择、滚动和焦点。 +2. 采购执行页顶部显示连接、轮询、当前任务与连续失败状态,开始/停止复用同一 `QAction`。独立运行且未注入 execution consumer 时开始按钮禁用,并显示“单趟执行能力尚未接入,不能领取真实任务”。 +3. 主体使用 `QSplitter`。左侧 `QStackedWidget` 在“当前任务”和“采购记录详情”间切换;当前任务左侧文字、右侧图片约 2:1,下方为滚动日志。右侧使用 `QTableView + QAbstractTableModel` 显示按时间倒序的标题和状态,不放假记录。 +4. 记录表单击只选择;双击非控件区域、Enter、显式“查看所选记录”和上下文命令复用同一 QAction。详情态选择另一行立即更新;Esc 仅从详情返回当前任务,不停止轮询、不关闭程序、不改变服务端状态,并恢复记录选择、滚动和焦点。 +5. 配置页使用 `QScrollArea + QFormLayout` 显式保存。service URL 为只读精确 `http://127.0.0.1:8080`;设备 token 使用密码框,保存后立即清空、不回填。没有 heartbeat 时不得调用 claim-next 测试连接,只显示凭据将在首次真实领取时验证。 +6. 配置承载 device id、ADB 路径、serial/transport、轮询间隔默认 15 秒且范围 5–300、连续失败阈值默认 3 且范围 1–10、HTTP 超时默认 10 秒且范围 1–120、真机步骤超时默认 45 秒且范围 5–300。pending/active claim 时冻结 service/device 身份。 +7. 轮询协调器状态固定为 STOPPED、STARTING、BLOCKED、RECOVERING、WAITING、CLAIMING、ACTIVE、RECOVERY_REQUIRED。启动必须先取得 T-303 单实例 guard 并加载 recovery snapshot;重启不自动开始,active claim 只显示待安全恢复。 +8. 停止只设置 `accept_new_claims=false`。WAITING 取消下一计时器;CLAIMING 等待有界结果并先落库;返回 claim 后进入 RECOVERY_REQUIRED。不得中断已发请求、清 pending/active、release/abandon、生成新 key/session 或调用真机返回动作。 +9. `QTimer` 只调度下一轮;阻塞 I/O 放长期 worker QObject/QThread,worker 不接触 Widget。claim 业务结果必须先交 T-303 持久化,不能因 UI generation 过期而丢弃;迟到的纯视图结果按稳定 request id 丢弃。 +10. 连续失败只统计 T-303 标记为可用同幂等键安全重放的网络、超时、5xx 或截断;同 pending request 按轮询间隔重放,达到阈值立即停止。401、协议错误、409、DPAPI/SQLite 错误立即转持久 Banner,不进入普通重试。 + +## 验收要点 + +- 纯状态机覆盖开始、EMPTY、等待、停止、请求中停止、claim 落库、无重叠请求、同键恢复、失败阈值、401/403/409/本地错误和 active 阻止新领取。 +- QtTest 覆盖默认 Tab、固定 Tab 状态、按钮禁用原因、配置验证/Ctrl+S/token 不回显、记录倒序、单击/双击/Enter/按钮、详情切换、Esc 层级与焦点恢复。 +- compact/medium/wide 不重建模型或丢选择;长文案、100%–200% DPI、浅色/深色/高对比与纯键盘行为可人工复核。 +- 应用独立启动、切换 Tab、Esc、查看记录与关闭窗口均产生零 claim、零 release、零 ADB;代码不导入 PDD 点击、数量、确认页、围栏、提交或付款能力。 +- client 全量 unittest、compileall、wheel metadata、根目录完整 init、Vikunja 导出、上下文校验与 diff-check 通过。 + +## 执行记录 + +### 2026-08-04T13:35:53Z · ila + +2026-08-04 已按确认原型与 Windows UI/UX 规范落成任务:采用固定双 Tab、稳定 ID 的主从工作区、非模态持久错误、Esc 只退出记录详情、显式配置保存,以及停止仅阻止下一次领取的会话边界。独立运行时未注入单趟执行器,开始轮询必须禁用,确保零真实 claim、零 ADB;依赖 T-303、T-006 完成后再开工。 + + +## 边界 + +- 本任务只能消费 T-303 暴露的 profile/session/recovery API,不得另建 SQLite、DPAPI、mutex、 + HTTP task source 或第二套 active-claim 状态源。配置或恢复状态损坏必须失败闭合,不能用界面默认值 + 覆盖持久业务事实。 +- 独立应用在未注入单趟 execution consumer 时必须禁用“开始轮询”,且启动、切换 Tab、Esc、查看记录、 + 保存配置和关闭窗口都必须产生零 claim、零 ADB。不能为了演示界面领取真实任务,也不能填充会被当作 + 真实状态的假记录。 +- 停止轮询只阻止下一次新领取。不得取消已发出的 claim、清除 pending/active、release/abandon、 + 生成新 session 或幂等键、自动转领,也不得触发真机 Back、退出页面或其他设备动作;返回的 claim + 必须先由 T-303 原子落库再更新 UI。 +- 重启不自动开始轮询,不自动恢复任何真机点击。pending claim 只能用原 session/request 恢复;active + claim 只显示“待安全恢复”并阻止新领取,租约过期或 409 交 T-207 人工处理。 +- 配置页不得使用 `claim-next` 充当“测试连接”,因为它会产生 EMPTY 幂等事实甚至领取任务。服务地址 + 只读为精确 `http://127.0.0.1:8080`;token 保存后立即清空输入框,不回填、不入日志或异常文本。 +- Qt worker 不得直接访问 Widget,UI 回调不得丢弃迟到的 claim 业务结果。连续失败只允许用 T-303 + 已持久化的同一幂等键重放安全网络操作;`retryable` 绝不推导为页面点击、证据替换、下单或提交可重试。 +- 记录表的双击仅是非破坏性详情入口,并必须有 Enter 和显式按钮等价路径。Esc 只在详情态返回当前任务, + 不停止轮询、不关闭窗口、不释放 claim、不改变服务端状态;返回后按稳定记录 ID 恢复选择、滚动和焦点。 +- 不导入或实现 PDD 页面判据、规格选择、数量、确认页、证据上传、事件、失败上报、提交围栏或结果接口; + 不编写或引用点击“提交订单”的代码,不编写支付、免密支付、先用后付或任何扣款控件代码。