- 将订单的PaidAt和CancelledAt从指针类型改为值类型 - 统一时间字段的判空逻辑,使用IsZero()替代nil检查 - 调整多个数据库模型结构,添加新字段并优化字段顺序 - 为活动奖励设置、用户邀请等表添加新字段 - 更新对应的DAO层代码以匹配模型变更
192 lines
6.6 KiB
Go
192 lines
6.6 KiB
Go
package admin
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"bindbox-game/internal/code"
|
|
"bindbox-game/internal/pkg/core"
|
|
"bindbox-game/internal/pkg/validation"
|
|
prodsvc "bindbox-game/internal/service/product"
|
|
)
|
|
|
|
type createProductRequest struct {
|
|
Name string `json:"name" binding:"required"`
|
|
CategoryID int64 `json:"category_id" binding:"required"`
|
|
ImagesJSON string `json:"images_json"`
|
|
Price int64 `json:"price" binding:"required"`
|
|
Stock int64 `json:"stock" binding:"required"`
|
|
Status int32 `json:"status"`
|
|
Description string `json:"description"`
|
|
}
|
|
|
|
type createProductResponse struct {
|
|
ID int64 `json:"id"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
// CreateProduct 创建商品
|
|
// @Summary 创建商品
|
|
// @Tags 管理端.商品
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param RequestBody body createProductRequest true "请求参数"
|
|
// @Success 200 {object} createProductResponse
|
|
// @Failure 400 {object} code.Failure
|
|
// @Router /api/admin/products [post]
|
|
// @Security LoginVerifyToken
|
|
func (h *handler) CreateProduct() core.HandlerFunc {
|
|
return func(ctx core.Context) {
|
|
req := new(createProductRequest)
|
|
res := new(createProductResponse)
|
|
if err := ctx.ShouldBindJSON(req); err != nil {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
|
return
|
|
}
|
|
if ctx.SessionUserInfo().IsSuper != 1 {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
|
|
return
|
|
}
|
|
item, err := h.product.CreateProduct(ctx.RequestContext(), prodsvc.CreateProductInput{Name: req.Name, CategoryID: req.CategoryID, ImagesJSON: req.ImagesJSON, Price: req.Price, Stock: req.Stock, Status: req.Status, Description: req.Description})
|
|
if err != nil {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
|
|
return
|
|
}
|
|
res.ID = item.ID
|
|
res.Message = "操作成功"
|
|
ctx.Payload(res)
|
|
}
|
|
}
|
|
|
|
type modifyProductRequest struct {
|
|
Name *string `json:"name"`
|
|
CategoryID *int64 `json:"category_id"`
|
|
ImagesJSON *string `json:"images_json"`
|
|
Price *int64 `json:"price"`
|
|
Stock *int64 `json:"stock"`
|
|
Status *int32 `json:"status"`
|
|
Description *string `json:"description"`
|
|
}
|
|
|
|
// ModifyProduct 修改商品
|
|
// @Summary 修改商品
|
|
// @Tags 管理端.商品
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param product_id path string true "商品ID"
|
|
// @Param RequestBody body modifyProductRequest true "请求参数"
|
|
// @Success 200 {object} pcSimpleMessage
|
|
// @Failure 400 {object} code.Failure
|
|
// @Router /api/admin/products/{product_id} [put]
|
|
// @Security LoginVerifyToken
|
|
func (h *handler) ModifyProduct() core.HandlerFunc {
|
|
return func(ctx core.Context) {
|
|
req := new(modifyProductRequest)
|
|
if err := ctx.ShouldBindJSON(req); err != nil {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
|
return
|
|
}
|
|
idStr := ctx.Param("product_id")
|
|
id, _ := strconv.ParseInt(idStr, 10, 64)
|
|
if ctx.SessionUserInfo().IsSuper != 1 {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
|
|
return
|
|
}
|
|
if err := h.product.ModifyProduct(ctx.RequestContext(), id, prodsvc.ModifyProductInput{Name: req.Name, CategoryID: req.CategoryID, ImagesJSON: req.ImagesJSON, Price: req.Price, Stock: req.Stock, Status: req.Status, Description: req.Description}); err != nil {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
|
|
return
|
|
}
|
|
ctx.Payload(pcSimpleMessage{Message: "操作成功"})
|
|
}
|
|
}
|
|
|
|
// DeleteProduct 删除商品
|
|
// @Summary 删除商品
|
|
// @Tags 管理端.商品
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param product_id path string true "商品ID"
|
|
// @Success 200 {object} pcSimpleMessage
|
|
// @Failure 400 {object} code.Failure
|
|
// @Router /api/admin/products/{product_id} [delete]
|
|
// @Security LoginVerifyToken
|
|
func (h *handler) DeleteProduct() core.HandlerFunc {
|
|
return func(ctx core.Context) {
|
|
idStr := ctx.Param("product_id")
|
|
id, _ := strconv.ParseInt(idStr, 10, 64)
|
|
if ctx.SessionUserInfo().IsSuper != 1 {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
|
|
return
|
|
}
|
|
if err := h.product.DeleteProduct(ctx.RequestContext(), id); err != nil {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
|
|
return
|
|
}
|
|
ctx.Payload(pcSimpleMessage{Message: "操作成功"})
|
|
}
|
|
}
|
|
|
|
type listProductsRequest struct {
|
|
Name string `form:"name"`
|
|
CategoryID *int64 `form:"category_id"`
|
|
Status *int32 `form:"status"`
|
|
Page int `form:"page"`
|
|
PageSize int `form:"page_size"`
|
|
}
|
|
|
|
type productItem struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"`
|
|
CategoryID int64 `json:"category_id"`
|
|
ImagesJSON string `json:"images_json"`
|
|
Price int64 `json:"price"`
|
|
Stock int64 `json:"stock"`
|
|
Sales int64 `json:"sales"`
|
|
Status int32 `json:"status"`
|
|
Description string `json:"description"`
|
|
}
|
|
type listProductsResponse struct {
|
|
Page int `json:"page"`
|
|
PageSize int `json:"page_size"`
|
|
Total int64 `json:"total"`
|
|
List []productItem `json:"list"`
|
|
}
|
|
|
|
// ListProducts 查看商品列表
|
|
// @Summary 查看商品列表
|
|
// @Tags 管理端.商品
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param name query string false "名称"
|
|
// @Param category_id query int false "分类ID"
|
|
// @Param status query int false "状态"
|
|
// @Param page query int true "页码" default(1)
|
|
// @Param page_size query int true "每页数量" default(20)
|
|
// @Success 200 {object} listProductsResponse
|
|
// @Failure 400 {object} code.Failure
|
|
// @Router /api/admin/products [get]
|
|
// @Security LoginVerifyToken
|
|
func (h *handler) ListProducts() core.HandlerFunc {
|
|
return func(ctx core.Context) {
|
|
req := new(listProductsRequest)
|
|
res := new(listProductsResponse)
|
|
if err := ctx.ShouldBindForm(req); err != nil {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
|
return
|
|
}
|
|
items, total, err := h.product.ListProducts(ctx.RequestContext(), prodsvc.ListProductsInput{Name: req.Name, CategoryID: req.CategoryID, Status: req.Status, Page: req.Page, PageSize: req.PageSize})
|
|
if err != nil {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
|
|
return
|
|
}
|
|
res.Page = req.Page
|
|
res.PageSize = req.PageSize
|
|
res.Total = total
|
|
res.List = make([]productItem, len(items))
|
|
for i, it := range items {
|
|
res.List[i] = productItem{ID: it.ID, Name: it.Name, CategoryID: it.CategoryID, ImagesJSON: it.ImagesJSON, Price: it.Price, Stock: it.Stock, Sales: it.Sales, Status: it.Status, Description: it.Description}
|
|
}
|
|
ctx.Payload(res)
|
|
}
|
|
}
|