重构 monorepo 并完善网页端订阅与首页体验

- 迁移为 frontend-web、frontend-electron、backend-web 与 docker 部署结构
- 网页端:订阅门禁二次弹窗、套餐/支付组件化、顶栏分组对齐
- 首页:最近文件与模板库布局优化,缩略图对齐,下载与删除操作
- 新增管理后台、支付与云端文件 API,更新 README 与项目规范

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
24kycj
2026-06-08 18:17:39 +08:00
parent 5814b7bc0e
commit 88c6ce8ccc
511 changed files with 189528 additions and 22804 deletions
+201
View File
@@ -0,0 +1,201 @@
# 列表分页 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 /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` | 50legacy | 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/plans/me` | 会员信息 + `recent_orders`(默认 8 条,非翻页) |
| `GET /api/v1/settings` | 扁平 key-value 对象,非 `items` 数组 |
| `GET /api/v1/soon-models` | manifest 内容 |
---
## 前端约定
### 管理后台(`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/totalfiles 兼容 limit/offsetpay/orders 分页 |