CopyMapCommandHandler.cs 6.01 KB
using MassTransit;
using Microsoft.Extensions.Logging;
using Rcs.Application.Common;
using Rcs.Application.MessageBus.Commands;
using Rcs.Application.MessageBus.Responses;
using Rcs.Domain.Entities;
using Rcs.Domain.Repositories;

namespace Rcs.Infrastructure.MessageBus.Handlers.Commands;

public class CopyMapCommandHandler : IConsumer<CopyMapCommand>
{
    private readonly ILogger<CopyMapCommandHandler> _logger;
    private readonly IMapRepository _mapRepository;
    private readonly IMapNodeRepository _mapNodeRepository;

    public CopyMapCommandHandler(
        ILogger<CopyMapCommandHandler> logger,
        IMapRepository mapRepository,
        IMapNodeRepository mapNodeRepository)
    {
        _logger = logger;
        _mapRepository = mapRepository;
        _mapNodeRepository = mapNodeRepository;
    }

    public async Task Consume(ConsumeContext<CopyMapCommand> context)
    {
        var command = context.Message;

        try
        {
            var sourceMap = await _mapRepository.GetWithFullDetailsAsync(
                command.MapId,
                context.CancellationToken);

            if (sourceMap == null)
            {
                throw new InvalidOperationException($"未找到地图ID为 {command.MapId} 的地图");
            }

            var suffix = $"_C{DateTime.Now:MMddHHmmss}";
            var maxBaseLength = 100 - suffix.Length;
            var baseCode = sourceMap.MapCode.Length > maxBaseLength 
                ? sourceMap.MapCode.Substring(0, maxBaseLength) 
                : sourceMap.MapCode;
            var newMapCode = $"{baseCode}{suffix}";

            var newMap = Map.Create(
                newMapCode,
                $"{sourceMap.MapName} (副本)",
                sourceMap.MapType,
                sourceMap.Version,
                sourceMap.Description,
                sourceMap.Active
            );

            await _mapRepository.AddAsync(newMap, context.CancellationToken);

            // 建立源节点 NodeId 到 NodeCode 的映射
            var sourceNodeIdToCodeMap = sourceMap.MapNodes.ToDictionary(n => n.NodeId, n => n.NodeCode);

            foreach (var node in sourceMap.MapNodes)
            {
                var newNode = new MapNode
                {
                    NodeId = Guid.NewGuid(),
                    MapId = newMap.MapId,
                    NodeCode = node.NodeCode,
                    NodeName = node.NodeName,
                    Description = node.Description,
                    X = node.X,
                    Y = node.Y,
                    Theta = node.Theta,
                    IsReverseParking = node.IsReverseParking,
                    AllowRotate = node.AllowRotate,
                    MaxCoordinateOffset = node.MaxCoordinateOffset,
                    Type = node.Type,
                    Metadata = node.Metadata != null ? new Dictionary<string, object>(node.Metadata) : null,
                    CreatedAt = DateTime.Now,
                    Active = node.Active
                };

                newMap.MapNodes.Add(newNode);
            }

            foreach (var edge in sourceMap.MapEdges)
            {
                // 通过源边的 FromNode/ToNode (NodeId) 找到源节点的 NodeCode
                var fromNodeCode = sourceNodeIdToCodeMap.GetValueOrDefault(edge.FromNode);
                var toNodeCode = sourceNodeIdToCodeMap.GetValueOrDefault(edge.ToNode);

                // 通过 NodeCode 找到新节点的 NodeId
                var newFromNodeId = newMap.MapNodes.FirstOrDefault(n => n.NodeCode == fromNodeCode)?.NodeId ?? Guid.Empty;
                var newToNodeId = newMap.MapNodes.FirstOrDefault(n => n.NodeCode == toNodeCode)?.NodeId ?? Guid.Empty;

                var newEdge = new MapEdge
                {
                    EdgeId = Guid.NewGuid(),
                    MapId = newMap.MapId,
                    EdgeCode = edge.EdgeCode,
                    FromNode = newFromNodeId,
                    ToNode = newToNodeId,
                    EdgeName = edge.EdgeName,
                    Length = edge.Length,
                    Cost = edge.Cost,
                    CreatedAt = DateTime.Now,
                    Active = edge.Active,
                    IsCurve = edge.IsCurve,
                    Radius = edge.Radius,
                    CenterX = edge.CenterX,
                    CenterY = edge.CenterY,
                    Degree = edge.Degree,
                    ControlPoints = edge.ControlPoints != null ? new List<Point>(edge.ControlPoints.Select(p => new Point { X = p.X, Y = p.Y })) : null,
                    Weights = edge.Weights != null ? new List<double>(edge.Weights) : null,
                    Knots = edge.Knots != null ? new List<double>(edge.Knots) : null,
                    Regress = edge.Regress,
                    MaxCoordinateOffset = edge.MaxCoordinateOffset,
                    MaxAngleDeviation = edge.MaxAngleDeviation,
                    MaxSpeed = edge.MaxSpeed
                };

                newMap.MapEdges.Add(newEdge);
            }

            foreach (var resource in sourceMap.MapResources)
            {
                var newResource = new MapResource
                {
                    ResourceId = Guid.NewGuid(),
                    MapId = newMap.MapId,
                    ResourceCode = resource.ResourceCode,
                    ResourceName = resource.ResourceName,
                    Type = resource.Type,
                    Capacity = resource.Capacity,
                    LocationCoordinates = resource.LocationCoordinates != null ? new List<Point>(resource.LocationCoordinates.Select(p => new Point { X = p.X, Y = p.Y })) : null,
                    CreatedAt = DateTime.Now,
                    Active = resource.Active
                };

                newMap.MapResources.Add(newResource);
            }

            await _mapRepository.AddAsync(newMap, context.CancellationToken);

            await context.RespondAsync(ApiResponse.Successful());
        }
        catch (Exception ex)
        {
            await context.RespondAsync(ApiResponse.Failed(ex.Message));
        }
    }
}