docs: add Swagger annotations to 5 handlers

Add comprehensive Swagger/Swagger comments to:
- export_handler.go (ExportUsers, ImportUsers, GetImportTemplate)
- sms_handler.go (SendCode, LoginByCode)
- sso_handler.go (Authorize, Token, Introspect, Revoke, UserInfo)
- theme_handler.go (8 endpoints)
- webhook_handler.go (5 endpoints)

All 18 handlers now have Swagger annotations.
This commit is contained in:
2026-04-11 22:49:13 +08:00
parent 1929c42e35
commit 84d9ed28af
5 changed files with 296 additions and 20 deletions

View File

@@ -20,6 +20,21 @@ func NewExportHandler(exportService *service.ExportService) *ExportHandler {
return &ExportHandler{exportService: exportService}
}
// ExportUsers 导出用户
// @Summary 导出用户数据
// @Description 导出用户数据为 CSV 或 Excel 格式
// @Tags 数据导入导出
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param format query string false "导出格式" default(csv) Enums(csv, excel)
// @Param fields query string false "导出字段,逗号分隔"
// @Param keyword query string false "关键词过滤"
// @Param status query int false "用户状态过滤"
// @Success 200 {file} file "用户数据文件"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/exports/users [get]
func (h *ExportHandler) ExportUsers(c *gin.Context) {
format := c.DefaultQuery("format", "csv")
fieldsStr := c.Query("fields")
@@ -57,6 +72,20 @@ func (h *ExportHandler) ExportUsers(c *gin.Context) {
c.Data(http.StatusOK, contentType, data)
}
// ImportUsers 导入用户
// @Summary 导入用户数据
// @Description 从 CSV 或 Excel 文件导入用户数据
// @Tags 数据导入导出
// @Accept multipart/form-data
// @Produce json
// @Security BearerAuth
// @Param file formData file true "导入文件"
// @Param format query string false "文件格式" default(csv) Enums(csv, excel)
// @Success 200 {object} Response "导入结果"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/exports/users [post]
func (h *ExportHandler) ImportUsers(c *gin.Context) {
file, _, err := c.Request.FormFile("file")
if err != nil {
@@ -84,6 +113,17 @@ func (h *ExportHandler) ImportUsers(c *gin.Context) {
})
}
// GetImportTemplate 获取导入模板
// @Summary 获取用户导入模板
// @Description 下载用户批量导入的 CSV 或 Excel 模板
// @Tags 数据导入导出
// @Produce json
// @Security BearerAuth
// @Param format query string false "模板格式" default(csv) Enums(csv, excel)
// @Success 200 {file} file "导入模板文件"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/exports/template [get]
func (h *ExportHandler) GetImportTemplate(c *gin.Context) {
format := c.DefaultQuery("format", "csv")
data, filename, contentType, err := h.exportService.GetImportTemplateByFormat(format)

View File

@@ -14,6 +14,16 @@ type SMSHandler struct {
smsCodeService *service.SMSCodeService
}
// SMSLoginRequest 短信登录请求
type SMSLoginRequest struct {
Phone string `json:"phone" binding:"required"`
Code string `json:"code" binding:"required"`
DeviceID string `json:"device_id"`
DeviceName string `json:"device_name"`
DeviceBrowser string `json:"device_browser"`
DeviceOS string `json:"device_os"`
}
// NewSMSHandler creates a new SMSHandler (stub, no SMS configured)
func NewSMSHandler() *SMSHandler {
return &SMSHandler{}
@@ -27,7 +37,17 @@ func NewSMSHandlerWithService(authService *service.AuthService, smsCodeService *
}
}
// SendCode 发送短信验证码(用于注册/登录)
// SendCode 发送短信验证码
// @Summary 发送短信验证码
// @Description 向指定手机号发送短信验证码(用于注册或登录)
// @Tags 短信验证
// @Accept json
// @Produce json
// @Param request body service.SendCodeRequest true "发送验证码请求"
// @Success 200 {object} Response "发送成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 503 {object} Response "短信服务未配置"
// @Router /api/v1/sms/send [post]
func (h *SMSHandler) SendCode(c *gin.Context) {
if h.smsCodeService == nil {
c.JSON(http.StatusServiceUnavailable, gin.H{"code": 503, "message": "SMS service not configured"})
@@ -53,22 +73,25 @@ func (h *SMSHandler) SendCode(c *gin.Context) {
})
}
// LoginByCode 短信验证码登录(带设备信息以支持设备信任链路)
// LoginByCode 短信验证码登录
// @Summary 短信验证码登录
// @Description 使用手机号和短信验证码登录(带设备信息以支持设备信任链路)
// @Tags 短信验证
// @Accept json
// @Produce json
// @Param request body SMSLoginRequest true "登录请求"
// @Success 200 {object} Response "登录成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "验证码错误"
// @Failure 503 {object} Response "短信登录未配置"
// @Router /api/v1/sms/login [post]
func (h *SMSHandler) LoginByCode(c *gin.Context) {
if h.authService == nil {
c.JSON(http.StatusServiceUnavailable, gin.H{"code": 503, "message": "SMS login not configured"})
return
}
var req struct {
Phone string `json:"phone" binding:"required"`
Code string `json:"code" binding:"required"`
DeviceID string `json:"device_id"`
DeviceName string `json:"device_name"`
DeviceBrowser string `json:"device_browser"`
DeviceOS string `json:"device_os"`
}
var req SMSLoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
return

View File

@@ -34,7 +34,22 @@ type AuthorizeRequest struct {
}
// Authorize 处理 SSO 授权请求
// GET /api/v1/sso/authorize?client_id=xxx&redirect_uri=xxx&response_type=code&scope=openid&state=xxx
// @Summary SSO 授权
// @Description 处理 SSO 授权请求,返回授权码或访问令牌
// @Tags SSO
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param client_id query string true "客户端ID"
// @Param redirect_uri query string true "回调地址"
// @Param response_type query string true "响应类型" Enums(code, token)
// @Param scope query string false "授权范围"
// @Param state query string false "状态参数"
// @Success 302 {string} string "重定向到回调地址"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/sso/authorize [get]
func (h *SSOHandler) Authorize(c *gin.Context) {
var req AuthorizeRequest
if err := c.ShouldBindQuery(&req); err != nil {
@@ -138,8 +153,22 @@ type TokenResponse struct {
Scope string `json:"scope"`
}
// Token 处理 Token 请求(授权码模式第二步)
// POST /api/v1/sso/token
// Token 处理 Token 请求
// @Summary 获取 Access Token
// @Description 使用授权码获取 Access Token授权码模式第二步
// @Tags SSO
// @Accept json
// @Produce json
// @Param grant_type formData string true "授权类型" Enums(authorization_code)
// @Param code formData string false "授权码"
// @Param redirect_uri formData string false "回调地址"
// @Param client_id formData string true "客户端ID"
// @Param client_secret formData string true "客户端密钥"
// @Success 200 {object} TokenResponse "访问令牌响应"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "客户端认证失败"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/sso/token [post]
func (h *SSOHandler) Token(c *gin.Context) {
var req TokenRequest
if err := c.ShouldBind(&req); err != nil {
@@ -205,7 +234,17 @@ type IntrospectResponse struct {
}
// Introspect 验证 access token
// POST /api/v1/sso/introspect
// @Summary 验证 Access Token
// @Description 验证 Access Token 的有效性并返回相关信息
// @Tags SSO
// @Accept json
// @Produce json
// @Param token formData string true "Access Token"
// @Param client_id formData string false "客户端ID"
// @Success 200 {object} IntrospectResponse "Token信息"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/sso/introspect [post]
func (h *SSOHandler) Introspect(c *gin.Context) {
var req IntrospectRequest
if err := c.ShouldBind(&req); err != nil {
@@ -234,7 +273,16 @@ type RevokeRequest struct {
}
// Revoke 撤销 access token
// POST /api/v1/sso/revoke
// @Summary 撤销 Access Token
// @Description 撤销指定的 Access Token
// @Tags SSO
// @Accept json
// @Produce json
// @Param token formData string true "Access Token"
// @Success 200 {object} Response "撤销成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/sso/revoke [post]
func (h *SSOHandler) Revoke(c *gin.Context) {
var req RevokeRequest
if err := c.ShouldBind(&req); err != nil {
@@ -253,8 +301,16 @@ type UserInfoResponse struct {
Username string `json:"username"`
}
// UserInfo 获取当前用户信息SSO 专用)
// GET /api/v1/sso/userinfo
// UserInfo 获取当前用户信息
// @Summary 获取 SSO 用户信息
// @Description 获取当前通过 SSO 授权的用户信息
// @Tags SSO
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=UserInfoResponse} "用户信息"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/sso/userinfo [get]
func (h *SSOHandler) UserInfo(c *gin.Context) {
userID, exists := c.Get("user_id")
if !exists {

View File

@@ -20,6 +20,18 @@ func NewThemeHandler(themeService *service.ThemeService) *ThemeHandler {
}
// CreateTheme 创建主题
// @Summary 创建主题
// @Description 创建新的主题配置
// @Tags 主题管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body service.CreateThemeRequest true "主题信息"
// @Success 201 {object} Response{data=domain.Theme} "主题创建成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/themes [post]
func (h *ThemeHandler) CreateTheme(c *gin.Context) {
var req service.CreateThemeRequest
if err := c.ShouldBindJSON(&req); err != nil {
@@ -41,6 +53,19 @@ func (h *ThemeHandler) CreateTheme(c *gin.Context) {
}
// UpdateTheme 更新主题
// @Summary 更新主题
// @Description 更新指定主题的配置
// @Tags 主题管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "主题ID"
// @Param request body service.UpdateThemeRequest true "更新信息"
// @Success 200 {object} Response{data=domain.Theme} "主题更新成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/themes/{id} [put]
func (h *ThemeHandler) UpdateTheme(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -68,6 +93,17 @@ func (h *ThemeHandler) UpdateTheme(c *gin.Context) {
}
// DeleteTheme 删除主题
// @Summary 删除主题
// @Description 删除指定的主题
// @Tags 主题管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "主题ID"
// @Success 200 {object} Response "主题删除成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/themes/{id} [delete]
func (h *ThemeHandler) DeleteTheme(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -87,6 +123,17 @@ func (h *ThemeHandler) DeleteTheme(c *gin.Context) {
}
// GetTheme 获取主题
// @Summary 获取主题
// @Description 根据ID获取主题详情
// @Tags 主题管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "主题ID"
// @Success 200 {object} Response{data=domain.Theme} "主题详情"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/themes/{id} [get]
func (h *ThemeHandler) GetTheme(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -107,7 +154,16 @@ func (h *ThemeHandler) GetTheme(c *gin.Context) {
})
}
// ListThemes 获取所有主题
// ListThemes 获取主题列表
// @Summary 获取主题列表
// @Description 获取所有已启用的主题
// @Tags 主题管理
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=[]domain.Theme} "主题列表"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/themes [get]
func (h *ThemeHandler) ListThemes(c *gin.Context) {
themes, err := h.themeService.ListThemes(c.Request.Context())
if err != nil {
@@ -123,6 +179,15 @@ func (h *ThemeHandler) ListThemes(c *gin.Context) {
}
// ListAllThemes 获取所有主题(包括禁用的)
// @Summary 获取所有主题
// @Description 获取所有主题(包括已禁用的)
// @Tags 主题管理
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=[]domain.Theme} "主题列表"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/themes/all [get]
func (h *ThemeHandler) ListAllThemes(c *gin.Context) {
themes, err := h.themeService.ListAllThemes(c.Request.Context())
if err != nil {
@@ -138,6 +203,15 @@ func (h *ThemeHandler) ListAllThemes(c *gin.Context) {
}
// GetDefaultTheme 获取默认主题
// @Summary 获取默认主题
// @Description 获取系统默认主题
// @Tags 主题管理
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=domain.Theme} "默认主题"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/themes/default [get]
func (h *ThemeHandler) GetDefaultTheme(c *gin.Context) {
theme, err := h.themeService.GetDefaultTheme(c.Request.Context())
if err != nil {
@@ -153,6 +227,17 @@ func (h *ThemeHandler) GetDefaultTheme(c *gin.Context) {
}
// SetDefaultTheme 设置默认主题
// @Summary 设置默认主题
// @Description 将指定主题设为系统默认主题
// @Tags 主题管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "主题ID"
// @Success 200 {object} Response "设置成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/themes/{id}/default [put]
func (h *ThemeHandler) SetDefaultTheme(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -171,7 +256,14 @@ func (h *ThemeHandler) SetDefaultTheme(c *gin.Context) {
})
}
// GetActiveTheme 获取当前生效的主题(公开接口)
// GetActiveTheme 获取当前生效的主题
// @Summary 获取当前生效的主题
// @Description 获取当前系统正在使用的主题(公开接口)
// @Tags 主题管理
// @Produce json
// @Success 200 {object} Response{data=domain.Theme} "当前生效主题"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/themes/active [get]
func (h *ThemeHandler) GetActiveTheme(c *gin.Context) {
theme, err := h.themeService.GetActiveTheme(c.Request.Context())
if err != nil {

View File

@@ -19,6 +19,19 @@ func NewWebhookHandler(webhookService *service.WebhookService) *WebhookHandler {
return &WebhookHandler{webhookService: webhookService}
}
// CreateWebhook 创建 Webhook
// @Summary 创建 Webhook
// @Description 创建新的 Webhook 配置
// @Tags Webhook管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body service.CreateWebhookRequest true "Webhook信息"
// @Success 201 {object} Response{data=domain.Webhook} "Webhook创建成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/webhooks [post]
func (h *WebhookHandler) CreateWebhook(c *gin.Context) {
var req service.CreateWebhookRequest
if err := c.ShouldBindJSON(&req); err != nil {
@@ -38,6 +51,19 @@ func (h *WebhookHandler) CreateWebhook(c *gin.Context) {
c.JSON(http.StatusCreated, gin.H{"code": 0, "message": "success", "data": webhook})
}
// ListWebhooks 获取 Webhook 列表
// @Summary 获取 Webhook 列表
// @Description 获取当前用户的 Webhook 配置列表
// @Tags Webhook管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param page query int false "页码" default(1)
// @Param page_size query int false "每页数量" default(20)
// @Success 200 {object} Response "Webhook列表"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/webhooks [get]
func (h *WebhookHandler) ListWebhooks(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
@@ -70,6 +96,20 @@ func (h *WebhookHandler) ListWebhooks(c *gin.Context) {
})
}
// UpdateWebhook 更新 Webhook
// @Summary 更新 Webhook
// @Description 更新指定 Webhook 的配置
// @Tags Webhook管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "Webhook ID"
// @Param request body service.UpdateWebhookRequest true "更新信息"
// @Success 200 {object} Response "更新成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/webhooks/{id} [put]
func (h *WebhookHandler) UpdateWebhook(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -91,6 +131,18 @@ func (h *WebhookHandler) UpdateWebhook(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "更新成功"})
}
// DeleteWebhook 删除 Webhook
// @Summary 删除 Webhook
// @Description 删除指定的 Webhook 配置
// @Tags Webhook管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "Webhook ID"
// @Success 200 {object} Response "删除成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/webhooks/{id} [delete]
func (h *WebhookHandler) DeleteWebhook(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -106,6 +158,19 @@ func (h *WebhookHandler) DeleteWebhook(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "删除成功"})
}
// GetWebhookDeliveries 获取 Webhook 投递记录
// @Summary 获取 Webhook 投递记录
// @Description 获取指定 Webhook 的最近投递记录
// @Tags Webhook管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "Webhook ID"
// @Param limit query int false "返回记录数量" default(20)
// @Success 200 {object} Response "投递记录列表"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/webhooks/{id}/deliveries [get]
func (h *WebhookHandler) GetWebhookDeliveries(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {