Files
junhong_cmp_fiber/internal/service/device/audit.go
huang 29d3d48dbe
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m48s
黑魔法
2026-05-06 16:59:10 +08:00

288 lines
7.5 KiB
Go

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,
}
}