diff --git a/.gitignore b/.gitignore index 679d59b..edff431 100644 --- a/.gitignore +++ b/.gitignore @@ -475,3 +475,5 @@ FodyWeavers.xsd # Local History for Visual Studio Code .history/ +# Custom +!/EC.Helper/libs/** diff --git a/Cis.Application/AppConfig.json b/Cis.Application/AppConfig.json index 5c17e0c..f66edbd 100644 --- a/Cis.Application/AppConfig.json +++ b/Cis.Application/AppConfig.json @@ -1,12 +1,13 @@ { "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json", - "CameraDataOptions": { - "LazyInit": false, - "LoopInterval": "1000" - }, - "PTZServer": { - "Type": "", - "Ip": "127.0.0.1", - "Port": "7022" + "CameraData": { + "CameraPtz": { + "LoopInterval": "1000", + "Timeout": "2000" + }, + "MarkSearcher": { + "LoopInterval": "1000", + "Timeout": "2000" + } } } \ No newline at end of file diff --git a/Cis.Application/Cb/Common/CbInfo.cs b/Cis.Application/Cb/Common/CbInfo.cs index b612a81..6f658e5 100644 --- a/Cis.Application/Cb/Common/CbInfo.cs +++ b/Cis.Application/Cb/Common/CbInfo.cs @@ -5,40 +5,50 @@ /// public class CbInfo { - #region Api Info + #region Api Info - /// - /// Api 分组名 - /// - public const string GroupName = "CameraBase"; + /// + /// Api 分组名 + /// + public const string GroupName = "CameraBase"; - /// - /// Api 分组排序 - /// - public const int GroupOrder = 100; + /// + /// Api 分组排序 + /// + public const int GroupOrder = 100; - #endregion Api Info + #endregion Api Info - #region Database Info + #region Database Info - /// - /// 数据库标识 - /// - public const string DbName = SqlSugarConst.DefaultConfigId; + /// + /// 数据库标识 + /// + public const string DbName = SqlSugarConst.DefaultConfigId; - #endregion Database Info + #endregion Database Info - #region Table Info + #region Table Info - /// - /// CbCamera 表名 - /// - public const string CbCameraTbName = "cb_camera"; + /// + /// CbCamera 表名 + /// + public const string CbCameraTbName = "cb_camera"; - /// - /// CbCamera 表描述 - /// - public const string CbCameraTbDesc = "相机表"; + /// + /// CbCamera 表描述 + /// + public const string CbCameraTbDesc = "相机表"; - #endregion Table Info + /// + /// CbCameraParams 表名 + /// + public const string CbCameraParamsTbName = "cb_camera_params"; + + /// + /// CbCameraParams 表描述 + /// + public const string CbCameraParamsTbDesc = "相机参数表"; + + #endregion Table Info } \ No newline at end of file diff --git a/Cis.Application/Cb/Entity/CbCamera.cs b/Cis.Application/Cb/Entity/CbCamera.cs index d4a1947..9776a10 100644 --- a/Cis.Application/Cb/Entity/CbCamera.cs +++ b/Cis.Application/Cb/Entity/CbCamera.cs @@ -1,44 +1,44 @@ namespace Cis.Application.Cb; /// -/// 系统字典类型表 +/// 相机表 /// [SugarTable(CbInfo.CbCameraTbName, CbInfo.CbCameraTbDesc)] [Tenant(CbInfo.DbName)] public class CbCamera : EntityBase { - /// - /// 名称 - /// - [SugarColumn(ColumnDescription = "名称", Length = 64)] - [Required, MaxLength(64)] - public string Name { get; set; } + /// + /// 名称 + /// + [SugarColumn(ColumnDescription = "名称", Length = 64)] + [Required, MaxLength(64)] + public string Name { get; set; } - /// - /// ip 地址 - /// - [SugarColumn(ColumnDescription = "ip地址", Length = 16)] - [Required, MaxLength(16)] - public string Ip { get; set; } + /// + /// ip 地址 + /// + [SugarColumn(ColumnDescription = "ip地址", Length = 16)] + [Required, MaxLength(16)] + public string Ip { get; set; } - /// - /// 端口 - /// - [SugarColumn(ColumnDescription = "端口", Length = 5, DefaultValue = "80")] - [Required, MaxLength(5)] - public string Port { get; set; } + /// + /// 账号 + /// + [SugarColumn(ColumnDescription = "账号", Length = 32)] + [Required, MaxLength(32)] + public string UserName { get; set; } - /// - /// 账号 - /// - [SugarColumn(ColumnDescription = "账号", Length = 32)] - [Required, MaxLength(32)] - public string UserName { get; set; } + /// + /// 密码 + /// + [SugarColumn(ColumnDescription = "密码", Length = 32)] + [Required, MaxLength(32)] + public string Password { get; set; } - /// - /// 密码 - /// - [SugarColumn(ColumnDescription = "密码", Length = 32)] - [Required, MaxLength(32)] - public string Password { get; set; } + /// + /// 相机参数 Id + /// + [SugarColumn(ColumnDescription = "相机参数Id")] + [Required] + public long CbCameraParamsId { get; set; } } \ No newline at end of file diff --git a/Cis.Application/Cb/Entity/CbCameraParams.cs b/Cis.Application/Cb/Entity/CbCameraParams.cs new file mode 100644 index 0000000..ed5187a --- /dev/null +++ b/Cis.Application/Cb/Entity/CbCameraParams.cs @@ -0,0 +1,44 @@ +namespace Cis.Application.Cb; + +/// +/// 相机参数表 +/// +[SugarTable(CbInfo.CbCameraParamsTbName, CbInfo.CbCameraParamsTbDesc)] +[Tenant(CbInfo.DbName)] +public class CbCameraParams : EntityBase +{ + /// + /// 名称 + /// + [SugarColumn(ColumnDescription = "名称", Length = 64)] + [Required, MaxLength(64)] + public string Name { get; set; } + + /// + /// 相机类型 + /// + [SugarColumn(ColumnDescription = "相机类型")] + [Required] + public int CameraType { get; set; } + + /// + /// sdk 端口 + /// + [SugarColumn(ColumnDescription = "sdk端口")] + [Required] + public int SdkPort { get; set; } + + /// + /// FocusX + /// + [SugarColumn(ColumnDescription = "FocusX")] + [Required] + public double FocusX { get; set; } + + /// + /// FocusY + /// + [SugarColumn(ColumnDescription = "FocusY")] + [Required] + public double FocusY { get; set; } +} \ No newline at end of file diff --git a/Cis.Application/Cb/Service/CbCameraParamsService.cs b/Cis.Application/Cb/Service/CbCameraParamsService.cs new file mode 100644 index 0000000..fb30cf0 --- /dev/null +++ b/Cis.Application/Cb/Service/CbCameraParamsService.cs @@ -0,0 +1,61 @@ +using Newtonsoft.Json.Linq; + +namespace Cis.Application.Cb; + +/// +/// 相机参数服务 +/// +[ApiDescriptionSettings(CbInfo.GroupName, Order = CbInfo.GroupOrder)] +public class CbCameraParamsService : IDynamicApiController, ITransient +{ + private readonly SqlSugarRepository _baseRep; + + public CbCameraParamsService(SqlSugarRepository baseRep) + { + _baseRep = baseRep; + } + + [HttpPost] + public async Task Add([FromForm] CbCameraParams entity) + { + return await _baseRep.InsertAsync(entity); + } + + [HttpPost] + public async Task Update([FromForm] CbCameraParams entity) + { + return await _baseRep.UpdateAsync(entity); + } + + [HttpPost] + public async Task Delete([FromForm] CbCameraParams entity) + { + return await _baseRep.DeleteAsync(entity); + } + + [HttpGet] + public async Task Get(long id) + { + CbCameraParams entity = await _baseRep.GetByIdAsync(id); + return entity; + } + + [HttpGet] + public async Task> GetList(string queryJson = "") + { + JObject queryObj = queryJson.ToJObject(); + List list = await _baseRep.AsQueryable() + .ToListAsync(); + return list; + } + + [HttpGet] + public async Task> GetPageList(string queryJson, string pagination) + { + Pagination pageObj = pagination.ToObject(); + JObject queryObj = queryJson.ToJObject(); + List list = await _baseRep.AsQueryable() + .ToPageListAsync(pageObj.Index, pageObj.Size); + return list; + } +} \ No newline at end of file diff --git a/Cis.Application/Cb/Service/CbCameraService.cs b/Cis.Application/Cb/Service/CbCameraService.cs index febfc89..2606197 100644 --- a/Cis.Application/Cb/Service/CbCameraService.cs +++ b/Cis.Application/Cb/Service/CbCameraService.cs @@ -8,55 +8,54 @@ namespace Cis.Application.Cb; [ApiDescriptionSettings(CbInfo.GroupName, Order = CbInfo.GroupOrder)] public class CbCameraService : IDynamicApiController, ITransient { - private readonly SqlSugarRepository _cbCameraRep; - - public CbCameraService(SqlSugarRepository cbCameraRep) - { - _cbCameraRep = cbCameraRep; - } - - [HttpPost] - public async Task Add([FromForm] CbCamera entity) - { - return await _cbCameraRep.InsertAsync(entity); - } - - [HttpPost] - public async Task Update([FromForm] CbCamera entity) - { - return await _cbCameraRep.UpdateAsync(entity); - } - - [HttpPost] - public async Task Delete([FromForm] CbCamera entity) - { - return await _cbCameraRep.DeleteAsync(entity); - } - - [HttpGet] - public async Task Get(long id) - { - CbCamera entity = await _cbCameraRep.GetByIdAsync(id); - return entity; - } - - [HttpGet] - public async Task> GetList(string queryJson = "") - { - JObject queryObj = queryJson.ToJObject(); - List list = await _cbCameraRep.AsQueryable() - .ToListAsync(); - return list; - } - - [HttpGet] - public async Task> GetPageList(string queryJson, string pagination) - { - Pagination pageObj = pagination.ToObject(); - JObject queryObj = queryJson.ToJObject(); - List list = await _cbCameraRep.AsQueryable() - .ToPageListAsync(pageObj.Index, pageObj.Size); - return list; - } - + private readonly SqlSugarRepository _baseRep; + + public CbCameraService(SqlSugarRepository baseRep) + { + _baseRep = baseRep; + } + + [HttpPost] + public async Task Add([FromForm] CbCamera entity) + { + return await _baseRep.InsertAsync(entity); + } + + [HttpPost] + public async Task Update([FromForm] CbCamera entity) + { + return await _baseRep.UpdateAsync(entity); + } + + [HttpPost] + public async Task Delete([FromForm] CbCamera entity) + { + return await _baseRep.DeleteAsync(entity); + } + + [HttpGet] + public async Task Get(long id) + { + CbCamera entity = await _baseRep.GetByIdAsync(id); + return entity; + } + + [HttpGet] + public async Task> GetList(string queryJson = "") + { + JObject queryObj = queryJson.ToJObject(); + List list = await _baseRep.AsQueryable() + .ToListAsync(); + return list; + } + + [HttpGet] + public async Task> GetPageList(string queryJson, string pagination) + { + Pagination pageObj = pagination.ToObject(); + JObject queryObj = queryJson.ToJObject(); + List list = await _baseRep.AsQueryable() + .ToPageListAsync(pageObj.Index, pageObj.Size); + return list; + } } \ No newline at end of file diff --git a/Cis.Application/Cis.Application.csproj b/Cis.Application/Cis.Application.csproj index f99bc03..5d90d17 100644 --- a/Cis.Application/Cis.Application.csproj +++ b/Cis.Application/Cis.Application.csproj @@ -24,6 +24,7 @@ + diff --git a/Cis.Application/Cis.Application.xml b/Cis.Application/Cis.Application.xml index 4df3d6c..288411d 100644 --- a/Cis.Application/Cis.Application.xml +++ b/Cis.Application/Cis.Application.xml @@ -34,9 +34,19 @@ CbCamera 表描述 + + + CbCameraParams 表名 + + + + + CbCameraParams 表描述 + + - 系统字典类型表 + 相机表 @@ -49,11 +59,6 @@ ip 地址 - - - 端口 - - 账号 @@ -64,6 +69,46 @@ 密码 + + + 相机参数 Id + + + + + 相机参数表 + + + + + 名称 + + + + + 相机类型 + + + + + sdk 端口 + + + + + FocusX + + + + + FocusY + + + + + 相机参数服务 + + 相机服务 @@ -131,7 +176,7 @@ - 标记标签表 + 标签表 @@ -176,281 +221,460 @@ - 标记标签服务 + 标签服务 - + - 当前相机参数信息 + {cameraId, List(MarkLabelCalcResult)} - + - _markLabelInfoList 锁对象,写锁 + 初始化线程 - + - 需要计算的 markLabelInfo 列表 + 刷新所有相机 ptz + 有待改善,应设置超时计数机制 + https://blog.csdn.net/qq_28368039/article/details/118597396 - + - 世界坐标转化为相机坐标矩阵 + 刷新相机 ptz + + - + - 计算标签位置过程 + 刷新所有 markSearcher - - + - 判断相机是否进行了转动,转动了则需要重新计算世界坐标到相机坐标的转换矩阵 + 刷新 markSearcher - + - + - 获取将世界坐标系中的点转化为相机坐标系中的点的转换矩阵 + CameraId2Ip 字典 - - - + - 获取将相机坐标系中的点转化为世界坐标系中的点的转换矩阵 + CameraIpCounts 字典 - + + + + CameraPtzInfos 字典 + + + + + Api 分组名 + + + + + Api 分组排序 + + + + + 循环间隔,单位毫秒 + + + + + 超时时间,单位毫秒 + + + + + 相机 sdk 服务类 + + + + + {ip, ICameraSDK} + + + + + 相机 sdk 服务接口 + + + + + 注册相机 + + - + - 此方法计算在球机zoom值最小的情况下成像矩阵中的 f 本质为获取像元大小 - 尝试方案1:通过计算的方式来获取 - 尝试方案2:通过张友定相机标定的方法来生成成像矩阵中的 f + 注销相机 + + - + - 将Pan值转化为角度 + 是否存在相机 + - + - 将Tilt转化为角度 + 获取 ptz + + - + - 根据当前zoom值获取相机矩阵参数 + 获取 ptz - + + - + + + 相机计算参数 + + + + + Camera Id + + + + + Ptz 信息 + + + + + FocusX + + + + + FocusY + + + + + 视频宽度 + + + + + 视频高度 + + + + + 标签计算参数 + + + - Ptz Api 接口 + MarkLabel Id - + - Ptz Api + Ptz 信息 - + - (cbCameraId, cbCameraIp) + 视频宽度 - + - (cameraIp, TbPtzCamera) + 视频高度 - + - (cameraIp, PtzInfo) + 画布 left 距离比例 - + - _markSearcherDict 锁对象,写锁 + 画布 top 距离比例 - + - (cbCameraId, MarkSearcherBase) + 标签计算结果 - + - (cameraId, List(MarkLabelCalcResult)) + MarkLabel Id - + - 循环运行 + true 显示(在当前视频画面里面) + false 不显示(不在当前视频画面里面) - + - 激活 cbCamera 进入运算 + 画布 left 距离比例 + + + + + 画布 top 距离比例 + + + + + 追踪标签服务接口 + + + + + 激活相机进入运算 - + - 解除 cbCamera 进入运算 + 解除相机进入运算 - + - 是否懒加载 + 是否存在相机进入运算 + + - + - 循环间隔,单位毫秒 + 获取 Searcher + + - + - PtzServer选项 + 激活标签进入运算 + + + - + - 服务类别 + 解除标签进入运算 + + + - + - 服务IP + 是否存在标签进入运算 + + + - + - 服务端口 + 激活相机进入运算 + + - + - 相机计算信息 + 解除相机进入运算 + + - + - Camera Id + 是否存在相机进入运算 + + - + - Ptz 信息 + 获取 Searcher + + - + - 视频的宽度 + 激活标签进入运算 + + + - + - 视频的高度 + 解除标签进入运算 + + + - + - 最小焦距 + 是否存在标签进入运算 + + + - + - Ptz 信息 + 追踪标签服务类 - + - Pan 坐标 + {cbCameraId, MarkSearcherBase} - + - Tilt 坐标 + MarkSearcherDict 原子操作锁 - + - Zoom 坐标 + ActivateSearcher 原子操作 + + - + - 标记标签计算信息 + DeactivateSearcher 原子操作 + + - + - MarkLabel Id + 当前相机计算参数 - + - Ptz 信息 + 相机当前位置的世界坐标转化为相机坐标矩阵 - + - 视频宽度 + {cameraId, MarkLabelCalcParams} - + - 视频高度 + 判断相机是否进行了转动,转动了则需要重新计算世界坐标到相机坐标的转换矩阵 + + - + - 画布 left 距离比例 + 此方法计算在球机zoom值最小的情况下成像矩阵中的 f 本质为获取像元大小 + 尝试方案1:通过计算的方式来获取 + 尝试方案2:通过张正友相机标定的方法来生成成像矩阵中的 f - + - 画布 top 距离比例 + 获取将世界坐标系中的点转化为相机坐标系中的点的转换矩阵 + + - + - 标记标签计算结果 + 获取将相机坐标系中的点转化为世界坐标系中的点的转换矩阵 + + - + - MarkLabel Id + 计算标签位置过程 + - + - true 显示(在当前视频画面里面) - false 不显示(不在当前视频画面里面) + 将Pan值转化为角度 + - + - 画布 left 距离比例 + 将Tilt转化为角度 + - + - 画布 top 距离比例 + 根据当前zoom值获取相机矩阵参数 + + + + + + + 更新相机计算参数 + + + + + + 添加标签计算参数 + + + + + + + 删除标签计算参数 + + + + + + 是否存在标签计算参数 + + + @@ -585,15 +809,5 @@ 系统字典类型服务 - - - 数据库标识 - - - - - TbPtzCamera 表名 - - diff --git a/Cis.Application/Cm/Common/CmInfo.cs b/Cis.Application/Cm/Common/CmInfo.cs index abfda16..eddfd1f 100644 --- a/Cis.Application/Cm/Common/CmInfo.cs +++ b/Cis.Application/Cm/Common/CmInfo.cs @@ -5,50 +5,50 @@ /// public class CmInfo { - #region Api Info + #region Api Info - /// - /// Api 分组名 - /// - public const string GroupName = "CameraMark"; + /// + /// Api 分组名 + /// + public const string GroupName = "CameraMark"; - /// - /// Api 分组排序 - /// - public const int GroupOrder = 100; + /// + /// Api 分组排序 + /// + public const int GroupOrder = 100; - #endregion Api Info + #endregion Api Info - #region Database Info + #region Database Info - /// - /// 数据库标识 - /// - public const string DbName = SqlSugarConst.DefaultConfigId; + /// + /// 数据库标识 + /// + public const string DbName = SqlSugarConst.DefaultConfigId; - #endregion Database Info + #endregion Database Info - #region Table Info + #region Table Info - /// - /// CmMarkGroup 表名 - /// - public const string CmMarkGroupTbName = "cm_mark_group"; + /// + /// CmMarkGroup 表名 + /// + public const string CmMarkGroupTbName = "cm_mark_group"; - /// - /// CmMarkGroup 表描述 - /// - public const string CmMarkGroupTbDesc = "标记分组表"; + /// + /// CmMarkGroup 表描述 + /// + public const string CmMarkGroupTbDesc = "标记分组表"; - /// - /// CmMarkLabel 表名 - /// - public const string CmMarkLabelTbName = "cm_mark_label"; + /// + /// CmMarkLabel 表名 + /// + public const string CmMarkLabelTbName = "cm_mark_label"; - /// - /// CmMarkLabel 表描述 - /// - public const string CmMarkLabelTbDesc = "标记标签表"; + /// + /// CmMarkLabel 表描述 + /// + public const string CmMarkLabelTbDesc = "标签表"; - #endregion Table Info + #endregion Table Info } \ No newline at end of file diff --git a/Cis.Application/Cm/Entity/CmMarkGroup.cs b/Cis.Application/Cm/Entity/CmMarkGroup.cs index b19e0ed..843f56d 100644 --- a/Cis.Application/Cm/Entity/CmMarkGroup.cs +++ b/Cis.Application/Cm/Entity/CmMarkGroup.cs @@ -7,22 +7,22 @@ [Tenant(CmInfo.DbName)] public class CmMarkGroup : EntityBase { - /// - /// 名称 - /// - [SugarColumn(ColumnDescription = "名称", Length = 64)] - public string Name { get; set; } + /// + /// 名称 + /// + [SugarColumn(ColumnDescription = "名称", Length = 64)] + public string Name { get; set; } - /// - /// 排序 - /// - [SugarColumn(ColumnDescription = "排序")] - public int Order { get; set; } + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int Order { get; set; } - /// - /// 备注 - /// - [SugarColumn(ColumnDescription = "备注", Length = 256)] - [MaxLength(256)] - public string Remark { get; set; } + /// + /// 备注 + /// + [SugarColumn(ColumnDescription = "备注", Length = 256)] + [MaxLength(256)] + public string Remark { get; set; } } \ No newline at end of file diff --git a/Cis.Application/Cm/Entity/CmMarkLabel.cs b/Cis.Application/Cm/Entity/CmMarkLabel.cs index 09e3617..3f4a646 100644 --- a/Cis.Application/Cm/Entity/CmMarkLabel.cs +++ b/Cis.Application/Cm/Entity/CmMarkLabel.cs @@ -1,64 +1,64 @@ namespace Cis.Application.Cm; /// -/// 标记标签表 +/// 标签表 /// [SugarTable(CmInfo.CmMarkLabelTbName, CmInfo.CmMarkLabelTbDesc)] [Tenant(CmInfo.DbName)] public class CmMarkLabel : EntityBase { - /// - /// 相机 Id - /// - [SugarColumn(ColumnDescription = "相机Id")] - public long CbCameraId { get; set; } + /// + /// 相机 Id + /// + [SugarColumn(ColumnDescription = "相机Id")] + public long CbCameraId { get; set; } - /// - /// 标记组 Id - /// - [SugarColumn(ColumnDescription = "标记组Id")] - public long CmMarkGroupId { get; set; } + /// + /// 标记组 Id + /// + [SugarColumn(ColumnDescription = "标记组Id")] + public long CmMarkGroupId { get; set; } - /// - /// 名称 - /// - [SugarColumn(ColumnDescription = "名称", Length = 64)] - public string Name { get; set; } + /// + /// 名称 + /// + [SugarColumn(ColumnDescription = "名称", Length = 64)] + public string Name { get; set; } - /// - /// Pan 坐标 - /// - [SugarColumn(ColumnDescription = "Pan坐标")] - public double PanPosition { get; set; } + /// + /// Pan 坐标 + /// + [SugarColumn(ColumnDescription = "Pan坐标")] + public double PanPosition { get; set; } - /// - /// Tilt 坐标 - /// - [SugarColumn(ColumnDescription = "Tilt坐标")] - public double TiltPosition { get; set; } + /// + /// Tilt 坐标 + /// + [SugarColumn(ColumnDescription = "Tilt坐标")] + public double TiltPosition { get; set; } - /// - /// Zoom 坐标 - /// - [SugarColumn(ColumnDescription = "Zoom坐标")] - public double ZoomPosition { get; set; } + /// + /// Zoom 坐标 + /// + [SugarColumn(ColumnDescription = "Zoom坐标")] + public double ZoomPosition { get; set; } - [SugarColumn(ColumnDescription = "视频宽度")] - public double VideoWidth { get; set; } + [SugarColumn(ColumnDescription = "视频宽度")] + public double VideoWidth { get; set; } - [SugarColumn(ColumnDescription = "视频高度")] - public double VideoHeight { get; set; } + [SugarColumn(ColumnDescription = "视频高度")] + public double VideoHeight { get; set; } - [SugarColumn(ColumnDescription = "画布 left 距离比例")] - public double CanvasLeftRatio { get; set; } + [SugarColumn(ColumnDescription = "画布 left 距离比例")] + public double CanvasLeftRatio { get; set; } - [SugarColumn(ColumnDescription = "画布 top 距离比例")] - public double CanvasTopRatio { get; set; } + [SugarColumn(ColumnDescription = "画布 top 距离比例")] + public double CanvasTopRatio { get; set; } - /// - /// 备注 - /// - [SugarColumn(ColumnDescription = "备注", Length = 256)] - [MaxLength(256)] - public string Remark { get; set; } + /// + /// 备注 + /// + [SugarColumn(ColumnDescription = "备注", Length = 256)] + [MaxLength(256)] + public string Remark { get; set; } } \ No newline at end of file diff --git a/Cis.Application/Cm/Service/CmMarkGroupService.cs b/Cis.Application/Cm/Service/CmMarkGroupService.cs index 0b9d9df..341bd51 100644 --- a/Cis.Application/Cm/Service/CmMarkGroupService.cs +++ b/Cis.Application/Cm/Service/CmMarkGroupService.cs @@ -8,54 +8,54 @@ namespace Cis.Application.Cm; [ApiDescriptionSettings(CmInfo.GroupName, Order = CmInfo.GroupOrder)] public class CmMarkGroupService : IDynamicApiController, ITransient { - private readonly SqlSugarRepository _cmMarkGroupRep; - - public CmMarkGroupService(SqlSugarRepository cmMarkGroupRep) - { - _cmMarkGroupRep = cmMarkGroupRep; - } - - [HttpPost] - public async Task Add([FromForm] CmMarkGroup entity) - { - return await _cmMarkGroupRep.InsertAsync(entity); - } - - [HttpPost] - public async Task Update([FromForm] CmMarkGroup entity) - { - return await _cmMarkGroupRep.UpdateAsync(entity); - } - - [HttpPost] - public async Task Delete([FromForm] CmMarkGroup entity) - { - return await _cmMarkGroupRep.DeleteAsync(entity); - } - - [HttpGet] - public async Task Get(long id) - { - CmMarkGroup entity = await _cmMarkGroupRep.GetByIdAsync(id); - return entity; - } - - [HttpGet] - public async Task> GetList(string queryJson) - { - JObject queryObj = queryJson.ToJObject(); - List list = await _cmMarkGroupRep.AsQueryable() - .ToListAsync(); - return list; - } - - [HttpGet] - public async Task> GetPageList(string queryJson, string pagination) - { - Pagination pageObj = pagination.ToObject(); - JObject queryObj = queryJson.ToJObject(); - List list = await _cmMarkGroupRep.AsQueryable() - .ToPageListAsync(pageObj.Index, pageObj.Size); - return list; - } + private readonly SqlSugarRepository _baseRep; + + public CmMarkGroupService(SqlSugarRepository baseRep) + { + _baseRep = baseRep; + } + + [HttpPost] + public async Task Add([FromForm] CmMarkGroup entity) + { + return await _baseRep.InsertAsync(entity); + } + + [HttpPost] + public async Task Update([FromForm] CmMarkGroup entity) + { + return await _baseRep.UpdateAsync(entity); + } + + [HttpPost] + public async Task Delete([FromForm] CmMarkGroup entity) + { + return await _baseRep.DeleteAsync(entity); + } + + [HttpGet] + public async Task Get(long id) + { + CmMarkGroup entity = await _baseRep.GetByIdAsync(id); + return entity; + } + + [HttpGet] + public async Task> GetList(string queryJson) + { + JObject queryObj = queryJson.ToJObject(); + List list = await _baseRep.AsQueryable() + .ToListAsync(); + return list; + } + + [HttpGet] + public async Task> GetPageList(string queryJson, string pagination) + { + Pagination pageObj = pagination.ToObject(); + JObject queryObj = queryJson.ToJObject(); + List list = await _baseRep.AsQueryable() + .ToPageListAsync(pageObj.Index, pageObj.Size); + return list; + } } \ No newline at end of file diff --git a/Cis.Application/Cm/Service/CmMarkLabelService.cs b/Cis.Application/Cm/Service/CmMarkLabelService.cs index 853af86..7a1bed5 100644 --- a/Cis.Application/Cm/Service/CmMarkLabelService.cs +++ b/Cis.Application/Cm/Service/CmMarkLabelService.cs @@ -1,85 +1,87 @@ using Cis.Application.Core; +using Cis.Application.Core.Component.CameraSDK; +using EC.Helper.CameraSDK; using Newtonsoft.Json.Linq; namespace Cis.Application.Cm; /// -/// 标记标签服务 +/// 标签服务 /// [ApiDescriptionSettings(CmInfo.GroupName, Order = CmInfo.GroupOrder)] public class CmMarkLabelService : IDynamicApiController, ITransient { - private readonly SqlSugarRepository _cmMarkLabelRep; + private readonly SqlSugarRepository _baseRep; - private CameraDataCenter _cameraDataCenter { get; set; } + private CameraSdkServer _cameraSdk { get; set; } - public CmMarkLabelService(CameraDataCenter cameraDataCenter, - SqlSugarRepository cmMarkLabelRep) - { - _cameraDataCenter = cameraDataCenter; - _cmMarkLabelRep = cmMarkLabelRep; - } + public CmMarkLabelService( + SqlSugarRepository baseRep, + CameraSdkServer cameraSdk + ) + { + _baseRep = baseRep; + _cameraSdk = cameraSdk; + } - [HttpPost] - public async Task Add([FromForm] CmMarkLabel entity) - { - PtzInfo ptzInfo = _cameraDataCenter.GetCameraPtzInfo(entity.CbCameraId); - if (ptzInfo == null) - return false; - entity.PanPosition = ptzInfo.Pan; - entity.TiltPosition = ptzInfo.Tilt; - entity.ZoomPosition = ptzInfo.Zoom; - return await _cmMarkLabelRep.InsertAsync(entity); - } + [HttpPost] + public async Task Add([FromForm] CmMarkLabel entity) + { + bool ret = _cameraSdk.GetPtzInfoById(entity.CbCameraId.ToString(), out PtzInfo ptzInfo); + if (!ret) return false; + entity.PanPosition = ptzInfo.Pan; + entity.TiltPosition = ptzInfo.Tilt; + entity.ZoomPosition = ptzInfo.Zoom; + return await _baseRep.InsertAsync(entity); + } - [HttpPost] - public async Task AddReturnId([FromForm] CmMarkLabel entity) - { - PtzInfo ptzInfo = _cameraDataCenter.GetCameraPtzInfo(entity.CbCameraId); - if (ptzInfo == null) - return 0; - entity.PanPosition = ptzInfo.Pan; - entity.TiltPosition = ptzInfo.Tilt; - entity.ZoomPosition = ptzInfo.Zoom; - await _cmMarkLabelRep.InsertAsync(entity); - return entity.Id; - } + [HttpPost] + public async Task AddReturnId([FromForm] CmMarkLabel entity) + { + bool ret = _cameraSdk.GetPtzInfoById(entity.CbCameraId.ToString(), out PtzInfo ptzInfo); + if (!ret) return 0; + entity.PanPosition = ptzInfo.Pan; + entity.TiltPosition = ptzInfo.Tilt; + entity.ZoomPosition = ptzInfo.Zoom; + await _baseRep.InsertAsync(entity); + return entity.Id; + } - [HttpPost] - public async Task Update([FromForm] CmMarkLabel entity) - { - return await _cmMarkLabelRep.UpdateAsync(entity); - } + [HttpPost] + public async Task Update([FromForm] CmMarkLabel entity) + { + return await _baseRep.UpdateAsync(entity); + } - [HttpPost] - public async Task Delete([FromForm] CmMarkLabel entity) - { - return await _cmMarkLabelRep.DeleteAsync(entity); - } + [HttpPost] + public async Task Delete([FromForm] CmMarkLabel entity) + { + return await _baseRep.DeleteAsync(entity); + } - [HttpGet] - public async Task Get(long id) - { - CmMarkLabel entity = await _cmMarkLabelRep.GetByIdAsync(id); - return entity; - } + [HttpGet] + public async Task Get(long id) + { + CmMarkLabel entity = await _baseRep.GetByIdAsync(id); + return entity; + } - [HttpGet] - public async Task> GetList(string queryJson = "") - { - JObject queryObj = queryJson.ToJObject(); - List list = await _cmMarkLabelRep.AsQueryable() - .ToListAsync(); - return list; - } + [HttpGet] + public async Task> GetList(string queryJson = "") + { + JObject queryObj = queryJson.ToJObject(); + List list = await _baseRep.AsQueryable() + .ToListAsync(); + return list; + } - [HttpGet] - public async Task> GetPageList(string queryJson, string pagination) - { - Pagination pageObj = pagination.ToObject(); - JObject queryObj = queryJson.ToJObject(); - List list = await _cmMarkLabelRep.AsQueryable() - .ToPageListAsync(pageObj.Index, pageObj.Size); - return list; - } + [HttpGet] + public async Task> GetPageList(string queryJson, string pagination) + { + Pagination pageObj = pagination.ToObject(); + JObject queryObj = queryJson.ToJObject(); + List list = await _baseRep.AsQueryable() + .ToPageListAsync(pageObj.Index, pageObj.Size); + return list; + } } \ No newline at end of file diff --git a/Cis.Application/Core/Algo/HikMarkSeacher.cs b/Cis.Application/Core/Algo/HikMarkSeacher.cs deleted file mode 100644 index b169e94..0000000 --- a/Cis.Application/Core/Algo/HikMarkSeacher.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.Drawing; - -namespace Cis.Application.Core; - -public class HikMarkSeacher : MarkSearcherBase -{ - public HikMarkSeacher(CameraCalcInfo cameraCalcInfo) : base(cameraCalcInfo) - { - } - - #region Implement - - protected override double ConvertPanPosToAngle(double panPos) - { - double ret = 0.1 * HexToDecMa(panPos) / 180 * Math.PI; - ret = (ret >= 0) ? ret : (2 * Math.PI + ret); - return ret; - } - - protected override double ConvertTiltPosToAngle(double tiltPos, double tiltMinPos = 0) - { - double ndiff; - if (tiltPos > tiltMinPos) - ndiff = HexToDecMa(tiltPos) - HexToDecMa(tiltMinPos); - else - ndiff = HexToDecMa(tiltPos) + HexToDecMa(13824) - HexToDecMa(tiltMinPos); - double ret = 0.1 * ndiff / 180 * Math.PI; - return ret; - } - - protected override PointF GetFOfMatrixByZoomPos(double zoomPos) - { - PointF pointF = new() - { - X = (float)GetFx(zoomPos), - Y = (float)GetFy(zoomPos) - }; - return pointF; - } - - protected override void CalcSensor() - { - _cameraCalcInfo.MinFocusX = 1783.6 / _cameraCalcInfo.VideoWidth; - _cameraCalcInfo.MinFocusY = 1781.4 / _cameraCalcInfo.VideoHeight; - } - - #endregion Implement - - #region Util - - protected virtual double GetFx(double zoomPos) - { - CameraCalcInfo calcInfo = _cameraCalcInfo; - return calcInfo.MinFocusX * GetZoomTag(zoomPos); - } - - protected virtual double GetFy(double zoomPos) - { - CameraCalcInfo calcInfo = _cameraCalcInfo; - return calcInfo.MinFocusY * GetZoomTag(zoomPos); - } - - protected virtual double GetZoomTag(double zoomPos) - { - double ret = HexToDecMa(zoomPos) * 0.1; - ret = (ret - 1) * 0.65 + 1; - return ret; - } - - protected int HexToDecMa(double wHex) - { - int wHexInt = wHex.ToInt(); - int ret = (wHexInt / 4096) * 1000 + ((wHexInt % 4096) / 256) * 100 + ((wHexInt % 256) / 16) * 10 + (wHexInt % 16); - return ret; - } - - - - #endregion Util -} diff --git a/Cis.Application/Core/Algo/MarkSearcherBase.cs b/Cis.Application/Core/Algo/MarkSearcherBase.cs deleted file mode 100644 index b840e9c..0000000 --- a/Cis.Application/Core/Algo/MarkSearcherBase.cs +++ /dev/null @@ -1,260 +0,0 @@ -using MathNet.Numerics.LinearAlgebra; -using MathNet.Numerics.LinearAlgebra.Double; -using System.Collections.Concurrent; -using System.Drawing; - -namespace Cis.Application.Core; - -public abstract class MarkSearcherBase -{ - #region Attr - - /// - /// 当前相机参数信息 - /// - protected CameraCalcInfo _cameraCalcInfo { get; set; } - - /// - /// _markLabelInfoList 锁对象,写锁 - /// - private static object mliListLock { get; } = new(); - - /// - /// 需要计算的 markLabelInfo 列表 - /// - protected ConcurrentDictionary _markLabelInfoDict { get; set; } = new(); - - //protected MatrixBuilder MBuilder { get; set; } = Matrix.Build; - - /// - /// 世界坐标转化为相机坐标矩阵 - /// - protected Matrix World2CameraMatrix { get; set; } - - #endregion Attr - - public MarkSearcherBase(CameraCalcInfo cameraCalcInfo) - { - UpdateCameraCalcInfoRelated(cameraCalcInfo); - } - - #region Calc - - /// - /// 计算标签位置过程 - /// - /// - public List Calc() - { - List resultList = new(); - - if (World2CameraMatrix == null || _markLabelInfoDict.IsEmpty) - return resultList; - - foreach (MarkLabelCalcInfo item in _markLabelInfoDict.Values) - { - Matrix labelC2WMatrix = ConvertCameraToWorld(item); - Matrix labelPointMatrix = new DenseMatrix(3, 1, new double[] - { - (item.CanvasLeftRatio * item.VideoWidth) / _cameraCalcInfo.VideoWidth - 0.5 , - (item.CanvasTopRatio * item.VideoHeight) / _cameraCalcInfo.VideoHeight - 0.5 , - 1 - }); - Matrix lResult = labelC2WMatrix.Multiply(labelPointMatrix); - Matrix pResult = World2CameraMatrix.Multiply(lResult); - - double x = pResult[0, 0] / pResult[2, 0] + 0.5; - double y = pResult[1, 0] / pResult[2, 0] + 0.5; - MarkLabelCalcResult labelCalcResult; - if (x > 0.99 || x < 0.01 || y > 0.99 || y < 0.01 || pResult[2, 0] < 0) - labelCalcResult = MarkLabelCalcResult.New(item.Id, false); - else - labelCalcResult = MarkLabelCalcResult.New(item.Id, true, x, y); - resultList.Add(labelCalcResult); - } - return resultList; - } - - public async Task> CalcAsync() - { - return await Task.Run(Calc); - } - - /// - /// 判断相机是否进行了转动,转动了则需要重新计算世界坐标到相机坐标的转换矩阵 - /// - /// - /// - protected bool IsCameraRotate(PtzInfo newInfo) - { - bool ret = _cameraCalcInfo.PtzInfo.Pan != newInfo.Pan || - _cameraCalcInfo.PtzInfo.Tilt != newInfo.Tilt || - _cameraCalcInfo.PtzInfo.Zoom != newInfo.Zoom; - return ret; - } - - /// - /// 获取将世界坐标系中的点转化为相机坐标系中的点的转换矩阵 - /// - /// - /// - protected Matrix ConvertWorldToCamera(CameraCalcInfo cameraCalcInfo) - { - double panAngle = ConvertPanPosToAngle(cameraCalcInfo.PtzInfo.Pan); - double tiltAngle = ConvertTiltPosToAngle(cameraCalcInfo.PtzInfo.Tilt); - PointF pointF = GetFOfMatrixByZoomPos(cameraCalcInfo.PtzInfo.Zoom); - double sinPan = Math.Sin(panAngle); - double cosPan = Math.Cos(panAngle); - double sinTilt = Math.Sin(tiltAngle); - double cosTilt = Math.Cos(tiltAngle); - - Matrix fMatrix = new DenseMatrix(3, 3, new double[] - { - pointF.X, 0, 0 , - 0, pointF.Y, 0 , - 0, 0, 1 , - }); - - Matrix rotateTiltMatrix = new DenseMatrix(3, 3, new double[] - { - 1, 0, 0 , - 0, cosTilt, sinTilt , - 0, -sinTilt, cosTilt , - }); - - Matrix midResult = fMatrix.Multiply(rotateTiltMatrix); - - Matrix rotatePanMatrix = new DenseMatrix(3, 3, new double[] - { - cosPan, 0, sinPan , - 0, 1, 0 , - -sinPan, 0, cosPan , - }); - - var last = midResult.Multiply(rotatePanMatrix); - return last; - } - - /// - /// 获取将相机坐标系中的点转化为世界坐标系中的点的转换矩阵 - /// - /// - /// - protected Matrix ConvertCameraToWorld(MarkLabelCalcInfo labelCalcInfo) - { - double panAngle = ConvertPanPosToAngle(labelCalcInfo.PtzInfo.Pan); - double tiltAngle = ConvertTiltPosToAngle(labelCalcInfo.PtzInfo.Tilt); - PointF pointF = GetFOfMatrixByZoomPos(labelCalcInfo.PtzInfo.Zoom); - double sinPan = Math.Sin(panAngle); - double cosPan = Math.Cos(panAngle); - double sinTilt = Math.Sin(tiltAngle); - double cosTilt = Math.Cos(tiltAngle); - - Matrix rotatePanMatrix = new DenseMatrix(3, 3, new double[] - { - cosPan, 0, -sinPan , - 0, 1, 0 , - sinPan, 0, cosPan - }); - - Matrix rotateTiltMatrix = new DenseMatrix(3, 3, new double[] - { - 1, 0, 0 , - 0, cosTilt, -sinTilt , - 0, sinTilt, cosTilt - }); - - Matrix midResult = rotatePanMatrix.Multiply(rotateTiltMatrix); - - Matrix fMatrix = new DenseMatrix(3, 3, new double[] - { - (1 / pointF.X), 0, 0 , - 0, (1 / pointF.Y), 0 , - 0, 0, 1 - }); - - var last = midResult.Multiply(fMatrix); - return last; - } - - /// - /// 此方法计算在球机zoom值最小的情况下成像矩阵中的 f 本质为获取像元大小 - /// 尝试方案1:通过计算的方式来获取 - /// 尝试方案2:通过张友定相机标定的方法来生成成像矩阵中的 f - /// - protected virtual void CalcSensor() - { - } - - #endregion Calc - - #region Util - - /// - /// 将Pan值转化为角度 - /// - /// - protected abstract double ConvertPanPosToAngle(double panPos); - - /// - /// 将Tilt转化为角度 - /// - /// - protected abstract double ConvertTiltPosToAngle(double tiltPos, double tiltMinPos = 0); - - /// - /// 根据当前zoom值获取相机矩阵参数 - /// - /// - /// - protected abstract PointF GetFOfMatrixByZoomPos(double zoomPos); - - #endregion Util - - #region Operate Attr - - protected void UpdateCameraCalcInfoRelated(CameraCalcInfo cameraCalcInfo) - { - _cameraCalcInfo = cameraCalcInfo; - CalcSensor(); - World2CameraMatrix = ConvertWorldToCamera(cameraCalcInfo); - } - - public void UpdateCameraCalcInfo(PtzInfo ptzInfo) - { - if (IsCameraRotate(ptzInfo)) - { - _cameraCalcInfo.PtzInfo = ptzInfo; - World2CameraMatrix = ConvertWorldToCamera(_cameraCalcInfo); - } - } - - public bool AddMarkLabelCalcInfo(MarkLabelCalcInfo info) - { - lock (mliListLock) - { - if (_markLabelInfoDict.ContainsKey(info.Id)) - return false; - return _markLabelInfoDict.TryAdd(info.Id, info); - } - } - - public bool DeleteMarkLabelCalcInfo(long id) - { - lock (mliListLock) - { - if (!_markLabelInfoDict.ContainsKey(id)) - return true; - return _markLabelInfoDict.Remove(id); - } - } - - public bool ExistsMarkLabelCalcInfo(long id) - { - if (_markLabelInfoDict.ContainsKey(id)) - return true; - return false; - } - - #endregion Operate Attr -} \ No newline at end of file diff --git a/Cis.Application/Core/Api/IPtzApi.cs b/Cis.Application/Core/Api/IPtzApi.cs deleted file mode 100644 index e3461e5..0000000 --- a/Cis.Application/Core/Api/IPtzApi.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Cis.Application.Core; - -/// -/// Ptz Api 接口 -/// -public interface IPtzApi -{ - -} \ No newline at end of file diff --git a/Cis.Application/Core/Api/PtzServerApi.cs b/Cis.Application/Core/Api/PtzServerApi.cs deleted file mode 100644 index f85b487..0000000 --- a/Cis.Application/Core/Api/PtzServerApi.cs +++ /dev/null @@ -1,205 +0,0 @@ -using System.Net.Sockets; -using System.Runtime.InteropServices; - -namespace Cis.Application.Core; - -/// -/// Ptz Api -/// -public class PtzServerApi : IPtzApi, ISingleton -{ - #region Attr - - private TcpClient _tcpClient { get; set; } - - private NetworkStream _stream { get; set; } - - #endregion Attr - - public PtzServerApi() - { - PtzServerOptions options = App.GetOptions(); - _tcpClient = new TcpClient(options.Ip, options.Port); - //创建一个 networkstream 用来写入和读取数据 - _stream = _tcpClient.GetStream(); - } - - public RequestRealControl GetPtzRrc(int cameraId) - { - RequestRealControl realControl = new(); - try - { - string recieve_string = string.Empty; - realControl.token = 666; - - realControl.CameraInfo.cameraid = cameraId; - realControl.Status = true; - realControl.realControlType = RealControlType.PTZINFO_GET_; - byte[] data = StructToByte(realControl); - _stream.Write(data, 0, data.Length); - - byte[] recieve_byte = new byte[_tcpClient.ReceiveBufferSize]; - _stream.Read(recieve_byte, 0, (int)_tcpClient.ReceiveBufferSize); - //stream.BeginRead(recieve_byte, 0, (int)tcp_client.ReceiveBufferSize,EndRead, stream); - realControl = (RequestRealControl)BytetoStruct(recieve_byte, typeof(RequestRealControl)); - if (realControl.PTZPositionInfo.FT < 0) - { - realControl.PTZPositionInfo.FT = 3600 + realControl.PTZPositionInfo.FT; - } - } - catch (Exception) - { - realControl = default; - } - return realControl; - } - - public PtzInfo GetPtzInfo(int cameraId) - { - RequestRealControl rrc = GetPtzRrc(cameraId); - PtzInfo ptzInfo = PtzInfo.New(rrc.PTZPositionInfo.FP, rrc.PTZPositionInfo.FT, rrc.PTZPositionInfo.FZ); - return ptzInfo; - } - - public static byte[] StructToByte(object structObj) - { - //获取结构体大小 - int size = Marshal.SizeOf(structObj); - - byte[] data = new byte[size]; - - //分配内存空间 - IntPtr structPtr = Marshal.AllocHGlobal(size); - // 将结构体数据复制到内存空间 - Marshal.StructureToPtr(structObj, structPtr, false); - // 将内存空间的数据拷贝到byte数组 - Marshal.Copy(structPtr, data, 0, size); - //释放内存 - Marshal.FreeHGlobal(structPtr); - return data; - } - - public static object BytetoStruct(byte[] bytes, Type type) - { - object obj = new object(); - try - { - byte[] temp = bytes; - // 获取结构体大小 - int size = Marshal.SizeOf(type); - if (size > bytes.Length) - return null; - // 分配结构体内存空间 - IntPtr structPtr = Marshal.AllocHGlobal(size); - // 将byte数组内容拷贝到内存中 - Marshal.Copy(temp, 0, structPtr, size); - - // 将内存空间转化为目标结构体 - obj = Marshal.PtrToStructure(structPtr, type); - //释放内存 - Marshal.FreeHGlobal(structPtr); - } - catch (Exception) - { - } - return obj; - } - -} - -#region 与ptz服务交互使用结构体 - -//---------------------------------------------------------------------------------------- -// 与ptz服务交互使用结构体 -//---------------------------------------------------------------------------------------- -//注意这个属性不能少 -[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] -public struct RequestRealControl -{ - public int token; - - public CameraInfo CameraInfo; - - public RealControlType realControlType; - - //请求时 状态 true:开始;false:结束 答复时:true:成功;其他:失败 - public bool Status; - - public PresentInfo PresentInfo; - - public PTZPosInfo PTZPositionInfo; - //int数组,SizeConst表示数组的个数,在转换成 - //byte数组前必须先初始化数组,再使用,初始化 - //的数组长度必须和SizeConst一致,例test = new int[6]; - //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - //public int[] test; -} - -[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 4)] -public struct CameraInfo -{ - public int cameraid; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] - public char[] ip; - - public ushort port; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] - private char[] user; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] - private char[] password; -} - -[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 4)] -public struct PresentInfo -{ - public int presentNo;//预置位编号 - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] - private char[] PresentName; // 预置位名称 -} - -[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 4)] -public struct PTZPosInfo -{ - public int FP;//p信息 - public int FT;//T信息 - public int FZ;//Z信息 - public int TitlePosMin;//描述点垂直参数min - public int ZoomPosMin;//描述点变倍参数min - - public float FHorWidth;//水平宽度 精确到小数点后两位 *10000 - public float FVerWidth;//垂直宽度 精确到小数点后两位 *10000 - public float FFold;//zoom=1没变时的焦距 精确到小数点后两位 *100 - - public int CameraType; -} - -public enum RealControlType -{ - MOVE_UP_ = 1, - MOVE_DOWN_, - MOVE_LEFT_, - MOVE_RIGHT_, - MOVE_LEFTUP_, - MOVE_LEFTDOWN_, - MOVE_RIGHTUP_, - MOVE_RIGHTDOWN_, - - ZOOM_IN_, - ZOOM_OUT_, - FOCUS_NEAR_, - FOCUS_FAR_, - IRIS_OPEN_, - IRIS_CLOSE_, - - PRESET_SET_, - PRESET_CALL_, - - PTZINFO_GET_, - PTZINFO_SET_ -} - -#endregion 与ptz服务交互使用结构体 \ No newline at end of file diff --git a/Cis.Application/Core/Center/CameraDataCenter.cs b/Cis.Application/Core/Center/CameraDataCenter.cs index 6dfef8b..0dbbeeb 100644 --- a/Cis.Application/Core/Center/CameraDataCenter.cs +++ b/Cis.Application/Core/Center/CameraDataCenter.cs @@ -1,309 +1,166 @@ using Cis.Application.Cb; using Cis.Application.Cm; -using Cis.Application.Tb; -using Microsoft.Extensions.Logging; +using Cis.Application.Core.Component.MarkSeacher; +using Cis.Application.Core.Component.PtzServer; +using EC.Helper.CameraSDK; +using StackExchange.Profiling.Internal; +using StackExchange.Redis; using System.Collections.Concurrent; namespace Cis.Application.Core; -public class CameraDataCenter +public class CameraDataCenter : ISingleton { #region Attr private readonly SqlSugarRepository _cbCameraRep; private readonly SqlSugarRepository _cmMarkLableRep; - private readonly SqlSugarRepository _tbPtzCameraRep; - private readonly PtzServerApi _ptzServerApi; - private readonly CameraDataOptions options; + private readonly IDatabase _cache; - private Thread _thread { get; set; } + private readonly CameraDataOptions _options; + private readonly ICameraSdkServer _cameraSdkServer; + private readonly IMarkSearcherServer _markSearcherServer; /// - /// (cbCameraId, cbCameraIp) + /// {cameraId, List(MarkLabelCalcResult)} /// - private Dictionary _cbCameraId2IpDict { get; set; } = new(); - /// - /// (cameraIp, TbPtzCamera) - /// - private ConcurrentDictionary _tbPtzCameraDict { get; set; } = new(); - - /// - /// (cameraIp, PtzInfo) - /// - private ConcurrentDictionary _cameraPtzInfoDict { get; set; } = new(); - - /// - /// _markSearcherDict 锁对象,写锁 - /// - private static ReaderWriterLockSlim msDictLock { get; } = new(); - - /// - /// (cbCameraId, MarkSearcherBase) - /// - private ConcurrentDictionary _markSearcherDict { get; set; } = new(); - - /// - /// (cameraId, List(MarkLabelCalcResult)) - /// - - private ConcurrentDictionary> _markLabelCalcResultListDict { get; set; } = new(); + private ConcurrentDictionary> SearchResultListDict { get; set; } = new(); #endregion Attr - private readonly ILogger _logger; - - public CameraDataCenter() + public CameraDataCenter( + IDatabase cache, + ICameraSdkServer cameraSdkServer, + IMarkSearcherServer markSearcherServer + ) { _cbCameraRep = App.GetService>(); _cmMarkLableRep = App.GetService>(); - _tbPtzCameraRep = App.GetService>(); - _ptzServerApi = App.GetService(); - options = App.GetOptions(); - _logger = App.GetService>(); - Init(); + _cache = cache; + _options = App.GetOptions(); + _cameraSdkServer = cameraSdkServer; + _markSearcherServer = markSearcherServer; + InitThread(); } - private void Init() + #region Loop + + private Thread RefreshCameraPtzThread { get; set; } + + private Thread RefreshMarkSearcherThread { get; set; } + + /// + /// 初始化线程 + /// + private void InitThread() { - if (!options.LazyInit) + // 初始化 CameraPtzThread + RefreshCameraPtzThread = new Thread(() => { - List list = _tbPtzCameraRep.GetList(); - // 根据 Ip 去重 - foreach (TbPtzCamera item in list) + while (true) { - if (!_tbPtzCameraDict.ContainsKey(item.Ip)) - _tbPtzCameraDict[item.Ip] = item; + RefreshCameraPtzInfos(); + Thread.Sleep(_options.CameraPtz.LoopInterval); } - } + }) + { + IsBackground = true// 设置后台线程 + }; + // 启动 CameraPtzThread + RefreshCameraPtzThread.Start(); - // 初始化 thread - _thread = new Thread(WorkLoop) + // 初始化 MarkSearcherThread + RefreshMarkSearcherThread = new Thread(() => + { + while (true) + { + RefreshMarkSearchers(); + Thread.Sleep(_options.MarkSearcher.LoopInterval); + } + }) { IsBackground = true// 设置后台线程 }; - _thread.Start(); + // 启动 MarkSearcherThread + RefreshMarkSearcherThread.Start(); } - #region Loop - /// - /// 循环运行 + /// 刷新所有相机 ptz + /// 有待改善,应设置超时计数机制 + /// https://blog.csdn.net/qq_28368039/article/details/118597396 /// - private void WorkLoop() + private async void RefreshCameraPtzInfos() { - while (true) + HashEntry[] entries = _cache.HashGetAll(CacheInfo.CameraIpCounts); + List tasks = new(); + foreach (HashEntry entry in entries) { - RefreshPtzInfoByApi(); - RefreshMarkSearcher(); - Thread.Sleep(options.LoopInterval); + string cameraIp = entry.Name; + tasks.Add(RefreshCameraPtzInfo(cameraIp)); } + await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(_options.CameraPtz.Timeout)); } - private void RefreshPtzInfoByApi() - { - foreach (TbPtzCamera item in _tbPtzCameraDict.Values) - { - PtzInfo ptzInfo = _ptzServerApi.GetPtzInfo(item.CameraId); - _cameraPtzInfoDict[item.Ip] = ptzInfo; - } - } - - private async void RefreshMarkSearcher() + /// + /// 刷新相机 ptz + /// + /// + /// + private async Task RefreshCameraPtzInfo(string cameraIp) { - foreach (KeyValuePair pair in _markSearcherDict) - { - long cameraId = pair.Key; - MarkSearcherBase markSearcher = pair.Value; - bool ret = _cbCameraId2IpDict.TryGetValue(cameraId, out string cameraIp); - if (!ret) continue; - ret = _cameraPtzInfoDict.TryGetValue(cameraIp, out PtzInfo ptzInfo); - if (!ret) continue; - markSearcher.UpdateCameraCalcInfo(ptzInfo); - List resultList = await markSearcher.CalcAsync(); - _markLabelCalcResultListDict[cameraId] = resultList; - } + bool ret = _cameraSdkServer.GetPtzInfoByIp(cameraIp, out PtzInfo ptzInfo); + if (!ret) return; + await _cache.HashSetAsync(CacheInfo.CameraPtzInfos, cameraIp, ptzInfo.ToJson()); } - #endregion Loop - - #region external call - /// - /// 激活 cbCamera 进入运算 + /// 刷新所有 markSearcher /// - /// - /// - public bool ActivateSearcher(long cameraId) + private async void RefreshMarkSearchers() { - try - { - msDictLock.EnterWriteLock(); - if (_markSearcherDict.ContainsKey(cameraId)) - return false; - // 获取 cbCamera - CbCamera cbCamera = _cbCameraRep.GetById(cameraId); - if (cbCamera == null) return false; - // 获取 tbPtzCamera - string cameraIp = cbCamera.Ip; - bool ret = _tbPtzCameraDict.TryGetValue(cameraIp, out TbPtzCamera tbPtzCamera); - if (!ret) - { - tbPtzCamera = _tbPtzCameraRep.GetFirst(u => u.Ip == cameraIp); - if (tbPtzCamera == null) return false; - _tbPtzCameraDict[cameraIp] = tbPtzCamera; - } - // 存储 cbCamera id 对应 ip 关系 - _cbCameraId2IpDict[cbCamera.Id] = cameraIp; - // 创建 cameraCalcInfo - CameraCalcInfo cameraCalcInfo = CameraCalcInfo.New(cameraId, _ptzServerApi.GetPtzInfo(tbPtzCamera.Id)); - // 创建 markSeacher - HikMarkSeacher markSeacher = new(cameraCalcInfo); - // 获取 cmMarkLabel 列表 - List cmMarkLabelList = _cmMarkLableRep.GetList(u => u.CbCameraId == cameraId); - // 将 cmMarkLabel 一一添加到 markSeacher - foreach (CmMarkLabel item in cmMarkLabelList) - { - MarkLabelCalcInfo markLabelCalcInfo = MarkLabelCalcInfo.New( - item.Id, - PtzInfo.New(item.PanPosition, item.TiltPosition, item.ZoomPosition), - item.VideoWidth, - item.VideoHeight, - item.CanvasLeftRatio, - item.CanvasTopRatio - ); - markSeacher.AddMarkLabelCalcInfo(markLabelCalcInfo); - } - // 将 markSeacher 放入字典 - _markSearcherDict[cameraId] = markSeacher; - } - finally + HashEntry[] entries = _cache.HashGetAll(CacheInfo.CameraId2Ip); + List tasks = new(); + foreach (HashEntry entry in entries) { - msDictLock.ExitWriteLock(); + string cameraId = entry.Name; + tasks.Add(RefreshMarkSearcher(cameraId.ToLong())); } - return true; + await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(_options.CameraPtz.Timeout)); } /// - /// 解除 cbCamera 进入运算 + /// 刷新 markSearcher /// /// /// - public bool DeActivateSearcher(long cameraId) + private async Task RefreshMarkSearcher(long cameraId) { - try - { - msDictLock.EnterWriteLock(); - _markSearcherDict.Remove(cameraId); - _markLabelCalcResultListDict.Remove(cameraId); - } - finally - { - msDictLock.ExitWriteLock(); - } - return true; - } - - public bool IsExistSearcher(long cameraId) - { - return _markSearcherDict.ContainsKey(cameraId); + MarkSearcherBase markSearcher = _markSearcherServer.GetSearcher(cameraId); + if (markSearcher == null) return; + string cameraIp = _cache.HashGet(CacheInfo.CameraId2Ip, cameraId); + RedisValue value = _cache.HashGet(CacheInfo.CameraPtzInfos, cameraIp); + if (value.IsNull) return; + PtzInfo ptzInfo = value.ToString().FromJson(); + markSearcher.UpdateCameraCalcParams(ptzInfo); + List resultList = await markSearcher.SearchAsync(); + SearchResultListDict[cameraId] = resultList; } - public bool ActivateMarkLabel(long cameraId, long markLabelId) - { - bool ret = _markSearcherDict.TryGetValue(cameraId, out MarkSearcherBase markSearcher); - if (!ret) - return false; - if (markSearcher.ExistsMarkLabelCalcInfo(markLabelId)) - return false; - CmMarkLabel label = _cmMarkLableRep.GetById(markLabelId); - if (label == null) - return false; - MarkLabelCalcInfo markLabelCalcInfo = MarkLabelCalcInfo.New( - label.Id, - PtzInfo.New(label.PanPosition, label.TiltPosition, label.ZoomPosition), - label.VideoWidth, - label.VideoHeight, - label.CanvasLeftRatio, - label.CanvasTopRatio - ); - return markSearcher.AddMarkLabelCalcInfo(markLabelCalcInfo); - } - - public bool DectivateMarkLabel(long cameraId, long markLabelId) - { - bool ret = _markSearcherDict.TryGetValue(cameraId, out MarkSearcherBase markSearcher); - return ret ? markSearcher.DeleteMarkLabelCalcInfo(markLabelId) : false; - } + #endregion Loop - public bool IsExistCameraMarkLabel(long cameraId, long markLabelId) - { - bool ret = _markSearcherDict.TryGetValue(cameraId, out MarkSearcherBase markSearcher) && - markSearcher.ExistsMarkLabelCalcInfo(markLabelId); - return ret; - } + #region Base Method public List GetMarkLabelCalcResultList(long cameraId) { - bool ret = _markLabelCalcResultListDict.TryGetValue(cameraId, out List list); - return ret ? list : new(); - } - - public PtzInfo GetCameraPtzInfo(long cameraId) - { - PtzInfo ptzInfo = null; - bool ret = _cbCameraId2IpDict.TryGetValue(cameraId, out string cameraIp) && - _cameraPtzInfoDict.TryGetValue(cameraIp, out ptzInfo); - return ret ? ptzInfo : null; - } - - public async Task ActivateSearcherAsync(long cameraId) - { - return await Task.Run(() => - { - return ActivateSearcher(cameraId); - }); - } - - public async Task DeActivateSearcherAsync(long cameraId) - { - return await Task.Run(() => - { - return DeActivateSearcher(cameraId); - }); - } - - public async Task IsExistSearcherAsync(long cameraId) - { - return await Task.Run(() => - { - return IsExistSearcher(cameraId); - }); - } - - public async Task ActivateMarkLabelAsync(long cameraId, long markLabelId) - { - return await Task.Run(() => - { - return ActivateMarkLabel(cameraId, markLabelId); - }); + bool ret = SearchResultListDict.TryGetValue(cameraId, out List resultList); + return ret ? resultList : new List(); } - public async Task DeactivateMarkLabelAsync(long cameraId, long markLabelId) - { - return await Task.Run(() => - { - return DectivateMarkLabel(cameraId, markLabelId); - }); - } + #endregion Base Method - public async Task IsExistMarkLabelAysnc(long cameraId, long markLabelId) - { - return await Task.Run(() => - { - return IsExistCameraMarkLabel(cameraId, markLabelId); - }); - } + #region Base Method Async public async Task> GetMarkLabelCalcResultListAsync(long cameraId) { @@ -313,5 +170,5 @@ public class CameraDataCenter }); } - #endregion external call + #endregion Base Method Async } \ No newline at end of file diff --git a/Cis.Application/Core/Common/CacheInfo.cs b/Cis.Application/Core/Common/CacheInfo.cs new file mode 100644 index 0000000..b5ec0f3 --- /dev/null +++ b/Cis.Application/Core/Common/CacheInfo.cs @@ -0,0 +1,23 @@ +namespace Cis.Application.Core; + +public class CacheInfo +{ + #region Cache Name + + /// + /// CameraId2Ip 字典 + /// + public static string CameraId2Ip { get; set; } = "CameraId2Ip"; + + /// + /// CameraIpCounts 字典 + /// + public static string CameraIpCounts { get; set; } = "CameraIpCounts"; + + /// + /// CameraPtzInfos 字典 + /// + public static string CameraPtzInfos { get; set; } = "CameraPtzInfos"; + + #endregion Cache Name +} \ No newline at end of file diff --git a/Cis.Application/Core/Common/CoreInfo.cs b/Cis.Application/Core/Common/CoreInfo.cs new file mode 100644 index 0000000..5130a4c --- /dev/null +++ b/Cis.Application/Core/Common/CoreInfo.cs @@ -0,0 +1,18 @@ +namespace Cis.Application.Core; + +public class CoreInfo +{ + #region Api Info + + /// + /// Api 分组名 + /// + public const string GroupName = "Core"; + + /// + /// Api 分组排序 + /// + public const int GroupOrder = 100; + + #endregion Api Info +} \ No newline at end of file diff --git a/Cis.Application/Core/Common/Extension.cs b/Cis.Application/Core/Common/Extension.cs new file mode 100644 index 0000000..e2746c8 --- /dev/null +++ b/Cis.Application/Core/Common/Extension.cs @@ -0,0 +1,30 @@ +using Cis.Application.Core.Component.MarkSeacher; +using EC.Helper.CameraSDK; + +namespace Cis.Application.Core; + +[SuppressSniffer] +public static class Extension +{ + public static ICameraSDK CreateCameraSDK(this CameraType cameraType, CameraInfo cameraInfo) + { + return cameraType switch + { + CameraType.HiK => new HiKSDK(cameraInfo), + CameraType.DaHua => new DaHuaSDK(cameraInfo), + CameraType.YuShi => new YuShiSDK(cameraInfo), + _ => null, + }; + } + + public static MarkSearcherBase CreateMarkSearcher(this CameraType cameraType, CameraCalcParams cameraCalcParams) + { + return cameraType switch + { + CameraType.HiK => new HiKMarkSearcher(cameraCalcParams), + CameraType.DaHua => new DaHuaMarkSearcher(cameraCalcParams), + CameraType.YuShi => new YuShiMarkSearcher(cameraCalcParams), + _ => null + }; + } +} \ No newline at end of file diff --git a/Cis.Application/Core/Common/Options.cs b/Cis.Application/Core/Common/Options.cs index 6eb32fa..8218838 100644 --- a/Cis.Application/Core/Common/Options.cs +++ b/Cis.Application/Core/Common/Options.cs @@ -2,34 +2,30 @@ public class CameraDataOptions : IConfigurableOptions { - /// - /// 是否懒加载 - /// - public bool LazyInit { get; set; } + public string Test { get; set; } - /// - /// 循环间隔,单位毫秒 - /// - public int LoopInterval { get; set; } + public CameraPtz CameraPtz { get; set; } + + public MarkSearcher MarkSearcher { get; set; } } -/// -/// PtzServer选项 -/// -public class PtzServerOptions : IConfigurableOptions +public class CameraDataBase { - /// - /// 服务类别 - /// - public string Type { get; set; } + /// + /// 循环间隔,单位毫秒 + /// + public int LoopInterval { get; set; } + + /// + /// 超时时间,单位毫秒 + /// + public int Timeout { get; set; } +} - /// - /// 服务IP - /// - public string Ip { get; set; } +public class CameraPtz : CameraDataBase +{ +} - /// - /// 服务端口 - /// - public int Port { get; set; } +public class MarkSearcher : CameraDataBase +{ } \ No newline at end of file diff --git a/Cis.Application/Core/Component/CameraSDK/CameraSdkServer.cs b/Cis.Application/Core/Component/CameraSDK/CameraSdkServer.cs new file mode 100644 index 0000000..05586c0 --- /dev/null +++ b/Cis.Application/Core/Component/CameraSDK/CameraSdkServer.cs @@ -0,0 +1,73 @@ +using Cis.Application.Core.Component.PtzServer; +using EC.Helper.CameraSDK; +using StackExchange.Redis; +using System.Collections.Concurrent; + +namespace Cis.Application.Core.Component.CameraSDK; + +/// +/// 相机 sdk 服务类 +/// +public class CameraSdkServer : ICameraSdkServer, ISingleton +{ + #region Attr + + private readonly IDatabase _cache; + + /// + /// {ip, ICameraSDK} + /// + private ConcurrentDictionary CameraSdkDict { get; set; } = new(); + + #endregion Attr + + public CameraSdkServer(IDatabase cache) + { + _cache = cache; + } + + #region Base Method + + public bool RegisterCamera(CameraInfo cameraInfo) + { + bool ret = CameraSdkDict.ContainsKey(cameraInfo.Ip); + if (ret) return false; + ICameraSDK cameraSDK = ((CameraType)cameraInfo.Type).CreateCameraSDK(cameraInfo); + if (cameraSDK == null) return false; + ret = cameraSDK.Init(); + if (!ret) return false; + ret = CameraSdkDict.TryAdd(cameraInfo.Ip, cameraSDK); + return ret; + } + + public bool DeleteCamera(string ip) + { + return CameraSdkDict.TryRemove(ip, out _); + } + + public bool IsExistsCamera(string ip) + { + return CameraSdkDict.ContainsKey(ip); + } + + #endregion Base Method + + #region Main Method + + public bool GetPtzInfoById(string cameraId, out PtzInfo ptzInfo) + { + RedisValue value = _cache.HashGet(CacheInfo.CameraId2Ip, cameraId); + if (value.IsNull) { ptzInfo = PtzInfo.Default; return false; } + string ip = value.ToString(); + return GetPtzInfoByIp(ip, out ptzInfo); + } + + public bool GetPtzInfoByIp(string ip, out PtzInfo ptzInfo) + { + bool ret = CameraSdkDict.TryGetValue(ip, out ICameraSDK cameraSDK); + if (!ret) { ptzInfo = PtzInfo.Default; return false; } + return cameraSDK.GetPtzInfo(out ptzInfo); + } + + #endregion Main Method +} \ No newline at end of file diff --git a/Cis.Application/Core/Component/CameraSDK/ICameraSdkServer.cs b/Cis.Application/Core/Component/CameraSDK/ICameraSdkServer.cs new file mode 100644 index 0000000..30adb5c --- /dev/null +++ b/Cis.Application/Core/Component/CameraSDK/ICameraSdkServer.cs @@ -0,0 +1,54 @@ +using EC.Helper.CameraSDK; + +namespace Cis.Application.Core.Component.PtzServer; + +/// +/// 相机 sdk 服务接口 +/// +public interface ICameraSdkServer +{ + #region Base Method + + /// + /// 注册相机 + /// + /// + /// + public bool RegisterCamera(CameraInfo cameraInfo); + + /// + /// 注销相机 + /// + /// + /// + public bool DeleteCamera(string ip); + + /// + /// 是否存在相机 + /// + /// + /// + public bool IsExistsCamera(string ip); + + #endregion Base Method + + #region Main Method + + /// + /// 获取 ptz + /// + /// + /// + /// + public bool GetPtzInfoById(string cameraId, out PtzInfo ptzInfo); + + /// + /// 获取 ptz + /// + /// + /// + /// + public bool GetPtzInfoByIp(string ip, out PtzInfo ptzInfo); + + #endregion Main Method +} \ No newline at end of file diff --git a/Cis.Application/Core/Component/MarkSeacher/Entity/CameraCalcParams.cs b/Cis.Application/Core/Component/MarkSeacher/Entity/CameraCalcParams.cs new file mode 100644 index 0000000..0f2515c --- /dev/null +++ b/Cis.Application/Core/Component/MarkSeacher/Entity/CameraCalcParams.cs @@ -0,0 +1,52 @@ +using EC.Helper.CameraSDK; + +namespace Cis.Application.Core.Component.MarkSeacher; + +/// +/// 相机计算参数 +/// +public class CameraCalcParams +{ + /// + /// Camera Id + /// + public long Id { get; set; } + + /// + /// Ptz 信息 + /// + public PtzInfo PtzInfo { get; set; } + + /// + /// FocusX + /// + public double FocusX { get; set; } + + /// + /// FocusY + /// + public double FocusY { get; set; } + + /// + /// 视频宽度 + /// + public int VideoWidth { get; set; } + + /// + /// 视频高度 + /// + public int VideoHeight { get; set; } + + public static CameraCalcParams New(long id, PtzInfo ptzInfo, double focusX, double focusY, int videoWidth = 1920, int videoHeight = 1080) + { + return new() + { + Id = id, + PtzInfo = ptzInfo, + FocusX = focusX, + FocusY = focusY, + VideoWidth = videoWidth, + VideoHeight = videoHeight, + }; + } +} \ No newline at end of file diff --git a/Cis.Application/Core/Component/MarkSeacher/Entity/MarkLabelCalcParams.cs b/Cis.Application/Core/Component/MarkSeacher/Entity/MarkLabelCalcParams.cs new file mode 100644 index 0000000..7fd8dc2 --- /dev/null +++ b/Cis.Application/Core/Component/MarkSeacher/Entity/MarkLabelCalcParams.cs @@ -0,0 +1,52 @@ +using EC.Helper.CameraSDK; + +namespace Cis.Application.Core.Component.MarkSeacher; + +/// +/// 标签计算参数 +/// +public class MarkLabelCalcParams +{ + /// + /// MarkLabel Id + /// + public long Id { get; set; } + + /// + /// Ptz 信息 + /// + public PtzInfo PtzInfo { get; set; } + + /// + /// 视频宽度 + /// + public double VideoWidth { get; set; } + + /// + /// 视频高度 + /// + public double VideoHeight { get; set; } + + /// + /// 画布 left 距离比例 + /// + public double CanvasLeftRatio { get; set; } + + /// + /// 画布 top 距离比例 + /// + public double CanvasTopRatio { get; set; } + + public static MarkLabelCalcParams New(long id, PtzInfo ptzInfo, double videoWidth, double videoHeight, double canvasLeftRatio, double canvasTopRatio) + { + return new() + { + Id = id, + PtzInfo = ptzInfo, + VideoWidth = videoWidth, + VideoHeight = videoHeight, + CanvasLeftRatio = canvasLeftRatio, + CanvasTopRatio = canvasTopRatio + }; + } +} \ No newline at end of file diff --git a/Cis.Application/Core/Component/MarkSeacher/Entity/MarkLabelCalcResult.cs b/Cis.Application/Core/Component/MarkSeacher/Entity/MarkLabelCalcResult.cs new file mode 100644 index 0000000..473db6b --- /dev/null +++ b/Cis.Application/Core/Component/MarkSeacher/Entity/MarkLabelCalcResult.cs @@ -0,0 +1,48 @@ +namespace Cis.Application.Core.Component.MarkSeacher; + +/// +/// 标签计算结果 +/// +public class MarkLabelCalcResult +{ + /// + /// MarkLabel Id + /// + public long Id { get; set; } + + /// + /// true 显示(在当前视频画面里面) + /// false 不显示(不在当前视频画面里面) + /// + public bool InFlag { get; set; } + + /// + /// 画布 left 距离比例 + /// + public double CanvasLeftRatio { get; set; } + + /// + /// 画布 top 距离比例 + /// + public double CanvasTopRatio { get; set; } + + public static MarkLabelCalcResult New(long id, bool inFlag) + { + return new() + { + Id = id, + InFlag = inFlag + }; + } + + public static MarkLabelCalcResult New(long id, bool inFlag, double canvasLeftRatio, double canvasTopRatio) + { + return new() + { + Id = id, + InFlag = inFlag, + CanvasLeftRatio = canvasLeftRatio, + CanvasTopRatio = canvasTopRatio + }; + } +} \ No newline at end of file diff --git a/Cis.Application/Core/Component/MarkSeacher/IMarkSearcherServer.cs b/Cis.Application/Core/Component/MarkSeacher/IMarkSearcherServer.cs new file mode 100644 index 0000000..9c63f74 --- /dev/null +++ b/Cis.Application/Core/Component/MarkSeacher/IMarkSearcherServer.cs @@ -0,0 +1,119 @@ +namespace Cis.Application.Core.Component.MarkSeacher; + +/// +/// 追踪标签服务接口 +/// +public interface IMarkSearcherServer +{ + #region Base Method + + /// + /// 激活相机进入运算 + /// + /// + /// + public bool ActivateSearcher(long cameraId); + + /// + /// 解除相机进入运算 + /// + /// + /// + public bool DeactivateSearcher(long cameraId); + + /// + /// 是否存在相机进入运算 + /// + /// + /// + public bool IsExistsSearcher(long cameraId); + + /// + /// 获取 Searcher + /// + /// + /// + public MarkSearcherBase GetSearcher(long cameraId); + + /// + /// 激活标签进入运算 + /// + /// + /// + /// + public bool ActivateMarkLabel(long cameraId, long markLabelId); + + /// + /// 解除标签进入运算 + /// + /// + /// + /// + public bool DeactivateMarkLabel(long cameraId, long markLabelId); + + /// + /// 是否存在标签进入运算 + /// + /// + /// + /// + public bool IsExistsMarkLabel(long cameraId, long markLabelId); + + #endregion Base Method + + #region Base Method + + /// + /// 激活相机进入运算 + /// + /// + /// + public Task ActivateSearcherAsync(long cameraId); + + /// + /// 解除相机进入运算 + /// + /// + /// + public Task DeactivateSearcherAsync(long cameraId); + + /// + /// 是否存在相机进入运算 + /// + /// + /// + public Task IsExistsSearcherAsync(long cameraId); + + /// + /// 获取 Searcher + /// + /// + /// + public Task GetSearcherAsync(long cameraId); + + /// + /// 激活标签进入运算 + /// + /// + /// + /// + public Task ActivateMarkLabelAsync(long cameraId, long markLabelId); + + /// + /// 解除标签进入运算 + /// + /// + /// + /// + public Task DeactivateMarkLabelAsync(long cameraId, long markLabelId); + + /// + /// 是否存在标签进入运算 + /// + /// + /// + /// + public Task IsExistsMarkLabelAsync(long cameraId, long markLabelId); + + #endregion Base Method +} \ No newline at end of file diff --git a/Cis.Application/Core/Component/MarkSeacher/MarkSearcherServer.cs b/Cis.Application/Core/Component/MarkSeacher/MarkSearcherServer.cs new file mode 100644 index 0000000..1b0fa7a --- /dev/null +++ b/Cis.Application/Core/Component/MarkSeacher/MarkSearcherServer.cs @@ -0,0 +1,268 @@ +using Cis.Application.Cb; +using Cis.Application.Cm; +using Cis.Application.Core.Component.PtzServer; +using EC.Helper.CameraSDK; +using StackExchange.Redis; +using System.Collections.Concurrent; + +namespace Cis.Application.Core.Component.MarkSeacher; + +/// +/// 追踪标签服务类 +/// +public class MarkSearcherServer : IMarkSearcherServer, ISingleton +{ + #region Attr + + private readonly SqlSugarRepository _cbCameraRep; + private readonly SqlSugarRepository _cbCameraParamsRep; + private readonly SqlSugarRepository _cmMarkLableRep; + private readonly IDatabase _cache; + + private readonly ICameraSdkServer _cameraSdkServer; + + /// + /// {cbCameraId, MarkSearcherBase} + /// + private ConcurrentDictionary MarkSearcherDict { get; set; } = new(); + + /// + /// MarkSearcherDict 原子操作锁 + /// + private ReaderWriterLockSlim MsDictRWLock { get; } = new(); + + #endregion Attr + + public MarkSearcherServer( + IDatabase cache, + ICameraSdkServer cameraSdkServer + ) + { + _cbCameraRep = App.GetService>(); + _cbCameraParamsRep = App.GetService>(); + _cmMarkLableRep = App.GetService>(); + _cache = cache; + _cameraSdkServer = cameraSdkServer; + } + + #region Base Method + + public bool ActivateSearcher(long cameraId) + { + try + { + MsDictRWLock.EnterWriteLock(); + return ActivateSearcherAtom(cameraId); + } + finally + { + MsDictRWLock.ExitWriteLock(); + } + } + + /// + /// ActivateSearcher 原子操作 + /// + /// + /// + private bool ActivateSearcherAtom(long cameraId) + { + bool ret = MarkSearcherDict.ContainsKey(cameraId); + if (ret) return false; + // 获取相机 + CbCamera cbCamera = _cbCameraRep.GetById(cameraId); + if (cbCamera == null) return false; + // 获取相机参数 + CbCameraParams cbCameraParams = _cbCameraParamsRep.GetById(cbCamera.CbCameraParamsId); + if (cbCameraParams == null) return false; + + // 注册并获取 ptz + ret = _cameraSdkServer.IsExistsCamera(cbCamera.Ip); + if (!ret) + { + CameraInfo cameraInfo = CameraInfo.New(cbCameraParams.CameraType, cbCamera.Ip, cbCamera.UserName, cbCamera.Password); + ret = _cameraSdkServer.RegisterCamera(cameraInfo); + if (!ret) + { + // double check + ret = _cameraSdkServer.IsExistsCamera(cbCamera.Ip); + if (!ret) return false; + } + } + ret = _cameraSdkServer.GetPtzInfoByIp(cbCamera.Ip, out PtzInfo ptzInfo); + if (!ret) return false; + + // 创建相机计算参数 + CameraCalcParams cameraCalcParams = CameraCalcParams.New(cbCamera.Id, ptzInfo, cbCameraParams.FocusX, cbCameraParams.FocusY); + // 创建 markSearcher + MarkSearcherBase markSearcher = ((CameraType)cbCameraParams.CameraType).CreateMarkSearcher(cameraCalcParams); + if (markSearcher == null) return false; + // 获取标签列表 + List cmMarkLabelList = _cmMarkLableRep.GetList(u => u.CbCameraId == cameraId); + // 将标签添加到 markSearcher + foreach (CmMarkLabel item in cmMarkLabelList) + { + // 创建标签计算参数 + MarkLabelCalcParams labelCalcParams = MarkLabelCalcParams.New( + item.Id, + PtzInfo.New(item.PanPosition, item.TiltPosition, item.ZoomPosition), + item.VideoWidth, + item.VideoHeight, + item.CanvasLeftRatio, + item.CanvasTopRatio + ); + markSearcher.AddMarkLabelCalcParams(labelCalcParams); + } + // 存放 markSearcher + ret = MarkSearcherDict.TryAdd(cameraId, markSearcher); + if (!ret) return false; + // 记录缓存 + _cache.HashSet(CacheInfo.CameraId2Ip, cbCamera.Id, cbCamera.Ip); + _cache.HashIncrement(CacheInfo.CameraIpCounts, cbCamera.Ip); + return true; + } + + public bool DeactivateSearcher(long cameraId) + { + try + { + MsDictRWLock.EnterWriteLock(); + return DeactivateSearcherAtom(cameraId); + } + finally + { + MsDictRWLock.ExitWriteLock(); + } + } + + /// + /// DeactivateSearcher 原子操作 + /// + /// + /// + private bool DeactivateSearcherAtom(long cameraId) + { + bool ret = MarkSearcherDict.TryRemove(cameraId, out _); + if (!ret) return false; + RedisValue value = _cache.HashGet(CacheInfo.CameraId2Ip, cameraId); + if (value.IsNull) return false; + string cameraIp = (string)value; + _cache.HashDelete(CacheInfo.CameraId2Ip, cameraId); + _cache.HashDecrement(CacheInfo.CameraIpCounts, cameraIp); + //int ipCount = (int)_cache.HashGet(CacheInfo.CameraIpCounts, cameraIp); + //if (ipCount <= 0) + //{ + // // 直接删除 or 设置过期 + // _cache.HashDelete(CacheInfo.CameraIpCounts, cameraIp); + // _cameraSdkServer.DeleteCamera(cameraIp); + //} + return true; + } + + public bool IsExistsSearcher(long cameraId) + { + return MarkSearcherDict.ContainsKey(cameraId); + } + + public MarkSearcherBase GetSearcher(long cameraId) + { + MarkSearcherDict.TryGetValue(cameraId, out MarkSearcherBase searcher); + return searcher; + } + + public bool ActivateMarkLabel(long cameraId, long markLabelId) + { + bool ret = MarkSearcherDict.TryGetValue(cameraId, out MarkSearcherBase markSearcher); + if (!ret) return false; + ret = markSearcher.IsExistsMarkLabelCalcParams(markLabelId); + if (ret) return false; + CmMarkLabel label = _cmMarkLableRep.GetById(markLabelId); + if (label == null) return false; + MarkLabelCalcParams labelCalcParams = MarkLabelCalcParams.New( + label.Id, + PtzInfo.New(label.PanPosition, label.TiltPosition, label.ZoomPosition), + label.VideoWidth, + label.VideoHeight, + label.CanvasLeftRatio, + label.CanvasTopRatio + ); + ret = markSearcher.AddMarkLabelCalcParams(labelCalcParams); + return ret; + } + + public bool DeactivateMarkLabel(long cameraId, long markLabelId) + { + bool ret = MarkSearcherDict.TryGetValue(cameraId, out MarkSearcherBase markSearcher); + if (!ret) return false; + ret = markSearcher.DeleteMarkLabelCalcParams(markLabelId); + return ret; + } + + public bool IsExistsMarkLabel(long cameraId, long markLabelId) + { + return MarkSearcherDict.TryGetValue(cameraId, out MarkSearcherBase searcher) + && searcher.IsExistsMarkLabelCalcParams(markLabelId); + } + + #endregion Base Method + + #region Base Method Async + + public async Task ActivateSearcherAsync(long cameraId) + { + return await Task.Run(() => + { + return ActivateSearcher(cameraId); + }); + } + + public async Task DeactivateSearcherAsync(long cameraId) + { + return await Task.Run(() => + { + return DeactivateSearcher(cameraId); + }); + } + + public async Task IsExistsSearcherAsync(long cameraId) + { + return await Task.Run(() => + { + return IsExistsSearcher(cameraId); + }); + } + + public async Task GetSearcherAsync(long cameraId) + { + return await Task.Run(() => + { + return GetSearcher(cameraId); + }); + } + + public async Task ActivateMarkLabelAsync(long cameraId, long markLabelId) + { + return await Task.Run(() => + { + return ActivateMarkLabel(cameraId, markLabelId); + }); + } + + public async Task DeactivateMarkLabelAsync(long cameraId, long markLabelId) + { + return await Task.Run(() => + { + return DeactivateMarkLabel(cameraId, markLabelId); + }); + } + + public async Task IsExistsMarkLabelAsync(long cameraId, long markLabelId) + { + return await Task.Run(() => + { + return IsExistsMarkLabel(cameraId, markLabelId); + }); + } + + #endregion Base Method Async +} \ No newline at end of file diff --git a/Cis.Application/Core/Component/MarkSeacher/Seacher/DaHuaMarkSearcher.cs b/Cis.Application/Core/Component/MarkSeacher/Seacher/DaHuaMarkSearcher.cs new file mode 100644 index 0000000..478cfd2 --- /dev/null +++ b/Cis.Application/Core/Component/MarkSeacher/Seacher/DaHuaMarkSearcher.cs @@ -0,0 +1,31 @@ +using System.Drawing; + +namespace Cis.Application.Core.Component.MarkSeacher; + +public class DaHuaMarkSearcher : MarkSearcherBase +{ + public DaHuaMarkSearcher(CameraCalcParams cameraCalcParams) : base(cameraCalcParams) + { + } + + #region Implement + + protected override double ConvertPanPosToAngle(double panPos) + { + double ret = (-0.1 * panPos) / 180 * Math.PI; + return ret; + } + + protected override double ConvertTiltPosToAngle(double tiltPos, double tiltMinPos = 0) + { + double ret = (0.1 * tiltPos) / 180 * Math.PI; + return ret; + } + + protected override PointF GetFOfMatrixByZoomPos(double zoomPos) + { + throw new NotImplementedException(); + } + + #endregion Implement +} \ No newline at end of file diff --git a/Cis.Application/Core/Component/MarkSeacher/Seacher/HiKMarkSeacher.cs b/Cis.Application/Core/Component/MarkSeacher/Seacher/HiKMarkSeacher.cs new file mode 100644 index 0000000..b841719 --- /dev/null +++ b/Cis.Application/Core/Component/MarkSeacher/Seacher/HiKMarkSeacher.cs @@ -0,0 +1,73 @@ +using System.Drawing; + +namespace Cis.Application.Core.Component.MarkSeacher; + +public class HiKMarkSearcher : MarkSearcherBase +{ + public HiKMarkSearcher(CameraCalcParams cameraCalcParams) : base(cameraCalcParams) + { + } + + #region Implement + + protected override double ConvertPanPosToAngle(double panPos) + { + double ret = 0.1 * HexToDecMa(panPos) / 180 * Math.PI; + ret = (ret >= 0) ? ret : (2 * Math.PI + ret); + return ret; + } + + protected override double ConvertTiltPosToAngle(double tiltPos, double tiltMinPos = 0) + { + double ndiff; + if (tiltPos > tiltMinPos) + + ndiff = HexToDecMa(tiltPos) - HexToDecMa(tiltMinPos); + else + ndiff = HexToDecMa(tiltPos) + HexToDecMa(13824) - HexToDecMa(tiltMinPos); + double ret = 0.1 * ndiff / 180 * Math.PI; + return ret; + } + + protected override PointF GetFOfMatrixByZoomPos(double zoomPos) + { + PointF pointF = new() + { + X = (float)GetFx(zoomPos), + Y = (float)GetFy(zoomPos) + }; + return pointF; + } + + #endregion Implement + + #region Util + + protected virtual double GetFx(double zoomPos) + { + CameraCalcParams calcParams = CameraCalcParams; + return calcParams.FocusX * GetZoomTag(zoomPos); + } + + protected virtual double GetFy(double zoomPos) + { + CameraCalcParams calcParams = CameraCalcParams; + return calcParams.FocusY * GetZoomTag(zoomPos); + } + + protected virtual double GetZoomTag(double zoomPos) + { + double ret = HexToDecMa(zoomPos) * 0.1; + ret = (ret - 1) * 0.65 + 1; + return ret; + } + + protected int HexToDecMa(double wHex) + { + int wHexInt = wHex.ToInt(); + int ret = (wHexInt / 4096) * 1000 + ((wHexInt % 4096) / 256) * 100 + ((wHexInt % 256) / 16) * 10 + (wHexInt % 16); + return ret; + } + + #endregion Util +} \ No newline at end of file diff --git a/Cis.Application/Core/Component/MarkSeacher/Seacher/MarkSearcherBase.cs b/Cis.Application/Core/Component/MarkSeacher/Seacher/MarkSearcherBase.cs new file mode 100644 index 0000000..bd6d8d2 --- /dev/null +++ b/Cis.Application/Core/Component/MarkSeacher/Seacher/MarkSearcherBase.cs @@ -0,0 +1,254 @@ +using EC.Helper.CameraSDK; +using MathNet.Numerics.LinearAlgebra; +using MathNet.Numerics.LinearAlgebra.Double; +using System.Collections.Concurrent; +using System.Drawing; + +namespace Cis.Application.Core.Component.MarkSeacher; + +public abstract class MarkSearcherBase +{ + #region Attr + + /// + /// 当前相机计算参数 + /// + protected CameraCalcParams CameraCalcParams { get; set; } + + /// + /// 相机当前位置的世界坐标转化为相机坐标矩阵 + /// + protected Matrix World2CameraMatrix { get; set; } + + /// + /// {cameraId, MarkLabelCalcParams} + /// + private ConcurrentDictionary MarkLabelCalcParamsDict { get; set; } = new(); + + #endregion Attr + + public MarkSearcherBase(CameraCalcParams cameraCalcParams) + { + CameraCalcParams = cameraCalcParams; + CalcSensor(); + World2CameraMatrix = ConvertWorldToCamera(cameraCalcParams); + } + + #region Calc + + /// + /// 判断相机是否进行了转动,转动了则需要重新计算世界坐标到相机坐标的转换矩阵 + /// + /// + /// + protected bool IsCameraRotate(PtzInfo newInfo) + { + bool ret = CameraCalcParams.PtzInfo.Pan != newInfo.Pan || + CameraCalcParams.PtzInfo.Tilt != newInfo.Tilt || + CameraCalcParams.PtzInfo.Zoom != newInfo.Zoom; + return ret; + } + + /// + /// 此方法计算在球机zoom值最小的情况下成像矩阵中的 f 本质为获取像元大小 + /// 尝试方案1:通过计算的方式来获取 + /// 尝试方案2:通过张正友相机标定的方法来生成成像矩阵中的 f + /// + protected void CalcSensor() + { + CameraCalcParams.FocusX /= CameraCalcParams.VideoWidth; + CameraCalcParams.FocusY /= CameraCalcParams.VideoHeight; + } + + /// + /// 获取将世界坐标系中的点转化为相机坐标系中的点的转换矩阵 + /// + /// + /// + protected Matrix ConvertWorldToCamera(CameraCalcParams cameraCalcParams) + { + double panAngle = ConvertPanPosToAngle(cameraCalcParams.PtzInfo.Pan); + double tiltAngle = ConvertTiltPosToAngle(cameraCalcParams.PtzInfo.Tilt); + PointF pointF = GetFOfMatrixByZoomPos(cameraCalcParams.PtzInfo.Zoom); + double sinPan = Math.Sin(panAngle); + double cosPan = Math.Cos(panAngle); + double sinTilt = Math.Sin(tiltAngle); + double cosTilt = Math.Cos(tiltAngle); + + Matrix fMatrix = new DenseMatrix(3, 3, new double[] + { + pointF.X, 0, 0, + 0, pointF.Y, 0, + 0, 0, 1, + }); + + Matrix rotateTiltMatrix = new DenseMatrix(3, 3, new double[] + { + 1, 0, 0, + 0, cosTilt, sinTilt, + 0, -sinTilt, cosTilt, + }); + + Matrix rotatePanMatrix = new DenseMatrix(3, 3, new double[] + { + cosPan, 0, sinPan, + 0, 1, 0, + -sinPan, 0, cosPan, + }); + + Matrix resultMatrix = fMatrix.Multiply(rotateTiltMatrix).Multiply(rotatePanMatrix); + return resultMatrix; + } + + /// + /// 获取将相机坐标系中的点转化为世界坐标系中的点的转换矩阵 + /// + /// + /// + protected Matrix ConvertCameraToWorld(MarkLabelCalcParams labelCalcParams) + { + double panAngle = ConvertPanPosToAngle(labelCalcParams.PtzInfo.Pan); + double tiltAngle = ConvertTiltPosToAngle(labelCalcParams.PtzInfo.Tilt); + PointF pointF = GetFOfMatrixByZoomPos(labelCalcParams.PtzInfo.Zoom); + double sinPan = Math.Sin(panAngle); + double cosPan = Math.Cos(panAngle); + double sinTilt = Math.Sin(tiltAngle); + double cosTilt = Math.Cos(tiltAngle); + + Matrix rotatePanMatrix = new DenseMatrix(3, 3, new double[] + { + cosPan, 0, -sinPan, + 0, 1, 0, + sinPan, 0, cosPan, + }); + + Matrix rotateTiltMatrix = new DenseMatrix(3, 3, new double[] + { + 1, 0, 0, + 0, cosTilt, -sinTilt, + 0, sinTilt, cosTilt, + }); + + Matrix fMatrix = new DenseMatrix(3, 3, new double[] + { + (1 / pointF.X), 0, 0, + 0, (1 / pointF.Y), 0, + 0, 0, 1, + }); + + Matrix resultMatrix = rotatePanMatrix.Multiply(rotateTiltMatrix).Multiply(fMatrix); + return resultMatrix; + } + + /// + /// 计算标签位置过程 + /// + /// + public List Search() + { + List resultList = new(); + + if (World2CameraMatrix == null || MarkLabelCalcParamsDict.IsEmpty) + return resultList; + + foreach (MarkLabelCalcParams item in MarkLabelCalcParamsDict.Values) + { + Matrix labelC2WMatrix = ConvertCameraToWorld(item); + Matrix labelPointMatrix = new DenseMatrix(3, 1, new double[] + { + (item.CanvasLeftRatio-0.5)*item.VideoWidth / CameraCalcParams.VideoWidth, + (item.CanvasTopRatio-0.5)*item.VideoHeight / CameraCalcParams.VideoHeight, + 1 + }); + Matrix lResult = labelC2WMatrix.Multiply(labelPointMatrix); + Matrix pResult = World2CameraMatrix.Multiply(lResult); + + double x = pResult[0, 0] / pResult[2, 0] + 0.5; + double y = pResult[1, 0] / pResult[2, 0] + 0.5; + MarkLabelCalcResult labelCalcResult; + if (x > 0.99 || x < 0.01 || y > 0.99 || y < 0.01 || pResult[2, 0] < 0) + labelCalcResult = MarkLabelCalcResult.New(item.Id, false); + else + labelCalcResult = MarkLabelCalcResult.New(item.Id, true, x, y); + resultList.Add(labelCalcResult); + } + return resultList; + } + + public async Task> SearchAsync() + { + return await Task.Run(Search); + } + + #endregion Calc + + #region Util + + /// + /// 将Pan值转化为角度 + /// + /// + protected abstract double ConvertPanPosToAngle(double panPos); + + /// + /// 将Tilt转化为角度 + /// + /// + protected abstract double ConvertTiltPosToAngle(double tiltPos, double tiltMinPos = 0); + + /// + /// 根据当前zoom值获取相机矩阵参数 + /// + /// + /// + protected abstract PointF GetFOfMatrixByZoomPos(double zoomPos); + + #endregion Util + + #region Base Method + + /// + /// 更新相机计算参数 + /// + /// + public void UpdateCameraCalcParams(PtzInfo ptzInfo) + { + if (IsCameraRotate(ptzInfo)) + { + CameraCalcParams.PtzInfo = ptzInfo; + World2CameraMatrix = ConvertWorldToCamera(CameraCalcParams); + } + } + + /// + /// 添加标签计算参数 + /// + /// + /// + public bool AddMarkLabelCalcParams(MarkLabelCalcParams labelCalcParams) + { + return MarkLabelCalcParamsDict.TryAdd(labelCalcParams.Id, labelCalcParams); + } + + /// + /// 删除标签计算参数 + /// + /// + /// + public bool DeleteMarkLabelCalcParams(long markLabelId) + { + return MarkLabelCalcParamsDict.TryRemove(markLabelId, out _); + } + + /// + /// 是否存在标签计算参数 + /// + /// + /// + public bool IsExistsMarkLabelCalcParams(long markLabelId) + { + return MarkLabelCalcParamsDict.ContainsKey(markLabelId); + } + + #endregion Base Method +} \ No newline at end of file diff --git a/Cis.Application/Core/Component/MarkSeacher/Seacher/YuShiMarkSeacher.cs b/Cis.Application/Core/Component/MarkSeacher/Seacher/YuShiMarkSeacher.cs new file mode 100644 index 0000000..2bd253f --- /dev/null +++ b/Cis.Application/Core/Component/MarkSeacher/Seacher/YuShiMarkSeacher.cs @@ -0,0 +1,29 @@ +using System.Drawing; + +namespace Cis.Application.Core.Component.MarkSeacher; + +public class YuShiMarkSearcher : MarkSearcherBase +{ + public YuShiMarkSearcher(CameraCalcParams cameraCalcParams) : base(cameraCalcParams) + { + } + + #region Implement + + protected override double ConvertPanPosToAngle(double panPos) + { + throw new NotImplementedException(); + } + + protected override double ConvertTiltPosToAngle(double tiltPos, double tiltMinPos = 0) + { + throw new NotImplementedException(); + } + + protected override PointF GetFOfMatrixByZoomPos(double zoomPos) + { + throw new NotImplementedException(); + } + + #endregion Implement +} \ No newline at end of file diff --git a/Cis.Application/Core/Entity/CameraCalcInfo.cs b/Cis.Application/Core/Entity/CameraCalcInfo.cs deleted file mode 100644 index 11b9191..0000000 --- a/Cis.Application/Core/Entity/CameraCalcInfo.cs +++ /dev/null @@ -1,181 +0,0 @@ -namespace Cis.Application.Core; - -/// -/// 相机计算信息 -/// -public class CameraCalcInfo -{ - /// - /// Camera Id - /// - public long Id { get; set; } - - /// - /// Ptz 信息 - /// - public PtzInfo PtzInfo { get; set; } - - /// - /// 视频的宽度 - /// - public int VideoWidth { get; set; } = 1920; - - /// - /// 视频的高度 - /// - public int VideoHeight { get; set; } = 1080; - - /// - /// 最小焦距 - /// - public double MinFocusX { get; set; } = 0f; - - public double MinFocusY { get; set; } = 0f; - - public static CameraCalcInfo New(long id, PtzInfo ptzInfo) - { - return new() - { - Id = id, - PtzInfo = ptzInfo - }; - } - - public static CameraCalcInfo New(long id, PtzInfo ptzInfo, int videoWidth, int videoHeight) - { - return new() - { - Id = id, - PtzInfo = ptzInfo, - VideoWidth = videoWidth, - VideoHeight = videoHeight - }; - } -} - -/// -/// Ptz 信息 -/// -public class PtzInfo -{ - /// - /// Pan 坐标 - /// - public double Pan { get; set; } - - /// - /// Tilt 坐标 - /// - public double Tilt { get; set; } - - /// - /// Zoom 坐标 - /// - public double Zoom { get; set; } - - public static PtzInfo New(double pan, double tilt, double zoom) - { - return new() - { - Pan = pan, - Tilt = tilt, - Zoom = zoom - }; - } -} - -/// -/// 标记标签计算信息 -/// -public class MarkLabelCalcInfo -{ - /// - /// MarkLabel Id - /// - public long Id { get; set; } - - /// - /// Ptz 信息 - /// - public PtzInfo PtzInfo { get; set; } - - /// - /// 视频宽度 - /// - public double VideoWidth { get; set; } - - /// - /// 视频高度 - /// - public double VideoHeight { get; set; } - - /// - /// 画布 left 距离比例 - /// - public double CanvasLeftRatio { get; set; } - - /// - /// 画布 top 距离比例 - /// - public double CanvasTopRatio { get; set; } - - public static MarkLabelCalcInfo New(long id, PtzInfo ptzInfo, double videoWidth, double videoHeight, double canvasLeftRatio, double canvasTopRatio) - { - return new() - { - Id = id, - PtzInfo = ptzInfo, - VideoWidth = videoWidth, - VideoHeight = videoHeight, - CanvasLeftRatio = canvasLeftRatio, - CanvasTopRatio = canvasTopRatio - }; - } -} - -/// -/// 标记标签计算结果 -/// -public class MarkLabelCalcResult -{ - /// - /// MarkLabel Id - /// - public long Id { get; set; } - - /// - /// true 显示(在当前视频画面里面) - /// false 不显示(不在当前视频画面里面) - /// - public bool InFlag { get; set; } - - /// - /// 画布 left 距离比例 - /// - public double CanvasLeftRatio { get; set; } - - /// - /// 画布 top 距离比例 - /// - public double CanvasTopRatio { get; set; } - - public static MarkLabelCalcResult New(long id, bool inFlag) - { - return new() - { - Id = id, - InFlag = inFlag - }; - } - - public static MarkLabelCalcResult New(long id, bool inFlag, double canvasLeftRatio, double canvasTopRatio) - { - return new() - { - Id = id, - InFlag = inFlag, - CanvasLeftRatio = canvasLeftRatio, - CanvasTopRatio = canvasTopRatio - }; - } -} \ No newline at end of file diff --git a/Cis.Application/Core/Service/MarkSearchService.cs b/Cis.Application/Core/Service/MarkSearchService.cs index 47654d9..59cdc34 100644 --- a/Cis.Application/Core/Service/MarkSearchService.cs +++ b/Cis.Application/Core/Service/MarkSearchService.cs @@ -1,60 +1,62 @@ -using Cis.Application.Cm; +using Cis.Application.Core.Component.MarkSeacher; namespace Cis.Application.Core; -[ApiDescriptionSettings(CmInfo.GroupName, Order = CmInfo.GroupOrder)] +[ApiDescriptionSettings(CoreInfo.GroupName, Order = CoreInfo.GroupOrder)] public class MarkSearchService : IDynamicApiController, ITransient { - #region Attr - - private CameraDataCenter _cameraDataCenter { get; set; } - - #endregion Attr - - public MarkSearchService(CameraDataCenter cameraDataCenter) - { - _cameraDataCenter = cameraDataCenter; - } - - [HttpPost] - public async Task ActivateSearcher([FromForm] long cameraId) - { - return await _cameraDataCenter.ActivateSearcherAsync(cameraId); - } - - [HttpPost] - public async Task DeActivateSearcher([FromForm] long cameraId) - { - return await _cameraDataCenter.DeActivateSearcherAsync(cameraId); - } - - [HttpGet] - public async Task IsExistSearcher(long cameraId) - { - return await _cameraDataCenter.IsExistSearcherAsync(cameraId); - } - - [HttpPost] - public async Task ActivateMarkLabel([FromForm] long cameraId, [FromForm] long markLabelId) - { - return await _cameraDataCenter.ActivateMarkLabelAsync(cameraId, markLabelId); - } - - [HttpPost] - public async Task DeactivateMarkLabel([FromForm] long cameraId, [FromForm] long markLabelId) - { - return await _cameraDataCenter.DeactivateMarkLabelAsync(cameraId, markLabelId); - } - - [HttpGet] - public async Task IsExistMarkLabel(long cameraId,long markLabelId) - { - return await _cameraDataCenter.IsExistMarkLabelAysnc(cameraId, markLabelId); - } - - [HttpGet] - public async Task> GetMarkLabelCalcResultList(long cameraId) - { - return await _cameraDataCenter.GetMarkLabelCalcResultListAsync(cameraId); - } + #region Attr + + private readonly CameraDataCenter _cameraDataCenter; + private readonly IMarkSearcherServer _markSearcherServer; + + #endregion Attr + + public MarkSearchService(CameraDataCenter cameraDataCenter, IMarkSearcherServer markSearcherServer) + { + _cameraDataCenter = cameraDataCenter; + _markSearcherServer = markSearcherServer; + } + + [HttpPost] + public async Task ActivateSearcher([FromForm] long cameraId) + { + return await _markSearcherServer.ActivateSearcherAsync(cameraId); + } + + [HttpPost] + public async Task DeactivateSearcher([FromForm] long cameraId) + { + return await _markSearcherServer.DeactivateSearcherAsync(cameraId); + } + + [HttpGet] + public async Task IsExistsSearcher(long cameraId) + { + return await _markSearcherServer.IsExistsSearcherAsync(cameraId); + } + + [HttpPost] + public async Task ActivateMarkLabel([FromForm] long cameraId, [FromForm] long markLabelId) + { + return await _markSearcherServer.ActivateMarkLabelAsync(cameraId, markLabelId); + } + + [HttpPost] + public async Task DeactivateMarkLabel([FromForm] long cameraId, [FromForm] long markLabelId) + { + return await _markSearcherServer.DeactivateMarkLabelAsync(cameraId, markLabelId); + } + + [HttpGet] + public async Task IsExistsMarkLabel(long cameraId, long markLabelId) + { + return await _markSearcherServer.IsExistsMarkLabelAsync(cameraId, markLabelId); + } + + [HttpGet] + public async Task> GetMarkLabelCalcResultList(long cameraId) + { + return await _cameraDataCenter.GetMarkLabelCalcResultListAsync(cameraId); + } } \ No newline at end of file diff --git a/Cis.Application/GlobalUsings.cs b/Cis.Application/GlobalUsings.cs index 9320314..76b15eb 100644 --- a/Cis.Application/GlobalUsings.cs +++ b/Cis.Application/GlobalUsings.cs @@ -3,7 +3,6 @@ global using Furion; global using Furion.ConfigurableOptions; global using Furion.DependencyInjection; global using Furion.DynamicApiController; -global using Furion.FriendlyException; global using Microsoft.AspNetCore.Mvc; global using SqlSugar; global using System.ComponentModel.DataAnnotations; \ No newline at end of file diff --git a/Cis.Application/Startup.cs b/Cis.Application/Startup.cs index bc134be..f9a3256 100644 --- a/Cis.Application/Startup.cs +++ b/Cis.Application/Startup.cs @@ -1,4 +1,7 @@ using Cis.Application.Core; +using Cis.Application.Core.Component.CameraSDK; +using Cis.Application.Core.Component.MarkSeacher; +using Cis.Application.Core.Component.PtzServer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; @@ -8,24 +11,25 @@ namespace Cis.Application; [AppStartup(100)] public class Startup : AppStartup { - /// - /// 配置应用所需服务,在该方法中可以添加应用所需要的功能或服务 - /// - /// - public void ConfigureServices(IServiceCollection services) - { - services.AddConfigurableOptions(); - services.AddConfigurableOptions(); + /// + /// 配置应用所需服务,在该方法中可以添加应用所需要的功能或服务 + /// + /// + public void ConfigureServices(IServiceCollection services) + { + services.AddConfigurableOptions(); - services.AddSingleton(new CameraDataCenter()); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(typeof(CameraDataCenter)); } - /// - /// 配置应用请求处理管道 - /// - /// - /// - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - } + /// + /// 配置应用请求处理管道 + /// + /// + /// + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + } } \ No newline at end of file diff --git a/Cis.Application/Sys/Common/SysInfo.cs b/Cis.Application/Sys/Common/SysInfo.cs index f68a522..326f615 100644 --- a/Cis.Application/Sys/Common/SysInfo.cs +++ b/Cis.Application/Sys/Common/SysInfo.cs @@ -5,50 +5,50 @@ /// public class SysInfo { - #region Api Info + #region Api Info - /// - /// Api 分组名 - /// - public const string GroupName = "System"; + /// + /// Api 分组名 + /// + public const string GroupName = "System"; - /// - /// Api 分组排序 - /// - public const int GroupOrder = 100; + /// + /// Api 分组排序 + /// + public const int GroupOrder = 100; - #endregion Api Info + #endregion Api Info - #region Database Info + #region Database Info - /// - /// 数据库标识 - /// - public const string DbName = SqlSugarConst.DefaultConfigId; + /// + /// 数据库标识 + /// + public const string DbName = SqlSugarConst.DefaultConfigId; - #endregion Database Info + #endregion Database Info - #region Table Info + #region Table Info - /// - /// SysDictType 表名 - /// - public const string SysDictTypeTbName = "sys_dict_type"; + /// + /// SysDictType 表名 + /// + public const string SysDictTypeTbName = "sys_dict_type"; - /// - /// SysDictType 表描述 - /// - public const string SysDictTypeTbDesc = "系统字典类型表"; + /// + /// SysDictType 表描述 + /// + public const string SysDictTypeTbDesc = "系统字典类型表"; - /// - /// SysDataType 表名 - /// - public const string SysDictDataTbName = "sys_data_data"; + /// + /// SysDataType 表名 + /// + public const string SysDictDataTbName = "sys_data_data"; - /// - /// SysDataType 表描述 - /// - public const string SysDictDataTbDesc = "系统字典值表"; + /// + /// SysDataType 表描述 + /// + public const string SysDictDataTbDesc = "系统字典值表"; - #endregion Table Info + #endregion Table Info } \ No newline at end of file diff --git a/Cis.Application/Sys/Entity/SysDictType.cs b/Cis.Application/Sys/Entity/SysDictType.cs index 5c325fc..00e5173 100644 --- a/Cis.Application/Sys/Entity/SysDictType.cs +++ b/Cis.Application/Sys/Entity/SysDictType.cs @@ -6,36 +6,36 @@ [SugarTable(SysInfo.SysDictTypeTbName, SysInfo.SysDictTypeTbDesc)] public class SysDictType : EntityBase { - /// - /// 名称 - /// - [SugarColumn(ColumnDescription = "名称", Length = 64)] - [Required, MaxLength(64)] - public string Name { get; set; } + /// + /// 名称 + /// + [SugarColumn(ColumnDescription = "名称", Length = 64)] + [Required, MaxLength(64)] + public string Name { get; set; } - /// - /// 编码 - /// - [SugarColumn(ColumnDescription = "编码", Length = 64)] - [Required, MaxLength(64)] - public string Code { get; set; } + /// + /// 编码 + /// + [SugarColumn(ColumnDescription = "编码", Length = 64)] + [Required, MaxLength(64)] + public string Code { get; set; } - /// - /// 排序 - /// - [SugarColumn(ColumnDescription = "排序")] - public int Order { get; set; } + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int Order { get; set; } - /// - /// 备注 - /// - [SugarColumn(ColumnDescription = "备注", Length = 256)] - [MaxLength(256)] - public string Remark { get; set; } + /// + /// 备注 + /// + [SugarColumn(ColumnDescription = "备注", Length = 256)] + [MaxLength(256)] + public string Remark { get; set; } - /// - /// 状态 - /// - [SugarColumn(ColumnDescription = "状态")] - public StatusEnum Status { get; set; } = StatusEnum.Enable; + /// + /// 状态 + /// + [SugarColumn(ColumnDescription = "状态")] + public StatusEnum Status { get; set; } = StatusEnum.Enable; } \ No newline at end of file diff --git a/Cis.Application/Sys/Service/SysDictDataService.cs b/Cis.Application/Sys/Service/SysDictDataService.cs index ccf6223..59b9890 100644 --- a/Cis.Application/Sys/Service/SysDictDataService.cs +++ b/Cis.Application/Sys/Service/SysDictDataService.cs @@ -8,54 +8,54 @@ namespace Cis.Application.Sys; [ApiDescriptionSettings(SysInfo.GroupName, Order = SysInfo.GroupOrder)] public class SysDictDataService : IDynamicApiController, ITransient { - private readonly SqlSugarRepository _sysDictDataRep; - - public SysDictDataService(SqlSugarRepository sysDictDataRep) - { - _sysDictDataRep = sysDictDataRep; - } - - [HttpPost] - public async Task Add([FromForm] SysDictData entity) - { - return await _sysDictDataRep.InsertAsync(entity); - } - - [HttpPost] - public async Task Update([FromForm] SysDictData entity) - { - return await _sysDictDataRep.UpdateAsync(entity); - } - - [HttpPost] - public async Task Delete([FromForm] SysDictData entity) - { - return await _sysDictDataRep.DeleteAsync(entity); - } - - [HttpGet] - public async Task Get(long id) - { - SysDictData entity = await _sysDictDataRep.GetByIdAsync(id); - return entity; - } - - [HttpGet] - public async Task> GetList(string queryJson) - { - JObject queryObj = queryJson.ToJObject(); - List list = await _sysDictDataRep.AsQueryable() - .ToListAsync(); - return list; - } - - [HttpGet] - public async Task> GetPageList(string queryJson, string pagination) - { - Pagination pageObj = pagination.ToObject(); - JObject queryObj = queryJson.ToJObject(); - List list = await _sysDictDataRep.AsQueryable() - .ToPageListAsync(pageObj.Index, pageObj.Size); - return list; - } + private readonly SqlSugarRepository _baseRep; + + public SysDictDataService(SqlSugarRepository baseRep) + { + _baseRep = baseRep; + } + + [HttpPost] + public async Task Add([FromForm] SysDictData entity) + { + return await _baseRep.InsertAsync(entity); + } + + [HttpPost] + public async Task Update([FromForm] SysDictData entity) + { + return await _baseRep.UpdateAsync(entity); + } + + [HttpPost] + public async Task Delete([FromForm] SysDictData entity) + { + return await _baseRep.DeleteAsync(entity); + } + + [HttpGet] + public async Task Get(long id) + { + SysDictData entity = await _baseRep.GetByIdAsync(id); + return entity; + } + + [HttpGet] + public async Task> GetList(string queryJson) + { + JObject queryObj = queryJson.ToJObject(); + List list = await _baseRep.AsQueryable() + .ToListAsync(); + return list; + } + + [HttpGet] + public async Task> GetPageList(string queryJson, string pagination) + { + Pagination pageObj = pagination.ToObject(); + JObject queryObj = queryJson.ToJObject(); + List list = await _baseRep.AsQueryable() + .ToPageListAsync(pageObj.Index, pageObj.Size); + return list; + } } \ No newline at end of file diff --git a/Cis.Application/Sys/Service/SysDictTypeService.cs b/Cis.Application/Sys/Service/SysDictTypeService.cs index d3805a3..a6179e0 100644 --- a/Cis.Application/Sys/Service/SysDictTypeService.cs +++ b/Cis.Application/Sys/Service/SysDictTypeService.cs @@ -1,5 +1,4 @@ -using Cis.Application.Cm; -using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Linq; namespace Cis.Application.Sys; @@ -9,55 +8,54 @@ namespace Cis.Application.Sys; [ApiDescriptionSettings(SysInfo.GroupName, Order = SysInfo.GroupOrder)] public class SysDictTypeService : IDynamicApiController, ITransient { - private readonly SqlSugarRepository _sysDictTypeRep; - - public SysDictTypeService(SqlSugarRepository sysDictTypeRep) - { - _sysDictTypeRep = sysDictTypeRep; - } - - [HttpPost] - public async Task Add([FromForm] SysDictType entity) - { - return await _sysDictTypeRep.InsertAsync(entity); - } - - [HttpPost] - public async Task Update([FromForm] SysDictType entity) - { - return await _sysDictTypeRep.UpdateAsync(entity); - } - - [HttpPost] - public async Task Delete([FromForm] SysDictType entity) - { - return await _sysDictTypeRep.DeleteAsync(entity); - } - - [HttpGet] - public async Task Get(long id) - { - SysDictType entity = await _sysDictTypeRep.GetByIdAsync(id); - return entity; - } - - [HttpGet] - public async Task> GetList(string queryJson) - { - JObject queryObj = queryJson.ToJObject(); - List list = await _sysDictTypeRep.AsQueryable() - .ToListAsync(); - return list; - } - - [HttpGet] - public async Task> GetPageList(string queryJson, string pagination) - { - Pagination pageObj = pagination.ToObject(); - JObject queryObj = queryJson.ToJObject(); - List list = await _sysDictTypeRep.AsQueryable() - .ToPageListAsync(pageObj.Index, pageObj.Size); - return list; - } - + private readonly SqlSugarRepository _baseRep; + + public SysDictTypeService(SqlSugarRepository baseRep) + { + _baseRep = baseRep; + } + + [HttpPost] + public async Task Add([FromForm] SysDictType entity) + { + return await _baseRep.InsertAsync(entity); + } + + [HttpPost] + public async Task Update([FromForm] SysDictType entity) + { + return await _baseRep.UpdateAsync(entity); + } + + [HttpPost] + public async Task Delete([FromForm] SysDictType entity) + { + return await _baseRep.DeleteAsync(entity); + } + + [HttpGet] + public async Task Get(long id) + { + SysDictType entity = await _baseRep.GetByIdAsync(id); + return entity; + } + + [HttpGet] + public async Task> GetList(string queryJson) + { + JObject queryObj = queryJson.ToJObject(); + List list = await _baseRep.AsQueryable() + .ToListAsync(); + return list; + } + + [HttpGet] + public async Task> GetPageList(string queryJson, string pagination) + { + Pagination pageObj = pagination.ToObject(); + JObject queryObj = queryJson.ToJObject(); + List list = await _baseRep.AsQueryable() + .ToPageListAsync(pageObj.Index, pageObj.Size); + return list; + } } \ No newline at end of file diff --git a/Cis.Application/Tb/Common/TbInfo.cs b/Cis.Application/Tb/Common/TbInfo.cs deleted file mode 100644 index b2e4830..0000000 --- a/Cis.Application/Tb/Common/TbInfo.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Cis.Application.Tb; - -public class TbInfo -{ - #region Database Info - - /// - /// 数据库标识 - /// - public const string DbName = "serverdb"; - - #endregion Database Info - - #region Table Info - - /// - /// TbPtzCamera 表名 - /// - public const string TbPtzCameraTbName = "tb_ptzcamera"; - - #endregion Table Info -} \ No newline at end of file diff --git a/Cis.Application/Tb/Entity/TbPtzCamera.cs b/Cis.Application/Tb/Entity/TbPtzCamera.cs deleted file mode 100644 index 6f75ea8..0000000 --- a/Cis.Application/Tb/Entity/TbPtzCamera.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Cis.Application.Tb; - -[SugarTable(TbInfo.TbPtzCameraTbName)] -[Tenant(TbInfo.DbName)] -public class TbPtzCamera -{ - public int Id { get; set; } - - public int Type { get; set; } - - public string Ip { get; set; } - - public int Port { get; set; } - - public string User { get; set; } - - public string Pass { get; set; } - - public int CameraId { get; set; } - - public double PanPosition { get; set; } - - public double TitlePosition { get; set; } - - public double ZoomPosition { get; set; } - - public byte Request { get; set; } -} \ No newline at end of file diff --git a/Cis.Application/Tb/Service/TbPtzCameraService.cs b/Cis.Application/Tb/Service/TbPtzCameraService.cs deleted file mode 100644 index bf69a64..0000000 --- a/Cis.Application/Tb/Service/TbPtzCameraService.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Newtonsoft.Json.Linq; - -namespace Cis.Application.Tb; - -public class TbPtzCameraService : ITransient -{ - private readonly SqlSugarRepository _tbPtzCameraRep; - - public TbPtzCameraService(SqlSugarRepository tbPtzCameraRep) - { - _tbPtzCameraRep = tbPtzCameraRep; - } - - [HttpPost] - public async Task Add([FromForm] TbPtzCamera entity) - { - return await _tbPtzCameraRep.InsertAsync(entity); - } - - [HttpPost] - public async Task Update([FromForm] TbPtzCamera entity) - { - return await _tbPtzCameraRep.UpdateAsync(entity); - } - - [HttpPost] - public async Task Delete([FromForm] TbPtzCamera entity) - { - return await _tbPtzCameraRep.DeleteAsync(entity); - } - - [HttpGet] - public async Task Get(int id) - { - TbPtzCamera entity = await _tbPtzCameraRep.GetByIdAsync(id); - return entity; - } - - [HttpGet] - public async Task> GetList(string queryJson = "") - { - JObject queryObj = !string.IsNullOrEmpty(queryJson) ? queryJson.ToJObject() : default; - List list = await _tbPtzCameraRep.AsQueryable() - .ToListAsync(); - return list; - } - - [HttpGet] - public async Task> GetPageList(string pagination, string queryJson = "") - { - Pagination pageObj = pagination.ToObject(); - JObject queryObj = queryJson.ToJObject(); - List list = await _tbPtzCameraRep.AsQueryable() - .ToPageListAsync(pageObj.Index, pageObj.Size); - return list; - } -} \ No newline at end of file diff --git a/Cis.Core/Cache/CacheSetup.cs b/Cis.Core/Cache/CacheSetup.cs index 311cbc0..3e847ed 100644 --- a/Cis.Core/Cache/CacheSetup.cs +++ b/Cis.Core/Cache/CacheSetup.cs @@ -1,28 +1,21 @@ -using NewLife.Caching; +using StackExchange.Redis; namespace Cis.Core; public static class CacheSetup { - /// - /// 缓存注册(新生命Redis组件) - /// - /// - public static void AddCache(this IServiceCollection services) - { - services.AddSingleton(options => - { - var cacheOptions = App.GetOptions(); - if (cacheOptions.CacheType == CacheTypeEnum.Redis.ToString()) - { - var redis = new Redis(); - redis.Init(cacheOptions.RedisConnectionString); - return redis; - } - else - { - return Cache.Default; - } - }); - } + /// + /// Redis 缓存注册 + /// + /// + public static void AddCache(this IServiceCollection services) + { + services.AddSingleton(options => + { + var redisOptions = App.GetOptions(); + ConnectionMultiplexer multiplexer = ConnectionMultiplexer.Connect(redisOptions.ConnectionString); + IDatabase cache = multiplexer.GetDatabase(); + return cache; + }); + } } \ No newline at end of file diff --git a/Cis.Core/Cache/SqlSugarCache.cs b/Cis.Core/Cache/SqlSugarCache.cs index 24e6da3..501cca6 100644 --- a/Cis.Core/Cache/SqlSugarCache.cs +++ b/Cis.Core/Cache/SqlSugarCache.cs @@ -7,45 +7,45 @@ namespace Cis.Core; /// public class SqlSugarCache : ICacheService, ISingleton { - private static readonly ICache _cache = NewLife.Caching.Cache.Default; - - public void Add(string key, V value) - { - _cache.Set(key, value); - } - - public void Add(string key, V value, int cacheDurationInSeconds) - { - _cache.Set(key, value, cacheDurationInSeconds); - } - - public bool ContainsKey(string key) - { - return _cache.ContainsKey(key); - } - - public V Get(string key) - { - return _cache.Get(key); - } - - public IEnumerable GetAllKey() - { - return _cache.Keys; - } - - public V GetOrCreate(string cacheKey, Func create, int cacheDurationInSeconds = int.MaxValue) - { - if (!_cache.TryGetValue(cacheKey, out V value)) - { - value = create(); - _cache.Set(cacheKey, value, cacheDurationInSeconds); - } - return value; - } - - public void Remove(string key) - { - _cache.Remove(key); - } + private static readonly ICache _cache = NewLife.Caching.Cache.Default; + + public void Add(string key, V value) + { + _cache.Set(key, value); + } + + public void Add(string key, V value, int cacheDurationInSeconds) + { + _cache.Set(key, value, cacheDurationInSeconds); + } + + public bool ContainsKey(string key) + { + return _cache.ContainsKey(key); + } + + public V Get(string key) + { + return _cache.Get(key); + } + + public IEnumerable GetAllKey() + { + return _cache.Keys; + } + + public V GetOrCreate(string cacheKey, Func create, int cacheDurationInSeconds = int.MaxValue) + { + if (!_cache.TryGetValue(cacheKey, out V value)) + { + value = create(); + _cache.Set(cacheKey, value, cacheDurationInSeconds); + } + return value; + } + + public void Remove(string key) + { + _cache.Remove(key); + } } \ No newline at end of file diff --git a/Cis.Core/Cis.Core.csproj b/Cis.Core/Cis.Core.csproj index 27ffbae..82ea3ed 100644 --- a/Cis.Core/Cis.Core.csproj +++ b/Cis.Core/Cis.Core.csproj @@ -6,6 +6,12 @@ Cis.Core.xml + + + + + + @@ -18,20 +24,16 @@ - + - - - + + - + - - - - + diff --git a/Cis.Core/Cis.Core.xml b/Cis.Core/Cis.Core.xml index 30c9dce..6a27031 100644 --- a/Cis.Core/Cis.Core.xml +++ b/Cis.Core/Cis.Core.xml @@ -4,14 +4,9 @@ Cis.Core - - - 非实体表特性 - - - 缓存注册(新生命Redis组件) + Redis 缓存注册 @@ -20,6 +15,11 @@ SqlSugar二级缓存(必须是内存缓存) + + + 非实体表特性 + + 默认数据库标识 @@ -289,21 +289,6 @@ - - - 缓存配置选项 - - - - - 缓存类型 - - - - - Redis连接字符串 - - 数据库配置选项 @@ -319,6 +304,16 @@ 启用库表初始化 + + + Redis 配置选项 + + + + + Redis 连接字符串 + + 雪花Id配置选项 diff --git a/Cis.Core/Attribute/NotTableAttribute.cs b/Cis.Core/Common/Attribute/NotTableAttribute.cs similarity index 100% rename from Cis.Core/Attribute/NotTableAttribute.cs rename to Cis.Core/Common/Attribute/NotTableAttribute.cs diff --git a/Cis.Core/Common/Const/SqlSugarConst.cs b/Cis.Core/Common/Const/SqlSugarConst.cs new file mode 100644 index 0000000..23486cc --- /dev/null +++ b/Cis.Core/Common/Const/SqlSugarConst.cs @@ -0,0 +1,14 @@ +namespace Cis.Core; + +public class SqlSugarConst +{ + /// + /// 默认数据库标识 + /// + public const string DefaultConfigId = "Cis"; + + /// + /// 默认表主键 + /// + public const string DefaultPrimaryKey = "Id"; +} \ No newline at end of file diff --git a/Cis.Core/Common/Entity/EntityBase.cs b/Cis.Core/Common/Entity/EntityBase.cs new file mode 100644 index 0000000..dc19a5e --- /dev/null +++ b/Cis.Core/Common/Entity/EntityBase.cs @@ -0,0 +1,61 @@ +namespace Cis.Core; + +/// +/// 框架实体基类Id +/// +public abstract class EntityBaseId +{ + /// + /// 雪花Id + /// + [SugarColumn(ColumnDescription = "Id", IsPrimaryKey = true, IsIdentity = false)] + public virtual long Id { get; set; } +} + +/// +/// 框架实体基类 +/// +public abstract class EntityBase : EntityBaseId +{ + /// + /// 创建时间 + /// + [SugarColumn(ColumnDescription = "创建时间")] + public virtual DateTime? CreateTime { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnDescription = "更新时间")] + public virtual DateTime? UpdateTime { get; set; } + + /// + /// 创建者Id + /// + [SugarColumn(ColumnDescription = "创建者Id")] + public virtual long? CreateUserId { get; set; } + + /// + /// 修改者Id + /// + [SugarColumn(ColumnDescription = "修改者Id")] + public virtual long? UpdateUserId { get; set; } + + /// + /// 软删除 + /// + [SugarColumn(ColumnDescription = "软删除")] + public virtual bool IsDelete { get; set; } = false; +} + +/// +/// 业务数据实体基类(数据权限) +/// +public abstract class DataEntityBase : EntityBase +{ + /// + /// 创建者部门Id + /// + [SugarColumn(ColumnDescription = "创建者部门Id")] + public virtual long? CreateOrgId { get; set; } +} \ No newline at end of file diff --git a/Cis.Core/Common/Entity/Pagination.cs b/Cis.Core/Common/Entity/Pagination.cs new file mode 100644 index 0000000..ace4fab --- /dev/null +++ b/Cis.Core/Common/Entity/Pagination.cs @@ -0,0 +1,47 @@ +namespace Cis.Core; + +public class Pagination +{ + /// + /// 当前页 + /// + public virtual int Index { get; set; } + + /// + /// 页码容量 + /// + public virtual int Size { get; set; } + + /// + /// 排序字段 + /// + public virtual string Field { get; set; } + + /// + /// 排序方向 + /// + public virtual string Order { get; set; } + + /// + /// 总记录数 + /// + public virtual int Total { get; set; } + + /// + /// 页码数 + /// + public virtual int Number + { + get + { + if (Size > 0) + { + return ((Size % Total) == 0) ? (Size / Total) : ((Size / Total) + 1); + } + else + { + return 0; + } + } + } +} \ No newline at end of file diff --git a/Cis.Core/Common/Entity/RespParamProvider.cs b/Cis.Core/Common/Entity/RespParamProvider.cs new file mode 100644 index 0000000..4d3d31d --- /dev/null +++ b/Cis.Core/Common/Entity/RespParamProvider.cs @@ -0,0 +1,128 @@ +namespace Cis.Core; + +/// +/// 全局规范化结果 +/// +[UnifyModel(typeof(RespParam<>))] +public class RespParamProvider : IUnifyResultProvider +{ + /// + /// 异常返回值 + /// + /// + /// + /// + public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata) + { + return new JsonResult(RESTfulResult(metadata.StatusCode, data: metadata.Data, errors: metadata.Errors)); + } + + /// + /// 成功返回值 + /// + /// + /// + /// + public IActionResult OnSucceeded(ActionExecutedContext context, object data) + { + return new JsonResult(RESTfulResult(StatusCodes.Status200OK, true, data)); + } + + /// + /// 验证失败返回值 + /// + /// + /// + /// + public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata) + { + return new JsonResult(RESTfulResult(metadata.StatusCode ?? StatusCodes.Status400BadRequest, data: metadata.Data, errors: metadata.ValidationResult)); + } + + /// + /// 特定状态码返回值 + /// + /// + /// + /// + /// + public async Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings) + { + // 设置响应状态码 + UnifyContext.SetResponseStatusCodes(context, statusCode, unifyResultSettings); + + switch (statusCode) + { + // 处理 401 状态码 + case StatusCodes.Status401Unauthorized: + await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "401 登录已过期,请重新登录"), + App.GetOptions()?.JsonSerializerOptions); + break; + // 处理 403 状态码 + case StatusCodes.Status403Forbidden: + await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "403 禁止访问,没有权限"), + App.GetOptions()?.JsonSerializerOptions); + break; + + default: break; + } + } + + /// + /// 返回 RESTful 风格结果集 + /// + /// + /// + /// + /// + /// + private static RespParam RESTfulResult(int statusCode, bool succeeded = default, object data = default, object errors = default) + { + return new RespParam + { + Code = statusCode, + Message = errors is string str ? str : JSON.Serialize(errors), + Data = data, + Type = succeeded ? "success" : "error", + Extras = UnifyContext.Take(), + Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + }; + } +} + +/// +/// 全局返回结果 +/// +/// +public class RespParam +{ + /// + /// 状态码 + /// + public int Code { get; set; } + + /// + /// 类型success、warning、error + /// + public string Type { get; set; } + + /// + /// 错误信息 + /// + public string Message { get; set; } + + /// + /// 数据 + /// + public T Data { get; set; } + + /// + /// 附加数据 + /// + public object Extras { get; set; } + + /// + /// 时间戳 + /// + public long Timestamp { get; set; } +} \ No newline at end of file diff --git a/Cis.Core/Enum/CacheTypeEnum.cs b/Cis.Core/Common/Enum/CacheTypeEnum.cs similarity index 100% rename from Cis.Core/Enum/CacheTypeEnum.cs rename to Cis.Core/Common/Enum/CacheTypeEnum.cs diff --git a/Cis.Core/Common/Enum/StatusEnum.cs b/Cis.Core/Common/Enum/StatusEnum.cs new file mode 100644 index 0000000..9cda263 --- /dev/null +++ b/Cis.Core/Common/Enum/StatusEnum.cs @@ -0,0 +1,19 @@ +namespace Cis.Core; + +/// +/// 通用状态枚举 +/// +public enum StatusEnum +{ + /// + /// 停用 + /// + [Description("停用")] + Disable = 0, + + /// + /// 启用 + /// + [Description("启用")] + Enable = 1, +} \ No newline at end of file diff --git a/Cis.Core/Common/Extension/ObjectExtension.cs b/Cis.Core/Common/Extension/ObjectExtension.cs new file mode 100644 index 0000000..4afe194 --- /dev/null +++ b/Cis.Core/Common/Extension/ObjectExtension.cs @@ -0,0 +1,141 @@ +using Newtonsoft.Json.Linq; +using System.Text; + +namespace Cis.Core; + +/// +/// 对象拓展 +/// +[SuppressSniffer] +public static class ObjectExtension +{ + /// + /// 判断类型是否实现某个泛型 + /// + /// 类型 + /// 泛型类型 + /// bool + public static bool HasImplementedRawGeneric(this Type type, Type generic) + { + // 检查接口类型 + var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType); + if (isTheRawGenericType) return true; + + // 检查类型 + while (type != null && type != typeof(object)) + { + isTheRawGenericType = IsTheRawGenericType(type); + if (isTheRawGenericType) return true; + type = type.BaseType; + } + + return false; + + // 判断逻辑 + bool IsTheRawGenericType(Type type) => generic == (type.IsGenericType ? type.GetGenericTypeDefinition() : type); + } + + /// + /// 将字典转化为QueryString格式 + /// + /// + /// + /// + public static string ToQueryString(this Dictionary dict, bool urlEncode = true) + { + return string.Join("&", dict.Select(p => $"{(urlEncode ? p.Key?.UrlEncode() : "")}={(urlEncode ? p.Value?.UrlEncode() : "")}")); + } + + /// + /// 将字符串URL编码 + /// + /// + /// + public static string UrlEncode(this string str) + { + return string.IsNullOrEmpty(str) ? "" : System.Web.HttpUtility.UrlEncode(str, Encoding.UTF8); + } + + /// + /// List转DataTable + /// + /// + /// + /// + public static DataTable ToDataTable(this List list) + { + DataTable result = new(); + if (list.Count > 0) + { + // result.TableName = list[0].GetType().Name; // 表名赋值 + PropertyInfo[] propertys = list[0].GetType().GetProperties(); + foreach (PropertyInfo pi in propertys) + { + Type colType = pi.PropertyType; + if (colType.IsGenericType && colType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + colType = colType.GetGenericArguments()[0]; + } + if (IsIgnoreColumn(pi)) + continue; + result.Columns.Add(pi.Name, colType); + } + for (int i = 0; i < list.Count; i++) + { + ArrayList tempList = new(); + foreach (PropertyInfo pi in propertys) + { + if (IsIgnoreColumn(pi)) + continue; + object obj = pi.GetValue(list[i], null); + tempList.Add(obj); + } + object[] array = tempList.ToArray(); + result.LoadDataRow(array, true); + } + } + return result; + } + + /// + /// 对象序列化成Json字符串 + /// + /// + /// + public static string ToJson(object obj) + { + return JSON.GetJsonSerializer().Serialize(obj); + } + + /// + /// Json字符串反序列化成对象 + /// + /// + /// + /// + public static T ToObject(this string json) + { + return JSON.GetJsonSerializer().Deserialize(json); + } + + /// + /// 字串反序列化成linq对象 + /// + /// 字串 + /// + public static JObject ToJObject(this string Json) + { + return string.IsNullOrEmpty(Json) ? JObject.Parse("{}") : JObject.Parse(Json.Replace(" ", "")); + } + + /// + /// 排除SqlSugar忽略的列 + /// + /// + /// + private static bool IsIgnoreColumn(PropertyInfo pi) + { + var sc = pi.GetCustomAttributes(false).FirstOrDefault(u => u.IsIgnore == true); + return sc != null; + } +} \ No newline at end of file diff --git a/Cis.Core/Common/Option/DbConnectionOptions.cs b/Cis.Core/Common/Option/DbConnectionOptions.cs new file mode 100644 index 0000000..cfe38d0 --- /dev/null +++ b/Cis.Core/Common/Option/DbConnectionOptions.cs @@ -0,0 +1,20 @@ +namespace Cis.Core; + +/// +/// 数据库配置选项 +/// +public sealed class DbConnectionOptions : IConfigurableOptions +{ + /// + /// 数据库集合 + /// + public List ConnectionConfigs { get; set; } +} + +public sealed class DbConnectionConfig : ConnectionConfig +{ + /// + /// 启用库表初始化 + /// + public bool EnableInitDb { get; set; } +} \ No newline at end of file diff --git a/Cis.Core/Common/Option/RedisOptions.cs b/Cis.Core/Common/Option/RedisOptions.cs new file mode 100644 index 0000000..8fa9d87 --- /dev/null +++ b/Cis.Core/Common/Option/RedisOptions.cs @@ -0,0 +1,12 @@ +namespace Cis.Core; + +/// +/// Redis 配置选项 +/// +public sealed class RedisOptions : IConfigurableOptions +{ + /// + /// Redis 连接字符串 + /// + public string ConnectionString { get; set; } +} \ No newline at end of file diff --git a/Cis.Core/Option/SnowIdOptions.cs b/Cis.Core/Common/Option/SnowIdOptions.cs similarity index 58% rename from Cis.Core/Option/SnowIdOptions.cs rename to Cis.Core/Common/Option/SnowIdOptions.cs index 869a8e4..fe0ccbc 100644 --- a/Cis.Core/Option/SnowIdOptions.cs +++ b/Cis.Core/Common/Option/SnowIdOptions.cs @@ -5,8 +5,8 @@ /// public sealed class SnowIdOptions : IConfigurableOptions { - /// - /// 机器码 - /// - public ushort WorkerId { get; set; } + /// + /// 机器码 + /// + public ushort WorkerId { get; set; } } \ No newline at end of file diff --git a/Cis.Core/Const/SqlSugarConst.cs b/Cis.Core/Const/SqlSugarConst.cs deleted file mode 100644 index 814797c..0000000 --- a/Cis.Core/Const/SqlSugarConst.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Cis.Core; - -public class SqlSugarConst -{ - /// - /// 默认数据库标识 - /// - public const string DefaultConfigId = "Cis"; - - /// - /// 默认表主键 - /// - public const string DefaultPrimaryKey = "Id"; -} \ No newline at end of file diff --git a/Cis.Core/CoreConfig.json b/Cis.Core/CoreConfig.json index 040f27e..cf8258a 100644 --- a/Cis.Core/CoreConfig.json +++ b/Cis.Core/CoreConfig.json @@ -1,5 +1,4 @@ { - "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json", "DbConnection": { "ConnectionConfigs": [ { @@ -10,19 +9,12 @@ //"ConnectionString": "DataSource=./cis.db", //"DbType": "PostgreSQL", //"ConnectionString": "HOST=127.0.0.1;PORT=5432;USER ID=pgsql;PASSWORD=123456;DATABASE=cis;", - "EnableInitDb": false // 启用库表初始化 - }, - { - "ConfigId": "serverdb", - "DbType": "MySql", - "ConnectionString": "Data Source=127.0.0.1;port=3306;User ID=root;Password=123456;Database=serverdb;pooling=true;sslmode=none;CharSet=utf8;", - "EnableInitDb": false // 启用库表初始化 + "EnableInitDb": true // 启用库表初始化 } ] }, - "Cache": { - "CacheType": "Memory", // Memory、Redis - "RedisConnectionString": "127.0.0.1:6379;password=123456;db=2" + "Redis": { + "ConnectionString": "127.0.0.1:6379,password=123456,defaultDatabase=2" }, "AppSettings": { "InjectSpecificationDocument": true // 生产环境是否开启Swagger diff --git a/Cis.Core/Entity/EntityBase.cs b/Cis.Core/Entity/EntityBase.cs deleted file mode 100644 index af01d77..0000000 --- a/Cis.Core/Entity/EntityBase.cs +++ /dev/null @@ -1,61 +0,0 @@ -namespace Cis.Core; - -/// -/// 框架实体基类Id -/// -public abstract class EntityBaseId -{ - /// - /// 雪花Id - /// - [SugarColumn(ColumnDescription = "Id", IsPrimaryKey = true, IsIdentity = false)] - public virtual long Id { get; set; } -} - -/// -/// 框架实体基类 -/// -public abstract class EntityBase : EntityBaseId -{ - /// - /// 创建时间 - /// - [SugarColumn(ColumnDescription = "创建时间")] - public virtual DateTime? CreateTime { get; set; } - - /// - /// 更新时间 - /// - [SugarColumn(ColumnDescription = "更新时间")] - public virtual DateTime? UpdateTime { get; set; } - - /// - /// 创建者Id - /// - [SugarColumn(ColumnDescription = "创建者Id")] - public virtual long? CreateUserId { get; set; } - - /// - /// 修改者Id - /// - [SugarColumn(ColumnDescription = "修改者Id")] - public virtual long? UpdateUserId { get; set; } - - /// - /// 软删除 - /// - [SugarColumn(ColumnDescription = "软删除")] - public virtual bool IsDelete { get; set; } = false; -} - -/// -/// 业务数据实体基类(数据权限) -/// -public abstract class DataEntityBase : EntityBase -{ - /// - /// 创建者部门Id - /// - [SugarColumn(ColumnDescription = "创建者部门Id")] - public virtual long? CreateOrgId { get; set; } -} \ No newline at end of file diff --git a/Cis.Core/Entity/Pagination.cs b/Cis.Core/Entity/Pagination.cs deleted file mode 100644 index 504c41e..0000000 --- a/Cis.Core/Entity/Pagination.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace Cis.Core; - -public class Pagination -{ - /// - /// 当前页 - /// - public virtual int Index { get; set; } - - /// - /// 页码容量 - /// - public virtual int Size { get; set; } - - /// - /// 排序字段 - /// - public virtual string Field { get; set; } - - /// - /// 排序方向 - /// - public virtual string Order { get; set; } - - /// - /// 总记录数 - /// - public virtual int Total { get; set; } - - /// - /// 页码数 - /// - public virtual int Number - { - get - { - if (Size > 0) - { - return ((Size % Total) == 0) ? (Size / Total) : ((Size / Total) + 1); - } - else - { - return 0; - } - } - } -} \ No newline at end of file diff --git a/Cis.Core/Entity/RespParamProvider.cs b/Cis.Core/Entity/RespParamProvider.cs deleted file mode 100644 index fcd6a89..0000000 --- a/Cis.Core/Entity/RespParamProvider.cs +++ /dev/null @@ -1,128 +0,0 @@ -namespace Cis.Core; - -/// -/// 全局规范化结果 -/// -[UnifyModel(typeof(RespParam<>))] -public class RespParamProvider : IUnifyResultProvider -{ - /// - /// 异常返回值 - /// - /// - /// - /// - public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata) - { - return new JsonResult(RESTfulResult(metadata.StatusCode, data: metadata.Data, errors: metadata.Errors)); - } - - /// - /// 成功返回值 - /// - /// - /// - /// - public IActionResult OnSucceeded(ActionExecutedContext context, object data) - { - return new JsonResult(RESTfulResult(StatusCodes.Status200OK, true, data)); - } - - /// - /// 验证失败返回值 - /// - /// - /// - /// - public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata) - { - return new JsonResult(RESTfulResult(metadata.StatusCode ?? StatusCodes.Status400BadRequest, data: metadata.Data, errors: metadata.ValidationResult)); - } - - /// - /// 特定状态码返回值 - /// - /// - /// - /// - /// - public async Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings) - { - // 设置响应状态码 - UnifyContext.SetResponseStatusCodes(context, statusCode, unifyResultSettings); - - switch (statusCode) - { - // 处理 401 状态码 - case StatusCodes.Status401Unauthorized: - await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "401 登录已过期,请重新登录"), - App.GetOptions()?.JsonSerializerOptions); - break; - // 处理 403 状态码 - case StatusCodes.Status403Forbidden: - await context.Response.WriteAsJsonAsync(RESTfulResult(statusCode, errors: "403 禁止访问,没有权限"), - App.GetOptions()?.JsonSerializerOptions); - break; - - default: break; - } - } - - /// - /// 返回 RESTful 风格结果集 - /// - /// - /// - /// - /// - /// - private static RespParam RESTfulResult(int statusCode, bool succeeded = default, object data = default, object errors = default) - { - return new RespParam - { - Code = statusCode, - Message = errors is string str ? str : JSON.Serialize(errors), - Data = data, - Type = succeeded ? "success" : "error", - Extras = UnifyContext.Take(), - Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - }; - } -} - -/// -/// 全局返回结果 -/// -/// -public class RespParam -{ - /// - /// 状态码 - /// - public int Code { get; set; } - - /// - /// 类型success、warning、error - /// - public string Type { get; set; } - - /// - /// 错误信息 - /// - public string Message { get; set; } - - /// - /// 数据 - /// - public T Data { get; set; } - - /// - /// 附加数据 - /// - public object Extras { get; set; } - - /// - /// 时间戳 - /// - public long Timestamp { get; set; } -} \ No newline at end of file diff --git a/Cis.Core/Enum/StatusEnum.cs b/Cis.Core/Enum/StatusEnum.cs deleted file mode 100644 index 27cf060..0000000 --- a/Cis.Core/Enum/StatusEnum.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Cis.Core; - -/// -/// 通用状态枚举 -/// -public enum StatusEnum -{ - /// - /// 停用 - /// - [Description("停用")] - Disable = 0, - - /// - /// 启用 - /// - [Description("启用")] - Enable = 1, -} \ No newline at end of file diff --git a/Cis.Core/Extension/ObjectExtension.cs b/Cis.Core/Extension/ObjectExtension.cs deleted file mode 100644 index e50bed7..0000000 --- a/Cis.Core/Extension/ObjectExtension.cs +++ /dev/null @@ -1,151 +0,0 @@ -using Newtonsoft.Json.Linq; -using System.Text; - -namespace Cis.Core; - -/// -/// 对象拓展 -/// -[SuppressSniffer] -public static class ObjectExtension -{ - /// - /// 判断类型是否实现某个泛型 - /// - /// 类型 - /// 泛型类型 - /// bool - public static bool HasImplementedRawGeneric(this Type type, Type generic) - { - // 检查接口类型 - var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType); - if (isTheRawGenericType) return true; - - // 检查类型 - while (type != null && type != typeof(object)) - { - isTheRawGenericType = IsTheRawGenericType(type); - if (isTheRawGenericType) return true; - type = type.BaseType; - } - - return false; - - // 判断逻辑 - bool IsTheRawGenericType(Type type) => generic == (type.IsGenericType ? type.GetGenericTypeDefinition() : type); - } - - /// - /// 将字典转化为QueryString格式 - /// - /// - /// - /// - public static string ToQueryString(this Dictionary dict, bool urlEncode = true) - { - return string.Join("&", dict.Select(p => $"{(urlEncode ? p.Key?.UrlEncode() : "")}={(urlEncode ? p.Value?.UrlEncode() : "")}")); - } - - /// - /// 将字符串URL编码 - /// - /// - /// - public static string UrlEncode(this string str) - { - return string.IsNullOrEmpty(str) ? "" : System.Web.HttpUtility.UrlEncode(str, Encoding.UTF8); - } - - /// - /// List转DataTable - /// - /// - /// - /// - public static DataTable ToDataTable(this List list) - { - DataTable result = new(); - if (list.Count > 0) - { - // result.TableName = list[0].GetType().Name; // 表名赋值 - PropertyInfo[] propertys = list[0].GetType().GetProperties(); - foreach (PropertyInfo pi in propertys) - { - Type colType = pi.PropertyType; - if (colType.IsGenericType && colType.GetGenericTypeDefinition() == typeof(Nullable<>)) - { - colType = colType.GetGenericArguments()[0]; - } - if (IsIgnoreColumn(pi)) - continue; - result.Columns.Add(pi.Name, colType); - } - for (int i = 0; i < list.Count; i++) - { - ArrayList tempList = new(); - foreach (PropertyInfo pi in propertys) - { - if (IsIgnoreColumn(pi)) - continue; - object obj = pi.GetValue(list[i], null); - tempList.Add(obj); - } - object[] array = tempList.ToArray(); - result.LoadDataRow(array, true); - } - } - return result; - } - - /// - /// 对象序列化成Json字符串 - /// - /// - /// - public static string ToJson(this object obj) - { - return JSON.GetJsonSerializer().Serialize(obj); - } - - /// - /// Json字符串反序列化成对象 - /// - /// - /// - /// - public static T ToObject(this string json) - { - return JSON.GetJsonSerializer().Deserialize(json); - } - - /// - /// 字串反序列化成linq对象 - /// - /// 字串 - /// - public static JObject ToJObject(this string Json) - { - return string.IsNullOrEmpty(Json) ? JObject.Parse("{}") : JObject.Parse(Json.Replace(" ", "")); - } - - /// - /// 排除SqlSugar忽略的列 - /// - /// - /// - private static bool IsIgnoreColumn(PropertyInfo pi) - { - var sc = pi.GetCustomAttributes(false).FirstOrDefault(u => u.IsIgnore == true); - return sc != null; - } - - public static bool ExistsKey(this IDictionary dict, object key) - { - foreach (object item in dict.Keys) - { - if (Equals(key, item)) - return true; - } - return false; - } -} \ No newline at end of file diff --git a/Cis.Core/Option/CacheOptions.cs b/Cis.Core/Option/CacheOptions.cs deleted file mode 100644 index ace990a..0000000 --- a/Cis.Core/Option/CacheOptions.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Cis.Core; - -/// -/// 缓存配置选项 -/// -public sealed class CacheOptions : IConfigurableOptions -{ - /// - /// 缓存类型 - /// - public string CacheType { get; set; } - - /// - /// Redis连接字符串 - /// - public string RedisConnectionString { get; set; } -} \ No newline at end of file diff --git a/Cis.Core/Option/DbConnectionOptions.cs b/Cis.Core/Option/DbConnectionOptions.cs deleted file mode 100644 index a5e81fc..0000000 --- a/Cis.Core/Option/DbConnectionOptions.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Cis.Core; - -/// -/// 数据库配置选项 -/// -public sealed class DbConnectionOptions : IConfigurableOptions -{ - /// - /// 数据库集合 - /// - public List ConnectionConfigs { get; set; } -} - -public sealed class DbConnectionConfig : ConnectionConfig -{ - /// - /// 启用库表初始化 - /// - public bool EnableInitDb { get; set; } -} \ No newline at end of file diff --git a/Cis.Core/SqlSugar/IEntityFilter.cs b/Cis.Core/SqlSugar/IEntityFilter.cs index 1869bb9..473eaf0 100644 --- a/Cis.Core/SqlSugar/IEntityFilter.cs +++ b/Cis.Core/SqlSugar/IEntityFilter.cs @@ -5,9 +5,9 @@ /// public interface IEntityFilter { - /// - /// 实体过滤器 - /// - /// - IEnumerable> AddEntityFilter(); + /// + /// 实体过滤器 + /// + /// + IEnumerable> AddEntityFilter(); } \ No newline at end of file diff --git a/Cis.Core/SqlSugar/ISqlSugarEntitySeedData.cs b/Cis.Core/SqlSugar/ISqlSugarEntitySeedData.cs index f703306..965984e 100644 --- a/Cis.Core/SqlSugar/ISqlSugarEntitySeedData.cs +++ b/Cis.Core/SqlSugar/ISqlSugarEntitySeedData.cs @@ -5,11 +5,11 @@ /// /// public interface ISqlSugarEntitySeedData - where TEntity : class, new() + where TEntity : class, new() { - /// - /// 种子数据 - /// - /// - IEnumerable HasData(); + /// + /// 种子数据 + /// + /// + IEnumerable HasData(); } \ No newline at end of file diff --git a/Cis.Core/SqlSugar/SqlSugarPagedList.cs b/Cis.Core/SqlSugar/SqlSugarPagedList.cs index 577f1cf..3b9c82d 100644 --- a/Cis.Core/SqlSugar/SqlSugarPagedList.cs +++ b/Cis.Core/SqlSugar/SqlSugarPagedList.cs @@ -5,42 +5,42 @@ /// /// public class SqlSugarPagedList - where TEntity : new() + where TEntity : new() { - /// - /// 页码 - /// - public int Page { get; set; } + /// + /// 页码 + /// + public int Page { get; set; } - /// - /// 页容量 - /// - public int PageSize { get; set; } + /// + /// 页容量 + /// + public int PageSize { get; set; } - /// - /// 总条数 - /// - public int Total { get; set; } + /// + /// 总条数 + /// + public int Total { get; set; } - /// - /// 总页数 - /// - public int TotalPages { get; set; } + /// + /// 总页数 + /// + public int TotalPages { get; set; } - /// - /// 当前页集合 - /// - public IEnumerable Items { get; set; } + /// + /// 当前页集合 + /// + public IEnumerable Items { get; set; } - /// - /// 是否有上一页 - /// - public bool HasPrevPage { get; set; } + /// + /// 是否有上一页 + /// + public bool HasPrevPage { get; set; } - /// - /// 是否有下一页 - /// - public bool HasNextPage { get; set; } + /// + /// 是否有下一页 + /// + public bool HasNextPage { get; set; } } /// @@ -48,53 +48,53 @@ public class SqlSugarPagedList /// public static class SqlSugarPagedExtensions { - /// - /// 分页拓展 - /// - /// - /// - /// - /// - public static SqlSugarPagedList ToPagedList(this ISugarQueryable entity, int pageIndex, int pageSize) - where TEntity : new() - { - var total = 0; - var items = entity.ToPageList(pageIndex, pageSize, ref total); - var totalPages = (int)Math.Ceiling(total / (double)pageSize); - return new SqlSugarPagedList - { - Page = pageIndex, - PageSize = pageSize, - Items = items, - Total = total, - TotalPages = totalPages, - HasNextPage = pageIndex < totalPages, - HasPrevPage = pageIndex - 1 > 0 - }; - } + /// + /// 分页拓展 + /// + /// + /// + /// + /// + public static SqlSugarPagedList ToPagedList(this ISugarQueryable entity, int pageIndex, int pageSize) + where TEntity : new() + { + var total = 0; + var items = entity.ToPageList(pageIndex, pageSize, ref total); + var totalPages = (int)Math.Ceiling(total / (double)pageSize); + return new SqlSugarPagedList + { + Page = pageIndex, + PageSize = pageSize, + Items = items, + Total = total, + TotalPages = totalPages, + HasNextPage = pageIndex < totalPages, + HasPrevPage = pageIndex - 1 > 0 + }; + } - /// - /// 分页拓展 - /// - /// - /// - /// - /// - public static async Task> ToPagedListAsync(this ISugarQueryable entity, int pageIndex, int pageSize) - where TEntity : new() - { - RefAsync total = 0; - var items = await entity.ToPageListAsync(pageIndex, pageSize, total); - var totalPages = (int)Math.Ceiling(total / (double)pageSize); - return new SqlSugarPagedList - { - Page = pageIndex, - PageSize = pageSize, - Items = items, - Total = total, - TotalPages = totalPages, - HasNextPage = pageIndex < totalPages, - HasPrevPage = pageIndex - 1 > 0 - }; - } + /// + /// 分页拓展 + /// + /// + /// + /// + /// + public static async Task> ToPagedListAsync(this ISugarQueryable entity, int pageIndex, int pageSize) + where TEntity : new() + { + RefAsync total = 0; + var items = await entity.ToPageListAsync(pageIndex, pageSize, total); + var totalPages = (int)Math.Ceiling(total / (double)pageSize); + return new SqlSugarPagedList + { + Page = pageIndex, + PageSize = pageSize, + Items = items, + Total = total, + TotalPages = totalPages, + HasNextPage = pageIndex < totalPages, + HasPrevPage = pageIndex - 1 > 0 + }; + } } \ No newline at end of file diff --git a/Cis.Core/SqlSugar/SqlSugarRepository.cs b/Cis.Core/SqlSugar/SqlSugarRepository.cs index c8fe3dc..98ddc09 100644 --- a/Cis.Core/SqlSugar/SqlSugarRepository.cs +++ b/Cis.Core/SqlSugar/SqlSugarRepository.cs @@ -6,11 +6,11 @@ /// public class SqlSugarRepository : SimpleClient where T : class, new() { - protected ITenant iTenant = null; // 多租户事务 + protected ITenant iTenant = null; // 多租户事务 - public SqlSugarRepository(ISqlSugarClient context = null) : base(context) // 默认值等于null不能少 - { - iTenant = App.GetService().AsTenant(); - base.Context = iTenant.GetConnectionWithAttr(); - } + public SqlSugarRepository(ISqlSugarClient context = null) : base(context) // 默认值等于null不能少 + { + iTenant = App.GetService().AsTenant(); + base.Context = iTenant.GetConnectionWithAttr(); + } } \ No newline at end of file diff --git a/Cis.Core/SqlSugar/SqlSugarSetup.cs b/Cis.Core/SqlSugar/SqlSugarSetup.cs index f1cafcf..2a56022 100644 --- a/Cis.Core/SqlSugar/SqlSugarSetup.cs +++ b/Cis.Core/SqlSugar/SqlSugarSetup.cs @@ -2,158 +2,158 @@ public static class SqlSugarSetup { - /// - /// Sqlsugar 上下文初始化 - /// - /// - public static void AddSqlSugar(this IServiceCollection services) - { - var dbOptions = App.GetOptions(); - var configureExternalServices = new ConfigureExternalServices - { - EntityService = (type, column) => // 修改列可空-1、带?问号 2、String类型若没有Required - { - if ((type.PropertyType.IsGenericType && type.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) - || (type.PropertyType == typeof(string) && type.GetCustomAttribute() == null)) - column.IsNullable = true; - }, - DataInfoCacheService = new SqlSugarCache(), - }; - dbOptions.ConnectionConfigs.ForEach(config => - { - config.ConfigureExternalServices = configureExternalServices; - config.InitKeyType = InitKeyType.Attribute; - config.IsAutoCloseConnection = true; - config.MoreSettings = new ConnMoreSettings - { - IsAutoRemoveDataCache = true - }; - }); + /// + /// Sqlsugar 上下文初始化 + /// + /// + public static void AddSqlSugar(this IServiceCollection services) + { + var dbOptions = App.GetOptions(); + var configureExternalServices = new ConfigureExternalServices + { + EntityService = (type, column) => // 修改列可空-1、带?问号 2、String类型若没有Required + { + if ((type.PropertyType.IsGenericType && type.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) + || (type.PropertyType == typeof(string) && type.GetCustomAttribute() == null)) + column.IsNullable = true; + }, + DataInfoCacheService = new SqlSugarCache(), + }; + dbOptions.ConnectionConfigs.ForEach(config => + { + config.ConfigureExternalServices = configureExternalServices; + config.InitKeyType = InitKeyType.Attribute; + config.IsAutoCloseConnection = true; + config.MoreSettings = new ConnMoreSettings + { + IsAutoRemoveDataCache = true + }; + }); - SqlSugarScope sqlSugar = new(dbOptions.ConnectionConfigs.Adapt>(), client => - { - dbOptions.ConnectionConfigs.ForEach(config => - { - var db = client.GetConnectionScope((string)config.ConfigId); + SqlSugarScope sqlSugar = new(dbOptions.ConnectionConfigs.Adapt>(), client => + { + dbOptions.ConnectionConfigs.ForEach(config => + { + var db = client.GetConnectionScope((string)config.ConfigId); - // 设置超时时间 - db.Ado.CommandTimeOut = 30; + // 设置超时时间 + db.Ado.CommandTimeOut = 30; - // 打印SQL语句 - db.Aop.OnLogExecuting = (sql, pars) => - { - if (sql.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase)) - Console.ForegroundColor = ConsoleColor.Green; - if (sql.StartsWith("UPDATE", StringComparison.OrdinalIgnoreCase) || sql.StartsWith("INSERT", StringComparison.OrdinalIgnoreCase)) - Console.ForegroundColor = ConsoleColor.White; - if (sql.StartsWith("DELETE", StringComparison.OrdinalIgnoreCase)) - Console.ForegroundColor = ConsoleColor.Blue; - Console.WriteLine("【" + DateTime.Now + "——执行SQL】\r\n" + UtilMethods.GetSqlString(config.DbType, sql, pars) + "\r\n"); - App.PrintToMiniProfiler("SqlSugar", "Info", sql + "\r\n" + db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); - }; - db.Aop.OnError = (ex) => - { - Console.ForegroundColor = ConsoleColor.Red; - var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value)); - Console.WriteLine("【" + DateTime.Now + "——错误SQL】\r\n" + UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres) + "\r\n"); - App.PrintToMiniProfiler("SqlSugar", "Error", $"{ex.Message}{Environment.NewLine}{ex.Sql}{pars}{Environment.NewLine}"); - }; + // 打印SQL语句 + db.Aop.OnLogExecuting = (sql, pars) => + { + if (sql.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase)) + Console.ForegroundColor = ConsoleColor.Green; + if (sql.StartsWith("UPDATE", StringComparison.OrdinalIgnoreCase) || sql.StartsWith("INSERT", StringComparison.OrdinalIgnoreCase)) + Console.ForegroundColor = ConsoleColor.White; + if (sql.StartsWith("DELETE", StringComparison.OrdinalIgnoreCase)) + Console.ForegroundColor = ConsoleColor.Blue; + Console.WriteLine("【" + DateTime.Now + "——执行SQL】\r\n" + UtilMethods.GetSqlString(config.DbType, sql, pars) + "\r\n"); + App.PrintToMiniProfiler("SqlSugar", "Info", sql + "\r\n" + db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); + }; + db.Aop.OnError = (ex) => + { + Console.ForegroundColor = ConsoleColor.Red; + var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value)); + Console.WriteLine("【" + DateTime.Now + "——错误SQL】\r\n" + UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres) + "\r\n"); + App.PrintToMiniProfiler("SqlSugar", "Error", $"{ex.Message}{Environment.NewLine}{ex.Sql}{pars}{Environment.NewLine}"); + }; - // 数据审计 - db.Aop.DataExecuting = (oldValue, entityInfo) => - { - // 新增操作 - if (entityInfo.OperationType == DataFilterType.InsertByObject) - { - // 主键(long类型)且没有值的---赋值雪花Id - if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(long)) - { - var id = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue); - if (id == null || (long)id == 0) - entityInfo.SetValue(Yitter.IdGenerator.YitIdHelper.NextId()); - } - if (entityInfo.PropertyName == "CreateTime") - entityInfo.SetValue(DateTime.Now); - } - // 更新操作 - if (entityInfo.OperationType == DataFilterType.UpdateByObject) - { - if (entityInfo.PropertyName == "UpdateTime") - entityInfo.SetValue(DateTime.Now); - } - }; - }); - }); + // 数据审计 + db.Aop.DataExecuting = (oldValue, entityInfo) => + { + // 新增操作 + if (entityInfo.OperationType == DataFilterType.InsertByObject) + { + // 主键(long类型)且没有值的---赋值雪花Id + if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(long)) + { + var id = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue); + if (id == null || (long)id == 0) + entityInfo.SetValue(Yitter.IdGenerator.YitIdHelper.NextId()); + } + if (entityInfo.PropertyName == "CreateTime") + entityInfo.SetValue(DateTime.Now); + } + // 更新操作 + if (entityInfo.OperationType == DataFilterType.UpdateByObject) + { + if (entityInfo.PropertyName == "UpdateTime") + entityInfo.SetValue(DateTime.Now); + } + }; + }); + }); - // 初始化数据库表结构及种子数据 - InitDataBase(sqlSugar, dbOptions); + // 初始化数据库表结构及种子数据 + InitDataBase(sqlSugar, dbOptions); - services.AddSingleton(sqlSugar); // 单例注册 - services.AddScoped(typeof(SqlSugarRepository<>)); // 注册仓储 - services.AddUnitOfWork(); // 注册事务与工作单元 - } + services.AddSingleton(sqlSugar); // 单例注册 + services.AddScoped(typeof(SqlSugarRepository<>)); // 注册仓储 + services.AddUnitOfWork(); // 注册事务与工作单元 + } - /// - /// 初始化数据库结构 - /// - private static void InitDataBase(SqlSugarScope db, DbConnectionOptions dbOptions) - { - // 创建数据库 - dbOptions.ConnectionConfigs.ForEach(config => - { - if (!config.EnableInitDb || config.DbType == SqlSugar.DbType.Oracle) return; - db.GetConnectionScope(config.ConfigId).DbMaintenance.CreateDatabase(); - }); + /// + /// 初始化数据库结构 + /// + private static void InitDataBase(SqlSugarScope db, DbConnectionOptions dbOptions) + { + // 创建数据库 + dbOptions.ConnectionConfigs.ForEach(config => + { + if (!config.EnableInitDb || config.DbType == SqlSugar.DbType.Oracle) return; + db.GetConnectionScope(config.ConfigId).DbMaintenance.CreateDatabase(); + }); - // 获取所有实体表-初始化表结构 - var entityTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass - && u.IsDefined(typeof(SugarTable), false) && !u.IsDefined(typeof(NotTableAttribute), false)); - if (!entityTypes.Any()) return; - foreach (var entityType in entityTypes) - { - var tAtt = entityType.GetCustomAttribute(); // 多数据库 - var configId = tAtt == null ? SqlSugarConst.DefaultConfigId : tAtt.configId.ToString(); - if (!dbOptions.ConnectionConfigs.FirstOrDefault(u => u.ConfigId == configId).EnableInitDb) - continue; - var db2 = db.GetConnectionScope(configId); - var splitTable = entityType.GetCustomAttribute(); // 分表 - if (splitTable == null) - db2.CodeFirst.InitTables(entityType); - else - db2.CodeFirst.SplitTables().InitTables(entityType); - } + // 获取所有实体表-初始化表结构 + var entityTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass + && u.IsDefined(typeof(SugarTable), false) && !u.IsDefined(typeof(NotTableAttribute), false)); + if (!entityTypes.Any()) return; + foreach (var entityType in entityTypes) + { + var tAtt = entityType.GetCustomAttribute(); // 多数据库 + var configId = tAtt == null ? SqlSugarConst.DefaultConfigId : tAtt.configId.ToString(); + if (!dbOptions.ConnectionConfigs.FirstOrDefault(u => u.ConfigId == configId).EnableInitDb) + continue; + var db2 = db.GetConnectionScope(configId); + var splitTable = entityType.GetCustomAttribute(); // 分表 + if (splitTable == null) + db2.CodeFirst.InitTables(entityType); + else + db2.CodeFirst.SplitTables().InitTables(entityType); + } - // 获取所有种子配置-初始化数据 - var seedDataTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass - && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarEntitySeedData<>)))); - if (!seedDataTypes.Any()) return; - foreach (var seedType in seedDataTypes) - { - var instance = Activator.CreateInstance(seedType); + // 获取所有种子配置-初始化数据 + var seedDataTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass + && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarEntitySeedData<>)))); + if (!seedDataTypes.Any()) return; + foreach (var seedType in seedDataTypes) + { + var instance = Activator.CreateInstance(seedType); - var hasDataMethod = seedType.GetMethod("HasData"); - var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast(); - if (seedData == null) continue; + var hasDataMethod = seedType.GetMethod("HasData"); + var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast(); + if (seedData == null) continue; - var entityType = seedType.GetInterfaces().First().GetGenericArguments().First(); - var tAtt = entityType.GetCustomAttribute(); - var configId = tAtt == null ? SqlSugarConst.DefaultConfigId : tAtt.configId.ToString(); - if (!dbOptions.ConnectionConfigs.FirstOrDefault(u => u.ConfigId == configId).EnableInitDb) - continue; - var db2 = db.GetConnectionScope(configId); - var seedDataTable = seedData.ToList().ToDataTable(); - seedDataTable.TableName = db.EntityMaintenance.GetEntityInfo(entityType).DbTableName; - if (seedDataTable.Columns.Contains(SqlSugarConst.DefaultPrimaryKey)) - { - var storage = db2.Storageable(seedDataTable).WhereColumns(SqlSugarConst.DefaultPrimaryKey).ToStorage(); - storage.AsInsertable.ExecuteCommand(); - storage.AsUpdateable.ExecuteCommand(); - } - else // 没有主键或者不是预定义的主键(没主键有重复的可能) - { - var storage = db2.Storageable(seedDataTable).ToStorage(); - storage.AsInsertable.ExecuteCommand(); - } - } - } + var entityType = seedType.GetInterfaces().First().GetGenericArguments().First(); + var tAtt = entityType.GetCustomAttribute(); + var configId = tAtt == null ? SqlSugarConst.DefaultConfigId : tAtt.configId.ToString(); + if (!dbOptions.ConnectionConfigs.FirstOrDefault(u => u.ConfigId == configId).EnableInitDb) + continue; + var db2 = db.GetConnectionScope(configId); + var seedDataTable = seedData.ToList().ToDataTable(); + seedDataTable.TableName = db.EntityMaintenance.GetEntityInfo(entityType).DbTableName; + if (seedDataTable.Columns.Contains(SqlSugarConst.DefaultPrimaryKey)) + { + var storage = db2.Storageable(seedDataTable).WhereColumns(SqlSugarConst.DefaultPrimaryKey).ToStorage(); + storage.AsInsertable.ExecuteCommand(); + storage.AsUpdateable.ExecuteCommand(); + } + else // 没有主键或者不是预定义的主键(没主键有重复的可能) + { + var storage = db2.Storageable(seedDataTable).ToStorage(); + storage.AsInsertable.ExecuteCommand(); + } + } + } } \ No newline at end of file diff --git a/Cis.Core/SqlSugar/SqlSugarUnitOfWork.cs b/Cis.Core/SqlSugar/SqlSugarUnitOfWork.cs index 45b1f9b..70a8728 100644 --- a/Cis.Core/SqlSugar/SqlSugarUnitOfWork.cs +++ b/Cis.Core/SqlSugar/SqlSugarUnitOfWork.cs @@ -5,61 +5,61 @@ /// public sealed class SqlSugarUnitOfWork : IUnitOfWork { - /// - /// SqlSugar 对象 - /// - private readonly ISqlSugarClient _sqlSugarClient; + /// + /// SqlSugar 对象 + /// + private readonly ISqlSugarClient _sqlSugarClient; - /// - /// 构造函数 - /// - /// - public SqlSugarUnitOfWork(ISqlSugarClient sqlSugarClient) - { - _sqlSugarClient = sqlSugarClient; - } + /// + /// 构造函数 + /// + /// + public SqlSugarUnitOfWork(ISqlSugarClient sqlSugarClient) + { + _sqlSugarClient = sqlSugarClient; + } - /// - /// 开启工作单元处理 - /// - /// - /// - /// - public void BeginTransaction(FilterContext context, UnitOfWorkAttribute unitOfWork) - { - _sqlSugarClient.AsTenant().BeginTran(); - } + /// + /// 开启工作单元处理 + /// + /// + /// + /// + public void BeginTransaction(FilterContext context, UnitOfWorkAttribute unitOfWork) + { + _sqlSugarClient.AsTenant().BeginTran(); + } - /// - /// 提交工作单元处理 - /// - /// - /// - /// - public void CommitTransaction(FilterContext resultContext, UnitOfWorkAttribute unitOfWork) - { - _sqlSugarClient.AsTenant().CommitTran(); - } + /// + /// 提交工作单元处理 + /// + /// + /// + /// + public void CommitTransaction(FilterContext resultContext, UnitOfWorkAttribute unitOfWork) + { + _sqlSugarClient.AsTenant().CommitTran(); + } - /// - /// 回滚工作单元处理 - /// - /// - /// - /// - public void RollbackTransaction(FilterContext resultContext, UnitOfWorkAttribute unitOfWork) - { - _sqlSugarClient.AsTenant().RollbackTran(); - } + /// + /// 回滚工作单元处理 + /// + /// + /// + /// + public void RollbackTransaction(FilterContext resultContext, UnitOfWorkAttribute unitOfWork) + { + _sqlSugarClient.AsTenant().RollbackTran(); + } - /// - /// 执行完毕(无论成功失败) - /// - /// - /// - /// - public void OnCompleted(FilterContext context, FilterContext resultContext) - { - _sqlSugarClient.Dispose(); - } + /// + /// 执行完毕(无论成功失败) + /// + /// + /// + /// + public void OnCompleted(FilterContext context, FilterContext resultContext) + { + _sqlSugarClient.Dispose(); + } } \ No newline at end of file diff --git a/Cis.Web.Core/Handlers/JwtHandler.cs b/Cis.Web.Core/Handlers/JwtHandler.cs index 575a8ca..b5d17f8 100644 --- a/Cis.Web.Core/Handlers/JwtHandler.cs +++ b/Cis.Web.Core/Handlers/JwtHandler.cs @@ -13,4 +13,4 @@ public class JwtHandler : AppAuthorizeHandler return Task.FromResult(true); } -} +} \ No newline at end of file diff --git a/Cis.Web.Core/ProjectOptions.cs b/Cis.Web.Core/ProjectOptions.cs index 7a9642f..6fdaaee 100644 --- a/Cis.Web.Core/ProjectOptions.cs +++ b/Cis.Web.Core/ProjectOptions.cs @@ -5,17 +5,17 @@ namespace Cis.Web.Core; public static class ProjectOptions { - /// - /// 注册项目配置选项 - /// - /// - /// - public static IServiceCollection AddProjectOptions(this IServiceCollection services) - { - services.AddConfigurableOptions(); - services.AddConfigurableOptions(); - services.AddConfigurableOptions(); + /// + /// 注册项目配置选项 + /// + /// + /// + public static IServiceCollection AddProjectOptions(this IServiceCollection services) + { + services.AddConfigurableOptions(); + services.AddConfigurableOptions(); + services.AddConfigurableOptions(); - return services; - } + return services; + } } \ No newline at end of file diff --git a/Cis.Web.Core/Startup.cs b/Cis.Web.Core/Startup.cs index e7de61a..0e80bf0 100644 --- a/Cis.Web.Core/Startup.cs +++ b/Cis.Web.Core/Startup.cs @@ -16,115 +16,115 @@ namespace Cis.Web.Core; [AppStartup(1000)] public class Startup : AppStartup { - /// - /// 配置应用所需服务,在该方法中可以添加应用所需要的功能或服务 - /// - /// - public void ConfigureServices(IServiceCollection services) - { - // 配置选项 - services.AddProjectOptions(); - // 缓存注册 - services.AddCache(); - // SqlSugar - services.AddSqlSugar(); - // JWT - services.AddJwt(); - // 允许跨域 - services.AddCorsAccessor(); - // 添加 https 跨域时请执行以下方法(关键方法 SetIsOriginAllowed),发现 http 和 https 仅能存在一个 跨域 - // 同时启用 http 和 https,猜测需要通过设置 WithOrigins - // 参考 https://furion.baiqian.ltd/docs/cors?_highlight=corsaccessorsettings#165-corsaccessorsettings-%E9%85%8D%E7%BD%AE - // 以及 http://www.manongjc.com/detail/26-gmogyzvnnewpkml.html - //services.AddCors(options => - //{ - // options.AddPolicy("CorsPolicy", opt => opt - // .SetIsOriginAllowed(_ => true) - // .AllowAnyHeader() - // .AllowAnyMethod() - // .AllowCredentials() - // ); - //}); - // 远程请求 - services.AddRemoteRequest(); - // 任务调度 - services.AddTaskScheduler(); - // 日志监听 - services.AddMonitorLogging(); + /// + /// 配置应用所需服务,在该方法中可以添加应用所需要的功能或服务 + /// + /// + public void ConfigureServices(IServiceCollection services) + { + // 配置选项 + services.AddProjectOptions(); + // 缓存注册 + services.AddCache(); + // SqlSugar + services.AddSqlSugar(); + // JWT + services.AddJwt(); + // 允许跨域 + services.AddCorsAccessor(); + // 添加 https 跨域时请执行以下方法(关键方法 SetIsOriginAllowed),发现 http 和 https 仅能存在一个 跨域 + // 同时启用 http 和 https,猜测需要通过设置 WithOrigins + // 参考 https://furion.baiqian.ltd/docs/cors?_highlight=corsaccessorsettings#165-corsaccessorsettings-%E9%85%8D%E7%BD%AE + // 以及 http://www.manongjc.com/detail/26-gmogyzvnnewpkml.html + //services.AddCors(options => + //{ + // options.AddPolicy("CorsPolicy", opt => opt + // .SetIsOriginAllowed(_ => true) + // .AllowAnyHeader() + // .AllowAnyMethod() + // .AllowCredentials() + // ); + //}); + // 远程请求 + services.AddRemoteRequest(); + // 任务调度 + services.AddTaskScheduler(); + // 日志监听 + services.AddMonitorLogging(); - services.AddControllersWithViews() - .AddNewtonsoftJson(options => - { - options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); // 首字母小写(驼峰样式) - options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;// 设置本地时区 - options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; // 时间格式化 - options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // 忽略循环引用 - options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; // 忽略空值 - }) - .AddInjectWithUnifyResult(); + services.AddControllersWithViews() + .AddNewtonsoftJson(options => + { + options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); // 首字母小写(驼峰样式) + options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;// 设置本地时区 + options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; // 时间格式化 + options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // 忽略循环引用 + options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; // 忽略空值 + }) + .AddInjectWithUnifyResult(); - // 日志记录 - if (App.GetConfig("Logging:File:Enabled")) // 日志写入文件 - { - Array.ForEach(new[] { LogLevel.Information, LogLevel.Warning, LogLevel.Error }, logLevel => - { - services.AddFileLogging(options => - { - options.FileNameRule = fileName => string.Format(fileName, DateTime.Now, logLevel.ToString()); // 每天创建一个文件 - options.WriteFilter = logMsg => logMsg.LogLevel == logLevel; // 日志级别 - options.HandleWriteError = (writeError) => // 写入失败时启用备用文件 - { - writeError.UseRollbackFileName(Path.GetFileNameWithoutExtension(writeError.CurrentFileName) + "-oops" + Path.GetExtension(writeError.CurrentFileName)); - }; - }); - }); - } + // 日志记录 + if (App.GetConfig("Logging:File:Enabled")) // 日志写入文件 + { + Array.ForEach(new[] { LogLevel.Information, LogLevel.Warning, LogLevel.Error }, logLevel => + { + services.AddFileLogging(options => + { + options.FileNameRule = fileName => string.Format(fileName, DateTime.Now, logLevel.ToString()); // 每天创建一个文件 + options.WriteFilter = logMsg => logMsg.LogLevel == logLevel; // 日志级别 + options.HandleWriteError = (writeError) => // 写入失败时启用备用文件 + { + writeError.UseRollbackFileName(Path.GetFileNameWithoutExtension(writeError.CurrentFileName) + "-oops" + Path.GetExtension(writeError.CurrentFileName)); + }; + }); + }); + } - // 配置雪花Id算法机器码 - YitIdHelper.SetIdGenerator(new IdGeneratorOptions - { - WorkerId = App.GetOptions().WorkerId - }); - } + // 配置雪花Id算法机器码 + YitIdHelper.SetIdGenerator(new IdGeneratorOptions + { + WorkerId = App.GetOptions().WorkerId + }); + } - /// - /// 配置应用请求处理管道 - /// - /// - /// - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - app.UseForwardedHeaders(); - } - else - { - app.UseExceptionHandler("/Home/Error"); - app.UseForwardedHeaders(); - app.UseHsts(); - } + /// + /// 配置应用请求处理管道 + /// + /// + /// + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + app.UseForwardedHeaders(); + } + else + { + app.UseExceptionHandler("/Home/Error"); + app.UseForwardedHeaders(); + app.UseHsts(); + } - // 启用HTTPS - app.UseHttpsRedirection(); - app.UseStaticFiles(); + // 启用HTTPS + app.UseHttpsRedirection(); + app.UseStaticFiles(); - app.UseRouting(); + app.UseRouting(); - app.UseCorsAccessor(); - //app.UseCors("CorsPolicy"); + app.UseCorsAccessor(); + //app.UseCors("CorsPolicy"); - app.UseAuthentication(); - app.UseAuthorization(); + app.UseAuthentication(); + app.UseAuthorization(); - app.UseInject(); + app.UseInject(); - app.UseEndpoints(endpoints => - { - endpoints.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); - }); - } + app.UseEndpoints(endpoints => + { + endpoints.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + }); + } } \ No newline at end of file diff --git a/Cis.Web.Entry/.config/dotnet-tools.json b/Cis.Web.Entry/.config/dotnet-tools.json new file mode 100644 index 0000000..fccc806 --- /dev/null +++ b/Cis.Web.Entry/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "7.0.0", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/Cis.Web.Entry/Controllers/HomeController.cs b/Cis.Web.Entry/Controllers/HomeController.cs index 3a64469..07245a0 100644 --- a/Cis.Web.Entry/Controllers/HomeController.cs +++ b/Cis.Web.Entry/Controllers/HomeController.cs @@ -6,14 +6,14 @@ namespace Cis.Web.Entry.Controllers; [AllowAnonymous] public class HomeController : Controller { - public HomeController() - { - } + public HomeController() + { + } - public IActionResult Index() - { - ViewBag.Description = "Hello, dotnet."; + public IActionResult Index() + { + ViewBag.Description = "Hello, dotnet."; - return View(); - } + return View(); + } } \ No newline at end of file diff --git a/EC.Helper/CameraSDK/Common/CameraStruct.cs b/EC.Helper/CameraSDK/Common/CameraStruct.cs index 42f6e27..132f394 100644 --- a/EC.Helper/CameraSDK/Common/CameraStruct.cs +++ b/EC.Helper/CameraSDK/Common/CameraStruct.cs @@ -47,9 +47,9 @@ public class CameraInfo CameraInfo info = new() { Type = type, Ip = ip, UserName = userName, Password = password }; int port = (CameraType)type switch { - CameraType.HiK => CameraPort.HiK, - CameraType.DaHua => CameraPort.DaHua, - CameraType.YuShi => CameraPort.YuShi, + CameraType.HiK => (int)CameraPort.HiK, + CameraType.DaHua => (int)CameraPort.DaHua, + CameraType.YuShi => (int)CameraPort.YuShi, _ => -1, }; info.Port = port; @@ -62,21 +62,21 @@ public class CameraInfo /// /// 相机类型 /// -public enum CameraType +public enum CameraType : int { - HiK = 0, - DaHua = 1, - YuShi = 2, + HiK = 1, + DaHua, + YuShi, } /// /// 相机默认连接端口 /// -public class CameraPort +public enum CameraPort : int { - public const int HiK = 8000; - public const int DaHua = 37777; - public const int YuShi = 8800; + HiK = 8000, + DaHua = 37777, + YuShi = 8800, } /// diff --git a/EC.Helper/CameraSDK/Common/ICameraSDK.cs b/EC.Helper/CameraSDK/Common/ICameraSDK.cs index b23107a..1bcd3a5 100644 --- a/EC.Helper/CameraSDK/Common/ICameraSDK.cs +++ b/EC.Helper/CameraSDK/Common/ICameraSDK.cs @@ -46,7 +46,7 @@ public abstract class ICameraSDK /// 获取 ptz /// /// - public abstract PtzInfo GetPtzInfo(); + public abstract bool GetPtzInfo(out PtzInfo ptzInfo); #endregion Main Method } \ No newline at end of file diff --git a/EC.Helper/CameraSDK/DaHua/DaHuaSDK.cs b/EC.Helper/CameraSDK/DaHua/DaHuaSDK.cs index 478746e..e7cb626 100644 --- a/EC.Helper/CameraSDK/DaHua/DaHuaSDK.cs +++ b/EC.Helper/CameraSDK/DaHua/DaHuaSDK.cs @@ -82,10 +82,10 @@ public class DaHuaSDK : ICameraSDK } } - public override PtzInfo GetPtzInfo() + public override bool GetPtzInfo(out PtzInfo ptzInfo) { bool ret = ConnectSuccess(); - if (!ret) return PtzInfo.Default; + if (!ret) { ptzInfo = PtzInfo.Default; return false; } DaHuaOriSDK.DH_PTZ_LOCATION_INFO entity = new(); int nBufLen = GPIParams.Size; @@ -95,11 +95,12 @@ public class DaHuaSDK : ICameraSDK try { ret = DaHuaOriSDK.CLIENT_QueryDevState(LoginId, (int)DaHuaOriSDK.EM_DEVICE_STATE.PTZ_LOCATION, ptrBuf, nBufLen, ref pRetLen, 3000); - if (!ret) { BuildException(); return PtzInfo.Default; } + if (!ret) { BuildException(); ptzInfo = PtzInfo.Default; return false; } object? objBuf = Marshal.PtrToStructure(ptrBuf, GPIParams.Type); - if (objBuf == null) return PtzInfo.Default; + if (objBuf == null) { ptzInfo = PtzInfo.Default; return false; } entity = (DaHuaOriSDK.DH_PTZ_LOCATION_INFO)objBuf; - return PtzInfo.New(entity.nPTZPan, entity.nPTZTilt, entity.nPTZZoom); + ptzInfo = PtzInfo.New(entity.nPTZPan, entity.nPTZTilt, entity.nPTZZoom); + return true; } finally { diff --git a/EC.Helper/CameraSDK/HiK/HiKSDK.cs b/EC.Helper/CameraSDK/HiK/HiKSDK.cs index 1185f37..7764f02 100644 --- a/EC.Helper/CameraSDK/HiK/HiKSDK.cs +++ b/EC.Helper/CameraSDK/HiK/HiKSDK.cs @@ -68,10 +68,10 @@ public class HiKSDK : ICameraSDK } } - public override PtzInfo GetPtzInfo() + public override bool GetPtzInfo(out PtzInfo ptzInfo) { bool ret = ConnectSuccess(); - if (!ret) return PtzInfo.Default; + if (!ret) { ptzInfo = PtzInfo.Default; return false; } HiKOriSDK.NET_DVR_PTZPOS entity = new(); int dwSize = GPIParams.Size; @@ -81,11 +81,12 @@ public class HiKSDK : ICameraSDK try { ret = HiKOriSDK.NET_DVR_GetDVRConfig(LoginId, HiKOriSDK.NET_DVR_GET_PTZPOS, 0, ptrBuf, (uint)dwSize, ref dwReturned); - if (!ret) { BuildException(); return PtzInfo.Default; } + if (!ret) { BuildException(); ptzInfo = PtzInfo.Default; return false; } object? objBuf = Marshal.PtrToStructure(ptrBuf, GPIParams.Type); - if (objBuf == null) return PtzInfo.Default; + if (objBuf == null) { ptzInfo = PtzInfo.Default; return false; } entity = (HiKOriSDK.NET_DVR_PTZPOS)objBuf; - return PtzInfo.New(entity.wPanPos, entity.wTiltPos, entity.wZoomPos); + ptzInfo = PtzInfo.New(entity.wPanPos, entity.wTiltPos, entity.wZoomPos); + return true; } finally { diff --git a/EC.Helper/CameraSDK/YuShi/YuShiSDK.cs b/EC.Helper/CameraSDK/YuShi/YuShiSDK.cs index 0d810d8..f62a409 100644 --- a/EC.Helper/CameraSDK/YuShi/YuShiSDK.cs +++ b/EC.Helper/CameraSDK/YuShi/YuShiSDK.cs @@ -58,16 +58,17 @@ public class YuShiSDK : ICameraSDK #region Main Method - public override PtzInfo GetPtzInfo() + public override bool GetPtzInfo(out PtzInfo ptzInfo) { bool ret = ConnectSuccess(); - if (!ret) return PtzInfo.Default; + if (!ret) { ptzInfo = PtzInfo.Default; return false; } YuShiOriSDK.NETDEV_PTZ_STATUS_S entity = new(); ret = YuShiOriSDK.NETDEV_PTZGetStatus(LoginId, 1, ref entity); - if (!ret) { BuildException(); return PtzInfo.Default; } + if (!ret) { BuildException(); ptzInfo = PtzInfo.Default; return false; } - return PtzInfo.New(entity.fPanTiltX, entity.fPanTiltY, entity.fZoomX); + ptzInfo = PtzInfo.New(entity.fPanTiltX, entity.fPanTiltY, entity.fZoomX); + return true; } #endregion Main Method diff --git a/EC.Helper/Test/CameraSDKTest.cs b/EC.Helper/Test/CameraSDKTest.cs deleted file mode 100644 index b7d44ac..0000000 --- a/EC.Helper/Test/CameraSDKTest.cs +++ /dev/null @@ -1,124 +0,0 @@ -using EC.Helper.CameraSDK; - -namespace EC.Helper.Test; - -public class CameraSDKTest -{ - public static void Test() - { - //HiKTest(); - //DaHuaTest(); - //YuShiTest(); - } - - public static void HiKTest() - { - Console.WriteLine("====HiK=========================="); - - try - { - string ip = "192.168.1.65"; - string username = "admin"; - string password = "hk123456"; - int type = (int)CameraType.HiK; - CameraInfo cameraInfo = CameraInfo.New(type, ip, username, password); - ICameraSDK sdk = new HiKSDK(cameraInfo); - ICameraSDK sdk2 = new HiKSDK(cameraInfo); - sdk.Init(); - sdk2.Init(); - - PtzInfo ptzInfo = sdk.GetPtzInfo(); - Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}"); - - sdk.Destory(); - - Thread.Sleep(1000); - - ptzInfo = sdk.GetPtzInfo(); - Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}"); - - ptzInfo = sdk2.GetPtzInfo(); - Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - Console.WriteLine("================================="); - } - - public static void DaHuaTest() - { - Console.WriteLine("====DaHua========================"); - - try - { - string ip = "192.168.1.71"; - string username = "admin"; - string password = "hk123456"; - int type = (int)CameraType.DaHua; - CameraInfo cameraInfo = CameraInfo.New(type, ip, username, password); - ICameraSDK sdk = new DaHuaSDK(cameraInfo); - ICameraSDK sdk2 = new DaHuaSDK(cameraInfo); - sdk.Init(); - sdk2.Init(); - PtzInfo ptzInfo = sdk.GetPtzInfo(); - Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}"); - - sdk.Destory(); - - Thread.Sleep(1000); - - ptzInfo = sdk.GetPtzInfo(); - Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}"); - - ptzInfo = sdk2.GetPtzInfo(); - Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - - Console.WriteLine("================================="); - } - - public static void YuShiTest() - { - Console.WriteLine("====YuShi========================"); - - try - { - string ip = "192.168.1.109"; - string username = "admin"; - string password = "hk123456"; - int type = (int)CameraType.YuShi; - CameraInfo cameraInfo = CameraInfo.New(type, ip, username, password); - ICameraSDK sdk = new YuShiSDK(cameraInfo); - ICameraSDK sdk2 = new YuShiSDK(cameraInfo); - sdk.Init(); - sdk2.Init(); - PtzInfo ptzInfo = sdk.GetPtzInfo(); - Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}"); - - sdk.Destory(); - - Thread.Sleep(1000); - - ptzInfo = sdk.GetPtzInfo(); - Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}"); - - ptzInfo = sdk2.GetPtzInfo(); - Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - - Console.WriteLine("================================="); - } -} \ No newline at end of file diff --git a/Frontend/src/views/page/cameraCenter.vue b/Frontend/src/views/page/cameraCenter.vue index c700f39..70f8415 100644 --- a/Frontend/src/views/page/cameraCenter.vue +++ b/Frontend/src/views/page/cameraCenter.vue @@ -76,6 +76,7 @@ export default defineComponent({ loadTreeData() { cameraApi.GetList().then((res) => { let list: Array = res.data.data; + console.log(res); for (let item of list) { this.cameraMap.set(item.id, item); this.treeData!.push({title: item.ip, key: item.id});