feat: 实现运营商模块重构,添加冗余字段优化查询性能
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m16s

主要变更:
- 新增 Carrier CRUD API(创建、列表、详情、更新、删除、状态更新)
- IotCard/IotCardImportTask 添加 carrier_type/carrier_name 冗余字段
- 移除 Carrier 表的 channel_name/channel_code 字段
- 查询时直接使用冗余字段,避免 JOIN Carrier 表
- 添加数据库迁移脚本(000021-000023)
- 添加单元测试和集成测试
- 同步更新 OpenAPI 文档和 specs
This commit is contained in:
2026-01-27 12:18:19 +08:00
parent 5a179ba16b
commit d104d297ca
42 changed files with 2431 additions and 122 deletions

View File

@@ -88,11 +88,11 @@ func (s *Service) ListStandalone(ctx context.Context, req *dto.ListStandaloneIot
return nil, err
}
carrierMap, shopMap := s.loadRelatedData(ctx, cards)
shopMap := s.loadShopNames(ctx, cards)
list := make([]*dto.StandaloneIotCardResponse, 0, len(cards))
for _, card := range cards {
item := s.toStandaloneResponse(card, carrierMap, shopMap)
item := s.toStandaloneResponse(card, shopMap)
list = append(list, item)
}
@@ -120,40 +120,25 @@ func (s *Service) GetByICCID(ctx context.Context, iccid string) (*dto.IotCardDet
return nil, err
}
carrierMap, shopMap := s.loadRelatedData(ctx, []*model.IotCard{card})
standaloneResp := s.toStandaloneResponse(card, carrierMap, shopMap)
shopMap := s.loadShopNames(ctx, []*model.IotCard{card})
standaloneResp := s.toStandaloneResponse(card, shopMap)
return &dto.IotCardDetailResponse{
StandaloneIotCardResponse: *standaloneResp,
}, nil
}
func (s *Service) loadRelatedData(ctx context.Context, cards []*model.IotCard) (map[uint]string, map[uint]string) {
carrierIDs := make([]uint, 0)
func (s *Service) loadShopNames(ctx context.Context, cards []*model.IotCard) map[uint]string {
shopIDs := make([]uint, 0)
carrierIDSet := make(map[uint]bool)
shopIDSet := make(map[uint]bool)
for _, card := range cards {
if card.CarrierID > 0 && !carrierIDSet[card.CarrierID] {
carrierIDs = append(carrierIDs, card.CarrierID)
carrierIDSet[card.CarrierID] = true
}
if card.ShopID != nil && *card.ShopID > 0 && !shopIDSet[*card.ShopID] {
shopIDs = append(shopIDs, *card.ShopID)
shopIDSet[*card.ShopID] = true
}
}
carrierMap := make(map[uint]string)
if len(carrierIDs) > 0 {
var carriers []model.Carrier
s.db.WithContext(ctx).Where("id IN ?", carrierIDs).Find(&carriers)
for _, c := range carriers {
carrierMap[c.ID] = c.CarrierName
}
}
shopMap := make(map[uint]string)
if len(shopIDs) > 0 {
var shops []model.Shop
@@ -163,17 +148,18 @@ func (s *Service) loadRelatedData(ctx context.Context, cards []*model.IotCard) (
}
}
return carrierMap, shopMap
return shopMap
}
func (s *Service) toStandaloneResponse(card *model.IotCard, carrierMap map[uint]string, shopMap map[uint]string) *dto.StandaloneIotCardResponse {
func (s *Service) toStandaloneResponse(card *model.IotCard, shopMap map[uint]string) *dto.StandaloneIotCardResponse {
resp := &dto.StandaloneIotCardResponse{
ID: card.ID,
ICCID: card.ICCID,
CardType: card.CardType,
CardCategory: card.CardCategory,
CarrierID: card.CarrierID,
CarrierName: carrierMap[card.CarrierID],
CarrierType: card.CarrierType,
CarrierName: card.CarrierName,
IMSI: card.IMSI,
MSISDN: card.MSISDN,
BatchNo: card.BatchNo,