Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
57a4038577 | ||
![]() |
b78a76e60f | ||
![]() |
28bd751d44 | ||
![]() |
dcba7b9810 | ||
![]() |
7f1a741ce6 | ||
![]() |
ca2b17d433 | ||
![]() |
af589eac10 | ||
![]() |
573670f1f5 | ||
![]() |
f3ec85a03d | ||
![]() |
c94308454f | ||
![]() |
c9c2b2b69d | ||
![]() |
40574b776f | ||
![]() |
f426c1533d | ||
![]() |
4a3b5163f1 | ||
![]() |
3a0946d357 | ||
![]() |
9dd21c644c | ||
![]() |
6713190a23 | ||
![]() |
9f24533425 | ||
![]() |
ed1d9374eb |
@@ -64,7 +64,7 @@ public sealed class OperDescAttribute : MoAttribute
|
||||
|
||||
public override void OnException(MethodContext context)
|
||||
{
|
||||
if (App.HttpContext.Request.Path.StartsWithSegments("/_blazor"))
|
||||
if (App.HttpContext?.Request.Path.StartsWithSegments("/_blazor") == true)
|
||||
{
|
||||
//插入异常日志
|
||||
SysOperateLog log = GetOperLog(LocalizerType, context);
|
||||
@@ -82,7 +82,7 @@ public sealed class OperDescAttribute : MoAttribute
|
||||
|
||||
public override void OnSuccess(MethodContext context)
|
||||
{
|
||||
if (App.HttpContext.Request.Path.StartsWithSegments("/_blazor"))
|
||||
if (App.HttpContext?.Request.Path.StartsWithSegments("/_blazor") == true)
|
||||
{
|
||||
|
||||
//插入操作日志
|
||||
|
@@ -10,10 +10,10 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
[SugarTable("sys_dict", TableDescription = "字典表")]
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -10,10 +10,10 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
|
@@ -10,10 +10,10 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -14,10 +14,10 @@ using Microsoft.AspNetCore.Components.Routing;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
|
@@ -10,10 +10,10 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
|
@@ -12,11 +12,11 @@ using BootstrapBlazor.Components;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
|
@@ -10,9 +10,8 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.List;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -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": "快捷方式"
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,8 +8,6 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -18,6 +16,7 @@ using ThingsGateway.FriendlyException;
|
||||
using ThingsGateway.Logging;
|
||||
using ThingsGateway.NewLife.Json.Extension;
|
||||
using ThingsGateway.Razor;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -10,10 +10,10 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Data;
|
||||
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
internal sealed class SysOperateLogService : BaseService<SysOperateLog>, ISysOperateLogService
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -10,10 +10,9 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.Extension.Generic;
|
||||
using ThingsGateway.FriendlyException;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -10,9 +10,8 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.FriendlyException;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -12,11 +12,10 @@ using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Globalization;
|
||||
|
||||
using ThingsGateway.FriendlyException;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -10,10 +10,9 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.FriendlyException;
|
||||
using ThingsGateway.NewLife.Json.Extension;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -12,7 +12,7 @@ using BootstrapBlazor.Components;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -12,13 +12,12 @@ using BootstrapBlazor.Components;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.DataEncryption;
|
||||
using ThingsGateway.Extension;
|
||||
using ThingsGateway.Extension.Generic;
|
||||
using ThingsGateway.FriendlyException;
|
||||
using ThingsGateway.NewLife.Json.Extension;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
@@ -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)
|
||||
|
@@ -27,9 +27,9 @@
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net9.0' ">
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.5" />
|
||||
<PackageReference Include="System.Formats.Asn1" Version="9.0.5" />
|
||||
<PackageReference Include="System.Threading.RateLimiting" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(NET9Version)" />
|
||||
<PackageReference Include="System.Formats.Asn1" Version="$(NET9Version)" />
|
||||
<PackageReference Include="System.Threading.RateLimiting" Version="$(NET9Version)" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Remove="SeedData\Admin\*.json" />
|
||||
|
@@ -8,9 +8,8 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.Extension.Generic;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -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": "个人工作台"
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,10 +8,9 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.Admin.Application;
|
||||
using ThingsGateway.NewLife.Extension;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Razor;
|
||||
|
||||
|
@@ -8,9 +8,8 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.Admin.Application;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Razor;
|
||||
|
||||
|
@@ -8,10 +8,9 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.Admin.Application;
|
||||
using ThingsGateway.NewLife.Extension;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Razor;
|
||||
|
||||
|
@@ -8,10 +8,9 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.Admin.Application;
|
||||
using ThingsGateway.NewLife.Extension;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Razor;
|
||||
|
||||
|
@@ -1,7 +0,0 @@
|
||||
@namespace ThingsGateway.Admin.Razor
|
||||
@using ThingsGateway.Admin.Application
|
||||
|
||||
<AvatarUpload @bind-Value="@Picture" DisplayText=@AdminLocalizer["Picture"] IsSingle Accept="image/*" OnChange="OnAvatarUpload" DefaultFileList=PreviewFileList></AvatarUpload>
|
||||
|
||||
|
||||
|
@@ -1,73 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
|
||||
using ThingsGateway.Admin.Application;
|
||||
|
||||
namespace ThingsGateway.Admin.Razor;
|
||||
|
||||
public partial class SysUserAvatarEdit : IDisposable
|
||||
{
|
||||
private List<UploadFile> PreviewFileList;
|
||||
|
||||
[Parameter]
|
||||
[NotNull]
|
||||
public SysUser? Model { get; set; }
|
||||
|
||||
[FileValidation(Extensions = [".png", ".jpg", ".jpeg"], FileSize = 200 * 1024)]
|
||||
public IBrowserFile? Picture { get; set; }
|
||||
|
||||
[Inject]
|
||||
private IStringLocalizer<ThingsGateway.Admin.Razor._Imports> AdminLocalizer { get; set; }
|
||||
|
||||
private CancellationTokenSource? ReadAvatarToken { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private ToastService ToastService { get; set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ReadAvatarToken?.Cancel();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected override Task OnParametersSetAsync()
|
||||
{
|
||||
PreviewFileList = new(new[] { new UploadFile { PrevUrl = Model.Avatar } });
|
||||
return base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
private async Task OnAvatarUpload(UploadFile file)
|
||||
{
|
||||
if (file?.File != null)
|
||||
{
|
||||
var format = file.File.ContentType;
|
||||
ReadAvatarToken ??= new CancellationTokenSource();
|
||||
if (ReadAvatarToken.IsCancellationRequested)
|
||||
{
|
||||
ReadAvatarToken.Dispose();
|
||||
ReadAvatarToken = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
await file.RequestBase64ImageFileAsync(format, 640, 480, 1024 * 200, ReadAvatarToken.Token);
|
||||
|
||||
if (file.Code != 0)
|
||||
{
|
||||
await ToastService.Error($"{file.Error} ");
|
||||
}
|
||||
else
|
||||
{
|
||||
Model.Avatar = file.PrevUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
<div class="row g-2 mx-1 form-inline">
|
||||
|
||||
<div class="col-12 col-md-12">
|
||||
<SysUserAvatarEdit Model="Model"></SysUserAvatarEdit>
|
||||
<AvatarUpload @bind-Value="@Picture" DisplayText=@AdminLocalizer["Picture"] IsMultiple=false Accept="image/*" OnChange="OnAvatarUpload" DefaultFileList=PreviewFileList></AvatarUpload>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6">
|
||||
|
@@ -8,6 +8,8 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
|
||||
using ThingsGateway.Admin.Application;
|
||||
using ThingsGateway.NewLife.Extension;
|
||||
|
||||
@@ -45,4 +47,55 @@ public partial class SysUserEdit
|
||||
Model.OrgId = items.LastOrDefault()?.Parent?.Value?.ToLong() ?? 0;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
[Inject]
|
||||
ToastService ToastService { get; set; }
|
||||
|
||||
#region 头像
|
||||
|
||||
private List<UploadFile> PreviewFileList;
|
||||
|
||||
[FileValidation(Extensions = [".png", ".jpg", ".jpeg"], FileSize = 200 * 1024)]
|
||||
public IBrowserFile? Picture { get; set; }
|
||||
|
||||
|
||||
private CancellationTokenSource? ReadAvatarToken { get; set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ReadAvatarToken?.Cancel();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
PreviewFileList = new(new[] { new UploadFile { PrevUrl = Model.Avatar } });
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
private async Task OnAvatarUpload(UploadFile file)
|
||||
{
|
||||
if (file?.File != null)
|
||||
{
|
||||
var format = file.File.ContentType;
|
||||
ReadAvatarToken ??= new CancellationTokenSource();
|
||||
if (ReadAvatarToken.IsCancellationRequested)
|
||||
{
|
||||
ReadAvatarToken.Dispose();
|
||||
ReadAvatarToken = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
await file.RequestBase64ImageFileAsync(format, 640, 480, 1024 * 200, token: ReadAvatarToken.Token);
|
||||
|
||||
if (file.Code != 0)
|
||||
{
|
||||
await ToastService.Error($"{file.Error} ");
|
||||
}
|
||||
else
|
||||
{
|
||||
Model.Avatar = file.PrevUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion 头像
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@
|
||||
|
||||
<ValidateForm class="p-4" Model="@Model" OnValidSubmit="OnSave">
|
||||
|
||||
<AvatarUpload @bind-Value="@Picture" DisplayText=@AdminLocalizer["Picture"] IsSingle Accept="image/*" OnChange="OnAvatarUpload" DefaultFileList=PreviewFileList></AvatarUpload>
|
||||
<AvatarUpload @bind-Value="@Picture" DisplayText=@AdminLocalizer["Picture"] IsMultiple=false Accept="image/*" OnChange="OnAvatarUpload" DefaultFileList=PreviewFileList></AvatarUpload>
|
||||
|
||||
<BootstrapInput @bind-Value=@Model.Phone></BootstrapInput>
|
||||
<BootstrapInput @bind-Value=@Model.Email></BootstrapInput>
|
||||
|
@@ -40,10 +40,10 @@ public partial class UserInfoEditComponent
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected override Task OnParametersSetAsync()
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
PreviewFileList = new(new[] { new UploadFile { PrevUrl = Model.Avatar } });
|
||||
return base.OnParametersSetAsync();
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
private async Task OnAvatarUpload(UploadFile file)
|
||||
@@ -58,7 +58,7 @@ public partial class UserInfoEditComponent
|
||||
ReadAvatarToken = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
await file.RequestBase64ImageFileAsync(format, 640, 480, 1024 * 200, ReadAvatarToken.Token);
|
||||
await file.RequestBase64ImageFileAsync(format, 640, 480, 1024 * 200, token: ReadAvatarToken.Token);
|
||||
|
||||
if (file.Code != 0)
|
||||
{
|
||||
|
@@ -9,10 +9,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net8.0'">
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.16" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="$(NET8Version)" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net9.0'">
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="$(NET9Version)" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
@@ -1 +1 @@
|
||||
global using ThingsGateway.Admin.Application;
|
||||
|
@@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
using ThingsGateway.Admin.Application;
|
||||
using ThingsGateway.Admin.Razor;
|
||||
using ThingsGateway.Extension;
|
||||
|
||||
|
@@ -13,6 +13,8 @@ using Microsoft.Extensions.Localization;
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using ThingsGateway.Admin.Application;
|
||||
|
||||
namespace ThingsGateway.AdminServer;
|
||||
|
||||
public partial class AccessDenied
|
||||
|
@@ -20,6 +20,7 @@ using Microsoft.Extensions.Options;
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using ThingsGateway.Admin.Application;
|
||||
using ThingsGateway.DataEncryption;
|
||||
using ThingsGateway.NewLife.Extension;
|
||||
using ThingsGateway.Razor;
|
||||
|
@@ -17,6 +17,7 @@ using Microsoft.Extensions.Options;
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using ThingsGateway.Admin.Application;
|
||||
using ThingsGateway.Admin.Razor;
|
||||
using ThingsGateway.Razor;
|
||||
|
||||
|
@@ -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": "重新登录"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -25,6 +25,7 @@ using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Unicode;
|
||||
|
||||
using ThingsGateway.Admin.Application;
|
||||
using ThingsGateway.Admin.Razor;
|
||||
using ThingsGateway.Extension;
|
||||
using ThingsGateway.NewLife.Caching;
|
||||
|
@@ -45,7 +45,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="$(NET9Version)" />
|
||||
</ItemGroup>
|
||||
<!--安装服务守护-->
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
|
||||
@@ -54,8 +54,8 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net9.0' ">
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="$(NET9Version)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="$(NET9Version)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -10,10 +10,10 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -8,11 +8,11 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -11,7 +11,7 @@
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -12,7 +12,7 @@ using BootstrapBlazor.Components;
|
||||
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -8,12 +8,12 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Collections;
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
/// <summary>
|
||||
|
@@ -10,10 +10,9 @@
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.Extension;
|
||||
using ThingsGateway.NewLife.Log;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -13,12 +13,11 @@ using BootstrapBlazor.Components;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using ThingsGateway.NewLife;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
/// <summary>
|
||||
|
@@ -8,9 +8,8 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using ThingsGateway.ConfigurableOptions;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -13,7 +13,7 @@ using BootstrapBlazor.Components;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Admin.Application;
|
||||
|
||||
|
@@ -14,7 +14,7 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
using ThingsGateway.Extension.Generic;
|
||||
using ThingsGateway.NewLife.Caching;
|
||||
|
||||
namespace ThingsGateway.Logging;
|
||||
|
||||
@@ -28,7 +28,7 @@ public sealed class DatabaseLoggerProvider : ILoggerProvider, ISupportExternalSc
|
||||
/// <summary>
|
||||
/// 存储多日志分类日志记录器
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, DatabaseLogger> _databaseLoggers = new();
|
||||
private readonly MemoryCache _databaseLoggers = new();
|
||||
|
||||
/// <summary>
|
||||
/// 日志消息队列(线程安全)
|
||||
|
@@ -11,9 +11,7 @@
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
using ThingsGateway.Extension.Generic;
|
||||
using ThingsGateway.NewLife.Caching;
|
||||
|
||||
namespace ThingsGateway.Logging;
|
||||
|
||||
@@ -27,7 +25,7 @@ public sealed class EmptyLoggerProvider : ILoggerProvider
|
||||
/// <summary>
|
||||
/// 存储多日志分类日志记录器
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, EmptyLogger> _emptyLoggers = new();
|
||||
private readonly MemoryCache _emptyLoggers = new();
|
||||
|
||||
/// <summary>
|
||||
/// 创建空日志记录器
|
||||
|
@@ -13,7 +13,7 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
using ThingsGateway.Extension.Generic;
|
||||
using ThingsGateway.NewLife.Caching;
|
||||
|
||||
namespace ThingsGateway.Logging;
|
||||
|
||||
@@ -27,7 +27,7 @@ public sealed class FileLoggerProvider : ILoggerProvider, ISupportExternalScope
|
||||
/// <summary>
|
||||
/// 存储多日志分类日志记录器
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, FileLogger> _fileLoggers = new();
|
||||
private readonly MemoryCache _fileLoggers = new();
|
||||
|
||||
/// <summary>
|
||||
/// 日志消息队列(线程安全)
|
||||
|
@@ -43,18 +43,18 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.16" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.16" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="$(NET8Version)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(NET8Version)" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="8.0.2" />
|
||||
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="8.0.1" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.5" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net9.0' ">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="9.0.5" />
|
||||
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="9.0.5" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="$(NET9Version)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(NET9Version)" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="$(NET9Version)" />
|
||||
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="$(NET9Version)" />
|
||||
<PackageReference Include="System.Text.Json" Version="$(NET9Version)" />
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
|
@@ -40,6 +40,61 @@ public static class ConcurrentDictionaryExtensions
|
||||
// 返回成功移除的项目数量
|
||||
return count;
|
||||
}
|
||||
/// <summary>
|
||||
/// 批量出队
|
||||
/// </summary>
|
||||
public static List<T> ToListWithDequeue<TKEY, T>(this ConcurrentDictionary<TKEY, T> values, int maxCount = 0)
|
||||
{
|
||||
if (maxCount <= 0)
|
||||
{
|
||||
maxCount = values.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxCount = Math.Min(maxCount, values.Count);
|
||||
}
|
||||
|
||||
var list = new List<T>(maxCount);
|
||||
if (maxCount == 0) return list;
|
||||
var keys = values.Keys;
|
||||
foreach (var key in keys)
|
||||
{
|
||||
if (maxCount-- <= 0) break;
|
||||
if (values.TryRemove(key, out var result))
|
||||
{
|
||||
list.Add(result);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
/// <summary>
|
||||
/// 批量出队
|
||||
/// </summary>
|
||||
public static Dictionary<TKEY, T> ToDictWithDequeue<TKEY, T>(this ConcurrentDictionary<TKEY, T> values, int maxCount = 0)
|
||||
{
|
||||
if (maxCount <= 0)
|
||||
{
|
||||
maxCount = values.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxCount = Math.Min(maxCount, values.Count);
|
||||
}
|
||||
|
||||
var dict = new Dictionary<TKEY, T>(maxCount);
|
||||
|
||||
if (maxCount == 0) return dict;
|
||||
|
||||
var keys = values.Keys;
|
||||
foreach (var key in keys)
|
||||
{
|
||||
if (maxCount-- <= 0) break;
|
||||
if (values.TryRemove(key, out var result))
|
||||
{
|
||||
dict.Add(key, result);
|
||||
}
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -92,6 +92,10 @@ public class TextFileLog : Logger, IDisposable
|
||||
|
||||
// 销毁前把队列日志输出
|
||||
if (Interlocked.CompareExchange(ref _writing, 1, 0) == 0) WriteAndClose(DateTime.MinValue);
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
_Logs?.Clear();
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@@ -13,10 +13,10 @@
|
||||
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView" Version="8.0.16" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView" Version="$(NET8Version)" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net9.0' ">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView" Version="$(NET9Version)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@@ -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>();
|
||||
|
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.0.2" />
|
||||
<PackageReference Include="BootstrapBlazor" Version="9.7.0" />
|
||||
<PackageReference Include="BootstrapBlazor" Version="9.7.3" />
|
||||
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@@ -26,6 +26,10 @@
|
||||
height: var(--line-chart-table-height);
|
||||
}
|
||||
|
||||
.wb-control .wb-full {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dialog-table {
|
||||
height: calc(100vh - 200px);
|
||||
}
|
||||
|
@@ -8,4 +8,5 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
global using ThingsGateway.NewLife.Extension;
|
||||
global using ThingsGateway.NewLife.Extension;
|
||||
global using ThingsGateway.SqlSugar.TDengineAdo;
|
||||
|
@@ -2,7 +2,7 @@
|
||||
using CsvHelper.Configuration;
|
||||
using CsvHelper.TypeConversion;
|
||||
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public class CsvHelperEnumToIntConverter : ITypeConverter
|
||||
{
|
||||
|
@@ -1,4 +1,4 @@
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public class QuestDbPageSizeBulkCopy
|
||||
{
|
||||
|
@@ -1,7 +1,7 @@
|
||||
using System.Data.Common;
|
||||
using System.Text;
|
||||
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
internal static class QuestDbRestAPHelper
|
||||
{
|
||||
|
@@ -10,7 +10,7 @@ using System.Globalization;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
/// <summary>
|
||||
/// QuestDb RestAPI
|
||||
|
@@ -1,4 +1,4 @@
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public static class QuestDbSqlSugarClientExtensions
|
||||
{
|
||||
|
@@ -1,7 +1,7 @@
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public partial class AdoAccessory
|
||||
{
|
||||
|
@@ -3,7 +3,7 @@ using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
///<summary>
|
||||
/// ** description:ActiveX Data Objects
|
||||
|
@@ -1,6 +1,6 @@
|
||||
using System.Data;
|
||||
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public class AopProvider
|
||||
{
|
||||
|
@@ -1,4 +1,4 @@
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public class SugarCacheProvider
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public partial class CodeFirstProvider : ICodeFirst
|
||||
{
|
||||
@@ -261,8 +261,8 @@ namespace SqlSugar
|
||||
}
|
||||
if (item.DataType?.Contains(',') == true && !Regex.IsMatch(item.DataType, @"\d\,\d"))
|
||||
{
|
||||
var types = item.DataType.Split(',').Select(it => it.ToLower()).ToHashSet();
|
||||
var mapingTypes = this.Context.Ado.DbBind.MappingTypes.Select(it => it.Key.ToLower()).ToHashSet();
|
||||
var types = item.DataType.Split(',').ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
var mapingTypes = this.Context.Ado.DbBind.MappingTypes.Select(it => it.Key.ToLower()).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
var mappingType = types.FirstOrDefault(it => mapingTypes.Contains(it));
|
||||
if (mappingType != null)
|
||||
{
|
||||
|
@@ -1,6 +1,6 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public class SplitCodeFirstProvider
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using System.Text;
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public class TableDifferenceProvider
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
using System.Data.Common;
|
||||
using System.Text;
|
||||
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public partial class DbBindAccessory
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public abstract partial class DbBindProvider : DbBindAccessory, IDbBind
|
||||
{
|
||||
@@ -22,7 +22,7 @@ namespace SqlSugar
|
||||
csharpTypeName = "short";
|
||||
if (csharpTypeName.Equals("int64", StringComparison.CurrentCultureIgnoreCase))
|
||||
csharpTypeName = "long";
|
||||
if (csharpTypeName.ToLower().IsIn("boolean", "bool"))
|
||||
if (csharpTypeName.IsInCase("boolean", "bool"))
|
||||
csharpTypeName = "bool";
|
||||
if (csharpTypeName == "DateTimeOffset")
|
||||
csharpTypeName = "DateTime";
|
||||
|
@@ -3,7 +3,7 @@ using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
///<summary>
|
||||
/// ** description:IDataReader Entity Builder
|
||||
@@ -329,7 +329,7 @@ namespace SqlSugar
|
||||
{
|
||||
method = isNullableType ? getConvertByte : getByte;
|
||||
}
|
||||
else if (bindPropertyType == UtilConstants.StringType && dbTypeName?.ToLower() == "timestamp")
|
||||
else if (bindPropertyType == UtilConstants.StringType && dbTypeName.EqualCase("timestamp"))
|
||||
{
|
||||
method = isNullableType ? getOtherNull.MakeGenericMethod(bindPropertyType) : getOther.MakeGenericMethod(bindPropertyType);
|
||||
}
|
||||
@@ -376,8 +376,8 @@ namespace SqlSugar
|
||||
method = isNullableType ? getConvertInt16 : getInt16;
|
||||
if (bindProperyTypeName == "uint32" && this.Context.CurrentConnectionConfig.DbType.IsIn(DbType.MySql, DbType.MySqlConnector))
|
||||
method = null;
|
||||
if (bindPropertyType == UtilConstants.IntType && this.Context.CurrentConnectionConfig.DbType == DbType.OceanBaseForOracle)
|
||||
method = isNullableType ? getMyIntNull : getMyInt;
|
||||
//if (bindPropertyType == UtilConstants.IntType && this.Context.CurrentConnectionConfig.DbType == DbType.OceanBaseForOracle)
|
||||
// method = isNullableType ? getMyIntNull : getMyInt;
|
||||
if (bindProperyTypeName == "int16")
|
||||
method = null;
|
||||
break;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
using System.Data;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public static partial class IDataRecordExtensions
|
||||
{
|
||||
|
@@ -1,7 +1,7 @@
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public abstract partial class DbFirstProvider : IDbFirst
|
||||
{
|
||||
@@ -212,7 +212,7 @@ namespace SqlSugar
|
||||
{
|
||||
if (objectNames.HasValue())
|
||||
{
|
||||
this.TableInfoList = this.TableInfoList.Where(it => objectNames.Select(x => x.ToLower()).Contains(it.Name.ToLower())).ToList();
|
||||
this.TableInfoList = this.TableInfoList.Where(it => objectNames.Contains(it.Name, StringComparer.OrdinalIgnoreCase)).ToList();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
using System.Text;
|
||||
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public static class DbFirstTemplate
|
||||
{
|
||||
|
@@ -1,6 +1,6 @@
|
||||
using System.Text;
|
||||
|
||||
namespace SqlSugar
|
||||
namespace ThingsGateway.SqlSugar
|
||||
{
|
||||
public class RazorFirst
|
||||
{
|
||||
@@ -11,7 +11,7 @@ namespace SqlSugar
|
||||
@"using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using SqlSugar;
|
||||
using ThingsGateway.SqlSugar;
|
||||
namespace @Model.Namespace
|
||||
{
|
||||
///<summary>
|
||||
@@ -31,7 +31,7 @@ namespace @Model.Namespace
|
||||
@:/// Default:@item.DefaultValue
|
||||
@:/// Nullable:@item.IsNullable
|
||||
@:/// </summary>
|
||||
@:[SqlSugar.SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||
@:[ThingsGateway.SqlSugar.SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||
@:public @item.DataType @item.DbColumnName {get;set;}
|
||||
}
|
||||
else if(item.IsPrimarykey)
|
||||
@@ -41,7 +41,7 @@ namespace @Model.Namespace
|
||||
@:/// Default:@item.DefaultValue
|
||||
@:/// Nullable:@item.IsNullable
|
||||
@:/// </summary>
|
||||
@:[SqlSugar.SugarColumn(IsPrimaryKey = true)]
|
||||
@:[ThingsGateway.SqlSugar.SugarColumn(IsPrimaryKey = true)]
|
||||
@:public @item.DataType @item.DbColumnName {get;set;}
|
||||
}
|
||||
else if(item.IsIdentity)
|
||||
@@ -51,7 +51,7 @@ namespace @Model.Namespace
|
||||
@:/// Default:@item.DefaultValue
|
||||
@:/// Nullable:@item.IsNullable
|
||||
@:/// </summary>
|
||||
@:[SqlSugar.SugarColumn(IsIdentity = true)]
|
||||
@:[ThingsGateway.SqlSugar.SugarColumn(IsIdentity = true)]
|
||||
@:public @item.DataType @item.DbColumnName {get;set;}
|
||||
}
|
||||
else
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user