mh_goadmin_server/app/admin/apis/lotterymanage/lottery.go

571 lines
16 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 lotterymanage
import (
"encoding/json"
"errors"
"fmt"
"github.com/gin-gonic/gin"
model "go-admin/app/admin/models"
orm "go-admin/common/global"
"go-admin/tools/app"
"gorm.io/gorm"
"net/http"
"time"
)
// GetPublicLotteryConfigHandler 查询抽奖配置(公开接口)
// @Summary 查询抽奖模块配置(公开)
// @Tags 积分抽奖V1.5.0
// @Produce json
// @Success 200 {object} models.LotteryConfig
// @Router /api/v1/lottery/config/public [post]
func GetPublicLotteryConfigHandler(c *gin.Context) {
cfg, err := model.GetLotteryConfig()
if err != nil {
app.Error(c, http.StatusInternalServerError, nil, "获取抽奖配置失败")
return
}
app.OK(c, cfg, "配置更新成功")
}
// UpdateLotteryConfig 更新抽奖参数配置
// @Summary 更新积分抽奖参数配置
// @Tags 积分抽奖V1.5.0
// @Accept json
// @Produce json
// @Param data body models.UpdateLotteryConfigRequest true "抽奖配置"
// @Success 200 {object} app.Response
// @Router /api/v1/lottery/config/update [post]
func UpdateLotteryConfig(c *gin.Context) {
var req model.UpdateLotteryConfigRequest
if err := c.ShouldBindJSON(&req); err != nil {
app.Error(c, http.StatusBadRequest, nil, "参数错误: "+err.Error())
return
}
// 转为 JSON 字符串
valueBytes, err := json.Marshal(req)
if err != nil {
app.Error(c, http.StatusInternalServerError, nil, "配置序列化失败")
return
}
// 尝试读取是否已有记录
var config model.Config
tx := orm.Eloquent
err = tx.Where("name = ?", model.ConfigNameLotteryLimit).First(&config).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
// 不存在则创建
newCfg := model.Config{
Name: model.ConfigNameLotteryLimit,
Value: string(valueBytes),
}
if err := tx.Create(&newCfg).Error; err != nil {
app.Error(c, http.StatusInternalServerError, nil, "创建配置失败: "+err.Error())
return
}
} else if err != nil {
app.Error(c, http.StatusInternalServerError, nil, "查询配置失败: "+err.Error())
return
} else {
// 存在则更新
if err := tx.Model(&config).
Update("value", string(valueBytes)).Error; err != nil {
app.Error(c, http.StatusInternalServerError, nil, "更新配置失败: "+err.Error())
return
}
}
app.OK(c, nil, "配置更新成功")
}
// CreateLotteryPrize 创建奖品
// @Summary 创建奖品
// @Tags 积分抽奖V1.5.0
// @Accept json
// @Produce json
// @Param data body models.CreatePrizeRequest true "奖品信息"
// @Success 200 {object} models.CreatePrizeResp
// @Router /api/v1/lottery/prize/create [post]
func CreateLotteryPrize(c *gin.Context) {
var req model.CreatePrizeRequest
if err := c.ShouldBindJSON(&req); err != nil {
app.Error(c, http.StatusBadRequest, nil, "参数错误: "+err.Error())
return
}
prize := model.LotteryPrize{
Name: req.Name,
PrizeType: req.PrizeType,
PrizeValue: req.PrizeValue,
Level: req.Level,
Weight: req.Weight,
Stock: req.Stock,
Status: req.Status,
UnlockUserCount: req.UnlockUserCount,
UnlockTotalCount: req.UnlockTotalCount,
Images: req.Images,
}
if err := orm.Eloquent.Create(&prize).Error; err != nil {
app.Error(c, http.StatusInternalServerError, nil, "创建失败: "+err.Error())
return
}
app.OK(c, model.CreatePrizeResp{ID: prize.ID}, "创建成功")
}
// UpdateLotteryPrize 编辑奖品
// @Summary 编辑奖品
// @Tags 积分抽奖V1.5.0
// @Accept json
// @Produce json
// @Param data body models.UpdatePrizeRequest true "奖品信息"
// @Success 200 {object} models.CreatePrizeResp
// @Router /api/v1/lottery/prize/update [post]
func UpdateLotteryPrize(c *gin.Context) {
var req model.UpdatePrizeRequest
if err := c.ShouldBindJSON(&req); err != nil {
app.Error(c, http.StatusBadRequest, nil, "参数错误: "+err.Error())
return
}
var prize model.LotteryPrize
if err := orm.Eloquent.First(&prize, req.ID).Error; err != nil {
app.Error(c, http.StatusNotFound, nil, "未找到该奖品")
return
}
// 更新字段
prize.Name = req.Name
prize.PrizeType = req.PrizeType
prize.PrizeValue = req.PrizeValue
prize.Level = req.Level
prize.Weight = req.Weight
prize.Stock = req.Stock
prize.Status = req.Status
prize.UnlockUserCount = req.UnlockUserCount
prize.UnlockTotalCount = req.UnlockTotalCount
prize.Images = req.Images
if err := orm.Eloquent.Save(&prize).Error; err != nil {
app.Error(c, http.StatusInternalServerError, nil, "更新失败: "+err.Error())
return
}
app.OK(c, model.CreatePrizeResp{ID: prize.ID}, "编辑成功")
}
// DeleteLotteryPrize 删除奖品
// @Summary 删除奖品
// @Tags 积分抽奖V1.5.0
// @Accept json
// @Produce json
// @Param data body models.DeletePrizeRequest true "奖品ID"
// @Success 200 {object} app.Response
// @Router /api/v1/lottery/prize/delete [post]
func DeleteLotteryPrize(c *gin.Context) {
var req model.DeletePrizeRequest
if err := c.ShouldBindJSON(&req); err != nil {
app.Error(c, http.StatusBadRequest, nil, "参数错误: "+err.Error())
return
}
if err := orm.Eloquent.Delete(&model.LotteryPrize{}, req.ID).Error; err != nil {
app.Error(c, http.StatusInternalServerError, nil, "删除失败: "+err.Error())
return
}
app.OK(c, nil, "删除成功")
}
// LotteryPrizeList 查询奖品列表(分页)
// @Summary 查询奖品列表
// @Tags 积分抽奖V1.5.0
// @Accept json
// @Produce json
// @Param data body models.PrizeListRequest true "查询参数"
// @Success 200 {object} models.PrizeListResponse
// @Router /api/v1/lottery/prize/list [post]
func LotteryPrizeList(c *gin.Context) {
var req model.PrizeListRequest
if err := c.ShouldBindJSON(&req); err != nil {
app.Error(c, http.StatusBadRequest, nil, "参数错误")
return
}
if req.Page <= 0 {
req.Page = 1
}
if req.PageSize <= 0 {
req.PageSize = 10
}
// 查询启用状态奖品的总权重(或根据筛选条件的权重)
weightDB := orm.Eloquent.Model(&model.LotteryPrize{})
if req.Status != 0 {
weightDB = weightDB.Where("status = ?", req.Status)
}
if req.Level > 0 {
weightDB = weightDB.Where("level = ?", req.Level)
}
if req.Name != "" {
weightDB = weightDB.Where("name LIKE ?", "%"+req.Name+"%")
}
var totalWeight int64
row := weightDB.Select("SUM(weight)").Row()
if err := row.Scan(&totalWeight); err != nil {
app.Error(c, http.StatusInternalServerError, nil, "计算总权重失败")
return
}
// 查询分页数据
db := orm.Eloquent.Model(&model.LotteryPrize{})
if req.Name != "" {
db = db.Where("name LIKE ?", "%"+req.Name+"%")
}
if req.Status != 0 {
db = db.Where("status = ?", req.Status)
}
if req.Level > 0 {
db = db.Where("level = ?", req.Level)
}
var total int64
if err := db.Count(&total).Error; err != nil {
app.Error(c, http.StatusInternalServerError, nil, "查询总数失败")
return
}
var list []model.LotteryPrize
if err := db.Order("id ASC").
Offset((req.Page - 1) * req.PageSize).
Limit(req.PageSize).
Find(&list).Error; err != nil {
app.Error(c, http.StatusInternalServerError, nil, "查询失败")
return
}
// 动态计算中奖概率,避免小概率显示为 0.00%
if totalWeight > 0 {
for i := range list {
rate := float64(list[i].Weight) / float64(totalWeight) * 100
switch {
case rate >= 1:
list[i].Probability = fmt.Sprintf("%.2f%%", rate)
case rate >= 0.01:
list[i].Probability = fmt.Sprintf("%.4f%%", rate)
default:
list[i].Probability = fmt.Sprintf("%.6f%%", rate)
}
list[i].Probability = model.TrimTrailingZerosFromPercent(list[i].Probability)
}
} else {
for i := range list {
list[i].Probability = "0.000000%"
}
}
resp := model.PrizeListResponse{
List: list,
Total: total,
Page: req.Page,
PageSize: req.PageSize,
}
app.OK(c, resp, "查询成功")
}
// LotteryRecordList 查询抽奖记录列表
// @Summary 查询抽奖记录列表
// @Tags 积分抽奖V1.5.0
// @Accept json
// @Produce json
// @Param data body models.LotteryRecordListRequest true "查询参数"
// @Success 200 {object} models.LotteryRecordListResponse
// @Router /api/v1/lottery/record/list [post]
func LotteryRecordList(c *gin.Context) {
var req model.LotteryRecordListRequest
if err := c.ShouldBindJSON(&req); err != nil {
app.Error(c, http.StatusBadRequest, nil, "参数错误")
return
}
if req.Page <= 0 {
req.Page = 1
}
if req.PageSize <= 0 {
req.PageSize = 10
}
db := orm.Eloquent.Model(&model.LotteryRecord{}).
Select(`lottery_record.id,
lottery_record.created_at,
lottery_record.updated_at,
lottery_record.deleted_at,
lottery_record.uid,
lottery_record.prize_id,
lottery_record.prize_name,
lottery_record.prize_type,
lottery_record.prize_level,
lottery_record.prize_value,
lottery_record.status,
lottery_record.is_win,
user.tel,
user.store_id as store_id,
user.member_level,
store.name as store_name`).
Joins("LEFT JOIN user ON user.uid = lottery_record.uid").
Joins("LEFT JOIN store ON store.id = user.store_id")
// 构建基础查询
query := orm.Eloquent.Model(&model.LotteryRecord{}).
Select(`lottery_record.id,
lottery_record.created_at,
lottery_record.updated_at,
lottery_record.deleted_at,
lottery_record.uid,
lottery_record.prize_id,
lottery_record.prize_name,
lottery_record.prize_type,
lottery_record.prize_level,
lottery_record.prize_value,
lottery_record.status,
lottery_record.is_win,
user.tel,
user.store_id as store_id,
user.member_level,
store.name as store_name`).
Joins("LEFT JOIN user ON user.uid = lottery_record.uid").
Joins("LEFT JOIN store ON store.id = user.store_id")
// 条件过滤
if req.Uid > 0 {
db = db.Where("lottery_record.uid = ?", req.Uid)
query = query.Where("lottery_record.uid = ?", req.Uid)
}
if req.Tel != "" {
db = db.Where("user.tel = ?", req.Tel)
query = query.Where("user.tel = ?", req.Tel)
}
if req.StoreId > 0 {
db = db.Where("user.store_id = ?", req.StoreId)
query = query.Where("user.store_id = ?", req.StoreId)
}
if req.MemberLevel > 0 {
db = db.Where("user.member_level = ?", req.MemberLevel)
query = query.Where("user.member_level = ?", req.MemberLevel)
}
if req.PrizeLevel > 0 {
db = db.Where("lottery_record.prize_level = ?", req.PrizeLevel)
query = query.Where("lottery_record.prize_level = ?", req.PrizeLevel)
}
if req.StartTime != "" {
if t, err := time.Parse("2006-01-02", req.StartTime); err == nil {
db = db.Where("lottery_record.created_at >= ?", t)
query = query.Where("lottery_record.created_at >= ?", t)
}
}
// 根据 win_status 筛选记录0=全部1=已中奖2=未中奖
switch req.WinStatus {
case 1:
db = db.Where("lottery_record.is_win = ?", true)
case 2:
db = db.Where("lottery_record.is_win = ?", false)
}
if req.EndTime != "" {
if t, err := time.Parse("2006-01-02", req.EndTime); err == nil {
db = db.Where("lottery_record.created_at <= ?", t.Add(24*time.Hour))
query = query.Where("lottery_record.created_at <= ?", t.Add(24*time.Hour))
}
}
var total int64
if err := query.Count(&total).Error; err != nil {
app.Error(c, http.StatusInternalServerError, nil, "统计失败")
return
}
var list []model.LotteryRecordWithUserInfo
if err := db.Order("lottery_record.id DESC").
Offset((req.Page - 1) * req.PageSize).
Limit(req.PageSize).
Scan(&list).Error; err != nil {
app.Error(c, http.StatusInternalServerError, nil, "查询失败")
return
}
app.OK(c, model.LotteryRecordListResponse{
List: list,
Total: total,
Page: req.Page,
PageSize: req.PageSize,
}, "查询成功")
}
// LotteryPrizeOrderList 查询抽奖订单列表
// @Summary 查询抽奖订单列表
// @Tags 积分抽奖V1.5.0
// @Accept json
// @Produce json
// @Param data body models.LotteryPrizeOrderListRequest true "查询参数"
// @Success 200 {object} models.LotteryPrizeOrderListResponse
// @Router /api/v1/lottery/prize_order/list [post]
func LotteryPrizeOrderList(c *gin.Context) {
var req model.LotteryPrizeOrderListRequest
if err := c.ShouldBindJSON(&req); err != nil {
app.Error(c, http.StatusBadRequest, nil, "参数错误")
return
}
if req.Page <= 0 {
req.Page = 1
}
if req.PageSize <= 0 {
req.PageSize = 10
}
db := orm.Eloquent.Model(&model.LotteryPrizeOrder{}).
Select(`lottery_prize_order.*,
user.tel,
user.store_id as store_id,
user.member_level,
store.name as store_name`).
Joins("LEFT JOIN user ON user.uid = lottery_prize_order.uid").
Joins("LEFT JOIN store ON store.id = user.store_id")
// 筛选条件
if req.Uid > 0 {
db = db.Where("lottery_prize_order.uid = ?", req.Uid)
}
if req.Tel != "" {
db = db.Where("lottery_prize_order.tel = ?", req.Tel)
}
if req.StoreId > 0 {
db = db.Where("user.store_id = ?", req.StoreId)
}
if req.MemberLevel > 0 {
db = db.Where("user.member_level = ?", req.MemberLevel)
}
if req.PrizeName != "" {
db = db.Where("lottery_prize_order.prize_name LIKE ?", "%"+req.PrizeName+"%")
}
if req.Status != model.LotteryPrizeOrderStatusAll {
db = db.Where("lottery_prize_order.status = ?", req.Status)
}
if req.StartTime != "" {
if t, err := time.Parse("2006-01-02", req.StartTime); err == nil {
db = db.Where("lottery_prize_order.created_at >= ?", t)
}
}
if req.EndTime != "" {
if t, err := time.Parse("2006-01-02", req.EndTime); err == nil {
db = db.Where("lottery_prize_order.created_at <= ?", t.Add(24*time.Hour))
}
}
// 分页统计
var total int64
if err := db.Count(&total).Error; err != nil {
app.Error(c, http.StatusInternalServerError, nil, "统计失败")
return
}
var list []model.LotteryPrizeOrderItem
if err := db.Order("lottery_prize_order.id DESC").
Offset((req.Page - 1) * req.PageSize).
Limit(req.PageSize).
Scan(&list).Error; err != nil {
app.Error(c, http.StatusInternalServerError, nil, "查询失败")
return
}
app.OK(c, model.LotteryPrizeOrderListResponse{
List: list,
Total: total,
Page: req.Page,
PageSize: req.PageSize,
}, "查询成功")
}
// GetLotteryPrizeOrderDetail 查询抽奖订单详情
// @Summary 查询抽奖订单详情
// @Tags 积分抽奖V1.5.0
// @Accept json
// @Produce json
// @Param data body models.GetLotteryPrizeOrderDetailRequest true "查询参数"
// @Success 200 {object} models.LotteryPrizeOrderDetailResponse
// @Router /api/v1/lottery/prize_order/detail [post]
func GetLotteryPrizeOrderDetail(c *gin.Context) {
var req model.GetLotteryPrizeOrderDetailRequest
if err := c.ShouldBindJSON(&req); err != nil || req.OrderID == 0 {
app.Error(c, http.StatusBadRequest, nil, "参数错误order_id 必传")
return
}
var detail model.LotteryPrizeOrderDetailResponse
db := orm.Eloquent.Table("lottery_prize_order").
Select(`lottery_prize_order.*,
user.wx_name as nickname,
user.tel,
user.member_level,
store.name as store_name,
lottery_prize.prize_type,
lottery_prize.level as prize_level,
lottery_prize.prize_value`).
Joins("LEFT JOIN user ON user.uid = lottery_prize_order.uid").
Joins("LEFT JOIN store ON store.id = user.store_id").
Joins("LEFT JOIN lottery_prize ON lottery_prize.id = lottery_prize_order.prize_id").
Where("lottery_prize_order.id = ?", req.OrderID)
if err := db.First(&detail).Error; err != nil {
app.Error(c, http.StatusNotFound, nil, "未找到对应的订单记录")
return
}
app.OK(c, detail, "查询成功")
}
// ShipLotteryPrizeOrder 抽奖订单发货
// @Summary 抽奖订单发货
// @Tags 积分抽奖V1.5.0
// @Accept json
// @Produce json
// @Param data body models.ShipLotteryPrizeOrderRequest true "查询参数"
// @Success 200 {object} app.Response
// @Router /api/v1/lottery/prize_order/ship [post]
func ShipLotteryPrizeOrder(c *gin.Context) {
var req model.ShipLotteryPrizeOrderRequest
if err := c.ShouldBindJSON(&req); err != nil {
app.Error(c, http.StatusBadRequest, nil, "参数错误:"+err.Error())
return
}
var order model.LotteryPrizeOrder
if err := orm.Eloquent.First(&order, req.OrderID).Error; err != nil {
app.Error(c, http.StatusNotFound, nil, "订单不存在")
return
}
if order.Status != 0 {
app.Error(c, http.StatusBadRequest, nil, "订单状态不为待发货,无法发货")
return
}
err := orm.Eloquent.Model(&order).Updates(map[string]interface{}{
"logistics_company": req.LogisticsCompany,
"logistics_number": req.LogisticsNumber,
"shipped_at": time.Now(),
"status": 1, // 已发货
}).Error
if err != nil {
app.Error(c, http.StatusInternalServerError, nil, "发货失败:"+err.Error())
return
}
app.OK(c, nil, "发货成功")
}