bindbox-game/internal/service/user/inventory_list.go

321 lines
8.8 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 user
import (
"context"
"time"
"bindbox-game/internal/repository/mysql/model"
)
type InventoryWithProduct struct {
*model.UserInventory
ProductName string `json:"product_name"`
ProductImages string `json:"product_images"`
ProductPrice int64 `json:"product_price"` // 新增价格字段
HasShipment bool `json:"has_shipment"`
ShippingStatus int32 `json:"shipping_status"`
}
type AggregatedInventory struct {
ProductID int64 `json:"product_id"`
ProductName string `json:"product_name"`
ProductImages string `json:"product_images"`
ProductPrice int64 `json:"product_price"`
Count int64 `json:"count"`
InventoryIDs []int64 `json:"inventory_ids"`
HasShipment bool `json:"has_shipment"`
ShippingStatus int32 `json:"shipping_status"`
Status int32 `json:"status"` // 用于区分 1持有 3已处理
UpdatedAt string `json:"updated_at"`
}
func (s *service) ListInventoryWithProduct(ctx context.Context, userID int64, page, pageSize int, status int32) (items []*InventoryWithProduct, total int64, err error) {
q := s.readDB.UserInventory.WithContext(ctx).ReadDB().Where(s.readDB.UserInventory.UserID.Eq(userID))
if status > 0 {
q = q.Where(s.readDB.UserInventory.Status.Eq(status))
} else {
// status=0时默认行为是不加额外状态过滤查询所有记录。
// 如果需要保持兼容性(例如之前可能过滤了软删除),需确认。假设这里是查询所有历史记录。
}
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.UserInventory.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
if err != nil {
return nil, 0, err
}
pidMap := make(map[int64]struct{})
invIDs := make([]int64, 0, len(rows))
for _, r := range rows {
invIDs = append(invIDs, r.ID)
if r.ProductID > 0 {
pidMap[r.ProductID] = struct{}{}
}
}
products := map[int64]*model.Products{}
if len(pidMap) > 0 {
ids := make([]int64, 0, len(pidMap))
for id := range pidMap {
ids = append(ids, id)
}
pros, err := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.ID.In(ids...)).Find()
if err != nil {
return nil, 0, err
}
for _, p := range pros {
products[p.ID] = p
}
}
// 查询发货记录,按 inventory 维度取最新状态
shipMap := map[int64]*model.ShippingRecords{}
if len(invIDs) > 0 {
ships, _ := s.readDB.ShippingRecords.WithContext(ctx).ReadDB().Where(s.readDB.ShippingRecords.InventoryID.In(invIDs...)).Order(s.readDB.ShippingRecords.UpdatedAt.Desc(), s.readDB.ShippingRecords.ID.Desc()).Find()
for _, sh := range ships {
if _, ok := shipMap[sh.InventoryID]; !ok {
shipMap[sh.InventoryID] = sh
}
}
}
items = make([]*InventoryWithProduct, len(rows))
for i, r := range rows {
p := products[r.ProductID]
name := ""
images := ""
price := r.ValueCents
if p != nil {
name = p.Name
images = p.ImagesJSON
}
if price <= 0 && p != nil {
price = p.Price
}
sh := shipMap[r.ID]
has := sh != nil && sh.Status != 5
var st int32
if sh != nil {
st = sh.Status
}
items[i] = &InventoryWithProduct{
UserInventory: r,
ProductName: name,
ProductImages: images,
ProductPrice: price,
HasShipment: has,
ShippingStatus: st,
}
}
return items, total, nil
}
func (s *service) ListInventoryWithProductActive(ctx context.Context, userID int64, page, pageSize int, status int32) (items []*InventoryWithProduct, total int64, err error) {
q := s.readDB.UserInventory.WithContext(ctx).ReadDB().Where(
s.readDB.UserInventory.UserID.Eq(userID),
)
if status > 0 {
q = q.Where(s.readDB.UserInventory.Status.Eq(status))
} else {
q = q.Where(s.readDB.UserInventory.Status.Neq(2))
}
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.UserInventory.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
if err != nil {
return nil, 0, err
}
pidMap := make(map[int64]struct{})
invIDs := make([]int64, 0, len(rows))
for _, r := range rows {
invIDs = append(invIDs, r.ID)
if r.ProductID > 0 {
pidMap[r.ProductID] = struct{}{}
}
}
products := map[int64]*model.Products{}
if len(pidMap) > 0 {
ids := make([]int64, 0, len(pidMap))
for id := range pidMap {
ids = append(ids, id)
}
pros, err := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.ID.In(ids...)).Find()
if err != nil {
return nil, 0, err
}
for _, p := range pros {
products[p.ID] = p
}
}
shipMap := map[int64]*model.ShippingRecords{}
if len(invIDs) > 0 {
ships, _ := s.readDB.ShippingRecords.WithContext(ctx).ReadDB().Where(s.readDB.ShippingRecords.InventoryID.In(invIDs...)).Order(s.readDB.ShippingRecords.UpdatedAt.Desc(), s.readDB.ShippingRecords.ID.Desc()).Find()
for _, sh := range ships {
if _, ok := shipMap[sh.InventoryID]; !ok {
shipMap[sh.InventoryID] = sh
}
}
}
items = make([]*InventoryWithProduct, len(rows))
for i, r := range rows {
p := products[r.ProductID]
name := ""
images := ""
price := r.ValueCents
if p != nil {
name = p.Name
images = p.ImagesJSON
}
if price <= 0 && p != nil {
price = p.Price
}
sh := shipMap[r.ID]
has := sh != nil && sh.Status != 5
var st int32
if sh != nil {
st = sh.Status
}
items[i] = &InventoryWithProduct{
UserInventory: r,
ProductName: name,
ProductImages: images,
ProductPrice: price,
HasShipment: has,
ShippingStatus: st,
}
}
return items, total, nil
}
func (s *service) ListInventoryAggregated(ctx context.Context, userID int64, page, pageSize int, status int32) (items []*AggregatedInventory, total int64, err error) {
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
if pageSize > 100 {
pageSize = 100
}
// 1. 获取聚合后的商品ID列表 (GROUP BY product_id, status)
var groupResults []struct {
ProductID int64 `gorm:"column:product_id"`
Status int32 `gorm:"column:status"`
Count int64 `gorm:"column:count"`
ValueCents int64 `gorm:"column:value_cents"`
UpdatedAt time.Time `gorm:"column:updated_at"`
}
q := s.readDB.UserInventory.WithContext(ctx).ReadDB().
Select(
s.readDB.UserInventory.ProductID,
s.readDB.UserInventory.Status,
s.readDB.UserInventory.ID.Count().As("count"),
s.readDB.UserInventory.ValueCents.Max().As("value_cents"),
s.readDB.UserInventory.UpdatedAt.Max().As("updated_at"),
).
Where(s.readDB.UserInventory.UserID.Eq(userID))
if status > 0 {
q = q.Where(s.readDB.UserInventory.Status.Eq(status))
} else {
q = q.Where(s.readDB.UserInventory.Status.Neq(2))
}
// 分组逻辑
err = q.Group(s.readDB.UserInventory.ProductID, s.readDB.UserInventory.Status).
Order(s.readDB.UserInventory.UpdatedAt.Max().Desc()).
Scan(&groupResults)
if err != nil {
return nil, 0, err
}
total = int64(len(groupResults))
start := (page - 1) * pageSize
if start >= len(groupResults) {
return []*AggregatedInventory{}, total, nil
}
end := start + pageSize
if end > len(groupResults) {
end = len(groupResults)
}
pagedGroups := groupResults[start:end]
// 2. 获取商品详情和发货状态
items = make([]*AggregatedInventory, 0, len(pagedGroups))
for _, g := range pagedGroups {
// 查询该分组下的所有 inventory id
var invIDs []int64
s.readDB.UserInventory.WithContext(ctx).ReadDB().
Select(s.readDB.UserInventory.ID).
Where(
s.readDB.UserInventory.UserID.Eq(userID),
s.readDB.UserInventory.ProductID.Eq(g.ProductID),
s.readDB.UserInventory.Status.Eq(g.Status),
).Scan(&invIDs)
// 获取商品元数据
p, _ := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.ID.Eq(g.ProductID)).First()
name := "未知商品"
images := ""
price := g.ValueCents
if p != nil {
name = p.Name
images = p.ImagesJSON
}
if price <= 0 && p != nil {
price = p.Price
}
// 检查发货状态 (取其中一个 inv id 检查即可)
var hasShip bool
var shipStatus int32
if len(invIDs) > 0 {
ship, _ := s.readDB.ShippingRecords.WithContext(ctx).ReadDB().
Where(s.readDB.ShippingRecords.InventoryID.Eq(invIDs[0])).
Where(s.readDB.ShippingRecords.Status.Neq(5)).
Order(s.readDB.ShippingRecords.ID.Desc()).
First()
if ship != nil {
hasShip = true
shipStatus = ship.Status
}
}
items = append(items, &AggregatedInventory{
ProductID: g.ProductID,
ProductName: name,
ProductImages: images,
ProductPrice: price,
Count: g.Count,
InventoryIDs: invIDs,
HasShipment: hasShip,
ShippingStatus: shipStatus,
Status: g.Status,
UpdatedAt: g.UpdatedAt.Format("2006-01-02 15:04:05"),
})
}
return items, total, nil
}