docs(architecture): adopt authorized single-pass purchase
This commit is contained in:
+131
-141
@@ -1,157 +1,147 @@
|
||||
# 路由与页面结构
|
||||
|
||||
> 本文约定采购服务(网页端,`admin/`)页面路由、页面职责和组件归属,以及采购工具
|
||||
> (桌面端,`client/`)的界面结构。
|
||||
> 具体交互行为以[交互清单](08-interaction-checklist.md)为准,接口形状以 [API 合约](api.md) 为准。
|
||||
> 采购服务使用服务端渲染;采购工具使用固定 tab 的 Windows 桌面外壳。交互细节以
|
||||
> [08-interaction-checklist.md](08-interaction-checklist.md) 为准。
|
||||
|
||||
## 一、采购服务页面路由
|
||||
|
||||
网页端用户可见产品名统一为“采购服务”。`cmbuyer` 只作为仓库和系统内部标识,不出现在
|
||||
网页标题、页头品牌或无障碍名称中;桌面端仍使用独立名称“采购工具”。
|
||||
|
||||
| 路由 | 页面 | 职责 | 用户故事 | 交互 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `/login` | 登录 | 建立管理会话 | US-007 | IX-001 |
|
||||
| `/tasks` | 采购任务 | 传统表格查询、创建弹窗、批量开始试选、进入详情抽屉 | US-001、US-002、US-010 | IX-002、IX-003、IX-004、IX-012 |
|
||||
| `/tasks/new` | 手工建单直达页 | 复用创建表单,作为无脚本和直接访问的完整页兜底 | US-001 | IX-002 |
|
||||
| `/tasks/{id}` | 任务详情 | 从列表进入时显示右侧详情抽屉;直接访问时显示完整页;承载试选确认、授权与待付款核对 | US-002、US-004、US-005 | IX-004、IX-005、IX-006 |
|
||||
|
||||
> `/tasks/import`(Excel)与 `/freight*`(ERP)随 F-002 / F-003 推迟到 V2。
|
||||
|
||||
登录后默认进入 `/tasks`。未登录访问受保护页面时跳转 `/login` 并携带站内返回路径;
|
||||
**只接受 `/tasks` 及其子路径**,拒绝绝对 URL、`//` 和反斜杠。
|
||||
|
||||
## 二、采购服务页面职责
|
||||
|
||||
### 采购任务 `/tasks`
|
||||
|
||||
采用采购人员熟悉的传统表格,默认按创建时间倒序。固定列为:选择、标题、颜色、尺码、
|
||||
价格上限、数量、采购结果、状态、创建时间;不设置操作列。
|
||||
|
||||
- 标题链接在新标签打开拼多多商品页;标题下方任务编号链接打开内部任务详情。
|
||||
- “采购结果”由结构化字段在展示层格式化为“阶段:颜色 | 尺码 | 单价 | 数量”;未产生
|
||||
试选或下单结果时显示 `—`,不得把试选写成已下单。
|
||||
- 双击行非控件区域,或聚焦行后按 Enter,打开 `/tasks/{id}` 的右侧详情抽屉。关闭抽屉、
|
||||
按 Esc 或浏览器返回后,保留筛选、选择、滚动位置并把焦点还给原行。
|
||||
- 直接访问 `/tasks/{id}` 或在抽屉中选择“在完整页面打开”时,使用完整详情页;关键路由可
|
||||
深链接,不能只有无法复制地址的弹层状态。
|
||||
- 第一工具行:导入(MVP 禁用占位并说明原因)、创建。创建打开模态表单;保存后任务以
|
||||
`DRAFT` 状态出现在第一行。`/tasks/new` 保留为同表单的直达兜底。
|
||||
- 第二工具行默认显示标题关键词、筛选、清除;状态和创建时间放在默认折叠的“更多条件”中,
|
||||
保留 F-004 查询范围而不挤占常用操作。勾选 `DRAFT` 后切换成上下文批量栏,显示已选数量、
|
||||
开始试选、清除选择;全选只覆盖当前筛选结果中的 `DRAFT`。
|
||||
- “开始试选”把所选任务原子转为 `PENDING`,只进入第一趟试选队列;不签发授权、不创建
|
||||
订单、不付款。其他状态复选框禁用并说明原因。
|
||||
- 窄屏允许表格容器内部横向滚动,但页面本身不得横向溢出;选择列与标题列保持可见。
|
||||
|
||||
### 任务详情 `/tasks/{id}`
|
||||
|
||||
按任务当前状态呈现不同主区块,同一时刻只出现一个主动作:
|
||||
|
||||
| 状态 | 主区块 |
|
||||
| --- | --- |
|
||||
| `WAITING_CONFIRMATION` | **试选确认卡** + 确认 / 退回 |
|
||||
| `AUTHORIZED` / 未围栏的 `ORDERING` | 授权摘要 + **放弃授权**入口 |
|
||||
| 已围栏的 `ORDERING` / `RECONCILIATION_REQUIRED` | 提交围栏摘要 + 「订单可能已创建」提示 + 人工核查入口;**无重试 / 放弃按钮** |
|
||||
| `WAITING_PAYMENT` | 待付款核对卡(订单截图、商品、规格、数量、授权金额)+ 标记完成 |
|
||||
| `NEEDS_MANUAL` | 原因说明 + 处理入口 |
|
||||
| 终态 | 结果摘要 + 执行证据 |
|
||||
|
||||
**试选确认卡**是 MVP 的核心交互。人只回答一个问题:**机器选对了吗**。
|
||||
|
||||
```text
|
||||
你要的: 白色 · XL · 2 件 · 上限 ¥80
|
||||
机器选到: 白色 · XL ✓ 一致
|
||||
单价 ¥32.50 × 2 = ¥65.00 ✓ 没超
|
||||
[规格面板截图]
|
||||
商品标题:2026夏季新款纯棉圆领短袖T恤…
|
||||
|
||||
[ 确认下单(不付款) ] [ 退回,不买 ]
|
||||
```
|
||||
|
||||
- 这是**轻量确认,不是对照台**——只有一个商品,不需要并排比较多个候选。
|
||||
多候选对照台随 B 路径推迟到 V2。
|
||||
- 不需要「选择理由 / 拒绝理由」下拉,保留一个可选备注即可。
|
||||
- 机器选到的值与需求不一致时(✗),确认按钮**默认禁用**,需先退回或转人工。
|
||||
- **不提供列表页一键确认。** 确认前必须看过截图,这道闸不能省。
|
||||
|
||||
### 授权卡住时的出口
|
||||
|
||||
`AUTHORIZED` / 未建立提交围栏的 `ORDERING` 必须提供「放弃授权」入口;放弃后进入
|
||||
`PENDING_RETRIAL`,重新跑第一趟。围栏建立后不得放弃,页面改为提供「进入人工核查」入口,
|
||||
并明确禁止再次提交。**每个状态都必须给出安全且可执行的下一步**——这是验收项。
|
||||
|
||||
### 建单页
|
||||
|
||||
`/tasks` 的创建弹窗与 `/tasks/new` 直达页复用同一表单:任务名称、拼多多链接、颜色分类、
|
||||
尺码、数量、价格上限。链接无法解析出 `goods_id` 时明确报错并保留已填内容;保存成功后
|
||||
任务为 `DRAFT`,尚未进入设备领取队列。
|
||||
|
||||
## 三、采购工具界面结构
|
||||
|
||||
桌面端产品名为“采购工具”,不是网页;使用顶部固定两页签,不做多级导航,默认打开采购执行:
|
||||
|
||||
| 页签 | 职责 | 用户故事 | 交互 |
|
||||
| 方法 | 路径 | 页面 / 动作 | 身份 |
|
||||
| --- | --- | --- | --- |
|
||||
| 采购执行 | 连接与会话状态、当前任务与可选图片、滚动日志、执行记录 | US-003、US-008 | IX-007、IX-008 |
|
||||
| 配置 | 设备档案、ADB 路径与 serial、常用超时参数、连接检查 | US-003 | IX-007 |
|
||||
| `GET` | `/login` | 登录页 | 匿名 |
|
||||
| `POST` | `/login` | 建立会话 | 匿名 + CSRF |
|
||||
| `POST` | `/logout` | 退出 | 管理员 + CSRF |
|
||||
| `GET` | `/tasks` | 采购任务表格、筛选、批量选择和创建入口 | 管理员 |
|
||||
| `GET` | `/tasks/new` | 无 JS 时的创建表单;有 JS 时装入对话框 | 管理员 |
|
||||
| `POST` | `/tasks` | 创建 `DRAFT` | 管理员 + CSRF |
|
||||
| `POST` | `/tasks/start-purchases` | 批量开始采购并签发一次性授权 | 管理员 + CSRF |
|
||||
| `GET` | `/tasks/{id}` | 完整任务详情;也作为列表抽屉的可复制 URL | 管理员 |
|
||||
| `POST` | `/tasks/{id}/reset-to-draft` | 围栏前人工处理后回待开始 | 管理员 + CSRF |
|
||||
| `POST` | `/tasks/{id}/cancel` | 围栏前取消 | 管理员 + CSRF |
|
||||
| `POST` | `/tasks/{id}/mark-paid` | 记录人工已付款并完成 | 管理员 + CSRF |
|
||||
| `POST` | `/order-submissions/{sid}/reconcile` | 围栏后调和同一提交 | 管理员 + CSRF |
|
||||
| `GET` | `/evidence/{asset_id}` | 受保护内部截图 | 管理员;不缓存 |
|
||||
|
||||
### 采购执行页
|
||||
设备 JSON API 不属于页面路由,见 [api.md](api.md)。
|
||||
|
||||
- 顶部状态区:web、设备、拼多多 App 实际 / 已取证版本和会话状态;开始 / 停止轮询固定在
|
||||
最右侧且只控制轮询会话。版本不一致时 fail closed 并提示重新取证。
|
||||
- 宽屏是主从工作区:左侧在“当前任务 + 滚动日志”和“执行记录详情”之间切换,右侧执行记录
|
||||
保持可见;窄屏进入详情时暂时收起记录表,返回后恢复列表现场。
|
||||
- 当前任务左侧显示商品、规格、数量、**当前是第一趟还是第二趟**、步骤和剩余租约;右侧约
|
||||
1/3 显示可选商品 / 证据预览。无可信图片时保持空态,有图必须标来源与采集时间。
|
||||
- 滚动日志标题区同时显示下次轮询、连续失败和本次完成,不再使用独立会话卡或底部控制条。
|
||||
- 执行记录只显示标题、状态两列,任务编号与时间放在标题次行,按采集时间倒序。单击选择;
|
||||
双击、Enter、可见“查看所选记录”或右键在左侧打开详情;详情态单击另一行直接更新详情。
|
||||
- 记录详情不是模态框:上部左侧显示原始文字、右侧显示图片证据,下部显示结构化采购结果;
|
||||
可见“返回当前任务”与 `Esc` 均能返回并恢复当前行焦点。加载失败、无图和记录不存在有明确
|
||||
状态,图片缺失不使用其他来源凑合。
|
||||
- **待人工时整页显著变色并说明缺什么**,不要让执行员盯着一个静止画面猜。
|
||||
- 关闭窗口即停止轮询;连续失败达阈值自动停止并显示原因。
|
||||
## 二、采购任务工作台 `/tasks`
|
||||
|
||||
### 配置页
|
||||
页面标题:**采购服务**。
|
||||
|
||||
- 设备档案必须**显式填写 serial**,不允许留空自动选——同一手机 USB + WiFi 同时在线时
|
||||
自动选会失败(见[架构设计](04-architecture.md)第六节)。
|
||||
- 连接检查只做连接和确认拼多多已安装,**不打开商品、不选规格、不创建订单**。
|
||||
- 运行中冻结设备切换与参数保存。
|
||||
表格上方两行:
|
||||
|
||||
## 四、导航规则
|
||||
1. 第一行:导入(disabled 占位)、创建按钮;存在选择时显示上下文批量操作条。
|
||||
2. 第二行:标题关键词输入框(默认筛选)、其他可选筛选,右侧“筛选”“清除”。
|
||||
|
||||
- 采购服务从路由化详情抽屉返回工作台时不重新加载列表;完整详情页返回时保留原筛选条件。
|
||||
- 采购工具启动时若服务端有本设备的活跃任务,优先恢复该任务,不允许直接领取下一条。
|
||||
- 第一趟试选完成后**必须退出商品页**再进入下一轮轮询,不停在规格面板等人。
|
||||
- 采购工具在真机步骤执行期间禁用硬取消和关闭窗口,避免留下无法判定的中间态。
|
||||
- 任何进入外部支付页的情形,采购工具立即停止并跳回待人工,**不提供「继续」按钮**。
|
||||
- dry-run 与真实下单必须使用不同的醒目标识;dry-run 不得出现可触发真实提交的控件。
|
||||
- 已建立提交围栏后,不提供重新领取、重新提交或放弃授权,只能恢复同一提交记录并调和。
|
||||
表格字段:
|
||||
|
||||
## 五、组件归属
|
||||
| 字段 | 行为 |
|
||||
| --- | --- |
|
||||
| checkbox | 只允许选择 `DRAFT`;表头全选当前筛选结果中的可选行 |
|
||||
| 标题 | `<a>` 指向 canonical 拼多多商品页;点击链接不触发行详情 |
|
||||
| 颜色 | 任务目标颜色 |
|
||||
| 尺码 | 任务目标尺码 |
|
||||
| 价格 | 任务最高总价;执行后详情另列实际闸门金额 |
|
||||
| 数量 | 正整数 |
|
||||
| 采购结果 | 用 `颜色|尺码|价格|数量` 展示已执行摘要;无结果显示 `—` |
|
||||
| 状态 | 中文状态徽标,不只靠颜色 |
|
||||
| 创建时间 | 本地时区显示,数据按 UTC 保存 |
|
||||
|
||||
| 组件 | 归属 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `AppShell` | web 全局 | 导航、登录态、CSRF 注入 |
|
||||
| `TaskTable` | 采购任务 | 任务表格、创建时间倒序、选择状态与结构化采购结果格式化 |
|
||||
| `QueryBar` | 采购任务 | 标题关键词、筛选与清除 |
|
||||
| `BulkTrialBar` | 采购任务 | `DRAFT` 批量选择与开始第一趟试选 |
|
||||
| `CreateTaskDialog` | 采购任务 / 建单直达页 | 复用手工建单表单与字段错误 |
|
||||
| `TaskDetailDrawer` | 采购任务 | `/tasks/{id}` 路由驱动的右侧详情容器与焦点恢复 |
|
||||
| `SpecTrialCard` | 任务详情 | 试选确认卡(MVP 签名组件) |
|
||||
| `AuthorizePanel` | 任务详情 | 确认 / 退回 / 放弃授权 |
|
||||
| `PaymentCheckCard` | 任务详情 | 待付款核对与标记完成 |
|
||||
| `DeviceStatusBar` | desk 采购执行页 | web、设备与 App 版本三项就绪状态 |
|
||||
| `PollControls` | desk 采购执行页 | 顶部固定的轮询开关与会话状态;日志标题区承载倒计时、失败和完成计数 |
|
||||
| `CurrentTaskPanel` | desk 采购执行页 | 当前任务文字、步骤与带来源的可选图片证据 |
|
||||
| `ExecutionLog` | desk 采购执行页 | 最新在上的滚动日志与假诊断导出 |
|
||||
| `ExecutionRecordTable` | desk 采购执行页 | 标题 / 状态两列、时间倒序和稳定记录 ID |
|
||||
| `ExecutionRecordDetailPanel` | desk 采购执行页 | 左侧内联原始文字、图片证据、采购结果、读取状态与返回焦点 |
|
||||
没有操作列。双击非控件区域或键盘 Enter 打开 `/tasks/{id}` 路由化详情抽屉;新 tab 直接访问同 URL
|
||||
则显示完整详情页。关闭抽屉或浏览器返回恢复筛选、滚动和触发行焦点。
|
||||
|
||||
## 六、原型
|
||||
### 批量开始采购
|
||||
|
||||
低保真原型放 `docs/design/`,约定见 [`design/README.md`](design/README.md)。
|
||||
原型只回答「页面上有什么」,行为权威是[交互清单](08-interaction-checklist.md);
|
||||
实现时按真实框架重写,**不复制原型代码**。
|
||||
选择 `DRAFT` 后,表格前的上下文操作条显示:
|
||||
|
||||
- 已选条数;
|
||||
- 所选最高总价合计;
|
||||
- “将授权采购工具逐条创建待付款订单,系统不会付款”;
|
||||
- 主按钮“开始采购(只创建待付款订单)”。
|
||||
|
||||
点击即为最终授权,不另弹“机器选对了吗”的同义确认框。整批全有或全无;成功更新 `PENDING`,
|
||||
冲突时保持页面现场并要求刷新重选。
|
||||
|
||||
### 创建任务
|
||||
|
||||
字段:标题、拼多多商品链接、颜色分类、尺码、最高总价、数量。保存成功后关闭对话框,新任务插到
|
||||
首行且状态为待开始;创建本身不授权、不领取、不执行。
|
||||
|
||||
## 三、任务详情 `/tasks/{id}`
|
||||
|
||||
详情按状态展示同一条单趟采购的事实,而不是审批流程:
|
||||
|
||||
1. 任务要求:商品链接 / goods_id、颜色、尺码、数量、最高总价、版本。
|
||||
2. 开始采购授权:授权 id、授权人、锁定任务版本、创建/有效期、当前状态。
|
||||
3. 设备执行:attempt、设备、App 版本、步骤时间线和失败 code。
|
||||
4. 三道闸门:两次规格面板单价、规格/数量读回、确认页总额与判定。
|
||||
5. 内部截图:规格面板、确认页和结果页;只经受保护端点读取。
|
||||
6. 提交围栏:submission id、是否首次明确许可、唯一点击和调和记录。
|
||||
7. 待付款收口:明确写系统尚未付款;人工核对后记录完成。
|
||||
|
||||
状态动作:
|
||||
|
||||
| 状态 | 页面动作 |
|
||||
| --- | --- |
|
||||
| `DRAFT` | 返回列表勾选并开始采购;可编辑/取消(按任务版本) |
|
||||
| `PENDING` / `CLAIMED` / `ORDERING` | 只读进度;围栏前异常由人工处理,不中途确认规格 |
|
||||
| `NEEDS_MANUAL` | 查看原因;确认没有围栏后重置为 DRAFT 或取消 |
|
||||
| `RECONCILIATION_REQUIRED` | 只调和同一 submission;无重试、释放或重新授权 |
|
||||
| `WAITING_PAYMENT` | 查看证据、人工付款、标记完成或转人工 |
|
||||
| 终态 | 只读审计 |
|
||||
|
||||
详情中不出现 `WAITING_CONFIRMATION`、“确认机器选对了吗”、“签发第二趟授权”或“重新试选”。
|
||||
|
||||
## 四、采购工具界面结构
|
||||
|
||||
应用名:**采购工具**。顶部固定 tab:
|
||||
|
||||
1. **采购执行**(默认)
|
||||
2. **配置**
|
||||
|
||||
### 采购执行 tab
|
||||
|
||||
- 顶部第一行:采购服务、ADB、拼多多版本、会话状态;其右侧是“开始轮询 / 停止轮询”。
|
||||
- 左上“当前任务”:左侧文字约 2/3,右侧商品图片约 1/3;空闲显示占位。
|
||||
- 左下“滚动日志”:占满剩余高度,显示阶段、固定 reason 和安全下一步。
|
||||
- 右侧“采购记录”:时间倒序表格,MVP 只显示标题和状态。
|
||||
- 双击或 Enter 记录:左侧原位切换到记录详情,不弹窗;上方文字/图片,下方执行结果。
|
||||
- Esc 或“返回当前任务”:恢复当前任务视图;不暂停执行、不释放围栏。
|
||||
|
||||
单趟状态:待领取、已领取、打开商品、选择规格、闸门一、数量复核、闸门二、确认页/闸门三、
|
||||
申请围栏、已发出唯一提交、待付款或待调和。桌面端没有让用户手工点击“提交订单”的按钮。
|
||||
|
||||
### 配置 tab
|
||||
|
||||
- 采购服务 URL、设备 token(密码框,不回显完整值);
|
||||
- ADB 路径、设备 serial、USB/WiFi 通道选择;
|
||||
- 轮询间隔与连续失败停止阈值;
|
||||
- 连接检查:服务、设备身份、拼多多安装和已取证版本。
|
||||
|
||||
配置凭据进入系统安全存储;日志和界面不显示完整 token。
|
||||
|
||||
## 五、导航和焦点规则
|
||||
|
||||
- Web 主导航 MVP 只有“采购任务”;logo 文案为“采购服务”。
|
||||
- 商品标题链接是外部导航;行详情是内部导航,两者事件相互隔离。
|
||||
- Web 路由抽屉与完整页共享数据和 URL;关闭恢复触发行焦点。
|
||||
- Desk tab 使用标准键盘关系;历史详情 Esc 返回当前任务,不关闭应用。
|
||||
- 真机执行、围栏和提交不受页面/视图切换影响;关闭窗口时若有活跃任务,提示只影响 UI/轮询,
|
||||
不把它解释为撤销服务端授权。
|
||||
|
||||
## 六、组件归属
|
||||
|
||||
| 组件 | 归属 |
|
||||
| --- | --- |
|
||||
| 会话 / CSRF / SSR 模板 | `admin/internal/transport/webui` |
|
||||
| 任务 / 授权 / attempt / submission 用例 | `admin/internal/usecase` |
|
||||
| SQLite / 证据存储 | `admin/internal/storage` |
|
||||
| 设备 API | `admin/internal/transport/httpapi` |
|
||||
| ADB / PDD 页面能力 | `client/src/cmbuyer_client/device`、`pdd` |
|
||||
| 任务来源与结果 sink | `client/src/cmbuyer_client/core`、`remote` |
|
||||
| PySide6 UI | `client/src/cmbuyer_client/app` |
|
||||
|
||||
## 七、原型
|
||||
|
||||
- Web:`docs/design/web-task-create.html`、`web-task-workbench.html`、`web-task-detail.html`。
|
||||
- Desk:`docs/design/desk-execution.html`;配置结构见 `desk-device-settings.html`。
|
||||
- 原型只使用假数据、无网络和生产副作用;显著流程变更先更新原型再实现。
|
||||
|
||||
Reference in New Issue
Block a user