1056 lines
38 KiB
Go
1056 lines
38 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/application/product/dto/responses"
|
||
"tyapi-server/internal/shared/interfaces"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
// ProductAdminHandler 产品管理员HTTP处理器
|
||
type ProductAdminHandler struct {
|
||
productAppService product.ProductApplicationService
|
||
categoryAppService product.CategoryApplicationService
|
||
subscriptionAppService product.SubscriptionApplicationService
|
||
documentationAppService product.DocumentationApplicationServiceInterface
|
||
responseBuilder interfaces.ResponseBuilder
|
||
validator interfaces.RequestValidator
|
||
logger *zap.Logger
|
||
}
|
||
|
||
// NewProductAdminHandler 创建产品管理员HTTP处理器
|
||
func NewProductAdminHandler(
|
||
productAppService product.ProductApplicationService,
|
||
categoryAppService product.CategoryApplicationService,
|
||
subscriptionAppService product.SubscriptionApplicationService,
|
||
documentationAppService product.DocumentationApplicationServiceInterface,
|
||
responseBuilder interfaces.ResponseBuilder,
|
||
validator interfaces.RequestValidator,
|
||
logger *zap.Logger,
|
||
) *ProductAdminHandler {
|
||
return &ProductAdminHandler{
|
||
productAppService: productAppService,
|
||
categoryAppService: categoryAppService,
|
||
subscriptionAppService: subscriptionAppService,
|
||
documentationAppService: documentationAppService,
|
||
responseBuilder: responseBuilder,
|
||
validator: validator,
|
||
logger: logger,
|
||
}
|
||
}
|
||
|
||
// CreateProduct 创建产品
|
||
// @Summary 创建产品
|
||
// @Description 管理员创建新产品
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param request body commands.CreateProductCommand true "创建产品请求"
|
||
// @Success 201 {object} map[string]interface{} "产品创建成功"
|
||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||
// @Router /api/v1/admin/products [post]
|
||
func (h *ProductAdminHandler) CreateProduct(c *gin.Context) {
|
||
var cmd commands.CreateProductCommand
|
||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
|
||
if err := h.productAppService.CreateProduct(c.Request.Context(), &cmd); err != nil {
|
||
h.logger.Error("创建产品失败", zap.Error(err))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Created(c, nil, "产品创建成功")
|
||
}
|
||
|
||
// UpdateProduct 更新产品
|
||
// @Summary 更新产品
|
||
// @Description 管理员更新产品信息
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "产品ID"
|
||
// @Param request body commands.UpdateProductCommand 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/admin/products/{id} [put]
|
||
func (h *ProductAdminHandler) UpdateProduct(c *gin.Context) {
|
||
var cmd commands.UpdateProductCommand
|
||
cmd.ID = c.Param("id")
|
||
if cmd.ID == "" {
|
||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||
return
|
||
}
|
||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
|
||
if err := h.productAppService.UpdateProduct(c.Request.Context(), &cmd); err != nil {
|
||
h.logger.Error("更新产品失败", zap.Error(err))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, nil, "产品更新成功")
|
||
}
|
||
|
||
// DeleteProduct 删除产品
|
||
// @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/admin/products/{id} [delete]
|
||
func (h *ProductAdminHandler) DeleteProduct(c *gin.Context) {
|
||
var cmd commands.DeleteProductCommand
|
||
if err := h.validator.ValidateParam(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
|
||
if err := h.productAppService.DeleteProduct(c.Request.Context(), &cmd); err != nil {
|
||
h.logger.Error("删除产品失败", zap.Error(err))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, nil, "产品删除成功")
|
||
}
|
||
|
||
// CreateCategory 创建分类
|
||
// @Summary 创建分类
|
||
// @Description 管理员创建新产品分类
|
||
// @Tags 分类管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param request body commands.CreateCategoryCommand true "创建分类请求"
|
||
// @Success 201 {object} map[string]interface{} "分类创建成功"
|
||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||
// @Router /api/v1/admin/product-categories [post]
|
||
func (h *ProductAdminHandler) CreateCategory(c *gin.Context) {
|
||
var cmd commands.CreateCategoryCommand
|
||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
|
||
if err := h.categoryAppService.CreateCategory(c.Request.Context(), &cmd); err != nil {
|
||
h.logger.Error("创建分类失败", zap.Error(err))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Created(c, nil, "分类创建成功")
|
||
}
|
||
|
||
// UpdateCategory 更新分类
|
||
// @Summary 更新分类
|
||
// @Description 管理员更新产品分类信息
|
||
// @Tags 分类管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "分类ID"
|
||
// @Param request body commands.UpdateCategoryCommand 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/admin/product-categories/{id} [put]
|
||
func (h *ProductAdminHandler) UpdateCategory(c *gin.Context) {
|
||
var cmd commands.UpdateCategoryCommand
|
||
if err := h.validator.ValidateParam(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
|
||
if err := h.categoryAppService.UpdateCategory(c.Request.Context(), &cmd); err != nil {
|
||
h.logger.Error("更新分类失败", zap.Error(err))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, nil, "分类更新成功")
|
||
}
|
||
|
||
// DeleteCategory 删除分类
|
||
// @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/admin/product-categories/{id} [delete]
|
||
func (h *ProductAdminHandler) DeleteCategory(c *gin.Context) {
|
||
var cmd commands.DeleteCategoryCommand
|
||
if err := h.validator.ValidateParam(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
|
||
if err := h.categoryAppService.DeleteCategory(c.Request.Context(), &cmd); err != nil {
|
||
h.logger.Error("删除分类失败", zap.Error(err))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, nil, "分类删除成功")
|
||
}
|
||
|
||
// UpdateSubscriptionPrice 更新订阅价格
|
||
// @Summary 更新订阅价格
|
||
// @Description 管理员修改用户订阅价格
|
||
// @Tags 订阅管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "订阅ID"
|
||
// @Param request body commands.UpdateSubscriptionPriceCommand 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/admin/subscriptions/{id}/price [put]
|
||
func (h *ProductAdminHandler) UpdateSubscriptionPrice(c *gin.Context) {
|
||
var cmd commands.UpdateSubscriptionPriceCommand
|
||
if err := h.validator.ValidateParam(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
|
||
if err := h.subscriptionAppService.UpdateSubscriptionPrice(c.Request.Context(), &cmd); err != nil {
|
||
h.logger.Error("更新订阅价格失败", zap.Error(err))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, nil, "订阅价格更新成功")
|
||
}
|
||
|
||
// ListProducts 获取产品列表(管理员)
|
||
// @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 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 sort_by query string false "排序字段"
|
||
// @Param sort_order query string false "排序方向" Enums(asc, desc)
|
||
// @Success 200 {object} responses.ProductAdminListResponse "获取产品列表成功"
|
||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||
// @Router /api/v1/admin/products [get]
|
||
func (h *ProductAdminHandler) ListProducts(c *gin.Context) {
|
||
// 解析查询参数
|
||
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
|
||
}
|
||
}
|
||
|
||
// 产品类型筛选
|
||
if isPackage := c.Query("is_package"); isPackage != "" {
|
||
if pkg, err := strconv.ParseBool(isPackage); err == nil {
|
||
filters["is_package"] = pkg
|
||
}
|
||
}
|
||
|
||
// 排序字段
|
||
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.productAppService.ListProductsForAdmin(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 *ProductAdminHandler) 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
|
||
}
|
||
|
||
// GetProductDetail 获取产品详情
|
||
// @Summary 获取产品详情
|
||
// @Description 管理员获取产品详细信息
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "产品ID"
|
||
// @Param with_document query bool false "是否包含文档信息"
|
||
// @Success 200 {object} responses.ProductAdminInfoResponse "获取产品详情成功"
|
||
// @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/admin/products/{id} [get]
|
||
func (h *ProductAdminHandler) 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.productAppService.GetProductByIDForAdmin(c.Request.Context(), &query)
|
||
if err != nil {
|
||
h.logger.Error("获取产品详情失败", zap.Error(err))
|
||
h.responseBuilder.NotFound(c, "产品不存在")
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, result, "获取产品详情成功")
|
||
}
|
||
|
||
// GetAvailableProducts 获取可选子产品列表
|
||
// @Summary 获取可选子产品列表
|
||
// @Description 管理员获取可选作组合包子产品的产品列表
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param exclude_package_id query string false "排除的组合包ID"
|
||
// @Param keyword query string false "搜索关键词"
|
||
// @Param category_id query string false "分类ID"
|
||
// @Param page query int false "页码" default(1)
|
||
// @Param page_size query int false "每页数量" default(20)
|
||
// @Success 200 {object} responses.ProductListResponse "获取可选产品列表成功"
|
||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||
// @Router /api/v1/admin/products/available [get]
|
||
func (h *ProductAdminHandler) GetAvailableProducts(c *gin.Context) {
|
||
var query queries.GetAvailableProductsQuery
|
||
if err := h.validator.ValidateQuery(c, &query); err != nil {
|
||
return
|
||
}
|
||
|
||
// 设置默认值
|
||
if query.Page <= 0 {
|
||
query.Page = 1
|
||
}
|
||
if query.PageSize <= 0 {
|
||
query.PageSize = 20
|
||
}
|
||
if query.PageSize > 100 {
|
||
query.PageSize = 100
|
||
}
|
||
|
||
result, err := h.productAppService.GetAvailableProducts(c.Request.Context(), &query)
|
||
if err != nil {
|
||
h.logger.Error("获取可选产品列表失败", zap.Error(err))
|
||
h.responseBuilder.InternalError(c, "获取可选产品列表失败")
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, result, "获取可选产品列表成功")
|
||
}
|
||
|
||
// AddPackageItem 添加组合包子产品
|
||
// @Summary 添加组合包子产品
|
||
// @Description 管理员向组合包添加子产品
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "组合包ID"
|
||
// @Param command body commands.AddPackageItemCommand 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/admin/products/{id}/package-items [post]
|
||
func (h *ProductAdminHandler) AddPackageItem(c *gin.Context) {
|
||
packageID := c.Param("id")
|
||
if packageID == "" {
|
||
h.responseBuilder.BadRequest(c, "组合包ID不能为空")
|
||
return
|
||
}
|
||
|
||
var cmd commands.AddPackageItemCommand
|
||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
|
||
err := h.productAppService.AddPackageItem(c.Request.Context(), packageID, &cmd)
|
||
if err != nil {
|
||
h.logger.Error("添加组合包子产品失败", zap.Error(err), zap.String("package_id", packageID))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, nil, "添加组合包子产品成功")
|
||
}
|
||
|
||
// UpdatePackageItem 更新组合包子产品
|
||
// @Summary 更新组合包子产品
|
||
// @Description 管理员更新组合包子产品信息
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "组合包ID"
|
||
// @Param item_id path string true "子产品项目ID"
|
||
// @Param command body commands.UpdatePackageItemCommand 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/admin/products/{id}/package-items/{item_id} [put]
|
||
func (h *ProductAdminHandler) UpdatePackageItem(c *gin.Context) {
|
||
packageID := c.Param("id")
|
||
itemID := c.Param("item_id")
|
||
if packageID == "" || itemID == "" {
|
||
h.responseBuilder.BadRequest(c, "参数不能为空")
|
||
return
|
||
}
|
||
|
||
var cmd commands.UpdatePackageItemCommand
|
||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
|
||
err := h.productAppService.UpdatePackageItem(c.Request.Context(), packageID, itemID, &cmd)
|
||
if err != nil {
|
||
h.logger.Error("更新组合包子产品失败", zap.Error(err), zap.String("package_id", packageID), zap.String("item_id", itemID))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, nil, "更新组合包子产品成功")
|
||
}
|
||
|
||
// RemovePackageItem 移除组合包子产品
|
||
// @Summary 移除组合包子产品
|
||
// @Description 管理员从组合包移除子产品
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "组合包ID"
|
||
// @Param item_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/admin/products/{id}/package-items/{item_id} [delete]
|
||
func (h *ProductAdminHandler) RemovePackageItem(c *gin.Context) {
|
||
packageID := c.Param("id")
|
||
itemID := c.Param("item_id")
|
||
if packageID == "" || itemID == "" {
|
||
h.responseBuilder.BadRequest(c, "参数不能为空")
|
||
return
|
||
}
|
||
|
||
err := h.productAppService.RemovePackageItem(c.Request.Context(), packageID, itemID)
|
||
if err != nil {
|
||
h.logger.Error("移除组合包子产品失败", zap.Error(err), zap.String("package_id", packageID), zap.String("item_id", itemID))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, nil, "移除组合包子产品成功")
|
||
}
|
||
|
||
// ReorderPackageItems 重新排序组合包子产品
|
||
// @Summary 重新排序组合包子产品
|
||
// @Description 管理员重新排序组合包子产品
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "组合包ID"
|
||
// @Param command body commands.ReorderPackageItemsCommand 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/admin/products/{id}/package-items/reorder [put]
|
||
func (h *ProductAdminHandler) ReorderPackageItems(c *gin.Context) {
|
||
packageID := c.Param("id")
|
||
if packageID == "" {
|
||
h.responseBuilder.BadRequest(c, "组合包ID不能为空")
|
||
return
|
||
}
|
||
|
||
var cmd commands.ReorderPackageItemsCommand
|
||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
|
||
err := h.productAppService.ReorderPackageItems(c.Request.Context(), packageID, &cmd)
|
||
if err != nil {
|
||
h.logger.Error("重新排序组合包子产品失败", zap.Error(err), zap.String("package_id", packageID))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, nil, "重新排序组合包子产品成功")
|
||
}
|
||
|
||
// UpdatePackageItems 批量更新组合包子产品
|
||
// @Summary 批量更新组合包子产品
|
||
// @Description 管理员批量更新组合包子产品配置
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "组合包ID"
|
||
// @Param command body commands.UpdatePackageItemsCommand 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/admin/products/{id}/package-items/batch [put]
|
||
func (h *ProductAdminHandler) UpdatePackageItems(c *gin.Context) {
|
||
packageID := c.Param("id")
|
||
if packageID == "" {
|
||
h.responseBuilder.BadRequest(c, "组合包ID不能为空")
|
||
return
|
||
}
|
||
|
||
var cmd commands.UpdatePackageItemsCommand
|
||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
|
||
err := h.productAppService.UpdatePackageItems(c.Request.Context(), packageID, &cmd)
|
||
if err != nil {
|
||
h.logger.Error("批量更新组合包子产品失败", zap.Error(err), zap.String("package_id", packageID))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, nil, "批量更新组合包子产品成功")
|
||
}
|
||
|
||
// ListCategories 获取分类列表(管理员)
|
||
// @Summary 获取分类列表
|
||
// @Description 管理员获取产品分类列表
|
||
// @Tags 分类管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param page query int false "页码" default(1)
|
||
// @Param page_size query int false "每页数量" default(10)
|
||
// @Success 200 {object} responses.CategoryListResponse "获取分类列表成功"
|
||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||
// @Router /api/v1/admin/product-categories [get]
|
||
func (h *ProductAdminHandler) 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
|
||
}
|
||
|
||
result, err := h.categoryAppService.ListCategories(c.Request.Context(), &query)
|
||
if err != nil {
|
||
h.logger.Error("获取分类列表失败", zap.Error(err))
|
||
h.responseBuilder.InternalError(c, "获取分类列表失败")
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, result, "获取分类列表成功")
|
||
}
|
||
|
||
// GetCategoryDetail 获取分类详情(管理员)
|
||
// @Summary 获取分类详情
|
||
// @Description 管理员获取分类详细信息
|
||
// @Tags 分类管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "分类ID"
|
||
// @Success 200 {object} responses.CategoryInfoResponse "获取分类详情成功"
|
||
// @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/admin/product-categories/{id} [get]
|
||
func (h *ProductAdminHandler) GetCategoryDetail(c *gin.Context) {
|
||
var query queries.GetCategoryQuery
|
||
query.ID = c.Param("id")
|
||
|
||
if query.ID == "" {
|
||
h.responseBuilder.BadRequest(c, "分类ID不能为空")
|
||
return
|
||
}
|
||
|
||
result, err := h.categoryAppService.GetCategoryByID(c.Request.Context(), &query)
|
||
if err != nil {
|
||
h.logger.Error("获取分类详情失败", zap.Error(err), zap.String("category_id", query.ID))
|
||
h.responseBuilder.NotFound(c, "分类不存在")
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, result, "获取分类详情成功")
|
||
}
|
||
|
||
// ListSubscriptions 获取订阅列表(管理员)
|
||
// @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 "订阅状态"
|
||
// @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/admin/subscriptions [get]
|
||
func (h *ProductAdminHandler) ListSubscriptions(c *gin.Context) {
|
||
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
|
||
}
|
||
|
||
result, err := h.subscriptionAppService.ListSubscriptions(c.Request.Context(), &query)
|
||
if err != nil {
|
||
h.logger.Error("获取订阅列表失败", zap.Error(err))
|
||
h.responseBuilder.InternalError(c, "获取订阅列表失败")
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, result, "获取订阅列表成功")
|
||
}
|
||
|
||
// GetSubscriptionStats 获取订阅统计(管理员)
|
||
// @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/admin/subscriptions/stats [get]
|
||
func (h *ProductAdminHandler) GetSubscriptionStats(c *gin.Context) {
|
||
result, err := h.subscriptionAppService.GetSubscriptionStats(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 管理员获取产品的API配置信息,如果不存在则返回空配置
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "产品ID"
|
||
// @Success 200 {object} responses.ProductApiConfigResponse "获取API配置成功"
|
||
// @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/admin/products/{id}/api-config [get]
|
||
func (h *ProductAdminHandler) GetProductApiConfig(c *gin.Context) {
|
||
productID := c.Param("id")
|
||
if productID == "" {
|
||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||
return
|
||
}
|
||
|
||
result, err := h.productAppService.GetProductApiConfig(c.Request.Context(), productID)
|
||
if err != nil {
|
||
// 如果是配置不存在的错误,返回空配置而不是错误
|
||
if err.Error() == "record not found" || err.Error() == "产品API配置不存在" {
|
||
// 返回空的配置结构,让前端可以创建新配置
|
||
emptyConfig := &responses.ProductApiConfigResponse{
|
||
ID: "",
|
||
ProductID: productID,
|
||
RequestParams: []responses.RequestParamResponse{},
|
||
ResponseFields: []responses.ResponseFieldResponse{},
|
||
ResponseExample: map[string]interface{}{},
|
||
}
|
||
h.responseBuilder.Success(c, emptyConfig, "获取API配置成功")
|
||
return
|
||
}
|
||
|
||
h.logger.Error("获取产品API配置失败", zap.Error(err), zap.String("product_id", productID))
|
||
h.responseBuilder.NotFound(c, "产品不存在")
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, result, "获取API配置成功")
|
||
}
|
||
|
||
// CreateProductApiConfig 创建产品API配置
|
||
// @Summary 创建产品API配置
|
||
// @Description 管理员为产品创建API配置
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "产品ID"
|
||
// @Param request body responses.ProductApiConfigResponse true "API配置信息"
|
||
// @Success 201 {object} map[string]interface{} "API配置创建成功"
|
||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||
// @Failure 409 {object} map[string]interface{} "API配置已存在"
|
||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||
// @Router /api/v1/admin/products/{id}/api-config [post]
|
||
func (h *ProductAdminHandler) CreateProductApiConfig(c *gin.Context) {
|
||
productID := c.Param("id")
|
||
if productID == "" {
|
||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||
return
|
||
}
|
||
|
||
var configResponse responses.ProductApiConfigResponse
|
||
if err := h.validator.BindAndValidate(c, &configResponse); err != nil {
|
||
return
|
||
}
|
||
|
||
if err := h.productAppService.CreateProductApiConfig(c.Request.Context(), productID, &configResponse); err != nil {
|
||
h.logger.Error("创建产品API配置失败", zap.Error(err), zap.String("product_id", productID))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Created(c, nil, "API配置创建成功")
|
||
}
|
||
|
||
// UpdateProductApiConfig 更新产品API配置
|
||
// @Summary 更新产品API配置
|
||
// @Description 管理员更新产品的API配置
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "产品ID"
|
||
// @Param request body responses.ProductApiConfigResponse true "API配置信息"
|
||
// @Success 200 {object} map[string]interface{} "API配置更新成功"
|
||
// @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/admin/products/{id}/api-config [put]
|
||
func (h *ProductAdminHandler) UpdateProductApiConfig(c *gin.Context) {
|
||
productID := c.Param("id")
|
||
if productID == "" {
|
||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||
return
|
||
}
|
||
|
||
var configResponse responses.ProductApiConfigResponse
|
||
if err := h.validator.BindAndValidate(c, &configResponse); err != nil {
|
||
return
|
||
}
|
||
|
||
// 先获取现有配置以获取配置ID
|
||
existingConfig, err := h.productAppService.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
|
||
}
|
||
|
||
if err := h.productAppService.UpdateProductApiConfig(c.Request.Context(), existingConfig.ID, &configResponse); err != nil {
|
||
h.logger.Error("更新产品API配置失败", zap.Error(err), zap.String("product_id", productID))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, nil, "API配置更新成功")
|
||
}
|
||
|
||
// DeleteProductApiConfig 删除产品API配置
|
||
// @Summary 删除产品API配置
|
||
// @Description 管理员删除产品的API配置
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "产品ID"
|
||
// @Success 200 {object} map[string]interface{} "API配置删除成功"
|
||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||
// @Failure 404 {object} map[string]interface{} "产品或API配置不存在"
|
||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||
// @Router /api/v1/admin/products/{id}/api-config [delete]
|
||
func (h *ProductAdminHandler) DeleteProductApiConfig(c *gin.Context) {
|
||
productID := c.Param("id")
|
||
if productID == "" {
|
||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||
return
|
||
}
|
||
|
||
if err := h.productAppService.DeleteProductApiConfig(c.Request.Context(), productID); err != nil {
|
||
h.logger.Error("删除产品API配置失败", zap.Error(err))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, nil, "API配置删除成功")
|
||
}
|
||
|
||
// GetProductDocumentation 获取产品文档
|
||
// @Summary 获取产品文档
|
||
// @Description 管理员获取产品的文档信息
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "产品ID"
|
||
// @Success 200 {object} responses.DocumentationResponse "获取文档成功"
|
||
// @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/admin/products/{id}/documentation [get]
|
||
func (h *ProductAdminHandler) 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.Info("产品文档不存在,返回空数据", zap.String("product_id", productID))
|
||
h.responseBuilder.Success(c, nil, "文档不存在")
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, doc, "获取文档成功")
|
||
}
|
||
|
||
// CreateOrUpdateProductDocumentation 创建或更新产品文档
|
||
// @Summary 创建或更新产品文档
|
||
// @Description 管理员创建或更新产品的文档信息,如果文档不存在则创建,存在则更新
|
||
// @Tags 产品管理
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Security Bearer
|
||
// @Param id path string true "产品ID"
|
||
// @Param request body commands.CreateDocumentationCommand true "文档信息"
|
||
// @Success 200 {object} responses.DocumentationResponse "文档操作成功"
|
||
// @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/admin/products/{id}/documentation [post]
|
||
func (h *ProductAdminHandler) CreateOrUpdateProductDocumentation(c *gin.Context) {
|
||
productID := c.Param("id")
|
||
if productID == "" {
|
||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||
return
|
||
}
|
||
|
||
var cmd commands.CreateDocumentationCommand
|
||
cmd.ProductID = productID
|
||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||
return
|
||
}
|
||
|
||
// 先尝试获取现有文档
|
||
existingDoc, err := h.documentationAppService.GetDocumentationByProductID(c.Request.Context(), productID)
|
||
if err != nil {
|
||
// 文档不存在,创建新文档
|
||
doc, err := h.documentationAppService.CreateDocumentation(c.Request.Context(), &cmd)
|
||
if err != nil {
|
||
h.logger.Error("创建产品文档失败", zap.Error(err))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
h.responseBuilder.Created(c, doc, "文档创建成功")
|
||
return
|
||
}
|
||
|
||
// 文档存在,更新文档
|
||
updateCmd := commands.UpdateDocumentationCommand{
|
||
RequestURL: cmd.RequestURL,
|
||
RequestMethod: cmd.RequestMethod,
|
||
BasicInfo: cmd.BasicInfo,
|
||
RequestParams: cmd.RequestParams,
|
||
ResponseFields: cmd.ResponseFields,
|
||
ResponseExample: cmd.ResponseExample,
|
||
ErrorCodes: cmd.ErrorCodes,
|
||
}
|
||
|
||
doc, err := h.documentationAppService.UpdateDocumentation(c.Request.Context(), existingDoc.ID, &updateCmd)
|
||
if err != nil {
|
||
h.logger.Error("更新产品文档失败", zap.Error(err))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, doc, "文档更新成功")
|
||
}
|
||
|
||
// DeleteProductDocumentation 删除产品文档
|
||
// @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/admin/products/{id}/documentation [delete]
|
||
func (h *ProductAdminHandler) DeleteProductDocumentation(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.responseBuilder.NotFound(c, "文档不存在")
|
||
return
|
||
}
|
||
|
||
// 删除文档
|
||
if err := h.documentationAppService.DeleteDocumentation(c.Request.Context(), doc.ID); err != nil {
|
||
h.logger.Error("删除产品文档失败", zap.Error(err))
|
||
h.responseBuilder.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
h.responseBuilder.Success(c, nil, "文档删除成功")
|
||
}
|