跳转至

DIP1-P3-A 联调操作手册 · P0 端点(28 个)

字段
报告编号 DWLG-20260810-10
关联文档 DWLG-20260810-09(P3 联调方案)/ DIP1-API V2.0
覆盖范围 P3-A D3-D4:AUTH(5) + QSV(9) + CPT(14) = 28 个 P0 端点
编制人 DT(听写)
编制日期 2026-08-10
状态 📋 执行中

一、联调环境确认

条件 状态 验证方式
后端 API ✅ localhost:8000 运行中 GET /health → status:ok
前端 OPR Web ✅ localhost:3000 运行中 HTTP 200
50 单 UAT 数据 ✅ 46 UAT50 + 4 DEMO seed 脚本验证通过
冒烟测试 ✅ 16/16 全绿 pytest tests/smoke/
admin 账号 ✅ admin/admin123 R3 UAT 验证

二、联调方式说明

2.1 双轨联调策略

方式 工具 适用场景 优点
A. 前端驱动 浏览器 → localhost:3000 验证 UI 交互 + API 联动 贴近真实用户操作
B. API 驱动 PowerShell / Apifox 验证边界场景 + 错误处理 精确控制请求参数

2.2 前端驱动操作流程

1. 打开浏览器 → http://localhost:3000
2. 按 F12 打开 DevTools → Network 面板
3. 在 OPR Web 上执行业务操作
4. 观察 Network 面板中的 API 请求/响应
5. 记录:端点 → 状态码 → 响应关键字段

2.3 API 驱动操作流程

# 1. 登录获取 token
$loginResp = Invoke-RestMethod -Uri "http://localhost:8000/api/v1/auth/login" `
    -Method POST -ContentType "application/json" `
    -Body '{"username":"admin","password":"admin123"}'
$token = $loginResp.access_token
$headers = @{ Authorization = "Bearer $token" }

# 2. 调用 API
$resp = Invoke-RestMethod -Uri "http://localhost:8000/api/v1/cpt/orders/board" `
    -Method GET -Headers $headers
$resp | ConvertTo-Json -Depth 5

三、P0 端点联调清单(28 个)

3.1 AUTH 认证域(5 端点)

端点 #1:POST /auth/login

项目 内容
前端操作 登录页输入 admin/admin123 → 点击登录
API 验证 POST /api/v1/auth/login body: {"username":"admin","password":"admin123"}
预期响应 200 + access_token + refresh_token + token_type: bearer
验证要点 token 非空 + user_id = USR-DEV-ADMIN-000001
实际结果 ☐ 通过 ☐ 失败
备注

端点 #2:POST /auth/refresh

项目 内容
前端操作 登录后等待 15min+ 自动刷新(或手动触发)
API 验证 POST /api/v1/auth/refresh body: {"refresh_token":"<上一步的refresh_token>"}
预期响应 200 + 新 access_token + 新 refresh_token
验证要点 旧 refresh_token 失效(轮换机制)
实际结果 ☐ 通过 ☐ 失败
备注

端点 #3:POST /auth/logout

项目 内容
前端操作 点击退出登录
API 验证 POST /api/v1/auth/logout Headers: Authorization
预期响应 200 + {"message":"logged out"}
验证要点 登出后 token 加入黑名单,后续请求 401
实际结果 ☐ 通过 ☐ 失败
备注

端点 #4:GET /auth/me

项目 内容
前端操作 登录后查看个人信息(侧栏头像/设置)
API 验证 GET /api/v1/auth/me Headers: Authorization
预期响应 200 + user_id + roles: ["TL"] + permissions: ["*"]
验证要点 roles 含 TL + permissions 含 *(超级管理员)
实际结果 ☐ 通过 ☐ 失败
备注

端点 #5:POST /auth/otp/send(WKR/CST 专用,OPR 不调)

项目 内容
API 验证 POST /api/v1/auth/otp/send body: {"phone":"+85291130001","channel":"whatsapp"}
预期响应 200 + {"message":"otp_sent"} 或 429 限流
验证要点 60s 内重复发送返回 429
实际结果 ☐ 通过 ☐ 跳过(P3-B)
备注 移动端认证,P3-A 可跳过

3.2 QSV 报价域(9 端点)

端点 #6:GET /qsv/categories

项目 内容
前端操作 报价计算器页面 → 品类选择下拉框
API 验证 GET /api/v1/qsv/categoriesGET /api/v1/mds/categories?active_only=true
预期响应 200 + 6 个 active 品类(WARDROBE/BED/KITCHEN_CABINET/DINING_TABLE/BOOKSHELF/TV_CABINET)
验证要点 每项含 category_id + code + base_fee_hkd + cap_price_hkd
实际结果 ☐ 通过 ☐ 失败
备注

端点 #7:GET /qsv/param-versions/current

项目 内容
API 验证 GET /api/v1/qsv/param-versions/current
预期响应 200 + version_id + version_code + effective_from
验证要点 返回当前生效参数版本(V-DEMO-1)
实际结果 ☐ 通过 ☐ 失败
备注

端点 #8:POST /qsv/calculator/preview ⭐ BUG-NEW-01 回归

项目 内容
前端操作 报价计算器 → 选择衣柜 → 选择楼宇 → 点击试算
API 验证 POST /api/v1/qsv/calculator/preview body: {"category_id":"CAT299723485B2B188EE7ED1C","building_id":"BLD0DEMO00000000000001","customer_id":"CUS0DEMO00000000000001","factors":{},"addons":[],"discounts":[]}
预期响应 200 + base_fee_hkd: "380.00" + cap_price_hkd: "1200" + final_hkd: "380.00" + capped_flag: false
验证要点 base_fee 非 0(BUG-NEW-01 核心回归点)+ factor_breakdown 非空
实际结果 ☐ 通过 ☐ 失败
备注 冒烟测试 smoke_qsv_preview_uuid.py 已覆盖

端点 #9:POST /qsv/quotes

项目 内容
前端操作 报价计算器试算后 → 点击"创建报价单"
API 验证 POST /api/v1/qsv/quotes body: {"customer_id":"CUS0DEMO00000000000001","category_id":"CAT299723485B2B188EE7ED1C","building_id":"BLD0DEMO00000000000001","factors":{},"addons":[],"discounts":[]}
预期响应 201 + quote_id + status: DRAFT
验证要点 创建 DRAFT 报价 + 返回 quote_id
实际结果 ☐ 通过 ☐ 失败
备注

端点 #10:GET /qsv/quotes ⭐ BUG-NEW-02 回归

项目 内容
前端操作 报价列表页
API 验证 GET /api/v1/qsv/quotes?page=1&page_size=20
预期响应 200 + 分页结构
验证要点 items 中含 category_code 字段且非空(BUG-NEW-02 核心回归点)
实际结果 ☐ 通过 ☐ 失败
备注 50 单数据下 total ≥ 48

端点 #11:GET /qsv/quotes/{quote_id}

项目 内容
前端操作 报价列表 → 点击某报价单详情
API 验证 GET /api/v1/qsv/quotes/QTE0UAT0000001
预期响应 200 + quote 详情含 factor_breakdown + calc_snapshot
验证要点 factor_breakdown 非空 + calc_snapshot 含 category_code
实际结果 ☐ 通过 ☐ 失败
备注

端点 #12:POST /qsv/quotes/{quote_id}/confirm

项目 内容
前端操作 DRAFT 报价详情 → 点击"确认报价"
API 验证 POST /api/v1/qsv/quotes/QTE0UAT0000001/confirm
预期响应 200 + status: CONFIRMED + confirmed_by + confirmed_at
验证要点 DRAFT → CONFIRMED 状态流转 + confirmed_at 非空
实际结果 ☐ 通过 ☐ 失败
备注 注意:确认后不可逆,建议用 DRAFT 状态的报价测试

端点 #13:POST /qsv/quotes/{quote_id}/reject

项目 内容
前端操作 DRAFT 报价详情 → 点击"拒绝报价"
API 验证 POST /api/v1/qsv/quotes/QTE0UAT0000002/reject body: {"reason":"客戶預算不足"}
预期响应 200 + status: REJECTED
验证要点 DRAFT → REJECTED 状态流转
实际结果 ☐ 通过 ☐ 失败
备注

端点 #14:GET /qsv/quotes/{quote_id}/pdf

项目 内容
前端操作 CONFIRMED 报价详情 → 点击"下载 PDF"
API 验证 GET /api/v1/qsv/quotes/QTE0UAT0000003/pdf
预期响应 200 + Content-Type: application/pdf
验证要点 PDF 文件可下载 + 内容含报价金额
实际结果 ☐ 通过 ☐ 失败
备注 需先确认报价(#12)后再下载

3.3 CPT 跟踪域(14 端点)

端点 #15:GET /cpt/orders/board ⭐ BUG-NEW-04 回归

项目 内容
前端操作 订单看板页(首页)
API 验证 GET /api/v1/cpt/orders/board
预期响应 200 + 含 6 个池 key:POOL_L1_NEW_LEADS / POOL_L3_PENDING_QUOTE / POOL_L4_PENDING_ASSIGN / POOL_L6_INSTALL_TODAY / POOL_L8_PENDING_FOLLOWUP / POOL_EXCEPTION
验证要点 6 池结构完整(BUG-NEW-04 核心回归点)+ 50 单数据下各池有数据
实际结果 ☐ 通过 ☐ 失败
备注 冒烟测试 smoke_12_endpoints.py 已覆盖

端点 #16:GET /cpt/orders

项目 内容
前端操作 订单列表页
API 验证 GET /api/v1/cpt/orders?page=1&page_size=20
预期响应 200 + 分页结构
验证要点 total ≥ 50 + 每项含 order_id + stage + customer_name
实际结果 ☐ 通过 ☐ 失败
备注

端点 #17:GET /cpt/orders/{order_id} ⭐ BUG-NEW-03 回归

项目 内容
前端操作 订单列表 → 点击某订单详情
API 验证 GET /api/v1/cpt/orders/ORD0UAT0000001
预期响应 200 + 订单详情含 category_code 字段
验证要点 category_code 非空(BUG-NEW-03 核心回归点)+ 含 stage/customer/worker 信息
实际结果 ☐ 通过 ☐ 失败
备注

端点 #18:POST /cpt/orders

项目 内容
前端操作 订单列表页 → "新建订单"按钮 → 填写表单 → 提交
API 验证 POST /api/v1/cpt/orders body: {"customer_id":"CUS0DEMO00000000000001","category_id":"CAT299723485B2B188EE7ED1C","building_id":"BLD0DEMO00000000000001","address_detail":"測試地址","lead_source_scene":"SCENE01_ONLINE_AD"}
预期响应 201 + order_id + stage: L1 + status: IN_PROGRESS
验证要点 新订单默认入 L1 新线索池
实际结果 ☐ 通过 ☐ 失败
备注

端点 #19:PATCH /cpt/orders/{order_id}/stage

项目 内容
前端操作 订单详情 → 状态流转按钮(如"标记已联系")
API 验证 PATCH /api/v1/cpt/orders/ORD0UAT0000001/stage body: {"target_stage":"L2","note":"已電話聯繫客戶"}
预期响应 200 + stage: L2
验证要点 L1 → L2 状态机流转 + 不可跳跃(如 L1 → L6 应 400)
实际结果 ☐ 通过 ☐ 失败
备注 测试正向流转 L1→L2→L3 + 测试非法跳转 400

端点 #20:POST /cpt/orders/{order_id}/assign

项目 内容
前端操作 L4 订单详情 → 派单 → 选择师傅 → 确认
API 验证 POST /api/v1/cpt/orders/ORD0UAT0000020/assign body: {"worker_id":"WKR0UAT0000001"}
预期响应 200 + assigned_worker_id + stage: L5
验证要点 派单后订单进入 L5 已派单
实际结果 ☐ 通过 ☐ 失败
备注 使用 L4 阶段的 UAT50 订单测试

端点 #21:POST /cpt/orders/{order_id}/checkin(WKR 专用,P3-A 可 API 验证)

项目 内容
API 验证 POST /api/v1/cpt/orders/ORD0UAT0000031/checkin body: {"gps_lat":22.3193,"gps_lng":114.1694}
预期响应 200 + checkin_at + stage: L6(签到中)
验证要点 GPS 坐标记录 + 签到时间
实际结果 ☐ 通过 ☐ 跳过(P3-B WKR App)
备注 移动端功能,P3-A 可 API 驱动验证

端点 #22:POST /cpt/orders/{order_id}/checkout(WKR 专用)

项目 内容
API 验证 POST /api/v1/cpt/orders/ORD0UAT0000031/checkout body: {"work_log":{...},"photos":["url1","url2"]}
预期响应 200 + checkout_at + stage: L7
验证要点 完工登记后进入 L7 待验收
实际结果 ☐ 通过 ☐ 跳过(P3-B WKR App)
备注

端点 #23:POST /cpt/orders/{order_id}/exception

项目 内容
前端操作 订单详情 → "上报异常" → 选择异常类型 → 填写描述 → 提交
API 验证 POST /api/v1/cpt/orders/ORD0UAT0000045/exception body: {"trigger_stage":"L4","kind":"INSTALL_CONDITION","description":"測試異常上報","level":1}
预期响应 200 + 订单进入 EXCEPTION 池
验证要点 异常池分支 + 异常记录写入 cpt_order_exceptions
实际结果 ☐ 通过 ☐ 失败
备注 UAT50 已有 2 单 EXCEPTION 数据

端点 #24:POST /cpt/orders/{order_id}/reopen

项目 内容
前端操作 异常池订单 → "恢复处理" → 填写恢复说明 → 提交
API 验证 POST /api/v1/cpt/orders/ORD0UAT0000045/reopen body: {"resolution":"已與客戶協商解決","returned_to_stage":"L4"}
预期响应 200 + 订单从 EXCEPTION 恢复至 L4
验证要点 异常恢复 + 返回指定阶段
实际结果 ☐ 通过 ☐ 失败
备注

端点 #25:GET /cpt/orders/{order_id}/timeline

项目 内容
前端操作 订单详情 → 时间线/操作记录 Tab
API 验证 GET /api/v1/cpt/orders/ORD0UAT0000001/timeline
预期响应 200 + 时间线事件数组 [{stage, action, at, by}, ...]
验证要点 时间线含创建事件 + 按时间排序
实际结果 ☐ 通过 ☐ 失败
备注

端点 #26:POST /cpt/orders/{order_id}/nps(CST 专用,P3-A 可 API 验证)

项目 内容
API 验证 POST /api/v1/cpt/orders/ORD0UAT0000044/nps body: {"score":9,"comment":"師傅服務很好","would_recommend":true}
预期响应 200 + nps 记录创建
验证要点 L8 阶段 NPS 采集 + would_recommend=true 触发 OPS 推荐反哺
实际结果 ☐ 通过 ☐ 跳过(P3-B CST App)
备注 使用 L8 阶段订单测试

端点 #27:GET /cpt/orders/{order_id}/work-log

项目 内容
前端操作 L6/L7 订单详情 → 现场登记表 Tab
API 验证 GET /api/v1/cpt/orders/ORD0UAT0000031/work-log
预期响应 200 + CPT-F 现场登记表数据
验证要点 L6 阶段订单有登记表数据
实际结果 ☐ 通过 ☐ 失败
备注

端点 #28:POST /cpt/orders/{order_id}/work-log(WKR 专用)

项目 内容
API 验证 POST /api/v1/cpt/orders/ORD0UAT0000031/work-log body: {"items":[...],"photos":["url1"]}
预期响应 200 + work-log 记录创建
验证要点 登记表提交成功
实际结果 ☐ 通过 ☐ 跳过(P3-B WKR App)
备注

四、联调执行顺序建议

4.1 第一轮:前端驱动(D3 上午)

按业务流程顺序操作,验证 UI × API 联动:

Step 1: 登录 → AUTH #1 #4
Step 2: 首页看板 → CPT #15(6 池结构)
Step 3: 订单列表 → CPT #16(分页)
Step 4: 订单详情 → CPT #17(category_code)+ #25(时间线)
Step 5: 新建订单 → CPT #18 → #19(L1→L2 流转)
Step 6: 报价列表 → QSV #10(category_code)+ #11(详情)
Step 7: 报价试算 → QSV #8(BUG-NEW-01 回归)
Step 8: 创建报价 → QSV #9 → #12(确认)→ #14(PDF)
Step 9: 异常处理 → CPT #23 → #24(恢复)

4.2 第二轮:API 驱动(D3 下午)

用 PowerShell/Apifox 补充前端未覆盖的端点和边界场景:

Step 1: AUTH #2(refresh 轮换)+ #3(logout 黑名单)
Step 2: QSV #7(param-versions)+ #13(reject)
Step 3: CPT #20(派单 L4→L5)
Step 4: CPT #21 #22(签到/完工,WKR 专用 API 验证)
Step 5: CPT #26(NPS 采集)+ #27 #28(work-log)
Step 6: 边界场景:
        - 非法状态跳转(L1→L6 应 400)
        - 无权限操作(普通 OL 角色不应能派单)
        - 重复派单(同一订单派两次应 409)

4.3 第三轮:50 单数据验证(D4)

在 50 单 UAT 数据下验证分页、筛选、看板数量:

Step 1: 看板各池数量验证
        - POOL_L1_NEW_LEADS: ≥ 8 单(含 DEMO)
        - POOL_L3_PENDING_QUOTE: ≥ 7 单
        - POOL_L6_INSTALL_TODAY: ≥ 8 单
        - POOL_EXCEPTION: = 2 单

Step 2: 订单分页验证
        - page=1&page_size=20 → total ≥ 50
        - page=3&page_size=20 → 返回第 41-50 单

Step 3: 品类筛选验证
        - 按 WARDROBE 筛选 → ≥ 10 单
        - 按 KITCHEN_CABINET 筛选 → ≥ 8 单

Step 4: 推荐关系链验证
        - 客户 CUS0UAT0000001→0002→0003→0004→0005 链式推荐
        - GET /mds/customers/CUS0UAT0000001 → referral_from_customer_id 链

五、联调记录模板

5.1 端点联调结果汇总表

# 端点 方法 前端驱动 API 驱动 状态 备注
1 AUTH /auth/login POST ☐✅☐❌
2 AUTH /auth/refresh POST ☐✅☐❌
3 AUTH /auth/logout POST ☐✅☐❌
4 AUTH /auth/me GET ☐✅☐❌
5 AUTH /auth/otp/send POST ☐✅☐⏭️ P3-B
6 QSV /qsv/categories GET ☐✅☐❌
7 QSV /qsv/param-versions/current GET ☐✅☐❌
8 QSV /qsv/calculator/preview POST ☐✅☐❌ BUG-NEW-01
9 QSV /qsv/quotes POST ☐✅☐❌
10 QSV /qsv/quotes GET ☐✅☐❌ BUG-NEW-02
11 QSV /qsv/quotes/{id} GET ☐✅☐❌
12 QSV /qsv/quotes/{id}/confirm POST ☐✅☐❌
13 QSV /qsv/quotes/{id}/reject POST ☐✅☐❌
14 QSV /qsv/quotes/{id}/pdf GET ☐✅☐❌
15 CPT /cpt/orders/board GET ☐✅☐❌ BUG-NEW-04
16 CPT /cpt/orders GET ☐✅☐❌
17 CPT /cpt/orders/{id} GET ☐✅☐❌ BUG-NEW-03
18 CPT /cpt/orders POST ☐✅☐❌
19 CPT /cpt/orders/{id}/stage PATCH ☐✅☐❌
20 CPT /cpt/orders/{id}/assign POST ☐✅☐❌
21 CPT /cpt/orders/{id}/checkin POST ☐✅☐⏭️ P3-B
22 CPT /cpt/orders/{id}/checkout POST ☐✅☐⏭️ P3-B
23 CPT /cpt/orders/{id}/exception POST ☐✅☐❌
24 CPT /cpt/orders/{id}/reopen POST ☐✅☐❌
25 CPT /cpt/orders/{id}/timeline GET ☐✅☐❌
26 CPT /cpt/orders/{id}/nps POST ☐✅☐⏭️ P3-B
27 CPT /cpt/orders/{id}/work-log GET ☐✅☐❌
28 CPT /cpt/orders/{id}/work-log POST ☐✅☐⏭️ P3-B

图例:✅ 通过 / ❌ 失败 / ⏭️ 跳过(P3-B 移动端)/ ☐ 待测

5.2 Bug 记录模板

Bug ID 端点 # 现象 期望 实际 严重度 状态
BUG-P3-001 ☐Critical ☐Major ☐Minor ☐Open ☐Fixed ☐Closed

六、P3-A D3-D4 验收标准

验收项 标准 当前
P0 端点通过率 28/28(含 P3-B 跳过的 5 个 WKR/CST 专用端点,P3-A 验证 23 个) ☐/23
BUG-NEW-01~04 回归 4/4 无回归 ☐/4
50 单数据看板 6 池均有数据 + 总数 = 50
分页正确性 total ≥ 50 + page 翻页正确
状态机合法性 L1→L8 正向流转通过 + 非法跳转 400

七、快速验证命令集

以下 PowerShell 命令可直接复制执行,快速验证核心端点:

# —— 前置:登录获取 token ——
$loginResp = Invoke-RestMethod -Uri "http://localhost:8000/api/v1/auth/login" -Method POST -ContentType "application/json" -Body '{"username":"admin","password":"admin123"}'
$token = $loginResp.access_token
$headers = @{ Authorization = "Bearer $token" }
Write-Host "✅ AUTH #1 login: token=$($token.Substring(0,20))..."

# —— AUTH #4 /auth/me ——
$me = Invoke-RestMethod -Uri "http://localhost:8000/api/v1/auth/me" -Method GET -Headers $headers
Write-Host "✅ AUTH #4 me: user_id=$($me.user_id) roles=$($me.roles -join ',')"

# —— QSV #8 preview(BUG-NEW-01 回归)——
$preview = Invoke-RestMethod -Uri "http://localhost:8000/api/v1/qsv/calculator/preview" -Method POST -ContentType "application/json" -Headers $headers -Body '{"category_id":"CAT299723485B2B188EE7ED1C","building_id":"BLD0DEMO00000000000001","customer_id":"CUS0DEMO00000000000001","factors":{},"addons":[],"discounts":[]}'
Write-Host "✅ QSV #8 preview: base_fee=$($preview.base_fee_hkd) cap=$($preview.cap_price_hkd) final=$($preview.final_hkd)"

# —— QSV #10 quotes list(BUG-NEW-02 回归)——
$quotes = Invoke-RestMethod -Uri "http://localhost:8000/api/v1/qsv/quotes?page=1&page_size=5" -Method GET -Headers $headers
Write-Host "✅ QSV #10 quotes: total=$($quotes.total) first_code=$($quotes.items[0].category_code)"

# —— CPT #15 board(BUG-NEW-04 回归)——
$board = Invoke-RestMethod -Uri "http://localhost:8000/api/v1/cpt/orders/board" -Method GET -Headers $headers
Write-Host "✅ CPT #15 board: pools=$($board.PSObject.Properties.Name -join ', ')"

# —— CPT #16 orders list ——
$orders = Invoke-RestMethod -Uri "http://localhost:8000/api/v1/cpt/orders?page=1&page_size=5" -Method GET -Headers $headers
Write-Host "✅ CPT #16 orders: total=$($orders.total) first_stage=$($orders.items[0].stage)"

# —— CPT #17 order detail(BUG-NEW-03 回归)——
$detail = Invoke-RestMethod -Uri "http://localhost:8000/api/v1/cpt/orders/ORD0UAT0000001" -Method GET -Headers $headers
Write-Host "✅ CPT #17 detail: order_id=$($detail.order_id) stage=$($detail.stage) category_code=$($detail.category_code)"

— 听写 DT,2026-08-10。本手册为 P3-A D3-D4 联调操作指南,执行后请填写 §五 联调记录。