wanshenmean
5 天以前 5171d3f59b89389bf75293afd210cfa6de4ccff7
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -1,16 +1,26 @@
using AutoMapper;
using Microsoft.AspNetCore.Components.Forms;
using Mapster;
using MapsterMapper;
using Microsoft.Extensions.Configuration;
using SqlSugar;
using System.DirectoryServices.Protocols;
using System.Text.Json;
using WIDESEA_Common.Constants;
using WIDESEA_Common.LocationEnum;
using WIDESEA_Common.StockEnum;
using WIDESEA_Common.TaskEnum;
using WIDESEA_Common.WareHouseEnum;
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_Core.Core;
using WIDESEA_Core.Enums;
using WIDESEA_Core.Helper;
using WIDESEA_DTO;
using WIDESEA_DTO.GradingMachine;
using WIDESEA_DTO.MES;
using WIDESEA_DTO.Stock;
using WIDESEA_DTO.Task;
using WIDESEA_IBasicService;
using WIDESEA_IRecordService;
using WIDESEA_IStockService;
using WIDESEA_ITaskInfoService;
using WIDESEA_Model.Models;
@@ -23,6 +33,13 @@
        private readonly IStockInfoService _stockInfoService;
        private readonly ILocationInfoService _locationInfoService;
        private readonly HttpClientHelper _httpClientHelper;
        private readonly IConfiguration _configuration;
        private readonly RoundRobinService _roundRobinService;
        private readonly IMesService _mesService;
        private readonly ITask_HtyService _task_HtyService;
        private readonly IStockInfo_HtyService _stockInfo_HtyService;
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        private readonly IRecordService _recordService;
        public IRepository<Dt_Task> Repository => BaseDal;
