Appearance
uniapp API 调用契约 · 总览与分工边界
本目录是 uniapp 前端调用视角的 API 文档 —— 回答「哪个页面在什么时机调、响应怎么读、失败时前端做什么」。 不回答「这个字段是什么类型、错误码是几、curl 怎么写」—— 那些一律去 前端联调 API 手册。
一、分工边界(端到端 · 先看这张表再看任何一页)
四套文档并存,接触面只有"锚点"一个 —— 接触面越窄,越不会互相矛盾。
提问 → 去哪
────────────────────────────────────────────────────────────────────
某个字段的类型 / 必填 / 可空 → 手册(契约权威)
某个错误码的码值 / HTTP / 触发条件 → 手册
想直接 curl 一条试试 → 手册
某页面在哪个生命周期调了哪个函数 → 本目录 api/*.md
响应应该从哪一层读(嵌套 vs 顶层) → 本目录 api/*.md ★ 历史 bug 高发区
失败了前端该做什么(提示?回退?登出?) → 本目录 api/*.md
从零把登录链搭起来(SDK/基座/manifest) → OAuth 落地手册
架构 / 分域 / 部署 / 运维 → internal-wiki| 内容 | 唯一归属 | 另一侧怎么写 |
|---|---|---|
| 请求/响应字段表(类型、必填、可空) | 前端联调 API 手册 | 本目录只写读法路径(res.data.calorie.budgetKcal),不写类型 |
| 错误码具体码值 + HTTP + 触发条件 | 手册 | 本目录只写前端动作(「提示并回退重拉」)+ 指锚点 |
全部 curl / BASE_URL 变量块 | 手册 | 本目录不出现 curl |
| 字段取值语义(每个值意味着什么 / 缺省行为 / 边界值) | 取值速查 | 本目录只在踩坑处指锚点,不复制取值表。⚠️ 2026-09-20 新增 —— 起因是一条真实联调 BUG:habits.exerciseFreq 文档只写「0–7」,前端不知道 0 是有效值(写 0 就通),卡了一轮 |
| 通用约定 G1-G7 | 手册 通用约定 | 本目录写一句「与手册 G2 一致」 |
| 10 条头号坑位 | 手册 头号坑位速查 + 联调台账 | 本目录只在自己页面确实踩到时指锚点 |
真机/框架坑(编译器锁版本、t.__f__ 崩溃、www 缓存、adb logcat、验证码渲染) | guide/uniapp 铁律 | 手册一字未提 —— 那是 guide 的独占资产 |
页面 ↔ API 映射、调用链时序、storage 键名 | 本目录 api/*.md + pages/*.md | 手册只在 page-direct 涉及 3 端点 |
| OAuth 从零施工(拷 SDK / 自定义基座 / 微信登录 manifest) | OAuth 登录链落地手册 | 该页页首已声明「契约见手册」 |
⚠️ 一致性的兜底是脚本,不是自觉:
scripts/check_uniapp_api_docs.py(pre-commit 钩子)机械校验 ① 矩阵 30 端点覆盖 ② 已证伪字面量(历史错误契约)③ 字段路径层级 ④ 跨目录死链。 已知边界:该脚本抓不到语义坑(字段名对但含义错)与可空性/枚举值域/常量 —— 那些只能靠人工对拍矩阵。
本目录已知的读法坑(扩展前必读)
request不解包:const res = await xxxApi()拿到的是完整响应体(含code/msg/data),业务字段在res.data之下- 嵌套 vs 平铺:响应里的分组对象(如
data.calorie.*/data.checkin.*)不是顶层字段。写错层级 ⇒ 恒undefined⇒?? 默认值兜底 ⇒ 需求静默失效。 同类事故已出现 2 次(首页热量目标恒 400 / 健康卡距离字段) - 业务失败可能不是 reject:部分端点失败仍返回
HTTP 200 + code "0",只是data为null或ok: false—— 必须判空、必须自查ok,否则出现"假成功" - 两套错误契约并存:
oauth是「HTTP 200 +40101xxx」;user/device/training/stats/upload是「HTTP 400/401/404 +code」。 按其中一套写拦截器会漏掉另一套 —— 细节见 手册 G4
二、阅读顺序
按「从登录到业务」的实际施工顺序读,每一步都建立在前一步的产物之上:
| 步 | 页面 | 解决什么 |
|---|---|---|
| 1 | 本页 | 分工边界 + 已知读法坑(不读这页,后面每一页都会读错层次) |
| 2 | api/oauth | 登录链 —— token 从哪来、怎么续(rotate)、怎么登出。所有后续请求的前提 |
| 3 | api/user | 新用户向导链(三页向导的调用顺序、画像与习惯字段) |
| 4 | api/splash | 开机信息屏(启动即拉,独立于登录态) |
| 5 | api/device | 设备线(厂商列表 / 授权 URL / 绑定与解绑) |
| 6 | api/training | 训练计划(报名 / 任务 / 打卡 / 提醒) |
| 7 | api/stats | 首页今日概览 —— 含嵌套读法防回归块(历史 bug 现场) |
| 8 | api/agreement | 用户协议 / 隐私政策(免登录,登录页就要用) |
| 9 | api/page-direct | 页面直调(不走 src/api/*.ts 的 3 个端点:首页健康卡 / 热量卡 / 头像上传) |
只想查一个端点 → 直接跳 第四节 反查表(锚点由 VitePress 从标题生成)。
三、本目录文件一览
| 文件 | 覆盖端点 | 覆盖的前端文件 / 触发方 |
|---|---|---|
| api/oauth | 7 | src/api/login.ts + src/utils/request.ts(rotate 拦截器) |
| api/user | 7 | src/api/user.ts |
| api/splash | 2 | src/api/splash.ts |
| api/device | 4 | src/api/device.ts |
| api/training | 5 | src/api/training.ts |
| api/stats | 1 | 页面直调 src/pages/index/index.vue |
| api/agreement | 2 | src/api/agreement.ts |
| api/page-direct | 3 | 页面直调(index.vue ×2 + personal-form.vue ×1) |
| 30 | 与 手册 30 端点总表 同源(tests/reports/contract-matrix.json) |
training另有 1 个前端未封装的端点(POST /api/v1/training/leave,不在 30 端点矩阵内)—— 已单列在 training 并标注「契约未审计」。
四、端点 → 文档 反查表
对齐 手册 30 端点总表 的逐条编号(
#列两侧同号)。 「前端函数」列给出消费视角的入口(业务直调 / 拦截器 / 页面直调)—— 字段与码值以手册为准。 ⚠️ 本表只证明端点被索引,不证明被写透 —— 每页的完成度看该页自身。
| # | 方法 | 路径 | 前端函数 / 触发方 | 消费视角文档 |
|---|---|---|---|---|
| 1 | POST | /api/v1/auth/oauth | getCaptcha() | oauth |
| 2 | POST | /api/v1/auth/oauth | sendSmsCode() | oauth |
| 3 | POST | /api/v1/auth/oauth | smsLogin() | oauth |
| 4 | POST | /api/v1/auth/oauth | rotateOnce()(拦截器自动,非业务直调) | oauth |
| 5 | POST | /api/v1/auth/oauth | listSessions() | oauth |
| 6 | POST | /api/v1/auth/oauth | revokeSession() | oauth |
| 7 | POST | /api/v1/auth/oauth | logout() | oauth |
| 8 | POST | /api/v1/user | updateBasicProfile() | user |
| 9 | POST | /api/v1/user | submitOnboarding() | user |
| 10 | POST | /api/v1/user | getOnboardingSuggestion() | user |
| 11 | POST | /api/v1/user | adoptPlanOption() | user |
| 12 | POST | /api/v1/user | completeOnboarding() | user |
| 13 | POST | /api/v1/user | myProfile() | user |
| 14 | POST | /api/v1/user | updateProfile() | user |
| 15 | GET | /api/v1/device/vendors | listVendors() | device |
| 16 | POST | /api/v1/device/vendors/{id}/auth-url | getAuthUrl() | device |
| 17 | POST | /api/v1/device | listMyBindings() | device |
| 18 | POST | /api/v1/device | unbindVendor() | device |
| 19 | GET | /api/v1/training/plans | listTrainingPlans() | training |
| 20 | POST | /api/v1/training/enroll | enrollTrainingPlan() | training |
| 21 | GET | /api/v1/training/tasks | listMyTasks() | training |
| 22 | POST | /api/v1/training/task/checkin | checkinTask() | training |
| 23 | GET | /api/v1/training/reminders | listMyReminders() | training |
| 24 | GET | /api/v1/splash-screen | getSplashScreen() | splash |
| 25 | POST | /api/v1/splash-screen/track | trackSplashEvent() | splash |
| 26 | GET | /api/v1/content/agreements | listAgreements() | agreement |
| 27 | GET | /api/v1/content/agreements/{type} | getAgreement() | agreement |
| 28 | POST | /api/v1/device | 页面直调 index.vue(健康卡) | page-direct |
| 29 | POST | /api/v1/stats | 页面直调 index.vue(热量卡) | page-direct |
| 30 | POST | /api/v1/upload?type=avatar | 页面直调 personal-form.vue(头像) | page-direct |
反查表逆用:知道自己在改哪个
.ts→ 找上表「前端函数」列 → 点进对应页。 注意/api/v1/user与/api/v1/device是多 action 共用一个路径:路径相同、action不同, 光看 URL 无法区分端点是哪一个(action名与入参见 手册总表)。