refactor(utils): 修复密码哈希比较逻辑错误 feat(user): 新增按状态筛选优惠券接口 docs: 添加虚拟发货与任务中心相关文档 fix(wechat): 修正Code2Session上下文传递问题 test: 补充订单折扣与积分转换测试用例 build: 更新配置文件与构建脚本 style: 清理多余的空行与注释
133 lines
3.5 KiB
Go
133 lines
3.5 KiB
Go
package user
|
||
|
||
import (
|
||
"context"
|
||
"strconv"
|
||
"time"
|
||
)
|
||
|
||
// ProductInfo 商品简要信息
|
||
type ProductInfo struct {
|
||
ID int64 `json:"id"`
|
||
Name string `json:"name"`
|
||
Image string `json:"image"`
|
||
Price int64 `json:"price"`
|
||
}
|
||
|
||
type ShipmentGroup struct {
|
||
ExpressCode string `json:"express_code"`
|
||
ExpressNo string `json:"express_no"`
|
||
BatchNo string `json:"batch_no"`
|
||
Status int32 `json:"status"`
|
||
Count int64 `json:"count"`
|
||
ShippedAt *time.Time `json:"shipped_at,omitempty"`
|
||
ReceivedAt *time.Time `json:"received_at,omitempty"`
|
||
InventoryIDs []int64 `json:"inventory_ids"`
|
||
ProductIDs []int64 `json:"product_ids"`
|
||
Products []ProductInfo `json:"products"`
|
||
}
|
||
|
||
func (s *service) ListUserShipmentGroups(ctx context.Context, userID int64, page, pageSize int) (items []*ShipmentGroup, total int64, err error) {
|
||
q := s.readDB.ShippingRecords.WithContext(ctx).ReadDB().Where(s.readDB.ShippingRecords.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.ShippingRecords.UpdatedAt.Desc(), s.readDB.ShippingRecords.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
|
||
if err != nil {
|
||
return nil, 0, err
|
||
}
|
||
type acc struct {
|
||
status int32
|
||
shippedAt *time.Time
|
||
receivedAt *time.Time
|
||
inv []int64
|
||
pid []int64
|
||
}
|
||
m := make(map[string]*acc)
|
||
meta := make(map[string]struct{ code, no, batch string })
|
||
order := make([]string, 0) // 保持顺序
|
||
for _, r := range rows {
|
||
// 分组优先级:运单号 > 批次号 > 记录ID
|
||
key := ""
|
||
if r.ExpressNo != "" {
|
||
// 有运单号,按运单号分组
|
||
key = "E|" + r.ExpressCode + "|" + r.ExpressNo
|
||
} else if r.BatchNo != "" {
|
||
// 无运单号但有批次号,按批次号分组
|
||
key = "B|" + r.BatchNo
|
||
} else {
|
||
// 无运单号也无批次号,按记录ID独立
|
||
key = "_" + strconv.FormatInt(r.ID, 10)
|
||
}
|
||
|
||
if _, ok := m[key]; !ok {
|
||
m[key] = &acc{}
|
||
meta[key] = struct{ code, no, batch string }{r.ExpressCode, r.ExpressNo, r.BatchNo}
|
||
order = append(order, key)
|
||
}
|
||
a := m[key]
|
||
if a.status == 0 || r.Status >= a.status {
|
||
a.status = r.Status
|
||
}
|
||
if !r.ShippedAt.IsZero() {
|
||
t := r.ShippedAt
|
||
a.shippedAt = &t
|
||
}
|
||
if !r.ReceivedAt.IsZero() {
|
||
t := r.ReceivedAt
|
||
a.receivedAt = &t
|
||
}
|
||
a.inv = append(a.inv, r.InventoryID)
|
||
if r.ProductID > 0 {
|
||
a.pid = append(a.pid, r.ProductID)
|
||
}
|
||
}
|
||
items = make([]*ShipmentGroup, 0, len(m))
|
||
for _, k := range order {
|
||
a := m[k]
|
||
md := meta[k]
|
||
c := int64(len(a.inv))
|
||
|
||
// 获取商品详情(去重)
|
||
pidSet := make(map[int64]struct{})
|
||
for _, pid := range a.pid {
|
||
pidSet[pid] = struct{}{}
|
||
}
|
||
products := make([]ProductInfo, 0, len(pidSet))
|
||
for pid := range pidSet {
|
||
if prod, _ := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.ID.Eq(pid)).First(); prod != nil {
|
||
products = append(products, ProductInfo{
|
||
ID: prod.ID,
|
||
Name: prod.Name,
|
||
Image: prod.ImagesJSON,
|
||
Price: prod.Price,
|
||
})
|
||
}
|
||
}
|
||
|
||
items = append(items, &ShipmentGroup{
|
||
ExpressCode: md.code,
|
||
ExpressNo: md.no,
|
||
BatchNo: md.batch,
|
||
Status: a.status,
|
||
Count: c,
|
||
ShippedAt: a.shippedAt,
|
||
ReceivedAt: a.receivedAt,
|
||
InventoryIDs: a.inv,
|
||
ProductIDs: a.pid,
|
||
Products: products,
|
||
})
|
||
}
|
||
return items, int64(len(items)), nil
|
||
}
|