From 1f95de373aa165f61b26ec6b4e1ee349cdae08fd Mon Sep 17 00:00:00 2001 From: chengma Date: Thu, 6 Aug 2026 12:01:38 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=A2=9E=E5=8A=A0=E7=BA=A2=E7=BA=BF?= =?UTF-8?q?=E6=B8=85=E5=8D=95=EF=BC=8C=E5=B9=B6=E6=8A=8A=E7=BA=A6=E6=9D=9F?= =?UTF-8?q?=E4=B8=8B=E6=B2=89=E5=88=B0=E4=BB=A3=E7=A0=81=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 起因:实测发现 Codex 不会主动把 338 行的规则手册当判断依据—— 问“能用 PySide6 吗”答“可以评估”,问“加个 emoji 图标”直接给改法, 问“改错别字要建工单吗”结论对但依据是通用常识、不是 §0 的实际条件。 三次都表现为“知道代码事实,但不应用项目规则”。 对策一:红线上收 - 根 AGENTS.md 开头新增 5 条红线(Qt 绑定、下单开关、风控、凭据、 不可逆阶段),并明确“不要论证其可行性,先停下来问用户” 对策二:把约束放到 agent 必然会打开的文件里 - pdd_ui.py / pdd_ui_event.py / settings_ui.py / settings_ui_event.py 写入模块 docstring,说明各自职责和最易踩的硬性规则 - 四个文件目前只有 docstring,无实现 同步修正 - ui_event.py 已拆成按页面分的四个文件,更新 client/AGENTS.md 的代码分层规则和 02 §3.1 的现状差异表 未包含:ui_main.py 和 demo1/auto_v1.py 的同类 docstring, 这两个文件承载尚未提交的代码,留待代码提交时一并处理。 Co-Authored-By: Claude Opus 5 --- AGENTS.md | 27 ++++++++++++++++++++++++--- client/AGENTS.md | 3 ++- client/src/pdd_ui.py | 26 ++++++++++++++++++++++++++ client/src/pdd_ui_event.py | 21 +++++++++++++++++++++ client/src/settings_ui.py | 22 ++++++++++++++++++++++ client/src/settings_ui_event.py | 25 +++++++++++++++++++++++++ docs/client/02-architecture.md | 2 +- 7 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 client/src/pdd_ui.py create mode 100644 client/src/pdd_ui_event.py create mode 100644 client/src/settings_ui.py create mode 100644 client/src/settings_ui_event.py diff --git a/AGENTS.md b/AGENTS.md index f9019d4..8918a4a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,5 +1,26 @@ # 项目协作规则 +## 红线 + +下面五条**任何情况下都不要自行改动,也不要论证它的可行性**。 +需要突破其中任何一条时,**停下来问用户**,不要先给方案、不要先评估成本。 + +1. **Qt 绑定固定 PyQt5。** 不得改用 PyQt6 / PySide2 / PySide6,也不得安装其他绑定对应的 Fluent Widgets 包。 +2. **真实下单开关默认关闭。** 不得通过调试参数、默认配置或界面误操作打开;未通过采购安全门禁前一律走演练模式。 +3. **不绕过拼多多的验证码、风控和安全机制**,不自动注册登录,不自动付款。 +4. **凭据(token、Cookie、密码)不得写入** `data/`、日志、数据库、Gitea 工单和 `docs/task`。 +5. **任务一旦进入不可逆阶段**(`task_runs.irreversible_action_at` 有值),**只准核对订单,绝不重新下单**。 + +改动看起来再合理,只要碰到上面任意一条,先停下来告诉用户。 + +> **动 `client/` 下任何东西之前,先读 [client/AGENTS.md](client/AGENTS.md)。** +> 那里有技术栈、代码分层、线程、采购安全和界面的硬性规则,本文件不重复。 +> **本项目的代码目前全部在 `client/` 下**,所以基本上只要是写代码,就必须先读它。 +> +> 第一次接手本项目,还要先看: +> [上手指南](docs/client/00-getting-started.md)(装环境、跑起来)和 +> [术语表](docs/client/00-glossary.md)(Outbox、幂等、不可逆阶段等)。 + ## 需求、缺陷与任务工作流 本流程适用于新需求、缺陷修复、重构以及会改变程序行为的任务。正式工单采用 **史诗级大工单(Epic)→ 最小可行产品工单(MVP)→ 单元任务工单** 三级结构。Gitea 工单是实施期间的事实来源,本地 `docs/task` 是任务完成后的最终归档。 @@ -216,7 +237,7 @@ Gitea 使用约定(**首次使用前需由项目负责人补全**): ## Client 子项目 -- 处理 `client/` 下的需求、代码、测试或文档前,必须读取并遵循 `client/AGENTS.md`。 -- 从仓库根目录启动 Codex 时也不能跳过该文件。 -- Client 的详细需求和技术基线位于 `docs/client/`;按当前任务只读取相关文档。 +- 处理 `client/` 下的需求、代码、测试或文档前,必须读取并遵循 [client/AGENTS.md](client/AGENTS.md)。 +- 从仓库根目录启动时也不能跳过该文件(本文件开头已重复提醒一次)。 +- Client 的详细需求和技术基线位于 [docs/client/](docs/client/);按当前任务只读取相关文档,清单见 [文档索引](docs/README.md)。 - Client 专用技术栈、线程、自动化安全、界面和验证规则不在根文件重复维护。 diff --git a/client/AGENTS.md b/client/AGENTS.md index 8760441..6110ec4 100644 --- a/client/AGENTS.md +++ b/client/AGENTS.md @@ -30,7 +30,8 @@ ## 代码分层 - 界面层只负责显示和输入转发,不直接调用 Admin、SQLite 长查询或 uiautomator2。 -- `src/ui_main.py` 负责应用和窗口装配;事件绑定放在 `src/ui_event.py` 或后续应用层服务中。 +- `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。 diff --git a/client/src/pdd_ui.py b/client/src/pdd_ui.py new file mode 100644 index 0000000..e2041a2 --- /dev/null +++ b/client/src/pdd_ui.py @@ -0,0 +1,26 @@ +"""PDD 任务页的界面结构。 + +这一页显示**本机已领取的全部任务**(正在做的和早已做完的), +提供搜索、筛选、详情,以及启动/停止自动获取。 +完整规范见 `docs/client/05-ui-specification.md`。 + +改动本文件前必读 `client/AGENTS.md`。以下几条最容易踩: + +- 本文件只负责显示和把用户操作转发出去,**不写业务逻辑**, + 不发 Admin 请求、不查数据库、不碰手机。这些放 `pdd_ui_event.py`。 +- 任务表格必须用**模型/视图**(`QAbstractTableModel` + `TableView`), + 并用 `remote_task_id` 作为任务身份。**不要用表格行号**—— + 行号会随排序和筛选变化,拿它当身份必出错。 +- 不要为每个单元格创建常驻 `QWidget`(几万行会把内存吃光)。 + “详情”那一列用委托绘制。 +- 不要把完整的 `pdd_data` 放进表格模型,那是详情数据, + 查看详情时再从数据库读。 +- 表格数据只增不减(已完成任务永久保留),所以增量加载是必须的, + 照抄 `docs/client/05-ui-specification.md` §5.3 的模板。 +- 空状态要分情况:从没领过任务、筛选无结果、加载失败,文案不能一样。 +- 图标用 `FluentIcon`,**不得用表情符号**。 +- 页面 `objectName` 固定为 `pddTaskPage`,不要改。 + +注意:本页唯一会产生外部后果(真的去操作手机、可能下单)的命令是 +“开始自动获取”。其余操作全部只读本地数据库。 +""" diff --git a/client/src/pdd_ui_event.py b/client/src/pdd_ui_event.py new file mode 100644 index 0000000..f9d9228 --- /dev/null +++ b/client/src/pdd_ui_event.py @@ -0,0 +1,21 @@ +"""PDD 任务页的事件绑定。 + +把 `pdd_ui.py` 里控件的信号,接到查询、任务引擎等实际动作上。 + +改动本文件前必读 `client/AGENTS.md`。以下几条最容易踩: + +- **禁止在 Qt 主线程做任何阻塞的事**:Admin 请求、uiautomator2/ADB 调用、 + `time.sleep()`、轮询、大 XML 解析、批量写文件。做了界面就会卡死转圈。 +- 长任务统一用 `QObject` + `moveToThread` 的 Worker 写法, + 模板照抄 `docs/client/02-architecture.md` §5.1。 + **不要**用 `QThread` 子类、`QRunnable` 或 Python 的 `threading`。 +- 后台结果只能通过**信号**回到主线程,Worker 里一行界面代码都不许有。 +- 窗口关闭时要断开信号并置标志位,否则迟到的后台结果会访问 + 已经销毁的控件、直接崩溃。做法见同文档 §5.2。 +- 数据库读写走 Repository,**不要在这里拼业务 SQL**。 +- “开始自动获取”会真的去操作手机、可能下单;“搜索”只读本地数据库。 + 两者必须分开,不得共用入口。 +- 普通成功不弹窗,更新界面即可;可恢复错误用 `InfoBar` + (模板见 `docs/client/05-ui-specification.md` §9.1); + 只有必须让用户当场做决定时才用模态对话框。 +""" diff --git a/client/src/settings_ui.py b/client/src/settings_ui.py new file mode 100644 index 0000000..d479c47 --- /dev/null +++ b/client/src/settings_ui.py @@ -0,0 +1,22 @@ +"""设置页的界面结构。 + +分四组:Admin、Android 设备、自动化、安全与诊断。 +完整规范见 `docs/client/05-ui-specification.md` §8。 + +改动本文件前必读 `client/AGENTS.md`。以下几条最容易踩: + +- **认证状态只显示“已配置/未配置”或掩码值,绝不回显完整 token。** +- 本文件只负责显示和输入转发,“测试连接”这类会联网、会连手机的动作 + 放 `settings_ui_event.py`,且必须走后台线程。 +- 表单必须有**可见标签**,占位符不能当标签用(占位符一输入就没了, + 用户会忘记这个框是干嘛的)。 +- 用可滚动布局和 Fluent 设置卡片;MVP 采用显式“保存设置”按钮, + 不要在同一页混用即时保存。 +- 校验失败时保留用户已输入的内容,并把焦点移到第一个出错的字段, + 不要清空重来。 +- 图标用 `FluentIcon`,**不得用表情符号**。 +- 页面 `objectName` 固定为 `settingsPage`,不要改。 + +注意:设备连接**不是**独立的顶级页面,统一放在本页, +见 `docs/client/01-requirements.md` §3。 +""" diff --git a/client/src/settings_ui_event.py b/client/src/settings_ui_event.py new file mode 100644 index 0000000..616d270 --- /dev/null +++ b/client/src/settings_ui_event.py @@ -0,0 +1,25 @@ +"""设置页的事件绑定。 + +处理保存设置、测试 Admin 连接、测试设备连接等动作。 + +改动本文件前必读 `client/AGENTS.md`。以下几条最容易踩: + +- **凭据(token、密码)不写进 SQLite 的 `app_settings`,也不写进日志。** + 存到 Windows 凭据管理器,见 `docs/client/06-quality-security.md` §7。 + `data/` 目录是明文的、设计上就是整个拷走的,拷一次等于泄露一次。 +- “测试连接”会联网、会连手机,**必须走后台线程**, + 用 `QObject` + `moveToThread`(模板见 `docs/client/02-architecture.md` §5.1)。 + 在主线程里直接连,界面会卡住好几秒。 +- 非敏感设置存 `app_settings` 表,键名沿用 `<分组>.<名称>` 的写法, + 清单见 `docs/client/03-data-model.md` §6。 +- 涉及路径的设置(日志目录、Artifact 目录)一律基于 `data_dir()`, + **不要硬编码,也不要用 `os.getcwd()`**——打包成 exe 后会失效, + 见 `docs/client/03-data-model.md` §2.2。 +- 保存前要校验:数量上限、价格偏差、轮询周期这些填错了会直接影响 + 采购安全,不能存进去再说。 +- 测试结果用 `InfoBar` 反馈,失败时说清“哪一步失败、下一步做什么”, + 不要把原始异常堆栈贴到界面上。 + +注意:真实下单开关属于红线,默认关闭,不得在这里做成 +一个随手能打开的普通开关,见根目录 `AGENTS.md` 红线第 2 条。 +""" diff --git a/docs/client/02-architecture.md b/docs/client/02-architecture.md index ed6f8fb..fb020c7 100644 --- a/docs/client/02-architecture.md +++ b/docs/client/02-architecture.md @@ -90,7 +90,7 @@ client/ | 目录分层 | domain / application / infrastructure / workers / ui | 只有 `src/`、`src/util/`、`src/demo1/` | | PDD 任务页 | 任务表格 + 搜索 + 状态栏 | 单个商品的输入表单(链接/颜色/尺码 + 开始按钮) | | 主按钮文案 | 「开始自动获取」 | 「开始任务」 | -| 事件层 | `src/ui_event.py` 或应用层服务 | `src/ui_event.py` 是空文件 | +| 页面与事件层 | `ui/` 下按页面分文件 | `src/pdd_ui.py`、`src/pdd_ui_event.py`、`src/settings_ui.py`、`src/settings_ui_event.py`,目前只有约束 docstring,尚无实现 | | SQLite / Admin / Outbox / 任务协调器 | 见 §4 | 尚未实现 | | PDD 自动化 | `infrastructure/pdd/` 适配层 | `src/util/` 下的独立函数 + `src/demo1/auto_v1.py` 演示脚本 |