445 lines
14 KiB
Go
445 lines
14 KiB
Go
package handlers
|
|
|
|
import (
|
|
"strconv"
|
|
"tyapi-server/internal/application/product"
|
|
"tyapi-server/internal/application/product/dto/commands"
|
|
"tyapi-server/internal/application/product/dto/queries"
|
|
"tyapi-server/internal/shared/interfaces"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// ProductHandler 产品相关HTTP处理器
|
|
type ProductHandler struct {
|
|
appService product.ProductApplicationService
|
|
categoryService product.CategoryApplicationService
|
|
subAppService product.SubscriptionApplicationService
|
|
responseBuilder interfaces.ResponseBuilder
|
|
logger *zap.Logger
|
|
}
|
|
|
|
// NewProductHandler 创建产品HTTP处理器
|
|
func NewProductHandler(
|
|
appService product.ProductApplicationService,
|
|
categoryService product.CategoryApplicationService,
|
|
subAppService product.SubscriptionApplicationService,
|
|
responseBuilder interfaces.ResponseBuilder,
|
|
logger *zap.Logger,
|
|
) *ProductHandler {
|
|
return &ProductHandler{
|
|
appService: appService,
|
|
categoryService: categoryService,
|
|
subAppService: subAppService,
|
|
responseBuilder: responseBuilder,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// ListProducts 获取产品列表(数据大厅)
|
|
// @Summary 获取产品列表
|
|
// @Description 分页获取可用的产品列表,支持筛选
|
|
// @Tags 数据大厅
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param page query int false "页码" default(1)
|
|
// @Param page_size query int false "每页数量" default(10)
|
|
// @Param keyword query string false "搜索关键词"
|
|
// @Param category_id query string false "分类ID"
|
|
// @Param min_price query number false "最低价格"
|
|
// @Param max_price query number false "最高价格"
|
|
// @Param is_enabled query bool false "是否启用"
|
|
// @Param is_visible query bool false "是否可见"
|
|
// @Param is_package query bool false "是否组合包"
|
|
// @Param sort_by query string false "排序字段"
|
|
// @Param sort_order query string false "排序方向" Enums(asc, desc)
|
|
// @Success 200 {object} responses.ProductListResponse "获取产品列表成功"
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
|
// @Router /api/v1/products [get]
|
|
func (h *ProductHandler) ListProducts(c *gin.Context) {
|
|
var query queries.ListProductsQuery
|
|
if err := c.ShouldBindQuery(&query); err != nil {
|
|
h.responseBuilder.BadRequest(c, "请求参数错误")
|
|
return
|
|
}
|
|
|
|
// 设置默认值
|
|
if query.Page <= 0 {
|
|
query.Page = 1
|
|
}
|
|
if query.PageSize <= 0 {
|
|
query.PageSize = 10
|
|
}
|
|
if query.PageSize > 100 {
|
|
query.PageSize = 100
|
|
}
|
|
|
|
result, err := h.appService.ListProducts(c.Request.Context(), &query)
|
|
if err != nil {
|
|
h.logger.Error("获取产品列表失败", zap.Error(err))
|
|
h.responseBuilder.InternalError(c, "获取产品列表失败")
|
|
return
|
|
}
|
|
|
|
h.responseBuilder.Success(c, result, "获取产品列表成功")
|
|
}
|
|
|
|
// GetProductDetail 获取产品详情
|
|
// @Summary 获取产品详情
|
|
// @Description 根据产品ID获取产品详细信息
|
|
// @Tags 数据大厅
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path string true "产品ID"
|
|
// @Success 200 {object} responses.ProductInfoResponse "获取产品详情成功"
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
|
// @Failure 404 {object} map[string]interface{} "产品不存在"
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
|
// @Router /api/v1/products/{id} [get]
|
|
func (h *ProductHandler) GetProductDetail(c *gin.Context) {
|
|
var query queries.GetProductQuery
|
|
query.ID = c.Param("id")
|
|
|
|
if query.ID == "" {
|
|
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
|
return
|
|
}
|
|
|
|
result, err := h.appService.GetProductByID(c.Request.Context(), &query)
|
|
if err != nil {
|
|
h.logger.Error("获取产品详情失败", zap.Error(err), zap.String("product_id", query.ID))
|
|
h.responseBuilder.NotFound(c, "产品不存在")
|
|
return
|
|
}
|
|
|
|
h.responseBuilder.Success(c, result, "获取产品详情成功")
|
|
}
|
|
|
|
|
|
// SubscribeProduct 订阅产品
|
|
// @Summary 订阅产品
|
|
// @Description 用户订阅指定产品
|
|
// @Tags 数据大厅
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security Bearer
|
|
// @Param id path string true "产品ID"
|
|
// @Param request body commands.CreateSubscriptionCommand true "订阅请求"
|
|
// @Success 200 {object} map[string]interface{} "订阅成功"
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
|
// @Failure 401 {object} map[string]interface{} "未认证"
|
|
// @Failure 404 {object} map[string]interface{} "产品不存在"
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
|
// @Router /api/v1/products/{id}/subscribe [post]
|
|
func (h *ProductHandler) SubscribeProduct(c *gin.Context) {
|
|
userID := c.GetString("user_id") // 从JWT中间件获取
|
|
if userID == "" {
|
|
h.responseBuilder.Unauthorized(c, "用户未认证")
|
|
return
|
|
}
|
|
|
|
productID := c.Param("id")
|
|
if productID == "" {
|
|
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
|
return
|
|
}
|
|
|
|
var cmd commands.CreateSubscriptionCommand
|
|
if err := c.ShouldBindJSON(&cmd); err != nil {
|
|
h.responseBuilder.BadRequest(c, "请求参数错误")
|
|
return
|
|
}
|
|
|
|
// 设置用户ID和产品ID
|
|
cmd.UserID = userID
|
|
cmd.ProductID = productID
|
|
|
|
// 设置默认值
|
|
if cmd.APILimit <= 0 {
|
|
cmd.APILimit = 1000 // 默认API调用限制
|
|
}
|
|
if cmd.Duration == "" {
|
|
cmd.Duration = "30d" // 默认订阅30天
|
|
}
|
|
|
|
if err := h.subAppService.CreateSubscription(c.Request.Context(), &cmd); err != nil {
|
|
h.logger.Error("订阅产品失败", zap.Error(err), zap.String("user_id", userID), zap.String("product_id", productID))
|
|
h.responseBuilder.BadRequest(c, err.Error())
|
|
return
|
|
}
|
|
|
|
h.responseBuilder.Success(c, nil, "订阅成功")
|
|
}
|
|
|
|
// GetProductStats 获取产品统计信息
|
|
// @Summary 获取产品统计
|
|
// @Description 获取产品相关的统计信息
|
|
// @Tags 数据大厅
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Success 200 {object} responses.ProductStatsResponse "获取统计信息成功"
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
|
// @Router /api/v1/products/stats [get]
|
|
func (h *ProductHandler) GetProductStats(c *gin.Context) {
|
|
result, err := h.appService.GetProductStats(c.Request.Context())
|
|
if err != nil {
|
|
h.logger.Error("获取产品统计失败", zap.Error(err))
|
|
h.responseBuilder.InternalError(c, "获取产品统计失败")
|
|
return
|
|
}
|
|
|
|
h.responseBuilder.Success(c, result, "获取产品统计成功")
|
|
}
|
|
|
|
// ================ 分类相关方法 ================
|
|
|
|
// ListCategories 获取分类列表
|
|
// @Summary 获取分类列表
|
|
// @Description 获取产品分类列表,支持层级筛选
|
|
// @Tags 数据大厅
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param parent_id query string false "父级分类ID"
|
|
// @Param level query int false "分类层级"
|
|
// @Success 200 {object} responses.CategoryListResponse "获取分类列表成功"
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
|
// @Router /api/v1/categories [get]
|
|
func (h *ProductHandler) ListCategories(c *gin.Context) {
|
|
// 解析查询参数
|
|
parentID := c.Query("parent_id")
|
|
levelStr := c.Query("level")
|
|
|
|
// 构建查询命令
|
|
query := &queries.ListCategoriesQuery{
|
|
Page: 1,
|
|
PageSize: 100,
|
|
SortBy: "sort_order",
|
|
SortOrder: "asc",
|
|
}
|
|
|
|
// 设置父级分类ID
|
|
if parentID != "" {
|
|
query.ParentID = &parentID
|
|
}
|
|
|
|
// 设置分类层级
|
|
if levelStr != "" {
|
|
if level, err := strconv.Atoi(levelStr); err == nil {
|
|
query.Level = &level
|
|
}
|
|
}
|
|
|
|
// 调用应用服务
|
|
categories, err := h.categoryService.ListCategories(c.Request.Context(), query)
|
|
if err != nil {
|
|
h.logger.Error("获取分类列表失败", zap.Error(err))
|
|
h.responseBuilder.InternalError(c, "获取分类列表失败")
|
|
return
|
|
}
|
|
|
|
// 返回结果
|
|
h.responseBuilder.Success(c, categories, "获取分类列表成功")
|
|
}
|
|
|
|
// GetCategoryDetail 获取分类详情
|
|
// @Summary 获取分类详情
|
|
// @Description 根据分类ID获取分类详细信息
|
|
// @Tags 数据大厅
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path string true "分类ID"
|
|
// @Success 200 {object} responses.CategoryInfoResponse "获取分类详情成功"
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
|
// @Failure 404 {object} map[string]interface{} "分类不存在"
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
|
// @Router /api/v1/categories/{id} [get]
|
|
func (h *ProductHandler) GetCategoryDetail(c *gin.Context) {
|
|
categoryID := c.Param("id")
|
|
if categoryID == "" {
|
|
h.responseBuilder.BadRequest(c, "分类ID不能为空")
|
|
return
|
|
}
|
|
|
|
// 构建查询命令
|
|
query := &queries.GetCategoryQuery{
|
|
ID: categoryID,
|
|
}
|
|
|
|
// 调用应用服务
|
|
category, err := h.categoryService.GetCategoryByID(c.Request.Context(), query)
|
|
if err != nil {
|
|
h.logger.Error("获取分类详情失败", zap.String("category_id", categoryID), zap.Error(err))
|
|
h.responseBuilder.NotFound(c, "分类不存在")
|
|
return
|
|
}
|
|
|
|
// 返回结果
|
|
h.responseBuilder.Success(c, category, "获取分类详情成功")
|
|
}
|
|
|
|
// ================ 我的订阅相关方法 ================
|
|
|
|
// ListMySubscriptions 获取我的订阅列表
|
|
// @Summary 获取我的订阅列表
|
|
// @Description 获取当前用户的订阅列表
|
|
// @Tags 我的订阅
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security Bearer
|
|
// @Param page query int false "页码" default(1)
|
|
// @Param page_size query int false "每页数量" default(10)
|
|
// @Param status query string false "订阅状态"
|
|
// @Param sort_by query string false "排序字段"
|
|
// @Param sort_order query string false "排序方向" Enums(asc, desc)
|
|
// @Success 200 {object} responses.SubscriptionListResponse "获取订阅列表成功"
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
|
// @Failure 401 {object} map[string]interface{} "未认证"
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
|
// @Router /api/v1/my/subscriptions [get]
|
|
func (h *ProductHandler) ListMySubscriptions(c *gin.Context) {
|
|
userID := c.GetString("user_id")
|
|
if userID == "" {
|
|
h.responseBuilder.Unauthorized(c, "用户未认证")
|
|
return
|
|
}
|
|
|
|
var query queries.ListSubscriptionsQuery
|
|
if err := c.ShouldBindQuery(&query); err != nil {
|
|
h.responseBuilder.BadRequest(c, "请求参数错误")
|
|
return
|
|
}
|
|
|
|
// 设置默认值
|
|
if query.Page <= 0 {
|
|
query.Page = 1
|
|
}
|
|
if query.PageSize <= 0 {
|
|
query.PageSize = 10
|
|
}
|
|
if query.PageSize > 100 {
|
|
query.PageSize = 100
|
|
}
|
|
|
|
// 设置用户ID
|
|
query.UserID = userID
|
|
|
|
result, err := h.subAppService.ListSubscriptions(c.Request.Context(), &query)
|
|
if err != nil {
|
|
h.logger.Error("获取我的订阅列表失败", zap.Error(err), zap.String("user_id", userID))
|
|
h.responseBuilder.InternalError(c, "获取我的订阅列表失败")
|
|
return
|
|
}
|
|
|
|
h.responseBuilder.Success(c, result, "获取我的订阅列表成功")
|
|
}
|
|
|
|
// GetMySubscriptionStats 获取我的订阅统计
|
|
// @Summary 获取我的订阅统计
|
|
// @Description 获取当前用户的订阅统计信息
|
|
// @Tags 我的订阅
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security Bearer
|
|
// @Success 200 {object} responses.SubscriptionStatsResponse "获取订阅统计成功"
|
|
// @Failure 401 {object} map[string]interface{} "未认证"
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
|
// @Router /api/v1/my/subscriptions/stats [get]
|
|
func (h *ProductHandler) GetMySubscriptionStats(c *gin.Context) {
|
|
userID := c.GetString("user_id")
|
|
if userID == "" {
|
|
h.responseBuilder.Unauthorized(c, "用户未认证")
|
|
return
|
|
}
|
|
|
|
result, err := h.subAppService.GetSubscriptionStats(c.Request.Context())
|
|
if err != nil {
|
|
h.logger.Error("获取我的订阅统计失败", zap.Error(err), zap.String("user_id", userID))
|
|
h.responseBuilder.InternalError(c, "获取我的订阅统计失败")
|
|
return
|
|
}
|
|
|
|
h.responseBuilder.Success(c, result, "获取我的订阅统计成功")
|
|
}
|
|
|
|
// GetMySubscriptionDetail 获取我的订阅详情
|
|
// @Summary 获取我的订阅详情
|
|
// @Description 获取指定订阅的详细信息
|
|
// @Tags 我的订阅
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security Bearer
|
|
// @Param id path string true "订阅ID"
|
|
// @Success 200 {object} responses.SubscriptionInfoResponse "获取订阅详情成功"
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
|
// @Failure 401 {object} map[string]interface{} "未认证"
|
|
// @Failure 404 {object} map[string]interface{} "订阅不存在"
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
|
// @Router /api/v1/my/subscriptions/{id} [get]
|
|
func (h *ProductHandler) GetMySubscriptionDetail(c *gin.Context) {
|
|
userID := c.GetString("user_id")
|
|
if userID == "" {
|
|
h.responseBuilder.Unauthorized(c, "用户未认证")
|
|
return
|
|
}
|
|
|
|
subscriptionID := c.Param("id")
|
|
if subscriptionID == "" {
|
|
h.responseBuilder.BadRequest(c, "订阅ID不能为空")
|
|
return
|
|
}
|
|
|
|
var query queries.GetSubscriptionQuery
|
|
query.ID = subscriptionID
|
|
|
|
result, err := h.subAppService.GetSubscriptionByID(c.Request.Context(), &query)
|
|
if err != nil {
|
|
h.logger.Error("获取我的订阅详情失败", zap.Error(err), zap.String("user_id", userID), zap.String("subscription_id", subscriptionID))
|
|
h.responseBuilder.NotFound(c, "订阅不存在")
|
|
return
|
|
}
|
|
|
|
h.responseBuilder.Success(c, result, "获取我的订阅详情成功")
|
|
}
|
|
|
|
// GetMySubscriptionUsage 获取我的订阅使用情况
|
|
// @Summary 获取我的订阅使用情况
|
|
// @Description 获取指定订阅的使用情况统计
|
|
// @Tags 我的订阅
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security Bearer
|
|
// @Param id path string true "订阅ID"
|
|
// @Success 200 {object} responses.SubscriptionUsageResponse "获取使用情况成功"
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
|
// @Failure 401 {object} map[string]interface{} "未认证"
|
|
// @Failure 404 {object} map[string]interface{} "订阅不存在"
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
|
// @Router /api/v1/my/subscriptions/{id}/usage [get]
|
|
func (h *ProductHandler) GetMySubscriptionUsage(c *gin.Context) {
|
|
userID := c.GetString("user_id")
|
|
if userID == "" {
|
|
h.responseBuilder.Unauthorized(c, "用户未认证")
|
|
return
|
|
}
|
|
|
|
subscriptionID := c.Param("id")
|
|
if subscriptionID == "" {
|
|
h.responseBuilder.BadRequest(c, "订阅ID不能为空")
|
|
return
|
|
}
|
|
|
|
result, err := h.subAppService.GetSubscriptionUsage(c.Request.Context(), subscriptionID)
|
|
if err != nil {
|
|
h.logger.Error("获取我的订阅使用情况失败", zap.Error(err), zap.String("user_id", userID), zap.String("subscription_id", subscriptionID))
|
|
h.responseBuilder.NotFound(c, "订阅不存在")
|
|
return
|
|
}
|
|
|
|
h.responseBuilder.Success(c, result, "获取我的订阅使用情况成功")
|
|
}
|
|
|
|
|
|
|