package iot_card import ( "context" "fmt" "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/constants" ) // AssetAuditService 资产审计服务接口。 type AssetAuditService interface { LogOperation(ctx context.Context, log *model.AssetOperationLog) } func (s *Service) logCardAudit(ctx context.Context, p assetAuditSvc.BuildLogParams) { if s == nil || s.assetAuditService == nil { return } if p.Operator.Type == "" { p.Operator = assetAuditSvc.OperatorFromContext(ctx) } if p.AssetType == "" { p.AssetType = constants.AssetTypeIotCard } p.BeforeData, p.AfterData = normalizeCardAuditPayload(p.BeforeData, p.AfterData) s.assetAuditService.LogOperation(ctx, assetAuditSvc.BuildLog(ctx, p)) } func (s *StopResumeService) logCardAudit(ctx context.Context, p assetAuditSvc.BuildLogParams) { if s == nil || s.assetAuditService == nil { return } if p.Operator.Type == "" { p.Operator = assetAuditSvc.OperatorFromContext(ctx) } if p.AssetType == "" { p.AssetType = constants.AssetTypeIotCard } p.BeforeData, p.AfterData = normalizeCardAuditPayload(p.BeforeData, p.AfterData) s.assetAuditService.LogOperation(ctx, assetAuditSvc.BuildLog(ctx, p)) } func normalizeCardAuditPayload(beforeData, afterData map[string]any) (map[string]any, map[string]any) { snapshot := map[string]any(nil) if raw, ok := beforeData["card"]; ok { if m, ok := raw.(map[string]any); ok { snapshot = m } } if snapshot == nil { if raw, ok := afterData["card"]; ok { if m, ok := raw.(map[string]any); ok { snapshot = m } } } beforeContent := stripCardOperationMeta(beforeData) afterContent := stripCardOperationMeta(afterData) beforeContent = ensureCardOperationContentMap(beforeContent, beforeData) afterContent = ensureCardOperationContentMap(afterContent, afterData) enrichCardOperationContent(beforeContent, beforeData) enrichCardOperationContent(afterContent, afterData) return assetAuditSvc.WrapOperationContent(beforeContent, afterContent, snapshot) } func stripCardOperationMeta(data map[string]any) map[string]any { if len(data) == 0 { return nil } out := make(map[string]any, len(data)) for k, v := range data { if k == "device" || k == "card" || k == "cards" || k == "asset_snapshot" || k == "operation_content" { continue } out[k] = v } if len(out) == 0 { return nil } return out } func ensureCardOperationContentMap(content map[string]any, raw map[string]any) map[string]any { if content != nil || len(raw) == 0 { return content } if _, ok := raw["card"].(map[string]any); ok { return make(map[string]any) } if _, ok := raw["device"].(map[string]any); ok { return make(map[string]any) } switch raw["cards"].(type) { case []map[string]any, []any: return make(map[string]any) default: return content } } func enrichCardOperationContent(content map[string]any, raw map[string]any) { if len(raw) == 0 { return } if cardRaw, ok := raw["card"].(map[string]any); ok { mergeReadableCardFields(content, cardRaw) } if deviceRaw, ok := raw["device"].(map[string]any); ok { mergeReadableDeviceFields(content, deviceRaw) } switch cardsRaw := raw["cards"].(type) { case []map[string]any: cardIDs, iccids := collectCardReadableLists(cardsRaw) if len(cardIDs) > 0 && content["card_ids"] == nil { content["card_ids"] = cardIDs } if len(iccids) > 0 && content["iccids"] == nil { content["iccids"] = iccids } case []any: cards := make([]map[string]any, 0, len(cardsRaw)) for _, item := range cardsRaw { cardMap, ok := item.(map[string]any) if !ok { continue } cards = append(cards, cardMap) } cardIDs, iccids := collectCardReadableLists(cards) if len(cardIDs) > 0 && content["card_ids"] == nil { content["card_ids"] = cardIDs } if len(iccids) > 0 && content["iccids"] == nil { content["iccids"] = iccids } } } func mergeReadableCardFields(content map[string]any, card map[string]any) { if len(card) == 0 { return } if _, ok := content["card_id"]; !ok { if v, exists := card["id"]; exists { content["card_id"] = v } } if _, ok := content["iccid"]; !ok { if v := stringifyCardAuditValue(card["iccid"]); v != "" { content["iccid"] = v } } if _, ok := content["device_virtual_no"]; !ok { if v := stringifyCardAuditValue(card["device_virtual_no"]); v != "" { content["device_virtual_no"] = v } } } func mergeReadableDeviceFields(content map[string]any, device map[string]any) { if len(device) == 0 { return } if _, ok := content["device_id"]; !ok { if v, exists := device["id"]; exists { content["device_id"] = v } } if _, ok := content["device_virtual_no"]; !ok { if v := stringifyCardAuditValue(device["virtual_no"]); v != "" { content["device_virtual_no"] = v } } if _, ok := content["device_imei"]; !ok { if v := stringifyCardAuditValue(device["imei"]); v != "" { content["device_imei"] = v } } if _, ok := content["device_sn"]; !ok { if v := stringifyCardAuditValue(device["sn"]); v != "" { content["device_sn"] = v } } } func collectCardReadableLists(cards []map[string]any) ([]any, []string) { cardIDs := make([]any, 0, len(cards)) iccids := make([]string, 0, len(cards)) for _, card := range cards { if id, ok := card["id"]; ok { cardIDs = append(cardIDs, id) } if iccid := stringifyCardAuditValue(card["iccid"]); iccid != "" { iccids = append(iccids, iccid) } } return cardIDs, iccids } func stringifyCardAuditValue(v any) string { switch vv := v.(type) { case string: return vv case fmt.Stringer: return vv.String() default: if vv == nil { return "" } return fmt.Sprint(vv) } } func cardSnapshot(card *model.IotCard) map[string]any { if card == nil { return nil } return map[string]any{ "id": card.ID, "iccid": card.ICCID, "device_virtual_no": card.DeviceVirtualNo, "shop_id": card.ShopID, "status": card.Status, "series_id": card.SeriesID, "enable_polling": card.EnablePolling, "realname_policy": card.RealnamePolicy, "real_name_status": card.RealNameStatus, "network_status": card.NetworkStatus, "stop_reason": card.StopReason, } }