Zuncle 46b9555823 feat(fragment): 商品成本价 + 活动奖品单次产出数量
- products 表新增 cost_price 字段(成本价/分)
- activity_reward_settings 新增 drop_quantity(单次产出数量,默认1)
  和 cost_snapshot_cents(成本价快照)
- 奖品创建/修改时自动快照成本价,drop_quantity 限制 1-100
- 抽奖发放逻辑按 drop_quantity 循环创建多个库存项
- 抽奖结果接口按 drop_quantity 返回多条 item,前端自动合并显示
- 抽奖记录接口返回 drop_quantity 字段
- 商品管理 API 全链路支持 cost_price
2026-03-23 22:26:06 +08:00

260 lines
7.6 KiB
Go
Executable File
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 activity
import (
"context"
"time"
"bindbox-game/internal/pkg/logger"
"bindbox-game/internal/repository/mysql"
"bindbox-game/internal/repository/mysql/dao"
"bindbox-game/internal/repository/mysql/model"
usersvc "bindbox-game/internal/service/user"
"github.com/redis/go-redis/v9"
)
type Service interface {
// ... (other methods)
// ProcessOrderLottery 处理订单开奖(统一幂等逻辑)
// 参数: ctx 上下文, orderID 订单ID
// 返回: 错误信息
ProcessOrderLottery(ctx context.Context, orderID int64) error
// CreateActivity 创建活动
// 参数: in 活动创建输入
// 返回: 活动记录与错误
CreateActivity(ctx context.Context, in CreateActivityInput) (*model.Activities, error)
// ModifyActivity 修改活动
// 参数: id 活动ID, in 修改输入
// 返回: 错误信息
ModifyActivity(ctx context.Context, id int64, in ModifyActivityInput) error
// DeleteActivity 删除活动
// 参数: id 活动ID
// 返回: 错误信息
DeleteActivity(ctx context.Context, id int64) error
// GetActivity 获取活动详情
// 参数: id 活动ID
// 返回: 活动记录与错误
GetActivity(ctx context.Context, id int64) (*model.Activities, error)
// ListActivities 活动列表
// 参数: in 列表查询输入
// 返回: 活动集合、总数与错误
ListActivities(ctx context.Context, in ListActivitiesInput) (items []*model.Activities, total int64, err error)
// ListIssues 活动期列表
// 参数: activityID 活动ID, page 页码, pageSize 每页数量
// 返回: 期列表、总数与错误
ListIssues(ctx context.Context, activityID int64, page, pageSize int) (items []*model.ActivityIssues, total int64, err error)
// CreateIssue 创建期
// 参数: activityID 活动ID, in 创建输入
// 返回: 期记录与错误
CreateIssue(ctx context.Context, activityID int64, in CreateIssueInput) (*model.ActivityIssues, error)
// ModifyIssue 修改期
// 参数: issueID 期ID, in 修改输入
// 返回: 错误信息
ModifyIssue(ctx context.Context, issueID int64, in ModifyIssueInput) error
// DeleteIssue 删除期
// 参数: issueID 期ID
// 返回: 错误信息
DeleteIssue(ctx context.Context, issueID int64) error
// CreateIssueRewards 批量创建期奖励
// 参数: issueID 期ID, rewards 奖励创建输入数组
// 返回: 错误信息
CreateIssueRewards(ctx context.Context, issueID int64, rewards []CreateRewardInput) error
// ListIssueRewards 查询期奖励列表
// 参数: issueID 期ID
// 返回: 奖励集合与错误
ListIssueRewards(ctx context.Context, issueID int64) (items []*model.ActivityRewardSettings, err error)
// ModifyIssueReward 修改单个奖励
// 参数: rewardID 奖励ID, in 修改输入
// 返回: 错误信息
ModifyIssueReward(ctx context.Context, rewardID int64, in ModifyRewardInput) error
// DeleteIssueReward 删除单个奖励
// 参数: rewardID 奖励ID
// 返回: 错误信息
DeleteIssueReward(ctx context.Context, rewardID int64) error
// ListDrawLogs 抽奖记录列表
// 参数: issueID 期ID, page/pageSize 分页, level 等级过滤
// 返回: 抽奖记录集合、总数与错误
ListDrawLogs(ctx context.Context, issueID int64, page, pageSize int, level *int32) (items []*model.ActivityDrawLogs, total int64, err error)
// GetCategoryNames 批量查询分类名称
// 参数: ids 分类ID数组
// 返回: id->名称映射与错误
GetCategoryNames(ctx context.Context, ids []int64) (map[int64]string, error)
// CopyActivity 复制活动及其期次与奖励
// 参数: activityID 源活动ID
// 返回: 新活动ID与错误
CopyActivity(ctx context.Context, activityID int64) (int64, error)
// SaveActivityDrawConfig 保存活动开奖配置
// 参数: activityID 活动ID, cfg 配置
// 返回: 错误信息
SaveActivityDrawConfig(ctx context.Context, activityID int64, cfg DrawConfig) error
// GetActivityDrawConfig 读取活动开奖配置
// 参数: activityID 活动ID
// 返回: 配置与错误
GetActivityDrawConfig(ctx context.Context, activityID int64) (*DrawConfig, error)
// ReconstructMatchingGame 还原对对碰游戏过程
ReconstructMatchingGame(ctx context.Context, orderNo string) (*MatchingGame, error)
// GetMatchingGameFromRedis 从缓存获取游戏
GetMatchingGameFromRedis(ctx context.Context, gameID string) (*MatchingGame, error)
// SaveMatchingGameToRedis 保存游戏到缓存
SaveMatchingGameToRedis(ctx context.Context, gameID string, game *MatchingGame) error
// ListMatchingCardTypes 获取卡牌类型配置
ListMatchingCardTypes(ctx context.Context) ([]CardTypeConfig, error)
// ClearIchibanPositionsByOrderID 清理订单对应的一番赏占位
ClearIchibanPositionsByOrderID(ctx context.Context, orderID int64) error
}
type service struct {
logger logger.CustomLogger
readDB *dao.Query
writeDB *dao.Query
repo mysql.Repo
user usersvc.Service
redis *redis.Client
}
func New(l logger.CustomLogger, db mysql.Repo, u usersvc.Service, rdb *redis.Client) Service {
return &service{
logger: l,
readDB: dao.Use(db.GetDbR()),
writeDB: dao.Use(db.GetDbW()),
repo: db,
user: u,
redis: rdb,
}
}
type CreateActivityInput struct {
// Name 活动名称
Name string
// Banner 活动头图
Banner string
// Image 活动主图
Image string
// GameplayIntro 玩法介绍
GameplayIntro string
// ActivityCategoryID 活动分类ID
ActivityCategoryID int64
// Status 活动状态
Status int32
// PriceDraw 单次抽奖价格(分)
PriceDraw int64
// IsBoss 是否Boss活动
IsBoss int32
// StartTime 活动开始时间(可选)
StartTime *time.Time
// EndTime 活动结束时间(可选)
EndTime *time.Time
AllowItemCards int32
AllowCoupons int32
}
type ModifyActivityInput struct {
// Name 活动名称
Name string
// Banner 活动头图
Banner string
// Image 活动主图
Image string
// GameplayIntro 玩法介绍
GameplayIntro string
// ActivityCategoryID 活动分类ID
ActivityCategoryID int64
// Status 活动状态
Status int32
// PriceDraw 单次抽奖价格(分)
PriceDraw int64
// IsBoss 是否Boss活动
IsBoss int32
// StartTime 活动开始时间(可选)
StartTime *time.Time
// EndTime 活动结束时间(可选)
EndTime *time.Time
AllowItemCards *int32
AllowCoupons *int32
}
type ListActivitiesInput struct {
// Name 名称过滤
Name string
// CategoryID 分类过滤
CategoryID int64
// IsBoss Boss过滤
IsBoss *int32
// Status 状态过滤
Status *int32
// Page 页码
Page int
// PageSize 每页数量
PageSize int
}
type CreateIssueInput struct {
// IssueNumber 期号
IssueNumber string
// Status 状态
Status int32
// Sort 排序
Sort int32
}
type ModifyIssueInput struct {
// IssueNumber 期号
IssueNumber string
// Status 状态
Status int32
// Sort 排序
Sort int32
}
type CreateRewardInput struct {
// ProductID 商品ID
ProductID int64
// Name 奖励名称
Name string
// Weight 权重
Weight int32
// Quantity 数量(-1 表示不限)
Quantity int64
// OriginalQty 初始数量
OriginalQty int64
// Level 奖励等级
Level int32
// Sort 排序
Sort int32
// IsBoss 是否Boss奖励
IsBoss int32
MinScore int64
// DropQuantity 单次抽中产出数量默认1
DropQuantity int32
}
type ModifyRewardInput struct {
// ProductID 商品ID
ProductID *int64
// Name 奖励名称
Name string
// Weight 权重
Weight *float64
// Quantity 数量(-1 表示不限)
Quantity *int64
// OriginalQty 初始数量
OriginalQty *int64
// Level 奖励等级
Level *int32
// Sort 排序
Sort *int32
// IsBoss 是否Boss奖励
IsBoss *int32
MinScore *int64
// DropQuantity 单次抽中产出数量
DropQuantity *int32
}