Merge branch 'refs/heads/dev' into dev-blazor
# Conflicts: # src/admin/Bootstrap.DataAccess/Bootstrap.DataAccess.csproj
This commit is contained in:
commit
bda547f321
|
@ -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
|
||||
|
|
|
@ -7,9 +7,14 @@
|
|||
<LangVersion>latest</LangVersion>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)src\Keys\Longbow.Utility.snk</AssemblyOriginatorKeyFile>
|
||||
<DocumentationFile>$(MSBuildProjectName).xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Condition=" $(IsWebProject) == true Or $(IsTestProject) == true" Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Message Text="Copy lic file -> $(TargetDir)" Importance="high" />
|
||||
<Copy Condition="'$(OS)' == 'Windows_NT'" DestinationFolder="$(TargetDir)" SourceFiles="$(MSBuildThisFileDirectory)src\admin\keys\Longbow.lic" SkipUnchangedFiles="true" />
|
||||
<Copy Condition="'$(OS)' == 'UNIX'" DestinationFolder="$(TargetDir)" SourceFiles="$(MSBuildThisFileDirectory)src/admin/keys/Longbow.lic" SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
|
||||
<Target Condition=" $(IsWebProject) == true " Name="PostPublish" AfterTargets="Publish">
|
||||
<Message Text="Publish lic file -> $(PublishDir)" Importance="high" />
|
||||
<Copy Condition="'$(OS)' == 'Windows_NT'" DestinationFolder="$(PublishDir)" SourceFiles="$(MSBuildThisFileDirectory)src\admin\keys\Longbow.lic" SkipUnchangedFiles="true" />
|
||||
|
@ -19,11 +24,4 @@
|
|||
<Copy Condition="'$(OS)' == 'UNIX'" DestinationFolder="$(PublishDir)" SourceFiles="$(MSBuildThisFileDirectory)src/admin/Bootstrap.Admin/BootstrapAdmin.db" SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
|
||||
<Target Condition=" $(IsWebProject) == true " Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Message Text="Copy lic file -> $(TargetDir)" Importance="high" />
|
||||
<Copy Condition="'$(OS)' == 'Windows_NT'" DestinationFolder="$(TargetDir)" SourceFiles="$(MSBuildThisFileDirectory)src\admin\keys\Longbow.lic" SkipUnchangedFiles="true" />
|
||||
<Message Text="Copy db file -> $(TargetDir)" Importance="high" />
|
||||
<Copy Condition="'$(OS)' == 'UNIX'" DestinationFolder="$(TargetDir)" SourceFiles="$(MSBuildThisFileDirectory)src/admin/keys/Longbow.lic" SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<Project>
|
||||
|
||||
<Import Project="..\Directory.Build.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageProjectUrl>https://gitee.com/LongbowGroup/$(MsBuildProjectName)</PackageProjectUrl>
|
||||
<RepositoryUrl>https://gitee.com/LongbowGroup/$(MsBuildProjectName).git</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<Nullable>enable</Nullable>
|
||||
<DocumentationFile>$(MSBuildProjectName).xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -1,14 +1,6 @@
|
|||
<Router AppAssembly="@typeof(Program).Assembly">
|
||||
<Found Context="routeData">
|
||||
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
|
||||
<NotAuthorized>
|
||||
<NotAuthorizedHandler></NotAuthorizedHandler>
|
||||
</NotAuthorized>
|
||||
<Authorizing>
|
||||
<h1>Authentication in progress</h1>
|
||||
<p>Only visible while authentication is in progress.</p>
|
||||
</Authorizing>
|
||||
</AuthorizeRouteView>
|
||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
|
||||
</Found>
|
||||
<NotFound>
|
||||
<CascadingAuthenticationState>
|
||||
|
@ -17,4 +9,4 @@
|
|||
</LayoutView>
|
||||
</CascadingAuthenticationState>
|
||||
</NotFound>
|
||||
</Router>
|
||||
</Router>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Longbow.Logging" Version="3.0.2-beta1" />
|
||||
<PackageReference Include="Longbow.Logging" Version="3.0.3-beta1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="4.0.0" />
|
||||
<PackageReference Include="Sentry.AspNetCore" Version="2.0.0-beta6" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc4" />
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace Bootstrap.Admin.Controllers
|
|||
/// <param name="appId"></param>
|
||||
/// <returns></returns>
|
||||
[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();
|
||||
|
|
|
@ -8,7 +8,7 @@ using System.Linq;
|
|||
namespace Bootstrap.Admin.Controllers.Api
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 网站分析控制器
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
|
@ -16,11 +16,11 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
public class AnalyseController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 通过 logType 查询分析数据接口
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet()]
|
||||
public ActionResult<AnalyseData> Get([FromQuery]string logType = "")
|
||||
public ActionResult<AnalyseData> Get([FromQuery]string logType)
|
||||
{
|
||||
var ret = new AnalyseData();
|
||||
if (logType.Equals("LoginUsers", StringComparison.OrdinalIgnoreCase))
|
||||
|
@ -60,19 +60,19 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 分析数据实体类
|
||||
/// </summary>
|
||||
public class AnalyseData
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 折线数据集合
|
||||
/// </summary>
|
||||
public IEnumerable<string> Polylines { get; set; }
|
||||
public IEnumerable<string> Polylines { get; set; } = new string[0];
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得 数据集合
|
||||
/// </summary>
|
||||
public List<KeyValuePair<string, string>> Datas { get; set; } = new List<KeyValuePair<string, string>>();
|
||||
public List<KeyValuePair<string, string>> Datas { get; } = new List<KeyValuePair<string, string>>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ using System.Collections.Generic;
|
|||
namespace Bootstrap.Admin.Controllers.Api
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 应用程序控制器
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
|
@ -14,7 +14,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
public class AppsController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 通过角色ID获取其授权的所有应用程序集合
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
public class CategoryController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取字典表中所有Category数据
|
||||
/// 获取字典表中所有 Category 数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
|
@ -26,7 +26,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 获取所有菜单数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
|
@ -36,7 +36,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 获取所有父级菜单数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过指定菜单检查子菜单是否有子菜单
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{id}")]
|
||||
public bool ValidateMenuBySubMenu(string id)
|
||||
{
|
||||
return !MenuHelper.RetrieveAllMenus(User.Identity.Name).Where(m => m.ParentId == id).Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过指定菜单检查父级菜单是否为菜单类型 资源与按钮返回 false
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{id}")]
|
||||
public bool ValidateParentMenuById(string id)
|
||||
{
|
||||
return MenuHelper.RetrieveAllMenus(User.Identity.Name).FirstOrDefault(m => m.Id == id)?.IsResource == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ using System.Collections.Generic;
|
|||
namespace Bootstrap.Admin.Controllers.Api
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 字典表维护控制器
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
|
@ -18,7 +18,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
public class DictsController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 获取所有字典表数据方法
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
|
@ -28,7 +28,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
return value.RetrieveData();
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// 保存字典方法
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[HttpPost]
|
||||
|
@ -38,7 +38,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
return DictHelper.Save(value);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// 删除字典项方法
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[HttpDelete]
|
||||
|
|
|
@ -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("<h4><b>{0}</b></h4>", line);
|
||||
else if (line.StartsWith("TimeStamp:")) sb.AppendFormat("<div class='logTs'>{0}</div>", line);
|
||||
else if (line.EndsWith("Exception Information")) sb.AppendFormat("<div class='logExcep'>{0}</div>", line);
|
||||
else if (line.StartsWith("Message:")) sb.AppendFormat("<div class='logMsg'>{0}</div>", line);
|
||||
else if (line.StartsWith("ErrorSql:")) sb.AppendFormat("<div class='logSql'>{0}</div>", line);
|
||||
else if (line.StartsWith("Exception Type: Longbow.Data.DBAccessException")) sb.AppendFormat("<div class='logDbExcep'>{0}</div>", line);
|
||||
else if (line.StartsWith("StackTrace Information")) sb.AppendFormat("<b>{0}</b><br>", line);
|
||||
else sb.AppendFormat("{0}<br>", line);
|
||||
var line = reader.ReadLine()?.Replace("<", "<").Replace(">", ">");
|
||||
if (!string.IsNullOrEmpty(line))
|
||||
{
|
||||
if (line == "General Information ") sb.AppendFormat("<h4><b>{0}</b></h4>", line);
|
||||
else if (line.StartsWith("TimeStamp:")) sb.AppendFormat("<div class='logTs'>{0}</div>", line);
|
||||
else if (line.EndsWith("Exception Information")) sb.AppendFormat("<div class='logExcep'>{0}</div>", line);
|
||||
else if (line.StartsWith("Message:")) sb.AppendFormat("<div class='logMsg'>{0}</div>", line);
|
||||
else if (line.StartsWith("ErrorSql:")) sb.AppendFormat("<div class='logSql'>{0}</div>", line);
|
||||
else if (line.StartsWith("Exception Type: Longbow.Data.DBAccessException")) sb.AppendFormat("<div class='logDbExcep'>{0}</div>", line);
|
||||
else if (line.StartsWith("StackTrace Information")) sb.AppendFormat("<b>{0}</b><br>", line);
|
||||
else sb.AppendFormat("{0}<br>", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new JsonResult(sb.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 查询服务器端日志文件参数类
|
||||
/// </summary>
|
||||
public class ExceptionFileQuery
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 获取/设置 文件名称
|
||||
/// </summary>
|
||||
public string FileName { get; set; }
|
||||
public string FileName { get; set; } = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
/// <param name="color"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult> Issues([FromServices]GiteeHttpClient client, [FromQuery]string userName = "LongbowEnterprise", [FromQuery]string repoName = "BootstrapAdmin", [FromQuery]string label = "custom badge", [FromQuery]string color = "orange")
|
||||
public async Task<ActionResult> 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
|
|||
/// <param name="color"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult> Pulls([FromServices]GiteeHttpClient client, [FromQuery]string userName = "LongbowEnterprise", [FromQuery]string repoName = "BootstrapAdmin", [FromQuery]string label = "custom badge", [FromQuery]string color = "orange")
|
||||
public async Task<ActionResult> 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
|
|||
/// <param name="color"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult> Releases([FromServices]GiteeHttpClient client, [FromQuery]string userName = "LongbowEnterprise", [FromQuery]string repoName = "BootstrapAdmin", [FromQuery]string label = "custom badge", [FromQuery]string color = "orange")
|
||||
public async Task<ActionResult> 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
|
|||
/// <param name="color"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult> 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<ActionResult> 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<AppveyorBuildResult>($"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
|
|||
/// <summary>
|
||||
/// Appveyor 编译版本实例
|
||||
/// </summary>
|
||||
public Build Build { get; set; }
|
||||
public Build Build { get; set; } = new Build();
|
||||
}
|
||||
|
||||
private class Build
|
||||
|
@ -134,7 +134,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
/// <summary>
|
||||
/// Build 版本信息
|
||||
/// </summary>
|
||||
public string Version { get; set; }
|
||||
public string Version { get; set; } = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 部门维护控制器
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
|
@ -18,7 +17,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
public class GroupsController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 部门数据查询方法
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
|
@ -29,18 +28,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{id}")]
|
||||
public Group Get(string id)
|
||||
{
|
||||
return GroupHelper.Retrieves().FirstOrDefault(t => t.Id == id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 保存部门方法
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[HttpPost]
|
||||
|
@ -51,7 +39,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 删除部门方法
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[HttpDelete]
|
||||
|
@ -64,7 +52,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
/// <summary>
|
||||
/// 获取部门授权
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="id">用户ID或者角色ID</param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("{id}")]
|
||||
|
|
|
@ -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
|
|||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[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<BootstrapMenu> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送健康检查结果
|
||||
/// </summary>
|
||||
/// <param name="httpClient"></param>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<bool> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
[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
|
|||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpOptions]
|
||||
public string Options()
|
||||
public string? Options()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ using System.Linq;
|
|||
namespace Bootstrap.Admin.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 新用户注册控制器
|
||||
/// </summary>
|
||||
[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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Ip { get; set; }
|
||||
public string? Ip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -108,7 +108,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
|||
namespace Bootstrap.Admin.Controllers.Api
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 个人中心控制器
|
||||
/// </summary>
|
||||
[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
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 待删除文件集合类
|
||||
/// </summary>
|
||||
public class DeleteFileCollection
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 文件名称
|
||||
/// </summary>
|
||||
public string Key { get; set; }
|
||||
public string Key { get; set; } = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -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
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 个人中心操作方法 更改样式 更改显示名称 更改默认应用
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPut]
|
||||
|
|
|
@ -11,7 +11,7 @@ using System.Linq;
|
|||
namespace Bootstrap.Admin.Controllers.Api
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 角色维护控制器
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
|
@ -19,7 +19,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
public class RolesController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 获取所有角色数据
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
|
@ -37,7 +37,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
[HttpPost("{id}")]
|
||||
public IEnumerable<object> Post(string id, [FromQuery]string type)
|
||||
{
|
||||
IEnumerable<Role> ret = new List<Role>();
|
||||
IEnumerable<Role> 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 });
|
||||
}
|
||||
/// <summary>
|
||||
/// 保存角色
|
||||
/// 保存角色授权方法
|
||||
/// </summary>
|
||||
/// <param name="id">角色ID</param>
|
||||
/// <param name="values">选中的ID集合</param>
|
||||
|
@ -82,7 +82,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
return ret;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// 保存角色方法
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[HttpPost]
|
||||
|
@ -92,7 +92,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
return RoleHelper.Save(value);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// 删除角色方法
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[HttpDelete]
|
||||
|
|
|
@ -9,7 +9,7 @@ using System.Collections.Generic;
|
|||
namespace Bootstrap.Admin.Controllers.Api
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 网站设置控制器
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
|
@ -17,7 +17,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
public class SettingsController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 保存网站设置方法
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
|
@ -26,7 +26,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
public bool Post([FromBody]BootstrapDict value) => DictHelper.SaveSettings(value);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 获取网站缓存站点集合
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public IEnumerable<ICacheCorsItem> Get() => CacheManager.CorsSites;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 任务管理控制器
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
|
@ -15,7 +16,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
public class TasksController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 获取所有任务数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 任务相关操作
|
||||
/// </summary>
|
||||
/// <param name="scheName">调度名称</param>
|
||||
/// <param name="operType">操作方式 pause run</param>
|
||||
[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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ using System.Threading.Tasks;
|
|||
namespace Bootstrap.Admin.Controllers.Api
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 任务日志控制器
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
|
@ -25,9 +25,14 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
public ActionResult Get([FromQuery]string name, [FromServices]IHubContext<TaskLogHub> 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<TaskLogHub> hub)
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace Bootstrap.Admin.Controllers.Api
|
|||
[HttpPost("{id}")]
|
||||
public IEnumerable<object> Post(string id, [FromQuery]string type)
|
||||
{
|
||||
IEnumerable<object> ret = null;
|
||||
IEnumerable<object> 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
|
|||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpOptions]
|
||||
public string Options()
|
||||
public string? Options()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -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<IConfiguration>();
|
||||
var autoGenerate = config.GetValue("AutoGenerateDatabase", false);
|
||||
if (!autoGenerate) _init = true;
|
||||
if (autoGenerate)
|
||||
{
|
||||
if (!_init)
|
||||
// 阻止所有线程继续往下运行,等待数据库检查
|
||||
lock (_locker)
|
||||
{
|
||||
// 数据检查
|
||||
var config = context.RequestServices.GetRequiredService<IConfiguration>();
|
||||
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<IWebHostEnvironment>();
|
||||
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<IWebHostEnvironment>();
|
||||
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();
|
||||
|
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件日志扩展方法
|
||||
/// </summary>
|
||||
public static class CloudLoggerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册邮件日志方法
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static ILoggingBuilder AddCloudLogger(this ILoggingBuilder builder)
|
||||
{
|
||||
builder.Services.AddSingleton<IConfigureOptions<CloudLoggerOption>, LoggerProviderConfigureOptions<CloudLoggerOption, CloudLoggerProvider>>();
|
||||
builder.Services.AddSingleton<IOptionsChangeTokenSource<CloudLoggerOption>, LoggerProviderOptionsChangeTokenSource<CloudLoggerOption, CloudLoggerProvider>>();
|
||||
builder.Services.AddSingleton<ILoggerProvider, CloudLoggerProvider>();
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 云日志提供类
|
||||
/// </summary>
|
||||
[ProviderAlias("Cloud")]
|
||||
public class CloudLoggerProvider : LoggerProvider
|
||||
{
|
||||
private readonly HttpClient httpClient;
|
||||
private readonly IDisposable optionsReloadToken;
|
||||
private CloudLoggerOption option;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public CloudLoggerProvider(IOptionsMonitor<CloudLoggerOption> options) : base(null, new Func<string, LogLevel, bool>((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<string>(async message =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(option.Url))
|
||||
{
|
||||
try { await httpClient.PostAsJsonAsync(option.Url, message).ConfigureAwait(false); }
|
||||
catch { }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (disposing)
|
||||
{
|
||||
httpClient.Dispose();
|
||||
optionsReloadToken.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 云日志配置类
|
||||
/// </summary>
|
||||
public class CloudLoggerOption
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得/设置 云日志地址
|
||||
/// </summary>
|
||||
public string Url { get; set; } = "";
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace Bootstrap.Admin.HealthChecks
|
|||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private static readonly Func<IConfiguration, string, string> ConnectionStringResolve = (c, name) => string.IsNullOrEmpty(name)
|
||||
private static readonly Func<IConfiguration, string, string?> 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<HealthCheckResult> 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<string, object>()
|
||||
var data = new Dictionary<string, object?>()
|
||||
{
|
||||
{ "ConnectionString", db.ConnectionString },
|
||||
{ "Reference", DbContextManager.Create<Dict>()?.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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<object>($"/api/Gitee/{url}", ex => error = ex, cancellationToken);
|
||||
sw.Stop();
|
||||
data.Add(url, error == null ? $"{result} Elapsed: {sw.Elapsed}" : $"{result} Elapsed: {sw.Elapsed} Exception: {error}");
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace Bootstrap.Admin.Models
|
|||
/// 默认构造函数
|
||||
/// </summary>
|
||||
/// <param name="appId"></param>
|
||||
public AdminModel(string appId = null)
|
||||
public AdminModel(string? appId = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(appId)) appId = BootstrapAppContext.AppId;
|
||||
|
||||
|
|
|
@ -13,28 +13,28 @@
|
|||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
public string Title { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Content { get; set; }
|
||||
public string Content { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Image { get; set; }
|
||||
public string Image { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
public string Detail { get; set; }
|
||||
public string Detail { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string ReturnUrl { get; set; }
|
||||
public string ReturnUrl { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Bootstrap.Admin.Models
|
|||
/// 默认构造函数
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
public HeaderBarModel(string userName)
|
||||
public HeaderBarModel(string? userName)
|
||||
{
|
||||
var user = UserHelper.RetrieveUserByUserName(userName);
|
||||
if (user != null)
|
||||
|
@ -42,31 +42,31 @@ namespace Bootstrap.Admin.Models
|
|||
/// <summary>
|
||||
/// 获得 当前用户登录名
|
||||
/// </summary>
|
||||
public string UserName { get; }
|
||||
public string UserName { get; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 获得 当前用户显示名称
|
||||
/// </summary>
|
||||
public string DisplayName { get; }
|
||||
public string DisplayName { get; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 获得 用户头像地址
|
||||
/// </summary>
|
||||
public string Icon { get; }
|
||||
public string Icon { get; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 获取 个人网站样式
|
||||
/// </summary>
|
||||
public string Css { get; }
|
||||
public string Css { get; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 获得 当前设置的默认应用
|
||||
/// </summary>
|
||||
public string AppId { get; }
|
||||
public string AppId { get; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 获得 当前样式
|
||||
/// </summary>
|
||||
public string ActiveCss { get; }
|
||||
public string ActiveCss { get; } = "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
public LockModel(string userName) : base(userName)
|
||||
public LockModel(string? userName) : base(userName)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -17,11 +17,11 @@
|
|||
/// <summary>
|
||||
/// 获得/设置 返回路径
|
||||
/// </summary>
|
||||
public string ReturnUrl { get; set; }
|
||||
public string? ReturnUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 认证方式 Cookie Mobile Gitee GitHub
|
||||
/// </summary>
|
||||
public string AuthenticationType { get; set; }
|
||||
public string? AuthenticationType { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Bootstrap.Admin.Models
|
|||
/// 默认构造函数
|
||||
/// </summary>
|
||||
/// <param name="appId"></param>
|
||||
public LoginModel(string appId = null) : base(appId)
|
||||
public LoginModel(string? appId = null) : base(appId)
|
||||
{
|
||||
ImageLibUrl = DictHelper.RetrieveImagesLibUrl();
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace Bootstrap.Admin.Models
|
|||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <param name="activeUrl"></param>
|
||||
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);
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace Bootstrap.Admin.Models
|
|||
/// <summary>
|
||||
/// 获得 头像文件名称
|
||||
/// </summary>
|
||||
public string FileName { get; }
|
||||
public string FileName { get; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 获得 是否为第三方用户
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@page "/Admin/Home"
|
||||
@page "/Pages/Admin/Index"
|
||||
@page "/Pages"
|
||||
|
||||
<h3>Home</h3>
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
@page "/Pages/Admin/Roles"
|
||||
<h3>Roles</h3>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
@page "/Pages/Admin/Users"
|
||||
<h3>Users</h3>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
namespace Bootstrap.Admin.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// Url 地址辅助操作类
|
||||
/// </summary>
|
||||
public static class UrlHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 转换为 Blazor 地址
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToBlazorLink(this string url) => url.TrimStart('~');
|
||||
|
||||
/// <summary>
|
||||
/// 转化为 Blazor 菜单地址
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToBlazorMenuUrl(this string url) => url.Replace("~", "/Pages");
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
@page "/"
|
||||
@page "/Pages"
|
||||
@namespace Bootstrap.Admin.Pages
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
||||
|
|
|
@ -13,15 +13,18 @@ namespace Bootstrap.Admin.Query
|
|||
/// <summary>
|
||||
/// 字典分项
|
||||
/// </summary>
|
||||
public string Category { get; set; }
|
||||
public string? Category { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字典名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字典种类
|
||||
/// </summary>
|
||||
public string Define { get; set; }
|
||||
public string? Define { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字典表查询
|
||||
/// </summary>
|
||||
|
@ -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<BootstrapDict>();
|
||||
ret.total = data.Count();
|
||||
|
|
|
@ -6,20 +6,22 @@ using System.Linq;
|
|||
namespace Bootstrap.Admin.Query
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 程序异常查询条件类
|
||||
/// </summary>
|
||||
public class QueryExceptionOption : PaginationOption
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 开始时间
|
||||
/// </summary>
|
||||
public DateTime? StartTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 结束时间
|
||||
/// </summary>
|
||||
public DateTime? EndTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 查询方法
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public QueryData<object> Retrieves()
|
||||
|
|
|
@ -5,20 +5,22 @@ using System.Linq;
|
|||
namespace Bootstrap.Admin.Query
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 部门查询条件类
|
||||
/// </summary>
|
||||
public class QueryGroupOption : PaginationOption
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 部门名称
|
||||
/// </summary>
|
||||
public string GroupName { get; set; }
|
||||
public string? GroupName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 部门描述
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 部门查询数据方法
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public QueryData<object> 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<object>();
|
||||
ret.total = data.Count();
|
||||
|
|
|
@ -5,27 +5,27 @@ using System;
|
|||
namespace Bootstrap.Admin.Query
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 操作日志查询条件类
|
||||
/// </summary>
|
||||
public class QueryLogOption : PaginationOption
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 操作类型
|
||||
/// </summary>
|
||||
public string OperateType { get; set; }
|
||||
public string? OperateType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 开始时间
|
||||
/// </summary>
|
||||
public DateTime? OperateTimeStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 结束时间
|
||||
/// </summary>
|
||||
public DateTime? OperateTimeEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 获取查询分页数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public QueryData<Log> RetrieveData()
|
||||
|
@ -37,4 +37,4 @@ namespace Bootstrap.Admin.Query
|
|||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Bootstrap.Admin.Query
|
|||
/// <summary>
|
||||
/// 登录IP地址
|
||||
/// </summary>
|
||||
public string LoginIP { get; set; }
|
||||
public string? LoginIP { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -30,8 +30,6 @@ namespace Bootstrap.Admin.Query
|
|||
/// <returns></returns>
|
||||
public QueryData<LoginUser> RetrieveData()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Order)) Order = "desc";
|
||||
if (string.IsNullOrEmpty(Sort)) Sort = "LoginTime";
|
||||
var data = LoginHelper.RetrievePages(this, StartTime, EndTime, LoginIP);
|
||||
return new QueryData<LoginUser>
|
||||
{
|
||||
|
|
|
@ -13,34 +13,34 @@ namespace Bootstrap.Admin.Query
|
|||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string ParentName { get; set; }
|
||||
public string? ParentName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Category { get; set; }
|
||||
public string? Category { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string IsResource { get; set; }
|
||||
public string? IsResource { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string AppId { get; set; }
|
||||
public string? AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
public QueryData<object> RetrieveData(string userName)
|
||||
public QueryData<object> RetrieveData(string? userName)
|
||||
{
|
||||
var data = MenuHelper.RetrieveMenusByUserName(userName);
|
||||
if (!string.IsNullOrEmpty(ParentName))
|
||||
|
|
|
@ -5,20 +5,22 @@ using System.Linq;
|
|||
namespace Bootstrap.Admin.Query
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 角色查询条件类
|
||||
/// </summary>
|
||||
public class QueryRoleOption : PaginationOption
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 角色名称
|
||||
/// </summary>
|
||||
public string RoleName { get; set; }
|
||||
public string? RoleName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 角色描述
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 角色数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public QueryData<object> RetrieveData()
|
||||
|
@ -40,4 +42,4 @@ namespace Bootstrap.Admin.Query
|
|||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace Bootstrap.Admin.Query
|
|||
/// <summary>
|
||||
/// 获得/设置 用户登录名
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
public string? UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 开始时间
|
||||
|
@ -30,7 +30,6 @@ namespace Bootstrap.Admin.Query
|
|||
/// <returns></returns>
|
||||
public QueryData<DBLog> RetrieveData()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Order)) Order = "LogTime";
|
||||
var data = LogHelper.RetrieveDBLogs(this, OperateTimeStart, OperateTimeEnd, UserName);
|
||||
var ret = new QueryData<DBLog>();
|
||||
ret.total = data.TotalItems;
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Bootstrap.Admin.Query
|
|||
/// <summary>
|
||||
/// 请求IP地址
|
||||
/// </summary>
|
||||
public string AccessIP { get; set; }
|
||||
public string? AccessIP { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
|
|
@ -5,20 +5,22 @@ using System.Linq;
|
|||
namespace Bootstrap.Admin.Query
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 用户维护查询条件类
|
||||
/// </summary>
|
||||
public class QueryUserOption : PaginationOption
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 用户登录名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得/设置 用户显示名称
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; }
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 获取用户分页数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public QueryData<object> RetrieveData()
|
||||
|
@ -67,4 +69,4 @@ namespace Bootstrap.Admin.Query
|
|||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
<footer class="position-fixed">
|
||||
<div><span id="websiteFooter">@Model.Footer</span><span asp-condition="@Model.IsDemo">(演示系统)</span></div>
|
||||
@inject IConfiguration configuration
|
||||
|
||||
<footer class="position-fixed">
|
||||
<div><span id="websiteFooter">@Model?.Footer</span><span asp-condition="@Model?.IsDemo">(演示系统)</span></div>
|
||||
<a id="gotoTop" href="#" class="go-top" title="返回顶部" data-toggle="tooltip" data-placement="left">
|
||||
<i class="fa fa-angle-up"></i>
|
||||
</a>
|
||||
</footer>
|
||||
|
||||
@code {
|
||||
private AdminModel Model;
|
||||
private AdminModel? Model;
|
||||
|
||||
protected override Task OnInitializedAsync()
|
||||
{
|
||||
Model = new AdminModel();
|
||||
Model = new AdminModel(configuration.GetValue("AppId", "BA"));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
|
@ -5,10 +5,10 @@
|
|||
<div class="d-flex align-items-center">
|
||||
<a id="navbar" href="#" class="sidebar-toggle-box">
|
||||
<i class="fa fa-bars"></i>
|
||||
<span id="websiteTitle">@Model.Title</span>
|
||||
<span id="websiteTitle">@Model?.Title</span>
|
||||
</a>
|
||||
<div class="nav">
|
||||
@if (User.IsInRole("Administrators"))
|
||||
@if (User?.IsInRole("Administrators") ?? false)
|
||||
{
|
||||
<!-- tasks start -->
|
||||
<div class="dropdown">
|
||||
|
@ -20,7 +20,7 @@
|
|||
<div class="dropdown-arrow arrow-primary"></div>
|
||||
<div id="msgHeaderTaskContent" class="dropdown-header bg-primary">您有 <span id="msgHeaderTask">0</span> 个未完成的任务</div>
|
||||
<div class="dropdown-footer">
|
||||
<a href="~/Admin/Tasks">查看所有任务</a>
|
||||
<a href="/Pages/Admin/Tasks">查看所有任务</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -35,7 +35,7 @@
|
|||
<div class="dropdown-arrow arrow-info"></div>
|
||||
<div id="msgHeaderMsgContent" class="dropdown-header bg-info">您有 <span id="msgHeaderMsg">0</span> 个未读的消息</div>
|
||||
<div class="dropdown-footer">
|
||||
<a href="~/Admin/Messages">查看所有消息</a>
|
||||
<a href="/Pages/Admin/Messages">查看所有消息</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -65,7 +65,7 @@
|
|||
<div class="dropdown-arrow arrow-warning"></div>
|
||||
<div id="msgHeaderAppContent" class="dropdown-header bg-warning">您有 <span id="msgHeaderApp">0</span> 条程序异常通知</div>
|
||||
<div class="dropdown-footer">
|
||||
<a href="~/Admin/Exceptions">查看所有异常</a>
|
||||
<a href="/Pages/Admin/Exceptions">查看所有异常</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -80,13 +80,13 @@
|
|||
<div class="dropdown-arrow arrow-danger"></div>
|
||||
<div id="msgHeaderDbContent" class="dropdown-header bg-danger">您有 <span id="msgHeaderDb">0</span> 条数据库异常通知</div>
|
||||
<div class="dropdown-footer">
|
||||
<a href="~/Admin/Exceptions">查看所有异常</a>
|
||||
<a href="/Pages/Admin/Exceptions">查看所有异常</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- db dropdown end -->
|
||||
<div class="dropdown">
|
||||
<a class="shadow-success" href="~/Account/Lock" data-toggle="tooltip" title="系统锁屏">
|
||||
<a class="shadow-success" href="/Account/Lock" data-toggle="tooltip" title="系统锁屏">
|
||||
<i class="fa fa-tv"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -94,41 +94,41 @@
|
|||
</div>
|
||||
<div class="dropdown userinfo">
|
||||
<a data-toggle="dropdown" class="dropdown-toggle shadow-default" href="#">
|
||||
<img id="headerIcon" alt="" src="@Model.Icon" />
|
||||
<span id="userDisplayName" data-userName="@Model.UserName" class="username text-truncate d-inline-block">@Model.DisplayName</span>
|
||||
<img id="headerIcon" alt="" src="@Model?.Icon.ToBlazorLink()" />
|
||||
<span id="userDisplayName" data-userName="@Model?.UserName" class="username text-truncate d-inline-block">@Model?.DisplayName</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<div class="dropdown-item">
|
||||
<div class="d-flex flex-fill align-items-center">
|
||||
<img src="@Model.Icon">
|
||||
<img src="@Model?.Icon.ToBlazorLink()">
|
||||
<div class="flex-fill">
|
||||
<div class="username text-truncate">@Model.DisplayName</div>
|
||||
<div>登录名:@Model.UserName</div>
|
||||
<div class="username text-truncate">@Model?.DisplayName</div>
|
||||
<div>登录名:@Model?.UserName</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown-item">
|
||||
<a href="~/Admin/Profiles"><i class=" fa fa-suitcase"></i>个人中心</a>
|
||||
<a href="~/Admin/Index"><i class="fa fa-cog"></i>设置</a>
|
||||
<a href="~/Admin/Notifications"><i class="fa fa-bell"></i>通知<span id="logoutNoti" class="badge badge-pill badge-success"></span></a>
|
||||
<a href="/Pages/Admin/Profiles"><i class=" fa fa-suitcase"></i>个人中心</a>
|
||||
<a href="/Pages/Admin/Index"><i class="fa fa-cog"></i>设置</a>
|
||||
<a href="/Pages/Admin/Notifications"><i class="fa fa-bell"></i>通知<span id="logoutNoti" class="badge badge-pill badge-success"></span></a>
|
||||
</div>
|
||||
<div class="dropdown-item">
|
||||
<a href="~/Account/Logout"><i class="fa fa-key"></i>注销</a>
|
||||
<a href="/Account/Logout"><i class="fa fa-key"></i>注销</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="~/Admin/Index"><i class="fa fa-home"></i>首页</a></li>
|
||||
<li class="breadcrumb-item"><a href="/Pages"><i class="fa fa-home"></i>首页</a></li>
|
||||
<li class="breadcrumb-item d-none" id="breadNav"></li>
|
||||
</ol>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
@code {
|
||||
private HeaderBarModel Model;
|
||||
private ClaimsPrincipal User;
|
||||
private HeaderBarModel? Model;
|
||||
private ClaimsPrincipal? User;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
@inherits LayoutComponentBase
|
||||
@inject AuthenticationStateProvider authenticationStateProvider
|
||||
@inject NavigationManager navigationManager
|
||||
|
||||
<Header></Header>
|
||||
<div class="sidebar">
|
||||
<NavMenu />
|
||||
</div>
|
||||
<section id="main-content" class="main-content @Model.ShowCardTitle">
|
||||
<input id="lockScreenPeriod" type="hidden" asp-condition="@Model.EnableAutoLockScreen" value="@Model.LockScreenPeriod" />
|
||||
<section id="main-content" class="main-content @Model?.ShowCardTitle">
|
||||
<input id="lockScreenPeriod" type="hidden" asp-condition="@Model?.EnableAutoLockScreen" value="@Model?.LockScreenPeriod" />
|
||||
<div class="main-header">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="~/Admin/Index"><i class="fa fa-home"></i>首页</a></li>
|
||||
<li class="breadcrumb-item"><a href="/Pages"><i class="fa fa-home"></i>首页</a></li>
|
||||
<li class="breadcrumb-item d-none"></li>
|
||||
</ol>
|
||||
</div>
|
||||
|
@ -17,11 +19,18 @@
|
|||
<Footer></Footer>
|
||||
|
||||
@code {
|
||||
private AdminModel Model;
|
||||
private AdminModel? Model;
|
||||
|
||||
protected override Task OnInitializedAsync()
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
Model = new AdminModel();
|
||||
return Task.CompletedTask;
|
||||
var state = await authenticationStateProvider.GetAuthenticationStateAsync();
|
||||
if (!state.User.Identity.IsAuthenticated)
|
||||
{
|
||||
navigationManager.NavigateTo("/Account/Login?returnUrl=" + WebUtility.UrlEncode(new Uri(navigationManager.Uri).PathAndQuery));
|
||||
}
|
||||
else
|
||||
{
|
||||
Model = new AdminModel();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,27 +1,31 @@
|
|||
@inject AuthenticationStateProvider authenticationStateProvider
|
||||
@inject NavigationManager navigationManager
|
||||
|
||||
<aside class="@Model.ShowSideBar">
|
||||
<aside class="@Model?.ShowSideBar">
|
||||
<div class="bg"></div>
|
||||
<div class="nav-brand justify-content-center">
|
||||
<a href="#">
|
||||
<img src="@Model.WebSiteLogo" />
|
||||
<span>@Model.Title</span>
|
||||
<img src="@Model?.WebSiteLogo.ToBlazorLink()" />
|
||||
<span>@Model?.Title</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="nav-header flex-fill align-items-center">
|
||||
<a href="~/Admin/Profiles">
|
||||
<img src="@Model.Icon" />
|
||||
<span class="username d-inline-block text-truncate flex-fill">@Model.DisplayName</span>
|
||||
<a href="/Pages/Admin/Profiles">
|
||||
<img src="@Model?.Icon.ToBlazorLink()" />
|
||||
<span class="username d-inline-block text-truncate flex-fill">@Model?.DisplayName</span>
|
||||
</a>
|
||||
</div>
|
||||
<!-- sidebar menu start-->
|
||||
<div class="sidebar">
|
||||
<ul class="nav-sidebar nav nav-pills flex-column flex-nowrap">
|
||||
@foreach (var menu in Model.Navigations)
|
||||
@if (Model != null)
|
||||
{
|
||||
<li class="nav-item" id="@string.Format("menus_{0}",menu.Id)">
|
||||
<a href="@menu.Url" class="nav-link @menu.Active" target="@menu.Target"><i class="@menu.Icon"></i><span class="flex-fill">@menu.Name</span></a>
|
||||
</li>
|
||||
foreach (var menu in Model.Navigations)
|
||||
{
|
||||
<li class="nav-item" id="@string.Format("menus_{0}",menu.Id)">
|
||||
<a href="@menu.Url.ToBlazorMenuUrl()" class="nav-link @menu.Active" target="@menu.Target"><i class="@menu.Icon"></i><span class="flex-fill">@menu.Name</span></a>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -29,14 +33,11 @@
|
|||
</aside>
|
||||
|
||||
@code {
|
||||
private NavigatorBarModel Model;
|
||||
private NavigatorBarModel? Model;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var state = await authenticationStateProvider.GetAuthenticationStateAsync();
|
||||
if (state.User.Identity.IsAuthenticated)
|
||||
{
|
||||
Model = new NavigatorBarModel(state.User.Identity.Name);
|
||||
}
|
||||
Model = new NavigatorBarModel(state.User.Identity.Name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
@inject AuthenticationStateProvider authenticationStateProvider
|
||||
@inject NavigationManager navigationManager
|
||||
|
||||
@if (showNotAuthorizedMessage)
|
||||
{
|
||||
<section class="section" id="not-authorized-message">
|
||||
<div class="container">
|
||||
<div class="notification is-danger">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
|
||||
@code {
|
||||
|
||||
private bool showNotAuthorizedMessage = false;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var state = await authenticationStateProvider.GetAuthenticationStateAsync();
|
||||
|
||||
if (!state.User.Identity.IsAuthenticated)
|
||||
{
|
||||
// If the user is not authenticated redirect them to the sign in page
|
||||
navigationManager.NavigateTo("/Account/Login?returnUrl=" + System.Net.WebUtility.UrlEncode(new Uri(navigationManager.Uri).PathAndQuery));
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the user is signed in, but authorization failed, display a message
|
||||
showNotAuthorizedMessage = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ using Longbow.Web.SignalR;
|
|||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
@ -44,13 +43,7 @@ namespace Bootstrap.Admin
|
|||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All));
|
||||
services.Configure<CookiePolicyOptions>(options =>
|
||||
{
|
||||
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
|
||||
options.CheckConsentNeeded = context => true;
|
||||
options.MinimumSameSitePolicy = SameSiteMode.None;
|
||||
});
|
||||
services.AddLogging(logging => logging.AddFileLogger().AddDBLogger(ExceptionsHelper.Log));
|
||||
services.AddLogging(logging => logging.AddFileLogger().AddCloudLogger().AddDBLogger(ExceptionsHelper.Log));
|
||||
services.AddCors();
|
||||
services.AddResponseCompression();
|
||||
|
||||
|
|
|
@ -147,10 +147,11 @@
|
|||
<input type="text" class="form-control flex-sm-fill" id="url" placeholder="不可为空,4000字以内" maxlength="4000" data-valid="true" />
|
||||
</div>
|
||||
<div class="form-group col-sm-6">
|
||||
<label class="control-label" for="category">菜单类别</label>
|
||||
<select data-toggle="lgbSelect" class="d-none" data-default-val="1" id="category">
|
||||
<option value="0">系统菜单</option>
|
||||
<option value="1">外部菜单</option>
|
||||
<label class="control-label" for="isRes">菜单类型</label>
|
||||
<select data-toggle="lgbSelect" class="d-none menuChild" data-default-val="0" id="isRes" data-valid="true">
|
||||
<option value="0">菜单</option>
|
||||
<option value="1">资源</option>
|
||||
<option value="2">按钮</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-sm-6">
|
||||
|
@ -162,14 +163,6 @@
|
|||
<option value="_top">顶级窗口</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-sm-6">
|
||||
<label class="control-label" for="isRes">菜单类型</label>
|
||||
<select data-toggle="lgbSelect" class="d-none" data-default-val="0" id="isRes">
|
||||
<option value="0">菜单</option>
|
||||
<option value="1">资源</option>
|
||||
<option value="2">按钮</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-sm-6">
|
||||
<label class="control-label" for="app">所属应用</label>
|
||||
<select data-toggle="lgbSelect" class="d-none" data-default-val="@BootstrapAppContext.AppId" id="app">
|
||||
|
@ -179,6 +172,13 @@
|
|||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-sm-6">
|
||||
<label class="control-label" for="category">菜单类别</label>
|
||||
<select data-toggle="lgbSelect" class="d-none" disabled data-default-val="1" id="category">
|
||||
<option value="0">系统菜单</option>
|
||||
<option value="1">外部菜单</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -1,80 +1,86 @@
|
|||
@model TaskModel
|
||||
@{
|
||||
ViewBag.Title = "任务管理";
|
||||
Layout = "_Default";
|
||||
Layout = "_Admin";
|
||||
}
|
||||
@section css {
|
||||
<environment include="Development">
|
||||
<link href="~/lib/bootstrap-table/bootstrap-table.css" rel="stylesheet" />
|
||||
</environment>
|
||||
<environment exclude="Development">
|
||||
<link href="~/lib/bootstrap-table/bootstrap-table.min.css" rel="stylesheet" />
|
||||
</environment>
|
||||
<link href="~/lib/longbow-select/longbow-select.css" rel="stylesheet" />
|
||||
<link href="~/css/tasks.css" rel="stylesheet" asp-append-version="true" />
|
||||
}
|
||||
@section javascript {
|
||||
<environment include="Development">
|
||||
<script src="~/lib/bootstrap-table/bootstrap-table.js"></script>
|
||||
<script src="~/lib/bootstrap-table/extensions/export/bootstrap-table-export.js"></script>
|
||||
<script src="~/lib/bootstrap-table/locale/bootstrap-table-zh-CN.js"></script>
|
||||
<script src="~/lib/tablexport/tableExport.js"></script>
|
||||
<script src="~/lib/validate/jquery.validate.js"></script>
|
||||
<script src="~/lib/validate/localization/messages_zh.js"></script>
|
||||
</environment>
|
||||
<environment exclude="Development">
|
||||
<script src="~/lib/bootstrap-table/bootstrap-table.min.js"></script>
|
||||
<script src="~/lib/bootstrap-table/extensions/export/bootstrap-table-export.min.js"></script>
|
||||
<script src="~/lib/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
|
||||
<script src="~/lib/tablexport/tableExport.min.js"></script>
|
||||
<script src="~/lib/validate/jquery.validate.min.js"></script>
|
||||
<script src="~/lib/validate/localization/messages_zh.min.js"></script>
|
||||
</environment>
|
||||
<script src="~/lib/longbow-checkbox/longbow-checkbox.js"></script>
|
||||
<script src="~/lib/longbow-select/longbow-select.js"></script>
|
||||
<script src="~/lib/longbow/longbow.dataentity.js" asp-append-version="true"></script>
|
||||
<script src="~/lib/longbow/longbow.validate.js" asp-append-version="true"></script>
|
||||
<script src="~/js/tasks.js" asp-append-version="true"></script>
|
||||
}
|
||||
@section tableButtons {
|
||||
<button class='info btn btn-sm btn-info' asp-auth="info"><i class='fa fa-info'></i><span>日志</span></button>
|
||||
}
|
||||
@section cardbody {
|
||||
<div class="alert alert-danger" role="alert" asp-condition="@Model.IsDemo">
|
||||
<span>演示系统禁止修改定时后台任务</span>
|
||||
</div>
|
||||
}
|
||||
@section query {
|
||||
<div class="alert alert-info">
|
||||
<p class="font-weight-bold">后台任务说明:</p>
|
||||
<p>1. 默认任务 (立即执行,仅执行一次)</p>
|
||||
<p>
|
||||
<code>
|
||||
TaskServicesManager.GetOrAdd("简单任务", token => Task.Delay(1000));
|
||||
</code>
|
||||
</p>
|
||||
<p>2. 周期性任务 (1 分钟后间隔 5 秒执行 2 次任务)</p>
|
||||
<p>
|
||||
<code>
|
||||
var trigger = TriggerBuilder.Default.WithInterval(TimeSpan.FromSeconds(5)).WithRepeatCount(2).WithStartTime(DateTimeOffset.Now.AddMinutes(1)).Build();
|
||||
<br />
|
||||
TaskServicesManager.GetOrAdd("测试任务", token => Task.Delay(1000), trigger);
|
||||
</code>
|
||||
</p>
|
||||
<p>3. Cron 表达式任务 (间隔 5 秒循环执行任务)</p>
|
||||
<p>
|
||||
<code>
|
||||
TaskServicesManager.GetOrAdd("Cron 表达式任务", token => Task.Delay(1000), TriggerBuilder.Build("*/5 * * * * *"));
|
||||
</code>
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
@section modal {
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="myModalLabel">任务编辑窗口</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-inline">
|
||||
<div class="row">
|
||||
<input type="hidden" id="taskID" />
|
||||
<div class="form-group col-12">
|
||||
<label class="control-label" for="taskName">任务名称</label>
|
||||
<input type="text" class="form-control flex-sm-fill" id="taskName" placeholder="不可为空,50字以内" maxlength="50" data-valid="true" />
|
||||
<div class="modal fade" id="dialogNew" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
|
||||
<div class="modal-content" data-toggle="LgbValidate" data-valid-button="#btnSubmit" data-valid-modal="#dialogNew">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="myModalLabel">任务编辑窗口</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
</div>
|
||||
<div class="form-group col-12">
|
||||
<label class="control-label" for="taskCron">Cron表达式</label>
|
||||
<input type="text" class="form-control flex-sm-fill" id="taskCron" placeholder="不可为空,2000字以内" maxlength="2000" data-valid="true" />
|
||||
<div class="modal-body">
|
||||
<form class="form-inline">
|
||||
<div class="row">
|
||||
<input type="hidden" id="taskID" />
|
||||
<div class="form-group col-12">
|
||||
<label class="control-label" for="taskName">任务名称</label>
|
||||
<input type="text" class="form-control flex-sm-fill" id="taskName" placeholder="不可为空,50字以内" maxlength="50" data-valid="true" />
|
||||
</div>
|
||||
<div class="form-group col-12">
|
||||
<label class="control-label" for="taskCron">Cron表达式</label>
|
||||
<input type="text" class="form-control flex-sm-fill" id="taskCron" placeholder="不可为空,2000字以内" maxlength="2000" data-valid="true" />
|
||||
</div>
|
||||
<div class="form-group col-12">
|
||||
<label class="control-label" for="taskContent">内置任务</label>
|
||||
<select id="taskList" data-toggle="lgbSelect">
|
||||
@foreach (var name in Model.Tasks)
|
||||
{
|
||||
<option value="@name">@name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="form-group col-12">
|
||||
<label class="control-label" for="taskContent">内置任务</label>
|
||||
<select id="taskList" data-toggle="lgbSelect">
|
||||
@foreach (var name in Model.Tasks)
|
||||
{
|
||||
<option value="@name">@name</option>
|
||||
}
|
||||
</select>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">
|
||||
<i class="fa fa-times"></i>
|
||||
<span>关闭</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" id="btnSubmit">
|
||||
<i class="fa fa-save"></i>
|
||||
<span>保存</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@section customModal {
|
||||
<div class="modal fade" id="dialogLog" tabindex="-1" role="dialog" data-backdrop="static" aria-labelledby="taskModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
|
@ -97,4 +103,50 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
<div class="card">
|
||||
<div class="card-header">任务介绍</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-info">
|
||||
<p class="font-weight-bold">后台任务说明:</p>
|
||||
<p>1. 默认任务 (立即执行,仅执行一次)</p>
|
||||
<p>
|
||||
<code>
|
||||
TaskServicesManager.GetOrAdd("简单任务", token => Task.Delay(1000));
|
||||
</code>
|
||||
</p>
|
||||
<p>2. 周期性任务 (1 分钟后间隔 5 秒执行 2 次任务)</p>
|
||||
<p>
|
||||
<code>
|
||||
var trigger = TriggerBuilder.Default.WithInterval(TimeSpan.FromSeconds(5)).WithRepeatCount(2).WithStartTime(DateTimeOffset.Now.AddMinutes(1)).Build();
|
||||
<br />
|
||||
TaskServicesManager.GetOrAdd("测试任务", token => Task.Delay(1000), trigger);
|
||||
</code>
|
||||
</p>
|
||||
<p>3. Cron 表达式任务 (间隔 5 秒循环执行任务)</p>
|
||||
<div>
|
||||
<code>
|
||||
TaskServicesManager.GetOrAdd("Cron 表达式任务", token => Task.Delay(1000), TriggerBuilder.Build("*/5 * * * * *"));
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
查询结果
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-danger" role="alert" asp-condition="@Model.IsDemo">
|
||||
<span>演示系统禁止修改定时后台任务</span>
|
||||
</div>
|
||||
<table></table>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tableButtons" class="d-none">
|
||||
<div class='btn-group'>
|
||||
<button class='pause btn btn-sm btn-danger' asp-auth="pause"><i class='fa fa-pause-circle'></i><span>暂停</span></button>
|
||||
<button class='run btn btn-sm btn-success' asp-auth="pause"><i class='fa fa-play-circle'></i><span>运行</span></button>
|
||||
<button class='info btn btn-sm btn-info' asp-auth="info"><i class='fa fa-info-circle'></i><span>日志</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@using System.Net.Http
|
||||
@using System.Net
|
||||
@using System.Net.Http
|
||||
@using System.Security.Claims
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
|
@ -6,7 +7,9 @@
|
|||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.AspNetCore.Mvc
|
||||
@using Microsoft.Extensions.Configuration
|
||||
@using Microsoft.JSInterop
|
||||
@using Bootstrap.Admin
|
||||
@using Bootstrap.Admin.Shared
|
||||
@using Bootstrap.Admin.Models
|
||||
@using Bootstrap.Admin.Pages
|
||||
@using Bootstrap.Admin.Shared
|
||||
|
|
|
@ -13,8 +13,15 @@
|
|||
},
|
||||
"FileName": "Error\\Log.log",
|
||||
"MaxFileCount": 1
|
||||
},
|
||||
"Cloud": {
|
||||
"LogLevel": {
|
||||
"Default": "Error"
|
||||
},
|
||||
"Url": "https://client.sdgxgz.com/api/Interface/Log"
|
||||
}
|
||||
},
|
||||
"AutoGenerateDatabase": true,
|
||||
"DB": [
|
||||
{
|
||||
"Enabled": false,
|
||||
|
@ -60,6 +67,7 @@
|
|||
"UseBlazor": true,
|
||||
"SwaggerPathBase": "",
|
||||
"AllowOrigins": "http://localhost:49185",
|
||||
"HealthsCloudUrl": "https://client.sdgxgz.com/api/Interface/Healths",
|
||||
"FileStorageOptions": {
|
||||
"Enabled": true,
|
||||
"Folder": "TaskStorage",
|
||||
|
|
|
@ -10,11 +10,18 @@
|
|||
"Default": "Error"
|
||||
},
|
||||
"FileName": "Error\\Log.log"
|
||||
},
|
||||
"Cloud": {
|
||||
"LogLevel": {
|
||||
"Default": "Error"
|
||||
},
|
||||
"Url": "https://client.sdgxgz.com/api/Interface/Log"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"ba": "Data Source=.;Initial Catalog=BootstrapAdmin;User ID=sa;Password=sa"
|
||||
},
|
||||
"AutoGenerateDatabase": false,
|
||||
"DB": [
|
||||
{
|
||||
"Enabled": false,
|
||||
|
@ -54,8 +61,10 @@
|
|||
}
|
||||
],
|
||||
"AppId": "BA",
|
||||
"UseBlazor": true,
|
||||
"SwaggerPathBase": "",
|
||||
"AllowOrigins": "http://localhost,http://ba.sdgxgz.cn",
|
||||
"HealthsCloudUrl": "https://client.sdgxgz.com/api/Interface/Healths",
|
||||
"GiteeHealthChecks": false,
|
||||
"Sentry": {
|
||||
"Dsn": "https://70bdfff562e84fa7b9a43d65924ab9ad@sentry.io/1469396"
|
||||
|
|
|
@ -353,6 +353,10 @@ body.trans-mute * {
|
|||
right: 45px;
|
||||
}
|
||||
|
||||
li.is-disabled .dd3-content {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.dd3-content .menuType {
|
||||
display: none;
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
(function ($) {
|
||||
$.extend({
|
||||
sendHealths: function (data) {
|
||||
$.bc({ url: 'api/Interface/Healths', data: JSON.stringify(data), method: 'post' });
|
||||
}
|
||||
});
|
||||
$.fn.extend({
|
||||
autoScrollSidebar: function (options) {
|
||||
var option = $.extend({ target: null, offsetTop: 0 }, options);
|
||||
|
@ -75,7 +80,7 @@
|
|||
var resultFormat = {
|
||||
"Success": '<span class="badge badge-pill badge-success badge-task"><i class="fa fa-check-circle"></i><span>成功</span></span>',
|
||||
"Timeout": '<span class="badge badge-pill badge-warning badge-task"><i class="fa fa-exclamation-circle"></i><span>超时</span></span>'
|
||||
}
|
||||
};
|
||||
var htmlUserTemplate = '<a class="dropdown-item position-relative" href="{0}"><span class="label label-primary"><i class="fa fa-thumb-tack"></i></span><div class="content">{1}</div><div class="small italic content-task">{2}</div>{3}</a>';
|
||||
var html = result.Tasks.map(function (u) {
|
||||
return $.format(htmlUserTemplate, $.formatUrl('Admin/Tasks'), u.Name, u.LastRuntime, resultFormat[u.LastRunResult]);
|
||||
|
@ -131,10 +136,10 @@
|
|||
var html = "";
|
||||
$.each(menus, function (index, menu) {
|
||||
if (menu.Menus.length === 0) {
|
||||
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{4}" data-category="{3}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{5}</span><span class="menuOrder">{4}</span></div></li>', menu.Id, menu.Icon, menu.Name, menu.Category, menu.Order, formatCategoryName(menu));
|
||||
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{4}" data-category="{3}" data-resource="{6}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{5}</span><span class="menuOrder">{4}</span></div></li>', menu.Id, menu.Icon, menu.Name, menu.Category, menu.Order, formatCategoryName(menu), menu.IsResource);
|
||||
}
|
||||
else {
|
||||
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{5}" data-category="{3}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{6}</span><span class="menuOrder">{5}</span></div><ol class="dd-list">{4}</ol></li>', menu.Id, menu.Icon, menu.Name, menu.Category, cascadeSubMenu(menu.Menus), menu.Order, formatCategoryName(menu));
|
||||
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{5}" data-category="{3}" data-resource="{7}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{6}</span><span class="menuOrder">{5}</span></div><ol class="dd-list">{4}</ol></li>', menu.Id, menu.Icon, menu.Name, menu.Category, cascadeSubMenu(menu.Menus), menu.Order, formatCategoryName(menu), menu.IsResource);
|
||||
}
|
||||
});
|
||||
return html;
|
||||
|
@ -144,10 +149,10 @@
|
|||
var html = "";
|
||||
$.each(menus, function (index, menu) {
|
||||
if (menu.Menus.length === 0) {
|
||||
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{4}" data-category="{3}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{5}</span><span class="menuOrder">{4}</span></div></li>', menu.Id, menu.Icon, menu.Name, menu.Category, menu.Order, formatCategoryName(menu));
|
||||
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{4}" data-category="{3}" data-resource="{6}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{5}</span><span class="menuOrder">{4}</span></div></li>', menu.Id, menu.Icon, menu.Name, menu.Category, menu.Order, formatCategoryName(menu), menu.IsResource);
|
||||
}
|
||||
else {
|
||||
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{5}" data-category="{3}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{6}</span><span class="menuOrder">{5}</span></div><ol class="dd-list">{4}</ol></li>', menu.Id, menu.Icon, menu.Name, menu.Category, cascadeSubMenu(menu.Menus), menu.Order, formatCategoryName(menu));
|
||||
html += $.format('<li class="dd-item dd3-item" data-id="{0}" data-order="{5}" data-category="{3}" data-resource="{7}"><div class="dd-handle dd3-handle"></div><div class="dd3-content"><div class="checkbox"><label><input type="checkbox" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><div class="radio"><label><input type="radio" name="menu" value="{0}"><span><i class="{1}"></i>{2}</span></label></div><span class="menuType">{6}</span><span class="menuOrder">{5}</span></div><ol class="dd-list">{4}</ol></li>', menu.Id, menu.Icon, menu.Name, menu.Category, cascadeSubMenu(menu.Menus), menu.Order, formatCategoryName(menu), menu.IsResource);
|
||||
}
|
||||
});
|
||||
return html;
|
||||
|
|
|
@ -49,6 +49,8 @@
|
|||
$.bc({
|
||||
url: 'healths',
|
||||
callback: function (result) {
|
||||
// async send result to cloud
|
||||
$.sendHealths(result);
|
||||
var data = $.map(result.Keys, function (name) {
|
||||
return { Name: name, Duration: result.Report.Entries[name].Duration, Status: result.Report.Entries[name].Status, Exception: result.Report.Entries[name].Exception, Description: result.Report.Entries[name].Description, Data: result.Report.Entries[name].Data };
|
||||
});
|
||||
|
|
|
@ -217,6 +217,7 @@ $(function () {
|
|||
$btnSubmitMenu.data('type', 'parent');
|
||||
$nestMenuInput.find('label:last').find('input').show();
|
||||
$nestMenu.find('li.dd-item').hide().remove('[data-id="0"]');
|
||||
$nestMenu.find('li[data-resource!="0"]').addClass('is-disabled').find(':radio').prop('disabled', true)
|
||||
$nestMenu.find('li[data-category="' + $category.val() + '"]').show();
|
||||
showDialog();
|
||||
});
|
||||
|
@ -240,8 +241,16 @@ $(function () {
|
|||
var type = $(this).data('type');
|
||||
switch (type) {
|
||||
case "parent":
|
||||
$parentMenuID.val($('.dd3-content :radio:checked').val());
|
||||
$parentMenuName.val($('.dd3-content :radio:checked').next('span').text());
|
||||
// 父级菜单不可以是资源或者按钮类型
|
||||
var pId = $('.dd3-content :radio:checked').val();
|
||||
var check = $.remoteValidate('api/Category/ValidateParentMenuById/' + pId);
|
||||
if (check) {
|
||||
$parentMenuID.val(pId);
|
||||
$parentMenuName.val($('.dd3-content :radio:checked').next('span').text());
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case "order":
|
||||
var data = $nestMenu.find('li:visible');
|
||||
|
@ -333,4 +342,19 @@ $(function () {
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 所属应用更新是联动菜单类别
|
||||
var $app = $('#app').on('changed.lgbSelect', function (e) {
|
||||
var defaultVal = $app.attr('data-default-val');
|
||||
var val = defaultVal === $app.val() ? '0' : '1';
|
||||
$category.lgbSelect('val', val);
|
||||
})
|
||||
|
||||
if ($.isFunction($.validator)) {
|
||||
$.validator.addMethod("menuChild", function (value, element) {
|
||||
var id = $("#menuID").val();
|
||||
var check = id === "" || value === "菜单" || $.remoteValidate('api/Category/ValidateMenuBySubMenu/' + id);
|
||||
return check;
|
||||
}, "拥有子菜单时菜单类型不可更改为资源或者按钮");
|
||||
}
|
||||
});
|
|
@ -11,7 +11,7 @@
|
|||
content = $.format(template, 'success', 'play-circle', '运行中');
|
||||
}
|
||||
else if (value === "Disabled") {
|
||||
content = $.format(template, 'danger', 'times-circle', '已禁用');
|
||||
content = $.format(template, 'danger', 'times-circle', '已停止');
|
||||
}
|
||||
return content;
|
||||
};
|
||||
|
@ -33,7 +33,7 @@
|
|||
return content;
|
||||
};
|
||||
|
||||
$('.card-body table').lgbTable({
|
||||
var $task = $('.card-body table').lgbTable({
|
||||
url: Tasks.url,
|
||||
dataBinder: {
|
||||
map: {
|
||||
|
@ -43,8 +43,8 @@
|
|||
},
|
||||
smartTable: {
|
||||
sidePagination: "client",
|
||||
sortName: 'CreateTime',
|
||||
sortOrder: 'desc',
|
||||
sortName: 'Name',
|
||||
sortOrder: 'asc',
|
||||
queryParams: function (params) { return $.extend(params, { operateType: $("#txt_operate_type").val(), OperateTimeStart: $("#txt_operate_start").val(), OperateTimeEnd: $("#txt_operate_end").val() }); },
|
||||
columns: [
|
||||
{ title: "名称", field: "Name", sortable: true },
|
||||
|
@ -95,6 +95,22 @@
|
|||
console.log(error);
|
||||
}
|
||||
});
|
||||
},
|
||||
'click .pause': function (e, value, row, index) {
|
||||
$.bc({
|
||||
url: 'api/Tasks/' + row.Name + "?operType=" + "pause", method: 'put',
|
||||
callback: function (result) {
|
||||
if (result) $task.bootstrapTable('refresh');
|
||||
}
|
||||
});
|
||||
},
|
||||
'click .run': function (e, value, row, index) {
|
||||
$.bc({
|
||||
url: 'api/Tasks/' + row.Name + "?operType=" + "run", method: 'put',
|
||||
callback: function (result) {
|
||||
if (result) $task.bootstrapTable('refresh');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,10 @@
|
|||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.form-select.is-disabled .form-select-append {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.form-select-input {
|
||||
color: #606266;
|
||||
outline: none;
|
||||
|
|
|
@ -114,11 +114,17 @@
|
|||
|
||||
// save attributes
|
||||
var attrs = [];
|
||||
["id", "data-default-val"].forEach(function (v, index) {
|
||||
["id", "name", "class", "data-valid", "data-default-val"].forEach(function (v, index) {
|
||||
var value = that.$element.attr(v);
|
||||
if (value !== undefined) attrs.push({ name: v, value: value });
|
||||
});
|
||||
|
||||
var disabled = this.$element.prop('disabled');
|
||||
// set disabled property
|
||||
if (disabled) {
|
||||
this.disabled();
|
||||
}
|
||||
|
||||
// replace element select -> input hidden
|
||||
this.$element.remove();
|
||||
this.$element = $('<input type="hidden" data-toggle="lgbSelect" />').val(that.val()).insertBefore(this.$input);
|
||||
|
@ -139,12 +145,15 @@
|
|||
this.$input.removeAttr('disabled');
|
||||
};
|
||||
|
||||
_proto.reset = function (value) {
|
||||
_proto.reset = function (value, init) {
|
||||
var that = this;
|
||||
|
||||
// keep old value
|
||||
var oldValue = this.$input.attr('value');
|
||||
|
||||
// default select value
|
||||
if (init == undefined) init = true;
|
||||
|
||||
// warning: must use attr('value') method instead of val(). otherwise the others input html element will filled by first element value.
|
||||
// see https://gitee.com/LongbowEnterprise/longbow-select/issues/IZ3BR?from=project-issue
|
||||
this.$input.attr('value', '').removeClass('is-valid is-invalid');
|
||||
|
@ -153,10 +162,12 @@
|
|||
$.each(value, function (index) {
|
||||
var $item = $('<a class="dropdown-item" href="#" data-val="' + this.value + '">' + this.text + '</a>');
|
||||
that.$menus.append($item);
|
||||
if (this.selected === true || this.value === oldValue || index === 0 || this.value === that.$element.attr('data-default-val')) {
|
||||
that.$input.attr('value', this.text);
|
||||
that.$element.val(this.value).attr('data-text', this.text);
|
||||
$activeItem = $item;
|
||||
if (init) {
|
||||
if (this.selected === true || this.value === oldValue || index === 0 || this.value === that.$element.attr('data-default-val')) {
|
||||
that.$input.attr('value', this.text);
|
||||
that.$element.val(this.value).attr('data-text', this.text);
|
||||
$activeItem = $item;
|
||||
}
|
||||
}
|
||||
});
|
||||
if ($activeItem !== null) $activeItem.addClass('active');
|
||||
|
|
|
@ -125,6 +125,19 @@
|
|||
document.webkitIsFullScreen || window.fullscreen ||
|
||||
false;
|
||||
},
|
||||
remoteValidate: function (url, method) {
|
||||
if (method === undefined) method = 'get';
|
||||
var check = false;
|
||||
jQuery[method]({
|
||||
url: $.formatUrl(url),
|
||||
async: false,
|
||||
cache: false,
|
||||
success: function (result) {
|
||||
check = result
|
||||
}
|
||||
});
|
||||
return check;
|
||||
},
|
||||
bc: function (options) {
|
||||
options = $.extend({
|
||||
id: "",
|
||||
|
|
|
@ -68,8 +68,12 @@
|
|||
}
|
||||
else if (dv !== undefined && ctl.val() === "") target[name] = dv;
|
||||
else target[name] = ctl.val();
|
||||
if (target[name] === "true" || target[name] === "True") target[name] = true;
|
||||
if (target[name] === "false" || target[name] === "False") target[name] = false;
|
||||
|
||||
// check boolean value
|
||||
if (ctl.attr('data-bool') === 'true') {
|
||||
if (target[name] === "true" || target[name] === "True") target[name] = true;
|
||||
if (target[name] === "false" || target[name] === "False") target[name] = false;
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
@ -183,7 +187,7 @@
|
|||
callback: function (result) {
|
||||
if (result) {
|
||||
$(options.bootstrapTable).bootstrapTable('refresh');
|
||||
handlerCallback.call(that, null, element, { oper: 'save', success: result, data: options.data });
|
||||
handlerCallback.call(that, null, element, { oper: 'save', success: result, data: [options.data] });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -22,8 +22,8 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
Id = d.Key,
|
||||
AppName = d.Value
|
||||
}).ToList();
|
||||
var role = RoleHelper.Retrieves().Cast<Role>().FirstOrDefault(r => r.Id == roleId);
|
||||
apps.ForEach(p => p.Checked = (role != null && (role.Apps.Contains(p.Id)) || role.RoleName.Equals("Administrators", StringComparison.OrdinalIgnoreCase)) ? "checked" : "");
|
||||
var role = RoleHelper.Retrieves().Cast<Role>().FirstOrDefault(r => r.Id == roleId) ?? new Role();
|
||||
apps.ForEach(p => p.Checked = (role.Apps.Contains(p.Id) || role.RoleName.Equals("Administrators", StringComparison.OrdinalIgnoreCase)) ? "checked" : "");
|
||||
return apps;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
namespace Bootstrap.DataAccess.MongoDB
|
||||
using Bootstrap.Security;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Bootstrap.DataAccess.MongoDB
|
||||
{
|
||||
/// <summary>
|
||||
/// 自动建库实体操作类
|
||||
|
@ -9,9 +12,10 @@
|
|||
/// 数据库检查方法
|
||||
/// <paramref name="folder"></paramref>
|
||||
/// </summary>
|
||||
public override void CheckDB(string folder)
|
||||
public override void EnsureCreated(string folder)
|
||||
{
|
||||
// UNDONE: 没有环境暂时未写代码
|
||||
// 检查数据库是否存在
|
||||
if (DbManager.Dicts.CountDocuments(FilterDefinition<BootstrapDict>.Empty) == 0) GenerateDB(folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Bootstrap.Security" Version="3.0.0" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="2.9.2" />
|
||||
<PackageReference Include="Bootstrap.Security" Version="3.0.1" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="2.9.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
/// </summary>
|
||||
internal static class DbManager
|
||||
{
|
||||
private static IMongoDatabase _db = null;
|
||||
private static IMongoDatabase? _db = null;
|
||||
private static bool _register = false;
|
||||
private static readonly object _locker = new object();
|
||||
|
||||
|
@ -38,7 +38,9 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
InitDb();
|
||||
}
|
||||
}
|
||||
#pragma warning disable CS8603 // 可能的 null 引用返回。
|
||||
return _db;
|
||||
#pragma warning restore CS8603 // 可能的 null 引用返回。
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
{
|
||||
if (string.IsNullOrEmpty(p.Id))
|
||||
{
|
||||
p.Id = null;
|
||||
DbManager.Dicts.InsertOne(p);
|
||||
p.Id = DbManager.Dicts.Find(d => d.Name == p.Name && d.Category == p.Category && d.Define == p.Define && d.Code == p.Code).FirstOrDefault().Id;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Longbow.Web.Mvc;
|
||||
using Longbow.Web.Mvc;
|
||||
using MongoDB.Driver;
|
||||
using PetaPoco;
|
||||
using System;
|
||||
|
@ -75,12 +75,9 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
|
||||
// sort
|
||||
var sortBuilder = Builders<DataAccess.Exceptions>.Sort;
|
||||
SortDefinition<DataAccess.Exceptions> sort = null;
|
||||
var sort = po.Order == "asc" ? sortBuilder.Ascending(t => t.LogTime) : sortBuilder.Descending(t => t.LogTime);
|
||||
switch (po.Sort)
|
||||
{
|
||||
case "LogTime":
|
||||
sort = po.Order == "asc" ? sortBuilder.Ascending(t => t.LogTime) : sortBuilder.Descending(t => t.LogTime);
|
||||
break;
|
||||
case "ErrorPage":
|
||||
sort = po.Order == "asc" ? sortBuilder.Ascending(t => t.ErrorPage) : sortBuilder.Descending(t => t.ErrorPage);
|
||||
break;
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public IEnumerable<string> Roles { get; set; }
|
||||
public IEnumerable<string> Roles { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
/// <param name="endTime"></param>
|
||||
/// <param name="opType"></param>
|
||||
/// <returns></returns>
|
||||
public override Page<DataAccess.Log> RetrievePages(PaginationOption po, DateTime? startTime, DateTime? endTime, string opType)
|
||||
public override Page<DataAccess.Log> RetrievePages(PaginationOption po, DateTime? startTime, DateTime? endTime, string? opType)
|
||||
{
|
||||
var filterBuilder = Builders<DataAccess.Log>.Filter;
|
||||
var filter = filterBuilder.Empty;
|
||||
|
@ -31,7 +31,7 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
|
||||
// sort
|
||||
var sortBuilder = Builders<DataAccess.Log>.Sort;
|
||||
SortDefinition<DataAccess.Log> sort = null;
|
||||
var sort = po.Order == "asc" ? sortBuilder.Ascending(t => t.LogTime) : sortBuilder.Descending(t => t.LogTime);
|
||||
switch (po.Sort)
|
||||
{
|
||||
case "CRUD":
|
||||
|
@ -40,9 +40,6 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
case "UserName":
|
||||
sort = po.Order == "asc" ? sortBuilder.Ascending(t => t.UserName) : sortBuilder.Descending(t => t.UserName);
|
||||
break;
|
||||
case "LogTime":
|
||||
sort = po.Order == "asc" ? sortBuilder.Ascending(t => t.LogTime) : sortBuilder.Descending(t => t.LogTime);
|
||||
break;
|
||||
case "Ip":
|
||||
sort = po.Order == "asc" ? sortBuilder.Ascending(t => t.Ip) : sortBuilder.Descending(t => t.Ip);
|
||||
break;
|
||||
|
@ -70,7 +67,7 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
/// <param name="endTime"></param>
|
||||
/// <param name="opType"></param>
|
||||
/// <returns></returns>
|
||||
public override IEnumerable<DataAccess.Log> RetrieveAll(DateTime? startTime, DateTime? endTime, string opType)
|
||||
public override IEnumerable<DataAccess.Log> RetrieveAll(DateTime? startTime, DateTime? endTime, string? opType)
|
||||
{
|
||||
var filterBuilder = Builders<DataAccess.Log>.Filter;
|
||||
var filter = filterBuilder.Empty;
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
/// <param name="endTime"></param>
|
||||
/// <param name="ip"></param>
|
||||
/// <returns></returns>
|
||||
public override Page<DataAccess.LoginUser> RetrieveByPages(PaginationOption po, DateTime? startTime, DateTime? endTime, string ip)
|
||||
public override Page<DataAccess.LoginUser> RetrieveByPages(PaginationOption po, DateTime? startTime, DateTime? endTime, string? ip)
|
||||
{
|
||||
var logs = RetrieveAll(startTime, endTime, ip);
|
||||
return new Page<DataAccess.LoginUser>()
|
||||
|
@ -49,7 +49,7 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
/// 获取所有登录数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override IEnumerable<DataAccess.LoginUser> RetrieveAll(DateTime? startTime, DateTime? endTime, string ip)
|
||||
public override IEnumerable<DataAccess.LoginUser> RetrieveAll(DateTime? startTime, DateTime? endTime, string? ip)
|
||||
{
|
||||
var filterBuilder = Builders<DataAccess.LoginUser>.Filter;
|
||||
var filter = filterBuilder.Empty;
|
||||
|
|
|
@ -40,8 +40,8 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
var dicts = DictHelper.RetrieveDicts().Where(m => m.Category == "菜单");
|
||||
menus.ForEach(m =>
|
||||
{
|
||||
m.CategoryName = dicts.FirstOrDefault(d => d.Code == m.Category)?.Name;
|
||||
if (m.ParentId != "0") m.ParentName = menus.FirstOrDefault(p => p.Id == m.ParentId)?.Name;
|
||||
m.CategoryName = dicts.FirstOrDefault(d => d.Code == m.Category)?.Name ?? "";
|
||||
if (m.ParentId != "0") m.ParentName = menus.FirstOrDefault(p => p.Id == m.ParentId)?.Name ?? "";
|
||||
});
|
||||
|
||||
return menus;
|
||||
|
@ -56,7 +56,6 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
{
|
||||
if (string.IsNullOrEmpty(p.Id))
|
||||
{
|
||||
p.Id = null;
|
||||
DbManager.Menus.InsertOne(p);
|
||||
p.Id = DbManager.Menus.Find(m => m.Name == p.Name && m.Category == p.Category && m.ParentId == p.ParentId && m.Url == p.Url).FirstOrDefault().Id;
|
||||
}
|
||||
|
|
|
@ -8,19 +8,18 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
public class RejectUser
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得/设置 操作日志主键ID
|
||||
///
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
public string? Id { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string UserName { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; }
|
||||
public string DisplayName { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -30,7 +29,7 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string RejectedBy { get; set; }
|
||||
public string RejectedBy { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -40,6 +39,6 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string RejectedReason { get; set; }
|
||||
public string RejectedReason { get; set; } = "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,12 +13,12 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
/// <summary>
|
||||
/// 此角色关联的所有菜单
|
||||
/// </summary>
|
||||
public IEnumerable<string> Menus { get; set; }
|
||||
public IEnumerable<string> Menus { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 此角色关联的所有应用程序
|
||||
/// </summary>
|
||||
public IEnumerable<string> Apps { get; set; }
|
||||
public IEnumerable<string> Apps { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -41,9 +41,7 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
DbManager.Roles.InsertOne(new Role()
|
||||
{
|
||||
RoleName = p.RoleName,
|
||||
Description = p.Description,
|
||||
Menus = new List<string>(),
|
||||
Apps = new List<string>()
|
||||
Description = p.Description
|
||||
});
|
||||
p.Id = DbManager.Roles.Find(r => r.RoleName == p.RoleName && r.Description == p.Description).FirstOrDefault().Id;
|
||||
}
|
||||
|
@ -130,7 +128,7 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
{
|
||||
var roles = RoleHelper.Retrieves().Cast<Role>().ToList();
|
||||
roles.ForEach(r => r.Checked = (r.Menus != null && r.Menus.Contains(menuId)) ? "checked" : "");
|
||||
roles.ForEach(r => r.Menus = null);
|
||||
roles.ForEach(r => r.Menus = new List<string>());
|
||||
return roles;
|
||||
}
|
||||
|
||||
|
@ -142,26 +140,41 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
/// <returns></returns>
|
||||
public override bool SavaByMenuId(string menuId, IEnumerable<string> roleIds)
|
||||
{
|
||||
var roles = DbManager.Roles.Find(md => md.Menus != null && md.Menus.Contains(menuId)).ToList();
|
||||
|
||||
// Remove roles
|
||||
roles.ForEach(p =>
|
||||
// 参数 id 可能是子菜单
|
||||
// https://gitee.com/LongbowEnterprise/dashboard/issues?id=IQW93
|
||||
if (!string.IsNullOrEmpty(menuId))
|
||||
{
|
||||
var menus = p.Menus == null ? new List<string>() : p.Menus.ToList();
|
||||
menus.Remove(menuId);
|
||||
DbManager.Roles.UpdateOne(md => md.Id == p.Id, Builders<Role>.Update.Set(md => md.Menus, menus));
|
||||
});
|
||||
// 找到所有包含此菜单的角色集合
|
||||
var roles = DbManager.Roles.Find(md => md.Menus != null && md.Menus.Contains(menuId)).ToList();
|
||||
|
||||
roles = DbManager.Roles.Find(md => roleIds.Contains(md.Id)).ToList();
|
||||
roles.ForEach(role =>
|
||||
{
|
||||
var menus = role.Menus == null ? new List<string>() : role.Menus.ToList();
|
||||
if (!menus.Contains(menuId))
|
||||
// 所有角色集合移除此菜单
|
||||
roles.ForEach(p =>
|
||||
{
|
||||
menus.Add(menuId);
|
||||
DbManager.Roles.UpdateOne(md => md.Id == role.Id, Builders<Role>.Update.Set(md => md.Menus, menus));
|
||||
var menus = p.Menus.ToList();
|
||||
menus.Remove(menuId);
|
||||
DbManager.Roles.UpdateOne(md => md.Id == p.Id, Builders<Role>.Update.Set(md => md.Menus, menus));
|
||||
});
|
||||
|
||||
// 授权角色集合
|
||||
string? parentId = menuId;
|
||||
roles = DbManager.Roles.Find(md => roleIds.Contains(md.Id)).ToList();
|
||||
do
|
||||
{
|
||||
roles.ForEach(role =>
|
||||
{
|
||||
var menus = role.Menus.ToList();
|
||||
if (!menus.Contains(parentId))
|
||||
{
|
||||
menus.Add(parentId);
|
||||
DbManager.Roles.UpdateOne(md => md.Id == role.Id, Builders<Role>.Update.Set(md => md.Menus, menus));
|
||||
}
|
||||
});
|
||||
|
||||
// 查找父级菜单
|
||||
parentId = DbManager.Menus.Find(md => md.Id == parentId).FirstOrDefault()?.ParentId;
|
||||
}
|
||||
});
|
||||
while (!string.IsNullOrEmpty(parentId) && parentId != "0");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override Page<DataAccess.Trace> RetrievePages(PaginationOption po, DateTime? startTime, DateTime? endTime, string ip)
|
||||
public override Page<DataAccess.Trace> RetrievePages(PaginationOption po, DateTime? startTime, DateTime? endTime, string? ip)
|
||||
{
|
||||
// filter
|
||||
var filterBuilder = Builders<DataAccess.Trace>.Filter;
|
||||
|
@ -28,12 +28,9 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
|
||||
// sort
|
||||
var sortBuilder = Builders<DataAccess.Trace>.Sort;
|
||||
SortDefinition<DataAccess.Trace> sort = null;
|
||||
var sort = po.Order == "asc" ? sortBuilder.Ascending(t => t.LogTime) : sortBuilder.Descending(t => t.LogTime);
|
||||
switch (po.Sort)
|
||||
{
|
||||
case "LogTime":
|
||||
sort = po.Order == "asc" ? sortBuilder.Ascending(t => t.LogTime) : sortBuilder.Descending(t => t.LogTime);
|
||||
break;
|
||||
case "IP":
|
||||
sort = po.Order == "asc" ? sortBuilder.Ascending(t => t.Ip) : sortBuilder.Descending(t => t.Ip);
|
||||
break;
|
||||
|
@ -73,7 +70,7 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
/// <param name="endTime"></param>
|
||||
/// <param name="ip"></param>
|
||||
/// <returns></returns>
|
||||
public override IEnumerable<DataAccess.Trace> RetrieveAll(DateTime? startTime, DateTime? endTime, string ip)
|
||||
public override IEnumerable<DataAccess.Trace> RetrieveAll(DateTime? startTime, DateTime? endTime, string? ip)
|
||||
{
|
||||
var filterBuilder = Builders<DataAccess.Trace>.Filter;
|
||||
var filter = filterBuilder.Empty;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Bootstrap.Security;
|
||||
using Bootstrap.Security.Mvc;
|
||||
using Longbow.Security.Cryptography;
|
||||
using MongoDB.Driver;
|
||||
using System;
|
||||
|
@ -15,19 +16,19 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public IEnumerable<string> Roles { get; set; }
|
||||
public IEnumerable<string> Roles { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public IEnumerable<string> Groups { get; set; }
|
||||
public IEnumerable<string> Groups { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
public override BootstrapUser RetrieveUserByUserName(string userName)
|
||||
public override BootstrapUser? RetrieveUserByUserName(string userName)
|
||||
{
|
||||
var project = Builders<User>.Projection.Include(u => u.Id)
|
||||
.Include(u => u.UserName)
|
||||
|
@ -39,7 +40,7 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
if (ret != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ret.Icon)) ret.Icon = "default.jpg";
|
||||
if (string.IsNullOrEmpty(ret.App)) ret.App = "0";
|
||||
if (string.IsNullOrEmpty(ret.App)) ret.App = BootstrapAppContext.AppId;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -118,8 +119,6 @@ namespace Bootstrap.DataAccess.MongoDB
|
|||
RegisterTime = DateTime.Now,
|
||||
ApprovedTime = user.ApprovedTime,
|
||||
ApprovedBy = user.ApprovedBy,
|
||||
Roles = new List<string>(),
|
||||
Groups = new List<string>(),
|
||||
Icon = user.Icon,
|
||||
Description = user.Description,
|
||||
IsReset = 0
|
||||
|
|
|
@ -14,17 +14,17 @@ namespace Bootstrap.DataAccess
|
|||
/// <summary>
|
||||
/// 获得/设置 应用程序主键ID
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 群组名称
|
||||
/// </summary>
|
||||
public string AppName { get; set; }
|
||||
public string AppName { get; set; } = "未设置";
|
||||
|
||||
/// <summary>
|
||||
/// 获取/设置 用户群组关联状态 checked 标示已经关联 '' 标示未关联
|
||||
/// </summary>
|
||||
public string Checked { get; set; }
|
||||
public string Checked { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 根据角色ID指派部门
|
||||
|
@ -33,7 +33,8 @@ namespace Bootstrap.DataAccess
|
|||
/// <returns></returns>
|
||||
public virtual IEnumerable<App> RetrievesByRoleId(string roleId)
|
||||
{
|
||||
var ret = DbManager.Create().Fetch<App>($"select d.Code as Id, d.Name as AppName, case ra.AppId when d.Code then 'checked' else '' end Checked from Dicts d left join RoleApp ra on d.Code = ra.AppId and ra.RoleId = @1 where d.Code > '0' and d.Category = @0", "应用程序", roleId);
|
||||
using var db = DbManager.Create();
|
||||
var ret = db.Fetch<App>($"select d.Code as Id, d.Name as AppName, case ra.AppId when d.Code then 'checked' else '' end Checked from Dicts d left join RoleApp ra on d.Code = ra.AppId and ra.RoleId = @1 where d.Category = @0", "应用程序", roleId);
|
||||
|
||||
// 判断是否为Administrators
|
||||
var role = RoleHelper.Retrieves().FirstOrDefault(r => r.Id == roleId);
|
||||
|
|
|
@ -11,34 +11,28 @@ namespace Bootstrap.DataAccess
|
|||
/// </summary>
|
||||
public class AutoDB
|
||||
{
|
||||
private string _folder;
|
||||
|
||||
/// <summary>
|
||||
/// 数据库检查方法
|
||||
/// </summary>
|
||||
public virtual void CheckDB(string folder)
|
||||
public virtual void EnsureCreated(string folder)
|
||||
{
|
||||
_folder = folder;
|
||||
using (var db = Longbow.Data.DbManager.Create())
|
||||
using var db = Longbow.Data.DbManager.Create();
|
||||
db.CommandTimeout = 5000;
|
||||
switch (db.Provider.GetType().Name)
|
||||
{
|
||||
db.CommandTimeout = 5000;
|
||||
switch (db.Provider.GetType().Name)
|
||||
{
|
||||
case "SQLiteDatabaseProvider":
|
||||
if (db.ExecuteScalar<int>("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='Users'") == 0) GenerateSQLiteDB(db);
|
||||
break;
|
||||
case "SqlServerDatabaseProvider":
|
||||
using (var newDB = ModifyConnectionString(db))
|
||||
{
|
||||
if (newDB.ExecuteScalar<int?>("select COUNT(1) from sys.databases where name = N'BootstrapAdmin'") == 0) GenerateSqlServer();
|
||||
}
|
||||
break;
|
||||
case "MySqlDatabaseProvider":
|
||||
case "MariaDbDatabaseProvider":
|
||||
// UNDONE: 本地没有环境此处代码未测试
|
||||
if (db.ExecuteScalar<int>("select count(*) from information_schema.tables where table_name ='Users' and Table_Schema = 'BootstrapAdmin'") == 0) GenerateMySql();
|
||||
break;
|
||||
}
|
||||
case "SQLiteDatabaseProvider":
|
||||
if (db.ExecuteScalar<int>("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='Users'") == 0) GenerateSQLiteDB(db, folder);
|
||||
break;
|
||||
case "SqlServerDatabaseProvider":
|
||||
using (var newDB = ModifyConnectionString(db))
|
||||
{
|
||||
if (newDB.ExecuteScalar<int?>("select COUNT(*) from sys.databases where name = N'BootstrapAdmin'") == 0) GenerateDB(folder);
|
||||
}
|
||||
break;
|
||||
case "MySqlDatabaseProvider":
|
||||
case "MariaDbDatabaseProvider":
|
||||
if (db.ExecuteScalar<int>("select count(*) from information_schema.tables where table_name ='Users' and Table_Schema = 'BootstrapAdmin'") == 0) GenerateDB(folder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,9 +50,8 @@ namespace Bootstrap.DataAccess
|
|||
return new Database(string.Join(";", newsegs), provider);
|
||||
}
|
||||
|
||||
private void GenerateSQLiteDB(IDatabase db)
|
||||
private void GenerateSQLiteDB(IDatabase db, string folder)
|
||||
{
|
||||
var folder = _folder;
|
||||
var initFile = Path.Combine(folder, "Install.sql");
|
||||
if (File.Exists(initFile))
|
||||
{
|
||||
|
@ -74,21 +67,19 @@ namespace Bootstrap.DataAccess
|
|||
}
|
||||
}
|
||||
|
||||
private void GenerateSqlServer()
|
||||
/// <summary>
|
||||
/// 执行建库脚本
|
||||
/// </summary>
|
||||
protected void GenerateDB(string folder)
|
||||
{
|
||||
// 检查 install.ps1 脚本
|
||||
var file = Path.Combine(_folder, $"install.ps1");
|
||||
var file = Path.Combine(folder, $"install.ps1");
|
||||
if (File.Exists(file))
|
||||
{
|
||||
var psi = new ProcessStartInfo("powershell", $"{file} \"{_folder}\"");
|
||||
var psi = new ProcessStartInfo("powershell", $"{file} \"{folder}\"");
|
||||
var p = Process.Start(psi);
|
||||
p.WaitForExit();
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateMySql()
|
||||
{
|
||||
// UNDONE: 没有环境暂时未写代码
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,22 +5,22 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Bootstrap.Security.DataAccess" Version="3.0.1-beta3" />
|
||||
<PackageReference Include="Bootstrap.Security.Mvc" Version="3.0.2-beta7" />
|
||||
<PackageReference Include="Longbow" Version="3.0.0" />
|
||||
<PackageReference Include="Longbow.Cache" Version="3.0.1-beta2" />
|
||||
<PackageReference Include="Longbow.Data" Version="3.0.1-beta1" />
|
||||
<PackageReference Include="Longbow.GiteeAuth" Version="3.0.1-beta1" />
|
||||
<PackageReference Include="Longbow.GitHubAuth" Version="3.0.1-beta1" />
|
||||
<PackageReference Include="Longbow.OAuth" Version="3.0.1" />
|
||||
<PackageReference Include="Bootstrap.Security.DataAccess" Version="3.0.1" />
|
||||
<PackageReference Include="Bootstrap.Security.Mvc" Version="3.0.2" />
|
||||
<PackageReference Include="Longbow" Version="3.0.1" />
|
||||
<PackageReference Include="Longbow.Cache" Version="3.0.3-beta1" />
|
||||
<PackageReference Include="Longbow.Data" Version="3.0.1" />
|
||||
<PackageReference Include="Longbow.GiteeAuth" Version="3.0.1" />
|
||||
<PackageReference Include="Longbow.GitHubAuth" Version="3.0.1" />
|
||||
<PackageReference Include="Longbow.OAuth" Version="3.0.2" />
|
||||
<PackageReference Include="Longbow.PetaPoco" Version="1.0.2" />
|
||||
<PackageReference Include="Longbow.Security.Cryptography" Version="1.3.0" />
|
||||
<PackageReference Include="Longbow.Tasks" Version="3.0.0" />
|
||||
<PackageReference Include="Longbow.Web" Version="3.0.1-beta1" />
|
||||
<PackageReference Include="Longbow.WeChatAuth" Version="3.0.0" />
|
||||
<PackageReference Include="Longbow.Tasks" Version="3.0.2-beta2" />
|
||||
<PackageReference Include="Longbow.Web" Version="3.0.1" />
|
||||
<PackageReference Include="Longbow.WeChatAuth" Version="3.0.1" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="3.0.0" />
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.7.0" />
|
||||
<PackageReference Include="PetaPoco.Extensions" Version="3.0.0" />
|
||||
<PackageReference Include="PetaPoco.Extensions" Version="3.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Bootstrap.DataAccess
|
|||
/// <param name="appIds"></param>
|
||||
/// <param name="dictIds"></param>
|
||||
/// <param name="cacheKey"></param>
|
||||
public static void ClearCache(IEnumerable<string> roleIds = null, IEnumerable<string> userIds = null, IEnumerable<string> groupIds = null, IEnumerable<string> menuIds = null, IEnumerable<string> appIds = null, IEnumerable<string> dictIds = null, string cacheKey = null)
|
||||
public static void ClearCache(IEnumerable<string>? roleIds = null, IEnumerable<string>? userIds = null, IEnumerable<string>? groupIds = null, IEnumerable<string>? menuIds = null, IEnumerable<string>? appIds = null, IEnumerable<string>? dictIds = null, string? cacheKey = null)
|
||||
{
|
||||
var cacheKeys = new List<string>();
|
||||
var corsKeys = new List<string>();
|
||||
|
|
|
@ -10,20 +10,21 @@ namespace Bootstrap.DataAccess
|
|||
[TableName("DBLogs")]
|
||||
public class DBLog
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 主键ID
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 当前登陆名
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
public string? UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 数据库执行脚本
|
||||
/// </summary>
|
||||
public string SQL { get; set; }
|
||||
public string SQL { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 获取/设置 用户角色关联状态 checked 标示已经关联 '' 标示未关联
|
||||
|
@ -38,8 +39,10 @@ namespace Bootstrap.DataAccess
|
|||
/// <param name="endTime"></param>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Page<DBLog> RetrievePages(PaginationOption po, DateTime? startTime, DateTime? endTime, string userName)
|
||||
public virtual Page<DBLog> RetrievePages(PaginationOption po, DateTime? startTime, DateTime? endTime, string? userName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(po.Sort)) po.Sort = "LogTime";
|
||||
if (string.IsNullOrEmpty(po.Order)) po.Order = "desc";
|
||||
var sql = new Sql("select * from DBLogs");
|
||||
if (startTime.HasValue) sql.Where("LogTime >= @0", startTime.Value);
|
||||
if (endTime.HasValue) sql.Where("LogTime < @0", endTime.Value.AddDays(1).AddSeconds(-1));
|
||||
|
@ -47,7 +50,8 @@ namespace Bootstrap.DataAccess
|
|||
if (!string.IsNullOrEmpty(userName)) sql.Where("UserName = @0", userName);
|
||||
sql.OrderBy($"{po.Sort} {po.Order}");
|
||||
|
||||
return DbManager.Create().Page<DBLog>(po.PageIndex, po.Limit, sql);
|
||||
using var db = DbManager.Create();
|
||||
return db.Page<DBLog>(po.PageIndex, po.Limit, sql);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -72,7 +76,8 @@ namespace Bootstrap.DataAccess
|
|||
{
|
||||
if (p == null) throw new ArgumentNullException(nameof(p));
|
||||
DeleteLogAsync();
|
||||
DbManager.Create(enableLog: false).Save(p);
|
||||
using var db = DbManager.Create(enableLog: false);
|
||||
db.Save(p);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,18 +10,19 @@ namespace Bootstrap.DataAccess
|
|||
/// <summary>
|
||||
/// 创建数据库实体类时发生异常实例
|
||||
/// </summary>
|
||||
public static Exception Exception { get; set; }
|
||||
public static Exception? Exception { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 根据配置文件动态创建数据库实体类方法
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static T Create<T>()
|
||||
public static T? Create<T>() where T : class
|
||||
{
|
||||
T t = default;
|
||||
T? t = default;
|
||||
try
|
||||
{
|
||||
Exception = null;
|
||||
t = Longbow.Data.DbContextManager.Create<T>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Bootstrap.DataAccess
|
|||
/// <param name="keepAlive"></param>
|
||||
/// <param name="enableLog">是否记录日志</param>
|
||||
/// <returns></returns>
|
||||
public static IDatabase Create(string connectionName = null, bool keepAlive = false, bool enableLog = true)
|
||||
public static IDatabase Create(string? connectionName = null, bool keepAlive = false, bool enableLog = true)
|
||||
{
|
||||
if (Mappers.GetMapper(typeof(Exceptions), null) == null) Mappers.Register(typeof(Exceptions).Assembly, new BootstrapDataAccessConventionMapper());
|
||||
var db = Longbow.Data.DbManager.Create(connectionName, keepAlive);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue