添加项目文件。
This commit is contained in:
parent
30b0ce1ac8
commit
1972c0d453
|
|
@ -0,0 +1,25 @@
|
||||||
|
**/.classpath
|
||||||
|
**/.dockerignore
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/azds.yaml
|
||||||
|
**/bin
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/obj
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
LICENSE
|
||||||
|
README.md
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
using NetTopologySuite.Geometries;
|
||||||
|
|
||||||
|
namespace LY.App.Common
|
||||||
|
{
|
||||||
|
public static class CoordConvert
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 经纬度转Web墨卡托(单位:米)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="longitude">经度</param>
|
||||||
|
/// <param name="latitude">纬度</param>
|
||||||
|
/// <returns>转换后的位置</returns>
|
||||||
|
public static CoordPoint WGS84ToMercator(double lon, double lat)
|
||||||
|
{
|
||||||
|
var x = lon * Math.PI / 180 * Parameters.LongRadius;
|
||||||
|
var param = lat * Math.PI / 180;
|
||||||
|
var y = Parameters.LongRadius / 2 * Math.Log((1.0 + Math.Sin(param)) / (1.0 - Math.Sin(param)));
|
||||||
|
return new CoordPoint(x, y);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 经纬度转Web墨卡托(单位:米)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="longitude">经度</param>
|
||||||
|
/// <param name="latitude">纬度</param>
|
||||||
|
/// <returns>转换后的位置</returns>
|
||||||
|
public static CoordPoint WGS84ToMercator(Coordinate coord)
|
||||||
|
{
|
||||||
|
return WGS84ToMercator(coord.Lon, coord.Lat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Web墨卡托转经纬度
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">X坐标值(单位:米)</param>
|
||||||
|
/// <param name="y">Y坐标值(单位:米)</param>
|
||||||
|
/// <returns>转换后的位置</returns>
|
||||||
|
public static Coordinate MercatorToWGS84(double x, double y)
|
||||||
|
{
|
||||||
|
var lon = x / Parameters.MercatorLength * 180;
|
||||||
|
var lat = y / Parameters.MercatorLength * 180;
|
||||||
|
lat = 180 / Math.PI * (2 * Math.Atan(Math.Exp(lat * Math.PI / 180)) - Math.PI / 2);
|
||||||
|
return new Coordinate(lon, lat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Web墨卡托转经纬度
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">X坐标值(单位:米)</param>
|
||||||
|
/// <param name="y">Y坐标值(单位:米)</param>
|
||||||
|
/// <returns>转换后的位置</returns>
|
||||||
|
public static Coordinate MercatorToWGS84(CoordPoint point)
|
||||||
|
{
|
||||||
|
return MercatorToWGS84(point.X, point.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
namespace LY.App.Common
|
||||||
|
{
|
||||||
|
public struct CoordPoint
|
||||||
|
{
|
||||||
|
public CoordPoint(double x, double y)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Z = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoordPoint(double x, double y, double z)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// X轴
|
||||||
|
/// </summary>
|
||||||
|
public double X { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Y轴
|
||||||
|
/// </summary>
|
||||||
|
public double Y { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Z轴
|
||||||
|
/// </summary>
|
||||||
|
public double Z { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
namespace LY.App.Common
|
||||||
|
{
|
||||||
|
public struct Coordinate
|
||||||
|
{
|
||||||
|
public Coordinate(double lon, double lat)
|
||||||
|
{
|
||||||
|
Lon = lon;
|
||||||
|
Lat = lat;
|
||||||
|
Alt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Coordinate(double lon, double lat, double alt)
|
||||||
|
{
|
||||||
|
Lon = lon;
|
||||||
|
Lat = lat;
|
||||||
|
Alt = alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 经度
|
||||||
|
/// </summary>
|
||||||
|
public double Lon { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 纬度
|
||||||
|
/// </summary>
|
||||||
|
public double Lat { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 高程
|
||||||
|
/// </summary>
|
||||||
|
public double Alt { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LY.App.Common.Cypher
|
||||||
|
{
|
||||||
|
public class AESCypherUtil
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// AES 加密
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">明文</param>
|
||||||
|
/// <param name="key">密钥对</param>
|
||||||
|
/// <returns>密文</returns>
|
||||||
|
public static string Encrypt(string str, string key, string iv)
|
||||||
|
{
|
||||||
|
using (var aes = Aes.Create())
|
||||||
|
{
|
||||||
|
aes.Key = Encoding.UTF8.GetBytes(key);
|
||||||
|
aes.IV = Encoding.UTF8.GetBytes(iv);
|
||||||
|
aes.Mode = CipherMode.CBC;
|
||||||
|
aes.Padding = PaddingMode.PKCS7;
|
||||||
|
|
||||||
|
byte[] strbuffer = Encoding.UTF8.GetBytes(str);
|
||||||
|
|
||||||
|
using (var crytTransform = aes.CreateEncryptor(aes.Key, aes.IV))
|
||||||
|
{
|
||||||
|
byte[] buffer = crytTransform.TransformFinalBlock(strbuffer, 0, strbuffer.Length);
|
||||||
|
return Convert.ToBase64String(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// AES 解密
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">密文</param>
|
||||||
|
/// <param name="key">密钥对</param>
|
||||||
|
/// <returns>明文</returns>
|
||||||
|
public static string Decrypt(string str, string key, string iv)
|
||||||
|
{
|
||||||
|
using (var aes = Aes.Create())
|
||||||
|
{
|
||||||
|
aes.Key = Encoding.UTF8.GetBytes(key);
|
||||||
|
aes.IV = Encoding.UTF8.GetBytes(iv);
|
||||||
|
aes.Mode = CipherMode.CBC;
|
||||||
|
aes.Padding = PaddingMode.PKCS7;
|
||||||
|
|
||||||
|
byte[] strbuffer = System.Convert.FromBase64String(str);
|
||||||
|
|
||||||
|
using (var crytTransform = aes.CreateDecryptor(aes.Key, aes.IV))
|
||||||
|
{
|
||||||
|
byte[] buffer = crytTransform.TransformFinalBlock(strbuffer, 0, strbuffer.Length);
|
||||||
|
return Encoding.UTF8.GetString(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LY.App.Common.Cypher
|
||||||
|
{
|
||||||
|
public class MD5CypherUtil
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// MD5加密
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">内容</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Hash(string str)
|
||||||
|
{
|
||||||
|
return Hash(Encoding.UTF8.GetBytes(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// MD5加密
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Hash(byte[] buffer)
|
||||||
|
{
|
||||||
|
return BitConverter.ToString(BinaryHash(buffer)).Replace("-", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// MD5加密
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static byte[] BinaryHash(string str)
|
||||||
|
{
|
||||||
|
return BinaryHash(Encoding.UTF8.GetBytes(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// MD5加密
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static byte[] BinaryHash(byte[] buffer)
|
||||||
|
{
|
||||||
|
using (var md5 = MD5.Create())
|
||||||
|
{
|
||||||
|
return md5.ComputeHash(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
namespace LY.App.Common
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 频段转换
|
||||||
|
/// </summary>
|
||||||
|
public static class FreqConvert
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///返回频段转换结果
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="frequency"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static double CoverFreq(double frequency)
|
||||||
|
{
|
||||||
|
double result = 0;
|
||||||
|
if (frequency > 0)
|
||||||
|
{
|
||||||
|
if (370 <= frequency && frequency <= 500)
|
||||||
|
{
|
||||||
|
return 433;
|
||||||
|
}
|
||||||
|
else if (700 <= frequency && frequency <= 890)
|
||||||
|
{
|
||||||
|
return 840;
|
||||||
|
}
|
||||||
|
else if (890 < frequency && frequency <= 1000)
|
||||||
|
{
|
||||||
|
return 915;
|
||||||
|
}
|
||||||
|
else if (1100 <= frequency && frequency <= 1300)
|
||||||
|
{
|
||||||
|
return 1.2;
|
||||||
|
}
|
||||||
|
else if (1300 < frequency && frequency <= 1500)
|
||||||
|
{
|
||||||
|
return 1.4;
|
||||||
|
}
|
||||||
|
else if (1500 < frequency && frequency <= 1700)
|
||||||
|
{
|
||||||
|
return 1.6;
|
||||||
|
}
|
||||||
|
else if (2300 <= frequency && frequency <= 2500)
|
||||||
|
{
|
||||||
|
return 2.4;
|
||||||
|
}
|
||||||
|
else if (5100 <= frequency && frequency <= 5300)
|
||||||
|
{
|
||||||
|
return 5.2;
|
||||||
|
}
|
||||||
|
else if (5700 <= frequency && frequency <= 5900)
|
||||||
|
{
|
||||||
|
return 5.8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return result; // 表示输入频率不在已定义范围内
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,622 @@
|
||||||
|
using LY.App.Model;
|
||||||
|
using NetTopologySuite.Features;
|
||||||
|
using NetTopologySuite.Geometries;
|
||||||
|
using NetTopologySuite.IO;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace LY.App.Common
|
||||||
|
{
|
||||||
|
public class GeoJsonHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 格式为json字符串
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string ConvertJsonString(string str)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//格式化json字符串
|
||||||
|
JsonSerializer serializer = new JsonSerializer();
|
||||||
|
TextReader tr = new StringReader(str);
|
||||||
|
JsonTextReader jtr = new JsonTextReader(tr);
|
||||||
|
object obj = serializer.Deserialize(jtr);
|
||||||
|
if (obj != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
StringWriter textWriter = new StringWriter();
|
||||||
|
JsonTextWriter jsonWriter = new JsonTextWriter(textWriter)
|
||||||
|
{
|
||||||
|
Formatting = Formatting.Indented,
|
||||||
|
Indentation = 4,
|
||||||
|
IndentChar = ' '
|
||||||
|
};
|
||||||
|
serializer.Serialize(jsonWriter, obj);
|
||||||
|
return textWriter.ToString();
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 转换为geojson格式字符串
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string GetGeoJson(object? value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
return "";
|
||||||
|
var serializer = GeoJsonSerializer.Create();
|
||||||
|
using (var sw = new System.IO.StringWriter())
|
||||||
|
{
|
||||||
|
serializer.Serialize(sw, value);
|
||||||
|
|
||||||
|
return sw.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将坐标转换为点
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">经度</param>
|
||||||
|
/// <param name="y">纬度</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static NetTopologySuite.Geometries.Point ConvertToPoint(double x, double y)
|
||||||
|
{
|
||||||
|
return new NetTopologySuite.Geometries.Point(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static object? GetDynamicFeature(Geometry geometry, IDictionary<string, object> attributes)
|
||||||
|
{
|
||||||
|
var f = GetGeoFeature(geometry, attributes);
|
||||||
|
var geoJson = GetGeoJson(f);
|
||||||
|
return geoJson;
|
||||||
|
// return JsonConvert.DeserializeObject(geoJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取集合中能够组成多面的几何数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="features"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static List<MultiPolygon> GetGeoMultiPolygon(FeatureCollection features)
|
||||||
|
{
|
||||||
|
var result = new List<MultiPolygon>();
|
||||||
|
if (features == null)
|
||||||
|
return result;
|
||||||
|
foreach (var feature in features)
|
||||||
|
{
|
||||||
|
if (feature.Geometry is MultiPolygon)
|
||||||
|
{
|
||||||
|
result.Add(feature.Geometry as MultiPolygon);
|
||||||
|
}
|
||||||
|
else if (feature.Geometry is Polygon)
|
||||||
|
{
|
||||||
|
result.Add(new MultiPolygon(new Polygon[] { feature.Geometry as Polygon }));
|
||||||
|
}
|
||||||
|
else if (feature.Geometry is LineString)
|
||||||
|
{
|
||||||
|
var line = (LineString)feature.Geometry;
|
||||||
|
if (line.IsRing)
|
||||||
|
{
|
||||||
|
result.Add(new MultiPolygon(new Polygon[] { new Polygon(new LinearRing(line.Coordinates)) }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取集合中能够组成多线的几何数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="features"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static List<MultiLineString> GetGeoMultiLineString(FeatureCollection features)
|
||||||
|
{
|
||||||
|
var result = new List<MultiLineString>();
|
||||||
|
if (features == null)
|
||||||
|
return result;
|
||||||
|
foreach (var feature in features)
|
||||||
|
{
|
||||||
|
if (feature.Geometry is MultiLineString)
|
||||||
|
{
|
||||||
|
result.Add(feature.Geometry as MultiLineString);
|
||||||
|
}
|
||||||
|
else if (feature.Geometry is LineString)
|
||||||
|
{
|
||||||
|
result.Add(new MultiLineString(new LineString[] { feature.Geometry as LineString }));
|
||||||
|
}
|
||||||
|
else if (feature.Geometry is MultiPoint)
|
||||||
|
{
|
||||||
|
var mp = (MultiPoint)feature.Geometry;
|
||||||
|
if (mp.Count() > 1)
|
||||||
|
{
|
||||||
|
result.Add(new MultiLineString(new LineString[] { new LineString(mp.Coordinates) }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将geojson转为FeatureCollection,
|
||||||
|
/// 原json支持点、线面等
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="geoJson"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static FeatureCollection? GetGeoFeatureCollectionBuild(string geoJson)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(geoJson)) return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var jObj = JObject.Parse(geoJson);
|
||||||
|
if (jObj != null)
|
||||||
|
{
|
||||||
|
if (jObj.TryGetValue("type", out var jToken))
|
||||||
|
{
|
||||||
|
if (jToken != null)
|
||||||
|
{
|
||||||
|
if (string.Compare(jToken.ToString(), "FeatureCollection") == 0)
|
||||||
|
{
|
||||||
|
return GetGeoFeatureCollection(geoJson);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var f = GetGeoFeatureBuild(geoJson);
|
||||||
|
if (f != null)
|
||||||
|
{
|
||||||
|
var result = new FeatureCollection();
|
||||||
|
result.Add(f);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
|
||||||
|
throw new Exception("geojson无效");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Feature? GetGeoFeatureBuild(string geoJson)
|
||||||
|
{
|
||||||
|
var jObj = JObject.Parse(geoJson);
|
||||||
|
if (jObj != null)
|
||||||
|
{
|
||||||
|
//先判断type
|
||||||
|
if (jObj.TryGetValue("type", out var jToken))
|
||||||
|
{
|
||||||
|
if (jToken != null)
|
||||||
|
{
|
||||||
|
if (string.Compare(jToken.ToString(), "Feature") == 0)
|
||||||
|
{
|
||||||
|
return GetGeoFeature(geoJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
Geometry? geometry = null;
|
||||||
|
if (string.Compare(jToken.ToString(), "Point") == 0)
|
||||||
|
{
|
||||||
|
geometry = GetGeoPoint(geoJson);
|
||||||
|
}
|
||||||
|
if (string.Compare(jToken.ToString(), "MultiPoint") == 0)
|
||||||
|
{
|
||||||
|
geometry = GetGeoMultiPoint(geoJson);
|
||||||
|
}
|
||||||
|
if (string.Compare(jToken.ToString(), "LineString") == 0)
|
||||||
|
{
|
||||||
|
geometry = GetGeoLineString(geoJson);
|
||||||
|
}
|
||||||
|
if (string.Compare(jToken.ToString(), "MultiLineString") == 0)
|
||||||
|
{
|
||||||
|
geometry = GetGeoMultiLineString(geoJson);
|
||||||
|
}
|
||||||
|
if (string.Compare(jToken.ToString(), "Polygon") == 0)
|
||||||
|
{
|
||||||
|
geometry = GetGeoPolygon(geoJson);
|
||||||
|
}
|
||||||
|
if (string.Compare(jToken.ToString(), "MultiPolygon") == 0)
|
||||||
|
{
|
||||||
|
geometry = GetGeoMultiPolygon(geoJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geometry != null)
|
||||||
|
return new Feature(geometry, new AttributesTable());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Feature? GetGeoFeature(Geometry geometry, IDictionary<string, object> attributes)
|
||||||
|
{
|
||||||
|
AttributesTable attributesTable = new AttributesTable();
|
||||||
|
foreach (var item in attributes)
|
||||||
|
{
|
||||||
|
attributesTable.Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
var result = new Feature(geometry, attributesTable);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Feature? GetGeoFeature(string geoJson)
|
||||||
|
{
|
||||||
|
var serializer = GeoJsonSerializer.Create();
|
||||||
|
using (var stringReader = new StringReader(geoJson))
|
||||||
|
using (var jsonReader = new JsonTextReader(stringReader))
|
||||||
|
{
|
||||||
|
return serializer.Deserialize<NetTopologySuite.Features.Feature>(jsonReader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FeatureCollection? GetGeoFeatureCollection(string geoJson)
|
||||||
|
{
|
||||||
|
var serializer = GeoJsonSerializer.Create();
|
||||||
|
using (var stringReader = new StringReader(geoJson))
|
||||||
|
using (var jsonReader = new JsonTextReader(stringReader))
|
||||||
|
{
|
||||||
|
return serializer.Deserialize<NetTopologySuite.Features.FeatureCollection>(jsonReader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NetTopologySuite.Geometries.Point? GetGeoPoint(string geoJson)
|
||||||
|
{
|
||||||
|
var jObj = JObject.Parse(geoJson);
|
||||||
|
if (jObj != null)
|
||||||
|
{
|
||||||
|
//先判断type
|
||||||
|
if (jObj.TryGetValue("type", out var jToken))
|
||||||
|
{
|
||||||
|
if (jToken != null)
|
||||||
|
{
|
||||||
|
if (string.Compare(jToken.ToString(), "Feature") == 0)
|
||||||
|
{
|
||||||
|
var f = GetGeoFeature(geoJson);
|
||||||
|
if (f.Geometry is Point)
|
||||||
|
return f.Geometry as NetTopologySuite.Geometries.Point;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var serializer = GeoJsonSerializer.Create();
|
||||||
|
using (var stringReader = new StringReader(geoJson))
|
||||||
|
using (var jsonReader = new JsonTextReader(stringReader))
|
||||||
|
{
|
||||||
|
return serializer.Deserialize<NetTopologySuite.Geometries.Point>(jsonReader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NetTopologySuite.Geometries.MultiPoint? GetGeoMultiPoint(string geoJson)
|
||||||
|
{
|
||||||
|
var serializer = GeoJsonSerializer.Create();
|
||||||
|
using (var stringReader = new StringReader(geoJson))
|
||||||
|
using (var jsonReader = new JsonTextReader(stringReader))
|
||||||
|
{
|
||||||
|
return serializer.Deserialize<NetTopologySuite.Geometries.MultiPoint>(jsonReader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NetTopologySuite.Geometries.LineString? GetGeoLineString(string geoJson)
|
||||||
|
{
|
||||||
|
var serializer = GeoJsonSerializer.Create();
|
||||||
|
using (var stringReader = new StringReader(geoJson))
|
||||||
|
using (var jsonReader = new JsonTextReader(stringReader))
|
||||||
|
{
|
||||||
|
return serializer.Deserialize<NetTopologySuite.Geometries.LineString>(jsonReader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NetTopologySuite.Geometries.MultiLineString? GetGeoMultiLineString(string geoJson)
|
||||||
|
{
|
||||||
|
var serializer = GeoJsonSerializer.Create();
|
||||||
|
using (var stringReader = new StringReader(geoJson))
|
||||||
|
using (var jsonReader = new JsonTextReader(stringReader))
|
||||||
|
{
|
||||||
|
return serializer.Deserialize<NetTopologySuite.Geometries.MultiLineString>(jsonReader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NetTopologySuite.Geometries.Polygon? GetGeoPolygon(string geoJson)
|
||||||
|
{
|
||||||
|
var serializer = GeoJsonSerializer.Create();
|
||||||
|
using (var stringReader = new StringReader(geoJson))
|
||||||
|
using (var jsonReader = new JsonTextReader(stringReader))
|
||||||
|
{
|
||||||
|
return serializer.Deserialize<NetTopologySuite.Geometries.Polygon>(jsonReader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NetTopologySuite.Geometries.MultiPolygon? GetGeoMultiPolygon(string geoJson)
|
||||||
|
{
|
||||||
|
var serializer = GeoJsonSerializer.Create();
|
||||||
|
using (var stringReader = new StringReader(geoJson))
|
||||||
|
using (var jsonReader = new JsonTextReader(stringReader))
|
||||||
|
{
|
||||||
|
return serializer.Deserialize<NetTopologySuite.Geometries.MultiPolygon>(jsonReader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetGeomWKTFromGeoJson(string? geoJson, out MultiPolygon? geometry)
|
||||||
|
{
|
||||||
|
geometry = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(geoJson))
|
||||||
|
{
|
||||||
|
var features = GeoJsonHelper.GetGeoFeatureCollectionBuild(geoJson);
|
||||||
|
var multPolygons = GeoJsonHelper.GetGeoMultiPolygon(features);
|
||||||
|
if (multPolygons?.Count > 0)
|
||||||
|
{
|
||||||
|
geometry = multPolygons[0];
|
||||||
|
geometry.SRID = 4326;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public static Geometry FromWKT(string wktData)
|
||||||
|
{
|
||||||
|
WKTReader reader = new WKTReader();
|
||||||
|
return reader.Read(wktData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Geometry FromWKB(byte[] wkbData)
|
||||||
|
{
|
||||||
|
WKBReader reader = new WKBReader();
|
||||||
|
return reader.Read(wkbData);
|
||||||
|
|
||||||
|
}
|
||||||
|
public static Polygon Transfer2CoordinateByCoords(List<Point> Coords)
|
||||||
|
{
|
||||||
|
if (Coords.Any())
|
||||||
|
{
|
||||||
|
var list = Coords.Select(s => s.X + "" + s.Y).ToList();
|
||||||
|
var content = $"POLYGON(({string.Join(",", list)}))";
|
||||||
|
WKTReader wktReader = new WKTReader();
|
||||||
|
Polygon polygon = wktReader.Read(content) as Polygon;
|
||||||
|
return polygon;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 坐标相关方法
|
||||||
|
|
||||||
|
private static GeometryFactory _gf = NetTopologySuite.NtsGeometryServices.Instance.CreateGeometryFactory(4326);
|
||||||
|
public static bool IsWithin(BasePoint pnt, BasePoint[] polygon)
|
||||||
|
{
|
||||||
|
if (IsValidPolygon(polygon))
|
||||||
|
{
|
||||||
|
var point = CreatPoint(pnt);
|
||||||
|
var region = CreatePolygon(polygon);
|
||||||
|
return point.Within(region);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 判断点是否在多边形内
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pnt"></param>
|
||||||
|
/// <param name="multiPolygon"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool isWithin(BasePoint pnt, MultiPolygon multiPolygon)
|
||||||
|
{
|
||||||
|
var point = CreatPoint(pnt);
|
||||||
|
return point.Within(multiPolygon);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 基本判断点数据是否有效转为面
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="polygon"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool IsValidPolygon(BasePoint[] polygon)
|
||||||
|
{
|
||||||
|
if (polygon?.Count() >= 4)
|
||||||
|
{
|
||||||
|
//polygon.Distinct();//重复点?
|
||||||
|
return polygon[0].Equal(polygon[polygon.Count() - 1]);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 基本判断点数据是否有效转为线
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="polygon"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool IsValidLineString(BasePoint[] polygon)
|
||||||
|
{
|
||||||
|
if (polygon?.Count() >= 2)
|
||||||
|
{
|
||||||
|
//polygon.Distinct();//重复点?
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建点
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pnt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Point CreatPoint(BasePoint pnt)
|
||||||
|
{
|
||||||
|
return _gf.CreatePoint(GetCoordinate(pnt));
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 创建点
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pnt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Point CreatPoint(double x, double y)
|
||||||
|
{
|
||||||
|
return _gf.CreatePoint(GetCoordinate(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建线
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="polygon"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static LineString CreateLineString(BasePoint[] points)
|
||||||
|
{
|
||||||
|
return _gf.CreateLineString(GetCoordinate(points));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建面
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="polygon"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Polygon CreatePolygon(BasePoint[] polygon)
|
||||||
|
{
|
||||||
|
return _gf.CreatePolygon(GetCoordinate(polygon));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 点转换到坐标
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pnt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static NetTopologySuite.Geometries.Coordinate GetCoordinate(BasePoint pnt)
|
||||||
|
{
|
||||||
|
return new NetTopologySuite.Geometries.Coordinate(pnt.X, pnt.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 点转换到坐标
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pnt"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static NetTopologySuite.Geometries.Coordinate GetCoordinate(double x, double y)
|
||||||
|
{
|
||||||
|
return new NetTopologySuite.Geometries.Coordinate(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 点组转换坐标组
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="polygon"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static NetTopologySuite.Geometries.Coordinate[] GetCoordinate(BasePoint[] polygon)
|
||||||
|
{
|
||||||
|
List<NetTopologySuite.Geometries.Coordinate> coordinates = new List<NetTopologySuite.Geometries.Coordinate>();
|
||||||
|
foreach (var item in polygon)
|
||||||
|
{
|
||||||
|
coordinates.Add(GetCoordinate(item));
|
||||||
|
}
|
||||||
|
return coordinates.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Geometry CreateCircleMercator(double x, double y, double radius)
|
||||||
|
{
|
||||||
|
var geometryFactory = new GeometryFactory();
|
||||||
|
var wbp = CoordConvert.WGS84ToMercator(x, y);
|
||||||
|
var point1 = geometryFactory.CreatePoint(new NetTopologySuite.Geometries.Coordinate(wbp.X, wbp.Y));
|
||||||
|
var geo = point1.Buffer(radius, 80);
|
||||||
|
//var geo1 = point1.Buffer(radius);
|
||||||
|
return geo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建圆形
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <param name="radius"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Geometry CreateCircle(double x, double y, double radius, int pnts = 100)
|
||||||
|
{
|
||||||
|
var geo1 = CreateCircleMercator(x, y, radius);
|
||||||
|
var coordinates = geo1.Coordinates;
|
||||||
|
List<BasePoint> points = new List<BasePoint>();
|
||||||
|
foreach (var item in coordinates)
|
||||||
|
{
|
||||||
|
var wgs84 = CoordConvert.MercatorToWGS84(item.X, item.Y);
|
||||||
|
points.Add(new BasePoint(wgs84.Lon, wgs84.Lat, 0));
|
||||||
|
}
|
||||||
|
return CreatePolygon(points.ToArray());
|
||||||
|
}
|
||||||
|
public static double CalculateCircleAreaKmUnit(double x, double y, double radius)
|
||||||
|
{
|
||||||
|
if (x > 0 && y > 0 && radius > 0)
|
||||||
|
{
|
||||||
|
var area11 = CalculateCircleArea(x, y, radius);
|
||||||
|
return Math.Round(area11 / 1000000, 5);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
public static double CalculateCircleArea(double x, double y, double radius)
|
||||||
|
{
|
||||||
|
if (x > 0 && y > 0 && radius > 0)
|
||||||
|
{
|
||||||
|
var geo1 = CreateCircleMercator(x, y, radius);
|
||||||
|
return geo1.Area;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 计算合并后的总面积
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="geometries"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static double CalculateAreaMercator(Geometry[] geometries)
|
||||||
|
{
|
||||||
|
//将多个 Geometry 合并成一个 Geometry,避免交集重复计算
|
||||||
|
var unionedGeometry = _gf.BuildGeometry(geometries).Union();
|
||||||
|
string geojson = GetGeoJson(unionedGeometry);
|
||||||
|
var area = unionedGeometry.Area;
|
||||||
|
// 计算合并后的总面积
|
||||||
|
return area;
|
||||||
|
}
|
||||||
|
///// <summary>
|
||||||
|
///// 计算合并后的总面积
|
||||||
|
///// </summary>
|
||||||
|
///// <param name="geometries"></param>
|
||||||
|
///// <returns></returns>
|
||||||
|
//public static double CalculateArea(Geometry[] geometries)
|
||||||
|
//{
|
||||||
|
// //将多个 Geometry 合并成一个 Geometry,避免交集重复计算
|
||||||
|
// var unionedGeometry = _gf.BuildGeometry(geometries).Union();
|
||||||
|
// string geojson = GetGeoJson(unionedGeometry);
|
||||||
|
// var area = Math.Round(unionedGeometry.ProjectTo(2855).Area / 1000000.0, 5);
|
||||||
|
// // 计算合并后的总面积
|
||||||
|
// return area;
|
||||||
|
//}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,420 @@
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace LY.App.Common.HttpUtil
|
||||||
|
{
|
||||||
|
public static class RequestUtil
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 是否已经初始化加密协议
|
||||||
|
/// </summary>
|
||||||
|
private static bool _securitinit = false;
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化加密协议
|
||||||
|
/// </summary>
|
||||||
|
public static void InitialSecurity()
|
||||||
|
{
|
||||||
|
if (_securitinit) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
|
||||||
|
| SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
|
||||||
|
| SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
|
||||||
|
_securitinit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取HTTP连接
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="haveSSL">是否ssl连接</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static HttpClient GetClient(bool haveSSL)
|
||||||
|
{
|
||||||
|
if (haveSSL)
|
||||||
|
{
|
||||||
|
InitialSecurity();
|
||||||
|
var handle = new HttpClientHandler();
|
||||||
|
handle.ServerCertificateCustomValidationCallback
|
||||||
|
= HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
|
||||||
|
return new HttpClient(handle);
|
||||||
|
}
|
||||||
|
else return new HttpClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步请求GET
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">网址</param>
|
||||||
|
/// <param name="headers">头部信息</param>
|
||||||
|
/// <param name="auth">验证信息</param>
|
||||||
|
/// <param name="timeout">过期时间</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<string> GetAsync(string url,
|
||||||
|
Dictionary<string, string> headers = null,
|
||||||
|
AuthenticationHeaderValue auth = null, int timeout = 5000)
|
||||||
|
{
|
||||||
|
using (var client = GetClient(url.StartsWith("https")))
|
||||||
|
{
|
||||||
|
client.Timeout = TimeSpan.FromMilliseconds(timeout);
|
||||||
|
if (headers != null && headers.Any())
|
||||||
|
{
|
||||||
|
foreach (var item in headers)
|
||||||
|
{
|
||||||
|
client.DefaultRequestHeaders.Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth != null)
|
||||||
|
client.DefaultRequestHeaders.Authorization = auth;
|
||||||
|
|
||||||
|
var result = await client.GetAsync(url);
|
||||||
|
if (result.IsSuccessStatusCode)
|
||||||
|
return await result.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步请求GET
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">网址</param>
|
||||||
|
/// <param name="headers">头部信息</param>
|
||||||
|
/// <param name="auth">验证信息</param>
|
||||||
|
/// <param name="timeout">过期时间</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<Stream> GetStreamAsync(string url,
|
||||||
|
Dictionary<string, string> headers = null,
|
||||||
|
AuthenticationHeaderValue auth = null, int timeout = 5000)
|
||||||
|
{
|
||||||
|
using (var client = GetClient(url.StartsWith("https")))
|
||||||
|
{
|
||||||
|
client.Timeout = TimeSpan.FromMilliseconds(timeout);
|
||||||
|
if (headers != null && headers.Any())
|
||||||
|
{
|
||||||
|
foreach (var item in headers)
|
||||||
|
{
|
||||||
|
client.DefaultRequestHeaders.Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth != null)
|
||||||
|
client.DefaultRequestHeaders.Authorization = auth;
|
||||||
|
|
||||||
|
var result = await client.GetAsync(url);
|
||||||
|
if (result.IsSuccessStatusCode)
|
||||||
|
return await result.Content.ReadAsStreamAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 删除
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url"></param>
|
||||||
|
/// <param name="headers"></param>
|
||||||
|
/// <param name="auth"></param>
|
||||||
|
/// <param name="timeout"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<string> DeleteAsync(string url,
|
||||||
|
Dictionary<string, string> headers = null,
|
||||||
|
AuthenticationHeaderValue auth = null, int timeout = 5000)
|
||||||
|
{
|
||||||
|
using (var client = GetClient(url.StartsWith("https")))
|
||||||
|
{
|
||||||
|
client.Timeout = TimeSpan.FromMilliseconds(timeout);
|
||||||
|
if (headers != null && headers.Any())
|
||||||
|
{
|
||||||
|
foreach (var item in headers)
|
||||||
|
{
|
||||||
|
client.DefaultRequestHeaders.Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth != null)
|
||||||
|
client.DefaultRequestHeaders.Authorization = auth;
|
||||||
|
|
||||||
|
var result = await client.DeleteAsync(url);
|
||||||
|
if (result.IsSuccessStatusCode)
|
||||||
|
return await result.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步请求并解析
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="url">网址</param>
|
||||||
|
/// <param name="headers">头部信息</param>
|
||||||
|
/// <param name="auth">验证信息</param>
|
||||||
|
/// <param name="timeout">过期时间</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<T> GetAsync<T>(string url,
|
||||||
|
Dictionary<string, string> headers = null,
|
||||||
|
AuthenticationHeaderValue auth = null,
|
||||||
|
int timeout = 5000)
|
||||||
|
{
|
||||||
|
var result = await GetAsync(url, headers, auth, timeout);
|
||||||
|
if (result != null)
|
||||||
|
return JsonConvert.DeserializeObject<T>(result);
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 返回btye[]
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<byte[]> GetAsync(string url)
|
||||||
|
{
|
||||||
|
using (var client = GetClient(url.StartsWith("https")))
|
||||||
|
{
|
||||||
|
client.Timeout = TimeSpan.FromMilliseconds(2000);
|
||||||
|
var result = await client.GetAsync(url);
|
||||||
|
if (result.IsSuccessStatusCode)
|
||||||
|
return await result.Content.ReadAsByteArrayAsync();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AuthenticationHeaderValue GetTokenHeader(string token)
|
||||||
|
{
|
||||||
|
return new AuthenticationHeaderValue("Bearer", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步请求POST
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">网址</param>
|
||||||
|
/// <param name="dataJson">信息</param>
|
||||||
|
/// <param name="headers">头部信息</param>
|
||||||
|
/// <param name="auth">验证信息</param>
|
||||||
|
/// <param name="timeout">过期时间</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<string> PostAsync(string url,
|
||||||
|
string dataJson = null,
|
||||||
|
Dictionary<string, string> headers = null,
|
||||||
|
AuthenticationHeaderValue auth = null, int timeout = 5000)
|
||||||
|
{
|
||||||
|
using (var client = GetClient(url.StartsWith("https")))
|
||||||
|
{
|
||||||
|
client.Timeout = TimeSpan.FromMilliseconds(timeout);
|
||||||
|
if (headers != null && headers.Any())
|
||||||
|
{
|
||||||
|
foreach (var item in headers)
|
||||||
|
{
|
||||||
|
client.DefaultRequestHeaders.Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth != null)
|
||||||
|
client.DefaultRequestHeaders.Authorization = auth;
|
||||||
|
|
||||||
|
StringContent content = null;
|
||||||
|
|
||||||
|
if (dataJson != null)
|
||||||
|
{
|
||||||
|
content = new StringContent(dataJson);
|
||||||
|
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await client.PostAsync(url, content);
|
||||||
|
if (result.IsSuccessStatusCode)
|
||||||
|
return await result.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步请求POST
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">网址</param>
|
||||||
|
/// <param name="data">消息</param>
|
||||||
|
/// <param name="headers">头部信息</param>
|
||||||
|
/// <param name="auth">验证信息</param>
|
||||||
|
/// <param name="timeout">过期时间</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<string> PostAsync(string url,
|
||||||
|
Dictionary<string, string> data,
|
||||||
|
Dictionary<string, string> headers = null,
|
||||||
|
AuthenticationHeaderValue auth = null, int timeout = 5000)
|
||||||
|
{
|
||||||
|
return await PostAsync(url, JsonConvert.SerializeObject(data), headers, auth, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步请求POST
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="url">网址</param>
|
||||||
|
/// <param name="dataJson">信息</param>
|
||||||
|
/// <param name="headers">头部信息</param>
|
||||||
|
/// <param name="auth">验证信息</param>
|
||||||
|
/// <param name="timeout">过期时间</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<T> PostAsync<T>(string url,
|
||||||
|
string dataJson = null,
|
||||||
|
Dictionary<string, string> headers = null,
|
||||||
|
AuthenticationHeaderValue auth = null, int timeout = 5000)
|
||||||
|
{
|
||||||
|
var result = await PostAsync(url, dataJson, headers, auth, timeout);
|
||||||
|
return JsonConvert.DeserializeObject<T>(result);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="url">网址</param>
|
||||||
|
/// <param name="data">消息</param>
|
||||||
|
/// <param name="headers">头部信息</param>
|
||||||
|
/// <param name="auth">验证信息</param>
|
||||||
|
/// <param name="timeout">过期时间</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<T> PostAsync<T>(string url,
|
||||||
|
Dictionary<string, string> data = null,
|
||||||
|
Dictionary<string, string> headers = null,
|
||||||
|
AuthenticationHeaderValue auth = null, int timeout = 5000)
|
||||||
|
{
|
||||||
|
return await PostAsync<T>(url, JsonConvert.SerializeObject(data), headers, auth, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步推送数据流
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">网址</param>
|
||||||
|
/// <param name="stream">数据流</param>
|
||||||
|
/// <param name="headers">头部信息</param>
|
||||||
|
/// <param name="auth">验证信息</param>
|
||||||
|
/// <param name="timeout">过期时间</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<string> PutStreamAsync(
|
||||||
|
string url, Stream stream,
|
||||||
|
Dictionary<string, string> headers = null,
|
||||||
|
AuthenticationHeaderValue auth = null, int timeout = 10000)
|
||||||
|
{
|
||||||
|
using (var client = GetClient(url.StartsWith("https")))
|
||||||
|
{
|
||||||
|
client.Timeout = TimeSpan.FromMilliseconds(timeout);
|
||||||
|
if (headers != null && headers.Any())
|
||||||
|
{
|
||||||
|
foreach (var item in headers)
|
||||||
|
{
|
||||||
|
client.DefaultRequestHeaders.Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth != null)
|
||||||
|
client.DefaultRequestHeaders.Authorization = auth;
|
||||||
|
|
||||||
|
StreamContent content = null;
|
||||||
|
|
||||||
|
if (stream != null)
|
||||||
|
{
|
||||||
|
content = new StreamContent(stream);
|
||||||
|
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await client.PutAsync(url, content);
|
||||||
|
if (result.IsSuccessStatusCode)
|
||||||
|
return await result.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步推送数据流
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">网址</param>
|
||||||
|
/// <param name="stream">数据流</param>
|
||||||
|
/// <param name="headers">头部信息</param>
|
||||||
|
/// <param name="auth">验证信息</param>
|
||||||
|
/// <param name="timeout">过期时间</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<T> PutStreamAsync<T>(
|
||||||
|
string url, Stream stream,
|
||||||
|
Dictionary<string, string> headers = null,
|
||||||
|
AuthenticationHeaderValue auth = null, int timeout = 10000)
|
||||||
|
{
|
||||||
|
var result = await PutStreamAsync(url, stream, headers, auth, timeout);
|
||||||
|
return JsonConvert.DeserializeObject<T>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// PUT请求
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url"></param>
|
||||||
|
/// <param name="dataJson"></param>
|
||||||
|
/// <param name="headers"></param>
|
||||||
|
/// <param name="auth"></param>
|
||||||
|
/// <param name="timeout"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<string> PutAsync(string url,
|
||||||
|
string dataJson = null,
|
||||||
|
Dictionary<string, string> headers = null,
|
||||||
|
AuthenticationHeaderValue auth = null, int timeout = 5000)
|
||||||
|
{
|
||||||
|
using (var client = GetClient(url.StartsWith("https")))
|
||||||
|
{
|
||||||
|
client.Timeout = TimeSpan.FromMilliseconds(timeout);
|
||||||
|
if (headers != null && headers.Any())
|
||||||
|
{
|
||||||
|
foreach (var item in headers)
|
||||||
|
{
|
||||||
|
client.DefaultRequestHeaders.Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth != null)
|
||||||
|
client.DefaultRequestHeaders.Authorization = auth;
|
||||||
|
|
||||||
|
StringContent content = null;
|
||||||
|
|
||||||
|
if (dataJson != null)
|
||||||
|
{
|
||||||
|
content = new StringContent(dataJson);
|
||||||
|
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await client.PutAsync(url, content);
|
||||||
|
if (result.IsSuccessStatusCode)
|
||||||
|
return await result.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
namespace LY.App.Common
|
||||||
|
{
|
||||||
|
public static class Parameters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 地球平均半径
|
||||||
|
/// </summary>
|
||||||
|
public const double EarthRadius = 6371393;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 地球长轴半径
|
||||||
|
/// </summary>
|
||||||
|
public const double LongRadius = 6378137;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 地球短轴半径
|
||||||
|
/// </summary>
|
||||||
|
public const double ShortRadius = 6356752.3142;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 地球扁率
|
||||||
|
/// </summary>
|
||||||
|
public const double Oblateness = 0.00335281066433;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public const double MercatorLength = 20037508.34;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
namespace LY.App.Common.Redis
|
||||||
|
{
|
||||||
|
public class RedisKeyList
|
||||||
|
{
|
||||||
|
public static string BatchIdBysn(string sn)
|
||||||
|
{
|
||||||
|
return $"batchid_{sn}";
|
||||||
|
}
|
||||||
|
public static string LogNum(string userName)
|
||||||
|
{
|
||||||
|
return $"login_fail_{userName}";
|
||||||
|
}
|
||||||
|
public static string TokenUser(string userName)
|
||||||
|
{
|
||||||
|
return $"token_{userName}";
|
||||||
|
}
|
||||||
|
public static string DeviceInfo(string code)
|
||||||
|
{
|
||||||
|
return $"deviceInfo_{code}";
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存首页数据
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string index_data()
|
||||||
|
{
|
||||||
|
return $"index_cache";
|
||||||
|
}
|
||||||
|
public static string DeviceStatus(string sn)
|
||||||
|
{
|
||||||
|
return $"device_status_{sn}";
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存设备token
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string DeviceTokenById(long id)
|
||||||
|
{
|
||||||
|
return $"device_token_{id}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
using LY.App.Extensions.DI;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace LY.App.Common.Redis
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// redis 连接服务
|
||||||
|
/// </summary>
|
||||||
|
public class RedisService
|
||||||
|
{
|
||||||
|
private readonly IDatabase _db;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connectionString"></param>
|
||||||
|
public RedisService(string connectionString)
|
||||||
|
{
|
||||||
|
var redis = ConnectionMultiplexer.Connect(connectionString);
|
||||||
|
_db = redis.GetDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 泛型存储数据到 Redis
|
||||||
|
/// </summary>
|
||||||
|
public async Task<bool> SetAsync<T>(string key, T value, TimeSpan? expiry = null)
|
||||||
|
{
|
||||||
|
string jsonData = JsonSerializer.Serialize(value);
|
||||||
|
return await _db.StringSetAsync(key, jsonData, expiry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 泛型获取数据
|
||||||
|
/// </summary>
|
||||||
|
public async Task<T?> GetAsync<T>(string key)
|
||||||
|
{
|
||||||
|
string jsonData = await _db.StringGetAsync(key);
|
||||||
|
return jsonData is not null ? JsonSerializer.Deserialize<T>(jsonData) : default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 删除 Key
|
||||||
|
/// </summary>
|
||||||
|
public async Task<bool> DeleteAsync(string key)
|
||||||
|
{
|
||||||
|
return await _db.KeyDeleteAsync(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查 Key 是否存在
|
||||||
|
/// </summary>
|
||||||
|
public async Task<bool> ExistsAsync(string key)
|
||||||
|
{
|
||||||
|
return await _db.KeyExistsAsync(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
using LY.App.Extensions.DI;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace LY.App.Common.WebSocket
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 客户端push消息
|
||||||
|
/// </summary>
|
||||||
|
[ServiceInjection(InjectionType.Singleton)]
|
||||||
|
public class PushService
|
||||||
|
{
|
||||||
|
private readonly IHubContext<SocketHub> _hubContext;
|
||||||
|
|
||||||
|
public PushService(IHubContext<SocketHub> hubContext)
|
||||||
|
{
|
||||||
|
_hubContext = hubContext;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 1对1消息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connectionId"></param>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task SendMessageToClient(string connectionId, object message)
|
||||||
|
{
|
||||||
|
await _hubContext.Clients.Client(connectionId).SendAsync("ReceiveMessage", message);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 全部消息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task SendMessageToAll(object message)
|
||||||
|
{
|
||||||
|
|
||||||
|
var data = JsonConvert.SerializeObject(message);
|
||||||
|
Console.WriteLine($"推送前端消息:{data}");
|
||||||
|
await _hubContext.Clients.All.SendAsync("ReceiveMessage", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
using LY.App.Extensions.DI;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace LY.App.Common.WebSocket
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// socket
|
||||||
|
/// </summary>
|
||||||
|
[ServiceInjection(InjectionType.Singleton)]
|
||||||
|
public class SocketHub : Hub
|
||||||
|
{
|
||||||
|
// 客户端连接事件
|
||||||
|
public override async Task OnConnectedAsync()
|
||||||
|
{
|
||||||
|
var msg = JsonConvert.SerializeObject(new { msgType = "info", data = "hello" });
|
||||||
|
// 发送消息给连接的客户端
|
||||||
|
await Clients.Caller.SendAsync("ReceiveMessage", msg);
|
||||||
|
await base.OnConnectedAsync();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// // 自定义方法,用于向客户端推送消息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task SendMessageToClient(object message)
|
||||||
|
{
|
||||||
|
// 发送消息给所有客户端
|
||||||
|
|
||||||
|
var connId = this.Context.ConnectionId;
|
||||||
|
var msg = JsonConvert.SerializeObject(message);
|
||||||
|
await this.Clients.All.SendAsync("ReceiveMessage", msg);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 向指的用户发送
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user"></param>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task SendMessageToUser(string user, object message)
|
||||||
|
{
|
||||||
|
var msg = JsonConvert.SerializeObject(message);
|
||||||
|
await Clients.All.SendAsync("ReceiveMessage", user, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
using LY.App.Model;
|
||||||
|
using LY.App.Service;
|
||||||
|
using Mapster;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace LY.App.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class AlarmController : ControllerBase
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly AlarmService _alarmService;
|
||||||
|
|
||||||
|
public AlarmController(AlarmService alarmService)
|
||||||
|
{
|
||||||
|
_alarmService = alarmService;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///列表
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("list")]
|
||||||
|
public async Task<IActionResult> List([FromQuery] AlarmReq input)
|
||||||
|
{
|
||||||
|
var result = await _alarmService.GetPage(input);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 新增告警
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("add")]
|
||||||
|
public async Task<IActionResult> AddAlarm(RevData input)
|
||||||
|
{
|
||||||
|
var result = await _alarmService.AddAlarm(input);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取指定批次的告警详情
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="batchid"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("detail")]
|
||||||
|
public async Task<IActionResult> detail(long batchid)
|
||||||
|
{
|
||||||
|
var result = await _alarmService.GetByBatchId(batchid);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 统计报表
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start"></param>
|
||||||
|
/// <param name="end"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("report")]
|
||||||
|
public async Task<IActionResult> report(DateTime? start, DateTime? end)
|
||||||
|
{
|
||||||
|
var result=await _alarmService.GetReport(start, end);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
using LY.App.Model;
|
||||||
|
using LY.App.Service;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Drawing.Printing;
|
||||||
|
using System.Security.Permissions;
|
||||||
|
|
||||||
|
namespace LY.App.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class DeviceController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly DeviceService _deviceService;
|
||||||
|
public DeviceController(DeviceService deviceService)
|
||||||
|
{
|
||||||
|
_deviceService = deviceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 新增设备
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("add")]
|
||||||
|
public async Task<IActionResult> Add(AddDevice input)
|
||||||
|
{
|
||||||
|
var result =await _deviceService.Add(input);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 列表
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pageNum"></param>
|
||||||
|
/// <param name="pageSize"></param>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("list")]
|
||||||
|
public async Task<IActionResult> List(int pageNum, int pageSize, string key)
|
||||||
|
{
|
||||||
|
var result = await _deviceService.List(pageNum, pageSize, key);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///更新
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("updata")]
|
||||||
|
public async Task<IActionResult> Updata(UpdateDevice input)
|
||||||
|
{
|
||||||
|
var result = _deviceService.updata(input);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
[HttpDelete("delete")]
|
||||||
|
public async Task<IActionResult> Delete(long id)
|
||||||
|
{
|
||||||
|
var result = await _deviceService.delete(id);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
using LY.App.Common.Redis;
|
||||||
|
using LY.App.Device;
|
||||||
|
using LY.App.Model;
|
||||||
|
using LY.App.Service;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace LY.App.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class HomeController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly DeviceService _deviceService;
|
||||||
|
private readonly DeviceManager deviceManager = DeviceManager.Instance;
|
||||||
|
private readonly PositionService _positionService;
|
||||||
|
private readonly RedisService _redisService;
|
||||||
|
public HomeController(DeviceService deviceService, PositionService positionService, RedisService redisService)
|
||||||
|
{
|
||||||
|
_deviceService = deviceService;
|
||||||
|
_positionService = positionService;
|
||||||
|
_redisService = redisService;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 首页
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("view")]
|
||||||
|
public async Task<IActionResult> view()
|
||||||
|
{
|
||||||
|
ApiResult result = new ApiResult();
|
||||||
|
var positions = await _positionService.Index();
|
||||||
|
result.data = new
|
||||||
|
{
|
||||||
|
positions
|
||||||
|
};
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
using LY.App.Model;
|
||||||
|
using LY.App.Service;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace LY.App.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class PositionController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly PositionService _positionService;
|
||||||
|
|
||||||
|
public PositionController(PositionService positionService)
|
||||||
|
{
|
||||||
|
_positionService = positionService;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取列表
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("list")]
|
||||||
|
public async Task<IActionResult> Get(PositionQueryInput input)
|
||||||
|
{
|
||||||
|
var positions = _positionService.GetList(input);
|
||||||
|
return Ok(positions);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 删除
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpDelete("delete")]
|
||||||
|
public async Task<IActionResult> Delete(long id)
|
||||||
|
{
|
||||||
|
var position = await _positionService.Delete(id);
|
||||||
|
return Ok(position);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 新增
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("add")]
|
||||||
|
public async Task<IActionResult> Add(AddPosition input)
|
||||||
|
{
|
||||||
|
var result = await _positionService.MainAdd(input);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 更新
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("update")]
|
||||||
|
public async Task<IActionResult> update(UpdatePosition input)
|
||||||
|
{
|
||||||
|
var result = await _positionService.Update(input);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
using LY.App.Model;
|
||||||
|
using LY.App.Service;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace LY.App.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class UserController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly UserService _userService;
|
||||||
|
public UserController(UserService userService)
|
||||||
|
{
|
||||||
|
_userService = userService;
|
||||||
|
}
|
||||||
|
#region 增删改查
|
||||||
|
[HttpPost("add")]
|
||||||
|
public async Task<IActionResult> Add(AddUser input)
|
||||||
|
{
|
||||||
|
var result = await _userService.Add(input);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 列表
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("list")]
|
||||||
|
public async Task<IActionResult> GetList(int pageSize = 10, int pageNum = 1, string key = "")
|
||||||
|
{
|
||||||
|
var result = await _userService.GetPage(pageSize, pageNum, key);
|
||||||
|
return Ok(new ApiResult() { data = result });
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 删除
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ids"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpDelete("remove")]
|
||||||
|
public async Task<IActionResult> Delete(IEnumerable<long> ids)
|
||||||
|
{
|
||||||
|
var result = await _userService.SoftDelete(ids);
|
||||||
|
return Ok(new ApiResult()
|
||||||
|
{
|
||||||
|
code = string.IsNullOrEmpty(result) ? 0 : 1,
|
||||||
|
msg = result
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 更新用户对象
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("update")]
|
||||||
|
public async Task<IActionResult> Update(UpdateUser input)
|
||||||
|
{
|
||||||
|
var result = await _userService.Update(input);
|
||||||
|
return Ok(new ApiResult()
|
||||||
|
{
|
||||||
|
code = string.IsNullOrEmpty(result) ? 0 : 1,
|
||||||
|
msg = result,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 更新密码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("updatepwd")]
|
||||||
|
public async Task<IActionResult> updatepwd(UpdatePwdDto input)
|
||||||
|
{
|
||||||
|
var result = await _userService.UpdatePwd(input);
|
||||||
|
return Ok(new ApiResult()
|
||||||
|
{
|
||||||
|
code = string.IsNullOrEmpty(result) ? 0 : 1,
|
||||||
|
msg = result
|
||||||
|
});
|
||||||
|
}
|
||||||
|
[HttpGet("detail")]
|
||||||
|
public async Task<IActionResult> Detail(long id)
|
||||||
|
{
|
||||||
|
var result = await _userService.GetUserById(id);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return Ok(new ApiResult()
|
||||||
|
{
|
||||||
|
code = 0,
|
||||||
|
data = { },
|
||||||
|
msg = ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Ok(new ApiResult()
|
||||||
|
{
|
||||||
|
code = 0,
|
||||||
|
data = result,
|
||||||
|
msg = ""
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region 登陆
|
||||||
|
[HttpPost("login")]
|
||||||
|
public async Task<IActionResult> Login(LoginModel input)
|
||||||
|
{
|
||||||
|
var result = await _userService.Login(input);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,240 @@
|
||||||
|
namespace LY.App.Device.Command
|
||||||
|
{
|
||||||
|
public static class GraphCommand
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取打击状态
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string AttackStatus()
|
||||||
|
{
|
||||||
|
return @"{
|
||||||
|
widebandJammer {
|
||||||
|
band15
|
||||||
|
band24
|
||||||
|
band58
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取无人机
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string GetFindTarget()
|
||||||
|
{
|
||||||
|
return @"{drone {
|
||||||
|
attack_bands,
|
||||||
|
attack_type,
|
||||||
|
attacking,
|
||||||
|
can_attack,
|
||||||
|
can_takeover,
|
||||||
|
created_time,
|
||||||
|
deleted_time,
|
||||||
|
description,
|
||||||
|
direction,
|
||||||
|
distance,
|
||||||
|
has_duplicate,
|
||||||
|
id,
|
||||||
|
initial_location {
|
||||||
|
lat
|
||||||
|
lng
|
||||||
|
},
|
||||||
|
jamming_conflicts,
|
||||||
|
lastseen,
|
||||||
|
latitude,
|
||||||
|
link_id,
|
||||||
|
localization {
|
||||||
|
lat
|
||||||
|
lng
|
||||||
|
},
|
||||||
|
longitude,
|
||||||
|
name,
|
||||||
|
height,
|
||||||
|
distance,
|
||||||
|
seen_sensor {
|
||||||
|
detected_freq_khz
|
||||||
|
noise_dbm
|
||||||
|
sensor_id
|
||||||
|
signal_dbm
|
||||||
|
snr_dB
|
||||||
|
},
|
||||||
|
state,
|
||||||
|
whitelisted
|
||||||
|
}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取设备状态信息
|
||||||
|
/// </summary>
|
||||||
|
public static string GetDeveceStatusInfo()
|
||||||
|
{
|
||||||
|
return @"{
|
||||||
|
devices{
|
||||||
|
id
|
||||||
|
config
|
||||||
|
gps_fixed
|
||||||
|
class
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
}
|
||||||
|
public static string GetAdsb()
|
||||||
|
{
|
||||||
|
|
||||||
|
return @"{
|
||||||
|
droneAdsB {
|
||||||
|
support
|
||||||
|
drone {
|
||||||
|
id
|
||||||
|
speed
|
||||||
|
height
|
||||||
|
latitude
|
||||||
|
longitude
|
||||||
|
yaw_angle
|
||||||
|
confirmed
|
||||||
|
registration
|
||||||
|
typecode
|
||||||
|
manufacturer
|
||||||
|
model
|
||||||
|
owner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取传感器状态
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string GetSensorStatus()
|
||||||
|
{
|
||||||
|
return @"{sensor {
|
||||||
|
config,
|
||||||
|
faults,
|
||||||
|
id,
|
||||||
|
mac,
|
||||||
|
name,
|
||||||
|
sensor_status {
|
||||||
|
built_time
|
||||||
|
component_type
|
||||||
|
first_seen
|
||||||
|
git_hash
|
||||||
|
ip_address
|
||||||
|
last_seen
|
||||||
|
temperature
|
||||||
|
version
|
||||||
|
},
|
||||||
|
state,
|
||||||
|
ttl
|
||||||
|
}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 白名单
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string GetWhitelist()
|
||||||
|
{
|
||||||
|
return @"{whitelist{dronetype,id}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 系统能力查询
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string GetSystemCapability()
|
||||||
|
{
|
||||||
|
return @"{sysCapability}";
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取宽带打击的频段
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string widebanJammer()
|
||||||
|
{
|
||||||
|
return @"{widebandJammer{
|
||||||
|
band12
|
||||||
|
band14
|
||||||
|
band15
|
||||||
|
band18
|
||||||
|
band24
|
||||||
|
band4
|
||||||
|
band58
|
||||||
|
band9}}";
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 添加白名单
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="droneId"></param>
|
||||||
|
/// <param name="droneType"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string AddWhitelist(string droneId, string droneType)
|
||||||
|
{
|
||||||
|
return "mutation{addWhitelist(id:\"" + droneId + "\"\ndronetype:\"" + droneType + "\"\ntimerange:\"permanent,permanent\")}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 删除白名单
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="droneId"></param>
|
||||||
|
/// <param name="droneType"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string DeleteWhitelist(string droneId)
|
||||||
|
{
|
||||||
|
return "mutation{deleteWhitelist(id:\"" + droneId + "\")}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 精确打击,flse开始,true停止
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="isAttack"></param>
|
||||||
|
/// <param name="droneId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string AccurateAttack(bool isAttack, string droneId)
|
||||||
|
{
|
||||||
|
string cmdstr = "mutation{ attack( cancel:true \n takeover:false \n id: \"" + droneId + "\"\n )}";
|
||||||
|
if (isAttack)
|
||||||
|
{
|
||||||
|
cmdstr = "mutation{ attack( cancel:false \n takeover:false \n id: \"" + droneId + "\"\n )}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmdstr = "mutation{ attack( cancel:true \n takeover:false \n id: \"" + droneId + "\"\n )}";
|
||||||
|
}
|
||||||
|
return cmdstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自动打击
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="isAuto"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string AutoAttack(bool isAuto)
|
||||||
|
{
|
||||||
|
string cmdstr = "mutation{ autoAttack( on: " + isAuto + " \n wbEnabled: false ) }";
|
||||||
|
if (isAuto)
|
||||||
|
{
|
||||||
|
cmdstr = "mutation{ autoAttack( on:true \n wbEnabled: false ) }";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmdstr = "mutation{ autoAttack( on:false \n wbEnabled: false ) }";
|
||||||
|
}
|
||||||
|
return cmdstr.ToLower();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 宽带打击
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="band">15,24,58</param>
|
||||||
|
/// <param name="status">true,开启,false,关闭</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string WidebandAttack(string band, bool status)
|
||||||
|
{
|
||||||
|
|
||||||
|
string cmdstr = "mutation{ wideband_attack( band: \"" + band + "\"\n wb_status:" + status + ")\n" +
|
||||||
|
"{band15\nband24\nband58\nband9}}";
|
||||||
|
return cmdstr.ToLower();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,429 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GraphQL.Client.Http;
|
||||||
|
using GraphQL.Transport;
|
||||||
|
using GraphQL.Client.Serializer.Newtonsoft;
|
||||||
|
using GraphQL.Client.Abstractions;
|
||||||
|
using MQTTnet;
|
||||||
|
using MQTTnet.Client;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using LY.App.Common.Redis;
|
||||||
|
using LY.App.Model;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
using LY.App.Common.HttpUtil;
|
||||||
|
using LY.App.Device.Command;
|
||||||
|
|
||||||
|
namespace LY.App.Device
|
||||||
|
{
|
||||||
|
public enum ProtocolType
|
||||||
|
{
|
||||||
|
TCP,
|
||||||
|
UDP,
|
||||||
|
GraphQL,
|
||||||
|
MQTT
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Device
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
public ProtocolType Protocol { get; set; }
|
||||||
|
public string IpAddress { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
public string GraphQlEndpoint { get; set; }
|
||||||
|
public bool IsConnected { get; set; }
|
||||||
|
public string BrokerAddress { get; set; } // MQTT Broker 地址
|
||||||
|
public string Topic { get; set; } // MQTT 主题
|
||||||
|
public string username { get; set; } // MQTT 用户名
|
||||||
|
public string password { get; set; } // MQTT 密码
|
||||||
|
/// <summary>
|
||||||
|
/// 数据接收事件
|
||||||
|
/// </summary>
|
||||||
|
public Action<string> DataReceived { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeviceManager
|
||||||
|
{
|
||||||
|
private readonly ConcurrentDictionary<long, Device> _devices = new();
|
||||||
|
private readonly ConcurrentDictionary<long, IMqttClient> _mqttClients = new(); // 维护 MQTT 客户端
|
||||||
|
private static DeviceManager _instance;
|
||||||
|
private readonly RedisService _redis = ServiceLocator.Instance.GetService<RedisService>();
|
||||||
|
private static readonly object _lock = new object();
|
||||||
|
|
||||||
|
private DeviceManager() { }
|
||||||
|
public static DeviceManager Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
_instance = new DeviceManager();
|
||||||
|
}
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddDevice(Device device)
|
||||||
|
{
|
||||||
|
if (_devices.TryAdd(device.Id, device))
|
||||||
|
{
|
||||||
|
switch (device.Protocol)
|
||||||
|
{
|
||||||
|
case ProtocolType.TCP:
|
||||||
|
Task.Run(() => HandleTcpDevice(device));
|
||||||
|
break;
|
||||||
|
case ProtocolType.UDP:
|
||||||
|
Task.Run(() => HandleUdpDevice(device));
|
||||||
|
break;
|
||||||
|
case ProtocolType.GraphQL:
|
||||||
|
Task.Run(() => HandleGraphQLDevice(device));
|
||||||
|
break;
|
||||||
|
case ProtocolType.MQTT:
|
||||||
|
Task.Run(() => HandleMqttDevice(device));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void RemoveDevice(long deviceId)
|
||||||
|
{
|
||||||
|
if (_devices.TryRemove(deviceId, out var device))
|
||||||
|
{
|
||||||
|
device.IsConnected = false; // 终止接收数据的循环
|
||||||
|
|
||||||
|
// 对于 MQTT 协议,断开客户端连接并清理
|
||||||
|
if (device.Protocol == ProtocolType.MQTT && _mqttClients.TryRemove(deviceId, out var mqttClient))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (mqttClient.IsConnected)
|
||||||
|
{
|
||||||
|
await mqttClient.DisconnectAsync();
|
||||||
|
}
|
||||||
|
mqttClient.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"设备 {deviceId} 断开 MQTT 连接时出错: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConcurrentDictionary<long, Device> GetAllDevices()
|
||||||
|
{
|
||||||
|
return _devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendCommand(long deviceId, string command)
|
||||||
|
{
|
||||||
|
if (_devices.TryGetValue(deviceId, out var device))
|
||||||
|
{
|
||||||
|
var data = Encoding.UTF8.GetBytes(command);
|
||||||
|
switch (device.Protocol)
|
||||||
|
{
|
||||||
|
case ProtocolType.TCP:
|
||||||
|
using (var client = new TcpClient())
|
||||||
|
{
|
||||||
|
await client.ConnectAsync(device.IpAddress, device.Port);
|
||||||
|
var stream = client.GetStream();
|
||||||
|
await stream.WriteAsync(data, 0, data.Length);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ProtocolType.UDP:
|
||||||
|
using (var udpClient = new UdpClient())
|
||||||
|
{
|
||||||
|
await udpClient.SendAsync(data, data.Length, device.IpAddress, device.Port);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ProtocolType.GraphQL:
|
||||||
|
using (var graphQLClient = new GraphQLHttpClient(device.GraphQlEndpoint, new NewtonsoftJsonSerializer()))
|
||||||
|
{
|
||||||
|
var token = await _redis.GetAsync<string>(RedisKeyList.DeviceTokenById(deviceId));
|
||||||
|
var response = await Send<dynamic>(device.GraphQlEndpoint, token, command);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ProtocolType.MQTT:
|
||||||
|
if (_mqttClients.TryGetValue(deviceId, out var mqttClient) && mqttClient.IsConnected)
|
||||||
|
{
|
||||||
|
var message = new MqttApplicationMessageBuilder()
|
||||||
|
.WithTopic(device.Topic)
|
||||||
|
.WithPayload(data)
|
||||||
|
.Build();
|
||||||
|
await mqttClient.PublishAsync(message);
|
||||||
|
Console.WriteLine($"设备 {deviceId} (MQTT) 发送命令 {command} 成功");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("MQTT 客户端未连接");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleTcpDevice(Device device)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var client = new TcpClient();
|
||||||
|
await client.ConnectAsync(device.IpAddress, device.Port);
|
||||||
|
device.IsConnected = true;
|
||||||
|
var buffer = new byte[1024];
|
||||||
|
var stream = client.GetStream();
|
||||||
|
|
||||||
|
while (device.IsConnected)
|
||||||
|
{
|
||||||
|
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
|
||||||
|
if (bytesRead > 0)
|
||||||
|
{
|
||||||
|
var data = Encoding.UTF8.GetString(buffer, 0, bytesRead);
|
||||||
|
device.DataReceived?.Invoke(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
device.IsConnected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleUdpDevice(Device device)
|
||||||
|
{
|
||||||
|
using var udpClient = new UdpClient(device.Port);
|
||||||
|
device.IsConnected = true;
|
||||||
|
|
||||||
|
while (device.IsConnected)
|
||||||
|
{
|
||||||
|
var result = await udpClient.ReceiveAsync();
|
||||||
|
var data = Encoding.UTF8.GetString(result.Buffer);
|
||||||
|
device.DataReceived?.Invoke(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleGraphQLDevice(Device device)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var user = new
|
||||||
|
{
|
||||||
|
device.username,
|
||||||
|
device.password
|
||||||
|
};
|
||||||
|
var jsonstr = JsonConvert.SerializeObject(user);
|
||||||
|
//登陆 历正设备,获取token
|
||||||
|
var loginUrl = $"https://{device.IpAddress}/login";
|
||||||
|
var req = await RequestUtil.PostAsync(loginUrl, jsonstr);
|
||||||
|
if (req != null)
|
||||||
|
{
|
||||||
|
var userinfo = JsonConvert.DeserializeObject<Dto.LoginModel>(req);
|
||||||
|
if (userinfo != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"设备 {device.Id} 连接成功");
|
||||||
|
string token = userinfo.token;
|
||||||
|
device.IsConnected = true;
|
||||||
|
await _redis.SetAsync<string>(RedisKeyList.DeviceTokenById(device.Id), token);
|
||||||
|
device.GraphQlEndpoint = $"https://{device.IpAddress}/rf/graphql";//更新graphql地址
|
||||||
|
using var graphQLClient = new GraphQLHttpClient(device.GraphQlEndpoint, new NewtonsoftJsonSerializer());
|
||||||
|
while (device.IsConnected)
|
||||||
|
{
|
||||||
|
var response = await Send<dynamic>(device.GraphQlEndpoint, token, GraphCommand.GetFindTarget());
|
||||||
|
device.DataReceived?.Invoke(response.ToString());
|
||||||
|
await Task.Delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Console.WriteLine("登录失败");
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
device.IsConnected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async Task<T> Send<T>(string url, string token, string cmd)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var httpClientHandle = new HttpClientHandler();
|
||||||
|
httpClientHandle.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
|
||||||
|
var client = new HttpClient(httpClientHandle);
|
||||||
|
var opt = new GraphQLHttpClientOptions() { EndPoint = new Uri(url) };
|
||||||
|
var graphQLClient = new GraphQLHttpClient(opt, new NewtonsoftJsonSerializer(), client);
|
||||||
|
var request = new GraphQL.GraphQLRequest
|
||||||
|
{
|
||||||
|
Query = cmd
|
||||||
|
};
|
||||||
|
|
||||||
|
graphQLClient.HttpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("Safari", "537.36"));
|
||||||
|
graphQLClient.HttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
|
||||||
|
graphQLClient.HttpClient.DefaultRequestHeaders.Add("ContentType", "application/json");
|
||||||
|
var graphQLResponse = await graphQLClient.SendQueryAsync<T>(request);
|
||||||
|
return graphQLResponse.Data;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
private async Task HandleMqttDevice(Device device)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var factory = new MqttFactory();
|
||||||
|
var mqttClient = factory.CreateMqttClient();
|
||||||
|
|
||||||
|
var options = new MqttClientOptionsBuilder()
|
||||||
|
.WithTcpServer(device.IpAddress, device.Port)
|
||||||
|
.WithCredentials(device.username, device.password)
|
||||||
|
.WithClientId(Guid.NewGuid().ToString())
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
mqttClient.ConnectedAsync += async e =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"设备 {device.Id} 连接成功");
|
||||||
|
await mqttClient.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(device.Topic).Build());
|
||||||
|
};
|
||||||
|
|
||||||
|
mqttClient.DisconnectedAsync += async e =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"设备 {device.Id} 掉线,尝试重连...");
|
||||||
|
device.IsConnected = false;
|
||||||
|
await HandleDeviceConnection(device);
|
||||||
|
};
|
||||||
|
|
||||||
|
mqttClient.ApplicationMessageReceivedAsync += e =>
|
||||||
|
{
|
||||||
|
// 接收到 MQTT 消息后,处理数据
|
||||||
|
var message = Encoding.UTF8.GetString(e.ApplicationMessage.PayloadSegment.Array);
|
||||||
|
device.DataReceived?.Invoke(message);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
|
||||||
|
await mqttClient.ConnectAsync(options);
|
||||||
|
if (mqttClient.IsConnected)
|
||||||
|
{
|
||||||
|
_mqttClients[device.Id] = mqttClient; // 保存 MQTT 客户端实例
|
||||||
|
device.IsConnected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//while (device.isconnected)
|
||||||
|
//{
|
||||||
|
// await task.delay(1000);
|
||||||
|
//}
|
||||||
|
|
||||||
|
// 循环结束后断开连接
|
||||||
|
//if (!mqttClient.IsConnected)
|
||||||
|
//{
|
||||||
|
// await mqttClient.DisconnectAsync();
|
||||||
|
// mqttClient.Dispose();
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"设备 {device.Id} 连接失败: {ex.Message}");
|
||||||
|
device.IsConnected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async Task HandleDeviceConnection(Device device)
|
||||||
|
{
|
||||||
|
int retryDelay = 1000; // 初始重连间隔(毫秒)
|
||||||
|
int maxDelay = 30000; // 最大重连间隔(30秒)
|
||||||
|
|
||||||
|
while (!device.IsConnected)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (device.Protocol)
|
||||||
|
{
|
||||||
|
case ProtocolType.TCP:
|
||||||
|
await HandleTcpDevice(device);
|
||||||
|
break;
|
||||||
|
case ProtocolType.UDP:
|
||||||
|
await HandleUdpDevice(device);
|
||||||
|
break;
|
||||||
|
case ProtocolType.GraphQL:
|
||||||
|
await HandleGraphQLDevice(device);
|
||||||
|
break;
|
||||||
|
case ProtocolType.MQTT:
|
||||||
|
await HandleMqttDevice(device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (device.IsConnected)
|
||||||
|
{
|
||||||
|
// 连接成功,重置重连间隔
|
||||||
|
retryDelay = 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"设备 {device.Id} 连接失败,{ex.Message},{retryDelay}ms 后重试...");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"设备 {device.Id} 连接失败,{retryDelay}ms 后重试...");
|
||||||
|
await Task.Delay(retryDelay);
|
||||||
|
// 指数退避算法,避免频繁重试
|
||||||
|
retryDelay = Math.Min(retryDelay * 2, maxDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task<bool> TestConnection(long deviceId)
|
||||||
|
{
|
||||||
|
if (_devices.TryGetValue(deviceId, out var device))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (device.Protocol)
|
||||||
|
{
|
||||||
|
case ProtocolType.TCP:
|
||||||
|
using (TcpClient client = new TcpClient())
|
||||||
|
{
|
||||||
|
await client.ConnectAsync(device.IpAddress, device.Port);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case ProtocolType.UDP:
|
||||||
|
using (var udpClient = new UdpClient())
|
||||||
|
{
|
||||||
|
await udpClient.SendAsync(new byte[] { 0 }, 1, device.IpAddress, device.Port);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case ProtocolType.GraphQL:
|
||||||
|
using (var graphQLClient = new GraphQLHttpClient(device.GraphQlEndpoint, new NewtonsoftJsonSerializer()))
|
||||||
|
{
|
||||||
|
var request = new GraphQL.GraphQLRequest { Query = "{ deviceStatus { id status } }" };
|
||||||
|
var response = await graphQLClient.SendQueryAsync<dynamic>(request);
|
||||||
|
return response.Data != null;
|
||||||
|
}
|
||||||
|
case ProtocolType.MQTT:
|
||||||
|
var factory = new MqttFactory();
|
||||||
|
var mqttClient = factory.CreateMqttClient();
|
||||||
|
var options = new MqttClientOptionsBuilder()
|
||||||
|
.WithTcpServer(device.BrokerAddress)
|
||||||
|
.WithClientId(Guid.NewGuid().ToString())
|
||||||
|
.Build();
|
||||||
|
await mqttClient.ConnectAsync(options);
|
||||||
|
await mqttClient.DisconnectAsync();
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Device GetDevice(long deviceId)
|
||||||
|
{
|
||||||
|
_devices.TryGetValue(deviceId, out var device);
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
namespace LY.App.Device.Dto
|
||||||
|
{
|
||||||
|
public class LoginModel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 秘钥
|
||||||
|
/// </summary>
|
||||||
|
public string token { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 用户信息
|
||||||
|
/// </summary>
|
||||||
|
public User user { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class User
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string id { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string displayName { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string imageUrl { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string role { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
|
||||||
|
WORKDIR /app
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||||
|
WORKDIR /src
|
||||||
|
COPY ["LY.App.csproj", "."]
|
||||||
|
RUN dotnet restore "./LY.App.csproj"
|
||||||
|
COPY . .
|
||||||
|
WORKDIR "/src/."
|
||||||
|
RUN dotnet build "LY.App.csproj" -c Release -o /app/build
|
||||||
|
|
||||||
|
FROM build AS publish
|
||||||
|
RUN dotnet publish "LY.App.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=publish /app/publish .
|
||||||
|
ENTRYPOINT ["dotnet", "LY.App.dll"]
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
namespace LY.App.Extensions.DI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Injection type
|
||||||
|
/// </summary>
|
||||||
|
public enum InjectionType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Transient
|
||||||
|
/// </summary>
|
||||||
|
Transient,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Scoped
|
||||||
|
/// </summary>
|
||||||
|
Scoped,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Singleton
|
||||||
|
/// </summary>
|
||||||
|
Singleton
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
namespace LY.App.Extensions.DI
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class ServiceInjectionAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public Type InterfaceType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注入类型
|
||||||
|
/// </summary>
|
||||||
|
public InjectionType InjectionType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 服务注入
|
||||||
|
/// </summary>
|
||||||
|
public ServiceInjectionAttribute()
|
||||||
|
{
|
||||||
|
this.InjectionType = InjectionType.Scoped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 服务注入
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="injectionType">注入类型</param>
|
||||||
|
public ServiceInjectionAttribute(InjectionType injectionType)
|
||||||
|
{
|
||||||
|
this.InjectionType = injectionType;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 服务注入
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="interfaceType">服务的接口类型</param>
|
||||||
|
/// <param name="injectionType">注入的类型</param>
|
||||||
|
public ServiceInjectionAttribute(Type interfaceType, InjectionType injectionType)
|
||||||
|
{
|
||||||
|
this.InterfaceType = interfaceType;
|
||||||
|
this.InjectionType = injectionType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
using LY.App.Extensions.DI;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace LY.App.Extensions
|
||||||
|
{
|
||||||
|
public static class AutoDIExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="serviceCollection"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IServiceCollection ServicesAutoInjectionExtension(this IServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
|
var directory = AppDomain.CurrentDomain.BaseDirectory;
|
||||||
|
var types = Directory.GetFiles(directory, "*.dll", SearchOption.TopDirectoryOnly)
|
||||||
|
.Where(s => !s.ToLower().Contains("sql"))
|
||||||
|
.Select(Assembly.LoadFrom)
|
||||||
|
.SelectMany(a => a.GetTypes());
|
||||||
|
Injection(serviceCollection, types);
|
||||||
|
return serviceCollection;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 服务自动注入
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="serviceCollection">需要自动注入服务的服务集合</param>
|
||||||
|
/// <param name="selector">应用于每个Assembly的筛选函数</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">指定的注入类型不在可注入的范围内</exception>
|
||||||
|
/// <exception cref="NoImplementationInterfaceException">指定注入的类型未实现任何服务</exception>
|
||||||
|
/// <exception cref="ArgumentException">输入的参数错误:1、注入的类型未实现指定的服务。2、指定的服务不是Interface类型</exception>
|
||||||
|
/// <returns>自动注入服务后的服务集合</returns>
|
||||||
|
public static IServiceCollection ServicesAutoInjection(this IServiceCollection serviceCollection, Func<Assembly, bool> selector)
|
||||||
|
{
|
||||||
|
var directory = AppDomain.CurrentDomain.BaseDirectory;
|
||||||
|
var types = Directory.GetFiles(directory, "*.dll", SearchOption.TopDirectoryOnly)
|
||||||
|
.Select(Assembly.LoadFrom)
|
||||||
|
.Where(selector)
|
||||||
|
.SelectMany(a => a.GetTypes());
|
||||||
|
|
||||||
|
Injection(serviceCollection, types);
|
||||||
|
|
||||||
|
return serviceCollection;
|
||||||
|
}
|
||||||
|
// 注入逻辑
|
||||||
|
private static void Injection(IServiceCollection serviceCollection, IEnumerable<Type> types)
|
||||||
|
{
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
var attribute = type.GetCustomAttribute<ServiceInjectionAttribute>();
|
||||||
|
if (attribute == null) continue;
|
||||||
|
switch (attribute.InjectionType)
|
||||||
|
{
|
||||||
|
case InjectionType.Transient:
|
||||||
|
serviceCollection.AddTransient(type);
|
||||||
|
break;
|
||||||
|
case InjectionType.Scoped:
|
||||||
|
serviceCollection.AddScoped(type);
|
||||||
|
break;
|
||||||
|
case InjectionType.Singleton:
|
||||||
|
serviceCollection.AddSingleton(type);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
<DockerfileContext>.</DockerfileContext>
|
||||||
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="GraphQL" Version="8.4.1" />
|
||||||
|
<PackageReference Include="GraphQL.Client" Version="6.1.0" />
|
||||||
|
<PackageReference Include="GraphQL.Client.Serializer.Newtonsoft" Version="6.1.0" />
|
||||||
|
<PackageReference Include="GraphQL.NewtonsoftJson" Version="8.4.1" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.4" />
|
||||||
|
<PackageReference Include="MQTTnet" Version="4.3.7.1207" />
|
||||||
|
<PackageReference Include="SqlSugarCore" Version="5.1.4.182" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
|
<PackageReference Include="Mapster" Version="7.4.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
<DockerfileContext>.</DockerfileContext>
|
||||||
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
|
<DocumentationFile>obj\Debug\net6.0\ly.xml</DocumentationFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="GraphQL" Version="8.4.1" />
|
||||||
|
<PackageReference Include="GraphQL.Client" Version="6.1.0" />
|
||||||
|
<PackageReference Include="GraphQL.Client.Serializer.Newtonsoft" Version="6.1.0" />
|
||||||
|
<PackageReference Include="GraphQL.NewtonsoftJson" Version="8.4.1" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.4" />
|
||||||
|
<PackageReference Include="MQTTnet" Version="4.3.7.1207" />
|
||||||
|
<PackageReference Include="NetTopologySuite" Version="2.6.0" />
|
||||||
|
<PackageReference Include="NetTopologySuite.IO.GeoJSON" Version="4.0.0" />
|
||||||
|
<PackageReference Include="SqlSugarCore" Version="5.1.4.182" />
|
||||||
|
<PackageReference Include="StackExchange.Redis" Version="2.8.31" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
|
<PackageReference Include="Mapster" Version="7.4.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.21" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Common\SSE\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.7.34221.43
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LY.App", "LY.App.csproj", "{0962C31E-CDCF-438A-B1EA-9C0F1E240F93}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{0962C31E-CDCF-438A-B1EA-9C0F1E240F93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0962C31E-CDCF-438A-B1EA-9C0F1E240F93}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0962C31E-CDCF-438A-B1EA-9C0F1E240F93}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0962C31E-CDCF-438A-B1EA-9C0F1E240F93}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {9AE26013-632A-4ACF-9F3E-307C788F4266}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
using LY.App.Service;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LY.App.MiddleWare
|
||||||
|
{
|
||||||
|
public class CustomErrorMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
private string body = string.Empty;
|
||||||
|
private readonly LogService _logger;
|
||||||
|
public CustomErrorMiddleware(RequestDelegate requestDelegate, LogService logger)
|
||||||
|
{
|
||||||
|
this._next = requestDelegate;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
public async Task Invoke(HttpContext context, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Check if the request is a form post with a file
|
||||||
|
if (context.Request.HasFormContentType && context.Request.Form.Files.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var file in context.Request.Form.Files)
|
||||||
|
{
|
||||||
|
// Log file information
|
||||||
|
|
||||||
|
//_logger.LogInformation($"File uploaded - Name: {file.Name}, " +
|
||||||
|
// $"FileName: {file.FileName}, " +
|
||||||
|
// $"ContentType: {file.ContentType}, " +
|
||||||
|
// $"Size: {file.Length} bytes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Request.EnableBuffering();
|
||||||
|
using (var reader = new StreamReader(context.Request.Body,
|
||||||
|
encoding: Encoding.UTF8,
|
||||||
|
detectEncodingFromByteOrderMarks: false,
|
||||||
|
leaveOpen: true))
|
||||||
|
{
|
||||||
|
body = await reader.ReadToEndAsync();
|
||||||
|
// Do some processing with body…
|
||||||
|
// Reset the request body stream position so the next middleware can read it
|
||||||
|
context.Request.Body.Position = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await _next.Invoke(context);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await HandleError(context, ex, configuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 错误信息处理方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <param name="ex"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task HandleError(HttpContext context, Exception ex, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
string pars = string.Empty;
|
||||||
|
var method = context.Request.Method.ToUpper();
|
||||||
|
var enable = configuration.GetSection("log2db").Value.ToLower();
|
||||||
|
if (enable == "true")
|
||||||
|
{
|
||||||
|
switch (method)
|
||||||
|
{
|
||||||
|
case "GET":
|
||||||
|
pars = context.Request.QueryString.ToString();
|
||||||
|
break;
|
||||||
|
case "POST":
|
||||||
|
// var requestReader = new StreamReader(context.Request.Body);
|
||||||
|
// pars = await requestReader.ReadToEndAsync();
|
||||||
|
pars = body;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await _logger.AddLog(new Model.AddLog()
|
||||||
|
{
|
||||||
|
StackTrace = ex.StackTrace.Length > 1000 ? ex.StackTrace.Substring(0, 999) : ex.StackTrace,
|
||||||
|
Message = ex.Message,
|
||||||
|
Parameters = pars,
|
||||||
|
url = context.Request.Path,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Console.WriteLine($"错误消息:{ex.Message}错误追踪{ex.StackTrace}");
|
||||||
|
context.Response.StatusCode = 500;
|
||||||
|
context.Response.ContentType = "text/json;charset=utf-8;";
|
||||||
|
await context.Response.WriteAsJsonAsync(new { code = 1, msg = $"抱歉,服务端出错了,错误消息:{ex.Message}", data = "" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static class RequestCultureMiddlewareExtensions
|
||||||
|
{
|
||||||
|
public static IApplicationBuilder UseCustomErrorMiddleware(
|
||||||
|
this IApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
return builder.UseMiddleware<CustomErrorMiddleware>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using SqlSugar;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
[SplitTable(SplitType.Month)]//按年分表 (自带分表支持 年、季、月、周、日)
|
||||||
|
[SugarTable("ly_alarm_{year}{month}{day}")]
|
||||||
|
public class Alarm : BaseEntity
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 无人机批次id,
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(ValueToStringConverter))]
|
||||||
|
[SugarColumn(ColumnName = "batch_id", ColumnDescription = "批次id")]
|
||||||
|
public long BatchId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// #无人机的序列号
|
||||||
|
/// </summary>
|
||||||
|
public string serial_number { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// #无人机型号
|
||||||
|
/// </summary>
|
||||||
|
public string device_type { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public int device_type_8 { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// #遥控器的纬
|
||||||
|
/// </summary>
|
||||||
|
public double app_lat { get; set; }
|
||||||
|
public double app_lon { get; set; }
|
||||||
|
public double drone_lat { get; set; }
|
||||||
|
public double drone_lon { get; set; }
|
||||||
|
public double height { get; set; }
|
||||||
|
public double altitude { get; set; }
|
||||||
|
public double home_lat { get; set; }
|
||||||
|
public double home_lon { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ,#东向速度
|
||||||
|
/// </summary>
|
||||||
|
public double speed_E { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// #北向速度
|
||||||
|
/// </summary>
|
||||||
|
public double speed_N { get; set; }
|
||||||
|
public double speed_U { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// #信号增益
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "rssi", ColumnDescription = "信号增益")]
|
||||||
|
public double RSSI { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 无人机型号
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 位置id
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(ValueToStringConverter))]
|
||||||
|
[SugarColumn(ColumnName = "position_id", ColumnDescription = "阵地id")]
|
||||||
|
public long positionId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 位置id
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "position_name", ColumnDescription = "阵地名字")]
|
||||||
|
public string PostionName { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(ValueToStringConverter))]
|
||||||
|
[SugarColumn(ColumnName = "device_Id", ColumnDescription = "设备id")]
|
||||||
|
public long DeviceId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 来源设备名称
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "device_name", ColumnDescription = "DeviceName")]
|
||||||
|
public string DeviceName { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 频率
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "freq", ColumnDescription = "频率")]
|
||||||
|
public double freq { get; set; }
|
||||||
|
public int alarmLevel { get; set; } = 1;
|
||||||
|
|
||||||
|
[SugarColumn(ColumnName = "time", ColumnDescription = "上传时间")]
|
||||||
|
public long Time { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 创建时间
|
||||||
|
/// </summary>
|
||||||
|
[SplitField]
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDescription = "创建时间")]
|
||||||
|
public override DateTime CreateTime { get; set; } = DateTime.Now;
|
||||||
|
}
|
||||||
|
public class RevData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 设备序列号
|
||||||
|
/// </summary>
|
||||||
|
public string product_ad_id { get; set; }
|
||||||
|
public IEnumerable<AddAlarm> data { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// time
|
||||||
|
/// </summary>
|
||||||
|
public long time { get; set; }
|
||||||
|
public double product_lat { get; set; }
|
||||||
|
public double product_lon { get; set; }
|
||||||
|
public string product_id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加报警
|
||||||
|
/// </summary>
|
||||||
|
public class AddAlarm
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// #无人机的序列号
|
||||||
|
/// </summary>
|
||||||
|
public string serial_number { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// #无人机型号
|
||||||
|
/// </summary>
|
||||||
|
public string device_type { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public int device_type_8 { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// #遥控器的纬
|
||||||
|
/// </summary>
|
||||||
|
public double app_lat { get; set; }
|
||||||
|
public double app_lon { get; set; }
|
||||||
|
public double drone_lat { get; set; }
|
||||||
|
public double drone_lon { get; set; }
|
||||||
|
public double height { get; set; }
|
||||||
|
public double altitude { get; set; }
|
||||||
|
public double home_lat { get; set; }
|
||||||
|
public double home_lon { get; set; }
|
||||||
|
public double freq { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// ,#东向速度
|
||||||
|
/// </summary>
|
||||||
|
public double speed_E { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// #北向速度
|
||||||
|
/// </summary>
|
||||||
|
public double speed_N { get; set; }
|
||||||
|
public double speed_U { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// #信号增益
|
||||||
|
/// </summary>
|
||||||
|
public double RSSI { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
public class AlarmRepDto
|
||||||
|
{
|
||||||
|
public string batchId { get; set; }
|
||||||
|
//非数据库字段
|
||||||
|
public DateTime startTime { get; set; }
|
||||||
|
//非数据库字段
|
||||||
|
public DateTime endTime { get; set; }
|
||||||
|
public double duration { get; set; }
|
||||||
|
public string model { get; set; }
|
||||||
|
public string sn { get; set; }
|
||||||
|
public double Frequency { get; set; }
|
||||||
|
//非数据库字段
|
||||||
|
public bool IsWhitelist { get; set; }
|
||||||
|
[SqlSugar.SugarColumn(IsIgnore = true)]
|
||||||
|
public string Whitelist { get; set; }
|
||||||
|
[JsonConverter(typeof(ValueToStringConverter))]
|
||||||
|
public long positionId { get; set; }
|
||||||
|
public string positionName { get; set; }
|
||||||
|
|
||||||
|
//public long position_id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
public class AlarmReq
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 开始日期
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? strartDate { get; set; }
|
||||||
|
public DateTime? endDate { get; set; }
|
||||||
|
|
||||||
|
public string sn { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 时长
|
||||||
|
/// </summary>
|
||||||
|
public int? startduration { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 结束时长
|
||||||
|
/// </summary>
|
||||||
|
public int? endduration { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 机型
|
||||||
|
/// </summary>
|
||||||
|
public string model { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 白名单
|
||||||
|
/// </summary>
|
||||||
|
public bool? IsWhitelist { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 频率
|
||||||
|
/// </summary>
|
||||||
|
public double? Frequency { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 页码
|
||||||
|
/// </summary>
|
||||||
|
public int pageNum { get; set; } = 1;
|
||||||
|
/// <summary>
|
||||||
|
/// 每页条数
|
||||||
|
/// </summary>
|
||||||
|
public int pageSize { get; set; } = 10;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
public class ApiResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 状态码
|
||||||
|
/// </summary>
|
||||||
|
public int code { get; set; } = 0;
|
||||||
|
/// <summary>
|
||||||
|
/// 返回信息
|
||||||
|
/// </summary>
|
||||||
|
public string msg { get; set; } = "";
|
||||||
|
/// <summary>
|
||||||
|
/// 返回数据
|
||||||
|
/// </summary>
|
||||||
|
public object data { get; set; }
|
||||||
|
|
||||||
|
public ApiResult() { }
|
||||||
|
public ApiResult(int codeValue, string msgValue)
|
||||||
|
{
|
||||||
|
code = codeValue;
|
||||||
|
msg = msgValue;
|
||||||
|
}
|
||||||
|
public ApiResult(bool sucecss, string msgValue)
|
||||||
|
{
|
||||||
|
code = sucecss == true ? 0 : 1;
|
||||||
|
msg = msgValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
public class BaseEntity
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ID
|
||||||
|
/// 精度原因,返回前端时要转成字符串
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = false, IsPrimaryKey = true)]
|
||||||
|
[JsonConverter(typeof(ValueToStringConverter))]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建时间
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDescription = "创建时间")]
|
||||||
|
public virtual DateTime CreateTime { get; set; } = DateTime.Now;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否删除
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDescription = "是否删除", DefaultValue = "0")]
|
||||||
|
[JsonIgnore]
|
||||||
|
public bool IsDeleted { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
public struct BasePoint
|
||||||
|
{
|
||||||
|
public BasePoint(double x, double y, double z, string time = null)
|
||||||
|
{
|
||||||
|
this.X = x;
|
||||||
|
this.Y = y;
|
||||||
|
this.Z = z;
|
||||||
|
this.Time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double X { get; set; }
|
||||||
|
|
||||||
|
public double Y { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 高度
|
||||||
|
/// </summary>
|
||||||
|
public double Z { get; set; }
|
||||||
|
|
||||||
|
public string Time { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 两点值是否相等
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="basePoint"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool Equal(BasePoint basePoint)
|
||||||
|
{
|
||||||
|
return basePoint.X == this.X && basePoint.Y == this.Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
using LY.App.Device;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
[SugarTable("ly_device_info")]
|
||||||
|
public class DeviceEntity : BaseEntity
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "device_sn", ColumnDescription = "DeviceSN")]
|
||||||
|
public string DeviceSN { get; set; }
|
||||||
|
[SugarColumn(Length = 63, IsNullable = true, ColumnDescription = "Name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
[SugarColumn(Length = 63, IsNullable = true, ColumnDescription = "account")]
|
||||||
|
public string account { get; set; }
|
||||||
|
[SugarColumn(Length = 63, IsNullable = true, ColumnDescription = "password")]
|
||||||
|
public string password { get; set; }
|
||||||
|
[JsonConverter(typeof(ValueToStringConverter))]
|
||||||
|
[SugarColumn(ColumnName = "position_id", ColumnDescription = "阵地id")]
|
||||||
|
public long PositionId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 阵地名称
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "position_name", ColumnDescription = "阵地名称")]
|
||||||
|
public string PositionName { get; set; }
|
||||||
|
public string ip { get; set; }
|
||||||
|
public ProtocolType Protocol { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
[SugarColumn(IsNullable = true)]
|
||||||
|
public string GraphQlEndpoint { get; set; }
|
||||||
|
[SugarColumn(IsNullable = true)]
|
||||||
|
public string BrokerAddress { get; set; } // MQTT Broker 地址
|
||||||
|
[SugarColumn(IsNullable = true)]
|
||||||
|
public string Topic { get; set; } // MQTT 主题
|
||||||
|
/// <summary>
|
||||||
|
/// 机型
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(Length = 63, IsNullable = true, ColumnDescription = "机型")]
|
||||||
|
public string Model { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 位置
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "address", ColumnDescription = "位置", IsNullable = true)]
|
||||||
|
public string Address { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 经度
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "lon", ColumnDescription = "经度", IsNullable = true)]
|
||||||
|
public double Lon { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 纬度
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "lat", ColumnDescription = "纬度", IsNullable = true)]
|
||||||
|
public double Lat { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 高度
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnName = "alt", ColumnDescription = "高度", IsNullable = true)]
|
||||||
|
public double Alt { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
public class AddDevice
|
||||||
|
{
|
||||||
|
public long PositionId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 阵地名称
|
||||||
|
/// </summary>
|
||||||
|
public string PositionName { get; set; }
|
||||||
|
public string account { get; set; }
|
||||||
|
public string password { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string DeviceSN { get; set; }
|
||||||
|
public string ip { get; set; }
|
||||||
|
public ProtocolType Protocol { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
public string GraphQlEndpoint { get; set; }
|
||||||
|
public string BrokerAddress { get; set; } // MQTT Broker 地址
|
||||||
|
public string Topic { get; set; } // MQTT 主题
|
||||||
|
/// <summary>
|
||||||
|
/// 机型
|
||||||
|
/// </summary>
|
||||||
|
public string Model { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 位置
|
||||||
|
/// </summary>
|
||||||
|
public string Address { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 经度
|
||||||
|
/// </summary>
|
||||||
|
public double Lon { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 纬度
|
||||||
|
/// </summary>
|
||||||
|
public double Lat { get; set; }
|
||||||
|
}
|
||||||
|
public class UpdateDevice : AddDevice
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
[SugarTable("ly_logInfo")]
|
||||||
|
public class LogEntity : BaseEntity
|
||||||
|
{
|
||||||
|
public string Parameters { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
public string StackTrace { get; set; }
|
||||||
|
public string url { get; set; }
|
||||||
|
}
|
||||||
|
public class AddLog
|
||||||
|
{
|
||||||
|
public string Message { get; set; }
|
||||||
|
public string Parameters { get; set; }
|
||||||
|
|
||||||
|
public string StackTrace { get; set; }
|
||||||
|
public string url { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
public class LoginModel
|
||||||
|
{
|
||||||
|
public string username { get; set; }
|
||||||
|
public string password { get; set; }
|
||||||
|
public string type { get; set; }
|
||||||
|
public string vertifyCode { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
using LY.App.Common;
|
||||||
|
using NetTopologySuite.Algorithm;
|
||||||
|
using NetTopologySuite.Geometries;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Pipelines.Sockets.Unofficial.Arenas;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 多边形实体
|
||||||
|
/// </summary>
|
||||||
|
public class MultPolygonEntity : BaseEntity
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 空间位置点数据
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(QuerySql = "st_astext(location)", ColumnDataType = "point", ColumnName = "location",
|
||||||
|
UpdateSql = "ST_GeomFromText(@location)",
|
||||||
|
InsertSql = "ST_GeomFromText(@location)", IsNullable = true, ColumnDescription = "空间位置点数据")]
|
||||||
|
[JsonIgnore]
|
||||||
|
public string? Location { get; set; } // Geometry
|
||||||
|
/// <summary>
|
||||||
|
/// 空间面数据
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(QuerySql = "st_astext(region)", ColumnDataType = "multipolygon", ColumnName = "region",
|
||||||
|
UpdateSql = "ST_GeomFromText(@region)",
|
||||||
|
InsertSql = "ST_GeomFromText(@region)", IsNullable = true, ColumnDescription = "空间面数据")]
|
||||||
|
[JsonIgnore]
|
||||||
|
public string? Region { get; set; } //MultiPolygon Geometry
|
||||||
|
|
||||||
|
[SugarColumn(IsIgnore = true)]
|
||||||
|
public string RegionJson { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 空间位置点经度
|
||||||
|
/// </summary>
|
||||||
|
public double Lon { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 空间位置点纬度
|
||||||
|
/// </summary>
|
||||||
|
public double Lat { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 空间位置点Json数据
|
||||||
|
/// </summary>
|
||||||
|
public void SetRegionJson()
|
||||||
|
{
|
||||||
|
RegionJson = "";
|
||||||
|
if (!string.IsNullOrWhiteSpace(Region))
|
||||||
|
{
|
||||||
|
var geo = GeoJsonHelper.FromWKT(Region);
|
||||||
|
if (geo != null)
|
||||||
|
{
|
||||||
|
RegionJson = GeoJsonHelper.GetGeoJson(geo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置空间位置点
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="region"></param>
|
||||||
|
public void SetRegion(MultiPolygon region)
|
||||||
|
{
|
||||||
|
if (region != null)
|
||||||
|
{
|
||||||
|
Region = region.AsText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置空间位置点
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lon"></param>
|
||||||
|
/// <param name="lat"></param>
|
||||||
|
public void SetLocation(double lon, double lat)
|
||||||
|
{
|
||||||
|
Lon = lon;
|
||||||
|
Lat = lat;
|
||||||
|
SetLocation();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置空间位置点
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="region"></param>
|
||||||
|
public void SetRegionJson(string region)
|
||||||
|
{
|
||||||
|
RegionJson = "";
|
||||||
|
if (!string.IsNullOrWhiteSpace(region))
|
||||||
|
{
|
||||||
|
var geo = GeoJsonHelper.FromWKT(region);
|
||||||
|
if (geo != null)
|
||||||
|
{
|
||||||
|
RegionJson = GeoJsonHelper.GetGeoJson(geo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 设置空间位置点
|
||||||
|
/// </summary>
|
||||||
|
public void SetLocation()
|
||||||
|
{
|
||||||
|
Location = $"POINT({Lon} {Lat})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
public class PositionDeviceDto
|
||||||
|
{
|
||||||
|
public PositionInfo position { get; set; }
|
||||||
|
public List<DeviceItem> Devices { get; set; }
|
||||||
|
}
|
||||||
|
public class DeviceItem
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(ValueToStringConverter))]
|
||||||
|
public long Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string DeviceSN { get; set; }
|
||||||
|
public double Lat { get; set; }
|
||||||
|
public double Lon { get; set; }
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,153 @@
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 位置信息
|
||||||
|
/// </summary>
|
||||||
|
[SugarTable("ly_position")]
|
||||||
|
public class PositionInfo: MultPolygonEntity
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 名称
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(Length = 63, IsNullable = true, ColumnDescription = "名称")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 地址
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDescription = "地址")]
|
||||||
|
|
||||||
|
public string Address { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 联系人
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(Length = 63, IsNullable = true, ColumnDescription = "联系人")]
|
||||||
|
public string ContactName { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 联系人电话
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(Length = 31, IsNullable = true, ColumnDescription = "联系人电话")]
|
||||||
|
public string ContactTel { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 图片文件名
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDescription = "图片地址")]
|
||||||
|
public string ImageName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 图片地址
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsIgnore = true)]
|
||||||
|
public string ImageUrl { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 图片缩略图地址
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsIgnore = true)]
|
||||||
|
public string ImageBriefUrl { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启用时间
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDescription = "启用时间")]
|
||||||
|
public DateTime? EnableTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否启用
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnDescription = "是否启用")]
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 状态
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDescription = "状态")]
|
||||||
|
public string Status { get; set; } = "离线";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 备注
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true, ColumnDescription = "备注")]
|
||||||
|
public string Remarks { get; set; }
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 添加
|
||||||
|
/// </summary>
|
||||||
|
public class AddPosition
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 名称
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 空间数据geojson
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
public string RegionJson { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 经度
|
||||||
|
/// </summary>
|
||||||
|
public double Lon { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 纬度
|
||||||
|
/// </summary>
|
||||||
|
public double Lat { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 地址
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
public string Address { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 联系人
|
||||||
|
/// </summary>
|
||||||
|
public string ContactName { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 联系人电话
|
||||||
|
/// </summary>
|
||||||
|
public string ContactTel { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 图片文件名
|
||||||
|
/// </summary>
|
||||||
|
public string ImageName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启用时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? EnableTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否启用
|
||||||
|
/// </summary>
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 状态
|
||||||
|
/// </summary>
|
||||||
|
public string Status { get; set; } = "离线";
|
||||||
|
/// <summary>
|
||||||
|
/// 备注
|
||||||
|
/// </summary>
|
||||||
|
public string Remarks { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 更新
|
||||||
|
/// </summary>
|
||||||
|
public class UpdatePosition : AddPosition
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 主键id
|
||||||
|
/// </summary>
|
||||||
|
public long Id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
public class PositionQueryInput
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 页码
|
||||||
|
/// </summary>
|
||||||
|
public int pageNum { get; set; } = 1;
|
||||||
|
/// <summary>
|
||||||
|
/// 每页条数
|
||||||
|
/// </summary>
|
||||||
|
public int pageSize { get; set; } = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace LY.App.Model
|
||||||
|
{
|
||||||
|
[SugarTable("ly_user")]
|
||||||
|
public class UserEntity
|
||||||
|
{
|
||||||
|
[Newtonsoft.Json.JsonConverter(typeof(ValueToStringConverter))]
|
||||||
|
[SugarColumn(IsPrimaryKey = true)]//long类型的主键会自动赋值
|
||||||
|
public long Id { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 用户名
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 密码
|
||||||
|
/// </summary>
|
||||||
|
public string Password { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 登录时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime LoginTime { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 创建时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime CreateTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 上次更新密码时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? UpdatePwdTime { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 删除状态
|
||||||
|
/// </summary>
|
||||||
|
public bool Disable { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 邮箱
|
||||||
|
/// </summary>
|
||||||
|
public string Email { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 是否管理员,如果不是管理员,不可操作
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAdmin { get; set; }
|
||||||
|
}
|
||||||
|
public class AddUser
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 用户名
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 密码
|
||||||
|
/// </summary>
|
||||||
|
public string Password { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 是否管理员,如果不是管理员,不可操作
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAdmin { get; set; }
|
||||||
|
}
|
||||||
|
public class UpdateUser:AddUser
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
}
|
||||||
|
public class UpdatePwdDto
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
public string oldPwd { get; set; }
|
||||||
|
public string newPwd { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
using LY.App.Extensions;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using SqlSugar;
|
||||||
|
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||||
|
using LY.App.Common.Redis;
|
||||||
|
using LY.App.Service;
|
||||||
|
using LY.App.Model;
|
||||||
|
using LY.App.MiddleWare;
|
||||||
|
using LY.App.Common.WebSocket;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
// Add services to the container.
|
||||||
|
|
||||||
|
builder.Services.AddControllers(options =>
|
||||||
|
{
|
||||||
|
// 禁用隐式 [Required] 属性标记对非可空引用类型的属性
|
||||||
|
options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true;
|
||||||
|
}).AddNewtonsoftJson()
|
||||||
|
.AddNewtonsoftJson(NewtonsoftInitialize); ;
|
||||||
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen(
|
||||||
|
options =>
|
||||||
|
{
|
||||||
|
options.SwaggerDoc("v1", new OpenApiInfo()
|
||||||
|
{
|
||||||
|
Title = "LY.App-Api",
|
||||||
|
Version = "v1",
|
||||||
|
Description = "Api接口文档",
|
||||||
|
});
|
||||||
|
var path = Path.Combine(AppContext.BaseDirectory, "ly.xml");
|
||||||
|
options.IncludeXmlComments(path, true);
|
||||||
|
options.OrderActionsBy(_ => _.RelativePath);
|
||||||
|
});
|
||||||
|
builder.Services.AddCors(CorsOptionsEvnet);
|
||||||
|
//redis
|
||||||
|
string redisConnection = builder.Configuration.GetValue<string>("Redis:ConnectionString") ?? "localhost:6379";
|
||||||
|
|
||||||
|
// 注册 RedisService
|
||||||
|
builder.Services.AddSingleton(new RedisService(redisConnection));
|
||||||
|
////注册SignalR
|
||||||
|
builder.Services.AddSignalR();
|
||||||
|
//注册依赖注入
|
||||||
|
builder.Services.ServicesAutoInjectionExtension();
|
||||||
|
//数据库
|
||||||
|
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
|
||||||
|
//sqlsugar
|
||||||
|
builder.Services.AddTransient<SqlSugarClient>(sp =>
|
||||||
|
{
|
||||||
|
return new SqlSugarClient(new ConnectionConfig()
|
||||||
|
{
|
||||||
|
ConnectionString = connectionString,
|
||||||
|
DbType = DbType.MySql,
|
||||||
|
IsAutoCloseConnection = true,
|
||||||
|
ConfigureExternalServices = new ConfigureExternalServices()
|
||||||
|
{
|
||||||
|
EntityService = (x, p) => //处理列名
|
||||||
|
{
|
||||||
|
//最好排除DTO类
|
||||||
|
p.DbColumnName = UtilMethods.ToUnderLine(p.DbColumnName);//ToUnderLine驼峰转下划线方法
|
||||||
|
}
|
||||||
|
},
|
||||||
|
InitKeyType = InitKeyType.Attribute // 使用属性名作为列名
|
||||||
|
}, db =>
|
||||||
|
{
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
db.Aop.OnLogExecuting = (sql, pars) =>
|
||||||
|
{
|
||||||
|
Console.WriteLine(sql + "参数值:" + db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)));
|
||||||
|
};
|
||||||
|
//创建数据库和表的语句仅执行一次
|
||||||
|
//db.DbMaintenance.CreateDatabase();
|
||||||
|
db.CodeFirst.SetStringDefaultLength(2000).InitTables(typeof(LogEntity));
|
||||||
|
#endif
|
||||||
|
//过滤器写在这儿就行了
|
||||||
|
// db.QueryFilter.AddTableFilter<IDeleted>(it => it.IsDeleted == false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
SnowFlakeSingle.WorkId = Convert.ToInt32(builder.Configuration.GetSection("SnowFlakeWordId")?.Value ?? "1");
|
||||||
|
var app = builder.Build();
|
||||||
|
ServiceLocator.Instance = app.Services;
|
||||||
|
var device = app.Services.GetService<DeviceService>();
|
||||||
|
device?.Init();
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI();
|
||||||
|
}
|
||||||
|
//路由匹配
|
||||||
|
app.UseRouting();
|
||||||
|
app.UseAuthorization();
|
||||||
|
app.UseCors("CorsPolicy");
|
||||||
|
|
||||||
|
//异常中间件
|
||||||
|
app.UseMiddleware<CustomErrorMiddleware>();
|
||||||
|
//执行匹配的端点
|
||||||
|
app.UseEndpoints(endpoints =>
|
||||||
|
{
|
||||||
|
endpoints.MapHub<SocketHub>("/notification");
|
||||||
|
endpoints.MapControllers();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapControllers();
|
||||||
|
app.Run();
|
||||||
|
|
||||||
|
static void NewtonsoftInitialize(MvcNewtonsoftJsonOptions options)
|
||||||
|
{
|
||||||
|
//忽略循环引用
|
||||||
|
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||||
|
//期类型默认格式化处理
|
||||||
|
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
//解决命名不一致问题
|
||||||
|
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
|
||||||
|
//空值处理
|
||||||
|
//options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
|
||||||
|
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 跨域配置事件
|
||||||
|
/// </summary>
|
||||||
|
static void CorsOptionsEvnet(CorsOptions options)
|
||||||
|
{
|
||||||
|
options.AddPolicy("CorsPolicy", cors =>
|
||||||
|
{
|
||||||
|
cors.AllowAnyOrigin();
|
||||||
|
cors.AllowAnyHeader();
|
||||||
|
cors.AllowAnyMethod();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static class ServiceLocator
|
||||||
|
{
|
||||||
|
public static IServiceProvider Instance { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"LY.App": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"applicationUrl": "http://localhost:5233"
|
||||||
|
},
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Docker": {
|
||||||
|
"commandName": "Docker",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_URLS": "http://+:80"
|
||||||
|
},
|
||||||
|
"publishAllPorts": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:53161",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,277 @@
|
||||||
|
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 Microsoft.AspNetCore.SignalR;
|
||||||
|
using SqlSugar;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (input.data.Any())
|
||||||
|
{
|
||||||
|
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>>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
await _db.CopyNew().Insertable(entity).SplitTable().ExecuteReturnSnowflakeIdListAsync();
|
||||||
|
//推送报警信息
|
||||||
|
await _pushService.SendMessageToAll(new { msgType = "event", data = entity });
|
||||||
|
}
|
||||||
|
return new ApiResult();
|
||||||
|
}
|
||||||
|
/// <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.Lat = input.product_lat;
|
||||||
|
deviceinfo.Lon = input.product_lon;
|
||||||
|
await _redisService.SetAsync(key, deviceinfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.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.CreateTime,
|
||||||
|
AlarmLevel = s.alarmLevel,
|
||||||
|
}).ToListAsync();
|
||||||
|
return new ApiResult() { data = items };
|
||||||
|
}
|
||||||
|
/// <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 })
|
||||||
|
.Select(st => new AlarmRepDto
|
||||||
|
{
|
||||||
|
batchId = st.BatchId.ToString(),
|
||||||
|
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,
|
||||||
|
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()
|
||||||
|
.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()
|
||||||
|
}),
|
||||||
|
hotmap = await GenerateHotMap(query.Select(s => s.batchId).ToList()),
|
||||||
|
device = query.GroupBy(s => new { s.deviceName })
|
||||||
|
.Select(s => new
|
||||||
|
{
|
||||||
|
s.Key.deviceName,
|
||||||
|
count = s.Count()
|
||||||
|
}),
|
||||||
|
date = query.GroupBy(s => s.startTime.ToString("yyyy-MM-dd"))
|
||||||
|
.Select(it => new { it.Key, count = it.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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,191 @@
|
||||||
|
using GraphQL;
|
||||||
|
using LY.App.Common.Redis;
|
||||||
|
using LY.App.Device;
|
||||||
|
using LY.App.Extensions.DI;
|
||||||
|
using LY.App.Model;
|
||||||
|
using Mapster;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace LY.App.Service
|
||||||
|
{
|
||||||
|
[ServiceInjection(InjectionType.Transient)]
|
||||||
|
public class DeviceService
|
||||||
|
{
|
||||||
|
private readonly SqlSugarClient _db;
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
private readonly RedisService _redisService;
|
||||||
|
private readonly AlarmService _alarmService;
|
||||||
|
private readonly DeviceManager deviceManager = DeviceManager.Instance;
|
||||||
|
public DeviceService(SqlSugarClient db, IConfiguration config, RedisService redisService, AlarmService alarmService)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
_config = config;
|
||||||
|
_redisService = redisService;
|
||||||
|
_alarmService = alarmService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 分页查询
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pageNum"></param>
|
||||||
|
/// <param name="pageSize"></param>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<object> List(int pageNum, int pageSize, string key)
|
||||||
|
{
|
||||||
|
RefAsync<int> total = 0;
|
||||||
|
var items = await _db.Queryable<DeviceEntity>()
|
||||||
|
.Where(s => s.IsDeleted == false)
|
||||||
|
.WhereIF(!string.IsNullOrEmpty(key), s => s.Name.Contains(key) || s.DeviceSN.Contains(key))
|
||||||
|
.OrderByDescending(s => s.Id)
|
||||||
|
.ToPageListAsync(pageNum, pageSize, total);
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
total = total.Value,
|
||||||
|
items
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 新增设备
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<ApiResult> Add(AddDevice input)
|
||||||
|
{
|
||||||
|
var entity = input.Adapt<DeviceEntity>();
|
||||||
|
var id = await _db.Insertable(entity).ExecuteReturnSnowflakeIdAsync();
|
||||||
|
entity.Id = id;
|
||||||
|
await AddDevice2Manager(entity);
|
||||||
|
var key = RedisKeyList.DeviceInfo(entity.DeviceSN);
|
||||||
|
await _redisService.SetAsync(key, entity, TimeSpan.FromDays(10));
|
||||||
|
return new ApiResult()
|
||||||
|
{
|
||||||
|
code = 0,
|
||||||
|
msg = "success"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 更新设备信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<ApiResult> updata(UpdateDevice input)
|
||||||
|
{
|
||||||
|
var entity = input.Adapt<DeviceEntity>();
|
||||||
|
await _db.Updateable(entity).ExecuteCommandAsync();
|
||||||
|
return new ApiResult()
|
||||||
|
{
|
||||||
|
code = 0,
|
||||||
|
msg = "success"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 删除设备
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<ApiResult> delete(long Id)
|
||||||
|
{
|
||||||
|
var entity = await _db.Queryable<DeviceEntity>().FirstAsync(s => s.Id == Id);
|
||||||
|
entity.IsDeleted = true;
|
||||||
|
await _db.Updateable(entity).ExecuteCommandAsync();
|
||||||
|
deviceManager.RemoveDevice(entity.Id);
|
||||||
|
return new ApiResult()
|
||||||
|
{
|
||||||
|
code = 0,
|
||||||
|
msg = "success"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 取单个设备详情
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<DeviceEntity> detail(long Id)
|
||||||
|
{
|
||||||
|
return await _db.Queryable<DeviceEntity>()
|
||||||
|
.FirstAsync(s => s.Id == Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取首页数据
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<List<DeviceEntity>> All()
|
||||||
|
{
|
||||||
|
var result = await _db.Queryable<DeviceEntity>()
|
||||||
|
.Where(s => s.IsDeleted == false)
|
||||||
|
.ToListAsync();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task AddDevice2Manager(DeviceEntity entity)
|
||||||
|
{
|
||||||
|
var device = new Device.Device()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
Port = entity.Port,
|
||||||
|
GraphQlEndpoint = entity.GraphQlEndpoint,
|
||||||
|
Topic = entity.Topic,
|
||||||
|
IpAddress = entity.ip,
|
||||||
|
Protocol = entity.Protocol,
|
||||||
|
username = entity.account,
|
||||||
|
password = entity.password,
|
||||||
|
DataReceived = async (data) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var input = JsonConvert.DeserializeObject<RevData>(data);
|
||||||
|
Console.WriteLine($"rev data:{data}");
|
||||||
|
await _alarmService.AddAlarm(input);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"error:{ex.Message},data:{data}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
deviceManager.AddDevice(device);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化,加载所有设备
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task Init()
|
||||||
|
{
|
||||||
|
var devices = await _db.Queryable<DeviceEntity>().Where(s => s.IsDeleted == false).ToListAsync();
|
||||||
|
foreach (var item in devices)
|
||||||
|
{
|
||||||
|
var key = RedisKeyList.DeviceInfo(item.DeviceSN);
|
||||||
|
await _redisService.SetAsync(key, item, TimeSpan.FromDays(10));
|
||||||
|
await AddDevice2Manager(item);
|
||||||
|
}
|
||||||
|
//deviceManager.AddDevice(new Device.Device()
|
||||||
|
//{
|
||||||
|
// Id = 1111,
|
||||||
|
// Port = 1883,
|
||||||
|
// GraphQlEndpoint = "http://localhost:5000/graphql",
|
||||||
|
// Topic = "F010/uav_dynamic_data/beijing",
|
||||||
|
// IpAddress = "110.42.53.32",
|
||||||
|
// Protocol = ProtocolType.MQTT,
|
||||||
|
// username = "yangzi",
|
||||||
|
// password = "64B7qvztS38l",
|
||||||
|
// DataReceived = async (data) =>
|
||||||
|
// {
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// var input = JsonConvert.DeserializeObject<RevData>(data);
|
||||||
|
// await _alarmService.AddAlarm(input);
|
||||||
|
// }
|
||||||
|
// catch (Exception ex)
|
||||||
|
// {
|
||||||
|
// Console.WriteLine($"error:{ex.Message},data:{data}");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
using Azure.Core;
|
||||||
|
using LY.App.Extensions.DI;
|
||||||
|
using LY.App.Model;
|
||||||
|
using Mapster;
|
||||||
|
using SqlSugar;
|
||||||
|
using System.Security.AccessControl;
|
||||||
|
|
||||||
|
namespace LY.App.Service
|
||||||
|
{
|
||||||
|
[ServiceInjection(InjectionType.Transient)]
|
||||||
|
public class LogService
|
||||||
|
{
|
||||||
|
private readonly SqlSugarClient _db;
|
||||||
|
public LogService(SqlSugarClient sqlSugarClient)
|
||||||
|
{
|
||||||
|
_db = sqlSugarClient;
|
||||||
|
}
|
||||||
|
public async Task AddLog(AddLog input)
|
||||||
|
{
|
||||||
|
var entity = input.Adapt<LogEntity>();
|
||||||
|
await _db.Insertable(entity).ExecuteReturnSnowflakeIdAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
using LY.App.Common;
|
||||||
|
using LY.App.Extensions.DI;
|
||||||
|
using LY.App.Model;
|
||||||
|
using Mapster;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using NetTopologySuite.Geometries;
|
||||||
|
using NetTopologySuite.GeometriesGraph;
|
||||||
|
using SqlSugar;
|
||||||
|
using System.Xml.Schema;
|
||||||
|
|
||||||
|
namespace LY.App.Service
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 阵地服务
|
||||||
|
/// </summary>
|
||||||
|
[ServiceInjection(InjectionType.Transient)]
|
||||||
|
public class PositionService
|
||||||
|
{
|
||||||
|
private readonly SqlSugarClient _db;
|
||||||
|
public PositionService(SqlSugarClient db)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 添加
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<ApiResult> MainAdd(AddPosition input)
|
||||||
|
{
|
||||||
|
var entity = input.Adapt<PositionInfo>();
|
||||||
|
entity.CreateTime = DateTime.Now;
|
||||||
|
//名称重复判断
|
||||||
|
var isNameExist = await _db.Queryable<PositionInfo>().CountAsync(a => a.Name == input.Name && a.IsDeleted != true);
|
||||||
|
if (isNameExist > 0)
|
||||||
|
{
|
||||||
|
return new ApiResult(false, "名称已存在");
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrWhiteSpace(entity.RegionJson))
|
||||||
|
{
|
||||||
|
if (GeoJsonHelper.TryGetGeomWKTFromGeoJson(entity.RegionJson, out MultiPolygon geo))
|
||||||
|
{
|
||||||
|
entity.SetRegion(geo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new ApiResult(false, "空间数据无效");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 位置
|
||||||
|
entity.SetLocation();
|
||||||
|
await _db.Insertable(entity).ExecuteReturnSnowflakeIdAsync();
|
||||||
|
return new ApiResult(true, "添加成功");
|
||||||
|
}
|
||||||
|
public async Task<ApiResult> Update(UpdatePosition input)
|
||||||
|
{
|
||||||
|
var entity = input.Adapt<PositionInfo>();
|
||||||
|
await _db.Queryable<PositionInfo>().FirstAsync(a => a.Id == input.Id && a.IsDeleted != true);
|
||||||
|
if (entity != null)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(entity.RegionJson))
|
||||||
|
{
|
||||||
|
if (GeoJsonHelper.TryGetGeomWKTFromGeoJson(entity.RegionJson, out MultiPolygon geo))
|
||||||
|
{
|
||||||
|
entity.SetRegion(geo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new ApiResult(false, "空间数据无效");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 位置
|
||||||
|
entity.SetLocation();
|
||||||
|
await _db.Updateable(entity).ExecuteCommandAsync();
|
||||||
|
return new ApiResult(true, "添加成功");
|
||||||
|
}
|
||||||
|
return new ApiResult(false, "未找到要更新的对象");
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<ApiResult> Delete(long id)
|
||||||
|
{
|
||||||
|
var entity = await _db.Queryable<PositionInfo>().FirstAsync(a => a.Id == id && a.IsDeleted != true);
|
||||||
|
if (entity != null)
|
||||||
|
{
|
||||||
|
entity.IsDeleted = true;
|
||||||
|
await _db.Updateable(entity).ExecuteCommandAsync();
|
||||||
|
return new ApiResult(true, "删除成功");
|
||||||
|
}
|
||||||
|
return new ApiResult(false, "未找到要删除的对象");
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<ApiResult> Get(int id)
|
||||||
|
{
|
||||||
|
var entity = await _db.Queryable<PositionInfo>().FirstAsync(a => a.Id == id && a.IsDeleted != true);
|
||||||
|
if (entity != null)
|
||||||
|
{
|
||||||
|
return new ApiResult() { data = entity };
|
||||||
|
}
|
||||||
|
return new ApiResult(false, "未找到要获取的对象");
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取列表
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<ApiResult> GetList(PositionQueryInput input)
|
||||||
|
{
|
||||||
|
var query = _db.Queryable<PositionInfo>()
|
||||||
|
.Where(a => a.IsDeleted != true)
|
||||||
|
.WhereIF(!string.IsNullOrWhiteSpace(input.Name), a => a.Name.Contains(input.Name))
|
||||||
|
.OrderBy(a => a.Id, OrderByType.Desc);
|
||||||
|
var result = await query.ToPageListAsync(input.pageNum, input.pageSize);
|
||||||
|
return new ApiResult()
|
||||||
|
{
|
||||||
|
data = new
|
||||||
|
{
|
||||||
|
items = result,
|
||||||
|
totalCount = query.Count()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 首页数据
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<List<PositionDeviceDto>> Index()
|
||||||
|
{
|
||||||
|
var query = await _db.Queryable<PositionInfo>()
|
||||||
|
.Where(a => a.IsDeleted != true).ToListAsync();
|
||||||
|
var positionIds = query.Select(s => s.Id).ToList();
|
||||||
|
var deviceList = await _db.Queryable<DeviceEntity>()
|
||||||
|
.Where(s => positionIds.Contains(s.PositionId))
|
||||||
|
.Where(s => s.IsDeleted == false)
|
||||||
|
.ToListAsync();
|
||||||
|
List<PositionDeviceDto> result = new List<PositionDeviceDto>();
|
||||||
|
foreach (var item in query)
|
||||||
|
{
|
||||||
|
result.Add(new PositionDeviceDto()
|
||||||
|
{
|
||||||
|
position = item,
|
||||||
|
Devices = deviceList.Where(s => s.PositionId == item.Id).ToList().Adapt<List<DeviceItem>>()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,237 @@
|
||||||
|
using GraphQL;
|
||||||
|
using LY.App.Common.Cypher;
|
||||||
|
using LY.App.Common.Redis;
|
||||||
|
using LY.App.Model;
|
||||||
|
using Mapster;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using SqlSugar;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LY.App.Service
|
||||||
|
{
|
||||||
|
public class UserService
|
||||||
|
{
|
||||||
|
private readonly SqlSugarClient _db;
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
private readonly RedisService _redisService;
|
||||||
|
public UserService(SqlSugarClient db, IConfiguration config, RedisService redisService)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
_config = config;
|
||||||
|
_redisService = redisService;
|
||||||
|
}
|
||||||
|
#region 增删改查
|
||||||
|
|
||||||
|
public async Task<ApiResult> Add(AddUser input)
|
||||||
|
{
|
||||||
|
var exists = await _db.Queryable<UserEntity>().AnyAsync(s => s.Name == input.Name && s.Disable == false);
|
||||||
|
if (!exists)
|
||||||
|
{
|
||||||
|
var entity = input.Adapt<UserEntity>();
|
||||||
|
// var entity = _mapper.Map<UserEntity>(input);
|
||||||
|
entity.CreateTime = DateTime.Now;
|
||||||
|
entity.UpdatePwdTime = DateTime.Now;
|
||||||
|
entity.Password = MD5CypherUtil.Hash("ly_" + input.Password);
|
||||||
|
var Id = await _db.Insertable(entity).ExecuteReturnSnowflakeIdAsync();
|
||||||
|
return new ApiResult() { code = 0, data = Id.ToString() };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new ApiResult() { code = 1, msg = "已存在该用户名" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 删除用户,标记删除,不是物理删除
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ids"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<string> SoftDelete(IEnumerable<long> ids)
|
||||||
|
{
|
||||||
|
if (ids.Any())
|
||||||
|
{
|
||||||
|
foreach (var item in ids)
|
||||||
|
{
|
||||||
|
var entity = await _db.Queryable<UserEntity>().FirstAsync(s => s.Id == item);
|
||||||
|
if (entity?.Name != "admin")
|
||||||
|
{
|
||||||
|
entity.Disable = entity.Disable == true ? false : true;
|
||||||
|
await _db.Updateable<UserEntity>(entity).ExecuteCommandAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return "admin 不可删除!";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return "ids不能为空";
|
||||||
|
}
|
||||||
|
public async Task<ApiResult> GetUserById(long userId)
|
||||||
|
{
|
||||||
|
var entity = await _db.Queryable<UserEntity>().FirstAsync(s => s.Id == userId);
|
||||||
|
if (entity != null)
|
||||||
|
{
|
||||||
|
entity.Password = "";
|
||||||
|
return new ApiResult() { code = 0, data = entity };
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 监测登录次数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="username"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task<bool> CheckLoginNum(string username)
|
||||||
|
{
|
||||||
|
int num = 0;
|
||||||
|
// var node = SettingHelper.Instance.GetNode("Vertify", "LoginFailed");
|
||||||
|
var node = _config["Vertify"];
|
||||||
|
var key = RedisKeyList.LogNum(username);
|
||||||
|
var val = await _redisService.GetAsync<int>(key);
|
||||||
|
if (num >= int.Parse(node))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public async Task<ApiResult> Login(LoginModel input)
|
||||||
|
{
|
||||||
|
if (await CheckLoginNum(input.username))
|
||||||
|
{
|
||||||
|
return new ApiResult()
|
||||||
|
{
|
||||||
|
code = 1,
|
||||||
|
msg = "连续登录失败5次,锁定30分钟"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var password = MD5CypherUtil.Hash("ly_" + input.password);
|
||||||
|
var users = await _db.Queryable<UserEntity>().ToListAsync();
|
||||||
|
var entity = await _db.Queryable<UserEntity>()
|
||||||
|
.Where(s => s.Disable == false &&
|
||||||
|
s.Name == input.username && s.Password == password).FirstAsync();
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
await SetLoginNum(input.username);
|
||||||
|
return new ApiResult()
|
||||||
|
{
|
||||||
|
code = 1,
|
||||||
|
msg = "请检查用户名跟密码!"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
entity.LoginTime = DateTime.Now;
|
||||||
|
await _db.Updateable(entity).ExecuteCommandAsync();
|
||||||
|
await RemoveLoginNum(input.username);
|
||||||
|
string token = CreateToken(entity);
|
||||||
|
//加入redis
|
||||||
|
await _redisService.SetAsync<string>(RedisKeyList.TokenUser(input.username),
|
||||||
|
token, TimeSpan.FromSeconds(60 * 60 * 24 * 7));
|
||||||
|
return new ApiResult()
|
||||||
|
{
|
||||||
|
code = 1,
|
||||||
|
data = new
|
||||||
|
{
|
||||||
|
token,
|
||||||
|
expires = DateTime.UtcNow.AddSeconds(60*60*24*7),
|
||||||
|
isAdmin = entity.IsAdmin,
|
||||||
|
userid = entity.Id.ToString()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
private async Task RemoveLoginNum(string username)
|
||||||
|
{
|
||||||
|
var key = $"login_num_{username}";
|
||||||
|
await _redisService.DeleteAsync(key);
|
||||||
|
}
|
||||||
|
private async Task SetLoginNum(string username)
|
||||||
|
{
|
||||||
|
var key = RedisKeyList.LogNum(username);
|
||||||
|
var num = await _redisService.GetAsync<int>(key);
|
||||||
|
await _redisService.SetAsync(key, num + 1, TimeSpan.FromMinutes(30));
|
||||||
|
}
|
||||||
|
private string CreateToken(UserEntity user)
|
||||||
|
{
|
||||||
|
// 创建JWT的密钥
|
||||||
|
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Token:SecretKey"]));
|
||||||
|
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
|
||||||
|
|
||||||
|
// 创建Claims
|
||||||
|
var claims = new[]
|
||||||
|
{
|
||||||
|
new Claim(JwtRegisteredClaimNames.Sub,user.Name),
|
||||||
|
new Claim(JwtRegisteredClaimNames.Sid, user.Id.ToString())
|
||||||
|
// 还可以添加其他需要的Claims
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建Token
|
||||||
|
var token = new JwtSecurityToken(
|
||||||
|
issuer: _config["Token:Issuer"],
|
||||||
|
audience: _config["Token:Audience"],
|
||||||
|
claims: claims,
|
||||||
|
expires: DateTime.UtcNow.AddSeconds(60 * 60 * 24 * 7), // 设置Token过期时间
|
||||||
|
signingCredentials: credentials
|
||||||
|
);
|
||||||
|
// 生成Token字符串
|
||||||
|
var tokenString = new JwtSecurityTokenHandler().WriteToken(token);
|
||||||
|
return tokenString;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pageSize"></param>
|
||||||
|
/// <param name="pageNum"></param>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<object> GetPage(int pageSize, int pageNum, string key)
|
||||||
|
{
|
||||||
|
RefAsync<int> total = 0;
|
||||||
|
var query = await _db.Queryable<UserEntity>()
|
||||||
|
.Where(s => s.Disable == false).ToPageListAsync(pageNum, pageSize, total);
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
total = total.Value,
|
||||||
|
items = query
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新密码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<string> UpdatePwd(UpdatePwdDto input)
|
||||||
|
{
|
||||||
|
var md5 = MD5CypherUtil.Hash("ly_" + input.oldPwd);
|
||||||
|
var entity = await _db.Queryable<UserEntity>().FirstAsync(s => s.Id == input.Id);
|
||||||
|
if (entity.Password == md5)
|
||||||
|
{
|
||||||
|
entity.Password = MD5CypherUtil.Hash("ly_" + input.newPwd);
|
||||||
|
entity.UpdatePwdTime = DateTime.Now;
|
||||||
|
await _db.Updateable(entity).UpdateColumns(s => new
|
||||||
|
{
|
||||||
|
s.Password,
|
||||||
|
s.UpdatePwdTime
|
||||||
|
}).ExecuteCommandAsync();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return "原密码不正确";
|
||||||
|
}
|
||||||
|
public async Task<string> Update(UpdateUser input)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(input.Name))
|
||||||
|
{
|
||||||
|
var entity = input.Adapt<UserEntity>();
|
||||||
|
await _db.Updateable(entity).UpdateColumns(it => new
|
||||||
|
{
|
||||||
|
it.UpdatePwdTime,
|
||||||
|
it.Password,
|
||||||
|
it.Email,
|
||||||
|
it.IsAdmin
|
||||||
|
}).ExecuteCommandAsync();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return "用户名不能为空";
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace LY.App
|
||||||
|
{
|
||||||
|
public class WeatherForecast
|
||||||
|
{
|
||||||
|
public DateTime Date { get; set; }
|
||||||
|
|
||||||
|
public int TemperatureC { get; set; }
|
||||||
|
|
||||||
|
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||||
|
|
||||||
|
public string? Summary { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"log2db": true, //是否记录
|
||||||
|
"AllowedHosts": "*",
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"DefaultConnection": "server=101.43.201.20;port=3307;database=lyapp;user=root;password=Aa123;Pooling=true;"
|
||||||
|
},
|
||||||
|
"Token": {
|
||||||
|
"SecretKey": "HWLSNPM+OhlFe4wwEV/teSWsxGjrWbxKnHonxW5Z+mFlQq3zonv5",
|
||||||
|
"Issuer": "ly_server_issuer",
|
||||||
|
"Audience": "ly_server_audience",
|
||||||
|
"AccessExpires": 86400,
|
||||||
|
"RefreshExpires": 43200,
|
||||||
|
"Admin": "GYJlKgVaHPThTGvw8iB9n/SQiApYPiVaisHHzs9z47eBI3TxseU7WYihNRLGTMcekVfgtcaD05r+hdOTpA0obMlMpb0I6lVFtaw2iUGXqpwleqtBOy5ajlE/cG3THTDUhkYJTwpAYt3mwPnvFc2gVskVUpzA3g9n33jHKhQQyIM="
|
||||||
|
},
|
||||||
|
"Swagger": {
|
||||||
|
"Title": "LY.App-Api",
|
||||||
|
"Description": "接口文档",
|
||||||
|
"Version": "v1.0"
|
||||||
|
},
|
||||||
|
"Redis": {
|
||||||
|
"ConnectionString": "101.43.201.20:6379,password=Aa123,abortConnect =false"
|
||||||
|
},
|
||||||
|
"Vertify": 5, //登录失败次数
|
||||||
|
"BatchId": 60, //无人机批次连续时间
|
||||||
|
"SnowFlakeWordId": 1 //雪花算法的wordId,多台服务器时,需要配置不同的wordId,最多32个节点,可以考虑加到环境变量中
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue