平安校园
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.
 
 
 
 
 
 

424 lines
17 KiB

  1. //
  2. using System.ComponentModel;
  3. namespace SafeCampus.System;
  4. /// <inheritdoc cref="IResourceService"/>
  5. public class ResourceService : DbRepository<SysResource>, IResourceService
  6. {
  7. private readonly ISimpleCacheService _simpleCacheService;
  8. private readonly IRelationService _relationService;
  9. public ResourceService(ISimpleCacheService simpleCacheService, IRelationService relationService)
  10. {
  11. _simpleCacheService = simpleCacheService;
  12. _relationService = relationService;
  13. }
  14. /// <inheritdoc />
  15. public async Task<List<string>> GetCodeByIds(List<long> ids, string category)
  16. {
  17. //根据分类获取所有
  18. var sysResources = await GetListByCategory(category);
  19. //条件查询
  20. var result = sysResources.Where(it => ids.Contains(it.Id)).Select(it => it.Code).ToList();
  21. return result;
  22. }
  23. /// <inheritdoc/>
  24. public async Task<List<SysResource>> GetListAsync(List<string>? categoryList = null)
  25. {
  26. //定义结果
  27. var sysResources = new List<SysResource>();
  28. //定义资源分类列表,如果是空的则获取全部资源
  29. categoryList = categoryList != null
  30. ? categoryList
  31. : new List<string>
  32. {
  33. CateGoryConst.RESOURCE_MENU, CateGoryConst.RESOURCE_BUTTON,
  34. CateGoryConst.RESOURCE_SPA, CateGoryConst.RESOURCE_MODULE
  35. };
  36. //遍历列表
  37. foreach (var category in categoryList)
  38. {
  39. //根据分类获取到资源列表
  40. var data = await GetListByCategory(category);
  41. //添加到结果集
  42. sysResources.AddRange(data);
  43. }
  44. return sysResources;
  45. }
  46. /// <inheritdoc/>
  47. public async Task<List<SysResource>> GetAllModuleAndMenuAndSpaList()
  48. {
  49. //获取所有的菜单和模块以及单页面列表,
  50. var sysResources = await GetListAsync(new List<string>
  51. {
  52. CateGoryConst.RESOURCE_MODULE, CateGoryConst.RESOURCE_MENU, CateGoryConst.RESOURCE_SPA
  53. });
  54. if (sysResources != null)
  55. {
  56. //并按分类和排序码排序
  57. sysResources = sysResources.OrderBy(it => it.Category).ThenBy(it => it.SortCode).ToList();
  58. }
  59. return sysResources;
  60. }
  61. /// <inheritdoc/>
  62. public async Task<List<SysResource>> GetMenuAndSpaListByModuleId(long id)
  63. {
  64. //获取所有的菜单和模块以及单页面列表,
  65. var sysResources = await GetListAsync(new List<string> { CateGoryConst.RESOURCE_MENU, CateGoryConst.RESOURCE_SPA });
  66. if (sysResources != null)
  67. {
  68. //并按分类和排序码排序
  69. sysResources = sysResources.Where(it => it.Category == CateGoryConst.RESOURCE_SPA || it.Module == id)//根据模块ID获取菜单
  70. .OrderBy(it => it.Category).ThenBy(it => it.SortCode).ToList();//排序
  71. }
  72. return sysResources;
  73. }
  74. /// <inheritdoc/>
  75. public async Task RefreshCache(string category = null)
  76. {
  77. //如果分类是空的
  78. if (category == null)
  79. {
  80. //删除全部key
  81. _simpleCacheService.DelByPattern(SystemConst.CACHE_SYS_RESOURCE);
  82. await GetListAsync();
  83. }
  84. else
  85. {
  86. //否则只删除一个Key
  87. _simpleCacheService.Remove(SystemConst.CACHE_SYS_RESOURCE + category);
  88. await GetListByCategory(category);
  89. }
  90. }
  91. /// <inheritdoc />
  92. public async Task<List<SysResource>> GetChildListById(long resId, bool isContainOneself = true)
  93. {
  94. //获取所有机构
  95. var sysResources = await GetListAsync();
  96. //查找下级
  97. var childList = GetResourceChildren(sysResources, resId);
  98. if (isContainOneself)//如果包含自己
  99. {
  100. //获取自己的机构信息
  101. var self = sysResources.Where(it => it.Id == resId).FirstOrDefault();
  102. if (self != null) childList.Insert(0, self);//如果机构不为空就插到第一个
  103. }
  104. return childList;
  105. }
  106. /// <inheritdoc />
  107. public List<SysResource> GetChildListById(List<SysResource> sysResources, long resId, bool isContainOneself = true)
  108. {
  109. //查找下级
  110. var childList = GetResourceChildren(sysResources, resId);
  111. if (isContainOneself)//如果包含自己
  112. {
  113. //获取自己的机构信息
  114. var self = sysResources.Where(it => it.Id == resId).FirstOrDefault();
  115. if (self != null) childList.Insert(0, self);//如果机构不为空就插到第一个
  116. }
  117. return childList;
  118. }
  119. /// <inheritdoc />
  120. public async Task<List<SysResource>> GetListByCategory(string category)
  121. {
  122. //先从Redis拿
  123. var sysResources = _simpleCacheService.Get<List<SysResource>>(SystemConst.CACHE_SYS_RESOURCE + category);
  124. if (sysResources == null)
  125. {
  126. //redis没有就去数据库拿
  127. sysResources = await base.GetListAsync(it => it.Category == category);
  128. if (sysResources.Count > 0)
  129. {
  130. //插入Redis
  131. _simpleCacheService.Set(SystemConst.CACHE_SYS_RESOURCE + category, sysResources);
  132. }
  133. }
  134. return sysResources;
  135. }
  136. /// <inheritdoc />
  137. public async Task<List<ResTreeSelector>> ResourceTreeSelector()
  138. {
  139. var resourceTreeSelectors = new List<ResTreeSelector>();//定义结果
  140. //获取模块列表
  141. var moduleList = await GetListByCategory(CateGoryConst.RESOURCE_MODULE);
  142. //遍历模块
  143. foreach (var module in moduleList)
  144. {
  145. //将实体转换为ResourceTreeSelectorOutPut获取基本信息
  146. var resourceTreeSelector = module.Adapt<ResTreeSelector>();
  147. resourceTreeSelector.Menu = await GetRoleGrantResourceMenus(module.Id);
  148. resourceTreeSelectors.Add(resourceTreeSelector);
  149. }
  150. return resourceTreeSelectors;
  151. }
  152. /// <inheritdoc />
  153. public List<PermissionTreeSelector> PermissionTreeSelector(List<string> routes)
  154. {
  155. var permissions = new List<PermissionTreeSelector>();//权限列表
  156. var controllerTypes =
  157. App.EffectiveTypes.Where(u =>
  158. !u.IsInterface && !u.IsAbstract && u.IsDefined(typeof(RolePermissionAttribute), false));
  159. foreach (var controller in controllerTypes)
  160. {
  161. var apiAttribute = controller.GetCustomAttribute<ApiDescriptionSettingsAttribute>();//获取接口描述特性
  162. var tag = apiAttribute.Tag;//获取标签
  163. //获取数据权限特性
  164. var routeAttributes = controller.GetCustomAttributes<RouteAttribute>().ToList();
  165. if (routeAttributes == null)
  166. continue;
  167. var route = routeAttributes[0];//取第一个值
  168. var routeName = GetRouteName(controller.Name, route.Template);//赋值路由名称
  169. //如果路由包含在路由列表中
  170. if (routes.Contains(routeName))
  171. {
  172. //获取所有方法
  173. var methods = controller.GetMethods();
  174. //遍历方法
  175. foreach (var method in methods)
  176. {
  177. //获取忽略数据权限特性
  178. var ignoreRolePermission = method.GetCustomAttribute<IgnoreRolePermissionAttribute>();
  179. if (ignoreRolePermission == null)//如果是空的代表需要数据权限
  180. {
  181. //获取接口描述
  182. var displayName = method.GetCustomAttribute<DisplayNameAttribute>();
  183. if (displayName != null)
  184. {
  185. //默认路由名称
  186. var apiRoute = StringHelper.FirstCharToLower(method.Name);
  187. //获取get特性
  188. var requestGet = method.GetCustomAttribute<HttpGetAttribute>();
  189. if (requestGet != null)//如果是get方法
  190. apiRoute = requestGet.Template;
  191. else
  192. {
  193. //获取post特性
  194. var requestPost = method.GetCustomAttribute<HttpPostAttribute>();
  195. if (requestPost != null)//如果是post方法
  196. apiRoute = requestPost.Template;
  197. }
  198. apiRoute = route.Template + $"/{apiRoute}";
  199. if (!apiRoute.StartsWith("/"))
  200. apiRoute = "/" + apiRoute;//如果路由地址不是/开头则加上/防止控制器没写
  201. var apiName = displayName.DisplayName;//如果描述不为空则接口名称用描述的名称
  202. //合并
  203. var permissionName = apiRoute + $"[{tag}-{apiName}]";
  204. //添加到权限列表
  205. permissions.Add(new PermissionTreeSelector
  206. {
  207. ApiName = apiName,
  208. ApiRoute = apiRoute,
  209. PermissionName = permissionName
  210. });
  211. }
  212. }
  213. }
  214. }
  215. }
  216. return permissions;
  217. }
  218. /// <inheritdoc />
  219. public async Task<List<SysResource>> GetResourcesByIds(List<long> ids, string category)
  220. {
  221. //获取所有菜单
  222. var menuList = await GetListByCategory(category);
  223. //获取菜单信息
  224. var menus = menuList.Where(it => ids.Contains(it.Id)).ToList();
  225. return menus;
  226. }
  227. /// <inheritdoc />
  228. public List<SysResource> GetResourceParent(List<SysResource> resourceList, long parentId)
  229. {
  230. //找上级资源ID列表
  231. var resources = resourceList.Where(it => it.Id == parentId).FirstOrDefault();
  232. if (resources != null)//如果数量大于0
  233. {
  234. var data = new List<SysResource>();
  235. var parents = GetResourceParent(resourceList, resources.ParentId.Value);
  236. data.AddRange(parents);//添加子节点;
  237. data.Add(resources);//添加到列表
  238. return data;//返回结果
  239. }
  240. return new List<SysResource>();
  241. }
  242. #region 方法
  243. /// <summary>
  244. /// 获取路由地址名称
  245. /// </summary>
  246. /// <param name="controllerName">控制器地址</param>
  247. /// <param name="template">路由名称</param>
  248. /// <returns></returns>
  249. private string GetRouteName(string controllerName, string template)
  250. {
  251. if (!template.StartsWith("/"))
  252. template = "/" + template;//如果路由名称不是/开头则加上/防止控制器没写
  253. if (template.Contains("[controller]"))
  254. {
  255. controllerName = controllerName.Replace("Controller", "");//去掉Controller
  256. controllerName = StringHelper.FirstCharToLower(controllerName);//转首字母小写写
  257. template = template.Replace("[controller]", controllerName);//替换[controller]
  258. }
  259. return template;
  260. }
  261. /// <summary>
  262. /// 获取资源所有下级
  263. /// </summary>
  264. /// <param name="resourceList">资源列表</param>
  265. /// <param name="parentId">父ID</param>
  266. /// <returns></returns>
  267. public List<SysResource> GetResourceChildren(List<SysResource> resourceList, long parentId)
  268. {
  269. //找下级资源ID列表
  270. var resources = resourceList.Where(it => it.ParentId == parentId).ToList();
  271. if (resources.Count > 0)//如果数量大于0
  272. {
  273. var data = new List<SysResource>();
  274. foreach (var item in resources)//遍历资源
  275. {
  276. var res = GetResourceChildren(resourceList, item.Id);
  277. data.AddRange(res);//添加子节点;
  278. data.Add(item);//添加到列表
  279. }
  280. return data;//返回结果
  281. }
  282. return new List<SysResource>();
  283. }
  284. /// <summary>
  285. /// 获取授权菜单
  286. /// </summary>
  287. /// <param name="moduleId">模块ID</param>
  288. /// <returns></returns>
  289. public async Task<List<ResTreeSelector.RoleGrantResourceMenu>> GetRoleGrantResourceMenus(long moduleId)
  290. {
  291. var roleGrantResourceMenus = new List<ResTreeSelector.RoleGrantResourceMenu>();//定义结果
  292. var allMenuList = (await GetListByCategory(CateGoryConst.RESOURCE_MENU)).Where(it => it.Module == moduleId).ToList();//获取所有菜单列表
  293. var allButtonList = await GetListByCategory(CateGoryConst.RESOURCE_BUTTON);//获取所有按钮列表
  294. var parentMenuList = allMenuList.Where(it => it.ParentId == SafeCampusConst.ZERO).ToList();//获取一级目录
  295. //遍历一级目录
  296. foreach (var parent in parentMenuList)
  297. {
  298. //如果是目录则去遍历下级
  299. if (parent.MenuType == SysResourceConst.CATALOG)
  300. {
  301. //获取所有下级菜单
  302. var menuList = GetChildListById(allMenuList, parent.Id, false);
  303. if (menuList.Count > 0)//如果有菜单
  304. {
  305. //遍历下级菜单
  306. foreach (var menu in menuList)
  307. {
  308. //如果菜单类型是菜单
  309. if (menu.MenuType is SysResourceConst.MENU or SysResourceConst.SUBSET)
  310. {
  311. //获取菜单下按钮集合并转换成对应实体
  312. var buttonList = allButtonList.Where(it => it.ParentId == menu.Id).ToList();
  313. var buttons = buttonList.Adapt<List<ResTreeSelector.RoleGrantResourceButton>>();
  314. roleGrantResourceMenus.Add(new ResTreeSelector.RoleGrantResourceMenu
  315. {
  316. Id = menu.Id,
  317. ParentId = parent.Id,
  318. ParentName = parent.Title,
  319. Module = moduleId,
  320. Title = GetRoleGrantResourceMenuTitle(menuList, menu),//菜单名称需要特殊处理因为有二级菜单
  321. Button = buttons
  322. });
  323. }
  324. else if (menu.MenuType == SysResourceConst.LINK || menu.MenuType == SysResourceConst.IFRAME)//如果是内链或者外链
  325. {
  326. //直接加到资源列表
  327. roleGrantResourceMenus.Add(new ResTreeSelector.RoleGrantResourceMenu
  328. {
  329. Id = menu.Id,
  330. ParentId = parent.Id,
  331. ParentName = parent.Title,
  332. Module = moduleId,
  333. Title = menu.Title
  334. });
  335. }
  336. }
  337. }
  338. else
  339. {
  340. //否则就将自己加到一级目录里面
  341. roleGrantResourceMenus.Add(new ResTreeSelector.RoleGrantResourceMenu
  342. {
  343. Id = parent.Id,
  344. ParentId = parent.Id,
  345. ParentName = parent.Title,
  346. Module = moduleId
  347. });
  348. }
  349. }
  350. else
  351. {
  352. //就将自己加到一级目录里面
  353. var roleGrantResourcesButtons = new ResTreeSelector.RoleGrantResourceMenu
  354. {
  355. Id = parent.Id,
  356. ParentId = parent.Id,
  357. ParentName = parent.Title,
  358. Module = moduleId,
  359. Title = parent.Title
  360. };
  361. //如果菜单类型是菜单
  362. if (parent.MenuType == SysResourceConst.MENU)
  363. {
  364. //获取菜单下按钮集合并转换成对应实体
  365. var buttonList = allButtonList.Where(it => it.ParentId == parent.Id).ToList();
  366. roleGrantResourcesButtons.Button = buttonList.Adapt<List<ResTreeSelector.RoleGrantResourceButton>>();
  367. }
  368. roleGrantResourceMenus.Add(roleGrantResourcesButtons);
  369. }
  370. }
  371. return roleGrantResourceMenus;
  372. }
  373. /// <inheritdoc />
  374. public string GetRoleGrantResourceMenuTitle(List<SysResource> menuList, SysResource menu)
  375. {
  376. //查找菜单上级
  377. var parentList = GetResourceParent(menuList, menu.ParentId.Value);
  378. //如果有父级菜单
  379. if (parentList.Count > 0)
  380. {
  381. var titles = parentList.Select(it => it.Title).ToList();//提取出父级的name
  382. var title = string.Join("- ", titles) + $"-{menu.Title}";//根据-分割,转换成字符串并在最后加上菜单的title
  383. return title;
  384. }
  385. return menu.Title;//原路返回
  386. }
  387. #endregion 方法
  388. }