feat: 添加系统菜单保护功能,防止删除内置菜单

This commit is contained in:
lvfengfree 2026-01-20 16:26:20 +08:00
parent eda41878a6
commit dcda5fa528
6 changed files with 904 additions and 10 deletions

View File

@ -1,7 +1,9 @@
using AmtScanner.Api.Data;
using AmtScanner.Api.Models;
using AmtScanner.Api.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace AmtScanner.Api.Controllers;
@ -12,10 +14,12 @@ namespace AmtScanner.Api.Controllers;
public class MenuController : ControllerBase
{
private readonly IMenuService _menuService;
private readonly AppDbContext _context;
public MenuController(IMenuService menuService)
public MenuController(IMenuService menuService, AppDbContext context)
{
_menuService = menuService;
_context = context;
}
/// <summary>
@ -45,4 +49,195 @@ public class MenuController : ControllerBase
var menus = await _menuService.GetAllMenusAsync();
return Ok(ApiResponse<List<MenuDto>>.Success(menus));
}
/// <summary>
/// 创建菜单
/// </summary>
[Authorize]
[HttpPost("api/menu")]
public async Task<ActionResult<ApiResponse<Menu>>> CreateMenu([FromBody] CreateMenuRequest request)
{
var menu = new Menu
{
ParentId = request.ParentId,
Name = request.Name,
Path = request.Path,
Component = request.Component,
Title = request.Title,
Icon = request.Icon,
Sort = request.Sort,
IsHide = request.IsHide,
KeepAlive = request.KeepAlive,
Link = request.Link,
IsIframe = request.IsIframe,
Roles = request.Roles != null ? string.Join(",", request.Roles) : null
};
_context.Menus.Add(menu);
await _context.SaveChangesAsync();
return Ok(ApiResponse<Menu>.Success(menu, "菜单创建成功"));
}
/// <summary>
/// 更新菜单
/// </summary>
[Authorize]
[HttpPut("api/menu/{id}")]
public async Task<ActionResult<ApiResponse<Menu>>> UpdateMenu(int id, [FromBody] UpdateMenuRequest request)
{
var menu = await _context.Menus.FindAsync(id);
if (menu == null)
{
return Ok(ApiResponse<Menu>.Fail(404, "菜单不存在"));
}
if (request.ParentId.HasValue) menu.ParentId = request.ParentId;
if (!string.IsNullOrEmpty(request.Name)) menu.Name = request.Name;
if (!string.IsNullOrEmpty(request.Path)) menu.Path = request.Path;
if (request.Component != null) menu.Component = request.Component;
if (!string.IsNullOrEmpty(request.Title)) menu.Title = request.Title;
if (request.Icon != null) menu.Icon = request.Icon;
if (request.Sort.HasValue) menu.Sort = request.Sort.Value;
if (request.IsHide.HasValue) menu.IsHide = request.IsHide.Value;
if (request.KeepAlive.HasValue) menu.KeepAlive = request.KeepAlive.Value;
if (request.Link != null) menu.Link = request.Link;
if (request.IsIframe.HasValue) menu.IsIframe = request.IsIframe.Value;
if (request.Roles != null) menu.Roles = string.Join(",", request.Roles);
await _context.SaveChangesAsync();
return Ok(ApiResponse<Menu>.Success(menu, "菜单更新成功"));
}
/// <summary>
/// 删除菜单
/// </summary>
[Authorize]
[HttpDelete("api/menu/{id}")]
public async Task<ActionResult<ApiResponse<object>>> DeleteMenu(int id)
{
var menu = await _context.Menus.FindAsync(id);
if (menu == null)
{
return Ok(ApiResponse<object>.Fail(404, "菜单不存在"));
}
// 检查是否为系统内置菜单
if (menu.IsSystem)
{
return Ok(ApiResponse<object>.Fail(400, "系统内置菜单不能删除"));
}
// 检查是否有子菜单
var hasChildren = await _context.Menus.AnyAsync(m => m.ParentId == id);
if (hasChildren)
{
return Ok(ApiResponse<object>.Fail(400, "请先删除子菜单"));
}
// 删除角色菜单关联
var roleMenus = await _context.RoleMenus.Where(rm => rm.MenuId == id).ToListAsync();
_context.RoleMenus.RemoveRange(roleMenus);
_context.Menus.Remove(menu);
await _context.SaveChangesAsync();
return Ok(ApiResponse<object>.Success(null, "菜单删除成功"));
}
/// <summary>
/// 重置菜单为默认配置
/// </summary>
[Authorize]
[HttpPost("api/menu/reset")]
public async Task<ActionResult<ApiResponse<object>>> ResetMenus()
{
// 清空现有菜单和角色菜单关联
_context.RoleMenus.RemoveRange(_context.RoleMenus);
_context.Menus.RemoveRange(_context.Menus);
await _context.SaveChangesAsync();
// 重新创建默认菜单
var menus = new List<Menu>
{
// 仪表盘菜单(系统内置)
new() { Id = 1, Name = "Dashboard", Path = "/dashboard", Component = "/index/index", Title = "menus.dashboard.title", Icon = "ri:pie-chart-line", Sort = 1, Roles = "R_SUPER,R_ADMIN,R_USER", IsSystem = true },
new() { Id = 2, ParentId = 1, Name = "Console", Path = "console", Component = "/dashboard/console", Title = "menus.dashboard.console", KeepAlive = false, Sort = 1, Roles = "R_SUPER,R_ADMIN,R_USER", IsSystem = true },
// 系统管理菜单(系统内置)
new() { Id = 10, Name = "System", Path = "/system", Component = "/index/index", Title = "menus.system.title", Icon = "ri:user-3-line", Sort = 99, Roles = "R_SUPER,R_ADMIN", IsSystem = true },
new() { Id = 11, ParentId = 10, Name = "User", Path = "user", Component = "/system/user", Title = "menus.system.user", KeepAlive = true, Sort = 1, Roles = "R_SUPER,R_ADMIN", IsSystem = true },
new() { Id = 12, ParentId = 10, Name = "Role", Path = "role", Component = "/system/role", Title = "menus.system.role", KeepAlive = true, Sort = 2, Roles = "R_SUPER", IsSystem = true },
new() { Id = 13, ParentId = 10, Name = "UserCenter", Path = "user-center", Component = "/system/user-center", Title = "menus.system.userCenter", IsHide = true, KeepAlive = true, Sort = 3, Roles = "R_SUPER,R_ADMIN,R_USER", IsSystem = true },
new() { Id = 14, ParentId = 10, Name = "Menus", Path = "menu", Component = "/system/menu", Title = "menus.system.menu", KeepAlive = true, Sort = 4, Roles = "R_SUPER", IsSystem = true }
};
_context.Menus.AddRange(menus);
await _context.SaveChangesAsync();
// 重新分配角色菜单
var superRole = await _context.Roles.FirstAsync(r => r.RoleCode == "R_SUPER");
var adminRole = await _context.Roles.FirstAsync(r => r.RoleCode == "R_ADMIN");
var userRole = await _context.Roles.FirstAsync(r => r.RoleCode == "R_USER");
var allMenuIds = await _context.Menus.Select(m => m.Id).ToListAsync();
var adminMenuIds = await _context.Menus
.Where(m => m.Roles != null && (m.Roles.Contains("R_ADMIN") || m.Roles.Contains("R_USER")))
.Select(m => m.Id).ToListAsync();
var userMenuIds = await _context.Menus
.Where(m => m.Roles != null && m.Roles.Contains("R_USER"))
.Select(m => m.Id).ToListAsync();
var roleMenus = new List<RoleMenu>();
foreach (var menuId in allMenuIds)
roleMenus.Add(new RoleMenu { RoleId = superRole.Id, MenuId = menuId });
foreach (var menuId in adminMenuIds)
roleMenus.Add(new RoleMenu { RoleId = adminRole.Id, MenuId = menuId });
foreach (var menuId in userMenuIds)
roleMenus.Add(new RoleMenu { RoleId = userRole.Id, MenuId = menuId });
_context.RoleMenus.AddRange(roleMenus);
await _context.SaveChangesAsync();
return Ok(ApiResponse<object>.Success(null, "菜单已重置为默认配置"));
}
}
/// <summary>
/// 创建菜单请求
/// </summary>
public class CreateMenuRequest
{
public int? ParentId { get; set; }
public string Name { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
public string? Component { get; set; }
public string Title { get; set; } = string.Empty;
public string? Icon { get; set; }
public int Sort { get; set; }
public bool IsHide { get; set; }
public bool KeepAlive { get; set; }
public string? Link { get; set; }
public bool IsIframe { get; set; }
public List<string>? Roles { get; set; }
}
/// <summary>
/// 更新菜单请求
/// </summary>
public class UpdateMenuRequest
{
public int? ParentId { get; set; }
public string? Name { get; set; }
public string? Path { get; set; }
public string? Component { get; set; }
public string? Title { get; set; }
public string? Icon { get; set; }
public int? Sort { get; set; }
public bool? IsHide { get; set; }
public bool? KeepAlive { get; set; }
public string? Link { get; set; }
public bool? IsIframe { get; set; }
public List<string>? Roles { get; set; }
}

View File

@ -101,16 +101,16 @@ public static class DbSeeder
var menus = new List<Menu>
{
// 仪表盘菜单 - 与前端 dashboard.ts 匹配
new() { Id = 1, Name = "Dashboard", Path = "/dashboard", Component = "/index/index", Title = "menus.dashboard.title", Icon = "ri:pie-chart-line", Sort = 1, Roles = "R_SUPER,R_ADMIN,R_USER" },
new() { Id = 2, ParentId = 1, Name = "Console", Path = "console", Component = "/dashboard/console", Title = "menus.dashboard.console", KeepAlive = false, Sort = 1, Roles = "R_SUPER,R_ADMIN,R_USER" },
// 仪表盘菜单 - 与前端 dashboard.ts 匹配(系统内置)
new() { Id = 1, Name = "Dashboard", Path = "/dashboard", Component = "/index/index", Title = "menus.dashboard.title", Icon = "ri:pie-chart-line", Sort = 1, Roles = "R_SUPER,R_ADMIN,R_USER", IsSystem = true },
new() { Id = 2, ParentId = 1, Name = "Console", Path = "console", Component = "/dashboard/console", Title = "menus.dashboard.console", KeepAlive = false, Sort = 1, Roles = "R_SUPER,R_ADMIN,R_USER", IsSystem = true },
// 系统管理菜单 - 与前端 system.ts 匹配
new() { Id = 10, Name = "System", Path = "/system", Component = "/index/index", Title = "menus.system.title", Icon = "ri:user-3-line", Sort = 99, Roles = "R_SUPER,R_ADMIN" },
new() { Id = 11, ParentId = 10, Name = "User", Path = "user", Component = "/system/user", Title = "menus.system.user", KeepAlive = true, Sort = 1, Roles = "R_SUPER,R_ADMIN" },
new() { Id = 12, ParentId = 10, Name = "Role", Path = "role", Component = "/system/role", Title = "menus.system.role", KeepAlive = true, Sort = 2, Roles = "R_SUPER" },
new() { Id = 13, ParentId = 10, Name = "UserCenter", Path = "user-center", Component = "/system/user-center", Title = "menus.system.userCenter", IsHide = true, KeepAlive = true, Sort = 3, Roles = "R_SUPER,R_ADMIN,R_USER" },
new() { Id = 14, ParentId = 10, Name = "Menus", Path = "menu", Component = "/system/menu", Title = "menus.system.menu", KeepAlive = true, Sort = 4, Roles = "R_SUPER" }
// 系统管理菜单 - 与前端 system.ts 匹配(系统内置)
new() { Id = 10, Name = "System", Path = "/system", Component = "/index/index", Title = "menus.system.title", Icon = "ri:user-3-line", Sort = 99, Roles = "R_SUPER,R_ADMIN", IsSystem = true },
new() { Id = 11, ParentId = 10, Name = "User", Path = "user", Component = "/system/user", Title = "menus.system.user", KeepAlive = true, Sort = 1, Roles = "R_SUPER,R_ADMIN", IsSystem = true },
new() { Id = 12, ParentId = 10, Name = "Role", Path = "role", Component = "/system/role", Title = "menus.system.role", KeepAlive = true, Sort = 2, Roles = "R_SUPER", IsSystem = true },
new() { Id = 13, ParentId = 10, Name = "UserCenter", Path = "user-center", Component = "/system/user-center", Title = "menus.system.userCenter", IsHide = true, KeepAlive = true, Sort = 3, Roles = "R_SUPER,R_ADMIN,R_USER", IsSystem = true },
new() { Id = 14, ParentId = 10, Name = "Menus", Path = "menu", Component = "/system/menu", Title = "menus.system.menu", KeepAlive = true, Sort = 4, Roles = "R_SUPER", IsSystem = true }
};
// 使用 IDENTITY_INSERT 插入带 ID 的数据

View File

@ -0,0 +1,662 @@
// <auto-generated />
using System;
using AmtScanner.Api.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace AmtScanner.Api.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20260120082406_AddMenuIsSystemColumn")]
partial class AddMenuIsSystemColumn
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("AmtScanner.Api.Models.AmtCredential", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Description")
.HasColumnType("longtext");
b.Property<bool>("IsDefault")
.HasColumnType("tinyint(1)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("longtext");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("Name");
b.ToTable("AmtCredentials");
});
modelBuilder.Entity("AmtScanner.Api.Models.AmtDevice", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
b.Property<bool>("AmtOnline")
.HasColumnType("tinyint(1)");
b.Property<string>("Description")
.HasColumnType("longtext");
b.Property<DateTime>("DiscoveredAt")
.HasColumnType("datetime(6)");
b.Property<string>("Hostname")
.HasColumnType("longtext");
b.Property<string>("IpAddress")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("varchar(50)");
b.Property<DateTime>("LastSeenAt")
.HasColumnType("datetime(6)");
b.Property<int>("MajorVersion")
.HasColumnType("int");
b.Property<int>("MinorVersion")
.HasColumnType("int");
b.Property<bool>("OsOnline")
.HasColumnType("tinyint(1)");
b.Property<int>("ProvisioningState")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("IpAddress")
.IsUnique();
b.ToTable("AmtDevices");
});
modelBuilder.Entity("AmtScanner.Api.Models.HardwareInfo", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<long>("DeviceId")
.HasColumnType("bigint");
b.Property<DateTime>("LastUpdated")
.HasColumnType("datetime(6)");
b.Property<int?>("ProcessorCores")
.HasColumnType("int");
b.Property<int?>("ProcessorCurrentClockSpeed")
.HasColumnType("int");
b.Property<int?>("ProcessorMaxClockSpeed")
.HasColumnType("int");
b.Property<string>("ProcessorModel")
.HasColumnType("longtext");
b.Property<int?>("ProcessorThreads")
.HasColumnType("int");
b.Property<string>("SystemManufacturer")
.HasColumnType("longtext");
b.Property<string>("SystemModel")
.HasColumnType("longtext");
b.Property<string>("SystemSerialNumber")
.HasColumnType("longtext");
b.Property<long?>("TotalMemoryBytes")
.HasColumnType("bigint");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.HasIndex("DeviceId");
b.HasIndex("LastUpdated");
b.ToTable("HardwareInfos");
});
modelBuilder.Entity("AmtScanner.Api.Models.MemoryModule", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
b.Property<long?>("CapacityBytes")
.HasColumnType("bigint");
b.Property<long>("HardwareInfoId")
.HasColumnType("bigint");
b.Property<string>("Manufacturer")
.HasColumnType("longtext");
b.Property<string>("MemoryType")
.HasColumnType("longtext");
b.Property<string>("PartNumber")
.HasColumnType("longtext");
b.Property<string>("SerialNumber")
.HasColumnType("longtext");
b.Property<string>("SlotLocation")
.HasColumnType("longtext");
b.Property<int?>("SpeedMHz")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("HardwareInfoId");
b.ToTable("MemoryModules");
});
modelBuilder.Entity("AmtScanner.Api.Models.Menu", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("AuthList")
.HasMaxLength(1000)
.HasColumnType("varchar(1000)");
b.Property<string>("Component")
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Icon")
.HasMaxLength(100)
.HasColumnType("varchar(100)");
b.Property<bool>("IsHide")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsHideTab")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsIframe")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsSystem")
.HasColumnType("tinyint(1)");
b.Property<bool>("KeepAlive")
.HasColumnType("tinyint(1)");
b.Property<string>("Link")
.HasMaxLength(500)
.HasColumnType("varchar(500)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("varchar(100)");
b.Property<int?>("ParentId")
.HasColumnType("int");
b.Property<string>("Path")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<string>("Roles")
.HasMaxLength(500)
.HasColumnType("varchar(500)");
b.Property<int>("Sort")
.HasColumnType("int");
b.Property<string>("Title")
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.HasKey("Id");
b.HasIndex("Name");
b.HasIndex("ParentId");
b.ToTable("Menus");
});
modelBuilder.Entity("AmtScanner.Api.Models.RemoteAccessToken", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<long>("DeviceId")
.HasColumnType("bigint");
b.Property<DateTime>("ExpiresAt")
.HasColumnType("datetime(6)");
b.Property<bool>("IsUsed")
.HasColumnType("tinyint(1)");
b.Property<int>("MaxUseCount")
.HasColumnType("int");
b.Property<string>("Note")
.HasMaxLength(500)
.HasColumnType("varchar(500)");
b.Property<string>("Token")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("varchar(64)");
b.Property<int>("UseCount")
.HasColumnType("int");
b.Property<DateTime?>("UsedAt")
.HasColumnType("datetime(6)");
b.Property<long?>("WindowsCredentialId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("DeviceId");
b.HasIndex("Token")
.IsUnique();
b.HasIndex("WindowsCredentialId");
b.ToTable("RemoteAccessTokens");
});
modelBuilder.Entity("AmtScanner.Api.Models.Role", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Description")
.HasMaxLength(500)
.HasColumnType("varchar(500)");
b.Property<bool>("Enabled")
.HasColumnType("tinyint(1)");
b.Property<string>("RoleCode")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("varchar(50)");
b.Property<string>("RoleName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("varchar(100)");
b.HasKey("Id");
b.HasIndex("RoleCode")
.IsUnique();
b.ToTable("Roles");
});
modelBuilder.Entity("AmtScanner.Api.Models.RoleMenu", b =>
{
b.Property<int>("RoleId")
.HasColumnType("int");
b.Property<int>("MenuId")
.HasColumnType("int");
b.HasKey("RoleId", "MenuId");
b.HasIndex("MenuId");
b.ToTable("RoleMenus");
});
modelBuilder.Entity("AmtScanner.Api.Models.StorageDevice", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
b.Property<long?>("CapacityBytes")
.HasColumnType("bigint");
b.Property<string>("DeviceId")
.HasColumnType("longtext");
b.Property<long>("HardwareInfoId")
.HasColumnType("bigint");
b.Property<string>("InterfaceType")
.HasColumnType("longtext");
b.Property<string>("Model")
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("HardwareInfoId");
b.ToTable("StorageDevices");
});
modelBuilder.Entity("AmtScanner.Api.Models.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Avatar")
.HasMaxLength(500)
.HasColumnType("varchar(500)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("CreatedBy")
.HasMaxLength(100)
.HasColumnType("varchar(100)");
b.Property<string>("Email")
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<string>("Gender")
.IsRequired()
.HasMaxLength(1)
.HasColumnType("varchar(1)");
b.Property<bool>("IsDeleted")
.HasColumnType("tinyint(1)");
b.Property<string>("NickName")
.HasMaxLength(100)
.HasColumnType("varchar(100)");
b.Property<string>("PasswordHash")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<string>("Phone")
.HasMaxLength(20)
.HasColumnType("varchar(20)");
b.Property<string>("RefreshToken")
.HasMaxLength(500)
.HasColumnType("varchar(500)");
b.Property<DateTime?>("RefreshTokenExpiryTime")
.HasColumnType("datetime(6)");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(1)
.HasColumnType("varchar(1)");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("UpdatedBy")
.HasMaxLength(100)
.HasColumnType("varchar(100)");
b.Property<string>("UserName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("varchar(100)");
b.HasKey("Id");
b.HasIndex("UserName")
.IsUnique();
b.ToTable("Users");
});
modelBuilder.Entity("AmtScanner.Api.Models.UserRole", b =>
{
b.Property<int>("UserId")
.HasColumnType("int");
b.Property<int>("RoleId")
.HasColumnType("int");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("UserRoles");
});
modelBuilder.Entity("AmtScanner.Api.Models.WindowsCredential", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Domain")
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<bool>("IsDefault")
.HasColumnType("tinyint(1)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.Property<string>("Note")
.HasMaxLength(500)
.HasColumnType("varchar(500)");
b.Property<string>("Password")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("varchar(500)");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Username")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("varchar(200)");
b.HasKey("Id");
b.HasIndex("Name");
b.ToTable("WindowsCredentials");
});
modelBuilder.Entity("AmtScanner.Api.Models.HardwareInfo", b =>
{
b.HasOne("AmtScanner.Api.Models.AmtDevice", "Device")
.WithMany()
.HasForeignKey("DeviceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Device");
});
modelBuilder.Entity("AmtScanner.Api.Models.MemoryModule", b =>
{
b.HasOne("AmtScanner.Api.Models.HardwareInfo", "HardwareInfo")
.WithMany("MemoryModules")
.HasForeignKey("HardwareInfoId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("HardwareInfo");
});
modelBuilder.Entity("AmtScanner.Api.Models.Menu", b =>
{
b.HasOne("AmtScanner.Api.Models.Menu", "Parent")
.WithMany("Children")
.HasForeignKey("ParentId")
.OnDelete(DeleteBehavior.Restrict);
b.Navigation("Parent");
});
modelBuilder.Entity("AmtScanner.Api.Models.RemoteAccessToken", b =>
{
b.HasOne("AmtScanner.Api.Models.AmtDevice", "Device")
.WithMany()
.HasForeignKey("DeviceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AmtScanner.Api.Models.WindowsCredential", "WindowsCredential")
.WithMany()
.HasForeignKey("WindowsCredentialId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Device");
b.Navigation("WindowsCredential");
});
modelBuilder.Entity("AmtScanner.Api.Models.RoleMenu", b =>
{
b.HasOne("AmtScanner.Api.Models.Menu", "Menu")
.WithMany("RoleMenus")
.HasForeignKey("MenuId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AmtScanner.Api.Models.Role", "Role")
.WithMany("RoleMenus")
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Menu");
b.Navigation("Role");
});
modelBuilder.Entity("AmtScanner.Api.Models.StorageDevice", b =>
{
b.HasOne("AmtScanner.Api.Models.HardwareInfo", "HardwareInfo")
.WithMany("StorageDevices")
.HasForeignKey("HardwareInfoId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("HardwareInfo");
});
modelBuilder.Entity("AmtScanner.Api.Models.UserRole", b =>
{
b.HasOne("AmtScanner.Api.Models.Role", "Role")
.WithMany("UserRoles")
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("AmtScanner.Api.Models.User", "User")
.WithMany("UserRoles")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Role");
b.Navigation("User");
});
modelBuilder.Entity("AmtScanner.Api.Models.HardwareInfo", b =>
{
b.Navigation("MemoryModules");
b.Navigation("StorageDevices");
});
modelBuilder.Entity("AmtScanner.Api.Models.Menu", b =>
{
b.Navigation("Children");
b.Navigation("RoleMenus");
});
modelBuilder.Entity("AmtScanner.Api.Models.Role", b =>
{
b.Navigation("RoleMenus");
b.Navigation("UserRoles");
});
modelBuilder.Entity("AmtScanner.Api.Models.User", b =>
{
b.Navigation("UserRoles");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AmtScanner.Api.Migrations
{
/// <inheritdoc />
public partial class AddMenuIsSystemColumn : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsSystem",
table: "Menus",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsSystem",
table: "Menus");
}
}
}

View File

@ -224,6 +224,9 @@ namespace AmtScanner.Api.Migrations
b.Property<bool>("IsIframe")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsSystem")
.HasColumnType("tinyint(1)");
b.Property<bool>("KeepAlive")
.HasColumnType("tinyint(1)");

View File

@ -73,6 +73,11 @@ public class Menu
/// </summary>
public bool IsIframe { get; set; } = false;
/// <summary>
/// 是否系统内置菜单(不可删除)
/// </summary>
public bool IsSystem { get; set; } = false;
/// <summary>
/// 是否隐藏标签页
/// </summary>