机卡分离复机接口
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m1s

This commit is contained in:
2026-05-14 09:50:48 +08:00
parent 81aa3c2b11
commit d597a25c69
10 changed files with 190 additions and 14 deletions

View File

@@ -3,6 +3,7 @@ package iot_card
import (
"context"
stderrors "errors"
"strings"
"time"
"github.com/break/junhong_cmp_fiber/internal/gateway"
@@ -1421,13 +1422,14 @@ 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)
gatewayExtend := strings.TrimSpace(statusResp.Extend)
updates["gateway_extend"] = gatewayExtend
networkStatus, ok := gateway.ParseCardNetworkStatus(statusResp.CardStatus, gatewayExtend)
if !ok {
s.logger.Warn("刷新卡数据:未知 Gateway 卡状态",
zap.String("iccid", iccid),
zap.String("card_status", statusResp.CardStatus),
zap.String("extend", statusResp.Extend))
zap.String("extend", gatewayExtend))
} else {
updates["network_status"] = networkStatus
}

View File

@@ -2,14 +2,14 @@ package iot_card
import (
"context"
stderrors "errors"
"strings"
"time"
"github.com/redis/go-redis/v9"
"go.uber.org/zap"
"gorm.io/gorm"
stderrors "errors"
"github.com/break/junhong_cmp_fiber/internal/gateway"
"github.com/break/junhong_cmp_fiber/internal/model"
assetAuditSvc "github.com/break/junhong_cmp_fiber/internal/service/asset_audit"
@@ -672,6 +672,108 @@ func (s *StopResumeService) resumeCardWithRetry(ctx context.Context, card *model
return lastErr
}
// StartMachineSeparatedCard 对机卡分离停机卡执行复机
// 调用上游复机前检查本地落库的 Gateway extend只有“机卡分离停机”才允许复机。
func (s *StopResumeService) StartMachineSeparatedCard(ctx context.Context, card *model.IotCard) error {
if card == nil {
return errors.New(errors.CodeInvalidParam)
}
if s.gatewayClient == nil {
return errors.New(errors.CodeInternalError, "Gateway 未配置,停复机操作不可用")
}
gatewayExtend := strings.TrimSpace(card.GatewayExtend)
if gatewayExtend != constants.GatewayCardExtendMachineSeparated {
denyErr := errors.New(errors.CodeForbidden, constants.AgentOpenAPIResumeOnlyMachineSeparatedMessage)
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(denyErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardManualStart,
OperationDesc: "机卡分离复机被拒绝",
ResultStatus: constants.AssetAuditResultDenied,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: cardSnapshot(card),
AfterData: map[string]any{
"gateway_extend": gatewayExtend,
},
})
return denyErr
}
if err := s.resumeCardWithRetry(ctx, card); err != nil {
wrapErr := errors.Wrap(errors.CodeGatewayError, err, "调用运营商复机失败,请稍后重试")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(wrapErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardManualStart,
OperationDesc: "机卡分离复机执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: cardSnapshot(card),
AfterData: map[string]any{
"gateway_extend": gatewayExtend,
},
})
return wrapErr
}
now := time.Now()
if err := s.iotCardStore.UpdateFields(ctx, card.ID, map[string]any{
"network_status": constants.NetworkStatusOnline,
"resumed_at": now,
"stop_reason": "",
"gateway_extend": "",
}); err != nil {
wrapErr := errors.Wrap(errors.CodeDatabaseError, err, "更新卡状态失败")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(wrapErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardManualStart,
OperationDesc: "机卡分离复机执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: map[string]any{
"network_status": card.NetworkStatus,
"stop_reason": card.StopReason,
"gateway_extend": gatewayExtend,
},
AfterData: map[string]any{
"network_status": constants.NetworkStatusOnline,
"stop_reason": "",
"gateway_extend": "",
},
})
return wrapErr
}
s.invalidatePollingCache(ctx, card.ID)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardManualStart,
OperationDesc: "机卡分离复机",
ResultStatus: constants.AssetAuditResultSuccess,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: map[string]any{
"network_status": card.NetworkStatus,
"stop_reason": card.StopReason,
"gateway_extend": gatewayExtend,
},
AfterData: map[string]any{
"network_status": constants.NetworkStatusOnline,
"stop_reason": "",
"gateway_extend": "",
},
})
return nil
}
// ManualStopCard 手动停机单张卡通过ICCID
func (s *StopResumeService) ManualStopCard(ctx context.Context, iccid string) error {
card, err := s.iotCardStore.GetByICCID(ctx, iccid)