diff --git a/internal/model/dto/iot_card_dto.go b/internal/model/dto/iot_card_dto.go index a83726c..da23a32 100644 --- a/internal/model/dto/iot_card_dto.go +++ b/internal/model/dto/iot_card_dto.go @@ -22,6 +22,7 @@ type ListStandaloneIotCardRequest struct { ICCIDStart string `json:"iccid_start" query:"iccid_start" validate:"omitempty,max=20" maxLength:"20" description:"ICCID起始号"` ICCIDEnd string `json:"iccid_end" query:"iccid_end" validate:"omitempty,max=20" maxLength:"20" description:"ICCID结束号"` CarrierName string `json:"carrier_name" query:"carrier_name" validate:"omitempty,max=100" maxLength:"100" description:"运营商名称(模糊查询)"` + Keyword string `json:"keyword" query:"keyword" validate:"omitempty,max=100" maxLength:"100" description:"关键字搜索,匹配ICCID或卡虚拟号(模糊查询,与iccid/virtual_no独立)"` } type StandaloneIotCardResponse struct { diff --git a/internal/service/iot_card/service.go b/internal/service/iot_card/service.go index 4bcbbe9..2487589 100644 --- a/internal/service/iot_card/service.go +++ b/internal/service/iot_card/service.go @@ -206,6 +206,9 @@ func (s *Service) ListStandalone(ctx context.Context, req *dto.ListStandaloneIot if req.HasActivePackage != nil { filters["has_active_package"] = *req.HasActivePackage } + if req.Keyword != "" { + filters["keyword"] = req.Keyword + } // 代理用户注入 subordinate_shop_ids,让 Store 层走并行查询路径 // 避免 PG 对 shop_id IN (...) + ORDER BY 选择全表扫描 diff --git a/internal/store/postgres/iot_card_store.go b/internal/store/postgres/iot_card_store.go index 82b580e..c2b4d35 100644 --- a/internal/store/postgres/iot_card_store.go +++ b/internal/store/postgres/iot_card_store.go @@ -461,7 +461,8 @@ func (s *IotCardStore) ListStandalone(ctx context.Context, opts *store.QueryOpti _, hasICCID := filters["iccid"].(string) _, hasMSISDN := filters["msisdn"].(string) _, hasVirtualNo := filters["virtual_no"].(string) - useFuzzySearch := (hasICCID && filters["iccid"] != "") || (hasMSISDN && filters["msisdn"] != "") || (hasVirtualNo && filters["virtual_no"] != "") + _, hasKeyword := filters["keyword"].(string) + useFuzzySearch := (hasICCID && filters["iccid"] != "") || (hasMSISDN && filters["msisdn"] != "") || (hasVirtualNo && filters["virtual_no"] != "") || (hasKeyword && filters["keyword"] != "") if !useFuzzySearch { if shopIDs, ok := filters["subordinate_shop_ids"].([]uint); ok && len(shopIDs) > 1 { @@ -854,6 +855,9 @@ func (s *IotCardStore) applyStandaloneFilters(ctx context.Context, query *gorm.D if virtualNo, ok := filters["virtual_no"].(string); ok && virtualNo != "" { query = query.Where("virtual_no LIKE ?", "%"+virtualNo+"%") } + if keyword, ok := filters["keyword"].(string); ok && keyword != "" { + query = query.Where("iccid LIKE ? OR virtual_no LIKE ?", "%"+keyword+"%", "%"+keyword+"%") + } if batchNo, ok := filters["batch_no"].(string); ok && batchNo != "" { query = query.Where("batch_no = ?", batchNo) }