library-picturebook-activity/docs/api/device-api.md

461 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 终端设备接口文档
> **基础地址**: `http://{服务器IP}:8580/api`
> **认证方式**: Bearer TokenJWT
> **数据格式**: JSON
> **字符编码**: UTF-8
---
## 目录
1. [发送短信验证码](#1-发送短信验证码)
2. [手机验证码登录](#2-手机验证码登录)
3. [用户作品列表](#3-用户作品列表)
4. [查询乐读派作品表单](#4-查询乐读派作品表单)
5. [保存乐读派作品表单](#5-保存乐读派作品表单)
6. [通用错误码](#6-通用错误码)
---
## 接口详情
### 1. 发送短信验证码
向指定手机号发送6位数字验证码验证码有效期 **5分钟**
```
POST /device/auth/sms/send
```
**请求头**
| 参数 | 值 |
|------|------|
| Content-Type | application/json |
**请求参数Body**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| phone | string | 是 | 手机号11位 |
**请求示例**
```json
{
"phone": "13800138000"
}
```
**响应参数**
| 字段 | 类型 | 说明 |
|------|------|------|
| code | int | 状态码200=成功 |
| message | string | 描述信息 |
| data | null | 无数据返回 |
**响应示例**
```json
{
"code": 200,
"message": "success",
"data": null,
"timestamp": "2026-04-11T12:00:00",
"path": "/api/device/auth/sms/send"
}
```
**注意事项**
- 同一手机号 **60秒内** 只能发送一次
- 同一手机号每天最多发送 **15次**
- 验证码 **5分钟** 内有效,仅可使用一次
---
### 2. 手机验证码登录
使用手机号 + 短信验证码登录,成功返回 JWT Token 和用户信息。
```
POST /device/auth/login/sms
```
**请求头**
| 参数 | 值 |
|------|------|
| Content-Type | application/json |
**请求参数Body**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| phone | string | 是 | 手机号11位 |
| smsCode | string | 是 | 6位数字验证码 |
**请求示例**
```json
{
"phone": "13800138000",
"smsCode": "406436"
}
```
**响应参数**
| 字段 | 类型 | 说明 |
|------|------|------|
| code | int | 状态码200=成功 |
| message | string | 描述信息 |
| data | object | 登录数据 |
| data.token | string | JWT Token后续接口需携带 |
| data.userId | long | 用户ID |
| data.username | string | 用户名 |
| data.nickname | string | 昵称 |
| data.avatar | string | 头像URL可为 null |
| data.phone | string | 手机号(脱敏,如 138****8000 |
**响应示例**
```json
{
"code": 200,
"message": "success",
"data": {
"token": "eyJhbGciOiJIUzM4NCJ9.eyJ0ZW5hbnRJZCI6OCwidXNlcm5hbWUiOiJkZW1vIiwic3ViIjoiOSIsImlhdCI6MTc3NTg4MjgwNywiZXhwIjoxNzc2NDg3NjA3fQ.xxx",
"userId": 9,
"username": "demo",
"nickname": "小明",
"avatar": "https://example.com/avatar.png",
"phone": "137****9302"
},
"timestamp": "2026-04-11T12:00:00",
"path": "/api/device/auth/login/sms"
}
```
**错误情况**
| code | 说明 |
|------|------|
| 404 | 该手机号未注册 |
| 403 | 账号已被禁用 |
| 400 | 验证码错误 |
| 400 | 验证码已过期 |
| 400 | 验证码不能为空 |
---
### 3. 用户作品列表
获取当前登录用户的创作作品列表(分页)。
```
GET /device/works
```
**请求头**
| 参数 | 值 | 必填 | 说明 |
|------|------|------|------|
| Authorization | Bearer {token} | 是 | 登录接口返回的 Token |
**请求参数Query**
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| page | int | 否 | 1 | 页码从1开始 |
| pageSize | int | 否 | 10 | 每页条数 |
| status | string | 否 | - | 筛选状态:`draft`/`unpublished`/`pending_review`/`published`/`rejected` |
| keyword | string | 否 | - | 标题关键词搜索 |
**请求示例**
```
GET /api/device/works?page=1&pageSize=10&status=unpublished&keyword=测试
```
**响应参数**
| 字段 | 类型 | 说明 |
|------|------|------|
| code | int | 状态码200=成功 |
| data | object | 分页数据 |
| data.list | array | 作品列表 |
| data.total | long | 总记录数 |
| data.page | long | 当前页码 |
| data.pageSize | long | 每页条数 |
**list 数组项字段**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | long | 作品ID本库主键 |
| remoteWorkId | string | 乐读派作品 ID用于调用下文 `GET/PUT /device/leai-works/{remoteWorkId}/work-form`;可能为 null |
| title | string | 作品标题 |
| coverUrl | string | 封面图URL可为 null |
| description | string | 作品描述,可为 null |
| status | string | 状态:`draft`(草稿)/ `unpublished`(待发布)/ `pending_review`(审核中)/ `published`(已发布)/ `rejected`(已拒绝) |
| authorName | string | 作者名称 |
| leaiStatus | int | AI创作进度`-1`=失败, `0`=初始化, `1`=排队中, `2`=处理中, `3`=完成, `4`=已编目, `5`=已配音 |
| pageCount | int | 绘本页数,可为 null |
| createTime | string | 创建时间,格式 `yyyy-MM-ddTHH:mm:ss` |
| modifyTime | string | 修改时间,格式 `yyyy-MM-ddTHH:mm:ss` |
列表项中的 `remoteWorkId` 与乐读派创作链路一致;编目/分页快照读写请使用 [§4 / §5](#4-查询乐读派作品表单)。
**响应示例**
```json
{
"code": 200,
"message": "success",
"data": {
"list": [
{
"id": 38,
"remoteWorkId": "2044624699115311104",
"title": "我的绘本",
"coverUrl": "https://oss.example.com/cover.png",
"description": "一个有趣的故事",
"status": "unpublished",
"authorName": "小明",
"leaiStatus": 5,
"pageCount": 6,
"createTime": "2026-04-10T17:07:00",
"modifyTime": "2026-04-10T17:10:53"
},
{
"id": 37,
"remoteWorkId": "2044624699115310999",
"title": "春天的故事",
"coverUrl": "https://oss.example.com/cover2.png",
"description": null,
"status": "published",
"authorName": "小红",
"leaiStatus": 5,
"pageCount": 6,
"createTime": "2026-04-10T16:53:17",
"modifyTime": "2026-04-10T16:58:54"
}
],
"total": 15,
"page": 1,
"pageSize": 10
}
}
```
---
### 4. 查询乐读派作品表单
获取本库中该乐读派作品的编目/分页快照(不经乐读派 B2 GET。**必须携带 Token**;仅可操作当前登录用户本人的作品。
```
GET /device/leai-works/{remoteWorkId}/work-form
```
**请求头**
| 参数 | 值 | 必填 | 说明 |
|------|------|------|------|
| Authorization | Bearer {token} | 是 | 登录接口返回的 Token |
**路径参数**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| remoteWorkId | string | 是 | 乐读派作品 ID可能为大整数建议按字符串传递URL 需编码) |
**请求示例**
```
GET /api/device/leai-works/2044624699115311104/work-form
```
**成功响应 `data` 字段说明**(与公众端 `GET /public/leai-works/{remoteWorkId}/work-form` 语义一致;设备端以结构化对象返回,字段名与下表一致)
| 字段 | 类型 | 说明 |
|------|------|------|
| workId | string | 与 remoteWorkId 一致 |
| status | int | 乐读派创作进度 `leai_status` |
| title | string | 标题,可为 null |
| author | string | 作者署名,可为 null |
| coverUrl | string | 封面 URL可为 null |
| subtitle | string | 副标题,可为 null |
| intro | string | 简介,可为 null |
| tags | array | 标签列表,元素类型由业务决定,可为 null |
| pageList | array | 分页快照,见下表 |
**`pageList` 数组项字段**
| 字段 | 类型 | 说明 |
|------|------|------|
| pageNum | int | 页码 |
| imageUrl | string | 页图 URL可为 null |
| text | string | 页文案,可为 null |
| audioUrl | string | 页音频 URL可为 null |
**响应示例**
```json
{
"code": 200,
"message": "success",
"data": {
"workId": "2044624699115311104",
"status": 5,
"title": "我的绘本",
"author": "小明",
"coverUrl": "https://oss.example.com/cover.png",
"subtitle": null,
"intro": "简介内容",
"tags": ["童话", "原创"],
"pageList": [
{
"pageNum": 1,
"imageUrl": "https://oss.example.com/p1.png",
"text": "从前有一座山",
"audioUrl": "https://oss.example.com/p1.mp3"
}
]
},
"timestamp": "2026-04-11T12:00:00",
"path": "/api/device/leai-works/2044624699115311104/work-form"
}
```
**错误情况**
| code | 说明 |
|------|------|
| 401 | 未登录或 Token 无效 |
| 404 | 作品不存在或无权操作(非本人) |
---
### 5. 保存乐读派作品表单
保存编目与分页快照至本库(不经乐读派 PUT。**必须携带 Token**;请求体非空。
```
PUT /device/leai-works/{remoteWorkId}/work-form
```
**请求头**
| 参数 | 值 | 必填 | 说明 |
|------|------|------|------|
| Authorization | Bearer {token} | 是 | 登录接口返回的 Token |
| Content-Type | application/json | 是 | JSON 请求体 |
**路径参数**:同 [§4](#4-查询乐读派作品表单)。
**请求体JSON**:字段均可选,但**至少需一项非空**;服务端将非 null 字段组装为内部 Map 再落库,与 [public-leai-work-form.md](./public-leai-work-form.md) 中 PUT 语义一致。发送 `{}` 或全部为 null 的等价体将返回 **400**`请求体不能为空`)。
| 字段 | 类型 | 说明 |
|------|------|------|
| author | string | 作者署名 |
| title | string | 标题 |
| subtitle | string | 副标题 |
| intro | string | 简介 |
| tags | array | 标签 |
| status | int | 乐读派进度,写入 `leai_status` |
| pageList | array | 分页快照,见下表 |
**`pageList` 数组项字段**
| 字段 | 类型 | 说明 |
|------|------|------|
| pageNum | int | 页码 |
| imageUrl | string | 页图 URL |
| text | string | 页文案 |
| audioUrl | string | 页音频 URL |
**请求示例**
```json
{
"title": "我的绘本",
"author": "小明",
"status": 4,
"pageList": [
{
"pageNum": 1,
"imageUrl": "https://oss.example.com/p1.png",
"text": "从前有一座山",
"audioUrl": "https://oss.example.com/p1.mp3"
}
]
}
```
**成功响应**`code=200``data` 通常为 null。
**错误情况**:同 §4另含参数校验失败或空请求体时 **400**
---
## 6. 通用错误码
所有接口统一响应格式:
```json
{
"code": 401,
"message": "未登录或 Token 已过期",
"timestamp": "2026-04-11T12:00:00",
"path": "/api/device/works"
}
```
| code | 说明 |
|------|------|
| 200 | 成功 |
| 400 | 请求参数错误 |
| 401 | 未登录或 Token 已过期 |
| 403 | 无权限访问 |
| 404 | 资源不存在 |
| 429 | 请求过于频繁(触发限流) |
| 500 | 服务器内部错误 |
---
## 调用流程
```
┌─────────────────────────────────────────────────────────┐
│ 终端设备调用流程 │
├─────────────────────────────────────────────────────────┤
│ │
│ 1. 发送验证码 POST /device/auth/sms/send │
│ └─ 参数: { phone } │
│ │
│ 2. 验证码登录 POST /device/auth/login/sms │
│ └─ 参数: { phone, smsCode } │
│ └─ 返回: token ← 保存到本地 │
│ │
│ 3. 作品列表 GET /device/works │
│ └─ Header: Authorization: Bearer {token} │
│ └─ 参数: page, pageSize, status(可选), keyword(可选) │
│ │
│ 4. 乐读派表单 GET/PUT /device/leai-works/{remoteWorkId}/work-form │
│ └─ 列表项中的 remoteWorkId 作为路径参数 │
│ └─ 用于编目/分页快照同步(与创作壳 work-form 一致) │
│ │
└─────────────────────────────────────────────────────────┘
```
**Token 有效期**: 7天604800秒过期后需重新登录获取。
**建议**:
- Token 存储在设备本地,每次启动时检查是否过期
- 过期后重新走 发送验证码 → 登录 流程
- 音频和图片资源使用返回的 URL 直接访问 OSS无需经过本服务