七月迭代短暂完结,还有很多后端的关键东西没有弄,这是一版赶时间做的东西
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m26s

This commit is contained in:
2026-07-25 17:06:58 +08:00
parent ad9f613dd6
commit 73f5125d3d
249 changed files with 17137 additions and 877 deletions

View File

@@ -0,0 +1,158 @@
package iot_card
import (
"context"
stderrors "errors"
"strconv"
"time"
"github.com/break/junhong_cmp_fiber/internal/gateway"
"github.com/break/junhong_cmp_fiber/internal/infrastructure/integrationlog"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
assetAuditSvc "github.com/break/junhong_cmp_fiber/internal/service/asset_audit"
"github.com/break/junhong_cmp_fiber/pkg/constants"
pkgerrors "github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/break/junhong_cmp_fiber/pkg/middleware"
"go.uber.org/zap"
)
type speedTierIntegrationLog interface {
Start(ctx context.Context, input integrationlog.Attempt) (*model.IntegrationLog, error)
Complete(ctx context.Context, integrationID string, completion integrationlog.Completion) (*model.IntegrationLog, error)
}
// SetSpeedTier 为有权限的 IoT 卡设置或恢复固定限速档位。
func (s *Service) SetSpeedTier(ctx context.Context, iccid string, code *int) (*dto.SetIotCardSpeedTierResponse, error) {
if !canManageCardSpeedTier(ctx) {
return nil, pkgerrors.New(pkgerrors.CodeForbidden, "仅平台和代理后台账号可设置卡限速档位")
}
if code == nil || !constants.IsGatewaySpeedTier(*code) {
return nil, pkgerrors.New(pkgerrors.CodeInvalidParam, "固定限速档位不合法")
}
if s == nil || s.iotCardStore == nil || s.gatewayClient == nil || s.speedTierIntegration == nil {
return nil, pkgerrors.New(pkgerrors.CodeServiceUnavailable, "卡限速服务未完整配置")
}
card, err := s.iotCardStore.GetByICCID(ctx, iccid)
if err != nil || card == nil || card.ICCID == "" {
return nil, pkgerrors.New(pkgerrors.CodeForbidden, "无权限操作该资源或资源不存在")
}
tierName := constants.GetGatewaySpeedTierName(*code)
resourceID := strconv.FormatUint(uint64(card.ID), 10)
requestID := middleware.GetRequestIDFromContext(ctx)
attempt, err := s.speedTierIntegration.Start(ctx, integrationlog.Attempt{
Provider: constants.IntegrationProviderGateway,
Direction: constants.IntegrationDirectionOutbound,
Operation: constants.IntegrationOperationGatewaySpeedTier,
ExternalID: &card.ICCID,
ResourceType: constants.AssetTypeIotCard,
ResourceID: &resourceID,
ResourceKey: &card.ICCID,
RequestID: requestID,
CorrelationID: requestID,
RequestSummary: map[string]any{
"iot_card_id": card.ID,
"iccid": card.ICCID,
"tier_code": *code,
"tier_name": tierName,
"operator_id": middleware.GetUserIDFromContext(ctx),
},
})
if err != nil {
s.logSpeedTierAudit(ctx, card, *code, "", constants.AssetAuditResultFailed, err)
return nil, err
}
startedAt := time.Now()
gatewayErr := s.gatewayClient.SetCardSpeedTier(ctx, &gateway.CardSpeedTierReq{
CardNo: card.ICCID,
Code: strconv.Itoa(*code),
})
completion := speedTierCompletion(gatewayErr, time.Since(startedAt))
if _, completeErr := s.speedTierIntegration.Complete(ctx, attempt.IntegrationID, completion); completeErr != nil {
if s.logger != nil {
s.logger.Error("终结卡限速 Integration Log 失败",
zap.Uint("iot_card_id", card.ID),
zap.String("integration_id", attempt.IntegrationID),
zap.Error(completeErr),
)
}
s.logSpeedTierAudit(ctx, card, *code, attempt.IntegrationID, constants.AssetAuditResultFailed, completeErr)
return nil, pkgerrors.Wrap(pkgerrors.CodeDatabaseError, completeErr, "终结卡限速外部交互记录失败")
}
if gatewayErr != nil {
s.logSpeedTierAudit(ctx, card, *code, attempt.IntegrationID, constants.AssetAuditResultFailed, gatewayErr)
if isGatewayTimeout(gatewayErr) {
return nil, pkgerrors.New(pkgerrors.CodeGatewayTimeout, "Gateway 卡限速请求结果未知,请核对实际档位后再操作")
}
return nil, gatewayErr
}
s.logSpeedTierAudit(ctx, card, *code, attempt.IntegrationID, constants.AssetAuditResultSuccess, nil)
return &dto.SetIotCardSpeedTierResponse{
IotCardID: card.ID, ICCID: card.ICCID, Code: *code,
SpeedTierName: tierName, IntegrationID: attempt.IntegrationID,
}, nil
}
func canManageCardSpeedTier(ctx context.Context) bool {
switch middleware.GetUserTypeFromContext(ctx) {
case constants.UserTypeSuperAdmin, constants.UserTypePlatform, constants.UserTypeAgent:
return middleware.GetUserIDFromContext(ctx) > 0
default:
return false
}
}
func speedTierCompletion(err error, duration time.Duration) integrationlog.Completion {
completion := integrationlog.Completion{
Result: constants.IntegrationResultSuccess,
DurationMS: duration.Milliseconds(),
StateChanged: true,
ResponseSummary: map[string]any{
"result": "success",
},
}
if err == nil {
return completion
}
completion.Result = constants.IntegrationResultFailed
completion.StateChanged = false
completion.ProviderMessage = err.Error()
completion.ResponseSummary = map[string]any{"result": "failed"}
if isGatewayTimeout(err) {
completion.Result = constants.IntegrationResultUnknown
completion.ResponseSummary = map[string]any{"result": "unknown"}
completion.RecoveryStrategy = constants.GatewaySpeedTierUnknownRecoveryStrategy
}
return completion
}
func isGatewayTimeout(err error) bool {
var appErr *pkgerrors.AppError
return stderrors.As(err, &appErr) && appErr != nil && appErr.Code == pkgerrors.CodeGatewayTimeout
}
func (s *Service) logSpeedTierAudit(ctx context.Context, card *model.IotCard, code int, integrationID, result string, err error) {
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
AssetType: constants.AssetTypeIotCard,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
OperationType: constants.AssetAuditOpCardSpeedTier,
OperationDesc: "设置 IoT 卡固定限速档位",
BeforeData: map[string]any{"card": cardSnapshot(card)},
AfterData: map[string]any{
"tier_code": code,
"tier_name": constants.GetGatewaySpeedTierName(code),
"integration_id": integrationID,
},
ResultStatus: result,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
})
}
var _ speedTierIntegrationLog = (*integrationlog.Repository)(nil)