1257 lines
32 KiB
YAML
1257 lines
32 KiB
YAML
openapi: 3.0.3
|
||
info:
|
||
title: 哈尔滨美食地图 API
|
||
version: 0.2.0
|
||
description: |
|
||
统一约定:
|
||
- 除 `/healthz` 外,所有 `/api/**` 接口都必须携带 `X-API-Key`
|
||
- 管理端 `/api/admin/**`(除登录外)还必须携带 `Authorization: Bearer <admin_token>`
|
||
- 用户端 `/api/user/**`(需要登录的接口)必须携带 `Authorization: Bearer <user_token>`
|
||
servers:
|
||
- url: http://localhost:8080
|
||
|
||
tags:
|
||
- name: Health
|
||
description: 健康检查
|
||
- name: Captcha
|
||
description: 验证码
|
||
- name: AdminAuth
|
||
description: 管理员登录与身份
|
||
- name: Settings
|
||
description: 系统设置(CORS)
|
||
- name: APIKeys
|
||
description: APIKey 管理
|
||
- name: Merchant
|
||
description: 商家入驻与审核
|
||
- name: Categories
|
||
description: 分类管理
|
||
- name: Stores
|
||
description: 店铺管理与搜索/热榜
|
||
- name: Reviews
|
||
description: 评论管理与用户发评
|
||
- name: Users
|
||
description: 用户注册/登录/信息
|
||
- name: Rankings
|
||
description: 排行(管理端)
|
||
- name: Upload
|
||
description: 上传(管理端)
|
||
|
||
components:
|
||
securitySchemes:
|
||
ApiKeyAuth:
|
||
type: apiKey
|
||
in: header
|
||
name: X-API-Key
|
||
BearerAuth:
|
||
type: http
|
||
scheme: bearer
|
||
|
||
schemas:
|
||
RespBase:
|
||
type: object
|
||
properties:
|
||
code:
|
||
type: integer
|
||
description: 0 表示成功;非 0 通常等于 HTTP 状态码
|
||
message:
|
||
type: string
|
||
data: {}
|
||
meta: {}
|
||
required: [code, message]
|
||
|
||
PaginationMeta:
|
||
type: object
|
||
properties:
|
||
page: { type: integer, example: 1 }
|
||
page_size: { type: integer, example: 20 }
|
||
total: { type: integer, example: 123 }
|
||
total_page: { type: integer, example: 7 }
|
||
|
||
AdminUser:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, example: 1 }
|
||
username: { type: string, example: admin }
|
||
role: { type: string, example: admin }
|
||
enabled: { type: boolean, example: true }
|
||
created_at: { type: string, format: date-time }
|
||
updated_at: { type: string, format: date-time }
|
||
|
||
User:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, example: 7 }
|
||
username: { type: string, example: tiedanzi888 }
|
||
status: { type: string, example: active }
|
||
created_at: { type: string, format: date-time }
|
||
updated_at: { type: string, format: date-time }
|
||
|
||
Category:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, example: 1 }
|
||
name: { type: string, example: 烧烤 }
|
||
icon_url: { type: string, example: "http://localhost:8080/static/upload/2025/12/xx.png" }
|
||
sort_order: { type: integer, example: 10 }
|
||
enabled: { type: boolean, example: true }
|
||
created_at: { type: string, format: date-time }
|
||
updated_at: { type: string, format: date-time }
|
||
|
||
StoreImage:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
url: { type: string, example: "http://localhost:8080/static/upload/2025/12/xx.jpg" }
|
||
sort_order: { type: integer, example: 0 }
|
||
|
||
SignatureDish:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
name: { type: string, example: 锅包肉 }
|
||
description: { type: string, example: 必点 }
|
||
image_url: { type: string, example: "http://localhost:8080/static/upload/2025/12/dish.jpg" }
|
||
sort_order: { type: integer, example: 0 }
|
||
|
||
Store:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, example: 1 }
|
||
name: { type: string, example: 示例店铺 }
|
||
category_id: { type: integer, example: 1 }
|
||
category:
|
||
$ref: "#/components/schemas/Category"
|
||
address: { type: string, example: 哈尔滨市道里区xxx路 }
|
||
open_hours: { type: string, example: "10:00-22:00" }
|
||
phone: { type: string, example: "13000000000" }
|
||
cover_url: { type: string, example: "http://localhost:8080/static/upload/2025/12/cover.jpg" }
|
||
description: { type: string, example: 店铺描述 }
|
||
status: { type: string, example: active }
|
||
images:
|
||
type: array
|
||
items: { $ref: "#/components/schemas/StoreImage" }
|
||
dishes:
|
||
type: array
|
||
items: { $ref: "#/components/schemas/SignatureDish" }
|
||
created_at: { type: string, format: date-time }
|
||
updated_at: { type: string, format: date-time }
|
||
|
||
Review:
|
||
type: object
|
||
properties:
|
||
id: { type: integer, example: 1 }
|
||
store_id: { type: integer, example: 1 }
|
||
store:
|
||
$ref: "#/components/schemas/Store"
|
||
user_id: { type: integer, nullable: true }
|
||
user_name: { type: string, example: tiedanzi888 }
|
||
rating: { type: integer, example: 5 }
|
||
content: { type: string, example: 太好吃了 }
|
||
image_urls:
|
||
type: array
|
||
items: { type: string }
|
||
recommend_dishes:
|
||
type: array
|
||
items:
|
||
type: object
|
||
additionalProperties: true
|
||
status: { type: string, example: pending }
|
||
created_at: { type: string, format: date-time }
|
||
updated_at: { type: string, format: date-time }
|
||
|
||
MerchantApplication:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
store_name: { type: string }
|
||
category_id: { type: integer }
|
||
address: { type: string }
|
||
open_hours: { type: string }
|
||
phone: { type: string }
|
||
cover_url: { type: string }
|
||
image_urls:
|
||
type: array
|
||
items: { type: string }
|
||
description: { type: string }
|
||
contact_name: { type: string }
|
||
contact_phone: { type: string }
|
||
status: { type: string, example: pending }
|
||
reject_reason: { type: string }
|
||
reviewed_at: { type: string, format: date-time, nullable: true }
|
||
reviewer_id: { type: integer, nullable: true }
|
||
created_at: { type: string, format: date-time }
|
||
updated_at: { type: string, format: date-time }
|
||
|
||
APIKeyItem:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
name: { type: string }
|
||
prefix: { type: string }
|
||
status: { type: string, example: active }
|
||
last_used_at: { type: string, format: date-time, nullable: true }
|
||
revoked_at: { type: string, format: date-time, nullable: true }
|
||
created_at: { type: string, format: date-time }
|
||
updated_at: { type: string, format: date-time }
|
||
|
||
# ---- Requests ----
|
||
CaptchaNewData:
|
||
type: object
|
||
properties:
|
||
captcha_id: { type: string, example: c180df303849ea6dc75c670c4f1062b0 }
|
||
svg: { type: string, description: SVG 字符串(可直接渲染) }
|
||
required: [captcha_id, svg]
|
||
|
||
AdminLoginReq:
|
||
type: object
|
||
required: [username, password, captcha_id, captcha_code]
|
||
properties:
|
||
username: { type: string, example: admin }
|
||
password: { type: string, example: admin123456 }
|
||
captcha_id: { type: string }
|
||
captcha_code: { type: string, example: XHSXY }
|
||
|
||
UserRegisterReq:
|
||
type: object
|
||
required: [username, password, captcha_id, captcha_code]
|
||
properties:
|
||
username: { type: string, example: tiedanzi888 }
|
||
password: { type: string, example: malegebi }
|
||
captcha_id: { type: string }
|
||
captcha_code: { type: string, example: XHSXY }
|
||
|
||
UserLoginReq:
|
||
type: object
|
||
required: [username, password, captcha_id, captcha_code]
|
||
properties:
|
||
username: { type: string }
|
||
password: { type: string }
|
||
captcha_id: { type: string }
|
||
captcha_code: { type: string }
|
||
|
||
CORSUpdateReq:
|
||
type: object
|
||
required: [origins]
|
||
properties:
|
||
origins:
|
||
type: array
|
||
items: { type: string }
|
||
example: ["http://localhost:5173", "https://admin.example.com"]
|
||
|
||
APIKeyCreateReq:
|
||
type: object
|
||
required: [name]
|
||
properties:
|
||
name: { type: string, example: 前端管理后台 }
|
||
|
||
CategoryUpsertReq:
|
||
type: object
|
||
required: [name]
|
||
properties:
|
||
name: { type: string, example: 烧烤 }
|
||
icon_url: { type: string }
|
||
sort_order: { type: integer, example: 10 }
|
||
enabled: { type: boolean, example: true }
|
||
|
||
StoreUpsertReq:
|
||
type: object
|
||
required: [name, category_id, address]
|
||
properties:
|
||
name: { type: string }
|
||
category_id: { type: integer }
|
||
address: { type: string }
|
||
open_hours: { type: string }
|
||
phone: { type: string }
|
||
cover_url: { type: string }
|
||
description: { type: string }
|
||
status: { type: string, description: active|inactive }
|
||
images:
|
||
type: array
|
||
items:
|
||
type: object
|
||
required: [url]
|
||
properties:
|
||
url: { type: string }
|
||
sort_order: { type: integer }
|
||
dishes:
|
||
type: array
|
||
items:
|
||
type: object
|
||
required: [name]
|
||
properties:
|
||
name: { type: string }
|
||
description: { type: string }
|
||
image_url: { type: string }
|
||
sort_order: { type: integer }
|
||
|
||
StatusReq:
|
||
type: object
|
||
required: [status]
|
||
properties:
|
||
status: { type: string }
|
||
|
||
MerchantApplyReq:
|
||
type: object
|
||
required: [store_name, category_id, address, contact_name, contact_phone]
|
||
properties:
|
||
store_name: { type: string }
|
||
category_id: { type: integer }
|
||
address: { type: string }
|
||
open_hours: { type: string }
|
||
phone: { type: string }
|
||
cover_url: { type: string }
|
||
image_urls:
|
||
type: array
|
||
items: { type: string }
|
||
description: { type: string }
|
||
contact_name: { type: string }
|
||
contact_phone: { type: string }
|
||
|
||
MerchantReviewReq:
|
||
type: object
|
||
required: [action]
|
||
properties:
|
||
action: { type: string, enum: [approve, reject] }
|
||
reject_reason: { type: string }
|
||
|
||
ReviewCreateReq:
|
||
type: object
|
||
required: [rating]
|
||
properties:
|
||
rating: { type: integer, minimum: 1, maximum: 5, example: 5 }
|
||
content: { type: string, example: 太好吃了 }
|
||
image_urls:
|
||
type: array
|
||
items: { type: string }
|
||
recommend_dishes:
|
||
type: array
|
||
items:
|
||
type: object
|
||
additionalProperties: true
|
||
|
||
AdminCreateReq:
|
||
type: object
|
||
required: [username, password]
|
||
properties:
|
||
username: { type: string }
|
||
password: { type: string }
|
||
enabled: { type: boolean, default: true }
|
||
|
||
AdminUpdatePasswordReq:
|
||
type: object
|
||
required: [password]
|
||
properties:
|
||
password: { type: string }
|
||
|
||
AdminUpdateEnabledReq:
|
||
type: object
|
||
required: [enabled]
|
||
properties:
|
||
enabled: { type: boolean }
|
||
|
||
parameters:
|
||
Page:
|
||
in: query
|
||
name: page
|
||
schema: { type: integer, default: 1 }
|
||
PageSize:
|
||
in: query
|
||
name: page_size
|
||
schema: { type: integer, default: 20 }
|
||
|
||
paths:
|
||
/healthz:
|
||
get:
|
||
tags: [Health]
|
||
summary: 健康检查
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/captcha/new:
|
||
get:
|
||
tags: [Captcha]
|
||
summary: 获取验证码(SVG)
|
||
description: |
|
||
- `captcha_id` 有效期 5 分钟
|
||
- 校验成功后删除(一次性使用)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: "#/components/schemas/RespBase"
|
||
- type: object
|
||
properties:
|
||
data: { $ref: "#/components/schemas/CaptchaNewData" }
|
||
examples:
|
||
ok:
|
||
value:
|
||
code: 0
|
||
message: ok
|
||
data:
|
||
captcha_id: c180df303849ea6dc75c670c4f1062b0
|
||
svg: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><svg ...>XHSXY</svg>"
|
||
|
||
/api/user/register:
|
||
post:
|
||
tags: [Users]
|
||
summary: 用户注册(需要验证码)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/UserRegisterReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: "#/components/schemas/RespBase"
|
||
- type: object
|
||
properties:
|
||
data:
|
||
type: object
|
||
properties:
|
||
token: { type: string }
|
||
user: { $ref: "#/components/schemas/User" }
|
||
"409":
|
||
description: username already exists
|
||
|
||
/api/user/login:
|
||
post:
|
||
tags: [Users]
|
||
summary: 用户登录(需要验证码)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/UserLoginReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: "#/components/schemas/RespBase"
|
||
- type: object
|
||
properties:
|
||
data:
|
||
type: object
|
||
properties:
|
||
token: { type: string }
|
||
user:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
username: { type: string }
|
||
|
||
/api/user/me:
|
||
get:
|
||
tags: [Users]
|
||
summary: 当前用户信息
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/user/reviews:
|
||
get:
|
||
tags: [Reviews]
|
||
summary: 我的评论列表(用户端)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- $ref: "#/components/parameters/Page"
|
||
- $ref: "#/components/parameters/PageSize"
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/user/upload:
|
||
post:
|
||
tags: [Upload]
|
||
summary: 用户上传图片(用于评论等)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
multipart/form-data:
|
||
schema:
|
||
type: object
|
||
required: [file]
|
||
properties:
|
||
file:
|
||
type: string
|
||
format: binary
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/user/douyin/login:
|
||
post:
|
||
tags: [Users]
|
||
summary: 抖音登录(预留)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
responses:
|
||
"501":
|
||
description: not implemented
|
||
|
||
/api/user/stores/{id}/reviews:
|
||
post:
|
||
tags: [Reviews]
|
||
summary: 用户提交评论(进入待审核)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/ReviewCreateReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/user/stores/{id}/like:
|
||
post:
|
||
tags: [Stores]
|
||
summary: 用户点赞/取消点赞(toggle)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/merchant/apply:
|
||
post:
|
||
tags: [Merchant]
|
||
summary: 商家入驻提交
|
||
security:
|
||
- ApiKeyAuth: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/MerchantApplyReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/categories:
|
||
get:
|
||
tags: [Categories]
|
||
summary: 分类列表(公开,只返回 enabled=true)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/stores:
|
||
get:
|
||
tags: [Stores]
|
||
summary: 店铺列表(公开,只返回 active)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
parameters:
|
||
- in: query
|
||
name: keyword
|
||
schema: { type: string }
|
||
- in: query
|
||
name: category_id
|
||
schema: { type: integer }
|
||
- $ref: "#/components/parameters/Page"
|
||
- $ref: "#/components/parameters/PageSize"
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/stores/{id}:
|
||
get:
|
||
tags: [Stores]
|
||
summary: 店铺详情(公开,只返回 active)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/stores/{id}/reviews:
|
||
get:
|
||
tags: [Reviews]
|
||
summary: 店铺评论列表(公开,只返回 approved)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
- $ref: "#/components/parameters/Page"
|
||
- $ref: "#/components/parameters/PageSize"
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/rankings/stores:
|
||
get:
|
||
tags: [Rankings]
|
||
summary: 店铺排行(公开,只返回 active)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
parameters:
|
||
- in: query
|
||
name: by
|
||
schema:
|
||
type: string
|
||
enum: [hotness, likes, search, reviews]
|
||
default: hotness
|
||
- $ref: "#/components/parameters/Page"
|
||
- $ref: "#/components/parameters/PageSize"
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/stores/search:
|
||
get:
|
||
tags: [Stores]
|
||
summary: 店铺搜索(会累积热度)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
parameters:
|
||
- in: query
|
||
name: keyword
|
||
schema: { type: string }
|
||
- $ref: "#/components/parameters/Page"
|
||
- $ref: "#/components/parameters/PageSize"
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/stores/hot:
|
||
get:
|
||
tags: [Stores]
|
||
summary: 店铺热榜
|
||
security:
|
||
- ApiKeyAuth: []
|
||
parameters:
|
||
- in: query
|
||
name: by
|
||
schema:
|
||
type: string
|
||
enum: [hotness, likes, search, reviews]
|
||
default: hotness
|
||
- in: query
|
||
name: limit
|
||
schema: { type: integer, default: 20 }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/login:
|
||
post:
|
||
tags: [AdminAuth]
|
||
summary: 管理员登录
|
||
security:
|
||
- ApiKeyAuth: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/AdminLoginReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/me:
|
||
get:
|
||
tags: [AdminAuth]
|
||
summary: 当前管理员信息
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/dashboard/overview:
|
||
get:
|
||
tags: [AdminAuth]
|
||
summary: 后台概览(统计)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/settings/cors:
|
||
get:
|
||
tags: [Settings]
|
||
summary: 获取 CORS origins
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
put:
|
||
tags: [Settings]
|
||
summary: 更新 CORS origins
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/CORSUpdateReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/apikeys:
|
||
get:
|
||
tags: [APIKeys]
|
||
summary: APIKey 列表
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- $ref: "#/components/parameters/Page"
|
||
- $ref: "#/components/parameters/PageSize"
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
post:
|
||
tags: [APIKeys]
|
||
summary: 创建 APIKey(只会返回一次明文 key)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/APIKeyCreateReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/apikeys/{id}/revoke:
|
||
patch:
|
||
tags: [APIKeys]
|
||
summary: 撤销 APIKey
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/merchant/applications:
|
||
get:
|
||
tags: [Merchant]
|
||
summary: 商家入驻申请列表
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: query
|
||
name: status
|
||
schema: { type: string, enum: [pending, approved, rejected] }
|
||
- $ref: "#/components/parameters/Page"
|
||
- $ref: "#/components/parameters/PageSize"
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/merchant/applications/{id}/review:
|
||
patch:
|
||
tags: [Merchant]
|
||
summary: 审核商家入驻(approve/reject)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/MerchantReviewReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/categories:
|
||
get:
|
||
tags: [Categories]
|
||
summary: 分类列表
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: query
|
||
name: keyword
|
||
schema: { type: string }
|
||
- $ref: "#/components/parameters/Page"
|
||
- $ref: "#/components/parameters/PageSize"
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
post:
|
||
tags: [Categories]
|
||
summary: 新增分类
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/CategoryUpsertReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/categories/{id}:
|
||
put:
|
||
tags: [Categories]
|
||
summary: 编辑分类
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/CategoryUpsertReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
delete:
|
||
tags: [Categories]
|
||
summary: 删除分类(软删)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/stores:
|
||
get:
|
||
tags: [Stores]
|
||
summary: 店铺列表
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: query
|
||
name: keyword
|
||
schema: { type: string }
|
||
- in: query
|
||
name: status
|
||
schema: { type: string, enum: [active, inactive] }
|
||
- in: query
|
||
name: category_id
|
||
schema: { type: integer }
|
||
- $ref: "#/components/parameters/Page"
|
||
- $ref: "#/components/parameters/PageSize"
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
post:
|
||
tags: [Stores]
|
||
summary: 新增店铺
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/StoreUpsertReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/stores/{id}:
|
||
get:
|
||
tags: [Stores]
|
||
summary: 店铺详情(含图片/招牌菜)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
put:
|
||
tags: [Stores]
|
||
summary: 编辑店铺
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/StoreUpsertReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
delete:
|
||
tags: [Stores]
|
||
summary: 删除店铺(软删)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/stores/{id}/status:
|
||
patch:
|
||
tags: [Stores]
|
||
summary: 上下架店铺
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/StatusReq" }
|
||
examples:
|
||
active: { value: { status: active } }
|
||
inactive: { value: { status: inactive } }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/reviews:
|
||
get:
|
||
tags: [Reviews]
|
||
summary: 评论列表
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: query
|
||
name: status
|
||
schema: { type: string, enum: [pending, approved, blocked] }
|
||
- in: query
|
||
name: store_id
|
||
schema: { type: integer }
|
||
- in: query
|
||
name: user_id
|
||
schema: { type: integer }
|
||
- $ref: "#/components/parameters/Page"
|
||
- $ref: "#/components/parameters/PageSize"
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/reviews/{id}/status:
|
||
patch:
|
||
tags: [Reviews]
|
||
summary: 修改评论状态(审核)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/StatusReq" }
|
||
examples:
|
||
approve: { value: { status: approved } }
|
||
block: { value: { status: blocked } }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/reviews/{id}:
|
||
delete:
|
||
tags: [Reviews]
|
||
summary: 删除评论(软删)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/users:
|
||
get:
|
||
tags: [Users]
|
||
summary: 用户列表(管理端)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: query
|
||
name: keyword
|
||
schema: { type: string }
|
||
- in: query
|
||
name: status
|
||
schema: { type: string, enum: [active, disabled] }
|
||
- $ref: "#/components/parameters/Page"
|
||
- $ref: "#/components/parameters/PageSize"
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/users/{id}:
|
||
get:
|
||
tags: [Users]
|
||
summary: 用户详情(管理端)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/users/{id}/status:
|
||
patch:
|
||
tags: [Users]
|
||
summary: 修改用户状态(启用/禁用)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/StatusReq" }
|
||
examples:
|
||
disable: { value: { status: disabled } }
|
||
active: { value: { status: active } }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/admins:
|
||
get:
|
||
tags: [AdminAuth]
|
||
summary: 管理员列表
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: query
|
||
name: keyword
|
||
schema: { type: string }
|
||
- $ref: "#/components/parameters/Page"
|
||
- $ref: "#/components/parameters/PageSize"
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
post:
|
||
tags: [AdminAuth]
|
||
summary: 创建管理员
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/AdminCreateReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/admins/{id}/password:
|
||
patch:
|
||
tags: [AdminAuth]
|
||
summary: 重置管理员密码
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/AdminUpdatePasswordReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/admins/{id}/enabled:
|
||
patch:
|
||
tags: [AdminAuth]
|
||
summary: 启用/禁用管理员
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: "#/components/schemas/AdminUpdateEnabledReq" }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/rankings/stores:
|
||
get:
|
||
tags: [Rankings]
|
||
summary: 店铺排行(管理端)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: query
|
||
name: by
|
||
schema:
|
||
type: string
|
||
enum: [hotness, likes, search, reviews]
|
||
default: hotness
|
||
- $ref: "#/components/parameters/Page"
|
||
- $ref: "#/components/parameters/PageSize"
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/rankings/stores/recalc:
|
||
post:
|
||
tags: [Rankings]
|
||
summary: 重算综合分(score)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
parameters:
|
||
- in: query
|
||
name: limit
|
||
schema: { type: integer, default: 5000 }
|
||
responses:
|
||
"200":
|
||
description: ok
|
||
|
||
/api/admin/upload:
|
||
post:
|
||
tags: [Upload]
|
||
summary: 上传图片(multipart/form-data)
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BearerAuth: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
multipart/form-data:
|
||
schema:
|
||
type: object
|
||
required: [file]
|
||
properties:
|
||
file:
|
||
type: string
|
||
format: binary
|
||
responses:
|
||
"200":
|
||
description: ok
|