bindbox-game/internal/service/user/item_cards_list.go
2025-12-26 12:22:32 +08:00

455 lines
13 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 user
import (
"context"
"bindbox-game/internal/repository/mysql/model"
)
type ItemCardWithTemplate struct {
*model.UserItemCards
Name string `json:"name"`
CardType int32 `json:"card_type"`
ScopeType int32 `json:"scope_type"`
EffectType int32 `json:"effect_type"`
StackingStrategy int32 `json:"stacking_strategy"`
Remark string `json:"remark"`
Count int64 `json:"count"`
UsedActivityName string `json:"used_activity_name"`
UsedIssueNumber string `json:"used_issue_number"`
UsedRewardName string `json:"used_reward_name"`
}
// ListAggregatedUserItemCards 获取聚合后的用户道具卡列表(按卡种分组)
func (s *service) ListAggregatedUserItemCards(ctx context.Context, userID int64, status int32, page, pageSize int) (items []*ItemCardWithTemplate, total int64, err error) {
// 1. 计算分组总数 (Using UnderlyingDB for raw SQL flexibility)
var countResult []struct {
CardID int64
Total int64
}
tx := s.readDB.UserItemCards.WithContext(ctx).ReadDB().UnderlyingDB().
Model(&model.UserItemCards{}).
Where("user_id = ? AND status = ?", userID, status)
// Count Distinct CardID
err = tx.Distinct("card_id").Count(&total).Error
if err != nil {
return nil, 0, err
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
// 2. 分页查询分组数据
err = tx.Select("card_id, count(*) as total").
Group("card_id").
Order("card_id desc").
Offset((page - 1) * pageSize).
Limit(pageSize).
Scan(&countResult).Error
if err != nil {
return nil, 0, err
}
if len(countResult) == 0 {
return []*ItemCardWithTemplate{}, 0, nil
}
// 3. 获取每组的一个实例(用于获取有效期等信息)和模板信息
cardIDs := make([]int64, 0, len(countResult))
for _, r := range countResult {
cardIDs = append(cardIDs, r.CardID)
}
// 获取模板信息
tpls := map[int64]*model.SystemItemCards{}
// Using GEN helpers for simple queries
tplList, err := s.readDB.SystemItemCards.WithContext(ctx).ReadDB().Where(s.readDB.SystemItemCards.ID.In(cardIDs...)).Find()
if err != nil {
return nil, 0, err
}
for _, t := range tplList {
tpls[t.ID] = t
}
items = make([]*ItemCardWithTemplate, 0, len(countResult))
for _, r := range countResult {
// Find latest instance using GEN helpers
instance, _ := s.readDB.UserItemCards.WithContext(ctx).ReadDB().
Where(s.readDB.UserItemCards.UserID.Eq(userID), s.readDB.UserItemCards.Status.Eq(status), s.readDB.UserItemCards.CardID.Eq(r.CardID)).
Order(s.readDB.UserItemCards.ID.Desc()).
First()
if instance == nil {
instance = &model.UserItemCards{UserID: userID, CardID: r.CardID, Status: status}
}
tpl := tpls[r.CardID]
var name, remark string
var cardType, scopeType, effectType, stacking int32
if tpl != nil {
name = tpl.Name
cardType = tpl.CardType
scopeType = tpl.ScopeType
effectType = tpl.EffectType
stacking = tpl.StackingStrategy
remark = tpl.Remark
}
items = append(items, &ItemCardWithTemplate{
UserItemCards: instance,
Name: name,
CardType: cardType,
ScopeType: scopeType,
EffectType: effectType,
StackingStrategy: stacking,
Remark: remark,
Count: r.Total,
})
}
return items, total, nil
}
// ListUserItemCards 获取用户道具卡列表
// 功能描述:
// - 查询指定用户的道具卡列表
// - 支持分页查询默认每页20条最大100条
// - 按创建时间倒序排列
//
// 参数说明:
// - ctx: 上下文
// - userID: 用户ID
// - page: 页码从1开始小于1时自动设为1
// - pageSize: 每页条数小于1时设为20大于100时设为100
//
// 返回说明:
// - items: 道具卡列表
// - total: 总记录数
// - err: 错误信息
func (s *service) ListUserItemCards(ctx context.Context, userID int64, page, pageSize int) (items []*model.UserItemCards, total int64, err error) {
q := s.readDB.UserItemCards.WithContext(ctx).ReadDB().Where(s.readDB.UserItemCards.UserID.Eq(userID))
total, err = q.Count()
if err != nil {
return nil, 0, err
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
if pageSize > 100 {
pageSize = 100
}
items, err = q.Order(s.readDB.UserItemCards.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
if err != nil {
return nil, 0, err
}
return items, total, nil
}
func (s *service) ListUserItemCardsWithTemplate(ctx context.Context, userID int64, page, pageSize int) (items []*ItemCardWithTemplate, total int64, err error) {
q := s.readDB.UserItemCards.WithContext(ctx).ReadDB().Where(s.readDB.UserItemCards.UserID.Eq(userID))
total, err = q.Count()
if err != nil {
return nil, 0, err
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
if pageSize > 100 {
pageSize = 100
}
rows, err := q.Order(s.readDB.UserItemCards.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
if err != nil {
return nil, 0, err
}
cidMap := make(map[int64]struct{})
for _, r := range rows {
if r.CardID > 0 {
cidMap[r.CardID] = struct{}{}
}
}
tpls := map[int64]*model.SystemItemCards{}
if len(cidMap) > 0 {
ids := make([]int64, 0, len(cidMap))
for id := range cidMap {
ids = append(ids, id)
}
list, err := s.readDB.SystemItemCards.WithContext(ctx).ReadDB().Where(s.readDB.SystemItemCards.ID.In(ids...)).Find()
if err != nil {
return nil, 0, err
}
for _, it := range list {
tpls[it.ID] = it
}
}
items = make([]*ItemCardWithTemplate, len(rows))
for i, r := range rows {
tpl := tpls[r.CardID]
var name string
var cardType, scopeType, effectType, stacking int32
var remark string
if tpl != nil {
name = tpl.Name
cardType = tpl.CardType
scopeType = tpl.ScopeType
effectType = tpl.EffectType
stacking = tpl.StackingStrategy
remark = tpl.Remark
}
items[i] = &ItemCardWithTemplate{
UserItemCards: r,
Name: name,
CardType: cardType,
ScopeType: scopeType,
EffectType: effectType,
StackingStrategy: stacking,
Remark: remark,
Count: 1, // Individual record
}
}
return items, total, nil
}
func (s *service) ListUserItemCardsWithTemplateUsable(ctx context.Context, userID int64, page, pageSize int) (items []*ItemCardWithTemplate, total int64, err error) {
q := s.readDB.UserItemCards.WithContext(ctx).ReadDB().Where(
s.readDB.UserItemCards.UserID.Eq(userID),
s.readDB.UserItemCards.Status.Eq(1),
)
total, err = q.Count()
if err != nil {
return nil, 0, err
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
if pageSize > 100 {
pageSize = 100
}
rows, err := q.Order(s.readDB.UserItemCards.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
if err != nil {
return nil, 0, err
}
cidMap := make(map[int64]struct{})
for _, r := range rows {
if r.CardID > 0 {
cidMap[r.CardID] = struct{}{}
}
}
tpls := map[int64]*model.SystemItemCards{}
if len(cidMap) > 0 {
ids := make([]int64, 0, len(cidMap))
for id := range cidMap {
ids = append(ids, id)
}
list, err := s.readDB.SystemItemCards.WithContext(ctx).ReadDB().Where(s.readDB.SystemItemCards.ID.In(ids...)).Find()
if err != nil {
return nil, 0, err
}
for _, it := range list {
tpls[it.ID] = it
}
}
items = make([]*ItemCardWithTemplate, len(rows))
for i, r := range rows {
tpl := tpls[r.CardID]
var name string
var cardType, scopeType, effectType, stacking int32
var remark string
if tpl != nil {
name = tpl.Name
cardType = tpl.CardType
scopeType = tpl.ScopeType
effectType = tpl.EffectType
stacking = tpl.StackingStrategy
remark = tpl.Remark
}
items[i] = &ItemCardWithTemplate{
UserItemCards: r,
Name: name,
CardType: cardType,
ScopeType: scopeType,
EffectType: effectType,
StackingStrategy: stacking,
Remark: remark,
Count: 1,
}
}
return items, total, nil
}
// ListUserItemCardsWithTemplateByStatus 按状态获取用户道具卡列表
func (s *service) ListUserItemCardsWithTemplateByStatus(ctx context.Context, userID int64, status int32, page, pageSize int) (items []*ItemCardWithTemplate, total int64, err error) {
q := s.readDB.UserItemCards.WithContext(ctx).ReadDB().Where(
s.readDB.UserItemCards.UserID.Eq(userID),
s.readDB.UserItemCards.Status.Eq(status),
)
total, err = q.Count()
if err != nil {
return nil, 0, err
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
if pageSize > 100 {
pageSize = 100
}
rows, err := q.Order(s.readDB.UserItemCards.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
if err != nil {
return nil, 0, err
}
cidMap := make(map[int64]struct{})
for _, r := range rows {
if r.CardID > 0 {
cidMap[r.CardID] = struct{}{}
}
}
tpls := map[int64]*model.SystemItemCards{}
if len(cidMap) > 0 {
ids := make([]int64, 0, len(cidMap))
for id := range cidMap {
ids = append(ids, id)
}
list, err := s.readDB.SystemItemCards.WithContext(ctx).ReadDB().Where(s.readDB.SystemItemCards.ID.In(ids...)).Find()
if err != nil {
return nil, 0, err
}
for _, it := range list {
tpls[it.ID] = it
}
}
// Data collection for batch fetching
var usedActivityIDs []int64
var usedIssueIDs []int64
var usedDrawLogIDs []int64
for _, r := range rows {
if status == 2 { // ONLY for Used status
if r.UsedActivityID > 0 {
usedActivityIDs = append(usedActivityIDs, r.UsedActivityID)
}
if r.UsedIssueID > 0 {
usedIssueIDs = append(usedIssueIDs, r.UsedIssueID)
}
if r.UsedDrawLogID > 0 {
usedDrawLogIDs = append(usedDrawLogIDs, r.UsedDrawLogID)
}
}
}
// Maps for enrichment
activityNameMap := make(map[int64]string)
issueNumberMap := make(map[int64]string)
rewardNameMap := make(map[int64]string)
if len(usedActivityIDs) > 0 {
var err error
var acts []*model.Activities
if acts, err = s.readDB.Activities.WithContext(ctx).ReadDB().Select(s.readDB.Activities.ID, s.readDB.Activities.Name).Where(s.readDB.Activities.ID.In(usedActivityIDs...)).Find(); err == nil {
for _, a := range acts {
activityNameMap[a.ID] = a.Name
}
}
}
if len(usedIssueIDs) > 0 {
var err error
var issues []*model.ActivityIssues
if issues, err = s.readDB.ActivityIssues.WithContext(ctx).ReadDB().Select(s.readDB.ActivityIssues.ID, s.readDB.ActivityIssues.IssueNumber).Where(s.readDB.ActivityIssues.ID.In(usedIssueIDs...)).Find(); err == nil {
for _, i := range issues {
issueNumberMap[i.ID] = i.IssueNumber
}
}
}
if len(usedDrawLogIDs) > 0 {
var err error
var logs []*model.ActivityDrawLogs
// join reward settings to get name
if logs, err = s.readDB.ActivityDrawLogs.WithContext(ctx).ReadDB().Select(s.readDB.ActivityDrawLogs.ID, s.readDB.ActivityDrawLogs.RewardID).Where(s.readDB.ActivityDrawLogs.ID.In(usedDrawLogIDs...)).Find(); err == nil {
var rewardIDs []int64
logToRewardID := make(map[int64]int64)
for _, l := range logs {
if l.RewardID > 0 {
rewardIDs = append(rewardIDs, l.RewardID)
logToRewardID[l.ID] = l.RewardID
}
}
if len(rewardIDs) > 0 {
var rewards []*model.ActivityRewardSettings
if rewards, err = s.readDB.ActivityRewardSettings.WithContext(ctx).ReadDB().Select(s.readDB.ActivityRewardSettings.ID, s.readDB.ActivityRewardSettings.Name).Where(s.readDB.ActivityRewardSettings.ID.In(rewardIDs...)).Find(); err == nil {
rewardNameMapByID := make(map[int64]string)
for _, r := range rewards {
rewardNameMapByID[r.ID] = r.Name
}
// Map log ID back to reward name
for logID, rewardID := range logToRewardID {
if name, ok := rewardNameMapByID[rewardID]; ok {
rewardNameMap[logID] = name
}
}
}
}
}
}
items = make([]*ItemCardWithTemplate, len(rows))
for i, r := range rows {
tpl := tpls[r.CardID]
var name string
var cardType, scopeType, effectType, stacking int32
var remark string
if tpl != nil {
name = tpl.Name
cardType = tpl.CardType
scopeType = tpl.ScopeType
effectType = tpl.EffectType
stacking = tpl.StackingStrategy
remark = tpl.Remark
}
item := &ItemCardWithTemplate{
UserItemCards: r,
Name: name,
CardType: cardType,
ScopeType: scopeType,
EffectType: effectType,
StackingStrategy: stacking,
Remark: remark,
Count: 1, // Individual record
}
// Fill enrichment data
if r.UsedActivityID > 0 {
item.UsedActivityName = activityNameMap[r.UsedActivityID]
}
if r.UsedIssueID > 0 {
item.UsedIssueNumber = issueNumberMap[r.UsedIssueID]
}
if r.UsedDrawLogID > 0 {
item.UsedRewardName = rewardNameMap[r.UsedDrawLogID]
}
items[i] = item
}
return items, total, nil
}