UserController.java 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. package com.xjrsoft.module.organization.controller;
  2. import cn.dev33.satoken.secure.BCrypt;
  3. import cn.dev33.satoken.session.SaSession;
  4. import cn.dev33.satoken.stp.StpUtil;
  5. import cn.hutool.core.bean.BeanUtil;
  6. import cn.hutool.core.util.ObjectUtil;
  7. import cn.hutool.core.util.StrUtil;
  8. import com.baomidou.mybatisplus.core.metadata.IPage;
  9. import com.baomidou.mybatisplus.core.toolkit.StringPool;
  10. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  11. import com.fasterxml.jackson.core.type.TypeReference;
  12. import com.github.yulichang.toolkit.MPJWrappers;
  13. import com.xjrsoft.common.constant.GlobalConstant;
  14. import com.xjrsoft.common.enums.EnabledMark;
  15. import com.xjrsoft.common.enums.RoleEnum;
  16. import com.xjrsoft.common.exception.MyException;
  17. import com.xjrsoft.common.model.result.R;
  18. import com.xjrsoft.common.model.result.RT;
  19. import com.xjrsoft.common.page.ConventPage;
  20. import com.xjrsoft.common.page.PageOutput;
  21. import com.xjrsoft.common.sms.SmsCtcc;
  22. import com.xjrsoft.common.utils.RedisUtil;
  23. import com.xjrsoft.common.utils.VoToColumnUtil;
  24. import com.xjrsoft.config.CommonPropertiesConfig;
  25. import com.xjrsoft.module.base.service.IBaseClassService;
  26. import com.xjrsoft.module.organization.dto.*;
  27. import com.xjrsoft.module.organization.entity.*;
  28. import com.xjrsoft.module.organization.service.*;
  29. import com.xjrsoft.module.organization.utils.OrganizationUtil;
  30. import com.xjrsoft.module.organization.vo.*;
  31. import com.xjrsoft.module.oss.factory.OssFactory;
  32. import com.xjrsoft.module.workflow.service.IWorkflowExecuteService;
  33. import io.swagger.annotations.Api;
  34. import io.swagger.annotations.ApiOperation;
  35. import lombok.AllArgsConstructor;
  36. import org.springframework.web.bind.annotation.*;
  37. import org.springframework.web.multipart.MultipartFile;
  38. import javax.validation.Valid;
  39. import java.util.ArrayList;
  40. import java.util.List;
  41. import java.util.Objects;
  42. import java.util.concurrent.CompletableFuture;
  43. import java.util.stream.Collectors;
  44. /**
  45. * <p>
  46. * 用户 前端控制器
  47. * </p>
  48. *
  49. * @author tzx
  50. * @since 2022-03-02
  51. */
  52. @RestController
  53. @RequestMapping(GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/user")
  54. @Api(value = GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/user", tags = "用户")
  55. @AllArgsConstructor
  56. public class UserController {
  57. private final IUserService userService;
  58. private final IDepartmentService departmentService;
  59. private final IPostService postService;
  60. private final IRoleService roleService;
  61. private final IUserRoleRelationService userRoleRelationService;
  62. private final IUserDeptRelationService userDeptRelationService;
  63. private final IUserPostRelationService userPostRelationService;
  64. private final CommonPropertiesConfig propertiesConfig;
  65. private final RedisUtil redisUtil;
  66. private final SmsCtcc smsCtcc;
  67. private final IUserStudentService userStudentService;
  68. private final IBaseClassService baseClassService;
  69. private final IWorkflowExecuteService workflowExecuteService;
  70. @GetMapping(value = "/list")
  71. @ApiOperation(value = "用户列表(不分页)")
  72. public R list(String keyword) {
  73. List<User> list = userService.list(Wrappers.lambdaQuery(User.class)
  74. .like(StrUtil.isNotBlank(keyword), User::getUserName, keyword)
  75. .like(StrUtil.isNotBlank(keyword), User::getCode, keyword)
  76. .like(StrUtil.isNotBlank(keyword), User::getName, keyword)
  77. .like(StrUtil.isNotBlank(keyword), User::getMobile, keyword)
  78. .select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserListVo.class).contains(x.getProperty())));
  79. List<UserListVo> userListVos = BeanUtil.copyToList(list, UserListVo.class);
  80. return R.ok(userListVos);
  81. }
  82. @GetMapping(value = "/page")
  83. @ApiOperation(value = "用户列表(分页)")
  84. public R page(UserPageDto dto) {
  85. List<Long> deptIds = new ArrayList<>();
  86. if (ObjectUtil.isNotNull(dto.getDepartmentId())) {
  87. List<Department> list = redisUtil.get(GlobalConstant.DEP_CACHE_KEY, new TypeReference<List<Department>>() {
  88. });
  89. //当前部门的层级
  90. String hierarchy = list.stream().filter(x -> x.getId().equals(dto.getDepartmentId())).findFirst().orElse(new Department()).getHierarchy();
  91. if (StrUtil.isNotBlank(hierarchy)) {
  92. //层级里面包含当前部门层级的就是它的子集,如1-1,下面包含了1-1、1-1-2这种
  93. deptIds = list.stream().filter(x -> StrUtil.isNotBlank(x.getHierarchy()) && x.getHierarchy().contains(hierarchy)).map(Department::getId).collect(Collectors.toList());
  94. } else {
  95. //如果不存在层级就查询自己的数据
  96. deptIds.add(dto.getDepartmentId());
  97. }
  98. }
  99. //因为多表关联 会有多个表都使用了id字段, 所以必须专门指定主表的Id
  100. if (ObjectUtil.isNotNull(dto.getDepartmentId())) {//不为空联合查询
  101. IPage<UserPageVo> page = userService.selectJoinListPage(ConventPage.getPage(dto), UserPageVo.class,
  102. MPJWrappers.<User>lambdaJoin()
  103. .disableSubLogicDel()
  104. .distinct()
  105. .like(StrUtil.isNotBlank(dto.getKeyword()), User::getName, dto.getKeyword())
  106. .or(StrUtil.isNotBlank(dto.getKeyword()), x -> x.like(StrUtil.isNotBlank(dto.getKeyword()), User::getCode, dto.getKeyword()))
  107. .in(ObjectUtil.isNotNull(dto.getDepartmentId()), UserDeptRelation::getDeptId, deptIds)
  108. .like(StrUtil.isNotBlank(dto.getUserName()), User::getUserName, dto.getUserName())
  109. .like(StrUtil.isNotBlank(dto.getCode()), User::getCode, dto.getCode())
  110. .like(StrUtil.isNotBlank(dto.getName()), User::getName, dto.getName())
  111. .like(StrUtil.isNotBlank(dto.getMobile()), User::getMobile, dto.getMobile())
  112. .eq(ObjectUtil.isNotNull(dto.getUserType()), Role::getId, dto.getUserType())
  113. .orderByDesc(User::getCreateDate)
  114. .select(User::getId)
  115. .select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()))
  116. .leftJoin(UserDeptRelation.class, UserDeptRelation::getUserId, User::getId)
  117. .leftJoin(UserRoleRelation.class, UserRoleRelation::getUserId, User::getId)
  118. .leftJoin(Role.class, Role::getId, UserRoleRelation::getRoleId));
  119. PageOutput<UserPageVo> pageOutput = ConventPage.getPageOutput(page);
  120. return R.ok(pageOutput);
  121. } else {
  122. // LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
  123. // queryWrapper.like(StrUtil.isNotBlank(dto.getKeyword()), User::getName, dto.getKeyword())
  124. // .or(StrUtil.isNotBlank(dto.getKeyword()), x -> x.like(StrUtil.isNotBlank(dto.getKeyword()), User::getCode, dto.getKeyword()))
  125. // .like(StrUtil.isNotBlank(dto.getUserName()), User::getUserName, dto.getUserName())
  126. // .like(StrUtil.isNotBlank(dto.getCode()), User::getCode, dto.getCode())
  127. // .like(StrUtil.isNotBlank(dto.getName()), User::getName, dto.getName())
  128. // .like(StrUtil.isNotBlank(dto.getMobile()), User::getMobile, dto.getMobile())
  129. // .orderByDesc(User::getCreateDate)
  130. // .select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()));
  131. //
  132. // IPage<User> page = userService.page(ConventPage.getPage(dto),queryWrapper);
  133. IPage<UserPageVo> page = userService.selectJoinListPage(ConventPage.getPage(dto), UserPageVo.class,
  134. MPJWrappers.<User>lambdaJoin()
  135. .disableSubLogicDel()
  136. .distinct()
  137. .like(StrUtil.isNotBlank(dto.getKeyword()), User::getName, dto.getKeyword())
  138. .or(StrUtil.isNotBlank(dto.getKeyword()), x -> x.like(StrUtil.isNotBlank(dto.getKeyword()), User::getCode, dto.getKeyword()))
  139. .like(StrUtil.isNotBlank(dto.getUserName()), User::getUserName, dto.getUserName())
  140. .like(StrUtil.isNotBlank(dto.getCode()), User::getCode, dto.getCode())
  141. .like(StrUtil.isNotBlank(dto.getName()), User::getName, dto.getName())
  142. .like(StrUtil.isNotBlank(dto.getMobile()), User::getMobile, dto.getMobile())
  143. .eq(ObjectUtil.isNotNull(dto.getUserType()), Role::getId, dto.getUserType())
  144. .orderByDesc(User::getCreateDate)
  145. .select(User::getId)
  146. .select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()))
  147. .leftJoin(UserRoleRelation.class, UserRoleRelation::getUserId, User::getId)
  148. .leftJoin(Role.class, Role::getId, UserRoleRelation::getRoleId));
  149. PageOutput<UserPageVo> pageOutput = ConventPage.getPageOutput(page, UserPageVo.class);
  150. return R.ok(pageOutput);
  151. }
  152. }
  153. @GetMapping(value = "/info")
  154. @ApiOperation(value = "根据id查询用户信息")
  155. public R info(@RequestParam Long id) {
  156. User user = userService.getById(id);
  157. if (user == null) {
  158. R.error("找不到此用户!");
  159. }
  160. UserVo userVo = BeanUtil.toBean(user, UserVo.class);
  161. List<Long> deptIds = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class)
  162. .eq(UserDeptRelation::getUserId, user.getId()))
  163. .stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());
  164. String allDeptIdStr = StrUtil.join(StringPool.COMMA, deptIds);
  165. userVo.setDepartmentIds(allDeptIdStr);
  166. return R.ok(userVo);
  167. }
  168. @PostMapping
  169. @ApiOperation(value = "新增用户")
  170. public R add(@Valid @RequestBody AddUserDto dto) {
  171. if (!OrganizationUtil.validatePassword(dto.getPassword())) {
  172. return R.error("密码必须包含大写字母、小写字母、数字和特殊字符,长度8~16位");
  173. }
  174. return R.ok(userService.add(dto));
  175. }
  176. @PutMapping
  177. @ApiOperation(value = "修改用户 不能修改用户名")
  178. public R update(@Valid @RequestBody UpdateUserDto dto) {
  179. return R.ok(userService.update(dto));
  180. }
  181. @GetMapping(value = "/current/info")
  182. @ApiOperation(value = "当前登录用户信息")
  183. public R info() {
  184. SaSession tokenSession = StpUtil.getTokenSession();
  185. User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
  186. List<Long> roleIds = userRoleRelationService.list(Wrappers.lambdaQuery(UserRoleRelation.class)
  187. .eq(UserRoleRelation::getUserId, user.getId()))
  188. .stream().map(UserRoleRelation::getRoleId).collect(Collectors.toList());
  189. List<Long> deptIds = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class)
  190. .eq(UserDeptRelation::getUserId, user.getId()))
  191. .stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());
  192. List<Long> postIds = userPostRelationService.list(Wrappers.lambdaQuery(UserPostRelation.class)
  193. .eq(UserPostRelation::getUserId, user.getId()))
  194. .stream().map(UserPostRelation::getPostId).collect(Collectors.toList());
  195. UserInfoVo vo = BeanUtil.toBean(user, UserInfoVo.class);
  196. if (roleIds.size() > 0) {
  197. List<Role> list = roleService.list(Wrappers.lambdaQuery(Role.class).in(Role::getId, roleIds));
  198. List<UserRoleVo> userRoleVoList = BeanUtil.copyToList(list, UserRoleVo.class);
  199. vo.setRoles(userRoleVoList);
  200. }
  201. if (deptIds.size() > 0) {
  202. List<Department> list = departmentService.list(Wrappers.lambdaQuery(Department.class).in(Department::getId, deptIds));
  203. List<UserDeptVo> userDeptVoList = BeanUtil.copyToList(list, UserDeptVo.class);
  204. vo.setDepartments(userDeptVoList);
  205. }
  206. if (postIds.size() > 0) {
  207. List<Post> list = postService.list(Wrappers.lambdaQuery(Post.class).in(Post::getId, postIds));
  208. List<UserPostVo> userPostVoList = BeanUtil.copyToList(list, UserPostVo.class);
  209. vo.setPosts(userPostVoList);
  210. }
  211. // 家长
  212. List<UserStudentVo> list = baseClassService.getStudents(user.getId());
  213. if (list != null) {
  214. vo.setStudents(list);
  215. }
  216. // 学生
  217. UserStudentVo userStudentVo = baseClassService.getClassInfo(user.getId());
  218. if (userStudentVo != null) {
  219. vo.setClassId(userStudentVo.getClassId());
  220. vo.setClassName(userStudentVo.getClassName());
  221. }
  222. return R.ok(vo);
  223. }
  224. @GetMapping(value = "/pending/count")
  225. @ApiOperation(value = "当前待办数量统计")
  226. public RT<PendingCountDto> pendingCount() {
  227. PendingCountDto pendingCountDto = new PendingCountDto();
  228. pendingCountDto.setWfPendingCount(workflowExecuteService.pendingCount());
  229. return RT.ok(pendingCountDto);
  230. }
  231. @PutMapping("/update/info")
  232. @ApiOperation(value = "登陆人修改自己得用户信息")
  233. public R updateInfo(@RequestBody @Valid UpdateInfoDto dto) {
  234. User updateUserInfo = BeanUtil.toBean(dto, User.class);
  235. updateUserInfo.setId(StpUtil.getLoginIdAsLong());
  236. CompletableFuture.runAsync(() -> {
  237. List<User> list = userService.list();
  238. redisUtil.set(GlobalConstant.USER_CACHE_KEY, list);
  239. });
  240. return R.ok(userService.updateById(updateUserInfo));
  241. }
  242. @PutMapping("/update/password")
  243. @ApiOperation(value = "当前登录用户修改本人密码")
  244. public RT<Boolean> updatePassword(@RequestBody @Valid UpdatePasswordDto dto) {
  245. if (!OrganizationUtil.validatePassword(dto.getNewPassword())) {
  246. return RT.error("密码必须包含大写字母、小写字母、数字和特殊字符,长度8~16位");
  247. }
  248. User user = userService.getById(StpUtil.getLoginIdAsLong());
  249. if (!BCrypt.checkpw(dto.getOldPassword(), user.getPassword())) {
  250. return RT.error("当前密码填写错误!");
  251. }
  252. if (!StrUtil.equals(dto.getNewPassword(), dto.getConfirmPassword())) {
  253. return RT.error("2次密码输入不一致!");
  254. }
  255. return RT.ok(userService.updatePassword(dto));
  256. }
  257. @PutMapping("/login/reset-password")
  258. @ApiOperation(value = "登录后修改密码")
  259. public RT<Boolean> loginResetPassword(@RequestBody @Valid LoginResetPasswordDto dto) {
  260. if (!OrganizationUtil.validatePassword(dto.getNewPassword())) {
  261. return RT.error("密码必须包含大写字母、小写字母、数字和特殊字符,长度8~16位");
  262. }
  263. if (!StrUtil.equals(dto.getNewPassword(), dto.getConfirmPassword())) {
  264. return RT.error("2次密码输入不一致!");
  265. }
  266. UpdatePasswordDto pd = BeanUtil.toBean(dto, UpdatePasswordDto.class);
  267. return RT.ok(userService.updatePassword(pd));
  268. }
  269. @PostMapping("/update/avatar")
  270. @ApiOperation(value = "当前登录用户修改头像")
  271. public R uploadAvatar(@RequestParam("file") MultipartFile file) throws Exception {
  272. if (file.isEmpty()) {
  273. throw new MyException("上传文件不能为空");
  274. }
  275. //上传文件
  276. String suffix = Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf(StringPool.DOT));
  277. String url = Objects.requireNonNull(OssFactory.build()).uploadSuffix(file.getBytes(), suffix);
  278. User updateUser = new User();
  279. updateUser.setId(StpUtil.getLoginIdAsLong());
  280. updateUser.setAvatar(url);
  281. userService.updateById(updateUser);
  282. SaSession tokenSession = StpUtil.getTokenSession();
  283. User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
  284. user.setAvatar(url);
  285. tokenSession.set(GlobalConstant.LOGIN_USER_INFO_KEY, user);
  286. return R.ok(url);
  287. }
  288. @DeleteMapping
  289. @ApiOperation(value = "删除用户(可批量)")
  290. public R delete(@RequestBody List<Long> ids) {
  291. if (ids.contains(GlobalConstant.SUPER_ADMIN_USER_ID)) {
  292. R.error("管理员账户不能删除!");
  293. }
  294. if (ids.contains(StpUtil.getLoginIdAsLong())) {
  295. R.error("当前登录账户不能删除!");
  296. }
  297. //删除时需要同时删除用户部门关联表和用户角色关联表和用户岗位关系表数据。
  298. return R.ok(userService.deleteBatch(ids));
  299. }
  300. @GetMapping("/info/multi")
  301. @ApiOperation(value = "批量获取用户信息")
  302. public R usersInfo(@RequestParam String ids) {
  303. return R.ok(userService.getUsersInfo(ids));
  304. }
  305. @GetMapping("/enabled")
  306. @ApiOperation(value = "启用/禁用用户")
  307. public R enabled(@RequestParam Long id) {
  308. User user = userService.getOne(Wrappers.<User>query().lambda().select(User::getEnabledMark).eq(User::getId, id), false);
  309. if (user != null) {
  310. User updateUser = new User();
  311. updateUser.setId(id);
  312. updateUser.setEnabledMark(user.getEnabledMark() == EnabledMark.ENABLED.getCode() ? EnabledMark.DISABLED.getCode() : EnabledMark.ENABLED.getCode());
  313. return R.ok(userService.updateById(updateUser));
  314. }
  315. CompletableFuture.runAsync(() -> {
  316. List<User> list = userService.list();
  317. redisUtil.set(GlobalConstant.USER_CACHE_KEY, list);
  318. });
  319. return R.error("该用户不存在!");
  320. }
  321. @PutMapping("/reset-password")
  322. @ApiOperation(value = "重置密码")
  323. public RT<Boolean> resetPassword(@RequestBody ResetPasswordDto dto) {
  324. return RT.ok(userService.resetPassword(dto));
  325. }
  326. @PostMapping("/bind-unionid")
  327. @ApiOperation(value = "绑定微信 UnionId")
  328. public R bindUnionId(@RequestBody BindOpenidDto dto) {
  329. User user = userService.getOne(Wrappers.<User>query().lambda().select(User::getId, User::getOpenId, User::getUnionId).eq(User::getId, dto.getId()), false);
  330. if (user != null) {
  331. if (StrUtil.isNotBlank(user.getUnionId())) {
  332. return R.error("该用户已经绑定微信!");
  333. }
  334. long count = userService.count(Wrappers.<User>query().lambda().eq(User::getUnionId, dto.getOpenid()));
  335. if (count > 0) {
  336. return R.error("该用户已经绑定微信!");
  337. }
  338. User updateUser = new User();
  339. updateUser.setId(dto.getId());
  340. // updateUser.setOpenId(dto.getOpenid());
  341. updateUser.setUnionId(dto.getOpenid());
  342. return R.ok(userService.updateById(updateUser));
  343. } else {
  344. long count = userService.count(Wrappers.<User>query().lambda().eq(User::getOpenId, dto.getOpenid()));
  345. if (count > 0) {
  346. return R.error("该用户已经绑定微信!");
  347. }
  348. }
  349. return R.error("该用户不存在!");
  350. }
  351. @PostMapping("/bind-openid")
  352. @ApiOperation(value = "绑定微信 Openid")
  353. public R bindOpenid(@RequestBody BindOpenidDto dto) {
  354. return R.ok(userService.bindOpenid(dto));
  355. }
  356. @GetMapping("/unbind-openid")
  357. @ApiOperation(value = "取消绑定微信 UnionId")
  358. public R unbindOpenid(@RequestParam Long id) {
  359. return R.ok(userService.unbindOpenid(id));
  360. }
  361. @PostMapping("/register")
  362. @ApiOperation(value = "家长注册")
  363. public R register(@Valid @RequestBody RegisterDto dto) {
  364. // 验证验证码
  365. if (!smsCtcc.captchaVerify(dto.getMobile(), dto.getSmsCode())) {
  366. return R.error("验证码不正确!");
  367. }
  368. // 赋值家长角色
  369. dto.setRoleId(RoleEnum.PARENT.getCode());
  370. return R.ok(userService.add(dto));
  371. }
  372. @PostMapping("/bind-student")
  373. @ApiOperation(value = "绑定学生")
  374. public R bindStudent(@Valid @RequestBody UserStudentBindDto dto) {
  375. User user = userService.getOne(Wrappers.<User>query().lambda()
  376. .eq(User::getName, dto.getName())
  377. .eq(User::getCredentialNumber, dto.getIdCard()));
  378. UserStudentAddDto userStudentAddDto = new UserStudentAddDto();
  379. if (user == null) {
  380. return R.error("学生不存在!");
  381. }
  382. userStudentAddDto.setUserId(dto.getUserId());
  383. userStudentAddDto.setStudentId(user.getId());
  384. return R.ok(userStudentService.add(userStudentAddDto));
  385. }
  386. @DeleteMapping("/unbind-student")
  387. @ApiOperation(value = "解绑学生")
  388. public R unBindStudent(@Valid @RequestBody UserStudentDeleteDto dto) {
  389. return R.ok(userStudentService.delete(dto));
  390. }
  391. @GetMapping("/student")
  392. @ApiOperation(value = "获取绑定学生")
  393. public R unBindStudent(@Valid @RequestParam Long id) {
  394. return R.ok(baseClassService.getStudents(id));
  395. }
  396. }