@ -1,4 +1,4 @@
using DocumentFormat.OpenXml.Wordprocessing ;
using DocumentFormat.OpenXml.Wordprocessing ;
using Infrastructure ;
using Infrastructure.CloudSdk.minio ;
using Infrastructure.CloudSdk.wayline ;
@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration ;
using Newtonsoft.Json ;
using OpenAuth.App.BaseApp.Base ;
using OpenAuth.App.BasicQueryService ;
using OpenAuth.App.Interface ;
using OpenAuth.App.ServiceApp.Request ;
using OpenAuth.App.ServiceApp.Response ;
@ -14,6 +15,7 @@ using OpenAuth.Repository.Domain;
using OpenAuth.WebApi ;
using OpenAuth.WebApi.CloudSdk ;
using SqlSugar ;
using System.Text ;
namespace OpenAuth.App.ServiceApp
{
@ -21,13 +23,15 @@ namespace OpenAuth.App.ServiceApp
{
private readonly MqttClientManager _mqttClientManager ;
private readonly MinioService _minioService ;
CommonDataManager _commonDataManager ;
public ManageApp ( ISugarUnitOfWork < SugarDbContext > unitWork , ISimpleClient < LasaDronePort > repository , IAuth auth ,
MqttClientManager mqttClientManager , MinioService minioService )
MqttClientManager mqttClientManager , CommonDataManager commonDataManager , MinioService minioService )
: base ( unitWork , repository , auth )
{
_mqttClientManager = mqttClientManager ;
_minioService = minioService ;
_commonDataManager = commonDataManager ;
}
#region 机场管理
@ -488,21 +492,23 @@ namespace OpenAuth.App.ServiceApp
using ( var db = UnitWork . CreateContext ( ) )
{
WorkSpaceRes res = new WorkSpaceRes ( ) ;
var workspace = await db . LasaWorkspace . AsQueryable ( ) . Where ( r = > r . Id = = id ) . FirstAsync ( ) ;
var sysuser = db . User . AsQueryable ( )
. LeftJoin < LasaSpaceUser > ( ( r , a ) = > r . Id = = a . UserId )
. Where ( ( r , a ) = > a . WorkSpaceId = = id )
. Select ( ( r , a ) = > r ) . ToList ( ) ;
var uav = db . LasaDronePort . AsQueryable ( )
. LeftJoin < LasaSpaceDevice > ( ( r , a ) = > r . Id = = a . DeviceId )
. Where ( ( r , a ) = > a . WorkSpaceId = = id )
. Select ( ( r , a ) = > r ) . ToList ( ) ;
var lockfly = db . LasaSpaceLockFly . AsQueryable ( ) . Where ( r = > r . WorkSpaceId = = id ) . ToList ( ) ;
res . users = sysuser ;
res . LasaDronePort = uav ;
res . lasaSpaceLockFlies = lockfly ;
res . workspace = workspace ;
var workspace = await db . LasaWorkspace . AsQueryable ( ) . Where ( r = > r . Id = = id & & r . IsDelete = = false ) . FirstAsync ( ) ;
if ( workspace ! = null )
{
var sysuser = db . User . AsQueryable ( )
. LeftJoin < LasaSpaceUser > ( ( r , a ) = > r . Id = = a . UserId )
. Where ( ( r , a ) = > a . WorkSpaceId = = id )
. Select ( ( r , a ) = > r ) . ToList ( ) ;
var uav = db . LasaDronePort . AsQueryable ( )
. LeftJoin < LasaSpaceDevice > ( ( r , a ) = > r . Id = = a . DeviceId )
. Where ( ( r , a ) = > a . WorkSpaceId = = id )
. Select ( ( r , a ) = > r ) . ToList ( ) ;
var lockfly = db . LasaSpaceLockFly . AsQueryable ( ) . Where ( r = > r . WorkSpaceId = = id ) . ToList ( ) ;
res . users = sysuser ;
res . LasaDronePort = uav ;
res . lasaSpaceLockFlies = lockfly ;
res . workspace = workspace ;
}
return new Response < WorkSpaceRes >
{
Result = res
@ -579,75 +585,82 @@ namespace OpenAuth.App.ServiceApp
var wpmlDir = configuration [ "WpmlDir" ] ;
// 读取连接字符串
//var serverIp = configuration["MQTT:Server"];
var data = new
{
flight_id = Guid . NewGuid ( ) . ToString ( ) ,
execute_time = DateTime . Now . Ticks , // 任务开始执行时间毫秒时间戳。可选字段。当 task_type 为 0 或 1 时必填,为 2 时非必填。
//立即任务和定时任务均由 execute_time 指定执行时间。条件任务支持 ready_conditions 字段指定任务就绪条件。任务可在指定时间段内满足一定条件后即可执行。立即任务媒体上传优先级最高,定时任务和条件任务媒体上传优先级相同。
//0":"立即任务","1":"定时任务","2":"条件任务
task_type = task . TaskType ,
file = new
{
url = wpml , // todo 拼接地址
fingerprint = "" // todo 计算md5
} ,
dynamic data = new ExpandoObject ( ) ;
data . flight_id = Guid . NewGuid ( ) . ToString ( ) ;
data . execute_time = DateTime . Now . Ticks ;
data . task_type = task . TaskType ;
data . file = new
{
url = wpml ,
fingerprint = _minioService . GetMetaObject ( wpml , "" )
} ;
//任务执行条件
data . executable_conditions = new
{
// 可执行任务的机场或飞行器最低存储容量,机场或飞行器存储容量不满足 storage_capacity 时,任务执行失败。
// todo 容量单位是什么? 一个图片多少兆,预计拍多少图片?
// 1. 需要多少容量
// 2. 多少图片需要多少容量
// 3. 要存多少图片
// 4.
storage_capacity = 1000
} ;
// todo 1. 查询上报断点 2. 断点续飞方法支持
data . break_point = new
{
index = 1 , // 断点序号
state = 1 , // “0":"在航段上","1":"在航点上
progress = 1.0 , // {"max":"1.0","min":"0"}
wayline_id = "" // 航线id
} ;
// 返航高度 {"max":1500,"min":20,"step":"","unit_name":"米 / m"}
data . rth_altitude = 150 ; // todo 取自任务
// 返航高度模式 {"0":"智能高度","1":"设定高度"}
// 智能返航模式下,飞行器将自动规划最佳返航高度。大疆机场当前不支持设置返航高度模式,只能选择'设定高度'模式。当环境,光线不满足视觉系统要求时(譬如傍晚阳光直射、夜间弱光无光),飞行器将使用您设定的返航高度进行直线返航
data . rth_mode = 1 ;
// {"0":"返航","1":"悬停","2":"降落"}
// 失控动作,当前固定传的值是 0, 即返航。注意该枚举值定义跟飞控跟机场定义的不一致, 机场端会进行转换。
data . out_of_control_action = 0 ;
// 航线失控动作 保持跟 KMZ 文件一致
// {"0":"继续执行航线任务","1":"退出航线任务,执行遥控器失控动作"}
data . exit_wayline_when_rc_lost = 0 ;
// 航线精度类型 {"0":"GPS 任务","1":"高精度 RTK 任务"}
// 高精度 RTK 任务:飞行器起飞后会在空中等待 RTK 收敛后再执行任务,等待 RTK 收敛的过程中无法暂停任务。默认场景建议使用该模式。GPS 任务:飞行器无需等待 RTK 收敛便可以直接开始执行。精度要求不高的任务或对起飞时效性要求较高的任务建议使用该模式。
data . wayline_precision_type = task . PeriodicFormula ; // todo 值来自任务
// 是否在模拟器中执行任务 todo 调试时使用
/ * data . simulate_mission = new
{
//是否开启模拟器任务
//{"0":"不开启","1":"开启"}
is_enable = 1 ,
// 纬度 {"max":"90.0","min":"-90.0"}
latitude = 35.0 ,
// 经度 {"max":"180.0","min":"-180.0"}
longitude = 120.0 ,
// 高度 {"max":"9999.9","min":"-9999.9"unit_name":"米 / m"}
altitude = 200.0
} ; * /
// 飞行安全预检查
// {"0":"关闭","1":"开启"}
// 设置一键起飞和航线任务中的飞行安全是否预先检查。此字段为可选, 默认为0, 值为0表示关闭, 1表示开启。飞行安全预先检查表示: 飞行器执行任务前,检查自身作业区文件是否与云端一致,如果不一致则拉取文件更新,如果一致则不处理
data . flight_safety_advance_check = 0 ;
if ( data . task_type = = 2 )
{
// 任务就绪条件 可选字段。条件任务(即 task_type 为2) 时必填, 其他类型任务会忽略该字段。下发条件任务后, 设备会定频检查 ready_conditions 是否全部满足,若全部满足则会有 flighttask_ready 事件通知。且设备端接收 flighttask_execute 指令时,也会检查任务的 ready_conditions 是否已全部满足。
ready_conditions = new
data . ready_conditions = new
{
// 可执行任务的飞行器电池电量百分比阈值,任务开始执行时的飞行器电量必须大于
// todo 去哪里取值 任务限制中是否存在
// todo 获取指定值 计算 还是
battery_capacity = 77 , // 设备电量百分比,范围 0-100
// todo 设定时间
begin_time = DateTime . Now . Ticks , // 任务开始执行时间必须大于该值
// todo 设定结束时间
end_time = DateTime . Now . Ticks , // 任务结束时间必须
} ,
// 任务执行条件
executable_conditions = new
{
// 可执行任务的机场或飞行器最低存储容量,机场或飞行器存储容量不满足 storage_capacity 时,任务执行失败。
// todo 容量单位是什么? 一个图片多少兆,预计拍多少图片?
storage_capacity = 1000
} ,
break_point = new
{
index = 1 , // 断点序号
state = 1 , // “0":"在航段上","1":"在航点上
progress = 1.0 , // {"max":"1.0","min":"0"}
wayline_id = "" // 航线id
} ,
// 返航高度 {"max":1500,"min":20,"step":"","unit_name":"米 / m"}
rth_altitude = 150 , // todo 取自任务
// 返航高度模式 {"0":"智能高度","1":"设定高度"}
// 智能返航模式下,飞行器将自动规划最佳返航高度。大疆机场当前不支持设置返航高度模式,只能选择'设定高度'模式。当环境,光线不满足视觉系统要求时(譬如傍晚阳光直射、夜间弱光无光),飞行器将使用您设定的返航高度进行直线返航
rth_mode = 1 ,
// {"0":"返航","1":"悬停","2":"降落"}
// 失控动作,当前固定传的值是 0, 即返航。注意该枚举值定义跟飞控跟机场定义的不一致, 机场端会进行转换。
out_of_control_action = 0 ,
// 航线失控动作 保持跟 KMZ 文件一致
// {"0":"继续执行航线任务","1":"退出航线任务,执行遥控器失控动作"}
exit_wayline_when_rc_lost = 0 ,
// 航线精度类型 {"0":"GPS 任务","1":"高精度 RTK 任务"}
// 高精度 RTK 任务:飞行器起飞后会在空中等待 RTK 收敛后再执行任务,等待 RTK 收敛的过程中无法暂停任务。默认场景建议使用该模式。GPS 任务:飞行器无需等待 RTK 收敛便可以直接开始执行。精度要求不高的任务或对起飞时效性要求较高的任务建议使用该模式。
wayline_precision_type = 1 , // todo 值来自任务
// 是否在模拟器中执行任务
simulate_mission = new
{
//是否开启模拟器任务
//{"0":"不开启","1":"开启"}
is_enable = 1 ,
// 纬度 {"max":"90.0","min":"-90.0"}
latitude = 35.0 ,
// 经度 {"max":"180.0","min":"-180.0"}
longitude = 120.0 ,
// 高度 {"max":"9999.9","min":"-9999.9"unit_name":"米 / m"}
altitude = 200.0
} ,
// 飞行安全预检查
// {"0":"关闭","1":"开启"}
// 设置一键起飞和航线任务中的飞行安全是否预先检查。此字段为可选, 默认为0, 值为0表示关闭, 1表示开启。飞行安全预先检查表示: 飞行器执行任务前,检查自身作业区文件是否与云端一致,如果不一致则拉取文件更新,如果一致则不处理
flight_safety_advance_check = 0
} ;
} ;
}
request . SetData ( data ) ;
// 任务下发
await _mqttClientManager . PublishAsync ( topic , JsonConvert . SerializeObject ( request ) ) ;
@ -682,5 +695,165 @@ namespace OpenAuth.App.ServiceApp
{
return _minioService . UploadFile ( xmlFile , "" ) ;
}
#region 添加地图作业区域
/// <summary>
/// 添加地图作业区域
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public async Task < Response < string > > AddWorkArea ( LasaShpData model )
{
var _user = _auth . GetCurrentUser ( ) . User ;
model . CreateTime = DateTime . Now ;
model . CreateUser = _user . Id . ToString ( ) ;
model . CreateUserName = _user . Name . ToString ( ) ;
using ( var db = base . UnitWork . CreateContext ( ) . Db . CopyNew ( ) )
{
//获取主键
string id = Guid . NewGuid ( ) . ToString ( ) ;
model . Id = id ;
//格式化数据
string _wktModel = _commonDataManager . WktDataConvert ( model . Geom , "MULTIPOLYGON ZM" , 4 ) ;
model . Geom = null ;
StringBuilder geomSql = new StringBuilder ( ) ;
geomSql . AppendFormat ( $" update lasa_shpdata set \" Geom \ " = st_geomfromtext('{_wktModel}',4326) where \"Id\" = '{id}'" ) ;
//更新面积
StringBuilder sql = new StringBuilder ( ) ;
sql . AppendFormat ( $" update lasa_shpdata set \" Area \ " = st_area(st_transform(\"Geom\",4527)) where \"Geom\" is not null and \"Id\" = '{id}'" ) ;
//更新周长
StringBuilder sqlle = new StringBuilder ( ) ;
sqlle . AppendFormat ( $" update lasa_shpdata set \" Length \ " = ST_Perimeter(st_transform(\"Geom\",4527)) where \"Geom\" is not null and \"Id\" = '{id}'" ) ;
//使用事务提交数据
var transFlag = await db . UseTranAsync ( async ( ) = >
{
//插入图斑数据
var flag = await db . Insertable ( model ) . ExecuteCommandAsync ( ) ;
//修改图斑数据
var flagGeom = await db . Ado . ExecuteCommandAsync ( geomSql . ToString ( ) ) ;
//修改图斑面积
var flagUpdate = await db . Ado . ExecuteCommandAsync ( sql . ToString ( ) ) ;
//修改图斑周长
var lengthUpdate = await db . Ado . ExecuteCommandAsync ( sqlle . ToString ( ) ) ;
} ) ;
if ( transFlag . IsSuccess )
return new Response < string >
{
Result = id ,
Message = "新增成功"
} ;
else
return new Response < string >
{
Message = "新增失败"
} ;
}
}
/// <summary>
/// 更新地图作业区域
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public async Task < Response < string > > UpdateWorkArea ( LasaShpData model )
{
using ( var db = base . UnitWork . CreateContext ( ) . Db . CopyNew ( ) )
{
//格式化数据
string _wktModel = _commonDataManager . WktDataConvert ( model . Geom , "MULTIPOLYGON ZM" , 4 ) ;
model . Geom = null ;
StringBuilder geomSql = new StringBuilder ( ) ;
geomSql . AppendFormat ( $" update lasa_shpdata set \" Geom \ " = st_geomfromtext('{_wktModel}',4326) where \"Id\" = '{model.Id}'" ) ;
//更新面积
StringBuilder sql = new StringBuilder ( ) ;
sql . AppendFormat ( $" update lasa_shpdata set \" Area \ " = st_area(st_transform(\"Geom\",4527)) where \"Geom\" is not null and \"Id\" = '{model.Id}'" ) ;
//更新周长
StringBuilder sqlle = new StringBuilder ( ) ;
sqlle . AppendFormat ( $" update lasa_shpdata set \" Length \ " = ST_Perimeter(st_transform(\"Geom\",4527)) where \"Geom\" is not null and \"Id\" = '{model.Id}'" ) ;
//使用事务提交数据
var transFlag = await db . UseTranAsync ( async ( ) = >
{
//插入图斑数据
var flag = await db . Updateable ( model ) . ExecuteCommandAsync ( ) ;
//修改图斑数据
var flagGeom = await db . Ado . ExecuteCommandAsync ( geomSql . ToString ( ) ) ;
//修改图斑面积
var flagUpdate = await db . Ado . ExecuteCommandAsync ( sql . ToString ( ) ) ;
//修改图斑周长
var lengthUpdate = await db . Ado . ExecuteCommandAsync ( sqlle . ToString ( ) ) ;
} ) ;
if ( transFlag . IsSuccess )
return new Response < string >
{
Result = model . Id ,
Message = "更新成功"
} ;
else
return new Response < string >
{
Message = "更新失败"
} ;
}
}
//删除地图作业区域
public async Task < Response < bool > > DeleteWorkArea ( string id )
{
using ( var db = UnitWork . CreateContext ( ) )
{
await db . LasaShpData . DeleteByIdAsync ( id ) ;
if ( db . Commit ( ) )
return new Response < bool > { Result = true , Message = "删除成功" } ;
else
return new Response < bool > { Result = false , Message = "删除失败" } ;
}
}
/// <summary>
/// 获取地图作业区域列表
/// </summary>
/// <param name="workspaceid">项目id</param>
/// <returns></returns>
public async Task < Response < List < LasaShpData > > > GetWorkAreaList ( string workspaceid , int? state , string type )
{
using ( var db = UnitWork . CreateContext ( ) )
{
StringBuilder sql = new StringBuilder ( ) ;
sql . AppendFormat ( $" Select * from lasa_shpdata where \" WorkSpaceId \ " = '{workspaceid}'" ) ;
var list = db . Db . SqlQueryable < LasaShpData > ( sql . ToString ( ) ) . ToList ( ) ;
if ( ! string . IsNullOrEmpty ( type ) & & list . Count > 0 )
{
list = list . Where ( r = > r . Type = = type ) . ToList ( ) ;
}
if ( state ! = null )
{
list = list . Where ( r = > r . State = = state ) . ToList ( ) ;
}
return new Response < List < LasaShpData > >
{
Result = list
} ;
}
}
# endregion
}
}