build: 10.7.42
feat:更改后台服务多语言处理方式
This commit is contained in:
@@ -110,7 +110,7 @@ public class HardwareJob : IJob, IHardwareJob
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!error)
|
||||
_logger.LogWarning(ex, _localizer["GetHardwareInfoFail"]);
|
||||
_logger.LogWarning(ex, "Get Hardwareinfo Fail");
|
||||
error = true;
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ public class HardwareJob : IJob, IHardwareJob
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!error)
|
||||
_logger.LogWarning(ex, _localizer["GetHardwareInfoFail"]);
|
||||
_logger.LogWarning(ex, "Get Hardwareinfo Fail");
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
@@ -1,459 +1,402 @@
|
||||
{
|
||||
"ThingsGateway.Admin.Application.AppConfig": {
|
||||
"LoginPolicy": "LoginPolicy",
|
||||
"PagePolicy": "PagePolicy",
|
||||
"PasswordPolicy": "PasswordPolicy",
|
||||
"WebsitePolicy": "WebsitePolicy"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.AuthController": {
|
||||
"AuthController": "Login API",
|
||||
"LoginAsync": "Login",
|
||||
"LogoutAsync": "Logout"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.AuthService": {
|
||||
"AuthErrorMax": "Account password error, will be locked for {1} minutes after exceeding {0} times, error count {2}",
|
||||
"MustDesc": "Password needs to be encrypted with DESC before passing",
|
||||
"OrgDisable": "The affiliated company/department has been deactivated, please contact the administrator",
|
||||
"PasswordError": "Too many password errors, please try again in {0} minutes",
|
||||
"SingleLoginWarn": "Your account is logged in elsewhere",
|
||||
"TenantNull": "The tenant does not exist",
|
||||
"UserDisable": "Account {0} has been disabled",
|
||||
"UserNoModule": "This account has not been assigned a module. Please contact the administrator",
|
||||
"UserNull": "User {0} does not exist"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.BaseDataEntity": {
|
||||
"CreateOrgId": "CreateOrgId"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.BaseEntity": {
|
||||
"SortCode": "SortCode",
|
||||
"CreateTime": "CreateTime",
|
||||
"CreateUser": "CreateUser",
|
||||
"SortCode": "SortCode",
|
||||
"UpdateTime": "UpdateTime",
|
||||
"UpdateUser": "UpdateUser"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.BlazorAuthenticationHandler": {
|
||||
"UserExpire": "User expired, please login again"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.SysUser": {
|
||||
"Disable": "Disable",
|
||||
"Enable": "Enable",
|
||||
"GrantRole": "GrantRole",
|
||||
"ExitVerificat": "You have been forcibly logged out",
|
||||
"PasswordEdited": "Password changed, logged out",
|
||||
|
||||
"Avatar": "Avatar",
|
||||
"Account": "Account",
|
||||
"Account.Required": "Account.Required",
|
||||
"Password": "Password",
|
||||
"Status": "Status",
|
||||
"Phone": "Phone",
|
||||
"Email": "Email",
|
||||
"LastLoginIp": "LastLoginIp",
|
||||
"LastLoginDevice": "LastLoginDevice",
|
||||
"LastLoginTime": "LastLoginTime",
|
||||
"LastLoginAddress": "LastLoginAddress",
|
||||
"LatestLoginIp": "LatestLoginIp",
|
||||
"LatestLoginTime": "LatestLoginTime",
|
||||
"LatestLoginDevice": "LatestLoginDevice",
|
||||
"LatestLoginAddress": "LatestLoginAddress",
|
||||
"OrgNames": "OrgNames",
|
||||
"PositionName": "PositionName",
|
||||
"OrgId": "Org",
|
||||
"PositionId": "Position",
|
||||
"DirectorId": "Director",
|
||||
|
||||
"CheckSelf": "Prohibit {0} yourself",
|
||||
"CanotDeleteAdminUser": "Cannot delete built-in super admin user",
|
||||
"CanotEditAdminUser": "Cannot edit super admin user",
|
||||
"CanotGrantAdmin": "Cannot assign admins roles",
|
||||
"EmailDup": "Duplicate email {0} exists",
|
||||
"AccountDup": "Duplicate account {0} exists",
|
||||
"CanotDeleteSelf": "Cannot delete yourself",
|
||||
"EmailError": "Email format error {0}",
|
||||
"PhoneError": "Phone number format error {0}",
|
||||
"NoOrg": "The organization does not exist",
|
||||
"DirectorSelf": "Cannot set oneself as the supervisor",
|
||||
|
||||
"DemoCanotUpdatePassword": "DEMO environment does not allow password modification",
|
||||
"OldPasswordError": "Incorrect old password",
|
||||
"ConfirmPasswordDiff": "Passwords entered twice are inconsistent",
|
||||
"PasswordLengthLess": "Password length cannot be less than {0}",
|
||||
"PasswordMustNum ": "Password must contain numbers",
|
||||
"PasswordMustLow": "Password must contain lowercase letters",
|
||||
"PasswordMustUpp": "Password must contain uppercase letters",
|
||||
"PasswordMustSpecial": "Password must contain special characters"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.SysRole": {
|
||||
"Code": "Code",
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} is required",
|
||||
"Category": "Category",
|
||||
"OrgId": "Org",
|
||||
"Global": "Global",
|
||||
"Status": "Status",
|
||||
"CanotDeleteAdmin": "Cannot delete built-in super admin role",
|
||||
"CanotEditAdmin": "Cannot edit super admin role",
|
||||
"CanotGrantAdmin": "Cannot assign admins roles",
|
||||
"NameDup": "Duplicate role name {0}",
|
||||
|
||||
"OrgNotNull": "Organization cannot be null",
|
||||
"SameOrgNameDup": "Duplicate role name exists: {0}",
|
||||
"CannotRoleScopeAll": "Organization role cannot select global data scope",
|
||||
"CodeDup": "Duplicate code exists: {0}"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.RoleCategoryEnum": {
|
||||
"Global": "Global",
|
||||
"Org": "Org"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.DataScopeEnum": {
|
||||
"SCOPE_SELF": "Self",
|
||||
"SCOPE_ALL": "All",
|
||||
"SCOPE_ORG": "OnlyOrg",
|
||||
"SCOPE_ORG_CHILD": "OrgChild",
|
||||
"SCOPE_ORG_DEFINE": "Define"
|
||||
"SCOPE_ORG_DEFINE": "Define",
|
||||
"SCOPE_SELF": "Self"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.DefaultDataScope": {
|
||||
"ScopeCategory": "DataScope",
|
||||
"ScopeDefineOrgIdList": "DefineOrgList"
|
||||
},
|
||||
|
||||
|
||||
"ThingsGateway.Admin.Application.SysResource": {
|
||||
"Title": "Title",
|
||||
"Module": "Module",
|
||||
"Title.Required": "{0} is required",
|
||||
"Href.Required": "{0} is required",
|
||||
"Icon": "Icon",
|
||||
"Href": "Path",
|
||||
"Code": "Code",
|
||||
"Category": "Category",
|
||||
"Target": "Target",
|
||||
"NavLinkMatch": "NavLinkMatch",
|
||||
"ParentId": "Parent",
|
||||
"ResourceDup": "Duplicate name {0} exists",
|
||||
"ResourceParentChoiceSelf": "Parent cannot choose itself",
|
||||
"ResourceParentNull": "Parent does not exist {0}",
|
||||
"NotFoundResource": "System exception, menu not found",
|
||||
"ModuleIdDiff": "Module is inconsistent with parent menu",
|
||||
"CanotDeleteSystemResource": "Cannot delete system resource {0}",
|
||||
"ResourceMenuHrefNotNull": "Menu href cannot null"
|
||||
"ThingsGateway.Admin.Application.DictTypeEnum": {
|
||||
"Define": "Business",
|
||||
"System": "System"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.SysOrgCopyInput": {
|
||||
"TargetId": "Target",
|
||||
"ContainsChild": "ContainsChild",
|
||||
"ContainsPosition": "ContainsPosition"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.SysPosition": {
|
||||
"Category.Required": "{0} is a required field",
|
||||
"Name.Required": "{0} is a required field",
|
||||
"Code.Required": "{0} is a required field",
|
||||
"OrgId.MinValue": "{0} is a required field",
|
||||
"Category": "Category",
|
||||
"Name": "Name",
|
||||
"Code": "Code",
|
||||
"Status": "Status",
|
||||
"OrgId": "Organization",
|
||||
"Remark": "Remarks",
|
||||
"Dup": "Duplicate position exists with Category {0} and Name {1}",
|
||||
"CodeDup": "Duplicate code {0} exists",
|
||||
"NameDup": "Duplicate name {0} exists",
|
||||
"CanotContainsSelf": "Cannot contain itself",
|
||||
"TargetNameDup": "Target node has duplicate name {0}",
|
||||
"ParentChoiceSelf": "Parent cannot be itself",
|
||||
"ParentNull": "Parent does not exist {0}",
|
||||
"DeleteUserFirst": "Please remove the users under the position first"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.SysOrg": {
|
||||
"Category.Required": "{0} is a required field",
|
||||
"Name.Required": "{0} is a required field",
|
||||
"Code.Required": "{0} is a required field",
|
||||
"Category": "Category",
|
||||
"Name": "Name",
|
||||
"Code": "Code",
|
||||
"Status": "Status",
|
||||
"ParentId": "ParentOrg",
|
||||
"Names": "Names",
|
||||
"Remark": "Remarks",
|
||||
"DirectorId": "Director",
|
||||
"Dup": "Duplicate organization exists with Category {0} and Name {1}",
|
||||
"CodeDup": "Duplicate code {0} exists",
|
||||
"NameDup": "Duplicate name {0} exists",
|
||||
"CanotContainsSelf": "Cannot contain itself",
|
||||
"TargetNameDup": "Target node has duplicate name {0}",
|
||||
"ParentChoiceSelf": "Parent cannot be itself",
|
||||
"ParentNull": "Parent does not exist {0}",
|
||||
"DeleteUserFirst": "Please remove the users under the organization first",
|
||||
"DeleteRoleFirst": "Please remove the roles under the organization first",
|
||||
"DeletePositionFirst": "Please remove the positions under the organization first",
|
||||
"RootOrg": "Unable to create top-level organization"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.OrgEnum": {
|
||||
"COMPANY": "Company",
|
||||
"DEPT": "Dept"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.PositionCategoryEnum": {
|
||||
"HIGH": "High",
|
||||
"MIDDLE": "Middle",
|
||||
"LOW": "Low"
|
||||
},
|
||||
//controller
|
||||
"ThingsGateway.Admin.Application.AuthController": {
|
||||
//auth
|
||||
"AuthController": "Login API",
|
||||
"LoginAsync": "Login",
|
||||
"LogoutAsync": "Logout"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.TestController": {
|
||||
//auth
|
||||
"TestController": "Test API",
|
||||
"Test": "Test"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.OpenApiAuthController": {
|
||||
//auth
|
||||
"OpenApiAuthController": "Login API",
|
||||
"LoginAsync": "Login",
|
||||
"LogoutAsync": "Logout"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.FileService": {
|
||||
"FileNullError": "File cannot be empty",
|
||||
"FileLengthError": "File size cannot exceed {0} M",
|
||||
"FileNullError": "File cannot be empty",
|
||||
"FileTypeError": "Not supported format {0}"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.UnifyResultProvider": {
|
||||
"TokenOver": "Login has expired, please login again",
|
||||
"NoPermission": "Access denied, no permission"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.AuthService": {
|
||||
|
||||
"TenantNull": "The tenant does not exist",
|
||||
"OrgDisable": "The affiliated company/department has been deactivated, please contact the administrator",
|
||||
|
||||
"SingleLoginWarn": "Your account is logged in elsewhere",
|
||||
"UserNull": "User {0} does not exist",
|
||||
"MustDesc": "Password needs to be encrypted with DESC before passing",
|
||||
"PasswordError": "Too many password errors, please try again in {0} minutes",
|
||||
"UserDisable": "Account {0} has been disabled",
|
||||
"UserNoModule": "This account has not been assigned a module. Please contact the administrator",
|
||||
"AuthErrorMax": "Account password error, will be locked for {1} minutes after exceeding {0} times, error count {2}"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.HardwareInfo": {
|
||||
"Environment": "HostEnvironment",
|
||||
"FrameworkDescription": ".NETFramework",
|
||||
"OsArchitecture": "System Architecture",
|
||||
"UUID": "UUID",
|
||||
"UpdateTime": "UpdateTime"
|
||||
"UpdateTime": "UpdateTime",
|
||||
"UUID": "UUID"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.HistoryHardwareInfo": {
|
||||
"DriveUsage": "Disk Usage",
|
||||
"MemoryUsage": "Memory",
|
||||
"CpuUsage": "CPU Usage",
|
||||
"Temperature": "Temperature",
|
||||
"Battery": "Battery"
|
||||
},
|
||||
|
||||
|
||||
//oper
|
||||
"ThingsGateway.Admin.Application.OperDescAttribute": {
|
||||
//dict
|
||||
"SaveDict": "Modify dictionary",
|
||||
"DeleteDict": "Delete dictionary",
|
||||
"EditLoginPolicy": "Modify login policy",
|
||||
"EditPasswordPolicy": "Modify password policy",
|
||||
"EditPagePolicy": "Modify page policy",
|
||||
"EditWebsitePolicy": "Modify website settings",
|
||||
//operlog
|
||||
"DeleteOperLog": "Delete operation log",
|
||||
"ExportOperLog": "Export operation log",
|
||||
|
||||
//resource
|
||||
"SaveResource": "Modify resource",
|
||||
"DeleteResource": "Delete resource",
|
||||
|
||||
//role
|
||||
"SaveRole": "Modify role",
|
||||
"DeleteRole": "Delete role",
|
||||
"RoleGrantResource": "Role grant resource",
|
||||
"RoleGrantUser": "Role grant user",
|
||||
"RoleGrantApiPermission": "Role grant OpenApi",
|
||||
"GrantApi": "GrantApi",
|
||||
"GrantUser": "GrantUser",
|
||||
"GrantRole": "GrantRole",
|
||||
"GrantResource": "GrantResource",
|
||||
//user
|
||||
"SaveUser": "Modify user",
|
||||
"DeleteuSER": "Delete user",
|
||||
"ResetPassword": "Reset pw",
|
||||
"UserGrantRole": "User grant role",
|
||||
"UserGrantResource": "User grant resource",
|
||||
"UserGrantApiPermission": "User grant OpenApi",
|
||||
|
||||
//usercenter
|
||||
"UpdateUserInfo": "Update personal information",
|
||||
"WorkbenchInfo": "Update personal workbench",
|
||||
"UpdatePassword": "Update personal password",
|
||||
|
||||
//session
|
||||
"ExitVerificat": "Force token off",
|
||||
"ExitSession": "Force session off",
|
||||
|
||||
|
||||
"CopyOrg": "Copy Organization",
|
||||
"DeleteOrg": "Delete Organization",
|
||||
"SaveOrg": "Save Organization",
|
||||
|
||||
"DeletePosition": "Delete Position",
|
||||
"SavePosition": "Save Position",
|
||||
|
||||
"NoPermission": "No Permission",
|
||||
|
||||
|
||||
"CopyResource": "CopyResource",
|
||||
"ChangeParentResource": "ChangeParentResource"
|
||||
},
|
||||
|
||||
|
||||
//service
|
||||
|
||||
"ThingsGateway.Admin.Application.HardwareJob": {
|
||||
"GetHardwareInfoFail": "Get Hardwareinfo Fail"
|
||||
},
|
||||
|
||||
//dto
|
||||
"ThingsGateway.Admin.Application.UserSelectorOutput": {
|
||||
"ThingsGateway.Admin.Application.HistoryHardwareInfo": {
|
||||
"Battery": "Battery",
|
||||
"CpuUsage": "CPU Usage",
|
||||
"DriveUsage": "Disk Usage",
|
||||
"MemoryUsage": "Memory",
|
||||
"Temperature": "Temperature"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LogCateGoryEnum": {
|
||||
"Exception": "Exception",
|
||||
"Login": "Login",
|
||||
"Logout": "Logout",
|
||||
"Operate": "Operation"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LogEnum": {
|
||||
"FAIL": "Fail",
|
||||
"SUCCESS": "Success"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LoginInput": {
|
||||
"Account": "Account",
|
||||
"OrgId": "Org"
|
||||
"Account.Required": "{0} is required",
|
||||
"Password": "Password",
|
||||
"Password.Required": "{0} is required"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LoginPolicy": {
|
||||
"ErrorCount": "Login error count lock threshold",
|
||||
"ErrorCount.MinValue": "{0} value is too small",
|
||||
"ErrorLockTime": "Login error lock duration (min)",
|
||||
"ErrorLockTime.MinValue": "{0} value is too small",
|
||||
"ErrorResetTime": "Login error count expiration duration (min)",
|
||||
"ErrorResetTime.MinValue": "{0} value is too small",
|
||||
"SingleOpen": "Single user login switch",
|
||||
"VerificatExpireTime": "Login expiration time (min)",
|
||||
"VerificatExpireTime.MinValue": "{0} value is too small"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LogoutInput": {
|
||||
"VerificatId.Required": "{0} is required"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.OpenApiAuthController": {
|
||||
"LoginAsync": "Login",
|
||||
"LogoutAsync": "Logout",
|
||||
"OpenApiAuthController": "Login API"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.OperateLogPageInput": {
|
||||
"Account": "Account",
|
||||
"Category": "Category",
|
||||
"SearchDate": "SearchDate"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.OperDescAttribute": {
|
||||
"ChangeParentResource": "ChangeParentResource",
|
||||
"CopyOrg": "Copy Organization",
|
||||
"CopyResource": "CopyResource",
|
||||
"DeleteDict": "Delete dictionary",
|
||||
"DeleteOperLog": "Delete operation log",
|
||||
"DeleteOrg": "Delete Organization",
|
||||
"DeletePosition": "Delete Position",
|
||||
"DeleteResource": "Delete resource",
|
||||
"DeleteRole": "Delete role",
|
||||
"DeleteuSER": "Delete user",
|
||||
"EditLoginPolicy": "Modify login policy",
|
||||
"EditPagePolicy": "Modify page policy",
|
||||
"EditPasswordPolicy": "Modify password policy",
|
||||
"EditWebsitePolicy": "Modify website settings",
|
||||
"ExitSession": "Force session off",
|
||||
"ExitVerificat": "Force token off",
|
||||
"ExportOperLog": "Export operation log",
|
||||
"GrantApi": "GrantApi",
|
||||
"GrantResource": "GrantResource",
|
||||
"GrantRole": "GrantRole",
|
||||
"GrantUser": "GrantUser",
|
||||
"NoPermission": "No Permission",
|
||||
"ResetPassword": "Reset pw",
|
||||
"RoleGrantApiPermission": "Role grant OpenApi",
|
||||
"RoleGrantResource": "Role grant resource",
|
||||
"RoleGrantUser": "Role grant user",
|
||||
"SaveDict": "Modify dictionary",
|
||||
"SaveOrg": "Save Organization",
|
||||
"SavePosition": "Save Position",
|
||||
"SaveResource": "Modify resource",
|
||||
"SaveRole": "Modify role",
|
||||
"SaveUser": "Modify user",
|
||||
"UpdatePassword": "Update personal password",
|
||||
"UpdateUserInfo": "Update personal information",
|
||||
"UserGrantApiPermission": "User grant OpenApi",
|
||||
"UserGrantResource": "User grant resource",
|
||||
"UserGrantRole": "User grant role",
|
||||
"WorkbenchInfo": "Update personal workbench"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.OrgEnum": {
|
||||
"COMPANY": "Company",
|
||||
"DEPT": "Dept"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.PagePolicy": {
|
||||
"Razor": "Default homepage",
|
||||
"Shortcuts": "Default shortcuts"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.PasswordPolicy": {
|
||||
"DefaultPassword": "Default user password",
|
||||
"DefaultPassword.Required": "{0} is required",
|
||||
"PasswordContainChar": "Contain special characters",
|
||||
"PasswordContainLower": "Contain lowercase letters",
|
||||
"PasswordContainNum": "Contain numbers",
|
||||
"PasswordContainUpper": "Contain uppercase letters",
|
||||
"PasswordMinLen": "Minimum password length",
|
||||
"PasswordMinLen.MinValue": "{0} value is too small"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.PositionCategoryEnum": {
|
||||
"HIGH": "High",
|
||||
"LOW": "Low",
|
||||
"MIDDLE": "Middle"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.ResourceCategoryEnum": {
|
||||
"Button": "Button",
|
||||
"Menu": "Menu",
|
||||
"Module": "Module"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.ResourceTableSearchModel": {
|
||||
"Module": "Module",
|
||||
"Href": "Path",
|
||||
"Module": "Module",
|
||||
"Title": "Title"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.WorkbenchInfo": {
|
||||
"Razor": "Homepage",
|
||||
"Shortcuts": "Shortcuts"
|
||||
"ThingsGateway.Admin.Application.RoleCategoryEnum": {
|
||||
"Global": "Global",
|
||||
"Org": "Org"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.UpdatePasswordInput": {
|
||||
"Password": "Password",
|
||||
"NewPassword": "New password",
|
||||
"ConfirmPassword": "Confirm password",
|
||||
"Password.Required": "{0} is required",
|
||||
"NewPassword.Required": "{0} is required",
|
||||
"ConfirmPassword.Required": "{0} is required"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.VerificatInfo": {
|
||||
"Expire": "Expire(min)",
|
||||
"Online": "Online",
|
||||
"VerificatTimeout": "VerificatTimeout",
|
||||
"Device": "Device",
|
||||
"LoginIp": "LoginIp",
|
||||
"LoginTime": "LoginTime"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.SessionOutput": {
|
||||
"Account": "Account",
|
||||
"Online": "Online status",
|
||||
"LatestLoginIp": "Latest login IP",
|
||||
"LatestLoginTime": "Latest login time",
|
||||
"Online": "Online status",
|
||||
"VerificatCount": "Token count"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.SysDict": {
|
||||
"Category.Required": "{0} is required",
|
||||
"Name.Required": "{0} is required",
|
||||
"Code.Required": "{0} is required",
|
||||
"Category": "Category",
|
||||
"Name": "Name",
|
||||
"Category.Required": "{0} is required",
|
||||
"Code": "Code",
|
||||
"Remark": "Remark",
|
||||
"Code.Required": "{0} is required",
|
||||
"DemoCanotUpdateWebsitePolicy": "DEMO environment does not allow modifying website settings",
|
||||
"DictDup": "Duplicate configuration exists, category {0}, name {1}"
|
||||
"DictDup": "Duplicate configuration exists, category {0}, name {1}",
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} is required",
|
||||
"Remark": "Remark"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.SysOperateLog": {
|
||||
"Category": "Category",
|
||||
"ClassName": "ClassName",
|
||||
"ExeMessage": "ExeMessage",
|
||||
"MethodName": "MethodName",
|
||||
"ParamJson": "ParamJson",
|
||||
"ReqMethod": "RequestMethod",
|
||||
"ReqUrl": "RequestUrl",
|
||||
"ResultJson": "ResultJson",
|
||||
"Category": "Category",
|
||||
"ExeStatus": "ExeStatus",
|
||||
"MethodName": "MethodName",
|
||||
"Name": "Name",
|
||||
"OpAccount": "OpAccount",
|
||||
"OpBrowser": "OpBrowser",
|
||||
"OpIp": "OpIp",
|
||||
"OpOs": "OpOs",
|
||||
"OpTime": "OpTime",
|
||||
"ParamJson": "ParamJson",
|
||||
"ReqMethod": "RequestMethod",
|
||||
"ReqUrl": "RequestUrl",
|
||||
"ResultJson": "ResultJson",
|
||||
"VerificatId": "VerificatId"
|
||||
|
||||
},
|
||||
"ThingsGateway.Admin.Application.OperateLogPageInput": {
|
||||
"SearchDate": "SearchDate",
|
||||
"Account": "Account",
|
||||
"Category": "Category"
|
||||
"ThingsGateway.Admin.Application.SysOrg": {
|
||||
"CanotContainsSelf": "Cannot contain itself",
|
||||
"Category": "Category",
|
||||
"Category.Required": "{0} is a required field",
|
||||
"Code": "Code",
|
||||
"Code.Required": "{0} is a required field",
|
||||
"CodeDup": "Duplicate code {0} exists",
|
||||
"DeletePositionFirst": "Please remove the positions under the organization first",
|
||||
"DeleteRoleFirst": "Please remove the roles under the organization first",
|
||||
"DeleteUserFirst": "Please remove the users under the organization first",
|
||||
"DirectorId": "Director",
|
||||
"Dup": "Duplicate organization exists with Category {0} and Name {1}",
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} is a required field",
|
||||
"NameDup": "Duplicate name {0} exists",
|
||||
"Names": "Names",
|
||||
"ParentChoiceSelf": "Parent cannot be itself",
|
||||
"ParentId": "ParentOrg",
|
||||
"ParentNull": "Parent does not exist {0}",
|
||||
"Remark": "Remarks",
|
||||
"RootOrg": "Unable to create top-level organization",
|
||||
"Status": "Status",
|
||||
"TargetNameDup": "Target node has duplicate name {0}"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LoginInput": {
|
||||
"Account": "Account",
|
||||
"Password": "Password",
|
||||
"Account.Required": "{0} is required",
|
||||
"Password.Required": "{0} is required"
|
||||
"ThingsGateway.Admin.Application.SysOrgCopyInput": {
|
||||
"ContainsChild": "ContainsChild",
|
||||
"ContainsPosition": "ContainsPosition",
|
||||
"TargetId": "Target"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LogoutInput": {
|
||||
"VerificatId.Required": "{0} is required"
|
||||
"ThingsGateway.Admin.Application.SysPosition": {
|
||||
"CanotContainsSelf": "Cannot contain itself",
|
||||
"Category": "Category",
|
||||
"Category.Required": "{0} is a required field",
|
||||
"Code": "Code",
|
||||
"Code.Required": "{0} is a required field",
|
||||
"CodeDup": "Duplicate code {0} exists",
|
||||
"DeleteUserFirst": "Please remove the users under the position first",
|
||||
"Dup": "Duplicate position exists with Category {0} and Name {1}",
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} is a required field",
|
||||
"NameDup": "Duplicate name {0} exists",
|
||||
"OrgId": "Organization",
|
||||
"OrgId.MinValue": "{0} is a required field",
|
||||
"ParentChoiceSelf": "Parent cannot be itself",
|
||||
"ParentNull": "Parent does not exist {0}",
|
||||
"Remark": "Remarks",
|
||||
"Status": "Status",
|
||||
"TargetNameDup": "Target node has duplicate name {0}"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.AppConfig": {
|
||||
"LoginPolicy": "LoginPolicy",
|
||||
"PasswordPolicy": "PasswordPolicy",
|
||||
"PagePolicy": "PagePolicy",
|
||||
"WebsitePolicy": "WebsitePolicy"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LoginPolicy": {
|
||||
"SingleOpen": "Single user login switch",
|
||||
"ErrorLockTime": "Login error lock duration (min)",
|
||||
"ErrorResetTime": "Login error count expiration duration (min)",
|
||||
"ErrorCount": "Login error count lock threshold",
|
||||
"VerificatExpireTime": "Login expiration time (min)",
|
||||
"ErrorLockTime.MinValue": "{0} value is too small",
|
||||
"ErrorResetTime.MinValue": "{0} value is too small",
|
||||
"ErrorCount.MinValue": "{0} value is too small",
|
||||
"VerificatExpireTime.MinValue": "{0} value is too small"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.PagePolicy": {
|
||||
"Shortcuts": "Default shortcuts",
|
||||
"Razor": "Default homepage"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.PasswordPolicy": {
|
||||
"DefaultPassword": "Default user password",
|
||||
"DefaultPassword.Required": "{0} is required",
|
||||
"PasswordMinLen": "Minimum password length",
|
||||
"PasswordMinLen.MinValue": "{0} value is too small",
|
||||
"PasswordContainNum": "Contain numbers",
|
||||
"PasswordContainLower": "Contain lowercase letters",
|
||||
"PasswordContainUpper": "Contain uppercase letters",
|
||||
"PasswordContainChar": "Contain special characters"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.WebsitePolicy": {
|
||||
"WebStatus": "WebStatus",
|
||||
"CloseTip": "CloseTip",
|
||||
"CloseTip.Required": "{0} is required"
|
||||
},
|
||||
//enum
|
||||
"ThingsGateway.Admin.Application.ResourceCategoryEnum": {
|
||||
"ThingsGateway.Admin.Application.SysResource": {
|
||||
"CanotDeleteSystemResource": "Cannot delete system resource {0}",
|
||||
"Category": "Category",
|
||||
"Code": "Code",
|
||||
"Href": "Path",
|
||||
"Href.Required": "{0} is required",
|
||||
"Icon": "Icon",
|
||||
"Module": "Module",
|
||||
"Menu": "Menu",
|
||||
"Button": "Button"
|
||||
"ModuleIdDiff": "Module is inconsistent with parent menu",
|
||||
"NavLinkMatch": "NavLinkMatch",
|
||||
"NotFoundResource": "System exception, menu not found",
|
||||
"ParentId": "Parent",
|
||||
"ResourceDup": "Duplicate name {0} exists",
|
||||
"ResourceMenuHrefNotNull": "Menu href cannot null",
|
||||
"ResourceParentChoiceSelf": "Parent cannot choose itself",
|
||||
"ResourceParentNull": "Parent does not exist {0}",
|
||||
"Target": "Target",
|
||||
"Title": "Title",
|
||||
"Title.Required": "{0} is required"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.SysRole": {
|
||||
"CannotRoleScopeAll": "Organization role cannot select global data scope",
|
||||
"CanotDeleteAdmin": "Cannot delete built-in super admin role",
|
||||
"CanotEditAdmin": "Cannot edit super admin role",
|
||||
"CanotGrantAdmin": "Cannot assign admins roles",
|
||||
"Category": "Category",
|
||||
"Code": "Code",
|
||||
"CodeDup": "Duplicate code exists: {0}",
|
||||
"Global": "Global",
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} is required",
|
||||
"NameDup": "Duplicate role name {0}",
|
||||
"OrgId": "Org",
|
||||
"OrgNotNull": "Organization cannot be null",
|
||||
"SameOrgNameDup": "Duplicate role name exists: {0}",
|
||||
"Status": "Status"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.SysUser": {
|
||||
"Account": "Account",
|
||||
"Account.Required": "Account.Required",
|
||||
"AccountDup": "Duplicate account {0} exists",
|
||||
"Avatar": "Avatar",
|
||||
"CanotDeleteAdminUser": "Cannot delete built-in super admin user",
|
||||
"CanotDeleteSelf": "Cannot delete yourself",
|
||||
"CanotEditAdminUser": "Cannot edit super admin user",
|
||||
"CanotGrantAdmin": "Cannot assign admins roles",
|
||||
"CheckSelf": "Prohibit {0} yourself",
|
||||
"ConfirmPasswordDiff": "Passwords entered twice are inconsistent",
|
||||
"DemoCanotUpdatePassword": "DEMO environment does not allow password modification",
|
||||
"DirectorId": "Director",
|
||||
"DirectorSelf": "Cannot set oneself as the supervisor",
|
||||
"Disable": "Disable",
|
||||
"Email": "Email",
|
||||
"EmailDup": "Duplicate email {0} exists",
|
||||
"EmailError": "Email format error {0}",
|
||||
"Enable": "Enable",
|
||||
"ExitVerificat": "You have been forcibly logged out",
|
||||
"GrantRole": "GrantRole",
|
||||
"LastLoginAddress": "LastLoginAddress",
|
||||
"LastLoginDevice": "LastLoginDevice",
|
||||
"LastLoginIp": "LastLoginIp",
|
||||
"LastLoginTime": "LastLoginTime",
|
||||
"LatestLoginAddress": "LatestLoginAddress",
|
||||
"LatestLoginDevice": "LatestLoginDevice",
|
||||
"LatestLoginIp": "LatestLoginIp",
|
||||
"LatestLoginTime": "LatestLoginTime",
|
||||
"NoOrg": "The organization does not exist",
|
||||
"OldPasswordError": "Incorrect old password",
|
||||
"OrgId": "Org",
|
||||
"OrgNames": "OrgNames",
|
||||
"Password": "Password",
|
||||
"PasswordEdited": "Password changed, logged out",
|
||||
"PasswordLengthLess": "Password length cannot be less than {0}",
|
||||
"PasswordMustLow": "Password must contain lowercase letters",
|
||||
"PasswordMustNum": "Password must contain numbers",
|
||||
"PasswordMustSpecial": "Password must contain special characters",
|
||||
"PasswordMustUpp": "Password must contain uppercase letters",
|
||||
"Phone": "Phone",
|
||||
"PhoneError": "Phone number format error {0}",
|
||||
"PositionId": "Position",
|
||||
"PositionName": "PositionName",
|
||||
"Status": "Status"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.TargetEnum": {
|
||||
"_self": "Current window",
|
||||
"_blank": "New window",
|
||||
"_parent": "Parent window",
|
||||
"_self": "Current window",
|
||||
"_top": "Top window"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.DictTypeEnum": {
|
||||
"System": "System",
|
||||
"Define": "Business"
|
||||
"ThingsGateway.Admin.Application.TestController": {
|
||||
"Test": "Test",
|
||||
"TestController": "Test API"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.LogCateGoryEnum": {
|
||||
"Login": "Login",
|
||||
"Logout": "Logout",
|
||||
"Operate": "Operation",
|
||||
"Exception": "Exception"
|
||||
"ThingsGateway.Admin.Application.UnifyResultProvider": {
|
||||
"NoPermission": "Access denied, no permission",
|
||||
"TokenOver": "Login has expired, please login again"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.LogEnum": {
|
||||
"SUCCESS": "Success",
|
||||
"FAIL": "Fail"
|
||||
"ThingsGateway.Admin.Application.UpdatePasswordInput": {
|
||||
"ConfirmPassword": "Confirm password",
|
||||
"ConfirmPassword.Required": "{0} is required",
|
||||
"NewPassword": "New password",
|
||||
"NewPassword.Required": "{0} is required",
|
||||
"Password": "Password",
|
||||
"Password.Required": "{0} is required"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.UserSelectorOutput": {
|
||||
"Account": "Account",
|
||||
"OrgId": "Org"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.VerificatInfo": {
|
||||
"Device": "Device",
|
||||
"Expire": "Expire(min)",
|
||||
"LoginIp": "LoginIp",
|
||||
"LoginTime": "LoginTime",
|
||||
"Online": "Online",
|
||||
"VerificatTimeout": "VerificatTimeout"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.WebsitePolicy": {
|
||||
"CloseTip": "CloseTip",
|
||||
"CloseTip.Required": "{0} is required",
|
||||
"WebStatus": "WebStatus"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.WorkbenchInfo": {
|
||||
"Razor": "Homepage",
|
||||
"Shortcuts": "Shortcuts"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,462 +1,402 @@
|
||||
{
|
||||
"ThingsGateway.Admin.Application.AppConfig": {
|
||||
"LoginPolicy": "登录策略",
|
||||
"PagePolicy": "页面设置",
|
||||
"PasswordPolicy": "密码策略",
|
||||
"WebsitePolicy": "网站设置"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.AuthController": {
|
||||
"AuthController": "登录API",
|
||||
"LoginAsync": "登录",
|
||||
"LogoutAsync": "注销"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.AuthService": {
|
||||
"AuthErrorMax": "账号密码错误,超过 {0} 次后将锁定 {1} 分钟,错误次数 {2} ",
|
||||
"MustDesc": "密码需要DESC加密后传入",
|
||||
"OrgDisable": "所属公司/部门已停用,请联系管理员",
|
||||
"PasswordError": "密码错误次数过多,请 {0} 分钟后再试",
|
||||
"SingleLoginWarn": "您的账号已在别处登录",
|
||||
"TenantNull": "租户不存在",
|
||||
"UserDisable": "账号 {0} 已停用",
|
||||
"UserNoModule": "该账号未分配模块,请联系管理员",
|
||||
"UserNull": "用户 {0} 不存在"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.BaseDataEntity": {
|
||||
"CreateOrgId": "创建机构Id"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.BaseEntity": {
|
||||
"SortCode": "排序",
|
||||
"CreateTime": "创建时间",
|
||||
"CreateUser": "创建人",
|
||||
"SortCode": "排序",
|
||||
"UpdateTime": "更新时间",
|
||||
"UpdateUser": "更新人"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.BlazorAuthenticationHandler": {
|
||||
"UserExpire": "用户登录已过期,请重新登录"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.SysUser": {
|
||||
"Disable": "禁用",
|
||||
"Enable": "启用",
|
||||
"GrantRole": "分配角色",
|
||||
"ExitVerificat": "您已被强制下线",
|
||||
"PasswordEdited": "密码被修改,已退出登录",
|
||||
"Avatar": "头像",
|
||||
"Account": "账号",
|
||||
"Account.Required": " {0} 是必填项",
|
||||
"Password": "密码",
|
||||
"Status": "状态",
|
||||
"Phone": "手机",
|
||||
"Email": "邮箱",
|
||||
"LastLoginIp": "上次登录ip",
|
||||
"LastLoginDevice": "上次登录设备",
|
||||
"LastLoginTime": "上次登录时间",
|
||||
"LastLoginAddress": "上次登录地点",
|
||||
"LatestLoginIp": "最新登录ip",
|
||||
"LatestLoginTime": "最新登录时间",
|
||||
"LatestLoginDevice": "最新登录设备",
|
||||
"LatestLoginAddress": "最新登录地点",
|
||||
"OrgNames": "机构名称",
|
||||
"PositionName": "职位名称",
|
||||
"OrgId": "机构",
|
||||
"PositionId": "职位",
|
||||
"DirectorId": "主管",
|
||||
"CheckSelf": "禁止 {0} 自己",
|
||||
"CanotDeleteAdminUser": "不可删除系统内置超管用户",
|
||||
"CanotEditAdminUser": "不可编辑超管用户",
|
||||
"CanotGrantAdmin": "不能分配超管角色",
|
||||
"EmailDup": "存在重复的邮箱 {0}",
|
||||
"AccountDup": "存在重复的账号 {0}",
|
||||
"CanotDeleteSelf": "不可删除自己",
|
||||
"EmailError": "邮箱 {0} 格式错误",
|
||||
"PhoneError": "手机号码 {0} 格式错误",
|
||||
"NoOrg": "组织机构不存在",
|
||||
"DirectorSelf": "不能设置自己为主管",
|
||||
|
||||
|
||||
"DemoCanotUpdatePassword": "DEMO环境不允许修改密码",
|
||||
"OldPasswordError": "原密码错误",
|
||||
"ConfirmPasswordDiff": "两次输入的密码不一致",
|
||||
"PasswordLengthLess": "密码长度不能小于 {0} ",
|
||||
"PasswordMustNum ": "密码必须包含数字",
|
||||
"PasswordMustLow": "密码必须包含小写字母",
|
||||
"PasswordMustUpp": "密码必须包含大写字母",
|
||||
"PasswordMustSpecial": "密码必须包含特殊字符"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.SysRole": {
|
||||
"Code": "编码",
|
||||
"Name": "名称",
|
||||
"Name.Required": " {0} 是必填项",
|
||||
"Category": "分类",
|
||||
"Global": "全局",
|
||||
"Status": "状态",
|
||||
"OrgId": "机构",
|
||||
|
||||
"CanotDeleteAdmin": "不可删除系统内置超管角色",
|
||||
"CanotEditAdmin": "不可编辑超管角色",
|
||||
"CanotGrantAdmin": "不能分配超管角色",
|
||||
|
||||
"NameDup": "存在重复的角色名称 {0}",
|
||||
"OrgNotNull": "机构不能为空",
|
||||
"SameOrgNameDup": "存在重复的角色名称 {0}",
|
||||
"CannotRoleScopeAll": "机构角色不能选择全局数据范围",
|
||||
"CodeDup": "存在重复的编码 {0}"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.RoleCategoryEnum": {
|
||||
"Global": "全局",
|
||||
"Org": "机构"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.DataScopeEnum": {
|
||||
"SCOPE_SELF": "仅自己",
|
||||
"SCOPE_ALL": "全部",
|
||||
"SCOPE_ORG": "仅所属组织",
|
||||
"SCOPE_ORG_CHILD": "所属组织及以下",
|
||||
"SCOPE_ORG_DEFINE": "自定义"
|
||||
"SCOPE_ORG_DEFINE": "自定义",
|
||||
"SCOPE_SELF": "仅自己"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.DefaultDataScope": {
|
||||
"ScopeCategory": "数据范围",
|
||||
"ScopeDefineOrgIdList": "自定义列表"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.SysResource": {
|
||||
"Title": "标题",
|
||||
"Module": "模块",
|
||||
"Title.Required": "{0} 是必填项",
|
||||
"Href.Required": "{0} 是必填项",
|
||||
"Icon": "图标",
|
||||
"Href": "路径",
|
||||
"Code": "编码",
|
||||
"Category": "分类",
|
||||
"Target": "跳转类型",
|
||||
"NavLinkMatch": "匹配类型",
|
||||
"ParentId": "上级菜单",
|
||||
"ResourceDup": "存在重复的名称 {0}",
|
||||
"ResourceParentChoiceSelf": "父级不能选择自己",
|
||||
"ResourceParentNull": "父级不存在 {0}",
|
||||
"NotFoundResource": "系统异常,没找到该菜单",
|
||||
"ModuleIdDiff": "模块与上级菜单不一致",
|
||||
"CanotDeleteSystemResource": "不可删除系统资源 {0}",
|
||||
"ResourceMenuHrefNotNull": "菜单的路径不能为空"
|
||||
"ThingsGateway.Admin.Application.DictTypeEnum": {
|
||||
"Define": "业务配置",
|
||||
"System": "系统配置"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.SysOrgCopyInput": {
|
||||
"TargetId": "目标机构",
|
||||
"ContainsChild": "包含下级",
|
||||
"ContainsPosition": "包含职位"
|
||||
"ThingsGateway.Admin.Application.FileService": {
|
||||
"FileLengthError": "文件大小不允许超过 {0} M",
|
||||
"FileNullError": "文件不能为空",
|
||||
"FileTypeError": "不支持 {0} 格式"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.SysPosition": {
|
||||
"Category.Required": "{0} 是必填项",
|
||||
"Name.Required": "{0} 是必填项",
|
||||
"Code.Required": "{0} 是必填项",
|
||||
"OrgId.MinValue": "{0} 是必填项",
|
||||
"Category": "分类",
|
||||
"Name": "名称",
|
||||
"Code": "代码",
|
||||
"Status": "状态",
|
||||
"OrgId": "机构",
|
||||
"Remark": "备注",
|
||||
"Dup": "存在重复的岗位 分类 {0} 名称 {1}",
|
||||
"CodeDup": "存在重复的编码 {0}",
|
||||
"NameDup": "存在重复的名称 {0}",
|
||||
"CanotContainsSelf": "不可包含自己",
|
||||
"TargetNameDup": "目标节点存在重复的名称 {0}",
|
||||
"ParentChoiceSelf": "父级不能选择自己",
|
||||
"ParentNull": "父级不存在 {0}",
|
||||
"DeleteUserFirst": "请先删除职位下的用户"
|
||||
|
||||
"ThingsGateway.Admin.Application.HardwareInfo": {
|
||||
"Environment": "主机环境",
|
||||
"FrameworkDescription": "NET框架",
|
||||
"OsArchitecture": "系统架构",
|
||||
"UpdateTime": "更新时间",
|
||||
"UUID": "唯一编码"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.SysOrg": {
|
||||
"Category.Required": "{0} 是必填项",
|
||||
"Name.Required": "{0} 是必填项",
|
||||
"Code.Required": "{0} 是必填项",
|
||||
"ThingsGateway.Admin.Application.HardwareJob": {
|
||||
"GetHardwareInfoFail": "获取硬件信息出错"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.HistoryHardwareInfo": {
|
||||
"Battery": "电池",
|
||||
"CpuUsage": "CPU使用率",
|
||||
"DriveUsage": "磁盘使用率",
|
||||
"MemoryUsage": "内存",
|
||||
"Temperature": "温度"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LogCateGoryEnum": {
|
||||
"Exception": "异常",
|
||||
"Login": "登录",
|
||||
"Logout": "注销",
|
||||
"Operate": "操作"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LogEnum": {
|
||||
"FAIL": "失败",
|
||||
"SUCCESS": "成功"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LoginInput": {
|
||||
"Account": "登录账号",
|
||||
"Account.Required": "{0} 是必填项",
|
||||
"Password": "登录密码",
|
||||
"Password.Required": "{0} 是必填项"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LoginPolicy": {
|
||||
"ErrorCount": "登录错误次数锁定阈值",
|
||||
"ErrorCount.MinValue": " {0} 值太小",
|
||||
"ErrorLockTime": "登录错误锁定时长(分)",
|
||||
"ErrorLockTime.MinValue": " {0} 值太小",
|
||||
"ErrorResetTime": "登录错误次数过期时长(分)",
|
||||
"ErrorResetTime.MinValue": " {0} 值太小",
|
||||
"SingleOpen": "单用户登录开关",
|
||||
"VerificatExpireTime": "登录过期时间(分)",
|
||||
"VerificatExpireTime.MinValue": " {0} 值太小"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LogoutInput": {
|
||||
"VerificatId.Required": "{0} 是必填项"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.OpenApiAuthController": {
|
||||
"LoginAsync": "登录",
|
||||
"LogoutAsync": "注销",
|
||||
"OpenApiAuthController": "登录API"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.OperateLogPageInput": {
|
||||
"Account": "操作账号",
|
||||
"Category": "分类",
|
||||
"Name": "名称",
|
||||
"Code": "代码",
|
||||
"Status": "状态",
|
||||
"ParentId": "上级机构",
|
||||
"Names": "机构全称",
|
||||
"Remark": "备注",
|
||||
"DirectorId": "主管",
|
||||
"Dup": "存在重复的机构 分类 {0} 名称 {1}",
|
||||
"CodeDup": "存在重复的编码 {0}",
|
||||
"NameDup": "存在重复的名称 {0}",
|
||||
"CanotContainsSelf": "不可包含自己",
|
||||
"TargetNameDup": "目标节点存在重复的名称 {0}",
|
||||
"ParentChoiceSelf": "父级不能选择自己",
|
||||
"ParentNull": "父级不存在 {0}",
|
||||
"DeleteUserFirst": "请先删除机构下的用户",
|
||||
"DeleteRoleFirst": "请先删除机构下的角色",
|
||||
"DeletePositionFirst": "请先删除机构下的职位",
|
||||
"RootOrg": "无法创建顶层机构"
|
||||
"SearchDate": "时间范围"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.OperDescAttribute": {
|
||||
"ChangeParentResource": "更改父节点",
|
||||
"CopyOrg": "复制机构",
|
||||
"CopyResource": "复制资源",
|
||||
"DeleteDict": "删除字典",
|
||||
"DeleteOperLog": "删除操作日志",
|
||||
"DeleteOrg": "删除机构",
|
||||
"DeletePosition": "删除岗位",
|
||||
"DeleteResource": "删除资源",
|
||||
"DeleteRole": "删除角色",
|
||||
"DeleteuSER": "删除用户",
|
||||
"EditLoginPolicy": "修改登录策略",
|
||||
"EditPagePolicy": "修改页面策略",
|
||||
"EditPasswordPolicy": "修改密码策略",
|
||||
"EditWebsitePolicy": "修改网站设置",
|
||||
"ExitSession": "强退会话",
|
||||
"ExitVerificat": "强退令牌",
|
||||
"ExportOperLog": "导出操作日志",
|
||||
"GrantApi": "API",
|
||||
"GrantResource": "资源",
|
||||
"GrantRole": "角色",
|
||||
"GrantUser": "用户",
|
||||
"NoPermission": "无权限操作",
|
||||
"ResetPassword": "重置密码",
|
||||
"RoleGrantApiPermission": "角色授权OpenApi",
|
||||
"RoleGrantResource": "角色授权资源",
|
||||
"RoleGrantUser": "角色授权用户",
|
||||
"SaveDict": "修改字典",
|
||||
"SaveOrg": "保存机构",
|
||||
"SavePosition": "保存岗位",
|
||||
"SaveResource": "修改资源",
|
||||
"SaveRole": "修改角色",
|
||||
"SaveUser": "修改用户",
|
||||
"UpdatePassword": "更新个人密码",
|
||||
"UpdateUserInfo": "更新个人信息",
|
||||
"UserGrantApiPermission": "用户授权OpenApi",
|
||||
"UserGrantResource": "用户授权资源",
|
||||
"UserGrantRole": "用户授权角色",
|
||||
"WorkbenchInfo": "更新个人工作台"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.OrgEnum": {
|
||||
"COMPANY": "公司",
|
||||
"DEPT": "部门"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.PagePolicy": {
|
||||
"Razor": "默认主页",
|
||||
"Shortcuts": "默认快捷方式"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.PasswordPolicy": {
|
||||
"DefaultPassword": "默认用户密码",
|
||||
"DefaultPassword.Required": " {0} 是必填项",
|
||||
"PasswordContainChar": "包含特殊字符",
|
||||
"PasswordContainLower": "包含小写字母",
|
||||
"PasswordContainNum": "包含数字",
|
||||
"PasswordContainUpper": "包含大写字母",
|
||||
"PasswordMinLen": "密码最小长度",
|
||||
"PasswordMinLen.MinValue": " {0} 值太小"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.PositionCategoryEnum": {
|
||||
"HIGH": "高层",
|
||||
"MIDDLE": "中层",
|
||||
"LOW": "低层"
|
||||
"LOW": "低层",
|
||||
"MIDDLE": "中层"
|
||||
},
|
||||
|
||||
//controller
|
||||
"ThingsGateway.Admin.Application.AuthController": {
|
||||
//auth
|
||||
"AuthController": "登录API",
|
||||
"LoginAsync": "登录",
|
||||
"LogoutAsync": "注销"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.TestController": {
|
||||
//auth
|
||||
"TestController": "测试API",
|
||||
"Test": "测试"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.OpenApiAuthController": {
|
||||
//auth
|
||||
"OpenApiAuthController": "登录API",
|
||||
"LoginAsync": "登录",
|
||||
"LogoutAsync": "注销"
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
"ThingsGateway.Admin.Application.FileService": {
|
||||
"FileNullError": "文件不能为空",
|
||||
"FileLengthError": "文件大小不允许超过 {0} M",
|
||||
"FileTypeError": "不支持 {0} 格式"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.UnifyResultProvider": {
|
||||
"TokenOver": "登录已过期,请重新登录",
|
||||
"NoPermission": "禁止访问,没有权限"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.AuthService": {
|
||||
"TenantNull": "租户不存在",
|
||||
"OrgDisable": "所属公司/部门已停用,请联系管理员",
|
||||
"SingleLoginWarn": "您的账号已在别处登录",
|
||||
"UserNull": "用户 {0} 不存在",
|
||||
"PasswordError": "密码错误次数过多,请 {0} 分钟后再试",
|
||||
"AuthErrorMax": "账号密码错误,超过 {0} 次后将锁定 {1} 分钟,错误次数 {2} ",
|
||||
"UserDisable": "账号 {0} 已停用",
|
||||
"MustDesc": "密码需要DESC加密后传入",
|
||||
"UserNoModule": "该账号未分配模块,请联系管理员"
|
||||
},
|
||||
|
||||
|
||||
"ThingsGateway.Admin.Application.HardwareInfo": {
|
||||
"Environment": "主机环境",
|
||||
"FrameworkDescription": "NET框架",
|
||||
"OsArchitecture": "系统架构",
|
||||
"UUID": "唯一编码",
|
||||
"UpdateTime": "更新时间"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.HistoryHardwareInfo": {
|
||||
"DriveUsage": "磁盘使用率",
|
||||
"MemoryUsage": "内存",
|
||||
"CpuUsage": "CPU使用率",
|
||||
"Temperature": "温度",
|
||||
"Battery": "电池"
|
||||
},
|
||||
|
||||
//oper
|
||||
"ThingsGateway.Admin.Application.OperDescAttribute": {
|
||||
//dict
|
||||
"SaveDict": "修改字典",
|
||||
"DeleteDict": "删除字典",
|
||||
"EditLoginPolicy": "修改登录策略",
|
||||
"EditPasswordPolicy": "修改密码策略",
|
||||
"EditPagePolicy": "修改页面策略",
|
||||
"EditWebsitePolicy": "修改网站设置",
|
||||
//operlog
|
||||
"DeleteOperLog": "删除操作日志",
|
||||
"ExportOperLog": "导出操作日志",
|
||||
|
||||
//resource
|
||||
"SaveResource": "修改资源",
|
||||
"DeleteResource": "删除资源",
|
||||
|
||||
//role
|
||||
"SaveRole": "修改角色",
|
||||
"DeleteRole": "删除角色",
|
||||
"RoleGrantResource": "角色授权资源",
|
||||
"RoleGrantUser": "角色授权用户",
|
||||
"RoleGrantApiPermission": "角色授权OpenApi",
|
||||
"GrantApi": "API",
|
||||
"GrantUser": "用户",
|
||||
"GrantRole": "角色",
|
||||
"GrantResource": "资源",
|
||||
//user
|
||||
"SaveUser": "修改用户",
|
||||
"DeleteuSER": "删除用户",
|
||||
"ResetPassword": "重置密码",
|
||||
"UserGrantRole": "用户授权角色",
|
||||
"UserGrantResource": "用户授权资源",
|
||||
"UserGrantApiPermission": "用户授权OpenApi",
|
||||
|
||||
//usercenter
|
||||
"UpdateUserInfo": "更新个人信息",
|
||||
"WorkbenchInfo": "更新个人工作台",
|
||||
"UpdatePassword": "更新个人密码",
|
||||
|
||||
//session
|
||||
"ExitVerificat": "强退令牌",
|
||||
"ExitSession": "强退会话",
|
||||
|
||||
|
||||
"CopyOrg": "复制机构",
|
||||
"DeleteOrg": "删除机构",
|
||||
"SaveOrg": "保存机构",
|
||||
|
||||
"DeletePosition": "删除岗位",
|
||||
"SavePosition": "保存岗位",
|
||||
|
||||
"NoPermission": "无权限操作",
|
||||
|
||||
"CopyResource": "复制资源",
|
||||
"ChangeParentResource": "更改父节点"
|
||||
},
|
||||
|
||||
//service
|
||||
|
||||
"ThingsGateway.Admin.Application.HardwareJob": {
|
||||
"GetHardwareInfoFail": "获取硬件信息出错"
|
||||
},
|
||||
|
||||
//dto
|
||||
"ThingsGateway.Admin.Application.UserSelectorOutput": {
|
||||
"Account": "账号",
|
||||
"OrgId": "机构"
|
||||
"ThingsGateway.Admin.Application.ResourceCategoryEnum": {
|
||||
"Button": "按钮",
|
||||
"Menu": "菜单",
|
||||
"Module": "模块"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.ResourceTableSearchModel": {
|
||||
"Module": "模块",
|
||||
"Href": "路径",
|
||||
"Module": "模块",
|
||||
"Title": "标题"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.WorkbenchInfo": {
|
||||
"Razor": "主页",
|
||||
"Shortcuts": "快捷方式"
|
||||
"ThingsGateway.Admin.Application.RoleCategoryEnum": {
|
||||
"Global": "全局",
|
||||
"Org": "机构"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.UpdatePasswordInput": {
|
||||
"Password": "密码",
|
||||
"NewPassword": "新密码",
|
||||
"ConfirmPassword": "确认密码",
|
||||
"Password.Required": " {0} 是必填项",
|
||||
"NewPassword.Required": " {0} 是必填项",
|
||||
"ConfirmPassword.Required": " {0} 是必填项"
|
||||
},
|
||||
|
||||
|
||||
"ThingsGateway.Admin.Application.VerificatInfo": {
|
||||
"Expire": "过期时间(分)",
|
||||
"Online": "在线状态",
|
||||
"VerificatTimeout": "超时时间",
|
||||
"Device": "登录设备",
|
||||
"LoginIp": "登录IP",
|
||||
"LoginTime": "登录时间"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.SessionOutput": {
|
||||
"Account": "账号",
|
||||
"Online": "在线状态",
|
||||
"LatestLoginIp": "最新登录ip",
|
||||
"LatestLoginTime": "最新登录时间",
|
||||
"Online": "在线状态",
|
||||
"VerificatCount": "令牌数量"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.SysDict": {
|
||||
"Category.Required": "{0} 是必填项",
|
||||
"Name.Required": "{0} 是必填项",
|
||||
"Code.Required": "{0} 是必填项",
|
||||
"Category": "分类",
|
||||
"Name": "名称",
|
||||
"Category.Required": "{0} 是必填项",
|
||||
"Code": "代码",
|
||||
"Remark": "备注",
|
||||
"Code.Required": "{0} 是必填项",
|
||||
"DemoCanotUpdateWebsitePolicy": "DEMO环境不允许修改网站设置",
|
||||
"DictDup": "存在重复的配置 分类 {0} 名称 {1}",
|
||||
"DemoCanotUpdateWebsitePolicy": "DEMO环境不允许修改网站设置"
|
||||
"Name": "名称",
|
||||
"Name.Required": "{0} 是必填项",
|
||||
"Remark": "备注"
|
||||
},
|
||||
|
||||
|
||||
"ThingsGateway.Admin.Application.SysOperateLog": {
|
||||
"Category": "日志分类",
|
||||
"ClassName": "类名",
|
||||
"ExeMessage": "具体消息",
|
||||
"MethodName": "方法名称",
|
||||
"ParamJson": "请求参数",
|
||||
"ReqMethod": "请求方式",
|
||||
"ReqUrl": "请求地址",
|
||||
"ResultJson": "返回结果",
|
||||
"Category": "日志分类",
|
||||
"ExeStatus": "执行状态",
|
||||
"MethodName": "方法名称",
|
||||
"Name": "日志名称",
|
||||
"OpAccount": "账号",
|
||||
"OpBrowser": "浏览器",
|
||||
"OpIp": "ip",
|
||||
"OpOs": "系统",
|
||||
"OpTime": "操作时间",
|
||||
"ParamJson": "请求参数",
|
||||
"ReqMethod": "请求方式",
|
||||
"ReqUrl": "请求地址",
|
||||
"ResultJson": "返回结果",
|
||||
"VerificatId": "验证Id"
|
||||
|
||||
},
|
||||
"ThingsGateway.Admin.Application.OperateLogPageInput": {
|
||||
"SearchDate": "时间范围",
|
||||
"Account": "操作账号",
|
||||
"Category": "分类"
|
||||
"ThingsGateway.Admin.Application.SysOrg": {
|
||||
"CanotContainsSelf": "不可包含自己",
|
||||
"Category": "分类",
|
||||
"Category.Required": "{0} 是必填项",
|
||||
"Code": "代码",
|
||||
"Code.Required": "{0} 是必填项",
|
||||
"CodeDup": "存在重复的编码 {0}",
|
||||
"DeletePositionFirst": "请先删除机构下的职位",
|
||||
"DeleteRoleFirst": "请先删除机构下的角色",
|
||||
"DeleteUserFirst": "请先删除机构下的用户",
|
||||
"DirectorId": "主管",
|
||||
"Dup": "存在重复的机构 分类 {0} 名称 {1}",
|
||||
"Name": "名称",
|
||||
"Name.Required": "{0} 是必填项",
|
||||
"NameDup": "存在重复的名称 {0}",
|
||||
"Names": "机构全称",
|
||||
"ParentChoiceSelf": "父级不能选择自己",
|
||||
"ParentId": "上级机构",
|
||||
"ParentNull": "父级不存在 {0}",
|
||||
"Remark": "备注",
|
||||
"RootOrg": "无法创建顶层机构",
|
||||
"Status": "状态",
|
||||
"TargetNameDup": "目标节点存在重复的名称 {0}"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LoginInput": {
|
||||
"Account": "登录账号",
|
||||
"Password": "登录密码",
|
||||
"Account.Required": "{0} 是必填项",
|
||||
"Password.Required": "{0} 是必填项"
|
||||
"ThingsGateway.Admin.Application.SysOrgCopyInput": {
|
||||
"ContainsChild": "包含下级",
|
||||
"ContainsPosition": "包含职位",
|
||||
"TargetId": "目标机构"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LogoutInput": {
|
||||
"VerificatId.Required": "{0} 是必填项"
|
||||
"ThingsGateway.Admin.Application.SysPosition": {
|
||||
"CanotContainsSelf": "不可包含自己",
|
||||
"Category": "分类",
|
||||
"Category.Required": "{0} 是必填项",
|
||||
"Code": "代码",
|
||||
"Code.Required": "{0} 是必填项",
|
||||
"CodeDup": "存在重复的编码 {0}",
|
||||
"DeleteUserFirst": "请先删除职位下的用户",
|
||||
"Dup": "存在重复的岗位 分类 {0} 名称 {1}",
|
||||
"Name": "名称",
|
||||
"Name.Required": "{0} 是必填项",
|
||||
"NameDup": "存在重复的名称 {0}",
|
||||
"OrgId": "机构",
|
||||
"OrgId.MinValue": "{0} 是必填项",
|
||||
"ParentChoiceSelf": "父级不能选择自己",
|
||||
"ParentNull": "父级不存在 {0}",
|
||||
"Remark": "备注",
|
||||
"Status": "状态",
|
||||
"TargetNameDup": "目标节点存在重复的名称 {0}"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.AppConfig": {
|
||||
"LoginPolicy": "登录策略",
|
||||
"PasswordPolicy": "密码策略",
|
||||
"PagePolicy": "页面设置",
|
||||
"WebsitePolicy": "网站设置"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.LoginPolicy": {
|
||||
"SingleOpen": "单用户登录开关",
|
||||
"ErrorLockTime": "登录错误锁定时长(分)",
|
||||
"ErrorResetTime": "登录错误次数过期时长(分)",
|
||||
"ErrorCount": "登录错误次数锁定阈值",
|
||||
"VerificatExpireTime": "登录过期时间(分)",
|
||||
"ErrorLockTime.MinValue": " {0} 值太小",
|
||||
"ErrorResetTime.MinValue": " {0} 值太小",
|
||||
"ErrorCount.MinValue": " {0} 值太小",
|
||||
"VerificatExpireTime.MinValue": " {0} 值太小"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.PagePolicy": {
|
||||
"Shortcuts": "默认快捷方式",
|
||||
"Razor": "默认主页"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.PasswordPolicy": {
|
||||
"DefaultPassword": "默认用户密码",
|
||||
"DefaultPassword.Required": " {0} 是必填项",
|
||||
"PasswordMinLen": "密码最小长度",
|
||||
"PasswordMinLen.MinValue": " {0} 值太小",
|
||||
"PasswordContainNum": "包含数字",
|
||||
"PasswordContainLower": "包含小写字母",
|
||||
"PasswordContainUpper": "包含大写字母",
|
||||
"PasswordContainChar": "包含特殊字符"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.WebsitePolicy": {
|
||||
"WebStatus": "是否开放",
|
||||
"CloseTip": "关闭提示",
|
||||
"CloseTip.Required": " {0} 是必填项"
|
||||
},
|
||||
|
||||
|
||||
|
||||
//enum
|
||||
"ThingsGateway.Admin.Application.ResourceCategoryEnum": {
|
||||
"ThingsGateway.Admin.Application.SysResource": {
|
||||
"CanotDeleteSystemResource": "不可删除系统资源 {0}",
|
||||
"Category": "分类",
|
||||
"Code": "编码",
|
||||
"Href": "路径",
|
||||
"Href.Required": "{0} 是必填项",
|
||||
"Icon": "图标",
|
||||
"Module": "模块",
|
||||
"Menu": "菜单",
|
||||
"Button": "按钮"
|
||||
"ModuleIdDiff": "模块与上级菜单不一致",
|
||||
"NavLinkMatch": "匹配类型",
|
||||
"NotFoundResource": "系统异常,没找到该菜单",
|
||||
"ParentId": "上级菜单",
|
||||
"ResourceDup": "存在重复的名称 {0}",
|
||||
"ResourceMenuHrefNotNull": "菜单的路径不能为空",
|
||||
"ResourceParentChoiceSelf": "父级不能选择自己",
|
||||
"ResourceParentNull": "父级不存在 {0}",
|
||||
"Target": "跳转类型",
|
||||
"Title": "标题",
|
||||
"Title.Required": "{0} 是必填项"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.SysRole": {
|
||||
"CannotRoleScopeAll": "机构角色不能选择全局数据范围",
|
||||
"CanotDeleteAdmin": "不可删除系统内置超管角色",
|
||||
"CanotEditAdmin": "不可编辑超管角色",
|
||||
"CanotGrantAdmin": "不能分配超管角色",
|
||||
"Category": "分类",
|
||||
"Code": "编码",
|
||||
"CodeDup": "存在重复的编码 {0}",
|
||||
"Global": "全局",
|
||||
"Name": "名称",
|
||||
"Name.Required": " {0} 是必填项",
|
||||
"NameDup": "存在重复的角色名称 {0}",
|
||||
"OrgId": "机构",
|
||||
"OrgNotNull": "机构不能为空",
|
||||
"SameOrgNameDup": "存在重复的角色名称 {0}",
|
||||
"Status": "状态"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.SysUser": {
|
||||
"Account": "账号",
|
||||
"Account.Required": " {0} 是必填项",
|
||||
"AccountDup": "存在重复的账号 {0}",
|
||||
"Avatar": "头像",
|
||||
"CanotDeleteAdminUser": "不可删除系统内置超管用户",
|
||||
"CanotDeleteSelf": "不可删除自己",
|
||||
"CanotEditAdminUser": "不可编辑超管用户",
|
||||
"CanotGrantAdmin": "不能分配超管角色",
|
||||
"CheckSelf": "禁止 {0} 自己",
|
||||
"ConfirmPasswordDiff": "两次输入的密码不一致",
|
||||
"DemoCanotUpdatePassword": "DEMO环境不允许修改密码",
|
||||
"DirectorId": "主管",
|
||||
"DirectorSelf": "不能设置自己为主管",
|
||||
"Disable": "禁用",
|
||||
"Email": "邮箱",
|
||||
"EmailDup": "存在重复的邮箱 {0}",
|
||||
"EmailError": "邮箱 {0} 格式错误",
|
||||
"Enable": "启用",
|
||||
"ExitVerificat": "您已被强制下线",
|
||||
"GrantRole": "分配角色",
|
||||
"LastLoginAddress": "上次登录地点",
|
||||
"LastLoginDevice": "上次登录设备",
|
||||
"LastLoginIp": "上次登录ip",
|
||||
"LastLoginTime": "上次登录时间",
|
||||
"LatestLoginAddress": "最新登录地点",
|
||||
"LatestLoginDevice": "最新登录设备",
|
||||
"LatestLoginIp": "最新登录ip",
|
||||
"LatestLoginTime": "最新登录时间",
|
||||
"NoOrg": "组织机构不存在",
|
||||
"OldPasswordError": "原密码错误",
|
||||
"OrgId": "机构",
|
||||
"OrgNames": "机构名称",
|
||||
"Password": "密码",
|
||||
"PasswordEdited": "密码被修改,已退出登录",
|
||||
"PasswordLengthLess": "密码长度不能小于 {0} ",
|
||||
"PasswordMustLow": "密码必须包含小写字母",
|
||||
"PasswordMustNum": "密码必须包含数字",
|
||||
"PasswordMustSpecial": "密码必须包含特殊字符",
|
||||
"PasswordMustUpp": "密码必须包含大写字母",
|
||||
"Phone": "手机",
|
||||
"PhoneError": "手机号码 {0} 格式错误",
|
||||
"PositionId": "职位",
|
||||
"PositionName": "职位名称",
|
||||
"Status": "状态"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.TargetEnum": {
|
||||
"_self": "本窗口",
|
||||
"_blank": "新窗口",
|
||||
"_parent": "父级窗口",
|
||||
"_self": "本窗口",
|
||||
"_top": "顶级窗口"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.DictTypeEnum": {
|
||||
"System": "系统配置",
|
||||
"Define": "业务配置"
|
||||
"ThingsGateway.Admin.Application.TestController": {
|
||||
"Test": "测试",
|
||||
"TestController": "测试API"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.LogCateGoryEnum": {
|
||||
"Login": "登录",
|
||||
"Logout": "注销",
|
||||
"Operate": "操作",
|
||||
"Exception": "异常"
|
||||
"ThingsGateway.Admin.Application.UnifyResultProvider": {
|
||||
"NoPermission": "禁止访问,没有权限",
|
||||
"TokenOver": "登录已过期,请重新登录"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Application.LogEnum": {
|
||||
"SUCCESS": "成功",
|
||||
"FAIL": "失败"
|
||||
"ThingsGateway.Admin.Application.UpdatePasswordInput": {
|
||||
"ConfirmPassword": "确认密码",
|
||||
"ConfirmPassword.Required": " {0} 是必填项",
|
||||
"NewPassword": "新密码",
|
||||
"NewPassword.Required": " {0} 是必填项",
|
||||
"Password": "密码",
|
||||
"Password.Required": " {0} 是必填项"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.UserSelectorOutput": {
|
||||
"Account": "账号",
|
||||
"OrgId": "机构"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.VerificatInfo": {
|
||||
"Device": "登录设备",
|
||||
"Expire": "过期时间(分)",
|
||||
"LoginIp": "登录IP",
|
||||
"LoginTime": "登录时间",
|
||||
"Online": "在线状态",
|
||||
"VerificatTimeout": "超时时间"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.WebsitePolicy": {
|
||||
"CloseTip": "关闭提示",
|
||||
"CloseTip.Required": " {0} 是必填项",
|
||||
"WebStatus": "是否开放"
|
||||
},
|
||||
"ThingsGateway.Admin.Application.WorkbenchInfo": {
|
||||
"Razor": "主页",
|
||||
"Shortcuts": "快捷方式"
|
||||
}
|
||||
}
|
||||
}
|
@@ -37,6 +37,8 @@ internal sealed class VerificatInfoService : BaseService<VerificatInfo>, IVerifi
|
||||
|
||||
private VerificatInfo? GetFromDb(long id)
|
||||
{
|
||||
if (id == 0)
|
||||
return null;
|
||||
using var db = GetDB();
|
||||
var verificatInfo = db.Queryable<VerificatInfo>().First(u => u.Id == id);
|
||||
if (verificatInfo != null)
|
||||
|
@@ -1,74 +1,73 @@
|
||||
{
|
||||
"ThingsGateway.Admin.Razor.LoginConnectionHub": {
|
||||
"Jump": "Jump"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.UserLogin": {
|
||||
"Account": "Username",
|
||||
"Password": "Password",
|
||||
"Login": "Login"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor._Imports": {
|
||||
"Org": "Org",
|
||||
"Position": "Position",
|
||||
"Role": "Role",
|
||||
"RoleList": "Role List",
|
||||
"PositionList": "Position List",
|
||||
"OrgList": "Org List",
|
||||
"MaxCount": "Exceeding the quantity limit",
|
||||
"All": "All",
|
||||
"Copy": "Copy",
|
||||
"Choice": "Choice",
|
||||
"Picture": "Picture",
|
||||
"Root": "Root",
|
||||
"Save": "Save",
|
||||
"Copy": "Copy",
|
||||
"CurrentVerificat": "CurrentVerificat",
|
||||
"EmptyText": "Empty",
|
||||
"SelectPlaceHolder": "Please select ...",
|
||||
"ExportButtonText": "Export/Import"
|
||||
"ExportButtonText": "Export/Import",
|
||||
"MaxCount": "Exceeding the quantity limit",
|
||||
"Org": "Org",
|
||||
"OrgList": "Org List",
|
||||
"Picture": "Picture",
|
||||
"Position": "Position",
|
||||
"PositionList": "Position List",
|
||||
"Role": "Role",
|
||||
"RoleList": "Role List",
|
||||
"Root": "Root",
|
||||
"Save": "Save",
|
||||
"SelectPlaceHolder": "Please select ..."
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.ChoiceModuleComponent": {
|
||||
"SetDefaultModule": "Set as default module"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Razor.HardwareInfoPage": {
|
||||
"SystemInfo": "System Information",
|
||||
"AvailableDisk": "Available Disk",
|
||||
"AvailableMemory": "Available Memory",
|
||||
"CpuUsage": "CPU Usage",
|
||||
"Data": "Data",
|
||||
"DateTime": "Date Time",
|
||||
"DiskUsage": "Disk Usage",
|
||||
"HardwareInfo": "Hardware Resources",
|
||||
"HardwareInfoChart": "Hardware Resources History Chart",
|
||||
"CpuUsage": "CPU Usage",
|
||||
"AvailableMemory": "Available Memory",
|
||||
"TotalMemory": "Total Memory",
|
||||
"WorkingSet": "WorkingSet",
|
||||
"MemoryUsage": "Memory",
|
||||
"AvailableDisk": "Available Disk",
|
||||
"TotalDisk": "Total Disk",
|
||||
"DiskUsage": "Disk Usage",
|
||||
"HistoryHardwareInfo": "Historical Trends",
|
||||
"DateTime": "Date Time",
|
||||
"Data": "Data",
|
||||
"MemoryUsage": "Memory",
|
||||
"OSName": "OS Name",
|
||||
"OSVersion": "OS Version"
|
||||
"OSVersion": "OS Version",
|
||||
"SystemInfo": "System Information",
|
||||
"TotalDisk": "Total Disk",
|
||||
"TotalMemory": "Total Memory",
|
||||
"WorkingSet": "WorkingSet"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.LoginConnectionHub": {
|
||||
"Jump": "Jump"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.OperLogPage": {
|
||||
"Date": "Date",
|
||||
"Count": "Count",
|
||||
"Operate": "Succeed",
|
||||
"Date": "Date",
|
||||
"Exception": "Failed",
|
||||
"Login": "Login",
|
||||
"Logout": "Logout",
|
||||
"Operate": "Succeed",
|
||||
"SysOperateLog": "Operation Log"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.SessionPage": {
|
||||
"VerificatInfo": "Token List",
|
||||
"ExitSession": "Force Logout"
|
||||
"ExitSession": "Force Logout",
|
||||
"VerificatInfo": "Token List"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.UserCenterPage": {
|
||||
"UpdatePasswordInfo": "Change Password",
|
||||
"UpdateUserInfo": "Update Personal Information",
|
||||
"UpdateWorkbenchInfo": "Update Personal Workbench",
|
||||
"UserInfo": "Personal Information",
|
||||
"WorkbenchInfo": "Personal Workbench"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.UserLogin": {
|
||||
"Account": "Username",
|
||||
"Login": "Login",
|
||||
"Password": "Password"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.VerificatListDialog": {
|
||||
"ExitVerificat": "Force Logout Token"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.UserCenterPage": {
|
||||
"UpdateUserInfo": "Update Personal Information",
|
||||
"UserInfo": "Personal Information",
|
||||
"UpdatePasswordInfo": "Change Password",
|
||||
"UpdateWorkbenchInfo": "Update Personal Workbench",
|
||||
"WorkbenchInfo": "Personal Workbench"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,74 +1,73 @@
|
||||
{
|
||||
"ThingsGateway.Admin.Razor.LoginConnectionHub": {
|
||||
"Jump": "跳转"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.UserLogin": {
|
||||
"Account": "登录账号",
|
||||
"Password": "登录密码",
|
||||
"Login": "登录"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor._Imports": {
|
||||
"All": "全部",
|
||||
"Choice": "选择",
|
||||
"Copy": "复制",
|
||||
"CurrentVerificat": "当前令牌",
|
||||
"EmptyText": "空",
|
||||
"ExportButtonText": "导出/导入",
|
||||
"MaxCount": "超过数量限制",
|
||||
"Org": "机构",
|
||||
"OrgList": "机构列表",
|
||||
"Picture": "头像",
|
||||
"Position": "岗位",
|
||||
"PositionList": "岗位列表",
|
||||
"Role": "角色",
|
||||
"RoleList": "角色列表",
|
||||
"PositionList": "岗位列表",
|
||||
"OrgList": "机构列表",
|
||||
"MaxCount": "超过数量限制",
|
||||
"All": "全部",
|
||||
"Copy": "复制",
|
||||
"Choice": "选择",
|
||||
"Picture": "头像",
|
||||
"Root": "根目录",
|
||||
"Save": "保存",
|
||||
"CurrentVerificat": "当前令牌",
|
||||
"SelectPlaceHolder": "请选择 ...",
|
||||
"EmptyText": "空",
|
||||
"ExportButtonText": "导出/导入"
|
||||
"SelectPlaceHolder": "请选择 ..."
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.ChoiceModuleComponent": {
|
||||
"SetDefaultModule": "设置为默认模块"
|
||||
},
|
||||
|
||||
"ThingsGateway.Admin.Razor.HardwareInfoPage": {
|
||||
"SystemInfo": "系统信息",
|
||||
"AvailableDisk": "可用磁盘",
|
||||
"AvailableMemory": "可用内存",
|
||||
"CpuUsage": "CPU使用率",
|
||||
"Data": "数据",
|
||||
"DateTime": "时间",
|
||||
"DiskUsage": "磁盘使用率",
|
||||
"HardwareInfo": "硬件资源",
|
||||
"HardwareInfoChart": "硬件资源历史曲线",
|
||||
"CpuUsage": "CPU使用率",
|
||||
"AvailableMemory": "可用内存",
|
||||
"TotalMemory": "总内存",
|
||||
"WorkingSet": "进程内存",
|
||||
"MemoryUsage": "内存",
|
||||
"AvailableDisk": "可用磁盘",
|
||||
"TotalDisk": "总磁盘",
|
||||
"DiskUsage": "磁盘使用率",
|
||||
"HistoryHardwareInfo": "历史曲线",
|
||||
"DateTime": "时间",
|
||||
"Data": "数据",
|
||||
"MemoryUsage": "内存",
|
||||
"OSName": "系统名称",
|
||||
"OSVersion": "系统版本"
|
||||
"OSVersion": "系统版本",
|
||||
"SystemInfo": "系统信息",
|
||||
"TotalDisk": "总磁盘",
|
||||
"TotalMemory": "总内存",
|
||||
"WorkingSet": "进程内存"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.LoginConnectionHub": {
|
||||
"Jump": "跳转"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.OperLogPage": {
|
||||
"Date": "日期",
|
||||
"Count": "数量",
|
||||
"Operate": "成功",
|
||||
"Date": "日期",
|
||||
"Exception": "失败",
|
||||
"Login": "登录",
|
||||
"Logout": "注销",
|
||||
"Operate": "成功",
|
||||
"SysOperateLog": "操作日志"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.SessionPage": {
|
||||
"VerificatInfo": "令牌列表",
|
||||
"ExitSession": "强退会话"
|
||||
"ExitSession": "强退会话",
|
||||
"VerificatInfo": "令牌列表"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.UserCenterPage": {
|
||||
"UpdatePasswordInfo": "修改密码",
|
||||
"UpdateUserInfo": "更新个人信息",
|
||||
"UpdateWorkbenchInfo": "更新个人工作台",
|
||||
"UserInfo": "个人信息",
|
||||
"WorkbenchInfo": "个人工作台"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.UserLogin": {
|
||||
"Account": "登录账号",
|
||||
"Login": "登录",
|
||||
"Password": "登录密码"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.VerificatListDialog": {
|
||||
"ExitVerificat": "强退令牌"
|
||||
},
|
||||
"ThingsGateway.Admin.Razor.UserCenterPage": {
|
||||
"UpdateUserInfo": "更新个人信息",
|
||||
"UserInfo": "个人信息",
|
||||
"UpdatePasswordInfo": "修改密码",
|
||||
"UpdateWorkbenchInfo": "更新个人工作台",
|
||||
"WorkbenchInfo": "个人工作台"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,81 +1,77 @@
|
||||
{
|
||||
"ThingsGateway.AdminServer.NotFound404": {
|
||||
"404": "Sorry, the page you are looking for does not exist.",
|
||||
"401": "Sorry, you do not have permission to access this page.",
|
||||
"Home": "Back to Home",
|
||||
"Login": "Login"
|
||||
"ThingsGateway.AdminServer.AdminIndex": {
|
||||
"Alarm": "Real-time Alarm",
|
||||
"AlarmCount": "Alarm Count",
|
||||
"BackendLog": "Gateway Backend Log",
|
||||
"BusinessDevice": "Business Device",
|
||||
"CollectDevice": "Collect Device",
|
||||
"Data": "Data",
|
||||
"DateTime": "Date Time",
|
||||
"HardwareInfoChart": "Hardware Information Historical Chart",
|
||||
"HistoryHardwareInfo": "Historical Chart",
|
||||
"OffLine": "Offline",
|
||||
"OnLine": "Online",
|
||||
"OperLog": "Recent Operations",
|
||||
"RpcLog": "Gateway RPC Log",
|
||||
"Shortcuts": "Shortcuts",
|
||||
"Variable": "Variable"
|
||||
},
|
||||
"ThingsGateway.AdminServer.Login": {
|
||||
"LoginErrorh1": "Login Error",
|
||||
"LoginSuccessh1": "Login Success",
|
||||
"LoginSuccessc1": "Redirecting to the page",
|
||||
"LoginErrorh2": "Login Failed",
|
||||
"LoginErrorc2": "Please contact the administrator!",
|
||||
"LoginErrorh1": "Login Error",
|
||||
"LoginErrorh2": "Login Failed",
|
||||
"LoginSuccessc1": "Redirecting to the page",
|
||||
"LoginSuccessh1": "Login Success",
|
||||
"Remark1": "Admin",
|
||||
"Remark2": "",
|
||||
"Remark3": "Permission Framework Based on BlazorServer",
|
||||
"Welcome": "Welcome"
|
||||
},
|
||||
|
||||
"ThingsGateway.AdminServer.MainLayout": {
|
||||
"About": "About",
|
||||
"FullScreenButton": "Full Screen",
|
||||
"UserCenter": "User Center",
|
||||
"ChoiceModule": "Switch Module",
|
||||
|
||||
"LoginErrorh1": "Login Error",
|
||||
"LoginSuccessh1": "Login Success",
|
||||
"LoginSuccessc1": "Redirecting to the page",
|
||||
"LoginErrorh2": "Login Failed",
|
||||
"LoginErrorc2": "Please contact the administrator!",
|
||||
"Logout": "Logout",
|
||||
|
||||
"系统首页": "Home",
|
||||
"权限管理": "Permission",
|
||||
"用户管理": "User",
|
||||
"角色管理": "Role",
|
||||
"菜单管理": "Menu",
|
||||
"机构管理": "Organization",
|
||||
"职位管理": "Position",
|
||||
"系统运维": "SystemOperation",
|
||||
"系统配置": "System",
|
||||
"字典管理": "Dictionary",
|
||||
"操作日志": "Operation",
|
||||
"会话管理": "Session",
|
||||
"硬件信息": "HardwareInfo",
|
||||
"网关管理": "GatewayManagement",
|
||||
"插件管理": "PluginManagement",
|
||||
"插件调试": "PluginDebugging",
|
||||
"通道管理": "Channel",
|
||||
"采集设备": "CollectionDevices",
|
||||
"业务设备": "BusinessDevices",
|
||||
"变量管理": "Variable",
|
||||
"网关状态": "GatewayStatus",
|
||||
"设备状态": "Device",
|
||||
"实时数据": "RealTimeData",
|
||||
"实时报警": "RealTimeAlarms",
|
||||
"网关日志": "GatewayLogs",
|
||||
"采集设备": "CollectionDevices",
|
||||
"菜单管理": "Menu",
|
||||
"操作日志": "Operation",
|
||||
"插件调试": "PluginDebugging",
|
||||
"插件管理": "PluginManagement",
|
||||
"后台日志": "Backend",
|
||||
"RPC日志": "RPC",
|
||||
"会话管理": "Session",
|
||||
"机构管理": "Organization",
|
||||
"角色管理": "Role",
|
||||
"权限管理": "Permission",
|
||||
"设备状态": "Device",
|
||||
"实时报警": "RealTimeAlarms",
|
||||
"实时数据": "RealTimeData",
|
||||
"通道管理": "Channel",
|
||||
"网关管理": "GatewayManagement",
|
||||
"网关日志": "GatewayLogs",
|
||||
"网关状态": "GatewayStatus",
|
||||
"物联网关": "Gateway",
|
||||
"系统管理": "Admin"
|
||||
"系统管理": "Admin",
|
||||
"系统配置": "System",
|
||||
"系统首页": "Home",
|
||||
"系统运维": "SystemOperation",
|
||||
"业务设备": "BusinessDevices",
|
||||
"硬件信息": "HardwareInfo",
|
||||
"用户管理": "User",
|
||||
"职位管理": "Position",
|
||||
"字典管理": "Dictionary",
|
||||
"About": "About",
|
||||
"ChoiceModule": "Switch Module",
|
||||
"FullScreenButton": "Full Screen",
|
||||
"LoginErrorc2": "Please contact the administrator!",
|
||||
"LoginErrorh1": "Login Error",
|
||||
"LoginErrorh2": "Login Failed",
|
||||
"LoginSuccessc1": "Redirecting to the page",
|
||||
"LoginSuccessh1": "Login Success",
|
||||
"Logout": "Logout",
|
||||
"RPC日志": "RPC",
|
||||
"UserCenter": "User Center"
|
||||
},
|
||||
|
||||
"ThingsGateway.AdminServer.AdminIndex": {
|
||||
"CollectDevice": "Collect Device",
|
||||
"BusinessDevice": "Business Device",
|
||||
"Variable": "Variable",
|
||||
"Alarm": "Real-time Alarm",
|
||||
"AlarmCount": "Alarm Count",
|
||||
"OnLine": "Online",
|
||||
"OffLine": "Offline",
|
||||
"Shortcuts": "Shortcuts",
|
||||
"OperLog": "Recent Operations",
|
||||
"BackendLog": "Gateway Backend Log",
|
||||
"RpcLog": "Gateway RPC Log",
|
||||
"HardwareInfoChart": "Hardware Information Historical Chart",
|
||||
"DateTime": "Date Time",
|
||||
"Data": "Data",
|
||||
"HistoryHardwareInfo": "Historical Chart"
|
||||
"ThingsGateway.AdminServer.NotFound404": {
|
||||
"401": "Sorry, you do not have permission to access this page.",
|
||||
"404": "Sorry, the page you are looking for does not exist.",
|
||||
"Home": "Back to Home",
|
||||
"Login": "Login"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,85 +1,77 @@
|
||||
{
|
||||
|
||||
"ThingsGateway.AdminServer.NotFound404": {
|
||||
"404": "抱歉,您访问的页面不存在。",
|
||||
"401": "抱歉,您无权限访问该页面。",
|
||||
"Home": "回到首页",
|
||||
"Login": "重新登录"
|
||||
"ThingsGateway.AdminServer.AdminIndex": {
|
||||
"Alarm": "实时报警",
|
||||
"AlarmCount": "报警数量",
|
||||
"BackendLog": "网关后台日志",
|
||||
"BusinessDevice": "业务设备",
|
||||
"CollectDevice": "采集设备",
|
||||
"Data": "数据",
|
||||
"DateTime": "时间",
|
||||
"HardwareInfoChart": "硬件信息历史曲线",
|
||||
"HistoryHardwareInfo": "历史曲线",
|
||||
"OffLine": "离线",
|
||||
"OnLine": "在线",
|
||||
"OperLog": "最近操作",
|
||||
"RpcLog": "网关RPC日志",
|
||||
"Shortcuts": "快捷方式",
|
||||
"Variable": "变量"
|
||||
},
|
||||
"ThingsGateway.AdminServer.Login": {
|
||||
"LoginErrorh1": "登录异常",
|
||||
"LoginSuccessh1": "登录成功",
|
||||
"LoginSuccessc1": "即将跳转页面",
|
||||
"LoginErrorh2": "登录失败",
|
||||
"LoginErrorc2": "请联系管理员!",
|
||||
"LoginErrorh1": "登录异常",
|
||||
"LoginErrorh2": "登录失败",
|
||||
"LoginSuccessc1": "即将跳转页面",
|
||||
"LoginSuccessh1": "登录成功",
|
||||
"Remark1": "后台管理",
|
||||
"Remark2": "",
|
||||
"Remark3": "基于BlazorServer的权限框架",
|
||||
"Welcome": "欢迎使用"
|
||||
},
|
||||
|
||||
|
||||
"ThingsGateway.AdminServer.MainLayout": {
|
||||
"About": "关于",
|
||||
"FullScreenButton": "全屏",
|
||||
"UserCenter": "个人中心",
|
||||
"ChoiceModule": "切换模块",
|
||||
|
||||
"LoginErrorh1": "登录异常",
|
||||
"LoginSuccessh1": "登录成功",
|
||||
"LoginSuccessc1": "即将跳转页面",
|
||||
"LoginErrorh2": "登录失败",
|
||||
"LoginErrorc2": "请联系管理员!",
|
||||
"Logout": "注销",
|
||||
|
||||
"系统首页": "系统首页",
|
||||
"权限管理": "权限管理",
|
||||
"用户管理": "用户管理",
|
||||
"角色管理": "角色管理",
|
||||
"菜单管理": "菜单管理",
|
||||
"机构管理": "机构管理",
|
||||
"职位管理": "职位管理",
|
||||
"系统运维": "系统运维",
|
||||
"系统配置": "系统配置",
|
||||
"字典管理": "字典管理",
|
||||
"操作日志": "操作日志",
|
||||
"会话管理": "会话管理",
|
||||
"硬件信息": "硬件信息",
|
||||
"网关管理": "网关管理",
|
||||
"插件管理": "插件管理",
|
||||
"插件调试": "插件调试",
|
||||
"通道管理": "通道管理",
|
||||
"采集设备": "采集设备",
|
||||
"业务设备": "业务设备",
|
||||
"变量管理": "变量管理",
|
||||
"网关状态": "网关状态",
|
||||
"设备状态": "设备状态",
|
||||
"实时数据": "实时数据",
|
||||
"实时报警": "实时报警",
|
||||
"网关日志": "网关日志",
|
||||
"采集设备": "采集设备",
|
||||
"菜单管理": "菜单管理",
|
||||
"操作日志": "操作日志",
|
||||
"插件调试": "插件调试",
|
||||
"插件管理": "插件管理",
|
||||
"后台日志": "后台日志",
|
||||
"RPC日志": "RPC日志",
|
||||
"会话管理": "会话管理",
|
||||
"机构管理": "机构管理",
|
||||
"角色管理": "角色管理",
|
||||
"权限管理": "权限管理",
|
||||
"设备状态": "设备状态",
|
||||
"实时报警": "实时报警",
|
||||
"实时数据": "实时数据",
|
||||
"通道管理": "通道管理",
|
||||
"网关管理": "网关管理",
|
||||
"网关日志": "网关日志",
|
||||
"网关状态": "网关状态",
|
||||
"物联网关": "物联网关",
|
||||
"系统管理": "系统管理"
|
||||
"系统管理": "系统管理",
|
||||
"系统配置": "系统配置",
|
||||
"系统首页": "系统首页",
|
||||
"系统运维": "系统运维",
|
||||
"业务设备": "业务设备",
|
||||
"硬件信息": "硬件信息",
|
||||
"用户管理": "用户管理",
|
||||
"职位管理": "职位管理",
|
||||
"字典管理": "字典管理",
|
||||
"About": "关于",
|
||||
"ChoiceModule": "切换模块",
|
||||
"FullScreenButton": "全屏",
|
||||
"LoginErrorc2": "请联系管理员!",
|
||||
"LoginErrorh1": "登录异常",
|
||||
"LoginErrorh2": "登录失败",
|
||||
"LoginSuccessc1": "即将跳转页面",
|
||||
"LoginSuccessh1": "登录成功",
|
||||
"Logout": "注销",
|
||||
"RPC日志": "RPC日志",
|
||||
"UserCenter": "个人中心"
|
||||
},
|
||||
|
||||
|
||||
"ThingsGateway.AdminServer.AdminIndex": {
|
||||
"CollectDevice": "采集设备",
|
||||
"BusinessDevice": "业务设备",
|
||||
"Variable": "变量",
|
||||
"Alarm": "实时报警",
|
||||
"AlarmCount": "报警数量",
|
||||
"OnLine": "在线",
|
||||
"OffLine": "离线",
|
||||
"Shortcuts": "快捷方式",
|
||||
"OperLog": "最近操作",
|
||||
"BackendLog": "网关后台日志",
|
||||
"RpcLog": "网关RPC日志",
|
||||
"HardwareInfoChart": "硬件信息历史曲线",
|
||||
"DateTime": "时间",
|
||||
"Data": "数据",
|
||||
"HistoryHardwareInfo": "历史曲线"
|
||||
"ThingsGateway.AdminServer.NotFound404": {
|
||||
"401": "抱歉,您无权限访问该页面。",
|
||||
"404": "抱歉,您访问的页面不存在。",
|
||||
"Home": "回到首页",
|
||||
"Login": "重新登录"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -3,11 +3,11 @@
|
||||
<Button OnClick="() => step.Reset()">@Localizer["Reset"]</Button>
|
||||
<h6 class="my-3 green--text">@Localizer["Tip"] </h6>
|
||||
<Step @ref="@step" IsVertical="true">
|
||||
<StepItem Text=@Localizer[ "First"] Title=@Localizer["Upload"]>
|
||||
<StepItem Text=@Localizer["First"] Title=@Localizer["Upload"]>
|
||||
<InputUpload ShowDeleteButton="true" @bind-Value=_importFile Accept=".xlsx"></InputUpload>
|
||||
<Button class="mt-2" IsAsync OnClick="() => DeviceImport(_importFile)">@Localizer["Validate"]</Button>
|
||||
</StepItem>
|
||||
<StepItem Text=@Localizer[ "Second"] Title=@Localizer[ "ValidateText"]>
|
||||
<StepItem Text=@Localizer["Second"] Title=@Localizer["ValidateText"]>
|
||||
|
||||
<div class="overflow-y-auto">
|
||||
|
||||
@@ -15,22 +15,22 @@
|
||||
{
|
||||
<div class="mt-2">
|
||||
@(
|
||||
Localizer["UploadCount", item.Key, item.Value.DataCount]
|
||||
)
|
||||
Localizer["UploadCount", item.Key, item.Value.DataCount]
|
||||
)
|
||||
</div>
|
||||
<div class=@((item.Value.HasError?"my-2 red--text":"my-2 green--text"))>
|
||||
<div class=@((item.Value.HasError ? "my-2 red--text" : "my-2 green--text"))>
|
||||
@(
|
||||
(item.Value.HasError ? "Error" : "Success")
|
||||
)
|
||||
</div>
|
||||
if (item.Value.HasError)
|
||||
(item.Value.HasError ? "Error" : "Success")
|
||||
)
|
||||
</div>
|
||||
if (item.Value.HasError)
|
||||
{
|
||||
<div style="height:300px;" class="overflow-y-scroll">
|
||||
<Virtualize Items="item.Value.Results.Where(a=>!a.Success).OrderBy(a=>a.Row).ToList()" Context="item1" ItemSize="60" OverscanCount=2>
|
||||
<Virtualize Items="item.Value.Results.Where(a => !a.Success).OrderBy(a => a.Row).ToList()" Context="item1" ItemSize="60" OverscanCount=2>
|
||||
<ItemContent>
|
||||
<div class="row g-0">
|
||||
<span class="col mx-2">@item1.Row</span>
|
||||
<span class=@((item1.Success?"green--text col-auto":"red--text col-auto"))>
|
||||
<span class=@((item1.Success ? "green--text col-auto" : "red--text col-auto"))>
|
||||
<strong>@item1.ErrorMessage</strong>
|
||||
</span>
|
||||
</div>
|
||||
@@ -42,15 +42,15 @@
|
||||
}
|
||||
|
||||
|
||||
<Button IsAsync class="mt-2" IsDisabled=@_importPreviews.Any(it=>it.Value.HasError) OnClick="() => step.Next()">@Localizer["Next"]</Button>
|
||||
<Button IsAsync class="mt-2" IsDisabled=@_importPreviews.Any(it => it.Value.HasError) OnClick="() => step.Next()">@Localizer["Next"]</Button>
|
||||
|
||||
</div>
|
||||
</StepItem>
|
||||
<StepItem Text=@Localizer[ "Third"] Title=@Localizer[ "Import"]>
|
||||
<StepItem Text=@Localizer["Third"] Title=@Localizer["Import"]>
|
||||
<PopConfirmButton IsAsync Color=Color.Warning class="mt-2" OnConfirm=@(SaveDeviceImport)>@Localizer["Import"]</PopConfirmButton>
|
||||
</StepItem>
|
||||
</Step>
|
||||
@code {
|
||||
[NotNull]
|
||||
Step? step{ get; set; }
|
||||
Step? step { get; set; }
|
||||
}
|
||||
|
@@ -1,73 +1,46 @@
|
||||
{
|
||||
|
||||
"ThingsGateway.Razor.ImportExcel": {
|
||||
"First": "Step 1",
|
||||
"Upload": "Upload File",
|
||||
"Validate": "Validate",
|
||||
"Second": "Step 2",
|
||||
"ValidateText": "Validation Content",
|
||||
"UploadCount": " Table {0}, expecting to import {1} records",
|
||||
"Third": "Step 3",
|
||||
"Import": "Import",
|
||||
"Next": "Next",
|
||||
"Reset": "Reset",
|
||||
"Tip": "When the data volume is large (more than 200,000), the import may take more than 1 minute, please be patient"
|
||||
},
|
||||
"ThingsGateway.Razor._Imports": {
|
||||
"Refresh": "Refresh",
|
||||
"CloseOther": "CloseOther",
|
||||
"CloseAll": "CloseAll",
|
||||
"Copy": "Copy",
|
||||
"Add": "Add",
|
||||
"Remove": "Remove",
|
||||
"BatchEdit": "BacthEdit",
|
||||
"Edit": "Edit",
|
||||
"Close": "Close",
|
||||
"True": "Yes",
|
||||
"False": "No",
|
||||
"Save": "Save",
|
||||
"Fail": "Fail {0}",
|
||||
"Clear": "Clear",
|
||||
"Success": "Success",
|
||||
"PleaseSelect": "Please select the data",
|
||||
"TablesExportButtonExcelText": "Export Excel",
|
||||
"TablesImportButtonExcelText": "Import Excel",
|
||||
"Choice": "Select",
|
||||
"Clear": "Clear",
|
||||
"Close": "Close",
|
||||
"CloseAll": "CloseAll",
|
||||
"CloseOther": "CloseOther",
|
||||
"Copy": "Copy",
|
||||
"Delete": "Delete",
|
||||
"Disabled": "Disabled",
|
||||
"Edit": "Edit",
|
||||
"Enable": "Enable",
|
||||
"Export": "Export",
|
||||
"ExportAll": "ExportAll",
|
||||
"Fail": "Fail {0}",
|
||||
"False": "No",
|
||||
"Pause": "Pause",
|
||||
"Play": "Play",
|
||||
"Enable": "Enable",
|
||||
"Disabled": "Disabled",
|
||||
"Export": "Export",
|
||||
"Delete": "Delete",
|
||||
"ExportAll": "ExportAll"
|
||||
},
|
||||
"ThingsGateway.Razor.GlobalSearch": {
|
||||
"SearchText": "Search Page"
|
||||
},
|
||||
"ThingsGateway.Razor.MenuIconList": {
|
||||
"ChoiceIcon": "Icon for Selection"
|
||||
},
|
||||
"ThingsGateway.Razor.CommitItem": {
|
||||
"CommitCount": "Total {0} commits",
|
||||
"Author": "Author??",
|
||||
"Branch": "Branch name??",
|
||||
"Message": "Commit message??"
|
||||
"PleaseSelect": "Please select the data",
|
||||
"Refresh": "Refresh",
|
||||
"Remove": "Remove",
|
||||
"Save": "Save",
|
||||
"Success": "Success",
|
||||
"TablesExportButtonExcelText": "Export Excel",
|
||||
"TablesImportButtonExcelText": "Import Excel",
|
||||
"True": "Yes"
|
||||
},
|
||||
"ThingsGateway.Razor.About": {
|
||||
"Docs": "Docs",
|
||||
"Community": "Community",
|
||||
"Docs": "Docs",
|
||||
"QQGroup": "QQGroup"
|
||||
|
||||
},
|
||||
"ThingsGateway.Razor.BlazorReconnector": {
|
||||
"Reconnecting1": "Reconnecting...",
|
||||
"Reconnecting2": "Attempting to reconnect to the server",
|
||||
"Reconnecting3": "The server is updating to a new version, please wait for a moment to provide service, or press <kbd>F12</kbd> to open <b>Developer tools</b> and check the <b>Console</b> for error output, please contact the administrator",
|
||||
"ReconnectFailed1": "Reconnecting...",
|
||||
"ReconnectFailed2": "Failed to connect to the server",
|
||||
"ReconnectFailed3": "Please check if the network is normal, or press <kbd>F12</kbd> to open <b>Developer tools</b> and check the <b>Console</b> for error output, please contact the administrator",
|
||||
"ReconnectFailed4": "Reconnect",
|
||||
"ReconnectFailed5": "Reload",
|
||||
"Reconnecting1": "Reconnecting...",
|
||||
"Reconnecting2": "Attempting to reconnect to the server",
|
||||
"Reconnecting3": "The server is updating to a new version, please wait for a moment to provide service, or press <kbd>F12</kbd> to open <b>Developer tools</b> and check the <b>Console</b> for error output, please contact the administrator",
|
||||
"ReconnectRejected1": "Reconnecting...",
|
||||
"ReconnectRejected2": "Server rejected the connection",
|
||||
"ReconnectRejected3": "All connection attempts have been rejected, this is likely due to network or server issues, please contact the administrator",
|
||||
@@ -75,5 +48,30 @@
|
||||
"RenderThingsGateway1": "ThingsGateway Edge Collection Gateway",
|
||||
"RenderThingsGateway2": "Data aggregation, multi-path forwarding",
|
||||
"RenderThingsGateway3": "Edge computing, efficient processing"
|
||||
},
|
||||
"ThingsGateway.Razor.CommitItem": {
|
||||
"Author": "Author??",
|
||||
"Branch": "Branch name??",
|
||||
"CommitCount": "Total {0} commits",
|
||||
"Message": "Commit message??"
|
||||
},
|
||||
"ThingsGateway.Razor.GlobalSearch": {
|
||||
"SearchText": "Search Page"
|
||||
},
|
||||
"ThingsGateway.Razor.ImportExcel": {
|
||||
"First": "Step 1",
|
||||
"Import": "Import",
|
||||
"Next": "Next",
|
||||
"Reset": "Reset",
|
||||
"Second": "Step 2",
|
||||
"Third": "Step 3",
|
||||
"Tip": "When the data volume is large (more than 200,000), the import may take more than 1 minute, please be patient",
|
||||
"Upload": "Upload File",
|
||||
"UploadCount": " Table {0}, expecting to import {1} records",
|
||||
"Validate": "Validate",
|
||||
"ValidateText": "Validation Content"
|
||||
},
|
||||
"ThingsGateway.Razor.MenuIconList": {
|
||||
"ChoiceIcon": "Icon for Selection"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,73 +1,46 @@
|
||||
{
|
||||
|
||||
"ThingsGateway.Razor.ImportExcel": {
|
||||
"First": "第一步",
|
||||
"Upload": "上传文件",
|
||||
"Validate": "验证",
|
||||
"Second": "第二步",
|
||||
"ValidateText": "验证内容",
|
||||
"UploadCount": " 表 {0},预计导入 {1} 条数据",
|
||||
"Third": "第三",
|
||||
"Import": "导入",
|
||||
"Next": "下一步",
|
||||
"Reset": "重置",
|
||||
"Tip": "数据量较大时(大于20万),所需导入时间可能超过1分钟,请耐心等待"
|
||||
},
|
||||
"ThingsGateway.Razor._Imports": {
|
||||
"Refresh": "刷新",
|
||||
"CloseOther": "关闭其他",
|
||||
"CloseAll": "关闭全部",
|
||||
"Copy": "复制",
|
||||
"Add": "添加",
|
||||
"Remove": "移除",
|
||||
"BatchEdit": "批量编辑",
|
||||
"Edit": "编辑",
|
||||
"Close": "关闭",
|
||||
"True": "是",
|
||||
"False": "否",
|
||||
"Save": "保存",
|
||||
"Fail": "失败 {0}",
|
||||
"Clear": "清空",
|
||||
"Success": "成功",
|
||||
"PleaseSelect": "请选择需要操作的数据",
|
||||
"TablesExportButtonExcelText": "导出Excel",
|
||||
"TablesImportButtonExcelText": "导入Excel",
|
||||
"Choice": "选择",
|
||||
"Pause": "暂停",
|
||||
"Play": "继续",
|
||||
"Enable": "启用",
|
||||
"Clear": "清空",
|
||||
"Close": "关闭",
|
||||
"CloseAll": "关闭全部",
|
||||
"CloseOther": "关闭其他",
|
||||
"Copy": "复制",
|
||||
"Delete": "删除",
|
||||
"Disabled": "停用",
|
||||
"Edit": "编辑",
|
||||
"Enable": "启用",
|
||||
"Export": "导出",
|
||||
"ExportAll": "导出全部",
|
||||
"Delete": "删除"
|
||||
},
|
||||
"ThingsGateway.Razor.GlobalSearch": {
|
||||
"SearchText": "搜索页面"
|
||||
},
|
||||
"ThingsGateway.Razor.MenuIconList": {
|
||||
"ChoiceIcon": "选择图标"
|
||||
},
|
||||
"ThingsGateway.Razor.CommitItem": {
|
||||
"CommitCount": "共 {0} 个提交",
|
||||
"Author": "提交作者:",
|
||||
"Branch": "分支名称:",
|
||||
"Message": "提交信息:"
|
||||
"Fail": "失败 {0}",
|
||||
"False": "否",
|
||||
"Pause": "暂停",
|
||||
"Play": "继续",
|
||||
"PleaseSelect": "请选择需要操作的数据",
|
||||
"Refresh": "刷新",
|
||||
"Remove": "移除",
|
||||
"Save": "保存",
|
||||
"Success": "成功",
|
||||
"TablesExportButtonExcelText": "导出Excel",
|
||||
"TablesImportButtonExcelText": "导入Excel",
|
||||
"True": "是"
|
||||
},
|
||||
"ThingsGateway.Razor.About": {
|
||||
"Docs": "文档",
|
||||
"Community": "社区",
|
||||
"Docs": "文档",
|
||||
"QQGroup": "QQ群"
|
||||
|
||||
},
|
||||
"ThingsGateway.Razor.BlazorReconnector": {
|
||||
"Reconnecting1": "重连中...",
|
||||
"Reconnecting2": "正在尝试重新连接服务器",
|
||||
"Reconnecting3": "服务器正在更新新版本,稍等一会儿即可提供服务,或者 <kbd>F12</kbd> 打开 <b>Developer tools</b> 查看 <b>控制台</b> 是否有错误输出,请与管理员联系",
|
||||
"ReconnectFailed1": "重连中...",
|
||||
"ReconnectFailed2": "与服务器连接失败",
|
||||
"ReconnectFailed3": "请确认网络是否正常,或者 <kbd>F12</kbd> 打开 <b>Developer tools</b> 查看 <b>控制台</b> 是否有错误输出,请与管理员联系",
|
||||
"ReconnectFailed4": "重新连接",
|
||||
"ReconnectFailed5": "重新加载",
|
||||
"Reconnecting1": "重连中...",
|
||||
"Reconnecting2": "正在尝试重新连接服务器",
|
||||
"Reconnecting3": "服务器正在更新新版本,稍等一会儿即可提供服务,或者 <kbd>F12</kbd> 打开 <b>Developer tools</b> 查看 <b>控制台</b> 是否有错误输出,请与管理员联系",
|
||||
"ReconnectRejected1": "重连中...",
|
||||
"ReconnectRejected2": "服务器拒绝连接",
|
||||
"ReconnectRejected3": "所有的连接尝试都被拒绝了,这很有可能是由于网络问题或者服务器问题引起的,请与管理员联系",
|
||||
@@ -75,5 +48,30 @@
|
||||
"RenderThingsGateway1": "ThingsGateway 边缘采集网关",
|
||||
"RenderThingsGateway2": "数据集中,多路转发",
|
||||
"RenderThingsGateway3": "边缘计算,高效处理"
|
||||
},
|
||||
"ThingsGateway.Razor.CommitItem": {
|
||||
"Author": "提交作者:",
|
||||
"Branch": "分支名称:",
|
||||
"CommitCount": "共 {0} 个提交",
|
||||
"Message": "提交信息:"
|
||||
},
|
||||
"ThingsGateway.Razor.GlobalSearch": {
|
||||
"SearchText": "搜索页面"
|
||||
},
|
||||
"ThingsGateway.Razor.ImportExcel": {
|
||||
"First": "第一步",
|
||||
"Import": "导入",
|
||||
"Next": "下一步",
|
||||
"Reset": "重置",
|
||||
"Second": "第二步",
|
||||
"Third": "第三",
|
||||
"Tip": "数据量较大时(大于20万),所需导入时间可能超过1分钟,请耐心等待",
|
||||
"Upload": "上传文件",
|
||||
"UploadCount": " 表 {0},预计导入 {1} 条数据",
|
||||
"Validate": "验证",
|
||||
"ValidateText": "验证内容"
|
||||
},
|
||||
"ThingsGateway.Razor.MenuIconList": {
|
||||
"ChoiceIcon": "选择图标"
|
||||
}
|
||||
}
|
||||
}
|
725
src/Admin/ThingsGateway.Razor/Localization/Json/CacheManager.cs
Normal file
725
src/Admin/ThingsGateway.Razor/Localization/Json/CacheManager.cs
Normal file
@@ -0,0 +1,725 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the Apache 2.0 License
|
||||
// See the LICENSE file in the project root for more information.
|
||||
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
using System.Collections.Frozen;
|
||||
#endif
|
||||
|
||||
namespace ThingsGateway;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存操作类
|
||||
/// </summary>
|
||||
internal class CacheManager
|
||||
{
|
||||
private IMemoryCache Cache { get; set; }
|
||||
|
||||
private IServiceProvider Provider { get; set; }
|
||||
|
||||
[NotNull]
|
||||
private static CacheManager? Instance { get; set; }
|
||||
|
||||
[NotNull]
|
||||
internal static BootstrapBlazorOptions? Options { get; private set; }
|
||||
|
||||
private const string CacheKeyPrefix = "ThingsGateway.BootstrapBlazor";
|
||||
|
||||
static CacheManager()
|
||||
{
|
||||
Instance = new();
|
||||
Instance.Provider = App.RootServices;
|
||||
Instance.Cache = Instance.Provider.GetRequiredService<IMemoryCache>();
|
||||
Options = App.RootServices.GetRequiredService<IOptions<BootstrapBlazorOptions>>().Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得或者创建指定 Key 缓存项
|
||||
/// </summary>
|
||||
public TItem GetOrCreate<TItem>(object key, Func<ICacheEntry, TItem> factory) => Cache.GetOrCreate(key, entry =>
|
||||
{
|
||||
var item = factory(entry);
|
||||
|
||||
entry.SetDefaultSlidingExpiration(Options.CacheManagerOptions.SlidingExpiration);
|
||||
return item;
|
||||
})!;
|
||||
|
||||
/// <summary>
|
||||
/// 获得或者创建指定 Key 缓存项 异步重载方法
|
||||
/// </summary>
|
||||
public Task<TItem> GetOrCreateAsync<TItem>(object key, Func<ICacheEntry, Task<TItem>> factory) => Cache.GetOrCreateAsync(key, async entry =>
|
||||
{
|
||||
var item = await factory(entry).ConfigureAwait(false);
|
||||
|
||||
entry.SetDefaultSlidingExpiration(Options.CacheManagerOptions.SlidingExpiration);
|
||||
return item;
|
||||
})!;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryGetValue<TItem>(object key, [NotNullWhen(true)] out TItem? value)
|
||||
{
|
||||
var ret = Cache.TryGetValue(key, out var v);
|
||||
value = default;
|
||||
if (ret && v is TItem val)
|
||||
{
|
||||
value = val;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除指定 Key 缓存项
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
public void Clear(object? key)
|
||||
{
|
||||
if (key is "BootstrapBlazor_StartTime")
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (key is not null)
|
||||
{
|
||||
Cache.Remove(key);
|
||||
}
|
||||
else if (Cache is MemoryCache c)
|
||||
{
|
||||
c.Compact(100);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置 App 开始时间
|
||||
/// </summary>
|
||||
public void SetStartTime() => SetStartTime(DateTimeOffset.Now);
|
||||
|
||||
/// <summary>
|
||||
/// 设置 App 开始时间
|
||||
/// </summary>
|
||||
private void SetStartTime(DateTimeOffset startDateTimeOffset)
|
||||
{
|
||||
GetOrCreate("BootstrapBlazor_StartTime", entry =>
|
||||
{
|
||||
entry.Priority = CacheItemPriority.NeverRemove;
|
||||
return startDateTimeOffset;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 App 开始时间
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public DateTimeOffset GetStartTime()
|
||||
{
|
||||
var ret = DateTimeOffset.MinValue;
|
||||
if (Cache.TryGetValue("BootstrapBlazor_StartTime", out var v) && v is DateTimeOffset d)
|
||||
{
|
||||
ret = d;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得 缓存数量
|
||||
/// </summary>
|
||||
public long Count
|
||||
{
|
||||
get
|
||||
{
|
||||
var count = 0;
|
||||
if (Cache is MemoryCache c)
|
||||
{
|
||||
count = c.Count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
#if NET9_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// 获得 缓存键集合
|
||||
/// </summary>
|
||||
public IEnumerable<object> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
var keys = Enumerable.Empty<object>();
|
||||
if (Cache is MemoryCache c)
|
||||
{
|
||||
keys = c.Keys;
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
private object? _coherentStateInstance = null;
|
||||
|
||||
private MethodInfo? _allValuesMethodInfo = null;
|
||||
|
||||
private static readonly FieldInfo _coherentStateFieldInfo = typeof(MemoryCache).GetField("_coherentState", BindingFlags.Instance | BindingFlags.NonPublic)!;
|
||||
|
||||
private static MethodInfo GetAllValuesMethodInfo(Type type) => type.GetMethod("GetAllValues", BindingFlags.Instance | BindingFlags.Public)!;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="entry"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryGetCacheEntry(object? key, [NotNullWhen(true)] out ICacheEntry? entry)
|
||||
{
|
||||
entry = null;
|
||||
if (key == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Cache is MemoryCache cache)
|
||||
{
|
||||
var values = GetAllValues(cache);
|
||||
entry = values.Find(e => e.Key == key);
|
||||
}
|
||||
return entry != null;
|
||||
}
|
||||
|
||||
private List<ICacheEntry> GetAllValues(MemoryCache cache)
|
||||
{
|
||||
_coherentStateInstance = _coherentStateFieldInfo.GetValue(cache)!;
|
||||
_allValuesMethodInfo ??= GetAllValuesMethodInfo(_coherentStateInstance.GetType());
|
||||
|
||||
var ret = new List<ICacheEntry>();
|
||||
if (_allValuesMethodInfo.Invoke(_coherentStateInstance, null) is IEnumerable<ICacheEntry> values)
|
||||
{
|
||||
ret.AddRange(values);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#region Count
|
||||
public static int ElementCount(object? value)
|
||||
{
|
||||
var ret = 0;
|
||||
if (value != null)
|
||||
{
|
||||
var type = value.GetType();
|
||||
var cacheKey = $"{CacheKeyPrefix}-Lambda-Count-{type.GetUniqueTypeName()}";
|
||||
var invoker = Instance.GetOrCreate(cacheKey, entry =>
|
||||
{
|
||||
return LambdaExtensions.CountLambda(type).Compile();
|
||||
});
|
||||
ret = invoker(value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Localizer
|
||||
/// <summary>
|
||||
/// 通过 Type 获得 <see cref="IStringLocalizer"/> 实例
|
||||
/// </summary>
|
||||
/// <param name="resourceSource"></param>
|
||||
/// <returns></returns>
|
||||
public static IStringLocalizer? CreateLocalizerByType(Type resourceSource) => resourceSource.Assembly.IsDynamic
|
||||
? null
|
||||
: Instance.Provider.GetRequiredService<IStringLocalizerFactory>().Create(resourceSource);
|
||||
|
||||
/// <summary>
|
||||
/// 获得 <see cref="JsonLocalizationOptions"/> 值
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static JsonLocalizationOptions GetJsonLocalizationOption()
|
||||
{
|
||||
var localizationOptions = Instance.Provider.GetRequiredService<IOptions<JsonLocalizationOptions>>();
|
||||
return localizationOptions.Value;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获得 <see cref="JsonLocalizationOptions"/> 值
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static BootstrapBlazorOptions GetBootstrapBlazorOption()
|
||||
{
|
||||
var localizationOptions = Instance.Provider.GetRequiredService<IOptions<BootstrapBlazorOptions>>();
|
||||
return localizationOptions.Value;
|
||||
}
|
||||
/// <summary>
|
||||
/// 通过 程序集与类型获得 IStringLocalizer 实例
|
||||
/// </summary>
|
||||
/// <param name="assembly">Assembly 程序集实例</param>
|
||||
/// <param name="typeName">类型名称</param>
|
||||
/// <returns></returns>
|
||||
public static IStringLocalizer? GetStringLocalizerFromService(Assembly assembly, string typeName)
|
||||
{
|
||||
if (assembly.IsDynamic)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
IStringLocalizer? ret = null;
|
||||
var factories = Instance.Provider.GetServices<IStringLocalizerFactory>();
|
||||
var factory = factories.LastOrDefault(a => a is not JsonStringLocalizerFactory);
|
||||
if (factory != null)
|
||||
{
|
||||
var type = assembly.GetType(typeName);
|
||||
if (type != null)
|
||||
{
|
||||
ret = factory.Create(type);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定文化本地化资源集合
|
||||
/// </summary>
|
||||
/// <param name="assembly">Assembly 程序集实例</param>
|
||||
/// <param name="typeName">类型名称</param>
|
||||
public static IEnumerable<LocalizedString>? GetAllStringsByTypeName(Assembly assembly, string typeName)
|
||||
=> GetJsonStringByTypeName(GetJsonLocalizationOption(), assembly, typeName, CultureInfo.CurrentUICulture.Name);
|
||||
|
||||
/// <summary>
|
||||
/// 通过指定程序集获取所有本地化信息键值集合
|
||||
/// </summary>
|
||||
/// <param name="option">JsonLocalizationOptions 实例</param>
|
||||
/// <param name="assembly">Assembly 程序集实例</param>
|
||||
/// <param name="typeName">类型名称</param>
|
||||
/// <param name="cultureName">cultureName 未空时使用 CultureInfo.CurrentUICulture.Name</param>
|
||||
/// <param name="forceLoad">默认 false 使用缓存值 设置 true 时内部强制重新加载</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<LocalizedString>? GetJsonStringByTypeName(JsonLocalizationOptions option, Assembly assembly, string typeName, string? cultureName = null, bool forceLoad = false)
|
||||
{
|
||||
if (assembly.IsDynamic)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
cultureName ??= CultureInfo.CurrentUICulture.Name;
|
||||
if (string.IsNullOrEmpty(cultureName))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var key = $"{CacheKeyPrefix}-{nameof(GetJsonStringByTypeName)}-{assembly.GetUniqueName()}-{cultureName}";
|
||||
if (forceLoad)
|
||||
{
|
||||
Instance.Cache.Remove(key);
|
||||
}
|
||||
|
||||
var localizedItems = Instance.GetOrCreate(key, entry =>
|
||||
{
|
||||
var sections = option.GetJsonStringFromAssembly(assembly, cultureName);
|
||||
var items = sections.SelectMany(section => section.GetChildren().Select(kv =>
|
||||
{
|
||||
var value = kv.Value;
|
||||
if (value == null && option.UseKeyWhenValueIsNull == true)
|
||||
{
|
||||
value = kv.Key;
|
||||
}
|
||||
return new LocalizedString(kv.Key, value ?? "", false, section.Key);
|
||||
}));
|
||||
#if NET8_0_OR_GREATER
|
||||
return items.ToFrozenSet();
|
||||
#else
|
||||
return items.ToHashSet();
|
||||
#endif
|
||||
});
|
||||
return localizedItems.Where(item => item.SearchedLocation!.Equals(typeName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过 ILocalizationResolve 接口实现类获得本地化键值集合
|
||||
/// </summary>
|
||||
/// <param name="typeName"></param>
|
||||
/// <param name="includeParentCultures"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<LocalizedString> GetTypeStringsFromResolve(string typeName, bool includeParentCultures = true) => Instance.Provider.GetRequiredService<ILocalizationResolve>().GetAllStringsByType(typeName, includeParentCultures);
|
||||
#endregion
|
||||
|
||||
#region DisplayName
|
||||
/// <summary>
|
||||
/// 获得类型属性的描述信息
|
||||
/// </summary>
|
||||
/// <param name="modelType"></param>
|
||||
/// <param name="fieldName"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetDisplayName(Type modelType, string fieldName)
|
||||
{
|
||||
string? dn = null;
|
||||
// 显示名称为空时通过资源文件查找 FieldName 项
|
||||
var localizer = modelType.Assembly.IsDynamic ? null : CreateLocalizerByType(modelType);
|
||||
var stringLocalizer = localizer?[fieldName];
|
||||
if (stringLocalizer is { ResourceNotFound: false })
|
||||
{
|
||||
dn = stringLocalizer.Value;
|
||||
}
|
||||
else if (modelType.IsEnum)
|
||||
{
|
||||
var info = modelType.GetFieldByName(fieldName);
|
||||
if (info != null)
|
||||
{
|
||||
dn = FindDisplayAttribute(modelType, info);
|
||||
}
|
||||
}
|
||||
else if (TryGetProperty(modelType, fieldName, out var propertyInfo))
|
||||
{
|
||||
dn = FindDisplayAttribute(modelType, propertyInfo);
|
||||
}
|
||||
return dn ?? fieldName;
|
||||
}
|
||||
|
||||
private static string? FindDisplayAttribute(Type modelType, MemberInfo memberInfo)
|
||||
{
|
||||
// 回退查找 Display 标签
|
||||
var dn = memberInfo.GetCustomAttribute<DisplayAttribute>(true)?.Name
|
||||
?? memberInfo.GetCustomAttribute<DisplayNameAttribute>(true)?.DisplayName
|
||||
?? memberInfo.GetCustomAttribute<DescriptionAttribute>(true)?.Description;
|
||||
|
||||
// 回退查找资源文件通过 dn 查找匹配项 用于支持 Validation
|
||||
if (!modelType.Assembly.IsDynamic && !string.IsNullOrEmpty(dn))
|
||||
{
|
||||
dn = GetLocalizerValueFromResourceManager(dn);
|
||||
}
|
||||
return dn;
|
||||
}
|
||||
|
||||
public static List<SelectedItem> GetNullableBoolItems(Type modelType, string fieldName)
|
||||
{
|
||||
var cacheKey = $"{CacheKeyPrefix}-{nameof(GetNullableBoolItems)}-{modelType.GetUniqueTypeName()}-{fieldName}-{CultureInfo.CurrentUICulture.Name}";
|
||||
return Instance.GetOrCreate(cacheKey, entry =>
|
||||
{
|
||||
var items = new List<SelectedItem>();
|
||||
var localizer = modelType.Assembly.IsDynamic ? null : CreateLocalizerByType(modelType);
|
||||
IStringLocalizer? localizerAttr = null;
|
||||
items.Add(new SelectedItem("", FindDisplayText(nameof(NullableBoolItemsAttribute.NullValueDisplayText), attr => attr.NullValueDisplayText)));
|
||||
items.Add(new SelectedItem("True", FindDisplayText(nameof(NullableBoolItemsAttribute.TrueValueDisplayText), attr => attr.TrueValueDisplayText)));
|
||||
items.Add(new SelectedItem("False", FindDisplayText(nameof(NullableBoolItemsAttribute.FalseValueDisplayText), attr => attr.FalseValueDisplayText)));
|
||||
return items;
|
||||
|
||||
string FindDisplayText(string itemName, Func<NullableBoolItemsAttribute, string?> callback)
|
||||
{
|
||||
string? dn = null;
|
||||
|
||||
// 优先读取资源文件配置
|
||||
var stringLocalizer = localizer?[$"{fieldName}-{itemName}"];
|
||||
if (stringLocalizer is { ResourceNotFound: false })
|
||||
{
|
||||
dn = stringLocalizer.Value;
|
||||
}
|
||||
else if (TryGetProperty(modelType, fieldName, out var propertyInfo))
|
||||
{
|
||||
// 类资源文件未找到 回落查找标签
|
||||
var attr = propertyInfo.GetCustomAttribute<NullableBoolItemsAttribute>(true);
|
||||
if (attr != null && !modelType.Assembly.IsDynamic)
|
||||
{
|
||||
dn = callback(attr);
|
||||
}
|
||||
}
|
||||
|
||||
// 回落读取 NullableBoolItemsAttribute 资源文件配置
|
||||
return dn ?? FindDisplayTextByItemName(itemName);
|
||||
}
|
||||
|
||||
string FindDisplayTextByItemName(string itemName)
|
||||
{
|
||||
localizerAttr ??= CreateLocalizerByType(typeof(NullableBoolItemsAttribute));
|
||||
var stringLocalizer = localizerAttr![itemName];
|
||||
return stringLocalizer.Value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过指定 Key 获取资源文件中的键值
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
private static string? GetLocalizerValueFromResourceManager(string key)
|
||||
{
|
||||
string? dn = null;
|
||||
var options = GetJsonLocalizationOption();
|
||||
if (options.ResourceManagerStringLocalizerType != null)
|
||||
{
|
||||
var localizer = CreateLocalizerByType(options.ResourceManagerStringLocalizerType);
|
||||
dn = GetValueByKey(localizer);
|
||||
}
|
||||
return dn ?? key;
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
string? GetValueByKey(IStringLocalizer? l)
|
||||
{
|
||||
string? val = null;
|
||||
var stringLocalizer = l?[key];
|
||||
if (stringLocalizer is { ResourceNotFound: false })
|
||||
{
|
||||
val = stringLocalizer.Value;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Placeholder
|
||||
public static string? GetPlaceholder(Type modelType, string fieldName)
|
||||
{
|
||||
// 通过资源文件查找 FieldName 项
|
||||
string? ret = null;
|
||||
var localizer = CreateLocalizerByType(modelType);
|
||||
if (localizer != null)
|
||||
{
|
||||
var stringLocalizer = localizer[$"{fieldName}.PlaceHolder"];
|
||||
if (!stringLocalizer.ResourceNotFound)
|
||||
{
|
||||
ret = stringLocalizer.Value;
|
||||
}
|
||||
else if (TryGetProperty(modelType, fieldName, out var propertyInfo))
|
||||
{
|
||||
var placeHolderAttribute = propertyInfo.GetCustomAttribute<PlaceHolderAttribute>(true);
|
||||
if (placeHolderAttribute != null)
|
||||
{
|
||||
ret = placeHolderAttribute.Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Lambda Property
|
||||
public static bool TryGetProperty(Type modelType, string fieldName, [NotNullWhen(true)] out PropertyInfo? propertyInfo)
|
||||
{
|
||||
var props = modelType.GetRuntimeProperties();
|
||||
|
||||
// 支持 MetadataType
|
||||
var metadataType = modelType.GetCustomAttribute<MetadataTypeAttribute>(false);
|
||||
if (metadataType != null)
|
||||
{
|
||||
props = props.Concat(metadataType.MetadataClassType.GetRuntimeProperties());
|
||||
}
|
||||
|
||||
propertyInfo = props.FirstOrDefault(p => p.Name == fieldName);
|
||||
return propertyInfo != null;
|
||||
}
|
||||
|
||||
public static TResult GetPropertyValue<TModel, TResult>(TModel model, string fieldName) => (model is IDynamicColumnsObject d)
|
||||
? (TResult)d.GetValue(fieldName)!
|
||||
: GetValue<TModel, TResult>(model, fieldName);
|
||||
|
||||
private static TResult GetValue<TModel, TResult>(TModel model, string fieldName)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(model));
|
||||
}
|
||||
|
||||
var type = model.GetType();
|
||||
var cacheKey = $"{CacheKeyPrefix}-Lambda-Get-{type.GetUniqueTypeName()}-{typeof(TModel)}-{fieldName}-{typeof(TResult)}";
|
||||
var invoker = Instance.GetOrCreate(cacheKey, entry =>
|
||||
{
|
||||
if (type.Assembly.IsDynamic)
|
||||
{
|
||||
entry.SetAbsoluteExpiration(Options.CacheManagerOptions.AbsoluteExpiration);
|
||||
}
|
||||
|
||||
return LambdaExtensions.GetPropertyValueLambda<TModel, TResult>(model, fieldName).Compile();
|
||||
});
|
||||
return invoker(model);
|
||||
}
|
||||
|
||||
public static void SetPropertyValue<TModel, TValue>(TModel model, string fieldName, TValue value)
|
||||
{
|
||||
if (model is IDynamicColumnsObject d)
|
||||
{
|
||||
d.SetValue(fieldName, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(model));
|
||||
}
|
||||
|
||||
var type = model.GetType();
|
||||
var cacheKey = $"{CacheKeyPrefix}-Lambda-Set-{type.GetUniqueTypeName()}-{typeof(TModel)}-{fieldName}-{typeof(TValue)}";
|
||||
var invoker = Instance.GetOrCreate(cacheKey, entry =>
|
||||
{
|
||||
if (type.Assembly.IsDynamic)
|
||||
{
|
||||
entry.SetAbsoluteExpiration(Options.CacheManagerOptions.AbsoluteExpiration);
|
||||
}
|
||||
return LambdaExtensions.SetPropertyValueLambda<TModel, TValue>(model, fieldName).Compile();
|
||||
});
|
||||
invoker(model, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得 指定模型标记 <see cref="KeyAttribute"/> 的属性值
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="customAttribute"></param>
|
||||
/// <returns></returns>
|
||||
public static TValue? GetKeyValue<TModel, TValue>(TModel model, Type? customAttribute = null)
|
||||
{
|
||||
var ret = default(TValue);
|
||||
if (model != null)
|
||||
{
|
||||
var type = model.GetType();
|
||||
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetKeyValue)}-{type.GetUniqueTypeName()}-{typeof(TModel)}-{customAttribute?.GetUniqueTypeName()}";
|
||||
var invoker = Instance.GetOrCreate(cacheKey, entry => LambdaExtensions.GetKeyValue<TModel, TValue>(customAttribute).Compile());
|
||||
ret = invoker(model);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Lambda Sort
|
||||
public static Func<IEnumerable<T>, string, SortOrder, IEnumerable<T>> GetSortFunc<T>()
|
||||
{
|
||||
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetSortFunc)}-{typeof(T).GetUniqueTypeName()}";
|
||||
return Instance.GetOrCreate(cacheKey, entry => LambdaExtensions.GetSortLambda<T>().Compile());
|
||||
}
|
||||
|
||||
public static Func<IEnumerable<T>, List<string>, IEnumerable<T>> GetSortListFunc<T>()
|
||||
{
|
||||
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetSortListFunc)}-{typeof(T).GetUniqueTypeName()}";
|
||||
return Instance.GetOrCreate(cacheKey, entry => LambdaExtensions.GetSortListLambda<T>().Compile());
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Lambda ConvertTo
|
||||
public static Func<object, IEnumerable<string?>> CreateConverterInvoker(Type type)
|
||||
{
|
||||
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(CreateConverterInvoker)}-{type.GetUniqueTypeName()}";
|
||||
return Instance.GetOrCreate(cacheKey, entry =>
|
||||
{
|
||||
var method = typeof(CacheManager)
|
||||
.GetMethod(nameof(ConvertToString), BindingFlags.NonPublic | BindingFlags.Static)!
|
||||
.MakeGenericMethod(type);
|
||||
|
||||
var para_exp = Expression.Parameter(typeof(object));
|
||||
var convert = Expression.Convert(para_exp, typeof(List<>).MakeGenericType(type));
|
||||
var body = Expression.Call(method, convert);
|
||||
return Expression.Lambda<Func<object, IEnumerable<string?>>>(body, para_exp).Compile();
|
||||
});
|
||||
}
|
||||
|
||||
private static IEnumerable<string?> ConvertToString<TSource>(List<TSource> source) => source is List<SelectedItem> list
|
||||
? list.Select(i => i.Value)
|
||||
: source.Select(i => i?.ToString());
|
||||
#endregion
|
||||
|
||||
#region OnValueChanged Lambda
|
||||
/// <summary>
|
||||
/// 创建 OnValueChanged 回调委托
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel"></typeparam>
|
||||
/// <param name="fieldType"></param>
|
||||
/// <returns></returns>
|
||||
public static Func<TModel, ITableColumn, Func<TModel, ITableColumn, object?, Task>, object> GetOnValueChangedInvoke<TModel>(Type fieldType)
|
||||
{
|
||||
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetOnValueChangedInvoke)}-{typeof(TModel).GetUniqueTypeName()}-{fieldType.GetUniqueTypeName()}";
|
||||
return Instance.GetOrCreate(cacheKey, entry => Utility.CreateOnValueChanged<TModel>(fieldType).Compile());
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Format
|
||||
public static Func<object, string, IFormatProvider?, string> GetFormatInvoker(Type type)
|
||||
{
|
||||
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetFormatInvoker)}-{type.GetUniqueTypeName()}";
|
||||
return Instance.GetOrCreate(cacheKey, entry => GetFormatLambda(type).Compile());
|
||||
|
||||
static Expression<Func<object, string, IFormatProvider?, string>> GetFormatLambda(Type type)
|
||||
{
|
||||
var exp_p1 = Expression.Parameter(typeof(object));
|
||||
var exp_p2 = Expression.Parameter(typeof(string));
|
||||
var exp_p3 = Expression.Parameter(typeof(IFormatProvider));
|
||||
Expression? body = null;
|
||||
if (type.IsAssignableTo(typeof(IFormattable)))
|
||||
{
|
||||
// 通过 IFormattable 接口格式化
|
||||
var mi = type.GetMethod("ToString", [typeof(string), typeof(IFormatProvider)]);
|
||||
if (mi != null)
|
||||
{
|
||||
body = Expression.Call(Expression.Convert(exp_p1, type), mi, exp_p2, exp_p3);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 通过 ToString() 方法格式化
|
||||
var mi = type.GetMethod("ToString", []);
|
||||
if (mi != null)
|
||||
{
|
||||
body = Expression.Call(Expression.Convert(exp_p1, type), mi);
|
||||
}
|
||||
}
|
||||
return BuildExpression();
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
Expression<Func<object, string, IFormatProvider?, string>> BuildExpression() => body == null
|
||||
? (s, f, provider) => s.ToString() ?? ""
|
||||
: Expression.Lambda<Func<object, string, IFormatProvider?, string>>(body, exp_p1, exp_p2, exp_p3);
|
||||
}
|
||||
}
|
||||
|
||||
public static Func<object, IFormatProvider?, string> GetFormatProviderInvoker(Type type)
|
||||
{
|
||||
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetFormatProviderInvoker)}-{type.GetUniqueTypeName()}";
|
||||
return Instance.GetOrCreate(cacheKey, entry => GetFormatProviderLambda(type).Compile());
|
||||
|
||||
static Expression<Func<object, IFormatProvider?, string>> GetFormatProviderLambda(Type type)
|
||||
{
|
||||
var exp_p1 = Expression.Parameter(typeof(object));
|
||||
var exp_p2 = Expression.Parameter(typeof(IFormatProvider));
|
||||
Expression? body;
|
||||
|
||||
var mi = type.GetMethod("ToString", [typeof(IFormatProvider)]);
|
||||
if (mi != null)
|
||||
{
|
||||
// 通过 ToString(IFormatProvider? provider) 接口格式化
|
||||
body = Expression.Call(Expression.Convert(exp_p1, type), mi, exp_p2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 通过 ToString() 方法格式化
|
||||
mi = type.GetMethod("ToString");
|
||||
body = Expression.Call(Expression.Convert(exp_p1, type), mi!);
|
||||
}
|
||||
return Expression.Lambda<Func<object, IFormatProvider?, string>>(body, exp_p1, exp_p2);
|
||||
}
|
||||
}
|
||||
|
||||
public static object GetFormatterInvoker(Type type, Func<object, Task<string?>> formatter)
|
||||
{
|
||||
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetFormatterInvoker)}-{type.GetUniqueTypeName()}";
|
||||
var invoker = Instance.GetOrCreate(cacheKey, entry => GetFormatterInvokerLambda(type).Compile());
|
||||
return invoker(formatter);
|
||||
|
||||
static Expression<Func<Func<object, Task<string?>>, object>> GetFormatterInvokerLambda(Type type)
|
||||
{
|
||||
var method = typeof(CacheManager).GetMethod(nameof(InvokeFormatterAsync), BindingFlags.Static | BindingFlags.NonPublic)!.MakeGenericMethod(type);
|
||||
var exp_p1 = Expression.Parameter(typeof(Func<object?, Task<string?>>));
|
||||
var body = Expression.Call(null, method, exp_p1);
|
||||
return Expression.Lambda<Func<Func<object, Task<string?>>, object>>(body, exp_p1);
|
||||
}
|
||||
}
|
||||
|
||||
private static Func<TType, Task<string?>> InvokeFormatterAsync<TType>(Func<object?, Task<string?>> formatter) => new(v => formatter(v));
|
||||
#endregion
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the Apache 2.0 License
|
||||
// See the LICENSE file in the project root for more information.
|
||||
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
using System.Reflection;
|
||||
namespace ThingsGateway;
|
||||
|
||||
internal static class CacheManagerHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets default sliding expiration if no expiration is configured
|
||||
/// </summary>
|
||||
internal static void SetDefaultSlidingExpiration(this ICacheEntry entry, TimeSpan offset)
|
||||
{
|
||||
if (entry.SlidingExpiration == null && entry.AbsoluteExpiration == null
|
||||
&& entry.AbsoluteExpirationRelativeToNow == null
|
||||
&& entry.Priority != CacheItemPriority.NeverRemove)
|
||||
{
|
||||
entry.SetSlidingExpiration(offset);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得唯一类型名称方法
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetUniqueName(this Assembly assembly) => assembly.IsCollectible
|
||||
? $"{assembly.GetName().Name}-{assembly.GetHashCode()}"
|
||||
: $"{assembly.GetName().Name}";
|
||||
|
||||
/// <summary>
|
||||
/// 获得唯一类型名称方法
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetUniqueTypeName(this Type type) => type.IsCollectible
|
||||
? $"{type.FullName}-{type.TypeHandle.Value}"
|
||||
: $"{type.FullName}";
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the Apache 2.0 License
|
||||
// See the LICENSE file in the project root for more information.
|
||||
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace ThingsGateway;
|
||||
|
||||
/// <summary>
|
||||
/// 多语言支持注入服务扩展类
|
||||
/// </summary>
|
||||
internal static class JsonLocalizationServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 注入 Json 格式多语言服务
|
||||
/// </summary>
|
||||
/// <param name="services">IServiceCollection 实例</param>
|
||||
/// <param name="localizationConfigure">JsonLocalizationOptions 配置回调方法</param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddJsonLocalization(this IServiceCollection services, Action<JsonLocalizationOptions>? localizationConfigure = null)
|
||||
{
|
||||
// 防止被 AddLocalization 覆盖掉
|
||||
services.AddSingleton<IStringLocalizerFactory, JsonStringLocalizerFactory>();
|
||||
services.TryAddTransient(typeof(IStringLocalizer<>), typeof(StringLocalizer<>));
|
||||
if (localizationConfigure != null)
|
||||
{
|
||||
services.Configure(localizationConfigure);
|
||||
}
|
||||
return services;
|
||||
}
|
||||
}
|
@@ -0,0 +1,243 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the Apache 2.0 License
|
||||
// See the LICENSE file in the project root for more information.
|
||||
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
|
||||
namespace ThingsGateway;
|
||||
|
||||
/// <summary>
|
||||
/// JsonStringLocalizer 实现类
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <param name="typeName"></param>
|
||||
/// <param name="baseName"></param>
|
||||
/// <param name="jsonLocalizationOptions"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="resourceNamesCache"></param>
|
||||
/// <param name="localizationMissingItemHandler"></param>
|
||||
internal class JsonStringLocalizer(Assembly assembly, string typeName, string baseName, JsonLocalizationOptions jsonLocalizationOptions, ILogger logger, IResourceNamesCache resourceNamesCache, ILocalizationMissingItemHandler localizationMissingItemHandler) : ResourceManagerStringLocalizer(new ResourceManager(baseName, assembly), assembly, baseName, resourceNamesCache, logger)
|
||||
{
|
||||
private Assembly Assembly { get; } = assembly;
|
||||
|
||||
private ILogger Logger { get; } = logger;
|
||||
|
||||
/// <summary>
|
||||
/// 通过指定键值获取多语言值信息索引
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public override LocalizedString this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = GetStringSafely(name);
|
||||
return new LocalizedString(name, value ?? name, resourceNotFound: value == null, searchedLocation: typeName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 带格式化参数的通过指定键值获取多语言值信息索引
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="arguments"></param>
|
||||
/// <returns></returns>
|
||||
public override LocalizedString this[string name, params object[] arguments]
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = SafeFormat();
|
||||
return new LocalizedString(name, value ?? name, resourceNotFound: value == null, searchedLocation: typeName);
|
||||
|
||||
string? SafeFormat()
|
||||
{
|
||||
string? ret = null;
|
||||
try
|
||||
{
|
||||
var format = GetStringSafely(name);
|
||||
ret = string.Format(CultureInfo.CurrentCulture, format ?? name, arguments);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "{JsonStringLocalizerName} searched for '{Name}' in '{typeName}' with culture '{CultureName}' throw exception.", nameof(JsonStringLocalizer), name, typeName, CultureInfo.CurrentUICulture.Name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 只保留json
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
private string? GetStringSafely(string name) => GetStringFromJson(name);
|
||||
|
||||
private string? GetStringFromService(string name)
|
||||
{
|
||||
// get string from inject service
|
||||
string? ret = null;
|
||||
if (jsonLocalizationOptions.DisableGetLocalizerFromService == false)
|
||||
{
|
||||
var localizer = Utility.GetStringLocalizerFromService(Assembly, typeName);
|
||||
if (localizer != null && localizer is not JsonStringLocalizer)
|
||||
{
|
||||
var l = localizer[name];
|
||||
if (!l.ResourceNotFound)
|
||||
{
|
||||
ret = l.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private string? GetStringFromResourceManager(string name)
|
||||
{
|
||||
string? ret = null;
|
||||
if (jsonLocalizationOptions.DisableGetLocalizerFromResourceManager == false)
|
||||
{
|
||||
ret = GetStringSafely(name, CultureInfo.CurrentUICulture);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private readonly ConcurrentDictionary<string, object?> _missingManifestCache = [];
|
||||
private string? GetStringFromJson(string name)
|
||||
{
|
||||
// get string from json localization file
|
||||
var localizerStrings = MegerResolveLocalizers(CacheManager.GetAllStringsByTypeName(Assembly, typeName));
|
||||
var cacheKey = $"name={name}&culture={CultureInfo.CurrentUICulture.Name}";
|
||||
string? ret = null;
|
||||
if (!_missingManifestCache.ContainsKey(cacheKey))
|
||||
{
|
||||
var l = localizerStrings.Find(i => i.Name == name);
|
||||
if (l is { ResourceNotFound: false })
|
||||
{
|
||||
ret = l.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果没有找到资源信息则尝试从父类中查找
|
||||
ret ??= GetStringFromBaseType(name);
|
||||
|
||||
if (ret is null)
|
||||
{
|
||||
// 加入缺失资源信息缓存中
|
||||
HandleMissingResourceItem(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private string? GetStringFromBaseType(string name)
|
||||
{
|
||||
string? ret = null;
|
||||
var type = Assembly.GetType(typeName);
|
||||
var propertyInfo = type?.GetPropertyByName(name);
|
||||
if (propertyInfo is { DeclaringType: not null })
|
||||
{
|
||||
var baseType = propertyInfo.DeclaringType;
|
||||
if (baseType != type)
|
||||
{
|
||||
var baseAssembly = baseType.Assembly;
|
||||
var localizerStrings = MegerResolveLocalizers(CacheManager.GetAllStringsByTypeName(baseAssembly, baseType.FullName!));
|
||||
var l = localizerStrings.Find(i => i.Name == name);
|
||||
if (l is { ResourceNotFound: false })
|
||||
{
|
||||
ret = l.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private List<LocalizedString> MegerResolveLocalizers(IEnumerable<LocalizedString>? localizerStrings)
|
||||
{
|
||||
var localizers = new List<LocalizedString>(CacheManager.GetTypeStringsFromResolve(typeName));
|
||||
if (localizerStrings != null)
|
||||
{
|
||||
localizers.AddRange(localizerStrings);
|
||||
}
|
||||
return localizers;
|
||||
}
|
||||
|
||||
private void HandleMissingResourceItem(string name)
|
||||
{
|
||||
localizationMissingItemHandler.HandleMissingItem(name, typeName, CultureInfo.CurrentUICulture.Name);
|
||||
if (jsonLocalizationOptions.IgnoreLocalizerMissing == false)
|
||||
{
|
||||
Logger.LogInformation("{JsonStringLocalizerName} searched for '{Name}' in '{TypeName}' with culture '{CultureName}' not found.", nameof(JsonStringLocalizer), name, typeName, CultureInfo.CurrentUICulture.Name);
|
||||
}
|
||||
_missingManifestCache.TryAdd($"name={name}&culture={CultureInfo.CurrentUICulture.Name}", null);
|
||||
}
|
||||
|
||||
private List<LocalizedString>? _allLocalizerdStrings;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前语言的所有资源信息
|
||||
/// </summary>
|
||||
/// <param name="includeParentCultures"></param>
|
||||
/// <returns></returns>
|
||||
public override IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
|
||||
{
|
||||
if (_allLocalizerdStrings == null)
|
||||
{
|
||||
var items = GetAllStringsFromService()
|
||||
?? GetAllStringsFromBase()
|
||||
?? GetAllStringsFromJson();
|
||||
|
||||
_allLocalizerdStrings = MegerResolveLocalizers(items);
|
||||
}
|
||||
return _allLocalizerdStrings;
|
||||
|
||||
// 1. 从注入服务中获取所有资源信息
|
||||
// get all strings from the other inject service
|
||||
IEnumerable<LocalizedString>? GetAllStringsFromService()
|
||||
{
|
||||
IEnumerable<LocalizedString>? ret = null;
|
||||
if (jsonLocalizationOptions.DisableGetLocalizerFromService == false)
|
||||
{
|
||||
var localizer = Utility.GetStringLocalizerFromService(Assembly, typeName);
|
||||
if (localizer != null && localizer is not JsonStringLocalizer)
|
||||
{
|
||||
ret = localizer.GetAllStrings(includeParentCultures);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 2. 从父类 ResourceManagerStringLocalizer 中获取微软格式资源信息
|
||||
// get all strings from base json localization factory
|
||||
IEnumerable<LocalizedString>? GetAllStringsFromBase()
|
||||
{
|
||||
IEnumerable<LocalizedString>? ret = null;
|
||||
if (jsonLocalizationOptions.DisableGetLocalizerFromResourceManager == false)
|
||||
{
|
||||
ret = base.GetAllStrings(includeParentCultures);
|
||||
try
|
||||
{
|
||||
CheckMissing();
|
||||
}
|
||||
catch (MissingManifestResourceException)
|
||||
{
|
||||
ret = null;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
void CheckMissing() => _ = ret.Any();
|
||||
}
|
||||
|
||||
// 3. 从 Json 文件中获取资源信息
|
||||
// get all strings from json localization file
|
||||
IEnumerable<LocalizedString>? GetAllStringsFromJson() => CacheManager.GetAllStringsByTypeName(Assembly, typeName);
|
||||
}
|
||||
}
|
@@ -0,0 +1,107 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the Apache 2.0 License
|
||||
// See the LICENSE file in the project root for more information.
|
||||
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
namespace ThingsGateway;
|
||||
|
||||
/// <summary>
|
||||
/// IStringLocalizerFactory 实现类
|
||||
/// </summary>
|
||||
internal class JsonStringLocalizerFactory : ResourceManagerStringLocalizerFactory
|
||||
{
|
||||
private readonly ILoggerFactory _loggerFactory;
|
||||
private readonly JsonLocalizationOptions _jsonLocalizationOptions;
|
||||
private readonly ILocalizationMissingItemHandler _localizationMissingItemHandler;
|
||||
private string? _typeName;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="cacheManager"></param>
|
||||
/// <param name="localizationMissingItemHandler"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="jsonLocalizationOptions"></param>
|
||||
/// <param name="localizationOptions"></param>
|
||||
/// <param name="loggerFactory"></param>
|
||||
public JsonStringLocalizerFactory(
|
||||
ICacheManager cacheManager,
|
||||
ILocalizationMissingItemHandler localizationMissingItemHandler,
|
||||
IOptions<BootstrapBlazorOptions> options,
|
||||
IOptions<JsonLocalizationOptions> jsonLocalizationOptions,
|
||||
IOptions<LocalizationOptions> localizationOptions,
|
||||
ILoggerFactory loggerFactory) : base(localizationOptions, loggerFactory)
|
||||
{
|
||||
// 由于某些应用场景如 (WTM) Blazor 还未加载时 Localizer 模块先开始工作了
|
||||
// 为了保证 CacheManager 内部 Instance 可用这里需要使 ICacheManager 先实例化
|
||||
cacheManager.SetStartTime();
|
||||
|
||||
if (options.Value.IgnoreLocalizerMissing.HasValue)
|
||||
{
|
||||
jsonLocalizationOptions.Value.IgnoreLocalizerMissing = options.Value.IgnoreLocalizerMissing.Value;
|
||||
}
|
||||
if (options.Value.DisableGetLocalizerFromService.HasValue)
|
||||
{
|
||||
jsonLocalizationOptions.Value.DisableGetLocalizerFromService = options.Value.DisableGetLocalizerFromService.Value;
|
||||
}
|
||||
if (options.Value.DisableGetLocalizerFromResourceManager.HasValue)
|
||||
{
|
||||
jsonLocalizationOptions.Value.DisableGetLocalizerFromResourceManager = options.Value.DisableGetLocalizerFromResourceManager.Value;
|
||||
}
|
||||
_localizationMissingItemHandler = localizationMissingItemHandler;
|
||||
_loggerFactory = loggerFactory;
|
||||
_jsonLocalizationOptions = jsonLocalizationOptions.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetResourcePrefix 方法
|
||||
/// </summary>
|
||||
/// <param name="typeInfo"></param>
|
||||
/// <returns></returns>
|
||||
protected override string GetResourcePrefix(TypeInfo typeInfo)
|
||||
{
|
||||
var typeName = typeInfo.FullName;
|
||||
if (string.IsNullOrEmpty(typeName))
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(typeInfo)} full name is null or String.Empty.");
|
||||
}
|
||||
|
||||
if (typeInfo.IsGenericType)
|
||||
{
|
||||
var index = typeName.IndexOf('`');
|
||||
typeName = typeName[..index];
|
||||
}
|
||||
_typeName = typeName;
|
||||
|
||||
return base.GetResourcePrefix(typeInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetResourcePrefix 方法
|
||||
/// </summary>
|
||||
/// <param name="baseResourceName"></param>
|
||||
/// <param name="baseNamespace"></param>
|
||||
/// <returns></returns>
|
||||
protected override string GetResourcePrefix(string baseResourceName, string baseNamespace)
|
||||
{
|
||||
// https://gitee.com/LongbowEnterprise/BootstrapBlazor/issues/I5SRA1
|
||||
var resourcePrefix = base.GetResourcePrefix(baseResourceName, baseNamespace);
|
||||
_typeName = $"{baseNamespace}.{baseResourceName}";
|
||||
|
||||
return resourcePrefix;
|
||||
}
|
||||
|
||||
private IResourceNamesCache ResourceNamesCache { get; } = new ResourceNamesCache();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="ResourceManagerStringLocalizer"/> for the given input
|
||||
/// </summary>
|
||||
/// <param name="assembly">The assembly to create a <see cref="ResourceManagerStringLocalizer"/> for</param>
|
||||
/// <param name="baseName">The base name of the resource to search for</param>
|
||||
/// <returns></returns>
|
||||
protected override ResourceManagerStringLocalizer CreateResourceManagerStringLocalizer(Assembly assembly, string baseName) => new JsonStringLocalizer(assembly, _typeName!, baseName, _jsonLocalizationOptions, _loggerFactory.CreateLogger<JsonStringLocalizer>(), ResourceNamesCache, _localizationMissingItemHandler);
|
||||
}
|
@@ -0,0 +1,137 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the Apache 2.0 License
|
||||
// See the LICENSE file in the project root for more information.
|
||||
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
namespace ThingsGateway;
|
||||
|
||||
/// <summary>
|
||||
/// JsonLocalizationOptions 扩展方法
|
||||
/// </summary>
|
||||
internal static class LocalizationOptionsExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 通过系统 JsonLocalizationOptions 获取当前 Json 格式资源配置集合
|
||||
/// </summary>
|
||||
/// <param name="option"></param>
|
||||
/// <param name="assembly"></param>
|
||||
/// <param name="cultureName"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<IConfigurationSection> GetJsonStringFromAssembly(this JsonLocalizationOptions option, Assembly assembly, string cultureName)
|
||||
{
|
||||
// 创建配置 ConfigurationBuilder
|
||||
var builder = new ConfigurationBuilder();
|
||||
|
||||
// 获取程序集中的资源文件
|
||||
var assemblies = new List<Assembly>() { assembly };
|
||||
|
||||
// 获得主程序集资源文件
|
||||
// 支持合并操作
|
||||
var entryAssembly = GetEntryAssembly();
|
||||
if (assembly != entryAssembly)
|
||||
{
|
||||
assemblies.Add(entryAssembly);
|
||||
}
|
||||
|
||||
if (option.AdditionalJsonAssemblies != null)
|
||||
{
|
||||
assemblies.AddRange(option.AdditionalJsonAssemblies);
|
||||
}
|
||||
|
||||
var streams = assemblies.SelectMany(i => CacheManager.Options.GetResourceStream(i, cultureName)).ToList();
|
||||
|
||||
// 添加 Json 文件流到配置
|
||||
foreach (var s in streams)
|
||||
{
|
||||
builder.AddJsonStream(s);
|
||||
}
|
||||
|
||||
// 获得配置外置资源文件
|
||||
if (option.AdditionalJsonFiles != null)
|
||||
{
|
||||
var files = option.AdditionalJsonFiles.Where(f =>
|
||||
{
|
||||
var fileName = Path.GetFileNameWithoutExtension(f);
|
||||
return fileName.Equals(cultureName, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
foreach (var file in files)
|
||||
{
|
||||
builder.AddJsonFile(file, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
// 生成 IConfigurationRoot
|
||||
var config = builder.Build();
|
||||
|
||||
// dispose json stream
|
||||
foreach (var s in streams)
|
||||
{
|
||||
s.Dispose();
|
||||
}
|
||||
|
||||
return config.GetChildren();
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
Assembly GetEntryAssembly() => Assembly.GetEntryAssembly() ?? assembly;
|
||||
}
|
||||
|
||||
private static List<Stream> GetResourceStream(this BootstrapBlazorOptions option, Assembly assembly, string cultureName)
|
||||
{
|
||||
var resourceNames = assembly.GetManifestResourceNames();
|
||||
var ret = new List<Stream>();
|
||||
|
||||
// 如果开启回落机制优先增加回落语言
|
||||
//if (option.EnableFallbackCulture)
|
||||
{
|
||||
AddStream("zh-CN");
|
||||
}
|
||||
|
||||
// 查找父资源
|
||||
var parentName = GetParentCultureName(cultureName).Value;
|
||||
if (!string.IsNullOrEmpty(parentName) && !EqualFallbackCulture(parentName))
|
||||
{
|
||||
AddStream(parentName);
|
||||
}
|
||||
|
||||
// 当前文化资源
|
||||
if (!EqualFallbackCulture(cultureName))
|
||||
{
|
||||
AddStream(cultureName);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
void AddStream(string name)
|
||||
{
|
||||
var json = resourceNames.FirstOrDefault(i => i.Contains($".{name}.json"));
|
||||
if (json != null)
|
||||
{
|
||||
var stream = assembly.GetManifestResourceStream(json);
|
||||
if (stream != null)
|
||||
{
|
||||
ret.Add(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 开启回落机制并且当前文化信息与回落语言相同
|
||||
bool EqualFallbackCulture(string name) => option.EnableFallbackCulture && option.FallbackCulture == name;
|
||||
}
|
||||
|
||||
static StringSegment GetParentCultureName(StringSegment cultureInfoName)
|
||||
{
|
||||
var ret = new StringSegment();
|
||||
var index = cultureInfoName.IndexOf('-');
|
||||
if (index > 0)
|
||||
{
|
||||
ret = cultureInfoName.Subsegment(0, index);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
@@ -35,6 +35,9 @@ public class Startup : AppStartup
|
||||
jsonLocalizationOptions.UseKeyWhenValueIsNull = true;
|
||||
}
|
||||
);
|
||||
|
||||
services.AddJsonLocalization();
|
||||
|
||||
services.AddConfigurableOptions<MenuOptions>();
|
||||
services.ConfigureIconThemeOptions(options => options.ThemeKey = "fa");
|
||||
services.AddSingleton<IAppVersionService, VersionService>();
|
||||
|
@@ -99,10 +99,10 @@ namespace SqlSugar
|
||||
return this.initkey;
|
||||
}
|
||||
var key = "SqlSugarProviderScope_" + conn.CurrentConnectionConfig.ConfigId;
|
||||
if (frames == null)
|
||||
{
|
||||
frames = new StackTrace(false).GetFrames();
|
||||
}
|
||||
//if (frames == null)
|
||||
//{
|
||||
// frames = new StackTrace(false).GetFrames();
|
||||
//}
|
||||
//if (true)
|
||||
//{
|
||||
// foreach (var method in frames.Take(35))
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<PluginVersion>10.7.39</PluginVersion>
|
||||
<ProPluginVersion>10.7.39</ProPluginVersion>
|
||||
<PluginVersion>10.7.42</PluginVersion>
|
||||
<ProPluginVersion>10.7.42</ProPluginVersion>
|
||||
<AuthenticationVersion>2.5.0</AuthenticationVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<AnalysisModeStyle>None</AnalysisModeStyle>
|
||||
|
||||
<NoWarn>
|
||||
CS8603;CS8618;CS1591;CS8625;CS8602;CS8604;CS8600;CS8601;CS8714;CS8619;CS8629;CS8765;CS8634;CS8621;CS8767;CS8633;CS8620;CS8610;CS8631;CS8605;CS8622;CS8613;NU5100;NU5104;NU1903;NU1902;CA1813;CA1852;CA1822;CA2100;CA2008;CA1812;CA1508;CA1512;CA1513;CA1810;CA1814;CA1815;CA1835;CA1819;CA1823;CA2002;CA5350;CA5351;CA5358;CA5384;CA5392;CA1805;CA1851;CA1510;CA5401;CA2022;CA1848;CA2000;CA5394;CA3003;CA1515;CA1849
|
||||
CS8603;CS8618;CS1591;CS8625;CS8602;CS8604;CS8600;CS8601;CS8714;CS8619;CS8629;CS8765;CS8634;CS8621;CS8767;CS8633;CS8620;CS8610;CS8631;CS8605;CS8622;CS8613;NU5100;NU5104;NU1903;NU1902;CA1813;CA1852;CA1822;CA2100;CA2008;CA1812;CA1508;CA1512;CA1513;CA1810;CA1814;CA1815;CA1835;CA1819;CA1823;CA2002;CA5350;CA5351;CA5358;CA5384;CA5392;CA1805;CA1851;CA1510;CA5401;CA2022;CA1848;CA2000;CA5394;CA3003;CA1515;CA1849;CA1863
|
||||
</NoWarn>
|
||||
<TargetFrameworks>net8.0;</TargetFrameworks>
|
||||
<LangVersion>13.0</LangVersion>
|
||||
|
@@ -48,7 +48,7 @@ public partial class ChannelComponent : ComponentBase
|
||||
{
|
||||
if (Channel != null)
|
||||
{
|
||||
await Channel.CloseAsync(DefaultResource.Localizer["ProactivelyDisconnect", nameof(DisconnectClick)]);
|
||||
await Channel.CloseAsync(AppResource.Localizer["ProactivelyDisconnect", nameof(DisconnectClick)]);
|
||||
if (OnDisConnectClick.HasDelegate)
|
||||
await OnDisConnectClick.InvokeAsync();
|
||||
}
|
||||
|
@@ -1,85 +1,30 @@
|
||||
{
|
||||
"ThingsGateway.Debug.ChannelComponent": {
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"ChannelType": "Channel Type",
|
||||
"Enable": "Enable",
|
||||
"LogEnable": "Enable Debug Log",
|
||||
"RemoteUrl": "Remote IP Address",
|
||||
"BindUrl": "Local Bind IP Address",
|
||||
"PortName": "COM Port",
|
||||
"BaudRate": "Baud Rate",
|
||||
"DataBits": "Data Bits",
|
||||
"Parity": "Parity",
|
||||
"StopBits": "Stop Bits",
|
||||
"DtrEnable": "Dtr",
|
||||
"RtsEnable": "Rts",
|
||||
|
||||
"SaveChannel": "Add/Modify Channel",
|
||||
"DeleteChannel": "Delete Channel",
|
||||
"BindUrl": "Local Bind IP Address",
|
||||
"Channel": "Channel",
|
||||
"ChannelType": "Channel Type",
|
||||
"ClearChannel": "Clear Channel",
|
||||
"Confim": "Confim",
|
||||
"Connect": "Connect",
|
||||
"DataBits": "Data Bits",
|
||||
"DeleteChannel": "Delete Channel",
|
||||
"Disconnect": "Disconnect",
|
||||
"DtrEnable": "Dtr",
|
||||
"Enable": "Enable",
|
||||
"ExportChannel": "Export Channel",
|
||||
"ImportChannel": "Import Channel",
|
||||
"ImportNullError": "Unable to recognize",
|
||||
"NotOther": "Not supporting other channel types",
|
||||
"Connect": "Connect",
|
||||
"Confim": "Confim",
|
||||
"Disconnect": "Disconnect",
|
||||
"Channel": "Channel"
|
||||
},
|
||||
"ThingsGateway.Foundation.ChannelOptionsDefault": {
|
||||
"LogEnable": "Enable Debug Log",
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"ChannelType": "ChannelType",
|
||||
|
||||
"RemoteUrl": "RemoteUrl",
|
||||
"BindUrl": "BindUrl",
|
||||
|
||||
"PortName": "PortName",
|
||||
"BaudRate": "BaudRate",
|
||||
"DataBits": "DataBits",
|
||||
"NotOther": "Not supporting other channel types",
|
||||
"Parity": "Parity",
|
||||
"StopBits": "StopBits",
|
||||
"DtrEnable": "DtrEnable",
|
||||
"RtsEnable": "RtsEnable",
|
||||
"CacheTimeout": "CacheTimeout",
|
||||
"ConnectTimeout": "ConnectTimeout",
|
||||
"MaxConcurrentCount": "MaxConcurrentCount",
|
||||
|
||||
|
||||
|
||||
"MaxClientCount": "MaxClientCount",
|
||||
"CheckClearTime": "CheckClearTime",
|
||||
"Heartbeat": "Heartbeat",
|
||||
"HeartbeatTime": "HeartbeatTime",
|
||||
"DtuId": "DtuId",
|
||||
"DtuSeviceType": "DtuSeviceType"
|
||||
},
|
||||
"ThingsGateway.Debug.DeviceComponentBase": {
|
||||
"WriteSuccess": "WriteSuccess",
|
||||
"DefaultSend": "DefaultSend",
|
||||
"Send": "Send",
|
||||
"DataType": "DataType",
|
||||
"RegisterAddress": "RegisterAddress",
|
||||
"ArrayLength": "ArrayLength",
|
||||
"WriteValue": "WriteValue",
|
||||
"SendValue": "Send Raw Message"
|
||||
},
|
||||
"ThingsGateway.Debug.DeviceComponent": {
|
||||
"HeaderText": "Channel Log",
|
||||
"WriteSuccess": "WriteSuccess",
|
||||
"DefaultSend": "DefaultSend",
|
||||
"Send": "Send",
|
||||
"DataType": "DataType",
|
||||
"RegisterAddress": "RegisterAddress",
|
||||
"ArrayLength": "ArrayLength",
|
||||
"WriteValue": "WriteValue",
|
||||
"SendValue": "Send Raw Message",
|
||||
"CommonFunctions": "Common Functions",
|
||||
"SpecialFunctions": "Special Functions",
|
||||
"Read": "Read",
|
||||
"Write": "Write",
|
||||
"MulRead": "Multiple Read"
|
||||
"PortName": "COM Port",
|
||||
"RemoteUrl": "Remote IP Address",
|
||||
"RtsEnable": "Rts",
|
||||
"SaveChannel": "Add/Modify Channel",
|
||||
"StopBits": "Stop Bits"
|
||||
},
|
||||
"ThingsGateway.Debug.ChannelEditComponent": {
|
||||
"BasicInformation": "Basic Information",
|
||||
@@ -87,5 +32,54 @@
|
||||
},
|
||||
"ThingsGateway.Debug.ConverterConfigComponent": {
|
||||
"Converter": "Converter"
|
||||
},
|
||||
"ThingsGateway.Debug.DeviceComponent": {
|
||||
"ArrayLength": "ArrayLength",
|
||||
"CommonFunctions": "Common Functions",
|
||||
"DataType": "DataType",
|
||||
"DefaultSend": "DefaultSend",
|
||||
"HeaderText": "Channel Log",
|
||||
"MulRead": "Multiple Read",
|
||||
"Read": "Read",
|
||||
"RegisterAddress": "RegisterAddress",
|
||||
"Send": "Send",
|
||||
"SendValue": "Send Raw Message",
|
||||
"SpecialFunctions": "Special Functions",
|
||||
"Write": "Write",
|
||||
"WriteSuccess": "WriteSuccess",
|
||||
"WriteValue": "WriteValue"
|
||||
},
|
||||
"ThingsGateway.Debug.DeviceComponentBase": {
|
||||
"ArrayLength": "ArrayLength",
|
||||
"DataType": "DataType",
|
||||
"DefaultSend": "DefaultSend",
|
||||
"RegisterAddress": "RegisterAddress",
|
||||
"Send": "Send",
|
||||
"SendValue": "Send Raw Message",
|
||||
"WriteSuccess": "WriteSuccess",
|
||||
"WriteValue": "WriteValue"
|
||||
},
|
||||
"ThingsGateway.Foundation.ChannelOptionsDefault": {
|
||||
"BaudRate": "BaudRate",
|
||||
"BindUrl": "BindUrl",
|
||||
"CacheTimeout": "CacheTimeout",
|
||||
"ChannelType": "ChannelType",
|
||||
"CheckClearTime": "CheckClearTime",
|
||||
"ConnectTimeout": "ConnectTimeout",
|
||||
"DataBits": "DataBits",
|
||||
"DtrEnable": "DtrEnable",
|
||||
"DtuId": "DtuId",
|
||||
"DtuSeviceType": "DtuSeviceType",
|
||||
"Heartbeat": "Heartbeat",
|
||||
"HeartbeatTime": "HeartbeatTime",
|
||||
"MaxClientCount": "MaxClientCount",
|
||||
"MaxConcurrentCount": "MaxConcurrentCount",
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"Parity": "Parity",
|
||||
"PortName": "PortName",
|
||||
"RemoteUrl": "RemoteUrl",
|
||||
"RtsEnable": "RtsEnable",
|
||||
"StopBits": "StopBits"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,88 +1,30 @@
|
||||
{
|
||||
"ThingsGateway.Debug.ChannelComponent": {
|
||||
"Name": "名称",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"ChannelType": "通道类型",
|
||||
"Enable": "启用",
|
||||
"LogEnable": "启用调试日志",
|
||||
|
||||
"RemoteUrl": "远程url",
|
||||
"BindUrl": "本地url",
|
||||
|
||||
"PortName": "COM口",
|
||||
"BaudRate": "波特率",
|
||||
"DataBits": "数据位",
|
||||
"Parity": "校验位",
|
||||
"StopBits": "停止位",
|
||||
"DtrEnable": "Dtr",
|
||||
"RtsEnable": "Rts",
|
||||
|
||||
|
||||
"SaveChannel": "添加/修改通道",
|
||||
"DeleteChannel": "删除通道",
|
||||
"BindUrl": "本地url",
|
||||
"Channel": "通道",
|
||||
"ChannelType": "通道类型",
|
||||
"ClearChannel": "清空通道",
|
||||
"Confim": "创建",
|
||||
"Connect": "连接",
|
||||
"DataBits": "数据位",
|
||||
"DeleteChannel": "删除通道",
|
||||
"Disconnect": "断开",
|
||||
"DtrEnable": "Dtr",
|
||||
"Enable": "启用",
|
||||
"ExportChannel": "导出通道",
|
||||
"ImportChannel": "导入通道",
|
||||
|
||||
"ImportNullError": "无法识别",
|
||||
|
||||
"NotOther": "不支持其他通道类型",
|
||||
"Connect": "连接",
|
||||
"Confim": "创建",
|
||||
"Disconnect": "断开",
|
||||
"Channel": "通道"
|
||||
},
|
||||
"ThingsGateway.Foundation.ChannelOptionsDefault": {
|
||||
"LogEnable": "启用调试日志",
|
||||
"Name": "名称",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"ChannelType": "通道类型",
|
||||
|
||||
"RemoteUrl": "远程url",
|
||||
"BindUrl": "本地url",
|
||||
|
||||
"PortName": "COM口",
|
||||
"BaudRate": "波特率",
|
||||
"DataBits": "数据位",
|
||||
"NotOther": "不支持其他通道类型",
|
||||
"Parity": "校验位",
|
||||
"StopBits": "停止位",
|
||||
"DtrEnable": "Dtr",
|
||||
"PortName": "COM口",
|
||||
"RemoteUrl": "远程url",
|
||||
"RtsEnable": "Rts",
|
||||
"CacheTimeout": "接收缓存超时",
|
||||
"ConnectTimeout": "连接超时",
|
||||
"MaxConcurrentCount": "最大并发数",
|
||||
|
||||
"MaxClientCount": "最大连接数",
|
||||
"CheckClearTime": "客户端连接滑动过期时间",
|
||||
"Heartbeat": "心跳内容(utf8)",
|
||||
"HeartbeatTime": "心跳间隔",
|
||||
"DtuId": "Dtu终端注册包(utf-8)",
|
||||
"DtuSeviceType": "DTU服务类型"
|
||||
},
|
||||
"ThingsGateway.Debug.DeviceComponentBase": {
|
||||
"WriteSuccess": "写入成功",
|
||||
"DefaultSend": "直接发送",
|
||||
"Send": "发送",
|
||||
"DataType": "数据类型",
|
||||
"RegisterAddress": "寄存器地址",
|
||||
"ArrayLength": "数组长度",
|
||||
"WriteValue": "写入值",
|
||||
"SendValue": "发送原始报文"
|
||||
},
|
||||
"ThingsGateway.Debug.DeviceComponent": {
|
||||
"HeaderText": "通道日志",
|
||||
"WriteSuccess": "写入成功",
|
||||
"DefaultSend": "直接发送",
|
||||
"Send": "发送",
|
||||
"DataType": "数据类型",
|
||||
"RegisterAddress": "寄存器地址",
|
||||
"ArrayLength": "数组长度",
|
||||
"WriteValue": "写入值",
|
||||
"SendValue": "发送原始报文",
|
||||
"CommonFunctions": "常用功能",
|
||||
"SpecialFunctions": "特殊功能",
|
||||
"Read": "读取",
|
||||
"Write": "写入",
|
||||
"MulRead": "多读"
|
||||
"SaveChannel": "添加/修改通道",
|
||||
"StopBits": "停止位"
|
||||
},
|
||||
"ThingsGateway.Debug.ChannelEditComponent": {
|
||||
"BasicInformation": "基础信息",
|
||||
@@ -90,5 +32,54 @@
|
||||
},
|
||||
"ThingsGateway.Debug.ConverterConfigComponent": {
|
||||
"Converter": "内置数据转换"
|
||||
},
|
||||
"ThingsGateway.Debug.DeviceComponent": {
|
||||
"ArrayLength": "数组长度",
|
||||
"CommonFunctions": "常用功能",
|
||||
"DataType": "数据类型",
|
||||
"DefaultSend": "直接发送",
|
||||
"HeaderText": "通道日志",
|
||||
"MulRead": "多读",
|
||||
"Read": "读取",
|
||||
"RegisterAddress": "寄存器地址",
|
||||
"Send": "发送",
|
||||
"SendValue": "发送原始报文",
|
||||
"SpecialFunctions": "特殊功能",
|
||||
"Write": "写入",
|
||||
"WriteSuccess": "写入成功",
|
||||
"WriteValue": "写入值"
|
||||
},
|
||||
"ThingsGateway.Debug.DeviceComponentBase": {
|
||||
"ArrayLength": "数组长度",
|
||||
"DataType": "数据类型",
|
||||
"DefaultSend": "直接发送",
|
||||
"RegisterAddress": "寄存器地址",
|
||||
"Send": "发送",
|
||||
"SendValue": "发送原始报文",
|
||||
"WriteSuccess": "写入成功",
|
||||
"WriteValue": "写入值"
|
||||
},
|
||||
"ThingsGateway.Foundation.ChannelOptionsDefault": {
|
||||
"BaudRate": "波特率",
|
||||
"BindUrl": "本地url",
|
||||
"CacheTimeout": "接收缓存超时",
|
||||
"ChannelType": "通道类型",
|
||||
"CheckClearTime": "客户端连接滑动过期时间",
|
||||
"ConnectTimeout": "连接超时",
|
||||
"DataBits": "数据位",
|
||||
"DtrEnable": "Dtr",
|
||||
"DtuId": "Dtu终端注册包(utf-8)",
|
||||
"DtuSeviceType": "DTU服务类型",
|
||||
"Heartbeat": "心跳内容(utf8)",
|
||||
"HeartbeatTime": "心跳间隔",
|
||||
"MaxClientCount": "最大连接数",
|
||||
"MaxConcurrentCount": "最大并发数",
|
||||
"Name": "名称",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"Parity": "校验位",
|
||||
"PortName": "COM口",
|
||||
"RemoteUrl": "远程url",
|
||||
"RtsEnable": "Rts",
|
||||
"StopBits": "停止位"
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,6 +10,10 @@
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using System.Globalization;
|
||||
|
||||
using ThingsGateway.Foundation;
|
||||
|
||||
namespace ThingsGateway.Debug;
|
||||
|
||||
[AppStartup(100000000)]
|
||||
@@ -18,6 +22,16 @@ public class Startup : AppStartup
|
||||
public void Configure(IServiceCollection services)
|
||||
{
|
||||
Foundation.LocalizerUtil.SetLocalizerFactory((a) => App.CreateLocalizerByType(a));
|
||||
|
||||
if (CultureInfo.CurrentUICulture.Name.StartsWith("zh", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
AppResource.Lang = Language.Chinese;
|
||||
}
|
||||
else
|
||||
{
|
||||
AppResource.Lang = Language.English;
|
||||
}
|
||||
|
||||
services.AddScoped<IPlatformService, PlatformService>();
|
||||
}
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@ public class UriValidationAttribute : ValidationAttribute
|
||||
{
|
||||
if (port <= 0 || port > 65535)
|
||||
{
|
||||
return new ValidationResult(DefaultResource.Localizer["InvalidPortRange"]);
|
||||
return new ValidationResult(AppResource.Localizer["InvalidPortRange"]);
|
||||
}
|
||||
}
|
||||
else if (Regex.IsMatch(uriString, ipv4Pattern))
|
||||
@@ -45,14 +45,14 @@ public class UriValidationAttribute : ValidationAttribute
|
||||
{
|
||||
if (int.Parse(segment) > 255)
|
||||
{
|
||||
return new ValidationResult(DefaultResource.Localizer["InvalidIPv4Segment"]);
|
||||
return new ValidationResult(AppResource.Localizer["InvalidIPv4Segment"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!Regex.IsMatch(uriString, ipv6Pattern) && !Regex.IsMatch(uriString, domainPattern))
|
||||
{
|
||||
// 其他格式验证失败
|
||||
return new ValidationResult(DefaultResource.Localizer["InvalidUriFormat"]);
|
||||
return new ValidationResult(AppResource.Localizer["InvalidUriFormat"]);
|
||||
}
|
||||
|
||||
// 验证通过
|
||||
|
@@ -103,28 +103,28 @@ namespace ThingsGateway.Foundation
|
||||
{
|
||||
if (string.IsNullOrEmpty(RemoteUrl))
|
||||
{
|
||||
yield return new ValidationResult(DefaultResource.Localizer["RemoteUrlNotNull"], new[] { nameof(RemoteUrl) });
|
||||
yield return new ValidationResult(AppResource.Localizer["RemoteUrlNotNull"], new[] { nameof(RemoteUrl) });
|
||||
}
|
||||
}
|
||||
else if (ChannelType == ChannelTypeEnum.TcpService)
|
||||
{
|
||||
if (string.IsNullOrEmpty(BindUrl))
|
||||
{
|
||||
yield return new ValidationResult(DefaultResource.Localizer["BindUrlNotNull"], new[] { nameof(BindUrl) });
|
||||
yield return new ValidationResult(AppResource.Localizer["BindUrlNotNull"], new[] { nameof(BindUrl) });
|
||||
}
|
||||
}
|
||||
else if (ChannelType == ChannelTypeEnum.UdpSession)
|
||||
{
|
||||
if (string.IsNullOrEmpty(BindUrl) && string.IsNullOrEmpty(RemoteUrl))
|
||||
{
|
||||
yield return new ValidationResult(DefaultResource.Localizer["BindUrlOrRemoteUrlNotNull"], new[] { nameof(BindUrl), nameof(RemoteUrl) });
|
||||
yield return new ValidationResult(AppResource.Localizer["BindUrlOrRemoteUrlNotNull"], new[] { nameof(BindUrl), nameof(RemoteUrl) });
|
||||
}
|
||||
}
|
||||
else if (ChannelType == ChannelTypeEnum.SerialPort)
|
||||
{
|
||||
if (string.IsNullOrEmpty(PortName))
|
||||
{
|
||||
yield return new ValidationResult(DefaultResource.Localizer["PortNameNotNull"], new[] { nameof(PortName) });
|
||||
yield return new ValidationResult(AppResource.Localizer["PortNameNotNull"], new[] { nameof(PortName) });
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -127,12 +127,12 @@ public class DDPTcpSessionClientChannel : TcpSessionClientChannel
|
||||
//发送成功
|
||||
await DDPAdapter.SendInputAsync(new DDPSend(ReadOnlyMemory<byte>.Empty, id, true, 0x81)).ConfigureAwait(false);
|
||||
if (log)
|
||||
Logger?.Info(DefaultResource.Localizer["DtuConnected", Id]);
|
||||
Logger?.Info(string.Format(AppResource.DtuConnected, Id));
|
||||
}
|
||||
else if (message.Type == 0x02)
|
||||
{
|
||||
await DDPAdapter.SendInputAsync(new DDPSend(ReadOnlyMemory<byte>.Empty, Id, true, 0x82)).ConfigureAwait(false);
|
||||
Logger?.Info(DefaultResource.Localizer["DtuDisconnecting", Id]);
|
||||
Logger?.Info(string.Format(AppResource.DtuDisconnecting, Id));
|
||||
await Task.Delay(100).ConfigureAwait(false);
|
||||
await this.CloseAsync().ConfigureAwait(false);
|
||||
this.SafeDispose();
|
||||
|
@@ -161,12 +161,12 @@ public class DDPUdpSessionChannel : UdpSessionChannel, IClientChannel, IDtuUdpSe
|
||||
//发送成功
|
||||
await DDPAdapter.SendInputAsync(endPoint, new DDPSend(ReadOnlyMemory<byte>.Empty, id, false, 0x81)).ConfigureAwait(false);
|
||||
if (log)
|
||||
Logger?.Info(DefaultResource.Localizer["DtuConnected", id]);
|
||||
Logger?.Info(string.Format(AppResource.DtuConnected, id));
|
||||
}
|
||||
else if (message.Type == 0x02)
|
||||
{
|
||||
await DDPAdapter.SendInputAsync(endPoint, new DDPSend(ReadOnlyMemory<byte>.Empty, id, false, 0x82)).ConfigureAwait(false);
|
||||
Logger?.Info(DefaultResource.Localizer["DtuDisconnecting", id]);
|
||||
Logger?.Info(string.Format(AppResource.DtuDisconnecting, id));
|
||||
await Task.Delay(100).ConfigureAwait(false);
|
||||
IdDict.TryRemove(endPoint, out _);
|
||||
EndPointDcit.TryRemove(id, out _);
|
||||
|
@@ -57,7 +57,7 @@ public class DtuPlugin : PluginBase, ITcpReceivingPlugin
|
||||
}
|
||||
}
|
||||
await socket.ResetIdAsync(id).ConfigureAwait(false);
|
||||
client.Logger?.Info(DefaultResource.Localizer["DtuConnected", id]);
|
||||
client.Logger?.Info(string.Format(AppResource.DtuConnected, id));
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
|
@@ -82,7 +82,7 @@ public abstract class TcpServiceChannelBase<TClient> : TcpService<TClient>, ITcp
|
||||
await base.StartAsync().ConfigureAwait(false);
|
||||
if (ServerState == ServerState.Running)
|
||||
{
|
||||
Logger?.Info($"{Monitors.FirstOrDefault()?.Option.IpHost}{DefaultResource.Localizer["ServiceStarted"]}");
|
||||
Logger?.Info($"{Monitors.FirstOrDefault()?.Option.IpHost}{AppResource.ServiceStarted}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,7 +108,7 @@ public abstract class TcpServiceChannelBase<TClient> : TcpService<TClient>, ITcp
|
||||
var iPHost = Monitors.FirstOrDefault()?.Option.IpHost;
|
||||
var result = await base.StopAsync(token).ConfigureAwait(false);
|
||||
if (!Monitors.Any())
|
||||
Logger?.Info($"{iPHost}{DefaultResource.Localizer["ServiceStoped"]}");
|
||||
Logger?.Info($"{iPHost}{AppResource.ServiceStoped}");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@@ -113,7 +113,7 @@ public class UdpSessionChannel : UdpSession, IClientChannel
|
||||
await base.StartAsync().ConfigureAwait(false);
|
||||
if (ServerState == ServerState.Running)
|
||||
{
|
||||
Logger?.Info($"{Monitor.IPHost}{DefaultResource.Localizer["ServiceStarted"]}");
|
||||
Logger?.Info($"{Monitor.IPHost}{AppResource.ServiceStarted}");
|
||||
await this.OnChannelEvent(Started).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -141,7 +141,7 @@ public class UdpSessionChannel : UdpSession, IClientChannel
|
||||
if (Monitor == null)
|
||||
{
|
||||
await this.OnChannelEvent(Stoped).ConfigureAwait(false);
|
||||
Logger?.Info($"{DefaultResource.Localizer["ServiceStoped"]}");
|
||||
Logger?.Info($"{AppResource.ServiceStoped}");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ namespace ThingsGateway.Foundation;
|
||||
/// <summary>
|
||||
/// TCP/Serial适配器基类
|
||||
/// </summary>
|
||||
public class DeviceSingleStreamDataHandleAdapter<TRequest> : CustomDataHandlingAdapter<TRequest> where TRequest : MessageBase, new()
|
||||
public class DeviceSingleStreamDataHandleAdapter<TRequest> : TcpCustomDataHandlingAdapter<TRequest> where TRequest : MessageBase, new()
|
||||
{
|
||||
/// <inheritdoc cref="DeviceSingleStreamDataHandleAdapter{TRequest}"/>
|
||||
public DeviceSingleStreamDataHandleAdapter()
|
||||
|
@@ -0,0 +1,329 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://touchsocket.net/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 用户自定义数据处理适配器,使用该适配器时,接收方收到的数据中,<see cref="ByteBlock"/>将为null,
|
||||
/// 同时<see cref="IRequestInfo"/>将实现为TRequest,发送数据直接发送。
|
||||
/// </summary>
|
||||
public abstract class TcpCustomDataHandlingAdapter<TRequest> : SingleStreamDataHandlingAdapter where TRequest : IRequestInfo
|
||||
{
|
||||
|
||||
private ValueByteBlock m_tempByteBlock;
|
||||
|
||||
private readonly Type m_requestType;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化自定义数据处理适配器。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 该构造函数在创建<see cref="TcpCustomDataHandlingAdapter{TRequest}"/>实例时,会指定请求类型。
|
||||
/// </remarks>
|
||||
public TcpCustomDataHandlingAdapter()
|
||||
{
|
||||
this.m_requestType = typeof(TRequest);
|
||||
}
|
||||
|
||||
|
||||
private TRequest m_tempRequest;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool CanSendRequestInfo => false;
|
||||
|
||||
/// <summary>
|
||||
/// 默认不支持拼接发送
|
||||
/// </summary>
|
||||
public override bool CanSplicingSend => false;
|
||||
|
||||
/// <summary>
|
||||
/// 指示需要解析当前包的剩余长度。如果不能得知,请赋值<see cref="int.MaxValue"/>。
|
||||
/// </summary>
|
||||
protected int SurLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 尝试解析请求数据块。
|
||||
/// </summary>
|
||||
/// <typeparam name="TByteBlock">字节块类型,必须实现IByteBlock接口。</typeparam>
|
||||
/// <param name="byteBlock">待解析的字节块。</param>
|
||||
/// <param name="request">解析出的请求对象。</param>
|
||||
/// <returns>解析是否成功。</returns>
|
||||
public bool TryParseRequest<TByteBlock>(ref TByteBlock byteBlock, out TRequest request) where TByteBlock : IByteBlock
|
||||
{
|
||||
// 检查缓存是否超时,如果超时则清除缓存。
|
||||
if (this.CacheTimeoutEnable && DateTimeOffset.UtcNow - this.LastCacheTime > this.CacheTimeout)
|
||||
{
|
||||
this.Reset();
|
||||
}
|
||||
|
||||
// 如果临时字节块为空,则尝试直接解析。
|
||||
if (this.m_tempByteBlock.IsEmpty)
|
||||
{
|
||||
return this.Single(ref byteBlock, out request) == FilterResult.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果剩余长度小于等于0,则抛出异常。
|
||||
if (this.SurLength <= 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
// 计算本次可以读取的长度。
|
||||
var len = Math.Min(this.SurLength, byteBlock.CanReadLength);
|
||||
|
||||
// 从输入字节块中读取数据到临时字节块中。
|
||||
var block = this.m_tempByteBlock;
|
||||
block.Write(byteBlock.Span.Slice(byteBlock.Position, len));
|
||||
byteBlock.Position += len;
|
||||
this.SurLength -= len;
|
||||
|
||||
// 重置临时字节块并准备下一次使用。
|
||||
this.m_tempByteBlock = ValueByteBlock.Empty;
|
||||
|
||||
// 回到字节块的起始位置。
|
||||
block.SeekToStart();
|
||||
try
|
||||
{
|
||||
// 尝试解析字节块。
|
||||
var filterResult = this.Single(ref block, out request);
|
||||
switch (filterResult)
|
||||
{
|
||||
case FilterResult.Cache:
|
||||
{
|
||||
// 如果临时字节块不为空,则继续缓存。
|
||||
if (!this.m_tempByteBlock.IsEmpty)
|
||||
{
|
||||
byteBlock.Position += this.m_tempByteBlock.Length;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case FilterResult.Success:
|
||||
{
|
||||
// 如果字节块中还有剩余数据,则回退指针。
|
||||
if (block.CanReadLength > 0)
|
||||
{
|
||||
byteBlock.Position -= block.CanReadLength;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case FilterResult.GoOn:
|
||||
default:
|
||||
// 对于需要继续解析的情况,也回退指针。
|
||||
if (block.CanReadLength > 0)
|
||||
{
|
||||
byteBlock.Position -= block.CanReadLength;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 释放字节块资源。
|
||||
block.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。
|
||||
/// <para>当不满足解析条件时,请返回<see cref="FilterResult.Cache"/>,此时会保存<see cref="ByteBlock.CanReadLength"/>的数据</para>
|
||||
/// <para>当数据部分异常时,请移动<see cref="ByteBlock.Position"/>到指定位置,然后返回<see cref="FilterResult.GoOn"/></para>
|
||||
/// <para>当完全满足解析条件时,请返回<see cref="FilterResult.Success"/>最后将<see cref="ByteBlock.Position"/>移至指定位置。</para>
|
||||
/// </summary>
|
||||
/// <param name="byteBlock">字节块</param>
|
||||
/// <param name="beCached">是否为上次遗留对象,当该参数为<see langword="true"/>时,request也将是上次实例化的对象。</param>
|
||||
/// <param name="request">对象。</param>
|
||||
/// <param name="tempCapacity">缓存容量。当需要首次缓存时,指示申请的ByteBlock的容量。合理的值可避免ByteBlock扩容带来的性能消耗。</param>
|
||||
/// <returns></returns>
|
||||
protected abstract FilterResult Filter<TByteBlock>(ref TByteBlock byteBlock, bool beCached, ref TRequest request, ref int tempCapacity)
|
||||
where TByteBlock : IByteBlock;
|
||||
|
||||
/// <summary>
|
||||
/// 成功执行接收以后。
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
protected virtual void OnReceivedSuccess(TRequest request)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 即将执行<see cref="SingleStreamDataHandlingAdapter.GoReceivedAsync(ByteBlock, IRequestInfo)"/>。
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>返回值标识是否继续执行</returns>
|
||||
protected virtual bool OnReceivingSuccess(TRequest request)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <param name="byteBlock"></param>
|
||||
protected override async Task PreviewReceivedAsync(ByteBlock byteBlock)
|
||||
{
|
||||
if (this.CacheTimeoutEnable && DateTimeOffset.UtcNow - this.LastCacheTime > this.CacheTimeout)
|
||||
{
|
||||
this.Reset();
|
||||
}
|
||||
if (this.m_tempByteBlock.IsEmpty)
|
||||
{
|
||||
await this.SingleAsync(byteBlock, false).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_tempByteBlock.Write(byteBlock.Span);
|
||||
var block = this.m_tempByteBlock;
|
||||
this.m_tempByteBlock = ValueByteBlock.Empty;
|
||||
await this.SingleAsync(block, true).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Reset()
|
||||
{
|
||||
this.m_tempByteBlock.SafeDispose();
|
||||
this.m_tempByteBlock = ValueByteBlock.Empty;
|
||||
this.m_tempRequest = default;
|
||||
this.SurLength = 0;
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断请求对象是否应该被缓存。
|
||||
/// </summary>
|
||||
/// <param name="request">请求对象。</param>
|
||||
/// <returns>返回布尔值,指示请求对象是否应该被缓存。</returns>
|
||||
protected virtual bool IsBeCached(in TRequest request)
|
||||
{
|
||||
// 如果请求对象类型是值类型,则判断其哈希码是否与默认值不同;
|
||||
// 如果是引用类型,则判断对象本身是否为null。
|
||||
return this.m_requestType.IsValueType ? request.GetHashCode() != default(TRequest).GetHashCode() : request != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理单个字节块,提取请求对象。
|
||||
/// </summary>
|
||||
/// <typeparam name="TByteBlock">字节块类型,需要实现IByteBlock接口。</typeparam>
|
||||
/// <param name="byteBlock">字节块,将被解析以提取请求对象。</param>
|
||||
/// <param name="request">输出参数,提取出的请求对象。</param>
|
||||
/// <returns>返回过滤结果,指示处理的状态。</returns>
|
||||
protected FilterResult Single<TByteBlock>(ref TByteBlock byteBlock, out TRequest request) where TByteBlock : IByteBlock
|
||||
{
|
||||
// 初始化临时缓存容量。
|
||||
var tempCapacity = 1024 * 64;
|
||||
// 执行过滤操作,根据是否应该缓存来决定如何处理字节块和请求对象。
|
||||
var filterResult = this.Filter(ref byteBlock, this.IsBeCached(this.m_tempRequest), ref this.m_tempRequest, ref tempCapacity);
|
||||
switch (filterResult)
|
||||
{
|
||||
case FilterResult.Success:
|
||||
// 如果过滤结果是成功,则设置请求对象并重置临时请求对象为默认值。
|
||||
request = this.m_tempRequest;
|
||||
this.m_tempRequest = default;
|
||||
return filterResult;
|
||||
|
||||
case FilterResult.Cache:
|
||||
// 如果过滤结果需要缓存,则创建一个新的字节块来缓存数据。
|
||||
if (byteBlock.CanReadLength > 0)
|
||||
{
|
||||
this.m_tempByteBlock = new ValueByteBlock(tempCapacity);
|
||||
this.m_tempByteBlock.Write(byteBlock.Span.Slice(byteBlock.Position, byteBlock.CanReadLength));
|
||||
|
||||
// 如果缓存的数据长度超过设定的最大包大小,则抛出异常。
|
||||
if (this.m_tempByteBlock.Length > this.MaxPackageSize)
|
||||
{
|
||||
throw new Exception("缓存的数据长度大于设定值的情况下未收到解析信号");
|
||||
}
|
||||
|
||||
// 将字节块指针移到末尾。
|
||||
byteBlock.SeekToEnd();
|
||||
}
|
||||
// 更新缓存时间。
|
||||
if (this.UpdateCacheTimeWhenRev)
|
||||
{
|
||||
this.LastCacheTime = DateTimeOffset.UtcNow;
|
||||
}
|
||||
request = default;
|
||||
return filterResult;
|
||||
|
||||
case FilterResult.GoOn:
|
||||
default:
|
||||
// 对于继续或默认的过滤结果,更新缓存时间。
|
||||
if (this.UpdateCacheTimeWhenRev)
|
||||
{
|
||||
this.LastCacheTime = DateTimeOffset.UtcNow;
|
||||
}
|
||||
request = default;
|
||||
return filterResult;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SingleAsync<TByteBlock>(TByteBlock byteBlock, bool temp) where TByteBlock : IByteBlock
|
||||
{
|
||||
byteBlock.Position = 0;
|
||||
while (byteBlock.Position < byteBlock.Length)
|
||||
{
|
||||
if (this.DisposedValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var tempCapacity = 1024 * 64;
|
||||
var filterResult = this.Filter(ref byteBlock, this.IsBeCached(this.m_tempRequest), ref this.m_tempRequest, ref tempCapacity);
|
||||
|
||||
switch (filterResult)
|
||||
{
|
||||
case FilterResult.Success:
|
||||
if (this.OnReceivingSuccess(this.m_tempRequest))
|
||||
{
|
||||
await this.GoReceivedAsync(null, this.m_tempRequest).ConfigureAwait(EasyTask.ContinueOnCapturedContext);
|
||||
this.OnReceivedSuccess(this.m_tempRequest);
|
||||
}
|
||||
this.m_tempRequest = default;
|
||||
break;
|
||||
|
||||
case FilterResult.Cache:
|
||||
//if (byteBlock.CanReadLength > 0)
|
||||
{
|
||||
if (temp)
|
||||
{
|
||||
this.m_tempByteBlock = new ValueByteBlock(tempCapacity);
|
||||
this.m_tempByteBlock.Write(byteBlock.Span);
|
||||
//this.m_tempByteBlock.Write(byteBlock.Span.Slice(byteBlock.Position, byteBlock.CanReadLength));
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_tempByteBlock = new ValueByteBlock(tempCapacity);
|
||||
this.m_tempByteBlock.Write(byteBlock.Span);
|
||||
//this.m_tempByteBlock.Write(byteBlock.Span.Slice(byteBlock.Position, byteBlock.CanReadLength));
|
||||
}
|
||||
|
||||
if (this.m_tempByteBlock.Length > this.MaxPackageSize)
|
||||
{
|
||||
this.OnError(default, "缓存的数据长度大于设定值的情况下未收到解析信号", true, true);
|
||||
}
|
||||
}
|
||||
if (this.UpdateCacheTimeWhenRev)
|
||||
{
|
||||
this.LastCacheTime = DateTimeOffset.UtcNow;
|
||||
}
|
||||
return;
|
||||
|
||||
case FilterResult.GoOn:
|
||||
if (this.UpdateCacheTimeWhenRev)
|
||||
{
|
||||
this.LastCacheTime = DateTimeOffset.UtcNow;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -256,7 +256,7 @@ public abstract class DeviceBase : DisposableObject, IDevice
|
||||
/// <inheritdoc/>
|
||||
public virtual string GetAddressDescription()
|
||||
{
|
||||
return DefaultResource.Localizer["DefaultAddressDes"];
|
||||
return AppResource.DefaultAddressDes;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取bit偏移量
|
||||
@@ -441,7 +441,7 @@ public abstract class DeviceBase : DisposableObject, IDevice
|
||||
{
|
||||
return new OperResult<IClientChannel>() { Content = client1 };
|
||||
}
|
||||
return (new OperResult<IClientChannel>(DefaultResource.Localizer["DtuNoConnectedWaining", socketId]));
|
||||
return (new OperResult<IClientChannel>(string.Format(AppResource.DtuNoConnectedWaining, socketId)));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -468,7 +468,7 @@ public abstract class DeviceBase : DisposableObject, IDevice
|
||||
{
|
||||
return endPoint1;
|
||||
}
|
||||
throw new Exception(DefaultResource.Localizer["DtuNoConnectedWaining", socketId]);
|
||||
throw new Exception(string.Format(AppResource.DtuNoConnectedWaining, socketId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,7 +602,7 @@ public abstract class DeviceBase : DisposableObject, IDevice
|
||||
DataTypeEnum.UInt64 => await ReadUInt64Async(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
|
||||
DataTypeEnum.Single => await ReadSingleAsync(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
|
||||
DataTypeEnum.Double => await ReadDoubleAsync(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
|
||||
_ => new OperResult<Array>(DefaultResource.Localizer["DataTypeNotSupported", dataType]),
|
||||
_ => new OperResult<Array>(string.Format(AppResource.DataTypeNotSupported, dataType)),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -627,7 +627,7 @@ public abstract class DeviceBase : DisposableObject, IDevice
|
||||
DataTypeEnum.UInt64 => await WriteAsync(address, jArray.ToObject<UInt64[]>(), cancellationToken: cancellationToken).ConfigureAwait(false),
|
||||
DataTypeEnum.Single => await WriteAsync(address, jArray.ToObject<Single[]>(), cancellationToken: cancellationToken).ConfigureAwait(false),
|
||||
DataTypeEnum.Double => await WriteAsync(address, jArray.ToObject<Double[]>(), cancellationToken: cancellationToken).ConfigureAwait(false),
|
||||
_ => new OperResult(DefaultResource.Localizer["DataTypeNotSupported", dataType]),
|
||||
_ => new OperResult(string.Format(AppResource.DataTypeNotSupported, dataType)),
|
||||
};
|
||||
}
|
||||
else
|
||||
@@ -645,7 +645,7 @@ public abstract class DeviceBase : DisposableObject, IDevice
|
||||
DataTypeEnum.UInt64 => await WriteAsync(address, value.ToObject<UInt64>(), bitConverter, cancellationToken).ConfigureAwait(false),
|
||||
DataTypeEnum.Single => await WriteAsync(address, value.ToObject<Single>(), bitConverter, cancellationToken).ConfigureAwait(false),
|
||||
DataTypeEnum.Double => await WriteAsync(address, value.ToObject<Double>(), bitConverter, cancellationToken).ConfigureAwait(false),
|
||||
_ => new OperResult(DefaultResource.Localizer["DataTypeNotSupported", dataType]),
|
||||
_ => new OperResult(string.Format(AppResource.DataTypeNotSupported, dataType)),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -740,7 +740,7 @@ public abstract class DeviceBase : DisposableObject, IDevice
|
||||
public virtual async ValueTask<OperResult<String[]>> ReadStringAsync(string address, int length, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
|
||||
if (bitConverter.StringLength == null) return new OperResult<String[]>(DefaultResource.Localizer["StringAddressError"]);
|
||||
if (bitConverter.StringLength == null) return new OperResult<String[]>(AppResource.StringAddressError);
|
||||
var len = bitConverter.StringLength * length;
|
||||
|
||||
var result = await ReadAsync(address, GetLength(address, len.Value, 1), cancellationToken).ConfigureAwait(false);
|
||||
@@ -908,7 +908,7 @@ public abstract class DeviceBase : DisposableObject, IDevice
|
||||
public virtual async ValueTask<OperResult> WriteAsync(string address, string[] value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
|
||||
if (bitConverter.StringLength == null) return new OperResult(DefaultResource.Localizer["StringAddressError"]);
|
||||
if (bitConverter.StringLength == null) return new OperResult(AppResource.StringAddressError);
|
||||
List<byte> bytes = new();
|
||||
foreach (var a in value)
|
||||
{
|
||||
|
@@ -8,8 +8,6 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using TouchSocket.Resources;
|
||||
|
||||
namespace ThingsGateway.Foundation;
|
||||
|
||||
/// <summary>
|
||||
@@ -148,7 +146,7 @@ public static partial class DeviceExtension
|
||||
case WaitDataStatus.Default:
|
||||
default:
|
||||
{
|
||||
return waitDataAsync.WaitResult == null ? new(new Exception(TouchSocketCoreResource.UnknownError)) : new(waitDataAsync.WaitResult);
|
||||
return waitDataAsync.WaitResult == null ? new(new Exception(AppResource.UnknownError)) : new(waitDataAsync.WaitResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
108
src/Foundation/ThingsGateway.Foundation/Locales/AppResource.cs
Normal file
108
src/Foundation/ThingsGateway.Foundation/Locales/AppResource.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace ThingsGateway.Foundation;
|
||||
|
||||
public enum Language { Chinese, English }
|
||||
|
||||
public static class AppResource
|
||||
{
|
||||
private static IStringLocalizer localizer;
|
||||
|
||||
/// <summary>
|
||||
/// Localizer
|
||||
/// </summary>
|
||||
public static IStringLocalizer Localizer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (localizer == null)
|
||||
{
|
||||
localizer = LocalizerUtil.GetLocalizer.Invoke(typeof(AppResource));
|
||||
}
|
||||
return localizer;
|
||||
}
|
||||
}
|
||||
|
||||
public static Language Lang { get; set; } = Language.Chinese;
|
||||
|
||||
|
||||
|
||||
public static string DefaultAddressDes => Lang == Language.Chinese ? ChineseResource.DefaultAddressDes : EnglishResource.DefaultAddressDes;
|
||||
public static string StringAddressError => Lang == Language.Chinese ? ChineseResource.StringAddressError : EnglishResource.StringAddressError;
|
||||
public static string ErrorMessage => Lang == Language.Chinese ? ChineseResource.ErrorMessage : EnglishResource.ErrorMessage;
|
||||
public static string Exception => Lang == Language.Chinese ? ChineseResource.Exception : EnglishResource.Exception;
|
||||
public static string ServiceStarted => Lang == Language.Chinese ? ChineseResource.ServiceStarted : EnglishResource.ServiceStarted;
|
||||
public static string ServiceStoped => Lang == Language.Chinese ? ChineseResource.ServiceStoped : EnglishResource.ServiceStoped;
|
||||
public static string StringTypePackError => Lang == Language.Chinese ? ChineseResource.StringTypePackError : EnglishResource.StringTypePackError;
|
||||
public static string UnknownError => Lang == Language.Chinese ? ChineseResource.UnknownError : EnglishResource.UnknownError;
|
||||
public static string DtuConnected => Lang == Language.Chinese ? ChineseResource.DtuConnected : EnglishResource.DtuConnected;
|
||||
public static string DtuDisconnecting => Lang == Language.Chinese ? ChineseResource.DtuDisconnecting : EnglishResource.DtuDisconnecting;
|
||||
public static string DtuNoConnectedWaining => Lang == Language.Chinese ? ChineseResource.DtuNoConnectedWaining : EnglishResource.DtuNoConnectedWaining;
|
||||
public static string DataTypeNotSupported => Lang == Language.Chinese ? ChineseResource.DataTypeNotSupported : EnglishResource.DataTypeNotSupported;
|
||||
public static string TransBytesError => Lang == Language.Chinese ? ChineseResource.TransBytesError : EnglishResource.TransBytesError;
|
||||
}
|
||||
|
||||
|
||||
public static class ChineseResource
|
||||
{
|
||||
public const string DefaultAddressDes = """
|
||||
————————————————————
|
||||
4字节数据转换格式:data=ABCD;可选ABCD=>Big-Endian;BADC=>Big-Endian Byte Swap;CDAB=>Little-Endian Byte Swap;DCBA=>Little-Endian。
|
||||
字符串长度:len=1。
|
||||
数组长度:arraylen=1。
|
||||
Bcd格式:bcd=C8421,可选C8421;C5421;C2421;C3;Gray。
|
||||
字符格式:encoding=UTF-8,可选UTF-8;ASCII;Default;Unicode等。
|
||||
————————————————————
|
||||
""";
|
||||
|
||||
public const string StringAddressError = "字符串读写必须在寄存器地址中指定长度,例如 len=10;";
|
||||
public const string ErrorMessage = "错误信息";
|
||||
public const string Exception = "异常堆栈";
|
||||
public const string ServiceStarted = "启动";
|
||||
public const string ServiceStoped = "停止";
|
||||
|
||||
public const string StringTypePackError = "数据类型为字符串时,必须指定字符串长度,才能进行打包,例如 len=10;";
|
||||
public const string UnknownError = "未知错误,错误代码:{0}";
|
||||
public const string DtuConnected = "Dtu标识 {0} 连接成功";
|
||||
public const string DtuDisconnecting = "Dtu标识 {0} 正在断开连接";
|
||||
public const string DtuNoConnectedWaining = "客户端(Dtu)未连接,id:{0}";
|
||||
public const string DataTypeNotSupported = "{0} 数据类型未实现";
|
||||
public const string TransBytesError = "转换失败-原始字节数组 {0},长度 {1}";
|
||||
}
|
||||
|
||||
public static class EnglishResource
|
||||
{
|
||||
public const string DefaultAddressDes = """
|
||||
————————————————————
|
||||
4-byte data conversion format: data=ABCD; options: ABCD=>Big-Endian; BADC=>Big-Endian Byte Swap; CDAB=>Little-Endian Byte Swap; DCBA=>Little-Endian.
|
||||
String length: len=1.
|
||||
Array length: arraylen=1.
|
||||
BCD format: bcd=C8421, options: C8421; C5421; C2421; C3; Gray.
|
||||
Character encoding: encoding=UTF-8, options: UTF-8; ASCII; Default; Unicode, etc.
|
||||
————————————————————
|
||||
""";
|
||||
|
||||
public const string StringAddressError = "String read/write operations must specify length in the register address, e.g., len=10;";
|
||||
public const string ErrorMessage = "Error message";
|
||||
public const string Exception = "Exception stack trace";
|
||||
public const string ServiceStarted = "Started";
|
||||
public const string ServiceStoped = "Stopped";
|
||||
|
||||
public const string StringTypePackError = "When data type is string, the string length must be specified for packing, e.g., len=10;";
|
||||
public const string UnknownError = "Unknown error, error code: {0}";
|
||||
public const string DtuConnected = "DTU identifier {0} connected successfully";
|
||||
public const string DtuDisconnecting = "DTU identifier {0} is disconnecting";
|
||||
public const string DtuNoConnectedWaining = "Client (DTU) not connected, id: {0}";
|
||||
public const string DataTypeNotSupported = "{0} data type not implemented";
|
||||
public const string TransBytesError = "Conversion failed - original byte array {0}, length {1}";
|
||||
}
|
@@ -1,10 +1,39 @@
|
||||
{
|
||||
"ThingsGateway.Foundation.DefaultResource": {
|
||||
"EmptyUriString": "The URI string cannot be null or consist only of whitespace.",
|
||||
"InvalidPortRange": "The URI string cannot be null or consist only of whitespace.",
|
||||
"InvalidIPv4Segment": "The URI string cannot be null or consist only of whitespace.",
|
||||
"InvalidUriFormat": "The provided URI string format is not valid.",
|
||||
|
||||
"ThingsGateway.Foundation.ChannelOptions": {
|
||||
"BaudRate": "BaudRate",
|
||||
"BindUrl": "BindUrl",
|
||||
"CacheTimeout": "CacheTimeout",
|
||||
"ChannelType": "ChannelType",
|
||||
"CheckClearTime": "CheckClearTime",
|
||||
"ConnectTimeout": "ConnectTimeout",
|
||||
"DataBits": "DataBits",
|
||||
"DtrEnable": "DtrEnable",
|
||||
"DtuId": "DtuId",
|
||||
"DtuSeviceType": "DtuSeviceType",
|
||||
"Heartbeat": "Heartbeat",
|
||||
"HeartbeatTime": "HeartbeatTime",
|
||||
"MaxClientCount": "MaxClientCount",
|
||||
"MaxConcurrentCount": "MaxConcurrentCount",
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"Parity": "Parity",
|
||||
"PortName": "PortName",
|
||||
"RemoteUrl": "RemoteUrl",
|
||||
"RtsEnable": "RtsEnable",
|
||||
"StopBits": "StopBits"
|
||||
},
|
||||
"ThingsGateway.Foundation.ConverterConfig": {
|
||||
"BcdFormat": "BcdFormat",
|
||||
"DataFormat": "DataFormat",
|
||||
"Encoding": "Encoding",
|
||||
"EncodingName": "EncodingName",
|
||||
"Stringlength": "Stringlength",
|
||||
"VariableStringLength": "VariableStringLength"
|
||||
},
|
||||
"ThingsGateway.Foundation.AppResource": {
|
||||
"BaudRateNotNull": "Baud Rate cannot be empty",
|
||||
"BindUrlNotNull": "Local Bind IP Address cannot be empty",
|
||||
"BindUrlOrRemoteUrlNotNull": "Remote IP Address or Local Bind IP Address cannot be empty",
|
||||
"CannotSendIRequestInfo": "The current adapter does not support object sending",
|
||||
"CannotSet": "Not allowed to freely call {0} for assignment",
|
||||
"CannotSplicingSend": "This adapter does not support splicing sending",
|
||||
@@ -13,90 +42,39 @@
|
||||
"Connected": "Connection successful",
|
||||
"Connecting": "Connecting",
|
||||
"ConnectTimeout": "Connection timed out",
|
||||
"DataBitsNotNull": "Data Bits can be empty",
|
||||
"DataLengthError": "Data length error {0}",
|
||||
"DataTypeNotSupported": "{0} data type not implemented",
|
||||
"DefaultAddressDes": "————————————————————\n 4-byte data conversion format: data=ABCD; Optional ABCD=>Big-Endian; BADC=>Big-Endian Byte Swap; CDAB=>Little-Endian Byte Swap; DCBA=>Little-Endian.\n String length: len=1.\n Array length: arraylen=1.\n Bcd format: bcd=C8421, optional C8421; C5421; C2421; C3; Gray.\n Character format: encoding=UTF-8, optional UTF-8; ASCII; Default; Unicode, etc.\n————————————————————",
|
||||
"Disconnected": "Disconnected",
|
||||
"Disconnecting": "Disconnecting",
|
||||
"DtuConnected": "Dtu identifier {0} connection successful",
|
||||
"DtuDisconnecting": "Dtu identifier {0} Disconnecting",
|
||||
"DtuNoConnectedWaining": "The Client(Dtu) is not connected, id: {0}",
|
||||
"ErrorMessage": "Error message",
|
||||
"EmptyUriString": "The URI string cannot be null or consist only of whitespace.",
|
||||
"EventError": "Error occurred in event {0}",
|
||||
"Exception": "Exception stack",
|
||||
"InvalidIPv4Segment": "The URI string cannot be null or consist only of whitespace.",
|
||||
"InvalidPortRange": "The URI string cannot be null or consist only of whitespace.",
|
||||
"InvalidUriFormat": "The provided URI string format is not valid.",
|
||||
"LengthShortError": "Data length is insufficient, original data: {0}",
|
||||
"NotActiveQueryError": "Data received correctly, but the host did not actively request data",
|
||||
"ParityNotNull": "Parity cannot be empty",
|
||||
"PortNameNotNull": "COM Port cannot be empty",
|
||||
"ProactivelyDisconnect": " {0} Proactively disconnect",
|
||||
"ProcessReceiveError": "Error occurred in receiving {0}, error code {1}",
|
||||
"Receive": "Receive",
|
||||
"ReceiveError": "Error occurred while processing data",
|
||||
"RemoteClose": "Remote terminal closed",
|
||||
"RemoteUrlNotNull": "Remote IP Address cannot be empty",
|
||||
"Send": "Send",
|
||||
"SerialPortNotClient": "The new SerialPort must be in connected state",
|
||||
"ServiceStarted": "Started",
|
||||
"ServiceStoped": "Stopped",
|
||||
"StringAddressError": "String read and write must specify length in register address, for example len=10;",
|
||||
"TransBytesError": "Conversion failed - original byte array {0}, length {1}",
|
||||
"UnknownError": "Unknown error, code: {0}",
|
||||
"StringTypePackError": "When the data type is string, the string length must be specified in order to pack it",
|
||||
|
||||
"RemoteUrlNotNull": "Remote IP Address cannot be empty",
|
||||
"BindUrlNotNull": "Local Bind IP Address cannot be empty",
|
||||
"BindUrlOrRemoteUrlNotNull": "Remote IP Address or Local Bind IP Address cannot be empty",
|
||||
"PortNameNotNull": "COM Port cannot be empty",
|
||||
"BaudRateNotNull": "Baud Rate cannot be empty",
|
||||
"DataBitsNotNull": "Data Bits can be empty",
|
||||
"ParityNotNull": "Parity cannot be empty",
|
||||
"StopBitsNotNull": "Stop Bits cannot be empty"
|
||||
|
||||
},
|
||||
"ThingsGateway.Foundation.ChannelOptions": {
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"ChannelType": "ChannelType",
|
||||
|
||||
"RemoteUrl": "RemoteUrl",
|
||||
"BindUrl": "BindUrl",
|
||||
|
||||
"PortName": "PortName",
|
||||
"BaudRate": "BaudRate",
|
||||
"DataBits": "DataBits",
|
||||
"Parity": "Parity",
|
||||
"StopBits": "StopBits",
|
||||
"DtrEnable": "DtrEnable",
|
||||
"RtsEnable": "RtsEnable",
|
||||
"CacheTimeout": "CacheTimeout",
|
||||
"ConnectTimeout": "ConnectTimeout",
|
||||
"MaxConcurrentCount": "MaxConcurrentCount",
|
||||
|
||||
|
||||
"MaxClientCount": "MaxClientCount",
|
||||
"CheckClearTime": "CheckClearTime",
|
||||
"Heartbeat": "Heartbeat",
|
||||
"HeartbeatTime": "HeartbeatTime",
|
||||
"DtuId": "DtuId",
|
||||
"DtuSeviceType": "DtuSeviceType"
|
||||
},
|
||||
"ThingsGateway.Foundation.VariableClass": {
|
||||
"RegisterAddress": "RegisterAddress"
|
||||
},
|
||||
"ThingsGateway.Foundation.ConverterConfig": {
|
||||
"DataFormat": "DataFormat",
|
||||
"Encoding": "Encoding",
|
||||
"EncodingName": "EncodingName",
|
||||
"VariableStringLength": "VariableStringLength",
|
||||
"Stringlength": "Stringlength",
|
||||
"BcdFormat": "BcdFormat"
|
||||
},
|
||||
|
||||
"ThingsGateway.Foundation.DeviceBase": {
|
||||
|
||||
"SendDelayTime": "SendDelayTime",
|
||||
"DataFormat": "DataFormat",
|
||||
"Timeout": "Timeout",
|
||||
"IsStringReverseByteWord": "IsStringReverseByteWord"
|
||||
"IsStringReverseByteWord": "IsStringReverseByteWord",
|
||||
"SendDelayTime": "SendDelayTime",
|
||||
"Timeout": "Timeout"
|
||||
},
|
||||
"ThingsGateway.Foundation.DtuServiceDeviceBase": {
|
||||
"DtuId": "DtuId(UTF8)"
|
||||
},
|
||||
"ThingsGateway.Foundation.VariableClass": {
|
||||
"RegisterAddress": "RegisterAddress"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,10 +1,39 @@
|
||||
{
|
||||
"ThingsGateway.Foundation.DefaultResource": {
|
||||
"EmptyUriString": "URI 字符串不能为空或仅包含空白字符",
|
||||
"InvalidPortRange": "端口号必须是 1 到 65535 之间的整数",
|
||||
"InvalidIPv4Segment": "IPv4 地址的每段数值必须在 0 到 255 之间",
|
||||
"InvalidUriFormat": "输入的 URI 字符串格式不符合要求",
|
||||
|
||||
"ThingsGateway.Foundation.ChannelOptions": {
|
||||
"BaudRate": "波特率",
|
||||
"BindUrl": "本地url",
|
||||
"CacheTimeout": "接收缓存超时",
|
||||
"ChannelType": "通道类型",
|
||||
"CheckClearTime": "客户端连接滑动过期时间",
|
||||
"ConnectTimeout": "连接超时",
|
||||
"DataBits": "数据位",
|
||||
"DtrEnable": "Dtr",
|
||||
"DtuId": "Dtu终端注册包(utf-8)",
|
||||
"DtuSeviceType": "DTU服务类型",
|
||||
"Heartbeat": "心跳内容(utf8)",
|
||||
"HeartbeatTime": "心跳间隔",
|
||||
"MaxClientCount": "最大连接数",
|
||||
"MaxConcurrentCount": "最大并发数",
|
||||
"Name": "名称",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"Parity": "校验位",
|
||||
"PortName": "COM口",
|
||||
"RemoteUrl": "远程url",
|
||||
"RtsEnable": "Rts",
|
||||
"StopBits": "停止位"
|
||||
},
|
||||
"ThingsGateway.Foundation.ConverterConfig": {
|
||||
"BcdFormat": "BCD格式",
|
||||
"DataFormat": "字节顺序",
|
||||
"Encoding": "字符串编码",
|
||||
"EncodingName": "字符串编码",
|
||||
"Stringlength": "字符串长度",
|
||||
"VariableStringLength": "变长字符串"
|
||||
},
|
||||
"ThingsGateway.Foundation.AppResource": {
|
||||
"BaudRateNotNull": "波特率不可为空",
|
||||
"BindUrlNotNull": "本地url不可为空",
|
||||
"BindUrlOrRemoteUrlNotNull": "远程url或本地url不可为空",
|
||||
"CannotSendIRequestInfo": "当前适配器不支持对象发送",
|
||||
"CannotSet": "不允许自由调用 {0} 进行赋值",
|
||||
"CannotSplicingSend": "该适配器不支持拼接发送",
|
||||
@@ -13,93 +42,39 @@
|
||||
"Connected": "连接成功",
|
||||
"Connecting": "正在连接",
|
||||
"ConnectTimeout": "连接超时",
|
||||
"DataBitsNotNull": "数据位可为空",
|
||||
"DataLengthError": "数据长度错误 {0}",
|
||||
"DataTypeNotSupported": "{0} 数据类型未实现",
|
||||
"DefaultAddressDes": "————————————————————\n 4字节数据转换格式:data=ABCD;可选ABCD=>Big-Endian;BADC=>Big-Endian Byte Swap;CDAB=>Little-Endian Byte Swap;DCBA=>Little-Endian。\n 字符串长度:len=1。\n 数组长度:arraylen=1。\n Bcd格式:bcd=C8421,可选C8421;C5421;C2421;C3;Gray。\n 字符格式:encoding=UTF-8,可选UTF-8;ASCII;Default;Unicode等。\n————————————————————",
|
||||
"Disconnected": "断开连接",
|
||||
"Disconnecting": "正在断开连接",
|
||||
"DtuConnected": "Dtu标识 {0} 连接成功",
|
||||
"DtuDisconnecting": "Dtu标识 {0} 正在断开连接",
|
||||
"DtuNoConnectedWaining": "客户端(Dtu)未连接,id:{0}",
|
||||
"ErrorMessage": "错误信息",
|
||||
"EmptyUriString": "URI 字符串不能为空或仅包含空白字符",
|
||||
"EventError": "在事件 {0} 中发生错误",
|
||||
"Exception": "异常堆栈",
|
||||
"InvalidIPv4Segment": "IPv4 地址的每段数值必须在 0 到 255 之间",
|
||||
"InvalidPortRange": "端口号必须是 1 到 65535 之间的整数",
|
||||
"InvalidUriFormat": "输入的 URI 字符串格式不符合要求",
|
||||
"LengthShortError": "数据长度不足,原始数据:{0}",
|
||||
"NotActiveQueryError": "接收数据正确,但主机并没有主动请求数据",
|
||||
"ParityNotNull": "校验位不可为空",
|
||||
"PortNameNotNull": "COM口不可为空",
|
||||
"ProactivelyDisconnect": " {0} 主动断开",
|
||||
"ProcessReceiveError": "接收出现错误 {0},错误代码 {1}",
|
||||
"Receive": "接收",
|
||||
"ReceiveError": "在处理数据时发生错误",
|
||||
"RemoteClose": "远程终端已关闭",
|
||||
"RemoteUrlNotNull": "远程url不可为空",
|
||||
"Send": "发送",
|
||||
"SerialPortNotClient": "新的SerialPort必须在连接状态",
|
||||
"ServiceStarted": "启动",
|
||||
"ServiceStoped": "停止",
|
||||
"StringAddressError": "字符串读写必须在寄存器地址中指定长度,例如 len=10;",
|
||||
"TransBytesError": "转换失败-原始字节数组 {0},长度 {1}",
|
||||
"UnknownError": "未知错误,错误代码:{0}",
|
||||
"StringTypePackError": "数据类型为字符串时,必须指定字符串长度,才能进行打包",
|
||||
|
||||
"RemoteUrlNotNull": "远程url不可为空",
|
||||
"BindUrlNotNull": "本地url不可为空",
|
||||
"BindUrlOrRemoteUrlNotNull": "远程url或本地url不可为空",
|
||||
"PortNameNotNull": "COM口不可为空",
|
||||
"BaudRateNotNull": "波特率不可为空",
|
||||
"DataBitsNotNull": "数据位可为空",
|
||||
"ParityNotNull": "校验位不可为空",
|
||||
"StopBitsNotNull": "停止位不可为空"
|
||||
|
||||
},
|
||||
|
||||
"ThingsGateway.Foundation.ChannelOptions": {
|
||||
"Name": "名称",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"ChannelType": "通道类型",
|
||||
|
||||
"RemoteUrl": "远程url",
|
||||
"BindUrl": "本地url",
|
||||
|
||||
"PortName": "COM口",
|
||||
"BaudRate": "波特率",
|
||||
"DataBits": "数据位",
|
||||
"Parity": "校验位",
|
||||
"StopBits": "停止位",
|
||||
"DtrEnable": "Dtr",
|
||||
"RtsEnable": "Rts",
|
||||
"CacheTimeout": "接收缓存超时",
|
||||
"ConnectTimeout": "连接超时",
|
||||
"MaxConcurrentCount": "最大并发数",
|
||||
|
||||
"MaxClientCount": "最大连接数",
|
||||
"CheckClearTime": "客户端连接滑动过期时间",
|
||||
"Heartbeat": "心跳内容(utf8)",
|
||||
"HeartbeatTime": "心跳间隔",
|
||||
"DtuId": "Dtu终端注册包(utf-8)",
|
||||
"DtuSeviceType": "DTU服务类型"
|
||||
|
||||
},
|
||||
"ThingsGateway.Foundation.VariableClass": {
|
||||
"RegisterAddress": "寄存器地址"
|
||||
},
|
||||
"ThingsGateway.Foundation.ConverterConfig": {
|
||||
"DataFormat": "字节顺序",
|
||||
"Encoding": "字符串编码",
|
||||
"EncodingName": "字符串编码",
|
||||
"VariableStringLength": "变长字符串",
|
||||
"Stringlength": "字符串长度",
|
||||
"BcdFormat": "BCD格式"
|
||||
},
|
||||
|
||||
"ThingsGateway.Foundation.DeviceBase": {
|
||||
|
||||
"SendDelayTime": "发送延时",
|
||||
"DataFormat": "解析规则",
|
||||
"Timeout": "读写超时",
|
||||
"IsStringReverseByteWord": "字符串反转"
|
||||
"IsStringReverseByteWord": "字符串反转",
|
||||
"SendDelayTime": "发送延时",
|
||||
"Timeout": "读写超时"
|
||||
},
|
||||
"ThingsGateway.Foundation.DtuServiceDeviceBase": {
|
||||
"DtuId": "Dtu注册包(UTF8)"
|
||||
|
||||
},
|
||||
"ThingsGateway.Foundation.VariableClass": {
|
||||
"RegisterAddress": "寄存器地址"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -117,8 +117,8 @@ public struct OperResult<T> : IOperResult<T>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
string messageString = ErrorMessage == null ? string.Empty : $"{DefaultResource.Localizer["ErrorMessage"]}:{ErrorMessage}";
|
||||
string exceptionString = Exception == null ? string.Empty : ErrorMessage == null ? $"{DefaultResource.Localizer["Exception"]}:{Exception}" : $"{Environment.NewLine}{DefaultResource.Localizer["Exception"]}:{Exception}";
|
||||
string messageString = ErrorMessage == null ? string.Empty : $"{AppResource.ErrorMessage}:{ErrorMessage}";
|
||||
string exceptionString = Exception == null ? string.Empty : ErrorMessage == null ? $"{AppResource.Exception}:{Exception}" : $"{Environment.NewLine}{AppResource.Exception}:{Exception}";
|
||||
|
||||
return $"{messageString}{exceptionString}";
|
||||
}
|
||||
@@ -239,8 +239,8 @@ public struct OperResult<T, T2> : IOperResult<T, T2>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
string messageString = ErrorMessage == null ? string.Empty : $"{DefaultResource.Localizer["ErrorMessage"]}:{ErrorMessage}";
|
||||
string exceptionString = Exception == null ? string.Empty : ErrorMessage == null ? $"{DefaultResource.Localizer["Exception"]}:{Exception}" : $"{Environment.NewLine}{DefaultResource.Localizer["Exception"]}:{Exception}";
|
||||
string messageString = ErrorMessage == null ? string.Empty : $"{AppResource.ErrorMessage}:{ErrorMessage}";
|
||||
string exceptionString = Exception == null ? string.Empty : ErrorMessage == null ? $"{AppResource.Exception}:{Exception}" : $"{Environment.NewLine}{AppResource.Exception}:{Exception}";
|
||||
|
||||
return $"{messageString}{exceptionString}";
|
||||
}
|
||||
@@ -355,8 +355,8 @@ public struct OperResult<T, T2, T3> : IOperResult<T, T2, T3>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
string messageString = ErrorMessage == null ? string.Empty : $"{DefaultResource.Localizer["ErrorMessage"]}:{ErrorMessage}";
|
||||
string exceptionString = Exception == null ? string.Empty : ErrorMessage == null ? $"{DefaultResource.Localizer["Exception"]}:{Exception}" : $"{Environment.NewLine}{DefaultResource.Localizer["Exception"]}:{Exception}";
|
||||
string messageString = ErrorMessage == null ? string.Empty : $"{AppResource.ErrorMessage}:{ErrorMessage}";
|
||||
string exceptionString = Exception == null ? string.Empty : ErrorMessage == null ? $"{AppResource.Exception}:{Exception}" : $"{Environment.NewLine}{AppResource.Exception}:{Exception}";
|
||||
|
||||
return $"{messageString}{exceptionString}";
|
||||
}
|
||||
@@ -468,8 +468,8 @@ public struct OperResult : IOperResult
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
string messageString = ErrorMessage == null ? string.Empty : $"{DefaultResource.Localizer["ErrorMessage"]}:{ErrorMessage}";
|
||||
string exceptionString = Exception == null ? string.Empty : ErrorMessage == null ? $"{DefaultResource.Localizer["Exception"]}:{Exception}" : $"{Environment.NewLine}{DefaultResource.Localizer["Exception"]}:{Exception}";
|
||||
string messageString = ErrorMessage == null ? string.Empty : $"{AppResource.ErrorMessage}:{ErrorMessage}";
|
||||
string exceptionString = Exception == null ? string.Empty : ErrorMessage == null ? $"{AppResource.Exception}:{Exception}" : $"{Environment.NewLine}{AppResource.Exception}:{Exception}";
|
||||
|
||||
return $"{messageString}{exceptionString}";
|
||||
}
|
||||
|
@@ -117,8 +117,8 @@ public class OperResultClass : IOperResult
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
string messageString = ErrorMessage == null ? string.Empty : $"{DefaultResource.Localizer["ErrorMessage"]}:{ErrorMessage}";
|
||||
string exceptionString = Exception == null ? string.Empty : ErrorMessage == null ? $"{DefaultResource.Localizer["Exception"]}:{Exception}" : $"{Environment.NewLine}{DefaultResource.Localizer["Exception"]}:{Exception}";
|
||||
string messageString = ErrorMessage == null ? string.Empty : $"{AppResource.ErrorMessage}:{ErrorMessage}";
|
||||
string exceptionString = Exception == null ? string.Empty : ErrorMessage == null ? $"{AppResource.Exception}:{Exception}" : $"{Environment.NewLine}{AppResource.Exception}:{Exception}";
|
||||
|
||||
return $"{messageString}{exceptionString}";
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ public static class OperResultExtension
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult<TResult>(DefaultResource.Localizer["TransBytesError", result.Content?.ToHexString(' '), result.Content?.Length], ex);
|
||||
return new OperResult<TResult>(string.Format(AppResource.TransBytesError, result.Content?.ToHexString(' '), result.Content?.Length), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -10,8 +10,6 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
using ThingsGateway.Extension.Generic;
|
||||
using ThingsGateway.NewLife;
|
||||
using ThingsGateway.NewLife.Extension;
|
||||
@@ -55,18 +53,6 @@ public abstract class BusinessBase : DriverBase
|
||||
|
||||
protected abstract BusinessPropertyBase _businessPropertyBase { get; }
|
||||
|
||||
protected IStringLocalizer BusinessBaseLocalizer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化方法,用于初始化设备运行时。
|
||||
/// </summary>
|
||||
/// <param name="device">设备运行时实例。</param>
|
||||
internal override void ProtectedInitDevice(DeviceRuntime device)
|
||||
{
|
||||
BusinessBaseLocalizer = App.CreateLocalizerByType(typeof(BusinessBase))!;
|
||||
base.ProtectedInitDevice(device); // 调用基类的初始化方法
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前关联的变量
|
||||
/// </summary>
|
||||
|
@@ -67,7 +67,7 @@ public abstract class BusinessBaseWithCacheAlarmModel<VarModel, DevModel, AlarmM
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "Add cache fail");
|
||||
LogMessage?.LogWarning(ex, "Add cache fail");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -68,7 +68,7 @@ public abstract class BusinessBaseWithCacheDeviceModel<VarModel, DevModel> : Bus
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "Add cache fail");
|
||||
LogMessage?.LogWarning(ex, "Add cache fail");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -70,7 +70,7 @@ public abstract class BusinessBaseWithCacheVariableModel<VarModel> : BusinessBas
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "Add cache fail");
|
||||
LogMessage?.LogWarning(ex, "Add cache fail");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ public abstract class BusinessBaseWithCacheVariableModel<VarModel> : BusinessBas
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "Add cache fail");
|
||||
LogMessage?.LogWarning(ex, "Add cache fail");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -162,7 +162,7 @@ public abstract class BusinessBaseWithCacheIntervalAlarmModel<VarModel, DevModel
|
||||
{
|
||||
if (_exTTimerTick.IsTickHappen())
|
||||
{
|
||||
if (LogMessage.LogLevel <= LogLevel.Debug)
|
||||
if (LogMessage?.LogLevel <= LogLevel.Debug)
|
||||
LogMessage?.LogDebug($"Interval {typeof(VarModel).Name} data, count {IdVariableRuntimes.Count}");
|
||||
// 间隔推送全部变量
|
||||
var variableRuntimes = IdVariableRuntimes.Select(a => a.Value);
|
||||
@@ -171,7 +171,7 @@ public abstract class BusinessBaseWithCacheIntervalAlarmModel<VarModel, DevModel
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, BusinessBaseLocalizer["IntervalInsertVariableFail"]);
|
||||
LogMessage?.LogWarning(ex, AppResource.IntervalInsertVariableFail);
|
||||
}
|
||||
try
|
||||
{
|
||||
@@ -179,7 +179,7 @@ public abstract class BusinessBaseWithCacheIntervalAlarmModel<VarModel, DevModel
|
||||
{
|
||||
if (CollectDevices != null)
|
||||
{
|
||||
if (LogMessage.LogLevel <= LogLevel.Debug)
|
||||
if (LogMessage?.LogLevel <= LogLevel.Debug)
|
||||
LogMessage?.LogDebug($"Interval {typeof(DevModel).Name} data, count {CollectDevices.Count}");
|
||||
|
||||
// 间隔推送全部设备
|
||||
@@ -192,7 +192,7 @@ public abstract class BusinessBaseWithCacheIntervalAlarmModel<VarModel, DevModel
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, BusinessBaseLocalizer["IntervalInsertDeviceFail"]);
|
||||
LogMessage?.LogWarning(ex, AppResource.IntervalInsertDeviceFail);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -152,7 +152,7 @@ public abstract class BusinessBaseWithCacheIntervalDeviceModel<VarModel, DevMode
|
||||
{
|
||||
if (_exTTimerTick.IsTickHappen())
|
||||
{
|
||||
if (LogMessage.LogLevel <= LogLevel.Debug)
|
||||
if (LogMessage?.LogLevel <= LogLevel.Debug)
|
||||
LogMessage?.LogDebug($"Interval {typeof(VarModel).Name} data, count {IdVariableRuntimes.Count}");
|
||||
// 上传所有变量信息
|
||||
var variableRuntimes = IdVariableRuntimes.Select(a => a.Value);
|
||||
@@ -161,7 +161,7 @@ public abstract class BusinessBaseWithCacheIntervalDeviceModel<VarModel, DevMode
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, BusinessBaseLocalizer["IntervalInsertVariableFail"]);
|
||||
LogMessage?.LogWarning(ex, AppResource.IntervalInsertVariableFail);
|
||||
}
|
||||
|
||||
try
|
||||
@@ -170,7 +170,7 @@ public abstract class BusinessBaseWithCacheIntervalDeviceModel<VarModel, DevMode
|
||||
{
|
||||
if (CollectDevices != null)
|
||||
{
|
||||
if (LogMessage.LogLevel <= LogLevel.Debug)
|
||||
if (LogMessage?.LogLevel <= LogLevel.Debug)
|
||||
LogMessage?.LogDebug($"Interval {typeof(DevModel).Name} data, count {CollectDevices.Count}");
|
||||
// 上传所有设备信息
|
||||
foreach (var deviceRuntime in CollectDevices.Select(a => a.Value))
|
||||
@@ -182,7 +182,7 @@ public abstract class BusinessBaseWithCacheIntervalDeviceModel<VarModel, DevMode
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, BusinessBaseLocalizer["IntervalInsertDeviceFail"]);
|
||||
LogMessage?.LogWarning(ex, AppResource.IntervalInsertDeviceFail);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -110,7 +110,7 @@ public abstract class BusinessBaseWithCacheIntervalVariableModel<VarModel> : Bus
|
||||
{
|
||||
if (_exTTimerTick.IsTickHappen())
|
||||
{
|
||||
if (LogMessage.LogLevel <= LogLevel.Debug)
|
||||
if (LogMessage?.LogLevel <= LogLevel.Debug)
|
||||
LogMessage?.LogDebug($"Interval {typeof(VarModel).Name} data, count {IdVariableRuntimes.Count}");
|
||||
//间隔推送全部变量
|
||||
var variableRuntimes = IdVariableRuntimes.Select(a => a.Value);
|
||||
@@ -119,7 +119,7 @@ public abstract class BusinessBaseWithCacheIntervalVariableModel<VarModel> : Bus
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, BusinessBaseLocalizer["IntervalInsertVariableFail"]);
|
||||
LogMessage?.LogWarning(ex, AppResource.IntervalInsertVariableFail);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -10,7 +10,6 @@
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -45,8 +44,6 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
|
||||
public sealed override object DriverProperties => CollectProperties;
|
||||
|
||||
protected IStringLocalizer Localizer { get; set; }
|
||||
|
||||
public override async Task AfterVariablesChangedAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
LogMessage?.LogInformation("Refresh variable");
|
||||
@@ -103,7 +100,7 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
{
|
||||
// 如果出现异常,记录日志并初始化 VariableSourceReads 属性为新实例
|
||||
currentDevice.VariableSourceReads = new();
|
||||
LogMessage.LogWarning(ex, Localizer["VariablePackError", ex.Message]);
|
||||
LogMessage?.LogWarning(ex, string.Format(AppResource.VariablePackError, ex.Message));
|
||||
}
|
||||
try
|
||||
{
|
||||
@@ -127,7 +124,7 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
{
|
||||
// 如果出现异常,记录日志并初始化 ReadVariableMethods 和 VariableMethods 属性为新实例
|
||||
currentDevice.ReadVariableMethods ??= new();
|
||||
LogMessage.LogWarning(ex, Localizer["GetMethodError", ex.Message]);
|
||||
LogMessage?.LogWarning(ex, string.Format(AppResource.GetMethodError, ex.Message));
|
||||
}
|
||||
|
||||
// 根据标签获取方法信息的局部函数
|
||||
@@ -147,7 +144,7 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
else
|
||||
{
|
||||
// 如果找不到对应方法,抛出异常
|
||||
throw new(Localizer["MethodNotNull", item.Name, item.OtherMethod]);
|
||||
throw new(string.Format(AppResource.MethodNotNull, item.Name, item.OtherMethod));
|
||||
}
|
||||
}
|
||||
return variablesMethodResult;
|
||||
@@ -158,7 +155,6 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
{
|
||||
// 调用基类的初始化方法
|
||||
base.ProtectedInitDevice(device);
|
||||
Localizer = App.CreateLocalizerByType(typeof(CollectBase))!;
|
||||
|
||||
// 从插件服务中获取当前设备关联的驱动方法信息列表
|
||||
DriverMethodInfos = GlobalData.PluginService.GetDriverMethodInfos(device.PluginName, this);
|
||||
@@ -345,7 +341,7 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
if (await TestOnline(cancellationToken).ConfigureAwait(false))
|
||||
return true;
|
||||
readErrorCount++;
|
||||
if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace)
|
||||
if (LogMessage?.LogLevel <= TouchSocket.Core.LogLevel.Trace)
|
||||
LogMessage?.Trace(string.Format("{0} - Execute method[{1}] - failed - {2}", DeviceName, readVariableMethods.MethodInfo.Name, readResult.ErrorMessage));
|
||||
|
||||
LogMessage?.Trace(string.Format("{0} - Executing method[{1}]", DeviceName, readVariableMethods.MethodInfo.Name));
|
||||
@@ -355,7 +351,7 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
if (readResult.IsSuccess)
|
||||
{
|
||||
// 方法调用成功时记录日志并增加成功计数器
|
||||
if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace)
|
||||
if (LogMessage?.LogLevel <= TouchSocket.Core.LogLevel.Trace)
|
||||
LogMessage?.Trace(string.Format("{0} - Execute method[{1}] - Succeeded {2}", DeviceName, readVariableMethods.MethodInfo.Name, readResult.Content?.ToSystemTextJsonString()));
|
||||
readResultCount.deviceMethodsVariableSuccessNum++;
|
||||
CurrentDevice.SetDeviceStatus(TimerX.Now, false);
|
||||
@@ -369,12 +365,12 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
if (readVariableMethods.LastErrorMessage != readResult.ErrorMessage)
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
LogMessage?.LogWarning(readResult.Exception, Localizer["MethodFail", DeviceName, readVariableMethods.MethodInfo.Name, readResult.ErrorMessage]);
|
||||
LogMessage?.LogWarning(readResult.Exception, string.Format(AppResource.MethodFail, DeviceName, readVariableMethods.MethodInfo.Name, readResult.ErrorMessage));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace)
|
||||
if (LogMessage?.LogLevel <= TouchSocket.Core.LogLevel.Trace)
|
||||
LogMessage?.Trace(string.Format("{0} - Execute method[{1}] - failed - {2}", DeviceName, readVariableMethods.MethodInfo.Name, readResult.ErrorMessage));
|
||||
}
|
||||
|
||||
@@ -422,7 +418,7 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
if (await TestOnline(cancellationToken).ConfigureAwait(false))
|
||||
return true;
|
||||
readErrorCount++;
|
||||
if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace)
|
||||
if (LogMessage?.LogLevel <= TouchSocket.Core.LogLevel.Trace)
|
||||
LogMessage?.Trace(string.Format("{0} - Collection[{1} - {2}] failed - {3}", DeviceName, variableSourceRead?.RegisterAddress, variableSourceRead?.Length, readResult.ErrorMessage));
|
||||
|
||||
|
||||
@@ -433,7 +429,7 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
if (readResult.IsSuccess)
|
||||
{
|
||||
// 读取成功时记录日志并增加成功计数器
|
||||
if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace)
|
||||
if (LogMessage?.LogLevel <= TouchSocket.Core.LogLevel.Trace)
|
||||
LogMessage?.Trace(string.Format("{0} - Collection[{1} - {2}] data succeeded {3}", DeviceName, variableSourceRead?.RegisterAddress, variableSourceRead?.Length, readResult.Content?.ToHexString(' ')));
|
||||
readResultCount.deviceSourceVariableSuccessNum++;
|
||||
CurrentDevice.SetDeviceStatus(TimerX.Now, false);
|
||||
@@ -448,12 +444,12 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
if (variableSourceRead.LastErrorMessage != readResult.ErrorMessage)
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
LogMessage?.LogWarning(readResult.Exception, Localizer["CollectFail", DeviceName, variableSourceRead?.RegisterAddress, variableSourceRead?.Length, readResult.ErrorMessage]);
|
||||
LogMessage?.LogWarning(readResult.Exception, string.Format(AppResource.CollectFail, DeviceName, variableSourceRead?.RegisterAddress, variableSourceRead?.Length, readResult.ErrorMessage));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
if (LogMessage.LogLevel <= TouchSocket.Core.LogLevel.Trace)
|
||||
if (LogMessage?.LogLevel <= TouchSocket.Core.LogLevel.Trace)
|
||||
LogMessage?.Trace(string.Format("{0} - Collection[{1} - {2}] data failed - {3}", DeviceName, variableSourceRead?.RegisterAddress, variableSourceRead?.Length, readResult.ErrorMessage));
|
||||
}
|
||||
|
||||
@@ -573,7 +569,7 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 如果转换失败,则记录错误信息
|
||||
results.Add(deviceVariable.Name, new OperResult<object>(Localizer["WriteExpressionsError", deviceVariable.Name, deviceVariable.WriteExpressions, ex.Message], ex));
|
||||
results.Add(deviceVariable.Name, new OperResult<object>(string.Format(AppResource.WriteExpressionsError, deviceVariable.Name, deviceVariable.WriteExpressions, ex.Message), ex));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -649,7 +645,7 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 如果转换失败,则记录错误信息
|
||||
results.Add(deviceVariable.Name, new OperResult(Localizer["WriteExpressionsError", deviceVariable.Name, deviceVariable.WriteExpressions, ex.Message], ex));
|
||||
results.Add(deviceVariable.Name, new OperResult(string.Format(AppResource.WriteExpressionsError, deviceVariable.Name, deviceVariable.WriteExpressions, ex.Message), ex));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -702,7 +698,7 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
if (method == null)
|
||||
{
|
||||
result.OperCode = 999;
|
||||
result.ErrorMessage = Localizer["MethodNotNull", variableMethod.Variable.Name, variableMethod.Variable.OtherMethod];
|
||||
result.ErrorMessage = string.Format(AppResource.MethodNotNull, variableMethod.Variable.Name, variableMethod.Variable.OtherMethod);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
|
@@ -100,7 +100,7 @@ public abstract class CollectFoundationBase : CollectBase
|
||||
if (item.LastErrorMessage != exception.Message)
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
LogMessage?.LogWarning(exception, Localizer["CollectFail", DeviceName, item?.RegisterAddress, item?.Length, exception.Message]);
|
||||
LogMessage?.LogWarning(exception, string.Format(AppResource.CollectFail, DeviceName, item?.RegisterAddress, item?.Length, exception.Message));
|
||||
}
|
||||
item.LastErrorMessage = exception.Message;
|
||||
CurrentDevice.SetDeviceStatus(TimerX.Now, true, exception.Message);
|
||||
@@ -112,7 +112,7 @@ public abstract class CollectFoundationBase : CollectBase
|
||||
if (item.LastErrorMessage != exception.Message)
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
LogMessage?.LogWarning(exception, Localizer["MethodFail", DeviceName, item.MethodInfo.Name, exception.Message]);
|
||||
LogMessage?.LogWarning(exception, string.Format(AppResource.MethodFail, DeviceName, item.MethodInfo.Name, exception.Message));
|
||||
}
|
||||
item.LastErrorMessage = exception.Message;
|
||||
CurrentDevice.SetDeviceStatus(TimerX.Now, true, exception.Message);
|
||||
|
@@ -122,8 +122,7 @@ public abstract class DriverBase : DisposableObject, IDriver
|
||||
lock (this)
|
||||
{
|
||||
if (CurrentDevice == null) return;
|
||||
var str = pause == true ? "DeviceTaskPause" : "DeviceTaskContinue";
|
||||
LogMessage?.LogInformation(Localizer[str, DeviceName]);
|
||||
LogMessage?.LogInformation(pause == true ? string.Format(AppResource.DeviceTaskPause, DeviceName) : string.Format(AppResource.DeviceTaskContinue, DeviceName));
|
||||
CurrentDevice.Pause = pause;
|
||||
}
|
||||
}
|
||||
@@ -182,7 +181,7 @@ public abstract class DriverBase : DisposableObject, IDriver
|
||||
// 移除旧的文件日志记录器并释放资源
|
||||
if (TextLogger != null)
|
||||
{
|
||||
LogMessage.RemoveLogger(TextLogger);
|
||||
LogMessage?.RemoveLogger(TextLogger);
|
||||
TextLogger?.Dispose();
|
||||
}
|
||||
|
||||
@@ -190,7 +189,7 @@ public abstract class DriverBase : DisposableObject, IDriver
|
||||
TextLogger = TextFileLogger.GetMultipleFileLogger(LogPath);
|
||||
TextLogger.LogLevel = logLevel ?? TouchSocket.Core.LogLevel.Trace;
|
||||
// 将文件日志记录器添加到日志消息组中
|
||||
LogMessage.AddLogger(TextLogger);
|
||||
LogMessage?.AddLogger(TextLogger);
|
||||
}
|
||||
|
||||
private TextFileLogger? TextLogger;
|
||||
@@ -215,7 +214,7 @@ public abstract class DriverBase : DisposableObject, IDriver
|
||||
LogMessage = new LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Warning };//不显示调试日志
|
||||
|
||||
// 添加默认日志记录器
|
||||
LogMessage.AddLogger(new EasyLogger(Log_Out) { LogLevel = TouchSocket.Core.LogLevel.Trace });
|
||||
LogMessage?.AddLogger(new EasyLogger(Log_Out) { LogLevel = TouchSocket.Core.LogLevel.Trace });
|
||||
|
||||
SetLog(CurrentDevice.LogLevel);
|
||||
|
||||
@@ -255,7 +254,7 @@ public abstract class DriverBase : DisposableObject, IDriver
|
||||
{
|
||||
|
||||
// 记录设备任务开始信息
|
||||
LogMessage?.LogInformation(Localizer["DeviceTaskStart", DeviceName]);
|
||||
LogMessage?.LogInformation(string.Format(AppResource.DeviceTaskStart, DeviceName));
|
||||
|
||||
var timeout = 60; // 设置超时时间为 60 秒
|
||||
|
||||
@@ -271,7 +270,7 @@ public abstract class DriverBase : DisposableObject, IDriver
|
||||
catch (TimeoutException)
|
||||
{
|
||||
// 如果初始化操作超时,则记录警告信息
|
||||
LogMessage?.LogInformation(Localizer["DeviceTaskStartTimeout", DeviceName, timeout]);
|
||||
LogMessage?.LogInformation(string.Format(AppResource.DeviceTaskStartTimeout, DeviceName, timeout));
|
||||
}
|
||||
|
||||
// 设置设备状态为当前时间
|
||||
@@ -320,7 +319,7 @@ public abstract class DriverBase : DisposableObject, IDriver
|
||||
LogMessage?.LogError(ex, "Dispose");
|
||||
}
|
||||
// 记录设备线程已停止的信息
|
||||
LogMessage?.LogInformation(Localizer["DeviceTaskStop", DeviceName]);
|
||||
LogMessage?.LogInformation(string.Format(AppResource.DeviceTaskStop, DeviceName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,111 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
public static class AppResource
|
||||
{
|
||||
public static string RealAlarmTaskStart => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.RealAlarmTaskStart : EnglishResource.RealAlarmTaskStart;
|
||||
public static string IntervalInsertAlarmFail => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.IntervalInsertAlarmFail : EnglishResource.IntervalInsertAlarmFail;
|
||||
public static string IntervalInsertDeviceFail => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.IntervalInsertDeviceFail : EnglishResource.IntervalInsertDeviceFail;
|
||||
public static string IntervalInsertVariableFail => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.IntervalInsertVariableFail : EnglishResource.IntervalInsertVariableFail;
|
||||
public static string PluginNotFound => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.PluginNotFound : EnglishResource.PluginNotFound;
|
||||
public static string WriteVariable => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.WriteVariable : EnglishResource.WriteVariable;
|
||||
public static string VariablePackError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.VariablePackError : EnglishResource.VariablePackError;
|
||||
public static string GetMethodError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.GetMethodError : EnglishResource.GetMethodError;
|
||||
public static string MethodNotNull => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.MethodNotNull : EnglishResource.MethodNotNull;
|
||||
public static string MethodFail => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.MethodFail : EnglishResource.MethodFail;
|
||||
public static string CollectFail => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.CollectFail : EnglishResource.CollectFail;
|
||||
public static string CollectSuccess => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.CollectSuccess : EnglishResource.CollectSuccess;
|
||||
public static string WriteExpressionsError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.WriteExpressionsError : EnglishResource.WriteExpressionsError;
|
||||
public static string ChannelCreate => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ChannelCreate : EnglishResource.ChannelCreate;
|
||||
public static string ChannelDispose => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ChannelDispose : EnglishResource.ChannelDispose;
|
||||
public static string InitFail => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.InitFail : EnglishResource.InitFail;
|
||||
public static string DeviceTaskContinue => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.DeviceTaskContinue : EnglishResource.DeviceTaskContinue;
|
||||
public static string DeviceTaskPause => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.DeviceTaskPause : EnglishResource.DeviceTaskPause;
|
||||
public static string DeviceTaskStart => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.DeviceTaskStart : EnglishResource.DeviceTaskStart;
|
||||
public static string DeviceTaskStartTimeout => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.DeviceTaskStartTimeout : EnglishResource.DeviceTaskStartTimeout;
|
||||
public static string DeviceTaskStop => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.DeviceTaskStop : EnglishResource.DeviceTaskStop;
|
||||
public static string AddPluginFile => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.AddPluginFile : EnglishResource.AddPluginFile;
|
||||
public static string LoadOtherFileFail => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.LoadOtherFileFail : EnglishResource.LoadOtherFileFail;
|
||||
public static string LoadPluginFail => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.LoadPluginFail : EnglishResource.LoadPluginFail;
|
||||
public static string LoadTypeFail1 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.LoadTypeFail1 : EnglishResource.LoadTypeFail1;
|
||||
public static string LoadTypeFail2 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.LoadTypeFail2 : EnglishResource.LoadTypeFail2;
|
||||
public static string LoadTypeSuccess => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.LoadTypeSuccess : EnglishResource.LoadTypeSuccess;
|
||||
}
|
||||
|
||||
|
||||
public static class ChineseResource
|
||||
{
|
||||
|
||||
public const string RealAlarmTaskStart = "实时报警服务启动";
|
||||
public const string IntervalInsertAlarmFail = "间隔上传报警失败";
|
||||
public const string IntervalInsertDeviceFail = "间隔上传设备失败";
|
||||
public const string IntervalInsertVariableFail = "间隔上传变量失败";
|
||||
public const string PluginNotFound = "没有发现插件类型";
|
||||
public const string WriteVariable = "写入变量";
|
||||
public const string VariablePackError = "变量打包失败 {0} ";
|
||||
public const string GetMethodError = "插件方法初始化失败 {0} ";
|
||||
public const string MethodNotNull = "特殊方法变量 {0} 找不到执行方法 {1},请检查现有方法列表";
|
||||
public const string MethodFail = "{0} - 执行方法[{1}] - 失败 {2}";
|
||||
public const string CollectFail = "{0} - 采集[{1} - {2}] 数据失败 {3}";
|
||||
public const string CollectSuccess = "{0} - 采集[{1} - {2}] 数据成功 {3}";
|
||||
public const string WriteExpressionsError = " {0} 转换写入表达式 {1} 失败 {2} ";
|
||||
public const string ChannelCreate = "通道 {0} 创建";
|
||||
public const string ChannelDispose = "通道 {0} 销毁";
|
||||
public const string InitFail = "插件 {0} 设备 {1} 初始化失败";
|
||||
public const string DeviceTaskContinue = "设备 {0} 线程继续";
|
||||
public const string DeviceTaskPause = "设备 {0} 线程暂停";
|
||||
public const string DeviceTaskStart = "设备 {0} 线程开始";
|
||||
public const string DeviceTaskStartTimeout = "设备 {0} 线程启动超时 {1} s";
|
||||
public const string DeviceTaskStop = "设备 {0} 线程停止";
|
||||
|
||||
public const string AddPluginFile = "添加插件文件 {0}";
|
||||
public const string LoadOtherFileFail = "尝试加载附属程序集 {0} 失败,如果此程序集为DllImport,可以忽略此警告。";
|
||||
public const string LoadPluginFail = "加载插件 {0} 失败";
|
||||
public const string LoadTypeFail1 = "加载插件 {0} 失败,插件类型不存在";
|
||||
public const string LoadTypeFail2 = "加载插件文件 {0} 失败,文件不存在";
|
||||
public const string LoadTypeSuccess = "加载插件 {0} 成功";
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class EnglishResource
|
||||
{
|
||||
public const string RealAlarmTaskStart = "Real-time alarm service started";
|
||||
public const string IntervalInsertAlarmFail = "Failed to upload alarms periodically";
|
||||
public const string IntervalInsertDeviceFail = "Failed to upload device data periodically";
|
||||
public const string IntervalInsertVariableFail = "Failed to upload variable data periodically";
|
||||
public const string PluginNotFound = "No plugin type found";
|
||||
public const string WriteVariable = "Write variable";
|
||||
public const string VariablePackError = "Failed to pack variable {0}";
|
||||
public const string GetMethodError = "Failed to initialize plugin method {0}";
|
||||
public const string MethodNotNull = "Special method variable {0} could not find method {1}, please check the available method list";
|
||||
public const string MethodFail = "{0} - Method [{1}] execution failed {2}";
|
||||
public const string CollectFail = "{0} - Data collection failed [{1} - {2}] {3}";
|
||||
public const string CollectSuccess = "{0} - Data collected successfully [{1} - {2}] {3}";
|
||||
public const string WriteExpressionsError = "{0} failed to convert write expression {1} {2}";
|
||||
public const string ChannelCreate = "Channel {0} created";
|
||||
public const string ChannelDispose = "Channel {0} disposed";
|
||||
public const string InitFail = "Plugin {0}, device {1} initialization failed";
|
||||
public const string DeviceTaskContinue = "Device {0} thread resumed";
|
||||
public const string DeviceTaskPause = "Device {0} thread paused";
|
||||
public const string DeviceTaskStart = "Device {0} thread started";
|
||||
public const string DeviceTaskStartTimeout = "Device {0} thread start timed out after {1} seconds";
|
||||
public const string DeviceTaskStop = "Device {0} thread stopped";
|
||||
|
||||
public const string AddPluginFile = "Added plugin file {0}";
|
||||
public const string LoadOtherFileFail = "Failed to load dependent assembly {0}. If this is a DllImport assembly, this warning can be ignored.";
|
||||
public const string LoadPluginFail = "Failed to load plugin {0}";
|
||||
public const string LoadTypeFail1 = "Failed to load plugin {0}, plugin type not found";
|
||||
public const string LoadTypeFail2 = "Failed to load plugin file {0}, file does not exist";
|
||||
public const string LoadTypeSuccess = "Plugin {0} loaded successfully";
|
||||
}
|
@@ -1,499 +1,420 @@
|
||||
{
|
||||
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationDtuPackPropertyBase": {
|
||||
"DtuId": "DtuId(UTF8)"
|
||||
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationDtuPropertyBase": {
|
||||
"DtuId": "DtuId(UTF8)"
|
||||
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationPackPropertyBase": {
|
||||
|
||||
"MaxPack": "MaxPack"
|
||||
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationPropertyBase": {
|
||||
"DataFormat": "DataFormat",
|
||||
"IsStringReverseByteWord": "IsStringReverseByteWord",
|
||||
"Timeout": "Timeout",
|
||||
"SendDelayTime": "SendDelayTime"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectPropertyRetryBase": {
|
||||
"ReIntervalTime": "ReIntervalTime",
|
||||
"RetryCount": "RetryCount"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectPropertyBase": {
|
||||
"ReIntervalTime": "ReIntervalTime",
|
||||
"RetryCount": "RetryCount",
|
||||
"ConcurrentCount": "ConcurrentCount"
|
||||
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.BusinessPropertyWithCacheIntervalScript": {
|
||||
|
||||
"DetailLog": "DetailLog",
|
||||
"JsonFormattingIndented": "JsonFormattingIndented",
|
||||
|
||||
"BigTextScriptDeviceModel": "BigTextScriptDeviceModel",
|
||||
"BigTextScriptVariableModel": "BigTextScriptVariableModel",
|
||||
"BigTextScriptAlarmModel": "BigTextScriptAlarmModel",
|
||||
|
||||
"IsDeviceList": "IsDeviceList",
|
||||
"IsVariableList": "IsVariableList",
|
||||
"IsAlarmList": "IsAlarmList",
|
||||
|
||||
"DeviceTopic": "DeviceTopic",
|
||||
"VariableTopic": "VariableTopic",
|
||||
"AlarmTopic": "AlarmTopic"
|
||||
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.BusinessPropertyWithCacheInterval": {
|
||||
|
||||
"BusinessUpdateEnum": "BusinessUpdateEnum",
|
||||
"BusinessInterval": "BusinessInterval",
|
||||
"IsAllVariable": "IsAllVariable"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.BusinessPropertyWithCache": {
|
||||
|
||||
"QueueMaxCount": "QueueMaxCount",
|
||||
"CacheFileMaxLength": "CacheFileMaxLength",
|
||||
"SplitSize": "SplitSize",
|
||||
"CacheEnable": "CacheEnable",
|
||||
|
||||
"GroupUpdate": "GroupUpdate",
|
||||
"OnlineFilter": "OnlineFilter"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.BusinessUpdateEnum": {
|
||||
"Change": "Change",
|
||||
"Interval": "Interval",
|
||||
"IntervalOrChange": "IntervalOrChange"
|
||||
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.ControlController": {
|
||||
"ControlController": "Device control",
|
||||
"PauseDeviceThreadAsync": "Control device thread start/stop",
|
||||
"RestartDeviceThreadAsync": "Restart device thread",
|
||||
"WriteVariablesAsync": "Write variables",
|
||||
"RemoveAllCache": "Remove all cache",
|
||||
"RemoveCache": "Remove device/channel Cache",
|
||||
"RestartAllThread": "Restart all thread",
|
||||
"BatchSaveChannelAsync": "BatchSaveChannel",
|
||||
"BatchSaveDeviceAsync": "BatchSaveDevice",
|
||||
"BatchSaveVariableAsync": "BatchSaveVariable",
|
||||
"DeleteChannelAsync": "DeleteChannel",
|
||||
"DeleteDeviceAsync": "DeleteDevice",
|
||||
"DeleteVariableAsync": "DeleteVariable",
|
||||
"InsertTestDataAsync": "InsertTestData"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RuntimeInfoController": {
|
||||
"RuntimeInfoController": "Get runtime information",
|
||||
"GetDeviceListAsync": "Get device information",
|
||||
"GetChannelListAsync": "Get channel information",
|
||||
"GetVariableList": "Get variable information",
|
||||
"GetRealAlarmList": "Get real-time alarm information",
|
||||
"CheckRealAlarm": "Confirm real-time alarm"
|
||||
},
|
||||
|
||||
|
||||
"ThingsGateway.Gateway.Application.DeviceRuntime": {
|
||||
"SourceVariableCount": "SourceVariableCount",
|
||||
"MethodVariableCount": "MethodVariableCount",
|
||||
"ActiveTime": "ActiveTime",
|
||||
"DeviceVariableCount": "DeviceVariableCount",
|
||||
"LastErrorMessage": "LastErrorMessage",
|
||||
"DeviceStatus": "DeviceStatus",
|
||||
"RedundantType": "RedundantType",
|
||||
"PluginName": "PluginName",
|
||||
"Name.Required": " {0} cannot be empty",
|
||||
"ChannelName": "ChannelName",
|
||||
"IntervalTime.MinValue": " {0} value is too small",
|
||||
|
||||
"PluginName.Required": "{0} cannot be empty"
|
||||
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.VariableRuntime": {
|
||||
"ChangeTime": "ChangeTime",
|
||||
"CollectTime": "CollectTime",
|
||||
"DeviceName": "DeviceName",
|
||||
"IsOnline": "IsOnline",
|
||||
"LastErrorMessage": "LastErrorMessage",
|
||||
"LastSetValue": "LastSetValue",
|
||||
"RawValue": "RawValue",
|
||||
"RuntimeType": "RuntimeType",
|
||||
"Value": "Value",
|
||||
"AlarmEnable": "AlarmEnable",
|
||||
|
||||
"DeviceId.MinValue": "{0} cannot be empty",
|
||||
"DeviceId.Required": "{0} cannot be empty",
|
||||
"IntervalTime.MinValue": "{0} value is too small",
|
||||
"DynamicVariable": "DynamicVariable",
|
||||
|
||||
"ThingsGateway.Gateway.Application.AlarmVariable": {
|
||||
"AlarmCode": "AlarmCode",
|
||||
"RecoveryCode": "RecoveryCode",
|
||||
"AlarmDelay": "AlarmDelay",
|
||||
"AlarmEnable": "AlarmEnable",
|
||||
"AlarmLimit": "AlarmLimit",
|
||||
"AlarmText": "AlarmText",
|
||||
"AlarmTime": "AlarmTime",
|
||||
"AlarmType": "AlarmType",
|
||||
"EventTime": "EventTime",
|
||||
"EventType": "EventType"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.AlarmVariable": {
|
||||
"ChangeTime": "ChangeTime",
|
||||
"CollectTime": "CollectTime",
|
||||
"DeviceName": "DeviceName",
|
||||
"IsOnline": "IsOnline",
|
||||
"LastErrorMessage": "LastErrorMessage",
|
||||
"LastSetValue": "LastSetValue",
|
||||
"RawValue": "RawValue",
|
||||
"Value": "Value",
|
||||
"AlarmEnable": "AlarmEnable",
|
||||
"ArrayLength": "ArrayLength",
|
||||
"BoolCloseAlarmEnable": "BoolCloseAlarmEnable",
|
||||
"BoolCloseAlarmText": "BoolCloseAlarmText",
|
||||
"BoolCloseRestrainExpressions": "BoolCloseRestrainExpressions",
|
||||
"BoolOpenAlarmEnable": "BoolOpenAlarmEnable",
|
||||
"BoolOpenAlarmText": "BoolOpenAlarmText",
|
||||
"BoolOpenRestrainExpressions": "BoolOpenRestrainExpressions",
|
||||
"BusinessGroup": "BusinessGroup",
|
||||
"ChangeTime": "ChangeTime",
|
||||
"CollectGroup": "CollectGroup",
|
||||
"Name": "Name",
|
||||
"CollectTime": "CollectTime",
|
||||
"CustomAlarmCode": "CustomAlarmCode",
|
||||
"CustomAlarmEnable": "CustomAlarmEnable",
|
||||
"CustomAlarmText": "CustomAlarmText",
|
||||
"CustomRestrainExpressions": "CustomRestrainExpressions",
|
||||
"DataType": "DataType",
|
||||
"Description": "Description",
|
||||
"DeviceId": "CollectionDevice",
|
||||
"IntervalTime": "IntervalTime",
|
||||
"DeviceName": "DeviceName",
|
||||
"Enable": "Enable",
|
||||
"ProtectType": "ProtectType",
|
||||
"DataType": "DataType",
|
||||
"ReadExpressions": "ReadExpressions",
|
||||
"WriteExpressions": "WriteExpressions",
|
||||
"RpcWriteEnable": "RpcWriteEnable",
|
||||
"SaveValue": "SaveValue",
|
||||
"ArrayLength": "ArrayLength",
|
||||
|
||||
"AlarmDelay": "AlarmDelay",
|
||||
"BoolOpenAlarmEnable": "BoolOpenAlarmEnable",
|
||||
"BoolOpenRestrainExpressions": "BoolOpenRestrainExpressions",
|
||||
"BoolOpenAlarmText": "BoolOpenAlarmText",
|
||||
"BoolCloseAlarmEnable": "BoolCloseAlarmEnable",
|
||||
"BoolCloseRestrainExpressions": "BoolCloseRestrainExpressions",
|
||||
"BoolCloseAlarmText": "BoolCloseAlarmText",
|
||||
"HAlarmEnable": "HAlarmEnable",
|
||||
"HRestrainExpressions": "HRestrainExpressions",
|
||||
"HAlarmText": "HAlarmText",
|
||||
"EventTime": "EventTime",
|
||||
"EventType": "EventType",
|
||||
"HAlarmCode": "HAlarmCode",
|
||||
"HHAlarmEnable": "HHAlarmEnable",
|
||||
"HHRestrainExpressions": "HHRestrainExpressions",
|
||||
"HHAlarmText": "HHAlarmText",
|
||||
"HAlarmEnable": "HAlarmEnable",
|
||||
"HAlarmText": "HAlarmText",
|
||||
"HHAlarmCode": "HHAlarmCode",
|
||||
"LAlarmEnable": "LAlarmEnable",
|
||||
"LRestrainExpressions": "LRestrainExpressions",
|
||||
"LAlarmText": "LAlarmText",
|
||||
"HHAlarmEnable": "HHAlarmEnable",
|
||||
"HHAlarmText": "HHAlarmText",
|
||||
"HHRestrainExpressions": "HHRestrainExpressions",
|
||||
"HRestrainExpressions": "HRestrainExpressions",
|
||||
"IntervalTime": "IntervalTime",
|
||||
"IsOnline": "IsOnline",
|
||||
"LAlarmCode": "LAlarmCode",
|
||||
"LLAlarmEnable": "LLAlarmEnable",
|
||||
"LLRestrainExpressions": "LLRestrainExpressions",
|
||||
"LLAlarmText": "LLAlarmText",
|
||||
"LAlarmEnable": "LAlarmEnable",
|
||||
"LAlarmText": "LAlarmText",
|
||||
"LastErrorMessage": "LastErrorMessage",
|
||||
"LastSetValue": "LastSetValue",
|
||||
"LLAlarmCode": "LLAlarmCode",
|
||||
"CustomAlarmEnable": "CustomAlarmEnable",
|
||||
"CustomRestrainExpressions": "CustomRestrainExpressions",
|
||||
"CustomAlarmText": "CustomAlarmText",
|
||||
"CustomAlarmCode": "CustomAlarmCode",
|
||||
"Unit": "Unit",
|
||||
"RegisterAddress": "RegisterAddress",
|
||||
"LLAlarmEnable": "LLAlarmEnable",
|
||||
"LLAlarmText": "LLAlarmText",
|
||||
"LLRestrainExpressions": "LLRestrainExpressions",
|
||||
"LRestrainExpressions": "LRestrainExpressions",
|
||||
"Name": "Name",
|
||||
"OtherMethod": "OtherMethod",
|
||||
"ProtectType": "ProtectType",
|
||||
"RawValue": "RawValue",
|
||||
"ReadExpressions": "ReadExpressions",
|
||||
"RecoveryCode": "RecoveryCode",
|
||||
"RegisterAddress": "RegisterAddress",
|
||||
"Remark1": "Remark1",
|
||||
"Remark2": "Remark2",
|
||||
"Remark3": "Remark3",
|
||||
"Remark4": "Remark4",
|
||||
"Remark5": "Remark5",
|
||||
"AlarmCode": "AlarmCode",
|
||||
"RecoveryCode": "RecoveryCode",
|
||||
"AlarmLimit": "AlarmLimit",
|
||||
"AlarmText": "AlarmText",
|
||||
"AlarmTime": "AlarmTime",
|
||||
"AlarmType": "AlarmType",
|
||||
"EventTime": "EventTime",
|
||||
"EventType": "EventType"
|
||||
"RpcWriteEnable": "RpcWriteEnable",
|
||||
"SaveValue": "SaveValue",
|
||||
"Unit": "Unit",
|
||||
"Value": "Value",
|
||||
"WriteExpressions": "WriteExpressions"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.BackendLog": {
|
||||
"DeleteBackendLog": "Delete Backend Log",
|
||||
"Exception": "Exception Object",
|
||||
"LogLevel": "Log Level",
|
||||
"LogMessage": "Specific Message",
|
||||
"LogSource": "Log Source",
|
||||
"LogTime": "Time"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.BackendLogPageInput": {
|
||||
"LogLevel": "LogLevel",
|
||||
"LogSource": "LogSource",
|
||||
"SearchDate": "SearchDate"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.BusinessBase": {
|
||||
"IntervalInsertVariableFail": "Interval insert variable failed",
|
||||
"IntervalInsertDeviceFail": "Interval insert device failed",
|
||||
"IntervalInsertAlarmFail": "Interval insert alarm failed"
|
||||
"ThingsGateway.Gateway.Application.BusinessPropertyWithCache": {
|
||||
"CacheEnable": "CacheEnable",
|
||||
"CacheFileMaxLength": "CacheFileMaxLength",
|
||||
"GroupUpdate": "GroupUpdate",
|
||||
"OnlineFilter": "OnlineFilter",
|
||||
"QueueMaxCount": "QueueMaxCount",
|
||||
"SplitSize": "SplitSize"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectBase": {
|
||||
"VariablePackError": "Variable packaging failed {0}",
|
||||
"GetMethodError": "Plugin method initialization failed {0}",
|
||||
"MethodNotNull": "Special method variable {0} cannot find execution method {1}, please check the existing method list",
|
||||
"CollectFail": "{0} - Collection[{1} - {2}] data failed {3}",
|
||||
"CollectSuccess": "{0} - Collection[{1} - {2}] data succeeded {3}",
|
||||
"MethodFail": "{0} - Execute method[{1}] - Failed {2}",
|
||||
"MethodSuccess": "{0} - Execute method[{1}] - Succeeded {2}",
|
||||
"WriteExpressionsError": "{0} conversion write expression {1} failed {2}"
|
||||
"ThingsGateway.Gateway.Application.BusinessPropertyWithCacheInterval": {
|
||||
"BusinessInterval": "BusinessInterval",
|
||||
"BusinessUpdateEnum": "BusinessUpdateEnum",
|
||||
"IsAllVariable": "IsAllVariable"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.BusinessPropertyWithCacheIntervalScript": {
|
||||
"AlarmTopic": "AlarmTopic",
|
||||
"BigTextScriptAlarmModel": "BigTextScriptAlarmModel",
|
||||
"BigTextScriptDeviceModel": "BigTextScriptDeviceModel",
|
||||
"BigTextScriptVariableModel": "BigTextScriptVariableModel",
|
||||
"DetailLog": "DetailLog",
|
||||
"DeviceTopic": "DeviceTopic",
|
||||
"IsAlarmList": "IsAlarmList",
|
||||
"IsDeviceList": "IsDeviceList",
|
||||
"IsVariableList": "IsVariableList",
|
||||
"JsonFormattingIndented": "JsonFormattingIndented",
|
||||
"VariableTopic": "VariableTopic"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.BusinessUpdateEnum": {
|
||||
"Change": "Change",
|
||||
"Interval": "Interval",
|
||||
"IntervalOrChange": "IntervalOrChange"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.Channel": {
|
||||
"BaudRate": "BaudRate",
|
||||
"BindUrl": "BindUrl",
|
||||
"CacheTimeout": "CacheTimeout",
|
||||
"Channel": "Channel",
|
||||
"ChannelType": "ChannelType",
|
||||
"CheckClearTime": "CheckClearTime",
|
||||
"ClearChannel": "Clear Channel",
|
||||
"Confim": "Confim",
|
||||
"Connect": "Connect",
|
||||
"ConnectTimeout": "ConnectTimeout",
|
||||
"CopyChannel": "Copy Channel",
|
||||
"CreateTime": "CreateTime",
|
||||
"CreateUser": "CreateUser",
|
||||
"DataBits": "DataBits",
|
||||
"DeleteChannel": "Delete Channel",
|
||||
"Disconnect": "Disconnect",
|
||||
"DtrEnable": "DtrEnable",
|
||||
"DtuId": "DtuId",
|
||||
"DtuSeviceType": "DtuSeviceType",
|
||||
"Enable": "Enable",
|
||||
"ExportChannel": "Export Channel",
|
||||
"Heartbeat": "Heartbeat",
|
||||
"HeartbeatTime": "HeartbeatTime",
|
||||
"ImportChannel": "Import Channel",
|
||||
"ImportNullError": "Unable to recognize",
|
||||
"LogEnable": "LogEnable",
|
||||
"LogLevel": "LogLevel",
|
||||
"MaxClientCount": "MaxClientCount",
|
||||
"MaxConcurrentCount": "MaxConcurrentCount",
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"NameDump": "Duplicate channel name {0}",
|
||||
"NotOther": "Not supporting other channel types",
|
||||
"Parity": "Parity",
|
||||
"PluginName": "PluginName",
|
||||
"PluginName.Required": "{0} cannot be empty",
|
||||
"PortName": "PortName",
|
||||
"RemoteUrl": "RemoteUrl",
|
||||
"RtsEnable": "RtsEnable",
|
||||
"SaveChannel": "Add/Modify Channel",
|
||||
"SortCode": "SortCode",
|
||||
"StopBits": "StopBits",
|
||||
"UpdateTime": "UpdateTime",
|
||||
"UpdateUser": "UpdateUser"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.ChannelRuntime": {
|
||||
"DeviceRuntimeCount": "DeviceRuntimeCount",
|
||||
"MaxConcurrentCount": "MaxConcurrentCount",
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"PluginName.Required": "{0} cannot be empty",
|
||||
"PluginType": "PluginType"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationDtuPackPropertyBase": {
|
||||
"DtuId": "DtuId(UTF8)"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationDtuPropertyBase": {
|
||||
"DtuId": "DtuId(UTF8)"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationPackPropertyBase": {
|
||||
"MaxPack": "MaxPack"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationPropertyBase": {
|
||||
"DataFormat": "DataFormat",
|
||||
"IsStringReverseByteWord": "IsStringReverseByteWord",
|
||||
"SendDelayTime": "SendDelayTime",
|
||||
"Timeout": "Timeout"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectPropertyBase": {
|
||||
"ConcurrentCount": "ConcurrentCount",
|
||||
"ReIntervalTime": "ReIntervalTime",
|
||||
"RetryCount": "RetryCount"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectPropertyRetryBase": {
|
||||
"ReIntervalTime": "ReIntervalTime",
|
||||
"RetryCount": "RetryCount"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.ControlController": {
|
||||
"BatchSaveChannelAsync": "BatchSaveChannel",
|
||||
"BatchSaveDeviceAsync": "BatchSaveDevice",
|
||||
"BatchSaveVariableAsync": "BatchSaveVariable",
|
||||
"ControlController": "Device control",
|
||||
"DeleteChannelAsync": "DeleteChannel",
|
||||
"DeleteDeviceAsync": "DeleteDevice",
|
||||
"DeleteVariableAsync": "DeleteVariable",
|
||||
"InsertTestDataAsync": "InsertTestData",
|
||||
"PauseDeviceThreadAsync": "Control device thread start/stop",
|
||||
"RemoveAllCache": "Remove all cache",
|
||||
"RemoveCache": "Remove device/channel Cache",
|
||||
"RestartAllThread": "Restart all thread",
|
||||
"RestartDeviceThreadAsync": "Restart device thread",
|
||||
"WriteVariablesAsync": "Write variables"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.Device": {
|
||||
"ChannelError": "Channel error",
|
||||
"ChannelId": "Channel",
|
||||
"ChannelId.MinValue": "{0} cannot be empty",
|
||||
"ChannelId.Required": "{0} cannot be empty",
|
||||
"ClearDevice": "Clear Device",
|
||||
"CopyDevice": "Copy Device",
|
||||
"DeleteDevice": "Delete Device",
|
||||
"Description": "Description",
|
||||
"DeviceNotNull": "Device name does not exist",
|
||||
"Enable": "Enable",
|
||||
"ExportDevice": "Export Device",
|
||||
"ImportDevice": "Import Device",
|
||||
"ImportNullError": "Unable to recognize",
|
||||
"IntervalTime": "DefaultIntervalTime",
|
||||
"IntervalTime.MinValue": "{0} value is too small",
|
||||
"LogEnable": "LogEnable",
|
||||
"LogLevel": "LogLevel",
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"NameDump": "Duplicate device name {0}",
|
||||
"NotNull": "{0} does not exist",
|
||||
"PluginNotNull": "Plugin name does not exist",
|
||||
"RedundantDeviceError": "Redundant device error",
|
||||
"RedundantDeviceId": "RedundantDevice",
|
||||
"RedundantDeviceNotNull": "When enabling redundancy, you must select a redundant device",
|
||||
"RedundantEnable": "RedundantEnable",
|
||||
"RedundantScanIntervalTime": "RedundantScanIntervalTime",
|
||||
"RedundantScript": "RedundantScript",
|
||||
"RedundantSwitchType": "RedundantSwitchType",
|
||||
"Remark1": "Remark1",
|
||||
"Remark2": "Remark2",
|
||||
"Remark3": "Remark3",
|
||||
"Remark4": "Remark4",
|
||||
"Remark5": "Remark5",
|
||||
"SaveDevice": "Add/Modify Device"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.DeviceRuntime": {
|
||||
"ActiveTime": "ActiveTime",
|
||||
"ChannelName": "ChannelName",
|
||||
"DeviceStatus": "DeviceStatus",
|
||||
"DeviceVariableCount": "DeviceVariableCount",
|
||||
"IntervalTime.MinValue": " {0} value is too small",
|
||||
"LastErrorMessage": "LastErrorMessage",
|
||||
"MethodVariableCount": "MethodVariableCount",
|
||||
"Name.Required": " {0} cannot be empty",
|
||||
"PluginName": "PluginName",
|
||||
"PluginName.Required": "{0} cannot be empty",
|
||||
"RedundantType": "RedundantType",
|
||||
"SourceVariableCount": "SourceVariableCount"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.DriverBase": {
|
||||
"Authorized": "Authorized",
|
||||
"Unauthorized": "Unauthorized",
|
||||
"ExpireTime": "ExpireTime",
|
||||
"DeviceTaskStart": "Device {0} thread started",
|
||||
"DeviceTaskStartTimeout": "Device {0} thread start timeout {1} s",
|
||||
"DeviceTaskStop": "Device {0} thread stopped",
|
||||
"DeviceTaskPause": "Device {0} thread paused",
|
||||
"DeviceTaskContinue": "Device {0} thread continued"
|
||||
"Unauthorized": "Unauthorized"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.DeviceThreadManage": {
|
||||
"InitFail": "Plugin {0} device {1} initialization failed",
|
||||
"ChannelCreate": "channel {0} create",
|
||||
"ChannelDispose": "channel {0} dispose"
|
||||
|
||||
},
|
||||
|
||||
|
||||
"ThingsGateway.Gateway.Application.AlarmHostedService": {
|
||||
"RealAlarmTask": "Realtime alarm service",
|
||||
"RealAlarmTaskStart": "Realtime alarm service start"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.PluginService": {
|
||||
"LoadTypeSuccess": "Plugin {0} loaded successfully",
|
||||
"LoadTypeFail1": "Failed to load plugin {0}, plugin type does not exist",
|
||||
"LoadTypeFail2": "Failed to load plugin file {0}, file does not exist",
|
||||
"PluginNotFound": "No plugin type found",
|
||||
"LoadOtherFileFail": "Failed to attempt loading subsidiary assembly {0}, if this assembly is DllImport, this warning can be ignored",
|
||||
"LoadPluginFail": "Failed to load plugin {0}",
|
||||
"AddPluginFile": "Add plugin file {0}"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.PluginInfo": {
|
||||
"FullName": "FullName",
|
||||
"FileName": "FileName",
|
||||
"PluginType": "PluginType",
|
||||
"Name": "Name",
|
||||
"DeviceCount": "DeviceCount",
|
||||
"Version": "Version",
|
||||
"LastWriteTime": "CompilationTime"
|
||||
"ThingsGateway.Gateway.Application.ExportString": {
|
||||
"BusinessDeviceName": "BusinessDevice",
|
||||
"ChannelName": "Channel",
|
||||
"DeviceName": "Device",
|
||||
"RedundantDeviceName": "Redundant Device",
|
||||
"VariableName": "Variable"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.PluginAddInput": {
|
||||
"MainFile": "Main Assembly",
|
||||
"OtherFiles": "Auxiliary Assemblies, can upload multiple",
|
||||
"SavePlugin": "Add/Modify Plugin"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.BackendLog": {
|
||||
"LogTime": "Time",
|
||||
"LogLevel": "Log Level",
|
||||
"LogSource": "Log Source",
|
||||
"LogMessage": "Specific Message",
|
||||
"Exception": "Exception Object",
|
||||
"DeleteBackendLog": "Delete Backend Log"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RpcLog": {
|
||||
"LogTime": "LogTime",
|
||||
"OperateSource": "OperationSource",
|
||||
"OperateObject": "OperationObject",
|
||||
"OperateDevice": "OperateDevice",
|
||||
"OperateMethod": "RPCMethod",
|
||||
"IsSuccess": "OperationResult",
|
||||
"ParamJson": "RequestParameters",
|
||||
"ResultJson": "ReturnResults",
|
||||
"OperateMessage": "SpecificMessage",
|
||||
"DeleteRpc": "DeleteRPCLog"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.Device": {
|
||||
"ThingsGateway.Gateway.Application.PluginInfo": {
|
||||
"DeviceCount": "DeviceCount",
|
||||
"FileName": "FileName",
|
||||
"FullName": "FullName",
|
||||
"LastWriteTime": "CompilationTime",
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"Description": "Description",
|
||||
"ChannelId": "Channel",
|
||||
"ChannelId.MinValue": "{0} cannot be empty",
|
||||
"ChannelId.Required": "{0} cannot be empty",
|
||||
"IntervalTime": "DefaultIntervalTime",
|
||||
"IntervalTime.MinValue": "{0} value is too small",
|
||||
"LogEnable": "LogEnable",
|
||||
"LogLevel": "LogLevel",
|
||||
"Enable": "Enable",
|
||||
"RedundantEnable": "RedundantEnable",
|
||||
"RedundantDeviceId": "RedundantDevice",
|
||||
"RedundantSwitchType": "RedundantSwitchType",
|
||||
"RedundantScanIntervalTime": "RedundantScanIntervalTime",
|
||||
"RedundantScript": "RedundantScript",
|
||||
|
||||
"Remark1": "Remark1",
|
||||
"Remark2": "Remark2",
|
||||
"Remark3": "Remark3",
|
||||
"Remark4": "Remark4",
|
||||
"Remark5": "Remark5",
|
||||
"RedundantDeviceNotNull": "When enabling redundancy, you must select a redundant device",
|
||||
"SaveDevice": "Add/Modify Device",
|
||||
"CopyDevice": "Copy Device",
|
||||
"DeleteDevice": "Delete Device",
|
||||
"ClearDevice": "Clear Device",
|
||||
"ExportDevice": "Export Device",
|
||||
"ImportDevice": "Import Device",
|
||||
"ImportNullError": "Unable to recognize",
|
||||
"RedundantDeviceError": "Redundant device error",
|
||||
"ChannelError": "Channel error",
|
||||
"NotNull": "{0} does not exist",
|
||||
"DeviceNotNull": "Device name does not exist",
|
||||
"PluginNotNull": "Plugin name does not exist",
|
||||
"NameDump": "Duplicate device name {0}"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.ChannelRuntime": {
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"PluginName.Required": "{0} cannot be empty",
|
||||
"PluginType": "PluginType",
|
||||
"DeviceRuntimeCount": "DeviceRuntimeCount",
|
||||
"MaxConcurrentCount": "MaxConcurrentCount"
|
||||
|
||||
|
||||
"Version": "Version"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.Channel": {
|
||||
"SortCode": "SortCode",
|
||||
"CreateTime": "CreateTime",
|
||||
"CreateUser": "CreateUser",
|
||||
"UpdateTime": "UpdateTime",
|
||||
"UpdateUser": "UpdateUser",
|
||||
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"ChannelType": "ChannelType",
|
||||
"PluginName": "PluginName",
|
||||
"PluginName.Required": "{0} cannot be empty",
|
||||
"LogLevel": "LogLevel",
|
||||
|
||||
"Enable": "Enable",
|
||||
"LogEnable": "LogEnable",
|
||||
"RemoteUrl": "RemoteUrl",
|
||||
"BindUrl": "BindUrl",
|
||||
"PortName": "PortName",
|
||||
"BaudRate": "BaudRate",
|
||||
"DataBits": "DataBits",
|
||||
"Parity": "Parity",
|
||||
"StopBits": "StopBits",
|
||||
"DtrEnable": "DtrEnable",
|
||||
"RtsEnable": "RtsEnable",
|
||||
|
||||
"CacheTimeout": "CacheTimeout",
|
||||
"ConnectTimeout": "ConnectTimeout",
|
||||
"MaxConcurrentCount": "MaxConcurrentCount",
|
||||
"MaxClientCount": "MaxClientCount",
|
||||
"CheckClearTime": "CheckClearTime",
|
||||
"Heartbeat": "Heartbeat",
|
||||
"HeartbeatTime": "HeartbeatTime",
|
||||
"DtuId": "DtuId",
|
||||
"DtuSeviceType": "DtuSeviceType",
|
||||
|
||||
|
||||
"SaveChannel": "Add/Modify Channel",
|
||||
"CopyChannel": "Copy Channel",
|
||||
"DeleteChannel": "Delete Channel",
|
||||
"ClearChannel": "Clear Channel",
|
||||
"ExportChannel": "Export Channel",
|
||||
"ImportChannel": "Import Channel",
|
||||
"ImportNullError": "Unable to recognize",
|
||||
"NotOther": "Not supporting other channel types",
|
||||
"Connect": "Connect",
|
||||
"Confim": "Confim",
|
||||
"Disconnect": "Disconnect",
|
||||
"Channel": "Channel",
|
||||
"NameDump": "Duplicate channel name {0}"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.Variable": {
|
||||
"AddressOrOtherMethodNotNull": "Variable address or special method cannot be empty at the same time",
|
||||
"SaveVariable": "Add/Modify Variable",
|
||||
"CopyVariable": "Copy Variable",
|
||||
"DeleteVariable": "Copy Variable",
|
||||
"ClearVariable": "Clear Variable",
|
||||
"ExportVariable": "Export Variable",
|
||||
"ImportVariable": "Import Variable",
|
||||
"NotNull": "{0} does not exist",
|
||||
"DeviceNotNull": "Device name does not exist",
|
||||
"VariableNotNull": "Variable name does not exist",
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"Description": "Description",
|
||||
"BusinessGroup": "BusinessGroup",
|
||||
"CollectGroup": "CollectGroup",
|
||||
"DeviceId": "CollectionDevice",
|
||||
"DeviceId.MinValue": "{0} cannot be empty",
|
||||
"DeviceId.Required": "{0} cannot be empty",
|
||||
"IntervalTime": "IntervalTime",
|
||||
"IntervalTime.MinValue": "{0} value is too small",
|
||||
"Enable": "Enable",
|
||||
"ProtectType": "ProtectType",
|
||||
"DataType": "DataType",
|
||||
"ReadExpressions": "ReadExpressions",
|
||||
"WriteExpressions": "WriteExpressions",
|
||||
"RpcWriteEnable": "RpcWriteEnable",
|
||||
"InitValue": "InitValue",
|
||||
"SaveValue": "SaveValue",
|
||||
"DynamicVariable": "DynamicVariable",
|
||||
"AlarmDelay": "AlarmDelay",
|
||||
"BoolOpenAlarmEnable": "BoolOpenAlarmEnable",
|
||||
"BoolOpenRestrainExpressions": "BoolOpenRestrainExpressions",
|
||||
"BoolOpenAlarmText": "BoolOpenAlarmText",
|
||||
"BoolCloseAlarmEnable": "BoolCloseAlarmEnable",
|
||||
"BoolCloseRestrainExpressions": "BoolCloseRestrainExpressions",
|
||||
"BoolCloseAlarmText": "BoolCloseAlarmText",
|
||||
"HAlarmEnable": "HAlarmEnable",
|
||||
"HRestrainExpressions": "HRestrainExpressions",
|
||||
"HAlarmText": "HAlarmText",
|
||||
"HAlarmCode": "HAlarmCode",
|
||||
"HHAlarmEnable": "HHAlarmEnable",
|
||||
"HHRestrainExpressions": "HHRestrainExpressions",
|
||||
"HHAlarmText": "HHAlarmText",
|
||||
"HHAlarmCode": "HHAlarmCode",
|
||||
"LAlarmEnable": "LAlarmEnable",
|
||||
"LRestrainExpressions": "LRestrainExpressions",
|
||||
"LAlarmText": "LAlarmText",
|
||||
"LAlarmCode": "LAlarmCode",
|
||||
"LLAlarmEnable": "LLAlarmEnable",
|
||||
"LLRestrainExpressions": "LLRestrainExpressions",
|
||||
"LLAlarmText": "LLAlarmText",
|
||||
"LLAlarmCode": "LLAlarmCode",
|
||||
"CustomAlarmEnable": "CustomAlarmEnable",
|
||||
"CustomRestrainExpressions": "CustomRestrainExpressions",
|
||||
"CustomAlarmText": "CustomAlarmText",
|
||||
"CustomAlarmCode": "CustomAlarmCode",
|
||||
"Unit": "Unit",
|
||||
"RegisterAddress": "RegisterAddress",
|
||||
"OtherMethod": "OtherMethod",
|
||||
"Remark1": "Remark1",
|
||||
"Remark2": "Remark2",
|
||||
"Remark3": "Remark3",
|
||||
"Remark4": "Remark4",
|
||||
"Remark5": "Remark5",
|
||||
"NameDump": "Duplicate variable name {0}",
|
||||
"PluginNotNull": "Plugin name does not exist",
|
||||
"ArrayLength": "ArrayLength"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RpcLogPageInput": {
|
||||
"SearchDate": "SearchDate",
|
||||
"OperateObject": "OperateObject",
|
||||
"OperateDevice": "OperateDevice",
|
||||
"OperateSource": "OperateSource"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.BackendLogPageInput": {
|
||||
"SearchDate": "SearchDate",
|
||||
"LogLevel": "LogLevel",
|
||||
"LogSource": "LogSource"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RpcService": {
|
||||
"VariableNotNull": "{0} variable does not exist",
|
||||
"DeviceNotNull": "Device name does not exist",
|
||||
"VariableReadOnly": "{0} variable is read-only",
|
||||
"VariableWriteDisable": "{0} variable is not allowed to write",
|
||||
"DriverNotNull": "System error, corresponding collection device does not exist, please try again later",
|
||||
"DevicePause": "{0} device is paused",
|
||||
"WriteVariable": "Write Variable"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.ExportString": {
|
||||
"VariableName": "Variable",
|
||||
"RedundantDeviceName": "Redundant Device",
|
||||
"ChannelName": "Channel",
|
||||
"DeviceName": "Device",
|
||||
"BusinessDeviceName": "BusinessDevice"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.ProtectTypeEnum": {
|
||||
"ReadOnly": "ReadOnly",
|
||||
"ReadWrite": "ReadWrite",
|
||||
"WriteOnly": "WriteOnly"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RpcLog": {
|
||||
"DeleteRpc": "DeleteRPCLog",
|
||||
"IsSuccess": "OperationResult",
|
||||
"LogTime": "LogTime",
|
||||
"OperateDevice": "OperateDevice",
|
||||
"OperateMessage": "SpecificMessage",
|
||||
"OperateMethod": "RPCMethod",
|
||||
"OperateObject": "OperationObject",
|
||||
"OperateSource": "OperationSource",
|
||||
"ParamJson": "RequestParameters",
|
||||
"ResultJson": "ReturnResults"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RpcLogPageInput": {
|
||||
"OperateDevice": "OperateDevice",
|
||||
"OperateObject": "OperateObject",
|
||||
"OperateSource": "OperateSource",
|
||||
"SearchDate": "SearchDate"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RpcService": {
|
||||
"DeviceNotNull": "Device name does not exist",
|
||||
"DevicePause": "{0} device is paused",
|
||||
"DriverNotNull": "System error, corresponding collection device does not exist, please try again later",
|
||||
"VariableNotNull": "{0} variable does not exist",
|
||||
"VariableReadOnly": "{0} variable is read-only",
|
||||
"VariableWriteDisable": "{0} variable is not allowed to write"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RuntimeInfoController": {
|
||||
"CheckRealAlarm": "Confirm real-time alarm",
|
||||
"GetChannelListAsync": "Get channel information",
|
||||
"GetDeviceListAsync": "Get device information",
|
||||
"GetRealAlarmList": "Get real-time alarm information",
|
||||
"GetVariableList": "Get variable information",
|
||||
"RuntimeInfoController": "Get runtime information"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.Variable": {
|
||||
"AddressOrOtherMethodNotNull": "Variable address or special method cannot be empty at the same time",
|
||||
"AlarmDelay": "AlarmDelay",
|
||||
"ArrayLength": "ArrayLength",
|
||||
"BoolCloseAlarmEnable": "BoolCloseAlarmEnable",
|
||||
"BoolCloseAlarmText": "BoolCloseAlarmText",
|
||||
"BoolCloseRestrainExpressions": "BoolCloseRestrainExpressions",
|
||||
"BoolOpenAlarmEnable": "BoolOpenAlarmEnable",
|
||||
"BoolOpenAlarmText": "BoolOpenAlarmText",
|
||||
"BoolOpenRestrainExpressions": "BoolOpenRestrainExpressions",
|
||||
"BusinessGroup": "BusinessGroup",
|
||||
"ClearVariable": "Clear Variable",
|
||||
"CollectGroup": "CollectGroup",
|
||||
"CopyVariable": "Copy Variable",
|
||||
"CustomAlarmCode": "CustomAlarmCode",
|
||||
"CustomAlarmEnable": "CustomAlarmEnable",
|
||||
"CustomAlarmText": "CustomAlarmText",
|
||||
"CustomRestrainExpressions": "CustomRestrainExpressions",
|
||||
"DataType": "DataType",
|
||||
"DeleteVariable": "Copy Variable",
|
||||
"Description": "Description",
|
||||
"DeviceId": "CollectionDevice",
|
||||
"DeviceId.MinValue": "{0} cannot be empty",
|
||||
"DeviceId.Required": "{0} cannot be empty",
|
||||
"DeviceNotNull": "Device name does not exist",
|
||||
"DynamicVariable": "DynamicVariable",
|
||||
"Enable": "Enable",
|
||||
"ExportVariable": "Export Variable",
|
||||
"HAlarmCode": "HAlarmCode",
|
||||
"HAlarmEnable": "HAlarmEnable",
|
||||
"HAlarmText": "HAlarmText",
|
||||
"HHAlarmCode": "HHAlarmCode",
|
||||
"HHAlarmEnable": "HHAlarmEnable",
|
||||
"HHAlarmText": "HHAlarmText",
|
||||
"HHRestrainExpressions": "HHRestrainExpressions",
|
||||
"HRestrainExpressions": "HRestrainExpressions",
|
||||
"ImportVariable": "Import Variable",
|
||||
"InitValue": "InitValue",
|
||||
"IntervalTime": "IntervalTime",
|
||||
"IntervalTime.MinValue": "{0} value is too small",
|
||||
"LAlarmCode": "LAlarmCode",
|
||||
"LAlarmEnable": "LAlarmEnable",
|
||||
"LAlarmText": "LAlarmText",
|
||||
"LLAlarmCode": "LLAlarmCode",
|
||||
"LLAlarmEnable": "LLAlarmEnable",
|
||||
"LLAlarmText": "LLAlarmText",
|
||||
"LLRestrainExpressions": "LLRestrainExpressions",
|
||||
"LRestrainExpressions": "LRestrainExpressions",
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"NameDump": "Duplicate variable name {0}",
|
||||
"NotNull": "{0} does not exist",
|
||||
"OtherMethod": "OtherMethod",
|
||||
"PluginNotNull": "Plugin name does not exist",
|
||||
"ProtectType": "ProtectType",
|
||||
"ReadExpressions": "ReadExpressions",
|
||||
"RegisterAddress": "RegisterAddress",
|
||||
"Remark1": "Remark1",
|
||||
"Remark2": "Remark2",
|
||||
"Remark3": "Remark3",
|
||||
"Remark4": "Remark4",
|
||||
"Remark5": "Remark5",
|
||||
"RpcWriteEnable": "RpcWriteEnable",
|
||||
"SaveValue": "SaveValue",
|
||||
"SaveVariable": "Add/Modify Variable",
|
||||
"Unit": "Unit",
|
||||
"VariableNotNull": "Variable name does not exist",
|
||||
"WriteExpressions": "WriteExpressions"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.VariableRuntime": {
|
||||
"AlarmCode": "AlarmCode",
|
||||
"AlarmEnable": "AlarmEnable",
|
||||
"AlarmLimit": "AlarmLimit",
|
||||
"AlarmText": "AlarmText",
|
||||
"AlarmTime": "AlarmTime",
|
||||
"AlarmType": "AlarmType",
|
||||
"ChangeTime": "ChangeTime",
|
||||
"CollectTime": "CollectTime",
|
||||
"DeviceId.MinValue": "{0} cannot be empty",
|
||||
"DeviceId.Required": "{0} cannot be empty",
|
||||
"DeviceName": "DeviceName",
|
||||
"DynamicVariable": "DynamicVariable",
|
||||
"EventTime": "EventTime",
|
||||
"EventType": "EventType",
|
||||
"IntervalTime.MinValue": "{0} value is too small",
|
||||
"IsOnline": "IsOnline",
|
||||
"LastErrorMessage": "LastErrorMessage",
|
||||
"LastSetValue": "LastSetValue",
|
||||
"RawValue": "RawValue",
|
||||
"RecoveryCode": "RecoveryCode",
|
||||
"RuntimeType": "RuntimeType",
|
||||
"Value": "Value"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,530 +1,424 @@
|
||||
{
|
||||
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationDtuPackPropertyBase": {
|
||||
"DtuId": "Dtu注册包(UTF8)"
|
||||
|
||||
"ThingsGateway.Gateway.Application.AlarmVariable": {
|
||||
"AlarmCode": "报警值",
|
||||
"AlarmDelay": "报警延时",
|
||||
"AlarmEnable": "报警使能",
|
||||
"AlarmLimit": "报警限值",
|
||||
"AlarmText": "报警文本",
|
||||
"AlarmTime": "报警时间",
|
||||
"AlarmType": "报警类型",
|
||||
"ArrayLength": "数组长度",
|
||||
"BoolCloseAlarmEnable": "布尔关报警使能",
|
||||
"BoolCloseAlarmText": "布尔关报警文本",
|
||||
"BoolCloseRestrainExpressions": "布尔关报警约束",
|
||||
"BoolOpenAlarmEnable": "布尔开报警使能",
|
||||
"BoolOpenAlarmText": "布尔开报警文本",
|
||||
"BoolOpenRestrainExpressions": "布尔开报警约束",
|
||||
"BusinessGroup": "业务组",
|
||||
"ChangeTime": "变化时间",
|
||||
"CollectGroup": "采集组",
|
||||
"CollectTime": "采集时间",
|
||||
"CustomAlarmCode": "自定义报警限值",
|
||||
"CustomAlarmEnable": "自定义报警使能",
|
||||
"CustomAlarmText": "自定义报警文本",
|
||||
"CustomRestrainExpressions": "自定义报警约束",
|
||||
"DataType": "数据类型",
|
||||
"Description": "描述",
|
||||
"DeviceId": "采集设备",
|
||||
"DeviceName": "设备名称",
|
||||
"Enable": "变量使能",
|
||||
"EventTime": "事件时间",
|
||||
"EventType": "事件类型",
|
||||
"HAlarmCode": "高限值",
|
||||
"HAlarmEnable": "高报使能",
|
||||
"HAlarmText": "高报文本",
|
||||
"HHAlarmCode": "高高限值",
|
||||
"HHAlarmEnable": "高高报使能",
|
||||
"HHAlarmText": "高高报文本",
|
||||
"HHRestrainExpressions": "高高报约束",
|
||||
"HRestrainExpressions": "高报约束",
|
||||
"IntervalTime": "执行间隔",
|
||||
"IsOnline": "在线",
|
||||
"LAlarmCode": "低限值",
|
||||
"LAlarmEnable": "低报使能",
|
||||
"LAlarmText": "低报文本",
|
||||
"LastErrorMessage": "离线原因",
|
||||
"LastSetValue": "上次值",
|
||||
"LLAlarmCode": "低低限值",
|
||||
"LLAlarmEnable": "低低报使能",
|
||||
"LLAlarmText": "低低报文本",
|
||||
"LLRestrainExpressions": "低低报约束",
|
||||
"LRestrainExpressions": "低报约束",
|
||||
"Name": "名称",
|
||||
"OtherMethod": "特殊方法",
|
||||
"ProtectType": "读写权限",
|
||||
"RawValue": "原始值",
|
||||
"ReadExpressions": "读取表达式",
|
||||
"RecoveryCode": "恢复值",
|
||||
"RegisterAddress": "变量地址",
|
||||
"Remark1": "备用1",
|
||||
"Remark2": "备用2",
|
||||
"Remark3": "备用3",
|
||||
"Remark4": "备用4",
|
||||
"Remark5": "备用5",
|
||||
"RpcWriteEnable": "远程写入",
|
||||
"SaveValue": "保存初始值",
|
||||
"Unit": "单位",
|
||||
"Value": "实时值",
|
||||
"WriteExpressions": "写入表达式"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationDtuPropertyBase": {
|
||||
"DtuId": "Dtu注册包(UTF8)"
|
||||
|
||||
"ThingsGateway.Gateway.Application.BackendLog": {
|
||||
"DeleteBackendLog": "删除后台日志",
|
||||
"Exception": "异常对象",
|
||||
"LogLevel": "日志级别",
|
||||
"LogMessage": "具体消息",
|
||||
"LogSource": "日志来源",
|
||||
"LogTime": "时间"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.BackendLogPageInput": {
|
||||
"LogLevel": "日志等级",
|
||||
"LogSource": "日志源",
|
||||
"SearchDate": "时间区间"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationPackPropertyBase": {
|
||||
|
||||
"MaxPack": "最大打包长度"
|
||||
|
||||
"ThingsGateway.Gateway.Application.BusinessPropertyWithCache": {
|
||||
"CacheEnable": "启用缓存",
|
||||
"CacheFileMaxLength": "缓存文件最大长度(mb)",
|
||||
"GroupUpdate": "分组上传",
|
||||
"OnlineFilter": "过滤离线变量",
|
||||
"QueueMaxCount": "内存队列最大数量",
|
||||
"SplitSize": "上传每页条数"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationPropertyBase": {
|
||||
"DataFormat": "解析规则",
|
||||
"IsStringReverseByteWord": "字符串反转",
|
||||
"Timeout": "读写超时时间",
|
||||
"SendDelayTime": "发送延时"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectPropertyRetryBase": {
|
||||
"ReIntervalTime": "离线恢复时间",
|
||||
"RetryCount": "失败重试次数"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectPropertyBase": {
|
||||
"ReIntervalTime": "离线恢复时间",
|
||||
"RetryCount": "失败重试次数",
|
||||
"ConcurrentCount": "最大并发数量"
|
||||
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.BusinessPropertyWithCacheIntervalScript": {
|
||||
|
||||
"DetailLog": "详细日志",
|
||||
"JsonFormattingIndented": "Json缩进格式化",
|
||||
|
||||
"BigTextScriptDeviceModel": "设备上传脚本",
|
||||
"BigTextScriptVariableModel": "变量上传脚本",
|
||||
"BigTextScriptAlarmModel": "报警上传脚本",
|
||||
|
||||
"IsDeviceList": "设备状态列表上传",
|
||||
"IsVariableList": "变量列表上传",
|
||||
"IsAlarmList": "报警列表上传",
|
||||
|
||||
"DeviceTopic": "设备主题",
|
||||
"VariableTopic": "变量主题",
|
||||
"AlarmTopic": "报警主题"
|
||||
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.BusinessPropertyWithCacheInterval": {
|
||||
|
||||
"BusinessUpdateEnum": "上传模式",
|
||||
"BusinessInterval": "定时上传间隔",
|
||||
"BusinessUpdateEnum": "上传模式",
|
||||
"IsAllVariable": "选择全部变量"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.BusinessPropertyWithCache": {
|
||||
|
||||
"QueueMaxCount": "内存队列最大数量",
|
||||
"CacheFileMaxLength": "缓存文件最大长度(mb)",
|
||||
"SplitSize": "上传每页条数",
|
||||
"CacheEnable": "启用缓存",
|
||||
|
||||
"GroupUpdate": "分组上传",
|
||||
"OnlineFilter": "过滤离线变量"
|
||||
"ThingsGateway.Gateway.Application.BusinessPropertyWithCacheIntervalScript": {
|
||||
"AlarmTopic": "报警主题",
|
||||
"BigTextScriptAlarmModel": "报警上传脚本",
|
||||
"BigTextScriptDeviceModel": "设备上传脚本",
|
||||
"BigTextScriptVariableModel": "变量上传脚本",
|
||||
"DetailLog": "详细日志",
|
||||
"DeviceTopic": "设备主题",
|
||||
"IsAlarmList": "报警列表上传",
|
||||
"IsDeviceList": "设备状态列表上传",
|
||||
"IsVariableList": "变量列表上传",
|
||||
"JsonFormattingIndented": "Json缩进格式化",
|
||||
"VariableTopic": "变量主题"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.BusinessUpdateEnum": {
|
||||
"Change": "变化",
|
||||
"Interval": "定时",
|
||||
"IntervalOrChange": "定时或变化"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.Channel": {
|
||||
"BaudRate": "波特率",
|
||||
"BindUrl": "本地url",
|
||||
"CacheTimeout": "接收缓存超时",
|
||||
"Channel": "通道",
|
||||
"ChannelType": "通道类型",
|
||||
"CheckClearTime": "客户端连接滑动过期时间",
|
||||
"ClearChannel": "清空通道",
|
||||
"Confim": "创建",
|
||||
"Connect": "连接",
|
||||
"ConnectTimeout": "连接超时",
|
||||
"CopyChannel": "复制通道",
|
||||
"CreateTime": "创建时间",
|
||||
"CreateUser": "创建人",
|
||||
"DataBits": "数据位",
|
||||
"DeleteChannel": "删除通道",
|
||||
"Disconnect": "断开",
|
||||
"DtrEnable": "Dtr",
|
||||
"DtuId": "Dtu终端注册包(utf-8)",
|
||||
"DtuSeviceType": "DTU服务类型",
|
||||
"Enable": "启用",
|
||||
"ExportChannel": "导出通道",
|
||||
"Heartbeat": "心跳内容(utf8)",
|
||||
"HeartbeatTime": "心跳间隔",
|
||||
"ImportChannel": "导入通道",
|
||||
"ImportNullError": "无法识别",
|
||||
"LogEnable": "启用调试日志",
|
||||
"LogLevel": "日志等级",
|
||||
"MaxClientCount": "最大连接数",
|
||||
"MaxConcurrentCount": "最大并发数",
|
||||
"Name": "名称",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"NameDump": "通道名称 {0} 重复",
|
||||
"NotOther": "不支持其他通道类型",
|
||||
"Parity": "校验位",
|
||||
"PluginName": "插件名称",
|
||||
"PluginName.Required": "{0} 插件名称不可为空",
|
||||
"PortName": "COM口",
|
||||
"RemoteUrl": "远程url",
|
||||
"RtsEnable": "Rts",
|
||||
"SaveChannel": "添加/修改通道",
|
||||
"SortCode": "排序",
|
||||
"StopBits": "停止位",
|
||||
"UpdateTime": "更新时间",
|
||||
"UpdateUser": "更新人"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.ChannelRuntime": {
|
||||
"DeviceRuntimeCount": "设备数量",
|
||||
"MaxConcurrentCount": "最大并发数量",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"PluginName.Required": "{0} 插件名称不可为空",
|
||||
"PluginType": "插件类型"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationDtuPackPropertyBase": {
|
||||
"DtuId": "Dtu注册包(UTF8)"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationDtuPropertyBase": {
|
||||
"DtuId": "Dtu注册包(UTF8)"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationPackPropertyBase": {
|
||||
"MaxPack": "最大打包长度"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectFoundationPropertyBase": {
|
||||
"DataFormat": "解析规则",
|
||||
"IsStringReverseByteWord": "字符串反转",
|
||||
"SendDelayTime": "发送延时",
|
||||
"Timeout": "读写超时时间"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectPropertyBase": {
|
||||
"ConcurrentCount": "最大并发数量",
|
||||
"ReIntervalTime": "离线恢复时间",
|
||||
"RetryCount": "失败重试次数"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectPropertyRetryBase": {
|
||||
"ReIntervalTime": "离线恢复时间",
|
||||
"RetryCount": "失败重试次数"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.ControlController": {
|
||||
"ControlController": "设备控制",
|
||||
"RemoveAllCache": "清空全部缓存",
|
||||
"RemoveCache": "删除通道/设备缓存",
|
||||
"PauseDeviceThreadAsync": "控制设备线程启停",
|
||||
"RestartAllThread": "重启全部线程",
|
||||
"RestartDeviceThreadAsync": "重启设备线程",
|
||||
"WriteVariablesAsync": "写入变量",
|
||||
"BatchSaveChannelAsync": "保存通道",
|
||||
"BatchSaveDeviceAsync": "保存设备",
|
||||
"BatchSaveVariableAsync": "保存变量",
|
||||
"ControlController": "设备控制",
|
||||
"DeleteChannelAsync": "删除通道",
|
||||
"DeleteDeviceAsync": "删除设备",
|
||||
"DeleteVariableAsync": "删除变量",
|
||||
"InsertTestDataAsync": "增加测试数据"
|
||||
"InsertTestDataAsync": "增加测试数据",
|
||||
"PauseDeviceThreadAsync": "控制设备线程启停",
|
||||
"RemoveAllCache": "清空全部缓存",
|
||||
"RemoveCache": "删除通道/设备缓存",
|
||||
"RestartAllThread": "重启全部线程",
|
||||
"RestartDeviceThreadAsync": "重启设备线程",
|
||||
"WriteVariablesAsync": "写入变量"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RuntimeInfoController": {
|
||||
"RuntimeInfoController": "获取运行态信息",
|
||||
"GetChannelListAsync": "获取通道信息",
|
||||
"GetDeviceListAsync": "获取设备信息",
|
||||
"GetVariableList": "获取变量信息",
|
||||
"GetRealAlarmList": "获取实时报警信息",
|
||||
"CheckRealAlarm": "确认实时报警"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.DeviceRuntime": {
|
||||
"SourceVariableCount": "打包数量",
|
||||
"MethodVariableCount": "方法数量",
|
||||
"ActiveTime": "活跃时间",
|
||||
"DeviceVariableCount": "变量数量",
|
||||
"LastErrorMessage": "离线原因",
|
||||
"DeviceStatus": "设备状态",
|
||||
"RedundantType": "冗余状态",
|
||||
"PluginName": "插件名称",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"ChannelName": "通道",
|
||||
"ThingsGateway.Gateway.Application.Device": {
|
||||
"ChannelError": "通道错误",
|
||||
"ChannelId": "通道",
|
||||
"ChannelId.MinValue": " {0} 不可为空",
|
||||
"ChannelId.Required": " {0} 不可为空",
|
||||
"IntervalTime.MinValue": " {0} 值太小",
|
||||
"PluginName.Required": "{0} 插件名称不可为空"
|
||||
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.VariableRuntime": {
|
||||
"ChangeTime": "变化时间",
|
||||
"CollectTime": "采集时间",
|
||||
"DeviceName": "设备名称",
|
||||
"IsOnline": "在线",
|
||||
"LastErrorMessage": "离线原因",
|
||||
"LastSetValue": "上次值",
|
||||
"RawValue": "原始值",
|
||||
"Value": "实时值",
|
||||
"RuntimeType": "动态类型",
|
||||
"AlarmEnable": "报警使能",
|
||||
"SortCode": "排序",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"DeviceId.MinValue": " {0} 不可为空",
|
||||
"DeviceId.Required": " {0} 不可为空",
|
||||
"IntervalTime.MinValue": " {0} 值太小",
|
||||
|
||||
"DynamicVariable": "动态变量",
|
||||
|
||||
"AlarmCode": "报警值",
|
||||
"RecoveryCode": "恢复值",
|
||||
"AlarmLimit": "报警限值",
|
||||
"AlarmText": "报警文本",
|
||||
"AlarmTime": "报警时间",
|
||||
"AlarmType": "报警类型",
|
||||
"EventTime": "事件时间",
|
||||
"EventType": "事件类型"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.AlarmVariable": {
|
||||
"ChangeTime": "变化时间",
|
||||
"CollectTime": "采集时间",
|
||||
"DeviceName": "设备名称",
|
||||
"IsOnline": "在线",
|
||||
"LastErrorMessage": "离线原因",
|
||||
"LastSetValue": "上次值",
|
||||
"RawValue": "原始值",
|
||||
"Value": "实时值",
|
||||
"AlarmEnable": "报警使能",
|
||||
"BusinessGroup": "业务组",
|
||||
"CollectGroup": "采集组",
|
||||
"Name": "名称",
|
||||
"ClearDevice": "清空设备",
|
||||
"CopyDevice": "复制设备",
|
||||
"DeleteDevice": "删除设备",
|
||||
"Description": "描述",
|
||||
"DeviceId": "采集设备",
|
||||
"IntervalTime": "执行间隔",
|
||||
|
||||
"ArrayLength": "数组长度",
|
||||
"Enable": "变量使能",
|
||||
"ProtectType": "读写权限",
|
||||
"DataType": "数据类型",
|
||||
"ReadExpressions": "读取表达式",
|
||||
"WriteExpressions": "写入表达式",
|
||||
"RpcWriteEnable": "远程写入",
|
||||
"SaveValue": "保存初始值",
|
||||
|
||||
"AlarmDelay": "报警延时",
|
||||
"BoolOpenAlarmEnable": "布尔开报警使能",
|
||||
"BoolOpenRestrainExpressions": "布尔开报警约束",
|
||||
"BoolOpenAlarmText": "布尔开报警文本",
|
||||
|
||||
"BoolCloseAlarmEnable": "布尔关报警使能",
|
||||
"BoolCloseRestrainExpressions": "布尔关报警约束",
|
||||
"BoolCloseAlarmText": "布尔关报警文本",
|
||||
|
||||
"HAlarmEnable": "高报使能",
|
||||
"HRestrainExpressions": "高报约束",
|
||||
"HAlarmText": "高报文本",
|
||||
"HAlarmCode": "高限值",
|
||||
|
||||
"HHAlarmEnable": "高高报使能",
|
||||
"HHRestrainExpressions": "高高报约束",
|
||||
"HHAlarmText": "高高报文本",
|
||||
"HHAlarmCode": "高高限值",
|
||||
|
||||
"LAlarmEnable": "低报使能",
|
||||
"LRestrainExpressions": "低报约束",
|
||||
"LAlarmText": "低报文本",
|
||||
"LAlarmCode": "低限值",
|
||||
|
||||
"LLAlarmEnable": "低低报使能",
|
||||
"LLRestrainExpressions": "低低报约束",
|
||||
"LLAlarmText": "低低报文本",
|
||||
"LLAlarmCode": "低低限值",
|
||||
|
||||
"CustomAlarmEnable": "自定义报警使能",
|
||||
"CustomRestrainExpressions": "自定义报警约束",
|
||||
"CustomAlarmText": "自定义报警文本",
|
||||
"CustomAlarmCode": "自定义报警限值",
|
||||
|
||||
"Unit": "单位",
|
||||
"RegisterAddress": "变量地址",
|
||||
"OtherMethod": "特殊方法",
|
||||
|
||||
"DeviceNotNull": "设备名称不存在",
|
||||
"Enable": "设备使能",
|
||||
"ExportDevice": "导出设备",
|
||||
"ImportDevice": "导入设备",
|
||||
"ImportNullError": "无法识别",
|
||||
"IntervalTime": "默认执行间隔",
|
||||
"IntervalTime.MinValue": " {0} 值太小",
|
||||
"LogEnable": "启用调试日志",
|
||||
"LogLevel": "日志等级",
|
||||
"Name": "名称",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"NameDump": "设备名称 {0} 重复",
|
||||
"NotNull": " {0} 不存在",
|
||||
"PluginNotNull": "插件不存在",
|
||||
"RedundantDeviceError": "冗余设备错误",
|
||||
"RedundantDeviceId": "冗余设备",
|
||||
"RedundantDeviceNotNull": "启用冗余时,必须选择备用设备",
|
||||
"RedundantEnable": "启用冗余",
|
||||
"RedundantScanIntervalTime": "冗余检测时间",
|
||||
"RedundantScript": "冗余检测脚本",
|
||||
"RedundantSwitchType": "冗余操作模式",
|
||||
"Remark1": "备用1",
|
||||
"Remark2": "备用2",
|
||||
"Remark3": "备用3",
|
||||
"Remark4": "备用4",
|
||||
"Remark5": "备用5",
|
||||
|
||||
"AlarmCode": "报警值",
|
||||
"RecoveryCode": "恢复值",
|
||||
"AlarmLimit": "报警限值",
|
||||
"AlarmText": "报警文本",
|
||||
"AlarmTime": "报警时间",
|
||||
"AlarmType": "报警类型",
|
||||
"EventTime": "事件时间",
|
||||
"EventType": "事件类型"
|
||||
"SaveDevice": "添加/修改设备"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.BusinessBase": {
|
||||
"IntervalInsertVariableFail": "间隔上传变量失败",
|
||||
"IntervalInsertDeviceFail": "间隔上传设备失败",
|
||||
"IntervalInsertAlarmFail": "间隔上传报警失败"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.CollectBase": {
|
||||
"VariablePackError": "变量打包失败 {0} ",
|
||||
"GetMethodError": "插件方法初始化失败 {0} ",
|
||||
"MethodNotNull": "特殊方法变量 {0} 找不到执行方法 {1},请检查现有方法列表",
|
||||
"CollectFail": "{0} - 采集[{1} - {2}] 数据失败 {3}",
|
||||
"CollectSuccess": "{0} - 采集[{1} - {2}] 数据成功 {3}",
|
||||
"MethodFail": "{0} - 执行方法[{1}] - 失败 {2}",
|
||||
"MethodSuccess": "{0} - 执行方法[{1}] - 成功 {2}",
|
||||
"WriteExpressionsError": " {0} 转换写入表达式 {1} 失败 {2} "
|
||||
"ThingsGateway.Gateway.Application.DeviceRuntime": {
|
||||
"ActiveTime": "活跃时间",
|
||||
"ChannelId.MinValue": " {0} 不可为空",
|
||||
"ChannelId.Required": " {0} 不可为空",
|
||||
"ChannelName": "通道",
|
||||
"DeviceStatus": "设备状态",
|
||||
"DeviceVariableCount": "变量数量",
|
||||
"IntervalTime.MinValue": " {0} 值太小",
|
||||
"LastErrorMessage": "离线原因",
|
||||
"MethodVariableCount": "方法数量",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"PluginName": "插件名称",
|
||||
"PluginName.Required": "{0} 插件名称不可为空",
|
||||
"RedundantType": "冗余状态",
|
||||
"SourceVariableCount": "打包数量"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.DriverBase": {
|
||||
"Authorized": "已授权",
|
||||
"Unauthorized": "未授权",
|
||||
"ExpireTime": "过期时间",
|
||||
"DeviceTaskStart": "设备 {0} 线程开始",
|
||||
"DeviceTaskStartTimeout": "设备 {0} 线程启动超时 {1} s",
|
||||
"DeviceTaskStop": "设备 {0} 线程停止",
|
||||
"DeviceTaskPause": "设备 {0} 线程暂停",
|
||||
"DeviceTaskContinue": "设备 {0} 线程继续"
|
||||
"Unauthorized": "未授权"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.DeviceThreadManage": {
|
||||
"InitFail": "插件 {0} 设备 {1} 初始化失败",
|
||||
"ChannelCreate": "通道 {0} 创建",
|
||||
"ChannelDispose": "通道 {0} 销毁"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.AlarmHostedService": {
|
||||
"RealAlarmTask": "实时报警服务",
|
||||
"RealAlarmTaskStart": "实时报警服务启动"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.PluginService": {
|
||||
"LoadTypeSuccess": "加载插件 {0} 成功",
|
||||
"LoadTypeFail1": "加载插件 {0} 失败,插件类型不存在",
|
||||
"LoadTypeFail2": "加载插件文件 {0} 失败,文件不存在",
|
||||
"PluginNotFound": "没有发现插件类型",
|
||||
"LoadOtherFileFail": "尝试加载附属程序集 {0} 失败,如果此程序集为DllImport,可以忽略此警告。",
|
||||
"LoadPluginFail": "加载插件 {0} 失败",
|
||||
"AddPluginFile": "添加插件文件 {0}"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.PluginInfo": {
|
||||
"FullName": "插件全名称",
|
||||
"FileName": "插件文件",
|
||||
"PluginType": "插件类型",
|
||||
"Name": "插件名称",
|
||||
"DeviceCount": "关联设备数量",
|
||||
"Version": "插件版本",
|
||||
"LastWriteTime": "插件编译时间"
|
||||
"ThingsGateway.Gateway.Application.ExportString": {
|
||||
"BusinessDeviceName": "业务设备",
|
||||
"ChannelName": "通道",
|
||||
"DeviceName": "设备",
|
||||
"RedundantDeviceName": "冗余设备",
|
||||
"VariableName": "变量"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.PluginAddInput": {
|
||||
"MainFile": "主程序集",
|
||||
"OtherFiles": "附属程序集,可上传多个",
|
||||
"SavePlugin": "添加/修改插件"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.BackendLog": {
|
||||
"LogTime": "时间",
|
||||
"LogLevel": "日志级别",
|
||||
"LogSource": "日志来源",
|
||||
"LogMessage": "具体消息",
|
||||
"Exception": "异常对象",
|
||||
|
||||
"DeleteBackendLog": "删除后台日志"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.RpcLog": {
|
||||
"LogTime": "时间",
|
||||
"OperateSource": "操作源",
|
||||
"OperateObject": "操作对象",
|
||||
"OperateDevice": "操作设备",
|
||||
"OperateMethod": "RPC方法",
|
||||
"IsSuccess": "操作结果",
|
||||
"ParamJson": "请求参数",
|
||||
"ResultJson": "返回结果",
|
||||
"OperateMessage": "具体消息",
|
||||
|
||||
"DeleteRpc": "删除RPC日志"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.Device": {
|
||||
"Name": "名称",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"Description": "描述",
|
||||
"ChannelId": "通道",
|
||||
"ChannelId.MinValue": " {0} 不可为空",
|
||||
"ChannelId.Required": " {0} 不可为空",
|
||||
"IntervalTime": "默认执行间隔",
|
||||
"IntervalTime.MinValue": " {0} 值太小",
|
||||
"LogEnable": "启用调试日志",
|
||||
"LogLevel": "日志等级",
|
||||
"Enable": "设备使能",
|
||||
|
||||
"RedundantEnable": "启用冗余",
|
||||
"RedundantDeviceId": "冗余设备",
|
||||
"RedundantSwitchType": "冗余操作模式",
|
||||
"RedundantScanIntervalTime": "冗余检测时间",
|
||||
"RedundantScript": "冗余检测脚本",
|
||||
|
||||
"Remark1": "备用1",
|
||||
"Remark2": "备用2",
|
||||
"Remark3": "备用3",
|
||||
"Remark4": "备用4",
|
||||
"Remark5": "备用5",
|
||||
|
||||
"RedundantDeviceNotNull": "启用冗余时,必须选择备用设备",
|
||||
|
||||
"SaveDevice": "添加/修改设备",
|
||||
"CopyDevice": "复制设备",
|
||||
"DeleteDevice": "删除设备",
|
||||
"ClearDevice": "清空设备",
|
||||
"ExportDevice": "导出设备",
|
||||
"ImportDevice": "导入设备",
|
||||
|
||||
"ImportNullError": "无法识别",
|
||||
"RedundantDeviceError": "冗余设备错误",
|
||||
"ChannelError": "通道错误",
|
||||
"NotNull": " {0} 不存在",
|
||||
"DeviceNotNull": "设备名称不存在",
|
||||
"PluginNotNull": "插件不存在",
|
||||
"NameDump": "设备名称 {0} 重复"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.ChannelRuntime": {
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"PluginName.Required": "{0} 插件名称不可为空",
|
||||
"ThingsGateway.Gateway.Application.PluginInfo": {
|
||||
"DeviceCount": "关联设备数量",
|
||||
"FileName": "插件文件",
|
||||
"FullName": "插件全名称",
|
||||
"LastWriteTime": "插件编译时间",
|
||||
"Name": "插件名称",
|
||||
"PluginType": "插件类型",
|
||||
"MaxConcurrentCount": "最大并发数量",
|
||||
"DeviceRuntimeCount": "设备数量"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.Channel": {
|
||||
"SortCode": "排序",
|
||||
"CreateTime": "创建时间",
|
||||
"CreateUser": "创建人",
|
||||
"UpdateTime": "更新时间",
|
||||
"UpdateUser": "更新人",
|
||||
|
||||
"Name": "名称",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"ChannelType": "通道类型",
|
||||
"Enable": "启用",
|
||||
"LogEnable": "启用调试日志",
|
||||
"PluginName": "插件名称",
|
||||
"PluginName.Required": "{0} 插件名称不可为空",
|
||||
"LogLevel": "日志等级",
|
||||
|
||||
"RemoteUrl": "远程url",
|
||||
"BindUrl": "本地url",
|
||||
|
||||
"PortName": "COM口",
|
||||
"BaudRate": "波特率",
|
||||
"DataBits": "数据位",
|
||||
"Parity": "校验位",
|
||||
"StopBits": "停止位",
|
||||
"DtrEnable": "Dtr",
|
||||
"RtsEnable": "Rts",
|
||||
"CacheTimeout": "接收缓存超时",
|
||||
"ConnectTimeout": "连接超时",
|
||||
"MaxConcurrentCount": "最大并发数",
|
||||
|
||||
|
||||
"MaxClientCount": "最大连接数",
|
||||
"CheckClearTime": "客户端连接滑动过期时间",
|
||||
"Heartbeat": "心跳内容(utf8)",
|
||||
"HeartbeatTime": "心跳间隔",
|
||||
"DtuId": "Dtu终端注册包(utf-8)",
|
||||
"DtuSeviceType": "DTU服务类型",
|
||||
|
||||
"SaveChannel": "添加/修改通道",
|
||||
"CopyChannel": "复制通道",
|
||||
"DeleteChannel": "删除通道",
|
||||
"ClearChannel": "清空通道",
|
||||
"ExportChannel": "导出通道",
|
||||
"ImportChannel": "导入通道",
|
||||
|
||||
"ImportNullError": "无法识别",
|
||||
|
||||
"NotOther": "不支持其他通道类型",
|
||||
"Connect": "连接",
|
||||
"Confim": "创建",
|
||||
"Disconnect": "断开",
|
||||
"Channel": "通道",
|
||||
"NameDump": "通道名称 {0} 重复"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.Variable": {
|
||||
"AddressOrOtherMethodNotNull": " 变量地址或特殊方法不能同时为空 ",
|
||||
"SaveVariable": "添加/修改变量",
|
||||
"CopyVariable": "复制变量",
|
||||
"DeleteVariable": "删除变量",
|
||||
"ClearVariable": "清空变量",
|
||||
"ExportVariable": "导出变量",
|
||||
"ImportVariable": "导入变量",
|
||||
|
||||
"NotNull": " {0} 不存在",
|
||||
"DeviceNotNull": "设备名称不存在",
|
||||
"PluginNotNull": "插件不存在",
|
||||
"VariableNotNull": "变量名称不存在",
|
||||
|
||||
"Name": "名称",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"Description": "描述",
|
||||
"BusinessGroup": "业务组",
|
||||
"CollectGroup": "采集组",
|
||||
"DeviceId": "采集设备",
|
||||
"DeviceId.MinValue": " {0} 不可为空",
|
||||
"DeviceId.Required": " {0} 不可为空",
|
||||
"IntervalTime": "执行间隔",
|
||||
"IntervalTime.MinValue": " {0} 值太小",
|
||||
"ArrayLength": "数组长度",
|
||||
|
||||
"Enable": "变量使能",
|
||||
"ProtectType": "读写权限",
|
||||
"DataType": "数据类型",
|
||||
"ReadExpressions": "读取表达式",
|
||||
"WriteExpressions": "写入表达式",
|
||||
"RpcWriteEnable": "远程写入",
|
||||
"InitValue": "初始值",
|
||||
"SaveValue": "保存初始值",
|
||||
"DynamicVariable": "动态变量",
|
||||
|
||||
"AlarmDelay": "报警延时",
|
||||
"BoolOpenAlarmEnable": "布尔开报警使能",
|
||||
"BoolOpenRestrainExpressions": "布尔开报警约束",
|
||||
"BoolOpenAlarmText": "布尔开报警文本",
|
||||
|
||||
"BoolCloseAlarmEnable": "布尔关报警使能",
|
||||
"BoolCloseRestrainExpressions": "布尔关报警约束",
|
||||
"BoolCloseAlarmText": "布尔关报警文本",
|
||||
|
||||
"HAlarmEnable": "高报使能",
|
||||
"HRestrainExpressions": "高报约束",
|
||||
"HAlarmText": "高报文本",
|
||||
"HAlarmCode": "高限值",
|
||||
|
||||
"HHAlarmEnable": "高高报使能",
|
||||
"HHRestrainExpressions": "高高报约束",
|
||||
"HHAlarmText": "高高报文本",
|
||||
"HHAlarmCode": "高高限值",
|
||||
|
||||
"LAlarmEnable": "低报使能",
|
||||
"LRestrainExpressions": "低报约束",
|
||||
"LAlarmText": "低报文本",
|
||||
"LAlarmCode": "低限值",
|
||||
|
||||
"LLAlarmEnable": "低低报使能",
|
||||
"LLRestrainExpressions": "低低报约束",
|
||||
"LLAlarmText": "低低报文本",
|
||||
"LLAlarmCode": "低低限值",
|
||||
|
||||
"CustomAlarmEnable": "自定义报警使能",
|
||||
"CustomRestrainExpressions": "自定义报警约束",
|
||||
"CustomAlarmText": "自定义报警文本",
|
||||
"CustomAlarmCode": "自定义报警限值",
|
||||
|
||||
"Unit": "单位",
|
||||
"RegisterAddress": "变量地址",
|
||||
"OtherMethod": "特殊方法",
|
||||
|
||||
"Remark1": "备用1",
|
||||
"Remark2": "备用2",
|
||||
"Remark3": "备用3",
|
||||
"Remark4": "备用4",
|
||||
"Remark5": "备用5",
|
||||
|
||||
"NameDump": "变量名称 {0} 重复"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.RpcLogPageInput": {
|
||||
"SearchDate": "时间区间",
|
||||
"OperateObject": "操作对象",
|
||||
"OperateDevice": "操作设备",
|
||||
"OperateSource": "操作源"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.BackendLogPageInput": {
|
||||
"SearchDate": "时间区间",
|
||||
"LogLevel": "日志等级",
|
||||
"LogSource": "日志源"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RpcService": {
|
||||
"DeviceNotNull": "设备名称不存在",
|
||||
"VariableNotNull": " {0} 变量不存在",
|
||||
"VariableReadOnly": " {0} 变量只读",
|
||||
"VariableWriteDisable": " {0} 变量不允许写入",
|
||||
"DriverNotNull": "系统错误,不存在对应采集设备,请稍候重试",
|
||||
"DevicePause": " {0} 设备已暂停",
|
||||
"WriteVariable": "写入变量"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.ExportString": {
|
||||
"VariableName": "变量",
|
||||
"RedundantDeviceName": "冗余设备",
|
||||
"ChannelName": "通道",
|
||||
"DeviceName": "设备",
|
||||
"BusinessDeviceName": "业务设备"
|
||||
"Version": "插件版本"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.ProtectTypeEnum": {
|
||||
"ReadOnly": "只读",
|
||||
"ReadWrite": "读写",
|
||||
"WriteOnly": "只写"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RpcLog": {
|
||||
"DeleteRpc": "删除RPC日志",
|
||||
"IsSuccess": "操作结果",
|
||||
"LogTime": "时间",
|
||||
"OperateDevice": "操作设备",
|
||||
"OperateMessage": "具体消息",
|
||||
"OperateMethod": "RPC方法",
|
||||
"OperateObject": "操作对象",
|
||||
"OperateSource": "操作源",
|
||||
"ParamJson": "请求参数",
|
||||
"ResultJson": "返回结果"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RpcLogPageInput": {
|
||||
"OperateDevice": "操作设备",
|
||||
"OperateObject": "操作对象",
|
||||
"OperateSource": "操作源",
|
||||
"SearchDate": "时间区间"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RpcService": {
|
||||
"DeviceNotNull": "设备名称不存在",
|
||||
"DevicePause": " {0} 设备已暂停",
|
||||
"DriverNotNull": "系统错误,不存在对应采集设备,请稍候重试",
|
||||
"VariableNotNull": " {0} 变量不存在",
|
||||
"VariableReadOnly": " {0} 变量只读",
|
||||
"VariableWriteDisable": " {0} 变量不允许写入"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.RuntimeInfoController": {
|
||||
"CheckRealAlarm": "确认实时报警",
|
||||
"GetChannelListAsync": "获取通道信息",
|
||||
"GetDeviceListAsync": "获取设备信息",
|
||||
"GetRealAlarmList": "获取实时报警信息",
|
||||
"GetVariableList": "获取变量信息",
|
||||
"RuntimeInfoController": "获取运行态信息"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.Variable": {
|
||||
"AddressOrOtherMethodNotNull": " 变量地址或特殊方法不能同时为空 ",
|
||||
"AlarmDelay": "报警延时",
|
||||
"ArrayLength": "数组长度",
|
||||
"BoolCloseAlarmEnable": "布尔关报警使能",
|
||||
"BoolCloseAlarmText": "布尔关报警文本",
|
||||
"BoolCloseRestrainExpressions": "布尔关报警约束",
|
||||
"BoolOpenAlarmEnable": "布尔开报警使能",
|
||||
"BoolOpenAlarmText": "布尔开报警文本",
|
||||
"BoolOpenRestrainExpressions": "布尔开报警约束",
|
||||
"BusinessGroup": "业务组",
|
||||
"ClearVariable": "清空变量",
|
||||
"CollectGroup": "采集组",
|
||||
"CopyVariable": "复制变量",
|
||||
"CustomAlarmCode": "自定义报警限值",
|
||||
"CustomAlarmEnable": "自定义报警使能",
|
||||
"CustomAlarmText": "自定义报警文本",
|
||||
"CustomRestrainExpressions": "自定义报警约束",
|
||||
"DataType": "数据类型",
|
||||
"DeleteVariable": "删除变量",
|
||||
"Description": "描述",
|
||||
"DeviceId": "采集设备",
|
||||
"DeviceId.MinValue": " {0} 不可为空",
|
||||
"DeviceId.Required": " {0} 不可为空",
|
||||
"DeviceNotNull": "设备名称不存在",
|
||||
"DynamicVariable": "动态变量",
|
||||
"Enable": "变量使能",
|
||||
"ExportVariable": "导出变量",
|
||||
"HAlarmCode": "高限值",
|
||||
"HAlarmEnable": "高报使能",
|
||||
"HAlarmText": "高报文本",
|
||||
"HHAlarmCode": "高高限值",
|
||||
"HHAlarmEnable": "高高报使能",
|
||||
"HHAlarmText": "高高报文本",
|
||||
"HHRestrainExpressions": "高高报约束",
|
||||
"HRestrainExpressions": "高报约束",
|
||||
"ImportVariable": "导入变量",
|
||||
"InitValue": "初始值",
|
||||
"IntervalTime": "执行间隔",
|
||||
"IntervalTime.MinValue": " {0} 值太小",
|
||||
"LAlarmCode": "低限值",
|
||||
"LAlarmEnable": "低报使能",
|
||||
"LAlarmText": "低报文本",
|
||||
"LLAlarmCode": "低低限值",
|
||||
"LLAlarmEnable": "低低报使能",
|
||||
"LLAlarmText": "低低报文本",
|
||||
"LLRestrainExpressions": "低低报约束",
|
||||
"LRestrainExpressions": "低报约束",
|
||||
"Name": "名称",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"NameDump": "变量名称 {0} 重复",
|
||||
"NotNull": " {0} 不存在",
|
||||
"OtherMethod": "特殊方法",
|
||||
"PluginNotNull": "插件不存在",
|
||||
"ProtectType": "读写权限",
|
||||
"ReadExpressions": "读取表达式",
|
||||
"RegisterAddress": "变量地址",
|
||||
"Remark1": "备用1",
|
||||
"Remark2": "备用2",
|
||||
"Remark3": "备用3",
|
||||
"Remark4": "备用4",
|
||||
"Remark5": "备用5",
|
||||
"RpcWriteEnable": "远程写入",
|
||||
"SaveValue": "保存初始值",
|
||||
"SaveVariable": "添加/修改变量",
|
||||
"Unit": "单位",
|
||||
"VariableNotNull": "变量名称不存在",
|
||||
"WriteExpressions": "写入表达式"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.VariableRuntime": {
|
||||
"AlarmCode": "报警值",
|
||||
"AlarmEnable": "报警使能",
|
||||
"AlarmLimit": "报警限值",
|
||||
"AlarmText": "报警文本",
|
||||
"AlarmTime": "报警时间",
|
||||
"AlarmType": "报警类型",
|
||||
"ChangeTime": "变化时间",
|
||||
"CollectTime": "采集时间",
|
||||
"DeviceId.MinValue": " {0} 不可为空",
|
||||
"DeviceId.Required": " {0} 不可为空",
|
||||
"DeviceName": "设备名称",
|
||||
"DynamicVariable": "动态变量",
|
||||
"EventTime": "事件时间",
|
||||
"EventType": "事件类型",
|
||||
"IntervalTime.MinValue": " {0} 值太小",
|
||||
"IsOnline": "在线",
|
||||
"LastErrorMessage": "离线原因",
|
||||
"LastSetValue": "上次值",
|
||||
"Name.Required": " {0} 不可为空",
|
||||
"RawValue": "原始值",
|
||||
"RecoveryCode": "恢复值",
|
||||
"RuntimeType": "动态类型",
|
||||
"SortCode": "排序",
|
||||
"Value": "实时值"
|
||||
}
|
||||
}
|
||||
}
|
@@ -11,7 +11,6 @@
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using ThingsGateway.Gateway.Application.Extensions;
|
||||
@@ -26,14 +25,11 @@ internal sealed class AlarmHostedService : BackgroundService, IAlarmHostedServic
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
/// <inheritdoc cref="AlarmHostedService"/>
|
||||
public AlarmHostedService(ILogger<AlarmHostedService> logger, IStringLocalizer<AlarmHostedService> localizer)
|
||||
public AlarmHostedService(ILogger<AlarmHostedService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
Localizer = localizer;
|
||||
}
|
||||
|
||||
private IStringLocalizer Localizer { get; }
|
||||
|
||||
#region 核心实现
|
||||
|
||||
/// <summary>
|
||||
@@ -450,7 +446,7 @@ internal sealed class AlarmHostedService : BackgroundService, IAlarmHostedServic
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation(Localizer["RealAlarmTaskStart"]);
|
||||
_logger.LogInformation(AppResource.RealAlarmTaskStart);
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
await DoWork(stoppingToken).ConfigureAwait(false);
|
||||
|
@@ -13,7 +13,6 @@ using BootstrapBlazor.Components;
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
@@ -93,7 +92,6 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
/// <param name="channelRuntime">通道表</param>
|
||||
public DeviceThreadManage(ChannelRuntime channelRuntime)
|
||||
{
|
||||
Localizer = App.CreateLocalizerByType(typeof(DeviceThreadManage));
|
||||
|
||||
var config = new TouchSocketConfig();
|
||||
LogMessage = new LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Warning };//不显示调试日志
|
||||
@@ -105,7 +103,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
|
||||
_logger = App.RootServices.GetService<Microsoft.Extensions.Logging.ILoggerFactory>().CreateLogger($"DeviceThreadManage[{channelRuntime.Name}]");
|
||||
// 添加默认日志记录器
|
||||
LogMessage.AddLogger(new EasyLogger(_logger.Log_Out) { LogLevel = TouchSocket.Core.LogLevel.Trace });
|
||||
LogMessage?.AddLogger(new EasyLogger(_logger.Log_Out) { LogLevel = TouchSocket.Core.LogLevel.Trace });
|
||||
|
||||
// 根据配置获取通道实例
|
||||
Channel = channelRuntime.GetChannel(config);
|
||||
@@ -118,7 +116,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
|
||||
GlobalData.DeviceStatusChangeEvent += GlobalData_DeviceStatusChangeEvent;
|
||||
|
||||
LogMessage?.LogInformation(Localizer["ChannelCreate", channelRuntime.Name]);
|
||||
LogMessage?.LogInformation(string.Format(AppResource.ChannelCreate, channelRuntime.Name));
|
||||
|
||||
CancellationToken = CancellationTokenSource.Token;
|
||||
|
||||
@@ -172,7 +170,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
// 移除旧的文件日志记录器并释放资源
|
||||
if (TextLogger != null)
|
||||
{
|
||||
LogMessage.RemoveLogger(TextLogger);
|
||||
LogMessage?.RemoveLogger(TextLogger);
|
||||
TextLogger?.Dispose();
|
||||
}
|
||||
|
||||
@@ -180,7 +178,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
TextLogger = TextFileLogger.GetMultipleFileLogger(LogPath);
|
||||
TextLogger.LogLevel = logLevel ?? TouchSocket.Core.LogLevel.Trace;
|
||||
// 将文件日志记录器添加到日志消息组中
|
||||
LogMessage.AddLogger(TextLogger);
|
||||
LogMessage?.AddLogger(TextLogger);
|
||||
|
||||
}
|
||||
|
||||
@@ -221,7 +219,6 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<long, DriverBase> Drivers { get; set; } = new();
|
||||
|
||||
private IStringLocalizer Localizer { get; }
|
||||
public IChannelThreadManage ChannelThreadManage { get; internal set; }
|
||||
|
||||
#endregion
|
||||
@@ -370,7 +367,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
// 如果初始化过程中发生异常,设置初始化状态为失败,并记录警告日志
|
||||
if (driver != null)
|
||||
driver.IsInitSuccess = false;
|
||||
LogMessage?.LogWarning(ex, Localizer["InitFail", CurrentChannel.PluginName, driver?.DeviceName]);
|
||||
LogMessage?.LogWarning(ex, string.Format(AppResource.InitFail, CurrentChannel.PluginName, driver?.DeviceName));
|
||||
}
|
||||
|
||||
// 创建令牌并与驱动程序对象的设备ID关联,用于取消操作
|
||||
@@ -506,7 +503,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "SaveValue");
|
||||
LogMessage?.LogWarning(ex, "SaveValue");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -751,7 +748,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex);
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,7 +798,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogError(ex, nameof(CheckRedundantAsync));
|
||||
LogMessage?.LogError(ex, nameof(CheckRedundantAsync));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -850,7 +847,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogError(ex, nameof(CheckThreadAsync));
|
||||
LogMessage?.LogError(ex, nameof(CheckThreadAsync));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -862,7 +859,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogError(ex, nameof(CheckThreadAsync));
|
||||
LogMessage?.LogError(ex, nameof(CheckThreadAsync));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -893,7 +890,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
|
||||
if (Channel?.Collects.Count == 0)
|
||||
Channel?.SafeDispose();
|
||||
|
||||
LogMessage?.LogInformation(Localizer["ChannelDispose", CurrentChannel?.Name ?? string.Empty]);
|
||||
LogMessage?.LogInformation(string.Format(AppResource.ChannelDispose, CurrentChannel?.Name ?? string.Empty));
|
||||
|
||||
LogMessage?.Logs?.ForEach(a => a.TryDispose());
|
||||
|
||||
|
@@ -45,11 +45,8 @@ internal sealed class PluginService : IPluginService
|
||||
private readonly WaitLock _locker = new();
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private IStringLocalizer Localizer;
|
||||
|
||||
public PluginService(ILogger<PluginService> logger, IStringLocalizer<PluginService> localizer, IDispatchService<PluginInfo> dispatchService)
|
||||
public PluginService(ILogger<PluginService> logger, IDispatchService<PluginInfo> dispatchService)
|
||||
{
|
||||
Localizer = localizer;
|
||||
_logger = logger;
|
||||
|
||||
_dispatchService = dispatchService;
|
||||
@@ -142,17 +139,17 @@ internal sealed class PluginService : IPluginService
|
||||
if (driverType != null)
|
||||
{
|
||||
var driver = (DriverBase)Activator.CreateInstance(driverType);
|
||||
_logger?.LogInformation(Localizer[$"LoadTypeSuccess", pluginName]);
|
||||
_logger?.LogInformation(string.Format(AppResource.LoadTypeSuccess, pluginName));
|
||||
_driverBaseDict.TryAdd(pluginName, driverType);
|
||||
return driver;
|
||||
}
|
||||
// 抛出异常,插件类型不存在
|
||||
throw new(Localizer[$"LoadTypeFail1", pluginName]);
|
||||
throw new(string.Format(AppResource.LoadTypeFail1, pluginName));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 抛出异常,插件文件不存在
|
||||
throw new(Localizer[$"LoadTypeFail2", path]);
|
||||
throw new(string.Format(AppResource.LoadTypeFail2, path));
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -426,7 +423,7 @@ internal sealed class PluginService : IPluginService
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 加载失败时记录警告信息
|
||||
_logger?.LogWarning(ex, Localizer[$"LoadOtherFileFail", item]);
|
||||
_logger?.LogWarning(ex, string.Format(AppResource.LoadOtherFileFail, item));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -438,7 +435,7 @@ internal sealed class PluginService : IPluginService
|
||||
// 检查是否存在驱动类型
|
||||
if (!driverTypes.Any())
|
||||
{
|
||||
throw new(Localizer[$"PluginNotFound"]);
|
||||
throw new(AppResource.PluginNotFound);
|
||||
}
|
||||
|
||||
assembly = null;
|
||||
@@ -652,7 +649,7 @@ internal sealed class PluginService : IPluginService
|
||||
}
|
||||
//添加到全局对象
|
||||
_assemblyLoadContextDict.TryAdd(fileName, (assemblyLoadContext, assembly));
|
||||
_logger?.LogInformation(Localizer["AddPluginFile", path]);
|
||||
_logger?.LogInformation(string.Format(AppResource.AddPluginFile, path));
|
||||
}
|
||||
return assembly;
|
||||
|
||||
@@ -702,7 +699,7 @@ internal sealed class PluginService : IPluginService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger?.LogWarning(ex, Localizer[$"LoadOtherFileFail", item]);
|
||||
_logger?.LogWarning(ex, string.Format(AppResource.LoadOtherFileFail, item));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -800,7 +797,7 @@ internal sealed class PluginService : IPluginService
|
||||
{
|
||||
//添加到字典
|
||||
_driverBaseDict.TryAdd($"{driverMainName}.{type.Name}", type);
|
||||
_logger?.LogInformation(Localizer[$"LoadTypeSuccess", PluginServiceUtil.GetFullName(driverMainName, type.Name)]);
|
||||
_logger?.LogInformation(string.Format(AppResource.LoadTypeSuccess, PluginServiceUtil.GetFullName(driverMainName, type.Name)));
|
||||
}
|
||||
var plugin = new PluginInfo()
|
||||
{
|
||||
@@ -820,7 +817,7 @@ internal sealed class PluginService : IPluginService
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 记录加载插件失败的日志
|
||||
_logger?.LogWarning(ex, Localizer[$"LoadPluginFail", Path.GetRelativePath(AppContext.BaseDirectory.CombinePathWithOs(DirName), folderPath)]);
|
||||
_logger?.LogWarning(ex, string.Format(AppResource.LoadPluginFail, Path.GetRelativePath(AppContext.BaseDirectory.CombinePathWithOs(DirName), folderPath)));
|
||||
}
|
||||
}
|
||||
return plugins.DistinctBy(a => a.FullName).OrderBy(a => a.EducationPlugin);
|
||||
|
@@ -152,7 +152,7 @@ internal sealed class RpcService : IRpcService
|
||||
LogTime = DateTime.Now,
|
||||
OperateMessage = variableResult.Value.IsSuccess ? null : variableResult.Value.ToString(),
|
||||
IsSuccess = variableResult.Value.IsSuccess,
|
||||
OperateMethod = Localizer["WriteVariable"],
|
||||
OperateMethod = AppResource.WriteVariable,
|
||||
OperateDevice = resultItem.Key,
|
||||
OperateObject = operObj,
|
||||
OperateSource = sourceDes,
|
||||
|
@@ -1,185 +1,156 @@
|
||||
{
|
||||
"ThingsGateway.Gateway.Razor.GatewayAbout": {
|
||||
"UUID": "UUID",
|
||||
"RegisterStatus": "RegisterStatus",
|
||||
"Authorized": "Authorized",
|
||||
"Unauthorized": "Unauthorized",
|
||||
"ExpireTime": "ExpireTime",
|
||||
"AuthName": "AuthName",
|
||||
"Register": "Register",
|
||||
"Unregister": "Unregister",
|
||||
"Password": "Password"
|
||||
"ThingsGateway.Gateway.Razor._Imports": {
|
||||
"AddChannel": "Add Channel",
|
||||
"AddDevice": "Add Device",
|
||||
"AddVariable": "Add Variable",
|
||||
"AlarmInformation": "Alarm Information",
|
||||
"AllChannel": "All Channel",
|
||||
"AllDevice": "All Device",
|
||||
"BasicInformation": "Basic Information",
|
||||
"BatchEditChannel": "Batch Edit Channel",
|
||||
"BatchEditDevice": "Batch Edit Device",
|
||||
"Business": "Business",
|
||||
"Check": "Check",
|
||||
"Collect": "Collect",
|
||||
"Connection": "Connection",
|
||||
"CopyChannel": "CopyChannel",
|
||||
"CopyChannelNamePrefix": "CopyChannelNamePrefix",
|
||||
"CopyChannelNameSuffixNumber": "CopyChannelNameSuffixNumber",
|
||||
"CopyCount": "CopyCount",
|
||||
"CopyDevice": "CopyDevice",
|
||||
"CopyDeviceNamePrefix": "CopyDeviceNamePrefix",
|
||||
"CopyDeviceNameSuffixNumber": "CopyDeviceNameSuffixNumber",
|
||||
"CopyVariable": "CopyVariable",
|
||||
"CopyVariableNamePrefix": "CopyVariableNamePrefix",
|
||||
"CopyVariableNameSuffixNumber": "CopyVariableNameSuffixNumber",
|
||||
"DeleteAllChannel": "Delete All Channel",
|
||||
"DeleteAllDevice": "Delete All Device",
|
||||
"DeleteCache": "Delete cache",
|
||||
"DeleteChannel": "Delete Channel",
|
||||
"DeleteConfirmTitle": "Delete Confirm",
|
||||
"DeleteCurrentChannel": "Delete Current Channel",
|
||||
"DeleteCurrentDevice": "Delete Current Device",
|
||||
"DeleteDevice": "Delete Device",
|
||||
"DeviceInformation": "Device Information",
|
||||
"DeviceList": "Device List",
|
||||
"DeviceRedundantThread": "Switching redundancy",
|
||||
"ExcelChannel": "ExcelChannel",
|
||||
"ExcelDevice": "ExcelDevice",
|
||||
"ExcelVariable": "ExcelVariable",
|
||||
"ExportAllChannel": "Export All Channel",
|
||||
"ExportAllDevice": "Export All Device",
|
||||
"ExportChannel": "Export Channel",
|
||||
"ExportCurrentChannel": "Export Current Channel",
|
||||
"ExportCurrentDevice": "Export Current Device",
|
||||
"ExportDevice": "Export Device",
|
||||
"GatewayChannelRestart": "Restart channel",
|
||||
"GatewayDeviceLog": "Channel log",
|
||||
"GatewayDevicePause": "Pause/Run",
|
||||
"GatewayDeviceRestart": "Restart device",
|
||||
"GatewayDeviceShowDriverUI": "Show driverUI",
|
||||
"ImportChannel": "Import Channel",
|
||||
"ImportDevice": "Import Device",
|
||||
"ImportVariable": "ImportVariable",
|
||||
"Input": "Input",
|
||||
"Output": "Output",
|
||||
"PluginInformation": "Plugin Information",
|
||||
"Redundant": "Redundant",
|
||||
"RefreshBusinessProperty": "Add/Refresh Business Property",
|
||||
"RefreshBusinessPropertyError": "Select business equipment and add business attributes",
|
||||
"RelationVariable": "Associated variables",
|
||||
"Remark": "Remark",
|
||||
"Runtime": "Runtime",
|
||||
"Script": "Script",
|
||||
"Unknown": "Unknown",
|
||||
"UpdateChannel": "Edit Channel",
|
||||
"UpdateDevice": "Edit Device",
|
||||
"VariableInformation": "Variable Information"
|
||||
},
|
||||
|
||||
|
||||
"ThingsGateway.Gateway.Razor.PluginPage": {
|
||||
"Reload": "Reload"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Razor.TcpSessionClientDto": {
|
||||
"Id": "Id",
|
||||
"IP": "IP",
|
||||
"Port": "Port",
|
||||
"LastReceivedTime": "LastReceivedTime",
|
||||
"LastSentTime": "LastSentTime"
|
||||
},
|
||||
|
||||
|
||||
"ThingsGateway.Gateway.Razor.Index": {
|
||||
"CollectDevice": "Collect Device",
|
||||
"BusinessDevice": "Business Device",
|
||||
"Variable": "Variable",
|
||||
"Alarm": "Real-time Alarm",
|
||||
"AlarmCount": "Alarm Count",
|
||||
"OnLine": "Online",
|
||||
"OffLine": "Offline",
|
||||
"Shortcuts": "Shortcuts",
|
||||
"OperLog": "Recent Operations",
|
||||
"ThingsGateway.Gateway.Razor.BackendLogPage": {
|
||||
"BackendLog": "Gateway Backend Log",
|
||||
"RpcLog": "Gateway RPC Log",
|
||||
"HardwareInfoChart": "Hardware Information Historical Chart",
|
||||
"DateTime": "Date Time",
|
||||
"Data": "Data",
|
||||
"HistoryHardwareInfo": "Historical Chart"
|
||||
"Count": "Count",
|
||||
"Date": "Date"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.ChannelDeviceTree": {
|
||||
"ShowType": "ShowType"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Razor.GatewayAbout": {
|
||||
"AuthName": "AuthName",
|
||||
"Authorized": "Authorized",
|
||||
"ExpireTime": "ExpireTime",
|
||||
"Password": "Password",
|
||||
"Register": "Register",
|
||||
"RegisterStatus": "RegisterStatus",
|
||||
"Unauthorized": "Unauthorized",
|
||||
"Unregister": "Unregister",
|
||||
"UUID": "UUID"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.Index": {
|
||||
"Alarm": "Real-time Alarm",
|
||||
"AlarmCount": "Alarm Count",
|
||||
"BackendLog": "Gateway Backend Log",
|
||||
"BusinessDevice": "Business Device",
|
||||
"CollectDevice": "Collect Device",
|
||||
"Data": "Data",
|
||||
"DateTime": "Date Time",
|
||||
"HardwareInfoChart": "Hardware Information Historical Chart",
|
||||
"HistoryHardwareInfo": "Historical Chart",
|
||||
"OffLine": "Offline",
|
||||
"OnLine": "Online",
|
||||
"OperLog": "Recent Operations",
|
||||
"RpcLog": "Gateway RPC Log",
|
||||
"Shortcuts": "Shortcuts",
|
||||
"Variable": "Variable"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.PluginDebugPage": {
|
||||
"New": "New",
|
||||
"NewWinbox": "NewWinbox",
|
||||
"PluginUINotNull": "This plugin does not implement a debugging page"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.PluginPage": {
|
||||
"Reload": "Reload"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.QuickActions": {
|
||||
"AutoRestartThread": "AutoRestartThread",
|
||||
"HeaderText": "Quick Operation",
|
||||
"ReloadPluginConfirmText": "Confirm the overloaded plugin?",
|
||||
"ReloadServiceConfirmText": "Confirm when restarting the runtime?",
|
||||
"ReloadServiceText": "Reload Service",
|
||||
"RestartText": "Restart",
|
||||
"TooltipText": "Quick Operation"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.RpcLogPage": {
|
||||
"Count": "Count",
|
||||
"Date": "Date",
|
||||
"RpcLog": "Gateway RPC Log"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.SavePlugin": {
|
||||
"SavePlugin": "Note: Plugins with the same file name will be overwritten",
|
||||
"SavePlugin1": "Plugin changes may take effect after restarting the software"
|
||||
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.BackendLogPage": {
|
||||
"BackendLog": "Gateway Backend Log",
|
||||
"Date": "Date",
|
||||
"Count": "Count"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.RpcLogPage": {
|
||||
"RpcLog": "Gateway RPC Log",
|
||||
"Date": "Date",
|
||||
"Count": "Count"
|
||||
},
|
||||
|
||||
|
||||
|
||||
"ThingsGateway.Gateway.Razor.VariableRuntimeInfo": {
|
||||
"WriteVariable": "WriteVariable",
|
||||
"WriteValue": "WriteValue",
|
||||
|
||||
"TestVariableCount": "TestVariableCount",
|
||||
"TestDeviceCount": "TestDeviceCount",
|
||||
"SlaveUrl": "SlaveUrl",
|
||||
"BusinessEnable": "BusinessEnable",
|
||||
"Test": "Addition of test variables"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Razor.PluginDebugPage": {
|
||||
"PluginUINotNull": "This plugin does not implement a debugging page",
|
||||
"New": "New",
|
||||
"NewWinbox": "NewWinbox"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Razor.QuickActions": {
|
||||
"TooltipText": "Quick Operation",
|
||||
"HeaderText": "Quick Operation",
|
||||
"RestartText": "Restart",
|
||||
"ReloadServiceText": "Reload Service",
|
||||
"ReloadPluginConfirmText": "Confirm the overloaded plugin?",
|
||||
"ReloadServiceConfirmText": "Confirm when restarting the runtime?",
|
||||
|
||||
"AutoRestartThread": "AutoRestartThread"
|
||||
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Razor.ShowTypeEnum": {
|
||||
"VariableTable": "VariableTable",
|
||||
"LogInfo": "LogInfo",
|
||||
"ChannelTable": "ChannelTable",
|
||||
"DeviceTable": "DeviceTable"
|
||||
"DeviceTable": "DeviceTable",
|
||||
"LogInfo": "LogInfo",
|
||||
"VariableTable": "VariableTable"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.TcpSessionClientDto": {
|
||||
"Id": "Id",
|
||||
"IP": "IP",
|
||||
"LastReceivedTime": "LastReceivedTime",
|
||||
"LastSentTime": "LastSentTime",
|
||||
"Port": "Port"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Razor.VariableEditComponent": {
|
||||
|
||||
"ChoiceBusinessDeviceId": "BusinessDevice"
|
||||
},
|
||||
|
||||
|
||||
"ThingsGateway.Gateway.Razor._Imports": {
|
||||
|
||||
"ExcelVariable": "ExcelVariable",
|
||||
"ImportVariable": "ImportVariable",
|
||||
|
||||
"CopyVariableNamePrefix": "CopyVariableNamePrefix",
|
||||
"CopyVariableNameSuffixNumber": "CopyVariableNameSuffixNumber",
|
||||
"CopyChannelNamePrefix": "CopyChannelNamePrefix",
|
||||
"CopyChannelNameSuffixNumber": "CopyChannelNameSuffixNumber",
|
||||
"CopyDeviceNamePrefix": "CopyDeviceNamePrefix",
|
||||
"CopyDeviceNameSuffixNumber": "CopyDeviceNameSuffixNumber",
|
||||
"CopyCount": "CopyCount",
|
||||
"CopyChannel": "CopyChannel",
|
||||
"CopyDevice": "CopyDevice",
|
||||
"CopyVariable": "CopyVariable",
|
||||
|
||||
"GatewayDeviceShowDriverUI": "Show driverUI",
|
||||
"DeviceRedundantThread": "Switching redundancy",
|
||||
"DeleteCache": "Delete cache",
|
||||
"GatewayDeviceLog": "Channel log",
|
||||
"RelationVariable": "Associated variables",
|
||||
"GatewayDevicePause": "Pause/Run",
|
||||
"GatewayDeviceRestart": "Restart device",
|
||||
"GatewayChannelRestart": "Restart channel",
|
||||
|
||||
"BasicInformation": "Basic Information",
|
||||
"Connection": "Connection",
|
||||
"DeviceInformation": "Device Information",
|
||||
"PluginInformation": "Plugin Information",
|
||||
"Redundant": "Redundant",
|
||||
"Remark": "Remark",
|
||||
"Check": "Check",
|
||||
"VariableInformation": "Variable Information",
|
||||
"AlarmInformation": "Alarm Information",
|
||||
|
||||
"RefreshBusinessProperty": "Add/Refresh Business Property",
|
||||
"RefreshBusinessPropertyError": "Select business equipment and add business attributes",
|
||||
"Runtime": "Runtime",
|
||||
|
||||
"DeviceList": "Device List",
|
||||
"AddChannel": "Add Channel",
|
||||
"BatchEditChannel": "Batch Edit Channel",
|
||||
"ExcelChannel": "ExcelChannel",
|
||||
"UpdateChannel": "Edit Channel",
|
||||
"DeleteChannel": "Delete Channel",
|
||||
"DeleteCurrentChannel": "Delete Current Channel",
|
||||
"DeleteAllChannel": "Delete All Channel",
|
||||
"ExportChannel": "Export Channel",
|
||||
"ExportCurrentChannel": "Export Current Channel",
|
||||
"ExportAllChannel": "Export All Channel",
|
||||
"ImportChannel": "Import Channel",
|
||||
"AddDevice": "Add Device",
|
||||
"BatchEditDevice": "Batch Edit Device",
|
||||
"ExcelDevice": "ExcelDevice",
|
||||
"UpdateDevice": "Edit Device",
|
||||
"DeleteDevice": "Delete Device",
|
||||
"DeleteCurrentDevice": "Delete Current Device",
|
||||
"DeleteAllDevice": "Delete All Device",
|
||||
"ExportDevice": "Export Device",
|
||||
"ExportCurrentDevice": "Export Current Device",
|
||||
"ExportAllDevice": "Export All Device",
|
||||
"ImportDevice": "Import Device",
|
||||
|
||||
"DeleteConfirmTitle": "Delete Confirm",
|
||||
"AllChannel": "All Channel",
|
||||
"AllDevice": "All Device",
|
||||
"Collect": "Collect",
|
||||
"Business": "Business",
|
||||
"Unknown": "Unknown",
|
||||
"AddVariable": "Add Variable",
|
||||
|
||||
"Script": "Script",
|
||||
"Input": "Input",
|
||||
"Output": "Output"
|
||||
"ThingsGateway.Gateway.Razor.VariableRuntimeInfo": {
|
||||
"BusinessEnable": "BusinessEnable",
|
||||
"SlaveUrl": "SlaveUrl",
|
||||
"Test": "Addition of test variables",
|
||||
"TestDeviceCount": "TestDeviceCount",
|
||||
"TestVariableCount": "TestVariableCount",
|
||||
"WriteValue": "WriteValue",
|
||||
"WriteVariable": "WriteVariable"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,177 +1,156 @@
|
||||
{
|
||||
"ThingsGateway.Gateway.Razor.GatewayAbout": {
|
||||
"UUID": "唯一编码",
|
||||
"RegisterStatus": "注册状态",
|
||||
"Authorized": "已授权",
|
||||
"Unauthorized": "未授权",
|
||||
"ExpireTime": "过期时间",
|
||||
"AuthName": "公司名称",
|
||||
"Register": "注册",
|
||||
"Unregister": "取消注册",
|
||||
"Password": "注册码"
|
||||
"ThingsGateway.Gateway.Razor._Imports": {
|
||||
"AddChannel": "添加通道",
|
||||
"AddDevice": "添加设备",
|
||||
"AddVariable": "添加变量",
|
||||
"AlarmInformation": "报警信息",
|
||||
"AllChannel": "全部通道",
|
||||
"AllDevice": "全部设备",
|
||||
"BasicInformation": "基础信息",
|
||||
"BatchEditChannel": "批量编辑通道",
|
||||
"BatchEditDevice": "批量编辑设备",
|
||||
"Business": "业务",
|
||||
"Check": "检查",
|
||||
"Collect": "采集",
|
||||
"Connection": "连接",
|
||||
"CopyChannel": "复制通道",
|
||||
"CopyChannelNamePrefix": "通道名称前缀",
|
||||
"CopyChannelNameSuffixNumber": "通道名称后缀开始序号",
|
||||
"CopyCount": "复制数量",
|
||||
"CopyDevice": "复制设备",
|
||||
"CopyDeviceNamePrefix": "设备名称前缀",
|
||||
"CopyDeviceNameSuffixNumber": "设备名称后缀开始序号",
|
||||
"CopyVariable": "复制变量",
|
||||
"CopyVariableNamePrefix": "变量名称前缀",
|
||||
"CopyVariableNameSuffixNumber": "变量名称后缀开始序号",
|
||||
"DeleteAllChannel": "删除全部通道",
|
||||
"DeleteAllDevice": "删除全部设备",
|
||||
"DeleteCache": "删除缓存",
|
||||
"DeleteChannel": "删除通道",
|
||||
"DeleteConfirmTitle": "删除确认",
|
||||
"DeleteCurrentChannel": "删除当前节点下的通道",
|
||||
"DeleteCurrentDevice": "删除当前节点下的设备",
|
||||
"DeleteDevice": "删除设备",
|
||||
"DeviceInformation": "设备信息",
|
||||
"DeviceList": "设备节点",
|
||||
"DeviceRedundantThread": "切换冗余",
|
||||
"ExcelChannel": "在线excel编辑通道",
|
||||
"ExcelDevice": "在线excel编辑设备",
|
||||
"ExcelVariable": "在线excel编辑变量",
|
||||
"ExportAllChannel": "导出全部通道",
|
||||
"ExportAllDevice": "导出全部设备",
|
||||
"ExportChannel": "导出通道",
|
||||
"ExportCurrentChannel": "导出当前节点下的通道",
|
||||
"ExportCurrentDevice": "导出当前节点下的设备",
|
||||
"ExportDevice": "导出设备",
|
||||
"GatewayChannelRestart": "重启通道",
|
||||
"GatewayDeviceLog": "通道日志",
|
||||
"GatewayDevicePause": "暂停/运行",
|
||||
"GatewayDeviceRestart": "重启设备",
|
||||
"GatewayDeviceShowDriverUI": "插件UI",
|
||||
"ImportChannel": "导入通道",
|
||||
"ImportDevice": "导入设备",
|
||||
"ImportVariable": "导入变量",
|
||||
"Input": "输入",
|
||||
"Output": "输出",
|
||||
"PluginInformation": "插件信息",
|
||||
"Redundant": "冗余",
|
||||
"RefreshBusinessProperty": "添加/刷新业务属性",
|
||||
"RefreshBusinessPropertyError": "需选择业务设备,再添加业务属性",
|
||||
"RelationVariable": "关联变量",
|
||||
"Remark": "备用",
|
||||
"Runtime": "运行信息",
|
||||
"Script": "脚本",
|
||||
"Unknown": "未知",
|
||||
"UpdateChannel": "编辑通道",
|
||||
"UpdateDevice": "编辑设备",
|
||||
"VariableInformation": "变量信息"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Razor.PluginPage": {
|
||||
"Reload": "重载"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.TcpSessionClientDto": {
|
||||
"Id": "Id",
|
||||
"IP": "IP",
|
||||
"Port": "端口",
|
||||
"LastReceivedTime": "最近接收时间",
|
||||
"LastSentTime": "最近发送时间"
|
||||
},
|
||||
|
||||
|
||||
"ThingsGateway.Gateway.Razor.VariableRuntimeInfo": {
|
||||
"WriteVariable": "写入",
|
||||
"WriteValue": "写入值",
|
||||
"TestVariableCount": "变量数量",
|
||||
"TestDeviceCount": "采集设备数量",
|
||||
"SlaveUrl": "服务端Url",
|
||||
"BusinessEnable": "添加业务设备",
|
||||
"Test": "一键添加测试变量"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Razor.PluginDebugPage": {
|
||||
"PluginUINotNull": "此插件未实现调试页面",
|
||||
"New": "新建",
|
||||
"NewWinbox": "新建窗口"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Razor.Index": {
|
||||
"CollectDevice": "采集设备",
|
||||
"BusinessDevice": "业务设备",
|
||||
"Variable": "变量",
|
||||
"Alarm": "实时报警",
|
||||
"AlarmCount": "报警数量",
|
||||
"OnLine": "在线",
|
||||
"OffLine": "离线",
|
||||
"Shortcuts": "快捷方式",
|
||||
"OperLog": "最近操作",
|
||||
"ThingsGateway.Gateway.Razor.BackendLogPage": {
|
||||
"BackendLog": "网关后台日志",
|
||||
"RpcLog": "网关RPC日志",
|
||||
"HardwareInfoChart": "硬件信息历史曲线",
|
||||
"DateTime": "时间",
|
||||
"Data": "数据",
|
||||
"HistoryHardwareInfo": "历史曲线"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.QuickActions": {
|
||||
"TooltipText": "快捷操作",
|
||||
"HeaderText": "快捷操作",
|
||||
"RestartText": "重启",
|
||||
"ReloadServiceText": "重启运行时",
|
||||
"ReloadPluginConfirmText": "确定重载插件?",
|
||||
"ReloadServiceConfirmText": "确定重启运行时?",
|
||||
|
||||
"AutoRestartThread": "自动重启线程"
|
||||
|
||||
"Count": "数量",
|
||||
"Date": "日期"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.ChannelDeviceTree": {
|
||||
"ShowType": "显示类型"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Razor.ShowTypeEnum": {
|
||||
"VariableTable": "变量页面",
|
||||
"LogInfo": "日志页面",
|
||||
"ChannelTable": "通道页面",
|
||||
"DeviceTable": "设备页面"
|
||||
"ThingsGateway.Gateway.Razor.GatewayAbout": {
|
||||
"AuthName": "公司名称",
|
||||
"Authorized": "已授权",
|
||||
"ExpireTime": "过期时间",
|
||||
"Password": "注册码",
|
||||
"Register": "注册",
|
||||
"RegisterStatus": "注册状态",
|
||||
"Unauthorized": "未授权",
|
||||
"Unregister": "取消注册",
|
||||
"UUID": "唯一编码"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.Index": {
|
||||
"Alarm": "实时报警",
|
||||
"AlarmCount": "报警数量",
|
||||
"BackendLog": "网关后台日志",
|
||||
"BusinessDevice": "业务设备",
|
||||
"CollectDevice": "采集设备",
|
||||
"Data": "数据",
|
||||
"DateTime": "时间",
|
||||
"HardwareInfoChart": "硬件信息历史曲线",
|
||||
"HistoryHardwareInfo": "历史曲线",
|
||||
"OffLine": "离线",
|
||||
"OnLine": "在线",
|
||||
"OperLog": "最近操作",
|
||||
"RpcLog": "网关RPC日志",
|
||||
"Shortcuts": "快捷方式",
|
||||
"Variable": "变量"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.PluginDebugPage": {
|
||||
"New": "新建",
|
||||
"NewWinbox": "新建窗口",
|
||||
"PluginUINotNull": "此插件未实现调试页面"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.PluginPage": {
|
||||
"Reload": "重载"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.QuickActions": {
|
||||
"AutoRestartThread": "自动重启线程",
|
||||
"HeaderText": "快捷操作",
|
||||
"ReloadPluginConfirmText": "确定重载插件?",
|
||||
"ReloadServiceConfirmText": "确定重启运行时?",
|
||||
"ReloadServiceText": "重启运行时",
|
||||
"RestartText": "重启",
|
||||
"TooltipText": "快捷操作"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.RpcLogPage": {
|
||||
"Count": "数量",
|
||||
"Date": "日期",
|
||||
"RpcLog": "网关RPC日志"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Razor.SavePlugin": {
|
||||
"SavePlugin": "注意:文件名称相同的插件将被覆盖",
|
||||
"SavePlugin1": "插件变动可能需重启软件后生效"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Razor.BackendLogPage": {
|
||||
"BackendLog": "网关后台日志",
|
||||
"Date": "日期",
|
||||
"Count": "数量"
|
||||
"ThingsGateway.Gateway.Razor.ShowTypeEnum": {
|
||||
"ChannelTable": "通道页面",
|
||||
"DeviceTable": "设备页面",
|
||||
"LogInfo": "日志页面",
|
||||
"VariableTable": "变量页面"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.RpcLogPage": {
|
||||
"RpcLog": "网关RPC日志",
|
||||
"Date": "日期",
|
||||
"Count": "数量"
|
||||
"ThingsGateway.Gateway.Razor.TcpSessionClientDto": {
|
||||
"Id": "Id",
|
||||
"IP": "IP",
|
||||
"LastReceivedTime": "最近接收时间",
|
||||
"LastSentTime": "最近发送时间",
|
||||
"Port": "端口"
|
||||
},
|
||||
"ThingsGateway.Gateway.Razor.VariableEditComponent": {
|
||||
|
||||
"ChoiceBusinessDeviceId": "业务设备"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Razor._Imports": {
|
||||
"ExcelVariable": "在线excel编辑变量",
|
||||
"ImportVariable": "导入变量",
|
||||
|
||||
"CopyVariableNamePrefix": "变量名称前缀",
|
||||
"CopyVariableNameSuffixNumber": "变量名称后缀开始序号",
|
||||
"CopyChannelNamePrefix": "通道名称前缀",
|
||||
"CopyChannelNameSuffixNumber": "通道名称后缀开始序号",
|
||||
"CopyDeviceNamePrefix": "设备名称前缀",
|
||||
"CopyDeviceNameSuffixNumber": "设备名称后缀开始序号",
|
||||
"CopyCount": "复制数量",
|
||||
"CopyChannel": "复制通道",
|
||||
"CopyDevice": "复制设备",
|
||||
"CopyVariable": "复制变量",
|
||||
|
||||
"GatewayDeviceShowDriverUI": "插件UI",
|
||||
"DeviceRedundantThread": "切换冗余",
|
||||
"DeleteCache": "删除缓存",
|
||||
"GatewayDeviceLog": "通道日志",
|
||||
"RelationVariable": "关联变量",
|
||||
"GatewayDevicePause": "暂停/运行",
|
||||
"GatewayDeviceRestart": "重启设备",
|
||||
"GatewayChannelRestart": "重启通道",
|
||||
|
||||
"BasicInformation": "基础信息",
|
||||
"Connection": "连接",
|
||||
"DeviceInformation": "设备信息",
|
||||
"PluginInformation": "插件信息",
|
||||
"Redundant": "冗余",
|
||||
"Remark": "备用",
|
||||
"Check": "检查",
|
||||
"VariableInformation": "变量信息",
|
||||
"AlarmInformation": "报警信息",
|
||||
|
||||
"RefreshBusinessProperty": "添加/刷新业务属性",
|
||||
"RefreshBusinessPropertyError": "需选择业务设备,再添加业务属性",
|
||||
"Runtime": "运行信息",
|
||||
|
||||
"DeviceList": "设备节点",
|
||||
"AddChannel": "添加通道",
|
||||
"BatchEditChannel": "批量编辑通道",
|
||||
"ExcelChannel": "在线excel编辑通道",
|
||||
"UpdateChannel": "编辑通道",
|
||||
"DeleteChannel": "删除通道",
|
||||
"DeleteCurrentChannel": "删除当前节点下的通道",
|
||||
"DeleteAllChannel": "删除全部通道",
|
||||
"ExportChannel": "导出通道",
|
||||
"ExportCurrentChannel": "导出当前节点下的通道",
|
||||
"ExportAllChannel": "导出全部通道",
|
||||
"ImportChannel": "导入通道",
|
||||
"AddDevice": "添加设备",
|
||||
"BatchEditDevice": "批量编辑设备",
|
||||
"ExcelDevice": "在线excel编辑设备",
|
||||
"UpdateDevice": "编辑设备",
|
||||
"DeleteDevice": "删除设备",
|
||||
"DeleteCurrentDevice": "删除当前节点下的设备",
|
||||
"DeleteAllDevice": "删除全部设备",
|
||||
"ExportDevice": "导出设备",
|
||||
"ExportCurrentDevice": "导出当前节点下的设备",
|
||||
"ExportAllDevice": "导出全部设备",
|
||||
"ImportDevice": "导入设备",
|
||||
|
||||
"DeleteConfirmTitle": "删除确认",
|
||||
"AllChannel": "全部通道",
|
||||
"AllDevice": "全部设备",
|
||||
"Collect": "采集",
|
||||
"Business": "业务",
|
||||
"Unknown": "未知",
|
||||
"AddVariable": "添加变量",
|
||||
|
||||
"Script": "脚本",
|
||||
"Input": "输入",
|
||||
"Output": "输出"
|
||||
"ThingsGateway.Gateway.Razor.VariableRuntimeInfo": {
|
||||
"BusinessEnable": "添加业务设备",
|
||||
"SlaveUrl": "服务端Url",
|
||||
"Test": "一键添加测试变量",
|
||||
"TestDeviceCount": "采集设备数量",
|
||||
"TestVariableCount": "变量数量",
|
||||
"WriteValue": "写入值",
|
||||
"WriteVariable": "写入"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -1,77 +1,70 @@
|
||||
{
|
||||
"ThingsGateway.Management.RedundancyService": {
|
||||
"EditRedundancyOption": "EditRedundancyOption"
|
||||
"ThingsGateway.Management._Imports": {
|
||||
"Authentication": "Authentication",
|
||||
"CheckUpdate": "CheckUpdates",
|
||||
"HeaderText": "Communication Log",
|
||||
"Info": "Details",
|
||||
"Restart": "Restart Gateway",
|
||||
"Update": "Download Update"
|
||||
},
|
||||
"ThingsGateway.Management.Authentication": {
|
||||
"UUID": "UUID",
|
||||
"RegisterStatus": "RegisterStatus",
|
||||
"Authorized": "Authorized",
|
||||
"Unauthorized": "Unauthorized",
|
||||
"ExpireTime": "ExpireTime",
|
||||
"AuthName": "AuthName",
|
||||
"Authorized": "Authorized",
|
||||
"ExpireTime": "ExpireTime",
|
||||
"Password": "Password",
|
||||
"Register": "Register",
|
||||
"RegisterStatus": "RegisterStatus",
|
||||
"Unauthorized": "Unauthorized",
|
||||
"Unregister": "Unregister",
|
||||
"Password": "Password"
|
||||
"UUID": "UUID"
|
||||
},
|
||||
|
||||
"ThingsGateway.Management.AutoUpdateController": {
|
||||
"AutoUpdateController": "AutoUpdate",
|
||||
"Update": "Update"
|
||||
},
|
||||
|
||||
"ThingsGateway.Upgrade.UpdateZipFile": {
|
||||
"AppName": "AppName",
|
||||
"Version": "Version",
|
||||
"FileSize": "FileSize",
|
||||
"MinimumCompatibleVersion": "MinimumCompatibleVersion",
|
||||
"DotNetVersion": "DotNetVersion",
|
||||
"OSPlatform": "OSPlatform",
|
||||
"Architecture": "Architecture",
|
||||
"FilePath": "FilePath"
|
||||
"ThingsGateway.Management.RedundancyHostedService": {
|
||||
"ErrorSynchronizingData": "Synchronize data to standby site error",
|
||||
"RedundancyDisable": "Redundant gateway site not enabled",
|
||||
"RedundancyDup": "Redundant station settings duplicated",
|
||||
"Start": "Gateway management service started",
|
||||
"Stop": "Gateway management service stopped",
|
||||
"SwitchMasterState": "Cannot connect to redundant site, local machine will switch to normal state",
|
||||
"SwitchNormalState": "Local machine (primary site) will switch to normal state",
|
||||
"SwitchSlaveState": "Master site has recovered, local machine (standby) will switch to standby state"
|
||||
},
|
||||
"ThingsGateway.Management.RedundancyOptions": {
|
||||
"Confirm": "Confirm switching to redundant state",
|
||||
"Enable": "Enable Dual-Machine Redundancy",
|
||||
"ForcedSync": "Forced Synchronous",
|
||||
"ForcedSyncWarning": "Forcing synchronization will generate database configuration information.Are you sure you want to continue?",
|
||||
"HeartbeatInterval": "Heartbeat Interval",
|
||||
"IsMaster": "IsMaster",
|
||||
"IsStartBusinessDevice": "Enable Business Device in Slave Site",
|
||||
"Master": "Active Node",
|
||||
"MasterUri": "Master Node URL",
|
||||
"MaxErrorCount": "Maximum Error Count",
|
||||
"RedundancyOptions": "Dual-Machine Redundancy",
|
||||
"Restart": "The redundant service will be restarted soon",
|
||||
"Slave": "Slave Node",
|
||||
"Status": "Current Site Status",
|
||||
"Switch": "Switch",
|
||||
"SyncInterval": "Data Synchronization Interval",
|
||||
"VerifyToken": "Verification Token"
|
||||
},
|
||||
"ThingsGateway.Management.RedundancyService": {
|
||||
"EditRedundancyOption": "EditRedundancyOption"
|
||||
},
|
||||
|
||||
"ThingsGateway.Management.UpdateZipFileHostedService": {
|
||||
"Update": "New version detected"
|
||||
},
|
||||
"ThingsGateway.Management.RedundancyHostedService": {
|
||||
"Start": "Gateway management service started",
|
||||
"Stop": "Gateway management service stopped",
|
||||
"RedundancyDup": "Redundant station settings duplicated",
|
||||
"SwitchMasterState": "Cannot connect to redundant site, local machine will switch to normal state",
|
||||
"SwitchSlaveState": "Master site has recovered, local machine (standby) will switch to standby state",
|
||||
"SwitchNormalState": "Local machine (primary site) will switch to normal state",
|
||||
"ErrorSynchronizingData": "Synchronize data to standby site error",
|
||||
"RedundancyDisable": "Redundant gateway site not enabled"
|
||||
},
|
||||
"ThingsGateway.Management.RedundancyOptions": {
|
||||
"ForcedSync": "Forced Synchronous",
|
||||
"Enable": "Enable Dual-Machine Redundancy",
|
||||
"MasterUri": "Master Node URL",
|
||||
"IsMaster": "IsMaster",
|
||||
"VerifyToken": "Verification Token",
|
||||
"HeartbeatInterval": "Heartbeat Interval",
|
||||
"MaxErrorCount": "Maximum Error Count",
|
||||
"IsStartBusinessDevice": "Enable Business Device in Slave Site",
|
||||
"SyncInterval": "Data Synchronization Interval",
|
||||
"RedundancyOptions": "Dual-Machine Redundancy",
|
||||
"Status": "Current Site Status",
|
||||
"Master": "Active Node",
|
||||
"Slave": "Slave Node",
|
||||
"Switch": "Switch",
|
||||
|
||||
"Restart": "The redundant service will be restarted soon",
|
||||
"Confirm": "Confirm switching to redundant state",
|
||||
|
||||
"ForcedSyncWarning": "Forcing synchronization will generate database configuration information.Are you sure you want to continue?"
|
||||
|
||||
},
|
||||
|
||||
"ThingsGateway.Management._Imports": {
|
||||
"CheckUpdate": "CheckUpdates",
|
||||
"Authentication": "Authentication",
|
||||
"Update": "Download Update",
|
||||
"Restart": "Restart Gateway",
|
||||
"HeaderText": "Communication Log",
|
||||
"Info": "Details"
|
||||
"ThingsGateway.Upgrade.UpdateZipFile": {
|
||||
"AppName": "AppName",
|
||||
"Architecture": "Architecture",
|
||||
"DotNetVersion": "DotNetVersion",
|
||||
"FilePath": "FilePath",
|
||||
"FileSize": "FileSize",
|
||||
"MinimumCompatibleVersion": "MinimumCompatibleVersion",
|
||||
"OSPlatform": "OSPlatform",
|
||||
"Version": "Version"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,77 +1,70 @@
|
||||
{
|
||||
"ThingsGateway.Management.RedundancyService": {
|
||||
"EditRedundancyOption": "修改网关冗余配置"
|
||||
"ThingsGateway.Management._Imports": {
|
||||
"Authentication": "注册授权",
|
||||
"CheckUpdate": "检查更新",
|
||||
"HeaderText": "通讯日志",
|
||||
"Info": "详情",
|
||||
"Restart": "重启网关",
|
||||
"Update": "下载更新"
|
||||
},
|
||||
"ThingsGateway.Management.Authentication": {
|
||||
"UUID": "唯一编码",
|
||||
"RegisterStatus": "注册状态",
|
||||
"Authorized": "已授权",
|
||||
"Unauthorized": "未授权",
|
||||
"ExpireTime": "过期时间",
|
||||
"AuthName": "公司名称",
|
||||
"Authorized": "已授权",
|
||||
"ExpireTime": "过期时间",
|
||||
"Password": "注册码",
|
||||
"Register": "注册",
|
||||
"RegisterStatus": "注册状态",
|
||||
"Unauthorized": "未授权",
|
||||
"Unregister": "取消注册",
|
||||
"Password": "注册码"
|
||||
"UUID": "唯一编码"
|
||||
},
|
||||
"ThingsGateway.Management.AutoUpdateController": {
|
||||
"AutoUpdateController": "程序更新",
|
||||
"Update": "更新"
|
||||
},
|
||||
"ThingsGateway.Upgrade.UpdateZipFile": {
|
||||
|
||||
"AppName": "名称",
|
||||
"Version": "版本",
|
||||
|
||||
"FileSize": "文件大小",
|
||||
"MinimumCompatibleVersion": "最小兼容版本",
|
||||
"DotNetVersion": ".net版本",
|
||||
"OSPlatform": "系统版本",
|
||||
"Architecture": "架构",
|
||||
"FilePath": "文件路径"
|
||||
|
||||
"ThingsGateway.Management.RedundancyHostedService": {
|
||||
"ErrorSynchronizingData": "同步数据到从站错误",
|
||||
"RedundancyDisable": "不启用网关冗余站点",
|
||||
"RedundancyDup": "主备站设置重复",
|
||||
"Start": "网关管理服务启动",
|
||||
"Stop": "网关管理服务停止",
|
||||
"SwitchMasterState": "无法连接冗余站点,本机将切换到正常状态",
|
||||
"SwitchNormalState": "本机(主站)将切换到正常状态",
|
||||
"SwitchSlaveState": "主站已恢复,本机(从站)将切换到备用状态"
|
||||
},
|
||||
"ThingsGateway.Management.RedundancyOptions": {
|
||||
"Confirm": "确认切换冗余状态",
|
||||
"Enable": "启用双机冗余",
|
||||
"ForcedSync": "强制同步",
|
||||
"ForcedSyncWarning": "强制同步会生成数据库配置信息,是否继续?",
|
||||
"HeartbeatInterval": "心跳间隔",
|
||||
"IsMaster": "是否为主站",
|
||||
"IsStartBusinessDevice": "备用站点启用业务设备",
|
||||
"Master": "激活站",
|
||||
"MasterUri": "主站Url",
|
||||
"MaxErrorCount": "错误最大次数",
|
||||
"RedundancyOptions": "双机冗余",
|
||||
"Restart": "即将重新启动冗余服务",
|
||||
"Slave": "备用站",
|
||||
"Status": "当前站点状态",
|
||||
"Switch": "切换",
|
||||
"SyncInterval": "数据同步间隔",
|
||||
"VerifyToken": "Token"
|
||||
},
|
||||
"ThingsGateway.Management.RedundancyService": {
|
||||
"EditRedundancyOption": "修改网关冗余配置"
|
||||
},
|
||||
|
||||
"ThingsGateway.Management.UpdateZipFileHostedService": {
|
||||
"Update": "检测到新版本"
|
||||
},
|
||||
"ThingsGateway.Management.RedundancyHostedService": {
|
||||
"Start": "网关管理服务启动",
|
||||
"Stop": "网关管理服务停止",
|
||||
"RedundancyDup": "主备站设置重复",
|
||||
"SwitchMasterState": "无法连接冗余站点,本机将切换到正常状态",
|
||||
"SwitchSlaveState": "主站已恢复,本机(从站)将切换到备用状态",
|
||||
"SwitchNormalState": "本机(主站)将切换到正常状态",
|
||||
"ErrorSynchronizingData": "同步数据到从站错误",
|
||||
"RedundancyDisable": "不启用网关冗余站点"
|
||||
},
|
||||
|
||||
"ThingsGateway.Management.RedundancyOptions": {
|
||||
"ForcedSync": "强制同步",
|
||||
"Enable": "启用双机冗余",
|
||||
"MasterUri": "主站Url",
|
||||
"IsMaster": "是否为主站",
|
||||
"VerifyToken": "Token",
|
||||
"HeartbeatInterval": "心跳间隔",
|
||||
"MaxErrorCount": "错误最大次数",
|
||||
"IsStartBusinessDevice": "备用站点启用业务设备",
|
||||
"SyncInterval": "数据同步间隔",
|
||||
"RedundancyOptions": "双机冗余",
|
||||
"Status": "当前站点状态",
|
||||
"Master": "激活站",
|
||||
"Slave": "备用站",
|
||||
"Switch": "切换",
|
||||
|
||||
"Restart": "即将重新启动冗余服务",
|
||||
"Confirm": "确认切换冗余状态",
|
||||
"ForcedSyncWarning": "强制同步会生成数据库配置信息,是否继续?"
|
||||
},
|
||||
|
||||
"ThingsGateway.Management._Imports": {
|
||||
"CheckUpdate": "检查更新",
|
||||
"Authentication": "注册授权",
|
||||
"Update": "下载更新",
|
||||
"Restart": "重启网关",
|
||||
"HeaderText": "通讯日志",
|
||||
"Info": "详情"
|
||||
"ThingsGateway.Upgrade.UpdateZipFile": {
|
||||
"AppName": "名称",
|
||||
"Architecture": "架构",
|
||||
"DotNetVersion": ".net版本",
|
||||
"FilePath": "文件路径",
|
||||
"FileSize": "文件大小",
|
||||
"MinimumCompatibleVersion": "最小兼容版本",
|
||||
"OSPlatform": "系统版本",
|
||||
"Version": "版本"
|
||||
}
|
||||
}
|
||||
}
|
@@ -175,7 +175,7 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 输出警告日志,指示同步数据到从站时发生错误
|
||||
LogMessage?.LogWarning(ex, Localizer["ErrorSynchronizingData"]);
|
||||
LogMessage?.LogWarning(ex, "Synchronize data to standby site error");
|
||||
}
|
||||
await Task.Delay(syncInterval, stoppingToken).ConfigureAwait(false);
|
||||
}
|
||||
@@ -407,7 +407,7 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
|
||||
{
|
||||
// 输出日志,指示主站已恢复,从站将切换到备用状态
|
||||
if (first)
|
||||
LogMessage?.Warning(Localizer["SwitchSlaveState"]);
|
||||
LogMessage?.Warning("Master site has recovered, local machine (standby) will switch to standby state");
|
||||
|
||||
// 将 IsStart 设置为 false,表示当前设备为从站,切换到备用状态
|
||||
_gatewayRedundantSerivce.StartCollectChannelEnable = false;
|
||||
@@ -433,7 +433,7 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo
|
||||
{
|
||||
// 输出日志,指示无法连接冗余站点,本机将切换到正常状态
|
||||
if (first)
|
||||
LogMessage?.Warning(Localizer["SwitchMasterState"]);
|
||||
LogMessage?.Warning("Cannot connect to redundant site, local machine will switch to normal state");
|
||||
_gatewayRedundantSerivce.StartCollectChannelEnable = true;
|
||||
await RestartAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
@@ -8,31 +8,22 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Extensions.Localization;
|
||||
using ThingsGateway.Foundation;
|
||||
|
||||
namespace ThingsGateway.Foundation;
|
||||
namespace ThingsGateway.RulesEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 语言资源
|
||||
/// </summary>
|
||||
public class DefaultResource
|
||||
public static class AppResource
|
||||
{
|
||||
private static IStringLocalizer localizer;
|
||||
|
||||
/// <summary>
|
||||
/// Localizer
|
||||
/// </summary>
|
||||
public static IStringLocalizer Localizer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (localizer == null)
|
||||
{
|
||||
localizer = LocalizerUtil.GetLocalizer.Invoke(typeof(DefaultResource));
|
||||
}
|
||||
return localizer;
|
||||
}
|
||||
}
|
||||
|
||||
//使用频率高的多语言应初始化构建
|
||||
public static string RulesEngineTaskStart => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.RulesEngineTaskStart : EnglishResource.RulesEngineTaskStart;
|
||||
}
|
||||
|
||||
public static class ChineseResource
|
||||
{
|
||||
|
||||
public const string RulesEngineTaskStart = "规则引擎线程启动";
|
||||
}
|
||||
public static class EnglishResource
|
||||
{
|
||||
public const string RulesEngineTaskStart = "Rules engine service started";
|
||||
|
||||
}
|
@@ -1,59 +1,51 @@
|
||||
{
|
||||
"ThingsGateway.RulesEngine._Imports": {
|
||||
"Start": "Start",
|
||||
"StartNode": "Start",
|
||||
"End": "End",
|
||||
"EndNode": "End",
|
||||
"TimeIntervalTriggerNode": "IntervalExecutionTrigger",
|
||||
"TimeIntervalTriggerNode.Placeholder": "IntervalTime (ms)",
|
||||
"DeviceChangedTriggerNode": "DeviceStateTrigger",
|
||||
"Device.Placeholder": "DeviceName",
|
||||
"Actuator": "Actuator",
|
||||
"AlarmChangedTriggerNode": "AlarmStateTrigger",
|
||||
"Variable.Placeholder": "VariableName",
|
||||
"ValueChangedTriggerNode": "VariableStateTrigger",
|
||||
"DelayNode": "Delay",
|
||||
"DelayNode.Placeholder": "Interval Time (ms)",
|
||||
"DataNode": "DataScript",
|
||||
"ConditionNode": "Condition",
|
||||
"ConditionNode.Placeholder": "Calculation returns boolean",
|
||||
"ExecuteScriptNode": "CustomExecution",
|
||||
"BusinessNode": "BusinessDeviceExecution",
|
||||
"BusinessNode.Placeholder": "BusinessDeviceName",
|
||||
"Cancel": "Cancel",
|
||||
"Check": "Check",
|
||||
"Clear": "Clear",
|
||||
"ConditionNode": "Condition",
|
||||
"ConditionNode.Placeholder": "Calculation returns boolean",
|
||||
"DataNode": "DataScript",
|
||||
"DelayNode": "Delay",
|
||||
"DelayNode.Placeholder": "Interval Time (ms)",
|
||||
"Design": "Design",
|
||||
"Device.Placeholder": "DeviceName",
|
||||
"DeviceChangedTriggerNode": "DeviceStateTrigger",
|
||||
"Download": "Download JSON",
|
||||
"End": "End",
|
||||
"EndNode": "End",
|
||||
"ExecuteScriptNode": "CustomExecution",
|
||||
"Expression": "Script",
|
||||
"Load": "Load JSON",
|
||||
"Other": "Other",
|
||||
"Save": "Save",
|
||||
"Start": "Start",
|
||||
"Start/End": "Start/End",
|
||||
"StartNode": "Start",
|
||||
"TimeIntervalTriggerNode": "IntervalExecutionTrigger",
|
||||
"TimeIntervalTriggerNode.Placeholder": "IntervalTime (ms)",
|
||||
"Trigger": "Trigger",
|
||||
"ValueChangedTriggerNode": "VariableStateTrigger",
|
||||
"Variable.Placeholder": "VariableName",
|
||||
"VariableRpcNode": "VariableRpc",
|
||||
"VariableRpcNode.Placeholder": "VariableName",
|
||||
|
||||
"Clear": "Clear",
|
||||
|
||||
"Load": "Load JSON",
|
||||
"Download": "Download JSON",
|
||||
"Cancel": "Cancel",
|
||||
"Save": "Save",
|
||||
"Design": "Design",
|
||||
|
||||
"Start/End": "Start/End",
|
||||
"Trigger": "Trigger",
|
||||
"Expression": "Script",
|
||||
"Actuator": "Actuator",
|
||||
"Other": "Other",
|
||||
"ZoomToFit": "ZoomToFit",
|
||||
"Check": "Check"
|
||||
"ZoomToFit": "ZoomToFit"
|
||||
},
|
||||
"ThingsGateway.RulesEngine.Rules": {
|
||||
"Name": "Name",
|
||||
"Status": "Status",
|
||||
"SortCode": "SortCode",
|
||||
"ClearRules": "ClearRules",
|
||||
"DeleteRules": "DeleteRules",
|
||||
"SaveRules": "SaveRules"
|
||||
},
|
||||
|
||||
"ThingsGateway.RulesEngine.RulesEngineHostedService": {
|
||||
"RulesEngineTask": "Rules Engine Thread",
|
||||
"RulesEngineTaskStart": "Rules Engine Thread Start"
|
||||
"Name": "Name",
|
||||
"SaveRules": "SaveRules",
|
||||
"SortCode": "SortCode",
|
||||
"Status": "Status"
|
||||
},
|
||||
|
||||
"ThingsGateway.RulesEngine.RulesStatus": {
|
||||
"RulesId": "Name",
|
||||
"LogConsole": "Log"
|
||||
"LogConsole": "Log",
|
||||
"RulesId": "Name"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,63 +1,51 @@
|
||||
{
|
||||
"ThingsGateway.RulesEngine._Imports": {
|
||||
"Start": "开始",
|
||||
"StartNode": "开始",
|
||||
"End": "结束",
|
||||
"EndNode": "结束",
|
||||
"TimeIntervalTriggerNode": "间隔执行触发器",
|
||||
"TimeIntervalTriggerNode.Placeholder": "间隔时间(ms)",
|
||||
"DeviceChangedTriggerNode": "设备状态触发器",
|
||||
"Device.Placeholder": "设备名称",
|
||||
"Actuator": "执行",
|
||||
"AlarmChangedTriggerNode": "报警状态触发器",
|
||||
"ValueChangedTriggerNode": "变量状态触发器",
|
||||
"Variable.Placeholder": "变量名称",
|
||||
"DelayNode": "延时",
|
||||
"DelayNode.Placeholder": "间隔时间(ms)",
|
||||
"DataNode": "数据脚本",
|
||||
"ConditionNode": "条件",
|
||||
"ConditionNode.Placeholder": "计算返回boolean",
|
||||
"ExecuteScriptNode": "自定义执行",
|
||||
"BusinessNode": "业务设备执行",
|
||||
"BusinessNode.Placeholder": "设备名称",
|
||||
"Cancel": "取消",
|
||||
"Check": "检查",
|
||||
"Clear": "清空",
|
||||
"ConditionNode": "条件",
|
||||
"ConditionNode.Placeholder": "计算返回boolean",
|
||||
"DataNode": "数据脚本",
|
||||
"DelayNode": "延时",
|
||||
"DelayNode.Placeholder": "间隔时间(ms)",
|
||||
"Design": "设计",
|
||||
"Device.Placeholder": "设备名称",
|
||||
"DeviceChangedTriggerNode": "设备状态触发器",
|
||||
"Download": "下载Json",
|
||||
"End": "结束",
|
||||
"EndNode": "结束",
|
||||
"ExecuteScriptNode": "自定义执行",
|
||||
"Expression": "脚本",
|
||||
"Load": "加载Json",
|
||||
"Other": "其他",
|
||||
"Save": "保存",
|
||||
"Start": "开始",
|
||||
"Start/End": "开始/结束",
|
||||
"StartNode": "开始",
|
||||
"TimeIntervalTriggerNode": "间隔执行触发器",
|
||||
"TimeIntervalTriggerNode.Placeholder": "间隔时间(ms)",
|
||||
"Trigger": "触发器",
|
||||
"ValueChangedTriggerNode": "变量状态触发器",
|
||||
"Variable.Placeholder": "变量名称",
|
||||
"VariableRpcNode": "RPC写入",
|
||||
"VariableRpcNode.Placeholder": "变量名称",
|
||||
|
||||
|
||||
"Clear": "清空",
|
||||
|
||||
|
||||
"Load": "加载Json",
|
||||
"Download": "下载Json",
|
||||
"Cancel": "取消",
|
||||
"Save": "保存",
|
||||
"Design": "设计",
|
||||
|
||||
"Start/End": "开始/结束",
|
||||
"Trigger": "触发器",
|
||||
"Expression": "脚本",
|
||||
"Actuator": "执行",
|
||||
"Other": "其他",
|
||||
"ZoomToFit": "自适应",
|
||||
|
||||
"Check": "检查"
|
||||
"ZoomToFit": "自适应"
|
||||
},
|
||||
"ThingsGateway.RulesEngine.Rules": {
|
||||
|
||||
"Name": "名称",
|
||||
"Status": "状态",
|
||||
"SortCode": "排序",
|
||||
"ClearRules": "清空规则",
|
||||
"DeleteRules": "删除规则",
|
||||
"SaveRules": "保存规则"
|
||||
},
|
||||
|
||||
"ThingsGateway.RulesEngine.RulesEngineHostedService": {
|
||||
"RulesEngineTask": "规则引擎线程",
|
||||
"RulesEngineTaskStart": "规则引擎线程启动"
|
||||
"Name": "名称",
|
||||
"SaveRules": "保存规则",
|
||||
"SortCode": "排序",
|
||||
"Status": "状态"
|
||||
},
|
||||
|
||||
"ThingsGateway.RulesEngine.RulesStatus": {
|
||||
"RulesId": "名称",
|
||||
"LogConsole": "日志"
|
||||
"LogConsole": "日志",
|
||||
"RulesId": "名称"
|
||||
}
|
||||
}
|
||||
}
|
@@ -231,7 +231,7 @@ internal sealed class RulesEngineHostedService : BackgroundService, IRulesEngine
|
||||
await RestartLock.WaitAsync().ConfigureAwait(false); // 等待获取锁,以确保只有一个线程可以执行以下代码
|
||||
TokenSource ??= new CancellationTokenSource();
|
||||
await StartAll(TokenSource.Token).ConfigureAwait(false);
|
||||
_logger.LogInformation(Localizer["RulesEngineTaskStart"]);
|
||||
_logger.LogInformation(AppResource.RulesEngineTaskStart);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@@ -53,7 +53,7 @@ public class Dlt645_2007Message : MessageBase, IResultMessage
|
||||
if ((byte)sumCheck != byteBlock[endIndex - 2])
|
||||
{
|
||||
//校验错误
|
||||
ErrorMessage = DltResource.Localizer["SumError"];
|
||||
ErrorMessage = AppResource.SumError;
|
||||
OperCode = 999;
|
||||
return FilterResult.Success;
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public class Dlt645_2007Message : MessageBase, IResultMessage
|
||||
{
|
||||
Response.ErrorCode = (byte)(byteBlock[HeadCodeIndex + 10] - 0x33);
|
||||
var error = Dlt645Helper.Get2007ErrorMessage(Response.ErrorCode.Value);
|
||||
ErrorMessage = DltResource.Localizer["FunctionError", $"0x{controlCode:X2}", error];
|
||||
ErrorMessage = string.Format(AppResource.FunctionError, $"0x{controlCode:X2}", error);
|
||||
OperCode = 999;
|
||||
return FilterResult.Success;
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class Dlt645_2007Message : MessageBase, IResultMessage
|
||||
{
|
||||
if (!Request.Station.SequenceEqual(ReadStation))//读写通讯地址例外
|
||||
{
|
||||
ErrorMessage = DltResource.Localizer["StationNotSame"];
|
||||
ErrorMessage = AppResource.StationNotSame;
|
||||
OperCode = 999;
|
||||
return FilterResult.Success;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ public class Dlt645_2007Message : MessageBase, IResultMessage
|
||||
if (controlCode != ((byte)Dlt645_2007Send.ControlCode) + 0x80)//控制码不符合时,返回错误
|
||||
{
|
||||
ErrorMessage =
|
||||
DltResource.Localizer["FunctionNotSame", $"0x{controlCode:X2}", $"0x{(byte)Dlt645_2007Send.ControlCode:X2}"];
|
||||
string.Format(AppResource.FunctionNotSame, $"0x{controlCode:X2}", $"0x{(byte)Dlt645_2007Send.ControlCode:X2}");
|
||||
OperCode = 999;
|
||||
return FilterResult.Success;
|
||||
}
|
||||
@@ -97,7 +97,7 @@ public class Dlt645_2007Message : MessageBase, IResultMessage
|
||||
Response.DataId = byteBlock.Span.Slice(HeadCodeIndex + 10, 4).ToArray().BytesAdd(-0x33);
|
||||
if (!Response.DataId.SequenceEqual(Request.DataId))
|
||||
{
|
||||
ErrorMessage = DltResource.Localizer["DataIdNotSame"];
|
||||
ErrorMessage = AppResource.DataIdNotSame;
|
||||
OperCode = 999;
|
||||
return FilterResult.Success;
|
||||
}
|
||||
|
@@ -109,7 +109,7 @@ public class Dlt645_2007Send : ISendMessage
|
||||
{
|
||||
if (Dlt645_2007Address?.DataId.Length < 4)
|
||||
{
|
||||
throw new(DltResource.Localizer["DataIdError"]);
|
||||
throw new(AppResource.DataIdError);
|
||||
}
|
||||
if (Fehead.Length > 0)
|
||||
{
|
||||
@@ -132,7 +132,7 @@ public class Dlt645_2007Send : ISendMessage
|
||||
var dataInfos = Dlt645Helper.GetDataInfos(Dlt645_2007Address.DataId);
|
||||
if (Datas.Length != dataInfos.Count)
|
||||
{
|
||||
throw new(DltResource.Localizer["CountError"]);
|
||||
throw new(AppResource.CountError);
|
||||
}
|
||||
for (int i = 0; i < Datas.Length; i++)
|
||||
{
|
||||
|
@@ -116,7 +116,7 @@ public class Dlt645_2007Master : DtuServiceDeviceBase
|
||||
/// <inheritdoc/>
|
||||
public override string GetAddressDescription()
|
||||
{
|
||||
return $"{base.GetAddressDescription()}{Environment.NewLine}{DltResource.Localizer["AddressDes"]}";
|
||||
return $"{base.GetAddressDescription()}{Environment.NewLine}{AppResource.AddressDes}";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -313,7 +313,7 @@ public class Dlt645_2007Master : DtuServiceDeviceBase
|
||||
case 4800: baudRateByte = 0x10; break;
|
||||
case 9600: baudRateByte = 0x20; break;
|
||||
case 19200: baudRateByte = 0x40; break;
|
||||
default: return new OperResult<string>(DltResource.Localizer["BaudRateError", baudRate]);
|
||||
default: return new OperResult<string>(string.Format(AppResource.BaudRateError, baudRate));
|
||||
}
|
||||
|
||||
Dlt645_2007Address dAddress = new();
|
||||
|
@@ -7,7 +7,6 @@
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Dlt645;
|
||||
|
||||
/// <summary>
|
||||
@@ -37,14 +36,14 @@ internal static class Dlt645Helper
|
||||
{
|
||||
string error = buffer switch
|
||||
{
|
||||
0x80 => DltResource.Localizer["Error1"],
|
||||
0x40 => DltResource.Localizer["Error2"],
|
||||
0x20 => DltResource.Localizer["Error3"],
|
||||
0x10 => DltResource.Localizer["Error4"],
|
||||
0x08 => DltResource.Localizer["Error5"],
|
||||
0x04 => DltResource.Localizer["Error6"],
|
||||
0x02 => DltResource.Localizer["Error7"],
|
||||
_ => DltResource.Localizer["Error8"],
|
||||
0x80 => AppResource.Error1,
|
||||
0x40 => AppResource.Error2,
|
||||
0x20 => AppResource.Error3,
|
||||
0x10 => AppResource.Error4,
|
||||
0x08 => AppResource.Error5,
|
||||
0x04 => AppResource.Error6,
|
||||
0x02 => AppResource.Error7,
|
||||
_ => AppResource.Error8,
|
||||
};
|
||||
return error;
|
||||
}
|
||||
|
@@ -8,23 +8,100 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace ThingsGateway.Foundation.Dlt645;
|
||||
|
||||
public class DltResource
|
||||
public static class AppResource
|
||||
{
|
||||
private static IStringLocalizer localizer;
|
||||
|
||||
public static IStringLocalizer Localizer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (localizer == null)
|
||||
{
|
||||
localizer = LocalizerUtil.GetLocalizer.Invoke(typeof(DltResource));
|
||||
}
|
||||
return localizer;
|
||||
}
|
||||
}
|
||||
public static string Error1 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.Error1 : EnglishResource.Error1;
|
||||
public static string Error2 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.Error2 : EnglishResource.Error2;
|
||||
public static string Error3 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.Error3 : EnglishResource.Error3;
|
||||
public static string Error4 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.Error4 : EnglishResource.Error4;
|
||||
public static string Error5 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.Error5 : EnglishResource.Error5;
|
||||
public static string Error6 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.Error6 : EnglishResource.Error6;
|
||||
public static string Error7 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.Error7 : EnglishResource.Error7;
|
||||
public static string Error8 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.Error8 : EnglishResource.Error8;
|
||||
public static string AddressDes => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.AddressDes : EnglishResource.AddressDes;
|
||||
public static string SumError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.SumError : EnglishResource.SumError;
|
||||
public static string StationNotSame => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.StationNotSame : EnglishResource.StationNotSame;
|
||||
public static string FunctionError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.FunctionError : EnglishResource.FunctionError;
|
||||
public static string FunctionNotSame => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.FunctionNotSame : EnglishResource.FunctionNotSame;
|
||||
public static string DataIdNotSame => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.DataIdNotSame : EnglishResource.DataIdNotSame;
|
||||
public static string CountError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.CountError : EnglishResource.CountError;
|
||||
public static string DataIdError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.DataIdError : EnglishResource.DataIdError;
|
||||
public static string BaudRateError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.BaudRateError : EnglishResource.BaudRateError;
|
||||
|
||||
}
|
||||
|
||||
public static class ChineseResource
|
||||
{
|
||||
public const string Error1 = "其他错误";
|
||||
public const string Error2 = "费率数超";
|
||||
public const string Error3 = "日时段数超";
|
||||
public const string Error4 = "年时区数超";
|
||||
public const string Error5 = "通信速率不能更改";
|
||||
public const string Error6 = "密码错/未授权";
|
||||
public const string Error7 = "无请求数据";
|
||||
public const string Error8 = "其他错误";
|
||||
public const string AddressDes = """
|
||||
数据标识地址
|
||||
|
||||
查看附带文档或者相关资料,下面列举一些常见的数据标识地址
|
||||
|
||||
地址 说明
|
||||
-----------------------------------------
|
||||
02010100 A相电压
|
||||
02020100 A相电流
|
||||
02030000 瞬时总有功功率
|
||||
00000000 (当前)组合有功总电能
|
||||
00010000 (当前)正向有功总电能
|
||||
""";
|
||||
|
||||
|
||||
public const string SumError = "和校验错误";
|
||||
public const string StationNotSame = "站号不一致";
|
||||
public const string FunctionError = "异常控制码:{0},错误信息:{1}";
|
||||
public const string FunctionNotSame = "功能码不一致,请求功能码 {0},返回功能码 {1}";
|
||||
public const string DataIdNotSame = "返回数据标识不符合规则";
|
||||
public const string CountError = "写入参数数量不符合地址要求";
|
||||
public const string DataIdError = "变量寄存器地址错误";
|
||||
public const string BaudRateError = "不支持此波特率 {0}";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class EnglishResource
|
||||
{
|
||||
public const string Error1 = "Other error";
|
||||
public const string Error2 = "Exceeded number of rate segments";
|
||||
public const string Error3 = "Exceeded number of daily time segments";
|
||||
public const string Error4 = "Exceeded number of yearly time zones";
|
||||
public const string Error5 = "Communication baud rate cannot be changed";
|
||||
public const string Error6 = "Incorrect password / unauthorized";
|
||||
public const string Error7 = "No requested data";
|
||||
public const string Error8 = "Other error";
|
||||
|
||||
public const string AddressDes = """
|
||||
Data Identifier Address
|
||||
|
||||
Refer to the attached documentation or related materials. Below are some common data identifier addresses:
|
||||
|
||||
Address Description
|
||||
-----------------------------------------
|
||||
02010100 Phase A voltage
|
||||
02020100 Phase A current
|
||||
02030000 Instantaneous total active power
|
||||
00000000 (Current) Combined total active energy
|
||||
00010000 (Current) Forward total active energy
|
||||
""";
|
||||
|
||||
public const string SumError = "Checksum error";
|
||||
public const string StationNotSame = "Station numbers do not match";
|
||||
public const string FunctionError = "Exception function code: {0}, Error message: {1}";
|
||||
public const string FunctionNotSame = "Function code mismatch. Requested: {0}, Returned: {1}";
|
||||
public const string DataIdNotSame = "Returned data identifier does not match the expected format";
|
||||
public const string CountError = "Incorrect number of parameters for the address";
|
||||
public const string DataIdError = "Invalid variable register address";
|
||||
public const string BaudRateError = "Unsupported baud rate {0}";
|
||||
}
|
||||
|
@@ -1,36 +1,14 @@
|
||||
{
|
||||
"ThingsGateway.Foundation.Dlt645.Dlt645_2007Address": {
|
||||
"Data": "Address",
|
||||
"Reverse": "Reverse",
|
||||
"StationString": "特指站号"
|
||||
},
|
||||
"ThingsGateway.Foundation.Dlt645.Dlt645_2007Master": {
|
||||
"FEHead": "FEHead",
|
||||
"OperCode": "OperCode",
|
||||
"Password": "Password",
|
||||
"Station": "Station"
|
||||
|
||||
},
|
||||
|
||||
"ThingsGateway.Foundation.Dlt645.DltResource": {
|
||||
"AddressDes": "Data identification address\n\nRefer to accompanying documents or related materials. Below are some common data identification addresses\n\nAddress Description\n-----------------------------------------\n02010100 Phase A voltage\n02020100 Phase A current\n02030000 Instantaneous total active power\n00000000 (Current) Total active energy\n00010000 (Current) Forward active energy",
|
||||
"SumError": "Checksum error",
|
||||
"StationNotSame": "Inconsistent station number",
|
||||
"FunctionError": "Exception control code: {0}, error message: {1}",
|
||||
"FunctionNotSame": "Inconsistent function code, requested function code {0}, returned function code {1}",
|
||||
"DataIdNotSame": "Returned data identification does not comply with the rules",
|
||||
"BaudRateError": "Unsupported baud rate {0}",
|
||||
"CountError": "Number of parameters written does not meet address requirements",
|
||||
"DataIdError": "Variable Address error",
|
||||
"Error1": "Other errors",
|
||||
"Error2": "Excessive number of rates",
|
||||
"Error3": "Excessive number of daily time periods",
|
||||
"Error4": "Excessive number of yearly time zones",
|
||||
"Error5": "Communication rate cannot be changed",
|
||||
"Error6": "Incorrect password / unauthorized",
|
||||
"Error7": "No request data",
|
||||
"Error8": "Other errors"
|
||||
},
|
||||
"ThingsGateway.Foundation.Dlt645.Dlt645_2007Address": {
|
||||
"StationString": "特指站号",
|
||||
"Data": "Address",
|
||||
"Reverse": "Reverse"
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,36 +1,13 @@
|
||||
{
|
||||
"ThingsGateway.Foundation.Dlt645.Dlt645_2007Address": {
|
||||
"Data": "起始地址",
|
||||
"Reverse": "字节反转",
|
||||
"StationString": "特指站号"
|
||||
},
|
||||
"ThingsGateway.Foundation.Dlt645.Dlt645_2007Master": {
|
||||
"FEHead": "前导符报文头",
|
||||
"OperCode": "操作员代码",
|
||||
"Password": "写入密码",
|
||||
"Station": "通讯地址"
|
||||
|
||||
},
|
||||
|
||||
"ThingsGateway.Foundation.Dlt645.DltResource": {
|
||||
"AddressDes": "数据标识地址\n\n查看附带文档或者相关资料,下面列举一些常见的数据标识地址\n\n地址 说明\n-----------------------------------------\n02010100 A相电压\n02020100 A相电流\n02030000 瞬时总有功功率\n00000000 (当前)组合有功总电能\n00010000 (当前)正向有功总电能",
|
||||
"SumError": "和校验错误",
|
||||
"StationNotSame": "站号不一致",
|
||||
"FunctionError": "异常控制码:{0},错误信息:{1}",
|
||||
"FunctionNotSame": "功能码不一致,请求功能码 {0},返回功能码 {1}",
|
||||
"DataIdNotSame": "返回数据标识不符合规则",
|
||||
"BaudRateError": "不支持此波特率 {0}",
|
||||
"CountError": "写入参数数量不符合地址要求",
|
||||
"DataIdError": "变量寄存器地址错误",
|
||||
"Error1": "其他错误",
|
||||
"Error2": "费率数超",
|
||||
"Error3": "日时段数超",
|
||||
"Error4": "年时区数超",
|
||||
"Error5": "通信速率不能更改",
|
||||
"Error6": "密码错/未授权",
|
||||
"Error7": "无请求数据",
|
||||
"Error8": "其他错误"
|
||||
},
|
||||
|
||||
"ThingsGateway.Foundation.Dlt645.Dlt645_2007Address": {
|
||||
"StationString": "特指站号",
|
||||
"Data": "起始地址",
|
||||
"Reverse": "字节反转"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -112,7 +112,7 @@ public class ModbusAddress : ModbusRequest
|
||||
{
|
||||
var readF = ushort.Parse(address.Substring(0, 1));
|
||||
if (readF > 4)
|
||||
throw new(ModbusResource.Localizer["FunctionError"]);
|
||||
throw new(AppResource.FunctionError);
|
||||
switch (readF)
|
||||
{
|
||||
case 0:
|
||||
|
@@ -20,7 +20,7 @@ public static class ModbusHelper
|
||||
/// <returns></returns>
|
||||
public static string GetAddressDescription()
|
||||
{
|
||||
return ModbusResource.Localizer["AddressDes"];
|
||||
return AppResource.AddressDes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -30,16 +30,16 @@ public static class ModbusHelper
|
||||
{
|
||||
return code switch
|
||||
{
|
||||
1 => ModbusResource.Localizer["ModbusError1"],
|
||||
2 => ModbusResource.Localizer["ModbusError2"],
|
||||
3 => ModbusResource.Localizer["ModbusError3"],
|
||||
4 => ModbusResource.Localizer["ModbusError4"],
|
||||
5 => ModbusResource.Localizer["ModbusError5"],
|
||||
6 => ModbusResource.Localizer["ModbusError6"],
|
||||
8 => ModbusResource.Localizer["ModbusError8"],
|
||||
10 => ModbusResource.Localizer["ModbusError10"],
|
||||
11 => ModbusResource.Localizer["ModbusError11"],
|
||||
_ => DefaultResource.Localizer["UnknownError", code],
|
||||
1 => AppResource.ModbusError1,
|
||||
2 => AppResource.ModbusError2,
|
||||
3 => AppResource.ModbusError3,
|
||||
4 => AppResource.ModbusError4,
|
||||
5 => AppResource.ModbusError5,
|
||||
6 => AppResource.ModbusError6,
|
||||
8 => AppResource.ModbusError8,
|
||||
10 => AppResource.ModbusError10,
|
||||
11 => AppResource.ModbusError11,
|
||||
_ => string.Format(ThingsGateway.Foundation.AppResource.UnknownError, code),
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -71,7 +71,7 @@ public static class PackHelper
|
||||
{
|
||||
case DataTypeEnum.String:
|
||||
// 字符串类型需特殊处理
|
||||
lastLen = (it.ThingsGatewayBitConverter.StringLength == null ? throw new(DefaultResource.Localizer["StringTypePackError"]) : it.ThingsGatewayBitConverter.StringLength.Value);
|
||||
lastLen = (it.ThingsGatewayBitConverter.StringLength == null ? throw new(ThingsGateway.Foundation.AppResource.StringTypePackError) : it.ThingsGatewayBitConverter.StringLength.Value);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@@ -8,23 +8,87 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace ThingsGateway.Foundation.Modbus;
|
||||
|
||||
public class ModbusResource
|
||||
{
|
||||
private static IStringLocalizer localizer;
|
||||
|
||||
public static IStringLocalizer Localizer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (localizer == null)
|
||||
{
|
||||
localizer = LocalizerUtil.GetLocalizer.Invoke(typeof(ModbusResource));
|
||||
}
|
||||
return localizer;
|
||||
}
|
||||
}
|
||||
public static class AppResource
|
||||
{
|
||||
public static string CrcError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.CrcError : EnglishResource.CrcError;
|
||||
public static string FunctionError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.FunctionError : EnglishResource.FunctionError;
|
||||
public static string FunctionNotSame => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.FunctionNotSame : EnglishResource.FunctionNotSame;
|
||||
public static string ModbusError1 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ModbusError1 : EnglishResource.ModbusError1;
|
||||
public static string ModbusError10 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ModbusError10 : EnglishResource.ModbusError10;
|
||||
public static string ModbusError11 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ModbusError11 : EnglishResource.ModbusError11;
|
||||
public static string ModbusError2 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ModbusError2 : EnglishResource.ModbusError2;
|
||||
public static string ModbusError3 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ModbusError3 : EnglishResource.ModbusError3;
|
||||
public static string ModbusError4 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ModbusError4 : EnglishResource.ModbusError4;
|
||||
public static string ModbusError5 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ModbusError5 : EnglishResource.ModbusError5;
|
||||
public static string ModbusError6 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ModbusError6 : EnglishResource.ModbusError6;
|
||||
public static string ModbusError8 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ModbusError8 : EnglishResource.ModbusError8;
|
||||
public static string StationNotSame => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.StationNotSame : EnglishResource.StationNotSame;
|
||||
public static string AddressDes => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.AddressDes : EnglishResource.AddressDes;
|
||||
public static string ValueOverlimit => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ValueOverlimit : EnglishResource.ValueOverlimit;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class ChineseResource
|
||||
{
|
||||
|
||||
public const string CrcError = "Crc校验失败";
|
||||
public const string FunctionError = "功能码错误";
|
||||
public const string FunctionNotSame = "功能码不一致,请求功能码 {0},返回功能码 {1}";
|
||||
public const string ModbusError1 = "不支持的功能码";
|
||||
public const string ModbusError10 = "网关路径不可用";
|
||||
public const string ModbusError11 = "网关目标设备响应失败";
|
||||
public const string ModbusError2 = "读取寄存器越界";
|
||||
public const string ModbusError3 = "读取长度超限";
|
||||
public const string ModbusError4 = "设备故障";
|
||||
public const string ModbusError5 = "设备已确认,但未执行";
|
||||
public const string ModbusError6 = "设备忙";
|
||||
public const string ModbusError8 = "存储奇偶性错误";
|
||||
public const string StationNotSame = "站号不一致,请求站号 {0} ,返回站号 {1}";
|
||||
public const string AddressDes = """
|
||||
线圈寄存器使用从 00001 开始的地址编号。
|
||||
离散输入寄存器使用从 10001 开始的地址编号。
|
||||
输入寄存器使用从 30001 开始的地址编号。
|
||||
保持寄存器使用从 40001 开始的地址编号。
|
||||
举例:40001=>保持寄存器第一个寄存器
|
||||
额外格式
|
||||
设备站号 ,比如40001;s=2; ,代表设备地址为2的保持寄存器第一个寄存器
|
||||
写入功能码 ,比如40001;w=16; ,代表保持寄存器第一个寄存器,写入值时采用0x10功能码
|
||||
""";
|
||||
public const string ValueOverlimit = "{0} 不能超过 {1}";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class EnglishResource
|
||||
{
|
||||
public const string CrcError = "CRC check failed";
|
||||
public const string FunctionError = "Function code error";
|
||||
public const string FunctionNotSame = "Function code mismatch. Requested: {0}, Returned: {1}";
|
||||
public const string ModbusError1 = "Unsupported function code";
|
||||
public const string ModbusError10 = "Gateway path unavailable";
|
||||
public const string ModbusError11 = "Gateway target device failed to respond";
|
||||
public const string ModbusError2 = "Read register out of range";
|
||||
public const string ModbusError3 = "Read length exceeded";
|
||||
public const string ModbusError4 = "Device failure";
|
||||
public const string ModbusError5 = "Device acknowledged but did not execute";
|
||||
public const string ModbusError6 = "Device is busy";
|
||||
public const string ModbusError8 = "Memory parity error";
|
||||
public const string StationNotSame = "Station number mismatch. Requested: {0}, Returned: {1}";
|
||||
public const string AddressDes = """
|
||||
Coil registers start at address 00001.
|
||||
Discrete input registers start at address 10001.
|
||||
Input registers start at address 30001.
|
||||
Holding registers start at address 40001.
|
||||
Example: 40001 => first holding register
|
||||
|
||||
Extra format:
|
||||
Device station number, e.g., 40001;s=2; means device address 2, first holding register.
|
||||
Write function code, e.g., 40001;w=16; means writing to the first holding register using function code 0x10.
|
||||
""";
|
||||
public const string ValueOverlimit = "{0} cannot exceed {1}";
|
||||
}
|
||||
|
@@ -1,40 +1,20 @@
|
||||
{
|
||||
"ThingsGateway.Foundation.Modbus.ModbusAddress": {
|
||||
"BitIndex": "BitIndex",
|
||||
"FunctionCode": "FunctionCode",
|
||||
"StartAddress": "StartAddress",
|
||||
"BitIndex": "BitIndex",
|
||||
"Station": "Station",
|
||||
"WriteFunctionCode": "WriteFunctionCode"
|
||||
|
||||
},
|
||||
|
||||
"ThingsGateway.Foundation.Modbus.ModbusMaster": {
|
||||
"ModbusType": "ModbusType",
|
||||
"Station": "Station"
|
||||
},
|
||||
"ThingsGateway.Foundation.Modbus.ModbusSlave": {
|
||||
"ModbusType": "ModbusType",
|
||||
"Station": "Station",
|
||||
"CheckClearTime": "CheckClearTime",
|
||||
"IsWriteMemory": "IsWriteMemory",
|
||||
"ModbusType": "ModbusType",
|
||||
"MulStation": "MulStation",
|
||||
"IsWriteMemory": "IsWriteMemory"
|
||||
},
|
||||
|
||||
"ThingsGateway.Foundation.Modbus.ModbusResource": {
|
||||
"AddressDes": "Coil registers are numbered starting from 00001.\nDiscrete input registers are numbered starting from 10001.\nInput registers are numbered starting from 30001.\nHolding registers are numbered starting from 40001.\nExample: 40001=>Holding register first register\nAdditional format\nDevice station number, such as 40001;s=2;, indicates that the device address is the first register of the holding register with a device address of 2.\nWrite function code, such as 40001;w=16;, means that the first register of the holding register, when writing a value, uses the 0x10 function code",
|
||||
"FunctionError": "Function code error",
|
||||
"FunctionNotSame": "Function codes are inconsistent, request function code {0}, return function code {1}",
|
||||
"ModbusError1": "Unsupported function code",
|
||||
"ModbusError10": "Gateway path unavailable",
|
||||
"ModbusError11": "Gateway target device response failed",
|
||||
"ModbusError2": "Read register out of range",
|
||||
"ModbusError3": "Read length exceeds limit",
|
||||
"ModbusError4": "Device malfunction",
|
||||
"ModbusError5": "Device acknowledged but not executed",
|
||||
"ModbusError6": "Device busy",
|
||||
"ModbusError8": "Storage parity error",
|
||||
"StationNotSame": "Station numbers are inconsistent, request station number {0}, return station number {1}",
|
||||
"ValueOverlimit": "{0} cannot exceed {1}",
|
||||
"CrcError": "CRC check failed"
|
||||
"Station": "Station"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,42 +1,20 @@
|
||||
{
|
||||
"ThingsGateway.Foundation.Modbus.ModbusAddress": {
|
||||
"BitIndex": "Bit",
|
||||
"FunctionCode": "功能码",
|
||||
"StartAddress": "起始地址",
|
||||
"BitIndex": "Bit",
|
||||
"Station": "特指站号",
|
||||
"WriteFunctionCode": "特指写入功能码"
|
||||
|
||||
},
|
||||
|
||||
|
||||
"ThingsGateway.Foundation.Modbus.ModbusMaster": {
|
||||
"ModbusType": "Modbus类型",
|
||||
"Station": "站号"
|
||||
|
||||
},
|
||||
"ThingsGateway.Foundation.Modbus.ModbusSlave": {
|
||||
"ModbusType": "Modbus类型",
|
||||
"Station": "默认站号",
|
||||
"CheckClearTime": "连接滑动过期时间",
|
||||
"IsWriteMemory": "立即写入内存",
|
||||
"ModbusType": "Modbus类型",
|
||||
"MulStation": "多站点",
|
||||
"IsWriteMemory": "立即写入内存"
|
||||
|
||||
},
|
||||
"ThingsGateway.Foundation.Modbus.ModbusResource": {
|
||||
"AddressDes": "线圈寄存器使用从 00001 开始的地址编号。\n离散输入寄存器使用从 10001 开始的地址编号。\n输入寄存器使用从 30001 开始的地址编号。\n保持寄存器使用从 40001 开始的地址编号。\n举例:40001=>保持寄存器第一个寄存器\n额外格式\n设备站号 ,比如40001;s=2; ,代表设备地址为2的保持寄存器第一个寄存器\n写入功能码 ,比如40001;w=16; ,代表保持寄存器第一个寄存器,写入值时采用0x10功能码\nDTU模式(只在TCPService中起作用) ,比如40001;id=T123T; ,代表保持寄存器第一个寄存器,DTU注册包为T123T(UTF-8字符串)",
|
||||
"FunctionError": "功能码错误",
|
||||
"FunctionNotSame": "功能码不一致,请求功能码 {0},返回功能码 {1}",
|
||||
"ModbusError1": "不支持的功能码",
|
||||
"ModbusError10": "网关路径不可用",
|
||||
"ModbusError11": "网关目标设备响应失败",
|
||||
"ModbusError2": "读取寄存器越界",
|
||||
"ModbusError3": "读取长度超限",
|
||||
"ModbusError4": "设备故障",
|
||||
"ModbusError5": "设备已确认,但未执行",
|
||||
"ModbusError6": "设备忙",
|
||||
"ModbusError8": "存储奇偶性错误",
|
||||
"StationNotSame": "站号不一致,请求站号 {0} ,返回站号 {1}",
|
||||
"ValueOverlimit": "{0} 不能超过 {1}",
|
||||
"CrcError": "Crc校验失败"
|
||||
"Station": "默认站号"
|
||||
}
|
||||
}
|
||||
}
|
@@ -70,7 +70,7 @@ public class ModbusRtuMessage : MessageBase, IResultMessage
|
||||
else
|
||||
{
|
||||
OperCode = 999;
|
||||
ErrorMessage = ModbusResource.Localizer["ModbusError1"];
|
||||
ErrorMessage = AppResource.ModbusError1;
|
||||
return FilterResult.GoOn;
|
||||
}
|
||||
if (crcLen > 0)
|
||||
@@ -89,14 +89,14 @@ public class ModbusRtuMessage : MessageBase, IResultMessage
|
||||
{
|
||||
OperCode = 999;
|
||||
Response.ErrorCode = 1;
|
||||
ErrorMessage = ModbusResource.Localizer["StationNotSame", Request.Station, Response.Station];
|
||||
ErrorMessage = string.Format(AppResource.StationNotSame, Request.Station, Response.Station);
|
||||
return FilterResult.GoOn;
|
||||
}
|
||||
if (f > 4 ? Request.WriteFunctionCode != Response.FunctionCode : Request.FunctionCode != Response.FunctionCode)
|
||||
{
|
||||
OperCode = 999;
|
||||
Response.ErrorCode = 1;
|
||||
ErrorMessage = ModbusResource.Localizer["FunctionNotSame", Request.FunctionCode, Response.FunctionCode];
|
||||
ErrorMessage = string.Format(AppResource.FunctionNotSame, Request.FunctionCode, Response.FunctionCode);
|
||||
return FilterResult.GoOn;
|
||||
}
|
||||
}
|
||||
|
@@ -76,7 +76,7 @@ public class ModbusRtuSend : ISendMessage
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new System.InvalidOperationException(ModbusResource.Localizer["ModbusError1"]);
|
||||
throw new System.InvalidOperationException(AppResource.ModbusError1);
|
||||
}
|
||||
byteBlock.Write(CRC16Utils.Crc16Only(byteBlock.Span));
|
||||
}
|
||||
|
@@ -76,7 +76,7 @@ public class ModbusTcpMessage : MessageBase, IResultMessage
|
||||
else
|
||||
{
|
||||
OperCode = 999;
|
||||
ErrorMessage = ModbusResource.Localizer["ModbusError1"];
|
||||
ErrorMessage = AppResource.ModbusError1;
|
||||
}
|
||||
return FilterResult.GoOn;
|
||||
}
|
||||
|
@@ -95,7 +95,7 @@ public class ModbusTcpSend : ISendMessage
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new System.InvalidOperationException(ModbusResource.Localizer["ModbusError1"]);
|
||||
throw new System.InvalidOperationException(AppResource.ModbusError1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -155,7 +155,7 @@ public partial class ModbusMaster : DtuServiceDeviceBase, IModbusAddress
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(ModbusResource.Localizer["ValueOverlimit", nameof(mAddress.BitIndex), 2]);
|
||||
return new OperResult(string.Format(AppResource.ValueOverlimit, nameof(mAddress.BitIndex), 2));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -202,7 +202,7 @@ public partial class ModbusMaster : DtuServiceDeviceBase, IModbusAddress
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(ModbusResource.Localizer["ValueOverlimit", nameof(mAddress.BitIndex), 16]);
|
||||
return new OperResult(string.Format(AppResource.ValueOverlimit, nameof(mAddress.BitIndex), 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -224,7 +224,7 @@ public class ModbusSlave : DeviceBase, IModbusAddress
|
||||
{
|
||||
if (Station != mAddress.Station)
|
||||
{
|
||||
return new(ModbusResource.Localizer["StationNotSame", mAddress.Station, Station]);
|
||||
return new(string.Format(AppResource.StationNotSame, mAddress.Station, Station));
|
||||
}
|
||||
Init(mAddress);
|
||||
}
|
||||
@@ -287,7 +287,7 @@ public class ModbusSlave : DeviceBase, IModbusAddress
|
||||
}
|
||||
}
|
||||
|
||||
return new(ModbusResource.Localizer["FunctionError"]);
|
||||
return new(AppResource.FunctionError);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -362,7 +362,7 @@ public class ModbusSlave : DeviceBase, IModbusAddress
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(ModbusResource.Localizer["ValueOverlimit", nameof(mAddress.BitIndex), 16]);
|
||||
return new OperResult(string.Format(AppResource.ValueOverlimit, nameof(mAddress.BitIndex), 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,27 +1,25 @@
|
||||
{
|
||||
"ThingsGateway.Foundation.OpcDa.OpcDaProperty": {
|
||||
"ActiveSubscribe": "ActiveSubscribe",
|
||||
"Add": "Add",
|
||||
"CheckRate": "CheckRate(min)",
|
||||
"Close": "Close",
|
||||
"Connect": "Connect",
|
||||
"DeadBand": "DeadBand",
|
||||
"Disconnect": "Disconnect",
|
||||
"Export": "Export",
|
||||
"GroupSize": "GroupSize",
|
||||
"NoVariablesAvailable": "No variables available",
|
||||
"OpcIP": "OpcIP",
|
||||
"OpcName": "OpcName",
|
||||
"UpdateRate": "UpdateRate",
|
||||
|
||||
"Connect": "Connect",
|
||||
"Disconnect": "Disconnect",
|
||||
"Add": "Add",
|
||||
"Remove": "Remove",
|
||||
"Read": "Read",
|
||||
"Write": "Write",
|
||||
"ShowImport": "View OPC space",
|
||||
"RegisterAddress": "RegisterAddress",
|
||||
"WriteValue": "WriteValue",
|
||||
|
||||
"NoVariablesAvailable": "No variables available",
|
||||
"Success": "Success",
|
||||
"Close": "Close",
|
||||
"Remove": "Remove",
|
||||
"Save": "Import to system",
|
||||
"Export": "Export"
|
||||
"ShowImport": "View OPC space",
|
||||
"Success": "Success",
|
||||
"UpdateRate": "UpdateRate",
|
||||
"Write": "Write",
|
||||
"WriteValue": "WriteValue"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,27 +1,25 @@
|
||||
{
|
||||
"ThingsGateway.Foundation.OpcDa.OpcDaProperty": {
|
||||
"ActiveSubscribe": "订阅",
|
||||
"Add": "添加",
|
||||
"CheckRate": "心跳间隔(min)",
|
||||
"Close": "关闭",
|
||||
"Connect": "连接",
|
||||
"DeadBand": "死区",
|
||||
"Disconnect": "断开",
|
||||
"Export": "导出",
|
||||
"GroupSize": "最大组大小",
|
||||
"NoVariablesAvailable": "无可用变量",
|
||||
"OpcIP": "OpcIP",
|
||||
"OpcName": "OpcName",
|
||||
"UpdateRate": "订阅推送间隔",
|
||||
|
||||
"Connect": "连接",
|
||||
"Disconnect": "断开",
|
||||
"Add": "添加",
|
||||
"Remove": "移除",
|
||||
"Read": "读取",
|
||||
"Write": "写入",
|
||||
"ShowImport": "查看OPC空间",
|
||||
"RegisterAddress": "地址",
|
||||
"WriteValue": "写入值",
|
||||
|
||||
"NoVariablesAvailable": "无可用变量",
|
||||
"Success": "成功",
|
||||
"Close": "关闭",
|
||||
"Remove": "移除",
|
||||
"Save": "导入到系统",
|
||||
"Export": "导出"
|
||||
"ShowImport": "查看OPC空间",
|
||||
"Success": "成功",
|
||||
"UpdateRate": "订阅推送间隔",
|
||||
"Write": "写入",
|
||||
"WriteValue": "写入值"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,37 +1,33 @@
|
||||
{
|
||||
"ThingsGateway.Foundation.OpcUa.OpcUaProperty": {
|
||||
"OpcUrl": "OpcUrl",
|
||||
"UserName": "UserName",
|
||||
"Password": "Password",
|
||||
"CheckDomain": "CheckDomain",
|
||||
"UpdateRate": "UpdateRate",
|
||||
"ActiveSubscribe": "ActiveSubscribe",
|
||||
"GroupSize": "GroupSize",
|
||||
"DeadBand": "DeadBand",
|
||||
"KeepAliveInterval": "KeepAliveInterval(ms)",
|
||||
"UseSecurity": "IsUseSecurity",
|
||||
"LoadType": "LoadType",
|
||||
"AutoAcceptUntrustedCertificates": "AutoAcceptUntrustedCertificates",
|
||||
"ExportC": "ExportCertificate",
|
||||
|
||||
"Connect": "Connect",
|
||||
"Disconnect": "Disconnect",
|
||||
"Add": "Add",
|
||||
"Remove": "Remove",
|
||||
"Read": "Read",
|
||||
"Write": "Write",
|
||||
"ShowImport": "View OPC space",
|
||||
"RegisterAddress": "RegisterAddress",
|
||||
"WriteValue": "WriteValue",
|
||||
|
||||
"NoVariablesAvailable": "No variables available",
|
||||
"Success": "Success",
|
||||
"AutoAcceptUntrustedCertificates": "AutoAcceptUntrustedCertificates",
|
||||
"CheckDomain": "CheckDomain",
|
||||
"Close": "Close",
|
||||
"Save": "Import to system",
|
||||
"Connect": "Connect",
|
||||
"DeadBand": "DeadBand",
|
||||
"Disconnect": "Disconnect",
|
||||
"Export": "Export",
|
||||
"ShowSubvariable": "ShowSubvariable"
|
||||
"ExportC": "ExportCertificate",
|
||||
"GroupSize": "GroupSize",
|
||||
"KeepAliveInterval": "KeepAliveInterval(ms)",
|
||||
"LoadType": "LoadType",
|
||||
"NoVariablesAvailable": "No variables available",
|
||||
"OpcUrl": "OpcUrl",
|
||||
"Password": "Password",
|
||||
"Read": "Read",
|
||||
"RegisterAddress": "RegisterAddress",
|
||||
"Remove": "Remove",
|
||||
"Save": "Import to system",
|
||||
"ShowImport": "View OPC space",
|
||||
"ShowSubvariable": "ShowSubvariable",
|
||||
"Success": "Success",
|
||||
"UpdateRate": "UpdateRate",
|
||||
"UserName": "UserName",
|
||||
"UseSecurity": "IsUseSecurity",
|
||||
"Write": "Write",
|
||||
"WriteValue": "WriteValue"
|
||||
},
|
||||
|
||||
"ThingsGateway.Foundation.OpcUa.OpcUaResource": {
|
||||
}
|
||||
"ThingsGateway.Foundation.OpcUa.OpcUaResource": {}
|
||||
}
|
@@ -1,36 +1,33 @@
|
||||
{
|
||||
"ThingsGateway.Foundation.OpcUa.OpcUaProperty": {
|
||||
"OpcUrl": "OpcUrl",
|
||||
"UserName": "登录账号",
|
||||
"Password": "登录密码",
|
||||
"CheckDomain": "检查域",
|
||||
"UpdateRate": "推送间隔",
|
||||
"ActiveSubscribe": "订阅",
|
||||
"GroupSize": "分组大小",
|
||||
"DeadBand": "死区",
|
||||
"KeepAliveInterval": "心跳间隔(ms)",
|
||||
"UseSecurity": "安全策略",
|
||||
"LoadType": "加载服务端数据类型",
|
||||
"AutoAcceptUntrustedCertificates": "自动接受不受信任的证书",
|
||||
"ExportC": "导出证书",
|
||||
"Connect": "连接",
|
||||
"Disconnect": "断开",
|
||||
"Add": "添加",
|
||||
"Remove": "移除",
|
||||
"Read": "读取",
|
||||
"Write": "写入",
|
||||
"ShowImport": "查看OPC空间",
|
||||
"RegisterAddress": "地址",
|
||||
"WriteValue": "写入值",
|
||||
|
||||
"NoVariablesAvailable": "无可用变量",
|
||||
"Success": "成功",
|
||||
"AutoAcceptUntrustedCertificates": "自动接受不受信任的证书",
|
||||
"CheckDomain": "检查域",
|
||||
"Close": "关闭",
|
||||
"Save": "导入到系统",
|
||||
"Connect": "连接",
|
||||
"DeadBand": "死区",
|
||||
"Disconnect": "断开",
|
||||
"Export": "导出",
|
||||
"ShowSubvariable": "显示变量子节点"
|
||||
"ExportC": "导出证书",
|
||||
"GroupSize": "分组大小",
|
||||
"KeepAliveInterval": "心跳间隔(ms)",
|
||||
"LoadType": "加载服务端数据类型",
|
||||
"NoVariablesAvailable": "无可用变量",
|
||||
"OpcUrl": "OpcUrl",
|
||||
"Password": "登录密码",
|
||||
"Read": "读取",
|
||||
"RegisterAddress": "地址",
|
||||
"Remove": "移除",
|
||||
"Save": "导入到系统",
|
||||
"ShowImport": "查看OPC空间",
|
||||
"ShowSubvariable": "显示变量子节点",
|
||||
"Success": "成功",
|
||||
"UpdateRate": "推送间隔",
|
||||
"UserName": "登录账号",
|
||||
"UseSecurity": "安全策略",
|
||||
"Write": "写入",
|
||||
"WriteValue": "写入值"
|
||||
},
|
||||
|
||||
"ThingsGateway.Foundation.OpcUa.OpcUaResource": {
|
||||
}
|
||||
"ThingsGateway.Foundation.OpcUa.OpcUaResource": {}
|
||||
}
|
@@ -8,23 +8,85 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace ThingsGateway.Foundation.SiemensS7;
|
||||
|
||||
public class SiemensS7Resource
|
||||
public static class AppResource
|
||||
{
|
||||
private static IStringLocalizer localizer;
|
||||
public static string S7_AddressDes => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.AddressDes : EnglishResource.AddressDes;
|
||||
public static string DataLengthError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.DataLengthError : EnglishResource.DataLengthError;
|
||||
public static string ERROR1 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ERROR1 : EnglishResource.ERROR1;
|
||||
public static string ERROR10 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ERROR10 : EnglishResource.ERROR10;
|
||||
public static string ERROR3 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ERROR3 : EnglishResource.ERROR3;
|
||||
public static string ERROR5 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ERROR5 : EnglishResource.ERROR5;
|
||||
public static string ERROR6 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ERROR6 : EnglishResource.ERROR6;
|
||||
public static string ERROR7 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ERROR7 : EnglishResource.ERROR7;
|
||||
public static string HandshakeError1 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.HandshakeError1 : EnglishResource.HandshakeError1;
|
||||
public static string HandshakeError2 => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.HandshakeError2 : EnglishResource.HandshakeError2;
|
||||
public static string NotString => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.NotString : EnglishResource.NotString;
|
||||
public static string WriteDataLengthMore => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.WriteDataLengthMore : EnglishResource.WriteDataLengthMore;
|
||||
public static string StringLengthReadError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.StringLengthReadError : EnglishResource.StringLengthReadError;
|
||||
public static string ReturnError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ReturnError : EnglishResource.ReturnError;
|
||||
public static string ValidateDataError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.ValidateDataError : EnglishResource.ValidateDataError;
|
||||
public static string AddressError => ThingsGateway.Foundation.AppResource.Lang == Language.Chinese ? ChineseResource.AddressError : EnglishResource.AddressError;
|
||||
|
||||
public static IStringLocalizer Localizer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (localizer == null)
|
||||
{
|
||||
localizer = LocalizerUtil.GetLocalizer.Invoke(typeof(SiemensS7Resource));
|
||||
}
|
||||
return localizer;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static class ChineseResource
|
||||
{
|
||||
public const string AddressDes = """
|
||||
S7协议寄存器地址格式
|
||||
Txxxxx Timer寄存器,例如T100/T100.1
|
||||
Cxxxxx,Counter寄存器,例如C100/C100.1
|
||||
AIxxxxx,AI寄存器,例如AI100/AI100.1
|
||||
AQxxxxx,AQ寄存器,例如AQ100/AQ100.1
|
||||
Ixxxxx,I寄存器,例如I100/I100.1
|
||||
Qxxxxx,Q寄存器,例如Q100/Q100.1
|
||||
Mxxxxx,M寄存器,例如M100/M100.1
|
||||
DBxxxxx,DB寄存器,例如DB100.1/DB100.1.1
|
||||
""";
|
||||
|
||||
public const string DataLengthError = "数据块长度校验失败";
|
||||
public const string ERROR1 = "硬件错误";
|
||||
public const string ERROR10 = "对象不存在";
|
||||
public const string ERROR3 = "对象不允许访问";
|
||||
public const string ERROR5 = "无效地址,所需的地址超出此PLC的极限";
|
||||
public const string ERROR6 = "数据类型不支持";
|
||||
public const string ERROR7 = "日期类型不一致";
|
||||
public const string HandshakeError1 = "{0}:ISO_TP握手失败-{1},请检查机架号/槽号是否正确";
|
||||
public const string HandshakeError2 = "{0}:PDU初始化失败-{1},请检查机架号/槽号是否正确";
|
||||
public const string NotString = "PLC中的数据类型不是String";
|
||||
public const string WriteDataLengthMore = "写入长度超限";
|
||||
public const string StringLengthReadError = "不支持变长字符串的连读";
|
||||
public const string ReturnError = "PLC返回错误码,错误类型 {0} 错误代码 {1}";
|
||||
public const string ValidateDataError = "验证错误,代码 {0},类型 {1}";
|
||||
public const string AddressError = "寄存器地址格式错误 {0}";
|
||||
}
|
||||
public static class EnglishResource
|
||||
{
|
||||
public const string AddressDes = """
|
||||
S7 protocol register address format:
|
||||
Txxxxx - Timer register, e.g., T100/T100.1
|
||||
Cxxxxx - Counter register, e.g., C100/C100.1
|
||||
AIxxxxx - AI register, e.g., AI100/AI100.1
|
||||
AQxxxxx - AQ register, e.g., AQ100/AQ100.1
|
||||
Ixxxxx - I register, e.g., I100/I100.1
|
||||
Qxxxxx - Q register, e.g., Q100/Q100.1
|
||||
Mxxxxx - M register, e.g., M100/M100.1
|
||||
DBxxxxx - DB register, e.g., DB100.1/DB100.1.1
|
||||
""";
|
||||
|
||||
public const string DataLengthError = "Data block length validation failed";
|
||||
public const string ERROR1 = "Hardware error";
|
||||
public const string ERROR10 = "Object does not exist";
|
||||
public const string ERROR3 = "Access to the object is not permitted";
|
||||
public const string ERROR5 = "Invalid address; requested address exceeds PLC limits";
|
||||
public const string ERROR6 = "Unsupported data type";
|
||||
public const string ERROR7 = "Data type mismatch";
|
||||
public const string HandshakeError1 = "{0}: ISO_TP handshake failed - {1}, please check rack/slot settings";
|
||||
public const string HandshakeError2 = "{0}: PDU initialization failed - {1}, please check rack/slot settings";
|
||||
public const string NotString = "The data type in PLC is not String";
|
||||
public const string WriteDataLengthMore = "Write length exceeds limit";
|
||||
public const string StringLengthReadError = "Reading variable-length strings continuously is not supported";
|
||||
public const string ReturnError = "PLC returned error code. Type: {0}, Code: {1}";
|
||||
public const string ValidateDataError = "Validation failed. Code: {0}, Type: {1}";
|
||||
public const string AddressError = "Register address format error: {0}";
|
||||
}
|
||||
|
@@ -5,36 +5,10 @@
|
||||
"DataCode": "DataCode",
|
||||
"DbBlock": "DbBlock"
|
||||
},
|
||||
|
||||
"ThingsGateway.Foundation.SiemensS7.SiemensS7Master": {
|
||||
"SiemensS7Type": "SiemensS7Type",
|
||||
"LocalTSAP": "LocalTSAP",
|
||||
"Rack": "Rack",
|
||||
"SiemensS7Type": "SiemensS7Type",
|
||||
"Slot": "Slot"
|
||||
},
|
||||
|
||||
"ThingsGateway.Foundation.SiemensS7.SiemensS7Resource": {
|
||||
"AddressDes": "S7 Protocol Register Address Format\nTxxxxx Timer Register, for example T100/T100.1\nCxxxxx Counter Register, for example C100/C100.1\nAIxxxxx AI Register, for example AI100/AI100.1\nAQxxxxx AQ Register, for example AQ100/AQ100.1\nIxxxxx I Register, for example I100/I100.1\nQxxxxx Q Register, for example Q100/Q100.1\nMxxxxx M Register, for example M100/M100.1\nDBxxxxx DB Register, for example DB100.1/DB100.1.1",
|
||||
"ReturnError": "PLC returns error code, error type {0}, error code {1}",
|
||||
"ReturnCode": "PLC return code {0}",
|
||||
"DataLengthError": "Data block length check failed",
|
||||
"ValidateDataError": "Validation error, code {0}, type {1}",
|
||||
"NotString": "Data type in PLC is not String",
|
||||
"WriteDataLengthMore": "Write length exceeds limit",
|
||||
|
||||
"ERROR5": "Invalid address",
|
||||
"ERROR1": "Hardware error",
|
||||
"ERROR3": "Accessing the object not allowed",
|
||||
"ERROR6": "Data type not supported",
|
||||
"ERROR7": "Data type inconsistent",
|
||||
"ERROR10": "Object does not exist",
|
||||
|
||||
"MulWriteError": "Multiple write not supported",
|
||||
"StringLengthReadError": "Consecutive reading of variable-length strings not supported",
|
||||
|
||||
"HandshakeError1": "{0}: ISO_TP handshake failed - {1}, please check if the rack number/slot number is correct",
|
||||
"HandshakeError2": "{0}: PDU initialization failed - {1}, please check if the rack number/slot number is correct",
|
||||
|
||||
"AddressError": "Register address format error {0}"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,4 @@
|
||||
{
|
||||
|
||||
"ThingsGateway.Foundation.SiemensS7.SiemensS7Address": {
|
||||
"AddressStart": "起始地址",
|
||||
"BitCode": "Bit地址",
|
||||
@@ -7,35 +6,9 @@
|
||||
"DbBlock": "DB块"
|
||||
},
|
||||
"ThingsGateway.Foundation.SiemensS7.SiemensS7Master": {
|
||||
"SiemensS7Type": "S7类型",
|
||||
"LocalTSAP": "本地TSAP",
|
||||
"Rack": "机架号",
|
||||
"SiemensS7Type": "S7类型",
|
||||
"Slot": "槽号"
|
||||
|
||||
},
|
||||
|
||||
"ThingsGateway.Foundation.SiemensS7.SiemensS7Resource": {
|
||||
"AddressDes": "S7协议寄存器地址格式\nTxxxxx Timer寄存器,例如T100/T100.1\nCxxxxx,Counter寄存器,例如C100/C100.1\nAIxxxxx,AI寄存器,例如AI100/AI100.1\nAQxxxxx,AQ寄存器,例如AQ100/AQ100.1\nIxxxxx,I寄存器,例如I100/I100.1\nQxxxxx,Q寄存器,例如Q100/Q100.1\nMxxxxx,M寄存器,例如M100/M100.1\nDBxxxxx,DB寄存器,例如DB100.1/DB100.1.1",
|
||||
"ReturnError": "PLC返回错误码,错误类型 {0} 错误代码 {1} ",
|
||||
"ReturnCode": "PLC返回代码 {0} ",
|
||||
"DataLengthError": "数据块长度校验失败",
|
||||
"ValidateDataError": "验证错误,代码 {0},类型 {1}",
|
||||
"NotString": "PLC中的数据类型不是String",
|
||||
"WriteDataLengthMore": "写入长度超限",
|
||||
|
||||
"ERROR5": "无效地址,所需的地址超出此PLC的极限",
|
||||
"ERROR1": "硬件错误",
|
||||
"ERROR3": "对象不允许访问",
|
||||
"ERROR6": "数据类型不支持",
|
||||
"ERROR7": "日期类型不一致",
|
||||
"ERROR10": "对象不存在",
|
||||
|
||||
"MulWriteError": "不支持多写",
|
||||
"StringLengthReadError": "不支持变长字符串的连读",
|
||||
|
||||
"HandshakeError1": "{0}:ISO_TP握手失败-{1},请检查机架号/槽号是否正确",
|
||||
"HandshakeError2": "{0}:PDU初始化失败-{1},请检查机架号/槽号是否正确",
|
||||
|
||||
"AddressError": "寄存器地址格式错误 {0}"
|
||||
}
|
||||
}
|
||||
}
|
@@ -45,7 +45,7 @@ public class S7Message : MessageBase, IResultMessage
|
||||
if (byteBlock[pos + 13] + byteBlock[pos + 14] > 0) // 如果错误代码不为0
|
||||
{
|
||||
OperCode = 999;
|
||||
ErrorMessage = SiemensS7Resource.Localizer["ReturnError", byteBlock[pos + 13].ToString("X2"), byteBlock[pos + 14].ToString("X2")];
|
||||
ErrorMessage = string.Format(AppResource.ReturnError, byteBlock[pos + 13].ToString("X2"), byteBlock[pos + 14].ToString("X2"));
|
||||
return FilterResult.Success;
|
||||
}
|
||||
else
|
||||
@@ -67,7 +67,7 @@ public class S7Message : MessageBase, IResultMessage
|
||||
if (byteBlock[pos + 13] + byteBlock[pos + 14] > 0) // 如果错误代码不为0
|
||||
{
|
||||
OperCode = 999;
|
||||
ErrorMessage = SiemensS7Resource.Localizer["ReturnError", byteBlock[pos + 13].ToString("X2"), byteBlock[pos + 14].ToString("X2")];
|
||||
ErrorMessage = string.Format(AppResource.ReturnError, byteBlock[pos + 13].ToString("X2"), byteBlock[pos + 14].ToString("X2"));
|
||||
return FilterResult.Success;
|
||||
}
|
||||
else
|
||||
@@ -75,13 +75,13 @@ public class S7Message : MessageBase, IResultMessage
|
||||
if (byteBlock.Length < pos + 18)
|
||||
{
|
||||
OperCode = 999;
|
||||
ErrorMessage = SiemensS7Resource.Localizer["DataLengthError"];
|
||||
ErrorMessage = AppResource.DataLengthError;
|
||||
return FilterResult.Success;
|
||||
}
|
||||
if (byteBlock[pos + 17] != byte.MaxValue)
|
||||
{
|
||||
OperCode = 999;
|
||||
ErrorMessage = SiemensS7Resource.Localizer["ValidateDataError", byteBlock[pos + 17], SiemensHelper.GetCpuError(byteBlock[pos + 17])];
|
||||
ErrorMessage = string.Format(AppResource.ValidateDataError, byteBlock[pos + 17], SiemensHelper.GetCpuError(byteBlock[pos + 17]));
|
||||
return FilterResult.Success;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public class S7Message : MessageBase, IResultMessage
|
||||
if (byteBlock[dataIndex] != byte.MaxValue)
|
||||
{
|
||||
OperCode = 999;
|
||||
ErrorMessage = SiemensS7Resource.Localizer["ValidateDataError", byteBlock[dataIndex], SiemensHelper.GetCpuError(byteBlock[dataIndex])];
|
||||
ErrorMessage = string.Format(AppResource.ValidateDataError, byteBlock[dataIndex], SiemensHelper.GetCpuError(byteBlock[dataIndex]));
|
||||
return FilterResult.Success;
|
||||
}
|
||||
|
||||
@@ -136,13 +136,13 @@ public class S7Message : MessageBase, IResultMessage
|
||||
if (byteBlock[pos + 13] + byteBlock[pos + 14] > 0) // 如果错误代码不为0
|
||||
{
|
||||
OperCode = 999;
|
||||
ErrorMessage = SiemensS7Resource.Localizer["ReturnError", byteBlock[pos + 13].ToString("X2"), byteBlock[pos + 14].ToString("X2")];
|
||||
ErrorMessage = string.Format(AppResource.ReturnError, byteBlock[pos + 13].ToString("X2"), byteBlock[pos + 14].ToString("X2"));
|
||||
return FilterResult.Success;
|
||||
}
|
||||
if (byteBlock.Length < pos + 18)
|
||||
{
|
||||
OperCode = 999;
|
||||
ErrorMessage = SiemensS7Resource.Localizer["DataLengthError"];
|
||||
ErrorMessage = AppResource.DataLengthError;
|
||||
return FilterResult.Success;
|
||||
}
|
||||
for (int i = 0; i < itemLen; i++)
|
||||
@@ -150,7 +150,7 @@ public class S7Message : MessageBase, IResultMessage
|
||||
if (byteBlock[pos + 17 + i] != byte.MaxValue)
|
||||
{
|
||||
OperCode = 999;
|
||||
ErrorMessage = SiemensS7Resource.Localizer["ValidateDataError", byteBlock[pos + 17 + i], SiemensHelper.GetCpuError(byteBlock[pos + 17 + i])];
|
||||
ErrorMessage = string.Format(AppResource.ValidateDataError, byteBlock[pos + 17 + i], SiemensHelper.GetCpuError(byteBlock[pos + 17 + i]));
|
||||
return FilterResult.Success;
|
||||
}
|
||||
}
|
||||
|
@@ -271,7 +271,7 @@ public class SiemensS7Address : S7Request
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(SiemensS7Resource.Localizer["AddressError", address]);
|
||||
throw new Exception(string.Format(AppResource.AddressError, address));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -59,7 +59,7 @@ internal static class PackHelper
|
||||
case DataTypeEnum.String:
|
||||
if (it.ThingsGatewayBitConverter.StringLength == null)
|
||||
{
|
||||
throw new Exception(DefaultResource.Localizer["StringTypePackError"]);
|
||||
throw new Exception(ThingsGateway.Foundation.AppResource.StringTypePackError);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -55,15 +55,14 @@ internal sealed partial class SiemensHelper
|
||||
{
|
||||
return Error switch
|
||||
{
|
||||
0x01 => SiemensS7Resource.Localizer["ERROR1"],
|
||||
0x03 => SiemensS7Resource.Localizer["ERROR3"],
|
||||
0x05 => SiemensS7Resource.Localizer["ERROR5"],
|
||||
0x06 => SiemensS7Resource.Localizer["ERROR6"],
|
||||
0x07 => SiemensS7Resource.Localizer["ERROR7"],
|
||||
0x0a => SiemensS7Resource.Localizer["ERROR10"],
|
||||
0x01 => AppResource.ERROR1,
|
||||
0x03 => AppResource.ERROR3,
|
||||
0x05 => AppResource.ERROR5,
|
||||
0x06 => AppResource.ERROR6,
|
||||
0x07 => AppResource.ERROR7,
|
||||
0x0a => AppResource.ERROR10,
|
||||
_ => "Unknown",
|
||||
};
|
||||
;
|
||||
}
|
||||
|
||||
internal static async ValueTask<OperResult<string>> ReadStringAsync(SiemensS7Master plc, string address, Encoding encoding, CancellationToken cancellationToken)
|
||||
@@ -78,7 +77,7 @@ internal sealed partial class SiemensHelper
|
||||
}
|
||||
if (result1.Content[0] == 0 || result1.Content[0] == byte.MaxValue)
|
||||
{
|
||||
return new OperResult<string>(SiemensS7Resource.Localizer["NotString"]);
|
||||
return new OperResult<string>(AppResource.NotString);
|
||||
}
|
||||
var result2 = await plc.ReadAsync(address, 2 + result1.Content[1], cancellationToken).ConfigureAwait(false);
|
||||
if (!result2.IsSuccess)
|
||||
@@ -115,9 +114,9 @@ internal sealed partial class SiemensHelper
|
||||
{
|
||||
var result = await plc.ReadAsync(address, 2, cancellationToken).ConfigureAwait(false);
|
||||
if (!result.IsSuccess) return result;
|
||||
if (result.Content[0] == byte.MaxValue) return new OperResult<string>(SiemensS7Resource.Localizer["NotString"]);
|
||||
if (result.Content[0] == byte.MaxValue) return new OperResult<string>(AppResource.NotString);
|
||||
if (result.Content[0] == 0) result.Content[0] = 254;
|
||||
if (value.Length > result.Content[0]) return new OperResult<string>(SiemensS7Resource.Localizer["WriteDataLengthMore"]);
|
||||
if (value.Length > result.Content[0]) return new OperResult<string>(AppResource.WriteDataLengthMore);
|
||||
return await plc.WriteAsync(
|
||||
address,
|
||||
DataTransUtil.SpliceArray([result.Content[0], (byte)value.Length],
|
||||
|
@@ -66,9 +66,7 @@ public partial class SiemensS7Master : DeviceBase
|
||||
/// <inheritdoc/>
|
||||
public override string GetAddressDescription()
|
||||
{
|
||||
var str = SiemensS7Resource.Localizer["AddressDes"];
|
||||
|
||||
return $"{base.GetAddressDescription()}{Environment.NewLine}{str}";
|
||||
return $"{base.GetAddressDescription()}{Environment.NewLine}{AppResource.S7_AddressDes}";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -410,7 +408,7 @@ public partial class SiemensS7Master : DeviceBase
|
||||
if (result2.Exception is OperationCanceledException)
|
||||
return true;
|
||||
|
||||
Logger?.LogWarning(SiemensS7Resource.Localizer["HandshakeError1", channel.ToString(), result2]);
|
||||
Logger?.LogWarning(string.Format(AppResource.HandshakeError1, channel.ToString(), result2));
|
||||
await channel.CloseAsync().ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
@@ -418,7 +416,7 @@ public partial class SiemensS7Master : DeviceBase
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.LogWarning(SiemensS7Resource.Localizer["HandshakeError1", channel.ToString(), ex]);
|
||||
Logger?.LogWarning(string.Format(AppResource.HandshakeError1, channel.ToString(), ex));
|
||||
await channel.CloseAsync().ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
@@ -430,7 +428,7 @@ public partial class SiemensS7Master : DeviceBase
|
||||
if (result2.Exception is OperationCanceledException)
|
||||
return true;
|
||||
|
||||
Logger?.LogWarning(SiemensS7Resource.Localizer["HandshakeError2", channel.ToString(), result2]);
|
||||
Logger?.LogWarning(string.Format(AppResource.HandshakeError2, channel.ToString(), result2));
|
||||
await channel.CloseAsync().ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
@@ -446,7 +444,7 @@ public partial class SiemensS7Master : DeviceBase
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.LogWarning(SiemensS7Resource.Localizer["HandshakeError2", channel.ToString(), ex]);
|
||||
Logger?.LogWarning(string.Format(AppResource.HandshakeError2, channel.ToString(), ex));
|
||||
await channel.CloseAsync().ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
@@ -519,7 +517,7 @@ public partial class SiemensS7Master : DeviceBase
|
||||
{
|
||||
if (length > 1)
|
||||
{
|
||||
return new OperResult<string[]>(SiemensS7Resource.Localizer["StringLengthReadError"]);
|
||||
return new OperResult<string[]>(AppResource.StringLengthReadError);
|
||||
}
|
||||
var result = await SiemensHelper.ReadStringAsync(this, address, bitConverter.Encoding, cancellationToken).ConfigureAwait(false);
|
||||
if (result.IsSuccess)
|
||||
|
@@ -1,96 +1,81 @@
|
||||
{
|
||||
"ThingsGateway.Plugin.DB.RealDBProducerProperty": {
|
||||
"BigTextConnectStr": "ConnectString",
|
||||
"TableName": "TableName",
|
||||
"BigTextScriptHistoryTable": "DynamicScriptHistoryTable",
|
||||
"RealTableBusinessInterval": "RealTableBusinessInterval"
|
||||
|
||||
|
||||
"RealTableBusinessInterval": "RealTableBusinessInterval",
|
||||
"TableName": "TableName"
|
||||
},
|
||||
"ThingsGateway.Plugin.QuestDB.QuestDBHistoryValue": {
|
||||
"Id": "Id",
|
||||
|
||||
"CollectTime": "CollectTime",
|
||||
"CreateTime": "CreateTime",
|
||||
"DeviceName": "DeviceName",
|
||||
"Name": "Name",
|
||||
"Id": "Id",
|
||||
"IsOnline": "IsOnline",
|
||||
"Name": "Name",
|
||||
"Value": "Value"
|
||||
},
|
||||
|
||||
"ThingsGateway.Plugin.SqlDB.SqlDBProducerProperty": {
|
||||
"IsReadDB": "IsReadDB",
|
||||
"IsHistoryDB": "IsHistoryDB",
|
||||
"ReadDBTableName": "ReadDBTableName",
|
||||
"HistoryDBTableName": "HistoryDBTableName",
|
||||
"DbType": "DbType",
|
||||
"BigTextConnectStr": "ConnectString",
|
||||
"BigTextScriptHistoryTable": "DynamicScriptHistoryTable",
|
||||
"BigTextScriptRealTable": "DynamicScriptRealTable",
|
||||
"DbType": "DbType",
|
||||
"HistoryDBTableName": "HistoryDBTableName",
|
||||
"IsHistoryDB": "IsHistoryDB",
|
||||
"IsReadDB": "IsReadDB",
|
||||
"ReadDBTableName": "ReadDBTableName",
|
||||
"RealTableBusinessInterval": "RealTableBusinessInterval",
|
||||
"SqlDBSplitType": "SplitType"
|
||||
|
||||
},
|
||||
"ThingsGateway.Plugin.SqlDB.SQLHistoryValue": {
|
||||
"Id": "Id",
|
||||
|
||||
"CollectTime": "CollectTime",
|
||||
"CreateTime": "CreateTime",
|
||||
"DeviceName": "DeviceName",
|
||||
"Name": "Name",
|
||||
"Id": "Id",
|
||||
"IsOnline": "IsOnline",
|
||||
"Name": "Name",
|
||||
"Value": "Value"
|
||||
},
|
||||
"ThingsGateway.Plugin.SqlDB.SQLRealValue": {
|
||||
"Id": "Id",
|
||||
|
||||
"CollectTime": "CollectTime",
|
||||
"CreateTime": "CreateTime",
|
||||
"DeviceName": "DeviceName",
|
||||
"Name": "Name",
|
||||
"IsOnline": "IsOnline",
|
||||
"Value": "Value"
|
||||
},
|
||||
|
||||
"ThingsGateway.Plugin.TDengineDB.TDengineDBHistoryValue": {
|
||||
"Id": "Id",
|
||||
|
||||
"CollectTime": "CollectTime",
|
||||
"CreateTime": "CreateTime",
|
||||
"DeviceName": "DeviceName",
|
||||
"Name": "Name",
|
||||
"IsOnline": "IsOnline",
|
||||
"Name": "Name",
|
||||
"Value": "Value"
|
||||
},
|
||||
|
||||
"ThingsGateway.Plugin.SqlHistoryAlarm.SQLHistoryAlarmProperty": {
|
||||
"DbType": "DbType",
|
||||
"BigTextConnectStr": "ConnectString",
|
||||
"TableName": "TableName"
|
||||
},
|
||||
|
||||
"ThingsGateway.Plugin.SqlHistoryAlarm.HistoryAlarm": {
|
||||
|
||||
"Name": "Name",
|
||||
"Description": "Description",
|
||||
"DeviceName": "DeviceName",
|
||||
"DataType": "DataType",
|
||||
"RegisterAddress": "RegisterAddress",
|
||||
|
||||
"AlarmCode": "AlarmCode",
|
||||
"RecoveryCode": "RecoveryCode",
|
||||
"AlarmLimit": "AlarmLimit",
|
||||
"AlarmText": "AlarmText",
|
||||
"AlarmTime": "AlarmTime",
|
||||
"AlarmType": "AlarmType",
|
||||
"DataType": "DataType",
|
||||
"Description": "Description",
|
||||
"DeviceName": "DeviceName",
|
||||
"EventTime": "EventTime",
|
||||
"EventType": "EventType",
|
||||
|
||||
"Name": "Name",
|
||||
"RecoveryCode": "RecoveryCode",
|
||||
"RegisterAddress": "RegisterAddress",
|
||||
"Remark1": "Remark1",
|
||||
"Remark2": "Remark2",
|
||||
"Remark3": "Remark3",
|
||||
"Remark4": "Remark4",
|
||||
"Remark5": "Remark5"
|
||||
},
|
||||
"ThingsGateway.Plugin.SqlHistoryAlarm.SQLHistoryAlarmProperty": {
|
||||
"BigTextConnectStr": "ConnectString",
|
||||
"DbType": "DbType",
|
||||
"TableName": "TableName"
|
||||
},
|
||||
"ThingsGateway.Plugin.TDengineDB.TDengineDBHistoryValue": {
|
||||
"CollectTime": "CollectTime",
|
||||
"CreateTime": "CreateTime",
|
||||
"DeviceName": "DeviceName",
|
||||
"Id": "Id",
|
||||
"IsOnline": "IsOnline",
|
||||
"Name": "Name",
|
||||
"Value": "Value"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,95 +1,81 @@
|
||||
{
|
||||
"ThingsGateway.Plugin.DB.RealDBProducerProperty": {
|
||||
"BigTextConnectStr": "连接字符串",
|
||||
"TableName": "表名称",
|
||||
"BigTextScriptHistoryTable": "历史表动态脚本",
|
||||
"RealTableBusinessInterval": "实时表定时上传间隔"
|
||||
|
||||
"RealTableBusinessInterval": "实时表定时上传间隔",
|
||||
"TableName": "表名称"
|
||||
},
|
||||
"ThingsGateway.Plugin.QuestDB.QuestDBHistoryValue": {
|
||||
"Id": "变量Id",
|
||||
|
||||
"CollectTime": "采集时间",
|
||||
"CreateTime": "上传时间",
|
||||
"DeviceName": "设备名称",
|
||||
"Name": "变量名称",
|
||||
"Id": "变量Id",
|
||||
"IsOnline": "是否在线",
|
||||
"Name": "变量名称",
|
||||
"Value": "变量值"
|
||||
},
|
||||
|
||||
"ThingsGateway.Plugin.SqlDB.SqlDBProducerProperty": {
|
||||
"IsReadDB": "启用实时表",
|
||||
"IsHistoryDB": "启用历史表",
|
||||
"ReadDBTableName": "实时表名称",
|
||||
"HistoryDBTableName": "历史表名称",
|
||||
"DbType": "数据库类型",
|
||||
"BigTextConnectStr": "链接字符串",
|
||||
"BigTextScriptHistoryTable": "历史表动态脚本",
|
||||
"BigTextScriptRealTable": "实时表动态脚本",
|
||||
"DbType": "数据库类型",
|
||||
"HistoryDBTableName": "历史表名称",
|
||||
"IsHistoryDB": "启用历史表",
|
||||
"IsReadDB": "启用实时表",
|
||||
"ReadDBTableName": "实时表名称",
|
||||
"RealTableBusinessInterval": "实时表定时上传间隔",
|
||||
"SqlDBSplitType": "分表模式"
|
||||
|
||||
},
|
||||
"ThingsGateway.Plugin.SqlDB.SQLHistoryValue": {
|
||||
"Id": "变量Id",
|
||||
|
||||
"CollectTime": "采集时间",
|
||||
"CreateTime": "上传时间",
|
||||
"DeviceName": "设备名称",
|
||||
"Name": "变量名称",
|
||||
"Id": "变量Id",
|
||||
"IsOnline": "是否在线",
|
||||
"Name": "变量名称",
|
||||
"Value": "变量值"
|
||||
},
|
||||
"ThingsGateway.Plugin.SqlDB.SQLRealValue": {
|
||||
"Id": "变量Id",
|
||||
|
||||
"CollectTime": "采集时间",
|
||||
"CreateTime": "上传时间",
|
||||
"DeviceName": "设备名称",
|
||||
"Name": "变量名称",
|
||||
"IsOnline": "是否在线",
|
||||
"Value": "变量值"
|
||||
},
|
||||
|
||||
"ThingsGateway.Plugin.TDengineDB.TDengineDBHistoryValue": {
|
||||
"Id": "变量Id",
|
||||
|
||||
"CollectTime": "采集时间",
|
||||
"CreateTime": "上传时间",
|
||||
"DeviceName": "设备名称",
|
||||
"Name": "变量名称",
|
||||
"IsOnline": "是否在线",
|
||||
"Name": "变量名称",
|
||||
"Value": "变量值"
|
||||
},
|
||||
|
||||
"ThingsGateway.Plugin.SqlHistoryAlarm.SQLHistoryAlarmProperty": {
|
||||
"DbType": "数据库类型",
|
||||
"BigTextConnectStr": "链接字符串",
|
||||
"TableName": "表名称"
|
||||
|
||||
},
|
||||
"ThingsGateway.Plugin.SqlHistoryAlarm.HistoryAlarm": {
|
||||
|
||||
"Name": "名称",
|
||||
"Description": "描述",
|
||||
"DeviceName": "采集设备",
|
||||
"DataType": "数据类型",
|
||||
"RegisterAddress": "变量地址",
|
||||
|
||||
|
||||
"AlarmCode": "报警值",
|
||||
"RecoveryCode": "恢复值",
|
||||
"AlarmLimit": "报警限值",
|
||||
"AlarmText": "报警文本",
|
||||
"AlarmTime": "报警时间",
|
||||
"AlarmType": "报警类型",
|
||||
"DataType": "数据类型",
|
||||
"Description": "描述",
|
||||
"DeviceName": "采集设备",
|
||||
"EventTime": "事件时间",
|
||||
"EventType": "事件类型",
|
||||
|
||||
"Name": "名称",
|
||||
"RecoveryCode": "恢复值",
|
||||
"RegisterAddress": "变量地址",
|
||||
"Remark1": "备用1",
|
||||
"Remark2": "备用2",
|
||||
"Remark3": "备用3",
|
||||
"Remark4": "备用4",
|
||||
"Remark5": "备用5"
|
||||
},
|
||||
"ThingsGateway.Plugin.SqlHistoryAlarm.SQLHistoryAlarmProperty": {
|
||||
"BigTextConnectStr": "链接字符串",
|
||||
"DbType": "数据库类型",
|
||||
"TableName": "表名称"
|
||||
},
|
||||
"ThingsGateway.Plugin.TDengineDB.TDengineDBHistoryValue": {
|
||||
"CollectTime": "采集时间",
|
||||
"CreateTime": "上传时间",
|
||||
"DeviceName": "设备名称",
|
||||
"Id": "变量Id",
|
||||
"IsOnline": "是否在线",
|
||||
"Name": "变量名称",
|
||||
"Value": "变量值"
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user