485 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			485 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
using LY.App.Common;
 | 
						||
using LY.App.Common.Redis;
 | 
						||
using LY.App.Common.WebSocket;
 | 
						||
using LY.App.Extensions.DI;
 | 
						||
using LY.App.Model;
 | 
						||
using Mapster;
 | 
						||
using NetTopologySuite.Geometries;
 | 
						||
using NetTopologySuite.IO;
 | 
						||
using SqlSugar;
 | 
						||
 | 
						||
namespace LY.App.Service
 | 
						||
{
 | 
						||
    /// <summary>
 | 
						||
    /// 报警服务
 | 
						||
    /// </summary>
 | 
						||
    [ServiceInjection(InjectionType.Transient)]
 | 
						||
    public class AlarmService
 | 
						||
    {
 | 
						||
        private readonly SqlSugarClient _db;
 | 
						||
        private readonly IConfiguration _config;
 | 
						||
        private readonly RedisService _redisService;
 | 
						||
        private readonly PushService _pushService;
 | 
						||
        public AlarmService(SqlSugarClient db, IConfiguration config, RedisService redisService, PushService pushService)
 | 
						||
        {
 | 
						||
            _db = db;
 | 
						||
            _config = config;
 | 
						||
            _redisService = redisService;
 | 
						||
            _pushService = pushService;
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// 新增报警信息
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="input"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        public async Task<ApiResult> AddAlarm(RevData input)
 | 
						||
        {
 | 
						||
            await SetDeviceStataus(input);
 | 
						||
            var key = RedisKeyList.DeviceInfo(input.product_ad_id);
 | 
						||
            var deviceinfo = await _redisService.GetAsync<DeviceEntity>(key);
 | 
						||
            if (deviceinfo == null)
 | 
						||
            {
 | 
						||
                deviceinfo = await _db.CopyNew().Queryable<DeviceEntity>().Where(s => s.DeviceSN == input.product_ad_id).FirstAsync();
 | 
						||
                if (deviceinfo == null)
 | 
						||
                {
 | 
						||
                    return new ApiResult() { code = 1, msg = "设备不存在" };
 | 
						||
                }
 | 
						||
                await _redisService.SetAsync(key, deviceinfo, TimeSpan.FromDays(1));
 | 
						||
            }
 | 
						||
            var entity = input.data.Adapt<List<Alarm>>();
 | 
						||
            if (entity.Any())
 | 
						||
            {
 | 
						||
                var O4entity = entity.Where(s => s.device_type == "O4" || s.serial_number == "O4");
 | 
						||
                entity = entity.Where(s => checkDistance(s.drone_lat, s.drone_lon, deviceinfo.Lat, deviceinfo.Lon) == true).ToList();
 | 
						||
                if (O4entity.Any())
 | 
						||
                {
 | 
						||
                    entity.AddRange(O4entity);
 | 
						||
                }
 | 
						||
                foreach (var item in entity)
 | 
						||
                {
 | 
						||
                    item.BatchId = await GetBatId(item.serial_number);
 | 
						||
                    item.DeviceId = deviceinfo.Id;
 | 
						||
                    item.DeviceName = deviceinfo.Name;
 | 
						||
                    item.positionId = deviceinfo.PositionId;
 | 
						||
                    item.PostionName = deviceinfo.PositionName;
 | 
						||
                    item.Time = input.time;
 | 
						||
                    item.distance = GisHelper.HaversineDistance(item.drone_lat, item.drone_lon, item.app_lat, item.app_lon);
 | 
						||
                    item.IsWhitelist = await Iswhitlist(item.serial_number, item.drone_lat, item.drone_lon);
 | 
						||
                    item.alarmLevel = item.IsWhitelist == true ? 0 : await GetAlarmLevel(deviceinfo.PositionId, item.drone_lon, item.drone_lat);
 | 
						||
                    item.centerdistance = await GetCenterDistance(item.drone_lat, item.drone_lon, item.positionId);
 | 
						||
                }
 | 
						||
                await _db.CopyNew().Insertable(entity).SplitTable().ExecuteReturnSnowflakeIdListAsync();
 | 
						||
                //推送报警信息
 | 
						||
                await _pushService.SendMessageToAll(new { msgType = "event", data = entity });
 | 
						||
            }
 | 
						||
            return new ApiResult();
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        ///     防区中心距离
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="lat"></param>
 | 
						||
        /// <param name="lon"></param>
 | 
						||
        /// <param name="positioonId"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        private async Task<double> GetCenterDistance(double lat, double lon, long positioonId)
 | 
						||
        {
 | 
						||
            try
 | 
						||
            {
 | 
						||
                var key = RedisKeyList.PositioinRegion(positioonId);
 | 
						||
                var pontion = await _redisService.GetAsync<PositionInfo>(key);
 | 
						||
                if (pontion == null)
 | 
						||
                {
 | 
						||
                    pontion = await _db.CopyNew().Queryable<PositionInfo>()
 | 
						||
                       .Where(s => s.Id == positioonId)
 | 
						||
                       .FirstAsync();
 | 
						||
                    await _redisService.SetAsync(key, pontion);
 | 
						||
                }
 | 
						||
                var distance = GisHelper.HaversineDistance(lat, lon, pontion.lat, pontion.lat);
 | 
						||
                return distance;
 | 
						||
            }
 | 
						||
            catch (Exception ex)
 | 
						||
            {
 | 
						||
                Console.WriteLine(ex.Message);
 | 
						||
            }
 | 
						||
            return 0;
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// 判断 距离是否在范围内
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="lat"></param>
 | 
						||
        /// <param name="lon"></param>
 | 
						||
        /// <param name="d_lat"></param>
 | 
						||
        /// <param name="d_lon"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        private bool checkDistance(double lat, double lon, double d_lat, double d_lon)
 | 
						||
        {
 | 
						||
            if (lat == 0 || lon == 0) return false;
 | 
						||
            var maxDistance = Convert.ToDouble(_config["MaxDistance"]);
 | 
						||
            var distance = GisHelper.HaversineDistance(lat, lon, d_lat, d_lon);
 | 
						||
            return distance < maxDistance;
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 判断是否在白名单中
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="serial_number"></param>
 | 
						||
        /// <param name="lat"></param>
 | 
						||
        /// <param name="lon"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        private async Task<bool> Iswhitlist(string serial_number, double lat, double lon)
 | 
						||
        {
 | 
						||
            string key = RedisKeyList.white_list(serial_number);
 | 
						||
            if (!await _redisService.ExistsAsync(key))
 | 
						||
                return false;
 | 
						||
            else
 | 
						||
            {
 | 
						||
                var entity = await _redisService.GetAsync<Whitelist>(key);
 | 
						||
                //判断 是否在防区内 
 | 
						||
                if (entity.positionId.Any())
 | 
						||
                {
 | 
						||
                    foreach (var item in entity.positionId)
 | 
						||
                    {
 | 
						||
                        var region = await _redisService.GetAsync<PositionInfo>(RedisKeyList.PositioinRegion(item));
 | 
						||
                        if (region != null)
 | 
						||
                        {
 | 
						||
                            region.SetRegionJson();
 | 
						||
                            if (IsPointInGeoJson(lat, lon, region.RegionJson))
 | 
						||
                            {
 | 
						||
                                //判断时间是否在区在
 | 
						||
                                if (entity.allDay)
 | 
						||
                                {
 | 
						||
                                    return true;
 | 
						||
                                }
 | 
						||
                                else
 | 
						||
                                {
 | 
						||
                                    return entity.startTime <= DateTime.Now && DateTime.Now <= entity.endTime;
 | 
						||
                                }
 | 
						||
                            }
 | 
						||
                        }
 | 
						||
 | 
						||
                    }
 | 
						||
                }
 | 
						||
            }
 | 
						||
            return false;
 | 
						||
        }
 | 
						||
 | 
						||
        static bool IsPointInGeoJson(double latitude, double longitude, string geoJson)
 | 
						||
        {
 | 
						||
            // 使用 NetTopologySuite 解析 GeoJSON
 | 
						||
            var reader = new GeoJsonReader();
 | 
						||
            Geometry geometry = reader.Read<Geometry>(geoJson);
 | 
						||
            // 创建点
 | 
						||
            var point = new Point(longitude, latitude);
 | 
						||
 | 
						||
            // 判断点是否在几何图形内
 | 
						||
            return geometry.Contains(point);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 计算入侵级别
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="positionId"></param>
 | 
						||
        /// <param name="lon"></param>
 | 
						||
        /// <param name="lat"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        private async Task<int> GetAlarmLevel(long positionId, double lon, double lat)
 | 
						||
        {
 | 
						||
            int result = 0;
 | 
						||
            if (positionId > 0 && lon > 0 && lat > 0)
 | 
						||
            {
 | 
						||
                var key = RedisKeyList.PositioinRegion(positionId);
 | 
						||
                var geodata = await _redisService.GetAsync<PositionInfo>(key);
 | 
						||
                if (geodata == null)
 | 
						||
                {
 | 
						||
                    geodata = await _db.CopyNew().Queryable<PositionInfo>()
 | 
						||
                       .Where(s => s.Id == positionId)
 | 
						||
                       .FirstAsync();
 | 
						||
                    await _redisService.SetAsync<PositionInfo>(key, geodata);
 | 
						||
                }
 | 
						||
                WKTReader reader = new WKTReader();
 | 
						||
                Geometry point = reader.Read($"POINT ({lon} {lat})");
 | 
						||
                Geometry multipolygon = reader.Read(geodata.Region);
 | 
						||
                if (multipolygon.Contains(point))
 | 
						||
                {
 | 
						||
                    return 1;
 | 
						||
                }
 | 
						||
            }
 | 
						||
            return result;
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// 推送消息
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="message"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        public async Task PushMessage(object message)
 | 
						||
        {
 | 
						||
            //推送前端无人机数据
 | 
						||
            await _pushService.SendMessageToAll(message);
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// 设置设备在线状态,并更新数据
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="input"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        private async Task SetDeviceStataus(RevData input)
 | 
						||
        {
 | 
						||
            await _redisService.SetAsync(RedisKeyList.DeviceStatus(input.product_ad_id), true, TimeSpan.FromSeconds(5));
 | 
						||
            //更新 设备缓存
 | 
						||
            var key = RedisKeyList.DeviceInfo(input.product_ad_id);
 | 
						||
            var deviceinfo = await _redisService.GetAsync<DeviceEntity>(key);
 | 
						||
            if (deviceinfo != null && deviceinfo.isMove)
 | 
						||
            {
 | 
						||
                deviceinfo.Lat = input.product_lat;
 | 
						||
                deviceinfo.Lon = input.product_lon;
 | 
						||
                await _redisService.SetAsync(key, deviceinfo);
 | 
						||
                //更新位置
 | 
						||
                //   await _db.Updateable(deviceinfo).ExecuteCommandAsync();
 | 
						||
                await _db.CopyNew().Updateable<DeviceEntity>(deviceinfo).UpdateColumns(it => new { it.Lat, it.Lon }).ExecuteCommandAsync();
 | 
						||
            }
 | 
						||
        }
 | 
						||
        private async Task<long> GetBatId(string droneId)
 | 
						||
        {
 | 
						||
            var timeSpan = Convert.ToDouble(_config["BatchId"]);
 | 
						||
            var key = RedisKeyList.BatchIdBysn(droneId);
 | 
						||
            //从redis取出batchid,如果没有,就新加一个,每次访问都重置一下过期时间来模拟滑动过期
 | 
						||
            var batchId = await _redisService.GetAsync<long>(key);
 | 
						||
            if (batchId == 0)
 | 
						||
            {
 | 
						||
                batchId = SnowFlakeSingle.Instance.NextId();
 | 
						||
                await _redisService.DeleteAsync(RedisKeyList.index_data());
 | 
						||
            }
 | 
						||
            await _redisService.SetAsync(key, batchId, TimeSpan.FromSeconds(timeSpan));
 | 
						||
            return batchId;
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// //根据batchId获取报警信息
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="batchId"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        public async Task<ApiResult> GetByBatchId(long batchId)
 | 
						||
        {
 | 
						||
            var items = await _db.Queryable<Alarm>().SplitTable()
 | 
						||
                  .Where(s => s.BatchId == batchId)
 | 
						||
                  .OrderBy(s => s.Id).Select(s => new
 | 
						||
                  {
 | 
						||
                      Lon = s.drone_lon,
 | 
						||
                      Lat = s.drone_lat,
 | 
						||
                      Alt = s.height,
 | 
						||
                      s.app_lat,
 | 
						||
                      s.app_lon,
 | 
						||
                      s.CreateTime,
 | 
						||
                      AlarmLevel = s.alarmLevel,
 | 
						||
                  }).ToListAsync();
 | 
						||
            return new ApiResult() { data = items };
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 首页统计
 | 
						||
        /// </summary>
 | 
						||
        /// <returns></returns>
 | 
						||
        public async Task<Dictionary<string, int>> IndexCount()
 | 
						||
        {
 | 
						||
            Dictionary<string, int> result = new Dictionary<string, int>();
 | 
						||
            // 获取当前日期和时间
 | 
						||
            DateTime currentDate = DateTime.Now;
 | 
						||
            // 获取当天的开始时间
 | 
						||
            DateTime startDate = currentDate.Date;
 | 
						||
            // 获取当天的结束时间(23:59:59)
 | 
						||
            DateTime endDate = currentDate.Date.AddDays(1).AddTicks(-1);
 | 
						||
            //计算当天
 | 
						||
            var todaywaring = await _db.Queryable<Alarm>().SplitTable()
 | 
						||
                .Where(s => s.alarmLevel > 0 && s.IsWhitelist == false)
 | 
						||
                .Where(s => s.CreateTime >= startDate && s.CreateTime <= endDate)
 | 
						||
                .GroupBy(s => s.BatchId)
 | 
						||
                .Select(s => s.BatchId).CountAsync();
 | 
						||
            //计算当天处理次数
 | 
						||
            //var todayhandle = _db.Queryable<AttackEntity>()
 | 
						||
            //    .Where(s => s.BatchId > 0)
 | 
						||
            //    .Where(s => s.CreateTime >= startDate && s.CreateTime <= endDate);
 | 
						||
            //计算总数
 | 
						||
            var totalcount = _db.Queryable<Alarm>().SplitTable()
 | 
						||
                        .Where(s => s.alarmLevel > 0 && s.IsWhitelist == false)
 | 
						||
                 .GroupBy(s => s.BatchId)
 | 
						||
                 .Select(s => s.BatchId);
 | 
						||
            //计算处理总数
 | 
						||
            //var totalhandle = _db.Queryable<AttackEntity>()
 | 
						||
            //    .Where(x => x.BatchId > 0);
 | 
						||
            //组合查询结果
 | 
						||
            //return new
 | 
						||
            //{
 | 
						||
            //    todaywaring = await todaywaring.CountAsync(),
 | 
						||
            //    todayhandle =0,
 | 
						||
            //    totalcount = await totalcount.CountAsync(),
 | 
						||
            //    totalhandle = 0
 | 
						||
            //};
 | 
						||
            result.Add("todaywaring", todaywaring);
 | 
						||
            result.Add("todayhandle", 0);
 | 
						||
            result.Add("totalcount", await totalcount.CountAsync());
 | 
						||
            result.Add("totalhandle", 0);
 | 
						||
            return result;
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// 分页
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="input"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        public async Task<ApiResult> GetPage(AlarmReq input)
 | 
						||
        {
 | 
						||
            var result = await CreatePage(input);
 | 
						||
            return new ApiResult()
 | 
						||
            {
 | 
						||
                code = 0,
 | 
						||
                data = new
 | 
						||
                {
 | 
						||
                    total = result.Item1,
 | 
						||
                    items = result.Item2
 | 
						||
                }
 | 
						||
            };
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// 热力图
 | 
						||
        /// </summary>
 | 
						||
        /// <returns></returns>
 | 
						||
        public async Task<ApiResult> hotmap()
 | 
						||
        {
 | 
						||
            var query = await _db.Queryable<Alarm>().SplitTable()
 | 
						||
                .GroupBy(x => new { Lon = SqlFunc.Round(x.drone_lon, 4), Lat = SqlFunc.Round(x.drone_lat, 4) }) // 按经纬度分组
 | 
						||
                .Select(x => new
 | 
						||
                {
 | 
						||
                    Lon = SqlFunc.Round(x.drone_lon, 4),
 | 
						||
                    Lat = SqlFunc.Round(x.drone_lat, 4),
 | 
						||
                    Count = SqlFunc.AggregateCount(x.BatchId), // 统计去重后的BatchId
 | 
						||
                })
 | 
						||
                .ToListAsync();
 | 
						||
            return new ApiResult() { data = query };
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// 列表
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="input"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        public async Task<Tuple<int, List<AlarmRepDto>>> CreatePage(AlarmReq input)
 | 
						||
        {
 | 
						||
            RefAsync<int> total = 0;
 | 
						||
            var items = await _db.Queryable<Alarm>().SplitTable()
 | 
						||
                .WhereIF(input.Frequency.HasValue, st => st.freq == input.Frequency.Value)
 | 
						||
                .WhereIF(!string.IsNullOrEmpty(input.sn), s => s.serial_number.Contains(input.sn))
 | 
						||
                .WhereIF(!string.IsNullOrEmpty(input.model), st => st.device_type == input.model)
 | 
						||
                .WhereIF(input.strartDate.HasValue, st => st.CreateTime >= input.strartDate.Value)
 | 
						||
                .WhereIF(input.endDate.HasValue, st => st.CreateTime <= input.endDate.Value.AddDays(1))
 | 
						||
                .OrderBy(s => s.BatchId, OrderByType.Desc)
 | 
						||
                .GroupBy(s => new { s.BatchId, s.serial_number, s.device_type, s.positionId, s.PostionName, s.freq })
 | 
						||
                .Select(st => new AlarmRepDto
 | 
						||
                {
 | 
						||
                    batchId = st.BatchId.ToString(),
 | 
						||
                    startTime = SqlFunc.AggregateMin(st.CreateTime),
 | 
						||
                    endTime = SqlFunc.AggregateMax(st.CreateTime),
 | 
						||
                    sn = st.serial_number,
 | 
						||
                    Frequency = st.freq,
 | 
						||
                    duration = (SqlFunc.AggregateMax(st.CreateTime) - SqlFunc.AggregateMin(st.CreateTime)).TotalSeconds,
 | 
						||
                    model = st.device_type,
 | 
						||
                    positionId = st.positionId,
 | 
						||
                    positionName = st.PostionName
 | 
						||
                }).MergeTable()//合并查询
 | 
						||
                .ToPageListAsync(input.pageNum, input.pageSize, total);
 | 
						||
            return Tuple.Create(total.Value, items);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 报表统计
 | 
						||
        /// </summary>
 | 
						||
        /// <returns></returns>
 | 
						||
        public async Task<ApiResult> GetReport(DateTime? start, DateTime? end)
 | 
						||
        {
 | 
						||
            start = start.HasValue ? start.Value : DateTime.Now.AddMonths(-1);
 | 
						||
            end = end.HasValue ? end.Value.AddDays(1) : DateTime.Now.Date.AddDays(1);
 | 
						||
            var query = await _db.Queryable<Alarm>().SplitTable()
 | 
						||
                .Where(s => s.alarmLevel > 0)
 | 
						||
                .WhereIF(start.HasValue, st => st.CreateTime >= start.Value)
 | 
						||
                .WhereIF(end.HasValue, st => st.CreateTime <= end.Value.AddDays(1))
 | 
						||
                .GroupBy(s => new { s.BatchId, s.serial_number, s.device_type, s.positionId, s.PostionName, s.DeviceId, s.DeviceName })
 | 
						||
                .Select(st => new
 | 
						||
                {
 | 
						||
                    batchId = st.BatchId,
 | 
						||
                    startTime = SqlFunc.AggregateMin(st.CreateTime),
 | 
						||
                    endTime = SqlFunc.AggregateMax(st.CreateTime),
 | 
						||
                    sn = st.serial_number,
 | 
						||
                    Frequency = SqlFunc.AggregateMax(st.freq),
 | 
						||
                    duration = (SqlFunc.AggregateMax(st.CreateTime) - SqlFunc.AggregateMin(st.CreateTime)).TotalSeconds,
 | 
						||
                    model = st.device_type,
 | 
						||
                    positionName = st.PostionName,
 | 
						||
                    deviceId = st.DeviceId,
 | 
						||
                    deviceName = st.DeviceName
 | 
						||
                }).MergeTable()//合并查询
 | 
						||
                .ToListAsync();
 | 
						||
            return new ApiResult()
 | 
						||
            {
 | 
						||
                data = new
 | 
						||
                {
 | 
						||
                    freq = query.GroupBy(s => new { freq = FreqConvert.CoverFreq(s.Frequency) })
 | 
						||
                   .Select(b => new
 | 
						||
                   {
 | 
						||
                       b.Key.freq,
 | 
						||
                       count = b.Count()
 | 
						||
                   }),
 | 
						||
                    model = query.GroupBy(s => new { s.model })
 | 
						||
                   .Select(b => new
 | 
						||
                   {
 | 
						||
                       b.Key.model,
 | 
						||
                       count = b.Count()
 | 
						||
                   }),
 | 
						||
                    position = query.GroupBy(s => new { s.positionName })
 | 
						||
                   .Select(s => new
 | 
						||
                   {
 | 
						||
                       s.Key.positionName,
 | 
						||
                       count = s.Count()
 | 
						||
                   }),
 | 
						||
                    time = query.GroupBy(s => s.startTime.ToString("HH"))
 | 
						||
                    .Select(it => new
 | 
						||
                    {
 | 
						||
                        it.Key,
 | 
						||
                        count = it.Count()
 | 
						||
                    }),
 | 
						||
                    date = query.GroupBy(s => s.startTime.ToString("yyyy-MM-dd"))
 | 
						||
                    .Select(it => new
 | 
						||
                    {
 | 
						||
                        it.Key,
 | 
						||
                        count = it.Count()
 | 
						||
                    }),
 | 
						||
                    device = query.GroupBy(s => new { s.deviceName })
 | 
						||
                   .Select(b => new
 | 
						||
                   {
 | 
						||
                       b.Key.deviceName,
 | 
						||
                       count = b.Count()
 | 
						||
                   })
 | 
						||
                }
 | 
						||
            };
 | 
						||
        }
 | 
						||
        /// <summary>
 | 
						||
        /// 热力图,取经纬度4位数
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="batchIds"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        private async Task<object> GenerateHotMap(List<long> batchIds)
 | 
						||
        {
 | 
						||
            return await _db.Queryable<Alarm>().SplitTable()
 | 
						||
                .Where(s => s.drone_lat > 0 && s.drone_lon > 0 && batchIds.Contains(s.BatchId))
 | 
						||
                .Select(s => new
 | 
						||
                {
 | 
						||
                    drone_lon = SqlFunc.Round(s.drone_lon, 4),
 | 
						||
                    drone_lat = SqlFunc.Round(s.drone_lat, 4),
 | 
						||
                })
 | 
						||
                .GroupBy(s => new { s.drone_lat, s.drone_lon })
 | 
						||
                .Select(s => new
 | 
						||
                {
 | 
						||
                    Key = new { Lon = SqlFunc.Round(s.drone_lat, 4), Lat = SqlFunc.Round(s.drone_lon, 4) },
 | 
						||
                    val = SqlFunc.AggregateCount(s)
 | 
						||
                })
 | 
						||
                .ToListAsync();
 | 
						||
        }
 | 
						||
    }
 | 
						||
}
 |