平安校园
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MenuService.cs 11 KiB

4 月之前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. 
  2. //
  3. namespace SafeCampus.System;
  4. /// <summary>
  5. /// <inheritdoc cref="IMenuService"/>
  6. /// </summary>
  7. public class MenuService : DbRepository<SysResource>, IMenuService
  8. {
  9. private readonly ILogger<MenuService> _logger;
  10. private readonly IResourceService _resourceService;
  11. private readonly IRelationService _relationService;
  12. public MenuService(ILogger<MenuService> logger, IResourceService resourceService, IRelationService relationService)
  13. {
  14. _logger = logger;
  15. _resourceService = resourceService;
  16. _relationService = relationService;
  17. }
  18. /// <inheritdoc/>
  19. public List<SysResource> ConstructMenuTrees(List<SysResource> resourceList, long? parentId = 0)
  20. {
  21. //找下级资源ID列表
  22. var resources = resourceList.Where(it => it.ParentId == parentId).OrderBy(it => it.SortCode).ToList();
  23. if (resources.Count > 0)//如果数量大于0
  24. {
  25. var data = new List<SysResource>();
  26. foreach (var item in resources)//遍历资源
  27. {
  28. item.Children = ConstructMenuTrees(resourceList, item.Id);//添加子节点
  29. data.Add(item);//添加到列表
  30. }
  31. return data;//返回结果
  32. }
  33. return new List<SysResource>();
  34. }
  35. /// <inheritdoc />
  36. public async Task<List<SysResource>> Tree(MenuTreeInput input, bool showDisabled = true)
  37. {
  38. //获取所有菜单
  39. var sysResources = await _resourceService.GetListByCategory(CateGoryConst.RESOURCE_MENU);
  40. sysResources = sysResources.WhereIF(input.Module != null, it => it.Module.Value == input.Module.Value)//根据模块查找
  41. .WhereIF(!showDisabled, it => it.Status == CommonStatusConst.ENABLE)//是否显示禁用的
  42. .WhereIF(!string.IsNullOrEmpty(input.SearchKey), it => it.Title == input.SearchKey)//根据关键字查找
  43. .ToList();
  44. //构建菜单树
  45. var tree = ConstructMenuTrees(sysResources);
  46. return tree;
  47. }
  48. /// <inheritdoc />
  49. public async Task<List<SysResource>> ShortcutTree(List<SysResource> sysResources = null)
  50. {
  51. if (sysResources == null)
  52. //获取所有菜单
  53. sysResources = (await _resourceService.GetAllModuleAndMenuAndSpaList())
  54. .Where(it => it.Status == CommonStatusConst.ENABLE).ToList();
  55. // //获取所有单页
  56. // var sysSpas = (await _resourceService.GetConfigsByCategory(CateGoryConst.RESOURCE_SPA))
  57. // .Where(it => it.Status == CommonStatusConst.ENABLE).ToList();
  58. sysResources.ForEach(it =>
  59. {
  60. if (it.MenuType == SysResourceConst.CATALOG)
  61. it.ParentId = it.Module.Value;//目录的父级ID设置为模块ID
  62. });
  63. //构建菜单树
  64. var tree = ConstructMenuTrees(sysResources, null);
  65. //将单页的排前面根据排序码排序
  66. tree = tree.OrderByDescending(it => it.Category == CateGoryConst.RESOURCE_SPA).ThenBy(it => it.SortCode).ToList();
  67. return tree;
  68. }
  69. /// <inheritdoc />
  70. public async Task Add(MenuAddInput input)
  71. {
  72. await CheckInput(input);//检查参数
  73. var sysResource = input.Adapt<SysResource>();//实体转换
  74. if (await InsertAsync(sysResource))//插入数据
  75. await _resourceService.RefreshCache(CateGoryConst.RESOURCE_MENU);//刷新菜单缓存
  76. }
  77. /// <inheritdoc />
  78. public async Task Edit(MenuEditInput input)
  79. {
  80. var resource = await CheckInput(input);//检查参数
  81. var sysResource = input.Adapt<SysResource>();//实体转换
  82. var updatePath = resource.Path != input.Path;//是否更新路径
  83. var permissions = new List<SysRelation>();
  84. if (updatePath)
  85. {
  86. //获取所有角色和用户的权限关系
  87. var rolePermissions = await _relationService.GetRelationByCategory(CateGoryConst.RELATION_SYS_ROLE_HAS_PERMISSION);
  88. var userPermissions = await _relationService.GetRelationByCategory(CateGoryConst.RELATION_SYS_USER_HAS_PERMISSION);
  89. //找到所有匹配的权限
  90. rolePermissions = rolePermissions.Where(it => it.TargetId.Contains(resource.Path)).ToList();
  91. userPermissions = userPermissions.Where(it => it.TargetId.Contains(resource.Path)).ToList();
  92. //更新路径
  93. rolePermissions.ForEach(it => it.TargetId = it.TargetId.Replace(resource.Path, input.Path));
  94. userPermissions.ForEach(it => it.TargetId = it.TargetId.Replace(resource.Path, input.Path));
  95. //添加到权限列表
  96. permissions.AddRange(rolePermissions);
  97. permissions.AddRange(userPermissions);
  98. }
  99. //事务
  100. var result = await Tenant.UseTranAsync(async () =>
  101. {
  102. await UpdateAsync(sysResource);//更新数据
  103. if (permissions.Count > 0)//如果权限列表大于0就更新
  104. {
  105. await Context.Updateable(permissions)
  106. .ExecuteCommandAsync();//更新关系表
  107. }
  108. });
  109. if (result.IsSuccess)//如果成功了
  110. {
  111. await _resourceService.RefreshCache(CateGoryConst.RESOURCE_MENU);//刷新菜单缓存
  112. //刷新关系表缓存
  113. if (updatePath)
  114. {
  115. await _relationService.RefreshCache(CateGoryConst.RELATION_SYS_ROLE_HAS_PERMISSION);
  116. await _relationService.RefreshCache(CateGoryConst.RELATION_SYS_USER_HAS_PERMISSION);
  117. }
  118. }
  119. }
  120. /// <inheritdoc />
  121. public async Task Delete(BaseIdListInput input)
  122. {
  123. //获取所有ID
  124. var ids = input.Ids;
  125. if (ids.Count > 0)
  126. {
  127. //获取所有菜单和按钮
  128. var resourceList = await _resourceService.GetListAsync(new List<string> { CateGoryConst.RESOURCE_MENU, CateGoryConst.RESOURCE_BUTTON });
  129. //找到要删除的菜单
  130. var sysResources = resourceList.Where(it => ids.Contains(it.Id)).ToList();
  131. //查找内置菜单
  132. var system = sysResources.Where(it => it.Code == SysResourceConst.SYSTEM).FirstOrDefault();
  133. if (system != null)
  134. throw Oops.Bah($"不可删除系统菜单:{system.Title}");
  135. //需要删除的资源ID列表
  136. var resourceIds = new List<long>();
  137. //遍历菜单列表
  138. sysResources.ForEach(it =>
  139. {
  140. //获取菜单所有子节点
  141. var child = _resourceService.GetChildListById(resourceList, it.Id, false);
  142. //将子节点ID添加到删除资源ID列表
  143. resourceIds.AddRange(child.Select(it => it.Id).ToList());
  144. resourceIds.Add(it.Id);//添加到删除资源ID列表
  145. });
  146. ids.AddRange(resourceIds);//添加到删除ID列表
  147. //事务
  148. var result = await Tenant.UseTranAsync(async () =>
  149. {
  150. await DeleteByIdsAsync(ids.Cast<object>().ToArray());//删除菜单和按钮
  151. await Context.Deleteable<SysRelation>()//关系表删除对应SYS_ROLE_HAS_RESOURCE
  152. .Where(it => it.Category == CateGoryConst.RELATION_SYS_ROLE_HAS_RESOURCE && resourceIds.Contains(SqlFunc.ToInt64(it.TargetId)))
  153. .ExecuteCommandAsync();
  154. });
  155. if (result.IsSuccess)//如果成功了
  156. {
  157. await _resourceService.RefreshCache(CateGoryConst.RESOURCE_MENU);//资源表菜单刷新缓存
  158. await _resourceService.RefreshCache(CateGoryConst.RESOURCE_BUTTON);//资源表按钮刷新缓存
  159. await _relationService.RefreshCache(CateGoryConst.RELATION_SYS_ROLE_HAS_RESOURCE);//关系表刷新缓存
  160. }
  161. else
  162. {
  163. //写日志
  164. _logger.LogError(result.ErrorMessage, result.ErrorException);
  165. throw Oops.Oh(ErrorCodeEnum.A0002);
  166. }
  167. }
  168. }
  169. /// <inheritdoc />
  170. public async Task<SysResource> Detail(BaseIdInput input)
  171. {
  172. var sysResources = await _resourceService.GetListByCategory(CateGoryConst.RESOURCE_MENU);
  173. var resource = sysResources.Where(it => it.Id == input.Id).FirstOrDefault();
  174. return resource;
  175. }
  176. /// <inheritdoc />
  177. public async Task ChangeModule(MenuChangeModuleInput input)
  178. {
  179. var sysResource = await Detail(new BaseIdInput { Id = input.Id });
  180. if (sysResource != null)
  181. {
  182. if (sysResource.Module == input.Module)//如果模块ID没变直接返回
  183. return;
  184. if (sysResource.ParentId != 0)
  185. throw Oops.Bah("非顶级菜单不可修改所属模块");
  186. //获取所有菜单和模块
  187. var resourceList = await _resourceService.GetListAsync(new List<string> { CateGoryConst.RESOURCE_MENU, CateGoryConst.RESOURCE_MODULE });
  188. if (!resourceList.Any(it => it.Category == CateGoryConst.RESOURCE_MODULE && it.Id == input.Module.Value))
  189. throw Oops.Bah("不存在的模块");
  190. //获取所有菜单
  191. var menuList = resourceList.Where(it => it.Category == CateGoryConst.RESOURCE_MENU).ToList();
  192. //获取需要改变模块菜单的所有子菜单
  193. var childList = _resourceService.GetChildListById(menuList, input.Id);
  194. childList.ForEach(it => it.Module = input.Module);
  195. //更新数据
  196. await UpdateRangeAsync(childList);
  197. //刷新菜单缓存
  198. await _resourceService.RefreshCache(CateGoryConst.RESOURCE_MENU);
  199. }
  200. }
  201. #region 方法
  202. /// <summary>
  203. /// 检查输入参数
  204. /// </summary>
  205. /// <param name="sysResource"></param>
  206. private async Task<SysResource> CheckInput(SysResource sysResource)
  207. {
  208. //获取所有菜单列表
  209. var menList = await _resourceService.GetListByCategory(CateGoryConst.RESOURCE_MENU);
  210. //判断是否有同级且同名的菜单
  211. if (menList.Any(it => it.ParentId == sysResource.ParentId && it.Title == sysResource.Title && it.Id != sysResource.Id))
  212. throw Oops.Bah($"存在重复的菜单名称:{sysResource.Title}");
  213. if (sysResource.ParentId != 0)
  214. {
  215. //获取父级,判断父级ID正不正确
  216. var parent = menList.Where(it => it.Id == sysResource.ParentId).FirstOrDefault();
  217. if (parent != null)
  218. {
  219. if (parent.Module != sysResource.Module)//如果父级的模块和当前模块不一样
  220. throw Oops.Bah("模块与上级菜单不一致");
  221. if (parent.Id == sysResource.Id)
  222. throw Oops.Bah("上级菜单不能选择自己");
  223. }
  224. else
  225. {
  226. throw Oops.Bah($"上级菜单不存在:{sysResource.ParentId}");
  227. }
  228. }
  229. //如果ID大于0表示编辑
  230. if (sysResource.Id > 0)
  231. {
  232. var resource = menList.Where(it => it.Id == sysResource.Id).FirstOrDefault();
  233. if (resource == null)
  234. throw Oops.Bah($"菜单不存在:{sysResource.Id}");
  235. return resource;
  236. }
  237. return null;
  238. }
  239. #endregion 方法
  240. }