4ce4486b26
新增 IndexedDB 与最近文件 L1 缓存、云保存/打开链路;首页支持下载与清空本地缓存;修复清空 storage 后语言初始化报错;优化 design2 背景加载与侧栏标签样式;完善会员激活/支付弹层样式;后端补充文件缩略图字段与 thumb 接口。 Co-authored-by: Cursor <cursoragent@cursor.com>
242 lines
7.5 KiB
Markdown
242 lines
7.5 KiB
Markdown
# 列表分页 API 契约
|
||
|
||
本文描述 `backend-web` 公开端(`/api/v1`)与管理端(`/api/admin`)列表接口的分页约定。实现以仓库内 PHP 控制器为准。
|
||
|
||
## 通用响应包装
|
||
|
||
所有 JSON 接口统一:
|
||
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"data": { }
|
||
}
|
||
```
|
||
|
||
失败时 `ok: false`,含 `error`(机器码)与 `message`(人类可读文案)。
|
||
|
||
## 推荐分页形态(page / size / total)
|
||
|
||
**新接口与前端管理列表优先使用此形态。**
|
||
|
||
### 请求 Query
|
||
|
||
| 参数 | 类型 | 默认 | 上限 | 说明 |
|
||
|------|------|------|------|------|
|
||
| `page` | int | `1` | — | 从 1 开始 |
|
||
| `size` | int | 见各接口 | 见各接口 | 每页条数 |
|
||
|
||
### 响应 `data`
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `items` | array | 当前页记录 |
|
||
| `total` | int | 符合条件的总条数(用于算总页数) |
|
||
| `page` | int | 当前页码(回显) |
|
||
| `size` | int | 当前每页条数(回显) |
|
||
|
||
总页数:`ceil(total / size)`,`total === 0` 时视为 0 条、1 页。
|
||
|
||
### 示例
|
||
|
||
```http
|
||
GET /api/admin/users?page=2&size=20&q=test%40local.test
|
||
Authorization: Bearer <admin_token>
|
||
```
|
||
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"data": {
|
||
"items": [ { "id": 1, "email": "..." } ],
|
||
"total": 42,
|
||
"page": 2,
|
||
"size": 20
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 管理端分页列表(`/api/admin`)
|
||
|
||
需管理员 JWT(`role=admin`)。默认 `size` 与上限见下表。
|
||
|
||
| 方法 | 路径 | 默认 size | size 上限 | 额外筛选 Query |
|
||
|------|------|-----------|-----------|----------------|
|
||
| GET | `/api/admin/users` | 20 | 200 | `q` 邮箱模糊 |
|
||
| GET | `/api/admin/orders` | 20 | 200 | `q` 订单号或邮箱;`status` pending/paid/cancelled/refunded;`refund_status` none/pending/approved/rejected;`channel` alipay/wechat;`from`/`to` 日期 YYYY-MM-DD |
|
||
| GET | `/api/admin/audits` | 50 | 200 | `q` 操作/目标/管理员邮箱;`action` 精确操作码;`from`/`to` 日期 |
|
||
|
||
实现参考:
|
||
|
||
- `backend-web/src/Admin/Controllers/UsersController.php`
|
||
- `backend-web/src/Admin/Controllers/OrdersController.php`
|
||
- `backend-web/src/Admin/Controllers/AuditsController.php`
|
||
|
||
### 管理端全量列表(无分页)
|
||
|
||
以下接口一次返回全部 `items`,数据量预期较小:
|
||
|
||
| 路径 | 说明 |
|
||
|------|------|
|
||
| `GET /api/admin/plans` | 套餐配置 |
|
||
| `GET/POST /api/admin/templates`、`PUT/DELETE /api/admin/templates/{id}` | 模板库 CRUD |
|
||
| `GET /api/admin/settings` | 系统键值 |
|
||
| `GET /api/admin/payment/status` | PEM 文件元数据 |
|
||
|
||
### 管理端固定条数嵌套列表
|
||
|
||
| 来源 | 条数 | 说明 |
|
||
|------|------|------|
|
||
| `GET /api/admin/stats` → `recent_orders` | 5 | 仪表盘最近订单,非翻页接口 |
|
||
| `GET /api/admin/users/{id}` → `recent_orders` | 5 | 用户详情内嵌 |
|
||
|
||
---
|
||
|
||
## 公开端分页列表(`/api/v1`)
|
||
|
||
需用户 JWT(除 plans 列表可匿名,见各控制器)。
|
||
|
||
| 方法 | 路径 | 默认 size | size 上限 | 分页参数 | 响应 |
|
||
|------|------|-----------|-----------|----------|------|
|
||
| GET | `/api/v1/files` | 50(legacy) | 200 | **推荐** `page`+`size`;**兼容** `limit`+`offset` | 见下文 |
|
||
| GET | `/api/v1/pay/orders` | 8 | 50 | `page`+`size` | page 形态 |
|
||
|
||
实现参考:
|
||
|
||
- `backend-web/src/Controllers/FileController.php`
|
||
- `backend-web/src/Controllers/PayController.php`
|
||
- `backend-web/src/Services/MembershipService.php`(`listOrders`)
|
||
|
||
### `GET /api/v1/files` 双模式
|
||
|
||
**推荐(page 形态)** — 传 `page`≥1 时生效:
|
||
|
||
```http
|
||
GET /api/v1/files?page=1&size=12
|
||
```
|
||
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"data": {
|
||
"items": [ { "id": 1, "name": "design.soon", "size": 1024, "version": 1 } ],
|
||
"total": 25,
|
||
"page": 1,
|
||
"size": 12
|
||
}
|
||
}
|
||
```
|
||
|
||
**兼容(offset 形态)** — 未传 `page` 或 `page=0` 时:
|
||
|
||
```http
|
||
GET /api/v1/files?limit=50&offset=0
|
||
```
|
||
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"data": {
|
||
"items": [ ],
|
||
"total": 25,
|
||
"limit": 50,
|
||
"offset": 0
|
||
}
|
||
}
|
||
```
|
||
|
||
两种形态均含 `total`。新前端(首页文件列表、管理端)应使用 `page`+`size`。
|
||
|
||
### `GET /api/v1/pay/orders`
|
||
|
||
会员中心订单历史,默认每页 8 条:
|
||
|
||
```http
|
||
GET /api/v1/pay/orders?page=1&size=8
|
||
```
|
||
|
||
### 公开端全量 / 非标准列表
|
||
|
||
| 路径 | 形态 |
|
||
|------|------|
|
||
| `GET /api/v1/plans` | `{ items: [...] }` 全量活跃套餐 |
|
||
| `GET /api/v1/auth/me` | 当前用户 + 会员摘要(`is_member` / `tier` / `name`) |
|
||
| `GET /api/v1/plans/me` | 完整会员配额信息(云端用量等,按需调用) |
|
||
| `GET /api/v1/settings` | 扁平 key-value 对象,非 `items` 数组 |
|
||
| `GET /api/v1/templates` | 首页模板列表(仅 `id/name/type/updated_at`;缩略图按需拉取) |
|
||
| `GET /api/v1/templates/{id}` | 模板 JSON 数据(门户标准读取端点,见下) |
|
||
| `GET /api/v1/templates/{id}/thumb` | 模板缩略图(从 `.soon` 内 `frontDisplayPic` 提取) |
|
||
| `GET /api/v1/templates/{id}/file` | 裸 `.soon` 流(`Cache-Control: max-age=86400`);门户读缓存首选 |
|
||
| `GET /api/v1/files/{id}/thumb` | 云文件缩略图(需登录;从 `.soon` 内 `frontDisplayPic` 提取) |
|
||
| `GET /api/v1/soon-models` | 兼容别名,同 `GET /api/v1/templates` |
|
||
|
||
#### `GET /api/v1/templates/{id}`(门户读取模板数据)
|
||
|
||
与 `GET /api/v1/files/{id}` 对齐,返回 JSON 包装,**非**裸文件流:
|
||
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"data": {
|
||
"id": 1,
|
||
"name": "示例模版",
|
||
"type": 1,
|
||
"updated_at": "2026-06-09 00:23:29",
|
||
"json": "{...}"
|
||
}
|
||
}
|
||
```
|
||
|
||
- `data.json` 为 **字符串**(与 `files/{id}` 一致),前端 `JSON.parse(data.json)` 后加载画布
|
||
- 公开接口,无需登录
|
||
|
||
### Web 虚拟 key 前缀(门户设计页)
|
||
|
||
| 前缀 | 含义 | readJsonFile | 保存 writeFile |
|
||
|------|------|--------------|----------------|
|
||
| `soondesign_file:{id}:v{ver}` | 云端已登记文件 | `GET /files/{id}` | `PUT /files/{id}` |
|
||
| `soondesign_template:{id}` | 云端模板(只读源) | `GET /templates/{id}/file` | `POST /files`(首次保存新建) |
|
||
| `soondesign_session:...` | 本地/临时会话 | sessionStorage | 已登录 `POST /files`;未登录写 session |
|
||
|
||
- **保存/打开**走 JSON API;**仅**首页「下载」走 `GET /files/{id}/download` 落盘 `.soon`
|
||
- 门户**读缓存**与最近文件本地优先策略见 [`WEB-LOCAL-CACHE.md`](WEB-LOCAL-CACHE.md);模板首次加载推荐 `GET /templates/{id}/file`(流式 `.soon`,避免 `GET /templates/{id}` 二次包装)
|
||
|
||
---
|
||
|
||
## 前端约定
|
||
|
||
### 管理后台(`frontend-web/pages/admin`)
|
||
|
||
- 分页状态:`AdminState`(`users` / `orders` / `audits` 的 `page`、`size` 及筛选字段)
|
||
- 分页 UI:`AdminPager` + `AdminUi.pagerHtml` / `bindPager`
|
||
- 请求:相对 admin base 的路径,如 `users?page=1&size=20`
|
||
|
||
### 门户 / 会员 / 首页
|
||
|
||
| 页面 | 接口 | 默认 size |
|
||
|------|------|-----------|
|
||
| 会员订单 | `GET /api/v1/pay/orders` | 8 |
|
||
| 首页云端文件 | `GET /api/v1/files?page=&size=` | 12 |
|
||
|
||
---
|
||
|
||
## 新增列表接口检查清单
|
||
|
||
1. 响应是否包含 `items` + `total`?
|
||
2. 是否使用 `page`(从 1)+ `size`,并在 `data` 中回显?
|
||
3. `size` 是否有合理默认值与上限(建议上限 200,管理端;用户订单建议 50)?
|
||
4. 筛选参数是否与分页独立(翻页时保留筛选)?
|
||
5. 是否在本文档「管理端/公开端」表中登记?
|
||
|
||
---
|
||
|
||
## 变更记录
|
||
|
||
| 日期 | 说明 |
|
||
|------|------|
|
||
| 2026-06-08 | 初版:统一 page/size/total;files 兼容 limit/offset;pay/orders 分页 |
|
||
| 2026-06-08 | 新增 GET /templates/{id} JSON 契约;Web 虚拟 key 前缀;/file 标 legacy |
|
||
| 2026-06-08 | 新增 GET /files/{id}/thumb;files list 增 `has_thumb`;模板 /file 长缓存 |
|