2025-03-22 12:16:22 +00:00
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 ;
2025-03-26 02:47:56 +00:00
using NetTopologySuite.Geometries ;
using NetTopologySuite.IO ;
2025-03-22 12:16:22 +00:00
using SqlSugar ;
2025-06-25 16:10:27 +00:00
using System.ComponentModel.DataAnnotations ;
2025-03-22 12:16:22 +00:00
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 ) ;
2025-04-05 09:50:08 +00:00
var key = RedisKeyList . DeviceInfo ( input . product_ad_id ) ;
var deviceinfo = await _redisService . GetAsync < DeviceEntity > ( key ) ;
if ( deviceinfo = = null )
2025-03-22 12:16:22 +00:00
{
2025-04-05 09:50:08 +00:00
deviceinfo = await _db . CopyNew ( ) . Queryable < DeviceEntity > ( ) . Where ( s = > s . DeviceSN = = input . product_ad_id ) . FirstAsync ( ) ;
2025-03-22 12:16:22 +00:00
if ( deviceinfo = = null )
{
2025-04-05 09:50:08 +00:00
return new ApiResult ( ) { code = 1 , msg = "设备不存在" } ;
2025-03-22 12:16:22 +00:00
}
2025-04-05 09:50:08 +00:00
await _redisService . SetAsync ( key , deviceinfo , TimeSpan . FromDays ( 1 ) ) ;
2025-03-22 12:16:22 +00:00
}
2025-04-05 13:08:36 +00:00
var entity = input . data . Adapt < List < Alarm > > ( ) ;
2025-04-06 13:56:20 +00:00
if ( entity . Any ( ) )
2025-04-05 13:08:36 +00:00
{
2025-04-23 05:10:24 +00:00
// 排除掉不在范围内的报警信息
2025-04-23 03:18:53 +00:00
var O4entity = entity . Where ( s = > s . device_type = = "O4" | | s . serial_number = = "O4" | | s . device_type = = "UAV" | | ! string . IsNullOrEmpty ( s . device_type ) ) ;
2025-09-20 09:17:51 +00:00
entity = entity . Where ( s = > checkDistance ( s . drone_lat , s . drone_lon , deviceinfo . Lat , deviceinfo . Lon ) = = true ) . ToList ( ) ;
2025-04-17 16:48:02 +00:00
if ( O4entity . Any ( ) )
{
2025-09-20 08:28:08 +00:00
foreach ( var item in O4entity )
{
if ( ! entity . Exists ( s = > s . serial_number = = item . serial_number ) )
{
entity . Add ( item ) ;
}
}
2025-04-23 05:10:24 +00:00
}
2025-09-20 09:17:51 +00:00
entity = entity . Distinct ( ) . ToList ( ) ;
2025-04-23 05:10:24 +00:00
if ( entity . Any ( ) )
{
2025-04-23 02:05:59 +00:00
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 ) ;
2025-06-25 16:10:27 +00:00
var temp = await Iswhitlist ( item . serial_number , item . drone_lat , item . drone_lon ) ;
item . IsWhitelist = temp . Item1 ;
item . WhiteListId = temp . Item2 ;
2025-04-23 02:05:59 +00:00
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 } ) ;
2025-04-17 16:48:02 +00:00
}
2025-04-05 13:08:36 +00:00
}
2025-03-22 12:16:22 +00:00
return new ApiResult ( ) ;
2025-03-26 02:47:56 +00:00
}
2025-04-13 05:55:26 +00:00
/// <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 ) ;
}
2025-04-25 17:23:01 +00:00
var distance = GisHelper . HaversineDistance ( lat , lon , pontion . lat , pontion . lon ) ;
2025-04-13 05:55:26 +00:00
return distance ;
}
catch ( Exception ex )
{
Console . WriteLine ( ex . Message ) ;
}
return 0 ;
}
2025-04-12 09:46:40 +00:00
/// <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 )
{
2025-04-17 16:48:02 +00:00
if ( lat = = 0 | | lon = = 0 ) return false ;
2025-04-12 09:46:40 +00:00
var maxDistance = Convert . ToDouble ( _config [ "MaxDistance" ] ) ;
var distance = GisHelper . HaversineDistance ( lat , lon , d_lat , d_lon ) ;
return distance < maxDistance ;
}
2025-04-12 15:17:49 +00:00
/// <summary>
/// 判断是否在白名单中
/// </summary>
/// <param name="serial_number"></param>
/// <param name="lat"></param>
/// <param name="lon"></param>
/// <returns></returns>
2025-06-25 16:10:27 +00:00
private async Task < Tuple < bool , long > > Iswhitlist ( string serial_number , double lat , double lon )
2025-04-12 09:46:40 +00:00
{
2025-04-12 15:17:49 +00:00
string key = RedisKeyList . white_list ( serial_number ) ;
2025-07-09 12:52:45 +00:00
if ( await _redisService . ExistsAsync ( key ) )
2025-04-12 09:46:40 +00:00
{
2025-04-12 15:17:49 +00:00
var entity = await _redisService . GetAsync < Whitelist > ( key ) ;
2025-07-09 12:52:45 +00:00
//判断时间是否在区在
if ( entity . allDay )
2025-04-12 15:17:49 +00:00
{
2025-07-09 12:52:45 +00:00
return new Tuple < bool , long > ( true , entity . Id ) ;
}
else
{
var has = entity . startTime < = DateTime . Now & & DateTime . Now < = entity . endTime ;
return new Tuple < bool , long > ( has , has ? entity . Id : 0 ) ;
2025-04-12 15:17:49 +00:00
}
2025-06-26 15:34:41 +00:00
}
2025-06-25 16:10:27 +00:00
return new Tuple < bool , long > ( false , 0 ) ; ;
2025-04-12 09:46:40 +00:00
}
2025-03-26 02:47:56 +00:00
2025-04-12 15:17:49 +00:00
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 ) ;
}
2025-03-26 02:47:56 +00:00
/// <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 ) ;
2025-04-13 07:41:40 +00:00
var geodata = await _redisService . GetAsync < PositionInfo > ( key ) ;
2025-03-26 02:54:22 +00:00
if ( geodata = = null )
{
geodata = await _db . CopyNew ( ) . Queryable < PositionInfo > ( )
. Where ( s = > s . Id = = positionId )
. FirstAsync ( ) ;
2025-04-13 07:41:40 +00:00
await _redisService . SetAsync < PositionInfo > ( key , geodata ) ;
2025-03-26 02:54:22 +00:00
}
2025-03-26 02:47:56 +00:00
WKTReader reader = new WKTReader ( ) ;
Geometry point = reader . Read ( $"POINT ({lon} {lat})" ) ;
2025-04-13 07:41:40 +00:00
Geometry multipolygon = reader . Read ( geodata . Region ) ;
2025-03-26 02:54:22 +00:00
if ( multipolygon . Contains ( point ) )
2025-03-26 02:47:56 +00:00
{
2025-03-26 02:54:22 +00:00
return 1 ;
2025-03-26 02:47:56 +00:00
}
}
return result ;
2025-03-22 12:16:22 +00:00
}
/// <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 )
{
2025-04-22 12:35:21 +00:00
await _redisService . SetAsync ( RedisKeyList . DeviceStatus ( input . product_ad_id ) , true , TimeSpan . FromSeconds ( 15 ) ) ;
2025-03-22 12:16:22 +00:00
//更新 设备缓存
var key = RedisKeyList . DeviceInfo ( input . product_ad_id ) ;
var deviceinfo = await _redisService . GetAsync < DeviceEntity > ( key ) ;
2025-04-12 09:46:40 +00:00
if ( deviceinfo ! = null & & deviceinfo . isMove )
2025-03-22 12:16:22 +00:00
{
deviceinfo . Lat = input . product_lat ;
deviceinfo . Lon = input . product_lon ;
await _redisService . SetAsync ( key , deviceinfo ) ;
2025-04-05 10:34:21 +00:00
//更新位置
// await _db.Updateable(deviceinfo).ExecuteCommandAsync();
2025-04-07 14:38:22 +00:00
await _db . CopyNew ( ) . Updateable < DeviceEntity > ( deviceinfo ) . UpdateColumns ( it = > new { it . Lat , it . Lon } ) . ExecuteCommandAsync ( ) ;
2025-03-22 12:16:22 +00:00
}
}
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 ( ) ;
2025-04-04 11:49:50 +00:00
await _redisService . DeleteAsync ( RedisKeyList . index_data ( ) ) ;
2025-03-22 12:16:22 +00:00
}
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 ,
2025-03-31 13:44:50 +00:00
s . app_lat ,
s . app_lon ,
2025-03-22 12:16:22 +00:00
s . CreateTime ,
AlarmLevel = s . alarmLevel ,
} ) . ToListAsync ( ) ;
return new ApiResult ( ) { data = items } ;
}
2025-03-27 16:34:20 +00:00
/// <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 ( )
2025-04-12 09:46:40 +00:00
. Where ( s = > s . alarmLevel > 0 & & s . IsWhitelist = = false )
2025-03-27 16:34:20 +00:00
. 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 ( )
2025-04-12 09:46:40 +00:00
. Where ( s = > s . alarmLevel > 0 & & s . IsWhitelist = = false )
2025-03-27 16:34:20 +00:00
. 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 ;
}
2025-03-22 12:16:22 +00:00
/// <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 ( )
2025-06-14 09:36:57 +00:00
. WhereIF ( input . positionId . HasValue , st = > st . positionId = = input . positionId . Value )
2025-06-26 15:34:41 +00:00
// .WhereIF(input.Frequency.HasValue, st => st.freq == input.Frequency.Value)
2025-03-22 12:16:22 +00:00
. 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 )
2025-06-29 12:55:31 +00:00
. GroupBy ( s = > new { s . BatchId , s . serial_number , s . device_type } )
2025-03-22 12:16:22 +00:00
. Select ( st = > new AlarmRepDto
{
batchId = st . BatchId . ToString ( ) ,
startTime = SqlFunc . AggregateMin ( st . CreateTime ) ,
endTime = SqlFunc . AggregateMax ( st . CreateTime ) ,
sn = st . serial_number ,
2025-06-26 15:34:41 +00:00
Frequency = SqlFunc . AggregateMax ( st . freq ) ,
2025-03-22 12:16:22 +00:00
duration = ( SqlFunc . AggregateMax ( st . CreateTime ) - SqlFunc . AggregateMin ( st . CreateTime ) ) . TotalSeconds ,
model = st . device_type ,
2025-06-29 12:55:31 +00:00
positionId = SqlFunc . AggregateMax ( st . positionId ) ,
2025-03-22 12:16:22 +00:00
} ) . MergeTable ( ) //合并查询
. ToPageListAsync ( input . pageNum , input . pageSize , total ) ;
2025-07-09 12:52:45 +00:00
var ids = items . Select ( s = > s . positionId ) . Distinct ( ) . ToList ( ) ;
2025-06-29 12:55:31 +00:00
var positionNames = await _db . Queryable < PositionInfo > ( )
. Where ( s = > ids . Contains ( s . Id ) )
. Select ( s = > new { s . Id , s . Name } )
. ToListAsync ( ) ;
foreach ( var item in items )
{
var positionName = positionNames . FirstOrDefault ( s = > s . Id = = item . positionId ) ? . Name ;
if ( ! string . IsNullOrEmpty ( positionName ) )
{
item . positionName = positionName ;
}
}
2025-03-22 12:16:22 +00:00
return Tuple . Create ( total . Value , items ) ;
}
2025-07-21 09:36:04 +00:00
/// <summary>
/// 快速分页
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task < ApiResult > CreateHistoryPage ( AlarmReq input )
{
var tables = _db . SplitHelper < Alarm > ( ) . GetTables ( ) ;
string coutsql = @ " SELECT COUNT(*)
FROM (
SELECT batch_id
FROM (
{ 0 }
) AS unionTable
GROUP BY batch_id
) AS CountTable ; ";
string page = @ " SELECT *
FROM (
SELECT batch_id
FROM (
{ 0 }
) AS unionTable
GROUP BY batch_id ORDER BY batch_id desc LIMIT { 1 } , { 2 }
) AS CountTable ";
2025-03-22 12:16:22 +00:00
2025-08-16 07:31:10 +00:00
string tablesql = string . Join ( " UNION ALL " , tables . Select ( item = > $"SELECT batch_id FROM {item.TableName} GROUP BY batch_id" ) ) ;
2025-07-21 09:36:04 +00:00
if ( ! string . IsNullOrEmpty ( input . sn ) )
{
2025-08-16 07:31:10 +00:00
tablesql = string . Join ( " UNION ALL " , tables . Select ( item = > $"SELECT batch_id FROM {item.TableName} where serial_number like '%{input.sn}%' GROUP BY batch_id" ) ) ;
2025-07-21 09:36:04 +00:00
}
var pageitem = await _db . Ado . SqlQueryAsync < int , long > ( string . Format ( coutsql , tablesql ) + string . Format ( page , tablesql , ( input . pageNum - 1 ) * input . pageSize , input . pageSize ) ) ;
2025-08-20 14:37:59 +00:00
var temp = await _db . Queryable < Alarm > ( )
2025-09-20 08:28:08 +00:00
. Where ( s = > pageitem . Item2 . Contains ( s . BatchId ) ) . SplitTable ( ) . Select ( s = > new { s . BatchId , s . freq , s . Id , s . positionId , s . PostionName , s . alarmLevel , s . device_type } ) . ToListAsync ( ) ;
2025-08-20 14:37:59 +00:00
2025-07-21 09:36:04 +00:00
var query = await _db . Queryable < Alarm > ( )
. Where ( s = > pageitem . Item2 . Contains ( s . BatchId ) ) . SplitTable ( )
2025-09-20 08:28:08 +00:00
. GroupBy ( s = > new { s . BatchId , s . serial_number } )
2025-07-21 09:36:04 +00:00
. Select ( st = > new AlarmRepDto
{
batchId = st . BatchId . ToString ( ) ,
startTime = SqlFunc . AggregateMin ( st . CreateTime ) ,
endTime = SqlFunc . AggregateMax ( st . CreateTime ) ,
sn = st . serial_number ,
2025-08-20 14:37:59 +00:00
Frequency = 0 ,
duration = ( SqlFunc . AggregateMax ( st . CreateTime ) - SqlFunc . AggregateMin ( st . CreateTime ) ) . TotalSeconds ,
IsWhitelist = SqlFunc . AggregateMax ( st . IsWhitelist ) ,
2025-07-21 09:36:04 +00:00
} ) . OrderByDescending ( s = > s . batchId ) . ToListAsync ( ) ;
2025-08-20 14:37:59 +00:00
query . ForEach ( s = >
{
s . duration = s . duration = = 0 ? 1 : s . duration ;
s . Frequency = temp . Where ( m = > m . BatchId = = long . Parse ( s . batchId ) ) . OrderByDescending ( o = > o . Id ) . FirstOrDefault ( ) . freq ;
2025-09-20 08:28:08 +00:00
s . positionId = temp . Where ( m = > m . BatchId = = long . Parse ( s . batchId ) ) . OrderByDescending ( o = > o . Id ) . FirstOrDefault ( ) . positionId ;
2025-08-20 14:37:59 +00:00
s . positionName = temp . Where ( m = > m . BatchId = = long . Parse ( s . batchId ) ) . OrderByDescending ( o = > o . Id ) . FirstOrDefault ( ) . PostionName ;
2025-08-22 17:38:27 +00:00
s . alarmLevel = temp . Where ( m = > m . BatchId = = long . Parse ( s . batchId ) ) . Any ( o = > o . alarmLevel = = 1 ) ? 1 : 0 ;
2025-08-24 07:22:56 +00:00
s . model = temp . Where ( m = > m . BatchId = = long . Parse ( s . batchId ) ) . OrderByDescending ( o = > o . Id ) . FirstOrDefault ( ) . device_type ;
2025-08-20 14:37:59 +00:00
} ) ;
2025-07-21 09:36:04 +00:00
return new ApiResult ( )
{
code = 0 ,
data = new
{
total = pageitem . Item1 . First ( ) ,
items = query
}
} ;
}
2025-04-13 05:55:26 +00:00
2025-03-22 12:16:22 +00:00
/// <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 ( )
2025-03-30 23:38:50 +00:00
. Where ( s = > s . alarmLevel > 0 )
2025-03-22 12:16:22 +00:00
. 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 ( )
} ) ,
2025-03-30 23:38:50 +00:00
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 ( )
} ) ,
2025-03-22 12:16:22 +00:00
device = query . GroupBy ( s = > new { s . deviceName } )
2025-03-30 23:38:50 +00:00
. Select ( b = > new
2025-03-22 12:16:22 +00:00
{
2025-03-30 23:38:50 +00:00
b . Key . deviceName ,
count = b . Count ( )
} )
2025-03-22 12:16:22 +00:00
}
} ;
}
/// <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 ( ) ;
}
}
}