From 8f3a68a673e7ed8b1c67464983f3f1a0b5582ba3 Mon Sep 17 00:00:00 2001 From: huang Date: Tue, 12 May 2026 11:13:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=B8=8A=E6=B8=B8=E7=9A=84?= =?UTF-8?q?=E5=81=9C=E6=9C=BA=E5=8E=9F=E5=9B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/admin-openapi.yaml | 29 ++++++++++++++++++- internal/handler/app/client_asset.go | 1 + internal/handler/app/client_device.go | 1 + internal/model/dto/agent_open_api_dto.go | 1 + internal/model/dto/asset_dto.go | 3 ++ internal/model/dto/client_asset_dto.go | 1 + .../model/dto/client_realname_device_dto.go | 1 + internal/model/dto/device_dto.go | 1 + .../dto/enterprise_card_authorization_dto.go | 1 + .../enterprise_device_authorization_dto.go | 1 + internal/model/dto/iot_card_dto.go | 1 + internal/model/iot_card.go | 1 + internal/service/agent_open_api/service.go | 1 + internal/service/asset/service.go | 4 +++ internal/service/device/binding.go | 1 + internal/service/enterprise_card/service.go | 1 + internal/service/iot_card/service.go | 2 ++ internal/store/postgres/iot_card_store.go | 2 +- internal/task/polling_card_cache.go | 4 +++ internal/task/polling_cardstatus_handler.go | 19 +++++++++++- ...43_add_gateway_extend_to_iot_card.down.sql | 4 +++ ...0143_add_gateway_extend_to_iot_card.up.sql | 6 ++++ 22 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 migrations/000143_add_gateway_extend_to_iot_card.down.sql create mode 100644 migrations/000143_add_gateway_extend_to_iot_card.up.sql diff --git a/docs/admin-openapi.yaml b/docs/admin-openapi.yaml index 23e9d21..db6db29 100644 --- a/docs/admin-openapi.yaml +++ b/docs/admin-openapi.yaml @@ -146,6 +146,9 @@ components: card_status_name: description: 卡状态名称(中文) type: string + gateway_extend: + description: Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因 + type: string stop_reason: description: 停机原因 type: string @@ -908,6 +911,9 @@ components: enable_virtual_data: description: 当前主套餐是否启用虚流量(按套餐使用记录快照返回) type: boolean + gateway_extend: + description: Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因 + type: string generation: description: 世代 type: string @@ -1314,6 +1320,9 @@ components: type: string device_realtime: $ref: '#/components/schemas/DtoDeviceGatewayInfo' + gateway_extend: + description: Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因 + type: string last_gateway_reading_mb: description: 运营商当前周期累计流量读数(MB,asset_type=card时有效,运营商口径展示建议读取该字段) type: number @@ -1446,6 +1455,9 @@ components: enable_virtual_data: description: 当前主套餐是否启用虚流量(按套餐使用记录快照返回) type: boolean + gateway_extend: + description: Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因 + type: string iccid: description: 卡ICCID(asset_type=card时有效) type: string @@ -2124,6 +2136,9 @@ components: carrier_type: description: 运营商类型 type: string + gateway_extend: + description: Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因 + type: string iccid: description: ICCID type: string @@ -3807,6 +3822,9 @@ components: carrier_name: description: 运营商名称 type: string + gateway_extend: + description: Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因 + type: string iccid: description: ICCID type: string @@ -3858,6 +3876,9 @@ components: carrier_type: description: 运营商类型(CMCC/CUCC/CTCC/CBN) type: string + gateway_extend: + description: Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因 + type: string iccid: description: 物联网卡ICCID type: string @@ -4542,6 +4563,9 @@ components: minimum: 0 nullable: true type: integer + gateway_extend: + description: Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因 + type: string iccid: description: ICCID type: string @@ -6911,7 +6935,7 @@ components: description: 下单时资产的标识符快照(ICCID 或 VirtualNo) type: string asset_reset: - description: 资产是否已重置 + description: 退款后资产处理是否完成 type: boolean asset_type: description: 资产类型 (card:单卡, device:设备) @@ -7750,6 +7774,9 @@ components: enable_polling: description: 是否参与轮询 type: boolean + gateway_extend: + description: Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因 + type: string iccid: description: ICCID type: string diff --git a/internal/handler/app/client_asset.go b/internal/handler/app/client_asset.go index 965aa75..b2afead 100644 --- a/internal/handler/app/client_asset.go +++ b/internal/handler/app/client_asset.go @@ -192,6 +192,7 @@ func (h *ClientAssetHandler) GetAssetInfo(c *fiber.Ctx) error { CarrierType: resolved.Asset.CarrierType, NetworkStatus: resolved.Asset.NetworkStatus, NetworkStatusName: constants.GetNetworkStatusName(resolved.Asset.NetworkStatus), + GatewayExtend: resolved.Asset.GatewayExtend, ActivationStatus: resolved.Asset.ActivationStatus, ActivationStatusName: constants.GetActivationStatusName(resolved.Asset.ActivationStatus), CardCategory: resolved.Asset.CardCategory, diff --git a/internal/handler/app/client_device.go b/internal/handler/app/client_device.go index dfd55d3..680a03b 100644 --- a/internal/handler/app/client_device.go +++ b/internal/handler/app/client_device.go @@ -166,6 +166,7 @@ func (h *ClientDeviceHandler) GetDeviceCards(c *fiber.Ctx) error { CarrierType: card.CarrierType, CarrierName: card.CarrierName, NetworkStatus: networkStatusText(card.NetworkStatus), + GatewayExtend: card.GatewayExtend, RealNameStatus: card.RealNameStatus, SlotPosition: slot, IsActive: isCurrentMap[card.ID], diff --git a/internal/model/dto/agent_open_api_dto.go b/internal/model/dto/agent_open_api_dto.go index f6a7eca..d330713 100644 --- a/internal/model/dto/agent_open_api_dto.go +++ b/internal/model/dto/agent_open_api_dto.go @@ -39,6 +39,7 @@ type AgentOpenAPICardStatusResponse struct { CardNo string `json:"card_no" description:"卡标识"` CardStatus string `json:"card_status" description:"卡状态 (normal:正常, stopped:停机)"` CardStatusName string `json:"card_status_name" description:"卡状态名称(中文)"` + GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因"` StopReason string `json:"stop_reason" description:"停机原因"` StopReasonName string `json:"stop_reason_name" description:"停机原因名称(中文)"` } diff --git a/internal/model/dto/asset_dto.go b/internal/model/dto/asset_dto.go index 340d199..8e88365 100644 --- a/internal/model/dto/asset_dto.go +++ b/internal/model/dto/asset_dto.go @@ -65,6 +65,7 @@ type AssetResolveResponse struct { ActivationStatus int `json:"activation_status,omitempty" description:"激活状态"` EnablePolling bool `json:"enable_polling" description:"是否参与轮询"` NetworkStatus int `json:"network_status" description:"网络状态:0停机 1开机(asset_type=card时有效)"` + GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因"` } // BoundCardInfo 设备绑定的卡信息 @@ -81,6 +82,7 @@ type BoundCardInfo struct { CarrierType string `json:"carrier_type,omitempty" description:"运营商类型"` CarrierName string `json:"carrier_name,omitempty" description:"运营商名称"` RealnamePolicy string `json:"realname_policy" description:"实名认证策略 (none:无需实名, before_order:先实名后充值/购买, after_order:先充值/购买后实名)"` + GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因"` } // AssetRealtimeStatusResponse 资产实时状态(只读DB/Redis) @@ -88,6 +90,7 @@ type AssetRealtimeStatusResponse struct { AssetType string `json:"asset_type" description:"资产类型:card 或 device"` AssetID uint `json:"asset_id" description:"资产ID"` 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已实名"` RealnamePolicy string `json:"realname_policy,omitempty" description:"实名认证策略 (none:无需实名, before_order:先实名后充值/购买, after_order:先充值/购买后实名)"` CurrentMonthUsageMB float64 `json:"current_month_usage_mb,omitempty" description:"系统自然月累计流量(MB,asset_type=card时有效,不等于运营商周期口径)"` diff --git a/internal/model/dto/client_asset_dto.go b/internal/model/dto/client_asset_dto.go index 03b282e..324c61c 100644 --- a/internal/model/dto/client_asset_dto.go +++ b/internal/model/dto/client_asset_dto.go @@ -63,6 +63,7 @@ type AssetInfoResponse struct { CarrierType string `json:"carrier_type,omitempty" description:"运营商类型(CMCC/CUCC/CTCC/CBN)"` NetworkStatus int `json:"network_status,omitempty" description:"网络状态(0:停机, 1:开机)"` 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:已激活)"` ActivationStatusName string `json:"activation_status_name,omitempty" description:"激活状态名称(中文)"` CardCategory string `json:"card_category,omitempty" description:"卡业务类型(normal:普通卡, industry:行业卡)"` diff --git a/internal/model/dto/client_realname_device_dto.go b/internal/model/dto/client_realname_device_dto.go index 4e75946..f71d957 100644 --- a/internal/model/dto/client_realname_device_dto.go +++ b/internal/model/dto/client_realname_device_dto.go @@ -42,6 +42,7 @@ type DeviceCardItem struct { CarrierType string `json:"carrier_type" description:"运营商类型(CMCC/CUCC/CTCC/CBN)"` CarrierName string `json:"carrier_name" description:"运营商名称"` NetworkStatus string `json:"network_status" description:"网络状态"` + GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因"` RealNameStatus int `json:"real_name_status" description:"实名状态 (0:未实名, 1:已实名)"` SlotPosition int `json:"slot_position" description:"插槽位置"` IsActive bool `json:"is_active" description:"是否当前激活卡"` diff --git a/internal/model/dto/device_dto.go b/internal/model/dto/device_dto.go index fa00c6e..86ec2f0 100644 --- a/internal/model/dto/device_dto.go +++ b/internal/model/dto/device_dto.go @@ -87,6 +87,7 @@ type DeviceCardBindingResponse struct { IsCurrent bool `json:"is_current" description:"是否为当前使用的卡"` RealnamePolicy string `json:"realname_policy" description:"实名认证策略 (none:无需实名, before_order:先实名后充值/购买, after_order:先充值/购买后实名)"` NetworkStatus int `json:"network_status" description:"网络状态:0停机 1开机(asset_type=card时有效)"` + GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因"` } type ListDeviceCardsResponse struct { diff --git a/internal/model/dto/enterprise_card_authorization_dto.go b/internal/model/dto/enterprise_card_authorization_dto.go index cc36498..8e0cc4d 100644 --- a/internal/model/dto/enterprise_card_authorization_dto.go +++ b/internal/model/dto/enterprise_card_authorization_dto.go @@ -87,6 +87,7 @@ type EnterpriseCardItem struct { StatusName string `json:"status_name" description:"状态名称"` NetworkStatus int `json:"network_status" description:"网络状态"` NetworkStatusName string `json:"network_status_name" description:"网络状态名称"` + GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因"` } type EnterpriseCardPageResult struct { diff --git a/internal/model/dto/enterprise_device_authorization_dto.go b/internal/model/dto/enterprise_device_authorization_dto.go index a893a98..c7d7f9a 100644 --- a/internal/model/dto/enterprise_device_authorization_dto.go +++ b/internal/model/dto/enterprise_device_authorization_dto.go @@ -85,6 +85,7 @@ type DeviceCardInfo struct { CarrierName string `json:"carrier_name" description:"运营商名称"` NetworkStatus int `json:"network_status" description:"网络状态:0=停机 1=开机"` NetworkStatusName string `json:"network_status_name" description:"网络状态名称"` + GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因"` } type DeviceDetailReq struct { diff --git a/internal/model/dto/iot_card_dto.go b/internal/model/dto/iot_card_dto.go index dddefc0..0c0a6ac 100644 --- a/internal/model/dto/iot_card_dto.go +++ b/internal/model/dto/iot_card_dto.go @@ -45,6 +45,7 @@ type StandaloneIotCardResponse struct { RealNameStatusName string `json:"real_name_status_name" description:"实名状态名称(中文)"` NetworkStatus int `json:"network_status" description:"网络状态 (0:停机, 1:开机)"` NetworkStatusName string `json:"network_status_name" description:"网络状态名称(中文)"` + GatewayExtend string `json:"gateway_extend" description:"Gateway 卡状态扩展字段,原样返回上游 extend,用于展示运营商侧实际停机原因"` DataUsageMB int64 `json:"data_usage_mb" description:"累计流量使用(MB)"` CurrentMonthUsageMB float64 `json:"current_month_usage_mb" description:"系统自然月累计流量(MB,不等于运营商周期口径)"` LastGatewayReadingMB float64 `json:"last_gateway_reading_mb" description:"运营商当前周期累计流量读数(MB,展示运营商口径时使用)"` diff --git a/internal/model/iot_card.go b/internal/model/iot_card.go index b9565b6..cc2c1a2 100644 --- a/internal/model/iot_card.go +++ b/internal/model/iot_card.go @@ -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"` 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"` + 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"` // ICCID 双列存储,用于支持 19/20 位 ICCID 精确路由查询 diff --git a/internal/service/agent_open_api/service.go b/internal/service/agent_open_api/service.go index 6cdbcb0..b51fd41 100644 --- a/internal/service/agent_open_api/service.go +++ b/internal/service/agent_open_api/service.go @@ -121,6 +121,7 @@ func (s *Service) GetCardStatus(ctx context.Context, req *dto.AgentOpenAPICardQu CardNo: req.CardNo, CardStatus: cardStatus, CardStatusName: constants.AgentOpenAPICardStatusName(cardStatus), + GatewayExtend: card.GatewayExtend, StopReason: stopReason, StopReasonName: constants.AgentOpenAPIStopReasonName(stopReason), }, nil diff --git a/internal/service/asset/service.go b/internal/service/asset/service.go index 0429ea7..075e171 100644 --- a/internal/service/asset/service.go +++ b/internal/service/asset/service.go @@ -200,6 +200,7 @@ func (s *Service) buildDeviceResolveResponse(ctx context.Context, device *model. CarrierType: c.CarrierType, CarrierName: c.CarrierName, RealnamePolicy: c.RealnamePolicy, + GatewayExtend: c.GatewayExtend, }) } @@ -255,6 +256,7 @@ func (s *Service) buildCardResolveResponse(ctx context.Context, card *model.IotC RealNameAt: card.FirstRealnameAt, RealnamePolicy: card.RealnamePolicy, NetworkStatus: card.NetworkStatus, + GatewayExtend: card.GatewayExtend, ICCID: card.ICCID, CarrierID: card.CarrierID, 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, "卡不存在") } resp.NetworkStatus = card.NetworkStatus + resp.GatewayExtend = card.GatewayExtend resp.RealNameStatus = card.RealNameStatus resp.CurrentMonthUsageMB = card.CurrentMonthUsageMB resp.LastGatewayReadingMB = card.LastGatewayReadingMB @@ -389,6 +392,7 @@ func (s *Service) GetRealtimeStatus(ctx context.Context, assetType string, id ui CarrierType: c.CarrierType, CarrierName: c.CarrierName, RealnamePolicy: c.RealnamePolicy, + GatewayExtend: c.GatewayExtend, }) } } diff --git a/internal/service/device/binding.go b/internal/service/device/binding.go index c9ea4ac..cf5a2fa 100644 --- a/internal/service/device/binding.go +++ b/internal/service/device/binding.go @@ -66,6 +66,7 @@ func (s *Service) ListBindings(ctx context.Context, deviceID uint) (*dto.ListDev IsCurrent: binding.IsCurrent, RealnamePolicy: card.RealnamePolicy, NetworkStatus: card.NetworkStatus, + GatewayExtend: card.GatewayExtend, } responses = append(responses, resp) } diff --git a/internal/service/enterprise_card/service.go b/internal/service/enterprise_card/service.go index ca17dce..155af3b 100644 --- a/internal/service/enterprise_card/service.go +++ b/internal/service/enterprise_card/service.go @@ -308,6 +308,7 @@ func (s *Service) ListCards(ctx context.Context, enterpriseID uint, req *dto.Ent StatusName: constants.GetIotCardStatusName(card.Status), NetworkStatus: card.NetworkStatus, NetworkStatusName: constants.GetNetworkStatusName(card.NetworkStatus), + GatewayExtend: card.GatewayExtend, }) } diff --git a/internal/service/iot_card/service.go b/internal/service/iot_card/service.go index 713a23b..6f34b46 100644 --- a/internal/service/iot_card/service.go +++ b/internal/service/iot_card/service.go @@ -369,6 +369,7 @@ func (s *Service) toStandaloneResponse(card *model.IotCard, shopMap map[uint]str RealNameStatusName: constants.GetRealNameStatusName(card.RealNameStatus), NetworkStatus: card.NetworkStatus, NetworkStatusName: constants.GetNetworkStatusName(card.NetworkStatus), + GatewayExtend: card.GatewayExtend, DataUsageMB: card.DataUsageMB, CurrentMonthUsageMB: card.CurrentMonthUsageMB, LastGatewayReadingMB: card.LastGatewayReadingMB, @@ -1420,6 +1421,7 @@ func (s *Service) RefreshCardDataFromGateway(ctx context.Context, iccid string) if err != nil { s.logger.Warn("刷新卡数据:查询网络状态失败", zap.String("iccid", iccid), zap.Error(err)) } else { + updates["gateway_extend"] = statusResp.Extend networkStatus, ok := gateway.ParseCardNetworkStatus(statusResp.CardStatus, statusResp.Extend) if !ok { s.logger.Warn("刷新卡数据:未知 Gateway 卡状态", diff --git a/internal/store/postgres/iot_card_store.go b/internal/store/postgres/iot_card_store.go index 1a76e62..190197e 100644 --- a/internal/store/postgres/iot_card_store.go +++ b/internal/store/postgres/iot_card_store.go @@ -440,7 +440,7 @@ var standaloneListColumns = []string{ "imsi", "msisdn", "batch_no", "supplier", "status", "shop_id", "activated_at", "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", - "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", } diff --git a/internal/task/polling_card_cache.go b/internal/task/polling_card_cache.go index 2008dca..e0bb5ac 100644 --- a/internal/task/polling_card_cache.go +++ b/internal/task/polling_card_cache.go @@ -74,6 +74,9 @@ func parseCardFromCache(cardID uint, result map[string]string) *model.IotCard { card.NetworkStatus = status } } + if v, ok := result["gateway_extend"]; ok { + card.GatewayExtend = v + } if v, ok := result["carrier_id"]; ok { if id, err := strconv.ParseUint(v, 10, 64); err == nil { card.CarrierID = uint(id) @@ -126,6 +129,7 @@ func writeCardToCache(b *PollingBase, key string, card *model.IotCard) { "card_category": card.CardCategory, "real_name_status": card.RealNameStatus, "network_status": card.NetworkStatus, + "gateway_extend": card.GatewayExtend, "carrier_id": card.CarrierID, "current_month_usage_mb": card.CurrentMonthUsageMB, "last_gateway_reading_mb": card.LastGatewayReadingMB, diff --git a/internal/task/polling_cardstatus_handler.go b/internal/task/polling_cardstatus_handler.go index ad19d0d..c6cb3bb 100644 --- a/internal/task/polling_cardstatus_handler.go +++ b/internal/task/polling_cardstatus_handler.go @@ -65,6 +65,8 @@ func (h *PollingCardStatusHandler) Handle(ctx context.Context, t *asynq.Task) er newNetworkStatus := card.NetworkStatus gatewayCardStatus := "" + gatewayExtend := card.GatewayExtend + statusQueried := false if h.gateway != nil { result, gwErr := h.gateway.QueryCardStatus(ctx, &gateway.CardStatusReq{CardNo: card.ICCID}) 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) } gatewayCardStatus = result.CardStatus + gatewayExtend = result.Extend + statusQueried = true parsedStatus, ok := gateway.ParseCardNetworkStatus(result.CardStatus, result.Extend) if !ok { 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} + if statusQueried { + fields["gateway_extend"] = gatewayExtend + } if statusChanged { fields["network_status"] = newNetworkStatus // 网关侧停机事件:补写 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) } + 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 { - h.base.updateCardCache(ctx, cardID, map[string]any{"network_status": newNetworkStatus}) h.base.logger.Info("卡状态已变化", zap.Uint("card_id", cardID), zap.Int("old_status", card.NetworkStatus), diff --git a/migrations/000143_add_gateway_extend_to_iot_card.down.sql b/migrations/000143_add_gateway_extend_to_iot_card.down.sql new file mode 100644 index 0000000..cacb8f6 --- /dev/null +++ b/migrations/000143_add_gateway_extend_to_iot_card.down.sql @@ -0,0 +1,4 @@ +-- 回滚 IoT 卡 Gateway 卡状态扩展字段 + +ALTER TABLE tb_iot_card + DROP COLUMN IF EXISTS gateway_extend; diff --git a/migrations/000143_add_gateway_extend_to_iot_card.up.sql b/migrations/000143_add_gateway_extend_to_iot_card.up.sql new file mode 100644 index 0000000..3a5c520 --- /dev/null +++ b/migrations/000143_add_gateway_extend_to_iot_card.up.sql @@ -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,用于展示运营商侧实际停机原因';