Compare commits
	
		
			73 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 65c695d9ce | ||
|   | 57253fe46a | ||
|   | 4e5c443440 | ||
|   | 0b3b73d8ec | ||
|   | 921eabc134 | ||
|   | 0faa428751 | ||
|   | f71a2fdd63 | ||
|   | 4eb9ed8aba | ||
|   | d7b549abb8 | ||
|   | 95d723c578 | ||
|   | 2fcd853e86 | ||
|   | 07eef7c812 | ||
|   | b01e0757fa | ||
|   | 32844a20c6 | ||
|   | 5b6532c601 | ||
|   | 2c5b4b4027 | ||
|   | 72d7ecf195 | ||
|   | 2cfa6b4306 | ||
|   | 6f6ffde0ab | ||
|   | 1694739a16 | ||
|   | 95d1e8bfca | ||
|   | 60dec08e3c | ||
|   | a99d71be93 | ||
|   | f1331b6a0c | ||
|   | 10d66b642b | ||
|   | cd2310e4a8 | ||
|   | 1b399cf6b0 | ||
|   | 877445bc0a | ||
|   | 9a5b345bde | ||
|   | fc9e8ea7b3 | ||
|   | 32be6fcfc1 | ||
|   | 49847236c2 | ||
|   | d8424443e6 | ||
|   | f3b571ec3f | ||
|   | 99318bb5d7 | ||
|   | 1aa154c9aa | ||
|   | c65d8a445b | ||
|   | 80f4f85570 | ||
|   | 5beee43a6b | ||
|   | 8d6ae203a0 | ||
|   | 4353479a5c | ||
|   | 34d7687f9e | ||
|   | b1dc3cf4af | ||
|   | 6a58b95933 | ||
|   | d3badfd02b | ||
|   | 0098be057b | ||
|   | 6f972aa515 | ||
|   | 7407ba6313 | ||
|   | 1c79de207b | ||
|   | 257c79db92 | ||
|   | 9d1934a308 | ||
|   | d70f959902 | ||
|   | e4d810222f | ||
|   | bc1af4ae07 | ||
|   | 6e688ef43f | ||
|   | f0fe1b23dc | ||
|   | aaf2006401 | ||
|   | b821e26935 | ||
|   | 7ae4287157 | ||
|   | c6fcc38a65 | ||
|   | ab2d5c8853 | ||
|   | 5e557ff0bc | ||
|   | 918ca449a1 | ||
|   | 8e73368008 | ||
|   | f3c1faf672 | ||
|   | d6df04dd6a | ||
|   | b1b9e51ab6 | ||
|   | e49d4770ac | ||
|   | 8fa1075511 | ||
|   | 9a70169b94 | ||
|   | fefb928237 | ||
|   | ad7e700d0d | ||
|   | 1699c69147 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -361,3 +361,6 @@ MigrationBackup/ | ||||
|  | ||||
| # Fody - auto-generated XML schema | ||||
| FodyWeavers.xsd | ||||
|  | ||||
|  | ||||
| /framework/*Pro* | ||||
|   | ||||
| @@ -5,12 +5,11 @@ | ||||
|  | ||||
|  **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](https://diego2098.gitee.io/thingsgateway-docs/) 文档。 | ||||
| @@ -23,7 +22,9 @@ | ||||
|  | ||||
| [ThingsGateway演示地址](http://120.24.62.140:5000/) | ||||
|  | ||||
| 账户	:  **superAdmin**	密码 : **111111** | ||||
| 账户	:  **superAdmin**	 | ||||
|  | ||||
| 密码 : **111111** | ||||
|  | ||||
| ## 赞助 | ||||
|  | ||||
|   | ||||
| @@ -81,6 +81,15 @@ dotnet_diagnostic.CA2208.severity = none | ||||
| # IDE0057: 使用范围运算符 | ||||
| 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] | ||||
| #### 命名样式 #### | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <Project> | ||||
| 	<PropertyGroup> | ||||
| 		<TargetFrameworks>net6.0;net7.0</TargetFrameworks> | ||||
| 		<Version>2.0.0.0</Version> | ||||
| 		<Version>2.1.0.0</Version> | ||||
| 		<Authors>Diego</Authors> | ||||
| 		<Product>ThingsGateway</Product> | ||||
| 		<Copyright>© 2023-present Diego</Copyright> | ||||
|   | ||||
| @@ -19,7 +19,7 @@ using ThingsGateway.Admin.Core; | ||||
| namespace ThingsGateway.Admin.Application; | ||||
|  | ||||
| /// <summary> | ||||
| /// 后台登录控制器 | ||||
| /// 文件下载 | ||||
| /// </summary> | ||||
| [ApiDescriptionSettings(CateGoryConst.ThingsGatewayAdmin, Order = 200)] | ||||
| [Route("file")] | ||||
|   | ||||
| @@ -46,7 +46,7 @@ namespace ThingsGateway.Admin.Application | ||||
|         [AllowAnonymous, NonUnify] | ||||
|         public async Task<int> SwaggerCheckUrlAsync() | ||||
|         { | ||||
|             var enable = (await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SWAGGERLOGIN_OPEN)).ConfigValue.ToBool(); | ||||
|             var enable = (await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SWAGGERLOGIN_OPEN)).ConfigValue.ToBoolean(); | ||||
|             return enable ? 401 : 200; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -30,7 +30,7 @@ | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Admin.Application.FileController"> | ||||
|             <summary> | ||||
|             后台登录控制器 | ||||
|             文件下载 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Admin.Application.FileController.#ctor(ThingsGateway.Admin.Application.IFileService,ThingsGateway.Admin.Application.IOperateLogService,ThingsGateway.Admin.Application.IVisitLogService)"> | ||||
|   | ||||
| @@ -22,7 +22,7 @@ public class LoginOpenApiEvent | ||||
|     /// <summary> | ||||
|     /// 时间 | ||||
|     /// </summary> | ||||
|     public DateTimeOffset DateTimeOffset = SysDateTimeExtensions.CurrentDateTime; | ||||
|     public DateTime DateTime = SysDateTimeExtensions.CurrentDateTime; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 登录设备 | ||||
|   | ||||
| @@ -41,7 +41,7 @@ public class OpenApiAuthEventSubscriber : IEventSubscriber, ISingleton | ||||
|         openApiUser.LastLoginTime = openApiUser.LatestLoginTime; | ||||
|         openApiUser.LatestLoginDevice = loginEvent.Device.ToString(); | ||||
|         openApiUser.LatestLoginIp = loginEvent.Ip; | ||||
|         openApiUser.LatestLoginTime = loginEvent.DateTimeOffset; | ||||
|         openApiUser.LatestLoginTime = loginEvent.DateTime; | ||||
|  | ||||
|         #endregion 重新赋值属性,设置本次登录信息为最新的信息 | ||||
|  | ||||
|   | ||||
| @@ -135,7 +135,7 @@ public class OpenApiAuthService : IOpenApiAuthService, ITransient | ||||
|     { | ||||
|         //获取verificat列表 | ||||
|         List<VerificatInfo> verificatInfos = await GetVerificatInfos(loginEvent.OpenApiUser.Id); | ||||
|         var verificatTimeout = loginEvent.DateTimeOffset.AddMinutes(loginEvent.Expire); | ||||
|         var verificatTimeout = loginEvent.DateTime.AddMinutes(loginEvent.Expire); | ||||
|         //生成verificat信息 | ||||
|         var verificatInfo = new VerificatInfo | ||||
|         { | ||||
| @@ -149,7 +149,7 @@ public class OpenApiAuthService : IOpenApiAuthService, ITransient | ||||
|         { | ||||
|             bool isSingle = false;//默认不开启单用户登录 | ||||
|             var singleConfig = await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SINGLE_OPEN);//获取系统单用户登录选项 | ||||
|             if (singleConfig != null) isSingle = singleConfig.ConfigValue.ToBool();//如果配置不为空则设置单用户登录选项为系统配置的值 | ||||
|             if (singleConfig != null) isSingle = singleConfig.ConfigValue.ToBoolean();//如果配置不为空则设置单用户登录选项为系统配置的值 | ||||
|  | ||||
|             //判断是否单用户登录 | ||||
|             if (isSingle) | ||||
|   | ||||
| @@ -40,7 +40,7 @@ public class OpenApiSessionOutput : PrimaryKeyEntity | ||||
|     ///</summary> | ||||
|     [Description("最新登录时间")] | ||||
|     [DataTable(Order = 3, IsShow = true, Sortable = true)] | ||||
|     public DateTimeOffset? LatestLoginTime { get; set; } | ||||
|     public DateTime? LatestLoginTime { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 令牌数量 | ||||
|   | ||||
| @@ -52,8 +52,8 @@ public class OpenApiSessionService : DbRepository<OpenApiUser>, IOpenApiSessionS | ||||
|         //获取该用户的verificat信息 | ||||
|         List<VerificatInfo> verificatInfos = await _verificatService.GetOpenApiVerificatIdAsync(input.Id); | ||||
|         //当前需要踢掉用户的verificat | ||||
|         var deleteVerificats = verificatInfos.Where(it => input.VerificatIds.Contains(it.Id)).ToList(); | ||||
|         await _verificatService.SetOpenApiVerificatIdAsync(input.Id, deleteVerificats);//如果还有verificat则更新verificat | ||||
|         var setVerificats = verificatInfos.Where(it => !input.VerificatIds.Contains(it.Id)).ToList(); | ||||
|         await _verificatService.SetOpenApiVerificatIdAsync(input.Id, setVerificats);//如果还有verificat则更新verificat | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -77,7 +77,7 @@ | ||||
|       "Id": "22222222222232", | ||||
|       "Category": "SYS_CONFIGBASEDEFAULT", | ||||
|       "ConfigKey": "CONFIG_SINGLE_OPEN", | ||||
|       "ConfigValue": "true", | ||||
|       "ConfigValue": "false", | ||||
|       "Remark": "单用户登录开关", | ||||
|       "SortCode": "10", | ||||
|       "IsDelete": "false" | ||||
|   | ||||
| @@ -42,7 +42,7 @@ public class AuthEventSubscriber : IEventSubscriber, ISingleton | ||||
|         sysUser.LastLoginTime = sysUser.LatestLoginTime; | ||||
|         sysUser.LatestLoginDevice = loginEvent.Device.ToString(); | ||||
|         sysUser.LatestLoginIp = loginEvent.Ip; | ||||
|         sysUser.LatestLoginTime = loginEvent.DateTimeOffset; | ||||
|         sysUser.LatestLoginTime = loginEvent.DateTime; | ||||
|  | ||||
|         #endregion 重新赋值属性,设置本次登录信息为最新的信息 | ||||
|  | ||||
|   | ||||
| @@ -79,7 +79,7 @@ public class AuthService : IAuthService | ||||
|  | ||||
|         if (sysBase != null)//如果有这个配置项 | ||||
|         { | ||||
|             if (sysBase.ConfigValue.ToBool())//如果需要验证码 | ||||
|             if (sysBase.ConfigValue.ToBoolean())//如果需要验证码 | ||||
|             { | ||||
|                 //如果没填验证码,提示验证码不能为空 | ||||
|                 if (input.ValidCode.IsNullOrEmpty() || input.ValidCodeReqNo == 0) throw Oops.Bah("验证码不能为空").StatusCode(410); | ||||
| @@ -202,7 +202,7 @@ public class AuthService : IAuthService | ||||
|     { | ||||
|         //获取verificat列表 | ||||
|         List<VerificatInfo> verificatInfos = await _verificatService.GetVerificatIdAsync(loginEvent.SysUser.Id); | ||||
|         var verificatTimeout = loginEvent.DateTimeOffset.AddMinutes(loginEvent.Expire); | ||||
|         var verificatTimeout = loginEvent.DateTime.AddMinutes(loginEvent.Expire); | ||||
|         //生成verificat信息 | ||||
|         var verificatInfo = new VerificatInfo | ||||
|         { | ||||
| @@ -217,7 +217,7 @@ public class AuthService : IAuthService | ||||
|             bool isSingle = false;//默认不开启单用户登录 | ||||
|  | ||||
|             var singleConfig = await _configService.GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_SINGLE_OPEN);//获取系统单用户登录选项 | ||||
|             if (singleConfig != null) isSingle = singleConfig.ConfigValue.ToBool();//如果配置不为空则设置单用户登录选项为系统配置的值 | ||||
|             if (singleConfig != null) isSingle = singleConfig.ConfigValue.ToBoolean();//如果配置不为空则设置单用户登录选项为系统配置的值 | ||||
|             if (isSingle)//判断是否单用户登录 | ||||
|             { | ||||
|                 await _noticeService.LogoutAsync(loginEvent.SysUser.Id, verificatInfos.Where(it => it.Device == loginEvent.Device.ToString()).ToList(), "该账号已在别处登录!");//通知其他用户下线 | ||||
|   | ||||
| @@ -22,7 +22,7 @@ public class LoginEvent | ||||
|     /// <summary> | ||||
|     /// 时间 | ||||
|     /// </summary> | ||||
|     public DateTimeOffset DateTimeOffset = SysDateTimeExtensions.CurrentDateTime; | ||||
|     public DateTime DateTime = SysDateTimeExtensions.CurrentDateTime; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 登录设备 | ||||
|   | ||||
| @@ -40,7 +40,7 @@ public class SessionOutput : PrimaryKeyEntity | ||||
|     ///</summary> | ||||
|     [Description("最新登录时间")] | ||||
|     [DataTable(Order = 4, IsShow = true, Sortable = true)] | ||||
|     public DateTimeOffset? LatestLoginTime { get; set; } | ||||
|     public DateTime? LatestLoginTime { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 在线状态 | ||||
|   | ||||
| @@ -52,12 +52,11 @@ public class SessionService : DbRepository<SysUser>, ISessionService | ||||
|     { | ||||
|         //获取该用户的verificat信息 | ||||
|         List<VerificatInfo> verificatInfos = await _verificatService.GetVerificatIdAsync(input.Id); | ||||
|         //当前需要踢掉用户的verificat | ||||
|         List<VerificatInfo> deleteVerificats = new(); | ||||
|  | ||||
|         //踢掉包含verificat列表的verificat信息 | ||||
|         deleteVerificats = verificatInfos.Where(it => input.VerificatIds.Contains(it.Id)).ToList(); | ||||
|         await _verificatService.SetVerificatIdAsync(input.Id, deleteVerificats);//如果还有verificat则更新verificat | ||||
|         var setVerificats = verificatInfos.Where(it => !input.VerificatIds.Contains(it.Id)).ToList(); | ||||
|         var deleteVerificats = verificatInfos.Where(it => input.VerificatIds.Contains(it.Id)).ToList(); | ||||
|         await _verificatService.SetVerificatIdAsync(input.Id, setVerificats);//如果还有verificat则更新verificat | ||||
|  | ||||
|         var message = "您已被强制下线!"; | ||||
|         await _noticeService.LogoutAsync(input.Id, deleteVerificats, message);//通知下线 | ||||
|   | ||||
| @@ -479,7 +479,7 @@ | ||||
|             登录事件参数 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Admin.Application.LoginOpenApiEvent.DateTimeOffset"> | ||||
|         <member name="F:ThingsGateway.Admin.Application.LoginOpenApiEvent.DateTime"> | ||||
|             <summary> | ||||
|             时间 | ||||
|             </summary> | ||||
| @@ -1192,7 +1192,7 @@ | ||||
|             登录事件参数 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Admin.Application.LoginEvent.DateTimeOffset"> | ||||
|         <member name="F:ThingsGateway.Admin.Application.LoginEvent.DateTime"> | ||||
|             <summary> | ||||
|             时间 | ||||
|             </summary> | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -20,19 +20,19 @@ namespace ThingsGateway.Admin.Blazor.Core; | ||||
| public partial class AppBarItems | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 链接 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_COPYRIGHT_URL { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>Ȩ | ||||
|     /// 版权 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_COPYRIGHT { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 标题 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_TITLE { get; set; } | ||||
|   | ||||
| @@ -294,7 +294,7 @@ public partial class AppDateTimePicker | ||||
|         Value = dateTime; | ||||
|         if (ValueChanged.HasDelegate) | ||||
|         { | ||||
|             await ValueChanged.InvokeAsync(dateTime); | ||||
|             await ValueChanged.InvokeAsync(DateTime.SpecifyKind(dateTime.Value, DateTimeKind.Utc)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -14,7 +14,7 @@ using Microsoft.AspNetCore.Components; | ||||
|  | ||||
| namespace ThingsGateway.Admin.Blazor.Core; | ||||
| /// <summary> | ||||
| /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>/ͣ<><CDA3> <20>ı<EFBFBD><C4B1><EFBFBD>ʾ | ||||
| /// 启用/停用 文本提示 | ||||
| /// </summary> | ||||
| public partial class EnableChip | ||||
| { | ||||
| @@ -46,5 +46,5 @@ public partial class EnableChip | ||||
|  | ||||
|     private string TextColor => Value ? "green" : "error"; | ||||
|     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 ?? "停用"; | ||||
| } | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| namespace ThingsGateway.Admin.Blazor.Core; | ||||
| /// <summary> | ||||
| /// <EFBFBD>ղ<EFBFBD>/<2F><><EFBFBD>ݷ<EFBFBD>ʽ | ||||
| /// 收藏/快捷方式 | ||||
| /// </summary> | ||||
| public partial class Favorite | ||||
| { | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -22,17 +22,17 @@ public partial class Foter | ||||
| { | ||||
|     private string Version = ""; | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 链接 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_COPYRIGHT_URL { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>Ȩ | ||||
|     /// 版权 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_COPYRIGHT { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 标题 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_TITLE { get; set; } | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -20,23 +20,23 @@ namespace ThingsGateway.Admin.Blazor.Core; | ||||
| public partial class Logo | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Logo<EFBFBD>߶<EFBFBD> | ||||
|     /// Logo高度 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public int HeightInt { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 链接 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_COPYRIGHT_URL { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>Ȩ | ||||
|     /// 版权 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_COPYRIGHT { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 标题 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public string CONFIG_TITLE { get; set; } | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -34,7 +34,7 @@ public partial class PageTabs | ||||
|         return op; | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// Tabsʵ<EFBFBD><EFBFBD> | ||||
|     /// Tabs实例 | ||||
|     /// </summary> | ||||
|     public PPageTabs PPageTabs { get; private set; } | ||||
|  | ||||
| @@ -46,7 +46,7 @@ public partial class PageTabs | ||||
|     [Parameter] | ||||
|     public IEnumerable<string> SelfPatterns { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 子组件 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public RenderFragment ChildContent { get; set; } | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -49,11 +49,11 @@ public partial class UserMenu | ||||
|         var ret = str?.ToJsonWithT<UnifyResult<string>>(); | ||||
|         if (ret?.Code != 200) | ||||
|         { | ||||
|             await PopupService.EnqueueSnackbarAsync("ע<EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD>", AlertTypes.Error); | ||||
|             await PopupService.EnqueueSnackbarAsync("注销失败", AlertTypes.Error); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             await PopupService.EnqueueSnackbarAsync("ע<EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); | ||||
|             await PopupService.EnqueueSnackbarAsync("注销成功", AlertTypes.Success); | ||||
|             await Task.Delay(500); | ||||
|             NavigationManager.NavigateTo(NavigationManager.Uri); | ||||
|         } | ||||
|   | ||||
| @@ -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 | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -10,6 +10,8 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using BlazorComponent; | ||||
|  | ||||
| using Furion; | ||||
|  | ||||
| using Masa.Blazor; | ||||
| @@ -61,6 +63,8 @@ public class Startup : AppStartup | ||||
|  | ||||
|  | ||||
|             }); | ||||
|             options.Locale = new Locale("zh-CN", "en-US"); | ||||
|  | ||||
|         }); | ||||
|  | ||||
|         services.AddScoped<InitTimezone>(); | ||||
|   | ||||
| @@ -14,8 +14,8 @@ | ||||
| 	 | ||||
| 	<ItemGroup> | ||||
|  | ||||
| 		<PackageReference Include="Masa.Blazor" Version="1.0.1" /> | ||||
| 		<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.9" /> | ||||
| 		<PackageReference Include="Masa.Blazor" Version="1.0.2" /> | ||||
| 		<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.10" /> | ||||
|  | ||||
| 	</ItemGroup> | ||||
| 	 | ||||
|   | ||||
| @@ -857,5 +857,38 @@ | ||||
|             设置深浅主题统一由这个方法为入口 | ||||
|             </summary> | ||||
|         </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> | ||||
| </doc> | ||||
|   | ||||
| @@ -153,7 +153,7 @@ public class UserResoures : IDisposable | ||||
|     { | ||||
|         if (MasaBlazor.Theme.Dark != isDark || isDark == null) | ||||
|             MasaBlazor.ToggleTheme(); | ||||
|         _cookieStorage?.SetItemAsync(BlazorResourceConst.ThemeCookieKey, isDark.ToJsonString()); | ||||
|         _cookieStorage?.SetItemAsync(BlazorResourceConst.ThemeCookieKey, MasaBlazor.Theme.Dark.ToJsonString()); | ||||
|     } | ||||
|  | ||||
|     private void InitCookie(IRequestCookieCollection cookies) | ||||
|   | ||||
| @@ -48,8 +48,7 @@ | ||||
|         var controllerTypes = App.EffectiveTypes. | ||||
|     Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass | ||||
|     && 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(); | ||||
|         return assemblys; | ||||
|     } | ||||
|   | ||||
| @@ -189,38 +189,39 @@ | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|  | ||||
|                     if (context?.Value?.GetType() == typeof(DateTimeOffset)) | ||||
|                     if (ItemColWithDTTemplate != null) | ||||
|                     { | ||||
|                         <span> | ||||
|                             @(((DateTimeOffset)context.Value).ToOffset(InitTimezone.TimezoneOffset).ToDefaultDateTimeFormat()) | ||||
|                         </span> | ||||
|                     } | ||||
|                     else if (context?.Value?.GetType() == typeof(DateTime)) | ||||
|                     { | ||||
|                         <span> | ||||
|                             @(((DateTime)context.Value).Add(InitTimezone.TimezoneOffset).ToDefaultDateTimeFormat()) | ||||
|                         </span> | ||||
|                     } | ||||
|                     else if (ItemColTemplate != null) | ||||
|                     { | ||||
|                         @ItemColTemplate(context) | ||||
|                         @ItemColWithDTTemplate(context) | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         @if (context.Header.CellClass?.Contains("text-truncate") == true) | ||||
|                         if (context?.Value?.GetType() == typeof(DateTime)) | ||||
|                         { | ||||
|                             <span title=@context.Value> | ||||
|                                 @context.Value | ||||
|                             <span> | ||||
|                                 @(((DateTime)context.Value).ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)) | ||||
|                             </span> | ||||
|                         } | ||||
|                         else if (ItemColTemplate != null) | ||||
|                         { | ||||
|                             @ItemColTemplate(context) | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             @context.Value | ||||
|                         } | ||||
|                             @if (context.Header.CellClass?.Contains("text-truncate") == true) | ||||
|                             { | ||||
|                                 <span title=@context.Value> | ||||
|                                     @context.Value | ||||
|                                 </span> | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 @context.Value | ||||
|                             } | ||||
|  | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|  | ||||
|                 } | ||||
|             </ItemColContent> | ||||
|         </MDataTable> | ||||
| @@ -309,16 +310,24 @@ | ||||
|                         { | ||||
|                             string value = DetailModelPairs[item.Value]; | ||||
|                             { | ||||
|                                 <tr @key="item.Text"> | ||||
|                                     <td class="text-start table-minwidth"> | ||||
|                                         @item.Text | ||||
|                                     </td> | ||||
|                                     <td class="text-start "> | ||||
|                                         <div style="word-break:break-all; white-space:pre-wrap;"> | ||||
|                                             @value | ||||
|                                         </div> | ||||
|                                     </td> | ||||
|                                 </tr> | ||||
|                                 @if (Detailemplate != null) | ||||
|                                 { | ||||
|                                     @Detailemplate((item,value)) | ||||
|                                 } | ||||
|                                 else | ||||
|                                 { | ||||
|                                     <tr @key="item.Text"> | ||||
|                                         <td class="text-start table-minwidth"> | ||||
|                                             @item.Text | ||||
|                                         </td> | ||||
|                                         <td class="text-start "> | ||||
|                                             <div style="word-break:break-all; white-space:pre-wrap;"> | ||||
|                                                 @value | ||||
|                                             </div> | ||||
|                                         </td> | ||||
|                                     </tr> | ||||
|                                 } | ||||
|                                  | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|   | ||||
| @@ -72,12 +72,6 @@ public partial class AppDataTable<TItem, SearchItem, AddItem, EditItem> : IAppDa | ||||
|     [Parameter] | ||||
|     public bool Dense { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获得/设置 明细行模板 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public RenderFragment<TItem> DetailRowTemplate { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 编辑项委托 | ||||
|     /// </summary> | ||||
| @@ -89,6 +83,11 @@ public partial class AppDataTable<TItem, SearchItem, AddItem, EditItem> : IAppDa | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public RenderFragment<EditItem> EditTemplate { get; set; } | ||||
|     /// <summary> | ||||
|     /// 获得/设置 详情模板 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public RenderFragment<(DataTableHeader<TItem>, string)> Detailemplate { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 表头过滤,返回DataTableHeader列表,传输参数已包含全部初始表头与表头标题 | ||||
| @@ -193,6 +192,13 @@ public partial class AppDataTable<TItem, SearchItem, AddItem, EditItem> : IAppDa | ||||
|     [Parameter] | ||||
|     public RenderFragment<ItemColProps<TItem>> ItemColTemplate { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 独立设置 Table Cols 模板,需自行实现DateTime类型的时区转换 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public RenderFragment<ItemColProps<TItem>> ItemColWithDTTemplate { get; set; } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 当前显示项目 | ||||
|     /// </summary> | ||||
| @@ -457,13 +463,9 @@ public partial class AppDataTable<TItem, SearchItem, AddItem, EditItem> : IAppDa | ||||
|                 if (item != BlazorResourceConst.DataTableActions) | ||||
|                 { | ||||
|                     var value = typeof(TItem).GetMemberInfoValue(DetailModel, item); | ||||
|                     if (value is DateTimeOffset dt) | ||||
|                     if (value is DateTime dt2) | ||||
|                     { | ||||
|                         value = dt.ToOffset(InitTimezone.TimezoneOffset).ToDefaultDateTimeFormat(); | ||||
|                     } | ||||
|                     else if (value is DateTime dt2) | ||||
|                     { | ||||
|                         value = dt2.Add(InitTimezone.TimezoneOffset).ToDefaultDateTimeFormat(); | ||||
|                         value = dt2.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset); | ||||
|                     } | ||||
|                     keyValuePairs.Add(item, value?.ToString()); | ||||
|                 } | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
|   | ||||
| @@ -66,7 +66,7 @@ | ||||
|                                       Small> | ||||
|                     <MRow Class="pt-1"> | ||||
|                         <MCol Cols="4"> | ||||
|                             <span class="text-caption">@item.OpTime.ToDefaultDateTimeFormat()</span> | ||||
|                             <span class="text-caption">@item.OpTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)</span> | ||||
|                         </MCol> | ||||
|                         <MCol> | ||||
|                             <div class="text-body-1">@item.Name</div> | ||||
| @@ -93,7 +93,7 @@ | ||||
|                                       Small> | ||||
|                     <MRow Class="pt-1"> | ||||
|                         <MCol Cols="4"> | ||||
|                             <span class="text-caption">@item.OpTime.ToDefaultDateTimeFormat()</span> | ||||
|                             <span class="text-caption">@item.OpTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)</span> | ||||
|                         </MCol> | ||||
|                         <MCol> | ||||
|                             <div class="text-body-1">@item.Name</div> | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -18,7 +18,7 @@ using ThingsGateway.Admin.Core; | ||||
|  | ||||
| namespace ThingsGateway.Admin.Blazor; | ||||
| /// <summary> | ||||
| /// <EFBFBD><EFBFBD>ҳ | ||||
| /// 首页 | ||||
| /// </summary> | ||||
| public partial class Index | ||||
| { | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -18,7 +18,7 @@ using ThingsGateway.Admin.Core; | ||||
|  | ||||
| namespace ThingsGateway.Admin.Blazor; | ||||
| /// <summary> | ||||
| /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
| /// 个人设置 | ||||
| /// </summary> | ||||
| public partial class UserCenter | ||||
| { | ||||
| @@ -50,25 +50,25 @@ public partial class UserCenter | ||||
|     { | ||||
|         await UserCenterService.UpdateUserDefaultRazorAsync(UserManager.UserId, DefaultMenuId); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|         await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); | ||||
|         await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|     } | ||||
|  | ||||
|     async Task OnShortcutSaveAsync() | ||||
|     { | ||||
|         await UserCenterService.UpdateWorkbenchAsync(_menusChoice); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|         await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); | ||||
|         await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|     } | ||||
|     async Task OnUpdatePasswordInfoAsync(FormContext context) | ||||
|     { | ||||
|         var success = context.Validate(); | ||||
|         if (success) | ||||
|         { | ||||
|             //<EFBFBD><EFBFBD>֤<EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD> | ||||
|             //验证成功,操作业务 | ||||
|             _passwordInfoInput.Id = UserResoures.CurrentUser.Id; | ||||
|             await UserCenterService.EditPasswordAsync(_passwordInfoInput); | ||||
|             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); | ||||
|             NavigationManager.NavigateTo(NavigationManager.Uri); | ||||
|         } | ||||
| @@ -78,6 +78,6 @@ public partial class UserCenter | ||||
|     { | ||||
|         await UserCenterService.UpdateUserInfoAsync(_updateInfoInput); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|         await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); | ||||
|         await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|     } | ||||
| } | ||||
| @@ -133,7 +133,7 @@ public partial class Login | ||||
|         GetCaptchaInfo(); | ||||
|         CONFIG_TITLE = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_TITLE))?.ConfigValue; | ||||
|         CONFIG_REMARK = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_REMARK))?.ConfigValue; | ||||
|         _showCaptcha = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_CAPTCHA_OPEN))?.ConfigValue?.ToBool() == true; | ||||
|         _showCaptcha = (await App.GetService<IConfigService>().GetByConfigKeyAsync(ConfigConst.SYS_CONFIGBASEDEFAULT, ConfigConst.CONFIG_CAPTCHA_OPEN))?.ConfigValue?.ToBoolean() == true; | ||||
|         Welcome = "欢迎使用" + CONFIG_TITLE + "!"; | ||||
|         await base.OnParametersSetAsync(); | ||||
|     } | ||||
|   | ||||
| @@ -43,11 +43,6 @@ | ||||
|             表格紧凑 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.DetailRowTemplate"> | ||||
|             <summary> | ||||
|             获得/设置 明细行模板 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.EditCallAsync"> | ||||
|             <summary> | ||||
|             编辑项委托 | ||||
| @@ -58,6 +53,11 @@ | ||||
|             获得/设置 编辑模板 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.Detailemplate"> | ||||
|             <summary> | ||||
|             获得/设置 详情模板 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.FilterHeaders"> | ||||
|             <summary> | ||||
|             表头过滤,返回DataTableHeader列表,传输参数已包含全部初始表头与表头标题 | ||||
| @@ -148,6 +148,11 @@ | ||||
|             获得/设置 Table Cols 模板 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.ItemColWithDTTemplate"> | ||||
|             <summary> | ||||
|             独立设置 Table Cols 模板,需自行实现DateTime类型的时区转换 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Admin.Blazor.Core.AppDataTable`4.Items"> | ||||
|             <summary> | ||||
|             当前显示项目 | ||||
|   | ||||
| @@ -22,7 +22,7 @@ public class UserManager | ||||
|     /// <summary> | ||||
|     /// 是否超级管理员 | ||||
|     /// </summary> | ||||
|     public static bool IsSuperAdmin => (App.User?.FindFirst(ClaimConst.IsSuperAdmin)?.Value).ToBool(); | ||||
|     public static bool IsSuperAdmin => (App.User?.FindFirst(ClaimConst.IsSuperAdmin)?.Value).ToBoolean(); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 当前用户账号 | ||||
|   | ||||
| @@ -50,7 +50,7 @@ public abstract class BaseEntity : PrimaryKeyEntity | ||||
|     /// </summary> | ||||
|     [SugarColumn(ColumnDescription = "创建时间", IsOnlyIgnoreUpdate = true, IsNullable = true)] | ||||
|     [IgnoreExcel] | ||||
|     public virtual DateTimeOffset? CreateTime { get; set; } | ||||
|     public virtual DateTime? CreateTime { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 创建人 | ||||
| @@ -78,7 +78,7 @@ public abstract class BaseEntity : PrimaryKeyEntity | ||||
|     /// </summary> | ||||
|     [SugarColumn(ColumnDescription = "更新时间", IsOnlyIgnoreInsert = true, IsNullable = true)] | ||||
|     [IgnoreExcel] | ||||
|     public virtual DateTimeOffset? UpdateTime { get; set; } | ||||
|     public virtual DateTime? UpdateTime { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 更新人 | ||||
|   | ||||
| @@ -54,7 +54,7 @@ public class OpenApiUser : BaseEntity | ||||
|     ///</summary> | ||||
|     [SugarColumn(ColumnName = "LastLoginTime", ColumnDescription = "上次登录时间", IsNullable = true)] | ||||
|     [DataTable(Order = 10, IsShow = true, Sortable = true, DefaultFilter = true)] | ||||
|     public DateTimeOffset? LastLoginTime { get; set; } | ||||
|     public DateTime? LastLoginTime { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 最新登录设备 | ||||
| @@ -75,7 +75,7 @@ public class OpenApiUser : BaseEntity | ||||
|     ///</summary> | ||||
|     [SugarColumn(ColumnName = "LatestLoginTime", ColumnDescription = "最新登录时间", IsNullable = true)] | ||||
|     [DataTable(Order = 7, IsShow = true, Sortable = true)] | ||||
|     public DateTimeOffset? LatestLoginTime { get; set; } | ||||
|     public DateTime? LatestLoginTime { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 密码 | ||||
|   | ||||
| @@ -60,7 +60,7 @@ public class SysUser : BaseEntity | ||||
|     ///</summary> | ||||
|     [SugarColumn(ColumnName = "LastLoginTime", ColumnDescription = "上次登录时间", IsNullable = true)] | ||||
|     [DataTable(Order = 5, IsShow = true, Sortable = true, DefaultFilter = true)] | ||||
|     public DateTimeOffset? LastLoginTime { get; set; } | ||||
|     public DateTime? LastLoginTime { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 最新登录设备 | ||||
| @@ -81,7 +81,7 @@ public class SysUser : BaseEntity | ||||
|     ///</summary> | ||||
|     [SugarColumn(ColumnName = "LatestLoginTime", ColumnDescription = "最新登录时间", IsNullable = true)] | ||||
|     [DataTable(Order = 8, IsShow = true, Sortable = true, DefaultFilter = false)] | ||||
|     public DateTimeOffset? LatestLoginTime { get; set; } | ||||
|     public DateTime? LatestLoginTime { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 密码 | ||||
|   | ||||
| @@ -100,5 +100,5 @@ public class VerificatInfo : PrimaryIdEntity | ||||
|     /// </summary> | ||||
|     [Description("超时时间")] | ||||
|     [DataTable(Order = 5, IsShow = true, Sortable = true)] | ||||
|     public DateTimeOffset VerificatTimeout { get; set; } | ||||
|     public DateTime VerificatTimeout { get; set; } | ||||
| } | ||||
| @@ -75,7 +75,7 @@ public class SysVisitLog : BaseEntity | ||||
|     ///</summary> | ||||
|     [SugarColumn(ColumnName = "OpTime", ColumnDescription = "操作时间")] | ||||
|     [DataTable(Order = 8, IsShow = true, Sortable = true, DefaultFilter = false)] | ||||
|     public DateTimeOffset OpTime { get; set; } | ||||
|     public DateTime OpTime { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 验证Id | ||||
|   | ||||
| @@ -330,7 +330,7 @@ public static class ObjectExtensions | ||||
|     /// 转换布尔值 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public static bool ToBool(this object value, bool defaultValue = false) => value?.ToString().ToUpper() switch | ||||
|     public static bool ToBoolean(this object value, bool defaultValue = false) => value?.ToString().ToUpper() switch | ||||
|     { | ||||
|         "1" or "TRUE" => true, | ||||
|         _ => defaultValue, | ||||
| @@ -356,10 +356,22 @@ public static class ObjectExtensions | ||||
|         { | ||||
|             return Double.IsNaN(d) ? defaultValue : (Decimal)d; | ||||
|         } | ||||
|         var str = value.ToString(); | ||||
|         var str = value?.ToString(); | ||||
|         return str.IsNullOrEmpty() ? defaultValue : Decimal.TryParse(str, out var n) ? n : defaultValue; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// ToDecimal | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public static double ToDouble(this object value, double defaultValue = 0) | ||||
|     { | ||||
|         if (value is Double d) | ||||
|         { | ||||
|             return Double.IsNaN(d) ? defaultValue : (Double)d; | ||||
|         } | ||||
|         var str = value?.ToString(); | ||||
|         return str.IsNullOrEmpty() ? defaultValue : double.TryParse(str, out var n) ? n : defaultValue; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// JsonElement 转 Object | ||||
|   | ||||
| @@ -97,7 +97,7 @@ public static class StringExtensions | ||||
|     /// 转换布尔值 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public static bool ToBool(this string value, bool defaultValue = false) => value?.ToUpper() switch | ||||
|     public static bool ToBoolean(this string value, bool defaultValue = false) => value?.ToUpper() switch | ||||
|     { | ||||
|         "1" or "TRUE" => true, | ||||
|         _ => defaultValue, | ||||
|   | ||||
| @@ -21,26 +21,39 @@ namespace ThingsGateway.Admin.Core; | ||||
| public static class SysDateTimeExtensions | ||||
| { | ||||
|     private static readonly DateTime _dt1970 = new(1970, 1, 1); | ||||
|     private static readonly DateTimeOffset _dto1970 = new(new DateTime(1970, 1, 1)); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 系统默认使用的当前时间 | ||||
|     /// </summary> | ||||
|     public static DateTimeOffset CurrentDateTime => DateTimeOffset.Now; | ||||
|     public static DateTime CurrentDateTime => DateTime.Now; | ||||
|     /// <summary> | ||||
|     /// 返回yyyy-MM-dd HH:mm:ss:fff zz时间格式字符串 | ||||
|     /// </summary> | ||||
|     public static string ToDefaultDateTimeFormat(this in DateTime dt) => dt.ToString("yyyy-MM-dd HH:mm:ss:fff zz"); | ||||
|  | ||||
|     public static string ToDefaultDateTimeFormat(this in DateTime dt, TimeSpan offset) | ||||
|     { | ||||
|         if (dt.Kind == DateTimeKind.Utc) | ||||
|             return new DateTimeOffset(dt.ToLocalTime(), offset).ToString("yyyy-MM-dd HH:mm:ss:fff zz"); | ||||
|         else if (dt == DateTime.MinValue || dt == DateTime.MaxValue) | ||||
|             return dt.ToString("yyyy-MM-dd HH:mm:ss:fff zz"); | ||||
|         else | ||||
|             return new DateTimeOffset(dt, offset).ToString("yyyy-MM-dd HH:mm:ss:fff zz"); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 返回yyyy-MM-dd HH:mm:ss:fff zz时间格式字符串 | ||||
|     /// </summary> | ||||
|     public static string ToDefaultDateTimeFormat(this in DateTimeOffset dt) => dt.ToString("yyyy-MM-dd HH:mm:ss:fff zz"); | ||||
|  | ||||
|     public static string ToDefaultDateTimeFormat(this in DateTime dt) | ||||
|     { | ||||
|         return dt.ToString("yyyy-MM-dd HH:mm:ss:fff zz"); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 返回yyyy-MM-dd HH-mm-ss-fff zz时间格式字符串 | ||||
|     /// 返回yyyy-MM-dd HH:mm:ss:fff zz时间格式字符串 | ||||
|     /// </summary> | ||||
|     public static string ToFileDateTimeFormat(this in DateTimeOffset dt) => dt.ToString("yyyy-MM-dd HH-mm-ss-fff zz"); | ||||
|     public static string ToFileDateTimeFormat(this in DateTime dt) | ||||
|     { | ||||
|         return dt.ToString("yyyy-MM-dd HH-mm-ss-fff zz"); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
| @@ -166,15 +179,5 @@ public static class SysDateTimeExtensions | ||||
|         return (Int64)(value - _dt1970).TotalMilliseconds; | ||||
|  | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// ToLong | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public static long ToLong(this DateTimeOffset value, long defaultValue = 0) | ||||
|     { | ||||
|         // 特殊处理时间,转Unix毫秒 | ||||
|         return value == DateTimeOffset.MinValue ? 0 : (Int64)(value - _dto1970).TotalMilliseconds; | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -9,13 +9,13 @@ | ||||
| 	</ItemGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.8.8.40" /> | ||||
| 		<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.8.8.40" /> | ||||
| 		<PackageReference Include="Furion.Pure" Version="4.8.8.40" /> | ||||
| 		<PackageReference Include="SqlSugarCore" Version="5.1.4.94" /> | ||||
| 		<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.8.8.41" /> | ||||
| 		<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.8.8.41" /> | ||||
| 		<PackageReference Include="Furion.Pure" Version="4.8.8.41" /> | ||||
| 		<PackageReference Include="SqlSugarCore" Version="5.1.4.102" /> | ||||
| 		<PackageReference Include="UAParser" Version="3.1.47" /> | ||||
| 		<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /> | ||||
| 		<PackageReference Include="MiniExcel" Version="1.31.0" /> | ||||
| 		<PackageReference Include="MiniExcel" Version="1.31.2" /> | ||||
| 	</ItemGroup> | ||||
| 	 | ||||
| </Project> | ||||
| @@ -1026,7 +1026,7 @@ | ||||
|             <param name="str"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Admin.Core.ObjectExtensions.ToBool(System.Object,System.Boolean)"> | ||||
|         <member name="M:ThingsGateway.Admin.Core.ObjectExtensions.ToBoolean(System.Object,System.Boolean)"> | ||||
|             <summary> | ||||
|             转换布尔值 | ||||
|             </summary> | ||||
| @@ -1050,6 +1050,12 @@ | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Admin.Core.ObjectExtensions.ToDouble(System.Object,System.Double)"> | ||||
|             <summary> | ||||
|             ToDecimal | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Admin.Core.ObjectExtensions.ToObject(System.Text.Json.JsonElement)"> | ||||
|             <summary> | ||||
|             JsonElement 转 Object | ||||
| @@ -1142,7 +1148,7 @@ | ||||
|             <param name="input"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Admin.Core.StringExtensions.ToBool(System.String,System.Boolean)"> | ||||
|         <member name="M:ThingsGateway.Admin.Core.StringExtensions.ToBoolean(System.String,System.Boolean)"> | ||||
|             <summary> | ||||
|             转换布尔值 | ||||
|             </summary> | ||||
| @@ -1196,21 +1202,21 @@ | ||||
|             系统默认使用的当前时间 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Admin.Core.SysDateTimeExtensions.ToDefaultDateTimeFormat(System.DateTime@,System.TimeSpan)"> | ||||
|             <summary> | ||||
|             返回yyyy-MM-dd HH:mm:ss:fff zz时间格式字符串 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Admin.Core.SysDateTimeExtensions.ToDefaultDateTimeFormat(System.DateTime@)"> | ||||
|             <summary> | ||||
|             返回yyyy-MM-dd HH:mm:ss:fff zz时间格式字符串 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Admin.Core.SysDateTimeExtensions.ToDefaultDateTimeFormat(System.DateTimeOffset@)"> | ||||
|         <member name="M:ThingsGateway.Admin.Core.SysDateTimeExtensions.ToFileDateTimeFormat(System.DateTime@)"> | ||||
|             <summary> | ||||
|             返回yyyy-MM-dd HH:mm:ss:fff zz时间格式字符串 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Admin.Core.SysDateTimeExtensions.ToFileDateTimeFormat(System.DateTimeOffset@)"> | ||||
|             <summary> | ||||
|             返回yyyy-MM-dd HH-mm-ss-fff zz时间格式字符串 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Admin.Core.SysDateTimeExtensions.GetDiffTime(System.DateTime@,System.DateTime@)"> | ||||
|             <summary> | ||||
|             计算2个时间差,返回文字描述 | ||||
| @@ -1233,12 +1239,6 @@ | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Admin.Core.SysDateTimeExtensions.ToLong(System.DateTimeOffset,System.Int64)"> | ||||
|             <summary> | ||||
|             ToLong | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Admin.Core.TextWriterExtensions"> | ||||
|             <summary> | ||||
|             TextWriter扩展 | ||||
|   | ||||
| @@ -41,5 +41,5 @@ public class UnifyResult<T> | ||||
|     /// <summary> | ||||
|     /// 时间 | ||||
|     /// </summary> | ||||
|     public DateTimeOffset Time { get; set; } | ||||
|     public DateTime Time { get; set; } | ||||
| } | ||||
| @@ -21,7 +21,7 @@ using ThingsGateway.Application; | ||||
| namespace ThingsGateway.ApiController; | ||||
|  | ||||
| /// <summary> | ||||
| /// 后台登录控制器 | ||||
| /// 文件下载 | ||||
| /// </summary> | ||||
| [ApiDescriptionSettings(CateGoryConst.ThingsGatewayAdmin, Order = 200)] | ||||
| [Route("gatewayFile")] | ||||
|   | ||||
| @@ -89,13 +89,8 @@ public class RpcControler : IDynamicApiController | ||||
|     [Description("写入变量")] | ||||
|     public async Task<Dictionary<string, OperResult>> WriteDeviceMethods(Dictionary<string, string> objs) | ||||
|     { | ||||
|         Dictionary<string, OperResult> operResultDict = new(); | ||||
|         foreach (KeyValuePair<string, string> obj in objs) | ||||
|         { | ||||
|             var result = await RpcCore.InvokeDeviceMethodAsync($"WebApi-{UserManager.UserAccount}-{App.HttpContext.Connection.RemoteIpAddress.MapToIPv4()}", obj); | ||||
|             operResultDict.Add(obj.Key, result); | ||||
|         } | ||||
|         return operResultDict; | ||||
|         var result = await RpcCore.InvokeDeviceMethodAsync($"WebApi-{UserManager.UserAccount}-{App.HttpContext.Connection.RemoteIpAddress.MapToIPv4()}", objs); | ||||
|         return result; | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -26,7 +26,7 @@ | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.ApiController.FileController"> | ||||
|             <summary> | ||||
|             后台登录控制器 | ||||
|             文件下载 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.ApiController.FileController.#ctor(ThingsGateway.Application.IRpcLogService,ThingsGateway.Application.IBackendLogService,ThingsGateway.Application.ICollectDeviceService,ThingsGateway.Application.IUploadDeviceService,ThingsGateway.Application.IVariableService)"> | ||||
|   | ||||
| @@ -34,13 +34,13 @@ public class TimerTick | ||||
|     /// <summary> | ||||
|     /// 上次操作时间 | ||||
|     /// </summary> | ||||
|     public DateTimeOffset LastTime { get; private set; } | ||||
|     public DateTime LastTime { get; private set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 是否触发时间刻度 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public bool IsTickHappen(DateTimeOffset currentTime) | ||||
|     public bool IsTickHappen(DateTime currentTime) | ||||
|     { | ||||
|         var dateTime = LastTime.AddMilliseconds(milliSeconds); | ||||
|         if (currentTime < dateTime) | ||||
|   | ||||
| @@ -28,7 +28,7 @@ public class BackendLog : PrimaryIdEntity | ||||
|     /// </summary> | ||||
|     [SugarColumn(ColumnName = "LogTime", ColumnDescription = "日志时间", IsNullable = false)] | ||||
|     [DataTable(Order = 1, IsShow = true, Sortable = true)] | ||||
|     public DateTimeOffset LogTime { get; set; } | ||||
|     public DateTime LogTime { get; set; } | ||||
|     /// <summary> | ||||
|     /// 日志级别 | ||||
|     /// </summary> | ||||
|   | ||||
| @@ -31,7 +31,7 @@ public class DeviceVariable : MemoryVariable | ||||
|     public virtual long DeviceId { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 写入表达式 | ||||
|     /// 单位 | ||||
|     /// </summary> | ||||
|     [SugarColumn(ColumnName = "Unit", ColumnDescription = "单位", Length = 200, IsNullable = true)] | ||||
|     [DataTable(Order = 3, IsShow = true, Sortable = true)] | ||||
| @@ -59,12 +59,7 @@ public class DeviceVariable : MemoryVariable | ||||
|     [DataTable(Order = 3, IsShow = true, Sortable = true)] | ||||
|     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> | ||||
|     /// 是否中间变量 | ||||
|   | ||||
| @@ -71,13 +71,13 @@ public class HistoryAlarm : PrimaryIdEntity | ||||
|     /// <inheritdoc  cref="DeviceVariableRunTime.AlarmTime"/> | ||||
|     [SugarColumn(ColumnName = "AlarmTime", ColumnDescription = "报警时间", IsNullable = false)] | ||||
|     [DataTable(Order = 8, IsShow = true, Sortable = true, CellClass = " table-text-truncate ")] | ||||
|     public DateTimeOffset AlarmTime { get; set; } | ||||
|     public DateTime AlarmTime { get; set; } | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc  cref="DeviceVariableRunTime.EventTime"/> | ||||
|     [SugarColumn(ColumnName = "EventTime", ColumnDescription = "事件时间", IsNullable = false)] | ||||
|     [DataTable(Order = 8, IsShow = true, Sortable = true, CellClass = " table-text-truncate ")] | ||||
|     public DateTimeOffset EventTime { get; set; } | ||||
|     public DateTime EventTime { get; set; } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -51,7 +51,12 @@ public class MemoryVariable : BaseEntity | ||||
|     [SugarColumn(ColumnName = "ReadExpressions", ColumnDescription = "读取表达式", Length = 200, IsNullable = true)] | ||||
|     [DataTable(Order = 7, IsShow = true, Sortable = true, CellClass = " table-text-truncate ")] | ||||
|     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> | ||||
|   | ||||
| @@ -24,7 +24,7 @@ public class RpcLog : PrimaryIdEntity | ||||
|     /// </summary> | ||||
|     [SugarColumn(ColumnName = "LogTime", ColumnDescription = "日志时间", IsNullable = false)] | ||||
|     [DataTable(Order = 1, IsShow = true, Sortable = true, CellClass = " table-text-truncate ")] | ||||
|     public DateTimeOffset LogTime { get; set; } | ||||
|     public DateTime LogTime { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 操作源 | ||||
|   | ||||
| @@ -44,7 +44,7 @@ public class BackendLogDatabaseLoggingWriter : IDatabaseLoggingWriter | ||||
|                 LogLevel = logMsg.LogLevel, | ||||
|                 LogMessage = logMsg.State.ToString(), | ||||
|                 LogSource = logMsg.LogName, | ||||
|                 LogTime = logMsg.LogDateTime.ToUniversalTime(), | ||||
|                 LogTime = logMsg.LogDateTime, | ||||
|                 Exception = logMsg.Exception?.ToString(), | ||||
|             }; | ||||
|             _logQueues.Enqueue(logRuntime); | ||||
|   | ||||
| @@ -55,7 +55,7 @@ public class CollectDeviceRunTime : CollectDevice | ||||
|     /// 设备活跃时间 | ||||
|     /// </summary> | ||||
|     [Description("活跃时间")] | ||||
|     public DateTimeOffset ActiveTime { get; private set; } = DateTimeOffset.MinValue; | ||||
|     public DateTime ActiveTime { get; private set; } = DateTime.MinValue; | ||||
|     /// <summary> | ||||
|     /// 设备状态 | ||||
|     /// </summary> | ||||
| @@ -121,7 +121,7 @@ public class CollectDeviceRunTime : CollectDevice | ||||
|     /// <param name="activeTime"></param> | ||||
|     /// <param name="errorCount"></param> | ||||
|     /// <param name="lastErrorMessage"></param> | ||||
|     public void SetDeviceStatus(DateTimeOffset? activeTime = null, int? errorCount = null, string lastErrorMessage = null) | ||||
|     public void SetDeviceStatus(DateTime? activeTime = null, int? errorCount = null, string lastErrorMessage = null) | ||||
|     { | ||||
|         if (activeTime != null) | ||||
|             ActiveTime = activeTime.Value; | ||||
|   | ||||
| @@ -23,7 +23,7 @@ public class DeviceData | ||||
|     /// <inheritdoc cref="CollectDeviceRunTime.DeviceVariableCount"/> | ||||
|     public int DeviceVariablesCount { get; set; } | ||||
|     /// <inheritdoc cref="CollectDeviceRunTime.ActiveTime"/> | ||||
|     public DateTimeOffset ActiveTime { get; set; } | ||||
|     public DateTime ActiveTime { get; set; } | ||||
|     /// <inheritdoc cref="CollectDeviceRunTime.DeviceStatus"/> | ||||
|     public int DeviceStatus { get; set; } | ||||
|     /// <inheritdoc cref="CollectDeviceRunTime.LastErrorMessage"/> | ||||
|   | ||||
| @@ -64,7 +64,7 @@ public class DeviceVariableMethodSource | ||||
|     /// </summary> | ||||
|     /// <param name="time"></param> | ||||
|     /// <returns></returns> | ||||
|     public bool CheckIfRequestAndUpdateTime(DateTimeOffset time) => exTimerTick.IsTickHappen(time); | ||||
|     public bool CheckIfRequestAndUpdateTime(DateTime time) => exTimerTick.IsTickHappen(time); | ||||
|  | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -82,7 +82,7 @@ public class DeviceVariableRunTime : DeviceVariable | ||||
|     /// </summary> | ||||
|     /// <param name="value"></param> | ||||
|     /// <param name="dateTime"></param> | ||||
|     public OperResult SetValue(object value, DateTimeOffset dateTime = default) | ||||
|     public OperResult SetValue(object value, DateTime dateTime = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -129,7 +129,7 @@ public class DeviceVariableRunTime : DeviceVariable | ||||
|  | ||||
|         void Set(object data) | ||||
|         { | ||||
|             DateTimeOffset time; | ||||
|             DateTime time; | ||||
|             if (dateTime == default) | ||||
|             { | ||||
|                 time = SysDateTimeExtensions.CurrentDateTime; | ||||
| @@ -139,22 +139,8 @@ public class DeviceVariableRunTime : DeviceVariable | ||||
|                 time = dateTime; | ||||
|             } | ||||
|             CollectTime = time; | ||||
|             if (data?.GetType().IsValueType == true) | ||||
|             { | ||||
|                 if (data != _value && LastSetValue != data || isOnlineChanged) | ||||
|                 { | ||||
|                     ChangeTime = time; | ||||
|                     if (IsOnline) | ||||
|                     { | ||||
|                         _value = data; | ||||
|                     } | ||||
|                     LastSetValue = data; | ||||
|                     VariableValueChange?.Invoke(this); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (data?.ToString() != _value?.ToString() && LastSetValue?.ToString() != data?.ToString() || isOnlineChanged) | ||||
|                 if ((data?.ToString() != _value?.ToString() && LastSetValue?.ToString() != data?.ToString()) || isOnlineChanged) | ||||
|                 { | ||||
|                     ChangeTime = time; | ||||
|                     if (IsOnline) | ||||
| @@ -175,13 +161,13 @@ public class DeviceVariableRunTime : DeviceVariable | ||||
|     /// </summary> | ||||
|     [Description("变化时间")] | ||||
|     [DataTable(Order = 2, IsShow = true, Sortable = true)] | ||||
|     public DateTimeOffset ChangeTime { get; private set; } | ||||
|     public DateTime ChangeTime { get; private set; } | ||||
|     /// <summary> | ||||
|     /// 采集时间 | ||||
|     /// </summary> | ||||
|     [Description("采集时间")] | ||||
|     [DataTable(Order = 2, IsShow = true, Sortable = true)] | ||||
|     public DateTimeOffset CollectTime { get; private set; } | ||||
|     public DateTime CollectTime { get; private set; } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
| @@ -255,11 +241,11 @@ public class DeviceVariableRunTime : DeviceVariable | ||||
|     /// <summary> | ||||
|     /// 报警时间 | ||||
|     /// </summary> | ||||
|     public DateTimeOffset AlarmTime { get; set; } | ||||
|     public DateTime AlarmTime { get; set; } | ||||
|     /// <summary> | ||||
|     /// 事件时间 | ||||
|     /// </summary> | ||||
|     public DateTimeOffset EventTime { get; set; } | ||||
|     public DateTime EventTime { get; set; } | ||||
|     /// <summary> | ||||
|     /// 报警类型 | ||||
|     /// </summary> | ||||
|   | ||||
| @@ -55,6 +55,6 @@ public class DeviceVariableSourceRead | ||||
|     /// </summary> | ||||
|     /// <param name="time"></param> | ||||
|     /// <returns></returns> | ||||
|     public bool CheckIfRequestAndUpdateTime(DateTimeOffset time) => exTimerTick.IsTickHappen(time); | ||||
|     public bool CheckIfRequestAndUpdateTime(DateTime time) => exTimerTick.IsTickHappen(time); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -35,7 +35,7 @@ public class UploadDeviceRunTime : UploadDevice | ||||
|     /// 设备活跃时间 | ||||
|     /// </summary> | ||||
|     [Description("活跃时间")] | ||||
|     public DateTimeOffset ActiveTime { get; private set; } = DateTimeOffset.MinValue; | ||||
|     public DateTime ActiveTime { get; private set; } = DateTime.MinValue; | ||||
|     /// <summary> | ||||
|     /// 设备状态 | ||||
|     /// </summary> | ||||
| @@ -113,7 +113,7 @@ public class UploadDeviceRunTime : UploadDevice | ||||
|     /// <param name="activeTime"></param> | ||||
|     /// <param name="errorCount"></param> | ||||
|     /// <param name="lastErrorMessage"></param> | ||||
|     public void SetDeviceStatus(DateTimeOffset? activeTime = null, int? errorCount = null, string lastErrorMessage = null) | ||||
|     public void SetDeviceStatus(DateTime? activeTime = null, int? errorCount = null, string lastErrorMessage = null) | ||||
|     { | ||||
|         if (activeTime != null) | ||||
|             ActiveTime = activeTime.Value; | ||||
|   | ||||
| @@ -20,6 +20,8 @@ public class VariableData | ||||
|     public long Id { get; set; } | ||||
|     /// <inheritdoc cref="MemoryVariable.Name"/> | ||||
|     public string Name { get; set; } | ||||
|     /// <inheritdoc cref="DeviceVariable.Unit"/> | ||||
|     public string Unit { get; set; } | ||||
|     /// <inheritdoc cref="MemoryVariable.Description"/> | ||||
|     public string Description { get; set; } | ||||
|     /// <inheritdoc cref="DeviceVariableRunTime.DeviceName"/> | ||||
| @@ -29,14 +31,14 @@ public class VariableData | ||||
|     /// <inheritdoc cref="DeviceVariableRunTime.Value"/> | ||||
|     public object Value { get; set; } | ||||
|     /// <inheritdoc cref="DeviceVariableRunTime.ChangeTime"/> | ||||
|     public DateTimeOffset ChangeTime { get; set; } | ||||
|     public DateTime ChangeTime { get; set; } | ||||
|     /// <inheritdoc cref="DeviceVariableRunTime.CollectTime"/> | ||||
|     public DateTimeOffset CollectTime { get; set; } | ||||
|     public DateTime CollectTime { get; set; } | ||||
|     /// <inheritdoc cref="DeviceVariableRunTime.IsOnline"/> | ||||
|     public bool IsOnline { get; set; } | ||||
|     /// <inheritdoc cref="MemoryVariable.ReadExpressions"/> | ||||
|     public string ReadExpressions { get; set; } | ||||
|     /// <inheritdoc cref="DeviceVariable.WriteExpressions"/> | ||||
|     /// <inheritdoc cref="MemoryVariable.WriteExpressions"/> | ||||
|     public string WriteExpressions { get; set; } | ||||
|     /// <inheritdoc cref="DeviceVariable.IntervalTime"/> | ||||
|     public int IntervalTime { get; set; } | ||||
|   | ||||
| @@ -17,8 +17,6 @@ using Newtonsoft.Json.Linq; | ||||
| using ThingsGateway.Foundation; | ||||
| using ThingsGateway.Foundation.Serial; | ||||
|  | ||||
| using TouchSocket.Core; | ||||
|  | ||||
| namespace ThingsGateway.Application; | ||||
| /// <summary> | ||||
| /// <para></para> | ||||
| @@ -38,6 +36,10 @@ public abstract class CollectBase : DriverBase | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public abstract bool IsSupportRequest { get; } | ||||
|     /// <summary> | ||||
|     /// 一般底层驱动,也有可能为null | ||||
|     /// </summary> | ||||
|     protected abstract IReadWriteDevice PLC { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 数据转换器 | ||||
| @@ -179,10 +181,22 @@ public abstract class CollectBase : DriverBase | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 写入变量值 | ||||
|     /// 批量写入变量值,需返回变量名称/结果 | ||||
|     /// </summary> | ||||
|     /// <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> | ||||
|     /// 初始化 | ||||
|   | ||||
| @@ -48,7 +48,7 @@ public abstract class DriverBase : DisposableObject | ||||
|         base.Dispose(disposing); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 调试UI Type,继承实现<see cref="DriverDebugUIBase"/>后,返回继承类的Type,如果不存在,返回null | ||||
|     /// 调试UI Type,如果不存在,返回null | ||||
|     /// </summary> | ||||
|     public abstract Type DriverDebugUIType { get; } | ||||
|  | ||||
|   | ||||
| @@ -48,92 +48,172 @@ public class RpcSingletonService : ISingleton | ||||
|     /// 反向RPC入口方法 | ||||
|     /// </summary> | ||||
|     /// <param name="sourceDes">触发该方法的源说明</param> | ||||
|     /// <param name="item">指定键为变量名称,值为附带方法参数或写入值</param> | ||||
|     /// <param name="items">指定键为变量名称,值为附带方法参数或写入值</param> | ||||
|     /// <param name="isBlazor">如果是true,不检查<see cref="MemoryVariable.RpcWriteEnable"/>字段</param> | ||||
|     /// <param name="token"><see cref="CancellationToken"/> 取消源</param> | ||||
|     /// <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 | ||||
|         await Task.Delay(10, token); | ||||
|         OperResult data = new(); | ||||
|         var tag = _globalDeviceData.AllVariables.FirstOrDefault(it => it.Name == item.Key); | ||||
|         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) | ||||
|         Dictionary<CollectDeviceCore, Dictionary<DeviceVariableRunTime, JToken>> WriteVariables = new(); | ||||
|         Dictionary<CollectDeviceCore, Dictionary<DeviceVariableRunTime, string>> WriteMethods = new(); | ||||
|         Dictionary<string, OperResult> results = new(); | ||||
|         foreach (var item in items) | ||||
|         { | ||||
|             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); | ||||
|             _logQueues.Enqueue( | ||||
|                 new RpcLog() | ||||
|             OperResult data = new(); | ||||
|             var tag = _globalDeviceData.AllVariables.FirstOrDefault(it => it.Name == item.Key); | ||||
|             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, | ||||
|                     IsSuccess = data.IsSuccess, | ||||
|                     OperateMethod = WriteVariable, | ||||
|                     OperateObject = tag.Name, | ||||
|                     OperateSource = sourceDes, | ||||
|                     ParamJson = item.Value, | ||||
|                     ResultJson = data.Message | ||||
|                     //写入变量 | ||||
|                     JToken tagValue; | ||||
|                     try | ||||
|                     { | ||||
|                         tagValue = JToken.Parse(item.Value); | ||||
|                     } | ||||
|                     catch (Exception) | ||||
|                     { | ||||
|                         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 | ||||
|             { | ||||
|                 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) | ||||
|             { | ||||
|                 data = new OperResult<string>(ex); | ||||
|             } | ||||
|             _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}"); | ||||
|                 _logger.LogWarning($"写入变量异常:{ex.Message + Environment.NewLine + ex.StackTrace}"); | ||||
|             } | ||||
|         } | ||||
|         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() | ||||
|     { | ||||
|   | ||||
| @@ -319,6 +319,39 @@ | ||||
|       "UpdateUserId": null, | ||||
|       "SortCode": 0, | ||||
|       "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 | ||||
|     } | ||||
|   ] | ||||
| } | ||||
| @@ -55,7 +55,7 @@ public interface IVariableService : ITransient | ||||
|     /// <summary> | ||||
|     /// 导出 | ||||
|     /// </summary> | ||||
|     Task<MemoryStream> ExportFileAsync(List<DeviceVariable> collectDeviceVariables = null); | ||||
|     Task<MemoryStream> ExportFileAsync(List<DeviceVariable> collectDeviceVariables = null, string deviceName = null); | ||||
|     /// <summary> | ||||
|     /// 导出 | ||||
|     /// </summary> | ||||
|   | ||||
| @@ -318,7 +318,7 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     [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); | ||||
|  | ||||
| @@ -343,7 +343,8 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService | ||||
|            ); | ||||
|        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) | ||||
|        { | ||||
| @@ -445,7 +446,7 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService | ||||
|                    try | ||||
|                    { | ||||
|                        var variable = ((ExpandoObject)item).ConvertToEntity<DeviceVariable>(true); | ||||
|  | ||||
|                        variable.IsMemoryVariable = true; | ||||
|                        //变量ID都需要手动补录 | ||||
|                        variables.Add(variable); | ||||
|                        if (dbVariableDicts.TryGetValue(variable.Name, out var dbvar1)) | ||||
|   | ||||
| @@ -37,7 +37,7 @@ | ||||
| 		<PackageReference Include="Hardware.Info" Version="11.1.1.1" /> | ||||
| 		<PackageReference Include="CS-Script" Version="4.8.1" /> | ||||
| 		<!--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> | ||||
| @@ -45,8 +45,4 @@ | ||||
| 	  <ProjectReference Include="..\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj" /> | ||||
| 	</ItemGroup> | ||||
| 	 | ||||
| 	<ItemGroup> | ||||
| 	  <Folder Include="Workers\Helper\" /> | ||||
| 	</ItemGroup> | ||||
| 	 | ||||
| </Project> | ||||
| @@ -184,7 +184,7 @@ | ||||
|             上次操作时间 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.TimerTick.IsTickHappen(System.DateTimeOffset)"> | ||||
|         <member name="M:ThingsGateway.Application.TimerTick.IsTickHappen(System.DateTime)"> | ||||
|             <summary> | ||||
|             是否触发时间刻度 | ||||
|             </summary> | ||||
| @@ -360,7 +360,7 @@ | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DeviceVariable.Unit"> | ||||
|             <summary> | ||||
|             写入表达式 | ||||
|             单位 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DeviceVariable.IntervalTime"> | ||||
| @@ -378,11 +378,6 @@ | ||||
|             变量地址,可能带有额外的信息,比如<see cref="T:ThingsGateway.Foundation.DataFormat"/> ,以;分割 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DeviceVariable.WriteExpressions"> | ||||
|             <summary> | ||||
|             写入表达式 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DeviceVariable.IsMemoryVariable"> | ||||
|             <summary> | ||||
|             是否中间变量 | ||||
| @@ -524,6 +519,11 @@ | ||||
|             读取表达式 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.MemoryVariable.WriteExpressions"> | ||||
|             <summary> | ||||
|             写入表达式 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.MemoryVariable.IsMemoryVariable"> | ||||
|             <summary> | ||||
|             是否中间变量 | ||||
| @@ -1457,7 +1457,7 @@ | ||||
|             距上次成功时的读取失败次数,超过3次设备更新为离线,等于0时设备更新为在线 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.CollectDeviceRunTime.SetDeviceStatus(System.Nullable{System.DateTimeOffset},System.Nullable{System.Int32},System.String)"> | ||||
|         <member name="M:ThingsGateway.Application.CollectDeviceRunTime.SetDeviceStatus(System.Nullable{System.DateTime},System.Nullable{System.Int32},System.String)"> | ||||
|             <summary> | ||||
|             传入设备的状态信息 | ||||
|             </summary> | ||||
| @@ -1559,7 +1559,7 @@ | ||||
|             地址参数,以;分割参数值 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DeviceVariableMethodSource.CheckIfRequestAndUpdateTime(System.DateTimeOffset)"> | ||||
|         <member name="M:ThingsGateway.Application.DeviceVariableMethodSource.CheckIfRequestAndUpdateTime(System.DateTime)"> | ||||
|             <summary> | ||||
|             检测是否达到读取间隔 | ||||
|             </summary> | ||||
| @@ -1601,7 +1601,7 @@ | ||||
|             最近一次值 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DeviceVariableRunTime.SetValue(System.Object,System.DateTimeOffset)"> | ||||
|         <member name="M:ThingsGateway.Application.DeviceVariableRunTime.SetValue(System.Object,System.DateTime)"> | ||||
|             <summary> | ||||
|             设置变量值与时间,设置为null时只更改质量戳状态 | ||||
|             </summary> | ||||
| @@ -1725,7 +1725,7 @@ | ||||
|             读取长度 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DeviceVariableSourceRead.CheckIfRequestAndUpdateTime(System.DateTimeOffset)"> | ||||
|         <member name="M:ThingsGateway.Application.DeviceVariableSourceRead.CheckIfRequestAndUpdateTime(System.DateTime)"> | ||||
|             <summary> | ||||
|             检测是否达到读取间隔 | ||||
|             </summary> | ||||
| @@ -1772,7 +1772,7 @@ | ||||
|             距上次成功时的读取失败次数,超过3次设备更新为离线,等于0时设备更新为在线 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.UploadDeviceRunTime.SetDeviceStatus(System.Nullable{System.DateTimeOffset},System.Nullable{System.Int32},System.String)"> | ||||
|         <member name="M:ThingsGateway.Application.UploadDeviceRunTime.SetDeviceStatus(System.Nullable{System.DateTime},System.Nullable{System.Int32},System.String)"> | ||||
|             <summary> | ||||
|             传入设备的状态信息 | ||||
|             </summary> | ||||
| @@ -1791,6 +1791,9 @@ | ||||
|         <member name="P:ThingsGateway.Application.VariableData.Name"> | ||||
|             <inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.Name"/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.VariableData.Unit"> | ||||
|             <inheritdoc cref="P:ThingsGateway.Application.DeviceVariable.Unit"/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.VariableData.Description"> | ||||
|             <inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.Description"/> | ||||
|         </member> | ||||
| @@ -1816,7 +1819,7 @@ | ||||
|             <inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.ReadExpressions"/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.VariableData.WriteExpressions"> | ||||
|             <inheritdoc cref="P:ThingsGateway.Application.DeviceVariable.WriteExpressions"/> | ||||
|             <inheritdoc cref="P:ThingsGateway.Application.MemoryVariable.WriteExpressions"/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.VariableData.IntervalTime"> | ||||
|             <inheritdoc cref="P:ThingsGateway.Application.DeviceVariable.IntervalTime"/> | ||||
| @@ -1852,6 +1855,11 @@ | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.CollectBase.PLC"> | ||||
|             <summary> | ||||
|             一般底层驱动,也有可能为null | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.CollectBase.ThingsGatewayBitConverter"> | ||||
|             <summary> | ||||
|             数据转换器 | ||||
| @@ -1903,9 +1911,9 @@ | ||||
|             采集驱动读取 | ||||
|             </summary> | ||||
|         </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> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
| @@ -1951,7 +1959,7 @@ | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DriverBase.DriverDebugUIType"> | ||||
|             <summary> | ||||
|             调试UI Type,继承实现<see cref="T:ThingsGateway.Application.DriverDebugUIBase"/>后,返回继承类的Type,如果不存在,返回null | ||||
|             调试UI Type,如果不存在,返回null | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DriverBase.DriverPlugin"> | ||||
| @@ -1995,78 +2003,6 @@ | ||||
|             底层日志输出 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Application.DriverDebugUIBase"> | ||||
|             <summary> | ||||
|             调试UI | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Application.DriverDebugUIBase.isDownExport"> | ||||
|             <summary> | ||||
|             导出提示 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Application.DriverDebugUIBase.Messages"> | ||||
|             <summary> | ||||
|             日志缓存 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DriverDebugUIBase.Plc"> | ||||
|             <summary> | ||||
|             默认读写设备 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DriverDebugUIBase.Address"> | ||||
|             <summary> | ||||
|             变量地址 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DriverDebugUIBase.DataTypeEnum"> | ||||
|             <summary> | ||||
|             数据类型 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DriverDebugUIBase.JS"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DriverDebugUIBase.WriteValue"> | ||||
|             <summary> | ||||
|             写入值 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.Dispose"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.ReadAsync"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.WriteAsync"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.DownDeviceExportAsync(ThingsGateway.Application.CollectDevice)"> | ||||
|             <summary> | ||||
|             导入设备 | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.DownDeviceExportAsync(System.Collections.Generic.List{ThingsGateway.Application.DeviceVariable})"> | ||||
|             <summary> | ||||
|             导入变量 | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.DownDeviceMessageExportAsync(System.Collections.Generic.IEnumerable{System.String})"> | ||||
|             <summary> | ||||
|             导出 | ||||
|             </summary> | ||||
|             <param name="values"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.LogOut(TouchSocket.Core.LogLevel,System.Object,System.String,System.Exception)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverDebugUIBase.OnInitialized"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Application.PluginSingletonService"> | ||||
|             <summary> | ||||
|             驱动插件服务   | ||||
| @@ -2311,12 +2247,12 @@ | ||||
|         <member name="M:ThingsGateway.Application.RpcSingletonService.#ctor(Microsoft.Extensions.Logging.ILogger{ThingsGateway.Application.RpcSingletonService})"> | ||||
|             <inheritdoc cref="T:ThingsGateway.Application.RpcSingletonService"/> | ||||
|         </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> | ||||
|             反向RPC入口方法 | ||||
|             </summary> | ||||
|             <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="token"><see cref="T:System.Threading.CancellationToken"/> 取消源</param> | ||||
|             <returns></returns> | ||||
| @@ -3244,7 +3180,7 @@ | ||||
|             编辑变量 | ||||
|             </summary> | ||||
|         </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> | ||||
| @@ -3339,7 +3275,7 @@ | ||||
|         <member name="M:ThingsGateway.Application.VariableService.MemoryVariableExportFileAsync(System.Collections.Generic.List{ThingsGateway.Application.MemoryVariable})"> | ||||
|             <inheritdoc/> | ||||
|         </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/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.VariableService.MemoryVariablePreviewAsync(Microsoft.AspNetCore.Components.Forms.IBrowserFile)"> | ||||
| @@ -3574,7 +3510,7 @@ | ||||
|             执行特殊方法 | ||||
|             </summary> | ||||
|         </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> | ||||
| @@ -3633,6 +3569,11 @@ | ||||
|             开始采集 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.CollectDeviceThread.BeforeStopThreadAsync"> | ||||
|             <summary> | ||||
|             停止采集前,提前取消Token | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.CollectDeviceThread.StopThreadAsync"> | ||||
|             <summary> | ||||
|             停止采集 | ||||
| @@ -4006,6 +3947,11 @@ | ||||
|             开始上传 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.UploadDeviceThread.BeforeStopThreadAsync"> | ||||
|             <summary> | ||||
|             停止采集前,提前取消Token | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.UploadDeviceThread.StopThreadAsync"> | ||||
|             <summary> | ||||
|             停止上传 | ||||
|   | ||||
| @@ -66,7 +66,7 @@ public class AlarmWorker : BackgroundService | ||||
|     /// </summary> | ||||
|     public OperResult StatuString { get; set; } = new OperResult("初始化"); | ||||
|     private ConcurrentQueue<DeviceVariableRunTime> DeviceVariables { get; set; } = new(); | ||||
|     private ConcurrentQueue<DeviceVariableRunTime> HisAlarmDeviceVariables { get; set; } = new(); | ||||
|     private ConcurrentQueue<HistoryAlarm> HisAlarmDeviceVariables { get; set; } = new(); | ||||
|     /// <summary> | ||||
|     /// 获取数据库链接 | ||||
|     /// </summary> | ||||
| @@ -74,7 +74,7 @@ public class AlarmWorker : BackgroundService | ||||
|     public async Task<OperResult<SqlSugarClient>> GetAlarmDbAsync() | ||||
|     { | ||||
|         var ConfigService = ServiceHelper.Services.GetService<IConfigService>(); | ||||
|         var alarmEnable = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_AlarmConfig_Base, ThingsGatewayConfigConst.Config_Alarm_Enable))?.ConfigValue?.ToBool(); | ||||
|         var alarmEnable = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_AlarmConfig_Base, ThingsGatewayConfigConst.Config_Alarm_Enable))?.ConfigValue?.ToBoolean(); | ||||
|         var alarmDbType = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_AlarmConfig_Base, ThingsGatewayConfigConst.Config_Alarm_DbType))?.ConfigValue; | ||||
|         var alarmConnstr = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_AlarmConfig_Base, ThingsGatewayConfigConst.Config_Alarm_ConnStr))?.ConfigValue; | ||||
|  | ||||
| @@ -132,14 +132,14 @@ public class AlarmWorker : BackgroundService | ||||
|         limit = string.Empty; | ||||
|         expressions = string.Empty; | ||||
|         text = string.Empty; | ||||
|         if (tag.BoolCloseAlarmEnable && tag.Value.ToBool() == false) | ||||
|         if (tag.BoolCloseAlarmEnable && tag.Value.ToBoolean() == false) | ||||
|         { | ||||
|             limit = false.ToString(); | ||||
|             expressions = tag.BoolCloseRestrainExpressions; | ||||
|             text = tag.BoolCloseAlarmText; | ||||
|             return AlarmEnum.Close; | ||||
|         } | ||||
|         if (tag.BoolOpenAlarmEnable && tag.Value.ToBool() == true) | ||||
|         if (tag.BoolOpenAlarmEnable && tag.Value.ToBoolean() == true) | ||||
|         { | ||||
|             limit = true.ToString(); | ||||
|             expressions = tag.BoolOpenRestrainExpressions; | ||||
| @@ -465,7 +465,7 @@ public class AlarmWorker : BackgroundService | ||||
|         OnAlarmChanged?.Invoke(item.Adapt<DeviceVariableRunTime>()); | ||||
|         if (!IsExited) | ||||
|         { | ||||
|             HisAlarmDeviceVariables.Enqueue(item); | ||||
|             HisAlarmDeviceVariables.Enqueue(item.Adapt<HistoryAlarm>()); | ||||
|         } | ||||
|  | ||||
|         if (eventEnum == EventEnum.Alarm) | ||||
| @@ -536,6 +536,7 @@ public class AlarmWorker : BackgroundService | ||||
|         HisAlarmTask = await Task.Factory.StartNew(async () => | ||||
|         { | ||||
|             _logger?.LogInformation($"历史报警线程开始"); | ||||
|             await Task.Yield();//返回线程控制,不再阻塞 | ||||
|             try | ||||
|             { | ||||
|                 await Task.Delay(500, stoppingToken.Token); | ||||
| @@ -561,8 +562,14 @@ public class AlarmWorker : BackgroundService | ||||
|                     } | ||||
|                     catch (Exception) | ||||
|                     { | ||||
|                         if (stoppingToken.Token.IsCancellationRequested) | ||||
|                         { | ||||
|                             IsExited = true; | ||||
|                             return; | ||||
|                         } | ||||
|                         try | ||||
|                         { | ||||
|                             _logger.LogWarning("连接历史报警表失败,尝试初始化表"); | ||||
|                             sqlSugarClient.CodeFirst.InitTables(typeof(HistoryAlarm)); | ||||
|                             isSuccess = true; | ||||
|                             StatuString = OperResult.CreateSuccessResult(); | ||||
| @@ -586,18 +593,20 @@ public class AlarmWorker : BackgroundService | ||||
|  | ||||
|                             //缓存值 | ||||
|                             var cacheData = await CacheDb.GetCacheData(); | ||||
|                             var data = cacheData.SelectMany(a => a.CacheStr.FromJson<List<HistoryAlarm>>()).ToList(); | ||||
|                             try | ||||
|                             if (cacheData.Count > 0) | ||||
|                             { | ||||
|                                 var count = await sqlSugarClient.Insertable(data).ExecuteCommandAsync(stoppingToken.Token); | ||||
|                                 await CacheDb.DeleteCacheData(cacheData.Select(a => a.Id).ToArray()); | ||||
|                                 var data = cacheData.SelectMany(a => a.CacheStr.FromJson<List<HistoryAlarm>>()).ToList(); | ||||
|                                 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) | ||||
|                                 break; | ||||
|  | ||||
| @@ -605,16 +614,15 @@ public class AlarmWorker : BackgroundService | ||||
|                             var list = HisAlarmDeviceVariables.ToListWithDequeue(); | ||||
|                             if (list.Count != 0) | ||||
|                             { | ||||
|                                 var hisalarm = list.Adapt<List<HistoryAlarm>>(); | ||||
|                                 ////Sql保存 | ||||
|                                 hisalarm.ForEach(it => | ||||
|                                 list.ForEach(it => | ||||
|                                 { | ||||
|                                     it.Id = YitIdHelper.NextId(); | ||||
|                                 }); | ||||
|                                 //插入 | ||||
|                                 try | ||||
|                                 { | ||||
|                                     await sqlSugarClient.Insertable(hisalarm).ExecuteCommandAsync(stoppingToken.Token); | ||||
|                                     await sqlSugarClient.Insertable(list).ExecuteCommandAsync(stoppingToken.Token); | ||||
|                                     isSuccess = true; | ||||
|                                 } | ||||
|                                 catch (Exception ex) | ||||
| @@ -622,7 +630,7 @@ public class AlarmWorker : BackgroundService | ||||
|                                     if (isSuccess) | ||||
|                                         _logger.LogWarning(ex, "写入历史报警失败"); | ||||
|  | ||||
|                                     var cacheDatas = hisalarm.ChunkTrivialBetter(500); | ||||
|                                     var cacheDatas = list.ChunkTrivialBetter(500); | ||||
|                                     foreach (var a in cacheDatas) | ||||
|                                     { | ||||
|                                         await CacheDb.AddCacheData("", a.ToJson(), 50000); | ||||
|   | ||||
| @@ -269,6 +269,7 @@ public class CollectDeviceCore | ||||
|         { | ||||
|             isInitSuccess = false; | ||||
|             GlobalDeviceData.CollectDevices.RemoveWhere(it => it.Id == Device.Id); | ||||
|             easyLock.SafeDispose(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -329,11 +330,6 @@ public class CollectDeviceCore | ||||
|                 return ThreadRunReturn.Continue; | ||||
|             } | ||||
|  | ||||
|             if (DeviceVariableSourceReads.Count == 0 && Device.DeviceVariableRunTimes.Where(a => string.IsNullOrEmpty(a.OtherMethod)).Any()) | ||||
|             { | ||||
|                 //无采集变量 | ||||
|                 return ThreadRunReturn.Continue; | ||||
|             } | ||||
|             if (token.IsCancellationRequested) | ||||
|                 return ThreadRunReturn.Break; | ||||
|  | ||||
| @@ -437,11 +433,11 @@ public class CollectDeviceCore | ||||
|                 if (_driver.IsConnected()) | ||||
|                 { | ||||
|                     //更新设备活动时间 | ||||
|                     Device.SetDeviceStatus(SysDateTimeExtensions.CurrentDateTime, 0); | ||||
|                     Device.SetDeviceStatus(SysDateTimeExtensions.CurrentDateTime, errorCount: 0); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Device.SetDeviceStatus(SysDateTimeExtensions.CurrentDateTime, 999); | ||||
|                     Device.SetDeviceStatus(errorCount: 999); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| @@ -533,7 +529,7 @@ public class CollectDeviceCore | ||||
|  | ||||
|                         if (!string.IsNullOrEmpty(methodResult.MethodStr)) | ||||
|                         { | ||||
|                             string[] strs = methodResult.MethodStr?.Trim()?.Split(';'); | ||||
|                             string[] strs = methodResult.MethodStr?.Trim()?.TrimEnd(';').Split(';'); | ||||
|                             try | ||||
|                             { | ||||
|                                 int index = 0; | ||||
| @@ -545,6 +541,8 @@ public class CollectDeviceCore | ||||
|                                     } | ||||
|                                     else | ||||
|                                     { | ||||
|                                         if (strs.Length <= index) | ||||
|                                             continue; | ||||
|                                         //得到对于的方法参数值 | ||||
|                                         methodResult.MethodObj[i] = methodResult.Converter.ConvertFrom(strs[index], ps[i].ParameterType); | ||||
|                                         index++; | ||||
| @@ -600,8 +598,8 @@ public class CollectDeviceCore | ||||
|  | ||||
|                     if (!string.IsNullOrEmpty(deviceVariableMethodSource.MethodStr) || !string.IsNullOrEmpty(value)) | ||||
|                     { | ||||
|                         string[] strs1 = deviceVariableMethodSource.MethodStr?.Trim()?.Split(';'); | ||||
|                         string[] strs2 = value?.Trim()?.Split(';'); | ||||
|                         string[] strs1 = deviceVariableMethodSource.MethodStr?.Trim()?.TrimEnd(';').Split(';'); | ||||
|                         string[] strs2 = value?.Trim()?.TrimEnd(';').Split(';'); | ||||
|                         //通过分号分割,并且合并参数 | ||||
|                         var strs = strs1?.SpliceArray(strs2); | ||||
|                         int index = 0; | ||||
| @@ -667,18 +665,25 @@ public class CollectDeviceCore | ||||
|                     if (method.HasReturn && result != null && result.IsSuccess) | ||||
|                     { | ||||
|                         var content = deviceVariableMethodSource.Converter.ConvertTo(result.Content?.ToString()?.Replace($"\0", "")); | ||||
|                         var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(content); | ||||
|                         if (!operResult.IsSuccess) | ||||
|                         if (isRead) | ||||
|                         { | ||||
|                             _logger?.LogWarning(operResult.Message, ToString()); | ||||
|                             var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(content); | ||||
|                             if (!operResult.IsSuccess) | ||||
|                             { | ||||
|                                 _logger?.LogWarning(operResult.Message, ToString()); | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(null); | ||||
|                         if (!operResult.IsSuccess) | ||||
|                         if (isRead) | ||||
|                         { | ||||
|                             _logger?.LogWarning(operResult.Message, ToString()); | ||||
|                             var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(null); | ||||
|                             if (!operResult.IsSuccess) | ||||
|                             { | ||||
|                                 _logger?.LogWarning(operResult.Message, ToString()); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     return result; | ||||
| @@ -707,46 +712,46 @@ public class CollectDeviceCore | ||||
|     /// 执行变量写入 | ||||
|     /// </summary> | ||||
|     /// <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 | ||||
|         { | ||||
|             await easyLock.WaitAsync(); | ||||
|             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.WriteValueAsync(deviceVariable, value, token); | ||||
|                 return result; | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return (new OperResult(ex)); | ||||
|             var result = await _driver.WriteValuesAsync(writeInfoLists. | ||||
|                 Where(a => !results.Any(b => b.Key == a.Key.Name)). | ||||
|                ToDictionary(item => item.Key, item => item.Value), | ||||
|                 token); | ||||
|  | ||||
|             return result; | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
| @@ -754,6 +759,8 @@ public class CollectDeviceCore | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 执行轮询特殊方法,并设置变量值 | ||||
|     /// </summary> | ||||
|   | ||||
| @@ -62,6 +62,7 @@ public class CollectDeviceThread : IAsyncDisposable | ||||
|     public async ValueTask DisposeAsync() | ||||
|     { | ||||
|         await StopThreadAsync(); | ||||
|         easyLock.SafeDispose(); | ||||
|         CollectDeviceCores.Clear(); | ||||
|     } | ||||
|  | ||||
| @@ -85,6 +86,29 @@ public class CollectDeviceThread : IAsyncDisposable | ||||
|             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> | ||||
|     /// 停止采集 | ||||
| @@ -173,7 +197,10 @@ public class CollectDeviceThread : IAsyncDisposable | ||||
|                 foreach (var device in CollectDeviceCores) | ||||
|                 { | ||||
|                     try | ||||
|                     {//初始化成功才能执行 | ||||
|                     { | ||||
|                         if (stoppingToken.IsCancellationRequested) | ||||
|                             break; | ||||
|                         //初始化成功才能执行 | ||||
|                         if (device.IsInitSuccess) | ||||
|                         { | ||||
|                             //如果是共享通道类型,需要每次转换时切换适配器 | ||||
|   | ||||
| @@ -328,6 +328,18 @@ public class CollectDeviceWorker : BackgroundService | ||||
|     /// </summary> | ||||
|     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) => | ||||
|          { | ||||
|              try | ||||
| @@ -496,7 +508,7 @@ public class CollectDeviceWorker : BackgroundService | ||||
|                     { | ||||
|                         //超过30分钟,或者(初始化失败并超过10分钟)会重启 | ||||
|                         if ( | ||||
|         (devcore.Device.ActiveTime != DateTimeOffset.MinValue && | ||||
|         (devcore.Device.ActiveTime != DateTime.MinValue && | ||||
|         devcore.Device.ActiveTime.AddMinutes(30) <= SysDateTimeExtensions.CurrentDateTime) | ||||
|         || (devcore.IsInitSuccess == false && devcore.Device.ActiveTime.AddMinutes(10) <= SysDateTimeExtensions.CurrentDateTime) | ||||
|         ) | ||||
|   | ||||
| @@ -60,7 +60,7 @@ public class HistoryValueWorker : BackgroundService | ||||
|     public async Task<OperResult<SqlSugarClient>> GetHisDbAsync() | ||||
|     { | ||||
|         var ConfigService = ServiceHelper.Services.GetService<IConfigService>(); | ||||
|         var hisEnable = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_HisConfig_Base, ThingsGatewayConfigConst.Config_His_Enable))?.ConfigValue?.ToBool(); | ||||
|         var hisEnable = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_HisConfig_Base, ThingsGatewayConfigConst.Config_His_Enable))?.ConfigValue?.ToBoolean(); | ||||
|         var hisDbType = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_HisConfig_Base, ThingsGatewayConfigConst.Config_His_DbType))?.ConfigValue; | ||||
|         var hisConnstr = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_HisConfig_Base, ThingsGatewayConfigConst.Config_His_ConnStr))?.ConfigValue; | ||||
|  | ||||
| @@ -167,7 +167,7 @@ public class HistoryValueWorker : BackgroundService | ||||
|         HistoryValueTask = await Task.Factory.StartNew(async () => | ||||
|         { | ||||
|             _logger?.LogInformation($"历史数据线程开始"); | ||||
|             IsExited = false; | ||||
|             await Task.Yield();//返回线程控制,不再阻塞 | ||||
|             try | ||||
|             { | ||||
|                 var result = await GetHisDbAsync(); | ||||
| @@ -191,8 +191,14 @@ public class HistoryValueWorker : BackgroundService | ||||
|                     } | ||||
|                     catch (Exception) | ||||
|                     { | ||||
|                         if (stoppingToken.Token.IsCancellationRequested) | ||||
|                         { | ||||
|                             IsExited = true; | ||||
|                             return; | ||||
|                         } | ||||
|                         try | ||||
|                         { | ||||
|                             _logger.LogWarning("连接历史数据表失败,尝试初始化表"); | ||||
|                             sqlSugarClient.CodeFirst.InitTables(typeof(HistoryValue)); | ||||
|                             LastIsSuccess = true; | ||||
|                             StatuString = OperResult.CreateSuccessResult(); | ||||
| @@ -204,6 +210,7 @@ public class HistoryValueWorker : BackgroundService | ||||
|                             _logger.LogWarning(ex, "连接历史数据库失败"); | ||||
|                         } | ||||
|                     } | ||||
|                     IsExited = false; | ||||
|  | ||||
|                     while (!stoppingToken.Token.IsCancellationRequested) | ||||
|                     { | ||||
| @@ -299,7 +306,6 @@ public class HistoryValueWorker : BackgroundService | ||||
|                             LastIsSuccess = false; | ||||
|                         } | ||||
|                     } | ||||
|                     IsExited = true; | ||||
|  | ||||
|                 } | ||||
|             } | ||||
| @@ -317,9 +323,11 @@ public class HistoryValueWorker : BackgroundService | ||||
|                 IsExited = true; | ||||
|                 _logger?.LogError(ex, $"历史数据循环异常"); | ||||
|             } | ||||
|             IsExited = true; | ||||
|         } | ||||
|  , TaskCreationOptions.LongRunning); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 重启 | ||||
|     /// </summary> | ||||
| @@ -451,14 +459,14 @@ public class HistoryValueMapper : IRegister | ||||
|     { | ||||
|         config.ForType<DeviceVariableRunTime, HistoryValue>() | ||||
|             .Map(dest => dest.Value, (src) => ValueReturn(src)) | ||||
|             .Map(dest => dest.CollectTime, (src) => src.CollectTime.UtcDateTime); | ||||
|             .Map(dest => dest.CollectTime, (src) => src.CollectTime.ToUniversalTime());//注意sqlsugar插入时无时区,直接utc时间 | ||||
|     } | ||||
|  | ||||
|     private static object ValueReturn(DeviceVariableRunTime src) | ||||
|     { | ||||
|         if (src.Value?.ToString()?.IsBoolValue() == true) | ||||
|         { | ||||
|             if (src.Value.ToBool()) | ||||
|             if (src.Value.ToBoolean()) | ||||
|             { | ||||
|                 return 1; | ||||
|             } | ||||
|   | ||||
| @@ -225,7 +225,13 @@ public class UploadDeviceCore | ||||
|         { | ||||
|             _logger?.LogError(ex, $"{Device.Name} 释放失败"); | ||||
|         } | ||||
|         isInitSuccess = false; | ||||
|         finally | ||||
|         { | ||||
|             isInitSuccess = false; | ||||
|             easyLock.SafeDispose(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -51,6 +51,7 @@ public class UploadDeviceThread : IAsyncDisposable | ||||
|     public async ValueTask DisposeAsync() | ||||
|     { | ||||
|         await StopThreadAsync(); | ||||
|         easyLock.SafeDispose(); | ||||
|         UploadDeviceCores.Clear(); | ||||
|     } | ||||
|  | ||||
| @@ -74,6 +75,29 @@ public class UploadDeviceThread : IAsyncDisposable | ||||
|             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> | ||||
|     /// 停止上传 | ||||
| @@ -152,7 +176,10 @@ public class UploadDeviceThread : IAsyncDisposable | ||||
|                 foreach (var device in UploadDeviceCores) | ||||
|                 { | ||||
|                     try | ||||
|                     {//初始化成功才能执行 | ||||
|                     { | ||||
|                         if (stoppingToken.IsCancellationRequested) | ||||
|                             break; | ||||
|                         //初始化成功才能执行 | ||||
|                         if (device.IsInitSuccess) | ||||
|                         { | ||||
|  | ||||
|   | ||||
| @@ -239,6 +239,17 @@ public class UploadDeviceWorker : BackgroundService | ||||
|     /// </summary> | ||||
|     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) => | ||||
|         { | ||||
|             try | ||||
| @@ -373,7 +384,7 @@ public class UploadDeviceWorker : BackgroundService | ||||
|                     { | ||||
|                         //超过30分钟,或者(初始化失败并超过10分钟)会重启 | ||||
|                         if ( | ||||
|         (devcore.Device.ActiveTime != DateTimeOffset.MinValue | ||||
|         (devcore.Device.ActiveTime != DateTime.MinValue | ||||
|         && devcore.Device.ActiveTime.AddMinutes(30) <= SysDateTimeExtensions.CurrentDateTime) | ||||
|         || (devcore.IsInitSuccess == false && devcore.Device.ActiveTime.AddMinutes(10) <= SysDateTimeExtensions.CurrentDateTime) | ||||
|         ) | ||||
|   | ||||
| @@ -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 class="mt-6"> | ||||
|                             <MButton Color="primary" Disabled=@ImportPreviews.Any(it=>it.Value.HasError) OnClick="()=>Step=3">下一步</MButton> | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -21,7 +21,7 @@ using ThingsGateway.Application; | ||||
|  | ||||
| namespace ThingsGateway.Blazor; | ||||
| /// <summary> | ||||
| /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>excel | ||||
| /// 导入excel | ||||
| /// </summary> | ||||
| public partial class ImportExcel | ||||
| { | ||||
| @@ -33,21 +33,21 @@ public partial class ImportExcel | ||||
|  | ||||
|     bool isSaveImport; | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 导入 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public Func<Dictionary<string, ImportPreviewOutputBase>, Task> Import { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD>ʾ | ||||
|     /// 是否显示 | ||||
|     /// </summary> | ||||
|     public bool IsShowImport { get; set; } | ||||
|     /// <summary> | ||||
|     /// Ԥ<EFBFBD><EFBFBD> | ||||
|     /// 预览 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public Func<IBrowserFile, Task<Dictionary<string, ImportPreviewOutputBase>>> Preview { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 当前步数 | ||||
|     /// </summary> | ||||
|     public int Step { get; set; } | ||||
|  | ||||
| @@ -75,7 +75,7 @@ public partial class ImportExcel | ||||
|             StateHasChanged(); | ||||
|             await Import.Invoke(ImportPreviews); | ||||
|             _importFile = null; | ||||
|             await PopupService.EnqueueSnackbarAsync("<EFBFBD>ɹ<EFBFBD>", AlertTypes.Success); | ||||
|             await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|   | ||||
| @@ -21,9 +21,9 @@ public class HisPageInput : VariablePageInput | ||||
|     /// <summary> | ||||
|     /// 开始时间 | ||||
|     /// </summary> | ||||
|     public DateTime? StartTime { get; set; } = DateTime.Now.AddDays(-1); | ||||
|     public DateTime? StartTime { get; set; } = DateTime.UtcNow.AddDays(-1); | ||||
|     /// <summary> | ||||
|     /// 结束时间 | ||||
|     /// </summary> | ||||
|     public DateTime? EndTime { get; set; } = DateTime.Now.AddDays(1); | ||||
|     public DateTime? EndTime { get; set; } = DateTime.UtcNow.AddDays(1); | ||||
| } | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -54,7 +54,7 @@ public partial class DefalutDebugDriverPage : DriverDebugUIBase | ||||
|     /// </summary> | ||||
|     public UdpSessionPage UdpSessionPage; | ||||
|     /// <summary> | ||||
|     /// ѡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>1-TCPCLIENT<EFBFBD><EFBFBD>2-<2D><><EFBFBD>ڣ<EFBFBD>3-UDP<EFBFBD><EFBFBD>4-TCPServer | ||||
|     /// 选择,1-TCPCLIENT,2-串口,3-UDP,4-TCPServer | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public ChannelEnum Channel { get; set; } | ||||
| @@ -65,12 +65,12 @@ public partial class DefalutDebugDriverPage : DriverDebugUIBase | ||||
|     public override ThingsGateway.Foundation.IReadWriteDevice Plc { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// ģ<EFBFBD><EFBFBD> | ||||
|     /// 模板 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public RenderFragment ChildContent { get; set; } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD> | ||||
|     /// 自定义模板 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public RenderFragment OtherContent { get; set; } | ||||
| @@ -100,7 +100,7 @@ public partial class DefalutDebugDriverPage : DriverDebugUIBase | ||||
|                 TcpServerPage.LogAction = LogOut; | ||||
|             if (UdpSessionPage != null) | ||||
|                 UdpSessionPage.LogAction = LogOut; | ||||
|             //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|             //载入配置 | ||||
|             StateHasChanged(); | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -14,6 +14,11 @@ using Microsoft.AspNetCore.Components; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using Microsoft.JSInterop; | ||||
| 
 | ||||
| using System.IO; | ||||
| using System.Threading; | ||||
| 
 | ||||
| using ThingsGateway.Admin.Blazor.Core; | ||||
| using ThingsGateway.Admin.Core; | ||||
| using ThingsGateway.Application.Extensions; | ||||
| using ThingsGateway.Foundation; | ||||
| 
 | ||||
| @@ -65,6 +70,8 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
| 
 | ||||
|     [Inject] | ||||
|     private IVariableService VariableService { get; set; } | ||||
|     [Inject] | ||||
|     private InitTimezone InitTimezone { get; set; } | ||||
| 
 | ||||
|     /// <inheritdoc/> | ||||
|     public virtual void Dispose() | ||||
| @@ -80,18 +87,18 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|             var data = await Plc.ReadAsync(Address, DataTypeEnum.GetSystemType()); | ||||
|             if (data.IsSuccess) | ||||
|             { | ||||
|                 Messages.Add((LogLevel.Information, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat() + " - 对应类型值:" + data.Content)); | ||||
|                 Messages.Add((LogLevel.Information, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - 对应类型值:" + data.Content)); | ||||
| 
 | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Messages.Add((LogLevel.Error, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat() + " - " + data.Message)); | ||||
|                 Messages.Add((LogLevel.Error, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + data.Message)); | ||||
| 
 | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             Messages.Add((LogLevel.Warning, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat() + "错误:" + ex.Message)); | ||||
|             Messages.Add((LogLevel.Warning, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + "错误:" + ex.Message)); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| @@ -104,23 +111,23 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|             var data = await Plc.WriteAsync(Address, DataTypeEnum.GetSystemType(), WriteValue); | ||||
|             if (data.IsSuccess) | ||||
|             { | ||||
|                 Messages.Add((LogLevel.Information, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat() + " - " + data.Message)); | ||||
|                 Messages.Add((LogLevel.Information, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + data.Message)); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Messages.Add((LogLevel.Warning, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat() + " - " + data.Message)); | ||||
|                 Messages.Add((LogLevel.Warning, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + data.Message)); | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             Messages.Add((LogLevel.Error, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat() + " - " + "写入前失败:" + ex.Message)); | ||||
|             Messages.Add((LogLevel.Error, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + "写入前失败:" + ex.Message)); | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 导入设备 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public async Task DownDeviceExportAsync(CollectDevice data) | ||||
|     public async Task DeviceImportAsync(CollectDevice data) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -138,7 +145,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|     /// 导入变量 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public async Task DownDeviceExportAsync(List<DeviceVariable> data) | ||||
|     public async Task DeviceVariableImportAsync(List<DeviceVariable> data) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
| @@ -152,6 +159,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// 导出 | ||||
|     /// </summary> | ||||
| @@ -180,10 +188,55 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|             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/> | ||||
|     public void LogOut(TouchSocket.Core.LogLevel logLevel, object source, string message, Exception exception) | ||||
|     { | ||||
|         Messages.Add(((LogLevel)logLevel, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat() + " - " + message + (exception != null ? exception.Message : ""))); | ||||
|         Messages.Add(((LogLevel)logLevel, SysDateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + " - " + message + (exception != null ? exception.Message : ""))); | ||||
|         if (Messages.Count > 2500) | ||||
|         { | ||||
|             Messages.Clear(); | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -20,7 +20,7 @@ namespace ThingsGateway.Blazor; | ||||
| public partial class SerialClientPage | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 日志输出 | ||||
|     /// </summary> | ||||
|     public Action<LogLevel, object, string, Exception> LogAction; | ||||
|  | ||||
| @@ -36,7 +36,7 @@ public partial class SerialClientPage | ||||
|         SerialClient.SafeDispose(); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 获取对象 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public SerialClient GetSerialClient() | ||||
| @@ -47,7 +47,7 @@ public partial class SerialClientPage | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetSerialProperty(serialProperty); | ||||
|         //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|         //载入配置 | ||||
|         SerialClient.Setup(config); | ||||
|         return SerialClient; | ||||
|     } | ||||
| @@ -78,8 +78,7 @@ public partial class SerialClientPage | ||||
|     /// <inheritdoc/> | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         config?.Dispose(); | ||||
|         config = new TouchSocketConfig(); | ||||
|         config ??= new TouchSocketConfig(); | ||||
|         var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -23,7 +23,7 @@ namespace ThingsGateway.Blazor; | ||||
| public partial class TcpClientPage | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 日志输出 | ||||
|     /// </summary> | ||||
|     public Action<LogLevel, object, string, Exception> LogAction; | ||||
|  | ||||
| @@ -33,7 +33,7 @@ public partial class TcpClientPage | ||||
|     /// </summary> | ||||
|     private string IP = "127.0.0.1"; | ||||
|     /// <summary> | ||||
|     /// <EFBFBD>˿<EFBFBD> | ||||
|     /// 端口 | ||||
|     /// </summary> | ||||
|     [Parameter] | ||||
|     public int Port { get; set; } = 502; | ||||
| @@ -73,18 +73,17 @@ public partial class TcpClientPage | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 获取对象 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public TcpClientEx GetTcpClient() | ||||
|     { | ||||
|         config?.Dispose(); | ||||
|         config = new TouchSocketConfig(); | ||||
|         config ??= new TouchSocketConfig(); | ||||
|         var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetRemoteIPHost(new IPHost(IP + ":" + Port)).SetBufferLength(300); | ||||
|         //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|         //载入配置 | ||||
|         TcpClientEx.Setup(config); | ||||
|         return TcpClientEx; | ||||
|     } | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -19,7 +19,7 @@ namespace ThingsGateway.Blazor; | ||||
| public partial class TcpServerPage | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 日志输出 | ||||
|     /// </summary> | ||||
|     public Action<LogLevel, object, string, Exception> LogAction; | ||||
|  | ||||
| @@ -62,19 +62,18 @@ public partial class TcpServerPage | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 获取对象 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public TcpService GetTcpServer() | ||||
|     { | ||||
|         config?.Dispose(); | ||||
|         config = new TouchSocketConfig(); | ||||
|         config ??= new TouchSocketConfig(); | ||||
|         var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetListenIPHosts(new IPHost[] { new IPHost(ip + ":" + port) }); | ||||
|         config.SetBufferLength(300); | ||||
|         //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|         //载入配置 | ||||
|         TcpServer.Setup(config); | ||||
|         return TcpServer; | ||||
|     } | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -19,7 +19,7 @@ namespace ThingsGateway.Blazor; | ||||
| public partial class UdpSessionPage : IDisposable | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 日志输出 | ||||
|     /// </summary> | ||||
|     public Action<LogLevel, object, string, Exception> LogAction; | ||||
|  | ||||
| @@ -62,19 +62,18 @@ public partial class UdpSessionPage : IDisposable | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     /// 获取对象 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public UdpSession GetUdpSession() | ||||
|     { | ||||
|         config?.Dispose(); | ||||
|         config = new TouchSocketConfig(); | ||||
|         config ??= new TouchSocketConfig(); | ||||
|         var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetRemoteIPHost(new IPHost(ip + ":" + port)).SetBufferLength(300); | ||||
|         config.SetBindIPHost(new IPHost(0)); | ||||
|         //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|         //载入配置 | ||||
|         UdpSession.Setup(config); | ||||
|         return UdpSession; | ||||
|     } | ||||
|   | ||||
| @@ -62,6 +62,7 @@ | ||||
|                             <MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_collectDeviceGroupSearchName" | ||||
|                                             Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.DeviceGroup)) /> | ||||
|                             </MCardTitle> | ||||
|  | ||||
|                             <MTreeview Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight + 240}px; overflow-y:auto)") Dense TItem="string" TKey="string" ActiveChanged=@(async a=> | ||||
|                                    { | ||||
|                                    if(_collectDeviceGroup!=a.FirstOrDefault()) | ||||
| @@ -95,7 +96,7 @@ | ||||
|                                                     <MLabel Class=@((item.Device?.DeviceStatus==DeviceStatusEnum.OnLine?"green--text":"red--text")+$" text-h6")> | ||||
|                                                         <div class="mt-1  d-flex align-center justify-space-between" title=@item.Device?.Name> | ||||
|                                                             <span>@item.Device?.Name</span> | ||||
|                                                             <span style="white-space: nowrap !important;overflow: hidden !important; text-overflow: ellipsis !important;" class="text-caption">@(item.Device?.ActiveTime.ToDefaultDateTimeFormat() + "     " + typeof(DeviceStatusEnum).GetDescription(item.Device?.DeviceStatus.ToString()))</span> | ||||
|                                                             <span style="white-space: nowrap !important;overflow: hidden !important; text-overflow: ellipsis !important;" class="text-caption">@(item.Device?.ActiveTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + "     " + typeof(DeviceStatusEnum).GetDescription(item.Device?.DeviceStatus.ToString()))</span> | ||||
|                                                         </div> | ||||
|                                                     </MLabel> | ||||
|                                                 </MListItemTitle> | ||||
| @@ -127,7 +128,7 @@ | ||||
|                                         <MLabel Class=@((item.Device?.DeviceStatus==DeviceStatusEnum.OnLine?"green--text":"red--text")+$" text-h6")> | ||||
|                                             <div class="mt-1  d-flex align-center justify-space-between"> | ||||
|                                                 <span class="mx-3">@item.Device?.Name</span> | ||||
|                                                 <span style="white-space: nowrap !important;overflow: hidden !important; text-overflow: ellipsis !important;" class="text-caption mx-3">@(item.Device?.ActiveTime.ToDefaultDateTimeFormat() + "     " + typeof(DeviceStatusEnum).GetDescription(item.Device?.DeviceStatus.ToString()))</span> | ||||
|                                                 <span style="white-space: nowrap !important;overflow: hidden !important; text-overflow: ellipsis !important;" class="text-caption mx-3">@(item.Device?.ActiveTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + "     " + typeof(DeviceStatusEnum).GetDescription(item.Device?.DeviceStatus.ToString()))</span> | ||||
|                                             </div> | ||||
|                                         </MLabel> | ||||
|  | ||||
| @@ -180,7 +181,7 @@ | ||||
|                                     <MRow Class="ml-2 mr-2 d-flex" NoGutters> | ||||
|                                     <MCol Md=6 Cols="12" Class="px-4 mt-1  d-flex align-center justify-space-between"> | ||||
|                                         <span class="text-subtitle-2 grey--text">@item.Device?.Description(a=>a.ActiveTime)</span> | ||||
|                                         <span class="text-caption">@item.Device?.ActiveTime.ToDefaultDateTimeFormat()</span> | ||||
|                                         <span class="text-caption">@item.Device?.ActiveTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)</span> | ||||
|                                     </MCol> | ||||
|                                     <MCol Md=6 Cols="12" Class="px-4 mt-1  d-flex align-center justify-space-between"> | ||||
|                                         <span class="text-subtitle-2 grey--text">@item.Device?.Description(a=>a.SourceVariableCount)</span> | ||||
| @@ -346,7 +347,7 @@ | ||||
|                                                     <MLabel Class=@((item.Device?.DeviceStatus==DeviceStatusEnum.OnLine?"green--text":"red--text")+$" text-h6")> | ||||
|                                                         <div class="mt-1  d-flex align-center justify-space-between" title=@item.Device?.Name> | ||||
|                                                             <span>@item.Device?.Name</span> | ||||
|                                                             <span style="white-space: nowrap !important;overflow: hidden !important; text-overflow: ellipsis !important;" class="text-caption">@(item.Device?.ActiveTime.ToDefaultDateTimeFormat() + "     " + typeof(DeviceStatusEnum).GetDescription(item.Device?.DeviceStatus.ToString()))</span> | ||||
|                                                             <span style="white-space: nowrap !important;overflow: hidden !important; text-overflow: ellipsis !important;" class="text-caption">@(item.Device?.ActiveTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + "     " + typeof(DeviceStatusEnum).GetDescription(item.Device?.DeviceStatus.ToString()))</span> | ||||
|                                                         </div> | ||||
|                                                     </MLabel> | ||||
|                                                 </MListItemTitle> | ||||
| @@ -378,7 +379,7 @@ | ||||
|                                         <MLabel Class=@((item.Device?.DeviceStatus==DeviceStatusEnum.OnLine?"green--text":"red--text")+$" text-h6")> | ||||
|                                             <div class="mt-1  d-flex align-center justify-space-between"> | ||||
|                                                 <span class="mx-3">@item.Device?.Name</span> | ||||
|                                                 <span style="white-space: nowrap !important;overflow: hidden !important; text-overflow: ellipsis !important;" class="text-caption mx-3">@(item.Device?.ActiveTime.ToDefaultDateTimeFormat() + "     " + typeof(DeviceStatusEnum).GetDescription(item.Device?.DeviceStatus.ToString()))</span> | ||||
|                                                 <span style="white-space: nowrap !important;overflow: hidden !important; text-overflow: ellipsis !important;" class="text-caption mx-3">@(item.Device?.ActiveTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset) + "     " + typeof(DeviceStatusEnum).GetDescription(item.Device?.DeviceStatus.ToString()))</span> | ||||
|                                             </div> | ||||
|                                         </MLabel> | ||||
|  | ||||
| @@ -432,7 +433,7 @@ | ||||
|                                     <MRow Class="ml-2 mr-2 d-flex" NoGutters> | ||||
|                                     <MCol Md=6 Cols="12" Class="px-4 mt-1  d-flex align-center justify-space-between"> | ||||
|                                         <span class="text-subtitle-2 grey--text">@item.Device?.Description(a=>a.ActiveTime)</span> | ||||
|                                         <span class="text-caption">@item.Device?.ActiveTime.ToDefaultDateTimeFormat()</span> | ||||
|                                         <span class="text-caption">@item.Device?.ActiveTime.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)</span> | ||||
|                                     </MCol> | ||||
|                                     <MCol Md=6 Cols="12" Class="px-4 mt-1  d-flex align-center justify-space-between"> | ||||
|                                         <span class="text-subtitle-2 grey--text">@item.Device?.Description(a=>a.UploadVariableCount)</span> | ||||
|   | ||||
| @@ -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> | ||||
| //  Դ<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 | ||||
| //  GithubԴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֿ⣺https://github.com/kimdiego2098/ThingsGateway | ||||
| //  ʹ<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQȺ<EFBFBD><EFBFBD>605534569 | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| @@ -32,7 +32,7 @@ using ThingsGateway.Application; | ||||
| namespace ThingsGateway.Blazor; | ||||
|  | ||||
| /// <summary> | ||||
| /// <EFBFBD>豸״̬ҳ<EFBFBD><EFBFBD> | ||||
| /// 设备状态页面 | ||||
| /// </summary> | ||||
| public partial class DeviceStatusPage : IDisposable | ||||
| { | ||||
| @@ -110,7 +110,7 @@ public partial class DeviceStatusPage : IDisposable | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var confirm = await PopupService.OpenConfirmDialogAsync("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"); | ||||
|             var confirm = await PopupService.OpenConfirmDialogAsync("重启", "确定重启?"); | ||||
|             if (confirm) | ||||
|             { | ||||
|                 isAllRestart = true; | ||||
| @@ -142,8 +142,8 @@ public partial class DeviceStatusPage : IDisposable | ||||
|     } | ||||
|     async Task ConfigAsync(long devId, bool? isStart) | ||||
|     { | ||||
|         var str = isStart == true ? "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" : "<EFBFBD><EFBFBD>ͣ"; | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync(str, $"ȷ<EFBFBD><EFBFBD>{str}?"); | ||||
|         var str = isStart == true ? "启动" : "暂停"; | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync(str, $"确定{str}?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             CollectDeviceHostService.ConfigDeviceThread(devId, isStart == true); | ||||
| @@ -167,19 +167,19 @@ public partial class DeviceStatusPage : IDisposable | ||||
|             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", $"<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD>{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.txt", streamRef); | ||||
|             await Helper.InvokeVoidAsync("downloadFileFromStream", $"报文导出{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.txt", streamRef); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             isDownExport = false; | ||||
|         } | ||||
|     } | ||||
|     //ȥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> | ||||
|     //去除单个采集重启 | ||||
|     //async Task RestartAsync(long devId) | ||||
|     //{ | ||||
|     //    try | ||||
|     //    { | ||||
|     //        var confirm = await PopupService.OpenConfirmDialogAsync("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "ȷ<><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"); | ||||
|     //        var confirm = await PopupService.OpenConfirmDialogAsync("重启", "确定重启?"); | ||||
|     //        if (confirm) | ||||
|     //        { | ||||
|     //            isRestart = true; | ||||
| @@ -199,7 +199,6 @@ public partial class DeviceStatusPage : IDisposable | ||||
|     //        await MainLayout.StateHasChangedAsync(); | ||||
|     //    } | ||||
|     //} | ||||
|  | ||||
|     private async Task RunTimerAsync() | ||||
|     { | ||||
|         while (await _periodicTimer.WaitForNextTickAsync()) | ||||
| @@ -232,8 +231,8 @@ public partial class DeviceStatusPage : IDisposable | ||||
|  | ||||
|     async Task UpConfigAsync(long devId, bool? isStart) | ||||
|     { | ||||
|         var str = isStart == true ? "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>" : "<EFBFBD><EFBFBD>ͣ"; | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync(str, $"ȷ<EFBFBD><EFBFBD>{str}?"); | ||||
|         var str = isStart == true ? "启动" : "暂停"; | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync(str, $"确定{str}?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             UploadDeviceHostService.ConfigDeviceThread(devId, isStart == true); | ||||
| @@ -254,7 +253,7 @@ public partial class DeviceStatusPage : IDisposable | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var confirm = await PopupService.OpenConfirmDialogAsync("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>", "ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?"); | ||||
|             var confirm = await PopupService.OpenConfirmDialogAsync("重启", "确定重启?"); | ||||
|             if (confirm) | ||||
|             { | ||||
|                 isRestart = true; | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user