@@ -40,229 +57,41 @@
            IMapper mapper,
            IStockInfoService stockInfoService,
            ILocationInfoService locationInfoService,
            HttpClientHelper httpClientHelper) : base(BaseDal)
            HttpClientHelper httpClientHelper,
            IConfiguration configuration,
            RoundRobinService roundRobinService,
            IMesService mesService,
            ITask_HtyService task_HtyService,
            IStockInfo_HtyService stockInfo_HtyService,
            IUnitOfWorkManage unitOfWorkManage,
            IRecordService recordService) : base(BaseDal)
        {
            _mapper = mapper;
            _stockInfoService = stockInfoService;
            _locationInfoService = locationInfoService;
            _httpClientHelper = httpClientHelper;
            _configuration = configuration;
            _roundRobinService = roundRobinService;
            _mesService = mesService;
            _task_HtyService = task_HtyService;
            _stockInfo_HtyService = stockInfo_HtyService;
            _unitOfWorkManage = unitOfWorkManage;
            _recordService = recordService;
        }
        /// <summary>
        /// 创建任务(组盘入库任务、空托盘回库任务)
        /// 查找托盘是否存在未完成任务。
        /// </summary>
        public async Task<WebResponseContent> CreateTaskInboundAsync(CreateTaskDto taskDto)
        private async Task<WebResponseContent> GetTaskByPalletCodeAsync(string palletCode)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(taskDto.PalletCode) ||
                    string.IsNullOrWhiteSpace(taskDto.SourceAddress) ||
                    string.IsNullOrWhiteSpace(taskDto.TargetAddress) ||
                    string.IsNullOrWhiteSpace(taskDto.Roadway))
                {
                    return WebResponseContent.Instance.Error("无效的任务详情");
                }
                var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == palletCode);
                if (task == null)
                    return WebResponseContent.Instance.Error("未找到对应的任务");
                if (taskDto.TaskType != TaskTypeEnum.Inbound && taskDto.TaskType != TaskTypeEnum.InEmpty)
                {
                    return WebResponseContent.Instance.Error("无效的任务详情");
                }
                var task = new Dt_Task
                {
                    TaskNum = 0,
                    PalletCode = taskDto.PalletCode,
                    PalletType = taskDto.PalletType,
                    Roadway = taskDto.Roadway,
                    TaskType = taskDto.TaskType.GetHashCode(),
                    TaskStatus = TaskStatusEnum.New.GetHashCode(),
                    SourceAddress = taskDto.SourceAddress,
                    TargetAddress = taskDto.TargetAddress,
                    CurrentAddress = taskDto.SourceAddress,
                    NextAddress = taskDto.TargetAddress,
                    WarehouseId = taskDto.WarehouseId,
                    Grade = 1,
                    Creater = "system"
                };
                var result = await Repository.AddDataAsync(task) > 0;
                if (!result) return WebResponseContent.Instance.Error("任务创建失败");
                var wmstaskDto = _mapper.Map<WMSTaskDTO>(task);
                return WebResponseContent.Instance.OK("任务创建成功", wmstaskDto);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"任务创建失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 根据指定的任务详情异步创建新的出库任务
        /// </summary>
        public async Task<WebResponseContent> CreateTaskOutboundAsync(CreateTaskDto taskDto)
        {
            try
            {
                var stockResult = await _stockInfoService.GetStockInfoAsync(taskDto.WarehouseId);
                if (stockResult == null || !stockResult.Any())
                    return WebResponseContent.Instance.Error("未找到库存信息");
                var taskList = stockResult.Select(item => new Dt_Task
                {
                    WarehouseId = item.WarehouseId,
                    PalletCode = item.PalletCode,
                    PalletType = item.PalletType,
                    SourceAddress = item.LocationCode,
                    TargetAddress = taskDto.TargetAddress,
                    Roadway = item.LocationDetails.RoadwayNo,
                    TaskType = TaskTypeEnum.Outbound.GetHashCode(),
                    TaskStatus = TaskStatusEnum.New.GetHashCode(),
                    Grade = 1,
                    TaskNum = 0,
                    CurrentAddress = item.LocationCode,
                    NextAddress = taskDto.TargetAddress,
                    Creater = "system",
                }).ToList();
                var result = await BaseDal.AddDataAsync(taskList) > 0;
                var wmstaskDto = result ? _mapper.Map<WMSTaskDTO>(taskList) : null;
                return WebResponseContent.Instance.OK(result ? "任务创建成功" : "任务创建失败", wmstaskDto ?? new object());
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"任务创建失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 获取可入库货位
        /// </summary>
        public async Task<WebResponseContent> GetTasksLocationAsync(CreateTaskDto taskDto)
        {
            try
            {
                var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode);
                if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务");
                var locationInfo = await _locationInfoService.GetLocationInfo(task.Roadway);
                if (locationInfo == null) return WebResponseContent.Instance.Error("未找到对应的货位");
                locationInfo.LocationStatus = LocationStatusEnum.FreeLock.GetHashCode();
                task.CurrentAddress = task.SourceAddress;
                task.NextAddress = locationInfo.LocationCode;
                task.TargetAddress = locationInfo.LocationCode;
                task.TaskStatus = TaskStatusEnum.Line_Finish.GetHashCode();
                var updateResult = await BaseDal.UpdateDataAsync(task);
                var locationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo);
                return WebResponseContent.Instance.OK(
                    updateResult && locationResult ? "任务更新成功" : "任务更新失败",
                    locationInfo.LocationCode);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"获取任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 入库任务完成:添加库存,修改货位状态,删除任务数据,添加历史任务数据
        /// </summary>
        public async Task<WebResponseContent> InboundFinishTaskAsync(CreateTaskDto taskDto)
        {
            try
            {
                var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode);
                if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务");
                var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.TargetAddress);
                if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位");
                var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode);
                stockInfo.LocationCode = location.LocationCode;
                stockInfo.LocationId = location.Id;
                stockInfo.OutboundDate = task.Roadway switch
                {
                    var r when r.Contains("GW") => DateTime.Now.AddHours(2),
                    var r when r.Contains("CW") => DateTime.Now.AddHours(1),
                    _ => DateTime.Now
                };
                location.LocationStatus = LocationStatusEnum.InStock.GetHashCode();
                var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
                var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
                if (!updateLocationResult || !updateStockResult)
                    return WebResponseContent.Instance.Error("任务完成失败");
                var deleteTaskResult = await BaseDal.DeleteDataAsync(task);
                if (!deleteTaskResult) return WebResponseContent.Instance.Error("任务完成失败");
                var historyTask = _mapper.Map<Dt_Task_Hty>(task);
                historyTask.InsertTime = DateTime.Now;
                return WebResponseContent.Instance.OK("任务完成");
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 出库任务完成 :修改库存,修改货位状态,删除任务数据,添加历史任务数据
        /// </summary>
        public async Task<WebResponseContent> OutboundFinishTaskAsync(CreateTaskDto taskDto)
        {
            try
            {
                var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode);
                if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务");
                var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress);
                if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位");
                var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); stockInfo.LocationCode = location.LocationCode;
                stockInfo.LocationId = location.Id;
                stockInfo.OutboundDate = DateTime.Now;
                location.LocationStatus = LocationStatusEnum.Free.GetHashCode();
                var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
                var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
                if (!updateLocationResult || !updateStockResult)
                    return WebResponseContent.Instance.Error("任务完成失败");
                var deleteTaskResult = await BaseDal.DeleteDataAsync(task);
                if (!deleteTaskResult) return WebResponseContent.Instance.Error("任务完成失败");
                var historyTask = _mapper.Map<Dt_Task_Hty>(task);
                historyTask.InsertTime = DateTime.Now;
                return WebResponseContent.Instance.OK("任务完成");
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 创建空托盘入库任务
        /// </summary>
        /// <param name="taskDto"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> CreateTaskInboundTrayAsync(CreateTaskDto taskDto)
        {
            try
            {
                //var tasks = await BaseDal.QueryAsync(s => s.PalletCode == palletCode);
                //if (tasks == null || !tasks.Any())
                //    return WebResponseContent.Instance.Error("未找到对应的任务");
                //var taskDtos = _mapper.Map<List<WMSTaskDTO>>(tasks);
                return WebResponseContent.Instance.OK("查询成功"/*, taskDtos*/);
                var taskDto = _mapper.Map<WMSTaskDTO>(task);
                return WebResponseContent.Instance.OK("查询成功", taskDto);
            }
            catch (Exception ex)
            {
@@ -270,188 +99,97 @@
            }
        }
        #region 分容柜接口
        /// <summary>
        /// 堆垛机取放货完成后物流通知化成分容柜完成信号
        /// 保存任务历史。
        /// </summary>
        public async Task<WebResponseContent> InOrOutCompletedAsync(InputDto input)
        private async Task<WebResponseContent> SaveTaskHistoryAsync(Dt_Task task, string operateType)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.PalletCode) || string.IsNullOrWhiteSpace(input.LocationCode))
            {
                return content.Error($"托盘号或者货位编号不能为空");
            }
            var historyTask = _mapper.Map<Dt_Task_Hty>(task);
            historyTask.InsertTime = DateTime.Now;
            historyTask.OperateType = operateType;
            try
            {
                var stockInfo = await _stockInfoService.GetStockInfoAsync(input.PalletCode, input.LocationCode);
                if (stockInfo == null)
                {
                    var location = await _locationInfoService.GetLocationInfoAsync(input.LocationCode);
                    OutPutDto outPutDto = new OutPutDto()
                    {
                        LocationCode = input.LocationCode,
                        PalletCode = input.PalletCode,
                        IsNormalProcedure = 1,
                        LocationStatus = location.LocationStatus
                    };
                    content.OK(data: outPutDto);
                }
                else
                {
                    OutPutDto outPutDto = new OutPutDto()
                    {
                        LocationCode = input.LocationCode,
                        PalletCode = input.PalletCode,
                        IsNormalProcedure = 1,
                        LocationStatus = stockInfo.LocationDetails.LocationStatus
                    };
                    content.OK(data: outPutDto);
                }
            }
            catch (Exception ex)
            {
                content.Error(ex.Message);
            }
            return content;
            var saved = await _task_HtyService.Repository.AddDataAsync(historyTask) > 0;
            return saved
                ? WebResponseContent.Instance.OK()
                : WebResponseContent.Instance.Error("任务历史保存失败");
        }
        /// <summary>
        /// 化成分容柜定时向物流更新分容柜状态信息
        /// 保存库存历史。
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> SendLocationStatusAsync(InputDto input)
        private async Task<WebResponseContent> SaveStockHistoryAsync(Dt_StockInfo stockInfo, string operateType)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.LocationCode))
            {
                return content.Error($"货位编号不能为空");
            }
            var historyStock = _mapper.Map<Dt_StockInfo_Hty>(stockInfo);
            historyStock.InsertTime = DateTime.Now;
            historyStock.OperateType = operateType;
            try
            {
                var result = await _locationInfoService.Db.Updateable<Dt_LocationInfo>()
                    .SetColumns(s => new Dt_LocationInfo
                    {
                        LocationStatus = input.LocationStatus
                    }).Where(s => s.LocationCode == input.LocationCode).ExecuteCommandAsync() > 0;
                if (result)
                {
                    content.OK("更新成功");
                }
                else
                {
                    content.Error("更新失败");
                }
            }
            catch (Exception ex)
            {
                content.Error(ex.Message);
            }
            return content;
            var saved = await _stockInfo_HtyService.Repository.AddDataAsync(historyStock) > 0;
            return saved
                ? WebResponseContent.Instance.OK()
                : WebResponseContent.Instance.Error("库存历史保存失败");
        }
        /// <summary>
        /// 分容柜工作完成后调用此接口通知物流出库
        /// 完成任务后统一处理。
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> RequestOutboundAsync(InputDto input)
        private async Task<WebResponseContent> CompleteTaskAsync(Dt_Task task, string operateType = "")
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.LocationCode) || string.IsNullOrWhiteSpace(input.PalletCode))
            {
                return content.Error($"托盘号或者货位编号不能为空");
            }
            try
            {
                var stock = await _stockInfoService.GetStockInfoAsync(input.PalletCode, input.LocationCode);
                if (stock == null)
                {
                    content.Error("未找到对应的托盘");
                }
                else
                {
                    var taskList = new Dt_Task
                    {
                        WarehouseId = stock.WarehouseId,
                        PalletCode = stock.PalletCode,
                        PalletType = stock.PalletType,
                        SourceAddress = stock.LocationCode,
                        CurrentAddress = stock.LocationCode,
                        NextAddress = "10080",
                        TargetAddress = "10081",
                        Roadway = stock.LocationDetails.RoadwayNo,
                        TaskType = TaskTypeEnum.Outbound.GetHashCode(),
                        TaskStatus = TaskStatusEnum.New.GetHashCode(),
                        Grade = 1,
                        TaskNum = await BaseDal.GetTaskNo(),
                        Creater = "system",
                    };
            var deleteTaskResult = await BaseDal.DeleteDataAsync(task);
            if (!deleteTaskResult)
                return WebResponseContent.Instance.Error("任务完成失败");
                    var result = await BaseDal.AddDataAsync(taskList) > 0;
                    var wmstaskDto = result ? _mapper.Map<WMSTaskDTO>(taskList) : null;
                    var httpResponse = _httpClientHelper.Post<WebResponseContent>("http://logistics-service/api/logistics/notifyoutbound", JsonSerializer.Serialize(wmstaskDto)).Data;
                    if (result && httpResponse != null)
                    {
                        content.OK("出库请求成功");
                    }
                    else
                    {
                        content.Error("出库请求失败");
                    }
                }
            }
            catch (Exception ex)
            {
                content.Error(ex.Message);
            }
            return content;
            return await SaveTaskHistoryAsync(task, operateType);
        }
        /// <summary>
        /// 入库完成分容调用获取托盘上每个通道电芯
        /// 根据巷道确定目标地址,支持多出库口轮询。
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> GetPalletCodeCellAsync(InputDto input)
        private string DetermineTargetAddress(string roadway, Dictionary<string, List<string>> addressMap)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.PalletCode) || string.IsNullOrWhiteSpace(input.LocationCode))
            if (string.IsNullOrWhiteSpace(roadway))
                return TaskAddressConstants.DEFAULT_ADDRESS;
            string? matchedPrefix = null;
            foreach (var kvp in addressMap)
            {
                return content.Error($"托盘号或者货位编号不能为空");
            }
            try
            {
                var stockInfo = await _stockInfoService.GetStockInfoAsync(input.PalletCode, input.LocationCode);
                if (stockInfo == null)
                if (roadway.Contains(kvp.Key))
                {
                    return content.Error("未找到对应的托盘");
                    matchedPrefix = kvp.Key;
                    break;
                }
                var outPutDtos = stockInfo.Details.Select(x => new OutPutDto()
                {
                    LocationCode = input.LocationCode,
                    PalletCode = input.PalletCode,
                    IsNormalProcedure = 1,
                    LocationStatus = stockInfo.LocationDetails.LocationStatus,
                    CellCode = x.SerialNumber,
                    Channel = x.InboundOrderRowNo.ToString()
                }).ToList();
                return content.OK(data: outPutDtos);
            }
            catch (Exception ex)
            {
                return content.Error(ex.Message);
            }
            if (matchedPrefix == null)
                return TaskAddressConstants.DEFAULT_ADDRESS;
            if (!addressMap.TryGetValue(matchedPrefix, out var addresses) || addresses == null || addresses.Count == 0)
                return TaskAddressConstants.DEFAULT_ADDRESS;
            if (addresses.Count == 1)
                return addresses[0];
            return _roundRobinService.GetNextAddress(matchedPrefix, addresses);
        }
        #endregion
        /// <summary>
        /// 根据库存 Remark 确定目标地址(GW_1→[11001,11010]轮询,GW_2→CWSC1,CW_1→22001)。
        /// </summary>
        private string DetermineTargetAddressByRemark(string remark, string roadway, Dictionary<string, List<string>> addressMap)
        {
            // 根据 Remark 确定目标地址
            if (!string.IsNullOrWhiteSpace(remark))
            {
                return remark switch
                {
                    StockRemarkConstants.GW1 => _roundRobinService.GetNextAddress(StockRemarkConstants.GW1, TaskAddressConstants.GW1_ADDRESSES.ToList()),
                    StockRemarkConstants.GW2 => TaskAddressConstants.GW2_ADDRESS,
                    StockRemarkConstants.CW1 => TaskAddressConstants.CW1_ADDRESS,
                    _ => DetermineTargetAddress(roadway, addressMap)
                };
            }
            // Remark 为空时,回退到巷道配置
            return DetermineTargetAddress(roadway, addressMap);
        }
    }
}
}