using System.Security.Claims;
using AgriculturalPlatform.Api.Data;
using AgriculturalPlatform.Api.Dtos;
using AgriculturalPlatform.Api.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace AgriculturalPlatform.Api.Controllers;
/// 菜单/权限管理
[ApiController]
[Route("api/menus")]
[Authorize]
public class MenusController(AppDbContext db) : ControllerBase
{
/// 菜单树(全部)
[HttpGet]
public async Task Tree()
{
var menus = await db.SysMenus.AsNoTracking().OrderBy(m => m.Sort).ThenBy(m => m.Id).ToListAsync();
return Ok(BuildTree(menus, null));
}
/// 当前登录用户的菜单与权限
[HttpGet("my")]
public async Task My()
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (userId is null) return Unauthorized();
// 用户角色 -> 菜单
var user = await db.Users.Include(u => u.SysRole).FirstOrDefaultAsync(u => u.Id == int.Parse(userId));
if (user is null) return Unauthorized();
int[] menuIds;
if (user.SysRole?.Code == "super_admin" || user.Role == UserRole.SuperAdmin)
{
menuIds = await db.SysMenus.Select(m => m.Id).ToArrayAsync();
}
else if (user.RoleId is int rid)
{
menuIds = await db.SysRoleMenus.Where(rm => rm.RoleId == rid).Select(rm => rm.MenuId).ToArrayAsync();
}
else
{
menuIds = Array.Empty();
}
var menus = await db.SysMenus.AsNoTracking()
.Where(m => menuIds.Contains(m.Id))
.OrderBy(m => m.Sort).ThenBy(m => m.Id)
.ToListAsync();
var tree = BuildTree(menus, null);
var permissions = menus.Where(m => !string.IsNullOrWhiteSpace(m.Permission)).Select(m => m.Permission).Distinct().ToArray();
return Ok(new { menus = tree, permissions });
}
private static List BuildTree(List all, int? parentId)
{
return all.Where(m => m.ParentId == parentId)
.Select(m => new MenuDto(
m.Id, m.ParentId, m.Name, m.Path, m.Component, m.Icon, m.Type,
m.Permission, m.Visible, m.Sort, BuildTree(all, m.Id)))
.ToList();
}
/// 新增菜单
[HttpPost]
public async Task Create(MenuSaveRequest req)
{
var menu = new SysMenu
{
ParentId = req.ParentId, Name = req.Name, Path = req.Path, Component = req.Component,
Icon = req.Icon, Type = req.Type, Permission = req.Permission, Visible = req.Visible,
Sort = req.Sort, CreatedAt = DateTime.Now
};
db.SysMenus.Add(menu);
await db.SaveChangesAsync();
return Ok(new { message = "保存成功", id = menu.Id });
}
/// 修改菜单
[HttpPut("{id:int}")]
public async Task Update(int id, MenuSaveRequest req)
{
var menu = await db.SysMenus.FindAsync(id);
if (menu is null) return NotFound();
if (req.ParentId == id) return BadRequest(new { message = "父级不能选择自身" });
menu.ParentId = req.ParentId; menu.Name = req.Name; menu.Path = req.Path;
menu.Component = req.Component; menu.Icon = req.Icon; menu.Type = req.Type;
menu.Permission = req.Permission; menu.Visible = req.Visible; menu.Sort = req.Sort;
await db.SaveChangesAsync();
return Ok(new { message = "保存成功" });
}
/// 删除菜单(有子菜单或已被角色引用时禁止删除)
[HttpDelete("{id:int}")]
public async Task Delete(int id)
{
if (await db.SysMenus.AnyAsync(m => m.ParentId == id))
return BadRequest(new { message = "请先删除子菜单" });
if (await db.SysRoleMenus.AnyAsync(rm => rm.MenuId == id))
return BadRequest(new { message = "该菜单已被角色引用,请先解除关联" });
var menu = await db.SysMenus.FindAsync(id);
if (menu is null) return NotFound();
db.SysMenus.Remove(menu);
await db.SaveChangesAsync();
return Ok(new { message = "删除成功" });
}
}