# 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 ` 用户端需要登录的接口(`/api/user/**` 的部分接口)需要用户 JWT: - `Authorization: Bearer ` 默认开发环境(可在 `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": "XHSXY" } } ``` 说明: - `captcha_id` 有效期 5 分钟 - 校验成功后删除(一次性使用) - `svg` 是字符串:前端可用 `v-html` 渲染,或转成 `data:image/svg+xml` 显示在 `` 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 `) ### 我的评论记录 `GET /api/user/reviews?page=1&page_size=20`(需要 `Authorization: Bearer `) ### 提交评论(进入待审核) `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 " ` -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 " ` -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`