# Client 子项目规则 本文件适用于 `client/` 下的全部代码和测试,并继承仓库根目录 `AGENTS.md` 的工作流、Git、安全、文档和初级程序员维护规则。 ## 开始工作前 - 从仓库根目录执行 Client 任务时,也必须先读取本文件。 - 第一次接手本项目,先看这两份: - 环境和运行:[00 上手指南](../docs/client/00-getting-started.md) - 看不懂的词:[00 术语表](../docs/client/00-glossary.md) - 只读取与当前任务有关的长期基线,不必每次加载全部文档: - 需求边界:[01 产品需求基线](../docs/client/01-requirements.md) - 模块和线程:[02 系统架构](../docs/client/02-architecture.md) - SQLite 与 JSON:[03 数据模型](../docs/client/03-data-model.md) - Admin 对接:[04 接口契约](../docs/client/04-admin-api-contract.md) - 页面和交互:[05 界面规范](../docs/client/05-ui-specification.md) - 测试和采购安全:[06 质量与安全](../docs/client/06-quality-security.md) - 文档仍是草案或存在未决事项时,不得自行选择会改变业务结果的答案,应按根目录工单流程确认。 ## 技术栈 - 固定使用 **Python 3.10 + PyQt5 + Qt Widgets + PyQt-Fluent-Widgets**。 - 界面组件优先使用 `qfluentwidgets`;没有合适组件时再使用 PyQt5 标准控件。 - 只有两者都无法满足明确需求时才创建自定义控件,并说明原因。 - 不得混用 PyQt6、PySide2 或 PySide6,也不得安装其他 Qt 绑定对应的 Fluent Widgets 包。 - 当前开发和验证解释器为 `C:/Python310/python.exe`。 - 依赖及版本以 `client/requirements.txt` 为准,版本必须固定。 - 新增或升级依赖前先检查准确版本、许可证和打包影响,并经过工单确认;确认后同步更新 `requirements.txt`。 ## 代码分层 - 界面层只负责显示和输入转发,不直接调用 Admin、SQLite 长查询或 uiautomator2。 - `src/ui_main.py` 负责应用和窗口装配;页面界面放 `src/<页面>_ui.py`,事件绑定放 `src/<页面>_ui_event.py`(当前有 `pdd_ui` / `settings_ui` 两组)。 - 每个文件顶部的模块 docstring 写明了该文件的约束,动手前先读那几行。 - 领域模型不导入 Qt、uiautomator2 或具体 HTTP 客户端。 - Admin 通过 Gateway 接口隔离,Mock 和 HTTP 实现必须遵守相同契约。 - SQLite 通过 Repository 访问,不在页面或自动化函数中散落业务 SQL。 - PDD 页面识别、采集和采购函数放在 PDD 适配层;演示脚本不得被正式流程直接导入。 - 类和函数骨架遵循根目录的初级程序员维护规则,优先补全现有清晰边界,不随意重做架构。 ## 数据与接口 - 数据库字段、任务状态和 `pdd_data` 结构以 `docs/client/03-data-model.md` 为准。 - Admin 路径、字段和幂等语义以 `docs/client/04-admin-api-contract.md` 为准;Admin 未完成时使用 Mock,不臆造正式响应。 - Client 与 Admin 只有三个调用:领取、提交结果、提交失败。**不得新增"向 Admin 查询状态"类接口。** - 金额使用人民币分整数,时间使用带时区 ISO 8601,稳定任务编号不得使用表格行号代替。 - 文件路径一律通过 `data_dir()`(可写数据)和 `app_dir()`(只读资源)获取,见 [03 数据模型 §2.2](../docs/client/03-data-model.md)。**不许硬编码路径,不许用 `os.getcwd()` 或 `__file__` 直接拼**,打包成 exe 后会失效。 - PDD 结果必须先写入 SQLite,再通过 Outbox 提交 Admin。 - 任务领取后中途不查 Admin 状态;Admin 取消或重派一律不感知,做完照常提交。 ## 线程与自动化 - QWidget 只能在 Qt 主线程创建和访问。 - 禁止在主线程执行 Admin 请求、uiautomator2/ADB、`time.sleep()`、轮询、大型 XML 解析或文件批量写入。 - 长任务统一使用 `QObject` + `moveToThread` 的 Worker 写法,模板见 [02 架构 §5.1](../docs/client/02-architecture.md);不得混用 `QThread` 子类、`QRunnable` 或 `threading`。 - 后台结果通过信号回到主线程;窗口关闭时按 [02 架构 §5.2](../docs/client/02-architecture.md) 断开连接,防止迟到结果访问已销毁控件。 - 一个 Android 设备同一时间只由一个工作线程控制,不跨线程共享 uiautomator2 Device 对象。 - 自动化任务必须处理启动、运行、安全停止、成功、失败、取消、超时、设备断开和迟到结果。 - 窗口或页面销毁后,后台回调不得再访问对应控件。 ## 采购安全 - 真实下单开关默认关闭;未满足质量文档中的采购安全门禁不得启用。 - 高风险点击前必须使用最新页面状态重新校验商品、规格、数量、价格和目标坐标。 - 进入不可逆下单阶段前先持久化执行步骤。 - 不可逆阶段发生崩溃或结果不确定时,只能核对订单或转人工处理,禁止自动重新下单。 - 多个订单候选、验证码、登录失效、未知弹窗、价格超限或规格不确定时停止自动执行。 ## 界面规则 - 顶级模块保持为“PDD 任务”和“设置”,页面使用唯一且稳定的 `objectName`。 - 优先使用 `FluentWindow`、Fluent 导航、主题和图标;不得使用表情符号充当结构图标。 - 使用布局、尺寸策略和伸缩项,不用固定坐标排列常规界面。 - 任务表格使用模型/视图和稳定任务编号,不把完整 `pdd_data` 放入隐藏列,也不为每个单元格创建常驻 QWidget。 - “开始自动获取”是界面上唯一会产生外部后果的命令;其余操作只读本地数据库。 - 本地只保存已领取的任务,不缓存 Admin 任务池;已完成任务永久保留,不得清理。 - 普通成功更新页面状态即可;可恢复错误使用 `InfoBar`,只有必须阻断决策时才使用模态对话框。 - 主要流程必须支持键盘;表单具有可见标签;状态和错误不能只依赖颜色。 - 验证浅色、深色、Windows 贴靠和 100%–200% 显示缩放。 - 避免全局 QSS 覆盖 Fluent 控件;局部样式必须保留悬停、按下、焦点和禁用状态。 ## 验证 全部命令从 `client/` 目录执行,可直接复制。 **1. 语法检查**(改了哪个文件就换成哪个) ```powershell C:/Python310/python.exe -m py_compile src/ui_main.py ``` **2. 界面离屏冒烟测试**(不弹窗口,跑完自动退出,CI 和本地都用这条) ```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 ``` 打印 `OK` 即通过。 **3. 手动看界面** ```powershell C:/Python310/python.exe buyer_main.py ``` 当前 `buyer_main.py` 只装配并显示窗口,**不连接设备、不执行任何自动化**,可以随时运行。 将来"开始自动获取"接上真实设备后,**启动自动化的命令会产生真实外部操作,届时不得作为普通冒烟测试运行**;那时的日常验证仍以第 2 条离屏测试为准。 **4. 其他情况** - 修改数据库时测试首次建库和从上一版本迁移。 - 修改 Admin Gateway 时运行 Mock 与 HTTP 共用的契约测试。 - 修改 PDD 解析时优先使用脱敏 XML 固件;真实设备测试必须单独标记并说明是否执行真实下单。 - 交付时说明已运行的命令、结果、未验证的设备行为和新增依赖。