633 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			633 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| //nolint:unused
 | ||
| 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/application/product/dto/responses"
 | ||
| 	"tyapi-server/internal/shared/interfaces"
 | ||
| 
 | ||
| 	"github.com/gin-gonic/gin"
 | ||
| 	"go.uber.org/zap"
 | ||
| )
 | ||
| 
 | ||
| // ProductHandler 产品相关HTTP处理器
 | ||
| type ProductHandler struct {
 | ||
| 	appService      product.ProductApplicationService
 | ||
| 	apiConfigService product.ProductApiConfigApplicationService
 | ||
| 	categoryService product.CategoryApplicationService
 | ||
| 	subAppService   product.SubscriptionApplicationService
 | ||
| 	documentationAppService product.DocumentationApplicationServiceInterface
 | ||
| 	responseBuilder interfaces.ResponseBuilder
 | ||
| 	validator       interfaces.RequestValidator
 | ||
| 	logger          *zap.Logger
 | ||
| }
 | ||
| 
 | ||
| // NewProductHandler 创建产品HTTP处理器
 | ||
| func NewProductHandler(
 | ||
| 	appService product.ProductApplicationService,
 | ||
| 	apiConfigService product.ProductApiConfigApplicationService,
 | ||
| 	categoryService product.CategoryApplicationService,
 | ||
| 	subAppService product.SubscriptionApplicationService,
 | ||
| 	documentationAppService product.DocumentationApplicationServiceInterface,
 | ||
| 	responseBuilder interfaces.ResponseBuilder,
 | ||
| 	validator interfaces.RequestValidator,
 | ||
| 	logger *zap.Logger,
 | ||
| ) *ProductHandler {
 | ||
| 	return &ProductHandler{
 | ||
| 		appService:      appService,
 | ||
| 		apiConfigService: apiConfigService,
 | ||
| 		categoryService: categoryService,
 | ||
| 		subAppService:   subAppService,
 | ||
| 		documentationAppService: documentationAppService,
 | ||
| 		responseBuilder: responseBuilder,
 | ||
| 		validator:       validator,
 | ||
| 		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 is_enabled query bool false "是否启用"
 | ||
| // @Param is_visible query bool false "是否可见"
 | ||
| // @Param is_package query bool false "是否组合包"
 | ||
| // @Param is_subscribed 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) {
 | ||
| 	// 获取当前用户ID(可选认证)
 | ||
| 	userID := h.getCurrentUserID(c)
 | ||
| 
 | ||
| 	// 解析查询参数
 | ||
| 	page := h.getIntQuery(c, "page", 1)
 | ||
| 	pageSize := h.getIntQuery(c, "page_size", 10)
 | ||
| 
 | ||
| 	// 构建筛选条件
 | ||
| 	filters := make(map[string]interface{})
 | ||
| 
 | ||
| 	// 搜索关键词筛选
 | ||
| 	if keyword := c.Query("keyword"); keyword != "" {
 | ||
| 		filters["keyword"] = keyword
 | ||
| 	}
 | ||
| 
 | ||
| 	// 分类ID筛选
 | ||
| 	if categoryID := c.Query("category_id"); categoryID != "" {
 | ||
| 		filters["category_id"] = categoryID
 | ||
| 	}
 | ||
| 
 | ||
| 	// 启用状态筛选
 | ||
| 	if isEnabled := c.Query("is_enabled"); isEnabled != "" {
 | ||
| 		if enabled, err := strconv.ParseBool(isEnabled); err == nil {
 | ||
| 			filters["is_enabled"] = enabled
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	// 可见状态筛选 - 用户端默认只显示可见的产品
 | ||
| 	if isVisible := c.Query("is_visible"); isVisible != "" {
 | ||
| 		if visible, err := strconv.ParseBool(isVisible); err == nil {
 | ||
| 			filters["is_visible"] = visible
 | ||
| 		}
 | ||
| 	} else {
 | ||
| 		// 如果没有指定可见状态,默认只显示可见的产品
 | ||
| 		filters["is_visible"] = true
 | ||
| 	}
 | ||
| 
 | ||
| 	// 产品类型筛选
 | ||
| 	if isPackage := c.Query("is_package"); isPackage != "" {
 | ||
| 		if pkg, err := strconv.ParseBool(isPackage); err == nil {
 | ||
| 			filters["is_package"] = pkg
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	// 订阅状态筛选(需要认证)
 | ||
| 	if userID != "" {
 | ||
| 		if isSubscribed := c.Query("is_subscribed"); isSubscribed != "" {
 | ||
| 			if subscribed, err := strconv.ParseBool(isSubscribed); err == nil {
 | ||
| 				filters["is_subscribed"] = subscribed
 | ||
| 			}
 | ||
| 		}
 | ||
| 		// 添加用户ID到筛选条件
 | ||
| 		filters["user_id"] = userID
 | ||
| 	}
 | ||
| 
 | ||
| 	// 排序字段
 | ||
| 	sortBy := c.Query("sort_by")
 | ||
| 	if sortBy == "" {
 | ||
| 		sortBy = "created_at"
 | ||
| 	}
 | ||
| 
 | ||
| 	// 排序方向
 | ||
| 	sortOrder := c.Query("sort_order")
 | ||
| 	if sortOrder == "" {
 | ||
| 		sortOrder = "desc"
 | ||
| 	}
 | ||
| 
 | ||
| 	// 构建分页选项
 | ||
| 	options := interfaces.ListOptions{
 | ||
| 		Page:     page,
 | ||
| 		PageSize: pageSize,
 | ||
| 		Sort:     sortBy,
 | ||
| 		Order:    sortOrder,
 | ||
| 	}
 | ||
| 
 | ||
| 	result, err := h.appService.ListProducts(c.Request.Context(), filters, options)
 | ||
| 	if err != nil {
 | ||
| 		h.logger.Error("获取产品列表失败", zap.Error(err))
 | ||
| 		h.responseBuilder.InternalError(c, "获取产品列表失败")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	h.responseBuilder.Success(c, result, "获取产品列表成功")
 | ||
| }
 | ||
| 
 | ||
| // getIntQuery 获取整数查询参数
 | ||
| func (h *ProductHandler) getIntQuery(c *gin.Context, key string, defaultValue int) int {
 | ||
| 	if value := c.Query(key); value != "" {
 | ||
| 		if intValue, err := strconv.Atoi(value); err == nil && intValue > 0 {
 | ||
| 			return intValue
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return defaultValue
 | ||
| }
 | ||
| 
 | ||
| // getCurrentUserID 获取当前用户ID
 | ||
| func (h *ProductHandler) getCurrentUserID(c *gin.Context) string {
 | ||
| 	if userID, exists := c.Get("user_id"); exists {
 | ||
| 		if id, ok := userID.(string); ok {
 | ||
| 			return id
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return ""
 | ||
| }
 | ||
| 
 | ||
| // GetProductDetail 获取产品详情
 | ||
| // @Summary 获取产品详情
 | ||
| // @Description 获取产品详细信息,用户端只能查看可见的产品
 | ||
| // @Tags 数据大厅
 | ||
| // @Accept json
 | ||
| // @Produce json
 | ||
| // @Param id path string true "产品ID"
 | ||
| // @Param with_document query bool false "是否包含文档信息"
 | ||
| // @Success 200 {object} responses.ProductInfoWithDocumentResponse "获取产品详情成功"
 | ||
| // @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.GetProductDetailQuery
 | ||
| 	query.ID = c.Param("id")
 | ||
| 	if query.ID == "" {
 | ||
| 		h.responseBuilder.BadRequest(c, "产品ID不能为空")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	// 解析可选参数
 | ||
| 	if withDocument := c.Query("with_document"); withDocument != "" {
 | ||
| 		if withDoc, err := strconv.ParseBool(withDocument); err == nil {
 | ||
| 			query.WithDocument = &withDoc
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	result, err := h.appService.GetProductByIDForUser(c.Request.Context(), &query)
 | ||
| 	if err != nil {
 | ||
| 		h.logger.Error("获取产品详情失败", zap.Error(err))
 | ||
| 		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"
 | ||
| // @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
 | ||
| 	}
 | ||
| 
 | ||
| 	var cmd commands.CreateSubscriptionCommand
 | ||
| 	if err := h.validator.ValidateParam(c, &cmd); err != nil {
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	// 设置用户ID
 | ||
| 	cmd.UserID = userID
 | ||
| 
 | ||
| 	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", cmd.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, "获取产品统计成功")
 | ||
| }
 | ||
| 
 | ||
| // GetProductApiConfig 获取产品API配置
 | ||
| // @Summary 获取产品API配置
 | ||
| // @Description 根据产品ID获取API配置信息
 | ||
| // @Tags 产品API配置
 | ||
| // @Accept json
 | ||
| // @Produce json
 | ||
| // @Param id path string true "产品ID"
 | ||
| // @Success 200 {object} responses.ProductApiConfigResponse "获取成功"
 | ||
| // @Failure 400 {object} interfaces.APIResponse "请求参数错误"
 | ||
| // @Failure 404 {object} interfaces.APIResponse "配置不存在"
 | ||
| // @Router /api/v1/products/{id}/api-config [get]
 | ||
| func (h *ProductHandler) GetProductApiConfig(c *gin.Context) {
 | ||
| 	productID := c.Param("id")
 | ||
| 	if productID == "" {
 | ||
| 		h.responseBuilder.BadRequest(c, "产品ID不能为空")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	config, err := h.apiConfigService.GetProductApiConfig(c.Request.Context(), productID)
 | ||
| 	if err != nil {
 | ||
| 		h.logger.Error("获取产品API配置失败", zap.Error(err), zap.String("product_id", productID))
 | ||
| 		h.responseBuilder.NotFound(c, "产品API配置不存在")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	h.responseBuilder.Success(c, config, "获取产品API配置成功")
 | ||
| }
 | ||
| 
 | ||
| // GetProductApiConfigByCode 根据产品代码获取API配置
 | ||
| // @Summary 根据产品代码获取API配置
 | ||
| // @Description 根据产品代码获取API配置信息
 | ||
| // @Tags 产品API配置
 | ||
| // @Accept json
 | ||
| // @Produce json
 | ||
| // @Param product_code path string true "产品代码"
 | ||
| // @Success 200 {object} responses.ProductApiConfigResponse "获取成功"
 | ||
| // @Failure 400 {object} interfaces.APIResponse "请求参数错误"
 | ||
| // @Failure 404 {object} interfaces.APIResponse "配置不存在"
 | ||
| // @Router /api/v1/products/code/{product_code}/api-config [get]
 | ||
| func (h *ProductHandler) GetProductApiConfigByCode(c *gin.Context) {
 | ||
| 	productCode := c.Param("product_code")
 | ||
| 	if productCode == "" {
 | ||
| 		h.responseBuilder.BadRequest(c, "产品代码不能为空")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	config, err := h.apiConfigService.GetProductApiConfigByCode(c.Request.Context(), productCode)
 | ||
| 	if err != nil {
 | ||
| 		h.logger.Error("根据产品代码获取API配置失败", zap.Error(err), zap.String("product_code", productCode))
 | ||
| 		h.responseBuilder.NotFound(c, "产品API配置不存在")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	h.responseBuilder.Success(c, config, "获取产品API配置成功")
 | ||
| }
 | ||
| 
 | ||
| // ================ 分类相关方法 ================
 | ||
| 
 | ||
| // ListCategories 获取分类列表
 | ||
| // @Summary 获取分类列表
 | ||
| // @Description 获取产品分类列表,支持筛选
 | ||
| // @Tags 数据大厅
 | ||
| // @Accept json
 | ||
| // @Produce json
 | ||
| // @Param page query int false "页码" default(1)
 | ||
| // @Param page_size query int false "每页数量" default(10)
 | ||
| // @Param is_enabled query bool false "是否启用"
 | ||
| // @Param is_visible query bool false "是否可见"
 | ||
| // @Success 200 {object} responses.CategoryListResponse "获取分类列表成功"
 | ||
| // @Failure 500 {object} map[string]interface{} "服务器内部错误"
 | ||
| // @Router /api/v1/categories [get]
 | ||
| func (h *ProductHandler) ListCategories(c *gin.Context) {
 | ||
| 	var query queries.ListCategoriesQuery
 | ||
| 	if err := h.validator.ValidateQuery(c, &query); err != nil {
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	// 设置默认值
 | ||
| 	if query.Page <= 0 {
 | ||
| 		query.Page = 1
 | ||
| 	}
 | ||
| 	if query.PageSize <= 0 {
 | ||
| 		query.PageSize = 10
 | ||
| 	}
 | ||
| 	if query.PageSize > 100 {
 | ||
| 		query.PageSize = 100
 | ||
| 	}
 | ||
| 
 | ||
| 	// 调用应用服务
 | ||
| 	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 keyword query string false "搜索关键词"
 | ||
| // @Param product_name query string false "产品名称"
 | ||
| // @Param start_time query string false "订阅开始时间" format(date-time)
 | ||
| // @Param end_time query string false "订阅结束时间" format(date-time)
 | ||
| // @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 := h.validator.ValidateQuery(c, &query); err != nil {
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	// 设置默认值
 | ||
| 	if query.Page <= 0 {
 | ||
| 		query.Page = 1
 | ||
| 	}
 | ||
| 	if query.PageSize <= 0 {
 | ||
| 		query.PageSize = 10
 | ||
| 	}
 | ||
| 	if query.PageSize > 100 {
 | ||
| 		query.PageSize = 100
 | ||
| 	}
 | ||
| 
 | ||
| 	// 设置默认排序
 | ||
| 	if query.SortBy == "" {
 | ||
| 		query.SortBy = "created_at"
 | ||
| 	}
 | ||
| 	if query.SortOrder == "" {
 | ||
| 		query.SortOrder = "desc"
 | ||
| 	}
 | ||
| 
 | ||
| 	// 用户端不支持企业名称筛选,清空该字段
 | ||
| 	query.CompanyName = ""
 | ||
| 
 | ||
| 	result, err := h.subAppService.ListMySubscriptions(c.Request.Context(), userID, &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.GetMySubscriptionStats(c.Request.Context(), userID)
 | ||
| 	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
 | ||
| 	}
 | ||
| 
 | ||
| 	// 验证订阅是否属于当前用户
 | ||
| 	if result.UserID != userID {
 | ||
| 		h.logger.Error("用户尝试访问不属于自己的订阅", zap.String("user_id", userID), zap.String("subscription_user_id", result.UserID), zap.String("subscription_id", subscriptionID))
 | ||
| 		h.responseBuilder.Forbidden(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} 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/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
 | ||
| 	}
 | ||
| 
 | ||
| 	// 先获取订阅信息以验证权限
 | ||
| 	var query queries.GetSubscriptionQuery
 | ||
| 	query.ID = subscriptionID
 | ||
| 
 | ||
| 	subscription, 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
 | ||
| 	}
 | ||
| 
 | ||
| 	// 验证订阅是否属于当前用户
 | ||
| 	if subscription.UserID != userID {
 | ||
| 		h.logger.Error("用户尝试访问不属于自己的订阅使用情况", zap.String("user_id", userID), zap.String("subscription_user_id", subscription.UserID), zap.String("subscription_id", subscriptionID))
 | ||
| 		h.responseBuilder.Forbidden(c, "无权访问此订阅")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	usage, err := h.subAppService.GetSubscriptionUsage(c.Request.Context(), subscriptionID)
 | ||
| 	if err != nil {
 | ||
| 		h.logger.Error("获取订阅使用情况失败", zap.Error(err))
 | ||
| 		h.responseBuilder.BadRequest(c, err.Error())
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	h.responseBuilder.Success(c, usage, "获取使用情况成功")
 | ||
| }
 | ||
| 
 | ||
| // GetProductDocumentation 获取产品文档
 | ||
| // @Summary 获取产品文档
 | ||
| // @Description 获取指定产品的文档信息
 | ||
| // @Tags 数据大厅
 | ||
| // @Accept json
 | ||
| // @Produce json
 | ||
| // @Param id path string true "产品ID"
 | ||
| // @Success 200 {object} responses.DocumentationResponse "获取产品文档成功"
 | ||
| // @Failure 400 {object} map[string]interface{} "请求参数错误"
 | ||
| // @Failure 404 {object} map[string]interface{} "产品不存在"
 | ||
| // @Failure 500 {object} map[string]interface{} "服务器内部错误"
 | ||
| // @Router /api/v1/products/{id}/documentation [get]
 | ||
| func (h *ProductHandler) GetProductDocumentation(c *gin.Context) {
 | ||
| 	productID := c.Param("id")
 | ||
| 	if productID == "" {
 | ||
| 		h.responseBuilder.BadRequest(c, "产品ID不能为空")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	doc, err := h.documentationAppService.GetDocumentationByProductID(c.Request.Context(), productID)
 | ||
| 	if err != nil {
 | ||
| 		h.logger.Error("获取产品文档失败", zap.Error(err))
 | ||
| 		h.responseBuilder.NotFound(c, "文档不存在")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	h.responseBuilder.Success(c, doc, "获取文档成功")
 | ||
| }
 |