diff --git a/internal/model/dto/agent_open_api_dto.go b/internal/model/dto/agent_open_api_dto.go index 9ac6853..b53dc4b 100644 --- a/internal/model/dto/agent_open_api_dto.go +++ b/internal/model/dto/agent_open_api_dto.go @@ -38,7 +38,8 @@ type AgentOpenAPIPackageTrafficItem struct { // AgentOpenAPICardTrafficResponse 开放接口卡流量响应 type AgentOpenAPICardTrafficResponse struct { - CardNo string `json:"card_no" description:"卡标识"` + CardNo string `json:"card_no" description:"卡标识(原始传入值)"` + DeviceNo string `json:"device_no,omitempty" description:"设备虚拟号(当入参被识别为设备维度时返回,表示该卡/标识关联的设备)"` ActiveRemainingFlowMB int64 `json:"active_remaining_flow_mb" description:"当前生效套餐剩余流量(MB)"` ActiveTotalFlowMB int64 `json:"active_total_flow_mb" description:"当前生效套餐总流量(MB)"` ActiveUsedFlowMB int64 `json:"active_used_flow_mb" description:"当前生效套餐已用流量(MB)"` diff --git a/internal/routes/open.go b/internal/routes/open.go index f9d0f99..b5c134a 100644 --- a/internal/routes/open.go +++ b/internal/routes/open.go @@ -74,8 +74,8 @@ function buildAgentSign({ method, path, query, body, timestamp, nonce, account, ` + "```" Register(router, doc, basePath, "GET", "/cards/traffic", handler.GetCardTraffic, RouteSpec{ - Summary: "查询单卡流量", - Description: authDescription + "\n\n按 card_no 查询单卡流量、当前套餐和待生效套餐。card_no 支持 ICCID、虚拟号、MSISDN。", + Summary: "查询单卡或设备流量", + Description: authDescription + "\n\n按 card_no 查询流量、当前套餐和待生效套餐。card_no 支持三种解析路径:1) ICCID/虚拟号/MSISDN 对应独立卡,查卡维度流量;2) 已绑定设备的卡,自动反查绑定设备,查设备维度流量(响应含 device_no);3) IMEI 或设备虚拟号,直接查设备维度流量(响应含 device_no)。", Input: new(dto.AgentOpenAPICardQueryRequest), Output: new(dto.AgentOpenAPICardTrafficResponse), Tags: []string{tag}, diff --git a/internal/service/agent_open_api/service.go b/internal/service/agent_open_api/service.go index 60b0da8..b10c8b9 100644 --- a/internal/service/agent_open_api/service.go +++ b/internal/service/agent_open_api/service.go @@ -72,20 +72,48 @@ func New( } } -// GetCardTraffic 查询开放接口单卡流量 +// GetCardTraffic 查询开放接口流量 +// 支持三种解析路径: +// 1. card_no 解析为独立卡 → 查卡维度流量 +// 2. card_no 解析为已绑定设备的卡 → 反查绑定设备 → 查设备维度流量 +// 3. card_no 无法解析为卡 → 尝试作为设备标识(IMEI/虚拟号)→ 查设备维度流量 func (s *Service) GetCardTraffic(ctx context.Context, req *dto.AgentOpenAPICardQueryRequest) (*dto.AgentOpenAPICardTrafficResponse, error) { - card, err := s.resolveOpenAPICard(ctx, req.CardNo) - if err != nil { - return nil, err + card, cardErr := s.resolveOpenAPICard(ctx, req.CardNo) + if cardErr == nil { + // 独立卡:直接查卡维度流量 + if card.IsStandalone { + return s.buildCardTrafficResponse(ctx, req.CardNo, "iot_card", card.ID, "") + } + // 已绑定设备的卡:反查设备后查设备维度流量 + binding, err := s.deviceSimBindingStore.GetActiveBindingByCardID(ctx, card.ID) + if err != nil { + return nil, errors.Wrap(errors.CodeInternalError, err, "查询卡绑定设备失败") + } + device, err := s.deviceStore.GetByID(ctx, binding.DeviceID) + if err != nil { + return nil, errors.Wrap(errors.CodeInternalError, err, "查询绑定设备信息失败") + } + return s.buildCardTrafficResponse(ctx, req.CardNo, "device", device.ID, device.VirtualNo) } + // 兜底:尝试解析为设备标识(支持 IMEI/虚拟号) + device, err := s.resolveOpenAPIDevice(ctx, req.CardNo) + if err != nil { + // 两种解析都失败,返回原始卡解析错误(语义更贴近入参) + return nil, cardErr + } + return s.buildCardTrafficResponse(ctx, req.CardNo, "device", device.ID, device.VirtualNo) +} + +// buildCardTrafficResponse 统一构造卡流量响应,支持卡和设备两种载体维度 +func (s *Service) buildCardTrafficResponse(ctx context.Context, cardNo, carrierType string, carrierID uint, deviceNo string) (*dto.AgentOpenAPICardTrafficResponse, error) { activeStatus := constants.PackageUsageStatusActive pendingStatus := constants.PackageUsageStatusPending - activeUsages, err := s.packageUsageStore.ListByCarrier(ctx, "iot_card", card.ID, &activeStatus) + activeUsages, err := s.packageUsageStore.ListByCarrier(ctx, carrierType, carrierID, &activeStatus) if err != nil { return nil, errors.Wrap(errors.CodeInternalError, err, "查询生效套餐失败") } - pendingUsages, err := s.packageUsageStore.ListByCarrier(ctx, "iot_card", card.ID, &pendingStatus) + pendingUsages, err := s.packageUsageStore.ListByCarrier(ctx, carrierType, carrierID, &pendingStatus) if err != nil { return nil, errors.Wrap(errors.CodeInternalError, err, "查询待生效套餐失败") } @@ -96,7 +124,8 @@ func (s *Service) GetCardTraffic(ctx context.Context, req *dto.AgentOpenAPICardQ } resp := &dto.AgentOpenAPICardTrafficResponse{ - CardNo: req.CardNo, + CardNo: cardNo, + DeviceNo: deviceNo, ActivePackages: make([]dto.AgentOpenAPIPackageTrafficItem, 0, len(activeUsages)), PendingPackages: make([]dto.AgentOpenAPIPackageTrafficItem, 0, len(pendingUsages)), } @@ -113,7 +142,6 @@ func (s *Service) GetCardTraffic(ctx context.Context, req *dto.AgentOpenAPICardQ for _, usage := range pendingUsages { resp.PendingPackages = append(resp.PendingPackages, s.buildTrafficItem(usage, packageMap, seriesMap, false)) } - return resp, nil }