diff --git a/internal/model/dto/asset_dto.go b/internal/model/dto/asset_dto.go index 85bb375f..2948d2a7 100644 --- a/internal/model/dto/asset_dto.go +++ b/internal/model/dto/asset_dto.go @@ -298,6 +298,7 @@ type PackageTrafficAdjustmentItem struct { RefObservationID string `json:"ref_observation_id" description:"关联的采集 ID"` RefEventID string `json:"ref_event_id" description:"关联的流量事件 ID"` OperatorID uint `json:"operator_id" description:"操作人账号ID"` + OperatorName string `json:"operator_name" description:"操作人账号用户名"` CreatedAt time.Time `json:"created_at" description:"冲正时间"` } diff --git a/internal/model/dto/record_query_dto.go b/internal/model/dto/record_query_dto.go index 22b51b97..715e610f 100644 --- a/internal/model/dto/record_query_dto.go +++ b/internal/model/dto/record_query_dto.go @@ -50,8 +50,10 @@ type TrafficCollectionListRequest struct { // TrafficCollectionRecordItem 采集成功记录。 type TrafficCollectionRecordItem struct { CardTrafficCollectionItem - IotCardID uint `json:"iot_card_id" description:"卡ID"` - CarrierID uint `json:"carrier_id" description:"运营商账户ID(历史记录为 0)"` + IotCardID uint `json:"iot_card_id" description:"卡ID"` + ICCID string `json:"iccid" description:"ICCID"` + CarrierID uint `json:"carrier_id" description:"运营商账户ID(历史记录为 0)"` + CarrierName string `json:"carrier_name" description:"运营商账户名称"` } // TrafficCollectionRecordListResponse 采集成功记录分页结果。 @@ -79,6 +81,7 @@ type TrafficCollectionFailureItem struct { IotCardID uint `json:"iot_card_id" description:"卡ID"` ICCID string `json:"iccid" description:"ICCID"` CarrierID uint `json:"carrier_id" description:"运营商账户ID"` + CarrierName string `json:"carrier_name" description:"运营商账户名称"` ObservedAt time.Time `json:"observed_at" description:"采集时间"` ObservationID string `json:"observation_id" description:"采集 ID(等于对接日志 integration_id)"` Source string `json:"source" description:"来源"` @@ -112,6 +115,7 @@ type CardDailyUsageItem struct { IotCardID uint `json:"iot_card_id" description:"卡ID"` ICCID string `json:"iccid" description:"ICCID"` CarrierID uint `json:"carrier_id" description:"运营商账户ID"` + CarrierName string `json:"carrier_name" description:"运营商账户名称"` Date string `json:"date" description:"日期(上海)"` SettledMB float64 `json:"settled_mb" description:"当日已结算增量合计(MB),即当日用量"` MonthUsedMB float64 `json:"month_used_mb" description:"当日结束时的本月自然月累计(MB)"` @@ -142,8 +146,12 @@ type PackageUsageDailyRecordItem struct { ID uint `json:"id" description:"记录ID"` PackageUsageID uint `json:"package_usage_id" description:"套餐使用记录ID"` PackageID uint `json:"package_id" description:"套餐ID"` + PackageName string `json:"package_name" description:"套餐名称(套餐使用记录快照)"` IotCardID uint `json:"iot_card_id" description:"卡ID,设备套餐为 0"` + ICCID string `json:"iccid" description:"ICCID(卡套餐)"` DeviceID uint `json:"device_id" description:"设备ID,卡套餐为 0"` + DeviceVirtualNo string `json:"device_virtual_no" description:"设备号(设备套餐)"` + DeviceIMEI string `json:"device_imei" description:"设备 IMEI(设备套餐)"` Date string `json:"date" description:"日期"` DailyUsageMB int `json:"daily_usage_mb" description:"当日流量(MB)"` CumulativeUsageMB int64 `json:"cumulative_usage_mb" description:"截止当日累计(MB)"` @@ -169,8 +177,12 @@ type PackageTrafficAdjustmentQueryRequest struct { // PackageTrafficAdjustmentRecordItem 冲正流水(跨卡列表)。 type PackageTrafficAdjustmentRecordItem struct { PackageTrafficAdjustmentItem - IotCardID uint `json:"iot_card_id" description:"卡ID"` - DeviceID uint `json:"device_id" description:"设备ID"` + PackageName string `json:"package_name" description:"套餐名称(套餐使用记录快照)"` + IotCardID uint `json:"iot_card_id" description:"卡ID"` + ICCID string `json:"iccid" description:"ICCID(卡套餐)"` + DeviceID uint `json:"device_id" description:"设备ID"` + DeviceVirtualNo string `json:"device_virtual_no" description:"设备号(设备套餐)"` + DeviceIMEI string `json:"device_imei" description:"设备 IMEI(设备套餐)"` } // PackageTrafficAdjustmentRecordListResponse 冲正流水分页结果(跨卡列表)。 @@ -194,20 +206,22 @@ type RefundPostProcessAttemptListRequest struct { // RefundPostProcessAttemptItem 退款资产后处理尝试记录。 type RefundPostProcessAttemptItem struct { - ID uint `json:"id" description:"记录ID"` - RefundID uint `json:"refund_id" description:"退款单ID"` - RefundNo string `json:"refund_no" description:"退款单号"` - Step string `json:"step" description:"处理步骤(失败时为失败步骤,成功为 done)"` - AssetType string `json:"asset_type" description:"资产类型"` - AssetID uint `json:"asset_id" description:"资产ID"` - ICCID string `json:"iccid" description:"ICCID(单卡资产)"` - Attempt int `json:"attempt" description:"尝试序号"` - Trigger string `json:"trigger" description:"触发方式"` - Result string `json:"result" description:"结果"` - ErrorCode string `json:"error_code" description:"错误码"` - ErrorMessage string `json:"error_message" description:"错误信息"` - DurationMS int `json:"duration_ms" description:"耗时(毫秒)"` - CreatedAt time.Time `json:"created_at" description:"记录时间"` + ID uint `json:"id" description:"记录ID"` + RefundID uint `json:"refund_id" description:"退款单ID"` + RefundNo string `json:"refund_no" description:"退款单号"` + Step string `json:"step" description:"处理步骤(失败时为失败步骤,成功为 done)"` + AssetType string `json:"asset_type" description:"资产类型"` + AssetID uint `json:"asset_id" description:"资产ID"` + ICCID string `json:"iccid" description:"ICCID(单卡资产)"` + DeviceVirtualNo string `json:"device_virtual_no" description:"设备号(设备资产)"` + DeviceIMEI string `json:"device_imei" description:"设备 IMEI(设备资产)"` + Attempt int `json:"attempt" description:"尝试序号"` + Trigger string `json:"trigger" description:"触发方式"` + Result string `json:"result" description:"结果"` + ErrorCode string `json:"error_code" description:"错误码"` + ErrorMessage string `json:"error_message" description:"错误信息"` + DurationMS int `json:"duration_ms" description:"耗时(毫秒)"` + CreatedAt time.Time `json:"created_at" description:"记录时间"` } // RefundPostProcessAttemptListResponse 退款资产后处理尝试记录分页结果。 diff --git a/internal/query/recorddisplay/lookup.go b/internal/query/recorddisplay/lookup.go new file mode 100644 index 00000000..a224d7e1 --- /dev/null +++ b/internal/query/recorddisplay/lookup.go @@ -0,0 +1,142 @@ +// Package recorddisplay 为记录查询列表补齐展示字段(ICCID、设备号、运营商名称、操作人)。 +// +// 记录表只存内部 ID;列表先分页,再按当前页出现的 ID 批量查主键补齐, +// 不在分页查询里关联,也不在记录表里冗余这些字段。查到的是当前值。 +package recorddisplay + +import ( + "context" + + "gorm.io/gorm" + + "github.com/break/junhong_cmp_fiber/internal/model" + "github.com/break/junhong_cmp_fiber/pkg/errors" +) + +// Device 是设备展示字段。 +type Device struct { + VirtualNo string + IMEI string +} + +// Lookup 是当前页的展示字段字典;未找到的 ID 返回零值。 +type Lookup struct { + iccids map[uint]string + devices map[uint]Device + carriers map[uint]string + operators map[uint]string + packages map[uint]string +} + +// Request 是需要补齐的 ID 集合(可重复、可含 0,内部去重并忽略 0)。 +type Request struct { + CardIDs []uint + DeviceIDs []uint + CarrierIDs []uint + OperatorIDs []uint + // PackageUsageIDs 用于取套餐使用记录上的套餐名称快照。 + PackageUsageIDs []uint +} + +// Load 按 ID 批量查询展示字段:每类最多一条主键查询,已删除的资产同样返回(历史记录仍需显示)。 +func Load(ctx context.Context, db *gorm.DB, req Request) (*Lookup, error) { + lookup := &Lookup{ + iccids: map[uint]string{}, devices: map[uint]Device{}, carriers: map[uint]string{}, operators: map[uint]string{}, + packages: map[uint]string{}, + } + session := db.WithContext(ctx).Unscoped() + + if ids := distinct(req.CardIDs); len(ids) > 0 { + var rows []struct { + ID uint + ICCID string + } + if err := session.Model(&model.IotCard{}).Select("id, iccid").Where("id IN ?", ids).Scan(&rows).Error; err != nil { + return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询卡展示信息失败") + } + for _, row := range rows { + lookup.iccids[row.ID] = row.ICCID + } + } + if ids := distinct(req.DeviceIDs); len(ids) > 0 { + var rows []struct { + ID uint + VirtualNo string + IMEI string + } + if err := session.Model(&model.Device{}).Select("id, virtual_no, imei").Where("id IN ?", ids).Scan(&rows).Error; err != nil { + return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询设备展示信息失败") + } + for _, row := range rows { + lookup.devices[row.ID] = Device{VirtualNo: row.VirtualNo, IMEI: row.IMEI} + } + } + if ids := distinct(req.CarrierIDs); len(ids) > 0 { + var rows []struct { + ID uint + CarrierName string + } + if err := session.Model(&model.Carrier{}).Select("id, carrier_name").Where("id IN ?", ids).Scan(&rows).Error; err != nil { + return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询运营商账户展示信息失败") + } + for _, row := range rows { + lookup.carriers[row.ID] = row.CarrierName + } + } + if ids := distinct(req.OperatorIDs); len(ids) > 0 { + var rows []struct { + ID uint + Username string + } + if err := session.Model(&model.Account{}).Select("id, username").Where("id IN ?", ids).Scan(&rows).Error; err != nil { + return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询操作人展示信息失败") + } + for _, row := range rows { + lookup.operators[row.ID] = row.Username + } + } + if ids := distinct(req.PackageUsageIDs); len(ids) > 0 { + var rows []struct { + ID uint + PackageName string + } + if err := session.Model(&model.PackageUsage{}).Select("id, package_name").Where("id IN ?", ids).Scan(&rows).Error; err != nil { + return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询套餐名称失败") + } + for _, row := range rows { + lookup.packages[row.ID] = row.PackageName + } + } + return lookup, nil +} + +// ICCID 返回卡 ICCID。 +func (l *Lookup) ICCID(cardID uint) string { return l.iccids[cardID] } + +// Device 返回设备号与 IMEI。 +func (l *Lookup) Device(deviceID uint) Device { return l.devices[deviceID] } + +// CarrierName 返回运营商账户名称。 +func (l *Lookup) CarrierName(carrierID uint) string { return l.carriers[carrierID] } + +// PackageName 返回套餐使用记录上的套餐名称快照。 +func (l *Lookup) PackageName(packageUsageID uint) string { return l.packages[packageUsageID] } + +// OperatorName 返回操作人账号用户名。 +func (l *Lookup) OperatorName(accountID uint) string { return l.operators[accountID] } + +func distinct(ids []uint) []uint { + seen := make(map[uint]struct{}, len(ids)) + result := make([]uint, 0, len(ids)) + for _, id := range ids { + if id == 0 { + continue + } + if _, ok := seen[id]; ok { + continue + } + seen[id] = struct{}{} + result = append(result, id) + } + return result +} diff --git a/internal/query/recorddisplay/lookup_test.go b/internal/query/recorddisplay/lookup_test.go new file mode 100644 index 00000000..95493865 --- /dev/null +++ b/internal/query/recorddisplay/lookup_test.go @@ -0,0 +1,50 @@ +package recorddisplay + +import ( + "reflect" + "testing" +) + +func TestDistinctSkipsZeroAndDuplicates(t *testing.T) { + tests := []struct { + name string + in []uint + want []uint + }{ + {name: "空", in: nil, want: []uint{}}, + {name: "只有 0", in: []uint{0, 0}, want: []uint{}}, + {name: "去重并保持顺序", in: []uint{3, 0, 1, 3, 2, 1}, want: []uint{3, 1, 2}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := distinct(tt.in); !reflect.DeepEqual(got, tt.want) { + t.Fatalf("distinct(%v) = %v, want %v", tt.in, got, tt.want) + } + }) + } +} + +func TestLookupMissingIDsReturnZeroValues(t *testing.T) { + lookup := &Lookup{ + iccids: map[uint]string{1: "8986001"}, + devices: map[uint]Device{2: {VirtualNo: "60003081372", IMEI: "869555083099518"}}, + carriers: map[uint]string{}, + operators: map[uint]string{}, + packages: map[uint]string{}, + } + if got := lookup.ICCID(1); got != "8986001" { + t.Fatalf("ICCID(1) = %q", got) + } + if got := lookup.ICCID(9); got != "" { + t.Fatalf("ICCID(9) = %q, want empty", got) + } + if got := lookup.Device(2); got.VirtualNo != "60003081372" || got.IMEI != "869555083099518" { + t.Fatalf("Device(2) = %+v", got) + } + if got := lookup.Device(0); got != (Device{}) { + t.Fatalf("Device(0) = %+v, want zero", got) + } + if lookup.CarrierName(5) != "" || lookup.OperatorName(5) != "" || lookup.PackageName(5) != "" { + t.Fatal("missing IDs must return empty strings") + } +} diff --git a/internal/service/asset/record_query.go b/internal/service/asset/record_query.go index 426f6b6c..1d37e68a 100644 --- a/internal/service/asset/record_query.go +++ b/internal/service/asset/record_query.go @@ -11,6 +11,7 @@ import ( "github.com/break/junhong_cmp_fiber/internal/domain/cardflow" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/model/dto" + "github.com/break/junhong_cmp_fiber/internal/query/recorddisplay" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" "github.com/break/junhong_cmp_fiber/pkg/middleware" @@ -182,9 +183,19 @@ func (s *Service) ListTrafficCollectionRecords(ctx context.Context, req *dto.Tra if err != nil { return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询采集成功记录失败") } + successReq := recorddisplay.Request{} + for _, row := range rows { + successReq.CardIDs = append(successReq.CardIDs, row.IotCardID) + successReq.CarrierIDs = append(successReq.CarrierIDs, row.CarrierID) + } + display, err := recorddisplay.Load(ctx, s.db, successReq) + if err != nil { + return nil, err + } for _, row := range rows { resp.Items = append(resp.Items, dto.TrafficCollectionRecordItem{ - CardTrafficCollectionItem: collectionSuccessItem(row), IotCardID: row.IotCardID, CarrierID: row.CarrierID, + CardTrafficCollectionItem: collectionSuccessItem(row), IotCardID: row.IotCardID, ICCID: display.ICCID(row.IotCardID), + CarrierID: row.CarrierID, CarrierName: display.CarrierName(row.CarrierID), }) } resp.Total = total @@ -217,8 +228,18 @@ func (s *Service) ListTrafficCollectionFailures(ctx context.Context, req *dto.Tr if err != nil { return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询采集失败记录失败") } + carrierIDs := make([]uint, 0, len(rows)) for _, row := range rows { - resp.Items = append(resp.Items, collectionFailureItem(row)) + carrierIDs = append(carrierIDs, row.CarrierID) + } + display, err := recorddisplay.Load(ctx, s.db, recorddisplay.Request{CarrierIDs: carrierIDs}) + if err != nil { + return nil, err + } + for _, row := range rows { + item := collectionFailureItem(row) + item.CarrierName = display.CarrierName(row.CarrierID) + resp.Items = append(resp.Items, item) } resp.Total = total return resp, nil @@ -257,10 +278,19 @@ func (s *Service) ListCardDailyUsages(ctx context.Context, req *dto.CardDailyUsa if err != nil { return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询卡日流量失败") } + carrierIDs := make([]uint, 0, len(rows)) + for _, item := range rows { + carrierIDs = append(carrierIDs, item.CarrierID) + } + display, err := recorddisplay.Load(ctx, s.db, recorddisplay.Request{CarrierIDs: carrierIDs}) + if err != nil { + return nil, err + } for _, item := range rows { resp.Items = append(resp.Items, dto.CardDailyUsageItem{ ID: item.ID, IotCardID: item.IotCardID, ICCID: item.ICCID, CarrierID: item.CarrierID, - Date: item.FlowDate.Format(recordDateLayout), SettledMB: item.SettledMB, MonthUsedMB: item.MonthUsedMB, + CarrierName: display.CarrierName(item.CarrierID), + Date: item.FlowDate.Format(recordDateLayout), SettledMB: item.SettledMB, MonthUsedMB: item.MonthUsedMB, VendorUsedMB: item.VendorUsedMB, StaleGuarded: item.StaleGuarded, ObsCount: item.ObsCount, UpdatedAt: item.UpdatedAt, }) } @@ -282,12 +312,13 @@ func (s *Service) ListPackageUsageDailyRecords(ctx context.Context, req *dto.Pac } type row struct { model.PackageUsageDailyRecord - PackageID uint - IotCardID uint - DeviceID uint + PackageID uint + PackageName string + IotCardID uint + DeviceID uint } query := s.db.WithContext(ctx).Table("tb_package_usage_daily_record AS r"). - Select("r.*, pu.package_id, COALESCE(pu.iot_card_id, 0) AS iot_card_id, COALESCE(pu.device_id, 0) AS device_id"). + Select("r.*, pu.package_id, pu.package_name, COALESCE(pu.iot_card_id, 0) AS iot_card_id, COALESCE(pu.device_id, 0) AS device_id"). Joins("JOIN tb_package_usage pu ON pu.id = r.package_usage_id"). Where("r.date >= ? AND r.date <= ?", from.Format(recordDateLayout), to.Format(recordDateLayout)) if !scope.all { @@ -310,10 +341,21 @@ func (s *Service) ListPackageUsageDailyRecords(ctx context.Context, req *dto.Pac if err != nil { return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询套餐日流量详单失败") } + dailyReq := recorddisplay.Request{} for _, item := range rows { + dailyReq.CardIDs = append(dailyReq.CardIDs, item.IotCardID) + dailyReq.DeviceIDs = append(dailyReq.DeviceIDs, item.DeviceID) + } + display, err := recorddisplay.Load(ctx, s.db, dailyReq) + if err != nil { + return nil, err + } + for _, item := range rows { + device := display.Device(item.DeviceID) resp.Items = append(resp.Items, dto.PackageUsageDailyRecordItem{ - ID: item.ID, PackageUsageID: item.PackageUsageID, PackageID: item.PackageID, IotCardID: item.IotCardID, - DeviceID: item.DeviceID, Date: item.Date.Format(recordDateLayout), DailyUsageMB: item.DailyUsageMB, + ID: item.ID, PackageUsageID: item.PackageUsageID, PackageID: item.PackageID, PackageName: item.PackageName, + IotCardID: item.IotCardID, ICCID: display.ICCID(item.IotCardID), + DeviceID: item.DeviceID, DeviceVirtualNo: device.VirtualNo, DeviceIMEI: device.IMEI, Date: item.Date.Format(recordDateLayout), DailyUsageMB: item.DailyUsageMB, CumulativeUsageMB: item.CumulativeUsageMB, UpdatedAt: item.UpdatedAt, }) } @@ -357,9 +399,25 @@ func (s *Service) ListPackageTrafficAdjustmentRecords(ctx context.Context, req * if err != nil { return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询套餐流量冲正流水失败") } + adjReq := recorddisplay.Request{} for _, row := range rows { + adjReq.CardIDs = append(adjReq.CardIDs, row.IotCardID) + adjReq.DeviceIDs = append(adjReq.DeviceIDs, row.DeviceID) + adjReq.OperatorIDs = append(adjReq.OperatorIDs, row.OperatorID) + adjReq.PackageUsageIDs = append(adjReq.PackageUsageIDs, row.PackageUsageID) + } + display, err := recorddisplay.Load(ctx, s.db, adjReq) + if err != nil { + return nil, err + } + for _, row := range rows { + item := toTrafficAdjustmentItem(row) + item.OperatorName = display.OperatorName(row.OperatorID) + device := display.Device(row.DeviceID) resp.Items = append(resp.Items, dto.PackageTrafficAdjustmentRecordItem{ - PackageTrafficAdjustmentItem: toTrafficAdjustmentItem(row), IotCardID: row.IotCardID, DeviceID: row.DeviceID, + PackageTrafficAdjustmentItem: item, PackageName: display.PackageName(row.PackageUsageID), + IotCardID: row.IotCardID, ICCID: display.ICCID(row.IotCardID), + DeviceID: row.DeviceID, DeviceVirtualNo: device.VirtualNo, DeviceIMEI: device.IMEI, }) } resp.Total = total diff --git a/internal/service/asset/traffic_adjustment.go b/internal/service/asset/traffic_adjustment.go index 6ec18385..e5f4b0cf 100644 --- a/internal/service/asset/traffic_adjustment.go +++ b/internal/service/asset/traffic_adjustment.go @@ -10,6 +10,7 @@ import ( stopresumedomain "github.com/break/junhong_cmp_fiber/internal/domain/stopresume" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/model/dto" + "github.com/break/junhong_cmp_fiber/internal/query/recorddisplay" "github.com/break/junhong_cmp_fiber/internal/store/postgres" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" @@ -190,9 +191,19 @@ func (s *Service) ListPackageTrafficAdjustments(ctx context.Context, assetType s if err := query.Order("created_at DESC, id DESC").Offset((page - 1) * size).Limit(size).Find(&rows).Error; err != nil { return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询冲正流水失败") } + operatorIDs := make([]uint, 0, len(rows)) + for _, row := range rows { + operatorIDs = append(operatorIDs, row.OperatorID) + } + display, err := recorddisplay.Load(ctx, s.db, recorddisplay.Request{OperatorIDs: operatorIDs}) + if err != nil { + return nil, err + } items := make([]dto.PackageTrafficAdjustmentItem, 0, len(rows)) for _, row := range rows { - items = append(items, toTrafficAdjustmentItem(row)) + item := toTrafficAdjustmentItem(row) + item.OperatorName = display.OperatorName(row.OperatorID) + items = append(items, item) } return &dto.PackageTrafficAdjustmentListResponse{Items: items, Total: total}, nil } diff --git a/internal/service/refund/asset_post_attempt_query.go b/internal/service/refund/asset_post_attempt_query.go index 9ea31065..c341fcce 100644 --- a/internal/service/refund/asset_post_attempt_query.go +++ b/internal/service/refund/asset_post_attempt_query.go @@ -8,6 +8,7 @@ import ( "github.com/break/junhong_cmp_fiber/internal/domain/cardflow" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/model/dto" + "github.com/break/junhong_cmp_fiber/internal/query/recorddisplay" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" "github.com/break/junhong_cmp_fiber/pkg/middleware" @@ -72,10 +73,24 @@ func (s *Service) ListAssetPostProcessAttempts(ctx context.Context, req *dto.Ref if err := query.Order("created_at DESC, id DESC").Offset((page - 1) * size).Limit(size).Find(&rows).Error; err != nil { return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询退款资产后处理尝试记录失败") } + displayReq := recorddisplay.Request{} for _, row := range rows { + if row.AssetType == constants.AssetTypeDevice { + displayReq.DeviceIDs = append(displayReq.DeviceIDs, row.AssetID) + } + } + display, err := recorddisplay.Load(ctx, s.db, displayReq) + if err != nil { + return nil, err + } + for _, row := range rows { + var device recorddisplay.Device + if row.AssetType == constants.AssetTypeDevice { + device = display.Device(row.AssetID) + } resp.Items = append(resp.Items, dto.RefundPostProcessAttemptItem{ ID: row.ID, RefundID: row.RefundID, RefundNo: row.RefundNo, Step: row.Step, AssetType: row.AssetType, - AssetID: row.AssetID, ICCID: row.ICCID, Attempt: row.Attempt, Trigger: row.Trigger, Result: row.Result, + AssetID: row.AssetID, ICCID: row.ICCID, DeviceVirtualNo: device.VirtualNo, DeviceIMEI: device.IMEI, Attempt: row.Attempt, Trigger: row.Trigger, Result: row.Result, ErrorCode: row.ErrorCode, ErrorMessage: row.ErrorMessage, DurationMS: row.DurationMS, CreatedAt: row.CreatedAt, }) }