341 lines
9.1 KiB
Markdown
341 lines
9.1 KiB
Markdown
# API 使用说明(中文)
|
||
|
||
## Base URL
|
||
|
||
- 后端:`http://localhost:8080`
|
||
- Swagger(推荐看这个,字段更全):`http://localhost:8081`(加载 `docs/openapi.yaml`)
|
||
|
||
## 统一响应结构
|
||
|
||
后端所有接口统一返回:
|
||
```json
|
||
{ "code": 0, "message": "ok", "data": {}, "meta": {} }
|
||
```
|
||
|
||
- `code=0` 表示成功
|
||
- `code!=0` 表示失败(通常等于 HTTP 状态码)
|
||
|
||
## 必须携带的请求头
|
||
|
||
本项目所有 `/api/**` 接口都需要 APIKey:
|
||
- `X-API-Key: <你的apikey>`
|
||
|
||
管理端接口(`/api/admin/**`,除登录外)还需要管理员 JWT:
|
||
- `Authorization: Bearer <admin_token>`
|
||
|
||
用户端需要登录的接口(`/api/user/**` 的部分接口)需要用户 JWT:
|
||
- `Authorization: Bearer <user_token>`
|
||
|
||
默认开发环境(可在 `backend/.env` 修改):
|
||
- `API_KEY=dev-api-key-change-me`
|
||
|
||
## PowerShell / curl 提示(Windows)
|
||
|
||
- Windows PowerShell 里的 `curl` 可能是 `Invoke-WebRequest` 的别名;建议用 `curl.exe` 或 `Invoke-RestMethod`。
|
||
|
||
## 验证码(Captcha)
|
||
|
||
用户注册/登录 **必须先获取验证码**,再把 `captcha_id` + `captcha_code` 带到接口里。
|
||
|
||
### 获取验证码(SVG)
|
||
|
||
`GET /api/captcha/new`
|
||
|
||
```bash
|
||
curl.exe "http://localhost:8080/api/captcha/new" -H "X-API-Key: dev-api-key-change-me"
|
||
```
|
||
|
||
返回示例:
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "ok",
|
||
"data": {
|
||
"captcha_id": "c180df303849ea6dc75c670c4f1062b0",
|
||
"svg": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><svg ...>XHSXY</svg>"
|
||
}
|
||
}
|
||
```
|
||
|
||
说明:
|
||
- `captcha_id` 有效期 5 分钟
|
||
- 校验成功后删除(一次性使用)
|
||
- `svg` 是字符串:前端可用 `v-html` 渲染,或转成 `data:image/svg+xml` 显示在 `<img>`
|
||
|
||
PowerShell 测试(从 SVG 中提取验证码文本,仅用于本地调试):
|
||
```powershell
|
||
$apiKey='dev-api-key-change-me'
|
||
$cap = Invoke-RestMethod -Method Get -Uri http://localhost:8080/api/captcha/new -Headers @{"X-API-Key"=$apiKey}
|
||
$id = $cap.data.captcha_id
|
||
$svg = $cap.data.svg
|
||
$code = [regex]::Match($svg,'>([0-9A-Z]{5})<').Groups[1].Value
|
||
```
|
||
|
||
## 用户侧(Web/小程序)
|
||
|
||
### 用户注册
|
||
|
||
`POST /api/user/register`
|
||
|
||
请求示例:
|
||
```bash
|
||
curl.exe -X POST "http://localhost:8080/api/user/register" `
|
||
-H "X-API-Key: dev-api-key-change-me" `
|
||
-H "Content-Type: application/json" `
|
||
-d "{\"username\":\"u1\",\"password\":\"pass123456\",\"captcha_id\":\"$CAPTCHA_ID\",\"captcha_code\":\"$CAPTCHA_CODE\"}"
|
||
```
|
||
|
||
请求结构体(JSON):
|
||
```json
|
||
{
|
||
"username": "u1",
|
||
"password": "pass123456",
|
||
"captcha_id": "xxxx",
|
||
"captcha_code": "ABCDE"
|
||
}
|
||
```
|
||
|
||
返回:
|
||
- `data.token`:用户 JWT
|
||
- `data.user`:用户信息
|
||
|
||
### 用户登录
|
||
|
||
`POST /api/user/login`
|
||
|
||
请求结构体(JSON):
|
||
```json
|
||
{
|
||
"username": "u1",
|
||
"password": "pass123456",
|
||
"captcha_id": "xxxx",
|
||
"captcha_code": "ABCDE"
|
||
}
|
||
```
|
||
|
||
返回:
|
||
- `data.token`:用户 JWT
|
||
- `data.user`:用户信息(简化字段)
|
||
|
||
### 当前用户
|
||
|
||
`GET /api/user/me`(需要 `Authorization: Bearer <user_token>`)
|
||
|
||
### 我的评论记录
|
||
|
||
`GET /api/user/reviews?page=1&page_size=20`(需要 `Authorization: Bearer <user_token>`)
|
||
|
||
### 提交评论(进入待审核)
|
||
|
||
`POST /api/user/stores/:id/reviews`
|
||
|
||
图片上传说明:
|
||
- 评论的 `image_urls` 需要先上传拿到图片 URL
|
||
- 用户上传接口:`POST /api/user/upload`(`multipart/form-data`,字段名 `file`)
|
||
|
||
请求结构体(JSON):
|
||
```json
|
||
{
|
||
"rating": 5,
|
||
"content": "太好吃了",
|
||
"image_urls": ["http://localhost:8080/static/upload/2025/12/xx.jpg"],
|
||
"recommend_dishes": [
|
||
{ "name": "锅包肉", "image_url": "http://...", "like": true }
|
||
]
|
||
}
|
||
```
|
||
|
||
返回示例:
|
||
```json
|
||
{ "code": 0, "message": "ok", "data": { "id": 1, "status": "pending" } }
|
||
```
|
||
|
||
### 点赞店铺(toggle)
|
||
|
||
`POST /api/user/stores/:id/like`
|
||
|
||
返回示例:
|
||
```json
|
||
{ "code": 0, "message": "ok", "data": { "liked": true } }
|
||
```
|
||
|
||
### 店铺搜索 / 热榜(公开)
|
||
|
||
- 搜索:`GET /api/stores/search?keyword=锅包肉&page=1&page_size=20`(会累积热度)
|
||
- 热榜:`GET /api/stores/hot?by=hotness&limit=20`
|
||
|
||
### 公共读取接口(前端可直接调用)
|
||
|
||
- 分类列表:`GET /api/categories`(只返回 enabled=true)
|
||
- 店铺列表:`GET /api/stores?page=1&page_size=20&category_id=1&keyword=xx`(只返回 active)
|
||
- 店铺详情:`GET /api/stores/:id`(只返回 active)
|
||
- 店铺评论:`GET /api/stores/:id/reviews?page=1&page_size=20`(只返回 approved)
|
||
- 店铺排行:`GET /api/rankings/stores?by=hotness&page=1&page_size=20`
|
||
|
||
## 商家入驻(公开提交)
|
||
|
||
`POST /api/merchant/apply`
|
||
|
||
请求结构体(JSON):
|
||
```json
|
||
{
|
||
"store_name": "示例店铺",
|
||
"category_id": 1,
|
||
"address": "哈尔滨市xx路",
|
||
"open_hours": "10:00-22:00",
|
||
"phone": "13000000000",
|
||
"cover_url": "",
|
||
"image_urls": [],
|
||
"description": "商家描述",
|
||
"contact_name": "张三",
|
||
"contact_phone": "13000000000"
|
||
}
|
||
```
|
||
|
||
返回示例:
|
||
```json
|
||
{ "code": 0, "message": "ok", "data": { "id": 1, "status": "pending" } }
|
||
```
|
||
|
||
## 管理后台(Admin)
|
||
|
||
### 管理员登录
|
||
|
||
`POST /api/admin/login`
|
||
|
||
说明:
|
||
- 管理员登录也需要验证码(防止暴力破解)
|
||
- 先调用 `GET /api/captcha/new` 获取 `captcha_id` + `svg`,再提交到登录接口
|
||
|
||
```bash
|
||
curl.exe -X POST "http://localhost:8080/api/admin/login" `
|
||
-H "X-API-Key: dev-api-key-change-me" `
|
||
-H "Content-Type: application/json" `
|
||
-d "{\"username\":\"admin\",\"password\":\"admin123456\",\"captcha_id\":\"$CAPTCHA_ID\",\"captcha_code\":\"$CAPTCHA_CODE\"}"
|
||
```
|
||
|
||
返回:
|
||
- `data.token`:管理员 JWT
|
||
|
||
### CORS 跨域设置(可视化配置)
|
||
|
||
- 获取:`GET /api/admin/settings/cors`
|
||
- 保存:`PUT /api/admin/settings/cors`
|
||
|
||
保存 payload:
|
||
```json
|
||
{ "origins": ["http://localhost:5173", "https://admin.example.com"] }
|
||
```
|
||
|
||
### 上传图片
|
||
|
||
`POST /api/admin/upload`(`multipart/form-data`,字段名 `file`)
|
||
|
||
```bash
|
||
curl.exe -X POST "http://localhost:8080/api/admin/upload" `
|
||
-H "X-API-Key: dev-api-key-change-me" `
|
||
-H "Authorization: Bearer <admin_token>" `
|
||
-F "file=@./test.jpg"
|
||
```
|
||
|
||
返回:
|
||
- `data.url`:可访问 URL(例如 `http://localhost:8080/static/upload/2025/12/xx.jpg`)
|
||
|
||
### 用户上传图片(用于评论)
|
||
|
||
`POST /api/user/upload`(`multipart/form-data`,字段名 `file`,需要用户 JWT)
|
||
|
||
```bash
|
||
curl.exe -X POST "http://localhost:8080/api/user/upload" `
|
||
-H "X-API-Key: dev-api-key-change-me" `
|
||
-H "Authorization: Bearer <user_token>" `
|
||
-F "file=@./test.jpg"
|
||
```
|
||
|
||
### 分类管理
|
||
|
||
- 列表:`GET /api/admin/categories?page=1&page_size=20&keyword=xxx`
|
||
- 新增:`POST /api/admin/categories`
|
||
- 编辑:`PUT /api/admin/categories/:id`
|
||
- 删除:`DELETE /api/admin/categories/:id`
|
||
|
||
新增/编辑 payload:
|
||
```json
|
||
{ "name": "烧烤", "icon_url": "", "sort_order": 10, "enabled": true }
|
||
```
|
||
|
||
### 店铺管理
|
||
|
||
- 列表:`GET /api/admin/stores?page=1&page_size=20&keyword=xx&status=active&category_id=1`
|
||
- 详情:`GET /api/admin/stores/:id`
|
||
- 新增:`POST /api/admin/stores`
|
||
- 编辑:`PUT /api/admin/stores/:id`
|
||
- 上下架:`PATCH /api/admin/stores/:id/status`(`{"status":"active|inactive"}`)
|
||
- 删除:`DELETE /api/admin/stores/:id`
|
||
|
||
新增/编辑 payload:
|
||
```json
|
||
{
|
||
"name": "示例店铺",
|
||
"category_id": 1,
|
||
"address": "哈尔滨市xx路",
|
||
"open_hours": "10:00-22:00",
|
||
"phone": "13000000000",
|
||
"cover_url": "http://localhost:8080/static/upload/2025/12/cover.jpg",
|
||
"description": "描述",
|
||
"status": "active",
|
||
"images": [{ "url": "http://...", "sort_order": 0 }],
|
||
"dishes": [{ "name": "锅包肉", "description": "必点", "image_url": "http://...", "sort_order": 0 }]
|
||
}
|
||
```
|
||
|
||
### 评论管理(审核/删除)
|
||
|
||
- 列表:`GET /api/admin/reviews?page=1&page_size=20&status=pending&store_id=1&user_id=2`
|
||
- 审核:`PATCH /api/admin/reviews/:id/status`(`{"status":"pending|approved|blocked"}`)
|
||
- 删除:`DELETE /api/admin/reviews/:id`
|
||
|
||
### 商家入驻审核
|
||
|
||
- 列表:`GET /api/admin/merchant/applications?status=pending&page=1&page_size=20`
|
||
- 审核:`PATCH /api/admin/merchant/applications/:id/review`
|
||
|
||
审核 payload:
|
||
- 通过:`{ "action": "approve" }`
|
||
- 拒绝:`{ "action": "reject", "reject_reason": "资料不完整" }`
|
||
|
||
### 排行管理
|
||
|
||
- 查看排行:`GET /api/admin/rankings/stores?by=hotness&page=1&page_size=20`
|
||
- `by=hotness|likes|search|reviews`
|
||
- 重算综合分:`POST /api/admin/rankings/stores/recalc`
|
||
|
||
### APIKey 管理
|
||
|
||
- 列表:`GET /api/admin/apikeys?page=1&page_size=20`
|
||
- 创建:`POST /api/admin/apikeys`(创建成功会返回一次性明文 `data.key`,请立即保存)
|
||
- 撤销:`PATCH /api/admin/apikeys/:id/revoke`
|
||
|
||
### 用户管理(管理端)
|
||
|
||
- 列表:`GET /api/admin/users?keyword=xx&status=active&page=1&page_size=20`
|
||
- 详情:`GET /api/admin/users/:id`
|
||
- 启用/禁用:`PATCH /api/admin/users/:id/status`(`{"status":"active|disabled"}`)
|
||
|
||
### 管理员管理
|
||
|
||
- 列表:`GET /api/admin/admins?keyword=xx&page=1&page_size=20`
|
||
- 新增:`POST /api/admin/admins`
|
||
- 重置密码:`PATCH /api/admin/admins/:id/password`
|
||
- 启用/禁用:`PATCH /api/admin/admins/:id/enabled`
|
||
|
||
新增 payload:
|
||
```json
|
||
{ "username": "ops", "password": "StrongPass123", "enabled": true }
|
||
```
|
||
|
||
## OpenAPI
|
||
|
||
- 文件:`docs/openapi.yaml`
|
||
- Swagger UI:`http://localhost:8081`
|