Compare commits

...

64 Commits

Author SHA1 Message Date
Kimdiego2098
65c695d9ce 更新版本2.1.0 2023-08-25 19:45:28 +08:00
Kimdiego2098
57253fe46a 更新解决方案 2023-08-25 19:38:47 +08:00
Kimdiego2098
4e5c443440 更新DLT645文档 2023-08-25 19:33:33 +08:00
Kimdiego2098
0b3b73d8ec 添加DLT645_2007协议插件 2023-08-25 19:33:08 +08:00
Kimdiego2098
921eabc134 调整Test位置 2023-08-25 19:32:27 +08:00
Kimdiego2098
0faa428751 调整非主从协议的状态判断策略;OPCUA去除主动连接 2023-08-25 17:23:00 +08:00
Kimdiego2098
f71a2fdd63 crc校验优化 2023-08-22 17:01:10 +08:00
Kimdiego2098
4eb9ed8aba OPCUAClient添加是否使用SourceTime的选项 2023-08-22 16:15:34 +08:00
Kimdiego2098
d7b549abb8 更新文档 2023-08-22 12:21:45 +08:00
Kimdiego2098
95d723c578 2.0.9.3 2023-08-22 11:31:36 +08:00
Kimdiego2098
2fcd853e86 去除mqtt throw an _MqttConnectingFailedException_.报错信息 2023-08-22 11:26:22 +08:00
Kimdiego2098
07eef7c812 更新批量写入方法,注意rpc入口参数变化,mqtt等RPC接口参数变化 2023-08-22 11:23:03 +08:00
Kimdiego2098
b01e0757fa 修正部分代码格式 2023-08-21 19:59:07 +08:00
Kimdiego2098
32844a20c6 2.0.9.2 2023-08-19 12:08:49 +08:00
Kimdiego2098
5b6532c601 xml 2023-08-19 11:06:05 +08:00
Kimdiego2098
2c5b4b4027 修复TcpClient重复释放导致锁异常 2023-08-19 11:05:29 +08:00
Kimdiego2098
72d7ecf195 mas1.0.2默认中文 2023-08-18 18:36:30 +08:00
Kimdiego2098
2cfa6b4306 更新masa1.0.2 2023-08-18 13:59:17 +08:00
Kimdiego2098
6f6ffde0ab 2.0.9.1 2023-08-18 13:33:45 +08:00
Kimdiego2098
1694739a16 修改锁为EasyLock 2023-08-18 12:07:01 +08:00
Kimdiego2098
95d1e8bfca 代码文件编码统一utf-8 2023-08-18 09:57:03 +08:00
Kimdiego2098
60dec08e3c 更换DEMO Include为PackageReference 2023-08-17 15:30:35 +08:00
Kimdiego2098
a99d71be93 底层驱动添加netstandard输出 2023-08-17 15:24:07 +08:00
Kimdiego2098
f1331b6a0c 2.0.8 2023-08-17 10:58:48 +08:00
Kimdiego2098
10d66b642b 调整readme,方便copy账密 2023-08-17 10:28:47 +08:00
Kimdiego2098
cd2310e4a8 优化变量地址输入分割方法;s7读写字符串添加默认编码 2023-08-17 09:50:10 +08:00
Kimdiego2098
1b399cf6b0 优化s7读写字符串,更改特殊方法为读写共用 2023-08-16 17:20:20 +08:00
Kimdiego2098
877445bc0a 修复写入返回结果时的解析,0XFF为成功 2023-08-16 15:56:25 +08:00
Kimdiego2098
9a5b345bde 修复s7字符串打包读取 2023-08-16 15:47:37 +08:00
Kimdiego2098
fc9e8ea7b3 修复s7字符串读取 2023-08-16 15:35:15 +08:00
Kimdiego2098
32be6fcfc1 主动释放锁 2023-08-16 14:56:47 +08:00
Kimdiego2098
49847236c2 OPCUA死区不再固定传入 2023-08-16 14:21:19 +08:00
Kimdiego2098
d8424443e6 fix: 优化JsonUtils中的获取type语句顺序 2023-08-16 08:59:18 +08:00
Kimdiego2098
f3b571ec3f OPC系列增加导出excel/导入系统双选项 2023-08-15 17:38:40 +08:00
Kimdiego2098
99318bb5d7 OPCUA采集设备写入字符串,不再需要传入双引号 2023-08-15 14:15:39 +08:00
Kimdiego2098
1aa154c9aa 历史数据/报警 线程初始化时不再阻塞 2023-08-15 12:12:00 +08:00
Kimdiego2098
c65d8a445b 更改ItemGroup Condition条件 2023-08-14 17:36:59 +08:00
Kimdiego2098
80f4f85570 传播token;
更新admin解决方案
2023-08-14 16:43:30 +08:00
Kimdiego2098
5beee43a6b 优化适配器解析代码 2023-08-14 14:21:00 +08:00
Kimdiego2098
8d6ae203a0 2.0.6 2023-08-13 16:57:12 +08:00
Kimdiego2098
4353479a5c OPCUACClient订阅初始化添加trycatch 2023-08-13 16:29:59 +08:00
Kimdiego2098
34d7687f9e Merge branch 'master' of https://gitee.com/dotnetchina/ThingsGateway 2023-08-13 15:53:33 +08:00
Kimdiego2098
b1dc3cf4af 更新opcuaclient,初始读取server类型改为动态读取 2023-08-13 15:50:47 +08:00
Diego2098
6a58b95933 更新nuget包 2023-08-12 12:09:50 +08:00
Kimdiego2098
d3badfd02b 修复批量令牌强退失效 2023-08-11 15:15:50 +08:00
Kimdiego2098
0098be057b 中间变量导入时添加标识 2023-08-11 14:15:22 +08:00
Kimdiego2098
6f972aa515 2.0.5 2023-08-10 18:23:40 +08:00
Kimdiego2098
7407ba6313 去除不需要的模板 2023-08-10 16:28:52 +08:00
Kimdiego2098
1c79de207b 修改详情模板 2023-08-10 11:23:18 +08:00
Kimdiego2098
257c79db92 添加自定义详情模板 2023-08-10 10:35:19 +08:00
Kimdiego2098
9d1934a308 底层修改:如果连接端口断开,停止等待返回 2023-08-10 10:35:01 +08:00
Kimdiego2098
d70f959902 上传DTO添加 单位 参数 2023-08-10 09:09:09 +08:00
Kimdiego2098
e4d810222f 调整调试页面 2023-08-09 23:45:53 +08:00
Kimdiego2098
bc1af4ae07 添加单文件发布配置 2023-08-09 15:12:55 +08:00
Kimdiego2098
6e688ef43f 去除页面多余引号 2023-08-09 13:45:27 +08:00
Kimdiego2098
f0fe1b23dc 更新2.0.4 2023-08-09 13:00:10 +08:00
Kimdiego2098
aaf2006401 更新opcua写入 2023-08-09 12:43:05 +08:00
Kimdiego2098
b821e26935 更新opcua调试页面 2023-08-09 12:01:23 +08:00
Kimdiego2098
7ae4287157 更新opcua 2023-08-09 11:47:04 +08:00
Kimdiego2098
c6fcc38a65 修复中间变量导入错误 2023-08-09 09:00:49 +08:00
Kimdiego2098
ab2d5c8853 修正错误注释 2023-08-08 18:09:23 +08:00
Kimdiego2098
5e557ff0bc opcua添加初始化连接错误重试 2023-08-08 18:04:24 +08:00
Kimdiego2098
918ca449a1 更新readme 2023-08-08 16:14:06 +08:00
Kimdiego2098
8e73368008 优化大量设备线程重启的耗时 2023-08-08 14:02:00 +08:00
295 changed files with 7093 additions and 2012 deletions

View File

@@ -5,12 +5,11 @@
**NetCore** 跨平台边缘采集网关(工业设备采集) **NetCore** 跨平台边缘采集网关(工业设备采集)
**ThingsGateway** 存储库同时提供 [**设备采集驱动**](https://www.nuget.org/profiles/KimDiego) **ThingsGateway** 存储库同时提供 [**设备采集驱动**](https://www.nuget.org/packages?q=Tags%3A%22ThingsGateway%22)
**ThingsGateway** 存储库同时提供 **基于Blazor的权限框架** 查看 [**ThingsGateway.Admin**](https://gitee.com/dotnetchina/ThingsGateway/blob/master/framework/ThingsGateway.Admin.sln) **ThingsGateway** 存储库同时提供 **基于Blazor的权限框架** 查看 [**ThingsGateway.Admin**](https://gitee.com/dotnetchina/ThingsGateway/blob/master/framework/ThingsGateway.Admin.sln)
## 文档 ## 文档
[ThingsGateway](https://diego2098.gitee.io/thingsgateway-docs/) 文档。 [ThingsGateway](https://diego2098.gitee.io/thingsgateway-docs/) 文档。
@@ -23,7 +22,9 @@
[ThingsGateway演示地址](http://120.24.62.140:5000/) [ThingsGateway演示地址](http://120.24.62.140:5000/)
账户 : **superAdmin** 密码 : **111111** 账户 : **superAdmin**
密码 : **111111**
## 赞助 ## 赞助

View File

@@ -81,6 +81,15 @@ dotnet_diagnostic.CA2208.severity = none
# IDE0057: 使用范围运算符 # IDE0057: 使用范围运算符
dotnet_diagnostic.IDE0057.severity = none dotnet_diagnostic.IDE0057.severity = none
# IDE0056: 使用索引运算符
dotnet_diagnostic.IDE0056.severity = none
# CA1830: 最好使用 StringBuilder 的强类型 Append 和 Insert 方法重载
dotnet_diagnostic.CA1830.severity = none
# CA1847: 将字符型文本用于单个字符查找
dotnet_diagnostic.CA1847.severity = none
[*.vb] [*.vb]
#### 命名样式 #### #### 命名样式 ####

View File

@@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks> <TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<Version>2.0.3.0</Version> <Version>2.1.0.0</Version>
<Authors>Diego</Authors> <Authors>Diego</Authors>
<Product>ThingsGateway</Product> <Product>ThingsGateway</Product>
<Copyright>© 2023-present Diego</Copyright> <Copyright>© 2023-present Diego</Copyright>

View File

@@ -19,7 +19,7 @@ using ThingsGateway.Admin.Core;
namespace ThingsGateway.Admin.Application; namespace ThingsGateway.Admin.Application;
/// <summary> /// <summary>
/// 后台登录控制器 /// 文件下载
/// </summary> /// </summary>
[ApiDescriptionSettings(CateGoryConst.ThingsGatewayAdmin, Order = 200)] [ApiDescriptionSettings(CateGoryConst.ThingsGatewayAdmin, Order = 200)]
[Route("file")] [Route("file")]

View File

@@ -30,7 +30,7 @@
</member> </member>
<member name="T:ThingsGateway.Admin.Application.FileController"> <member name="T:ThingsGateway.Admin.Application.FileController">
<summary> <summary>
后台登录控制器 文件下载
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Admin.Application.FileController.#ctor(ThingsGateway.Admin.Application.IFileService,ThingsGateway.Admin.Application.IOperateLogService,ThingsGateway.Admin.Application.IVisitLogService)"> <member name="M:ThingsGateway.Admin.Application.FileController.#ctor(ThingsGateway.Admin.Application.IFileService,ThingsGateway.Admin.Application.IOperateLogService,ThingsGateway.Admin.Application.IVisitLogService)">

View File

@@ -52,8 +52,8 @@ public class OpenApiSessionService : DbRepository<OpenApiUser>, IOpenApiSessionS
//获取该用户的verificat信息 //获取该用户的verificat信息
List<VerificatInfo> verificatInfos = await _verificatService.GetOpenApiVerificatIdAsync(input.Id); List<VerificatInfo> verificatInfos = await _verificatService.GetOpenApiVerificatIdAsync(input.Id);
//当前需要踢掉用户的verificat //当前需要踢掉用户的verificat
var deleteVerificats = verificatInfos.Where(it => input.VerificatIds.Contains(it.Id)).ToList(); var setVerificats = verificatInfos.Where(it => !input.VerificatIds.Contains(it.Id)).ToList();
await _verificatService.SetOpenApiVerificatIdAsync(input.Id, deleteVerificats);//如果还有verificat则更新verificat await _verificatService.SetOpenApiVerificatIdAsync(input.Id, setVerificats);//如果还有verificat则更新verificat
} }
/// <summary> /// <summary>

View File

@@ -52,12 +52,11 @@ public class SessionService : DbRepository<SysUser>, ISessionService
{ {
//获取该用户的verificat信息 //获取该用户的verificat信息
List<VerificatInfo> verificatInfos = await _verificatService.GetVerificatIdAsync(input.Id); List<VerificatInfo> verificatInfos = await _verificatService.GetVerificatIdAsync(input.Id);
//当前需要踢掉用户的verificat
List<VerificatInfo> deleteVerificats = new();
//踢掉包含verificat列表的verificat信息 //踢掉包含verificat列表的verificat信息
deleteVerificats = verificatInfos.Where(it => input.VerificatIds.Contains(it.Id)).ToList(); var setVerificats = verificatInfos.Where(it => !input.VerificatIds.Contains(it.Id)).ToList();
await _verificatService.SetVerificatIdAsync(input.Id, deleteVerificats);//如果还有verificat则更新verificat var deleteVerificats = verificatInfos.Where(it => input.VerificatIds.Contains(it.Id)).ToList();
await _verificatService.SetVerificatIdAsync(input.Id, setVerificats);//如果还有verificat则更新verificat
var message = "您已被强制下线!"; var message = "您已被强制下线!";
await _noticeService.LogoutAsync(input.Id, deleteVerificats, message);//通知下线 await _noticeService.LogoutAsync(input.Id, deleteVerificats, message);//通知下线

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -20,19 +20,19 @@ namespace ThingsGateway.Admin.Blazor.Core;
public partial class AppBarItems public partial class AppBarItems
{ {
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 链接
/// </summary> /// </summary>
[Parameter] [Parameter]
public string CONFIG_COPYRIGHT_URL { get; set; } public string CONFIG_COPYRIGHT_URL { get; set; }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>Ȩ /// 版权
/// </summary> /// </summary>
[Parameter] [Parameter]
public string CONFIG_COPYRIGHT { get; set; } public string CONFIG_COPYRIGHT { get; set; }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 标题
/// </summary> /// </summary>
[Parameter] [Parameter]
public string CONFIG_TITLE { get; set; } public string CONFIG_TITLE { get; set; }

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -14,7 +14,7 @@ using Microsoft.AspNetCore.Components;
namespace ThingsGateway.Admin.Blazor.Core; namespace ThingsGateway.Admin.Blazor.Core;
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><><CDA3> <20>ı<EFBFBD><C4B1><EFBFBD>ʾ /// 启用/停用 文本提示
/// </summary> /// </summary>
public partial class EnableChip public partial class EnableChip
{ {
@@ -46,5 +46,5 @@ public partial class EnableChip
private string TextColor => Value ? "green" : "error"; private string TextColor => Value ? "green" : "error";
private string Color => Value ? "green-lighten" : "warning-lighten"; private string Color => Value ? "green-lighten" : "warning-lighten";
private string Label => Value ? EnabledLabel ?? "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" : DisabledLabel ?? "ͣ<EFBFBD><EFBFBD>"; private string Label => Value ? EnabledLabel ?? "启用" : DisabledLabel ?? "停用";
} }

View File

@@ -1,18 +1,18 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
namespace ThingsGateway.Admin.Blazor.Core; namespace ThingsGateway.Admin.Blazor.Core;
/// <summary> /// <summary>
/// <EFBFBD>ղ<EFBFBD>/<2F><><EFBFBD>ݷ<EFBFBD>ʽ /// 收藏/快捷方式
/// </summary> /// </summary>
public partial class Favorite public partial class Favorite
{ {

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -22,17 +22,17 @@ public partial class Foter
{ {
private string Version = ""; private string Version = "";
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 链接
/// </summary> /// </summary>
[Parameter] [Parameter]
public string CONFIG_COPYRIGHT_URL { get; set; } public string CONFIG_COPYRIGHT_URL { get; set; }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>Ȩ /// 版权
/// </summary> /// </summary>
[Parameter] [Parameter]
public string CONFIG_COPYRIGHT { get; set; } public string CONFIG_COPYRIGHT { get; set; }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 标题
/// </summary> /// </summary>
[Parameter] [Parameter]
public string CONFIG_TITLE { get; set; } public string CONFIG_TITLE { get; set; }

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -20,23 +20,23 @@ namespace ThingsGateway.Admin.Blazor.Core;
public partial class Logo public partial class Logo
{ {
/// <summary> /// <summary>
/// Logo<EFBFBD>߶<EFBFBD> /// Logo高度
/// </summary> /// </summary>
[Parameter] [Parameter]
public int HeightInt { get; set; } public int HeightInt { get; set; }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 链接
/// </summary> /// </summary>
[Parameter] [Parameter]
public string CONFIG_COPYRIGHT_URL { get; set; } public string CONFIG_COPYRIGHT_URL { get; set; }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>Ȩ /// 版权
/// </summary> /// </summary>
[Parameter] [Parameter]
public string CONFIG_COPYRIGHT { get; set; } public string CONFIG_COPYRIGHT { get; set; }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 标题
/// </summary> /// </summary>
[Parameter] [Parameter]
public string CONFIG_TITLE { get; set; } public string CONFIG_TITLE { get; set; }

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -34,7 +34,7 @@ public partial class PageTabs
return op; return op;
} }
/// <summary> /// <summary>
/// Tabsʵ<EFBFBD><EFBFBD> /// Tabs实例
/// </summary> /// </summary>
public PPageTabs PPageTabs { get; private set; } public PPageTabs PPageTabs { get; private set; }
@@ -46,7 +46,7 @@ public partial class PageTabs
[Parameter] [Parameter]
public IEnumerable<string> SelfPatterns { get; set; } public IEnumerable<string> SelfPatterns { get; set; }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 子组件
/// </summary> /// </summary>
[Parameter] [Parameter]
public RenderFragment ChildContent { get; set; } public RenderFragment ChildContent { get; set; }

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -49,11 +49,11 @@ public partial class UserMenu
var ret = str?.ToJsonWithT<UnifyResult<string>>(); var ret = str?.ToJsonWithT<UnifyResult<string>>();
if (ret?.Code != 200) if (ret?.Code != 200)
{ {
await PopupService.EnqueueSnackbarAsync("ע<EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD>", AlertTypes.Error); await PopupService.EnqueueSnackbarAsync("注销失败", AlertTypes.Error);
} }
else else
{ {
await PopupService.EnqueueSnackbarAsync("ע<EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); await PopupService.EnqueueSnackbarAsync("注销成功", AlertTypes.Success);
await Task.Delay(500); await Task.Delay(500);
NavigationManager.NavigateTo(NavigationManager.Uri); NavigationManager.NavigateTo(NavigationManager.Uri);
} }

View File

@@ -0,0 +1,68 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using Furion.DependencyInjection;
namespace BlazorComponent.I18n;
/// <summary>
/// CookieStorage
/// </summary>
public class CookieStorage : IScoped
{
private readonly IJSRuntime _jsRuntime;
/// <summary>
/// CookieStorage
/// </summary>
/// <param name="jsRuntime"></param>
public CookieStorage(IJSRuntime jsRuntime)
{
_jsRuntime = jsRuntime;
}
/// <summary>
/// GetCookieAsync
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public async Task<string> GetCookieAsync(string key)
{
return await _jsRuntime.InvokeAsync<string>(JsInteropConstants.GetCookie, key);
}
/// <summary>
/// GetCookie
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public string GetCookie(string key)
{
if (_jsRuntime is IJSInProcessRuntime jsInProcess)
{
return jsInProcess.Invoke<string>(JsInteropConstants.GetCookie, key);
}
return null;
}
/// <summary>
/// SetItemAsync
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="value"></param>
public async void SetItemAsync<T>(string key, T value)
{
try
{
await _jsRuntime.InvokeVoidAsync(JsInteropConstants.SetCookie, key, value?.ToString());
}
catch
{
}
}
}

View File

@@ -10,6 +10,8 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
using BlazorComponent;
using Furion; using Furion;
using Masa.Blazor; using Masa.Blazor;
@@ -61,6 +63,8 @@ public class Startup : AppStartup
}); });
options.Locale = new Locale("zh-CN", "en-US");
}); });
services.AddScoped<InitTimezone>(); services.AddScoped<InitTimezone>();

View File

@@ -14,8 +14,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Masa.Blazor" Version="1.0.1" /> <PackageReference Include="Masa.Blazor" Version="1.0.2" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.9" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.10" />
</ItemGroup> </ItemGroup>

View File

@@ -857,5 +857,38 @@
设置深浅主题统一由这个方法为入口 设置深浅主题统一由这个方法为入口
</summary> </summary>
</member> </member>
<member name="T:BlazorComponent.I18n.CookieStorage">
<summary>
CookieStorage
</summary>
</member>
<member name="M:BlazorComponent.I18n.CookieStorage.#ctor(Microsoft.JSInterop.IJSRuntime)">
<summary>
CookieStorage
</summary>
<param name="jsRuntime"></param>
</member>
<member name="M:BlazorComponent.I18n.CookieStorage.GetCookieAsync(System.String)">
<summary>
GetCookieAsync
</summary>
<param name="key"></param>
<returns></returns>
</member>
<member name="M:BlazorComponent.I18n.CookieStorage.GetCookie(System.String)">
<summary>
GetCookie
</summary>
<param name="key"></param>
<returns></returns>
</member>
<member name="M:BlazorComponent.I18n.CookieStorage.SetItemAsync``1(System.String,``0)">
<summary>
SetItemAsync
</summary>
<typeparam name="T"></typeparam>
<param name="key"></param>
<param name="value"></param>
</member>
</members> </members>
</doc> </doc>

View File

@@ -153,7 +153,7 @@ public class UserResoures : IDisposable
{ {
if (MasaBlazor.Theme.Dark != isDark || isDark == null) if (MasaBlazor.Theme.Dark != isDark || isDark == null)
MasaBlazor.ToggleTheme(); MasaBlazor.ToggleTheme();
_cookieStorage?.SetItemAsync(BlazorResourceConst.ThemeCookieKey, isDark.ToJsonString()); _cookieStorage?.SetItemAsync(BlazorResourceConst.ThemeCookieKey, MasaBlazor.Theme.Dark.ToJsonString());
} }
private void InitCookie(IRequestCookieCollection cookies) private void InitCookie(IRequestCookieCollection cookies)

View File

@@ -48,8 +48,7 @@
var controllerTypes = App.EffectiveTypes. var controllerTypes = App.EffectiveTypes.
Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass
&& u.IsDefined(typeof(Microsoft.AspNetCore.Components.RouteAttribute), false)) && u.IsDefined(typeof(Microsoft.AspNetCore.Components.RouteAttribute), false))
.Where(it => it.Assembly != typeof(BlazorApp).Assembly) .Where(it => it.Assembly != typeof(BlazorApp).Assembly);
;
var assemblys = controllerTypes?.Select(it => it.Assembly)?.Distinct(); var assemblys = controllerTypes?.Select(it => it.Assembly)?.Distinct();
return assemblys; return assemblys;
} }

