Appearance
vendors —— 授权中心(四态状态机)
前缀:
/api/v1/device/vendors鉴权:Bearer access(C 端用户) 代码:src/app/device/interface/api/device_actions.py(cz_build_device_vendors_router)+application/usecase/vendor_center.py产品需求落档:docs/internal-wiki/architecture/device-cloud-integration-research.md「授权中心状态机」
四态语义(bound / available / reviewing / error)
C 端授权页列出全部目标平台。每个厂家的 status 字段四态之一:
| 状态 | 语义 | 前端渲染 | 交互 |
|---|---|---|---|
bound | 已连接(当前用户有 active 绑定) | 绿色徽标「已连接」+ 最近同步时间 | 点击 → 详情/解绑 |
available | 可授权(凭据已配置、未绑定) | 品牌色 + 「去连接」 | 点击 → OAuth 跳转 |
reviewing | 厂家审核中(预登记占位,未对接完成) | 灰色徽标「正在审核中」 | 点击 → toast「该设备厂家正在审核中,敬请期待」 |
error | 通道异常(凭据已配置但健康检查未就绪) | 黄色徽标「暂时不可用」 | 点击 → 重试 |
状态映射规则(服务端硬编码顺序:bound > available > error > reviewing):
| 条件 | status |
|---|---|
用户有该 vendor 的 active 绑定 | bound |
configured=true 且健康检查 ok=true | available |
configured=true 但 ok=false | error |
configured=false 且 planned=true(预登记占位) | reviewing |
configured=false 且非预登记(真实厂商未配凭据) | 不出现(过滤,前端无感) |
C 端消费现状(2026-09-18 真机实证 — qm-frontend pages/mine/data/device-list.vue)
| status | 实际渲染 | 交互 |
|---|---|---|
bound | 绿字「已连接」+ 红描边「解除连接」按钮;顶部「N 个已连接」徽章 | 点击 → showModal 确认 → unbind action → onShow 刷新 |
available | 深绿字「未连接」+ 绿描边「去连接」按钮 | 点击 → POST vendors/{id}/auth-url → webview 打开 authUrl;回调落绑定后返回页 onShow 自动变 bound |
reviewing | 灰字「正在审核中」 | 点击 → 前端 toast「该设备厂家正在审核中,敬请期待」(不发请求 — 后端 40403006 为兜底) |
error | 红字「暂时不可用」 | 点击 → toast 提示稍后再试 |
- 厂商清单为动态拉取(12 平台:honor_oauth / zepp / xiaomi / suunto / apple_health / garmin_cn / garmin_intl / coros / huawei / oppo / polar / werun),中文名取
meta.displayName.zh - 请求带
X-Env: Prd(qm-frontendconfig/index.tsX_ENV — 双库路由) - 真机 bound 闭环已实证:插绑定 → 已连接+解除连接 → 确认解绑 → 行删除 + 状态回流(详见
docs/internal-wiki/operations/device-binding-live.md)
GET /api/v1/device/vendors —— 厂家清单
响应 data:
json
{
"vendors": [
{
"meta": {
"id": "honor_oauth",
"displayName": { "zh": "荣耀运动健康", "en": "HONOR Health" },
"logoUrl": "https://…",
"authType": "oauth",
"dataWindowDays": 30,
"capabilities": { "sportStat": true, "sampleSets": true, "healthRecord": true, "realtime": false }
},
"health": { "ok": true, "configured": true, "serviceReady": true, "message": null },
"status": "bound"
}
]
}status 枚举:bound · available · reviewing · error(上表)。
POST /api/v1/device/vendors/{vendor_id}/auth-url —— 通用发起授权
registry 分发(非硬编码厂商列表)—— 同一端点服务全部厂商。
请求 body:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
platform | string | null | ⬜ | 平台(Zepp 三端用:web | android | ios;其他厂商忽略) |
响应 data:
| 字段 | 类型 | 说明 |
|---|---|---|
authUrl | string | 厂商授权页 URL |
sessionKey | string | null | 会话标识(服务端已存) |
requireProfileCompletion | bool | 是否需补资料(荣耀恒 true) |
错误码:
| code | HTTP | 场景 |
|---|---|---|
40403004 | 404 | vendor 不存在 |
40403006 | 400 | 厂家审核中(预登记占位 vendor)— msg=「该设备厂家正在审核中,敬请期待」+ data.vendor 回传 vendor id |
厂家清单(registry 当前注册)
| vendor id | 类型 | 状态 |
|---|---|---|
honor_oauth | 真实实现(荣耀) | ✅ 已迁移 |
zepp | 真实实现(Zepp) | ✅ 已迁移 |
xiaomi | 真实实现(小米 — S3) | 🔶 未配 env 显示审核中;配置 XIAOMI_CLIENT_ID/SECRET 即 available |
apple_health | 预登记占位 | ⏳ 审核中 |
garmin_cn / garmin_intl | 预登记占位 | ⏳ 审核中 |
coros | 预登记占位 | ⏳ 审核中 |
huawei | 预登记占位 | ⏳ 审核中 |
suunto | 预登记占位 | ⏳ 审核中 |
oppo | 预登记占位 | ⏳ 审核中 |
polar | 预登记占位 | ⏳ 审核中 |
werun | 预登记占位 | ⏳ 审核中 |
占位清单 = 设备云对接研究文档 12 平台矩阵(除已迁移荣耀 / Zepp / 小米外 9 家)。 接入完成一家即从占位升为真实实现(registry 覆盖注册 — 同 id 替换,端点契约不变)。
实现参考
IDeviceVendor统一抽象(v2 七方法):src/app/device/domain/vendor.py- 注册中心:
src/app/device/application/vendor_registry.py - 占位实现:
src/app/device/application/planned_vendor.py