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

  1. //
  2. using System.Text.RegularExpressions;
  3. namespace SafeCampus.System;
  4. /// <inheritdoc cref="IUserCenterService"/>
  5. public class UserCenterService : DbRepository<SysUser>, IUserCenterService
  6. {
  7. private readonly ISysUserService _userService;
  8. private readonly IRelationService _relationService;
  9. private readonly IResourceService _resourceService;
  10. private readonly IMenuService _menuService;
  11. private readonly IConfigService _configService;
  12. private readonly ISysOrgService _sysOrgService;
  13. private readonly IMessageService _messageService;
  14. public UserCenterService(ISysUserService userService, IRelationService relationService, IResourceService resourceService,
  15. IMenuService menuService, IConfigService configService, ISysOrgService sysOrgService,
  16. IMessageService messageService)
  17. {
  18. _userService = userService;
  19. _relationService = relationService;
  20. _resourceService = resourceService;
  21. _menuService = menuService;
  22. _configService = configService;
  23. _sysOrgService = sysOrgService;
  24. _messageService = messageService;
  25. }
  26. #region 查询
  27. /// <inheritdoc />
  28. public async Task<List<SysResource>> GetLoginMenu(BaseIdInput input)
  29. {
  30. var result = new List<SysResource>();
  31. //获取用户信息
  32. var userInfo = await _userService.GetUserByAccount(UserManager.UserAccount, UserManager.TenantId);
  33. if (userInfo != null)
  34. {
  35. //定义菜单ID列表
  36. var menuIdList = new HashSet<long>();//获取所有的菜单和模块以及单页面列表,并按分类和排序码排序
  37. var allModuleAndMenuAndSpaList = await _resourceService.GetMenuAndSpaListByModuleId(input.Id);
  38. //通过 App.GetOptions<TOptions> 获取选项
  39. var settings = App.GetOptions<SystemSettingsOptions>();
  40. //如果设置了超级管理员可以看到全部
  41. if (settings.SuperAdminViewAllData && UserManager.SuperAdmin)
  42. {
  43. menuIdList = allModuleAndMenuAndSpaList.Select(it => it.Id).ToHashSet();
  44. }
  45. else
  46. {
  47. //获取用户所拥有的资源集合
  48. var resourceList =
  49. await _relationService.GetRelationListByObjectIdAndCategory(userInfo.Id, CateGoryConst.RELATION_SYS_USER_HAS_RESOURCE);
  50. if (resourceList.Count == 0)//如果没有就获取角色的
  51. //获取角色所拥有的资源集合
  52. resourceList = await _relationService.GetRelationListByObjectIdListAndCategory(userInfo.RoleIdList,
  53. CateGoryConst.RELATION_SYS_ROLE_HAS_RESOURCE);
  54. //获取菜单Id集合
  55. menuIdList.AddRange(resourceList.Select(r => r.TargetId.ToLong()).ToList());
  56. }
  57. var allMenuList = new List<SysResource>();//菜单列表
  58. var allSpaList = new List<SysResource>();//单页列表
  59. //遍历菜单集合
  60. allModuleAndMenuAndSpaList.ForEach(it =>
  61. {
  62. switch (it.Category)
  63. {
  64. case CateGoryConst.RESOURCE_MENU://菜单
  65. allMenuList.Add(it);//添加到菜单列表
  66. break;
  67. case CateGoryConst.RESOURCE_SPA://单页
  68. allSpaList.Add(it);//添加到单页列表
  69. break;
  70. }
  71. });
  72. //获取我的菜单列表,只显示启用的
  73. var myMenus = allMenuList.Where(it => menuIdList.Contains(it.Id) && it.Status == CommonStatusConst.ENABLE).ToList();
  74. // 对获取到的角色对应的菜单列表进行处理,获取父列表
  75. var parentList = GetMyParentMenus(allMenuList, myMenus);
  76. myMenus.AddRange(parentList);//合并列表
  77. // 遍历单页列表
  78. allSpaList.ForEach(it =>
  79. {
  80. it.ParentId = SafeCampusConst.ZERO;
  81. });
  82. myMenus.AddRange(allSpaList);//单页添加到菜单
  83. //构建meta
  84. ConstructMeta(myMenus);
  85. //构建菜单树
  86. result = _menuService.ConstructMenuTrees(myMenus);
  87. }
  88. return result;
  89. }
  90. /// <inheritdoc />
  91. public async Task<string> GetLoginWorkbench()
  92. {
  93. //获取个人工作台信息
  94. var sysRelation = await _relationService.GetWorkbench(UserManager.UserId);
  95. if (sysRelation != null)
  96. {
  97. //如果有数据直接返回个人工作台
  98. return sysRelation.ExtJson.ToLower();
  99. }
  100. //如果没数据去系统配置里取默认的工作台
  101. var devConfig = await _configService.GetByConfigKey(CateGoryConst.CONFIG_SYS_BASE, SysConfigConst.SYS_DEFAULT_WORKBENCH_DATA);
  102. if (devConfig != null)
  103. {
  104. return devConfig.ConfigValue.ToLower();//返回工作台信息
  105. }
  106. return "";
  107. }
  108. /// <inheritdoc />
  109. public async Task<List<LoginOrgTreeOutput>> LoginOrgTree()
  110. {
  111. var orgList = await _sysOrgService.GetListAsync();//获取全部机构
  112. var parentOrgList = _sysOrgService.GetOrgParents(orgList, UserManager.OrgId);//获取父节点列表
  113. var topOrg = parentOrgList.Where(it => it.ParentId == SafeCampusConst.ZERO).FirstOrDefault();//获取顶级节点
  114. if (topOrg != null)
  115. {
  116. var orgChildList = await _sysOrgService.GetChildListById(topOrg.Id);//获取下级
  117. var orgTree = ConstrucOrgTrees(orgChildList, 0, UserManager.OrgId);//获取组织架构
  118. return orgTree;
  119. }
  120. return new List<LoginOrgTreeOutput>();
  121. }
  122. /// <inheritdoc />
  123. public async Task<SqlSugarPagedList<SysMessage>> LoginMessagePage(MessagePageInput input)
  124. {
  125. var messages = await _messageService.MyMessagePage(input, UserManager.UserId);//分页查询
  126. return messages;
  127. }
  128. /// <inheritdoc />
  129. public async Task<MessageDetailOutPut> LoginMessageDetail(BaseIdInput input)
  130. {
  131. return await _messageService.Detail(input, true);//返回详情,不带用户列表
  132. }
  133. /// <inheritdoc />
  134. public async Task<int> UnReadCount()
  135. {
  136. return await _messageService.UnReadCount(UserManager.UserId);
  137. }
  138. /// <inheritdoc />
  139. public async Task<List<SysResource>> ShortcutTree()
  140. {
  141. var sysResourceList = await _resourceService.GetAllModuleAndMenuAndSpaList();//获取模块和菜单和单页列表
  142. var userInfo = await _userService.GetUserById(UserManager.UserId);
  143. var hasResourcesList = new HashSet<long>();//拥有的资源列表
  144. var hasModuleList = new HashSet<long>();//拥有的资源列表
  145. var userResourceList =
  146. (await _relationService.GetRelationListByObjectIdAndCategory(UserManager.UserId, CateGoryConst.RELATION_SYS_USER_HAS_RESOURCE))
  147. .Select(it => it.TargetId.ToLong()).ToList();//获取用户资源id列表
  148. var userModuleList =
  149. (await _relationService.GetRelationListByObjectIdAndCategory(UserManager.UserId, CateGoryConst.RELATION_SYS_USER_HAS_MODULE))
  150. .Select(it => it.TargetId.ToLong()).ToList();//获取用户模块id列表
  151. if (userResourceList.Count > 0)//如果用户资源列表大于0就以用户为主
  152. {
  153. hasResourcesList.AddRange(userResourceList);
  154. hasResourcesList.AddRange(userModuleList);
  155. }
  156. else
  157. {
  158. var roleIds = userInfo.RoleIdList;//获取角色ID列表
  159. var roleResourceList =
  160. (await _relationService.GetRelationListByObjectIdListAndCategory(roleIds, CateGoryConst.RELATION_SYS_ROLE_HAS_RESOURCE))
  161. .Select(it => it.TargetId.ToLong()).ToList();//获取角色资源id列表
  162. var roleModuleList =
  163. (await _relationService.GetRelationListByObjectIdListAndCategory(roleIds, CateGoryConst.RELATION_SYS_ROLE_HAS_MODULE))
  164. .Select(it => it.TargetId.ToLong()).ToList();//获取角色模块id列表
  165. hasResourcesList.AddRange(roleResourceList);
  166. hasResourcesList.AddRange(roleModuleList);
  167. }
  168. // 获取目录
  169. var catalogList = sysResourceList.Where(it => it.MenuType == SysResourceConst.CATALOG).ToList();
  170. //过滤出拥有的资源列表
  171. sysResourceList =
  172. sysResourceList.Where(it =>
  173. hasResourcesList.Contains(it.Id) || it.Category == CateGoryConst.RESOURCE_SPA)
  174. .ToList();//获取拥有的资源列表
  175. var parentIds = sysResourceList.Select(it => it.ParentId).Distinct().ToList();//获取父ID列表
  176. var parentList = catalogList.Where(it => parentIds.Contains(it.Id)).ToList();//获取所拥有的父级目录
  177. sysResourceList.AddRange(parentList);//添加到列表
  178. return await _menuService.ShortcutTree(sysResourceList);
  179. }
  180. #endregion 查询
  181. #region 编辑
  182. /// <inheritdoc />
  183. public async Task UpdateUserInfo(UpdateInfoInput input)
  184. {
  185. //如果手机号不是空
  186. if (!string.IsNullOrEmpty(input.Phone))
  187. {
  188. if (!input.Phone.MatchPhoneNumber())//判断是否是手机号格式
  189. throw Oops.Bah("手机号码格式错误");
  190. input.Phone = CryptogramUtil.Sm4Encrypt(input.Phone);
  191. var any = await IsAnyAsync(it => it.Phone == input.Phone && it.Id != UserManager.UserId);//判断是否有重复的
  192. if (any)
  193. throw Oops.Bah("系统已存在该手机号");
  194. }
  195. if (!string.IsNullOrEmpty(input.Email))
  196. {
  197. var match = input.Email.MatchEmail();
  198. if (!match.isMatch)
  199. throw Oops.Bah("邮箱格式错误");
  200. }
  201. //更新指定字段
  202. var result = await UpdateSetColumnsTrueAsync(it => new SysUser
  203. {
  204. Name = input.Name,
  205. Email = input.Email,
  206. Phone = input.Phone,
  207. Nickname = input.Nickname,
  208. Gender = input.Gender,
  209. Birthday = input.Birthday
  210. }, it => it.Id == UserManager.UserId);
  211. if (result)
  212. _userService.DeleteUserFromRedis(UserManager.UserId);//redis删除用户数据
  213. }
  214. /// <inheritdoc />
  215. public async Task UpdateSignature(UpdateSignatureInput input)
  216. {
  217. var signatureArray = input.Signature.Split(",");//分割
  218. // var base64String = signatureArray[1];//根据逗号分割取到base64字符串
  219. // var image = base64String.GetSkBitmapFromBase64();//转成图片
  220. // var resizeImage = image.ResizeImage(100, 50);//重新裁剪
  221. // var newBase64String = resizeImage.ImgToBase64String();//重新转为base64
  222. // var newSignature = signatureArray[0] + "," + newBase64String;//赋值新的签名
  223. //更新签名
  224. var result = await UpdateSetColumnsTrueAsync(it => new SysUser
  225. {
  226. Signature = input.Signature
  227. }, it => it.Id == UserManager.UserId);
  228. if (result)
  229. _userService.DeleteUserFromRedis(UserManager.UserId);//redis删除用户数据
  230. }
  231. /// <inheritdoc />
  232. public async Task UpdateWorkbench(UpdateWorkbenchInput input)
  233. {
  234. //关系表保存个人工作台
  235. await _relationService.SaveRelation(CateGoryConst.RELATION_SYS_USER_WORKBENCH_DATA, UserManager.UserId, null, input.WorkbenchData,
  236. true);
  237. }
  238. /// <inheritdoc />
  239. public async Task DeleteMyMessage(BaseIdInput input)
  240. {
  241. await _messageService.DeleteMyMessage(input, UserManager.UserId);
  242. }
  243. /// <inheritdoc />
  244. public async Task UpdatePassword(UpdatePasswordInput input)
  245. {
  246. //获取用户信息
  247. var userInfo = await _userService.GetUserById(UserManager.UserId);
  248. var password = CryptogramUtil.Sm2Decrypt(input.Password);//SM2解密
  249. if (userInfo.Password != password) throw Oops.Bah("原密码错误");
  250. var newPassword = CryptogramUtil.Sm2Decrypt(input.NewPassword);//sm2解密
  251. var loginPolicy = await _configService.GetConfigsByCategory(CateGoryConst.CONFIG_PWD_POLICY);//获取密码策略
  252. var containNumber = loginPolicy.First(it => it.ConfigKey == SysConfigConst.PWD_CONTAIN_NUM).ConfigValue.ToBoolean();//是否包含数字
  253. var containLower = loginPolicy.First(it => it.ConfigKey == SysConfigConst.PWD_CONTAIN_LOWER).ConfigValue.ToBoolean();//是否包含小写
  254. var containUpper = loginPolicy.First(it => it.ConfigKey == SysConfigConst.PWD_CONTAIN_UPPER).ConfigValue.ToBoolean();//是否包含大写
  255. var containChar = loginPolicy.First(it => it.ConfigKey == SysConfigConst.PWD_CONTAIN_CHARACTER).ConfigValue.ToBoolean();//是否包含特殊字符
  256. var minLength = loginPolicy.First(it => it.ConfigKey == SysConfigConst.PWD_MIN_LENGTH).ConfigValue.ToInt();//最小长度
  257. if (minLength > newPassword.Length)
  258. throw Oops.Bah($"密码长度不能小于{minLength}");
  259. if (containNumber && !Regex.IsMatch(newPassword, "[0-9]"))
  260. throw Oops.Bah("密码必须包含数字");
  261. if (containLower && !Regex.IsMatch(newPassword, "[a-z]"))
  262. throw Oops.Bah("密码必须包含小写字母");
  263. if (containUpper && !Regex.IsMatch(newPassword, "[A-Z]"))
  264. throw Oops.Bah("密码必须包含大写字母");
  265. if (containChar && !Regex.IsMatch(newPassword, "[~!@#$%^&*()_+`\\-={}|\\[\\]:\";'<>?,./]"))
  266. throw Oops.Bah("密码必须包含特殊字符");
  267. // var similarity = PwdUtil.Similarity(password, newPassword);
  268. // if (similarity > 80)
  269. // throw Oops.Bah($"新密码请勿与旧密码过于相似");
  270. newPassword = CryptogramUtil.Sm4Encrypt(newPassword);//SM4加密
  271. userInfo.Password = newPassword;
  272. await UpdateSetColumnsTrueAsync(it => new SysUser() { Password = newPassword }, it => it.Id == userInfo.Id);//更新密码
  273. _userService.DeleteUserFromRedis(UserManager.UserId);//redis删除用户数据
  274. }
  275. /// <inheritdoc />
  276. public async Task<string> UpdateAvatar(BaseFileInput input)
  277. {
  278. var userInfo = await _userService.GetUserById(UserManager.UserId);
  279. var file = input.File;
  280. using var fileStream = file.OpenReadStream();//获取文件流
  281. var bytes = new byte[fileStream.Length];
  282. fileStream.Read(bytes, 0, bytes.Length);
  283. fileStream.Close();
  284. var base64String = Convert.ToBase64String(bytes);//转base64
  285. var avatar = base64String.ToImageBase64();//转图片
  286. await UpdateSetColumnsTrueAsync(it => new SysUser() { Avatar = avatar }, it => it.Id == userInfo.Id);// 更新头像
  287. _userService.DeleteUserFromRedis(UserManager.UserId);//redis删除用户数据
  288. return avatar;
  289. }
  290. /// <inheritdoc />
  291. public async Task SetDefaultModule(SetDefaultModuleInput input)
  292. {
  293. //获取用户信息
  294. var userInfo = await _userService.GetUserById(UserManager.UserId);
  295. //如果是默认模块
  296. if (input.IfDefault)
  297. userInfo.DefaultModule = input.Id;
  298. else
  299. userInfo.DefaultModule = null;
  300. await Context.Updateable(userInfo).UpdateColumns(it => new { it.DefaultModule }).ExecuteCommandAsync();//修改默认模块
  301. _userService.DeleteUserFromRedis(UserManager.UserId);//redis删除用户数据
  302. }
  303. #endregion 编辑
  304. #region 方法
  305. /// <summary>
  306. /// 获取父菜单集合
  307. /// </summary>
  308. /// <param name="allMenuList">所有菜单列表</param>
  309. /// <param name="myMenus">我的菜单列表</param>
  310. /// <returns></returns>
  311. private List<SysResource> GetMyParentMenus(List<SysResource> allMenuList, List<SysResource> myMenus)
  312. {
  313. var parentList = new List<SysResource>();
  314. myMenus.ForEach(it =>
  315. {
  316. var parents = _resourceService.GetResourceParent(allMenuList, it.ParentId.Value);//获取父级
  317. parents.ForEach(parent =>
  318. {
  319. // 如果父级菜单存在,并且父级菜单状态为启用,并不在父级列表中,则添加到父级列表
  320. if (parent != null && parent.Status == CommonStatusConst.ENABLE && !parentList.Contains(parent)
  321. && !myMenus.Contains(parent))
  322. {
  323. parentList.Add(parent);//添加到父列表
  324. }
  325. });
  326. });
  327. return parentList;
  328. }
  329. /// <summary>
  330. /// 构建Meta
  331. /// </summary>
  332. /// <param name="myMenus">我的菜单集合</param>
  333. private void ConstructMeta(List<SysResource> myMenus)
  334. {
  335. myMenus.ForEach(it =>
  336. {
  337. //定义meta
  338. var meta = new Meta
  339. {
  340. Icon = it.Icon,
  341. Title = it.Title,
  342. IsAffix = it.IsAffix,
  343. IsHide = it.IsHide,
  344. IsKeepAlive = it.IsKeepAlive,
  345. IsFull = it.IsFull,
  346. ActiveMenu = it.ActiveMenu,
  347. IsLink = it.Category == SysResourceConst.LINK ? it.Path : ""
  348. };
  349. it.Meta = meta;
  350. });
  351. }
  352. /// <summary>
  353. /// 构建机构树
  354. /// </summary>
  355. /// <param name="orgList">机构列表</param>
  356. /// <param name="parentId">父ID</param>
  357. /// <param name="orgId">用户ID</param>
  358. /// <returns></returns>
  359. public List<LoginOrgTreeOutput> ConstrucOrgTrees(List<SysOrg> orgList, long parentId, long orgId)
  360. {
  361. //找下级字典ID列表
  362. var orgParents = orgList.Where(it => it.ParentId == parentId).OrderBy(it => it.SortCode).ToList();
  363. if (orgParents.Count > 0)//如果数量大于0
  364. {
  365. var data = new List<LoginOrgTreeOutput>();
  366. foreach (var item in orgParents)//遍历字典
  367. {
  368. var loginOrg = new LoginOrgTreeOutput
  369. {
  370. Children = ConstrucOrgTrees(orgList, item.Id, orgId),//添加子节点
  371. Id = item.Id,
  372. Label = item.Name,
  373. Pid = item.ParentId,
  374. Style = orgId != item.Id ? null : new LoginOrgTreeOutput.MyStyle()
  375. };
  376. data.Add(loginOrg);//添加到列表
  377. }
  378. return data;//返回结果
  379. }
  380. return new List<LoginOrgTreeOutput>();
  381. }
  382. #endregion 方法
  383. }