diff --git a/BootstrapAdmin.sln b/BootstrapAdmin.sln index 00c43c05..f41fec3f 100644 --- a/BootstrapAdmin.sln +++ b/BootstrapAdmin.sln @@ -33,7 +33,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MongoDB", "MongoDB", "{A06A db\MongoDB\Dicts.js = db\MongoDB\Dicts.js db\MongoDB\Groups.js = db\MongoDB\Groups.js db\MongoDB\init.js = db\MongoDB\init.js - db\MongoDB\install.cmd = db\MongoDB\install.cmd + db\MongoDB\install.ps1 = db\MongoDB\install.ps1 db\MongoDB\install.sh = db\MongoDB\install.sh db\MongoDB\Navigations.js = db\MongoDB\Navigations.js db\MongoDB\Roles.js = db\MongoDB\Roles.js @@ -43,6 +43,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MySQL", "MySQL", "{084E2E94-6B7D-4D3E-9BF1-6972427FBF80}" ProjectSection(SolutionItems) = preProject db\MySQL\initData.sql = db\MySQL\initData.sql + db\MySQL\install.ps1 = db\MySQL\install.ps1 db\MySQL\install.sh = db\MySQL\install.sh db\MySQL\install.sql = db\MySQL\install.sql db\MySQL\my.ini = db\MySQL\my.ini diff --git a/Directory.Build.props b/Directory.Build.props index cd66f379..0f784c34 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,9 +7,14 @@ latest true $(MSBuildThisFileDirectory)src\Keys\Longbow.Utility.snk - $(MSBuildProjectName).xml + + + + + + @@ -19,11 +24,4 @@ - - - - - - - diff --git a/db/MongoDB/Navigations.js b/db/MongoDB/Navigations.js index 8d5bac4d..8a5cf67e 100644 --- a/db/MongoDB/Navigations.js +++ b/db/MongoDB/Navigations.js @@ -611,6 +611,30 @@ "IsResource": NumberInt(0), "Application": "BA" }, + { + "_id": ObjectId("1bd7b8445fa31256f77e4b9c"), + "ParentId": "5bd7b8445fa31256f77e4b9a", + "Name": "暂停", + "Order": NumberInt(20), + "Icon": "fa fa-fa", + "Url": "pause", + "Category": "0", + "Target": "_self", + "IsResource": NumberInt(2), + "Application": "BA" + }, + { + "_id": ObjectId("1bd7b8445fa31256f77e4b9d"), + "ParentId": "5bd7b8445fa31256f77e4b9a", + "Name": "日志", + "Order": NumberInt(30), + "Icon": "fa fa-fa", + "Url": "info", + "Category": "0", + "Target": "_self", + "IsResource": NumberInt(2), + "Application": "BA" + }, { "_id": ObjectId("5bd7b8445fa31256f77e4b9b"), "ParentId": "0", diff --git a/db/MongoDB/install.cmd b/db/MongoDB/install.ps1 similarity index 100% rename from db/MongoDB/install.cmd rename to db/MongoDB/install.ps1 diff --git a/db/MySQL/initData.sql b/db/MySQL/initData.sql index 6e932fc6..406b14c2 100644 --- a/db/MySQL/initData.sql +++ b/db/MySQL/initData.sql @@ -110,6 +110,8 @@ INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category, IsResourc INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category, IsResource) VALUES (@@identity - 2, '删除', 30, 'fa fa-fa', 'del', '0', 2); INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '站内消息', 100, 'fa fa-envelope', '~/Admin/Messages', '0'); INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '任务管理', 110, 'fa fa fa-tasks', '~/Admin/Tasks', '0'); +INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category, IsResource) VALUES (@@identity, '暂停', 10, 'fa fa-fa', 'pause', '0', 2); +INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category, IsResource) VALUES (@@identity - 1, '日志', 20, 'fa fa-fa', 'info', '0', 2); INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '通知管理', 120, 'fa fa-bell', '~/Admin/Notifications', '0'); INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '系统日志', 130, 'fa fa-gears', '#', '0'); INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (@@identity, '操作日志', 10, 'fa fa-edit', '~/Admin/Logs', '0'); diff --git a/db/MySQL/install.ps1 b/db/MySQL/install.ps1 new file mode 100644 index 00000000..82f44f6f --- /dev/null +++ b/db/MySQL/install.ps1 @@ -0,0 +1,9 @@ +# init mysql database +$startPath = $args[0] +if ($startPath -eq $null) { + $startPath = "Z:\src\Longbow\BootstrapAdmin\db\SqlServer" +} + +mysql -e "drop database if exists BootstrapAdmin; create database BootstrapAdmin;" -uroot +mysql -hlocalhost -uroot -DBootstrapAdmin < $startPath\install.sql +mysql -hlocalhost -uroot -DBootstrapAdmin < $startPath\initData.sql diff --git a/db/Postgresql/initData.sql b/db/Postgresql/initData.sql index e11ad9b5..9fa7600a 100644 --- a/db/Postgresql/initData.sql +++ b/db/Postgresql/initData.sql @@ -111,6 +111,8 @@ INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (currval('navigations_id_seq') - 3, '删除', 30, 'fa fa-fa', 'del', '0', 2); INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '站内消息', 100, 'fa fa-envelope', '~/Admin/Messages', '0'); INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '任务管理', 110, 'fa fa fa-tasks', '~/Admin/Tasks', '0'); +INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (currval('navigations_id_seq') - 1, '暂停', 10, 'fa fa-fa', 'pause', '0', 2); +INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (currval('navigations_id_seq') - 2, '日志', 20, 'fa fa-fa', 'info', '0', 2); INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '通知管理', 120, 'fa fa-bell', '~/Admin/Notifications', '0'); INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '系统日志', 130, 'fa fa-gears', '#', '0'); INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (currval('navigations_id_seq') - 1, 0, '操作日志', 10, 'fa fa-edit', '~/Admin/Logs', '0'); diff --git a/db/SQLite/InitData.sql b/db/SQLite/InitData.sql index 3d701bde..b5b13e4c 100644 --- a/db/SQLite/InitData.sql +++ b/db/SQLite/InitData.sql @@ -110,6 +110,8 @@ INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (last_insert_rowid() - 2, '删除', 30, 'fa fa-fa', 'del', '0', 2); INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '站内消息', 100, 'fa fa-envelope', '~/Admin/Messages', '0'); INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '任务管理', 110, 'fa fa fa-tasks', '~/Admin/Tasks', '0'); +INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (last_insert_rowid(), '暂停', 10, 'fa fa-fa', 'pause', '0', 2); +INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (last_insert_rowid() - 1, '日志', 20, 'fa fa-fa', 'info', '0', 2); INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '通知管理', 120, 'fa fa-bell', '~/Admin/Notifications', '0'); INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '系统日志', 130, 'fa fa-gears', '#', '0'); INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (last_insert_rowid(), '操作日志', 10, 'fa fa-edit', '~/Admin/Logs', '0'); diff --git a/db/SqlServer/InitData.sql b/db/SqlServer/InitData.sql index 0271917d..028a3a18 100644 --- a/db/SqlServer/InitData.sql +++ b/db/SqlServer/InitData.sql @@ -113,6 +113,8 @@ INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (@@Identity - 2, N'删除', 30, 'fa fa-fa', 'del', '0', 2); INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'站内消息', 100, N'fa fa-envelope', N'~/Admin/Messages', N'0') INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'任务管理', 110, N'fa fa fa-tasks', N'~/Admin/Tasks', N'0') +INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (@@Identity, N'暂停', 10, 'fa fa-fa', 'pause', '0', 2); +INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category], IsResource) VALUES (@@Identity - 1, N'日志', 20, 'fa fa-fa', 'info', '0', 2); INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'通知管理', 120, N'fa fa-bell', N'~/Admin/Notifications', N'0') INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'日志管理', 130, N'fa fa-gears', N'#', N'0') INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (@@Identity, N'操作日志', 10, N'fa fa-edit', N'~/Admin/Logs', N'0') diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 00000000..aad557b0 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,13 @@ + + + + + + https://gitee.com/LongbowGroup/$(MsBuildProjectName) + https://gitee.com/LongbowGroup/$(MsBuildProjectName).git + git + enable + $(MSBuildProjectName).xml + + + diff --git a/src/admin/Bootstrap.Admin/App.razor b/src/admin/Bootstrap.Admin/App.razor index 31b7f34d..a70a539a 100644 --- a/src/admin/Bootstrap.Admin/App.razor +++ b/src/admin/Bootstrap.Admin/App.razor @@ -1,14 +1,6 @@ - - - - - - Authentication in progress - Only visible while authentication is in progress. - - + @@ -17,4 +9,4 @@ - \ No newline at end of file + diff --git a/src/admin/Bootstrap.Admin/Bootstrap.Admin.csproj b/src/admin/Bootstrap.Admin/Bootstrap.Admin.csproj index 8d34494b..60085036 100644 --- a/src/admin/Bootstrap.Admin/Bootstrap.Admin.csproj +++ b/src/admin/Bootstrap.Admin/Bootstrap.Admin.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/admin/Bootstrap.Admin/Controllers/AccountController.cs b/src/admin/Bootstrap.Admin/Controllers/AccountController.cs index a32202b7..3277c156 100644 --- a/src/admin/Bootstrap.Admin/Controllers/AccountController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/AccountController.cs @@ -73,7 +73,7 @@ namespace Bootstrap.Admin.Controllers /// /// [HttpGet] - public ActionResult Login([FromQuery]string appId = null) + public ActionResult Login([FromQuery]string? appId = null) { if (DictHelper.RetrieveSystemModel()) { @@ -111,11 +111,14 @@ namespace Bootstrap.Admin.Controllers Description = "手机用户", App = provider.Options.App }; - UserHelper.Save(user); - - // 根据配置文件设置默认角色 - var roles = RoleHelper.Retrieves().Where(r => provider.Options.Roles.Any(rl => rl.Equals(r.RoleName, StringComparison.OrdinalIgnoreCase))).Select(r => r.Id); - RoleHelper.SaveByUserId(user.Id, roles); + if (UserHelper.Save(user) && !string.IsNullOrEmpty(user.Id)) + { + // 根据配置文件设置默认角色 + var roles = RoleHelper.Retrieves().Where(r => provider.Options.Roles.Any(rl => rl.Equals(r.RoleName, StringComparison.OrdinalIgnoreCase))).Select(r => r.Id); +#pragma warning disable CS8620 // 由于引用类型的可为 null 性差异,实参不能用于形参。 + RoleHelper.SaveByUserId(user.Id, roles); +#pragma warning restore CS8620 // 由于引用类型的可为 null 性差异,实参不能用于形参。 + } } } return auth ? await SignInAsync(phone, true, MobileSchema) : RedirectLogin(); diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/AnalyseController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/AnalyseController.cs index 365ec44a..07cf9a0b 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/AnalyseController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/AnalyseController.cs @@ -8,7 +8,7 @@ using System.Linq; namespace Bootstrap.Admin.Controllers.Api { /// - /// + /// 网站分析控制器 /// [Route("api/[controller]")] [Authorize] @@ -16,11 +16,11 @@ namespace Bootstrap.Admin.Controllers.Api public class AnalyseController : ControllerBase { /// - /// + /// 通过 logType 查询分析数据接口 /// /// [HttpGet()] - public ActionResult Get([FromQuery]string logType = "") + public ActionResult Get([FromQuery]string logType) { var ret = new AnalyseData(); if (logType.Equals("LoginUsers", StringComparison.OrdinalIgnoreCase)) @@ -60,19 +60,19 @@ namespace Bootstrap.Admin.Controllers.Api } /// - /// + /// 分析数据实体类 /// public class AnalyseData { /// - /// + /// 获得/设置 折线数据集合 /// - public IEnumerable Polylines { get; set; } + public IEnumerable Polylines { get; set; } = new string[0]; /// - /// + /// 获得 数据集合 /// - public List> Datas { get; set; } = new List>(); + public List> Datas { get; } = new List>(); } } } diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/AppsController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/AppsController.cs index a503c244..c5344f10 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/AppsController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/AppsController.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; namespace Bootstrap.Admin.Controllers.Api { /// - /// + /// 应用程序控制器 /// [Route("api/[controller]")] [Authorize] @@ -14,7 +14,7 @@ namespace Bootstrap.Admin.Controllers.Api public class AppsController : ControllerBase { /// - /// + /// 通过角色ID获取其授权的所有应用程序集合 /// /// /// diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/CategoryController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/CategoryController.cs index c6187c15..1158b60f 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/CategoryController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/CategoryController.cs @@ -15,7 +15,7 @@ namespace Bootstrap.Admin.Controllers.Api public class CategoryController : ControllerBase { /// - /// 获取字典表中所有Category数据 + /// 获取字典表中所有 Category 数据 /// /// [HttpGet] @@ -26,7 +26,7 @@ namespace Bootstrap.Admin.Controllers.Api } /// - /// + /// 获取所有菜单数据 /// /// [HttpGet] @@ -36,7 +36,7 @@ namespace Bootstrap.Admin.Controllers.Api } /// - /// + /// 获取所有父级菜单数据 /// /// [HttpGet] @@ -44,5 +44,25 @@ namespace Bootstrap.Admin.Controllers.Api { return MenuHelper.RetrieveMenus(User.Identity.Name).Where(m => m.Menus.Count() > 0).OrderBy(m => m.Name).Select(m => m.Name); } + + /// + /// 通过指定菜单检查子菜单是否有子菜单 + /// + /// + [HttpGet("{id}")] + public bool ValidateMenuBySubMenu(string id) + { + return !MenuHelper.RetrieveAllMenus(User.Identity.Name).Where(m => m.ParentId == id).Any(); + } + + /// + /// 通过指定菜单检查父级菜单是否为菜单类型 资源与按钮返回 false + /// + /// + [HttpGet("{id}")] + public bool ValidateParentMenuById(string id) + { + return MenuHelper.RetrieveAllMenus(User.Identity.Name).FirstOrDefault(m => m.Id == id)?.IsResource == 0; + } } } diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/DictsController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/DictsController.cs index 61e9df13..3dfc82b8 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/DictsController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/DictsController.cs @@ -10,7 +10,7 @@ using System.Collections.Generic; namespace Bootstrap.Admin.Controllers.Api { /// - /// + /// 字典表维护控制器 /// [Route("api/[controller]")] [Authorize] @@ -18,7 +18,7 @@ namespace Bootstrap.Admin.Controllers.Api public class DictsController : ControllerBase { /// - /// + /// 获取所有字典表数据方法 /// /// /// @@ -28,7 +28,7 @@ namespace Bootstrap.Admin.Controllers.Api return value.RetrieveData(); } /// - /// + /// 保存字典方法 /// /// [HttpPost] @@ -38,7 +38,7 @@ namespace Bootstrap.Admin.Controllers.Api return DictHelper.Save(value); } /// - /// + /// 删除字典项方法 /// /// [HttpDelete] diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/ExceptionsController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/ExceptionsController.cs index a61b9a40..d7e4d48a 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/ExceptionsController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/ExceptionsController.cs @@ -57,34 +57,37 @@ namespace Bootstrap.Admin.Controllers.Api var filePath = Path.Combine(AppContext.BaseDirectory, "Error"); var logName = $"{Path.Combine(filePath, exceptionFile.FileName)}.log"; if (!System.IO.File.Exists(logName)) return new JsonResult("无此日志文件"); - StringBuilder sb = new StringBuilder(); - using (StreamReader reader = new StreamReader(logName)) + var sb = new StringBuilder(); + using (var reader = new StreamReader(logName)) { while (!reader.EndOfStream) { - var line = reader.ReadLine().Replace("<", "<").Replace(">", ">"); - if (line == "General Information ") sb.AppendFormat("{0}", line); - else if (line.StartsWith("TimeStamp:")) sb.AppendFormat("{0}", line); - else if (line.EndsWith("Exception Information")) sb.AppendFormat("{0}", line); - else if (line.StartsWith("Message:")) sb.AppendFormat("{0}", line); - else if (line.StartsWith("ErrorSql:")) sb.AppendFormat("{0}", line); - else if (line.StartsWith("Exception Type: Longbow.Data.DBAccessException")) sb.AppendFormat("{0}", line); - else if (line.StartsWith("StackTrace Information")) sb.AppendFormat("{0}", line); - else sb.AppendFormat("{0}", line); + var line = reader.ReadLine()?.Replace("<", "<").Replace(">", ">"); + if (!string.IsNullOrEmpty(line)) + { + if (line == "General Information ") sb.AppendFormat("{0}", line); + else if (line.StartsWith("TimeStamp:")) sb.AppendFormat("{0}", line); + else if (line.EndsWith("Exception Information")) sb.AppendFormat("{0}", line); + else if (line.StartsWith("Message:")) sb.AppendFormat("{0}", line); + else if (line.StartsWith("ErrorSql:")) sb.AppendFormat("{0}", line); + else if (line.StartsWith("Exception Type: Longbow.Data.DBAccessException")) sb.AppendFormat("{0}", line); + else if (line.StartsWith("StackTrace Information")) sb.AppendFormat("{0}", line); + else sb.AppendFormat("{0}", line); + } } } return new JsonResult(sb.ToString()); } /// - /// + /// 查询服务器端日志文件参数类 /// public class ExceptionFileQuery { /// - /// + /// 获取/设置 文件名称 /// - public string FileName { get; set; } + public string FileName { get; set; } = ""; } } } diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/GiteeController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/GiteeController.cs index 731284dd..4bf97095 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/GiteeController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/GiteeController.cs @@ -27,7 +27,7 @@ namespace Bootstrap.Admin.Controllers.Api /// /// [HttpGet] - public async Task Issues([FromServices]GiteeHttpClient client, [FromQuery]string userName = "LongbowEnterprise", [FromQuery]string repoName = "BootstrapAdmin", [FromQuery]string label = "custom badge", [FromQuery]string color = "orange") + public async Task Issues([FromServices]GiteeHttpClient client, [FromQuery]string? userName = "LongbowEnterprise", [FromQuery]string? repoName = "BootstrapAdmin", [FromQuery]string? label = "custom badge", [FromQuery]string? color = "orange") { var ret = await GetJsonAsync(() => client.HttpClient.GetStringAsync($"https://gitee.com/{userName}/{repoName}/issues"), content => { @@ -50,7 +50,7 @@ namespace Bootstrap.Admin.Controllers.Api /// /// [HttpGet] - public async Task Pulls([FromServices]GiteeHttpClient client, [FromQuery]string userName = "LongbowEnterprise", [FromQuery]string repoName = "BootstrapAdmin", [FromQuery]string label = "custom badge", [FromQuery]string color = "orange") + public async Task Pulls([FromServices]GiteeHttpClient client, [FromQuery]string? userName = "LongbowEnterprise", [FromQuery]string? repoName = "BootstrapAdmin", [FromQuery]string? label = "custom badge", [FromQuery]string? color = "orange") { var ret = await GetJsonAsync(() => client.HttpClient.GetStringAsync($"https://gitee.com/{userName}/{repoName}/pulls"), content => { @@ -72,7 +72,7 @@ namespace Bootstrap.Admin.Controllers.Api /// /// [HttpGet] - public async Task Releases([FromServices]GiteeHttpClient client, [FromQuery]string userName = "LongbowEnterprise", [FromQuery]string repoName = "BootstrapAdmin", [FromQuery]string label = "custom badge", [FromQuery]string color = "orange") + public async Task Releases([FromServices]GiteeHttpClient client, [FromQuery]string? userName = "LongbowEnterprise", [FromQuery]string? repoName = "BootstrapAdmin", [FromQuery]string? label = "custom badge", [FromQuery]string? color = "orange") { var ret = await GetJsonAsync(() => client.HttpClient.GetStringAsync($"https://gitee.com/{userName}/{repoName}/releases"), content => { @@ -93,7 +93,7 @@ namespace Bootstrap.Admin.Controllers.Api /// /// [HttpGet] - public async Task Builds([FromServices]GiteeHttpClient client, [FromQuery]string userName = "ArgoZhang", [FromQuery]string projName = "bootstrapadmin", [FromQuery]string branchName = "master", [FromQuery]string label = "custom badge", [FromQuery]string color = "orange") + public async Task Builds([FromServices]GiteeHttpClient client, [FromQuery]string? userName = "ArgoZhang", [FromQuery]string? projName = "bootstrapadmin", [FromQuery]string? branchName = "master", [FromQuery]string? label = "custom badge", [FromQuery]string? color = "orange") { var ret = await GetJsonAsync(() => client.HttpClient.GetAsJsonAsync($"https://ci.appveyor.com/api/projects/{userName}/{projName}/branch/{branchName}", null, new CancellationTokenSource(10000).Token), content => { @@ -126,7 +126,7 @@ namespace Bootstrap.Admin.Controllers.Api /// /// Appveyor 编译版本实例 /// - public Build Build { get; set; } + public Build Build { get; set; } = new Build(); } private class Build @@ -134,7 +134,7 @@ namespace Bootstrap.Admin.Controllers.Api /// /// Build 版本信息 /// - public string Version { get; set; } + public string Version { get; set; } = ""; } } } diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/GroupsController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/GroupsController.cs index c7493b99..807aa9d2 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/GroupsController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/GroupsController.cs @@ -5,12 +5,11 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using System.Collections.Generic; -using System.Linq; namespace Bootstrap.Admin.Controllers.Api { /// - /// + /// 部门维护控制器 /// [Route("api/[controller]")] [Authorize] @@ -18,7 +17,7 @@ namespace Bootstrap.Admin.Controllers.Api public class GroupsController : ControllerBase { /// - /// + /// 部门数据查询方法 /// /// /// @@ -29,18 +28,7 @@ namespace Bootstrap.Admin.Controllers.Api } /// - /// - /// - /// - /// - [HttpGet("{id}")] - public Group Get(string id) - { - return GroupHelper.Retrieves().FirstOrDefault(t => t.Id == id); - } - - /// - /// + /// 保存部门方法 /// /// [HttpPost] @@ -51,7 +39,7 @@ namespace Bootstrap.Admin.Controllers.Api } /// - /// + /// 删除部门方法 /// /// [HttpDelete] @@ -64,7 +52,7 @@ namespace Bootstrap.Admin.Controllers.Api /// /// 获取部门授权 /// - /// + /// 用户ID或者角色ID /// /// [HttpPost("{id}")] diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/InterfaceController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/InterfaceController.cs index 6784bd8d..60c117f2 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/InterfaceController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/InterfaceController.cs @@ -3,7 +3,10 @@ using Bootstrap.Security; using Bootstrap.Security.Mvc; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; namespace Bootstrap.Admin.Controllers { @@ -50,7 +53,7 @@ namespace Bootstrap.Admin.Controllers /// /// [HttpPost] - public BootstrapUser RetrieveUserByUserName([FromBody]string userName) + public BootstrapUser? RetrieveUserByUserName([FromBody]string userName) { return UserHelper.RetrieveUserByUserName(userName); } @@ -63,7 +66,28 @@ namespace Bootstrap.Admin.Controllers [HttpPost] public IEnumerable RetrieveAppMenus([FromBody]AppMenuOption args) { + if (string.IsNullOrEmpty(args.AppId) || string.IsNullOrEmpty(args.UserName)) return new BootstrapMenu[0]; return MenuHelper.RetrieveAppMenus(args.AppId, args.UserName, args.Url); } + + /// + /// 发送健康检查结果 + /// + /// + /// + /// + /// + [HttpPost] + public async Task Healths([FromServices]GiteeHttpClient httpClient, [FromServices]IConfiguration config, [FromBody]string message) + { + var ret = false; + var url = config.GetValue("HealthsCloudUrl", ""); + if (!string.IsNullOrEmpty(url)) + { + try { await httpClient.HttpClient.PostAsJsonAsync(url, message); ret = true; } + catch { } + } + return ret; + } } } diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/LoginController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/LoginController.cs index 8b4c4888..c73aaf8b 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/LoginController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/LoginController.cs @@ -32,7 +32,7 @@ namespace Bootstrap.Admin.Controllers.Api /// /// [HttpPost] - public string Post([FromBody]User user) + public string? Post([FromBody]User user) { var token = string.Empty; string userName = user.UserName; @@ -59,7 +59,7 @@ namespace Bootstrap.Admin.Controllers.Api /// /// [HttpOptions] - public string Options() + public string? Options() { return null; } diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/LogsController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/LogsController.cs index 7c1d40f1..6d42a050 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/LogsController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/LogsController.cs @@ -42,7 +42,7 @@ namespace Bootstrap.Admin.Controllers.Api value.Browser = $"{agent.Browser?.Name} {agent.Browser?.Version}"; value.OS = $"{agent.OS?.Name} {agent.OS?.Version}"; value.City = ipLocator.Locate(value.Ip); - value.UserName = User.Identity.Name; + value.UserName = User.Identity.Name ?? string.Empty; return LogHelper.Save(value); } } diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/NewController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/NewController.cs index 33ed392f..02496093 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/NewController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/NewController.cs @@ -7,7 +7,7 @@ using System.Linq; namespace Bootstrap.Admin.Controllers { /// - /// + /// 新用户注册控制器 /// [Route("api/[controller]")] [Authorize] @@ -38,15 +38,19 @@ namespace Bootstrap.Admin.Controllers public bool Put([FromBody]User value) { var ret = false; - if (value.UserStatus == UserStates.ApproveUser) + var userName = User.Identity.Name; + if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(value.Id)) { - ret = UserHelper.Approve(value.Id, User.Identity.Name); - } - else if (value.UserStatus == UserStates.RejectUser) - { - ret = UserHelper.Reject(value.Id, User.Identity.Name); + if (value.UserStatus == UserStates.ApproveUser) + { + ret = UserHelper.Approve(value.Id, userName); + } + else if (value.UserStatus == UserStates.RejectUser) + { + ret = UserHelper.Reject(value.Id, userName); + } } return ret; } } -} \ No newline at end of file +} diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/NotificationsController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/NotificationsController.cs index 18ff4803..cdad1689 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/NotificationsController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/NotificationsController.cs @@ -56,7 +56,7 @@ namespace Bootstrap.Admin.Controllers.Api apps = apps.Take(6); apps.AsParallel().ForAll(n => { - n.ExceptionType = n.ExceptionType.Split('.').Last(); + n.ExceptionType = n.ExceptionType?.Split('.').Last(); var ts = DateTime.Now - n.LogTime; if (ts.TotalMinutes < 5) n.Period = "刚刚"; else if (ts.Days > 0) n.Period = string.Format("{0}天", ts.Days); diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/OnlineUsersController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/OnlineUsersController.cs index c0e08f05..152a5987 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/OnlineUsersController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/OnlineUsersController.cs @@ -72,7 +72,7 @@ namespace Bootstrap.Admin.Controllers.Api /// /// /// - public string Ip { get; set; } + public string? Ip { get; set; } /// /// @@ -108,7 +108,7 @@ namespace Bootstrap.Admin.Controllers.Api /// public void Reset() { - if (dispatcher != null) dispatcher.Change(TimeSpan.FromSeconds(30), Timeout.InfiniteTimeSpan); + dispatcher.Change(TimeSpan.FromSeconds(30), Timeout.InfiniteTimeSpan); } #region Impletement IDispose @@ -123,7 +123,6 @@ namespace Bootstrap.Admin.Controllers.Api if (dispatcher != null) { dispatcher.Dispose(); - dispatcher = null; } } } diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/ProfilesController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/ProfilesController.cs index 67265005..4b6d06bf 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/ProfilesController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/ProfilesController.cs @@ -11,7 +11,7 @@ using System.Threading.Tasks; namespace Bootstrap.Admin.Controllers.Api { /// - /// + /// 个人中心控制器 /// [Route("api/[controller]")] [Authorize] @@ -30,9 +30,6 @@ namespace Bootstrap.Admin.Controllers.Api public JsonResult Post(string id, [FromServices]IWebHostEnvironment env, [FromForm]DeleteFileCollection files) { if (!id.Equals("Delete", StringComparison.OrdinalIgnoreCase)) return new JsonResult(new object()); - - var previewUrl = string.Empty; - long fileSize = 0; var userName = User.Identity.Name; var fileName = files.Key; @@ -41,10 +38,10 @@ namespace Bootstrap.Admin.Controllers.Api fileName = "default.jpg"; var webSiteUrl = DictHelper.RetrieveIconFolderPath(); var filePath = Path.Combine(env.WebRootPath, webSiteUrl.Replace("~", string.Empty).Replace('/', Path.DirectorySeparatorChar).TrimStart(Path.DirectorySeparatorChar) + fileName); - fileSize = new FileInfo(filePath).Length; + var fileSize = new FileInfo(filePath).Length; var iconName = $"{fileName}?v={DateTime.Now.Ticks}"; - previewUrl = Url.Content($"{webSiteUrl}{iconName}"); - UserHelper.SaveUserIconByName(userName, iconName); + var previewUrl = Url.Content($"{webSiteUrl}{iconName}"); + if (!string.IsNullOrEmpty(userName)) UserHelper.SaveUserIconByName(userName, iconName); return new JsonResult(new { @@ -57,14 +54,14 @@ namespace Bootstrap.Admin.Controllers.Api } /// - /// + /// 待删除文件集合类 /// public class DeleteFileCollection { /// - /// + /// 获得/设置 文件名称 /// - public string Key { get; set; } + public string Key { get; set; } = ""; } /// @@ -96,7 +93,7 @@ namespace Bootstrap.Admin.Controllers.Api } var iconName = $"{fileName}?v={DateTime.Now.Ticks}"; previewUrl = Url.Content($"{webSiteUrl}{iconName}"); - UserHelper.SaveUserIconByName(userName, iconName); + if (!string.IsNullOrEmpty(userName)) UserHelper.SaveUserIconByName(userName, iconName); } return new JsonResult(new { @@ -109,7 +106,7 @@ namespace Bootstrap.Admin.Controllers.Api } /// - /// + /// 个人中心操作方法 更改样式 更改显示名称 更改默认应用 /// /// [HttpPut] diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/RolesController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/RolesController.cs index 6b0040d1..cfbb3bd5 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/RolesController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/RolesController.cs @@ -11,7 +11,7 @@ using System.Linq; namespace Bootstrap.Admin.Controllers.Api { /// - /// + /// 角色维护控制器 /// [Route("api/[controller]")] [Authorize] @@ -19,7 +19,7 @@ namespace Bootstrap.Admin.Controllers.Api public class RolesController : ControllerBase { /// - /// + /// 获取所有角色数据 /// /// /// @@ -37,7 +37,7 @@ namespace Bootstrap.Admin.Controllers.Api [HttpPost("{id}")] public IEnumerable Post(string id, [FromQuery]string type) { - IEnumerable ret = new List(); + IEnumerable ret = new Role[0]; switch (type) { case "user": @@ -53,7 +53,7 @@ namespace Bootstrap.Admin.Controllers.Api return ret.Select(m => new { m.Id, m.Checked, m.RoleName, m.Description }); } /// - /// 保存角色 + /// 保存角色授权方法 /// /// 角色ID /// 选中的ID集合 @@ -82,7 +82,7 @@ namespace Bootstrap.Admin.Controllers.Api return ret; } /// - /// + /// 保存角色方法 /// /// [HttpPost] @@ -92,7 +92,7 @@ namespace Bootstrap.Admin.Controllers.Api return RoleHelper.Save(value); } /// - /// + /// 删除角色方法 /// /// [HttpDelete] diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/SettingsController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/SettingsController.cs index 90fe3b3f..ec0bb679 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/SettingsController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/SettingsController.cs @@ -9,7 +9,7 @@ using System.Collections.Generic; namespace Bootstrap.Admin.Controllers.Api { /// - /// + /// 网站设置控制器 /// [Route("api/[controller]")] [Authorize] @@ -17,7 +17,7 @@ namespace Bootstrap.Admin.Controllers.Api public class SettingsController : ControllerBase { /// - /// + /// 保存网站设置方法 /// /// /// @@ -26,7 +26,7 @@ namespace Bootstrap.Admin.Controllers.Api public bool Post([FromBody]BootstrapDict value) => DictHelper.SaveSettings(value); /// - /// + /// 获取网站缓存站点集合 /// [HttpGet] public IEnumerable Get() => CacheManager.CorsSites; diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/TasksController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/TasksController.cs index 4265df72..81b86396 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/TasksController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/TasksController.cs @@ -1,4 +1,5 @@ -using Longbow.Tasks; +using Bootstrap.DataAccess; +using Longbow.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; @@ -7,7 +8,7 @@ using System.Linq; namespace Bootstrap.Admin.Controllers.Api { /// - /// + /// 任务管理控制器 /// [Route("api/[controller]")] [Authorize] @@ -15,7 +16,7 @@ namespace Bootstrap.Admin.Controllers.Api public class TasksController : ControllerBase { /// - /// + /// 获取所有任务数据 /// /// [HttpGet] @@ -23,5 +24,25 @@ namespace Bootstrap.Admin.Controllers.Api { return TaskServicesManager.ToList().Select(s => new { s.Name, Status = s.Status.ToString(), s.LastRuntime, s.CreatedTime, s.NextRuntime, LastRunResult = s.Triggers.First().LastResult.ToString(), TriggerExpression = s.Triggers.FirstOrDefault().ToString() }).OrderBy(s => s.Name); } + + /// + /// 任务相关操作 + /// + /// 调度名称 + /// 操作方式 pause run + [HttpPut("{scheName}")] + public bool Put(string scheName, [FromQuery]string operType) + { + var sche = TaskServicesManager.Get(scheName); + if (sche != null) sche.Status = operType == "pause" ? SchedulerStatus.Disabled : SchedulerStatus.Running; + + // SQL 日志任务特殊处理 + if (scheName == "SQL日志") + { + if (operType == "pause") LogHelper.Pause(); + else LogHelper.Run(); + } + return true; + } } } diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/TasksLogController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/TasksLogController.cs index c7d45297..9e9924b3 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/TasksLogController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/TasksLogController.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace Bootstrap.Admin.Controllers.Api { /// - /// + /// 任务日志控制器 /// [Route("api/[controller]")] [Authorize] @@ -25,9 +25,14 @@ namespace Bootstrap.Admin.Controllers.Api public ActionResult Get([FromQuery]string name, [FromServices]IHubContext hub) { var sche = TaskServicesManager.Get(name); - sche.Triggers.First().PulseCallback = t => SendTaskLog(sche, name, hub); - SendTaskLog(sche, name, hub); - return Ok(true); + var ret = false; + if (sche != null) + { + sche.Triggers.First().PulseCallback = t => SendTaskLog(sche, name, hub); + SendTaskLog(sche, name, hub); + ret = true; + } + return Ok(ret); } private Task SendTaskLog(IScheduler sche, string name, IHubContext hub) diff --git a/src/admin/Bootstrap.Admin/Controllers/Api/UsersController.cs b/src/admin/Bootstrap.Admin/Controllers/Api/UsersController.cs index 50733984..e7debd8b 100644 --- a/src/admin/Bootstrap.Admin/Controllers/Api/UsersController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/Api/UsersController.cs @@ -38,7 +38,7 @@ namespace Bootstrap.Admin.Controllers.Api [HttpPost("{id}")] public IEnumerable Post(string id, [FromQuery]string type) { - IEnumerable ret = null; + IEnumerable ret = new string[0]; switch (type) { case "role": @@ -68,7 +68,7 @@ namespace Bootstrap.Admin.Controllers.Api [ButtonAuthorize(Url = "~/Admin/Users", Auth = "add,edit")] public bool Post([FromBody]User value) { - var ret = false; + bool ret; if (string.IsNullOrEmpty(value.Id)) { value.Description = string.Format("管理员{0}创建用户", User.Identity.Name); @@ -124,7 +124,7 @@ namespace Bootstrap.Admin.Controllers.Api /// [AllowAnonymous] [HttpOptions] - public string Options() + public string? Options() { return null; } diff --git a/src/admin/Bootstrap.Admin/Controllers/HomeController.cs b/src/admin/Bootstrap.Admin/Controllers/HomeController.cs index 804aab7d..4518c0db 100644 --- a/src/admin/Bootstrap.Admin/Controllers/HomeController.cs +++ b/src/admin/Bootstrap.Admin/Controllers/HomeController.cs @@ -22,7 +22,7 @@ namespace Bootstrap.Admin.Controllers var model = new HeaderBarModel(User.Identity.Name); var homeUrl = DictHelper.RetrieveHomeUrl(model.AppId); var useBlazor = configuration.GetValue("UseBlazor", false); - return useBlazor ? Redirect("~/Admin/Home") : homeUrl.Equals("~/Home/Index", System.StringComparison.OrdinalIgnoreCase) ? (IActionResult)View(model) : Redirect(homeUrl); + return useBlazor ? Redirect("~/Pages") : homeUrl.Equals("~/Home/Index", System.StringComparison.OrdinalIgnoreCase) ? (IActionResult)View(model) : Redirect(homeUrl); } /// diff --git a/src/admin/Bootstrap.Admin/Extensions/AutoGenerateDatabaseExtensions.cs b/src/admin/Bootstrap.Admin/Extensions/AutoGenerateDatabaseExtensions.cs index baf0bf8f..7a5b3ca2 100644 --- a/src/admin/Bootstrap.Admin/Extensions/AutoGenerateDatabaseExtensions.cs +++ b/src/admin/Bootstrap.Admin/Extensions/AutoGenerateDatabaseExtensions.cs @@ -2,9 +2,9 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using System; using System.IO; using System.Linq; -using System; namespace Microsoft.AspNetCore.Builder { @@ -26,34 +26,40 @@ namespace Microsoft.AspNetCore.Builder { if (!_init) { - // 阻止所有线程继续往下运行,等待数据库检查 - lock (_locker) + // 优化性能 + var config = context.RequestServices.GetRequiredService(); + var autoGenerate = config.GetValue("AutoGenerateDatabase", false); + if (!autoGenerate) _init = true; + if (autoGenerate) { - if (!_init) + // 阻止所有线程继续往下运行,等待数据库检查 + lock (_locker) { - // 数据检查 - var config = context.RequestServices.GetRequiredService(); - var dbSection = config.GetSection("DB").GetChildren().FirstOrDefault(c => c.GetValue("Enabled", false)); - if (dbSection != null) + if (!_init) { - var folder = dbSection[SqlFolderKey]?.ReplaceOSPlatformPath(); - if (!string.IsNullOrEmpty(folder)) + // 数据检查 + var dbSection = config.GetSection("DB").GetChildren().FirstOrDefault(c => c.GetValue("Enabled", false)); + if (dbSection != null) { - // 判断文件夹是否存在 - var env = context.RequestServices.GetRequiredService(); - var fullFolder = Path.Combine(env.ContentRootPath, folder); - if (Directory.Exists(fullFolder)) + var folder = dbSection.GetValue(SqlFolderKey, "").ReplaceOSPlatformPath(); + if (!string.IsNullOrEmpty(folder)) { - try + // 判断文件夹是否存在 + var env = context.RequestServices.GetRequiredService(); + var fullFolder = Path.Combine(env.ContentRootPath, folder); + if (Directory.Exists(fullFolder)) { - AutoDbHelper.CheckDB(fullFolder); + try + { + AutoDbHelper.EnsureCreated(fullFolder); + } + catch { } } - catch { } } } } + _init = true; } - _init = true; } } await next(); diff --git a/src/admin/Bootstrap.Admin/Extensions/CloudLoggerExtensions.cs b/src/admin/Bootstrap.Admin/Extensions/CloudLoggerExtensions.cs new file mode 100644 index 00000000..2481f4dc --- /dev/null +++ b/src/admin/Bootstrap.Admin/Extensions/CloudLoggerExtensions.cs @@ -0,0 +1,88 @@ +using Longbow.Logging; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Configuration; +using Microsoft.Extensions.Options; +using System; +using System.Net.Http; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// 邮件日志扩展方法 + /// + public static class CloudLoggerExtensions + { + /// + /// 注册邮件日志方法 + /// + /// + /// + public static ILoggingBuilder AddCloudLogger(this ILoggingBuilder builder) + { + builder.Services.AddSingleton, LoggerProviderConfigureOptions>(); + builder.Services.AddSingleton, LoggerProviderOptionsChangeTokenSource>(); + builder.Services.AddSingleton(); + return builder; + } + } + + /// + /// 云日志提供类 + /// + [ProviderAlias("Cloud")] + public class CloudLoggerProvider : LoggerProvider + { + private readonly HttpClient httpClient; + private readonly IDisposable optionsReloadToken; + private CloudLoggerOption option; + + /// + /// 构造函数 + /// + public CloudLoggerProvider(IOptionsMonitor options) : base(null, new Func((name, logLevel) => logLevel >= LogLevel.Error)) + { + optionsReloadToken = options.OnChange(op => option = op); + option = options.CurrentValue; + + httpClient = new HttpClient + { + Timeout = TimeSpan.FromSeconds(10) + }; + httpClient.DefaultRequestHeaders.Connection.Add("keep-alive"); + + LogCallback = new Action(async message => + { + if (!string.IsNullOrEmpty(option.Url)) + { + try { await httpClient.PostAsJsonAsync(option.Url, message).ConfigureAwait(false); } + catch { } + } + }); + } + + /// + /// + /// + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + httpClient.Dispose(); + optionsReloadToken.Dispose(); + } + } + } + + /// + /// 云日志配置类 + /// + public class CloudLoggerOption + { + /// + /// 获得/设置 云日志地址 + /// + public string Url { get; set; } = ""; + } +} diff --git a/src/admin/Bootstrap.Admin/HealthChecks/DBHealthCheck.cs b/src/admin/Bootstrap.Admin/HealthChecks/DBHealthCheck.cs index 069a32e7..4878f013 100644 --- a/src/admin/Bootstrap.Admin/HealthChecks/DBHealthCheck.cs +++ b/src/admin/Bootstrap.Admin/HealthChecks/DBHealthCheck.cs @@ -18,7 +18,7 @@ namespace Bootstrap.Admin.HealthChecks { private readonly IConfiguration _configuration; private readonly IHttpContextAccessor _httpContextAccessor; - private static readonly Func ConnectionStringResolve = (c, name) => string.IsNullOrEmpty(name) + private static readonly Func ConnectionStringResolve = (c, name) => string.IsNullOrEmpty(name) ? c.GetSection("ConnectionStrings").GetChildren().FirstOrDefault()?.Value : c.GetConnectionString(name); @@ -42,13 +42,13 @@ namespace Bootstrap.Admin.HealthChecks public Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) { var db = _configuration.GetSection("DB").GetChildren() - .Select(config => new + .Select(config => new DbOption() { Enabled = bool.TryParse(config["Enabled"], out var en) ? en : false, ProviderName = config["ProviderName"], Widget = config["Widget"], ConnectionString = ConnectionStringResolve(config.GetSection("ConnectionStrings").Exists() ? config : _configuration, string.Empty) - }).FirstOrDefault(i => i.Enabled) ?? new + }).FirstOrDefault(i => i.Enabled) ?? new DbOption() { Enabled = true, ProviderName = Longbow.Data.DatabaseProviderType.SqlServer.ToString(), @@ -64,12 +64,11 @@ namespace Bootstrap.Admin.HealthChecks var roles = string.Empty; var displayName = string.Empty; var healths = false; - Exception error = null; + Exception? error = null; try { - DbContextManager.Exception = null; var user = UserHelper.RetrieveUserByUserName(userName); - displayName = user?.DisplayName; + displayName = user?.DisplayName ?? string.Empty; roles = string.Join(",", RoleHelper.RetrievesByUserName(userName) ?? new string[0]); menusCount = MenuHelper.RetrieveMenusByUserName(userName)?.Count() ?? 0; dictsCount = DictHelper.RetrieveDicts()?.Count() ?? 0; @@ -79,32 +78,41 @@ namespace Bootstrap.Admin.HealthChecks { error = ex; } - var data = new Dictionary() + var data = new Dictionary() { { "ConnectionString", db.ConnectionString }, { "Reference", DbContextManager.Create()?.GetType().Assembly.FullName ?? db.Widget }, { "DbType", db?.ProviderName }, { "Dicts", dictsCount }, - { "LoginName", loginUser }, + { "LoginName", userName }, { "DisplayName", displayName }, { "Roles", roles }, { "Navigations", menusCount } }; - if (string.IsNullOrEmpty(db.ConnectionString)) + if (string.IsNullOrEmpty(db?.ConnectionString)) { // 未启用连接字符串 data["ConnectionString"] = "未配置数据库连接字符串"; return Task.FromResult(HealthCheckResult.Unhealthy("Error", null, data)); } - if (error != null || DbContextManager.Exception != null) + if (DbContextManager.Exception != null) error = DbContextManager.Exception; + if (error != null) { - data.Add("Exception", (DbContextManager.Exception ?? error).Message); - return Task.FromResult(HealthCheckResult.Unhealthy("Error", error ?? DbContextManager.Exception, data)); + data.Add("Exception", error.Message); + return Task.FromResult(HealthCheckResult.Unhealthy("Error", error, data)); } return healths ? Task.FromResult(HealthCheckResult.Healthy("Ok", data)) : Task.FromResult(HealthCheckResult.Degraded("Failed", null, data)); } + + private class DbOption + { + public bool Enabled { get; set; } + public string? ProviderName { get; set; } + public string? Widget { get; set; } + public string? ConnectionString { get; set; } + } } } diff --git a/src/admin/Bootstrap.Admin/HealthChecks/GiteeHttpHealthCheck.cs b/src/admin/Bootstrap.Admin/HealthChecks/GiteeHttpHealthCheck.cs index 3aa807a5..21396fc0 100644 --- a/src/admin/Bootstrap.Admin/HealthChecks/GiteeHttpHealthCheck.cs +++ b/src/admin/Bootstrap.Admin/HealthChecks/GiteeHttpHealthCheck.cs @@ -41,7 +41,7 @@ namespace Bootstrap.Admin.HealthChecks Task.WaitAll(urls.Select(url => Task.Run(async () => { var sw = Stopwatch.StartNew(); - Exception error = null; + Exception? error = null; var result = await _client.HttpClient.GetAsJsonAsync($"/api/Gitee/{url}", ex => error = ex, cancellationToken); sw.Stop(); data.Add(url, error == null ? $"{result} Elapsed: {sw.Elapsed}" : $"{result} Elapsed: {sw.Elapsed} Exception: {error}"); diff --git a/src/admin/Bootstrap.Admin/Models/AdminModel.cs b/src/admin/Bootstrap.Admin/Models/AdminModel.cs index a5edae1f..a73ee8b3 100644 --- a/src/admin/Bootstrap.Admin/Models/AdminModel.cs +++ b/src/admin/Bootstrap.Admin/Models/AdminModel.cs @@ -12,7 +12,7 @@ namespace Bootstrap.Admin.Models /// 默认构造函数 /// /// - public AdminModel(string appId = null) + public AdminModel(string? appId = null) { if (string.IsNullOrEmpty(appId)) appId = BootstrapAppContext.AppId; diff --git a/src/admin/Bootstrap.Admin/Models/ErrorModel.cs b/src/admin/Bootstrap.Admin/Models/ErrorModel.cs index cff7c322..72a4f17b 100644 --- a/src/admin/Bootstrap.Admin/Models/ErrorModel.cs +++ b/src/admin/Bootstrap.Admin/Models/ErrorModel.cs @@ -13,28 +13,28 @@ /// /// /// - public string Title { get; set; } + public string Title { get; set; } = ""; /// /// /// - public string Content { get; set; } + public string Content { get; set; } = ""; /// /// /// - public string Image { get; set; } + public string Image { get; set; } = ""; /// /// /// - public string Detail { get; set; } + public string Detail { get; set; } = ""; /// /// /// - public string ReturnUrl { get; set; } + public string ReturnUrl { get; set; } = ""; /// /// diff --git a/src/admin/Bootstrap.Admin/Models/HeaderBarModel.cs b/src/admin/Bootstrap.Admin/Models/HeaderBarModel.cs index d3af6628..b3b4498a 100644 --- a/src/admin/Bootstrap.Admin/Models/HeaderBarModel.cs +++ b/src/admin/Bootstrap.Admin/Models/HeaderBarModel.cs @@ -13,7 +13,7 @@ namespace Bootstrap.Admin.Models /// 默认构造函数 /// /// - public HeaderBarModel(string userName) + public HeaderBarModel(string? userName) { var user = UserHelper.RetrieveUserByUserName(userName); if (user != null) @@ -42,31 +42,31 @@ namespace Bootstrap.Admin.Models /// /// 获得 当前用户登录名 /// - public string UserName { get; } + public string UserName { get; } = ""; /// /// 获得 当前用户显示名称 /// - public string DisplayName { get; } + public string DisplayName { get; } = ""; /// /// 获得 用户头像地址 /// - public string Icon { get; } + public string Icon { get; } = ""; /// /// 获取 个人网站样式 /// - public string Css { get; } + public string Css { get; } = ""; /// /// 获得 当前设置的默认应用 /// - public string AppId { get; } + public string AppId { get; } = ""; /// /// 获得 当前样式 /// - public string ActiveCss { get; } + public string ActiveCss { get; } = ""; } } diff --git a/src/admin/Bootstrap.Admin/Models/LockModel.cs b/src/admin/Bootstrap.Admin/Models/LockModel.cs index d33b1771..bb1e83c4 100644 --- a/src/admin/Bootstrap.Admin/Models/LockModel.cs +++ b/src/admin/Bootstrap.Admin/Models/LockModel.cs @@ -9,7 +9,7 @@ /// 构造函数 /// /// - public LockModel(string userName) : base(userName) + public LockModel(string? userName) : base(userName) { } @@ -17,11 +17,11 @@ /// /// 获得/设置 返回路径 /// - public string ReturnUrl { get; set; } + public string? ReturnUrl { get; set; } /// /// 获得/设置 认证方式 Cookie Mobile Gitee GitHub /// - public string AuthenticationType { get; set; } + public string? AuthenticationType { get; set; } } } diff --git a/src/admin/Bootstrap.Admin/Models/LoginModel.cs b/src/admin/Bootstrap.Admin/Models/LoginModel.cs index 1374f9c8..1a0fa1fa 100644 --- a/src/admin/Bootstrap.Admin/Models/LoginModel.cs +++ b/src/admin/Bootstrap.Admin/Models/LoginModel.cs @@ -11,7 +11,7 @@ namespace Bootstrap.Admin.Models /// 默认构造函数 /// /// - public LoginModel(string appId = null) : base(appId) + public LoginModel(string? appId = null) : base(appId) { ImageLibUrl = DictHelper.RetrieveImagesLibUrl(); } diff --git a/src/admin/Bootstrap.Admin/Models/NavigatorBarModel.cs b/src/admin/Bootstrap.Admin/Models/NavigatorBarModel.cs index 9ecc0611..9a859503 100644 --- a/src/admin/Bootstrap.Admin/Models/NavigatorBarModel.cs +++ b/src/admin/Bootstrap.Admin/Models/NavigatorBarModel.cs @@ -26,7 +26,7 @@ namespace Bootstrap.Admin.Models /// /// /// - public NavigatorBarModel(string userName, string activeUrl = "~/Admin/Index") : base(userName) + public NavigatorBarModel(string? userName, string activeUrl = "~/Admin/Index") : base(userName) { Navigations = MenuHelper.RetrieveSystemMenus(UserName, activeUrl); var authApps = AppHelper.RetrievesByUserName(userName); diff --git a/src/admin/Bootstrap.Admin/Models/ProfilesModel.cs b/src/admin/Bootstrap.Admin/Models/ProfilesModel.cs index e01cb5e2..4d47e6f4 100644 --- a/src/admin/Bootstrap.Admin/Models/ProfilesModel.cs +++ b/src/admin/Bootstrap.Admin/Models/ProfilesModel.cs @@ -18,7 +18,7 @@ namespace Bootstrap.Admin.Models /// /// 获得 头像文件名称 /// - public string FileName { get; } + public string FileName { get; } = ""; /// /// 获得 是否为第三方用户 diff --git a/src/admin/Bootstrap.Admin/Pages/Admin/Home.razor b/src/admin/Bootstrap.Admin/Pages/Admin/Home.razor index 2dd49493..e257c56b 100644 --- a/src/admin/Bootstrap.Admin/Pages/Admin/Home.razor +++ b/src/admin/Bootstrap.Admin/Pages/Admin/Home.razor @@ -1,4 +1,5 @@ -@page "/Admin/Home" +@page "/Pages/Admin/Index" +@page "/Pages" Home diff --git a/src/admin/Bootstrap.Admin/Pages/Admin/Roles.razor b/src/admin/Bootstrap.Admin/Pages/Admin/Roles.razor new file mode 100644 index 00000000..a85ab505 --- /dev/null +++ b/src/admin/Bootstrap.Admin/Pages/Admin/Roles.razor @@ -0,0 +1,6 @@ +@page "/Pages/Admin/Roles" +Roles + +@code { + +} diff --git a/src/admin/Bootstrap.Admin/Pages/Admin/Users.razor b/src/admin/Bootstrap.Admin/Pages/Admin/Users.razor new file mode 100644 index 00000000..ad7cacc6 --- /dev/null +++ b/src/admin/Bootstrap.Admin/Pages/Admin/Users.razor @@ -0,0 +1,6 @@ +@page "/Pages/Admin/Users" +Users + +@code { + +} diff --git a/src/admin/Bootstrap.Admin/Pages/UrlHelper.cs b/src/admin/Bootstrap.Admin/Pages/UrlHelper.cs new file mode 100644 index 00000000..36fbe642 --- /dev/null +++ b/src/admin/Bootstrap.Admin/Pages/UrlHelper.cs @@ -0,0 +1,22 @@ +namespace Bootstrap.Admin.Pages +{ + /// + /// Url 地址辅助操作类 + /// + public static class UrlHelper + { + /// + /// 转换为 Blazor 地址 + /// + /// + /// + public static string ToBlazorLink(this string url) => url.TrimStart('~'); + + /// + /// 转化为 Blazor 菜单地址 + /// + /// + /// + public static string ToBlazorMenuUrl(this string url) => url.Replace("~", "/Pages"); + } +} diff --git a/src/admin/Bootstrap.Admin/Pages/_Host.cshtml b/src/admin/Bootstrap.Admin/Pages/_Host.cshtml index fd5b1e37..d730135e 100644 --- a/src/admin/Bootstrap.Admin/Pages/_Host.cshtml +++ b/src/admin/Bootstrap.Admin/Pages/_Host.cshtml @@ -1,4 +1,4 @@ -@page "/" +@page "/Pages" @namespace Bootstrap.Admin.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/src/admin/Bootstrap.Admin/Query/QueryDictOption.cs b/src/admin/Bootstrap.Admin/Query/QueryDictOption.cs index e9977655..3fa9c3fb 100644 --- a/src/admin/Bootstrap.Admin/Query/QueryDictOption.cs +++ b/src/admin/Bootstrap.Admin/Query/QueryDictOption.cs @@ -13,15 +13,18 @@ namespace Bootstrap.Admin.Query /// /// 字典分项 /// - public string Category { get; set; } + public string? Category { get; set; } + /// /// 字典名称 /// - public string Name { get; set; } + public string? Name { get; set; } + /// /// 字典种类 /// - public string Define { get; set; } + public string? Define { get; set; } + /// /// 字典表查询 /// @@ -34,15 +37,15 @@ namespace Bootstrap.Admin.Query var data = DictHelper.RetrieveDicts(); if (!string.IsNullOrEmpty(Category)) { - data = data.Where(t => t.Category.Contains(Category)); + data = data.Where(t => t.Category?.Contains(Category) ?? false); } if (!string.IsNullOrEmpty(Name)) { - data = data.Where(t => t.Name.Contains(Name)); + data = data.Where(t => t.Name?.Contains(Name) ?? false); } if (!string.IsNullOrEmpty(Define)) { - data = data.Where(t => t.Define.ToString() == Define); + data = data.Where(t => t.Define.ToString() == (Define ?? "")); } var ret = new QueryData(); ret.total = data.Count(); diff --git a/src/admin/Bootstrap.Admin/Query/QueryExceptionOption.cs b/src/admin/Bootstrap.Admin/Query/QueryExceptionOption.cs index 60f768fb..47810e93 100644 --- a/src/admin/Bootstrap.Admin/Query/QueryExceptionOption.cs +++ b/src/admin/Bootstrap.Admin/Query/QueryExceptionOption.cs @@ -6,20 +6,22 @@ using System.Linq; namespace Bootstrap.Admin.Query { /// - /// + /// 程序异常查询条件类 /// public class QueryExceptionOption : PaginationOption { /// - /// + /// 获得/设置 开始时间 /// public DateTime? StartTime { get; set; } + /// - /// + /// 获得/设置 结束时间 /// public DateTime? EndTime { get; set; } + /// - /// + /// 查询方法 /// /// public QueryData Retrieves() diff --git a/src/admin/Bootstrap.Admin/Query/QueryGroupOption.cs b/src/admin/Bootstrap.Admin/Query/QueryGroupOption.cs index 69582f3b..5e975659 100644 --- a/src/admin/Bootstrap.Admin/Query/QueryGroupOption.cs +++ b/src/admin/Bootstrap.Admin/Query/QueryGroupOption.cs @@ -5,20 +5,22 @@ using System.Linq; namespace Bootstrap.Admin.Query { /// - /// + /// 部门查询条件类 /// public class QueryGroupOption : PaginationOption { /// - /// + /// 获得/设置 部门名称 /// - public string GroupName { get; set; } + public string? GroupName { get; set; } + /// - /// + /// 获得/设置 部门描述 /// - public string Description { get; set; } + public string? Description { get; set; } + /// - /// + /// 部门查询数据方法 /// /// public QueryData RetrieveData() @@ -27,11 +29,11 @@ namespace Bootstrap.Admin.Query var data = GroupHelper.Retrieves(); if (!string.IsNullOrEmpty(GroupName)) { - data = data.Where(t => t.GroupName.Contains(GroupName)); + data = data.Where(t => t.GroupName?.Contains(GroupName) ?? false); } if (!string.IsNullOrEmpty(Description)) { - data = data.Where(t => t.Description.Contains(Description)); + data = data.Where(t => t.Description?.Contains(Description) ?? false); } var ret = new QueryData(); ret.total = data.Count(); diff --git a/src/admin/Bootstrap.Admin/Query/QueryLogOption.cs b/src/admin/Bootstrap.Admin/Query/QueryLogOption.cs index a787eb2f..324e8746 100644 --- a/src/admin/Bootstrap.Admin/Query/QueryLogOption.cs +++ b/src/admin/Bootstrap.Admin/Query/QueryLogOption.cs @@ -5,27 +5,27 @@ using System; namespace Bootstrap.Admin.Query { /// - /// + /// 操作日志查询条件类 /// public class QueryLogOption : PaginationOption { /// - /// + /// 获得/设置 操作类型 /// - public string OperateType { get; set; } + public string? OperateType { get; set; } /// - /// + /// 获得/设置 开始时间 /// public DateTime? OperateTimeStart { get; set; } /// - /// + /// 获得/设置 结束时间 /// public DateTime? OperateTimeEnd { get; set; } /// - /// + /// 获得/设置 获取查询分页数据 /// /// public QueryData RetrieveData() @@ -37,4 +37,4 @@ namespace Bootstrap.Admin.Query return ret; } } -} \ No newline at end of file +} diff --git a/src/admin/Bootstrap.Admin/Query/QueryLoginOption.cs b/src/admin/Bootstrap.Admin/Query/QueryLoginOption.cs index 11be5093..aadc988e 100644 --- a/src/admin/Bootstrap.Admin/Query/QueryLoginOption.cs +++ b/src/admin/Bootstrap.Admin/Query/QueryLoginOption.cs @@ -22,7 +22,7 @@ namespace Bootstrap.Admin.Query /// /// 登录IP地址 /// - public string LoginIP { get; set; } + public string? LoginIP { get; set; } /// /// @@ -30,8 +30,6 @@ namespace Bootstrap.Admin.Query /// public QueryData RetrieveData() { - if (string.IsNullOrEmpty(Order)) Order = "desc"; - if (string.IsNullOrEmpty(Sort)) Sort = "LoginTime"; var data = LoginHelper.RetrievePages(this, StartTime, EndTime, LoginIP); return new QueryData { diff --git a/src/admin/Bootstrap.Admin/Query/QueryMenuOption.cs b/src/admin/Bootstrap.Admin/Query/QueryMenuOption.cs index 03a21ab2..9b21cd97 100644 --- a/src/admin/Bootstrap.Admin/Query/QueryMenuOption.cs +++ b/src/admin/Bootstrap.Admin/Query/QueryMenuOption.cs @@ -13,34 +13,34 @@ namespace Bootstrap.Admin.Query /// /// /// - public string Name { get; set; } + public string? Name { get; set; } /// /// /// - public string ParentName { get; set; } + public string? ParentName { get; set; } /// /// /// - public string Category { get; set; } + public string? Category { get; set; } /// /// /// - public string IsResource { get; set; } + public string? IsResource { get; set; } /// /// /// - public string AppId { get; set; } + public string? AppId { get; set; } /// /// /// /// /// - public QueryData RetrieveData(string userName) + public QueryData RetrieveData(string? userName) { var data = MenuHelper.RetrieveMenusByUserName(userName); if (!string.IsNullOrEmpty(ParentName)) diff --git a/src/admin/Bootstrap.Admin/Query/QueryRoleOption.cs b/src/admin/Bootstrap.Admin/Query/QueryRoleOption.cs index 036ac003..5fe73d05 100644 --- a/src/admin/Bootstrap.Admin/Query/QueryRoleOption.cs +++ b/src/admin/Bootstrap.Admin/Query/QueryRoleOption.cs @@ -5,20 +5,22 @@ using System.Linq; namespace Bootstrap.Admin.Query { /// - /// + /// 角色查询条件类 /// public class QueryRoleOption : PaginationOption { /// - /// + /// 角色名称 /// - public string RoleName { get; set; } + public string? RoleName { get; set; } + /// - /// + /// 角色描述 /// - public string Description { get; set; } + public string? Description { get; set; } + /// - /// + /// 角色数据 /// /// public QueryData RetrieveData() @@ -40,4 +42,4 @@ namespace Bootstrap.Admin.Query return ret; } } -} \ No newline at end of file +} diff --git a/src/admin/Bootstrap.Admin/Query/QuerySQLOption.cs b/src/admin/Bootstrap.Admin/Query/QuerySQLOption.cs index 8b6c7840..8d286d2c 100644 --- a/src/admin/Bootstrap.Admin/Query/QuerySQLOption.cs +++ b/src/admin/Bootstrap.Admin/Query/QuerySQLOption.cs @@ -12,7 +12,7 @@ namespace Bootstrap.Admin.Query /// /// 获得/设置 用户登录名 /// - public string UserName { get; set; } + public string? UserName { get; set; } /// /// 获得/设置 开始时间 @@ -30,7 +30,6 @@ namespace Bootstrap.Admin.Query /// public QueryData RetrieveData() { - if (string.IsNullOrEmpty(Order)) Order = "LogTime"; var data = LogHelper.RetrieveDBLogs(this, OperateTimeStart, OperateTimeEnd, UserName); var ret = new QueryData(); ret.total = data.TotalItems; diff --git a/src/admin/Bootstrap.Admin/Query/QueryTraceOptions.cs b/src/admin/Bootstrap.Admin/Query/QueryTraceOptions.cs index 37793641..a3e3cdcb 100644 --- a/src/admin/Bootstrap.Admin/Query/QueryTraceOptions.cs +++ b/src/admin/Bootstrap.Admin/Query/QueryTraceOptions.cs @@ -22,7 +22,7 @@ namespace Bootstrap.Admin.Query /// /// 请求IP地址 /// - public string AccessIP { get; set; } + public string? AccessIP { get; set; } /// /// diff --git a/src/admin/Bootstrap.Admin/Query/QueryUserOption.cs b/src/admin/Bootstrap.Admin/Query/QueryUserOption.cs index b4b6521f..8bcd8a98 100644 --- a/src/admin/Bootstrap.Admin/Query/QueryUserOption.cs +++ b/src/admin/Bootstrap.Admin/Query/QueryUserOption.cs @@ -5,20 +5,22 @@ using System.Linq; namespace Bootstrap.Admin.Query { /// - /// + /// 用户维护查询条件类 /// public class QueryUserOption : PaginationOption { /// - /// + /// 获得/设置 用户登录名称 /// - public string Name { get; set; } + public string? Name { get; set; } + /// - /// + /// 获得/设置 用户显示名称 /// - public string DisplayName { get; set; } + public string? DisplayName { get; set; } + /// - /// + /// 获取用户分页数据 /// /// public QueryData RetrieveData() @@ -67,4 +69,4 @@ namespace Bootstrap.Admin.Query return ret; } } -} \ No newline at end of file +} diff --git a/src/admin/Bootstrap.Admin/Shared/Footer.razor b/src/admin/Bootstrap.Admin/Shared/Footer.razor index 0ec7230f..d98f874a 100644 --- a/src/admin/Bootstrap.Admin/Shared/Footer.razor +++ b/src/admin/Bootstrap.Admin/Shared/Footer.razor @@ -1,16 +1,18 @@ -
Only visible while authentication is in progress.