# 架构设计 > 本文讲“怎么把技术栈搭起来”:系统结构、职责划分、数据模型、技术难点、开发顺序。 > 具体用了哪些框架 / 库 / 数据库 / 部署方式,见 [技术栈](03-tech-stack.md)。 ## 一、系统结构 ```text 运营同事 | v Windows 桌面 GUI(PySide6) | +--> Excel 导入/回写模块(openpyxl) | +--> 任务执行器 / 状态机 | +--> Android 控制模块(uiautomator2 + ADB) | | | v | Android 真机 + 拼多多 App | +--> 截图 / UI XML / 日志归档 ``` MVP 没有独立后端服务,也没有数据库。Excel 是任务输入和结果输出,日志和截图是排查辅助文件。 ## 二、职责划分 **桌面 GUI** - 导入 Excel 文件。 - 展示任务表格、状态、订单号、失败原因。 - 支持勾选任务、开始、暂停、继续、取消、人工接管和支付模式配置。 - 展示当前手机截图、当前步骤和实时日志。 - 防止执行中重复启动同一批任务。 **Excel 模块** - 校验固定表头。 - 读取任务行并转换为内部任务模型。 - 生成默认结果文件路径,不默认覆盖原始 Excel。 - 将状态、订单号、失败原因、执行时间、截图路径写回结果文件。 **任务执行器 / 状态机** - 接收 GUI 选中的任务列表。 - 按顺序逐条执行。 - 管理任务状态流转。 - 根据支付模式决定支付前暂停或受控继续支付。 - 遇到需要人工处理的节点时暂停并通知 GUI。 - 捕获异常并记录失败原因。 **Android 控制模块** - 连接和检查 Android 真机。 - 打开拼多多商品链接。 - 等待并识别当前页面状态。 - 点击购买按钮、打开 SKU 面板、选择 SKU、设置数量。 - 到支付确认节点时执行二次校验,并根据支付模式暂停或继续。 - 到安全校验节点时停止自动动作并转人工。 - 保存截图和 UI XML。 **拼多多流程模块** - 封装与拼多多 App 页面相关的选择器、文本匹配和步骤判断。 - 不直接散落在 GUI 或 Excel 模块中。 - 页面变化时优先修改这里。 **日志与归档** - 每条任务记录开始时间、结束时间、状态、关键步骤。 - 失败时保存截图和 UI XML。 - 日志不记录支付密码、短信验证码、账号密码等敏感信息。 ## 三、数据模型 ### 3.1 Excel 输入字段 最终字段以用户提供的真实样例为准。MVP 建议固定表头: | 字段 | 必填 | 说明 | | --- | --- | --- | | `任务ID` | 否 | 运营侧任务编号;为空时系统可用行号作为内部编号。 | | `商品链接` | 是 | 拼多多商品链接。 | | `商品名称` | 否 | 便于运营识别,不作为自动化唯一依据。 | | `SKU信息` | 是 | 建议格式:`颜色=黑色;尺码=XL;套餐=单件`。 | | `数量` | 是 | 下单数量,默认应为正整数。 | | `收货人` | 否 | MVP 可先使用拼多多账号默认地址;如需要校验地址再启用。 | | `手机号` | 否 | 同上。 | | `地址` | 否 | 同上。 | | `备注` | 否 | 运营备注,不影响自动化。 | | `预期金额` | 否 | 开启受控自动支付时建议填写,用于支付前比对。 | | `最高可支付金额` | 否 | 开启受控自动支付时建议填写,作为单笔金额上限。 | 如果业务需要拆分 SKU,可后续支持 `SKU1`、`SKU2`、`SKU3`,但 MVP 优先统一用 `SKU信息`。 ### 3.2 Excel 输出字段 结果文件应在原始字段基础上追加或更新: | 字段 | 说明 | | --- | --- | | `状态` | `待执行`、`执行中`、`待人工`、`成功`、`失败`、`已取消`。 | | `订单号` | 成功后读取到的拼多多订单号。 | | `失败原因` | 失败或暂停原因。 | | `执行时间` | 最近一次完成或失败时间。 | | `截图路径` | 失败或关键节点截图保存路径。 | | `结果备注` | 可选,记录人工接管说明。 | ### 3.3 内部任务模型 ```text OrderTask task_id: str row_index: int product_url: str product_name: str | None sku_text: str sku_items: dict[str, str] quantity: int receiver: str | None phone: str | None address: str | None note: str | None expected_amount: Decimal | None max_pay_amount: Decimal | None status: TaskStatus order_no: str | None fail_reason: str | None screenshot_path: str | None started_at: datetime | None finished_at: datetime | None ``` 支付模式不挂在单条任务上:是否启用受控自动支付由**全局** `PaymentConfig` 决定(见 §4.4),`OrderTask` 只持有支付前二次校验需要的 `expected_amount` / `max_pay_amount` 等输入数据。 ### 3.4 任务状态 ```text 待执行 -> 执行中 -> 待人工 -> 执行中 -> 成功 待执行 -> 执行中 -> 失败 待执行 -> 已取消 执行中 -> 已取消 待人工 -> 已取消 ``` 状态含义: - `待执行`:已导入但未开始。 - `执行中`:自动化正在处理。 - `待人工`:需要运营在手机或 GUI 中确认/接管。 - `成功`:已获得订单号并写入结果。 - `失败`:无法继续执行,已记录原因。 - `已取消`:用户取消执行。 #### 枚举命名与中英映射 代码标识符使用英文(见 [`05-coding-rules.md`](05-coding-rules.md) §6),中文仅用于 GUI 展示和 Excel 回写。`TaskStatus` 枚举以英文成员名定义,中文为其显示值,映射如下: | 枚举成员(代码) | 显示值(GUI / Excel) | | --- | --- | | `TaskStatus.PENDING` | `待执行` | | `TaskStatus.RUNNING` | `执行中` | | `TaskStatus.MANUAL` | `待人工` | | `TaskStatus.SUCCESS` | `成功` | | `TaskStatus.FAILED` | `失败` | | `TaskStatus.CANCELLED` | `已取消` | 约定: - 中↔英映射只在写入 Excel 或渲染 GUI 的边界处发生,由 `TaskStatus` 的 `display_name` 属性与 `from_display` 反查集中维护(单一事实源),核心逻辑只比较英文枚举成员。 - `OrderTask.status` 字段类型为 `TaskStatus`,不直接存中文字符串。 - 注意区分「任务状态」与「执行器状态」:上表是单条任务的 `status`;批次级的「暂停」属于执行器状态,不进入本枚举(见 §4.5)。 ## 四、核心流程 ### 4.1 批量执行流程 ```text 导入 Excel -> 校验表头 -> GUI 展示任务 -> 用户勾选任务 -> 点击开始 -> 检查 Android 设备 -> 按顺序执行每条任务 -> 更新 GUI 状态 -> 写入结果 Excel ``` ### 4.2 单条任务流程 ```text 打开商品链接 -> 跳转拼多多 App -> 识别商品详情页 -> 点击购买入口 -> 打开 SKU 面板 -> 按 SKU 信息选择规格 -> 设置数量 -> 进入订单确认页 -> 校验商品标题 / SKU / 数量 / 地址 / 实付金额 -> 默认支付前暂停 / 开启受控自动支付时继续支付 -> 如需人工处理则等待人工完成后继续 -> 读取订单号 -> 写回结果 ``` ### 4.3 异常处理原则 - 找不到按钮、SKU、数量控件:暂停或失败,不使用不确定坐标硬点。 - 出现验证码、风控、人脸、短信、安全验证:进入 `待人工`。 - 价格变化、超过最高可支付金额、库存不足、商品下架:记录明确失败原因。 - 设备断开、App 崩溃、网络异常:失败并保留截图/日志。 - 未读取到订单号:允许人工录入或标记为待核查,MVP 具体交互待实现时确认。 ### 4.4 支付模式 支付模式是**全局批次级配置**,不是按行任务字段。整个批次共用一个 `PaymentConfig`,由 GUI 显式设置(默认人工确认),执行中不得悄悄切换。 ```text PaymentConfig mode: PaymentMode # MANUAL(默认)/ AUTO(受控自动支付) per_order_limit: Decimal # 单笔金额上限,开启 AUTO 时必填 batch_limit: Decimal | None # 批次金额上限,建议填写 price_tolerance: Decimal # 实付与预期金额的允许偏差,默认 0 ``` ```text PaymentMode(枚举,代码用英文名,显示用中文) MANUAL -> 人工确认支付 AUTO -> 受控自动支付 ``` 单条任务的支付决策 = 全局 `PaymentConfig` + 该任务行的 `expected_amount` / `max_pay_amount`。MVP 不支持按行覆盖支付模式;如未来需要,再在本文和 `api.md` 中显式扩展,不得在代码里临时加按行开关。 MVP 支持两种支付模式: ```text 人工确认支付(默认) -> 到支付确认页 -> 校验商品 / SKU / 数量 / 地址 / 金额 -> 进入待人工 -> 运营确认后继续读取订单号 受控自动支付(显式开启) -> 到支付确认页 -> 校验商品 / SKU / 数量 / 地址 / 金额 -> 检查单笔金额上限和批次金额上限 -> 未触发安全校验时继续支付 -> 触发验证码 / 风控 / 人脸 / 短信时进入待人工 ``` 受控自动支付约束: - 必须由 GUI 配置显式开启,不能默认开启。 - 必须配置单笔金额上限;建议配置批次金额上限。 - 如果 Excel 提供 `预期金额`,支付页实付金额必须与预期一致或在允许偏差内。 - 如果 Excel 提供 `最高可支付金额`,支付页实付金额不得超过该值。 - 支付前必须保存截图和 UI XML。 - 不保存支付密码、短信验证码、人脸信息等敏感数据。 - 出现安全校验时只允许转人工,不做绕过。 ### 4.5 执行器状态与暂停语义 「暂停」是**执行器(批次)层**的状态,不是单条任务的 `status`。任务级状态只有 §3.4 的六种;GUI 工具栏的「暂停 / 继续」控制的是执行器是否继续领取下一条任务,不会把任何任务改成「已暂停」。 执行器状态(`RunnerState`,与 `TaskStatus` 分离): ```text IDLE 空闲(未开始或批次已结束) RUNNING 正在按顺序执行 PAUSED 已暂停;当前任务执行完后不再领取下一条 STOPPING 取消中;正在安全收尾当前任务 ``` 约定: - 点「暂停」时,正在执行的任务跑完当前安全步骤后停在边界,执行器进入 `PAUSED`;已进入 `待人工` 的任务不受影响。 - 点「继续」时执行器回到 `RUNNING`,从下一条勾选任务继续。 - 「取消」使执行器进入 `STOPPING`;无法安全中断的当前任务按 §3.4 转 `待人工` 或 `已取消`,不会硬杀。 - `RunnerState` 不写入 Excel;Excel 只记录任务级 `status`。 ## 五、关键技术难点 | 难点 | 说明 | 应对 | | --- | --- | --- | | 拼多多页面可识别性 | 第三方 App 控件文本和结构可能变化,部分区域可能无法通过 UI XML 获取。 | Phase 1 先做真机原型;必要时保存截图并后续引入 OCR。 | | SKU 精确匹配 | SKU 文案可能存在同义、缺货、套餐组合、层级顺序问题。 | MVP 用明确文本匹配;匹配失败即暂停/失败,不猜测。 | | 支付和安全节点 | 涉及真实资金和账号安全。 | 默认人工确认;受控自动支付必须经过二次校验、金额上限和显式开关;安全校验转人工。 | | 批量执行稳定性 | App 卡顿、网络波动、设备锁屏会导致流程中断。 | 增加超时、重试、截图、状态恢复;先单设备验证。 | | 结果回写可靠性 | 执行中断可能导致结果丢失。 | 每条任务结束后立即保存结果文件。 | ## 六、推荐开发顺序 1. 初始化 Python 项目骨架和文档约定。 2. 实现 Excel 读取、表头校验、内部任务模型。 3. 实现最小 PySide6 GUI:导入、表格展示、日志区域。 4. 验证 ADB 和 `uiautomator2` 真机连接。 5. 做单条商品链接跳转和截图/UI XML 保存原型。 6. 做 SKU 面板打开和 SKU 文本选择原型。 7. 接入任务执行器,跑通单条任务到支付前校验和默认暂停。 8. 接入批量顺序执行、状态更新和结果 Excel 回写。 9. 完善异常处理、人工接管、受控自动支付开关和打包。 ## 七、项目结构建议 ```text cmpdd/ ├── docs/ ├── src/ │ ├── main.py │ ├── app/ │ │ ├── main_window.py │ │ └── widgets/ │ ├── core/ │ │ ├── models.py │ │ ├── task_runner.py │ │ └── status.py │ ├── excel/ │ │ ├── reader.py │ │ └── writer.py │ ├── android/ │ │ ├── device.py │ │ └── pdd_flow.py │ ├── logging_config.py │ └── paths.py ├── tests/ ├── samples/ ├── logs/ ├── artifacts/ ├── requirements.txt └── README.md ``` - `src/app/`:PySide6 GUI。 - `src/core/`:任务模型、状态机、执行编排。 - `src/excel/`:Excel 导入、校验、回写。 - `src/android/`:设备连接、拼多多 App 自动化流程。 - `src/logging_config.py`:统一日志格式(含 `task_id`、`step`),输出到控制台与 `logs/app.log`;不记录敏感信息。 - `src/paths.py`:集中管理运行时路径与产物命名;截图与 UI XML 按 `artifacts//<时间戳>_.png|.xml` 归档,`task_id`/`step` 入路径前安全化以防穿越。 - `logs/`:本地运行日志(`app.log`),运行时自动创建并被 `.gitignore` 忽略,不提交真实敏感日志。 - `artifacts/`:截图、UI XML、结果文件等运行产物,运行时自动创建并被 `.gitignore` 忽略,不提交真实数据。 - `samples/`:脱敏样例 Excel。 ## 八、架构纪律 - GUI 不直接写 Android 点击细节,必须通过任务执行器和 Android 模块。 - Android 模块不直接读写 Excel。 - Excel 模块不关心拼多多页面状态。 - 状态枚举和字段变化必须同步更新本文、`api.md` 和相关任务验收。 - 支付逻辑必须受显式开关、二次校验和金额上限控制。 - 安全校验、验证码、风控逻辑只能进入人工接管分支。