package iot_card import ( "context" "strconv" "github.com/google/uuid" "gorm.io/gorm" infraAudit "github.com/break/junhong_cmp_fiber/internal/infrastructure/audit" "github.com/break/junhong_cmp_fiber/internal/model" assetAuditSvc "github.com/break/junhong_cmp_fiber/internal/service/asset_audit" "github.com/break/junhong_cmp_fiber/pkg/auditcontext" "github.com/break/junhong_cmp_fiber/pkg/auditfailure" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" ) func (s *Service) appendPollingStatusAudit(ctx context.Context, tx *gorm.DB, card *model.IotCard, before, after bool) error { return s.appendCardLifecycleAudit(ctx, tx, constants.AuditActionIotCardPollingStatusUpdated, "更新 IoT 卡轮询开关", constants.AuditResultSuccess, card, map[string]any{"enable_polling": before}, map[string]any{"enable_polling": after}, nil) } func (s *Service) appendBatchPollingStatusAudit(ctx context.Context, tx *gorm.DB, cards []*model.IotCard, enablePolling bool) error { if s.auditWriter == nil { return errors.New(errors.CodeInvalidStatus, "IoT 卡统一审计接缝未配置") } linkage := auditcontext.From(ctx) batchKey := linkage.RequestID if batchKey == "" { batchKey = uuid.NewString() } rootEventID := "evt_" + uuid.NewSHA1(uuid.NameSpaceOID, []byte("iot-card-polling-status:"+batchKey)).String() children := make([]infraAudit.AppendInput, 0, len(cards)) for _, card := range cards { if card == nil || card.ID == 0 { continue } id := strconv.FormatUint(uint64(card.ID), 10) children = append(children, infraAudit.AppendInput{ EventID: "evt_" + uuid.NewSHA1(uuid.NameSpaceOID, []byte(rootEventID+":"+id)).String(), ActionCode: constants.AuditActionIotCardPollingStatusUpdated, Summary: "批量更新 IoT 卡轮询开关", Result: constants.AuditResultSuccess, Resources: []infraAudit.ResourceInput{{ Type: constants.AuditResourceIotCard, ID: &id, Key: infraAudit.IotCardResourceKey(card), DisplayName: card.ICCID, Relation: constants.AuditResourceRelationPrimary, Role: constants.AuditResourceRoleIotCardTarget, IdentitySnapshot: infraAudit.IotCardIdentitySnapshot(card), BeforeData: map[string]any{"enable_polling": card.EnablePolling}, AfterData: map[string]any{"enable_polling": enablePolling}, SubjectVisibility: constants.AuditSubjectResult, SubjectSummary: "IoT 卡轮询开关已更新", }}, }) } return s.auditWriter.AppendBatch(ctx, tx, infraAudit.BatchInput{ Root: infraAudit.AppendInput{ EventID: rootEventID, ActionCode: constants.AuditActionIotCardPollingStatusBatchUpdated, Summary: "批量更新 IoT 卡轮询开关", Result: constants.AuditResultSuccess, BatchTotal: len(children), SuccessCount: len(children), Resources: []infraAudit.ResourceInput{{ Type: constants.AuditResourceIotCardBatch, Key: batchKey, DisplayName: batchKey, Relation: constants.AuditResourceRelationPrimary, Role: constants.AuditResourceRoleIotCardBatch, IdentitySnapshot: map[string]any{"card_count": len(children), "enable_polling": enablePolling}, SubjectVisibility: constants.AuditSubjectInternalOnly, }}, }, Children: children, }) } func (s *Service) recordPollingStatusFailure(ctx context.Context, actionCode, result string, card *model.IotCard, enablePolling bool, businessErr error) { if card == nil || card.ID == 0 || s.db == nil || s.auditWriter == nil { return } err := s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { return s.appendCardLifecycleAudit(ctx, tx, actionCode, "更新 IoT 卡轮询开关失败", result, card, nil, map[string]any{"enable_polling": enablePolling}, businessErr) }) if err == nil { return } linkage := auditcontext.From(ctx) errorCode, _ := assetAuditSvc.BuildErrorInfo(businessErr) auditfailure.RecordSecondaryWriteFailure(actionCode, strconv.FormatUint(uint64(card.ID), 10), linkage.RequestID, linkage.CorrelationID, errorCode, err) }