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 QueryRoutersByDeviceCode(string deviceCode)
{
// 从缓存获取入口类型和出口类型的全量路由数据
List inRouters = GetAllRoutersFromCache(RouterInOutType.In.ObjToInt());
List outRouters = GetAllRoutersFromCache(RouterInOutType.Out.ObjToInt());
// 合并后筛选出经过指定设备的路由(ChildPosiDeviceCode匹配)
return inRouters.Concat(outRouters)
.Where(x => x.ChildPosiDeviceCode == deviceCode)
.ToList();
}
///
/// 判断两点之间是否存在路由(全类型)
///
public bool ExistsRouter(string startPosi, string endPosi)
{
// 从缓存获取入口类型和出口类型的全量路由数据并合并
List inRouters = GetAllRoutersFromCache(RouterInOutType.In.ObjToInt());
List outRouters = GetAllRoutersFromCache(RouterInOutType.Out.ObjToInt());
var allRouters = inRouters.Concat(outRouters).ToList();
// 在内存中查找从起点到终点的路由
var routes = FindRoutesInMemory(startPosi, endPosi, allRouters, null);
return routes.Count > 0;
}
///
/// 判断两点之间是否存在指定类型的路由
///
public bool ExistsRouter(string startPosi, string endPosi, int routeType)
{
// 从缓存获取指定类型的全量路由数据
List allRouters = GetAllRoutersFromCache(routeType);
// 在内存中查找从起点到终点的路由
var routes = FindRoutesInMemory(startPosi, endPosi, allRouters, routeType);
return routes.Count > 0;
}
///
/// 根据起点/当前位置、终点获取下一个子节点。
///
/// 起点/当前位置。
/// 终点。
/// 返回路由实体集合。
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