wanshenmean
2026-03-27 b50c79d022c363b1d5ad582e9ef7d71fd7e7f427
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/RouterService.cs
@@ -4,6 +4,8 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Common;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Enums;
@@ -11,6 +13,7 @@
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Repository;
using ICacheService = WIDESEAWCS_Core.Caches.ICacheService;
namespace WIDESEAWCS_QuartzJob.Service
{
@@ -21,6 +24,7 @@
    {
        private readonly IDeviceProtocolRepository _deviceProtocolRepository;
        private readonly IDeviceInfoRepository _deviceInfoRepository;
        private readonly ICacheService _cacheService;
        /// <summary>
        /// 路由配置业务层
@@ -28,10 +32,52 @@
        /// <param name="BaseDal"></param>
        /// <param name="deviceProtocolRepository"></param>
        /// <param name="deviceInfoRepository"></param>
        public RouterService(IRouterRepository BaseDal, IDeviceProtocolRepository deviceProtocolRepository, IDeviceInfoRepository deviceInfoRepository) : base(BaseDal)
        public RouterService(IRouterRepository BaseDal, IDeviceProtocolRepository deviceProtocolRepository, IDeviceInfoRepository deviceInfoRepository, ICacheService cacheService) : base(BaseDal)
        {
            _deviceProtocolRepository = deviceProtocolRepository;
            _deviceInfoRepository = deviceInfoRepository;
            _cacheService = cacheService;
        }
        /// <summary>
        /// 从缓存获取指定类型的全量路由数据,缓存不存在时自动从数据库加载并写入缓存
        /// </summary>
        /// <param name="routeType">路由类型(入口/出口)</param>
        /// <returns>该类型的全部路由列表</returns>
        private List<Dt_Router> GetAllRoutersFromCache(int routeType)
        {
            // 根据路由类型构建缓存Key,In类型对应"In",Out类型对应"Out"
            string cacheKey = $"Router:AllRouters:{(routeType == RouterInOutType.In.ObjToInt() ? "In" : "Out")}";
            // 通过缓存服务获取数据,缓存未命中时调用工厂方法从数据库查询并写入缓存
            return _cacheService.GetOrAdd(
                cacheKey,
                _ => BaseDal.QueryData(x => x.InOutType == routeType)
            );
        }
        /// <summary>
        /// 清除所有路由缓存(入口和出口类型)
        /// </summary>
        public void ClearRouterCache()
        {
            _cacheService.Remove("Router:AllRouters:In");
            _cacheService.Remove("Router:AllRouters:Out");
        }
        /// <summary>
        /// 根据设备编号查询经过该设备的所有路由(合并入口+出口类型)
        /// </summary>
        /// <param name="deviceCode">设备编号</param>
        /// <returns>经过该设备的路由列表</returns>
        public List<Dt_Router> QueryRoutersByDeviceCode(string deviceCode)
        {
            // 从缓存获取入口类型和出口类型的全量路由数据
            List<Dt_Router> inRouters = GetAllRoutersFromCache(RouterInOutType.In.ObjToInt());
            List<Dt_Router> outRouters = GetAllRoutersFromCache(RouterInOutType.Out.ObjToInt());
            // 合并后筛选出经过指定设备的路由(ChildPosiDeviceCode匹配)
            return inRouters.Concat(outRouters)
                .Where(x => x.ChildPosiDeviceCode == deviceCode)
                .ToList();
        }
        /// <summary>
@@ -45,12 +91,14 @@
            List<Dt_Router> routers = new List<Dt_Router>();
            try
            {
                // 一次性查询所有路由数据到内存
                List<Dt_Router> allRouters = BaseDal.QueryData(x => true);
                // 从缓存加载入口类型和出口类型的路由数据并合并(创建新列表,避免修改缓存引用)
                List<Dt_Router> allRouters = GetAllRoutersFromCache(RouterInOutType.In.ObjToInt())
                    .Concat(GetAllRoutersFromCache(RouterInOutType.Out.ObjToInt()))
                    .ToList();
                // 在内存中进行路径搜索
                routers = FindRoutesInMemory(startPosi, endPosi, allRouters, null);
                if (routers.Count == 0)
                {
                    throw new Exception($"该路径未配置或配置错误,请检查设备路由信息,起点:【{startPosi}】,终点:【{endPosi}】");
@@ -75,12 +123,12 @@
            List<Dt_Router> routers = new List<Dt_Router>();
            try
            {
                // 一次性查询指定类型的所有路由数据到内存
                List<Dt_Router> allRouters = BaseDal.QueryData(x => x.InOutType == routeType);
                // 从缓存加载指定类型的所有路由数据
                List<Dt_Router> allRouters = GetAllRoutersFromCache(routeType);
                // 在内存中进行路径搜索
                routers = FindRoutesInMemory(startPosi, endPosi, allRouters, routeType);
                if (routers.Count == 0)
                {
                    throw new Exception($"该路径未配置或配置错误,请检查设备路由信息,起点:【{startPosi}】,终点:【{endPosi}】");
@@ -110,7 +158,7 @@
            var routersByNext = allRouters
                .GroupBy(r => r.NextPosi)
                .ToDictionary(g => g.Key, g => g.ToList());
            var routersByChild = allRouters
                .GroupBy(r => r.ChildPosi)
                .ToDictionary(g => g.Key, g => g.ToList());
@@ -127,7 +175,7 @@
            // 使用队列进行广度优先搜索
            Queue<(Dt_Router router, List<Dt_Router> path)> queue = new Queue<(Dt_Router, List<Dt_Router>)>();
            // 将所有终点路由加入队列
            foreach (var endRouter in endRouters)
            {
@@ -185,10 +233,12 @@
        {
            try
            {
                // 查询从起点出发的所有路由
                List<Dt_Router> routes = BaseDal.QueryData(x => x.StartPosi == startPosi,
                    new Dictionary<string, OrderByType> { { nameof(Dt_Router.IsEnd), OrderByType.Desc } });
                // 从缓存获取入口类型的所有路由数据,基于起点筛选后按IsEnd降序排序
                List<Dt_Router> routes = GetAllRoutersFromCache(RouterInOutType.In.ObjToInt())
                    .Where(x => x.StartPosi == startPosi)
                    .ToList();
                routes = routes.OrderByDescending(x => x.IsEnd).ToList();
                // 返回第一个路由
                return routes.FirstOrDefault();
            }
@@ -209,10 +259,12 @@
        {
            try
            {
                // 查询从起点出发的指定类型路由
                List<Dt_Router> routes = BaseDal.QueryData(x => x.StartPosi == startPosi && x.InOutType == routeType,
                    new Dictionary<string, OrderByType> { { nameof(Dt_Router.IsEnd), OrderByType.Desc } });
                // 从缓存获取指定类型的所有路由数据,筛选起点后按IsEnd降序排列
                List<Dt_Router> routes = GetAllRoutersFromCache(routeType)
                    .Where(x => x.StartPosi == startPosi)
                    .ToList();
                routes = routes.OrderByDescending(x => x.IsEnd).ToList();
                // 返回第一个路由
                return routes.FirstOrDefault();
            }
@@ -234,10 +286,12 @@
        {
            try
            {
                // 查询从起点出发的指定类型路由
                List<Dt_Router> routes = BaseDal.QueryData(x => x.StartPosi == startPosi && x.InOutType == routeType,
                    new Dictionary<string, OrderByType> { { nameof(Dt_Router.IsEnd), OrderByType.Desc } });
                // 从缓存获取指定类型的所有路由数据,筛选起点后按IsEnd降序排列
                List<Dt_Router> routes = GetAllRoutersFromCache(routeType)
                    .Where(x => x.StartPosi == startPosi)
                    .ToList();
                routes = routes.OrderByDescending(x => x.IsEnd).ToList();
                if (routes.Count == 0)
                    return null;
@@ -246,8 +300,8 @@
                if (directRoute != null)
                    return directRoute;
                // 如果没有直接路由,使用查找算法找到朝向终点的路由
                List<Dt_Router> allRouters = BaseDal.QueryData(x => x.InOutType == routeType);
                // 如果没有直接路由,使用缓存中的全量路由数据查找朝向终点的路由
                List<Dt_Router> allRouters = GetAllRoutersFromCache(routeType);
                foreach (var route in routes)
                {
                    // 检查从这个路由的下一个位置是否能到达终点
@@ -255,6 +309,42 @@
                    if (pathToEnd.Count > 0)
                        return route;
                }
                // 如果都不能到达终点,返回第一个路由
                return routes.FirstOrDefault();
            }
            catch (Exception ex)
            {
                // 记录错误信息
                return null;
            }
        }
        /// <summary>
        /// 根据起点、终点方向和路由类型获取下一个单个子节点路由(智能选择朝向终点的路由)
        /// </summary>
        /// <param name="startPosi">起点/当前位置</param>
        /// <param name="endPosi">终点位置(用于方向判断)</param>
        /// <returns>返回下一个路由节点,优先返回朝向终点的路由,如果没有则返回null</returns>
        public Dt_Router QueryNextRoute(string startPosi, string endPosi)
        {
            try
            {
                // 从缓存获取入口和出口类型的所有路由数据,筛选起点后按IsEnd降序排序
                List<Dt_Router> inRoutes = GetAllRoutersFromCache(RouterInOutType.In.ObjToInt());
                List<Dt_Router> outRoutes = GetAllRoutersFromCache(RouterInOutType.Out.ObjToInt());
                List<Dt_Router> routes = inRoutes.Concat(outRoutes)
                    .Where(x => x.StartPosi == startPosi)
                    .ToList();
                routes = routes.OrderByDescending(x => x.IsEnd).ToList();
                if (routes.Count == 0)
                    return null;
                // 优先选择直接指向终点的路由
                Dt_Router directRoute = routes.FirstOrDefault(x => x.NextPosi == endPosi || x.ChildPosi == endPosi);
                if (directRoute != null)
                    return directRoute;
                // 如果都不能到达终点,返回第一个路由
                return routes.FirstOrDefault();
@@ -278,7 +368,7 @@
            List<Dt_Router> path = new List<Dt_Router>();
            string currentPosi = startPosi;
            HashSet<string> visitedPositions = new HashSet<string>();
            try
            {
                while (currentPosi != endPosi)
@@ -290,21 +380,21 @@
                    visitedPositions.Add(currentPosi);
                    Dt_Router nextRoute = QueryNextRoute(currentPosi, endPosi, routeType);
                    if (nextRoute == null)
                    {
                        break;
                    }
                    path.Add(nextRoute);
                    currentPosi = nextRoute.NextPosi;
                    if (path.Count > 1000)
                    {
                        break;
                    }
                }
                if (currentPosi != endPosi)
                {
                    return new List<Dt_Router>();
@@ -314,7 +404,7 @@
            {
                return new List<Dt_Router>();
            }
            return path;
        }
@@ -327,24 +417,34 @@
        {
            // 创建一个字符串列表,用于存储所有位置
            List<string> positions = new List<string>();
            try
            var device = _cacheService.Get<List<string>>($"{RedisPrefix.System}:{RedisName.DevicePositions}:{deviceCode}");
            if (device.IsNullOrEmpty())
            {
                // 查询所有进入路由器的位置
                List<string> inRouterPositions = BaseDal.QueryData(x => x.ChildPosiDeviceCode == deviceCode && x.InOutType == RouterInOutType.In.ObjToInt()).GroupBy(x => x.StartPosi).Select(x => x.Key).ToList();
                try
                {
                    // 查询所有进入路由器的位置
                    List<string> inRouterPositions = BaseDal.QueryData(x => x.ChildPosiDeviceCode == deviceCode && x.InOutType == RouterInOutType.In.ObjToInt()).GroupBy(x => x.StartPosi).Select(x => x.Key).ToList();
                // 查询所有离开路由器的位置
                List<string> outRouterPositions = BaseDal.QueryData(x => x.ChildPosiDeviceCode == deviceCode && x.InOutType == RouterInOutType.Out.ObjToInt()).GroupBy(x => x.ChildPosi).Select(x => x.Key).ToList();
                    // 查询所有离开路由器的位置
                    List<string> outRouterPositions = BaseDal.QueryData(x => x.ChildPosiDeviceCode == deviceCode && x.InOutType == RouterInOutType.Out.ObjToInt()).GroupBy(x => x.ChildPosi).Select(x => x.Key).ToList();
                // 将进入和离开路由器的位置添加到列表中
                positions.AddRange(inRouterPositions);
                positions.AddRange(outRouterPositions);
                // 返回去重后的位置列表
                return positions.GroupBy(x => x).Select(x => x.Key).ToList();
                    // 将进入和离开路由器的位置添加到列表中
                    positions.AddRange(inRouterPositions);
                    positions.AddRange(outRouterPositions);
                    // 返回去重后的位置列表
                    return positions.GroupBy(x => x).Select(x => x.Key).ToList();
                }
                catch (Exception ex)
                {
                    ConsoleHelper.WriteErrorLine($"RouterService.QueryAllPositions 查询失败: {ex.Message}");
                }
                finally
                {
                    _cacheService.TryAdd($"{RedisPrefix.System}:{RedisName.DevicePositions}:{deviceCode}", positions);
                }
            }
            catch
            {
            }
            else
                positions = device;
            // 返回位置列表
            return positions;
        }
@@ -355,42 +455,34 @@
        public List<object> GetAllWholeRouters()
        {
            List<object> data = new List<object>();
            // 查询所有路由
            List<Dt_Router> allRouters = BaseDal.QueryData(x => true);
            // 从缓存加载入口类型和出口类型的全量路由数据并合并
            List<Dt_Router> inRouters = GetAllRoutersFromCache(RouterInOutType.In.ObjToInt());
            List<Dt_Router> outRouters = GetAllRoutersFromCache(RouterInOutType.Out.ObjToInt());
            List<Dt_Router> allRouters = inRouters.Concat(outRouters).ToList();
            // 查询所有结束的路由,并按Id排序
            List<Dt_Router> dt_Routers = allRouters.Where(x => x.IsEnd).OrderBy(x => x.Id).ToList();
            // 遍历所有结束的路由
            foreach (var item in dt_Routers)
            {
                // 获取当前路由的子路由
                string routes = $"{item.NextPosi},";
                // 获取当前路由的父路由
                string str = GetPreviousRoutes(item.StartPosi, allRouters, item.InOutType);
                // 如果父路由不为空
                if (!string.IsNullOrEmpty(str))
                // 获取所有可能的完整路径
                List<List<string>> allPaths = GetAllPaths(item.StartPosi, item.NextPosi, allRouters, item.InOutType);
                // 为每条独立路径生成结果
                foreach (var path in allPaths)
                {
                    // 去掉最后一个逗号
                    if (str.EndsWith(","))
                        str = str.Substring(0, str.Length - 1);
                    // 将父路由添加到子路由中
                    routes += str;
                }
                // 如果当前路由是入口
                if (item.InOutType == RouterInOutType.In.ObjToInt())
                {
                    // 将子路由反转并添加到data中
                    List<string> itemRouters = routes.Split(",").Reverse().ToList();
                    object obj = new { type = RouterInOutType.In, routes = itemRouters };
                    data.Add(obj);
                }
                // 如果当前路由是出口
                else
                {
                    // 将子路由反转并添加到data中
                    List<string> itemRouters = routes.Split(",").Reverse().ToList();
                    object obj = new { type = RouterInOutType.Out, routes = itemRouters };
                    data.Add(obj);
                    // 如果当前路由是入口
                    if (item.InOutType == RouterInOutType.In.ObjToInt())
                    {
                        object obj = new { type = RouterInOutType.In, routes = path };
                        data.Add(obj);
                    }
                    // 如果当前路由是出口
                    else
                    {
                        object obj = new { type = RouterInOutType.Out, routes = path };
                        data.Add(obj);
                    }
                }
            }
@@ -398,42 +490,61 @@
            return data;
        }
        private string GetPreviousRoutes(string startPosi, List<Dt_Router> allRouters, int routerType)
        /// <summary>
        /// 获取从起点到终点的所有完整路径
        /// </summary>
        /// <param name="startPosi">当前起始位置</param>
        /// <param name="endPosi">终点位置</param>
        /// <param name="allRouters">所有路由数据</param>
        /// <param name="routerType">路由类型</param>
        /// <returns>所有完整路径列表,每条路径是从起点到终点的位置列表</returns>
        private List<List<string>> GetAllPaths(string startPosi, string endPosi, List<Dt_Router> allRouters, int routerType)
        {
            // 定义一个空字符串routers
            string routers = string.Empty;
            // 判断startPosi是否为空
            if (!string.IsNullOrEmpty(startPosi))
            List<List<string>> result = new List<List<string>>();
            // 从终点开始反向查找所有路径
            List<List<string>> reversePaths = new List<List<string>>();
            BuildReversePaths(startPosi, new List<string> { endPosi, startPosi }, allRouters, routerType, reversePaths);
            // 将反向路径转为正向(从起点到终点)
            foreach (var reversePath in reversePaths)
            {
                // 判断routers是否以逗号结尾
                if (!routers.EndsWith(","))
                    // 如果不是,则将startPosi添加到routers中,并在后面加上逗号
                    routers += $"{startPosi},";
                else
                    // 如果是,则将startPosi添加到routers中
                    routers += $"{startPosi}";
                result.Add(reversePath.AsEnumerable().Reverse().ToList());
            }
            // 从allRouters中筛选出NextPosi等于startPosi且InOutType等于routerType的元素,并转换为List
            List<Dt_Router> preRouters = allRouters.Where(x => x.NextPosi == startPosi && x.InOutType == routerType).ToList();
            // 遍历preRouters中的每个元素
            foreach (var item in preRouters)
            return result;
        }
        /// <summary>
        /// 递归构建反向路径(从终点向起点查找)
        /// </summary>
        /// <param name="currentStartPosi">当前节点的起始位置</param>
        /// <param name="currentPath">当前已构建的路径(反向,从终点开始)</param>
        /// <param name="allRouters">所有路由数据</param>
        /// <param name="routerType">路由类型</param>
        /// <param name="result">收集所有完整路径</param>
        private void BuildReversePaths(string currentStartPosi, List<string> currentPath, List<Dt_Router> allRouters, int routerType, List<List<string>> result)
        {
            // 查找当前节点的前置节点(NextPosi等于当前StartPosi的路由)
            List<Dt_Router> preRouters = allRouters.Where(x => x.NextPosi == currentStartPosi && x.InOutType == routerType).ToList();
            // 如果没有前置节点,说明已经到达路径起点,保存当前路径
            if (preRouters.Count == 0)
            {
                // 调用GetPreviousRoutes方法,传入item.StartPosi、allRouters和routerType,并将返回值赋给str
                string str = GetPreviousRoutes(item.StartPosi, allRouters, routerType);
                // 判断str是否为空
                if (!string.IsNullOrEmpty(str))
                {
                    // 判断routers是否以逗号结尾
                    if (routers.EndsWith(","))
                        // 如果是,则将str添加到routers中
                        routers += $"{str}";
                    else
                        // 如果不是,则将str添加到routers中,并在后面加上逗号
                        routers += $"{str},";
                }
                result.Add(new List<string>(currentPath));
                return;
            }
            // 返回routers
            return routers;
            // 对每个前置节点,创建新的路径分支
            foreach (var preRouter in preRouters)
            {
                // 创建新的路径副本
                List<string> newPath = new List<string>(currentPath);
                newPath.Add(preRouter.StartPosi);
                // 递归查找前置节点
                BuildReversePaths(preRouter.StartPosi, newPath, allRouters, routerType, result);
            }
        }
        /// <summary>
@@ -518,6 +629,20 @@
                // 添加新的路由信息
                BaseDal.AddData(routers);
                // 重新查询全量路由(此时才包含新增的路由),再写入缓存
                List<Dt_Router> updatedRouters = BaseDal.QueryData(x => x.InOutType == routerType);
                string cacheKey = $"Router:AllRouters:{(routerType == RouterInOutType.In.ObjToInt() ? "In" : "Out")}";
                try
                {
                    _cacheService.AddOrUpdate(cacheKey, updatedRouters);
                }
                catch
                {
                    // 缓存更新失败时静默忽略,下次查询会从DB自动重建缓存
                }
                content = WebResponseContent.Instance.OK();
            }
            catch (Exception ex)