wanshenmean
3 天以前 64a2aa2301946f777659239247233e47ad1e3076
feat(事务管理): 添加异步事务处理方法

refactor(任务服务): 重构出库任务流程使用事务管理
重构出库任务流程服务,使用事务管理确保数据一致性,并移除对ITaskRepository的直接依赖。

fix(任务查询): 移除不必要的创建者条件
移除TaskService中查询入库任务时不必要的创建者条件,简化查询逻辑。

style(代码清理): 移除未使用的引用和空行
清理多个文件中的未使用引用和多余空行,保持代码整洁。

feat(手动任务): 添加手动任务创建的事务支持
在手动任务创建方法中添加事务支持,确保任务创建和发送到WCS的原子性。
已修改8个文件
183 ■■■■■ 文件已修改
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/UnitOfWorks/IUnitOfWorkManage.cs 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/UnitOfWorks/UnitOfWorkManage.cs 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/OutboundTaskFlowService.cs 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/RobotTaskFlowService.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/BaseRepository/UnitOfWorks/IUnitOfWorkManage.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/BaseRepository/UnitOfWorks/UnitOfWorkManage.cs 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_WCS.cs 72 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/UnitOfWorks/IUnitOfWorkManage.cs
@@ -1,10 +1,5 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.BaseRepository
{
@@ -15,6 +10,7 @@
        /// </summary>
        /// <returns>SqlSugarClient数据库客户端对象</returns>
        SqlSugarClient GetDbClient();
        int TranCount { get; }
        /// <summary>
@@ -27,28 +23,40 @@
        /// 开始一个事务
        /// </summary>
        void BeginTran();
        /// <summary>
        /// 开始一个事务
        /// </summary>
        /// <param name="method">触发事务的方法信息</param>
        void BeginTran(MethodInfo method);
        /// <summary>
        /// 开始一个事务,并执行提供的函数
        /// </summary>
        /// <param name="func">委托方法</param>
        /// <returns></returns>
        WebResponseContent BeginTran(Func<WebResponseContent> func);
        /// <summary>
        /// 提交当前事务
        /// </summary>
        void CommitTran();
        /// <summary>
        /// 提交事务
        /// </summary>
        /// <param name="method">触发提交事务的方法信息</param>
        void CommitTran(MethodInfo method);
        /// <summary>
        /// 回滚当前事务
        /// </summary>
        void RollbackTran();
        /// <summary>
        /// 回滚当前事务
        /// </summary>
        /// <param name="method">触发回滚的方法信息</param>
        void RollbackTran(MethodInfo method);
    }
}
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/UnitOfWorks/UnitOfWorkManage.cs
@@ -1,13 +1,7 @@
using Microsoft.Extensions.Logging;
using SqlSugar;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
namespace WIDESEAWCS_Core.BaseRepository
@@ -16,13 +10,16 @@
    {
        // 定义日志记录器
        private readonly ILogger<UnitOfWorkManage> _logger;
        // 定义SqlSugarClient
        private readonly ISqlSugarClient _sqlSugarClient;
        // 定义事务计数器
        private int _tranCount { get; set; }
        // 定义事务计数器的只读属性
        public int TranCount => _tranCount;
        // 定义事务栈
        public readonly ConcurrentStack<string> TranStack = new();
@@ -44,7 +41,6 @@
            return _sqlSugarClient as SqlSugarClient;
        }
        // 创建UnitOfWork
        public UnitOfWork CreateUnitOfWork()
        {
@@ -56,7 +52,7 @@
            uow.Db.Open();
            uow.Tenant.BeginTran();
            _logger.LogDebug("UnitOfWork Begin");
            return uow;
        }
@@ -101,7 +97,7 @@
                    }
                    return content;
                }
                catch(Exception ex)
                catch (Exception ex)
                {
                    RollbackTran();
                    return WebResponseContent.Instance.Error(ex.Message);
@@ -141,7 +137,6 @@
                {
                    spinner.SpinOnce();
                }
                if (result == method.GetFullName())
                {
@@ -209,4 +204,4 @@
            }
        }
    }
}
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/OutboundTaskFlowService.cs
@@ -1,19 +1,18 @@
using Autofac;
using Newtonsoft.Json;
using System.Diagnostics.CodeAnalysis;
using WIDESEA_Core;
using WIDESEAWCS_Common.HttpEnum;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEA_Core;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_DTO;
using WIDESEAWCS_DTO.Stock;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_ITaskInfoRepository;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Service;
@@ -28,8 +27,8 @@
        private readonly IRouterService _routerService;
        private readonly HttpClientHelper _httpClientHelper;
        private readonly IRobotTaskService _robotTaskService;
        private readonly ITaskRepository _taskRepository;
        private readonly IComponentContext _componentContext;
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        /// <summary>
        /// 初始化出库任务流程服务。
@@ -37,15 +36,14 @@
        /// <param name="routerService">路由服务。</param>
        /// <param name="httpClientHelper">WMS接口调用帮助类。</param>
        /// <param name="robotTaskService">机械手任务服务。</param>
        /// <param name="taskRepository">任务仓储(用于删除出库任务)。</param>
        /// <param name="componentContext">Autofac组件上下文(用于延迟解析ITaskService以避免循环依赖)。</param>
        public OutboundTaskFlowService(IRouterService routerService, HttpClientHelper httpClientHelper, IRobotTaskService robotTaskService, ITaskRepository taskRepository, IComponentContext componentContext)
        public OutboundTaskFlowService(IRouterService routerService, HttpClientHelper httpClientHelper, IRobotTaskService robotTaskService, IComponentContext componentContext, IUnitOfWorkManage unitOfWorkManage)
        {
            _routerService = routerService;
            _httpClientHelper = httpClientHelper;
            _robotTaskService = robotTaskService;
            _taskRepository = taskRepository;
            _componentContext = componentContext;
            _unitOfWorkManage = unitOfWorkManage;
        }
        /// <summary>
@@ -154,15 +152,23 @@
                if (inboundTaskDto != null)
                {
                    // 先删除本地出库任务,避免托盘号唯一键冲突
                    _taskRepository.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成);
                    // 调用ReceiveWMSTask创建本地入库任务
                    var receiveResult = TaskService.ReceiveWMSTask(new List<WMSTaskDTO> { inboundTaskDto });
                    if (!receiveResult.Status)
                    _unitOfWorkManage.BeginTran(() =>
                    {
                        return content.Error($"创建本地入库任务失败: {receiveResult.Message}");
                    }
                        // 先删除本地出库任务,避免托盘号唯一键冲突
                        bool isDeleted = TaskService.Repository.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成);
                        if (!isDeleted)
                        {
                            return content.Error($"删除本地出库任务失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】");
                        }
                        // 调用ReceiveWMSTask创建本地入库任务
                        var receiveResult = TaskService.ReceiveWMSTask(new List<WMSTaskDTO> { inboundTaskDto });
                        if (!receiveResult.Status)
                        {
                            return content.Error($"创建本地入库任务失败: {receiveResult.Message}");
                        }
                        return content.OK("创建本地入库任务成功");
                    });
                }
            }
@@ -244,4 +250,4 @@
            return WebResponseContent.Instance.OK();
        }
    }
}
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/RobotTaskFlowService.cs
@@ -1,7 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
@@ -53,4 +52,4 @@
            return WebResponseContent.Instance.OK();
        }
    }
}
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs
@@ -676,8 +676,7 @@
            return BaseDal.QueryFirst(x =>
                x.TaskType == (int)TaskInboundTypeEnum.Inbound &&
                x.TaskStatus == (int)TaskInStatusEnum.InNew &&
                x.SourceAddress == sourceAddress &&
                x.Creater == "WMS");
                x.SourceAddress == sourceAddress);
        }
    }
Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/BaseRepository/UnitOfWorks/IUnitOfWorkManage.cs
@@ -17,6 +17,8 @@
        void BeginTran();
        void BeginTran(MethodInfo method);
        WebResponseContent BeginTran(Func<WebResponseContent> func);
        Task<WebResponseContent> BeginTranAsync(Func<Task<WebResponseContent>> funcAsync);
        void CommitTran();
        void CommitTran(MethodInfo method);
        void RollbackTran();
Code/WMS/WIDESEA_WMSServer/WIDESEA_Core/BaseRepository/UnitOfWorks/UnitOfWorkManage.cs
@@ -100,6 +100,32 @@
            }
        }
        private readonly SemaphoreSlim _asyncLock = new SemaphoreSlim(1, 1);
        public async Task<WebResponseContent> BeginTranAsync(Func<Task<WebResponseContent>> funcAsync)
        {
            await _asyncLock.WaitAsync();
            try
            {
                BeginTran();   // 假设这是同步方法,启动事务
                WebResponseContent content = await funcAsync();
                if (content.Status)
                    CommitTran();   // 同步提交
                else
                    RollbackTran(); // 同步回滚
                return content;
            }
            catch (Exception ex)
            {
                RollbackTran();
                return WebResponseContent.Instance.Error(ex.Message);
            }
            finally
            {
                _asyncLock.Release();
            }
        }
        public void CommitTran()
        {
            lock (this)
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_WCS.cs
@@ -1,27 +1,15 @@
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.GradingMachine;
using WIDESEA_DTO.MES;
using WIDESEA_DTO.Stock;
using WIDESEA_DTO.Task;
using WIDESEA_IBasicService;
using WIDESEA_IStockService;
using WIDESEA_ITaskInfoService;
using WIDESEA_Model.Models;
namespace WIDESEA_TaskInfoService
@@ -185,7 +173,6 @@
                // 判断是不是极卷库任务
                if (taskDto.WarehouseId == (int)WarehouseEnum.FJ1 || taskDto.WarehouseId == (int)WarehouseEnum.ZJ1)
                {
                    return await CompleteAgvInboundTaskAsync(taskDto);
                }
@@ -885,31 +872,31 @@
        {
            try
            {
                // 1. 根据任务类型字符串确定 TaskType 和 TaskStatus
                int taskType;
                int taskStatus;
                switch (dto.TaskType)
                {
                    case "入库":
                        taskType = TaskTypeEnum.Inbound.GetHashCode();
                        taskType = TaskInboundTypeEnum.Inbound.GetHashCode();
                        taskStatus = TaskInStatusEnum.InNew.GetHashCode();
                        break;
                    case "出库":
                        taskType = TaskTypeEnum.Outbound.GetHashCode();
                        taskType = TaskOutboundTypeEnum.Outbound.GetHashCode();
                        taskStatus = TaskOutStatusEnum.OutNew.GetHashCode();
                        break;
                    case "移库":
                        taskType = TaskTypeEnum.Relocation.GetHashCode();
                        taskType = TaskRelocationTypeEnum.Relocation.GetHashCode();
                        taskStatus = TaskRelocationStatusEnum.RelocationNew.GetHashCode();
                        break;
                    default:
                        return WebResponseContent.Instance.Error($"不支持的任务类型: {dto.TaskType}");
                }
                // 2. 生成任务号
                int taskNum = await BaseDal.GetTaskNo();
                // 3. 构建任务实体
                var task = new Dt_Task
                {
                    TaskNum = taskNum,
@@ -919,6 +906,7 @@
                    TaskType = taskType,
                    TaskStatus = taskStatus,
                    Grade = dto.Grade,
                    Roadway = dto.TargetAddress,
                    WarehouseId = dto.WarehouseId,
                    CurrentAddress = dto.SourceAddress,
                    NextAddress = dto.TargetAddress,
@@ -927,31 +915,37 @@
                    ModifyDate = DateTime.Now
                };
                // 4. 保存到数据库
                var result = await BaseDal.AddDataAsync(task) > 0;
                if (!result)
                    return WebResponseContent.Instance.Error("创建任务失败");
                // 5. 发送到 WCS
                var wmsTaskDto = new WMSTaskDTO
                var wmsTaskDtos = new List<WMSTaskDTO>()
                {
                    TaskNum = task.TaskNum,
                    PalletCode = task.PalletCode,
                    SourceAddress = task.SourceAddress,
                    TargetAddress = task.TargetAddress,
                    TaskType = task.TaskType,
                    TaskStatus = task.TaskStatus,
                    WarehouseId = task.WarehouseId
                    new()
                    {
                        TaskNum = task.TaskNum,
                        PalletCode = task.PalletCode,
                        SourceAddress = task.SourceAddress,
                        TargetAddress = task.TargetAddress,
                        TaskType = task.TaskType,
                        Roadway = task.Roadway,
                        TaskStatus = task.TaskStatus,
                        WarehouseId = task.WarehouseId
                    }
                };
                var wcsResult = _httpClientHelper.Post<WebResponseContent>(
                    "http://localhost:9292/api/Task/ReceiveManualTask",
                    wmsTaskDto.ToJson());
                await _unitOfWorkManage.BeginTranAsync(async () =>
                {
                    // 4. 保存到数据库
                    var result = await BaseDal.AddDataAsync(task) > 0;
                    if (!result)
                        return WebResponseContent.Instance.Error("创建任务失败");
                if (!wcsResult.IsSuccess || !wcsResult.Data.Status)
                    return WebResponseContent.Instance.Error($"任务已创建但发送给WCS失败: {wcsResult.Data?.Message}");
                    var wcsResult = _httpClientHelper.Post<WebResponseContent>(
                        "http://localhost:9292/api/Task/ReceiveManualTask",
                        wmsTaskDtos.ToJson());
                return WebResponseContent.Instance.OK($"手动创建任务成功,任务号: {taskNum}");
                    if (!wcsResult.IsSuccess || !wcsResult.Data.Status)
                        return WebResponseContent.Instance.Error($"任务已创建但发送给WCS失败: {wcsResult.Data?.Message}");
                    return WebResponseContent.Instance.OK($"手动创建任务成功,任务号: {taskNum}");
                });
            }
            catch (Exception ex)
            {