新增上游的停机原因
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m5s

This commit is contained in:
2026-05-12 11:13:04 +08:00
parent 95fc0b0a1b
commit 8f3a68a673
22 changed files with 83 additions and 3 deletions

View File

@@ -146,6 +146,9 @@ components:
card_status_name: card_status_name:
description: 卡状态名称(中文) description: 卡状态名称(中文)
type: string type: string
gateway_extend:
description: Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因
type: string
stop_reason: stop_reason:
description: 停机原因 description: 停机原因
type: string type: string
@@ -908,6 +911,9 @@ components:
enable_virtual_data: enable_virtual_data:
description: 当前主套餐是否启用虚流量(按套餐使用记录快照返回) description: 当前主套餐是否启用虚流量(按套餐使用记录快照返回)
type: boolean type: boolean
gateway_extend:
description: Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因
type: string
generation: generation:
description: 世代 description: 世代
type: string type: string
@@ -1314,6 +1320,9 @@ components:
type: string type: string
device_realtime: device_realtime:
$ref: '#/components/schemas/DtoDeviceGatewayInfo' $ref: '#/components/schemas/DtoDeviceGatewayInfo'
gateway_extend:
description: Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因
type: string
last_gateway_reading_mb: last_gateway_reading_mb:
description: 运营商当前周期累计流量读数(MBasset_type=card时有效运营商口径展示建议读取该字段) description: 运营商当前周期累计流量读数(MBasset_type=card时有效运营商口径展示建议读取该字段)
type: number type: number
@@ -1446,6 +1455,9 @@ components:
enable_virtual_data: enable_virtual_data:
description: 当前主套餐是否启用虚流量(按套餐使用记录快照返回) description: 当前主套餐是否启用虚流量(按套餐使用记录快照返回)
type: boolean type: boolean
gateway_extend:
description: Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因
type: string
iccid: iccid:
description: 卡ICCIDasset_type=card时有效 description: 卡ICCIDasset_type=card时有效
type: string type: string
@@ -2124,6 +2136,9 @@ components:
carrier_type: carrier_type:
description: 运营商类型 description: 运营商类型
type: string type: string
gateway_extend:
description: Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因
type: string
iccid: iccid:
description: ICCID description: ICCID
type: string type: string
@@ -3807,6 +3822,9 @@ components:
carrier_name: carrier_name:
description: 运营商名称 description: 运营商名称
type: string type: string
gateway_extend:
description: Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因
type: string
iccid: iccid:
description: ICCID description: ICCID
type: string type: string
@@ -3858,6 +3876,9 @@ components:
carrier_type: carrier_type:
description: 运营商类型(CMCC/CUCC/CTCC/CBN) description: 运营商类型(CMCC/CUCC/CTCC/CBN)
type: string type: string
gateway_extend:
description: Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因
type: string
iccid: iccid:
description: 物联网卡ICCID description: 物联网卡ICCID
type: string type: string
@@ -4542,6 +4563,9 @@ components:
minimum: 0 minimum: 0
nullable: true nullable: true
type: integer type: integer
gateway_extend:
description: Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因
type: string
iccid: iccid:
description: ICCID description: ICCID
type: string type: string
@@ -6911,7 +6935,7 @@ components:
description: 下单时资产的标识符快照ICCID 或 VirtualNo description: 下单时资产的标识符快照ICCID 或 VirtualNo
type: string type: string
asset_reset: asset_reset:
description: 资产是否已重置 description: 退款后资产处理是否完成
type: boolean type: boolean
asset_type: asset_type:
description: 资产类型 (card:单卡, device:设备) description: 资产类型 (card:单卡, device:设备)
@@ -7750,6 +7774,9 @@ components:
enable_polling: enable_polling:
description: 是否参与轮询 description: 是否参与轮询
type: boolean type: boolean
gateway_extend:
description: Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因
type: string
iccid: iccid:
description: ICCID description: ICCID
type: string type: string

View File

@@ -192,6 +192,7 @@ func (h *ClientAssetHandler) GetAssetInfo(c *fiber.Ctx) error {
CarrierType: resolved.Asset.CarrierType, CarrierType: resolved.Asset.CarrierType,
NetworkStatus: resolved.Asset.NetworkStatus, NetworkStatus: resolved.Asset.NetworkStatus,
NetworkStatusName: constants.GetNetworkStatusName(resolved.Asset.NetworkStatus), NetworkStatusName: constants.GetNetworkStatusName(resolved.Asset.NetworkStatus),
GatewayExtend: resolved.Asset.GatewayExtend,
ActivationStatus: resolved.Asset.ActivationStatus, ActivationStatus: resolved.Asset.ActivationStatus,
ActivationStatusName: constants.GetActivationStatusName(resolved.Asset.ActivationStatus), ActivationStatusName: constants.GetActivationStatusName(resolved.Asset.ActivationStatus),
CardCategory: resolved.Asset.CardCategory, CardCategory: resolved.Asset.CardCategory,

View File

@@ -166,6 +166,7 @@ func (h *ClientDeviceHandler) GetDeviceCards(c *fiber.Ctx) error {
CarrierType: card.CarrierType, CarrierType: card.CarrierType,
CarrierName: card.CarrierName, CarrierName: card.CarrierName,
NetworkStatus: networkStatusText(card.NetworkStatus), NetworkStatus: networkStatusText(card.NetworkStatus),
GatewayExtend: card.GatewayExtend,
RealNameStatus: card.RealNameStatus, RealNameStatus: card.RealNameStatus,
SlotPosition: slot, SlotPosition: slot,
IsActive: isCurrentMap[card.ID], IsActive: isCurrentMap[card.ID],

View File

@@ -39,6 +39,7 @@ type AgentOpenAPICardStatusResponse struct {
CardNo string `json:"card_no" description:"卡标识"` CardNo string `json:"card_no" description:"卡标识"`
CardStatus string `json:"card_status" description:"卡状态 (normal:正常, stopped:停机)"` CardStatus string `json:"card_status" description:"卡状态 (normal:正常, stopped:停机)"`
CardStatusName string `json:"card_status_name" description:"卡状态名称(中文)"` CardStatusName string `json:"card_status_name" description:"卡状态名称(中文)"`
GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因"`
StopReason string `json:"stop_reason" description:"停机原因"` StopReason string `json:"stop_reason" description:"停机原因"`
StopReasonName string `json:"stop_reason_name" description:"停机原因名称(中文)"` StopReasonName string `json:"stop_reason_name" description:"停机原因名称(中文)"`
} }

View File

@@ -65,6 +65,7 @@ type AssetResolveResponse struct {
ActivationStatus int `json:"activation_status,omitempty" description:"激活状态"` ActivationStatus int `json:"activation_status,omitempty" description:"激活状态"`
EnablePolling bool `json:"enable_polling" description:"是否参与轮询"` EnablePolling bool `json:"enable_polling" description:"是否参与轮询"`
NetworkStatus int `json:"network_status" description:"网络状态0停机 1开机asset_type=card时有效"` NetworkStatus int `json:"network_status" description:"网络状态0停机 1开机asset_type=card时有效"`
GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因"`
} }
// BoundCardInfo 设备绑定的卡信息 // BoundCardInfo 设备绑定的卡信息
@@ -81,6 +82,7 @@ type BoundCardInfo struct {
CarrierType string `json:"carrier_type,omitempty" description:"运营商类型"` CarrierType string `json:"carrier_type,omitempty" description:"运营商类型"`
CarrierName string `json:"carrier_name,omitempty" description:"运营商名称"` CarrierName string `json:"carrier_name,omitempty" description:"运营商名称"`
RealnamePolicy string `json:"realname_policy" description:"实名认证策略 (none:无需实名, before_order:先实名后充值/购买, after_order:先充值/购买后实名)"` RealnamePolicy string `json:"realname_policy" description:"实名认证策略 (none:无需实名, before_order:先实名后充值/购买, after_order:先充值/购买后实名)"`
GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因"`
} }
// AssetRealtimeStatusResponse 资产实时状态只读DB/Redis // AssetRealtimeStatusResponse 资产实时状态只读DB/Redis
@@ -88,6 +90,7 @@ type AssetRealtimeStatusResponse struct {
AssetType string `json:"asset_type" description:"资产类型card 或 device"` AssetType string `json:"asset_type" description:"资产类型card 或 device"`
AssetID uint `json:"asset_id" description:"资产ID"` AssetID uint `json:"asset_id" description:"资产ID"`
NetworkStatus int `json:"network_status" description:"网络状态asset_type=card时有效0停机 1开机"` NetworkStatus int `json:"network_status" description:"网络状态asset_type=card时有效0停机 1开机"`
GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因"`
RealNameStatus int `json:"real_name_status" description:"实名状态asset_type=card时有效0未实名 1已实名"` RealNameStatus int `json:"real_name_status" description:"实名状态asset_type=card时有效0未实名 1已实名"`
RealnamePolicy string `json:"realname_policy,omitempty" description:"实名认证策略 (none:无需实名, before_order:先实名后充值/购买, after_order:先充值/购买后实名)"` RealnamePolicy string `json:"realname_policy,omitempty" description:"实名认证策略 (none:无需实名, before_order:先实名后充值/购买, after_order:先充值/购买后实名)"`
CurrentMonthUsageMB float64 `json:"current_month_usage_mb,omitempty" description:"系统自然月累计流量(MBasset_type=card时有效不等于运营商周期口径)"` CurrentMonthUsageMB float64 `json:"current_month_usage_mb,omitempty" description:"系统自然月累计流量(MBasset_type=card时有效不等于运营商周期口径)"`

View File

@@ -63,6 +63,7 @@ type AssetInfoResponse struct {
CarrierType string `json:"carrier_type,omitempty" description:"运营商类型CMCC/CUCC/CTCC/CBN"` CarrierType string `json:"carrier_type,omitempty" description:"运营商类型CMCC/CUCC/CTCC/CBN"`
NetworkStatus int `json:"network_status,omitempty" description:"网络状态0:停机, 1:开机)"` NetworkStatus int `json:"network_status,omitempty" description:"网络状态0:停机, 1:开机)"`
NetworkStatusName string `json:"network_status_name,omitempty" description:"网络状态名称(中文)"` NetworkStatusName string `json:"network_status_name,omitempty" description:"网络状态名称(中文)"`
GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因"`
ActivationStatus int `json:"activation_status,omitempty" description:"激活状态0:未激活, 1:已激活)"` ActivationStatus int `json:"activation_status,omitempty" description:"激活状态0:未激活, 1:已激活)"`
ActivationStatusName string `json:"activation_status_name,omitempty" description:"激活状态名称(中文)"` ActivationStatusName string `json:"activation_status_name,omitempty" description:"激活状态名称(中文)"`
CardCategory string `json:"card_category,omitempty" description:"卡业务类型normal:普通卡, industry:行业卡)"` CardCategory string `json:"card_category,omitempty" description:"卡业务类型normal:普通卡, industry:行业卡)"`

View File

@@ -42,6 +42,7 @@ type DeviceCardItem struct {
CarrierType string `json:"carrier_type" description:"运营商类型(CMCC/CUCC/CTCC/CBN)"` CarrierType string `json:"carrier_type" description:"运营商类型(CMCC/CUCC/CTCC/CBN)"`
CarrierName string `json:"carrier_name" description:"运营商名称"` CarrierName string `json:"carrier_name" description:"运营商名称"`
NetworkStatus string `json:"network_status" description:"网络状态"` NetworkStatus string `json:"network_status" description:"网络状态"`
GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因"`
RealNameStatus int `json:"real_name_status" description:"实名状态 (0:未实名, 1:已实名)"` RealNameStatus int `json:"real_name_status" description:"实名状态 (0:未实名, 1:已实名)"`
SlotPosition int `json:"slot_position" description:"插槽位置"` SlotPosition int `json:"slot_position" description:"插槽位置"`
IsActive bool `json:"is_active" description:"是否当前激活卡"` IsActive bool `json:"is_active" description:"是否当前激活卡"`

View File

@@ -87,6 +87,7 @@ type DeviceCardBindingResponse struct {
IsCurrent bool `json:"is_current" description:"是否为当前使用的卡"` IsCurrent bool `json:"is_current" description:"是否为当前使用的卡"`
RealnamePolicy string `json:"realname_policy" description:"实名认证策略 (none:无需实名, before_order:先实名后充值/购买, after_order:先充值/购买后实名)"` RealnamePolicy string `json:"realname_policy" description:"实名认证策略 (none:无需实名, before_order:先实名后充值/购买, after_order:先充值/购买后实名)"`
NetworkStatus int `json:"network_status" description:"网络状态0停机 1开机asset_type=card时有效"` NetworkStatus int `json:"network_status" description:"网络状态0停机 1开机asset_type=card时有效"`
GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因"`
} }
type ListDeviceCardsResponse struct { type ListDeviceCardsResponse struct {

View File

@@ -87,6 +87,7 @@ type EnterpriseCardItem struct {
StatusName string `json:"status_name" description:"状态名称"` StatusName string `json:"status_name" description:"状态名称"`
NetworkStatus int `json:"network_status" description:"网络状态"` NetworkStatus int `json:"network_status" description:"网络状态"`
NetworkStatusName string `json:"network_status_name" description:"网络状态名称"` NetworkStatusName string `json:"network_status_name" description:"网络状态名称"`
GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因"`
} }
type EnterpriseCardPageResult struct { type EnterpriseCardPageResult struct {

View File

@@ -85,6 +85,7 @@ type DeviceCardInfo struct {
CarrierName string `json:"carrier_name" description:"运营商名称"` CarrierName string `json:"carrier_name" description:"运营商名称"`
NetworkStatus int `json:"network_status" description:"网络状态0=停机 1=开机"` NetworkStatus int `json:"network_status" description:"网络状态0=停机 1=开机"`
NetworkStatusName string `json:"network_status_name" description:"网络状态名称"` NetworkStatusName string `json:"network_status_name" description:"网络状态名称"`
GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因"`
} }
type DeviceDetailReq struct { type DeviceDetailReq struct {

View File

@@ -45,6 +45,7 @@ type StandaloneIotCardResponse struct {
RealNameStatusName string `json:"real_name_status_name" description:"实名状态名称(中文)"` RealNameStatusName string `json:"real_name_status_name" description:"实名状态名称(中文)"`
NetworkStatus int `json:"network_status" description:"网络状态 (0:停机, 1:开机)"` NetworkStatus int `json:"network_status" description:"网络状态 (0:停机, 1:开机)"`
NetworkStatusName string `json:"network_status_name" description:"网络状态名称(中文)"` NetworkStatusName string `json:"network_status_name" description:"网络状态名称(中文)"`
GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend用于展示运营商侧实际停机原因"`
DataUsageMB int64 `json:"data_usage_mb" description:"累计流量使用(MB)"` DataUsageMB int64 `json:"data_usage_mb" description:"累计流量使用(MB)"`
CurrentMonthUsageMB float64 `json:"current_month_usage_mb" description:"系统自然月累计流量(MB不等于运营商周期口径)"` CurrentMonthUsageMB float64 `json:"current_month_usage_mb" description:"系统自然月累计流量(MB不等于运营商周期口径)"`
LastGatewayReadingMB float64 `json:"last_gateway_reading_mb" description:"运营商当前周期累计流量读数(MB展示运营商口径时使用)"` LastGatewayReadingMB float64 `json:"last_gateway_reading_mb" description:"运营商当前周期累计流量读数(MB展示运营商口径时使用)"`

View File

@@ -54,6 +54,7 @@ type IotCard struct {
VirtualNo string `gorm:"column:virtual_no;type:varchar(50);uniqueIndex:idx_iot_card_virtual_no,where:deleted_at IS NULL AND virtual_no IS NOT NULL AND virtual_no <> '';comment:虚拟号(可选,非空时全局唯一)" json:"virtual_no,omitempty"` VirtualNo string `gorm:"column:virtual_no;type:varchar(50);uniqueIndex:idx_iot_card_virtual_no,where:deleted_at IS NULL AND virtual_no IS NOT NULL AND virtual_no <> '';comment:虚拟号(可选,非空时全局唯一)" json:"virtual_no,omitempty"`
DeviceVirtualNo string `gorm:"column:device_virtual_no;type:varchar(100);not null;default:'';comment:绑定设备的虚拟号快照(未绑定时为空字符串)" json:"device_virtual_no"` DeviceVirtualNo string `gorm:"column:device_virtual_no;type:varchar(100);not null;default:'';comment:绑定设备的虚拟号快照(未绑定时为空字符串)" json:"device_virtual_no"`
LastGatewayReadingMB float64 `gorm:"column:last_gateway_reading_mb;type:float;not null;default:0;comment:运营商当前周期累计流量读数(MB来自网关)" json:"last_gateway_reading_mb"` LastGatewayReadingMB float64 `gorm:"column:last_gateway_reading_mb;type:float;not null;default:0;comment:运营商当前周期累计流量读数(MB来自网关)" json:"last_gateway_reading_mb"`
GatewayExtend string `gorm:"column:gateway_extend;type:text;not null;default:'';comment:Gateway 卡状态扩展字段,原样保存上游 extend用于展示运营商侧实际停机原因" json:"gateway_extend"`
RealnamePolicy string `gorm:"column:realname_policy;type:varchar(20);default:'after_order';not null;comment:实名认证策略(none=无需实名,before_order=先实名后充值/购买,after_order=先充值/购买后实名)" json:"realname_policy"` RealnamePolicy string `gorm:"column:realname_policy;type:varchar(20);default:'after_order';not null;comment:实名认证策略(none=无需实名,before_order=先实名后充值/购买,after_order=先充值/购买后实名)" json:"realname_policy"`
// ICCID 双列存储,用于支持 19/20 位 ICCID 精确路由查询 // ICCID 双列存储,用于支持 19/20 位 ICCID 精确路由查询

View File

@@ -121,6 +121,7 @@ func (s *Service) GetCardStatus(ctx context.Context, req *dto.AgentOpenAPICardQu
CardNo: req.CardNo, CardNo: req.CardNo,
CardStatus: cardStatus, CardStatus: cardStatus,
CardStatusName: constants.AgentOpenAPICardStatusName(cardStatus), CardStatusName: constants.AgentOpenAPICardStatusName(cardStatus),
GatewayExtend: card.GatewayExtend,
StopReason: stopReason, StopReason: stopReason,
StopReasonName: constants.AgentOpenAPIStopReasonName(stopReason), StopReasonName: constants.AgentOpenAPIStopReasonName(stopReason),
}, nil }, nil

View File

@@ -200,6 +200,7 @@ func (s *Service) buildDeviceResolveResponse(ctx context.Context, device *model.
CarrierType: c.CarrierType, CarrierType: c.CarrierType,
CarrierName: c.CarrierName, CarrierName: c.CarrierName,
RealnamePolicy: c.RealnamePolicy, RealnamePolicy: c.RealnamePolicy,
GatewayExtend: c.GatewayExtend,
}) })
} }
@@ -255,6 +256,7 @@ func (s *Service) buildCardResolveResponse(ctx context.Context, card *model.IotC
RealNameAt: card.FirstRealnameAt, RealNameAt: card.FirstRealnameAt,
RealnamePolicy: card.RealnamePolicy, RealnamePolicy: card.RealnamePolicy,
NetworkStatus: card.NetworkStatus, NetworkStatus: card.NetworkStatus,
GatewayExtend: card.GatewayExtend,
ICCID: card.ICCID, ICCID: card.ICCID,
CarrierID: card.CarrierID, CarrierID: card.CarrierID,
CarrierType: card.CarrierType, CarrierType: card.CarrierType,
@@ -353,6 +355,7 @@ func (s *Service) GetRealtimeStatus(ctx context.Context, assetType string, id ui
return nil, errors.Wrap(errors.CodeNotFound, err, "卡不存在") return nil, errors.Wrap(errors.CodeNotFound, err, "卡不存在")
} }
resp.NetworkStatus = card.NetworkStatus resp.NetworkStatus = card.NetworkStatus
resp.GatewayExtend = card.GatewayExtend
resp.RealNameStatus = card.RealNameStatus resp.RealNameStatus = card.RealNameStatus
resp.CurrentMonthUsageMB = card.CurrentMonthUsageMB resp.CurrentMonthUsageMB = card.CurrentMonthUsageMB
resp.LastGatewayReadingMB = card.LastGatewayReadingMB resp.LastGatewayReadingMB = card.LastGatewayReadingMB
@@ -389,6 +392,7 @@ func (s *Service) GetRealtimeStatus(ctx context.Context, assetType string, id ui
CarrierType: c.CarrierType, CarrierType: c.CarrierType,
CarrierName: c.CarrierName, CarrierName: c.CarrierName,
RealnamePolicy: c.RealnamePolicy, RealnamePolicy: c.RealnamePolicy,
GatewayExtend: c.GatewayExtend,
}) })
} }
} }

