chore: 增加数据服务实现层
This commit is contained in:
parent
663580b8ae
commit
1317b2828f
|
@ -149,7 +149,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapAdmin.DataAccess.P
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapAdmin.Web.Core", "src\blazor\admin\BootstrapAdmin.Web.Core\BootstrapAdmin.Web.Core.csproj", "{DA143654-C258-410D-B5DC-FE446ED99CE4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapClient.Web.DataAccess", "src\blazor\client\BootstrapClient.DataAccess\BootstrapClient.Web.DataAccess.csproj", "{640F598B-6586-4AD6-B544-78CFF2602DFB}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapClient.DataAccess.PetaPoco", "src\blazor\client\BootstrapClient.DataAccess\BootstrapClient.DataAccess.PetaPoco.csproj", "{640F598B-6586-4AD6-B544-78CFF2602DFB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapClient.Web.Shared", "src\blazor\client\BootstrapClient.Shared\BootstrapClient.Web.Shared.csproj", "{93770088-3463-427B-9CD8-88B8D7945C83}"
|
||||
EndProject
|
||||
|
@ -159,6 +159,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootStarpAdmin.DataAccess.F
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootStarpAdmin.DataAccess.SqlSugar", "src\blazor\admin\BootStarpAdmin.DataAccess.SqlSugar\BootStarpAdmin.DataAccess.SqlSugar.csproj", "{1D20E6CF-9825-4CDE-B732-AE586BD1AABA}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapClient.Web.Core", "src\blazor\client\BootstrapClient.Web.Core\BootstrapClient.Web.Core.csproj", "{FFDF9FF9-0B29-47D3-AD42-53A476B570EC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapClient.DataAccess.Models", "src\blazor\client\BootstrapClient.Web.Models\BootstrapClient.DataAccess.Models.csproj", "{CC3DF23A-2880-438F-BDEB-DB093E919ABA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -233,6 +237,14 @@ Global
|
|||
{1D20E6CF-9825-4CDE-B732-AE586BD1AABA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1D20E6CF-9825-4CDE-B732-AE586BD1AABA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1D20E6CF-9825-4CDE-B732-AE586BD1AABA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FFDF9FF9-0B29-47D3-AD42-53A476B570EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FFDF9FF9-0B29-47D3-AD42-53A476B570EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FFDF9FF9-0B29-47D3-AD42-53A476B570EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FFDF9FF9-0B29-47D3-AD42-53A476B570EC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CC3DF23A-2880-438F-BDEB-DB093E919ABA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CC3DF23A-2880-438F-BDEB-DB093E919ABA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CC3DF23A-2880-438F-BDEB-DB093E919ABA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CC3DF23A-2880-438F-BDEB-DB093E919ABA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -272,6 +284,8 @@ Global
|
|||
{6CD7A35B-93A8-4DB2-B078-EE5A81F40032} = {55A2459A-6BDE-4493-B2C0-5BE1673E99EE}
|
||||
{11122D97-B349-4A3E-B7DD-73B8B363C47C} = {45ADEF9B-C8BD-4224-9E12-F6716E85A22C}
|
||||
{1D20E6CF-9825-4CDE-B732-AE586BD1AABA} = {45ADEF9B-C8BD-4224-9E12-F6716E85A22C}
|
||||
{FFDF9FF9-0B29-47D3-AD42-53A476B570EC} = {55A2459A-6BDE-4493-B2C0-5BE1673E99EE}
|
||||
{CC3DF23A-2880-438F-BDEB-DB093E919ABA} = {55A2459A-6BDE-4493-B2C0-5BE1673E99EE}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {221EAE38-5F75-4391-9A48-E462A9F3B8FC}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
using PetaPoco;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BootstrapClient.DataAccess.PetaPoco;
|
||||
|
||||
class BootstrapAdminConventionMapper : ConventionMapper
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="pocoType"></param>
|
||||
/// <returns></returns>
|
||||
public override TableInfo GetTableInfo(Type pocoType)
|
||||
{
|
||||
var ti = base.GetTableInfo(pocoType);
|
||||
ti.AutoIncrement = true;
|
||||
|
||||
// 支持 Oracle 数据库
|
||||
ti.SequenceName = $"SEQ_{ti.TableName.ToUpperInvariant()}_ID";
|
||||
|
||||
ti.TableName = pocoType.Name switch
|
||||
{
|
||||
"Error" => "Exceptions",
|
||||
_ => $"{pocoType.Name}s"
|
||||
};
|
||||
return ti;
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
/////
|
||||
///// </summary>
|
||||
///// <param name="pocoProperty"></param>
|
||||
///// <returns></returns>
|
||||
//public override ColumnInfo GetColumnInfo(PropertyInfo pocoProperty) => pocoProperty.DeclaringType?.Name switch
|
||||
//{
|
||||
// nameof(Models.User) => GetUserColumnInfo(pocoProperty),
|
||||
// nameof(Models.Navigation) => GetNavigationColumnInfo(pocoProperty),
|
||||
// _ => base.GetColumnInfo(pocoProperty)
|
||||
//};
|
||||
|
||||
//private ColumnInfo GetUserColumnInfo(PropertyInfo pocoProperty)
|
||||
//{
|
||||
// var ci = base.GetColumnInfo(pocoProperty);
|
||||
// var resultColumns = new List<string>
|
||||
// {
|
||||
// nameof(Models.User.NewPassword),
|
||||
// nameof(Models.User.ConfirmPassword),
|
||||
// nameof(Models.User.Period),
|
||||
// nameof(Models.User.IsReset)
|
||||
// };
|
||||
// ci.ResultColumn = resultColumns.Any(c => c == ci.ColumnName);
|
||||
// return ci;
|
||||
//}
|
||||
|
||||
//private ColumnInfo GetNavigationColumnInfo(PropertyInfo pocoProperty)
|
||||
//{
|
||||
// var ci = base.GetColumnInfo(pocoProperty);
|
||||
// var resultColumns = new List<string>
|
||||
// {
|
||||
// nameof(Models.Navigation.HasChildren)
|
||||
// };
|
||||
// ci.ResultColumn = resultColumns.Any(c => c == ci.ColumnName);
|
||||
// return ci;
|
||||
//}
|
||||
|
||||
//public override Func<object?, object?> GetFromDbConverter(PropertyInfo targetProperty, Type sourceType) => targetProperty.PropertyType.IsEnum && sourceType == typeof(string)
|
||||
// ? new StringToEnumConverter(targetProperty.PropertyType).ConvertFromDb
|
||||
// : base.GetFromDbConverter(targetProperty, sourceType);
|
||||
|
||||
//public override Func<object?, object?> GetToDbConverter(PropertyInfo targetProperty) => targetProperty.PropertyType.IsEnum
|
||||
// ? new StringToEnumConverter(targetProperty.PropertyType).ConvertToDb
|
||||
// : base.GetToDbConverter(targetProperty);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor" Version="6.2.7-beta03" />
|
||||
<PackageReference Include="Longbow.Security.Cryptography" Version="5.2.0" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.1" />
|
||||
<PackageReference Include="PetaPoco.Extensions" Version="5.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BootstrapClient.Web.Core\BootstrapClient.Web.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,8 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\admin\BootstrapAdmin.DataAccess.PetaPoco\BootstrapAdmin.DataAccess.PetaPoco.csproj" />
|
||||
<ProjectReference Include="..\..\admin\BootstrapAdmin.Web.Core\BootstrapAdmin.Web.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,75 @@
|
|||
using BootstrapBlazor.Components;
|
||||
using BootstrapClient.DataAccess.PetaPoco;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using PetaPoco;
|
||||
using System.Collections.Specialized;
|
||||
using System.Data.Common;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddPetaPocoDataAccessServices(this IServiceCollection services, Action<IServiceProvider, IDatabaseBuildConfiguration> builder)
|
||||
{
|
||||
services.TryAddSingleton<IDatabase>(provider =>
|
||||
{
|
||||
var option = DatabaseConfiguration.Build();
|
||||
builder(provider, option);
|
||||
option.UsingDefaultMapper<BootstrapAdminConventionMapper>();
|
||||
var db = new Database(option);
|
||||
|
||||
var logger = provider.GetRequiredService<ILogger<Database>>();
|
||||
db.ExceptionThrown += (sender, e) =>
|
||||
{
|
||||
var message = e.Exception.Format(new NameValueCollection()
|
||||
{
|
||||
[nameof(db.LastCommand)] = db.LastCommand,
|
||||
[nameof(db.LastArgs)] = string.Join(",", db.LastArgs)
|
||||
});
|
||||
logger.LogError(new EventId(1001, "GlobalException"), e.Exception, message);
|
||||
};
|
||||
var env = provider.GetRequiredService<IWebHostEnvironment>();
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
db.CommandExecuted += (sender, args) =>
|
||||
{
|
||||
var parameters = new StringBuilder();
|
||||
foreach (DbParameter p in args.Command.Parameters)
|
||||
{
|
||||
parameters.AppendFormat("{0}: {1} ", p.ParameterName, p.Value);
|
||||
}
|
||||
logger.LogInformation(args.Command.CommandText);
|
||||
logger.LogInformation(parameters.ToString());
|
||||
};
|
||||
};
|
||||
return db;
|
||||
});
|
||||
|
||||
//// 增加数据服务
|
||||
//services.AddSingleton(typeof(IDataService<>), typeof(DefaultDataService<>));
|
||||
|
||||
//// 增加业务服务
|
||||
//services.AddSingleton<IApp, AppService>();
|
||||
//services.AddSingleton<IDict, DictService>();
|
||||
//services.AddSingleton<IException, ExceptionService>();
|
||||
//services.AddSingleton<IGroup, GroupService>();
|
||||
//services.AddSingleton<ILogin, LoginService>();
|
||||
//services.AddSingleton<INavigation, NavigationService>();
|
||||
//services.AddSingleton<IRole, RoleService>();
|
||||
//services.AddSingleton<IUser, UserService>();
|
||||
return services;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
using BootstrapAdmin.DataAccess.Models;
|
||||
using BootstrapClient.Web.Core;
|
||||
using PetaPoco;
|
||||
|
||||
namespace BootstrapClient.DataAccess.PetaPoco.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
class NavigationService : INavigation
|
||||
{
|
||||
private IDatabase Database { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
public NavigationService(IDatabase db)
|
||||
{
|
||||
Database = db;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得指定用户名可访问的所有菜单集合
|
||||
/// </summary>
|
||||
/// <param name="userName">当前用户名</param>
|
||||
/// <returns>未层次化的菜单集合</returns>
|
||||
public List<Navigation> GetMenus(string userName)
|
||||
{
|
||||
var order = Database.Provider.EscapeSqlIdentifier("Order");
|
||||
return Database.Fetch<Navigation>($"select n.ID, n.ParentId, n.Name, n.{order}, n.Icon, n.Url, n.Category, n.Target, n.IsResource, n.Application, ln.Name as ParentName from Navigations n inner join Dicts d on n.Category = d.Code and d.Category = @Category and d.Define = @Define left join Navigations ln on n.ParentId = ln.ID inner join (select nr.NavigationID from Users u inner join UserRole ur on ur.UserID = u.ID inner join NavigationRole nr on nr.RoleID = ur.RoleID where u.UserName = @UserName union select nr.NavigationID from Users u inner join UserGroup ug on u.ID = ug.UserID inner join RoleGroup rg on rg.GroupID = ug.GroupID inner join NavigationRole nr on nr.RoleID = rg.RoleID where u.UserName = @UserName union select n.ID from Navigations n where EXISTS (select UserName from Users u inner join UserRole ur on u.ID = ur.UserID inner join Roles r on ur.RoleID = r.ID where u.UserName = @UserName and r.RoleName = @RoleName)) nav on n.ID = nav.NavigationID ORDER BY n.Application, n.{order}", new { UserName = userName, Category = "菜单", RoleName = "Administrators", Define = 1 });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="roleId"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetMenusByRoleId(string? roleId)
|
||||
{
|
||||
return Database.Fetch<string>("select NavigationID from NavigationRole where RoleID = @0", roleId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="roleId"></param>
|
||||
/// <param name="menuIds"></param>
|
||||
/// <returns></returns>
|
||||
public bool SaveMenusByRoleId(string? roleId, List<string> menuIds)
|
||||
{
|
||||
var ret = false;
|
||||
try
|
||||
{
|
||||
Database.BeginTransaction();
|
||||
Database.Execute("delete from NavigationRole where RoleID = @0", roleId);
|
||||
Database.InsertBatch("NavigationRole", menuIds.Select(g => new { NavigationID = g, RoleID = roleId }));
|
||||
Database.CompleteTransaction();
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Database.AbortTransaction();
|
||||
throw;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using BootstrapAdmin.DataAccess.Models;
|
||||
using BootstrapClient.Web.Core;
|
||||
using PetaPoco;
|
||||
|
||||
namespace BootstrapClient.DataAccess.PetaPoco.Services;
|
||||
|
||||
class UserService : IUser
|
||||
{
|
||||
private IDatabase Database { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
public UserService(IDatabase db)
|
||||
{
|
||||
Database = db;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
public User? GetUserByUserName(string? userName)
|
||||
{
|
||||
return string.IsNullOrEmpty(userName) ? null : Database.FirstOrDefault<User>("Where UserName = @0", userName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public List<string> GetApps(string userName)
|
||||
{
|
||||
return Database.Fetch<string>($"select d.Code from Dicts d inner join RoleApp ra on d.Code = ra.AppId inner join (select r.Id from Roles r inner join UserRole ur on r.ID = ur.RoleID inner join Users u on ur.UserID = u.ID where u.UserName = @0 union select r.Id from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {Database.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID where u.UserName = @0) r on ra.RoleId = r.ID union select Code from Dicts where Category = @1 and exists(select r.ID from Roles r inner join UserRole ur on r.ID = ur.RoleID inner join Users u on ur.UserID = u.ID where u.UserName = @0 and r.RoleName = @2 union select r.ID from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {Database.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID where u.UserName = @0 and r.RoleName = @2)", userName, "应用程序", "Administrators");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public List<string> GetRoles(string userName)
|
||||
{
|
||||
return Database.Fetch<string>($"select r.RoleName from Roles r inner join UserRole ur on r.ID=ur.RoleID inner join Users u on ur.UserID = u.ID and u.UserName = @0 union select r.RoleName from Roles r inner join RoleGroup rg on r.ID = rg.RoleID inner join {Database.Provider.EscapeSqlIdentifier("Groups")} g on rg.GroupID = g.ID inner join UserGroup ug on ug.GroupID = g.ID inner join Users u on ug.UserID = u.ID and u.UserName=@0", userName);
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BootstrapClient.DataAccess\BootstrapClient.Web.DataAccess.csproj" />
|
||||
<ProjectReference Include="..\BootstrapClient.DataAccess\BootstrapClient.DataAccess.PetaPoco.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -14,16 +14,19 @@ public static class MenuExtensions
|
|||
/// </summary>
|
||||
/// <param name="menu"></param>
|
||||
/// <returns></returns>
|
||||
public static MenuItem Parse(this Navigation menu) => new()
|
||||
public static MenuItem Parse(this Navigation menu)
|
||||
{
|
||||
Text = menu.Name,
|
||||
Url = menu.Url.Replace("~", ""),
|
||||
Icon = menu.Icon,
|
||||
Match = NavLinkMatch.All,
|
||||
Target = menu.Target,
|
||||
Id = menu.Id,
|
||||
ParentId = menu.ParentId
|
||||
};
|
||||
return new()
|
||||
{
|
||||
Text = menu.Name,
|
||||
Url = menu.Url.Replace("~", ""),
|
||||
Icon = menu.Icon,
|
||||
Match = NavLinkMatch.All,
|
||||
Target = menu.Target,
|
||||
Id = menu.Id,
|
||||
ParentId = menu.ParentId
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取前台菜单
|
||||
|
@ -31,7 +34,7 @@ public static class MenuExtensions
|
|||
/// <returns></returns>
|
||||
public static IEnumerable<MenuItem> ToClientMenus(this List<Navigation> navigations)
|
||||
{
|
||||
var menus = navigations.Where(m => m.Category == EnumNavigationCategory.Customer && m.IsResource == 0);
|
||||
var menus = navigations.Where(m => m.IsResource == 0);
|
||||
return CascadeMenus(menus);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Bootstrap.Security.Blazor;
|
||||
using BootstrapAdmin.Web.Core;
|
||||
using BootstrapBlazor.Components;
|
||||
using BootstrapClient.Web.Core;
|
||||
using BootstrapClient.Web.Shared.Extensions;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
@ -8,130 +8,132 @@ using Microsoft.AspNetCore.Components.Authorization;
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace BootstrapClient.Web.Shared.Shared
|
||||
namespace BootstrapClient.Web.Shared.Shared;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public sealed partial class MainLayout
|
||||
{
|
||||
private bool UseTabSet { get; set; } = true;
|
||||
|
||||
private string Theme { get; set; } = "";
|
||||
|
||||
private bool IsOpen { get; set; }
|
||||
|
||||
private bool IsFixedHeader { get; set; } = true;
|
||||
|
||||
private bool IsFixedFooter { get; set; } = true;
|
||||
|
||||
private bool IsFullSide { get; set; } = true;
|
||||
|
||||
private bool ShowFooter { get; set; } = true;
|
||||
|
||||
private IEnumerable<MenuItem>? MenuItems { get; set; }
|
||||
|
||||
private string? ProfileUrl { get; set; }
|
||||
|
||||
private string? SettingsUrl { get; set; }
|
||||
|
||||
private string? NotificationUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// 获得 当前用户登录显示名称
|
||||
/// </summary>
|
||||
public sealed partial class MainLayout
|
||||
[NotNull]
|
||||
public string? DisplayName { get; private set; }
|
||||
|
||||
private string? Title { get; set; }
|
||||
|
||||
private string? Footer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得 当前用户登录名
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public string? UserName { get; private set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IBootstrapAdminService? SecurityService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private AuthenticationStateProvider? AuthenticationStateProvider { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IDict? DictsService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IUser? UsersService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private INavigation? NavigationsService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IOptions<BootstrapAdminAuthenticationOptions>? AuthorizationOption { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private NavigationManager? NavigationManager { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IConfiguration? Configuration { get; set; }
|
||||
|
||||
private string? AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OnInitialized 方法
|
||||
/// </summary>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
private bool UseTabSet { get; set; } = true;
|
||||
base.OnInitialized();
|
||||
|
||||
private string Theme { get; set; } = "";
|
||||
|
||||
private bool IsOpen { get; set; }
|
||||
|
||||
private bool IsFixedHeader { get; set; } = true;
|
||||
|
||||
private bool IsFixedFooter { get; set; } = true;
|
||||
|
||||
private bool IsFullSide { get; set; } = true;
|
||||
|
||||
private bool ShowFooter { get; set; } = true;
|
||||
|
||||
private IEnumerable<MenuItem>? MenuItems { get; set; }
|
||||
|
||||
private string? ProfileUrl { get; set; }
|
||||
|
||||
private string? SettingsUrl { get; set; }
|
||||
|
||||
private string? NotificationUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得 当前用户登录显示名称
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public string? DisplayName { get; private set; }
|
||||
|
||||
private string? Title { get; set; }
|
||||
|
||||
private string? Footer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得 当前用户登录名
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public string? UserName { get; private set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IBootstrapAdminService? SecurityService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private AuthenticationStateProvider? AuthenticationStateProvider { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IDict? DictsService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IUser? UsersService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private INavigation? NavigationsService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IOptions<BootstrapAdminAuthenticationOptions>? AuthorizationOption { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private NavigationManager? NavigationManager { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IConfiguration? Configuration { get; set; }
|
||||
|
||||
private string? AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OnInitialized 方法
|
||||
/// </summary>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
AppId = Configuration.GetValue("AppId", "Blazor");
|
||||
ProfileUrl = CombinePath(DictsService.GetProfileUrl(AppId));
|
||||
SettingsUrl = CombinePath(DictsService.GetSettingsUrl(AppId));
|
||||
NotificationUrl = CombinePath(DictsService.GetNotificationUrl(AppId));
|
||||
}
|
||||
|
||||
private string CombinePath(string? url)
|
||||
{
|
||||
url ??= "";
|
||||
var hostUrl = AuthorizationOption.Value.AuthHost.TrimEnd('/');
|
||||
return string.Join('/', hostUrl, url.TrimStart('/'));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OnInitialized 方法
|
||||
/// </summary>
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var state = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
var userName = state.User.Identity?.Name;
|
||||
|
||||
if (!string.IsNullOrEmpty(userName))
|
||||
{
|
||||
UserName = userName;
|
||||
var user = UsersService.GetUserByUserName(userName);
|
||||
|
||||
MenuItems = NavigationsService.GetAllMenus(userName).ToClientMenus();
|
||||
|
||||
DisplayName = user?.DisplayName ?? "未注册账户";
|
||||
Title = DictsService.GetWebTitle();
|
||||
Footer = DictsService.GetWebFooter();
|
||||
}
|
||||
}
|
||||
|
||||
private Task<bool> OnAuthorizing(string url) => SecurityService.AuhorizingNavigation(UserName, url);
|
||||
|
||||
private string LogoutUrl => CombinePath($"/Account/Logout?AppId={AppId}");
|
||||
|
||||
private string AuthorUrl => CombinePath($"/Account/Login?ReturnUrl={NavigationManager.Uri}&AppId={AppId}");
|
||||
AppId = Configuration.GetValue("AppId", "Blazor");
|
||||
ProfileUrl = CombinePath(DictsService.GetProfileUrl(AppId));
|
||||
SettingsUrl = CombinePath(DictsService.GetSettingsUrl(AppId));
|
||||
NotificationUrl = CombinePath(DictsService.GetNotificationUrl(AppId));
|
||||
}
|
||||
|
||||
private string CombinePath(string? url)
|
||||
{
|
||||
url ??= "";
|
||||
var hostUrl = AuthorizationOption.Value.AuthHost.TrimEnd('/');
|
||||
return string.Join('/', hostUrl, url.TrimStart('/'));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OnInitialized 方法
|
||||
/// </summary>
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var state = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
var userName = state.User.Identity?.Name;
|
||||
|
||||
if (!string.IsNullOrEmpty(userName))
|
||||
{
|
||||
UserName = userName;
|
||||
var user = UsersService.GetUserByUserName(userName);
|
||||
|
||||
MenuItems = NavigationsService.GetMenus(userName).ToClientMenus();
|
||||
|
||||
DisplayName = user?.DisplayName ?? "未注册账户";
|
||||
Title = DictsService.GetWebTitle();
|
||||
Footer = DictsService.GetWebFooter();
|
||||
}
|
||||
}
|
||||
|
||||
private Task<bool> OnAuthorizing(string url)
|
||||
{
|
||||
return SecurityService.AuhorizingNavigation(UserName, url);
|
||||
}
|
||||
|
||||
private string LogoutUrl => CombinePath($"/Account/Logout?AppId={AppId}");
|
||||
|
||||
private string AuthorUrl => CombinePath($"/Account/Login?ReturnUrl={NavigationManager.Uri}&AppId={AppId}");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
using Bootstrap.Security.Blazor;
|
||||
|
||||
namespace BootstrapClient.Web.Core.Services;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class AdminService : IBootstrapAdminService
|
||||
{
|
||||
private IUser User { get; set; }
|
||||
|
||||
private INavigation Navigations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="navigations"></param>
|
||||
public AdminService(IUser user, INavigation navigations)
|
||||
{
|
||||
User = user;
|
||||
Navigations = navigations;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过用户名获取角色集合方法
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetRoles(string userName) => User.GetRoles(userName);
|
||||
|
||||
/// <summary>
|
||||
/// 通过用户名获取授权 App 集合方法
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetApps(string userName) => User.GetApps(userName);
|
||||
|
||||
/// <summary>
|
||||
/// 通过用户名检查当前请求 Url 是否已授权方法
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> AuhorizingNavigation(string userName, string url)
|
||||
{
|
||||
var ret = false;
|
||||
if (Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out var uri))
|
||||
{
|
||||
ret = Navigations.GetMenus(userName)
|
||||
.Any(m => m.Url.Contains(uri.AbsolutePath, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
return Task.FromResult(ret);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Bootstrap.Security.Blazor" Version="6.0.1-beta01" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BootstrapClient.Web.Models\BootstrapClient.DataAccess.Models.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,52 @@
|
|||
namespace BootstrapClient.Web.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Dict 字典表接口
|
||||
/// </summary>
|
||||
public interface IDict
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取当前系统配置是否为演示模式
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool IsDemo();
|
||||
|
||||
/// <summary>
|
||||
/// 获取 站点 Title 配置信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
string GetWebTitle();
|
||||
|
||||
/// <summary>
|
||||
/// 获取站点 Footer 配置信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
string GetWebFooter();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="appId"></param>
|
||||
/// <returns></returns>
|
||||
string? GetProfileUrl(string appId);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="appId"></param>
|
||||
/// <returns></returns>
|
||||
string? GetSettingsUrl(string appId);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="appId"></param>
|
||||
/// <returns></returns>
|
||||
string? GetNotificationUrl(string appId);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
string RetrieveIconFolderPath();
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using BootstrapAdmin.DataAccess.Models;
|
||||
|
||||
namespace BootstrapClient.Web.Core;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public interface INavigation
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<Navigation> GetMenus(string userName);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using BootstrapAdmin.DataAccess.Models;
|
||||
|
||||
namespace BootstrapClient.Web.Core;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public interface IUser
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
User? GetUserByUserName(string? userName);
|
||||
|
||||
/// <summary>
|
||||
/// 通过用户名获取角色列表
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
List<string> GetRoles(string userName);
|
||||
|
||||
/// <summary>
|
||||
/// 通过用户名获得授权 App 集合
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <returns></returns>
|
||||
List<string> GetApps(string userName);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace BootstrapAdmin.DataAccess.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Bootstrap Admin 后台管理菜单相关操作实体类
|
||||
/// </summary>
|
||||
[Table("Navigations")]
|
||||
public class Navigation
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得/设置 菜单主键ID
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public string? Id { set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 父级菜单ID 默认为 0
|
||||
/// </summary>
|
||||
public string ParentId { set; get; } = "0";
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 菜单名称
|
||||
/// </summary>
|
||||
[Display(Name = "名称")]
|
||||
[NotNull]
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 菜单序号
|
||||
/// </summary>
|
||||
[Display(Name = "序号")]
|
||||
public int Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 菜单图标
|
||||
/// </summary>
|
||||
[Display(Name = "图标")]
|
||||
public string? Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 菜单URL地址
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
[Display(Name = "地址")]
|
||||
public string? Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 菜单分类, 0 表示系统菜单 1 表示用户自定义菜单
|
||||
/// </summary>
|
||||
[Display(Name = "类别")]
|
||||
public int Category { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 链接目标
|
||||
/// </summary>
|
||||
[Display(Name = "目标")]
|
||||
public string? Target { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否为资源文件, 0 表示菜单 1 表示资源 2 表示按钮
|
||||
/// </summary>
|
||||
[Display(Name = "类型")]
|
||||
public int IsResource { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 所属应用程序,此属性由BA后台字典表分配
|
||||
/// </summary>
|
||||
[Display(Name = "所属应用")]
|
||||
public string? Application { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool HasChildren { get; set; }
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace BootstrapAdmin.DataAccess.Models;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class User
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得/设置 系统登录用户名
|
||||
/// </summary>
|
||||
[Display(Name = "登录名称")]
|
||||
[Required(ErrorMessage = "{0}不可为空")]
|
||||
[RegularExpression("^[a-zA-Z0-9_@.]*$", ErrorMessage = "登录名称包含非法字符")]
|
||||
[MaxLength(16, ErrorMessage = "{0}不能超过 16 个字符")]
|
||||
[NotNull]
|
||||
public string? UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 用户显示名称
|
||||
/// </summary>
|
||||
[Display(Name = "显示名称")]
|
||||
[Required(ErrorMessage = "{0}不可为空")]
|
||||
[MaxLength(20, ErrorMessage = "{0}不能超过 20 个字符")]
|
||||
[NotNull]
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 用户头像图标路径
|
||||
/// </summary>
|
||||
[Display(Name = "用户头像")]
|
||||
public string? Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 用户设置样式表名称
|
||||
/// </summary>
|
||||
[Display(Name = "主题")]
|
||||
public string? Css { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 用户默认登陆 App 标识
|
||||
/// </summary>
|
||||
[Display(Name = "默认 APP")]
|
||||
public string? App { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 用户主键ID
|
||||
/// </summary>
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取/设置 密码
|
||||
/// </summary>
|
||||
[Display(Name = "密码")]
|
||||
[Required(ErrorMessage = "{0}不可为空")]
|
||||
[MaxLength(16, ErrorMessage = "{0}不能超过 16 个字符")]
|
||||
[NotNull]
|
||||
public string? Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取/设置 密码盐
|
||||
/// </summary>
|
||||
public string? PassSalt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 用户注册时间
|
||||
/// </summary>
|
||||
[Display(Name = "注册时间")]
|
||||
public DateTime RegisterTime { get; set; } = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 用户被批复时间
|
||||
/// </summary>
|
||||
[Display(Name = "授权时间")]
|
||||
public DateTime? ApprovedTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 用户批复人
|
||||
/// </summary>
|
||||
[Display(Name = "授权人")]
|
||||
public string? ApprovedBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 用户的申请理由
|
||||
/// </summary>
|
||||
[Display(Name = "说明")]
|
||||
[NotNull]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 通知描述 2分钟内为刚刚
|
||||
/// </summary>
|
||||
public string? Period { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 新密码
|
||||
/// </summary>
|
||||
[Display(Name = "新密码")]
|
||||
[Required(ErrorMessage = "{0}不可为空")]
|
||||
[MaxLength(16, ErrorMessage = "{0}不能超过 16 个字符")]
|
||||
[NotNull]
|
||||
public string? NewPassword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 新密码
|
||||
/// </summary>
|
||||
[Display(Name = "确认密码")]
|
||||
[Required(ErrorMessage = "{0}不可为空")]
|
||||
[Compare("NewPassword", ErrorMessage = "{0}与{1}不一致")]
|
||||
[MaxLength(16, ErrorMessage = "{0}不能超过 16 个字符")]
|
||||
[NotNull]
|
||||
public string? ConfirmPassword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否重置密码
|
||||
/// </summary>
|
||||
public int IsReset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 默认格式为 DisplayName (UserName)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString() => $"{DisplayName} ({UserName})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户状态枚举类型
|
||||
/// </summary>
|
||||
public enum UserStates
|
||||
{
|
||||
/// <summary>
|
||||
/// 更改密码
|
||||
/// </summary>
|
||||
ChangePassword,
|
||||
|
||||
/// <summary>
|
||||
/// 更改样式
|
||||
/// </summary>
|
||||
ChangeTheme,
|
||||
|
||||
/// <summary>
|
||||
/// 更改显示名称
|
||||
/// </summary>
|
||||
ChangeDisplayName,
|
||||
|
||||
/// <summary>
|
||||
/// 审批用户
|
||||
/// </summary>
|
||||
ApproveUser,
|
||||
|
||||
/// <summary>
|
||||
/// 拒绝用户
|
||||
/// </summary>
|
||||
RejectUser,
|
||||
|
||||
/// <summary>
|
||||
/// 保存默认应用
|
||||
/// </summary>
|
||||
SaveApp
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using BootstrapAdmin.Web.Core.Services;
|
||||
using BootstrapClient.Web.Core.Services;
|
||||
using PetaPoco;
|
||||
using PetaPoco.Providers;
|
||||
|
||||
|
|
Loading…
Reference in New Issue