# 新项目 API 规格（/v1）

## 0. 通用约定

### 0.1 Base URL 与租户

- Base：`/v1`
- 多租户路径 `/t/:tenant_code/v1` 为后续规划，待统一改造后启用

### 0.2 认证

- 现实现：OTP 登录 + JWT，所有受保护接口需携带 `Authorization: Bearer <token>`
- Admin：同上（Bearer Token）

### 0.3 响应

- 成功：`200`（或 201/204），JSON
- 业务错误：`400`（含错误信息）
- 未登录：`401`
- 无权限：`403`
- 不存在：`404`

---

### 0.4 当前实现说明

- 当前端到端实现已切换为 OTP + JWT；以下 WeChat OAuth/H5 内容为历史规格，待后续统一重写

---

## 1. OTP 登录

### 1.1 发送验证码

`POST /auth/otp`

Body：
```json
{ "phone": "13800000000" }
```

### 1.2 登录/注册

`POST /auth/login`

Body：
```json
{ "phone": "13800000000", "otp": "1234" }
```

---

## 2. WeChat H5 内容与用户

### 2.1 曲谱列表（仅已发布）

`GET /posts`

Query：
- `page`（默认 1）
- `limit`（默认 10）
- `keyword`（可选）

Response（示例结构）：
```json
{
  "items": [
    {
      "id": 1,
      "title": "标题",
      "description": "简介",
      "price": 19900,
      "discount": 80,
      "views": 10,
      "likes": 0,
      "tags": ["tag"],
      "head_images": ["https://signed-url..."],
      "bought": false,
      "recharge_wechat": "联系微信（可选）"
    }
  ],
  "total": 123,
  "page": 1,
  "limit": 10
}
```

### 2.2 曲谱详情（仅已发布）

`GET /posts/:id/show`

Response：同 `PostItem`，额外含 `content`

### 2.3 获取播放 URL

`GET /posts/:id/play`

Response：
```json
{ "url": "https://signed-url..." }
```

规则：未购买返回 `metas.short=true` 的视频 URL；已购买返回 `metas.short=false` 的视频 URL。

### 2.4 我的已购

`GET /posts/mine`

Query：`page`、`limit`、`keyword`（可选）

Response：同分页结构

### 2.5 余额购买

`POST /posts/:id/buy`

Response（余额支付成功）：
- 可直接返回 `{ "ok": true }` 或返回订单信息（由你最终 UI/交互决定）

错误：
- 余额不足：`400`，message 建议为“余额不足，请联系管理员充值”
- 已购买：`400`

### 2.6 用户资料

`GET /users/profile`

Response：
```json
{ "id": 1001, "created_at": "2025-01-01T00:00:00Z", "username": "xx", "avatar": "url", "balance": 10000 }
```

### 2.7 修改用户名

`PUT /users/username`

Body：
```json
{ "username": "新昵称" }
```

约束：trim 后不能为空；最大 12 个字符（按 rune 计）。

### 2.8 JS-SDK 配置

`GET /wechats/js-sdk?url=<current_page_url_without_hash>`

Response：JS-SDK 签名数据（结构按前端 `weixin-js-sdk` 需要输出）

---

## 3. Admin（租户后台）

### 3.1 登录

`POST /admin/auth`

Body：
```json
{ "username": "admin", "password": "******" }
```

Response：
```json
{ "token": "..." }
```

### 3.2 仪表盘统计

`GET /admin/statistics`

Response：
```json
{
  "post_draft": 0,
  "post_published": 0,
  "media": 0,
  "order": 0,
  "user": 0,
  "amount": 0
}
```

### 3.3 媒体库

`GET /admin/medias?page=&limit=&keyword=`

`GET /admin/medias/:id`：302 跳转到 OSS 签名 URL

`DELETE /admin/medias/:id`：删除 OSS 对象并软删/删 DB 记录（最终由你决定）

### 3.4 上传（预签名）

`GET /admin/uploads/pre-uploaded-check/:md5.:ext?mime=<mime>`

Response：
```json
{ "exists": false, "pre_sign": { "...": "..." } }
```

说明：
- `md5` 在租户内去重
- OSS Key：`quyun/<tenant_uuid>/<md5>.<ext>`

`POST /admin/uploads/post-uploaded-action`

Body：
```json
{ "originalName": "a.mp4", "md5": "...", "mimeType": "video/mp4", "size": 123 }
```

### 3.5 曲谱管理

`GET /admin/posts?page=&limit=&keyword=`

`POST /admin/posts`、`PUT /admin/posts/:id` Body（示例）：
```json
{
  "title": "标题",
  "head_images": [1,2,3],
  "price": 19900,
  "discount": 80,
  "introduction": "简介",
  "content": "正文",
  "status": 1,
  "medias": [10,11,12]
}
```

`GET /admin/posts/:id`：返回曲谱 + medias 列表

`DELETE /admin/posts/:id`

`POST /admin/posts/:id/send-to/:userId`：赠送曲谱（写入授权记录）

### 3.6 用户管理

`GET /admin/users?page=&limit=&keyword=`

`GET /admin/users/:id`

`GET /admin/users/:id/articles?page=&limit=`

`POST /admin/users/:id/balance`

Body：
```json
{ "balance": 10000 }
```

### 3.7 订单管理

`GET /admin/orders?page=&limit=&order_number=&user_id=`

`POST /admin/orders/:id/refund`：仅余额订单可退款
