平安校园
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

UserCenterService.cs 18 KiB

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