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) (items []*InventoryWithProduct, total int64, err error) { q := s.readDB.UserInventory.WithContext(ctx).ReadDB().Where(s.readDB.UserInventory.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.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 := "" var price int64 if p != nil { name = p.Name images = p.ImagesJSON 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 := "" var price int64 if p != nil { name = p.Name images = p.ImagesJSON 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"` 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.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 := "" var price int64 if p != nil { name = p.Name images = p.ImagesJSON 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 }