feat(security): 支持通过环境变量配置主密钥和JWT密钥 refactor(router): 移除开发便捷路由接口 feat(admin): 添加超级管理员权限检查 feat(titles): 增加系统标题效果参数验证逻辑
621 lines
21 KiB
Go
621 lines
21 KiB
Go
package admin
|
||
|
||
import (
|
||
"net/http"
|
||
"strconv"
|
||
"time"
|
||
|
||
"bindbox-game/internal/code"
|
||
"bindbox-game/internal/pkg/core"
|
||
"bindbox-game/internal/pkg/validation"
|
||
"bindbox-game/internal/repository/mysql/model"
|
||
"bindbox-game/internal/service/user"
|
||
)
|
||
|
||
type listUsersRequest struct {
|
||
Page int `form:"page"`
|
||
PageSize int `form:"page_size"`
|
||
Nickname string `form:"nickname"`
|
||
InviteCode string `form:"inviteCode"`
|
||
StartDate string `form:"startDate"`
|
||
EndDate string `form:"endDate"`
|
||
}
|
||
type listUsersResponse struct {
|
||
Page int `json:"page"`
|
||
PageSize int `json:"page_size"`
|
||
Total int64 `json:"total"`
|
||
List []adminUserItem `json:"list"`
|
||
}
|
||
|
||
// ListAppUsers 管理端用户列表
|
||
// @Summary 管理端用户列表
|
||
// @Description 查看APP端用户分页列表
|
||
// @Tags 管理端.用户
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param page query int true "页码" default(1)
|
||
// @Param page_size query int true "每页数量,最多100" default(20)
|
||
// @Param nickname query string false "用户昵称"
|
||
// @Param inviteCode query string false "邀请码"
|
||
// @Param startDate query string false "开始日期(YYYY-MM-DD)"
|
||
// @Param endDate query string false "结束日期(YYYY-MM-DD)"
|
||
// @Success 200 {object} listUsersResponse
|
||
// @Failure 400 {object} code.Failure
|
||
// @Router /api/admin/users [get]
|
||
// @Security LoginVerifyToken
|
||
func (h *handler) ListAppUsers() core.HandlerFunc {
|
||
return func(ctx core.Context) {
|
||
req := new(listUsersRequest)
|
||
rsp := new(listUsersResponse)
|
||
if err := ctx.ShouldBindForm(req); err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
||
return
|
||
}
|
||
if req.Page <= 0 {
|
||
req.Page = 1
|
||
}
|
||
if req.PageSize <= 0 {
|
||
req.PageSize = 20
|
||
}
|
||
if req.PageSize > 100 {
|
||
req.PageSize = 100
|
||
}
|
||
q := h.readDB.Users.WithContext(ctx.RequestContext()).ReadDB()
|
||
|
||
// 应用搜索条件
|
||
if req.Nickname != "" {
|
||
q = q.Where(h.readDB.Users.Nickname.Like("%" + req.Nickname + "%"))
|
||
}
|
||
if req.InviteCode != "" {
|
||
q = q.Where(h.readDB.Users.InviteCode.Eq(req.InviteCode))
|
||
}
|
||
if req.StartDate != "" {
|
||
if startTime, err := time.Parse("2006-01-02", req.StartDate); err == nil {
|
||
q = q.Where(h.readDB.Users.CreatedAt.Gte(startTime))
|
||
}
|
||
}
|
||
if req.EndDate != "" {
|
||
if endTime, err := time.Parse("2006-01-02", req.EndDate); err == nil {
|
||
// 设置结束时间为当天的23:59:59
|
||
endTime = endTime.Add(24 * time.Hour).Add(-time.Second)
|
||
q = q.Where(h.readDB.Users.CreatedAt.Lte(endTime))
|
||
}
|
||
}
|
||
|
||
total, err := q.Count()
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 20101, err.Error()))
|
||
return
|
||
}
|
||
rows, err := q.Order(h.readDB.Users.ID.Desc()).Offset((req.Page - 1) * req.PageSize).Limit(req.PageSize).Find()
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 20102, err.Error()))
|
||
return
|
||
}
|
||
rsp.Page = req.Page
|
||
rsp.PageSize = req.PageSize
|
||
rsp.Total = total
|
||
rsp.List = make([]adminUserItem, len(rows))
|
||
for i, v := range rows {
|
||
rsp.List[i] = adminUserItem{ID: v.ID, Nickname: v.Nickname, Avatar: v.Avatar, InviteCode: v.InviteCode, InviterID: v.InviterID, CreatedAt: v.CreatedAt.Format("2006-01-02 15:04:05")}
|
||
}
|
||
ctx.Payload(rsp)
|
||
}
|
||
}
|
||
|
||
type listInvitesRequest struct {
|
||
Page int `form:"page"`
|
||
PageSize int `form:"page_size"`
|
||
}
|
||
type listInvitesResponse struct {
|
||
Page int `json:"page"`
|
||
PageSize int `json:"page_size"`
|
||
Total int64 `json:"total"`
|
||
List []adminUserItem `json:"list"`
|
||
}
|
||
|
||
// ListUserInvites 查看用户邀请列表
|
||
// @Summary 查看用户邀请列表
|
||
// @Description 查看指定用户邀请的用户列表
|
||
// @Tags 管理端.用户
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path integer true "用户ID"
|
||
// @Param page query int true "页码" default(1)
|
||
// @Param page_size query int true "每页数量,最多100" default(20)
|
||
// @Success 200 {object} listInvitesResponse
|
||
// @Failure 400 {object} code.Failure
|
||
// @Router /api/admin/users/{user_id}/invites [get]
|
||
// @Security LoginVerifyToken
|
||
func (h *handler) ListUserInvites() core.HandlerFunc {
|
||
return func(ctx core.Context) {
|
||
req := new(listInvitesRequest)
|
||
rsp := new(listInvitesResponse)
|
||
if err := ctx.ShouldBindForm(req); err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
||
return
|
||
}
|
||
userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
|
||
return
|
||
}
|
||
rows, total, err := h.user.ListInvites(ctx.RequestContext(), userID, req.Page, req.PageSize)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 20103, err.Error()))
|
||
return
|
||
}
|
||
rsp.Page = req.Page
|
||
rsp.PageSize = req.PageSize
|
||
rsp.Total = total
|
||
rsp.List = make([]adminUserItem, len(rows))
|
||
for i, v := range rows {
|
||
rsp.List[i] = adminUserItem{ID: v.ID, Nickname: v.Nickname, Avatar: v.Avatar, InviteCode: v.InviteCode, InviterID: v.InviterID, CreatedAt: v.CreatedAt.Format("2006-01-02 15:04:05")}
|
||
}
|
||
ctx.Payload(rsp)
|
||
}
|
||
}
|
||
|
||
type listOrdersRequest struct {
|
||
Page int `form:"page"`
|
||
PageSize int `form:"page_size"`
|
||
}
|
||
type listOrdersResponse struct {
|
||
Page int `json:"page"`
|
||
PageSize int `json:"page_size"`
|
||
Total int64 `json:"total"`
|
||
List []*user.OrderWithItems `json:"list"`
|
||
}
|
||
|
||
type listInventoryRequest struct {
|
||
Page int `form:"page"`
|
||
PageSize int `form:"page_size"`
|
||
}
|
||
type listInventoryResponse struct {
|
||
Page int `json:"page"`
|
||
PageSize int `json:"page_size"`
|
||
Total int64 `json:"total"`
|
||
List []*user.InventoryWithProduct `json:"list"`
|
||
}
|
||
|
||
// ListUserOrders 查看用户订单列表
|
||
// @Summary 查看用户订单列表
|
||
// @Description 查看指定用户的订单记录
|
||
// @Tags 管理端.用户
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path integer true "用户ID"
|
||
// @Param page query int true "页码" default(1)
|
||
// @Param page_size query int true "每页数量,最多100" default(20)
|
||
// @Success 200 {object} listOrdersResponse
|
||
// @Failure 400 {object} code.Failure
|
||
// @Router /api/admin/users/{user_id}/orders [get]
|
||
// @Security LoginVerifyToken
|
||
func (h *handler) ListUserOrders() core.HandlerFunc {
|
||
return func(ctx core.Context) {
|
||
req := new(listOrdersRequest)
|
||
rsp := new(listOrdersResponse)
|
||
if err := ctx.ShouldBindForm(req); err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
||
return
|
||
}
|
||
userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
|
||
return
|
||
}
|
||
items, total, err := h.user.ListOrdersWithItems(ctx.RequestContext(), userID, req.Page, req.PageSize)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 20104, err.Error()))
|
||
return
|
||
}
|
||
rsp.Page = req.Page
|
||
rsp.PageSize = req.PageSize
|
||
rsp.Total = total
|
||
rsp.List = items
|
||
ctx.Payload(rsp)
|
||
}
|
||
}
|
||
|
||
// 查看用户资产列表
|
||
// @Summary 查看用户资产列表
|
||
// @Description 查看指定用户的资产记录
|
||
// @Tags 管理端.用户
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path integer true "用户ID"
|
||
// @Param page query int true "页码" default(1)
|
||
// @Param page_size query int true "每页数量,最多100" default(20)
|
||
// @Success 200 {object} listInventoryResponse
|
||
// @Failure 400 {object} code.Failure
|
||
// @Router /api/admin/users/{user_id}/inventory [get]
|
||
// @Security LoginVerifyToken
|
||
func (h *handler) ListUserInventory() core.HandlerFunc {
|
||
return func(ctx core.Context) {
|
||
req := new(listInventoryRequest)
|
||
rsp := new(listInventoryResponse)
|
||
if err := ctx.ShouldBindForm(req); err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
||
return
|
||
}
|
||
userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
|
||
return
|
||
}
|
||
rows, total, err := h.user.ListInventoryWithProduct(ctx.RequestContext(), userID, req.Page, req.PageSize)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 20105, err.Error()))
|
||
return
|
||
}
|
||
rsp.Page = req.Page
|
||
rsp.PageSize = req.PageSize
|
||
rsp.Total = total
|
||
rsp.List = rows
|
||
ctx.Payload(rsp)
|
||
}
|
||
}
|
||
|
||
type listUserItemCardsRequest struct {
|
||
Page int `form:"page"`
|
||
PageSize int `form:"page_size"`
|
||
}
|
||
|
||
type listUserItemCardsResponse struct {
|
||
Page int `json:"page"`
|
||
PageSize int `json:"page_size"`
|
||
Total int64 `json:"total"`
|
||
List []*user.ItemCardWithTemplate `json:"list"`
|
||
}
|
||
|
||
// ListUserItemCards 查看用户道具卡列表
|
||
// @Summary 查看用户道具卡列表
|
||
// @Description 查看指定用户的道具卡持有记录
|
||
// @Tags 管理端.用户
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path integer true "用户ID"
|
||
// @Param page query int true "页码" default(1)
|
||
// @Param page_size query int true "每页数量,最多100" default(20)
|
||
// @Success 200 {object} listUserItemCardsResponse
|
||
// @Failure 400 {object} code.Failure
|
||
// @Router /api/admin/users/{user_id}/item_cards [get]
|
||
// @Security LoginVerifyToken
|
||
func (h *handler) ListUserItemCards() core.HandlerFunc {
|
||
return func(ctx core.Context) {
|
||
req := new(listUserItemCardsRequest)
|
||
rsp := new(listUserItemCardsResponse)
|
||
if err := ctx.ShouldBindForm(req); err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
||
return
|
||
}
|
||
userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
|
||
return
|
||
}
|
||
items, total, err := h.user.ListUserItemCardsWithTemplate(ctx.RequestContext(), userID, req.Page, req.PageSize)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 20106, err.Error()))
|
||
return
|
||
}
|
||
rsp.Page = req.Page
|
||
rsp.PageSize = req.PageSize
|
||
rsp.Total = total
|
||
rsp.List = items
|
||
ctx.Payload(rsp)
|
||
}
|
||
}
|
||
|
||
type listCouponsRequest struct {
|
||
Page int `form:"page"`
|
||
PageSize int `form:"page_size"`
|
||
}
|
||
type adminUserCouponItem struct {
|
||
ID int64 `json:"id"`
|
||
CouponID int64 `json:"coupon_id"`
|
||
Status int32 `json:"status"`
|
||
UsedOrderID int64 `json:"used_order_id"`
|
||
UsedAt string `json:"used_at"`
|
||
ValidStart string `json:"valid_start"`
|
||
ValidEnd string `json:"valid_end"`
|
||
Name string `json:"name"`
|
||
ScopeType int32 `json:"scope_type"`
|
||
DiscountType int32 `json:"discount_type"`
|
||
DiscountValue int64 `json:"discount_value"`
|
||
MinSpend int64 `json:"min_spend"`
|
||
}
|
||
|
||
type listCouponsResponse struct {
|
||
Page int `json:"page"`
|
||
PageSize int `json:"page_size"`
|
||
Total int64 `json:"total"`
|
||
List []adminUserCouponItem `json:"list"`
|
||
}
|
||
|
||
// ListUserCoupons 查看用户优惠券列表
|
||
// @Summary 查看用户优惠券列表
|
||
// @Description 查看指定用户持有的优惠券列表
|
||
// @Tags 管理端.用户
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path integer true "用户ID"
|
||
// @Param page query int true "页码" default(1)
|
||
// @Param page_size query int true "每页数量,最多100" default(20)
|
||
// @Success 200 {object} listCouponsResponse
|
||
// @Failure 400 {object} code.Failure
|
||
// @Router /api/admin/users/{user_id}/coupons [get]
|
||
// @Security LoginVerifyToken
|
||
func (h *handler) ListUserCoupons() core.HandlerFunc {
|
||
return func(ctx core.Context) {
|
||
req := new(listCouponsRequest)
|
||
rsp := new(listCouponsResponse)
|
||
if err := ctx.ShouldBindForm(req); err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
||
return
|
||
}
|
||
userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
|
||
return
|
||
}
|
||
// 统计总数
|
||
base := h.readDB.UserCoupons.WithContext(ctx.RequestContext()).ReadDB().Where(h.readDB.UserCoupons.UserID.Eq(userID))
|
||
total, err := base.Count()
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 20105, err.Error()))
|
||
return
|
||
}
|
||
// 联表查询 system_coupons 获取优惠券模板信息
|
||
type row struct {
|
||
ID int64
|
||
CouponID int64
|
||
Status int32
|
||
UsedOrderID int64
|
||
UsedAt *string
|
||
ValidStart *string
|
||
ValidEnd *string
|
||
Name string
|
||
ScopeType int32
|
||
DiscountType int32
|
||
DiscountValue int64
|
||
MinSpend int64
|
||
}
|
||
q := h.readDB.UserCoupons.WithContext(ctx.RequestContext()).ReadDB().
|
||
LeftJoin(h.readDB.SystemCoupons, h.readDB.SystemCoupons.ID.EqCol(h.readDB.UserCoupons.CouponID)).
|
||
Select(
|
||
h.readDB.UserCoupons.ID, h.readDB.UserCoupons.CouponID, h.readDB.UserCoupons.Status,
|
||
h.readDB.UserCoupons.UsedOrderID, h.readDB.UserCoupons.UsedAt, h.readDB.UserCoupons.ValidStart, h.readDB.UserCoupons.ValidEnd,
|
||
h.readDB.SystemCoupons.Name, h.readDB.SystemCoupons.ScopeType, h.readDB.SystemCoupons.DiscountType,
|
||
h.readDB.SystemCoupons.DiscountValue, h.readDB.SystemCoupons.MinSpend,
|
||
).
|
||
Where(h.readDB.UserCoupons.UserID.Eq(userID)).
|
||
Order(h.readDB.UserCoupons.ID.Desc()).
|
||
Limit(req.PageSize).Offset((req.Page-1)*req.PageSize)
|
||
|
||
var rows []row
|
||
if err := q.Scan(&rows); err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 20105, err.Error()))
|
||
return
|
||
}
|
||
|
||
rsp.Page = req.Page
|
||
rsp.PageSize = req.PageSize
|
||
rsp.Total = total
|
||
rsp.List = make([]adminUserCouponItem, len(rows))
|
||
for i, v := range rows {
|
||
rsp.List[i] = adminUserCouponItem{
|
||
ID: v.ID,
|
||
CouponID: v.CouponID,
|
||
Status: v.Status,
|
||
UsedOrderID: v.UsedOrderID,
|
||
UsedAt: nullableToString(v.UsedAt),
|
||
ValidStart: nullableToString(v.ValidStart),
|
||
ValidEnd: nullableToString(v.ValidEnd),
|
||
Name: v.Name,
|
||
ScopeType: v.ScopeType,
|
||
DiscountType: v.DiscountType,
|
||
DiscountValue: v.DiscountValue,
|
||
MinSpend: v.MinSpend,
|
||
}
|
||
}
|
||
ctx.Payload(rsp)
|
||
}
|
||
}
|
||
|
||
func nullableToString(s *string) string {
|
||
if s == nil {
|
||
return ""
|
||
}
|
||
return *s
|
||
}
|
||
|
||
type listPointsRequest struct {
|
||
Page int `form:"page"`
|
||
PageSize int `form:"page_size"`
|
||
}
|
||
type listPointsResponse struct {
|
||
Page int `json:"page"`
|
||
PageSize int `json:"page_size"`
|
||
Total int64 `json:"total"`
|
||
List []*model.UserPointsLedger `json:"list"`
|
||
}
|
||
|
||
// ListUserPoints 查看用户积分记录
|
||
// @Summary 查看用户积分记录
|
||
// @Description 查看指定用户的积分流水记录
|
||
// @Tags 管理端.用户
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path integer true "用户ID"
|
||
// @Param page query int true "页码" default(1)
|
||
// @Param page_size query int true "每页数量,最多100" default(20)
|
||
// @Success 200 {object} listPointsResponse
|
||
// @Failure 400 {object} code.Failure
|
||
// @Router /api/admin/users/{user_id}/points [get]
|
||
// @Security LoginVerifyToken
|
||
func (h *handler) ListUserPoints() core.HandlerFunc {
|
||
return func(ctx core.Context) {
|
||
req := new(listPointsRequest)
|
||
rsp := new(listPointsResponse)
|
||
if err := ctx.ShouldBindForm(req); err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
||
return
|
||
}
|
||
userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
|
||
return
|
||
}
|
||
items, total, err := h.user.ListPointsLedger(ctx.RequestContext(), userID, req.Page, req.PageSize)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 20106, err.Error()))
|
||
return
|
||
}
|
||
rsp.Page = req.Page
|
||
rsp.PageSize = req.PageSize
|
||
rsp.Total = total
|
||
rsp.List = items
|
||
ctx.Payload(rsp)
|
||
}
|
||
}
|
||
|
||
type pointsBalanceResponse struct {
|
||
Balance int64 `json:"balance"`
|
||
}
|
||
|
||
type adminUserItem struct {
|
||
ID int64 `json:"id"`
|
||
Nickname string `json:"nickname"`
|
||
Avatar string `json:"avatar"`
|
||
InviteCode string `json:"invite_code"`
|
||
InviterID int64 `json:"inviter_id"`
|
||
CreatedAt string `json:"created_at"`
|
||
}
|
||
|
||
// GetUserPointsBalance 查看用户积分余额
|
||
// @Summary 查看用户积分余额
|
||
// @Description 查看指定用户当前积分余额(过滤过期)
|
||
// @Tags 管理端.用户
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path integer true "用户ID"
|
||
// @Success 200 {object} pointsBalanceResponse
|
||
// @Failure 400 {object} code.Failure
|
||
// @Router /api/admin/users/{user_id}/points/balance [get]
|
||
// @Security LoginVerifyToken
|
||
func (h *handler) GetUserPointsBalance() core.HandlerFunc {
|
||
return func(ctx core.Context) {
|
||
rsp := new(pointsBalanceResponse)
|
||
userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
|
||
return
|
||
}
|
||
total, err := h.user.GetPointsBalance(ctx.RequestContext(), userID)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 20107, err.Error()))
|
||
return
|
||
}
|
||
rsp.Balance = total
|
||
ctx.Payload(rsp)
|
||
}
|
||
}
|
||
|
||
type addPointsRequest struct {
|
||
Points int64 `json:"points" binding:"required"`
|
||
Kind string `json:"kind"`
|
||
Remark string `json:"remark"`
|
||
ValidDays *int `json:"valid_days"`
|
||
}
|
||
type addPointsResponse struct {
|
||
Success bool `json:"success"`
|
||
}
|
||
|
||
// AddUserPoints 给用户添加积分
|
||
// @Summary 给用户添加积分
|
||
// @Description 管理端为指定用户发放积分,支持设置有效期
|
||
// @Tags 管理端.用户
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path integer true "用户ID"
|
||
// @Param RequestBody body addPointsRequest true "请求参数"
|
||
// @Success 200 {object} addPointsResponse
|
||
// @Failure 400 {object} code.Failure
|
||
// @Router /api/admin/users/{user_id}/points/add [post]
|
||
// @Security LoginVerifyToken
|
||
func (h *handler) AddUserPoints() core.HandlerFunc {
|
||
return func(ctx core.Context) {
|
||
req := new(addPointsRequest)
|
||
rsp := new(addPointsResponse)
|
||
if err := ctx.ShouldBindJSON(req); err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
||
return
|
||
}
|
||
userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
|
||
return
|
||
}
|
||
var validStart *time.Time
|
||
var validEnd *time.Time
|
||
now := time.Now()
|
||
validStart = &now
|
||
if req.ValidDays != nil && *req.ValidDays > 0 {
|
||
ve := now.Add(time.Duration(*req.ValidDays) * 24 * time.Hour)
|
||
validEnd = &ve
|
||
}
|
||
if err := h.user.AddPoints(ctx.RequestContext(), userID, req.Points, req.Kind, req.Remark, validStart, validEnd); err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 20108, err.Error()))
|
||
return
|
||
}
|
||
rsp.Success = true
|
||
ctx.Payload(rsp)
|
||
}
|
||
}
|
||
|
||
type addCouponRequest struct {
|
||
CouponID int64 `json:"coupon_id" binding:"required"`
|
||
}
|
||
type addCouponResponse struct {
|
||
Success bool `json:"success"`
|
||
}
|
||
|
||
// AddUserCoupon 给用户添加优惠券
|
||
// @Summary 给用户添加优惠券
|
||
// @Description 管理端为指定用户发放优惠券
|
||
// @Tags 管理端.用户
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path integer true "用户ID"
|
||
// @Param RequestBody body addCouponRequest true "请求参数"
|
||
// @Success 200 {object} addCouponResponse
|
||
// @Failure 400 {object} code.Failure
|
||
// @Router /api/admin/users/{user_id}/coupons/add [post]
|
||
// @Security LoginVerifyToken
|
||
func (h *handler) AddUserCoupon() core.HandlerFunc {
|
||
return func(ctx core.Context) {
|
||
req := new(addCouponRequest)
|
||
rsp := new(addCouponResponse)
|
||
if err := ctx.ShouldBindJSON(req); err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
||
return
|
||
}
|
||
userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
|
||
if err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
|
||
return
|
||
}
|
||
if ctx.SessionUserInfo().IsSuper != 1 {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
|
||
return
|
||
}
|
||
if err := h.user.AddCoupon(ctx.RequestContext(), userID, req.CouponID); err != nil {
|
||
ctx.AbortWithError(core.Error(http.StatusBadRequest, 20109, err.Error()))
|
||
return
|
||
}
|
||
rsp.Success = true
|
||
ctx.Payload(rsp)
|
||
}
|
||
}
|