Files
ThingsGateway/src/Admin/ThingsGateway.Admin.Application/Services/Resource/SysResourceService.cs
2025-07-24 19:46:30 +08:00

390 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://thingsgateway.cn/
// QQ群605534569
//------------------------------------------------------------------------------
using Microsoft.Extensions.DependencyInjection;
using ThingsGateway.FriendlyException;
namespace ThingsGateway.Admin.Application;
internal sealed class SysResourceService : BaseService<SysResource>, ISysResourceService
{
private readonly IRelationService _relationService;
private string CacheKey = $"{CacheConst.Cache_SysResource}";
public SysResourceService(IRelationService relationService)
{
_relationService = relationService;
}
#region
[OperDesc("CopyResource")]
public async Task CopyAsync(IEnumerable<long> ids, long moduleId)
{
var resourceList = await GetAllAsync().ConfigureAwait(false);
var myResourceList = resourceList.Where(a => ids.Contains(a.Id)).ToList();
var parent = GetMyParentResources(resourceList, myResourceList);
myResourceList = myResourceList.Concat(parent).Where(a => a.Category != ResourceCategoryEnum.Module).DistinctBy(a => a.Id).ToList();
var tree = ConstructMenuTrees(myResourceList).ToList();
SysResourceService.SetTreeValue(tree, moduleId, 0);
var data = MenuTreesToSaveLevel(tree);
using var db = GetDB();
var result = await db.Insertable(data).ExecuteCommandAsync().ConfigureAwait(false);
RefreshCache();//刷新缓存
}
private static void SetTreeValue(List<SysResource> tree, long moduleId, long parentId)
{
if (tree == null) return;
foreach (var item in tree)
{
item.Id = CommonUtils.GetSingleId();
item.ParentId = parentId;
item.Code = RandomHelper.CreateRandomString(10);
item.Module = moduleId;
SysResourceService.SetTreeValue(item.Children, moduleId, item.Id);
}
}
[OperDesc("ChangeParentResource")]
public async Task ChangeParentAsync(long id, long parentMenuId)
{
var resourceList = await GetAllAsync().ConfigureAwait(false);
var resource = resourceList.First(a => a.Id == id);
resource.ParentId = parentMenuId;
using var db = GetDB();
var result = await db.UpdateableT(resource).ExecuteCommandAsync().ConfigureAwait(false);
RefreshCache();//刷新缓存
_relationService.RefreshCache(RelationCategoryEnum.RoleHasResource);//关系表刷新缓存
_relationService.RefreshCache(RelationCategoryEnum.UserHasResource);//关系表刷新缓存
}
/// <summary>
/// 删除资源
/// </summary>
/// <param name="ids">id列表</param>
/// <returns></returns>
[OperDesc("DeleteResource")]
public async Task<bool> DeleteResourceAsync(HashSet<long> ids)
{
//删除
if (ids.Count != 0)
{
//获取所有菜单和按钮
var resourceList = await GetAllAsync().ConfigureAwait(false);
//找到要删除的菜单
var delSysResources = resourceList.Where(it => ids.Contains(it.Id));
//找到要删除的模块
var delModules = resourceList.Where(a => a.Category == ResourceCategoryEnum.Module).Where(it => ids.Contains(it.Id));
//获取模块下的所有列表
var delHashSet = delModules.Select(a => a.Id).ToHashSet();
if (delHashSet.Count != 0)
{
var delModuleResources = resourceList.Where(it => delHashSet.Contains(it.Module));
delSysResources = delSysResources.Concat(delModuleResources).ToHashSet();
}
//查找内置菜单
var system = delSysResources.FirstOrDefault(it => it.Code == ResourceConst.System);
if (system != null)
throw Oops.Bah(Localizer["CanotDeleteSystemResource", system.Title]);
//需要删除的资源ID列表
var resourceIds = delSysResources.SelectMany(it =>
{
var child = GetResourceChilden(resourceList, it.Id);
return child.Select(c => c.Id).Concat(new List<long>() { it.Id });
});
var deleteIds = ids.Concat(resourceIds).ToHashSet();//添加到删除ID列表
using var db = GetDB();
//事务
var result = await db.UseTranAsync(async () =>
{
await db.Deleteable<SysResource>().In(deleteIds.ToList()).ExecuteCommandAsync().ConfigureAwait(false);//删除菜单和按钮
await db.Deleteable<SysRelation>()//关系表删除对应RoleHasResource
.Where(it => it.Category == RelationCategoryEnum.RoleHasResource && resourceIds.Contains(SqlFunc.ToInt64(it.TargetId))).ExecuteCommandAsync().ConfigureAwait(false);
await db.Deleteable<SysRelation>()//关系表删除对应UserHasResource
.Where(it => it.Category == RelationCategoryEnum.UserHasResource && resourceIds.Contains(SqlFunc.ToInt64(it.TargetId))).ExecuteCommandAsync().ConfigureAwait(false);
}).ConfigureAwait(false);
if (result.IsSuccess)//如果成功了
{
RefreshCache();//资源表菜单刷新缓存
_relationService.RefreshCache(RelationCategoryEnum.RoleHasResource);//关系表刷新缓存
_relationService.RefreshCache(RelationCategoryEnum.UserHasResource);//关系表刷新缓存
return true;
}
else
{
throw new(result.ErrorMessage, result.ErrorException);
}
}
return false;
}
/// <summary>
/// 从缓存/数据库读取全部资源列表
/// </summary>
/// <returns>全部资源列表</returns>
public async Task<List<SysResource>> GetAllAsync()
{
var sysResources = App.CacheService.Get<List<SysResource>>(CacheConst.Cache_SysResource);
if (sysResources == null)
{
using var db = GetDB();
sysResources = await db.Queryable<SysResource>().ToListAsync().ConfigureAwait(false);
App.CacheService.Set(CacheConst.Cache_SysResource, sysResources);
}
return sysResources;
}
/// <summary>
/// 根据菜单Id获取菜单列表
/// </summary>
/// <param name="menuIds">菜单id列表</param>
/// <returns>菜单列表</returns>
public async Task<IEnumerable<SysResource>> GetMenuByMenuIdsAsync(IEnumerable<long> menuIds)
{
var menuList = await GetAllAsync().ConfigureAwait(false);
var menus = menuList.Where(it => it.Category == ResourceCategoryEnum.Menu && menuIds.Contains(it.Id));
return menus;
}
/// <summary>
/// 根据模块Id获取模块列表
/// </summary>
/// <param name="moduleIds">模块id列表</param>
/// <returns>菜单列表</returns>
public async Task<IEnumerable<SysResource>> GetMuduleByMuduleIdsAsync(IEnumerable<long> moduleIds)
{
var moduleList = await GetAllAsync().ConfigureAwait(false);
var modules = moduleList.Where(it => it.Category == ResourceCategoryEnum.Module && moduleIds.Contains(it.Id));
return modules;
}
/// <summary>
/// 表格查询
/// </summary>
/// <param name="options">查询条件</param>
/// <param name="searchModel">查询条件</param>
/// <returns></returns>
public Task<QueryData<SysResource>> PageAsync(QueryPageOptions options, ResourceTableSearchModel searchModel)
{
return QueryAsync(options, b => b.Where(a => (a.Category == ResourceCategoryEnum.Module && a.Id == searchModel.Module) || (a.Category != ResourceCategoryEnum.Module && a.Module == searchModel.Module)));
}
/// <summary>
/// 保存资源
/// </summary>
/// <param name="input">资源</param>
/// <param name="type">保存类型</param>
[OperDesc("SaveResource")]
public async Task<bool> SaveResourceAsync(SysResource input, ItemChangedType type)
{
var resource = await CheckInput(input).ConfigureAwait(false);//检查参数
using var db = GetDB();
if (type == ItemChangedType.Add)
{
var result = await db.InsertableT(input).ExecuteCommandAsync().ConfigureAwait(false);
RefreshCache();//刷新缓存
return result > 0;
}
else
{
var permissions = new List<SysRelation>();
if (resource.Href != input.Href)
{
//获取所有角色和用户的权限关系
var rolePermissions = await _relationService.GetRelationByCategoryAsync(RelationCategoryEnum.RoleHasPermission).ConfigureAwait(false);
var userPermissions = await _relationService.GetRelationByCategoryAsync(RelationCategoryEnum.UserHasPermission).ConfigureAwait(false);
//找到所有匹配的权限
rolePermissions = rolePermissions.Where(it => it.TargetId!.Contains(resource.Href)).ToList();
userPermissions = userPermissions.Where(it => it.TargetId!.Contains(resource.Href)).ToList();
//更新路径
rolePermissions.ForEach(it => it.TargetId = it.TargetId!.Replace(resource.Href, input.Href));
userPermissions.ForEach(it => it.TargetId = it.TargetId!.Replace(resource.Href, input.Href));
//添加到权限列表
permissions.AddRange(rolePermissions);
permissions.AddRange(userPermissions);
}
//事务
var result = await db.UseTranAsync(async () =>
{
await db.UpdateableT(input).ExecuteCommandAsync().ConfigureAwait(false);//更新数据
if (permissions.Count > 0)//如果权限列表大于0就更新
{
await db.Updateable(permissions).ExecuteCommandAsync().ConfigureAwait(false);//更新关系表
}
}).ConfigureAwait(false);
if (result.IsSuccess)//如果成功了
{
RefreshCache();//刷新菜单缓存
if (resource.Href != input.Href)
{
_relationService.RefreshCache(RelationCategoryEnum.RoleHasPermission);
_relationService.RefreshCache(RelationCategoryEnum.UserHasPermission);
}
return true;
}
else
{
throw new(result.ErrorMessage, result.ErrorException);
}
}
}
#endregion
#region
/// <summary>
/// 刷新缓存
/// </summary>
public void RefreshCache()
{
App.CacheService.Remove(CacheConst.Cache_SysResource);
//删除超级管理员的缓存
App.RootServices.GetRequiredService<ISysUserService>().DeleteUserFromCache(RoleConst.SuperAdminId);
}
#endregion
#region
/// <summary>
/// 检查输入参数
/// </summary>
/// <param name="sysResource">资源</param>
private async Task<SysResource> CheckInput(SysResource sysResource)
{
if (sysResource.Code.IsNullOrWhiteSpace()) //默认编码
{
sysResource.Code = RandomHelper.CreateRandomString(10);
}
//如果菜单类型是菜单
//if (sysResource.Category == ResourceCategoryEnum.Menu)
//{
// if (string.IsNullOrEmpty(sysResource.Href))
// throw Oops.Bah("ResourceMenuHrefNotNull");
//}
//获取所有列表
var menList = await GetAllAsync().ConfigureAwait(false);
//判断是否有同级且同名
if (menList.Any(it => it.ParentId == sysResource.ParentId && it.Title == sysResource.Title && it.Id != sysResource.Id && it.Module == sysResource.Module))
throw Oops.Bah(Localizer["ResourceDup", sysResource.Title]);
if (sysResource.ParentId != 0)
{
//获取父级,判断父级ID正不正确
var parent = menList.Where(it => it.Id == sysResource.ParentId).FirstOrDefault();
if (parent != null)
{
if (parent.Module != sysResource.Module)//如果父级的模块和当前模块不一样
throw Oops.Bah(Localizer["ModuleIdDiff"]);
if (parent.Id == sysResource.Id)
throw Oops.Bah(Localizer["ResourceChoiceSelf"]);
}
else
{
throw Oops.Bah(Localizer["ResourceParentNull", sysResource.ParentId]);
}
}
//如果ID大于0表示编辑
if (sysResource.Id > 0)
{
var resource = menList.FirstOrDefault(it => it.Id == sysResource.Id);
if (resource == null)
throw Oops.Bah(Localizer["NotFoundResource"]);
return resource;
}
return null;
}
#endregion
/// <inheritdoc/>
private static List<SysResource> MenuTreesToSaveLevel(IEnumerable<SysResource> resourceList)
{
var flatList = new List<SysResource>();
void TraverseTree(SysResource node)
{
// 添加当前节点到平级列表
flatList.Add(node);
// 如果当前节点有子节点,则递归处理每个子节点
if (node.Children?.Count > 0)
{
foreach (var child in node.Children)
{
TraverseTree(child);
}
}
}
// 遍历资源列表中的每个顶级节点
foreach (var resource in resourceList)
{
TraverseTree(resource);
}
return flatList;
}
/// <inheritdoc/>
public IEnumerable<SysResource> ConstructMenuTrees(List<SysResource> resourceList, long parentId = 0)
{
//找下级资源ID列表
var resources = resourceList.Where(it => it.ParentId == parentId).OrderBy(it => it.SortCode);
foreach (var item in resources)//遍历资源
{
var children = ConstructMenuTrees(resourceList, item.Id).ToList();//添加子节点
item.Children = children.Count > 0 ? children : null;
}
return resources;
}
/// <inheritdoc/>
public IEnumerable<SysResource> GetMyParentResources(IEnumerable<SysResource> allMenuList, IEnumerable<SysResource> myMenus)
{
var parentList = myMenus
.SelectMany(it => GetResourceParent(allMenuList, it.ParentId))
.Where(parent => parent != null
&& !myMenus.Contains(parent)
&& !myMenus.Any(m => m.Id == parent.Id))
.Distinct();
return parentList;
}
/// <inheritdoc/>
public IEnumerable<SysResource> GetResourceChilden(IEnumerable<SysResource> resourceList, long parentId)
{
//找下级资源ID列表
return resourceList.Where(it => it.ParentId == parentId)
.SelectMany(item => new List<SysResource> { item }.Concat(GetResourceChilden(resourceList, item.Id)));
}
/// <inheritdoc/>
public IEnumerable<SysResource> GetResourceParent(IEnumerable<SysResource> resourceList, long resourceId)
{
//找上级资源ID列表
return resourceList.Where(it => it.Id == resourceId)
.SelectMany(item => new List<SysResource> { item }.Concat(GetResourceParent(resourceList, item.ParentId)));
}
}