操作日志
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m10s

This commit is contained in:
2026-04-27 12:16:38 +08:00
parent 95104100c9
commit cb75b5668b
33 changed files with 3860 additions and 112 deletions

View File

@@ -8,6 +8,7 @@ import (
"github.com/break/junhong_cmp_fiber/internal/gateway"
"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/internal/store"
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
"github.com/break/junhong_cmp_fiber/pkg/constants"
@@ -64,6 +65,7 @@ type Service struct {
deviceSimBindingStore *postgres.DeviceSimBindingStore
redis *redis.Client
assetIdentifierStore *postgres.AssetIdentifierStore
assetAuditService AssetAuditService
}
func New(
@@ -76,6 +78,7 @@ func New(
packageSeriesStore *postgres.PackageSeriesStore,
gatewayClient *gateway.Client,
logger *zap.Logger,
assetAuditService AssetAuditService,
) *Service {
return &Service{
db: db,
@@ -87,6 +90,7 @@ func New(
packageSeriesStore: packageSeriesStore,
gatewayClient: gatewayClient,
logger: logger,
assetAuditService: assetAuditService,
}
}
@@ -341,11 +345,37 @@ func (s *Service) toStandaloneResponse(card *model.IotCard, shopMap map[uint]str
func (s *Service) AllocateCards(ctx context.Context, req *dto.AllocateStandaloneCardsRequest, operatorID uint, operatorShopID *uint) (*dto.AllocateStandaloneCardsResponse, error) {
if err := s.validateDirectSubordinate(ctx, operatorShopID, req.ToShopID); err != nil {
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardAllocate,
OperationDesc: "单卡分配被拒绝",
ResultStatus: constants.AssetAuditResultDenied,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AfterData: map[string]any{
"to_shop_id": req.ToShopID,
"selection_type": req.SelectionType,
"requested_count": len(req.ICCIDs),
},
})
return nil, err
}
cards, err := s.getCardsForAllocation(ctx, req, operatorShopID)
if err != nil {
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardAllocate,
OperationDesc: "单卡分配执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AfterData: map[string]any{
"to_shop_id": req.ToShopID,
"selection_type": req.SelectionType,
"requested_count": len(req.ICCIDs),
},
})
return nil, err
}
@@ -401,6 +431,19 @@ func (s *Service) AllocateCards(ctx context.Context, req *dto.AllocateStandalone
}
if len(cardIDs) == 0 {
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardAllocate,
OperationDesc: "单卡分配被拒绝",
ResultStatus: constants.AssetAuditResultDenied,
ErrorMsg: "无可分配卡",
BatchTotal: len(cards),
FailCount: len(failedItems),
AfterData: map[string]any{
"to_shop_id": req.ToShopID,
"failed_items": failedItems,
"selection_type": req.SelectionType,
},
})
return &dto.AllocateStandaloneCardsResponse{
TotalCount: len(cards),
SuccessCount: 0,
@@ -426,6 +469,21 @@ func (s *Service) AllocateCards(ctx context.Context, req *dto.AllocateStandalone
})
if err != nil {
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardAllocate,
OperationDesc: "单卡分配执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
BatchTotal: len(cards),
SuccessCount: len(cardIDs),
FailCount: len(failedItems),
AfterData: map[string]any{
"to_shop_id": req.ToShopID,
"failed_items": failedItems,
},
})
return nil, err
}
@@ -436,6 +494,32 @@ func (s *Service) AllocateCards(ctx context.Context, req *dto.AllocateStandalone
}
}
beforeData := make([]map[string]any, 0, len(cards))
for _, card := range cards {
beforeData = append(beforeData, map[string]any{
"id": card.ID,
"iccid": card.ICCID,
"shop_id": card.ShopID,
"status": card.Status,
})
}
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardAllocate,
OperationDesc: "单卡分配",
ResultStatus: constants.AssetAuditResultSuccess,
BatchTotal: len(cards),
SuccessCount: len(cardIDs),
FailCount: len(failedItems),
BeforeData: map[string]any{
"cards": beforeData,
},
AfterData: map[string]any{
"to_shop_id": req.ToShopID,
"new_status": newStatus,
"failed_items": failedItems,
},
})
return &dto.AllocateStandaloneCardsResponse{
TotalCount: len(cards),
SuccessCount: len(cardIDs),
@@ -449,6 +533,18 @@ func (s *Service) RecallCards(ctx context.Context, req *dto.RecallStandaloneCard
// 1. 查询卡列表
cards, err := s.getCardsForRecall(ctx, req)
if err != nil {
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRecall,
OperationDesc: "单卡回收执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AfterData: map[string]any{
"selection_type": req.SelectionType,
"requested_count": len(req.ICCIDs),
},
})
return nil, err
}
@@ -535,6 +631,18 @@ func (s *Service) RecallCards(ctx context.Context, req *dto.RecallStandaloneCard
}
if len(cardIDs) == 0 {
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRecall,
OperationDesc: "单卡回收被拒绝",
ResultStatus: constants.AssetAuditResultDenied,
ErrorMsg: "无可回收卡",
BatchTotal: len(cards),
FailCount: len(failedItems),
AfterData: map[string]any{
"failed_items": failedItems,
"selection_type": req.SelectionType,
},
})
return &dto.RecallStandaloneCardsResponse{
TotalCount: len(cards),
SuccessCount: 0,
@@ -570,6 +678,20 @@ func (s *Service) RecallCards(ctx context.Context, req *dto.RecallStandaloneCard
})
if err != nil {
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRecall,
OperationDesc: "单卡回收执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
BatchTotal: len(cards),
SuccessCount: len(cardIDs),
FailCount: len(failedItems),
AfterData: map[string]any{
"failed_items": failedItems,
},
})
return nil, err
}
@@ -580,6 +702,32 @@ func (s *Service) RecallCards(ctx context.Context, req *dto.RecallStandaloneCard
}
}
beforeData := make([]map[string]any, 0, len(successCards))
for _, card := range successCards {
beforeData = append(beforeData, map[string]any{
"id": card.ID,
"iccid": card.ICCID,
"shop_id": card.ShopID,
"status": card.Status,
})
}
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRecall,
OperationDesc: "单卡回收",
ResultStatus: constants.AssetAuditResultSuccess,
BatchTotal: len(cards),
SuccessCount: len(cardIDs),
FailCount: len(failedItems),
BeforeData: map[string]any{
"cards": beforeData,
},
AfterData: map[string]any{
"to_shop_id": newShopID,
"new_status": newStatus,
"failed_items": failedItems,
},
})
return &dto.RecallStandaloneCardsResponse{
TotalCount: len(cards),
SuccessCount: len(cardIDs),
@@ -750,10 +898,35 @@ func (s *Service) buildRecallRecords(successCards []*model.IotCard, toShopID *ui
func (s *Service) BatchSetSeriesBinding(ctx context.Context, req *dto.BatchSetCardSeriesBindngRequest, operatorShopID *uint) (*dto.BatchSetCardSeriesBindngResponse, error) {
cards, err := s.iotCardStore.GetByICCIDs(ctx, req.ICCIDs)
if err != nil {
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardSeriesBinding,
OperationDesc: "卡系列绑定执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
BatchTotal: len(req.ICCIDs),
AfterData: map[string]any{
"series_id": req.SeriesID,
"iccids": req.ICCIDs,
},
})
return nil, err
}
if len(cards) == 0 {
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardSeriesBinding,
OperationDesc: "卡系列绑定被拒绝",
ResultStatus: constants.AssetAuditResultDenied,
ErrorMsg: "卡不存在",
BatchTotal: len(req.ICCIDs),
FailCount: len(req.ICCIDs),
AfterData: map[string]any{
"series_id": req.SeriesID,
"iccids": req.ICCIDs,
},
})
return &dto.BatchSetCardSeriesBindngResponse{
SuccessCount: 0,
FailCount: len(req.ICCIDs),
@@ -772,12 +945,53 @@ func (s *Service) BatchSetSeriesBinding(ctx context.Context, req *dto.BatchSetCa
packageSeries, err = s.packageSeriesStore.GetByID(ctx, req.SeriesID)
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, errors.New(errors.CodeNotFound, "套餐系列不存在或已禁用")
denyErr := errors.New(errors.CodeNotFound, "套餐系列不存在或已禁用")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(denyErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardSeriesBinding,
OperationDesc: "卡系列绑定被拒绝",
ResultStatus: constants.AssetAuditResultDenied,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
BatchTotal: len(req.ICCIDs),
AfterData: map[string]any{
"series_id": req.SeriesID,
"iccids": req.ICCIDs,
},
})
return nil, denyErr
}
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardSeriesBinding,
OperationDesc: "卡系列绑定执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
BatchTotal: len(req.ICCIDs),
AfterData: map[string]any{
"series_id": req.SeriesID,
"iccids": req.ICCIDs,
},
})
return nil, err
}
if packageSeries.Status != 1 {
return nil, errors.New(errors.CodeInvalidParam, "套餐系列不存在或已禁用")
denyErr := errors.New(errors.CodeInvalidParam, "套餐系列不存在或已禁用")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(denyErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardSeriesBinding,
OperationDesc: "卡系列绑定被拒绝",
ResultStatus: constants.AssetAuditResultDenied,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
BatchTotal: len(req.ICCIDs),
AfterData: map[string]any{
"series_id": req.SeriesID,
"iccids": req.ICCIDs,
},
})
return nil, denyErr
}
}
@@ -836,10 +1050,67 @@ func (s *Service) BatchSetSeriesBinding(ctx context.Context, req *dto.BatchSetCa
seriesIDPtr = &req.SeriesID
}
if err := s.iotCardStore.BatchUpdateSeriesID(ctx, successCardIDs, seriesIDPtr); err != nil {
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardSeriesBinding,
OperationDesc: "卡系列绑定执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
BatchTotal: len(req.ICCIDs),
SuccessCount: len(successCardIDs),
FailCount: len(failedItems),
AfterData: map[string]any{
"series_id": req.SeriesID,
"success_ids": successCardIDs,
"failed_items": failedItems,
},
})
return nil, err
}
}
resultStatus := constants.AssetAuditResultSuccess
operationDesc := "批量设置卡系列绑定"
errorMsg := ""
if len(successCardIDs) == 0 && len(failedItems) > 0 {
resultStatus = constants.AssetAuditResultDenied
operationDesc = "卡系列绑定被拒绝"
errorMsg = "无可操作卡"
}
beforeCards := make([]map[string]any, 0, len(successCardIDs))
successSet := make(map[uint]struct{}, len(successCardIDs))
for _, id := range successCardIDs {
successSet[id] = struct{}{}
}
for _, card := range cards {
if _, ok := successSet[card.ID]; !ok {
continue
}
beforeCards = append(beforeCards, map[string]any{
"id": card.ID,
"iccid": card.ICCID,
"series_id": card.SeriesID,
})
}
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardSeriesBinding,
OperationDesc: operationDesc,
ResultStatus: resultStatus,
ErrorMsg: errorMsg,
BatchTotal: len(req.ICCIDs),
SuccessCount: len(successCardIDs),
FailCount: len(failedItems),
BeforeData: map[string]any{
"cards": beforeCards,
},
AfterData: map[string]any{
"series_id": req.SeriesID,
"success_ids": successCardIDs,
"failed_items": failedItems,
},
})
return &dto.BatchSetCardSeriesBindngResponse{
SuccessCount: len(successCardIDs),
FailCount: len(failedItems),
@@ -1052,19 +1323,74 @@ func (s *Service) UpdatePollingStatus(ctx context.Context, cardID uint, enablePo
card, err := s.iotCardStore.GetByID(ctx, cardID)
if err != nil {
if err == gorm.ErrRecordNotFound {
return errors.New(errors.CodeNotFound, "IoT卡不存在")
denyErr := errors.New(errors.CodeNotFound, "IoT卡不存在")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(denyErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardPollingStatus,
OperationDesc: "更新卡轮询状态被拒绝",
ResultStatus: constants.AssetAuditResultDenied,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: cardID,
AssetIdentifier: "",
AfterData: map[string]any{
"enable_polling": enablePolling,
},
})
return denyErr
}
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardPollingStatus,
OperationDesc: "更新卡轮询状态执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: cardID,
AfterData: map[string]any{
"enable_polling": enablePolling,
},
})
return err
}
// 检查是否需要更新
if card.EnablePolling == enablePolling {
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardPollingStatus,
OperationDesc: "更新卡轮询状态",
ResultStatus: constants.AssetAuditResultSuccess,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: map[string]any{
"enable_polling": card.EnablePolling,
},
AfterData: map[string]any{
"enable_polling": enablePolling,
},
})
return nil // 状态未变化
}
// 更新数据库
card.EnablePolling = enablePolling
if err := s.iotCardStore.Update(ctx, card); err != nil {
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardPollingStatus,
OperationDesc: "更新卡轮询状态执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: map[string]any{
"enable_polling": !enablePolling,
},
AfterData: map[string]any{
"enable_polling": enablePolling,
},
})
return err
}
@@ -1082,6 +1408,20 @@ func (s *Service) UpdatePollingStatus(ctx context.Context, cardID uint, enablePo
}
}
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardPollingStatus,
OperationDesc: "更新卡轮询状态",
ResultStatus: constants.AssetAuditResultSuccess,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: map[string]any{
"enable_polling": !enablePolling,
},
AfterData: map[string]any{
"enable_polling": enablePolling,
},
})
return nil
}
@@ -1093,6 +1433,21 @@ func (s *Service) BatchUpdatePollingStatus(ctx context.Context, cardIDs []uint,
// 批量更新数据库
if err := s.iotCardStore.BatchUpdatePollingStatus(ctx, cardIDs, enablePolling); err != nil {
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardPollingStatus,
OperationDesc: "批量更新卡轮询状态执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
BatchTotal: len(cardIDs),
FailCount: len(cardIDs),
AfterData: map[string]any{
"card_ids": cardIDs,
"enable_polling": enablePolling,
"trigger_source": "batch",
},
})
return err
}
@@ -1112,6 +1467,19 @@ func (s *Service) BatchUpdatePollingStatus(ctx context.Context, cardIDs []uint,
}
}
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardPollingStatus,
OperationDesc: "批量更新卡轮询状态",
ResultStatus: constants.AssetAuditResultSuccess,
BatchTotal: len(cardIDs),
SuccessCount: len(cardIDs),
AfterData: map[string]any{
"card_ids": cardIDs,
"enable_polling": enablePolling,
"trigger_source": "batch",
},
})
return nil
}
@@ -1120,12 +1488,42 @@ func (s *Service) DeleteCard(ctx context.Context, cardID uint) error {
card, err := s.iotCardStore.GetByID(ctx, cardID)
if err != nil {
if err == gorm.ErrRecordNotFound {
return errors.New(errors.CodeNotFound, "IoT卡不存在")
denyErr := errors.New(errors.CodeNotFound, "IoT卡不存在")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(denyErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardDelete,
OperationDesc: "删除卡被拒绝",
ResultStatus: constants.AssetAuditResultDenied,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: cardID,
})
return denyErr
}
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardDelete,
OperationDesc: "删除卡执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: cardID,
})
return err
}
if err := s.iotCardStore.Delete(ctx, cardID); err != nil {
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardDelete,
OperationDesc: "删除卡执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: cardSnapshot(card),
})
return err
}
@@ -1139,6 +1537,18 @@ func (s *Service) DeleteCard(ctx context.Context, cardID uint) error {
s.pollingCallback.OnCardDeleted(ctx, cardID)
}
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardDelete,
OperationDesc: "删除卡",
ResultStatus: constants.AssetAuditResultSuccess,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: cardSnapshot(card),
AfterData: map[string]any{
"deleted": true,
},
})
return nil
}
@@ -1147,9 +1557,39 @@ func (s *Service) BatchDeleteCards(ctx context.Context, cardIDs []uint) error {
if len(cardIDs) == 0 {
return nil
}
cards, queryErr := s.iotCardStore.GetByIDs(ctx, cardIDs)
if queryErr != nil {
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(queryErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardBatchDelete,
OperationDesc: "批量删除卡执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
BatchTotal: len(cardIDs),
FailCount: len(cardIDs),
AfterData: map[string]any{
"card_ids": cardIDs,
},
})
return queryErr
}
// 批量软删除
if err := s.iotCardStore.BatchDelete(ctx, cardIDs); err != nil {
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardBatchDelete,
OperationDesc: "批量删除卡执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
BatchTotal: len(cardIDs),
FailCount: len(cardIDs),
AfterData: map[string]any{
"card_ids": cardIDs,
},
})
return err
}
@@ -1161,6 +1601,24 @@ func (s *Service) BatchDeleteCards(ctx context.Context, cardIDs []uint) error {
s.pollingCallback.OnCardDeleted(ctx, cardID)
}
}
beforeCards := make([]map[string]any, 0, len(cards))
for _, card := range cards {
beforeCards = append(beforeCards, cardSnapshot(card))
}
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardBatchDelete,
OperationDesc: "批量删除卡",
ResultStatus: constants.AssetAuditResultSuccess,
BatchTotal: len(cardIDs),
SuccessCount: len(cardIDs),
BeforeData: map[string]any{
"cards": beforeCards,
},
AfterData: map[string]any{
"card_ids": cardIDs,
"deleted": true,
},
})
return nil
}
@@ -1171,19 +1629,75 @@ func (s *Service) UpdateRealnamePolicy(ctx context.Context, cardID uint, realnam
card, err := s.iotCardStore.GetByID(ctx, cardID)
if err != nil {
if err == gorm.ErrRecordNotFound {
return errors.New(errors.CodeNotFound, "IoT卡不存在")
denyErr := errors.New(errors.CodeNotFound, "IoT卡不存在")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(denyErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRealnamePolicy,
OperationDesc: "更新卡实名认证策略被拒绝",
ResultStatus: constants.AssetAuditResultDenied,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: cardID,
AfterData: map[string]any{
"realname_policy": realnamePolicy,
},
})
return denyErr
}
return errors.Wrap(errors.CodeDatabaseError, err, "查询IoT卡失败")
wrapErr := errors.Wrap(errors.CodeDatabaseError, err, "查询IoT卡失败")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(wrapErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRealnamePolicy,
OperationDesc: "更新卡实名认证策略执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: cardID,
AfterData: map[string]any{
"realname_policy": realnamePolicy,
},
})
return wrapErr
}
// 幂等检查
if card.RealnamePolicy == realnamePolicy {
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRealnamePolicy,
OperationDesc: "更新卡实名认证策略",
ResultStatus: constants.AssetAuditResultSuccess,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: map[string]any{
"realname_policy": card.RealnamePolicy,
},
AfterData: map[string]any{
"realname_policy": realnamePolicy,
},
})
return nil
}
// 更新数据库
if err := s.iotCardStore.UpdateRealnamePolicy(ctx, cardID, realnamePolicy); err != nil {
return errors.Wrap(errors.CodeDatabaseError, err, "更新实名认证策略失败")
wrapErr := errors.Wrap(errors.CodeDatabaseError, err, "更新实名认证策略失败")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(wrapErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRealnamePolicy,
OperationDesc: "更新卡实名认证策略执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: map[string]any{
"realname_policy": card.RealnamePolicy,
},
AfterData: map[string]any{
"realname_policy": realnamePolicy,
},
})
return wrapErr
}
s.logger.Info("更新卡实名认证策略",
@@ -1191,6 +1705,20 @@ func (s *Service) UpdateRealnamePolicy(ctx context.Context, cardID uint, realnam
zap.String("realname_policy", realnamePolicy),
)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRealnamePolicy,
OperationDesc: "更新卡实名认证策略",
ResultStatus: constants.AssetAuditResultSuccess,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: map[string]any{
"realname_policy": card.RealnamePolicy,
},
AfterData: map[string]any{
"realname_policy": realnamePolicy,
},
})
return nil
}
@@ -1199,15 +1727,54 @@ func (s *Service) UpdateRealnamePolicy(ctx context.Context, cardID uint, realnam
func (s *Service) ManualUpdateRealnameStatus(ctx context.Context, cardID uint, realNameStatus int) (*model.IotCard, error) {
if realNameStatus != constants.RealNameStatusNotVerified &&
realNameStatus != constants.RealNameStatusVerified {
return nil, errors.New(errors.CodeInvalidParam, "无效的实名状态")
denyErr := errors.New(errors.CodeInvalidParam, "无效的实名状态")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(denyErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRealnameStatus,
OperationDesc: "手动更新卡实名状态被拒绝",
ResultStatus: constants.AssetAuditResultDenied,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: cardID,
AfterData: map[string]any{
"real_name_status": realNameStatus,
},
})
return nil, denyErr
}
card, err := s.iotCardStore.GetByID(ctx, cardID)
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, errors.New(errors.CodeNotFound, "IoT卡不存在")
denyErr := errors.New(errors.CodeNotFound, "IoT卡不存在")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(denyErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRealnameStatus,
OperationDesc: "手动更新卡实名状态被拒绝",
ResultStatus: constants.AssetAuditResultDenied,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: cardID,
AfterData: map[string]any{
"real_name_status": realNameStatus,
},
})
return nil, denyErr
}
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询IoT卡失败")
wrapErr := errors.Wrap(errors.CodeDatabaseError, err, "查询IoT卡失败")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(wrapErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRealnameStatus,
OperationDesc: "手动更新卡实名状态执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: cardID,
AfterData: map[string]any{
"real_name_status": realNameStatus,
},
})
return nil, wrapErr
}
oldStatus := card.RealNameStatus
@@ -1227,12 +1794,46 @@ func (s *Service) ManualUpdateRealnameStatus(ctx context.Context, cardID uint, r
}
if err := s.iotCardStore.UpdateFields(ctx, cardID, fields); err != nil {
return nil, errors.Wrap(errors.CodeDatabaseError, err, "更新卡实名状态失败")
wrapErr := errors.Wrap(errors.CodeDatabaseError, err, "更新卡实名状态失败")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(wrapErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRealnameStatus,
OperationDesc: "手动更新卡实名状态执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: map[string]any{
"real_name_status": oldStatus,
},
AfterData: map[string]any{
"real_name_status": realNameStatus,
},
})
return nil, wrapErr
}
freshCard, err := s.iotCardStore.GetByID(ctx, cardID)
if err != nil {
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询更新后的IoT卡失败")
wrapErr := errors.Wrap(errors.CodeDatabaseError, err, "查询更新后的IoT卡失败")
errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(wrapErr)
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRealnameStatus,
OperationDesc: "手动更新卡实名状态执行失败",
ResultStatus: constants.AssetAuditResultFailed,
ErrorCode: errorCode,
ErrorMsg: errorMsg,
AssetID: card.ID,
AssetIdentifier: card.ICCID,
BeforeData: map[string]any{
"real_name_status": oldStatus,
},
AfterData: map[string]any{
"real_name_status": realNameStatus,
},
})
return nil, wrapErr
}
if statusChanged {
@@ -1249,6 +1850,22 @@ func (s *Service) ManualUpdateRealnameStatus(ctx context.Context, cardID uint, r
zap.Int("new_status", realNameStatus),
zap.Uint("operator_id", middleware.GetUserIDFromContext(ctx)))
s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
OperationType: constants.AssetAuditOpCardRealnameStatus,
OperationDesc: "手动更新卡实名状态",
ResultStatus: constants.AssetAuditResultSuccess,
AssetID: freshCard.ID,
AssetIdentifier: freshCard.ICCID,
BeforeData: map[string]any{
"real_name_status": oldStatus,
"first_realname_at": card.FirstRealnameAt,
},
AfterData: map[string]any{
"real_name_status": freshCard.RealNameStatus,
"first_realname_at": freshCard.FirstRealnameAt,
},
})
return freshCard, nil
}