TaskCompletedDomainEventHandler.cs 7.47 KB
using Microsoft.Extensions.Logging;
using Rcs.Application.Services;
using Rcs.Domain.Entities;
using Rcs.Domain.Entities.DomainEvents.RobotTask;
using Rcs.Domain.Repositories;
using Rcs.Infrastructure.DB.MsSql;

namespace Rcs.Infrastructure.MessageBus.Handlers.Events.RobotTask
{
    /// <summary>
    /// 任务完成领域事件处理器
    /// 更新库位状态:起点改为空闲,终点改为有货
    /// @author zzy
    /// </summary>
    public class TaskCompletedDomainEventHandler
    {
        private readonly ILogger<TaskCompletedDomainEventHandler> _logger;
        private readonly IRobotTaskRepository _taskRepository;
        private readonly IRobotRepository _robotRepository;
        private readonly IStorageLocationRepository _locationRepository;
        private readonly IWmsTaskCallbackService _wmsTaskCallbackService;
        private readonly AppDbContext _dbContext;

        public TaskCompletedDomainEventHandler(
            ILogger<TaskCompletedDomainEventHandler> logger,
            IRobotTaskRepository taskRepository,
            IRobotRepository robotRepository,
            IStorageLocationRepository locationRepository,
            IWmsTaskCallbackService wmsTaskCallbackService,
            AppDbContext dbContext)
        {   
            _logger = logger;
            _taskRepository = taskRepository;
            _robotRepository = robotRepository;
            _locationRepository = locationRepository;
            _wmsTaskCallbackService = wmsTaskCallbackService;
            _dbContext = dbContext;
        }

        public async System.Threading.Tasks.Task Handle(TaskCompletedDomainEvent domainEvent)
        {
            _logger.LogInformation("TaskCompletedDomainEvent - 任务ID: {TaskId}", domainEvent.TaskId);

            var task = await _taskRepository.GetByIdWithDetailsAsync(domainEvent.TaskId);
            if (task == null)
            {
                _logger.LogWarning("任务不存在: {TaskId}", domainEvent.TaskId);
                return;
            }

            // 更新起点库位为空闲
            if (task.BeginLocationId.HasValue)
            {
                var beginLocation = await _locationRepository.GetByIdAsync(task.BeginLocationId.Value);
                if (beginLocation != null)
                {
                    beginLocation.Status = StorageLocationStatus.Empty;
                    beginLocation.UpdatedAt = DateTime.Now;
                    await _locationRepository.UpdateAsync(beginLocation);
                    _logger.LogInformation("起点库位 {LocationId} 状态更新为空闲", task.BeginLocationId.Value);
                }
            }

            // 更新终点库位为有货
            if (task.EndLocationId.HasValue)
            {
                var endLocation = await _locationRepository.GetByIdAsync(task.EndLocationId.Value);
                if (endLocation != null)
                {
                    endLocation.Status = StorageLocationStatus.Occupied;
                    endLocation.UpdatedAt = DateTime.Now;
                    await _locationRepository.UpdateAsync(endLocation);
                    _logger.LogInformation("终点库位 {LocationId} 状态更新为有货", task.EndLocationId.Value);
                }
            }

            await _locationRepository.SaveChangesAsync();
            // 调用WMS回调接口回传任务完成状态
            // @author zzy
            if (!string.IsNullOrEmpty(task.Source) && task.Source.Equals("WMS", StringComparison.OrdinalIgnoreCase))
            {
                var callbackSuccess = await _wmsTaskCallbackService.SendTaskCompletedAsync(task.TaskCode, 0, "RCS");
                if (!callbackSuccess)
                {
                    _logger.LogWarning("WMS任务状态回传失败,TaskCode: {TaskCode}", task.TaskCode);
                }
            }
            // 释放对应资源
            await ReleaseTaskShelfAndRobotCacheLocationAsync(task);
            // 迁移到历史表
            await ArchiveCompletedTaskAsync(task);
        }

        private async Task ReleaseTaskShelfAndRobotCacheLocationAsync(Rcs.Domain.Entities.RobotTask task)
        {
            var shelfCode = task.ShelfCode;
            var containerId = task.ContainerID;

            if (task.RobotId.HasValue)
            {
                var robot = await _robotRepository.GetByIdFullDataAsync(task.RobotId.Value);
                if (robot != null)
                {
                    var targetCacheLocation = robot.CacheLocations
                        .FirstOrDefault(c => !string.IsNullOrWhiteSpace(shelfCode) && c.LocationCode == shelfCode)
                        ?? robot.CacheLocations.FirstOrDefault(c => !string.IsNullOrWhiteSpace(containerId) && c.ContainerId == containerId);

                    if (targetCacheLocation != null)
                    {
                        targetCacheLocation.ContainerId = null;
                        targetCacheLocation.UpdatedAt = DateTime.Now;
                    }
                }
            }

            task.ShelfCode = null;
            task.UpdatedAt = DateTime.Now;
            await _taskRepository.UpdateAsync(task);
            await _taskRepository.SaveChangesAsync();
        }

        private async System.Threading.Tasks.Task ArchiveCompletedTaskAsync(Rcs.Domain.Entities.RobotTask task)
        {
            var archivedAt = DateTime.Now;

            var taskHistory = new RobotTaskHistory
            {
                TaskId = task.TaskId,
                TaskCode = task.TaskCode,
                TaskName = task.TaskName,
                RobotCode = task.Robot?.RobotCode,
                TaskTemplateCode = task.TaskTemplate?.TemplateCode,
                BeginLocationCode = task.BeginLocation?.LocationCode,
                EndLocationCode = task.EndLocation?.LocationCode,
                Status = task.Status,
                Pause = task.Pause,
                Priority = task.Priority,
                Source = task.Source,
                Relation = task.Relation,
                ShelfCode = task.ShelfCode,
                ContainerID = task.ContainerID,
                ErrorInfo = task.ErrorInfo,
                CreatedAt = task.CreatedAt,
                UpdatedAt = task.UpdatedAt,
                ArchivedAt = archivedAt
            };

            var subTaskHistories = task.SubTasks.Select(subTask => new RobotSubTaskHistory
            {
                SubTaskId = subTask.SubTaskId,
                TaskCode = task.TaskCode,
                RobotCode = subTask.Robot?.RobotCode,
                BeginNodeCode = subTask.BeginNode?.NodeCode ?? string.Empty,
                EndNodeCode = subTask.EndNode?.NodeCode ?? string.Empty,
                Sequence = subTask.Sequence,
                Status = subTask.Status,
                ExecutionCount = subTask.ExecutionCount,
                CreatedAt = subTask.CreatedAt,
                UpdatedAt = subTask.UpdatedAt,
                ArchivedAt = archivedAt
            }).ToList();

            await _dbContext.RobotTaskHistories.AddAsync(taskHistory);
            if (subTaskHistories.Count > 0)
            {
                await _dbContext.RobotSubTaskHistories.AddRangeAsync(subTaskHistories);
            }

            await _taskRepository.DeleteAsync(task);
            await _taskRepository.SaveChangesAsync();

            _logger.LogInformation(
                "任务已迁移至历史表: TaskId={TaskId}, TaskCode={TaskCode}, SubTaskCount={SubTaskCount}",
                task.TaskId,
                task.TaskCode,
                subTaskHistories.Count);
        }
    }
}