View File

@@ -189,7 +189,7 @@
} }
else else
{ {
if (ItemColWithDTTemplate!=null) if (ItemColWithDTTemplate != null)
{ {
@ItemColWithDTTemplate(context) @ItemColWithDTTemplate(context)
} }
@@ -220,7 +220,7 @@
} }
} }
} }
</ItemColContent> </ItemColContent>
@@ -310,16 +310,24 @@
{ {
string value = DetailModelPairs[item.Value]; string value = DetailModelPairs[item.Value];
{ {
<tr @key="item.Text"> @if (Detailemplate != null)
<td class="text-start table-minwidth"> {
@item.Text @Detailemplate((item,value))
</td> }
<td class="text-start "> else
<div style="word-break:break-all; white-space:pre-wrap;"> {
@value <tr @key="item.Text">
</div> <td class="text-start table-minwidth">
</td> @item.Text
</tr> </td>
<td class="text-start ">
<div style="word-break:break-all; white-space:pre-wrap;">
@value
</div>
</td>
</tr>
}
} }
} }
} }

View File

@@ -72,12 +72,6 @@ public partial class AppDataTable<TItem, SearchItem, AddItem, EditItem> : IAppDa
[Parameter] [Parameter]
public bool Dense { get; set; } public bool Dense { get; set; }
/// <summary>
/// 获得/设置 明细行模板
/// </summary>
[Parameter]
public RenderFragment<TItem> DetailRowTemplate { get; set; }
/// <summary> /// <summary>
/// 编辑项委托 /// 编辑项委托
/// </summary> /// </summary>
@@ -89,6 +83,11 @@ public partial class AppDataTable<TItem, SearchItem, AddItem, EditItem> : IAppDa
/// </summary> /// </summary>
[Parameter] [Parameter]
public RenderFragment<EditItem> EditTemplate { get; set; } public RenderFragment<EditItem> EditTemplate { get; set; }
/// <summary>
/// 获得/设置 详情模板
/// </summary>
[Parameter]
public RenderFragment<(DataTableHeader<TItem>, string)> Detailemplate { get; set; }
/// <summary> /// <summary>
/// 表头过滤返回DataTableHeader列表传输参数已包含全部初始表头与表头标题 /// 表头过滤返回DataTableHeader列表传输参数已包含全部初始表头与表头标题

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -18,7 +18,7 @@ using ThingsGateway.Admin.Core;
namespace ThingsGateway.Admin.Blazor; namespace ThingsGateway.Admin.Blazor;
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>ҳ /// 首页
/// </summary> /// </summary>
public partial class Index public partial class Index
{ {

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -18,7 +18,7 @@ using ThingsGateway.Admin.Core;
namespace ThingsGateway.Admin.Blazor; namespace ThingsGateway.Admin.Blazor;
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 个人设置
/// </summary> /// </summary>
public partial class UserCenter public partial class UserCenter
{ {
@@ -50,25 +50,25 @@ public partial class UserCenter
{ {
await UserCenterService.UpdateUserDefaultRazorAsync(UserManager.UserId, DefaultMenuId); await UserCenterService.UpdateUserDefaultRazorAsync(UserManager.UserId, DefaultMenuId);
await MainLayout.StateHasChangedAsync(); await MainLayout.StateHasChangedAsync();
await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success);
} }
async Task OnShortcutSaveAsync() async Task OnShortcutSaveAsync()
{ {
await UserCenterService.UpdateWorkbenchAsync(_menusChoice); await UserCenterService.UpdateWorkbenchAsync(_menusChoice);
await MainLayout.StateHasChangedAsync(); await MainLayout.StateHasChangedAsync();
await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success);
} }
async Task OnUpdatePasswordInfoAsync(FormContext context) async Task OnUpdatePasswordInfoAsync(FormContext context)
{ {
var success = context.Validate(); var success = context.Validate();
if (success) if (success)
{ {
//<EFBFBD><EFBFBD>֤<EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD> //验证成功,操作业务
_passwordInfoInput.Id = UserResoures.CurrentUser.Id; _passwordInfoInput.Id = UserResoures.CurrentUser.Id;
await UserCenterService.EditPasswordAsync(_passwordInfoInput); await UserCenterService.EditPasswordAsync(_passwordInfoInput);
await MainLayout.StateHasChangedAsync(); await MainLayout.StateHasChangedAsync();
await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD>¼", AlertTypes.Success); await PopupService.EnqueueSnackbarAsync("成功,将重新登录", AlertTypes.Success);
await Task.Delay(2000); await Task.Delay(2000);
NavigationManager.NavigateTo(NavigationManager.Uri); NavigationManager.NavigateTo(NavigationManager.Uri);
} }
@@ -78,6 +78,6 @@ public partial class UserCenter
{ {
await UserCenterService.UpdateUserInfoAsync(_updateInfoInput); await UserCenterService.UpdateUserInfoAsync(_updateInfoInput);
await MainLayout.StateHasChangedAsync(); await MainLayout.StateHasChangedAsync();
await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success);
} }
} }

View File

@@ -43,11 +43,6 @@
表格紧凑 表格紧凑
</summary> </summary>
</member> </member>
<member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.DetailRowTemplate">
<summary>
获得/设置 明细行模板
</summary>
</member>
<member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.EditCallAsync"> <member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.EditCallAsync">
<summary> <summary>
编辑项委托 编辑项委托
@@ -58,6 +53,11 @@
获得/设置 编辑模板 获得/设置 编辑模板
</summary> </summary>
</member> </member>
<member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.Detailemplate">
<summary>
获得/设置 详情模板
</summary>
</member>
<member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.FilterHeaders"> <member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.FilterHeaders">
<summary> <summary>
表头过滤返回DataTableHeader列表传输参数已包含全部初始表头与表头标题 表头过滤返回DataTableHeader列表传输参数已包含全部初始表头与表头标题

View File

@@ -9,13 +9,13 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.8.8.40" /> <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.8.8.41" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.8.8.40" /> <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.8.8.41" />
<PackageReference Include="Furion.Pure" Version="4.8.8.40" /> <PackageReference Include="Furion.Pure" Version="4.8.8.41" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.94" /> <PackageReference Include="SqlSugarCore" Version="5.1.4.102" />
<PackageReference Include="UAParser" Version="3.1.47" /> <PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /> <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
<PackageReference Include="MiniExcel" Version="1.31.0" /> <PackageReference Include="MiniExcel" Version="1.31.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -21,7 +21,7 @@ using ThingsGateway.Application;
namespace ThingsGateway.ApiController; namespace ThingsGateway.ApiController;
/// <summary> /// <summary>
/// 后台登录控制器 /// 文件下载
/// </summary> /// </summary>
[ApiDescriptionSettings(CateGoryConst.ThingsGatewayAdmin, Order = 200)] [ApiDescriptionSettings(CateGoryConst.ThingsGatewayAdmin, Order = 200)]
[Route("gatewayFile")] [Route("gatewayFile")]

View File

@@ -89,13 +89,8 @@ public class RpcControler : IDynamicApiController
[Description("写入变量")] [Description("写入变量")]
public async Task<Dictionary<string, OperResult>> WriteDeviceMethods(Dictionary<string, string> objs) public async Task<Dictionary<string, OperResult>> WriteDeviceMethods(Dictionary<string, string> objs)
{ {
Dictionary<string, OperResult> operResultDict = new(); var result = await RpcCore.InvokeDeviceMethodAsync($"WebApi-{UserManager.UserAccount}-{App.HttpContext.Connection.RemoteIpAddress.MapToIPv4()}", objs);
foreach (KeyValuePair<string, string> obj in objs) return result;
{
var result = await RpcCore.InvokeDeviceMethodAsync($"WebApi-{UserManager.UserAccount}-{App.HttpContext.Connection.RemoteIpAddress.MapToIPv4()}", obj);
operResultDict.Add(obj.Key, result);
}
return operResultDict;
} }
} }

View File

@@ -26,7 +26,7 @@
</member> </member>
<member name="T:ThingsGateway.ApiController.FileController"> <member name="T:ThingsGateway.ApiController.FileController">
<summary> <summary>
后台登录控制器 文件下载
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.ApiController.FileController.#ctor(ThingsGateway.Application.IRpcLogService,ThingsGateway.Application.IBackendLogService,ThingsGateway.Application.ICollectDeviceService,ThingsGateway.Application.IUploadDeviceService,ThingsGateway.Application.IVariableService)"> <member name="M:ThingsGateway.ApiController.FileController.#ctor(ThingsGateway.Application.IRpcLogService,ThingsGateway.Application.IBackendLogService,ThingsGateway.Application.ICollectDeviceService,ThingsGateway.Application.IUploadDeviceService,ThingsGateway.Application.IVariableService)">

View File

@@ -31,7 +31,7 @@ public class DeviceVariable : MemoryVariable
public virtual long DeviceId { get; set; } public virtual long DeviceId { get; set; }
/// <summary> /// <summary>
/// 写入表达式 /// 单位
/// </summary> /// </summary>
[SugarColumn(ColumnName = "Unit", ColumnDescription = "单位", Length = 200, IsNullable = true)] [SugarColumn(ColumnName = "Unit", ColumnDescription = "单位", Length = 200, IsNullable = true)]
[DataTable(Order = 3, IsShow = true, Sortable = true)] [DataTable(Order = 3, IsShow = true, Sortable = true)]
@@ -59,12 +59,7 @@ public class DeviceVariable : MemoryVariable
[DataTable(Order = 3, IsShow = true, Sortable = true)] [DataTable(Order = 3, IsShow = true, Sortable = true)]
public string VariableAddress { get; set; } public string VariableAddress { get; set; }
/// <summary>
/// 写入表达式
/// </summary>
[SugarColumn(ColumnName = "WriteExpressions", ColumnDescription = "写入表达式", Length = 200, IsNullable = true)]
[DataTable(Order = 7, IsShow = true, Sortable = true)]
public string WriteExpressions { get; set; }
/// <summary> /// <summary>
/// 是否中间变量 /// 是否中间变量

View File

@@ -51,7 +51,12 @@ public class MemoryVariable : BaseEntity
[SugarColumn(ColumnName = "ReadExpressions", ColumnDescription = "读取表达式", Length = 200, IsNullable = true)] [SugarColumn(ColumnName = "ReadExpressions", ColumnDescription = "读取表达式", Length = 200, IsNullable = true)]
[DataTable(Order = 7, IsShow = true, Sortable = true, CellClass = " table-text-truncate ")] [DataTable(Order = 7, IsShow = true, Sortable = true, CellClass = " table-text-truncate ")]
public string ReadExpressions { get; set; } public string ReadExpressions { get; set; }
/// <summary>
/// 写入表达式
/// </summary>
[SugarColumn(ColumnName = "WriteExpressions", ColumnDescription = "写入表达式", Length = 200, IsNullable = true)]
[DataTable(Order = 7, IsShow = true, Sortable = true)]
public string WriteExpressions { get; set; }
/// <summary> /// <summary>
/// 是否中间变量 /// 是否中间变量
/// </summary> /// </summary>

View File

@@ -20,6 +20,8 @@ public class VariableData
public long Id { get; set; } public long Id { get; set; }
/// <inheritdoc cref="MemoryVariable.Name"/> /// <inheritdoc cref="MemoryVariable.Name"/>
public string Name { get; set; } public string Name { get; set; }
/// <inheritdoc cref="DeviceVariable.Unit"/>
public string Unit { get; set; }
/// <inheritdoc cref="MemoryVariable.Description"/> /// <inheritdoc cref="MemoryVariable.Description"/>
public string Description { get; set; } public string Description { get; set; }
/// <inheritdoc cref="DeviceVariableRunTime.DeviceName"/> /// <inheritdoc cref="DeviceVariableRunTime.DeviceName"/>
@@ -36,7 +38,7 @@ public class VariableData
public bool IsOnline { get; set; } public bool IsOnline { get; set; }
/// <inheritdoc cref="MemoryVariable.ReadExpressions"/> /// <inheritdoc cref="MemoryVariable.ReadExpressions"/>
public string ReadExpressions { get; set; } public string ReadExpressions { get; set; }
/// <inheritdoc cref="DeviceVariable.WriteExpressions"/> /// <inheritdoc cref="MemoryVariable.WriteExpressions"/>
public string WriteExpressions { get; set; } public string WriteExpressions { get; set; }
/// <inheritdoc cref="DeviceVariable.IntervalTime"/> /// <inheritdoc cref="DeviceVariable.IntervalTime"/>
public int IntervalTime { get; set; } public int IntervalTime { get; set; }

View File

@@ -17,8 +17,6 @@ using Newtonsoft.Json.Linq;
using ThingsGateway.Foundation; using ThingsGateway.Foundation;
using ThingsGateway.Foundation.Serial; using ThingsGateway.Foundation.Serial;
using TouchSocket.Core;
namespace ThingsGateway.Application; namespace ThingsGateway.Application;
/// <summary> /// <summary>
/// <para></para> /// <para></para>
@@ -38,6 +36,10 @@ public abstract class CollectBase : DriverBase
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public abstract bool IsSupportRequest { get; } public abstract bool IsSupportRequest { get; }
/// <summary>
/// 一般底层驱动也有可能为null
/// </summary>
protected abstract IReadWriteDevice PLC { get; }
/// <summary> /// <summary>
/// 数据转换器 /// 数据转换器
@@ -179,10 +181,22 @@ public abstract class CollectBase : DriverBase
} }
/// <summary> /// <summary>
/// 写入变量值 /// 批量写入变量值,需返回变量名称/结果
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public abstract Task<OperResult> WriteValueAsync(DeviceVariableRunTime deviceVariable, JToken value, CancellationToken token); public virtual async Task<Dictionary<string, OperResult>> WriteValuesAsync(Dictionary<DeviceVariableRunTime, JToken> writeInfoLists, CancellationToken token)
{
if (PLC == null)
throw new("未初始化成功");
Dictionary<string, OperResult> operResults = new();
foreach (var writeInfo in writeInfoLists)
{
var result = await PLC.WriteAsync(writeInfo.Key.VariableAddress, writeInfo.Key.DataType, writeInfo.Value.ToString(), token);
await Task.Delay(10, token); //防止密集写入
operResults.Add(writeInfo.Key.Name, result);
}
return operResults;
}
/// <summary> /// <summary>
/// 初始化 /// 初始化

View File

@@ -48,92 +48,172 @@ public class RpcSingletonService : ISingleton
/// 反向RPC入口方法 /// 反向RPC入口方法
/// </summary> /// </summary>
/// <param name="sourceDes">触发该方法的源说明</param> /// <param name="sourceDes">触发该方法的源说明</param>
/// <param name="item">指定键为变量名称,值为附带方法参数或写入值</param> /// <param name="items">指定键为变量名称,值为附带方法参数或写入值</param>
/// <param name="isBlazor">如果是true不检查<see cref="MemoryVariable.RpcWriteEnable"/>字段</param> /// <param name="isBlazor">如果是true不检查<see cref="MemoryVariable.RpcWriteEnable"/>字段</param>
/// <param name="token"><see cref="CancellationToken"/> 取消源</param> /// <param name="token"><see cref="CancellationToken"/> 取消源</param>
/// <returns></returns> /// <returns></returns>
public async Task<OperResult> InvokeDeviceMethodAsync(string sourceDes, KeyValuePair<string, string> item, bool isBlazor = false, CancellationToken token = default) public async Task<Dictionary<string, OperResult>> InvokeDeviceMethodAsync(string sourceDes, Dictionary<string, string> items, bool isBlazor = false, CancellationToken token = default)
{ {
//避免并发过高这里延时10ms Dictionary<CollectDeviceCore, Dictionary<DeviceVariableRunTime, JToken>> WriteVariables = new();
await Task.Delay(10, token); Dictionary<CollectDeviceCore, Dictionary<DeviceVariableRunTime, string>> WriteMethods = new();
OperResult data = new(); Dictionary<string, OperResult> results = new();
var tag = _globalDeviceData.AllVariables.FirstOrDefault(it => it.Name == item.Key); foreach (var item in items)
if (tag == null) return new OperResult("不存在变量:" + item.Key);
if (tag.ProtectTypeEnum == ProtectTypeEnum.ReadOnly) return new OperResult("只读变量");
if (!tag.RpcWriteEnable && !isBlazor) return new OperResult("不允许远程写入");
if (tag.IsMemoryVariable == true)
{ {
return tag.SetValue(item.Value);
}
var dev = _collectDeviceHostService.CollectDeviceCores.FirstOrDefault(it => it.Device.Id == tag.DeviceId);
if (dev == null) return new OperResult("系统错误,不存在对应采集设备,请稍候重试");
if (dev.Device.DeviceStatus == DeviceStatusEnum.OffLine) return new OperResult("设备已离线");
if (dev.Device.DeviceStatus == DeviceStatusEnum.Pause) return new OperResult("设备已暂停");
if (string.IsNullOrEmpty(tag.OtherMethod))
{
//写入变量
JToken tagValue;
try
{
tagValue = JToken.Parse(item.Value);
}
catch (Exception)
{
tagValue = JToken.Parse("\"" + item.Value + "\"");
}
data = await dev.InVokeWriteAsync(tag, tagValue, token); OperResult data = new();
_logQueues.Enqueue( var tag = _globalDeviceData.AllVariables.FirstOrDefault(it => it.Name == item.Key);
new RpcLog() if (tag == null)
results.Add(item.Key, new("不存在变量:" + item.Key));
if (tag.ProtectTypeEnum == ProtectTypeEnum.ReadOnly)
results.Add(item.Key, new("只读变量:" + item.Key));
if (!tag.RpcWriteEnable && !isBlazor)
results.Add(item.Key, new("不允许远程写入:" + item.Key));
if (tag.IsMemoryVariable == true)
{
results.Add(item.Key, tag.SetValue(item.Value));
}
var dev = _collectDeviceHostService.CollectDeviceCores.FirstOrDefault(it => it.Device.Id == tag.DeviceId);
if (dev == null)
results.Add(item.Key, new OperResult("系统错误,不存在对应采集设备,请稍候重试"));
if (dev.Device.DeviceStatus == DeviceStatusEnum.OffLine)
results.Add(item.Key, new OperResult("设备已离线"));
if (dev.Device.DeviceStatus == DeviceStatusEnum.Pause)
results.Add(item.Key, new OperResult("设备已暂停"));
if (!results.ContainsKey(item.Key))
{
if (string.IsNullOrEmpty(tag.OtherMethod))
{ {
LogTime = SysDateTimeExtensions.CurrentDateTime, //写入变量
OperateMessage = data.Exception, JToken tagValue;
IsSuccess = data.IsSuccess, try
OperateMethod = WriteVariable, {
OperateObject = tag.Name, tagValue = JToken.Parse(item.Value);
OperateSource = sourceDes, }
ParamJson = item.Value, catch (Exception)
ResultJson = data.Message {
tagValue = JToken.Parse("\"" + item.Value + "\"");
}
if (WriteVariables.ContainsKey(dev))
{
WriteVariables[dev].Add(tag, tagValue);
}
else
{
WriteVariables.Add(dev, new());
WriteVariables[dev].Add(tag, tagValue);
}
}
else
{
if (WriteMethods.ContainsKey(dev))
{
WriteMethods[dev].Add(tag, item.Value);
}
else
{
WriteVariables.Add(dev, new());
WriteVariables[dev].Add(tag, item.Value);
}
} }
);
if (!data.IsSuccess)
{
_logger.LogWarning($"写入变量[{tag.Name}]失败:{data.Message}");
} }
} }
else
foreach (var item in WriteVariables)
{ {
//执行变量附带的方法
var method = dev.DeviceVariableMethodSources.FirstOrDefault(it => it.DeviceVariable == tag);
try try
{ {
data = await dev.InvokeMethodAsync(method, false, item.Value, token); var result = await item.Key.InVokeWriteAsync(item.Value, token);
foreach (var resultItem in result)
{
string operObj;
string parJson;
if (resultItem.Key.IsNullOrEmpty())
{
operObj = items.Select(x => x.Key).ToJsonString();
parJson = items.Select(x => x.Value).ToJsonString();
}
else
{
operObj = resultItem.Key;
parJson = items[resultItem.Key];
}
_logQueues.Enqueue(
new RpcLog()
{
LogTime = SysDateTimeExtensions.CurrentDateTime,
OperateMessage = resultItem.Value.Exception,
IsSuccess = resultItem.Value.IsSuccess,
OperateMethod = WriteVariable,
OperateObject = operObj,
OperateSource = sourceDes,
ParamJson = parJson,
ResultJson = resultItem.Value.Message
}
);
if (!resultItem.Value.IsSuccess)
{
_logger.LogWarning($"写入变量[{resultItem.Key}]失败:{resultItem.Value.Message}");
}
}
results.AddRange(result);
} }
catch (Exception ex) catch (Exception ex)
{ {
data = new OperResult<string>(ex); _logger.LogWarning($"写入变量异常:{ex.Message + Environment.NewLine + ex.StackTrace}");
}
_logQueues.Enqueue(
new RpcLog()
{
LogTime = SysDateTimeExtensions.CurrentDateTime,
OperateMessage = data.Exception,
IsSuccess = data.IsSuccess,
OperateMethod = tag.OtherMethod,
OperateObject = tag.Name,
OperateSource = sourceDes,
ParamJson = item.Value?.ToString(),
ResultJson = data.Message
}
);
if (!data.IsSuccess)
{
_logger.LogWarning($"执行变量[{tag.Name}]方法[{tag.OtherMethod}]失败:{data.Message}");
} }
} }
return data; foreach (var item in WriteMethods)
{
foreach (var writeMethod in item.Value)
{
//执行变量附带的方法
var method = item.Key.DeviceVariableMethodSources.FirstOrDefault(it => it.DeviceVariable == writeMethod.Key);
OperResult<string> result;
try
{
result = await item.Key.InvokeMethodAsync(method, false, writeMethod.Value, token);
results.Add(writeMethod.Key.Name, result);
}
catch (Exception ex)
{
result = new OperResult<string>(ex);
results.Add(writeMethod.Key.Name, result);
}
_logQueues.Enqueue(
new RpcLog()
{
LogTime = SysDateTimeExtensions.CurrentDateTime,
OperateMessage = result.Exception,
IsSuccess = result.IsSuccess,
OperateMethod = writeMethod.Key.OtherMethod,
OperateObject = writeMethod.Key.Name,
OperateSource = sourceDes,
ParamJson = writeMethod.Value?.ToString(),
ResultJson = result.Message
} }
);
if (!result.IsSuccess)
{
_logger.LogWarning($"执行变量[{writeMethod.Key.Name}]方法[{writeMethod.Key.OtherMethod}]失败:{result.Message}");
}
}
}
return results;
}
private async Task RpcLogInsertAsync() private async Task RpcLogInsertAsync()
{ {

View File

@@ -319,6 +319,39 @@
"UpdateUserId": null, "UpdateUserId": null,
"SortCode": 0, "SortCode": 0,
"ExtJson": null "ExtJson": null
},
{
"Id": 442505,
"FileName": "ThingsGateway.DLT645",
"AssembleName": "DLT645_2007",
"DriverTypeEnum": "Collect",
"FilePath": "Plugins/ThingsGateway.DLT645/ThingsGateway.DLT645.dll",
"CreateTime": "2023/8/6 18:22:33",
"CreateUser": "superAdmin",
"CreateUserId": 212725263002001,
"IsDelete": 0,
"UpdateTime": null,
"UpdateUser": null,
"UpdateUserId": null,
"SortCode": 0,
"ExtJson": null
},
{
"Id": 442506,
"FileName": "ThingsGateway.DLT645",
"AssembleName": "DLT645_2007OverTcp",
"DriverTypeEnum": "Collect",
"FilePath": "Plugins/ThingsGateway.DLT645/ThingsGateway.DLT645.dll",
"CreateTime": "2023/8/6 18:22:33",
"CreateUser": "superAdmin",
"CreateUserId": 212725263002001,
"IsDelete": 0,
"UpdateTime": null,
"UpdateUser": null,
"UpdateUserId": null,
"SortCode": 0,
"ExtJson": null
} }
] ]
} }

View File

@@ -55,7 +55,7 @@ public interface IVariableService : ITransient
/// <summary> /// <summary>
/// 导出 /// 导出
/// </summary> /// </summary>
Task<MemoryStream> ExportFileAsync(List<DeviceVariable> collectDeviceVariables = null); Task<MemoryStream> ExportFileAsync(List<DeviceVariable> collectDeviceVariables = null, string deviceName = null);
/// <summary> /// <summary>
/// 导出 /// 导出
/// </summary> /// </summary>

View File

@@ -318,7 +318,7 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService
/// <inheritdoc/> /// <inheritdoc/>
[OperDesc("导出采集变量表", IsRecordPar = false)] [OperDesc("导出采集变量表", IsRecordPar = false)]
public async Task<MemoryStream> ExportFileAsync(List<DeviceVariable> deviceVariables = null) public async Task<MemoryStream> ExportFileAsync(List<DeviceVariable> deviceVariables = null, string deviceName = null)
{ {
deviceVariables ??= await GetListAsync(a => !a.IsMemoryVariable); deviceVariables ??= await GetListAsync(a => !a.IsMemoryVariable);
@@ -343,7 +343,8 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService
); );
Dictionary<string, object> variableExport = new(); Dictionary<string, object> variableExport = new();
//变量实体没有包含设备名称,手动插入 //变量实体没有包含设备名称,手动插入
variableExport.Add(ExportHelpers.DeviceName, collectDeviceDicts[devData.DeviceId].Name); var devName = collectDeviceDicts.GetValueOrDefault(devData.DeviceId)?.Name ?? deviceName;
variableExport.Add(ExportHelpers.DeviceName, devName);
foreach (var item in data) foreach (var item in data)
{ {
@@ -445,7 +446,7 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService
try try
{ {
var variable = ((ExpandoObject)item).ConvertToEntity<DeviceVariable>(true); var variable = ((ExpandoObject)item).ConvertToEntity<DeviceVariable>(true);
variable.IsMemoryVariable = true;
//变量ID都需要手动补录 //变量ID都需要手动补录
variables.Add(variable); variables.Add(variable);
if (dbVariableDicts.TryGetValue(variable.Name, out var dbvar1)) if (dbVariableDicts.TryGetValue(variable.Name, out var dbvar1))

View File

@@ -37,7 +37,7 @@
<PackageReference Include="Hardware.Info" Version="11.1.1.1" /> <PackageReference Include="Hardware.Info" Version="11.1.1.1" />
<PackageReference Include="CS-Script" Version="4.8.1" /> <PackageReference Include="CS-Script" Version="4.8.1" />
<!--CS-Script与Furion冲突直接安装覆盖版本--> <!--CS-Script与Furion冲突直接安装覆盖版本-->
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.6.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.7.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -360,7 +360,7 @@
</member> </member>
<member name="P:ThingsGateway.Application.DeviceVariable.Unit"> <member name="P:ThingsGateway.Application.DeviceVariable.Unit">
<summary> <summary>
写入表达式 单位
</summary> </summary>
</member> </member>
<member name="P:ThingsGateway.Application.DeviceVariable.IntervalTime"> <member name="P:ThingsGateway.Application.DeviceVariable.IntervalTime">
@@ -378,11 +378,6 @@
变量地址,可能带有额外的信息,比如<see cref="T:ThingsGateway.Foundation.DataFormat"/> ,以;分割 变量地址,可能带有额外的信息,比如<see cref="T:ThingsGateway.Foundation.DataFormat"/> ,以;分割
</summary> </summary>
</member> </member>
<member name="P:ThingsGateway.Application.DeviceVariable.WriteExpressions">
<summary>
写入表达式
</summary>
</member>
<member name="P:ThingsGateway.Application.DeviceVariable.IsMemoryVariable"> <member name="P:ThingsGateway.Application.DeviceVariable.IsMemoryVariable">
<summary> <summary>
是否中间变量 是否中间变量
@@ -524,6 +519,11 @@
读取表达式 读取表达式
</summary> </summary>
</member> </member>
<member name="P:ThingsGateway.Application.MemoryVariable.WriteExpressions">
<summary>
写入表达式
</summary>
</member>
<member name="P:ThingsGateway.Application.MemoryVariable.IsMemoryVariable"> <member name="P:ThingsGateway.Application.MemoryVariable.IsMemoryVariable">
<summary> <summary>
是否中间变量 是否中间变量
@@ -1791,6 +1791,9 @@
<member name="P:ThingsGateway.Application.VariableData.Name"> <member name="P:ThingsGateway.Application.VariableData.Name">
<inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.Name"/> <inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.Name"/>
</member> </member>
<member name="P:ThingsGateway.Application.VariableData.Unit">
<inheritdoc cref="P:ThingsGateway.Application.DeviceVariable.Unit"/>
</member>
<member name="P:ThingsGateway.Application.VariableData.Description"> <member name="P:ThingsGateway.Application.VariableData.Description">
<inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.Description"/> <inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.Description"/>
</member> </member>
@@ -1816,7 +1819,7 @@
<inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.ReadExpressions"/> <inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.ReadExpressions"/>
</member> </member>
<member name="P:ThingsGateway.Application.VariableData.WriteExpressions"> <member name="P:ThingsGateway.Application.VariableData.WriteExpressions">
<inheritdoc cref="P:ThingsGateway.Application.DeviceVariable.WriteExpressions"/> <inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.WriteExpressions"/>
</member> </member>
<member name="P:ThingsGateway.Application.VariableData.IntervalTime"> <member name="P:ThingsGateway.Application.VariableData.IntervalTime">
<inheritdoc cref="P:ThingsGateway.Application.DeviceVariable.IntervalTime"/> <inheritdoc cref="P:ThingsGateway.Application.DeviceVariable.IntervalTime"/>
@@ -1852,6 +1855,11 @@
</summary> </summary>
<returns></returns> <returns></returns>
</member> </member>
<member name="P:ThingsGateway.Application.CollectBase.PLC">
<summary>
一般底层驱动也有可能为null
</summary>
</member>
<member name="P:ThingsGateway.Application.CollectBase.ThingsGatewayBitConverter"> <member name="P:ThingsGateway.Application.CollectBase.ThingsGatewayBitConverter">
<summary> <summary>
数据转换器 数据转换器
@@ -1903,9 +1911,9 @@
采集驱动读取 采集驱动读取
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Application.CollectBase.WriteValueAsync(ThingsGateway.Application.DeviceVariableRunTime,Newtonsoft.Json.Linq.JToken,System.Threading.CancellationToken)"> <member name="M:ThingsGateway.Application.CollectBase.WriteValuesAsync(System.Collections.Generic.Dictionary{ThingsGateway.Application.DeviceVariableRunTime,Newtonsoft.Json.Linq.JToken},System.Threading.CancellationToken)">
<summary> <summary>
写入变量值 批量写入变量值,需返回变量名称/结果
</summary> </summary>
<returns></returns> <returns></returns>
</member> </member>
@@ -2239,12 +2247,12 @@
<member name="M:ThingsGateway.Application.RpcSingletonService.#ctor(Microsoft.Extensions.Logging.ILogger{ThingsGateway.Application.RpcSingletonService})"> <member name="M:ThingsGateway.Application.RpcSingletonService.#ctor(Microsoft.Extensions.Logging.ILogger{ThingsGateway.Application.RpcSingletonService})">
<inheritdoc cref="T:ThingsGateway.Application.RpcSingletonService"/> <inheritdoc cref="T:ThingsGateway.Application.RpcSingletonService"/>
</member> </member>
<member name="M:ThingsGateway.Application.RpcSingletonService.InvokeDeviceMethodAsync(System.String,System.Collections.Generic.KeyValuePair{System.String,System.String},System.Boolean,System.Threading.CancellationToken)"> <member name="M:ThingsGateway.Application.RpcSingletonService.InvokeDeviceMethodAsync(System.String,System.Collections.Generic.Dictionary{System.String,System.String},System.Boolean,System.Threading.CancellationToken)">
<summary> <summary>
反向RPC入口方法 反向RPC入口方法
</summary> </summary>
<param name="sourceDes">触发该方法的源说明</param> <param name="sourceDes">触发该方法的源说明</param>
<param name="item">指定键为变量名称,值为附带方法参数或写入值</param> <param name="items">指定键为变量名称,值为附带方法参数或写入值</param>
<param name="isBlazor">如果是true不检查<see cref="P:ThingsGateway.Application.MemoryVariable.RpcWriteEnable"/>字段</param> <param name="isBlazor">如果是true不检查<see cref="P:ThingsGateway.Application.MemoryVariable.RpcWriteEnable"/>字段</param>
<param name="token"><see cref="T:System.Threading.CancellationToken"/> 取消源</param> <param name="token"><see cref="T:System.Threading.CancellationToken"/> 取消源</param>
<returns></returns> <returns></returns>
@@ -3172,7 +3180,7 @@
编辑变量 编辑变量
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Application.IVariableService.ExportFileAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable})"> <member name="M:ThingsGateway.Application.IVariableService.ExportFileAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable},System.String)">
<summary> <summary>
导出 导出
</summary> </summary>
@@ -3267,7 +3275,7 @@
<member name="M:ThingsGateway.Application.VariableService.MemoryVariableExportFileAsync(System.Collections.Generic.List{ThingsGateway.Application.MemoryVariable})"> <member name="M:ThingsGateway.Application.VariableService.MemoryVariableExportFileAsync(System.Collections.Generic.List{ThingsGateway.Application.MemoryVariable})">
<inheritdoc/> <inheritdoc/>
</member> </member>
<member name="M:ThingsGateway.Application.VariableService.ExportFileAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable})"> <member name="M:ThingsGateway.Application.VariableService.ExportFileAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable},System.String)">
<inheritdoc/> <inheritdoc/>
</member> </member>
<member name="M:ThingsGateway.Application.VariableService.MemoryVariablePreviewAsync(Microsoft.AspNetCore.Components.Forms.IBrowserFile)"> <member name="M:ThingsGateway.Application.VariableService.MemoryVariablePreviewAsync(Microsoft.AspNetCore.Components.Forms.IBrowserFile)">
@@ -3502,7 +3510,7 @@
执行特殊方法 执行特殊方法
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Application.CollectDeviceCore.InVokeWriteAsync(ThingsGateway.Application.DeviceVariableRunTime,Newtonsoft.Json.Linq.JToken,System.Threading.CancellationToken)"> <member name="M:ThingsGateway.Application.CollectDeviceCore.InVokeWriteAsync(System.Collections.Generic.Dictionary{ThingsGateway.Application.DeviceVariableRunTime,Newtonsoft.Json.Linq.JToken},System.Threading.CancellationToken)">
<summary> <summary>
执行变量写入 执行变量写入
</summary> </summary>
@@ -3561,6 +3569,11 @@
开始采集 开始采集
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Application.CollectDeviceThread.BeforeStopThreadAsync">
<summary>
停止采集前提前取消Token
</summary>
</member>
<member name="M:ThingsGateway.Application.CollectDeviceThread.StopThreadAsync"> <member name="M:ThingsGateway.Application.CollectDeviceThread.StopThreadAsync">
<summary> <summary>
停止采集 停止采集
@@ -3934,6 +3947,11 @@
开始上传 开始上传
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Application.UploadDeviceThread.BeforeStopThreadAsync">
<summary>
停止采集前提前取消Token
</summary>
</member>
<member name="M:ThingsGateway.Application.UploadDeviceThread.StopThreadAsync"> <member name="M:ThingsGateway.Application.UploadDeviceThread.StopThreadAsync">
<summary> <summary>
停止上传 停止上传

View File

