feat: add admin menu management crud
This commit is contained in:
@@ -6,6 +6,7 @@ using TakeoutSaaS.Domain.Identity.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.Common.Extensions;
|
||||
using TakeoutSaaS.Infrastructure.Identity.Options;
|
||||
using TakeoutSaaS.Infrastructure.Identity.Persistence;
|
||||
using TakeoutSaaS.Infrastructure.Identity.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.Identity.Services;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using DomainIdentityUser = TakeoutSaaS.Domain.Identity.Entities.IdentityUser;
|
||||
@@ -53,6 +54,7 @@ public static class ServiceCollectionExtensions
|
||||
services.AddScoped<IUserRoleRepository, EfUserRoleRepository>();
|
||||
services.AddScoped<IRolePermissionRepository, EfRolePermissionRepository>();
|
||||
services.AddScoped<IRoleTemplateRepository, EfRoleTemplateRepository>();
|
||||
services.AddScoped<IMenuRepository, EfMenuRepository>();
|
||||
services.AddScoped<IJwtTokenService, JwtTokenService>();
|
||||
services.AddScoped<IRefreshTokenStore, RedisRefreshTokenStore>();
|
||||
services.AddScoped<ILoginRateLimiter, RedisLoginRateLimiter>();
|
||||
|
||||
@@ -58,6 +58,11 @@ public sealed class IdentityDbContext(
|
||||
/// </summary>
|
||||
public DbSet<RolePermission> RolePermissions => Set<RolePermission>();
|
||||
|
||||
/// <summary>
|
||||
/// 菜单定义集合。
|
||||
/// </summary>
|
||||
public DbSet<MenuDefinition> MenuDefinitions => Set<MenuDefinition>();
|
||||
|
||||
/// <summary>
|
||||
/// 配置实体模型。
|
||||
/// </summary>
|
||||
@@ -73,6 +78,7 @@ public sealed class IdentityDbContext(
|
||||
ConfigurePermission(modelBuilder.Entity<Permission>());
|
||||
ConfigureUserRole(modelBuilder.Entity<UserRole>());
|
||||
ConfigureRolePermission(modelBuilder.Entity<RolePermission>());
|
||||
ConfigureMenuDefinition(modelBuilder.Entity<MenuDefinition>());
|
||||
ApplyTenantQueryFilters(modelBuilder);
|
||||
}
|
||||
|
||||
@@ -191,4 +197,26 @@ public sealed class IdentityDbContext(
|
||||
builder.HasIndex(x => x.TenantId);
|
||||
builder.HasIndex(x => new { x.TenantId, x.RoleId, x.PermissionId }).IsUnique();
|
||||
}
|
||||
|
||||
private static void ConfigureMenuDefinition(EntityTypeBuilder<MenuDefinition> builder)
|
||||
{
|
||||
builder.ToTable("menu_definitions");
|
||||
builder.HasKey(x => x.Id);
|
||||
builder.Property(x => x.TenantId).IsRequired();
|
||||
builder.Property(x => x.ParentId).IsRequired();
|
||||
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
|
||||
builder.Property(x => x.Path).HasMaxLength(256).IsRequired();
|
||||
builder.Property(x => x.Component).HasMaxLength(256).IsRequired();
|
||||
builder.Property(x => x.Title).HasMaxLength(128).IsRequired();
|
||||
builder.Property(x => x.Icon).HasMaxLength(64);
|
||||
builder.Property(x => x.Link).HasMaxLength(512);
|
||||
builder.Property(x => x.SortOrder).IsRequired();
|
||||
builder.Property(x => x.RequiredPermissions).HasMaxLength(1024);
|
||||
builder.Property(x => x.MetaPermissions).HasMaxLength(1024);
|
||||
builder.Property(x => x.MetaRoles).HasMaxLength(1024);
|
||||
builder.Property(x => x.AuthListJson).HasColumnType("text");
|
||||
ConfigureAuditableEntity(builder);
|
||||
ConfigureSoftDeleteEntity(builder);
|
||||
builder.HasIndex(x => new { x.TenantId, x.ParentId, x.SortOrder });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TakeoutSaaS.Domain.Identity.Entities;
|
||||
using TakeoutSaaS.Domain.Identity.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.Identity.Persistence;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Identity.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// 菜单仓储 EF 实现。
|
||||
/// </summary>
|
||||
public sealed class EfMenuRepository(IdentityDbContext dbContext) : IMenuRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<IReadOnlyList<MenuDefinition>> GetByTenantAsync(long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return dbContext.MenuDefinitions
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId)
|
||||
.OrderBy(x => x.ParentId)
|
||||
.ThenBy(x => x.SortOrder)
|
||||
.ToListAsync(cancellationToken)
|
||||
.ContinueWith(t => (IReadOnlyList<MenuDefinition>)t.Result, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<MenuDefinition?> FindByIdAsync(long id, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return dbContext.MenuDefinitions
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(x => x.Id == id && x.TenantId == tenantId, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddAsync(MenuDefinition menu, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return dbContext.MenuDefinitions.AddAsync(menu, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task UpdateAsync(MenuDefinition menu, CancellationToken cancellationToken = default)
|
||||
{
|
||||
dbContext.MenuDefinitions.Update(menu);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task DeleteAsync(long id, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// 1. 查询目标
|
||||
var entity = await dbContext.MenuDefinitions
|
||||
.FirstOrDefaultAsync(x => x.Id == id && x.TenantId == tenantId, cancellationToken);
|
||||
|
||||
// 2. 存在则删除
|
||||
if (entity is not null)
|
||||
{
|
||||
dbContext.MenuDefinitions.Remove(entity);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return dbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user