| | |
| | | using SqlSugar; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using WIDESEAWCS_Common; |
| | | using WIDESEAWCS_Core; |
| | | using WIDESEAWCS_Core.BaseServices; |
| | | using WIDESEAWCS_Core.Enums; |
| | |
| | | using WIDESEAWCS_DTO.BasicInfo; |
| | | using WIDESEAWCS_QuartzJob.Models; |
| | | using WIDESEAWCS_QuartzJob.Repository; |
| | | using ICacheService = WIDESEAWCS_Core.Caches.ICacheService; |
| | | |
| | | namespace WIDESEAWCS_QuartzJob.Service |
| | | { |
| | |
| | | { |
| | | private readonly IDeviceProtocolRepository _deviceProtocolRepository; |
| | | private readonly IDeviceInfoRepository _deviceInfoRepository; |
| | | private readonly ICacheService _cacheService; |
| | | |
| | | /// <summary> |
| | | /// 路由配置业务层 |
| | |
| | | /// <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> |
| | | /// 判断两点之间是否存在路由(全类型) |
| | | /// </summary> |
| | | public bool ExistsRouter(string startPosi, string endPosi) |
| | | { |
| | | // 从缓存获取入口类型和出口类型的全量路由数据并合并 |
| | | List<Dt_Router> inRouters = GetAllRoutersFromCache(RouterInOutType.In.ObjToInt()); |
| | | List<Dt_Router> outRouters = GetAllRoutersFromCache(RouterInOutType.Out.ObjToInt()); |
| | | var allRouters = inRouters.Concat(outRouters).ToList(); |
| | | // 在内存中查找从起点到终点的路由 |
| | | var routes = FindRoutesInMemory(startPosi, endPosi, allRouters, null); |
| | | return routes.Count > 0; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 判断两点之间是否存在指定类型的路由 |
| | | /// </summary> |
| | | public bool ExistsRouter(string startPosi, string endPosi, int routeType) |
| | | { |
| | | // 从缓存获取指定类型的全量路由数据 |
| | | List<Dt_Router> allRouters = GetAllRoutersFromCache(routeType); |
| | | // 在内存中查找从起点到终点的路由 |
| | | var routes = FindRoutesInMemory(startPosi, endPosi, allRouters, routeType); |
| | | return routes.Count > 0; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取全量路由数量(入口+出口合计) |
| | | /// </summary> |
| | | public int GetRouterCount() |
| | | { |
| | | // 分别获取入口类型和出口类型的路由数量并相加 |
| | | int inCount = GetAllRoutersFromCache(RouterInOutType.In.ObjToInt()).Count; |
| | | int outCount = GetAllRoutersFromCache(RouterInOutType.Out.ObjToInt()).Count; |
| | | return inCount + outCount; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取指定类型路由数量 |
| | | /// </summary> |
| | | public int GetRouterCount(int routeType) |
| | | { |
| | | // 获取指定类型的全量路由数据并返回数量 |
| | | return GetAllRoutersFromCache(routeType).Count; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 批量删除指定ID的路由,删除后同步清除对应类型的缓存 |
| | | /// </summary> |
| | | /// <param name="routerIds">待删除的路由ID列表</param> |
| | | /// <returns>返回处理结果</returns> |
| | | public WebResponseContent DeleteRouters(List<long> routerIds) |
| | | { |
| | | WebResponseContent content = new WebResponseContent(); |
| | | try |
| | | { |
| | | if (routerIds == null || routerIds.Count == 0) |
| | | { |
| | | return content = WebResponseContent.Instance.Error("待删除的路由ID列表不能为空"); |
| | | } |
| | | |
| | | // 查询待删除路由的类型(用于后续清除缓存) |
| | | var routersToDelete = BaseDal.QueryData(x => routerIds.Contains(x.Id)); |
| | | if (routersToDelete.Count == 0) |
| | | { |
| | | return content = WebResponseContent.Instance.Error("未找到待删除的路由"); |
| | | } |
| | | |
| | | // 记录涉及的类型(去重) |
| | | var affectedTypes = routersToDelete.Select(x => x.InOutType).Distinct().ToList(); |
| | | |
| | | // 执行批量删除 |
| | | BaseDal.DeleteData(routersToDelete); |
| | | |
| | | // 清除受影响类型的缓存 |
| | | foreach (var routeType in affectedTypes) |
| | | { |
| | | string cacheKey = $"Router:AllRouters:{(routeType == RouterInOutType.In.ObjToInt() ? "In" : "Out")}"; |
| | | _cacheService.Remove(cacheKey); |
| | | } |
| | | |
| | | content = WebResponseContent.Instance.OK(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | content = WebResponseContent.Instance.Error(ex.Message); |
| | | } |
| | | return content; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | 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}】"); |
| | |
| | | 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}】"); |
| | |
| | | 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()); |
| | |
| | | |
| | | // 使用队列进行广度优先搜索 |
| | | Queue<(Dt_Router router, List<Dt_Router> path)> queue = new Queue<(Dt_Router, List<Dt_Router>)>(); |
| | | |
| | | |
| | | // 将所有终点路由加入队列 |
| | | foreach (var endRouter in endRouters) |
| | | { |
| | |
| | | { |
| | | 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(); |
| | | } |
| | |
| | | { |
| | | 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(); |
| | | } |
| | |
| | | { |
| | | 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; |
| | | |
| | |
| | | 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) |
| | | { |
| | | // 检查从这个路由的下一个位置是否能到达终点 |
| | |
| | | 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(); |
| | |
| | | List<Dt_Router> path = new List<Dt_Router>(); |
| | | string currentPosi = startPosi; |
| | | HashSet<string> visitedPositions = new HashSet<string>(); |
| | | |
| | | |
| | | try |
| | | { |
| | | while (currentPosi != endPosi) |
| | |
| | | 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>(); |
| | |
| | | { |
| | | return new List<Dt_Router>(); |
| | | } |
| | | |
| | | |
| | | return path; |
| | | } |
| | | |
| | |
| | | { |
| | | // 创建一个字符串列表,用于存储所有位置 |
| | | 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; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取路由表中所有完整的路由信息(前端调用展示数据)。 |
| | | /// </summary> |
| | |
| | | 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(); |
| | | |
| | |
| | | |
| | | // 添加新的路由信息 |
| | | 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) |
| | |
| | | return content; |
| | | } |
| | | } |
| | | } |
| | | } |