feat: 新增数据库迁移,重命名 device_no 为 virtual_no,新增 iot_card.virtual_no 和 package.virtual_ratio 字段
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m3s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m3s
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -2,6 +2,7 @@ package iot_card
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/gateway"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
@@ -795,20 +796,9 @@ func (s *Service) buildCardNotFoundFailedItems(iccids []string) []dto.CardSeries
|
||||
return items
|
||||
}
|
||||
|
||||
// SyncCardStatusFromGateway 从 Gateway 同步卡状态(示例方法)
|
||||
func (s *Service) SyncCardStatusFromGateway(ctx context.Context, iccid string) error {
|
||||
if s.gatewayClient == nil {
|
||||
return errors.New(errors.CodeGatewayError, "Gateway 客户端未配置")
|
||||
}
|
||||
|
||||
resp, err := s.gatewayClient.QueryCardStatus(ctx, &gateway.CardStatusReq{
|
||||
CardNo: iccid,
|
||||
})
|
||||
if err != nil {
|
||||
s.logger.Error("查询卡状态失败", zap.String("iccid", iccid), zap.Error(err))
|
||||
return errors.Wrap(errors.CodeGatewayError, err, "查询卡状态失败")
|
||||
}
|
||||
|
||||
// RefreshCardDataFromGateway 从 Gateway 完整同步卡数据
|
||||
// 调用网关查询网络状态、实名状态、本月流量,并写回数据库
|
||||
func (s *Service) RefreshCardDataFromGateway(ctx context.Context, iccid string) error {
|
||||
card, err := s.iotCardStore.GetByICCID(ctx, iccid)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
@@ -817,40 +807,73 @@ func (s *Service) SyncCardStatusFromGateway(ctx context.Context, iccid string) e
|
||||
return err
|
||||
}
|
||||
|
||||
var newStatus int
|
||||
switch resp.CardStatus {
|
||||
case "准备":
|
||||
newStatus = constants.IotCardStatusInStock
|
||||
case "正常":
|
||||
newStatus = constants.IotCardStatusDistributed
|
||||
case "停机":
|
||||
newStatus = constants.IotCardStatusSuspended
|
||||
default:
|
||||
s.logger.Warn("未知的卡状态", zap.String("cardStatus", resp.CardStatus))
|
||||
return nil
|
||||
syncTime := time.Now()
|
||||
updates := map[string]any{
|
||||
"last_sync_time": syncTime,
|
||||
}
|
||||
|
||||
if card.Status != newStatus {
|
||||
oldStatus := card.Status
|
||||
card.Status = newStatus
|
||||
if err := s.iotCardStore.Update(ctx, card); err != nil {
|
||||
return err
|
||||
if s.gatewayClient != nil {
|
||||
// 1. 查询网络状态(卡的开/停机状态)
|
||||
statusResp, err := s.gatewayClient.QueryCardStatus(ctx, &gateway.CardStatusReq{
|
||||
CardNo: iccid,
|
||||
})
|
||||
if err != nil {
|
||||
s.logger.Warn("刷新卡数据:查询网络状态失败", zap.String("iccid", iccid), zap.Error(err))
|
||||
} else {
|
||||
networkStatus := parseNetworkStatus(statusResp.CardStatus)
|
||||
updates["network_status"] = networkStatus
|
||||
}
|
||||
s.logger.Info("同步卡状态成功",
|
||||
zap.String("iccid", iccid),
|
||||
zap.Int("oldStatus", oldStatus),
|
||||
zap.Int("newStatus", newStatus),
|
||||
)
|
||||
|
||||
// 通知轮询调度器状态变化
|
||||
if s.pollingCallback != nil {
|
||||
s.pollingCallback.OnCardStatusChanged(ctx, card.ID)
|
||||
// 2. 查询实名状态
|
||||
realnameResp, err := s.gatewayClient.QueryRealnameStatus(ctx, &gateway.CardStatusReq{
|
||||
CardNo: iccid,
|
||||
})
|
||||
if err != nil {
|
||||
s.logger.Warn("刷新卡数据:查询实名状态失败", zap.String("iccid", iccid), zap.Error(err))
|
||||
} else {
|
||||
realNameStatus := parseGatewayRealnameStatus(realnameResp.RealStatus)
|
||||
updates["real_name_status"] = realNameStatus
|
||||
}
|
||||
|
||||
// 3. 查询本月流量用量
|
||||
flowResp, err := s.gatewayClient.QueryFlow(ctx, &gateway.FlowQueryReq{
|
||||
CardNo: iccid,
|
||||
})
|
||||
if err != nil {
|
||||
s.logger.Warn("刷新卡数据:查询流量失败", zap.String("iccid", iccid), zap.Error(err))
|
||||
} else {
|
||||
updates["current_month_usage_mb"] = flowResp.Used
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.db.WithContext(ctx).Model(&model.IotCard{}).
|
||||
Where("id = ?", card.ID).
|
||||
Updates(updates).Error; err != nil {
|
||||
return errors.Wrap(errors.CodeInternalError, err, "更新卡数据失败")
|
||||
}
|
||||
|
||||
s.logger.Info("刷新卡数据成功", zap.String("iccid", iccid), zap.Uint("card_id", card.ID))
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseNetworkStatus 将网关返回的卡状态字符串转换为 network_status 数值
|
||||
// 停机→0,其他(准备/正常)→1
|
||||
func parseNetworkStatus(cardStatus string) int {
|
||||
if cardStatus == "停机" {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// parseGatewayRealnameStatus 将网关返回的实名状态布尔值转换为 real_name_status 数值
|
||||
// true=已实名(2),false=未实名(0)
|
||||
func parseGatewayRealnameStatus(realStatus bool) int {
|
||||
if realStatus {
|
||||
return 2
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// UpdatePollingStatus 更新卡的轮询状态
|
||||
// 启用或禁用卡的轮询功能
|
||||
func (s *Service) UpdatePollingStatus(ctx context.Context, cardID uint, enablePolling bool) error {
|
||||
|
||||
Reference in New Issue
Block a user