package device import ( "context" "fmt" "strings" "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) logDeviceAudit(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.AssetTypeDevice } s.assetAuditService.LogOperation(ctx, assetAuditSvc.BuildLog(ctx, p)) } func (s *Service) logDeviceOperation( ctx context.Context, operationType string, operationDesc string, resultStatus string, device *model.Device, beforeData map[string]any, afterData map[string]any, batchTotal int, successCount int, failCount int, err error, ) { if strings.TrimSpace(operationDesc) == "" { operationDesc = operationType } if strings.TrimSpace(resultStatus) == "" { if err != nil { resultStatus = constants.AssetAuditResultFailed } else { resultStatus = constants.AssetAuditResultSuccess } } params := assetAuditSvc.BuildLogParams{ OperationType: operationType, OperationDesc: operationDesc, ResultStatus: resultStatus, BatchTotal: batchTotal, SuccessCount: successCount, FailCount: failCount, } snapshot := deviceSnapshot(device) beforeContent := stripDeviceOperationMeta(beforeData) afterContent := stripDeviceOperationMeta(afterData) beforeContent = ensureDeviceOperationContentMap(beforeContent, beforeData) afterContent = ensureDeviceOperationContentMap(afterContent, afterData) enrichDeviceOperationContent(beforeContent, beforeData) enrichDeviceOperationContent(afterContent, afterData) params.BeforeData, params.AfterData = assetAuditSvc.WrapOperationContent(beforeContent, afterContent, snapshot) if device != nil { params.AssetID = device.ID params.AssetIdentifier = device.VirtualNo } if err != nil { params.ErrorCode, params.ErrorMsg = assetAuditSvc.BuildErrorInfo(err) } s.logDeviceAudit(ctx, params) } func stripDeviceOperationMeta(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 == "devices" || k == "card" || k == "cards" || k == "asset_snapshot" || k == "operation_content" { continue } out[k] = v } if len(out) == 0 { return nil } return out } func ensureDeviceOperationContentMap(content map[string]any, raw map[string]any) map[string]any { if content != nil || len(raw) == 0 { return content } if _, ok := raw["device"].(map[string]any); ok { return make(map[string]any) } if _, ok := raw["card"].(map[string]any); ok { return make(map[string]any) } switch raw["devices"].(type) { case []map[string]any, []any: return make(map[string]any) } switch raw["cards"].(type) { case []map[string]any, []any: return make(map[string]any) } return content } func enrichDeviceOperationContent(content map[string]any, raw map[string]any) { if len(raw) == 0 { return } if deviceRaw, ok := raw["device"].(map[string]any); ok { mergeReadableDeviceFields(content, deviceRaw) } if cardRaw, ok := raw["card"].(map[string]any); ok { mergeReadableCardFields(content, cardRaw) } switch devicesRaw := raw["devices"].(type) { case []map[string]any: deviceIDs, virtualNos := collectDeviceReadableLists(devicesRaw) if len(deviceIDs) > 0 && content["device_ids"] == nil { content["device_ids"] = deviceIDs } if len(virtualNos) > 0 && content["device_virtual_nos"] == nil { content["device_virtual_nos"] = virtualNos } case []any: devices := make([]map[string]any, 0, len(devicesRaw)) for _, item := range devicesRaw { deviceMap, ok := item.(map[string]any) if !ok { continue } devices = append(devices, deviceMap) } deviceIDs, virtualNos := collectDeviceReadableLists(devices) if len(deviceIDs) > 0 && content["device_ids"] == nil { content["device_ids"] = deviceIDs } if len(virtualNos) > 0 && content["device_virtual_nos"] == nil { content["device_virtual_nos"] = virtualNos } } switch cardsRaw := raw["cards"].(type) { case []map[string]any: cardIDs, iccids := collectDeviceAuditCardReadableLists(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 := collectDeviceAuditCardReadableLists(cards) if len(cardIDs) > 0 && content["card_ids"] == nil { content["card_ids"] = cardIDs } if len(iccids) > 0 && content["iccids"] == nil { content["iccids"] = iccids } } } 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 := stringifyDeviceAuditValue(device["virtual_no"]); v != "" { content["device_virtual_no"] = v } } if _, ok := content["device_imei"]; !ok { if v := stringifyDeviceAuditValue(device["imei"]); v != "" { content["device_imei"] = v } } if _, ok := content["device_sn"]; !ok { if v := stringifyDeviceAuditValue(device["sn"]); v != "" { content["device_sn"] = v } } } func mergeReadableCardFields(content map[string]any, card map[string]any) { if len(card) == 0 { return } if _, ok := content["iot_card_id"]; !ok { if v, exists := card["id"]; exists { content["iot_card_id"] = v } } if _, ok := content["iccid"]; !ok { if v := stringifyDeviceAuditValue(card["iccid"]); v != "" { content["iccid"] = v } } } func collectDeviceReadableLists(devices []map[string]any) ([]any, []string) { deviceIDs := make([]any, 0, len(devices)) virtualNos := make([]string, 0, len(devices)) for _, device := range devices { if id, ok := device["id"]; ok { deviceIDs = append(deviceIDs, id) } if virtualNo := stringifyDeviceAuditValue(device["virtual_no"]); virtualNo != "" { virtualNos = append(virtualNos, virtualNo) } } return deviceIDs, virtualNos } func collectDeviceAuditCardReadableLists(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 := stringifyDeviceAuditValue(card["iccid"]); iccid != "" { iccids = append(iccids, iccid) } } return cardIDs, iccids } func stringifyDeviceAuditValue(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 deviceSnapshot(device *model.Device) map[string]any { if device == nil { return nil } return map[string]any{ "id": device.ID, "virtual_no": device.VirtualNo, "imei": device.IMEI, "sn": device.SN, "shop_id": device.ShopID, "status": device.Status, "series_id": device.SeriesID, "enable_polling": device.EnablePolling, "realname_policy": device.RealnamePolicy, } }