@@ -66,7 +66,7 @@ public class AlarmWorker : BackgroundService
/// </summary> /// </summary>
public OperResult StatuString { get; set; } = new OperResult("初始化"); public OperResult StatuString { get; set; } = new OperResult("初始化");
private ConcurrentQueue<DeviceVariableRunTime> DeviceVariables { get; set; } = new(); private ConcurrentQueue<DeviceVariableRunTime> DeviceVariables { get; set; } = new();
private ConcurrentQueue<DeviceVariableRunTime> HisAlarmDeviceVariables { get; set; } = new(); private ConcurrentQueue<HistoryAlarm> HisAlarmDeviceVariables { get; set; } = new();
/// <summary> /// <summary>
/// 获取数据库链接 /// 获取数据库链接
/// </summary> /// </summary>
@@ -465,7 +465,7 @@ public class AlarmWorker : BackgroundService
OnAlarmChanged?.Invoke(item.Adapt<DeviceVariableRunTime>()); OnAlarmChanged?.Invoke(item.Adapt<DeviceVariableRunTime>());
if (!IsExited) if (!IsExited)
{ {
HisAlarmDeviceVariables.Enqueue(item); HisAlarmDeviceVariables.Enqueue(item.Adapt<HistoryAlarm>());
} }
if (eventEnum == EventEnum.Alarm) if (eventEnum == EventEnum.Alarm)
@@ -536,6 +536,7 @@ public class AlarmWorker : BackgroundService
HisAlarmTask = await Task.Factory.StartNew(async () => HisAlarmTask = await Task.Factory.StartNew(async () =>
{ {
_logger?.LogInformation($"历史报警线程开始"); _logger?.LogInformation($"历史报警线程开始");
await Task.Yield();//返回线程控制,不再阻塞
try try
{ {
await Task.Delay(500, stoppingToken.Token); await Task.Delay(500, stoppingToken.Token);
@@ -561,8 +562,14 @@ public class AlarmWorker : BackgroundService
} }
catch (Exception) catch (Exception)
{ {
if (stoppingToken.Token.IsCancellationRequested)
{
IsExited = true;
return;
}
try try
{ {
_logger.LogWarning("连接历史报警表失败,尝试初始化表");
sqlSugarClient.CodeFirst.InitTables(typeof(HistoryAlarm)); sqlSugarClient.CodeFirst.InitTables(typeof(HistoryAlarm));
isSuccess = true; isSuccess = true;
StatuString = OperResult.CreateSuccessResult(); StatuString = OperResult.CreateSuccessResult();
@@ -586,18 +593,20 @@ public class AlarmWorker : BackgroundService
//缓存值 //缓存值
var cacheData = await CacheDb.GetCacheData(); var cacheData = await CacheDb.GetCacheData();
var data = cacheData.SelectMany(a => a.CacheStr.FromJson<List<HistoryAlarm>>()).ToList(); if (cacheData.Count > 0)
try
{ {
var count = await sqlSugarClient.Insertable(data).ExecuteCommandAsync(stoppingToken.Token); var data = cacheData.SelectMany(a => a.CacheStr.FromJson<List<HistoryAlarm>>()).ToList();
await CacheDb.DeleteCacheData(cacheData.Select(a => a.Id).ToArray()); try
{
var count = await sqlSugarClient.Insertable(data).ExecuteCommandAsync(stoppingToken.Token);
await CacheDb.DeleteCacheData(cacheData.Select(a => a.Id).ToArray());
}
catch (Exception ex)
{
if (isSuccess)
_logger.LogWarning(ex, "写入历史报警失败");
}
} }
catch (Exception ex)
{
if (isSuccess)
_logger.LogWarning(ex, "写入历史报警失败");
}
if (stoppingToken.Token.IsCancellationRequested) if (stoppingToken.Token.IsCancellationRequested)
break; break;
@@ -605,16 +614,15 @@ public class AlarmWorker : BackgroundService
var list = HisAlarmDeviceVariables.ToListWithDequeue(); var list = HisAlarmDeviceVariables.ToListWithDequeue();
if (list.Count != 0) if (list.Count != 0)
{ {
var hisalarm = list.Adapt<List<HistoryAlarm>>();
////Sql保存 ////Sql保存
hisalarm.ForEach(it => list.ForEach(it =>
{ {
it.Id = YitIdHelper.NextId(); it.Id = YitIdHelper.NextId();
}); });
//插入 //插入
try try
{ {
await sqlSugarClient.Insertable(hisalarm).ExecuteCommandAsync(stoppingToken.Token); await sqlSugarClient.Insertable(list).ExecuteCommandAsync(stoppingToken.Token);
isSuccess = true; isSuccess = true;
} }
catch (Exception ex) catch (Exception ex)
@@ -622,7 +630,7 @@ public class AlarmWorker : BackgroundService
if (isSuccess) if (isSuccess)
_logger.LogWarning(ex, "写入历史报警失败"); _logger.LogWarning(ex, "写入历史报警失败");
var cacheDatas = hisalarm.ChunkTrivialBetter(500); var cacheDatas = list.ChunkTrivialBetter(500);
foreach (var a in cacheDatas) foreach (var a in cacheDatas)
{ {
await CacheDb.AddCacheData("", a.ToJson(), 50000); await CacheDb.AddCacheData("", a.ToJson(), 50000);

View File

@@ -269,6 +269,7 @@ public class CollectDeviceCore
{ {
isInitSuccess = false; isInitSuccess = false;
GlobalDeviceData.CollectDevices.RemoveWhere(it => it.Id == Device.Id); GlobalDeviceData.CollectDevices.RemoveWhere(it => it.Id == Device.Id);
easyLock.SafeDispose();
} }
} }
@@ -329,11 +330,6 @@ public class CollectDeviceCore
return ThreadRunReturn.Continue; return ThreadRunReturn.Continue;
} }
if (DeviceVariableSourceReads.Count == 0 && Device.DeviceVariableRunTimes.Where(a => string.IsNullOrEmpty(a.OtherMethod)).Any())
{
//无采集变量
return ThreadRunReturn.Continue;
}
if (token.IsCancellationRequested) if (token.IsCancellationRequested)
return ThreadRunReturn.Break; return ThreadRunReturn.Break;
@@ -437,11 +433,11 @@ public class CollectDeviceCore
if (_driver.IsConnected()) if (_driver.IsConnected())
{ {
//更新设备活动时间 //更新设备活动时间
Device.SetDeviceStatus(SysDateTimeExtensions.CurrentDateTime, 0); Device.SetDeviceStatus(SysDateTimeExtensions.CurrentDateTime, errorCount: 0);
} }
else else
{ {
Device.SetDeviceStatus(SysDateTimeExtensions.CurrentDateTime, 999); Device.SetDeviceStatus(errorCount: 999);
} }
} }
@@ -533,7 +529,7 @@ public class CollectDeviceCore
if (!string.IsNullOrEmpty(methodResult.MethodStr)) if (!string.IsNullOrEmpty(methodResult.MethodStr))
{ {
string[] strs = methodResult.MethodStr?.Trim()?.Split(';'); string[] strs = methodResult.MethodStr?.Trim()?.TrimEnd(';').Split(';');
try try
{ {
int index = 0; int index = 0;
@@ -545,6 +541,8 @@ public class CollectDeviceCore
} }
else else
{ {
if (strs.Length <= index)
continue;
//得到对于的方法参数值 //得到对于的方法参数值
methodResult.MethodObj[i] = methodResult.Converter.ConvertFrom(strs[index], ps[i].ParameterType); methodResult.MethodObj[i] = methodResult.Converter.ConvertFrom(strs[index], ps[i].ParameterType);
index++; index++;
@@ -600,8 +598,8 @@ public class CollectDeviceCore
if (!string.IsNullOrEmpty(deviceVariableMethodSource.MethodStr) || !string.IsNullOrEmpty(value)) if (!string.IsNullOrEmpty(deviceVariableMethodSource.MethodStr) || !string.IsNullOrEmpty(value))
{ {
string[] strs1 = deviceVariableMethodSource.MethodStr?.Trim()?.Split(';'); string[] strs1 = deviceVariableMethodSource.MethodStr?.Trim()?.TrimEnd(';').Split(';');
string[] strs2 = value?.Trim()?.Split(';'); string[] strs2 = value?.Trim()?.TrimEnd(';').Split(';');
//通过分号分割,并且合并参数 //通过分号分割,并且合并参数
var strs = strs1?.SpliceArray(strs2); var strs = strs1?.SpliceArray(strs2);
int index = 0; int index = 0;
@@ -667,18 +665,25 @@ public class CollectDeviceCore
if (method.HasReturn && result != null && result.IsSuccess) if (method.HasReturn && result != null && result.IsSuccess)
{ {
var content = deviceVariableMethodSource.Converter.ConvertTo(result.Content?.ToString()?.Replace($"\0", "")); var content = deviceVariableMethodSource.Converter.ConvertTo(result.Content?.ToString()?.Replace($"\0", ""));
var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(content); if (isRead)
if (!operResult.IsSuccess)
{ {
_logger?.LogWarning(operResult.Message, ToString()); var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(content);
if (!operResult.IsSuccess)
{
_logger?.LogWarning(operResult.Message, ToString());
}
} }
} }
else else
{ {
var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(null); if (isRead)
if (!operResult.IsSuccess)
{ {
_logger?.LogWarning(operResult.Message, ToString()); var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(null);
if (!operResult.IsSuccess)
{
_logger?.LogWarning(operResult.Message, ToString());
}
} }
} }
return result; return result;
@@ -707,46 +712,46 @@ public class CollectDeviceCore
/// 执行变量写入 /// 执行变量写入
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal async Task<OperResult> InVokeWriteAsync(DeviceVariableRunTime deviceVariable, JToken value, CancellationToken token) internal async Task<Dictionary<string, OperResult>> InVokeWriteAsync(Dictionary<DeviceVariableRunTime, JToken> writeInfoLists, CancellationToken token)
{ {
try try
{ {
await easyLock.WaitAsync(); await easyLock.WaitAsync();
if (IsShareChannel) _driver.InitDataAdapter(); if (IsShareChannel) _driver.InitDataAdapter();
Dictionary<string, OperResult> results = new();
foreach (var deviceVariable in writeInfoLists.Keys)
{
if (!string.IsNullOrEmpty(deviceVariable.WriteExpressions))
{
var jToken = writeInfoLists[deviceVariable];
object rawdata;
if (jToken is JValue jValue)
{
rawdata = jValue.Value;
}
else
{
rawdata = jToken.ToString();
}
object data;
try
{
data = deviceVariable.WriteExpressions.GetExpressionsResult(rawdata);
writeInfoLists[deviceVariable] = JToken.FromObject(data);
}
catch (Exception ex)
{
results.Add(deviceVariable.Name, new OperResult(deviceVariable.Name + " 转换写入表达式失败:" + ex.Message));
}
}
if (!string.IsNullOrEmpty(deviceVariable.WriteExpressions))
{
var jToken = value;
object rawdata;
if (jToken is JValue jValue)
{
rawdata = jValue.Value;
}
else
{
rawdata = jToken.ToString();
}
object data;
try
{
data = deviceVariable.WriteExpressions.GetExpressionsResult(rawdata);
var result = await _driver.WriteValueAsync(deviceVariable, JToken.FromObject(data), token);
return result;
}
catch (Exception ex)
{
return new OperResult(deviceVariable.Name + " 转换写入表达式失败:" + ex.Message);
}
} }
else var result = await _driver.WriteValuesAsync(writeInfoLists.
{ Where(a => !results.Any(b => b.Key == a.Key.Name)).
var result = await _driver.WriteValueAsync(deviceVariable, value, token); ToDictionary(item => item.Key, item => item.Value),
return result; token);
}
} return result;
catch (Exception ex)
{
return (new OperResult(ex));
} }
finally finally
{ {
@@ -754,6 +759,8 @@ public class CollectDeviceCore
} }
} }
/// <summary> /// <summary>
/// 执行轮询特殊方法,并设置变量值 /// 执行轮询特殊方法,并设置变量值
/// </summary> /// </summary>

View File

@@ -62,6 +62,7 @@ public class CollectDeviceThread : IAsyncDisposable
public async ValueTask DisposeAsync() public async ValueTask DisposeAsync()
{ {
await StopThreadAsync(); await StopThreadAsync();
easyLock.SafeDispose();
CollectDeviceCores.Clear(); CollectDeviceCores.Clear();
} }
@@ -85,6 +86,29 @@ public class CollectDeviceThread : IAsyncDisposable
easyLock.Release(); easyLock.Release();
} }
} }
/// <summary>
/// 停止采集前提前取消Token
/// </summary>
public virtual async Task BeforeStopThreadAsync()
{
try
{
await easyLock.WaitAsync();
if (DeviceTask == null)
{
return;
}
foreach (var token in StoppingTokens)
{
token.Cancel();
}
}
finally
{
easyLock.Release();
}
}
/// <summary> /// <summary>
/// 停止采集 /// 停止采集
@@ -173,7 +197,10 @@ public class CollectDeviceThread : IAsyncDisposable
foreach (var device in CollectDeviceCores) foreach (var device in CollectDeviceCores)
{ {
try try
{//初始化成功才能执行 {
if (stoppingToken.IsCancellationRequested)
break;
//初始化成功才能执行
if (device.IsInitSuccess) if (device.IsInitSuccess)
{ {
//如果是共享通道类型,需要每次转换时切换适配器 //如果是共享通道类型,需要每次转换时切换适配器

View File

@@ -328,6 +328,18 @@ public class CollectDeviceWorker : BackgroundService
/// </summary> /// </summary>
private async Task RemoveAllDeviceThreadAsync() private async Task RemoveAllDeviceThreadAsync()
{ {
await CollectDeviceThreads.ParallelForEachAsync(async (deviceThread, token) =>
{
try
{
await deviceThread.BeforeStopThreadAsync();
}
catch (Exception ex)
{
_logger?.LogError(ex, deviceThread.ToString());
}
}, 10);
await CollectDeviceThreads.ParallelForEachAsync(async (deviceThread, token) => await CollectDeviceThreads.ParallelForEachAsync(async (deviceThread, token) =>
{ {
try try

View File

@@ -167,7 +167,7 @@ public class HistoryValueWorker : BackgroundService
HistoryValueTask = await Task.Factory.StartNew(async () => HistoryValueTask = await Task.Factory.StartNew(async () =>
{ {
_logger?.LogInformation($"历史数据线程开始"); _logger?.LogInformation($"历史数据线程开始");
IsExited = false; await Task.Yield();//返回线程控制,不再阻塞
try try
{ {
var result = await GetHisDbAsync(); var result = await GetHisDbAsync();
@@ -191,8 +191,14 @@ public class HistoryValueWorker : BackgroundService
} }
catch (Exception) catch (Exception)
{ {
if (stoppingToken.Token.IsCancellationRequested)
{
IsExited = true;
return;
}
try try
{ {
_logger.LogWarning("连接历史数据表失败,尝试初始化表");
sqlSugarClient.CodeFirst.InitTables(typeof(HistoryValue)); sqlSugarClient.CodeFirst.InitTables(typeof(HistoryValue));
LastIsSuccess = true; LastIsSuccess = true;
StatuString = OperResult.CreateSuccessResult(); StatuString = OperResult.CreateSuccessResult();
@@ -204,6 +210,7 @@ public class HistoryValueWorker : BackgroundService
_logger.LogWarning(ex, "连接历史数据库失败"); _logger.LogWarning(ex, "连接历史数据库失败");
} }
} }
IsExited = false;
while (!stoppingToken.Token.IsCancellationRequested) while (!stoppingToken.Token.IsCancellationRequested)
{ {
@@ -299,7 +306,6 @@ public class HistoryValueWorker : BackgroundService
LastIsSuccess = false; LastIsSuccess = false;
} }
} }
IsExited = true;
} }
} }
@@ -317,9 +323,11 @@ public class HistoryValueWorker : BackgroundService
IsExited = true; IsExited = true;
_logger?.LogError(ex, $"历史数据循环异常"); _logger?.LogError(ex, $"历史数据循环异常");
} }
IsExited = true;
} }
, TaskCreationOptions.LongRunning); , TaskCreationOptions.LongRunning);
} }
/// <summary> /// <summary>
/// 重启 /// 重启
/// </summary> /// </summary>

View File

@@ -225,7 +225,13 @@ public class UploadDeviceCore
{ {
_logger?.LogError(ex, $"{Device.Name} 释放失败"); _logger?.LogError(ex, $"{Device.Name} 释放失败");
} }
isInitSuccess = false; finally
{
isInitSuccess = false;
easyLock.SafeDispose();
}
} }
/// <summary> /// <summary>

View File

@@ -51,6 +51,7 @@ public class UploadDeviceThread : IAsyncDisposable
public async ValueTask DisposeAsync() public async ValueTask DisposeAsync()
{ {
await StopThreadAsync(); await StopThreadAsync();
easyLock.SafeDispose();
UploadDeviceCores.Clear(); UploadDeviceCores.Clear();
} }
@@ -74,6 +75,29 @@ public class UploadDeviceThread : IAsyncDisposable
easyLock.Release(); easyLock.Release();
} }
} }
/// <summary>
/// 停止采集前提前取消Token
/// </summary>
public virtual async Task BeforeStopThreadAsync()
{
try
{
await easyLock.WaitAsync();
if (DeviceTask == null)
{
return;
}
foreach (var token in StoppingTokens)
{
token.Cancel();
}
}
finally
{
easyLock.Release();
}
}
/// <summary> /// <summary>
/// 停止上传 /// 停止上传
@@ -152,7 +176,10 @@ public class UploadDeviceThread : IAsyncDisposable
foreach (var device in UploadDeviceCores) foreach (var device in UploadDeviceCores)
{ {
try try
{//初始化成功才能执行 {
if (stoppingToken.IsCancellationRequested)
break;
//初始化成功才能执行
if (device.IsInitSuccess) if (device.IsInitSuccess)
{ {

View File

@@ -239,6 +239,17 @@ public class UploadDeviceWorker : BackgroundService
/// </summary> /// </summary>
private async Task RemoveAllDeviceThreadAsync() private async Task RemoveAllDeviceThreadAsync()
{ {
await UploadDeviceThreads.ParallelForEachAsync(async (deviceThread, token) =>
{
try
{
await deviceThread.BeforeStopThreadAsync();
}
catch (Exception ex)
{
_logger?.LogError(ex, deviceThread.ToString());
}
}, 10);
await UploadDeviceThreads.ParallelForEachAsync(async (deviceThread, token) => await UploadDeviceThreads.ParallelForEachAsync(async (deviceThread, token) =>
{ {
try try

View File

@@ -102,44 +102,6 @@
} }
@foreach (var item in ImportPreviews)
{
<MSubheader Class="mt-2 font-weight-black">
@(
$"{item.Key},预计导入{item.Value.DataCount}条数据"
)
</MSubheader>
<MSubheader Class=@((item.Value.HasError?"mt-2 red--text":"mt-2 green--text"))>
@(
(item.Value.HasError ? "出现错误" : "验证成功")
)
</MSubheader>
<MVirtualScroll Context="item1" Height=300 OverscanCount=2 ItemSize="60" Items="item.Value.Results">
<ItemContent>
<MListItem>
<MListItemAction>
<MChip Class="ma-2">
@(
$"第{item1.row}行"
)
</MChip>
</MListItemAction>
<MListItemContent>
<MListItemTitle Class=@((item1.isSuccess?"green--text":"red--text"))>
<strong>@item1.resultString</strong>
</MListItemTitle>
</MListItemContent>
</MListItem>
<MDivider></MDivider>
</ItemContent>
</MVirtualScroll>
}
</div> </div>
<div class="mt-6"> <div class="mt-6">
<MButton Color="primary" Disabled=@ImportPreviews.Any(it=>it.Value.HasError) OnClick="()=>Step=3">下一步</MButton> <MButton Color="primary" Disabled=@ImportPreviews.Any(it=>it.Value.HasError) OnClick="()=>Step=3">下一步</MButton>

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -21,7 +21,7 @@ using ThingsGateway.Application;
namespace ThingsGateway.Blazor; namespace ThingsGateway.Blazor;
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>excel /// 导入excel
/// </summary> /// </summary>
public partial class ImportExcel public partial class ImportExcel
{ {
@@ -33,21 +33,21 @@ public partial class ImportExcel
bool isSaveImport; bool isSaveImport;
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 导入
/// </summary> /// </summary>
[Parameter] [Parameter]
public Func<Dictionary<string, ImportPreviewOutputBase>, Task> Import { get; set; } public Func<Dictionary<string, ImportPreviewOutputBase>, Task> Import { get; set; }
/// <summary> /// <summary>
/// <EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD>ʾ /// 是否显示
/// </summary> /// </summary>
public bool IsShowImport { get; set; } public bool IsShowImport { get; set; }
/// <summary> /// <summary>
/// Ԥ<EFBFBD><EFBFBD> /// 预览
/// </summary> /// </summary>
[Parameter] [Parameter]
public Func<IBrowserFile, Task<Dictionary<string, ImportPreviewOutputBase>>> Preview { get; set; } public Func<IBrowserFile, Task<Dictionary<string, ImportPreviewOutputBase>>> Preview { get; set; }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 当前步数
/// </summary> /// </summary>
public int Step { get; set; } public int Step { get; set; }
@@ -75,7 +75,7 @@ public partial class ImportExcel
StateHasChanged(); StateHasChanged();
await Import.Invoke(ImportPreviews); await Import.Invoke(ImportPreviews);
_importFile = null; _importFile = null;
await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success);
} }
finally finally
{ {

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -54,7 +54,7 @@ public partial class DefalutDebugDriverPage : DriverDebugUIBase
/// </summary> /// </summary>
public UdpSessionPage UdpSessionPage; public UdpSessionPage UdpSessionPage;
/// <summary> /// <summary>
/// ѡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>1-TCPCLIENT<EFBFBD><EFBFBD>2-<2D><><EFBFBD>ڣ<EFBFBD>3-UDP<EFBFBD><EFBFBD>4-TCPServer /// 选择,1-TCPCLIENT2-串口,3-UDP4-TCPServer
/// </summary> /// </summary>
[Parameter] [Parameter]
public ChannelEnum Channel { get; set; } public ChannelEnum Channel { get; set; }
@@ -65,12 +65,12 @@ public partial class DefalutDebugDriverPage : DriverDebugUIBase
public override ThingsGateway.Foundation.IReadWriteDevice Plc { get; set; } public override ThingsGateway.Foundation.IReadWriteDevice Plc { get; set; }
/// <summary> /// <summary>
/// ģ<EFBFBD><EFBFBD> /// 模板
/// </summary> /// </summary>
[Parameter] [Parameter]
public RenderFragment ChildContent { get; set; } public RenderFragment ChildContent { get; set; }
/// <summary> /// <summary>
/// <EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD> /// 自定义模板
/// </summary> /// </summary>
[Parameter] [Parameter]
public RenderFragment OtherContent { get; set; } public RenderFragment OtherContent { get; set; }
@@ -100,7 +100,7 @@ public partial class DefalutDebugDriverPage : DriverDebugUIBase
TcpServerPage.LogAction = LogOut; TcpServerPage.LogAction = LogOut;
if (UdpSessionPage != null) if (UdpSessionPage != null)
UdpSessionPage.LogAction = LogOut; UdpSessionPage.LogAction = LogOut;
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> //载入配置
StateHasChanged(); StateHasChanged();
} }

View File

@@ -127,7 +127,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable
/// 导入设备 /// 导入设备
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task DownDeviceExportAsync(CollectDevice data) public async Task DeviceImportAsync(CollectDevice data)
{ {
try try
{ {
@@ -145,7 +145,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable
/// 导入变量 /// 导入变量
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task DownDeviceExportAsync(List<DeviceVariable> data) public async Task DeviceVariableImportAsync(List<DeviceVariable> data)
{ {
try try
{ {
@@ -159,6 +159,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable
} }
} }
/// <summary> /// <summary>
/// 导出 /// 导出
/// </summary> /// </summary>
@@ -187,6 +188,51 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable
isDownExport = false; isDownExport = false;
} }
} }
/// <summary>
/// 导出到excel
/// </summary>
/// <returns></returns>
public async Task DownDeviceExportAsync(CollectDevice data)
{
try
{
isDownExport = true;
StateHasChanged();
using var memoryStream = await CollectDeviceService.ExportFileAsync(new List<CollectDevice>() { data });
memoryStream.Seek(0, SeekOrigin.Begin);
using var streamRef = new DotNetStreamReference(stream: memoryStream);
_helper ??= await JS.InvokeAsync<IJSObjectReference>("import", $"/_content/ThingsGateway.Admin.Blazor.Core/js/downloadFileFromStream.js");
await _helper.InvokeVoidAsync("downloadFileFromStream", $"设备导出{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx", streamRef);
}
finally
{
isDownExport = false;
}
}
/// <summary>
/// 导出到excel
/// </summary>
/// <returns></returns>
public async Task DownDeviceVariableExportAsync(List<DeviceVariable> data, string devName)
{
try
{
isDownExport = true;
StateHasChanged();
using var memoryStream = await VariableService.ExportFileAsync(data, devName);
memoryStream.Seek(0, SeekOrigin.Begin);
using var streamRef = new DotNetStreamReference(stream: memoryStream);
_helper ??= await JS.InvokeAsync<IJSObjectReference>("import", $"/_content/ThingsGateway.Admin.Blazor.Core/js/downloadFileFromStream.js");
await _helper.InvokeVoidAsync("downloadFileFromStream", $"变量导出{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx", streamRef);
}
finally
{
isDownExport = false;
}
}
/// <inheritdoc/> /// <inheritdoc/>
public void LogOut(TouchSocket.Core.LogLevel logLevel, object source, string message, Exception exception) public void LogOut(TouchSocket.Core.LogLevel logLevel, object source, string message, Exception exception)
{ {

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -20,7 +20,7 @@ namespace ThingsGateway.Blazor;
public partial class SerialClientPage public partial class SerialClientPage
{ {
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 日志输出
/// </summary> /// </summary>
public Action<LogLevel, object, string, Exception> LogAction; public Action<LogLevel, object, string, Exception> LogAction;
@@ -36,7 +36,7 @@ public partial class SerialClientPage
SerialClient.SafeDispose(); SerialClient.SafeDispose();
} }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 获取对象
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public SerialClient GetSerialClient() public SerialClient GetSerialClient()
@@ -47,7 +47,7 @@ public partial class SerialClientPage
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
config.SetSerialProperty(serialProperty); config.SetSerialProperty(serialProperty);
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> //载入配置
SerialClient.Setup(config); SerialClient.Setup(config);
return SerialClient; return SerialClient;
} }
@@ -78,8 +78,7 @@ public partial class SerialClientPage
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnInitialized() protected override void OnInitialized()
{ {
config?.Dispose(); config ??= new TouchSocketConfig();
config = new TouchSocketConfig();
var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -23,7 +23,7 @@ namespace ThingsGateway.Blazor;
public partial class TcpClientPage public partial class TcpClientPage
{ {
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 日志输出
/// </summary> /// </summary>
public Action<LogLevel, object, string, Exception> LogAction; public Action<LogLevel, object, string, Exception> LogAction;
@@ -33,7 +33,7 @@ public partial class TcpClientPage
/// </summary> /// </summary>
private string IP = "127.0.0.1"; private string IP = "127.0.0.1";
/// <summary> /// <summary>
/// <EFBFBD>˿<EFBFBD> /// 端口
/// </summary> /// </summary>
[Parameter] [Parameter]
public int Port { get; set; } = 502; public int Port { get; set; } = 502;
@@ -73,18 +73,17 @@ public partial class TcpClientPage
} }
} }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 获取对象
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public TcpClientEx GetTcpClient() public TcpClientEx GetTcpClient()
{ {
config?.Dispose(); config ??= new TouchSocketConfig();
config = new TouchSocketConfig();
var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
config.SetRemoteIPHost(new IPHost(IP + ":" + Port)).SetBufferLength(300); config.SetRemoteIPHost(new IPHost(IP + ":" + Port)).SetBufferLength(300);
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> //载入配置
TcpClientEx.Setup(config); TcpClientEx.Setup(config);
return TcpClientEx; return TcpClientEx;
} }

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -19,7 +19,7 @@ namespace ThingsGateway.Blazor;
public partial class TcpServerPage public partial class TcpServerPage
{ {
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 日志输出
/// </summary> /// </summary>
public Action<LogLevel, object, string, Exception> LogAction; public Action<LogLevel, object, string, Exception> LogAction;
@@ -62,19 +62,18 @@ public partial class TcpServerPage
} }
} }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 获取对象
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public TcpService GetTcpServer() public TcpService GetTcpServer()
{ {
config?.Dispose(); config ??= new TouchSocketConfig();
config = new TouchSocketConfig();
var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
config.SetListenIPHosts(new IPHost[] { new IPHost(ip + ":" + port) }); config.SetListenIPHosts(new IPHost[] { new IPHost(ip + ":" + port) });
config.SetBufferLength(300); config.SetBufferLength(300);
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> //载入配置
TcpServer.Setup(config); TcpServer.Setup(config);
return TcpServer; return TcpServer;
} }

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -19,7 +19,7 @@ namespace ThingsGateway.Blazor;
public partial class UdpSessionPage : IDisposable public partial class UdpSessionPage : IDisposable
{ {
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 日志输出
/// </summary> /// </summary>
public Action<LogLevel, object, string, Exception> LogAction; public Action<LogLevel, object, string, Exception> LogAction;
@@ -62,19 +62,18 @@ public partial class UdpSessionPage : IDisposable
} }
} }
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 获取对象
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public UdpSession GetUdpSession() public UdpSession GetUdpSession()
{ {
config?.Dispose(); config ??= new TouchSocketConfig();
config = new TouchSocketConfig();
var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace };
LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace });
config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage));
config.SetRemoteIPHost(new IPHost(ip + ":" + port)).SetBufferLength(300); config.SetRemoteIPHost(new IPHost(ip + ":" + port)).SetBufferLength(300);
config.SetBindIPHost(new IPHost(0)); config.SetBindIPHost(new IPHost(0));
//<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> //载入配置
UdpSession.Setup(config); UdpSession.Setup(config);
return UdpSession; return UdpSession;
} }

View File

@@ -62,6 +62,7 @@
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_collectDeviceGroupSearchName" <MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_collectDeviceGroupSearchName"
Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.DeviceGroup)) /> Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.DeviceGroup)) />
</MCardTitle> </MCardTitle>
<MTreeview Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight + 240}px; overflow-y:auto)") Dense TItem="string" TKey="string" ActiveChanged=@(async a=> <MTreeview Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight + 240}px; overflow-y:auto)") Dense TItem="string" TKey="string" ActiveChanged=@(async a=>
{ {
if(_collectDeviceGroup!=a.FirstOrDefault()) if(_collectDeviceGroup!=a.FirstOrDefault())

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -32,7 +32,7 @@ using ThingsGateway.Application;
namespace ThingsGateway.Blazor; namespace ThingsGateway.Blazor;
/// <summary> /// <summary>
/// <EFBFBD>豸״̬ҳ<EFBFBD><EFBFBD> /// 设备状态页面
/// </summary> /// </summary>
public partial class DeviceStatusPage : IDisposable public partial class DeviceStatusPage : IDisposable
{ {
@@ -110,7 +110,7 @@ public partial class DeviceStatusPage : IDisposable
{ {
try try
{ {
var confirm = await PopupService.OpenConfirmDialogAsync("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"); var confirm = await PopupService.OpenConfirmDialogAsync("重启", "确定重启?");
if (confirm) if (confirm)
{ {
isAllRestart = true; isAllRestart = true;
@@ -142,8 +142,8 @@ public partial class DeviceStatusPage : IDisposable
} }
async Task ConfigAsync(long devId, bool? isStart) async Task ConfigAsync(long devId, bool? isStart)
{ {
var str = isStart == true ? "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" : "<EFBFBD><EFBFBD>ͣ"; var str = isStart == true ? "启动" : "暂停";
var confirm = await PopupService.OpenConfirmDialogAsync(str, $"ȷ<EFBFBD><EFBFBD>{str}?"); var confirm = await PopupService.OpenConfirmDialogAsync(str, $"确定{str}?");
if (confirm) if (confirm)
{ {
CollectDeviceHostService.ConfigDeviceThread(devId, isStart == true); CollectDeviceHostService.ConfigDeviceThread(devId, isStart == true);
@@ -167,19 +167,19 @@ public partial class DeviceStatusPage : IDisposable
memoryStream.Seek(0, SeekOrigin.Begin); memoryStream.Seek(0, SeekOrigin.Begin);
using var streamRef = new DotNetStreamReference(stream: memoryStream); using var streamRef = new DotNetStreamReference(stream: memoryStream);
Helper ??= await JS.InvokeAsync<IJSObjectReference>("import", $"/_content/ThingsGateway.Admin.Blazor.Core/js/downloadFileFromStream.js"); Helper ??= await JS.InvokeAsync<IJSObjectReference>("import", $"/_content/ThingsGateway.Admin.Blazor.Core/js/downloadFileFromStream.js");
await Helper.InvokeVoidAsync("downloadFileFromStream", $"<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.txt", streamRef); await Helper.InvokeVoidAsync("downloadFileFromStream", $"报文导出{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.txt", streamRef);
} }
finally finally
{ {
isDownExport = false; isDownExport = false;
} }
} }
//ȥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> //去除单个采集重启
//async Task RestartAsync(long devId) //async Task RestartAsync(long devId)
//{ //{
// try // try
// { // {
// var confirm = await PopupService.OpenConfirmDialogAsync("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "ȷ<><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"); // var confirm = await PopupService.OpenConfirmDialogAsync("重启", "确定重启?");
// if (confirm) // if (confirm)
// { // {
// isRestart = true; // isRestart = true;
@@ -199,7 +199,6 @@ public partial class DeviceStatusPage : IDisposable
// await MainLayout.StateHasChangedAsync(); // await MainLayout.StateHasChangedAsync();
// } // }
//} //}
private async Task RunTimerAsync() private async Task RunTimerAsync()
{ {
while (await _periodicTimer.WaitForNextTickAsync()) while (await _periodicTimer.WaitForNextTickAsync())
@@ -232,8 +231,8 @@ public partial class DeviceStatusPage : IDisposable
async Task UpConfigAsync(long devId, bool? isStart) async Task UpConfigAsync(long devId, bool? isStart)
{ {
var str = isStart == true ? "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" : "<EFBFBD><EFBFBD>ͣ"; var str = isStart == true ? "启动" : "暂停";
var confirm = await PopupService.OpenConfirmDialogAsync(str, $"ȷ<EFBFBD><EFBFBD>{str}?"); var confirm = await PopupService.OpenConfirmDialogAsync(str, $"确定{str}?");
if (confirm) if (confirm)
{ {
UploadDeviceHostService.ConfigDeviceThread(devId, isStart == true); UploadDeviceHostService.ConfigDeviceThread(devId, isStart == true);
@@ -254,7 +253,7 @@ public partial class DeviceStatusPage : IDisposable
{ {
try try
{ {
var confirm = await PopupService.OpenConfirmDialogAsync("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"); var confirm = await PopupService.OpenConfirmDialogAsync("重启", "确定重启?");
if (confirm) if (confirm)
{ {
isRestart = true; isRestart = true;

View File

@@ -180,8 +180,41 @@ else
} }
</ItemColTemplate> </ItemColTemplate>
<Detailemplate>
@{
switch (context.Item1.Value)
{
case nameof(DeviceVariable.DeviceId):
<tr @key="context.Item1.Text">
<td class="text-start table-minwidth">
@context.Item1.Text
</td>
<td class="text-start ">
<div style="word-break:break-all; white-space:pre-wrap;">
@(App.GetService<ICollectDeviceService>().GetNameById(context.Item2.ToLong()))
</div>
</td>
</tr>
break;
default:
<tr @key="context.Item1.Text">
<td class="text-start table-minwidth">
@context.Item1.Text
</td>
<td class="text-start ">
<div style="word-break:break-all; white-space:pre-wrap;">
@context.Item2
</div>
</td>
</tr>
break;
}
}
</Detailemplate>
</AppDataTable> </AppDataTable>
; ;
return renderFragment; return renderFragment;
} }

View File

@@ -61,6 +61,7 @@ else
</span> </span>
</LabelContent> </LabelContent>
</MTreeview> </MTreeview>
</MCard> </MCard>
</MCol> </MCol>
<MCol Md=10 Cols="12"> <MCol Md=10 Cols="12">
@@ -119,7 +120,38 @@ else
} }
</ItemColTemplate> </ItemColTemplate>
<Detailemplate>
@{
switch (context.Item1.Value)
{
case nameof(DeviceVariable.DeviceId):
<tr @key="context.Item1.Text">
<td class="text-start table-minwidth">
@context.Item1.Text
</td>
<td class="text-start ">
<div style="word-break:break-all; white-space:pre-wrap;">
@(App.GetService<ICollectDeviceService>().GetNameById(context.Item2.ToLong()))
</div>
</td>
</tr>
break;
default:
<tr @key="context.Item1.Text">
<td class="text-start table-minwidth">
@context.Item1.Text
</td>
<td class="text-start ">
<div style="word-break:break-all; white-space:pre-wrap;">
@context.Item2
</div>
</td>
</tr>
break;
}
}
</Detailemplate>
</AppDataTable> </AppDataTable>
; ;

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -28,7 +28,7 @@ using ThingsGateway.Application;
namespace ThingsGateway.Blazor; namespace ThingsGateway.Blazor;
/// <summary> /// <summary>
/// ʵʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ /// 实时数据页
/// </summary> /// </summary>
public partial class DeviceVariableRunTimePage public partial class DeviceVariableRunTimePage
{ {
@@ -37,13 +37,13 @@ public partial class DeviceVariableRunTimePage
List<DeviceTree> _deviceGroups = new(); List<DeviceTree> _deviceGroups = new();
string _searchName; string _searchName;
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 设备名称
/// </summary> /// </summary>
[Parameter] [Parameter]
[SupplyParameterFromQuery] [SupplyParameterFromQuery]
public string DeviceName { get; set; } public string DeviceName { get; set; }
/// <summary> /// <summary>
/// <EFBFBD>ϴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 上传设备名称
/// </summary> /// </summary>
[Parameter] [Parameter]
[SupplyParameterFromQuery] [SupplyParameterFromQuery]
@@ -149,15 +149,23 @@ public partial class DeviceVariableRunTimePage
private EventCallback<string> WriteValueAsync; private EventCallback<string> WriteValueAsync;
private async Task OnWriteValueAsync(DeviceVariableRunTime tag, string value) private async Task OnWriteValueAsync(DeviceVariableRunTime tag, string value)
{ {
var data = await RpcCore?.InvokeDeviceMethodAsync($"BLAZOR-{UserResoures.CurrentUser.Account}-{App.HttpContext.Connection.RemoteIpAddress.MapToIPv4()}", new KeyValuePair<string, string>(tag.Name, value), true); var data = await RpcCore?.InvokeDeviceMethodAsync($"BLAZOR-{UserResoures.CurrentUser.Account}-{App.HttpContext.Connection.RemoteIpAddress.MapToIPv4()}",
if (!data.IsSuccess)
new Dictionary<string, string>()
{
{ tag.Name, value}
}
, true);
if (data.Count > 0 && !data.FirstOrDefault().Value.IsSuccess)
{ {
throw new(data.Message); throw new(data.FirstOrDefault().Value.Message);
} }
} }
private async Task WriteAsync(DeviceVariableRunTime collectVariableRunTime) private async Task WriteAsync(DeviceVariableRunTime collectVariableRunTime)
{ {
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD>ص<EFBFBD><EFBFBD><EFBFBD> // 将异步方法添加到事件回调上
WriteValueAsync = EventCallback.Factory.Create<string>(this, value => OnWriteValueAsync(collectVariableRunTime, value)); WriteValueAsync = EventCallback.Factory.Create<string>(this, value => OnWriteValueAsync(collectVariableRunTime, value));
await PopupService.OpenAsync(typeof(WriteValue), new Dictionary<string, object>() await PopupService.OpenAsync(typeof(WriteValue), new Dictionary<string, object>()
{ {

View File

@@ -32,7 +32,7 @@
@layout MainLayout @layout MainLayout
<MRow NoGutters> <MRow NoGutters>
<MCol Md=@(IsShowTreeView?4:0)> <MCol Md=@(IsShowTreeView?3:0)>
<MCard Show=IsShowTreeView Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight}px);border-radius:0px;")> <MCard Show=IsShowTreeView Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight}px);border-radius:0px;")>
<MCardTitle> <MCardTitle>
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_searchName" Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.PluginId)) /> <MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_searchName" Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.PluginId)) />
@@ -62,7 +62,7 @@
</MTreeview> </MTreeview>
</MCard> </MCard>
</MCol> </MCol>
<MCol Md=@(IsShowTreeView?8:12)> <MCol Md=@(IsShowTreeView?9:12)>
<MCard Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight}px);border-radius:0px;")> <MCard Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight}px);border-radius:0px;")>
<MCard Class="mb-3 pa-2 text-h6" Elevation="0" Flat Rounded="false"> <MCard Class="mb-3 pa-2 text-h6" Elevation="0" Flat Rounded="false">
<MRow Align="AlignTypes.Center" Class="mt-1"> <MRow Align="AlignTypes.Center" Class="mt-1">

View File

@@ -130,7 +130,7 @@
<MCard Elevation="1" Class="ma-2"> <MCard Elevation="1" Class="ma-2">
<MCardSubtitle Class=@("text-h6")> <MCardSubtitle Class=@("text-h6")>
<div class="mt-1 d-flex align-center justify-space-between"> <div class="mt-1 d-flex align-center justify-space-between">
<span>"当前内存/磁盘信息</span> <span>当前内存/磁盘信息</span>
</div> </div>
</MCardSubtitle> </MCardSubtitle>
<MDivider></MDivider> <MDivider></MDivider>

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -19,7 +19,7 @@ using ThingsGateway.Application;
namespace ThingsGateway.Blazor; namespace ThingsGateway.Blazor;
/// <summary> /// <summary>
/// Ӳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣҳ<EFBFBD><EFBFBD> /// 硬件信息页面
/// </summary> /// </summary>
public partial class HardwareInfoPage public partial class HardwareInfoPage
{ {

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -25,7 +25,7 @@ using ThingsGateway.Application;
namespace ThingsGateway.Blazor; namespace ThingsGateway.Blazor;
/// <summary> /// <summary>
/// <EFBFBD><EFBFBD>ʷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><EFBFBD> /// 历史报警页面
/// </summary> /// </summary>
public partial class HistoryAlarmPage public partial class HistoryAlarmPage
{ {
@@ -75,7 +75,7 @@ public partial class HistoryAlarmPage
} }
catch (Exception ex) catch (Exception ex)
{ {
await InvokeAsync(async () => await PopupService.EnqueueSnackbarAsync("<EFBFBD><EFBFBD>ѯʧ<EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD>" + ex.Message, AlertTypes.Warning)); await InvokeAsync(async () => await PopupService.EnqueueSnackbarAsync("查询失败,请检查网络连接:" + ex.Message, AlertTypes.Warning));
return new() return new()
{ {
Current = 1, Current = 1,

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -23,7 +23,7 @@ using ThingsGateway.Application;
namespace ThingsGateway.Blazor; namespace ThingsGateway.Blazor;
/// <summary> /// <summary>
/// ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><EFBFBD> /// 时序库页面
/// </summary> /// </summary>
public partial class HistoryValuePage public partial class HistoryValuePage
{ {
@@ -74,7 +74,7 @@ public partial class HistoryValuePage
} }
catch (Exception ex) catch (Exception ex)
{ {
await InvokeAsync(async () => await PopupService.EnqueueSnackbarAsync("<EFBFBD><EFBFBD>ѯʧ<EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD>" + ex.Message, AlertTypes.Warning)); await InvokeAsync(async () => await PopupService.EnqueueSnackbarAsync("查询失败,请检查网络连接:" + ex.Message, AlertTypes.Warning));
return new() return new()
{ {
Current = 1, Current = 1,

View File

@@ -149,6 +149,7 @@
<MTextField Dense Outlined HideDetails="@("auto")" @bind-Value=@context.ReadExpressions /> <MTextField Dense Outlined HideDetails="@("auto")" @bind-Value=@context.ReadExpressions />
</MCol> </MCol>
<MCol Md=6 Cols=12 class="px-1"> <MCol Md=6 Cols=12 class="px-1">
<MSubheader Class="font-weight-black"> @(context.Description(x => x.WriteExpressions)) </MSubheader> <MSubheader Class="font-weight-black"> @(context.Description(x => x.WriteExpressions)) </MSubheader>

View File

@@ -96,7 +96,7 @@ public partial class MemoryVariablePage
Task<Dictionary<string, ImportPreviewOutputBase>> DeviceImportAsync(IBrowserFile file) Task<Dictionary<string, ImportPreviewOutputBase>> DeviceImportAsync(IBrowserFile file)
{ {
return VariableService.PreviewAsync(file); return VariableService.MemoryVariablePreviewAsync(file);
} }

View File

@@ -1,12 +1,12 @@
#region copyright #region copyright
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊȫ<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// <EFBFBD>˴<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߱<EFBFBD><EFBFBD><EFBFBD>Diego<EFBFBD><EFBFBD><EFBFBD><EFBFBD> // 此代码版权(除特别声明外的代码)归作者本人Diego所有
// Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD>Ŀ<EFBFBD>ԴЭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD> // 源代码使用协议遵循本仓库的开源协议及附加协议
// GiteeԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://gitee.com/diego2098/ThingsGateway // Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
// GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway // Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
// ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ // 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
// QQȺ<EFBFBD><EFBFBD>605534569 // QQ群:605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#endregion #endregion
@@ -22,7 +22,7 @@ using ThingsGateway.Application;
namespace ThingsGateway.Blazor; namespace ThingsGateway.Blazor;
/// <summary> /// <summary>
/// ʵʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> /// 实时报警
/// </summary> /// </summary>
public partial class RealAlarmPage public partial class RealAlarmPage
{ {

View File

@@ -428,13 +428,13 @@
<member name="M:ThingsGateway.Application.DriverDebugUIBase.WriteAsync"> <member name="M:ThingsGateway.Application.DriverDebugUIBase.WriteAsync">
<inheritdoc/> <inheritdoc/>
</member> </member>
<member name="M:ThingsGateway.Application.DriverDebugUIBase.DownDeviceExportAsync(ThingsGateway.Application.CollectDevice)"> <member name="M:ThingsGateway.Application.DriverDebugUIBase.DeviceImportAsync(ThingsGateway.Application.CollectDevice)">
<summary> <summary>
导入设备 导入设备
</summary> </summary>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:ThingsGateway.Application.DriverDebugUIBase.DownDeviceExportAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable})"> <member name="M:ThingsGateway.Application.DriverDebugUIBase.DeviceVariableImportAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable})">
<summary> <summary>
导入变量 导入变量
</summary> </summary>
@@ -447,6 +447,18 @@
<param name="values"></param> <param name="values"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:ThingsGateway.Application.DriverDebugUIBase.DownDeviceExportAsync(ThingsGateway.Application.CollectDevice)">
<summary>
导出到excel
</summary>
<returns></returns>
</member>
<member name="M:ThingsGateway.Application.DriverDebugUIBase.DownDeviceVariableExportAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable},System.String)">
<summary>
导出到excel
</summary>
<returns></returns>
</member>
<member name="M:ThingsGateway.Application.DriverDebugUIBase.LogOut(TouchSocket.Core.LogLevel,System.Object,System.String,System.Exception)"> <member name="M:ThingsGateway.Application.DriverDebugUIBase.LogOut(TouchSocket.Core.LogLevel,System.Object,System.String,System.Exception)">
<inheritdoc/> <inheritdoc/>
</member> </member>

View File

@@ -30,7 +30,7 @@ public abstract class ReadWriteDevicesSerialBase : ReadWriteDevicesClientBase
public ReadWriteDevicesSerialBase(SerialClient serialClient) public ReadWriteDevicesSerialBase(SerialClient serialClient)
{ {
SerialClient = serialClient; SerialClient = serialClient;
WaitingClientEx = SerialClient.GetWaitingClientEx(new()); WaitingClientEx = SerialClient.GetWaitingClientEx(new() { BreakTrigger = true });
SerialClient.Connecting -= Connecting; SerialClient.Connecting -= Connecting;
SerialClient.Connected -= Connected; SerialClient.Connected -= Connected;

View File

@@ -26,7 +26,7 @@ public abstract class ReadWriteDevicesTcpClientBase : ReadWriteDevicesClientBase
public ReadWriteDevicesTcpClientBase(TcpClientEx tcpClient) public ReadWriteDevicesTcpClientBase(TcpClientEx tcpClient)
{ {
TcpClientEx = tcpClient; TcpClientEx = tcpClient;
WaitingClientEx = TcpClientEx.GetWaitingClientEx(new()); WaitingClientEx = TcpClientEx.GetWaitingClientEx(new() { BreakTrigger = true });
TcpClientEx.Connecting -= Connecting; TcpClientEx.Connecting -= Connecting;
TcpClientEx.Connected -= Connected; TcpClientEx.Connected -= Connected;
TcpClientEx.Disconnecting -= Disconnecting; TcpClientEx.Disconnecting -= Disconnecting;

View File

@@ -24,10 +24,8 @@ public abstract class ReadWriteDevicesUdpBase : ReadWriteDevicesClientBase
/// <inheritdoc cref="ReadWriteDevicesUdpBase"/> /// <inheritdoc cref="ReadWriteDevicesUdpBase"/>
public ReadWriteDevicesUdpBase(UdpSession udpSession) public ReadWriteDevicesUdpBase(UdpSession udpSession)
{ {
UdpSession = udpSession; UdpSession = udpSession;
WaitingClientEx = UdpSession.GetWaitingClientEx(new()); WaitingClientEx = UdpSession.GetWaitingClientEx(new() { BreakTrigger = true });
SetDataAdapter(); SetDataAdapter();
} }
/// <summary> /// <summary>

View File

@@ -15,7 +15,7 @@ namespace ThingsGateway.Foundation;
/// <summary> /// <summary>
/// 自增 /// 自增
/// </summary> /// </summary>
public sealed class EasyIncrementCount : DisposableObject public sealed class EasyIncrementCount : IDisposable
{ {
private long current = 0; private long current = 0;
private readonly EasyLock easyLock; private readonly EasyLock easyLock;
@@ -30,6 +30,11 @@ public sealed class EasyIncrementCount : DisposableObject
IncreaseTick = tick; IncreaseTick = tick;
easyLock = new EasyLock(); easyLock = new EasyLock();
} }
/// <inheritdoc cref="EasyIncrementCount"/>
~EasyIncrementCount()
{
easyLock.SafeDispose();
}
/// <summary> /// <summary>
/// Tick /// Tick
@@ -117,10 +122,10 @@ public sealed class EasyIncrementCount : DisposableObject
} }
easyLock.Release(); easyLock.Release();
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void Dispose(bool disposing) public void Dispose()
{ {
easyLock.SafeDispose(); easyLock.SafeDispose();
base.Dispose(disposing);
} }
} }

View File

@@ -15,11 +15,15 @@ namespace ThingsGateway.Foundation;
/// <summary> /// <summary>
/// EasyLock使用轻量级SemaphoreSlim锁只允许一个并发量并记录并发信息 /// EasyLock使用轻量级SemaphoreSlim锁只允许一个并发量并记录并发信息
/// </summary> /// </summary>
public sealed class EasyLock : DisposableObject public sealed class EasyLock : IDisposable
{ {
private static long lockWaitCount; private static long lockWaitCount;
private readonly Lazy<SemaphoreSlim> m_waiterLock = new(() => new SemaphoreSlim(1)); private readonly Lazy<SemaphoreSlim> m_waiterLock = new(() => new SemaphoreSlim(1));
/// <inheritdoc/>
~EasyLock()
{
m_waiterLock.Value.SafeDispose();
}
/// <summary> /// <summary>
/// 当前正在等待的数量 /// 当前正在等待的数量
/// </summary> /// </summary>
@@ -28,6 +32,13 @@ public sealed class EasyLock : DisposableObject
/// 当前锁是否在等待当中 /// 当前锁是否在等待当中
/// </summary> /// </summary>
public bool IsWaitting => m_waiterLock.Value.CurrentCount == 0; public bool IsWaitting => m_waiterLock.Value.CurrentCount == 0;
/// <inheritdoc/>
public void Dispose()
{
m_waiterLock.Value.SafeDispose();
}
/// <summary> /// <summary>
/// 离开锁 /// 离开锁
/// </summary> /// </summary>
@@ -73,10 +84,5 @@ public sealed class EasyLock : DisposableObject
await m_waiterLock.Value.WaitAsync(timeSpan, token); await m_waiterLock.Value.WaitAsync(timeSpan, token);
Interlocked.Decrement(ref lockWaitCount); Interlocked.Decrement(ref lockWaitCount);
} }
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
m_waiterLock.Value.SafeDispose();
base.Dispose(disposing);
}
} }

View File

@@ -159,7 +159,7 @@ public class TcpClientBaseEx : BaseSocket, ITcpClient
{ {
return; return;
} }
this.PluginsManager.Raise(nameof(ITcpDisconnectedPlguin.OnTcpDisconnected), this, e); this.PluginsManager.Raise(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected), this, e);
} }
/// <summary> /// <summary>
@@ -325,27 +325,33 @@ public class TcpClientBaseEx : BaseSocket, ITcpClient
/// <param name="disposing"></param> /// <param name="disposing"></param>
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
try if (!DisposedValue)
{ {
privateEasyLock.Wait(); try
if (this.m_online)
{ {
this.m_online = false;
this.MainSocket.TryClose();
this.PrivateOnDisconnecting(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"));
this.MainSocket.SafeDispose(); privateEasyLock.Wait();
this.m_delaySender.SafeDispose(); if (this.m_online)
this.m_workStream.SafeDispose(); {
this.DataHandlingAdapter.SafeDispose(); this.m_online = false;
this.PluginsManager.SafeDispose(); this.MainSocket.TryClose();
this.PrivateOnDisconnected(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开")); this.PrivateOnDisconnecting(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"));
this.MainSocket.SafeDispose();
this.m_delaySender.SafeDispose();
this.m_workStream.SafeDispose();
this.DataHandlingAdapter.SafeDispose();
this.PluginsManager.SafeDispose();
this.PrivateOnDisconnected(new DisconnectEventArgs(true, $"{nameof(Dispose)}主动断开"));
}
}
finally
{
privateEasyLock.Release();
} }
} }
finally privateEasyLock.SafeDispose();
{
privateEasyLock.Release();
}
base.Dispose(disposing); base.Dispose(disposing);
} }

View File

@@ -12,12 +12,14 @@
using ThingsGateway.Foundation.Serial;
namespace ThingsGateway.Foundation; namespace ThingsGateway.Foundation;
internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClient> where TClient : IClient, IDefaultSender, ISender internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClient> where TClient : IClient, IDefaultSender, ISender
{ {
private readonly Func<ResponsedData, bool> m_func; private readonly Func<ResponsedData, bool> m_func;
private readonly SemaphoreSlim m_lock = new(1); private readonly EasyLock easyLock = new();
private readonly WaitData<ResponsedData> m_waitData = new WaitData<ResponsedData>(); private readonly WaitData<ResponsedData> m_waitData = new WaitData<ResponsedData>();
private readonly WaitDataAsync<ResponsedData> m_waitDataAsync = new WaitDataAsync<ResponsedData>(); private readonly WaitDataAsync<ResponsedData> m_waitDataAsync = new WaitDataAsync<ResponsedData>();
@@ -52,6 +54,8 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
{ {
this.Client = default; this.Client = default;
this.m_waitData.SafeDispose(); this.m_waitData.SafeDispose();
this.m_waitDataAsync.SafeDispose();
this.easyLock.SafeDispose();
base.Dispose(disposing); base.Dispose(disposing);
} }
@@ -66,7 +70,11 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
this.m_breaked = true; this.m_breaked = true;
this.Cancel(); this.Cancel();
} }
private void OnSerialClientDisconnected(ISerialClientBase client, DisconnectEventArgs e)
{
this.m_breaked = true;
this.Cancel();
}
private bool OnHandleRawBuffer(ByteBlock byteBlock) private bool OnHandleRawBuffer(ByteBlock byteBlock)
{ {
var responsedData = new ResponsedData(byteBlock.ToArray(), null, true); var responsedData = new ResponsedData(byteBlock.ToArray(), null, true);
@@ -114,14 +122,17 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
{ {
try try
{ {
m_lock.Wait(); easyLock.Wait();
this.m_breaked = false; this.m_breaked = false;
this.Reset(); this.Reset();
if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient)
{ {
tcpClient.Disconnected += this.OnDisconnected; tcpClient.Disconnected += this.OnDisconnected;
} }
if (this.WaitingOptions.BreakTrigger && this.Client is ISerialClientBase serialClient)
{
serialClient.Disconnected += this.OnSerialClientDisconnected;
}
if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
{ {
this.Client.OnHandleReceivedData += this.OnHandleReceivedData; this.Client.OnHandleReceivedData += this.OnHandleReceivedData;
@@ -174,12 +185,15 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
} }
finally finally
{ {
m_lock.Release(); easyLock.Release();
if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient)
{ {
tcpClient.Disconnected -= this.OnDisconnected; tcpClient.Disconnected -= this.OnDisconnected;
} }
if (this.WaitingOptions.BreakTrigger && this.Client is ISerialClientBase serialClient)
{
serialClient.Disconnected -= this.OnSerialClientDisconnected;
}
if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
{ {
this.Client.OnHandleReceivedData -= this.OnHandleReceivedData; this.Client.OnHandleReceivedData -= this.OnHandleReceivedData;
@@ -191,6 +205,8 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
} }
} }
public ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default) public ResponsedData SendThenResponse(byte[] buffer, int timeout = 1000 * 5, CancellationToken token = default)
{ {
return this.SendThenResponse(buffer, 0, buffer.Length, timeout, token); return this.SendThenResponse(buffer, 0, buffer.Length, timeout, token);
@@ -209,14 +225,17 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
{ {
try try
{ {
await m_lock.WaitAsync(); await easyLock.WaitAsync();
this.m_breaked = false; this.m_breaked = false;
this.Reset(); this.Reset();
if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient)
{ {
tcpClient.Disconnected += this.OnDisconnected; tcpClient.Disconnected += this.OnDisconnected;
} }
if (this.WaitingOptions.BreakTrigger && this.Client is ISerialClientBase serialClient)
{
serialClient.Disconnected += this.OnSerialClientDisconnected;
}
if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
{ {
this.Client.OnHandleReceivedData += this.OnHandleReceivedData; this.Client.OnHandleReceivedData += this.OnHandleReceivedData;
@@ -269,12 +288,15 @@ internal class WaitingClientEx<TClient> : DisposableObject, IWaitingClient<TClie
} }
finally finally
{ {
m_lock.Release(); easyLock.Release();
if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient) if (this.WaitingOptions.BreakTrigger && this.Client is ITcpClientBase tcpClient)
{ {
tcpClient.Disconnected -= this.OnDisconnected; tcpClient.Disconnected -= this.OnDisconnected;
} }
if (this.WaitingOptions.BreakTrigger && this.Client is ISerialClientBase serialClient)
{
serialClient.Disconnected -= this.OnSerialClientDisconnected;
}
if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter) if (this.WaitingOptions.AdapterFilter == AdapterFilter.AllAdapter || this.WaitingOptions.AdapterFilter == AdapterFilter.WaitAdapter)
{ {
this.Client.OnHandleReceivedData -= this.OnHandleReceivedData; this.Client.OnHandleReceivedData -= this.OnHandleReceivedData;

View File

@@ -46,19 +46,6 @@ public static class StringExtensions
} }
/// <summary>
/// 将16进制的字符转换为int32。
/// </summary>
/// <param name="hexString"></param>
/// <returns></returns>
public static int ByHexStringToInt32(this string hexString)
{
if (string.IsNullOrEmpty(hexString))
{
return default;
}
return int.Parse(hexString, System.Globalization.NumberStyles.HexNumber);
}
/// <summary> /// <summary>
/// <inheritdoc cref="Path.Combine(string[])"/> /// <inheritdoc cref="Path.Combine(string[])"/>
/// 并把\\转为/ /// 并把\\转为/

View File

@@ -15,6 +15,17 @@ namespace ThingsGateway.Foundation.Extension;
/// <inheritdoc/> /// <inheritdoc/>
public static class OperResultExtensions public static class OperResultExtensions
{ {
/// <summary>
/// 复制信息,包含第一个泛型类
/// </summary>
public static OperResult<T1> Copy<T1, T2>(this OperResult<T1, T2> result)
{
OperResult<T1> result1 = new(result.ResultCode, result.Message)
{
Content = result.Content1
};
return result1;
}
#region Public Methods #region Public Methods
/// <summary> /// <summary>

View File

@@ -172,7 +172,7 @@ public class SerialClientBase : BaseSerial, ISerialClient
{ {
return; return;
} }
this.PluginsManager.Raise(nameof(ITcpDisconnectedPlguin.OnTcpDisconnected), this, e); this.PluginsManager.Raise(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected), this, e);
} }
private void PrivateOnDisconnecting(DisconnectEventArgs e) private void PrivateOnDisconnecting(DisconnectEventArgs e)
{ {

View File

@@ -45,4 +45,9 @@ public class SerialProperty
/// </summary> /// </summary>
[Description("停止位")] [Description("停止位")]
public StopBits StopBits { get; set; } = StopBits.One; public StopBits StopBits { get; set; } = StopBits.One;
/// <inheritdoc/>
public override string ToString()
{
return $"{PortName}[{BaudRate},{DataBits},{StopBits},{Parity}]";
}
} }

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net45;net6.0;net7.0</TargetFrameworks> <TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
<OpenApiGenerateDocuments>false</OpenApiGenerateDocuments> <OpenApiGenerateDocuments>false</OpenApiGenerateDocuments>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression> <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
@@ -13,7 +13,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="TouchSocket" Version="2.0.0-beta.120" /> <PackageReference Include="TouchSocket" Version="2.0.0-beta.138" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'!='net45'"> <ItemGroup Condition="'$(TargetFramework)'!='net45'">
<PackageReference Include="System.IO.Ports" Version="7.0.0" /> <PackageReference Include="System.IO.Ports" Version="7.0.0" />

View File

@@ -588,6 +588,9 @@
<member name="M:ThingsGateway.Foundation.EasyIncrementCount.#ctor(System.Int64,System.Int64,System.Int32)"> <member name="M:ThingsGateway.Foundation.EasyIncrementCount.#ctor(System.Int64,System.Int64,System.Int32)">
<inheritdoc cref="T:ThingsGateway.Foundation.EasyIncrementCount"/> <inheritdoc cref="T:ThingsGateway.Foundation.EasyIncrementCount"/>
</member> </member>
<member name="M:ThingsGateway.Foundation.EasyIncrementCount.Finalize">
<inheritdoc cref="T:ThingsGateway.Foundation.EasyIncrementCount"/>
</member>
<member name="P:ThingsGateway.Foundation.EasyIncrementCount.IncreaseTick"> <member name="P:ThingsGateway.Foundation.EasyIncrementCount.IncreaseTick">
<summary> <summary>
Tick Tick
@@ -623,7 +626,7 @@
重置当前序号的初始值 重置当前序号的初始值
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Foundation.EasyIncrementCount.Dispose(System.Boolean)"> <member name="M:ThingsGateway.Foundation.EasyIncrementCount.Dispose">
<inheritdoc/> <inheritdoc/>
</member> </member>
<member name="T:ThingsGateway.Foundation.EasyLock"> <member name="T:ThingsGateway.Foundation.EasyLock">
@@ -631,6 +634,9 @@
EasyLock使用轻量级SemaphoreSlim锁只允许一个并发量并记录并发信息 EasyLock使用轻量级SemaphoreSlim锁只允许一个并发量并记录并发信息
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Foundation.EasyLock.Finalize">
<inheritdoc/>
</member>
<member name="P:ThingsGateway.Foundation.EasyLock.LockWaitCount"> <member name="P:ThingsGateway.Foundation.EasyLock.LockWaitCount">
<summary> <summary>
当前正在等待的数量 当前正在等待的数量
@@ -641,6 +647,9 @@
当前锁是否在等待当中 当前锁是否在等待当中
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Foundation.EasyLock.Dispose">
<inheritdoc/>
</member>
<member name="M:ThingsGateway.Foundation.EasyLock.Release"> <member name="M:ThingsGateway.Foundation.EasyLock.Release">
<summary> <summary>
离开锁 离开锁
@@ -666,9 +675,6 @@
进入锁 进入锁
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Foundation.EasyLock.Dispose(System.Boolean)">
<inheritdoc/>
</member>
<member name="T:ThingsGateway.Foundation.TcpClientEx"> <member name="T:ThingsGateway.Foundation.TcpClientEx">
<summary> <summary>
简单TCP客户端 简单TCP客户端
@@ -1283,13 +1289,6 @@
<param name="value"></param> <param name="value"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:ThingsGateway.Foundation.Extension.String.StringExtensions.ByHexStringToInt32(System.String)">
<summary>
将16进制的字符转换为int32。
</summary>
<param name="hexString"></param>
<returns></returns>
</member>
<member name="M:ThingsGateway.Foundation.Extension.String.StringExtensions.CombinePathOS(System.String,System.String[])"> <member name="M:ThingsGateway.Foundation.Extension.String.StringExtensions.CombinePathOS(System.String,System.String[])">
<summary> <summary>
<inheritdoc cref="M:System.IO.Path.Combine(System.String[])"/> <inheritdoc cref="M:System.IO.Path.Combine(System.String[])"/>
@@ -1313,6 +1312,11 @@
<member name="T:ThingsGateway.Foundation.Extension.OperResultExtensions"> <member name="T:ThingsGateway.Foundation.Extension.OperResultExtensions">
<inheritdoc/> <inheritdoc/>
</member> </member>
<member name="M:ThingsGateway.Foundation.Extension.OperResultExtensions.Copy``2(ThingsGateway.Foundation.OperResult{``0,``1})">
<summary>
复制信息,包含第一个泛型类
</summary>
</member>
<member name="M:ThingsGateway.Foundation.Extension.OperResultExtensions.Copy``1(ThingsGateway.Foundation.OperResult)"> <member name="M:ThingsGateway.Foundation.Extension.OperResultExtensions.Copy``1(ThingsGateway.Foundation.OperResult)">
<summary> <summary>
复制信息,不包含泛型类 复制信息,不包含泛型类
@@ -2288,6 +2292,9 @@
停止位 停止位
</summary> </summary>
</member> </member>
<member name="M:ThingsGateway.Foundation.Serial.SerialProperty.ToString">
<inheritdoc/>
</member>
<member name="T:ThingsGateway.Foundation.SerialPortExtensions"> <member name="T:ThingsGateway.Foundation.SerialPortExtensions">
<summary> <summary>
SocketExtension SocketExtension

View File

@@ -31,11 +31,11 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
private DataFormat dataFormat; private DataFormat dataFormat;
/// <inheritdoc/> /// <inheritdoc/>
[JsonIgnore] [JsonIgnore]
public Encoding Encoding { get; set; } = Encoding.UTF8; public virtual Encoding Encoding { get; set; } = Encoding.UTF8;
/// <inheritdoc/> /// <inheritdoc/>
public BcdFormat? BcdFormat { get; set; } public virtual BcdFormat? BcdFormat { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public int StringLength { get; set; } public virtual int StringLength { get; set; }
/// <summary> /// <summary>
/// 构造函数 /// 构造函数
@@ -55,7 +55,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public DataFormat DataFormat public virtual DataFormat DataFormat
{ {
get get
{ {
@@ -69,9 +69,9 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
/// <inheritdoc/> /// <inheritdoc/>
public EndianType EndianType => endianType; public virtual EndianType EndianType => endianType;
/// <inheritdoc/> /// <inheritdoc/>
public bool IsStringReverseByteWord { get; set; } public virtual bool IsStringReverseByteWord { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public virtual IThingsGatewayBitConverter CreateByDateFormat(DataFormat dataFormat) public virtual IThingsGatewayBitConverter CreateByDateFormat(DataFormat dataFormat)
@@ -86,7 +86,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
return byteConverter; return byteConverter;
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(bool value) public virtual byte[] GetBytes(bool value)
{ {
return GetBytes(new bool[1] return GetBytes(new bool[1]
{ {
@@ -95,13 +95,13 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(bool[] values) public virtual byte[] GetBytes(bool[] values)
{ {
return values?.BoolArrayToByte(); return values?.BoolArrayToByte();
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(short value) public virtual byte[] GetBytes(short value)
{ {
byte[] bytes = BitConverter.GetBytes(value); byte[] bytes = BitConverter.GetBytes(value);
if (!IsSameOfSet()) if (!IsSameOfSet())
@@ -111,7 +111,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
return bytes; return bytes;
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(short[] value) public virtual byte[] GetBytes(short[] value)
{ {
byte[] numArray = new byte[value.Length * 2]; byte[] numArray = new byte[value.Length * 2];
for (int index = 0; index < value.Length; ++index) for (int index = 0; index < value.Length; ++index)
@@ -123,7 +123,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(ushort value) public virtual byte[] GetBytes(ushort value)
{ {
byte[] bytes = BitConverter.GetBytes(value); byte[] bytes = BitConverter.GetBytes(value);
if (!IsSameOfSet()) if (!IsSameOfSet())
@@ -133,7 +133,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
return bytes; return bytes;
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(ushort[] value) public virtual byte[] GetBytes(ushort[] value)
{ {
byte[] numArray = new byte[value.Length * 2]; byte[] numArray = new byte[value.Length * 2];
for (int index = 0; index < value.Length; ++index) for (int index = 0; index < value.Length; ++index)
@@ -144,12 +144,12 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
return numArray; return numArray;
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(int value) public virtual byte[] GetBytes(int value)
{ {
return ByteTransDataFormat4(BitConverter.GetBytes(value)); return ByteTransDataFormat4(BitConverter.GetBytes(value));
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(int[] value) public virtual byte[] GetBytes(int[] value)
{ {
byte[] numArray = new byte[value.Length * 2]; byte[] numArray = new byte[value.Length * 2];
for (int index = 0; index < value.Length; ++index) for (int index = 0; index < value.Length; ++index)
@@ -160,12 +160,12 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
return numArray; return numArray;
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(uint value) public virtual byte[] GetBytes(uint value)
{ {
return ByteTransDataFormat4(BitConverter.GetBytes(value)); return ByteTransDataFormat4(BitConverter.GetBytes(value));
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(uint[] value) public virtual byte[] GetBytes(uint[] value)
{ {
byte[] numArray = new byte[value.Length * 2]; byte[] numArray = new byte[value.Length * 2];
for (int index = 0; index < value.Length; ++index) for (int index = 0; index < value.Length; ++index)
@@ -176,12 +176,12 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
return numArray; return numArray;
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(long value) public virtual byte[] GetBytes(long value)
{ {
return ByteTransDataFormat8(BitConverter.GetBytes(value)); return ByteTransDataFormat8(BitConverter.GetBytes(value));
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(long[] value) public virtual byte[] GetBytes(long[] value)
{ {
byte[] numArray = new byte[value.Length * 2]; byte[] numArray = new byte[value.Length * 2];
for (int index = 0; index < value.Length; ++index) for (int index = 0; index < value.Length; ++index)
@@ -192,12 +192,12 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
return numArray; return numArray;
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(ulong value) public virtual byte[] GetBytes(ulong value)
{ {
return ByteTransDataFormat8(BitConverter.GetBytes(value)); return ByteTransDataFormat8(BitConverter.GetBytes(value));
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(ulong[] value) public virtual byte[] GetBytes(ulong[] value)
{ {
byte[] numArray = new byte[value.Length * 2]; byte[] numArray = new byte[value.Length * 2];
for (int index = 0; index < value.Length; ++index) for (int index = 0; index < value.Length; ++index)
@@ -208,12 +208,12 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
return numArray; return numArray;
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(float value) public virtual byte[] GetBytes(float value)
{ {
return ByteTransDataFormat4(BitConverter.GetBytes(value)); return ByteTransDataFormat4(BitConverter.GetBytes(value));
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(float[] value) public virtual byte[] GetBytes(float[] value)
{ {
byte[] numArray = new byte[value.Length * 2]; byte[] numArray = new byte[value.Length * 2];
for (int index = 0; index < value.Length; ++index) for (int index = 0; index < value.Length; ++index)
@@ -224,12 +224,12 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
return numArray; return numArray;
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(double value) public virtual byte[] GetBytes(double value)
{ {
return ByteTransDataFormat8(BitConverter.GetBytes(value)); return ByteTransDataFormat8(BitConverter.GetBytes(value));
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(double[] value) public virtual byte[] GetBytes(double[] value)
{ {
byte[] numArray = new byte[value.Length * 2]; byte[] numArray = new byte[value.Length * 2];
for (int index = 0; index < value.Length; ++index) for (int index = 0; index < value.Length; ++index)
@@ -240,7 +240,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
return numArray; return numArray;
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] GetBytes(string value) public virtual byte[] GetBytes(string value)
{ {
if (value == null) if (value == null)
{ {
@@ -280,7 +280,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
/// <inheritdoc/> /// <inheritdoc/>
public bool IsSameOfSet() public virtual bool IsSameOfSet()
{ {
return !(BitConverter.IsLittleEndian ^ (endianType == EndianType.Little)); return !(BitConverter.IsLittleEndian ^ (endianType == EndianType.Little));
} }
@@ -288,7 +288,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
/// <inheritdoc/> /// <inheritdoc/>
public bool ToBoolean(byte[] buffer, int offset) public virtual bool ToBoolean(byte[] buffer, int offset)
{ {
byte[] bytes = new byte[buffer.Length]; byte[] bytes = new byte[buffer.Length];
Array.Copy(buffer, 0, bytes, 0, buffer.Length); Array.Copy(buffer, 0, bytes, 0, buffer.Length);
@@ -296,7 +296,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte ToByte(byte[] buffer, int offset) public virtual byte ToByte(byte[] buffer, int offset)
{ {
byte[] bytes = new byte[1]; byte[] bytes = new byte[1];
Array.Copy(buffer, offset, bytes, 0, bytes.Length); Array.Copy(buffer, offset, bytes, 0, bytes.Length);
@@ -304,7 +304,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public byte[] ToByte(byte[] buffer, int offset, int length) public virtual byte[] ToByte(byte[] buffer, int offset, int length)
{ {
byte[] bytes = new byte[length]; byte[] bytes = new byte[length];
Array.Copy(buffer, offset, bytes, 0, bytes.Length); Array.Copy(buffer, offset, bytes, 0, bytes.Length);
@@ -317,7 +317,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
/// <param name="buffer"></param> /// <param name="buffer"></param>
/// <param name="offset"></param> /// <param name="offset"></param>
/// <returns></returns> /// <returns></returns>
public double ToDouble(byte[] buffer, int offset) public virtual double ToDouble(byte[] buffer, int offset)
{ {
byte[] bytes = ByteTransDataFormat8(buffer, offset); byte[] bytes = ByteTransDataFormat8(buffer, offset);
@@ -325,7 +325,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public short ToInt16(byte[] buffer, int offset) public virtual short ToInt16(byte[] buffer, int offset)
{ {
byte[] bytes = new byte[2]; byte[] bytes = new byte[2];
Array.Copy(buffer, offset, bytes, 0, bytes.Length); Array.Copy(buffer, offset, bytes, 0, bytes.Length);
@@ -337,7 +337,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public int ToInt32(byte[] buffer, int offset) public virtual int ToInt32(byte[] buffer, int offset)
{ {
byte[] bytes = ByteTransDataFormat4(buffer, offset); byte[] bytes = ByteTransDataFormat4(buffer, offset);
@@ -345,14 +345,14 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public long ToInt64(byte[] buffer, int offset) public virtual long ToInt64(byte[] buffer, int offset)
{ {
byte[] bytes = ByteTransDataFormat8(buffer, offset); byte[] bytes = ByteTransDataFormat8(buffer, offset);
return BitConverter.ToInt64(bytes, 0); return BitConverter.ToInt64(bytes, 0);
} }
/// <inheritdoc/> /// <inheritdoc/>
public float ToSingle(byte[] buffer, int offset) public virtual float ToSingle(byte[] buffer, int offset)
{ {
byte[] bytes = ByteTransDataFormat4(buffer, offset); byte[] bytes = ByteTransDataFormat4(buffer, offset);
@@ -360,13 +360,13 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public string ToString(byte[] buffer) public virtual string ToString(byte[] buffer)
{ {
return ToString(buffer, 0, buffer.Length); return ToString(buffer, 0, buffer.Length);
} }
/// <inheritdoc/> /// <inheritdoc/>
public string ToString(byte[] buffer, int offset, int length) public virtual string ToString(byte[] buffer, int offset, int length)
{ {
byte[] numArray = buffer.SelectMiddle(offset, length); byte[] numArray = buffer.SelectMiddle(offset, length);
if (BcdFormat != null) if (BcdFormat != null)
@@ -385,7 +385,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public ushort ToUInt16(byte[] buffer, int offset) public virtual ushort ToUInt16(byte[] buffer, int offset)
{ {
byte[] bytes = new byte[2]; byte[] bytes = new byte[2];
Array.Copy(buffer, offset, bytes, 0, 2); Array.Copy(buffer, offset, bytes, 0, 2);
@@ -397,7 +397,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public uint ToUInt32(byte[] buffer, int offset) public virtual uint ToUInt32(byte[] buffer, int offset)
{ {
byte[] bytes = ByteTransDataFormat4(buffer, offset); byte[] bytes = ByteTransDataFormat4(buffer, offset);
@@ -405,7 +405,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public ulong ToUInt64(byte[] buffer, int offset) public virtual ulong ToUInt64(byte[] buffer, int offset)
{ {
byte[] bytes = ByteTransDataFormat8(buffer, offset); byte[] bytes = ByteTransDataFormat8(buffer, offset);
return BitConverter.ToUInt64(bytes, 0); return BitConverter.ToUInt64(bytes, 0);
@@ -508,7 +508,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public bool[] ToBoolean(byte[] buffer, int offset, int len) public virtual bool[] ToBoolean(byte[] buffer, int offset, int len)
{ {
bool[] flagArray = new bool[len]; bool[] flagArray = new bool[len];
for (int index = 0; index < len; ++index) for (int index = 0; index < len; ++index)
@@ -519,7 +519,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public double[] ToDouble(byte[] buffer, int offset, int len) public virtual double[] ToDouble(byte[] buffer, int offset, int len)
{ {
double[] numArray = new double[len]; double[] numArray = new double[len];
for (int index = 0; index < len; ++index) for (int index = 0; index < len; ++index)
@@ -530,7 +530,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public short[] ToInt16(byte[] buffer, int offset, int len) public virtual short[] ToInt16(byte[] buffer, int offset, int len)
{ {
short[] numArray = new short[len]; short[] numArray = new short[len];
for (int index = 0; index < len; ++index) for (int index = 0; index < len; ++index)
@@ -541,7 +541,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public int[] ToInt32(byte[] buffer, int offset, int len) public virtual int[] ToInt32(byte[] buffer, int offset, int len)
{ {
int[] numArray = new int[len]; int[] numArray = new int[len];
for (int index = 0; index < len; ++index) for (int index = 0; index < len; ++index)
@@ -552,7 +552,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public long[] ToInt64(byte[] buffer, int offset, int len) public virtual long[] ToInt64(byte[] buffer, int offset, int len)
{ {
long[] numArray = new long[len]; long[] numArray = new long[len];
for (int index = 0; index < len; ++index) for (int index = 0; index < len; ++index)
@@ -562,7 +562,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
return numArray; return numArray;
} }
/// <inheritdoc/> /// <inheritdoc/>
public float[] ToSingle(byte[] buffer, int offset, int len) public virtual float[] ToSingle(byte[] buffer, int offset, int len)
{ {
float[] numArray = new float[len]; float[] numArray = new float[len];
for (int index = 0; index < len; ++index) for (int index = 0; index < len; ++index)
@@ -573,7 +573,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public ushort[] ToUInt16(byte[] buffer, int offset, int len) public virtual ushort[] ToUInt16(byte[] buffer, int offset, int len)
{ {
ushort[] numArray = new ushort[len]; ushort[] numArray = new ushort[len];
for (int index = 0; index < len; ++index) for (int index = 0; index < len; ++index)
@@ -584,7 +584,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public uint[] ToUInt32(byte[] buffer, int offset, int len) public virtual uint[] ToUInt32(byte[] buffer, int offset, int len)
{ {
uint[] numArray = new uint[len]; uint[] numArray = new uint[len];
for (int index = 0; index < len; ++index) for (int index = 0; index < len; ++index)
@@ -595,7 +595,7 @@ public class ThingsGatewayBitConverter : IThingsGatewayBitConverter
} }
/// <inheritdoc/> /// <inheritdoc/>
public ulong[] ToUInt64(byte[] buffer, int offset, int len) public virtual ulong[] ToUInt64(byte[] buffer, int offset, int len)
{ {
ulong[] numArray = new ulong[len]; ulong[] numArray = new ulong[len];
for (int index = 0; index < len; ++index) for (int index = 0; index < len; ++index)

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Foundataion\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<doc> <doc>
<assembly> <assembly>
<name>ModbusDemo</name> <name>DLT645Test</name>
</assembly> </assembly>
<members> <members>
</members> </members>

View File

@@ -0,0 +1,112 @@
using ThingsGateway.Foundation;
using ThingsGateway.Foundation.Adapter.DLT645;
using ThingsGateway.Foundation.Extension.Byte;
using ThingsGateway.Foundation.Serial;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace DLT645Test
{
internal class Program
{
static async Task Main(string[] args)
{
await DLT645_2007ClientAsync();
Console.ReadLine();
}
private static async Task DLT645_2007ClientAsync()
{
//链路基础配置项
var config = new TouchSocketConfig();
config.SetRemoteIPHost(new IPHost("127.0.0.1:502"))//TCP/UDP链路才需要
.SetSerialProperty(new SerialProperty() //串口链路才需要
{
PortName = "COM1"
}).SetBufferLength(1024);
var serialClient = new SerialClient();//链路对象
serialClient.Setup(config);
//创建协议对象,构造函数需要传入对应链路对象
DLT645_2007 dlt6452007 = new(serialClient)//传入链路
{
//协议配置
DataFormat = DataFormat.ABCD,
FrameTime = 0,
CacheTimeout = 1000,
ConnectTimeOut = 3000,
TimeOut = 3000,
EnableFEHead = true,
};
#region
//测试读取写入
Console.WriteLine("dlt6452007" + dlt6452007.SerialClient.SerialProperty.ToJson());
await TestAsync(dlt6452007);
#endregion
}
private static async Task TestAsync(DLT645_2007 plc)
{
//下面的方法对应PLC读写协议对象都是通用的
//注意下面的方法都带有CancellationToken传播一般是在最后一个参数默认为None
//var bytes02010100Result = await plc.ReadAsync("03010100", 20);
////返回带有是否成功等参数实际数据在data.Content中
//Console.WriteLine("bytes02010100Result" + (bytes02010100Result.IsSuccess ? bytes02010100Result.Content.ToHexString() : bytes02010100Result.Message));
//Console.WriteLine("bytes02010100Result" + (bytes02010100Result.IsSuccess ? plc.ThingsGatewayBitConverter.ToDouble(bytes02010100Result.Content, 0) : bytes02010100Result.Message));
//var bytes02020100Result = await plc.ReadAsync("02020100", 20);
////返回带有是否成功等参数实际数据在data.Content中
//Console.WriteLine("bytes02020100Result" + (bytes02020100Result.IsSuccess ? bytes02020100Result.Content.ToHexString() : bytes02020100Result.Message));
//Console.WriteLine("bytes02020100Result" + (bytes02020100Result.IsSuccess ? plc.ThingsGatewayBitConverter.ToDouble(bytes02020100Result.Content, 0) : bytes02020100Result.Message));
//var bytes02020100Result = await plc.ReadAsync("04000103", 1);
////返回带有是否成功等参数实际数据在data.Content中
//Console.WriteLine("bytes02020100Result" + (bytes02020100Result.IsSuccess ? bytes02020100Result.Content.ToHexString() : bytes02020100Result.Message));
//Console.WriteLine("bytes02020100Result" + (bytes02020100Result.IsSuccess ? plc.ThingsGatewayBitConverter.ToString(bytes02020100Result.Content) : bytes02020100Result.Message));
var test1 = await plc.ReadDeviceStationAsync();
Console.WriteLine("bytes02020100Result" + (test1.IsSuccess ? test1.Content : test1.Message));
var test2 = await plc.WriteDeviceStationAsync("311111111114");
Console.WriteLine("bytes02020100Result" + (test2.IsSuccess ? test2.Message : test2.Message));
plc.BroadcastTime(DateTime.Now);
plc.Station = "311111111114";
var test3 = await plc.WriteBaudRateAsync(19200);
Console.WriteLine("bytes02020100Result" + (test3.IsSuccess ? test3.Message : test3.Message));
var test4 = await plc.FreezeAsync(DateTime.Now);
Console.WriteLine("bytes02020100Result" + (test4.IsSuccess ? test4.Message : test4.Message));
var test5 = await plc.WritePasswordAsync(1, "66666666", "11111111");
Console.WriteLine("bytes02020100Result" + (test5.IsSuccess ? test5.Message : test5.Message));
plc.Password = "11111111";
var bytes02020100Result1 = await plc.ReadAsync("04000403", 1);
//返回带有是否成功等参数实际数据在data.Content中
Console.WriteLine("bytes02020100Result" + (bytes02020100Result1.IsSuccess ? bytes02020100Result1.Content.ToHexString() : bytes02020100Result1.Message));
Console.WriteLine("bytes02020100Result" + (bytes02020100Result1.IsSuccess ? plc.ThingsGatewayBitConverter.ToString(bytes02020100Result1.Content) : bytes02020100Result1.Message));
var test = await plc.WriteAsync("04000403", "33");
//返回带有是否成功等参数实际数据在data.Content中
Console.WriteLine("test" + test.Message);
var bytes02020100Result = await plc.ReadAsync("04000403", 1);
//返回带有是否成功等参数实际数据在data.Content中
Console.WriteLine("bytes02020100Result" + (bytes02020100Result.IsSuccess ? bytes02020100Result.Content.ToHexString() : bytes02020100Result.Message));
Console.WriteLine("bytes02020100Result" + (bytes02020100Result.IsSuccess ? plc.ThingsGatewayBitConverter.ToString(bytes02020100Result.Content) : bytes02020100Result.Message));
}
}
}

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Foundataion\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>ModbusTest</name>
</assembly>
<members>
</members>
</doc>

View File

@@ -12,7 +12,7 @@ namespace ModbusDemo
{ {
static async Task Main(string[] args) static async Task Main(string[] args)
{ {
//await ModbusClientAsync(); await ModbusClientAsync();
await ModbusServerAsync(); await ModbusServerAsync();

View File

@@ -7,8 +7,9 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Foundataion\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj" /> <ProjectReference Include="..\..\Foundataion\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>OPCUAClientTest</name>
</assembly>
<members>
</members>
</doc>

View File

@@ -0,0 +1,29 @@
using ThingsGateway.Foundation.Adapter.OPCUA;
using TouchSocket.Core;
namespace ModbusDemo
{
internal class Program
{
static async Task Main(string[] args)
{
OPCUAClient oPCUAClient = new(new EasyLogger(a => Console.WriteLine(a)))
{
OPCNode = new()
{
OPCUrl = "opc.tcp://desktop-p5gb4iq:50001/StandardServer",
IsUseSecurity = true,
}
};
await oPCUAClient.ConnectAsync();
var testData1 = await oPCUAClient.ReadJTokenValueAsync(new[] { "ns=2;i=2897" });
await oPCUAClient.WriteNodeAsync(new()
{
{"ns=2;i=2897", testData1.FirstOrDefault().Item3 }
});
}
}
}

View File

@@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks> <TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<Version>2.0.3.0</Version> <Version>2.1.0.0</Version>
<Authors>Diego</Authors> <Authors>Diego</Authors>
<Product>ThingsGateway</Product> <Product>ThingsGateway</Product>
<Copyright>© 2023-present Diego</Copyright> <Copyright>© 2023-present Diego</Copyright>

View File

@@ -0,0 +1,459 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.ComponentModel;
using ThingsGateway.Foundation.Extension.Byte;
using ThingsGateway.Foundation.Extension.Generic;
using ThingsGateway.Foundation.Serial;
namespace ThingsGateway.Foundation.Adapter.DLT645;
/// <summary>
/// DLT645_2007
/// </summary>
public class DLT645_2007 : ReadWriteDevicesSerialBase
{
/// <summary>
/// DLT645_2007
/// </summary>
/// <param name="serialClient"></param>
public DLT645_2007(SerialClient serialClient) : base(serialClient)
{
ThingsGatewayBitConverter = new DLT645_2007BitConverter(EndianType.Big);
RegisterByteLength = 2;
}
/// <summary>
/// 组包缓存时间/ms
/// </summary>
[Description("组包缓存时间ms")]
public int CacheTimeout { get; set; } = 1000;
/// <summary>
/// 增加FE FE FE FE的报文头部
/// </summary>
[Description("前导符报文头")]
public bool EnableFEHead { get; set; }
/// <summary>
/// 帧前时间ms
/// </summary>
[Description("帧前时间ms")]
public int FrameTime { get; set; }
/// <summary>
/// 写入需操作员代码
/// </summary>
[Description("操作员代码")]
public string OperCode { get; set; }
/// <summary>
/// 写入密码
/// </summary>
[Description("写入密码")]
public string Password { get; set; }
/// <summary>
/// 通讯地址BCD码一般应该是12个字符
/// </summary>
[Description("通讯地址")]
public string Station { get; set; }
/// <inheritdoc/>
public override string GetAddressDescription() => base.GetAddressDescription() + Environment.NewLine;
/// <inheritdoc/>
public override async Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken token = default)
{
try
{
await ConnectAsync(token);
var commandResult = DLT645Helper.GetDLT645_2007Command(address, length, (byte)ControlCode.Read, Station);
if (commandResult.IsSuccess)
{
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
return (MessageBase)result.RequestInfo;
}
else
{
return OperResult.CreateFailedResult<byte[]>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <inheritdoc/>
public override void SetDataAdapter()
{
var dataHandleAdapter = new DLT645_2007DataHandleAdapter
{
EnableFEHead = EnableFEHead
};
SerialClient.SetDataHandlingAdapter(dataHandleAdapter);
}
/// <inheritdoc/>
public override async Task<OperResult> WriteAsync(string address, string value, CancellationToken token = default)
{
try
{
await ConnectAsync(token);
Password ??= string.Empty;
OperCode ??= string.Empty;
if (Password.Length < 8)
Password = Password.PadLeft(8, '0');
if (OperCode.Length < 8)
OperCode = OperCode.PadLeft(8, '0');
var data = DataTransUtil.SpliceArray(Password.ByHexStringToBytes(), OperCode.ByHexStringToBytes());
string[] strArray = value.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
var commandResult = DLT645Helper.GetDLT645_2007Command(address, 1, (byte)ControlCode.Write, Station, data, strArray);
if (commandResult.IsSuccess)
{
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
return (MessageBase)result.RequestInfo;
}
else
{
return OperResult.CreateFailedResult<byte[]>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<byte[]>(ex);
}
}
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, byte[] value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, uint value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, byte value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, double value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, float value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, long value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, ulong value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, ushort value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, short value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, int value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
/// <inheritdoc/>
public override Task<OperResult> WriteAsync(string address, bool[] value, CancellationToken token = default) => WriteAsync(address, value.ToString(), token);
#region
/// <summary>
/// 广播校时
/// </summary>
/// <param name="dateTime"></param>
/// <param name="token"></param>
/// <returns></returns>
public OperResult BroadcastTime(DateTime dateTime, CancellationToken token = default)
{
try
{
Connect(token);
string str = $"{dateTime.Second:D2}{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}{dateTime.Year % 100:D2}";
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.BroadcastTime, str.ByHexStringToBytes().Reverse().ToArray(), "999999999999".ByHexStringToBytes());
if (commandResult.IsSuccess)
{
SerialClient.Send(commandResult.Content);
return OperResult.CreateSuccessResult();
}
else
{
return OperResult.CreateFailedResult<string>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<string>(ex);
}
}
/// <summary>
/// 冻结
/// </summary>
/// <param name="dateTime"></param>
/// <param name="token"></param>
/// <returns></returns>
public async Task<OperResult> FreezeAsync(DateTime dateTime, CancellationToken token = default)
{
try
{
await ConnectAsync(token);
string str = $"{dateTime.Minute:D2}{dateTime.Hour:D2}{dateTime.Day:D2}{dateTime.Month:D2}";
if (Station.IsNullOrEmpty()) Station = string.Empty;
if (Station.Length < 12) Station = Station.PadLeft(12, '0');
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.Freeze, str.ByHexStringToBytes().Reverse().ToArray(), Station.ByHexStringToBytes().Reverse().ToArray());
if (commandResult.IsSuccess)
{
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
var result1 = ((MessageBase)result.RequestInfo);
if (result1.IsSuccess)
{
return OperResult.CreateSuccessResult();
}
else
{
return OperResult.CreateFailedResult<string>(result1);
}
}
else
{
return OperResult.CreateFailedResult<string>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<string>(ex);
}
}
/// <summary>
/// 读取通信地址
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public async Task<OperResult<string>> ReadDeviceStationAsync(CancellationToken token = default)
{
try
{
await ConnectAsync(token);
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.ReadStation, null, "AAAAAAAAAAAA".ByHexStringToBytes());
if (commandResult.IsSuccess)
{
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
var result1 = ((MessageBase)result.RequestInfo);
if (result1.IsSuccess)
{
var buffer = result1.Content.SelectMiddle(0, 6).BytesAdd(-0x33);
return OperResult.CreateSuccessResult(buffer.Reverse().ToArray().ToHexString());
}
else
{
return OperResult.CreateFailedResult<string>(result1);
}
}
else
{
return OperResult.CreateFailedResult<string>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<string>(ex);
}
}
/// <summary>
/// 修改波特率
/// </summary>
/// <param name="baudRate"></param>
/// <param name="token"></param>
/// <returns></returns>
public async Task<OperResult> WriteBaudRateAsync(int baudRate, CancellationToken token = default)
{
try
{
await ConnectAsync(token);
byte baudRateByte;
switch (baudRate)
{
case 600: baudRateByte = 0x02; break;
case 1200: baudRateByte = 0x04; break;
case 2400: baudRateByte = 0x08; break;
case 4800: baudRateByte = 0x10; break;
case 9600: baudRateByte = 0x20; break;
case 19200: baudRateByte = 0x40; break;
default: return new OperResult<string>($"不支持此波特率:{baudRate}");
}
if (Station.IsNullOrEmpty()) Station = string.Empty;
if (Station.Length < 12) Station = Station.PadLeft(12, '0');
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteBaudRate, new byte[] { baudRateByte }, Station.ByHexStringToBytes().Reverse().ToArray());
if (commandResult.IsSuccess)
{
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
var result1 = ((MessageBase)result.RequestInfo);
if (result1.IsSuccess)
{
return OperResult.CreateSuccessResult();
}
else
{
return OperResult.CreateFailedResult<string>(result1);
}
}
else
{
return OperResult.CreateFailedResult<string>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<string>(ex);
}
}
/// <summary>
/// 更新通信地址
/// </summary>
/// <param name="station"></param>
/// <param name="token"></param>
/// <returns></returns>
public async Task<OperResult> WriteDeviceStationAsync(string station, CancellationToken token = default)
{
try
{
await ConnectAsync(token);
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WriteStation, station.ByHexStringToBytes().Reverse().ToArray(), "AAAAAAAAAAAA".ByHexStringToBytes());
if (commandResult.IsSuccess)
{
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
var result1 = ((MessageBase)result.RequestInfo);
if (result1.IsSuccess)
{
return OperResult.CreateSuccessResult();
}
else
{
return OperResult.CreateFailedResult<string>(result1);
}
}
else
{
return OperResult.CreateFailedResult<string>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<string>(ex);
}
}
/// <summary>
/// 修改密码
/// </summary>
/// <param name="level"></param>
/// <param name="oldPassword"></param>
/// <param name="newPassword"></param>
/// <param name="token"></param>
/// <returns></returns>
public async Task<OperResult> WritePasswordAsync(byte level, string oldPassword, string newPassword, CancellationToken token = default)
{
try
{
await ConnectAsync(token);
if (Station.IsNullOrEmpty()) Station = string.Empty;
if (Station.Length < 12) Station = Station.PadLeft(12, '0');
string str = $"04000C{level:D2}";
var commandResult = DLT645Helper.GetDLT645_2007Command((byte)ControlCode.WritePassword,
str.ByHexStringToBytes().Reverse().ToArray()
.SpliceArray(oldPassword.ByHexStringToBytes().Reverse().ToArray())
.SpliceArray(newPassword.ByHexStringToBytes().Reverse().ToArray())
, Station.ByHexStringToBytes().Reverse().ToArray());
if (commandResult.IsSuccess)
{
var result = await WaitingClientEx.SendThenResponseAsync(commandResult.Content, TimeOut, token);
var result1 = ((MessageBase)result.RequestInfo);
if (result1.IsSuccess)
{
return OperResult.CreateSuccessResult();
}
else
{
return OperResult.CreateFailedResult<string>(result1);
}
}
else
{
return OperResult.CreateFailedResult<string>(commandResult);
}
}
catch (Exception ex)
{
return new OperResult<string>(ex);
}
}
#endregion
}
/// <summary>
/// 控制码
/// </summary>
public enum ControlCode : byte
{
/// <summary>
/// 读数据
/// </summary>
Read = 0x11,
/// <summary>
/// 读后续数据
/// </summary>
ReadSub = 0x12,
/// <summary>
/// 读站号
/// </summary>
ReadStation = 0x13,
/// <summary>
/// 写数据
/// </summary>
Write = 0x14,
/// <summary>
/// 写站号
/// </summary>
WriteStation = 0x15,
/// <summary>
/// 广播校时
/// </summary>
BroadcastTime = 0x08,
/// <summary>
/// 冻结
/// </summary>
Freeze = 0x16,
/// <summary>
/// 更新波特率
/// </summary>
WriteBaudRate = 0x17,
/// <summary>
/// 更新密码
/// </summary>
WritePassword = 0x18,
}

Some files were not shown because too many files have changed in this diff Show More