using SqlSugar; using System; using System.Collections.Generic; 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; using WIDESEAWCS_Core.Helper; using WIDESEAWCS_DTO.BasicInfo; using WIDESEAWCS_QuartzJob.Models; using WIDESEAWCS_QuartzJob.Repository; using ICacheService = WIDESEAWCS_Core.Caches.ICacheService; namespace WIDESEAWCS_QuartzJob.Service { /// /// 路由配置业务层 /// public class RouterService : ServiceBase, IRouterService { private readonly IDeviceProtocolRepository _deviceProtocolRepository; private readonly IDeviceInfoRepository _deviceInfoRepository; private readonly ICacheService _cacheService; /// /// 路由配置业务层 /// /// /// /// public RouterService(IRouterRepository BaseDal, IDeviceProtocolRepository deviceProtocolRepository, IDeviceInfoRepository deviceInfoRepository, ICacheService cacheService) : base(BaseDal) { _deviceProtocolRepository = deviceProtocolRepository; _deviceInfoRepository = deviceInfoRepository; _cacheService = cacheService; } /// /// 从缓存获取指定类型的全量路由数据,缓存不存在时自动从数据库加载并写入缓存 /// /// 路由类型(入口/出口) /// 该类型的全部路由列表 private List 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) ); } /// /// 清除所有路由缓存(入口和出口类型) /// public void ClearRouterCache() { _cacheService.Remove("Router:AllRouters:In"); _cacheService.Remove("Router:AllRouters:Out"); } /// /// 根据起点/当前位置、终点获取下一个子节点。 /// /// 起点/当前位置。 /// 终点。 /// 返回路由实体集合。 public List QueryNextRoutes(string startPosi, string endPosi) { List routers = new List(); try { // 从缓存加载入口类型和出口类型的路由数据并合并(创建新列表,避免修改缓存引用) List 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}】"); } } catch (Exception ex) { // 记录错误信息 } return routers; } /// /// 根据起点/当前位置、终点获取下一个子节点。 /// /// 起点/当前位置。 /// 终点。 /// 路由类型。 /// 返回路由实体集合。 public List QueryNextRoutes(string startPosi, string endPosi, int routeType) { List routers = new List(); try { // 从缓存加载指定类型的所有路由数据 List allRouters = GetAllRoutersFromCache(routeType); // 在内存中进行路径搜索 routers = FindRoutesInMemory(startPosi, endPosi, allRouters, routeType); if (routers.Count == 0) { throw new Exception($"该路径未配置或配置错误,请检查设备路由信息,起点:【{startPosi}】,终点:【{endPosi}】"); } } catch (Exception ex) { // 记录错误信息 } return routers; } /// /// 在内存中查找从起点到终点的所有路由 /// /// 起点位置 /// 终点位置 /// 所有路由数据 /// 路由类型(可选) /// 符合条件的路由列表 private List FindRoutesInMemory(string startPosi, string endPosi, List allRouters, int? routeType) { List result = new List(); HashSet addedIds = new HashSet(); // 构建索引:以 NextPosi 和 ChildPosi 为键的字典,加速查找 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()); // 找到所有指向终点的路由(终点的父节点) List endRouters = new List(); if (routersByNext.ContainsKey(endPosi)) endRouters.AddRange(routersByNext[endPosi]); if (routersByChild.ContainsKey(endPosi)) endRouters.AddRange(routersByChild[endPosi].Where(r => !endRouters.Any(e => e.Id == r.Id))); // 按 IsEnd 降序排序 endRouters = endRouters.OrderByDescending(r => r.IsEnd).ToList(); // 使用队列进行广度优先搜索 Queue<(Dt_Router router, List path)> queue = new Queue<(Dt_Router, List)>(); // 将所有终点路由加入队列 foreach (var endRouter in endRouters) { queue.Enqueue((endRouter, new List { endRouter })); } // 广度优先搜索 while (queue.Count > 0) { var (currentRouter, currentPath) = queue.Dequeue(); // 如果当前路由的起点就是目标起点,找到完整路径 if (currentRouter.StartPosi == startPosi) { // 将路径中的所有路由添加到结果中(去重) foreach (var router in currentPath) { if (!addedIds.Contains(router.Id)) { result.Add(router); addedIds.Add(router.Id); } } continue; } // 查找当前路由起点的父路由 List parentRouters = new List(); if (routersByNext.ContainsKey(currentRouter.StartPosi)) parentRouters.AddRange(routersByNext[currentRouter.StartPosi]); if (routersByChild.ContainsKey(currentRouter.StartPosi)) parentRouters.AddRange(routersByChild[currentRouter.StartPosi].Where(r => !parentRouters.Any(p => p.Id == r.Id))); // 将父路由加入队列 foreach (var parentRouter in parentRouters) { // 避免循环引用 if (!currentPath.Any(p => p.Id == parentRouter.Id)) { var newPath = new List(currentPath) { parentRouter }; queue.Enqueue((parentRouter, newPath)); } } } return result; } /// /// 根据起点获取下一个单个子节点路由 /// /// 起点/当前位置 /// 返回下一个路由节点,如果没有则返回null public Dt_Router QueryNextRoute(string startPosi) { try { // 从缓存获取入口类型的所有路由数据,基于起点筛选后按IsEnd降序排序 List routes = GetAllRoutersFromCache(RouterInOutType.In.ObjToInt()) .Where(x => x.StartPosi == startPosi) .ToList(); routes = routes.OrderByDescending(x => x.IsEnd).ToList(); // 返回第一个路由 return routes.FirstOrDefault(); } catch (Exception ex) { // 记录错误信息 return null; } } /// /// 根据起点和路由类型获取下一个单个子节点路由 /// /// 起点/当前位置 /// 路由类型 /// 返回下一个路由节点,如果没有则返回null public Dt_Router QueryNextRoute(string startPosi, int routeType) { try { // 从缓存获取指定类型的所有路由数据,筛选起点后按IsEnd降序排列 List routes = GetAllRoutersFromCache(routeType) .Where(x => x.StartPosi == startPosi) .ToList(); routes = routes.OrderByDescending(x => x.IsEnd).ToList(); // 返回第一个路由 return routes.FirstOrDefault(); } catch (Exception ex) { // 记录错误信息 return null; } } /// /// 根据起点、终点方向和路由类型获取下一个单个子节点路由(智能选择朝向终点的路由) /// /// 起点/当前位置 /// 终点位置(用于方向判断) /// 路由类型 /// 返回下一个路由节点,优先返回朝向终点的路由,如果没有则返回null public Dt_Router QueryNextRoute(string startPosi, string endPosi, int routeType) { try { // 从缓存获取指定类型的所有路由数据,筛选起点后按IsEnd降序排列 List routes = GetAllRoutersFromCache(routeType) .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; // 如果没有直接路由,使用缓存中的全量路由数据查找朝向终点的路由 List allRouters = GetAllRoutersFromCache(routeType); foreach (var route in routes) { // 检查从这个路由的下一个位置是否能到达终点 var pathToEnd = FindRoutesInMemory(route.NextPosi, endPosi, allRouters, routeType); if (pathToEnd.Count > 0) return route; } // 如果都不能到达终点,返回第一个路由 return routes.FirstOrDefault(); } catch (Exception ex) { // 记录错误信息 return null; } } /// /// 根据起点、终点方向和路由类型获取下一个单个子节点路由(智能选择朝向终点的路由) /// /// 起点/当前位置 /// 终点位置(用于方向判断) /// 返回下一个路由节点,优先返回朝向终点的路由,如果没有则返回null public Dt_Router QueryNextRoute(string startPosi, string endPosi) { try { // 从缓存获取入口和出口类型的所有路由数据,筛选起点后按IsEnd降序排序 List inRoutes = GetAllRoutersFromCache(RouterInOutType.In.ObjToInt()); List outRoutes = GetAllRoutersFromCache(RouterInOutType.Out.ObjToInt()); List 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(); } catch (Exception ex) { // 记录错误信息 return null; } } /// /// 获取从起点到终点的完整路径(按顺序返回每个子节点路由) /// /// 起点位置 /// 终点位置 /// 路由类型 /// 返回有序的路由列表,如果找不到路径则返回空列表 public List QueryRoutePath(string startPosi, string endPosi, int routeType) { List path = new List(); string currentPosi = startPosi; HashSet visitedPositions = new HashSet(); try { while (currentPosi != endPosi) { if (visitedPositions.Contains(currentPosi)) { break; } 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(); } } catch (Exception ex) { return new List(); } return path; } /// /// 根据设备编号获取对应的路由点位编号(输送线站台编号)信息 /// /// 设备编号 /// 返回路由点位编号(输送线站台编号)集合 public List QueryAllPositions(string deviceCode) { // 创建一个字符串列表,用于存储所有位置 List positions = new List(); var device = _cacheService.Get>($"{RedisPrefix.System}:{RedisName.DevicePositions}:{deviceCode}"); if (device.IsNullOrEmpty()) { try { // 查询所有进入路由器的位置 List inRouterPositions = BaseDal.QueryData(x => x.ChildPosiDeviceCode == deviceCode && x.InOutType == RouterInOutType.In.ObjToInt()).GroupBy(x => x.StartPosi).Select(x => x.Key).ToList(); // 查询所有离开路由器的位置 List 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(); } catch (Exception ex) { ConsoleHelper.WriteErrorLine($"RouterService.QueryAllPositions 查询失败: {ex.Message}"); } finally { _cacheService.TryAdd($"{RedisPrefix.System}:{RedisName.DevicePositions}:{deviceCode}", positions); } } else positions = device; // 返回位置列表 return positions; } /// /// 获取路由表中所有完整的路由信息(前端调用展示数据)。 /// /// 匿名对象集合。 public List GetAllWholeRouters() { List data = new List(); // 从缓存加载入口类型和出口类型的全量路由数据并合并 List inRouters = GetAllRoutersFromCache(RouterInOutType.In.ObjToInt()); List outRouters = GetAllRoutersFromCache(RouterInOutType.Out.ObjToInt()); List allRouters = inRouters.Concat(outRouters).ToList(); // 查询所有结束的路由,并按Id排序 List dt_Routers = allRouters.Where(x => x.IsEnd).OrderBy(x => x.Id).ToList(); // 遍历所有结束的路由 foreach (var item in dt_Routers) { // 获取所有可能的完整路径 List> allPaths = GetAllPaths(item.StartPosi, item.NextPosi, allRouters, item.InOutType); // 为每条独立路径生成结果 foreach (var path in allPaths) { // 如果当前路由是入口 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); } } } // 返回data return data; } /// /// 获取从起点到终点的所有完整路径 /// /// 当前起始位置 /// 终点位置 /// 所有路由数据 /// 路由类型 /// 所有完整路径列表,每条路径是从起点到终点的位置列表 private List> GetAllPaths(string startPosi, string endPosi, List allRouters, int routerType) { List> result = new List>(); // 从终点开始反向查找所有路径 List> reversePaths = new List>(); BuildReversePaths(startPosi, new List { endPosi, startPosi }, allRouters, routerType, reversePaths); // 将反向路径转为正向(从起点到终点) foreach (var reversePath in reversePaths) { result.Add(reversePath.AsEnumerable().Reverse().ToList()); } return result; } /// /// 递归构建反向路径(从终点向起点查找) /// /// 当前节点的起始位置 /// 当前已构建的路径(反向,从终点开始) /// 所有路由数据 /// 路由类型 /// 收集所有完整路径 private void BuildReversePaths(string currentStartPosi, List currentPath, List allRouters, int routerType, List> result) { // 查找当前节点的前置节点(NextPosi等于当前StartPosi的路由) List preRouters = allRouters.Where(x => x.NextPosi == currentStartPosi && x.InOutType == routerType).ToList(); // 如果没有前置节点,说明已经到达路径起点,保存当前路径 if (preRouters.Count == 0) { result.Add(new List(currentPath)); return; } // 对每个前置节点,创建新的路径分支 foreach (var preRouter in preRouters) { // 创建新的路径副本 List newPath = new List(currentPath); newPath.Add(preRouter.StartPosi); // 递归查找前置节点 BuildReversePaths(preRouter.StartPosi, newPath, allRouters, routerType, result); } } /// /// 添加完整路由信息(前端调用配置路由信息)。 /// /// 设备路由配置添加DTO /// 路由类型 /// 返回处理结果 public WebResponseContent AddRouters(List routersAddDTOs, int routerType) { WebResponseContent content = new WebResponseContent(); try { // 检查子位置编号是否重复 if (routersAddDTOs.GroupBy(x => x.ChildPositionCode).Where(x => !string.IsNullOrEmpty(x.Key)).Select(x => x.Count()).Any(x => x > 1)) { return content = WebResponseContent.Instance.Error("子位置编号重复"); } // 检查根位置编号是否重复 if (routersAddDTOs.GroupBy(x => x.PositionCode).Select(x => x.Count()).Any(x => x > 1)) { return content = WebResponseContent.Instance.Error("根位置编号重复"); } // 查询设备信息 List deviceCode = _deviceInfoRepository.QueryTabs((a, b) => new object[] { JoinType.Inner, a.Id == b.DeviceId }, (a, b) => new { b.DeviceChildCode, a.DeviceCode }, (a, b) => true, x => true).Distinct().ToList(); List routers = new List(); // 遍历routersAddDTOs,生成Dt_Router对象 for (int i = 0; i < routersAddDTOs.Count - 1; i++) { dynamic obj = deviceCode.FirstOrDefault(x => x.DeviceChildCode == routersAddDTOs[i + 1].PositionCode || x.DeviceChildCode == routersAddDTOs[i + 1].ChildPositionCode); Dt_Router router = new Dt_Router() { ChildPosi = routersAddDTOs[i + 1].PositionCode, ChildPosiDeviceCode = obj.DeviceCode, Depth = 1, InOutType = routerType, NextPosi = routersAddDTOs[i + 1].PositionCode, SrmColumn = string.IsNullOrEmpty(routersAddDTOs[i].SCColumn) ? int.TryParse(routersAddDTOs[i + 1].SCColumn, out int col) ? col : null : int.TryParse(routersAddDTOs[i].SCColumn, out int col2) ? col2 : null, SrmLayer = string.IsNullOrEmpty(routersAddDTOs[i].SCLayer) ? int.TryParse(routersAddDTOs[i + 1].SCLayer, out int lay) ? lay : null : int.TryParse(routersAddDTOs[i].SCLayer, out int lay2) ? lay2 : null, SrmRow = string.IsNullOrEmpty(routersAddDTOs[i].SCRow) ? int.TryParse(routersAddDTOs[i + 1].SCRow, out int row) ? row : null : int.TryParse(routersAddDTOs[i].SCRow, out int row2) ? row2 : null, StartPosi = routersAddDTOs[i].PositionCode, IsEnd = false }; // 如果是最后一个元素,设置终点位置编号 if (i == routersAddDTOs.Count - 2) { if (routerType == (int)RouterInOutType.Out) router.ChildPosi = routersAddDTOs[i + 1].ChildPositionCode; router.IsEnd = true; } routers.Add(router); } // 检查起点位置编号与子位置编号是否相同 if (routers.Any(x => x.StartPosi == x.ChildPosi)) { return content = WebResponseContent.Instance.Error("输入数据起点位置编号与子位置编号相同"); } // 检查起点位置编号与终点位置编号是否相同 if (routers.Any(x => x.StartPosi == x.NextPosi)) { return content = WebResponseContent.Instance.Error("输入数据起点位置编号与终点位置编号相同"); } // 查询数据库中已有的路由信息 List dt_Routers = BaseDal.QueryData(x => x.InOutType == routerType); // 移除重复的路由信息 dt_Routers.ForEach(x => { var t = routers.FirstOrDefault(v => v.StartPosi == x.StartPosi && v.NextPosi == x.NextPosi); if (t != null) { routers.Remove(t); } var r = routers.FirstOrDefault(v => v.StartPosi == x.StartPosi && v.ChildPosi == x.ChildPosi); if (r != null) { routers.Remove(r); } }); // 添加新的路由信息 BaseDal.AddData(routers); // 重新查询全量路由(此时才包含新增的路由),再写入缓存 List 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) { content = WebResponseContent.Instance.Error(ex.Message); } return content; } } }