bindbox-game/internal/api/user/coupons_app.go
2026-01-27 01:33:32 +08:00

155 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package app
import (
"fmt"
"net/http"
"bindbox-game/internal/code"
"bindbox-game/internal/pkg/core"
"bindbox-game/internal/pkg/validation"
"bindbox-game/internal/repository/mysql/model"
)
type listCouponsRequest struct {
Page int `form:"page"`
PageSize int `form:"page_size"`
Status *int32 `form:"status"` // 1未使用 2已使用 3已过期不传默认1
}
type listCouponsResponse struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
Total int64 `json:"total"`
List []couponItem `json:"list"`
}
type couponItem struct {
ID int64 `json:"id"`
Name string `json:"name"`
Amount int64 `json:"amount"`
Remaining int64 `json:"remaining"`
ValidStart string `json:"valid_start"`
ValidEnd string `json:"valid_end"`
Status int32 `json:"status"`
StatusDesc string `json:"status_desc"` // 状态描述:未使用、已用完、已过期
Rules string `json:"rules"`
UsedAt string `json:"used_at,omitempty"` // 使用时间(已使用时返回)
UsedAmount int64 `json:"used_amount"` // 已使用金额
}
// ListUserCoupons 查看用户优惠券
// @Summary 查看用户优惠券
// @Description 查看用户持有的优惠券列表,支持按状态过滤
// @Tags APP端.用户
// @Accept json
// @Produce json
// @Param user_id path integer true "用户ID"
// @Security LoginVerifyToken
// @Param page query int true "页码" default(1)
// @Param page_size query int true "每页数量最多100" default(20)
// @Param status query int false "状态1未使用 2已使用 3已过期不传默认1"
// @Success 200 {object} listCouponsResponse
// @Failure 400 {object} code.Failure
// @Router /api/app/users/{user_id}/coupons [get]
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 := int64(ctx.SessionUserInfo().Id)
// 状态0未使用 1已使用 2已过期 (直接对接前端标准)
status := int32(0)
if req.Status != nil {
status = *req.Status
}
items, total, err := h.user.ListAppCoupons(ctx.RequestContext(), userID, status, req.Page, req.PageSize)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 10003, err.Error()))
return
}
rsp.Page = req.Page
rsp.PageSize = req.PageSize
rsp.Total = total
if len(items) == 0 {
rsp.List = []couponItem{}
ctx.Payload(rsp)
return
}
ids := make([]int64, 0, len(items))
for _, it := range items {
ids = append(ids, it.CouponID)
}
rows, err := h.readDB.SystemCoupons.WithContext(ctx.RequestContext()).Where(h.readDB.SystemCoupons.ID.In(ids...)).Find()
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, 10003, err.Error()))
return
}
mp := make(map[int64]*model.SystemCoupons, len(rows))
for i := range rows {
c := rows[i]
mp[c.ID] = c
}
rsp.List = make([]couponItem, 0, len(items))
for _, it := range items {
sc := mp[it.CouponID]
name := ""
amount := int64(0)
remaining := int64(0)
rules := ""
if sc != nil {
name = sc.Name
amount = sc.DiscountValue
remaining = it.BalanceAmount
rules = buildCouponRules(sc)
}
vs := it.ValidStart.Format("2006-01-02 15:04:05")
ve := ""
if !it.ValidEnd.IsZero() {
ve = it.ValidEnd.Format("2006-01-02 15:04:05")
}
usedAt := ""
if !it.UsedAt.IsZero() {
usedAt = it.UsedAt.Format("2006-01-02 15:04:05")
}
statusDesc := "未使用"
if it.Status == 2 {
if it.BalanceAmount == 0 {
statusDesc = "已使用"
} else {
statusDesc = "使用中"
}
} else if it.Status == 3 {
// 若面值等于余额,说明完全没用过,否则为“已到期”
sc, ok := mp[it.CouponID]
if ok && it.BalanceAmount < sc.DiscountValue {
statusDesc = "已到期"
} else {
statusDesc = "已过期"
}
}
usedAmount := amount - remaining
vi := couponItem{ID: it.ID, Name: name, Amount: amount, Remaining: remaining, UsedAmount: usedAmount, ValidStart: vs, ValidEnd: ve, Status: it.Status, StatusDesc: statusDesc, Rules: rules, UsedAt: usedAt}
rsp.List = append(rsp.List, vi)
}
ctx.Payload(rsp)
}
}
func buildCouponRules(c *model.SystemCoupons) string {
switch c.DiscountType {
case 1:
return fmt.Sprintf("直减%v分满%v分可用", c.DiscountValue, c.MinSpend)
case 2:
return fmt.Sprintf("满%v分减%v分", c.MinSpend, c.DiscountValue)
case 3:
p := float64(c.DiscountValue) / 10.0
return fmt.Sprintf("折扣%0.1f%%,满%v分可用", p, c.MinSpend)
default:
return ""
}
}