View File

@@ -66,6 +66,7 @@ func (s *Service) ListBindings(ctx context.Context, deviceID uint) (*dto.ListDev
IsCurrent: binding.IsCurrent, IsCurrent: binding.IsCurrent,
RealnamePolicy: card.RealnamePolicy, RealnamePolicy: card.RealnamePolicy,
NetworkStatus: card.NetworkStatus, NetworkStatus: card.NetworkStatus,
GatewayExtend: card.GatewayExtend,
} }
responses = append(responses, resp) responses = append(responses, resp)
} }

View File

@@ -308,6 +308,7 @@ func (s *Service) ListCards(ctx context.Context, enterpriseID uint, req *dto.Ent
StatusName: constants.GetIotCardStatusName(card.Status), StatusName: constants.GetIotCardStatusName(card.Status),
NetworkStatus: card.NetworkStatus, NetworkStatus: card.NetworkStatus,
NetworkStatusName: constants.GetNetworkStatusName(card.NetworkStatus), NetworkStatusName: constants.GetNetworkStatusName(card.NetworkStatus),
GatewayExtend: card.GatewayExtend,
}) })
} }

View File

@@ -369,6 +369,7 @@ func (s *Service) toStandaloneResponse(card *model.IotCard, shopMap map[uint]str
RealNameStatusName: constants.GetRealNameStatusName(card.RealNameStatus), RealNameStatusName: constants.GetRealNameStatusName(card.RealNameStatus),
NetworkStatus: card.NetworkStatus, NetworkStatus: card.NetworkStatus,
NetworkStatusName: constants.GetNetworkStatusName(card.NetworkStatus), NetworkStatusName: constants.GetNetworkStatusName(card.NetworkStatus),
GatewayExtend: card.GatewayExtend,
DataUsageMB: card.DataUsageMB, DataUsageMB: card.DataUsageMB,
CurrentMonthUsageMB: card.CurrentMonthUsageMB, CurrentMonthUsageMB: card.CurrentMonthUsageMB,
LastGatewayReadingMB: card.LastGatewayReadingMB, LastGatewayReadingMB: card.LastGatewayReadingMB,
@@ -1420,6 +1421,7 @@ func (s *Service) RefreshCardDataFromGateway(ctx context.Context, iccid string)
if err != nil { if err != nil {
s.logger.Warn("刷新卡数据:查询网络状态失败", zap.String("iccid", iccid), zap.Error(err)) s.logger.Warn("刷新卡数据:查询网络状态失败", zap.String("iccid", iccid), zap.Error(err))
} else { } else {
updates["gateway_extend"] = statusResp.Extend
networkStatus, ok := gateway.ParseCardNetworkStatus(statusResp.CardStatus, statusResp.Extend) networkStatus, ok := gateway.ParseCardNetworkStatus(statusResp.CardStatus, statusResp.Extend)
if !ok { if !ok {
s.logger.Warn("刷新卡数据:未知 Gateway 卡状态", s.logger.Warn("刷新卡数据:未知 Gateway 卡状态",

View File

@@ -440,7 +440,7 @@ var standaloneListColumns = []string{
"imsi", "msisdn", "batch_no", "supplier", "status", "shop_id", "activated_at", "imsi", "msisdn", "batch_no", "supplier", "status", "shop_id", "activated_at",
"activation_status", "real_name_status", "network_status", "data_usage_mb", "activation_status", "real_name_status", "network_status", "data_usage_mb",
"current_month_usage_mb", "last_gateway_reading_mb", "current_month_start_date", "last_month_total_mb", "current_month_usage_mb", "last_gateway_reading_mb", "current_month_start_date", "last_month_total_mb",
"last_data_check_at", "last_real_name_check_at", "enable_polling", "series_id", "device_virtual_no", "realname_policy", "gateway_extend", "last_data_check_at", "last_real_name_check_at", "enable_polling", "series_id", "device_virtual_no", "realname_policy",
"created_at", "updated_at", "created_at", "updated_at",
} }

View File

@@ -74,6 +74,9 @@ func parseCardFromCache(cardID uint, result map[string]string) *model.IotCard {
card.NetworkStatus = status card.NetworkStatus = status
} }
} }
if v, ok := result["gateway_extend"]; ok {
card.GatewayExtend = v
}
if v, ok := result["carrier_id"]; ok { if v, ok := result["carrier_id"]; ok {
if id, err := strconv.ParseUint(v, 10, 64); err == nil { if id, err := strconv.ParseUint(v, 10, 64); err == nil {
card.CarrierID = uint(id) card.CarrierID = uint(id)
@@ -126,6 +129,7 @@ func writeCardToCache(b *PollingBase, key string, card *model.IotCard) {
"card_category": card.CardCategory, "card_category": card.CardCategory,
"real_name_status": card.RealNameStatus, "real_name_status": card.RealNameStatus,
"network_status": card.NetworkStatus, "network_status": card.NetworkStatus,
"gateway_extend": card.GatewayExtend,
"carrier_id": card.CarrierID, "carrier_id": card.CarrierID,
"current_month_usage_mb": card.CurrentMonthUsageMB, "current_month_usage_mb": card.CurrentMonthUsageMB,
"last_gateway_reading_mb": card.LastGatewayReadingMB, "last_gateway_reading_mb": card.LastGatewayReadingMB,

View File

@@ -65,6 +65,8 @@ func (h *PollingCardStatusHandler) Handle(ctx context.Context, t *asynq.Task) er
newNetworkStatus := card.NetworkStatus newNetworkStatus := card.NetworkStatus
gatewayCardStatus := "" gatewayCardStatus := ""
gatewayExtend := card.GatewayExtend
statusQueried := false
if h.gateway != nil { if h.gateway != nil {
result, gwErr := h.gateway.QueryCardStatus(ctx, &gateway.CardStatusReq{CardNo: card.ICCID}) result, gwErr := h.gateway.QueryCardStatus(ctx, &gateway.CardStatusReq{CardNo: card.ICCID})
if gwErr != nil { if gwErr != nil {
@@ -74,6 +76,8 @@ func (h *PollingCardStatusHandler) Handle(ctx context.Context, t *asynq.Task) er
return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingCardStatus) return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingCardStatus)
} }
gatewayCardStatus = result.CardStatus gatewayCardStatus = result.CardStatus
gatewayExtend = result.Extend
statusQueried = true
parsedStatus, ok := gateway.ParseCardNetworkStatus(result.CardStatus, result.Extend) parsedStatus, ok := gateway.ParseCardNetworkStatus(result.CardStatus, result.Extend)
if !ok { if !ok {
h.base.logger.Warn("卡状态轮询:未知 Gateway 卡状态", h.base.logger.Warn("卡状态轮询:未知 Gateway 卡状态",
@@ -100,6 +104,9 @@ func (h *PollingCardStatusHandler) Handle(ctx context.Context, t *asynq.Task) er
// 无论状态是否变化,都更新最后一次检查时间 // 无论状态是否变化,都更新最后一次检查时间
fields := map[string]any{"last_card_status_check_at": now} fields := map[string]any{"last_card_status_check_at": now}
if statusQueried {
fields["gateway_extend"] = gatewayExtend
}
if statusChanged { if statusChanged {
fields["network_status"] = newNetworkStatus fields["network_status"] = newNetworkStatus
// 网关侧停机事件:补写 stop_reason便于状态追踪和区分手动停机 // 网关侧停机事件:补写 stop_reason便于状态追踪和区分手动停机
@@ -116,8 +123,18 @@ func (h *PollingCardStatusHandler) Handle(ctx context.Context, t *asynq.Task) er
return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingCardStatus) return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingCardStatus)
} }
if statusQueried || statusChanged {
cacheUpdates := map[string]any{}
if statusQueried {
cacheUpdates["gateway_extend"] = gatewayExtend
}
if statusChanged {
cacheUpdates["network_status"] = newNetworkStatus
}
h.base.updateCardCache(ctx, cardID, cacheUpdates)
}
if statusChanged { if statusChanged {
h.base.updateCardCache(ctx, cardID, map[string]any{"network_status": newNetworkStatus})
h.base.logger.Info("卡状态已变化", h.base.logger.Info("卡状态已变化",
zap.Uint("card_id", cardID), zap.Uint("card_id", cardID),
zap.Int("old_status", card.NetworkStatus), zap.Int("old_status", card.NetworkStatus),

View File

@@ -0,0 +1,4 @@
-- 回滚 IoT 卡 Gateway 卡状态扩展字段
ALTER TABLE tb_iot_card
DROP COLUMN IF EXISTS gateway_extend;

View File

@@ -0,0 +1,6 @@
-- 为 IoT 卡保存 Gateway 卡状态扩展字段,用于展示运营商侧实际停机原因
ALTER TABLE tb_iot_card
ADD COLUMN IF NOT EXISTS gateway_extend TEXT NOT NULL DEFAULT '';
COMMENT ON COLUMN tb_iot_card.gateway_extend IS 'Gateway 卡状态扩展字段,原样保存上游 extend用于展示运营商侧实际停机原因';