package com.xjrsoft.module.organization.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.toolkit.MPJWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.EnabledMark;
import com.xjrsoft.common.enums.RoleEnum;
import com.xjrsoft.common.exception.MyException;
import com.xjrsoft.common.model.result.R;
import com.xjrsoft.common.page.ConventPage;
import com.xjrsoft.common.page.PageOutput;
import com.xjrsoft.common.sms.SmsCtcc;
import com.xjrsoft.common.utils.RedisUtil;
import com.xjrsoft.common.utils.VoToColumnUtil;
import com.xjrsoft.config.CommonPropertiesConfig;
import com.xjrsoft.module.organization.dto.*;
import com.xjrsoft.module.organization.entity.*;
import com.xjrsoft.module.organization.service.*;
import com.xjrsoft.module.organization.vo.*;
import com.xjrsoft.module.oss.factory.OssFactory;
import com.xjrsoft.module.student.entity.BaseClass;
import com.xjrsoft.module.student.entity.BaseStudent;
import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
import com.xjrsoft.module.student.entity.BaseStudentUser;
import com.xjrsoft.module.student.service.IBaseClassService;
import com.xjrsoft.module.student.vo.BaseStudentClassVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
*
* 用户 前端控制器
*
*
* @author tzx
* @since 2022-03-02
*/
@RestController
@RequestMapping(GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/user")
@Api(value = GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/user", tags = "用户")
@AllArgsConstructor
public class UserController {
private final IUserService userService;
private final IDepartmentService departmentService;
private final IPostService postService;
private final IRoleService roleService;
private final IUserRoleRelationService userRoleRelationService;
private final IUserDeptRelationService userDeptRelationService;
private final IUserPostRelationService userPostRelationService;
private final CommonPropertiesConfig propertiesConfig;
private final RedisUtil redisUtil;
private final SmsCtcc smsCtcc;
private final IUserStudentService userStudentService;
private final IBaseClassService baseClassService;
@GetMapping(value = "/list")
@ApiOperation(value = "用户列表(不分页)")
public R list(String keyword) {
List list = userService.list(Wrappers.lambdaQuery(User.class)
.like(StrUtil.isNotBlank(keyword), User::getUserName, keyword)
.like(StrUtil.isNotBlank(keyword), User::getCode, keyword)
.like(StrUtil.isNotBlank(keyword), User::getName, keyword)
.like(StrUtil.isNotBlank(keyword), User::getMobile, keyword)
.select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserListVo.class).contains(x.getProperty())));
List userListVos = BeanUtil.copyToList(list, UserListVo.class);
return R.ok(userListVos);
}
@GetMapping(value = "/page")
@ApiOperation(value = "用户列表(分页)")
public R page(UserPageDto dto) {
List deptIds = new ArrayList<>();
if (ObjectUtil.isNotNull(dto.getDepartmentId())){
List list = redisUtil.get(GlobalConstant.DEP_CACHE_KEY,new TypeReference>() {
});
//当前部门的层级
String hierarchy = list.stream().filter(x -> x.getId().equals(dto.getDepartmentId())).findFirst().orElse(new Department()).getHierarchy();
if (StrUtil.isNotBlank(hierarchy)){
//层级里面包含当前部门层级的就是它的子集,如1-1,下面包含了1-1、1-1-2这种
deptIds = list.stream().filter(x -> StrUtil.isNotBlank(x.getHierarchy())&&x.getHierarchy().contains(hierarchy)).map(Department::getId).collect(Collectors.toList());
}else {
//如果不存在层级就查询自己的数据
deptIds.add(dto.getDepartmentId());
}
}
//因为多表关联 会有多个表都使用了id字段, 所以必须专门指定主表的Id
if (ObjectUtil.isNotNull(dto.getDepartmentId())){//不为空联合查询
IPage page = userService.selectJoinListPage(ConventPage.getPage(dto), UserPageVo.class,
MPJWrappers.lambdaJoin()
.distinct()
.like(StrUtil.isNotBlank(dto.getKeyword()), User::getName, dto.getKeyword())
.or(StrUtil.isNotBlank(dto.getKeyword()), x -> x.like(StrUtil.isNotBlank(dto.getKeyword()), User::getCode, dto.getKeyword()))
.in(ObjectUtil.isNotNull(dto.getDepartmentId()), UserDeptRelation::getDeptId, deptIds)
.like(StrUtil.isNotBlank(dto.getUserName()), User::getUserName, dto.getUserName())
.like(StrUtil.isNotBlank(dto.getCode()), User::getCode, dto.getCode())
.like(StrUtil.isNotBlank(dto.getName()), User::getName, dto.getName())
.like(StrUtil.isNotBlank(dto.getMobile()), User::getMobile, dto.getMobile())
.orderByDesc(User::getCreateDate)
.select(User::getId)
.select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()))
.leftJoin(UserDeptRelation.class, UserDeptRelation::getUserId, User::getId));
PageOutput pageOutput = ConventPage.getPageOutput(page);
return R.ok(pageOutput);
}else {
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StrUtil.isNotBlank(dto.getKeyword()), User::getName, dto.getKeyword())
.or(StrUtil.isNotBlank(dto.getKeyword()), x -> x.like(StrUtil.isNotBlank(dto.getKeyword()), User::getCode, dto.getKeyword()))
.like(StrUtil.isNotBlank(dto.getUserName()), User::getUserName, dto.getUserName())
.like(StrUtil.isNotBlank(dto.getCode()), User::getCode, dto.getCode())
.like(StrUtil.isNotBlank(dto.getName()), User::getName, dto.getName())
.like(StrUtil.isNotBlank(dto.getMobile()), User::getMobile, dto.getMobile())
.orderByDesc(User::getCreateDate)
.select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()));
IPage page = userService.page(ConventPage.getPage(dto),queryWrapper);
PageOutput pageOutput = ConventPage.getPageOutput(page, UserPageVo.class);
return R.ok(pageOutput);
}
}
@GetMapping(value = "/info")
@ApiOperation(value = "根据id查询用户信息")
public R info(@RequestParam Long id) {
User user = userService.getById(id);
if (user == null) {
R.error("找不到此用户!");
}
return R.ok(BeanUtil.toBean(user, UserVo.class));
}
@PostMapping
@ApiOperation(value = "新增用户")
public R add(@Valid @RequestBody AddUserDto dto) {
return R.ok(userService.add(dto));
}
@PutMapping
@ApiOperation(value = "修改用户 不能修改用户名")
public R update(@Valid @RequestBody UpdateUserDto dto) {
return R.ok(userService.update(dto));
}
@GetMapping(value = "/current/info")
@ApiOperation(value = "当前登录用户信息")
public R info() {
SaSession tokenSession = StpUtil.getTokenSession();
User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
List roleIds = userRoleRelationService.list(Wrappers.lambdaQuery(UserRoleRelation.class)
.eq(UserRoleRelation::getUserId, user.getId().toString()))
.stream().map(UserRoleRelation::getRoleId).collect(Collectors.toList());
List deptIds = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class)
.eq(UserDeptRelation::getUserId, user.getId().toString()))
.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());
List postIds = userPostRelationService.list(Wrappers.lambdaQuery(UserPostRelation.class)
.eq(UserPostRelation::getUserId, user.getId().toString()))
.stream().map(UserPostRelation::getPostId).collect(Collectors.toList());
UserInfoVo vo = BeanUtil.toBean(user, UserInfoVo.class);
if (roleIds.size() > 0) {
List list = roleService.list(Wrappers.lambdaQuery(Role.class).in(Role::getId, roleIds));
List userRoleVoList = BeanUtil.copyToList(list, UserRoleVo.class);
vo.setRoles(userRoleVoList);
}
if (deptIds.size() > 0) {
List list = departmentService.list(Wrappers.lambdaQuery(Department.class).in(Department::getId, deptIds));
List userDeptVoList = BeanUtil.copyToList(list, UserDeptVo.class);
vo.setDepartments(userDeptVoList);
}
if (postIds.size() > 0) {
List list = postService.list(Wrappers.lambdaQuery(Post.class).in(Post::getId, postIds));
List userPostVoList = BeanUtil.copyToList(list, UserPostVo.class);
vo.setPosts(userPostVoList);
}
// 家长
List list = baseClassService.getStudents(user.getId());
if (list != null) {
vo.setStudents(list);
}
// 学生
UserStudentVo userStudentVo = baseClassService.getClassInfo(user.getId());
if (userStudentVo != null) {
vo.setClassId(userStudentVo.getClassId());
vo.setClassName(userStudentVo.getClassName());
}
return R.ok(vo);
}
@PutMapping("/update/info")
@ApiOperation(value = "登陆人修改自己得用户信息")
public R updateInfo(@RequestBody @Valid UpdateInfoDto dto) {
User updateUserInfo = BeanUtil.toBean(dto, User.class);
updateUserInfo.setId(StpUtil.getLoginIdAsLong());
CompletableFuture.runAsync(() -> {
List list = userService.list();
redisUtil.set(GlobalConstant.USER_CACHE_KEY, list);
});
return R.ok(userService.updateById(updateUserInfo));
}
@PutMapping("/update/password")
@ApiOperation(value = "当前登录用户修改本人密码")
public R updatePassword(@RequestBody @Valid UpdatePasswordDto dto) {
User user = userService.getById(StpUtil.getLoginIdAsLong());
// if (!StrUtil.equals(SaSecureUtil.md5BySalt(dto.getOldPassword(), GlobalConstant.SECRET_KEY), user.getPassword())) {
// return R.error("当前密码填写错误!");
// }
if (!BCrypt.checkpw(dto.getOldPassword(), user.getPassword())) {
return R.error("当前密码填写错误!");
}
if (!StrUtil.equals(dto.getNewPassword(), dto.getConfirmPassword())) {
return R.error("2次密码输入不一致!");
}
User updateUser = new User();
updateUser.setId(StpUtil.getLoginIdAsLong());
// updateUser.setPassword(SaSecureUtil.md5BySalt(dto.getNewPassword(), GlobalConstant.SECRET_KEY));
updateUser.setPassword(BCrypt.hashpw(dto.getNewPassword(), BCrypt.gensalt()));
return R.ok(userService.updateById(updateUser));
}
@PostMapping("/update/avatar")
@ApiOperation(value = "当前登录用户修改头像")
public R uploadAvatar(@RequestParam("file") MultipartFile file) throws Exception {
if (file.isEmpty()) {
throw new MyException("上传文件不能为空");
}
//上传文件
String suffix = Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf(StringPool.DOT));
String url = Objects.requireNonNull(OssFactory.build()).uploadSuffix(file.getBytes(), suffix);
User updateUser = new User();
updateUser.setId(StpUtil.getLoginIdAsLong());
updateUser.setAvatar(url);
userService.updateById(updateUser);
SaSession tokenSession = StpUtil.getTokenSession();
User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
user.setAvatar(url);
tokenSession.set(GlobalConstant.LOGIN_USER_INFO_KEY, user);
return R.ok(url);
}
@DeleteMapping
@ApiOperation(value = "删除用户(可批量)")
public R delete(@RequestBody List ids) {
if (ids.contains(GlobalConstant.SUPER_ADMIN_USER_ID)) {
R.error("管理员账户不能删除!");
}
if (ids.contains(StpUtil.getLoginIdAsLong())) {
R.error("当前登录账户不能删除!");
}
//删除时需要同时删除用户部门关联表和用户角色关联表和用户岗位关系表数据。
return R.ok(userService.deleteBatch(ids));
}
@GetMapping("/info/multi")
@ApiOperation(value = "批量获取用户信息")
public R usersInfo(@RequestParam String ids) {
return R.ok(userService.getUsersInfo(ids));
}
@GetMapping("/enabled")
@ApiOperation(value = "启用/禁用用户")
public R enabled(@RequestParam Long id) {
User user = userService.getOne(Wrappers.query().lambda().select(User::getEnabledMark).eq(User::getId, id), false);
if (user != null) {
User updateUser = new User();
updateUser.setId(id);
updateUser.setEnabledMark(user.getEnabledMark() == EnabledMark.ENABLED.getCode() ? EnabledMark.DISABLED.getCode() : EnabledMark.ENABLED.getCode());
return R.ok(userService.updateById(updateUser));
}
CompletableFuture.runAsync(() -> {
List list = userService.list();
redisUtil.set(GlobalConstant.USER_CACHE_KEY, list);
});
return R.error("该用户不存在!");
}
@PutMapping("/reset-password")
@ApiOperation(value = "重置密码")
public R resetPassword(@RequestBody ResetPasswordDto dto) {
User user = new User();
user.setId(dto.getId());
// user.setPassword(DigestUtil.md5Hex(propertiesConfig.getDefaultPassword()));
// user.setPassword(SaSecureUtil.md5BySalt(propertiesConfig.getDefaultPassword(), GlobalConstant.SECRET_KEY));
user.setPassword(BCrypt.hashpw(propertiesConfig.getDefaultPassword(), BCrypt.gensalt()));
CompletableFuture.runAsync(() -> {
List list = userService.list();
redisUtil.set(GlobalConstant.USER_CACHE_KEY, list);
});
return R.ok(userService.updateById(user));
}
@PostMapping("/bind-openid")
@ApiOperation(value = "绑定微信")
public R bindOpenid(@RequestBody BindOpenidDto dto) {
User user = userService.getOne(Wrappers.query().lambda().select(User::getId, User::getOpenId).eq(User::getId, dto.getId()), false);
if (user != null) {
if (StrUtil.isNotBlank(user.getOpenId())) {
return R.error("该用户已经绑定微信!");
}
User updateUser = new User();
updateUser.setId(dto.getId());
updateUser.setOpenId(dto.getOpenid());
return R.ok(userService.updateById(updateUser));
}
return R.error("该用户不存在!");
}
@GetMapping("/unbind-openid")
@ApiOperation(value = "取消绑定微信")
public R unbindOpenid(@RequestParam Long id) {
User updateUser = new User();
updateUser.setId(id);
updateUser.setOpenId("");
return R.ok(userService.updateById(updateUser));
}
@PostMapping("/register")
@ApiOperation(value = "家长注册")
public R register(@Valid @RequestBody RegisterDto dto) {
// 验证验证码
if (!smsCtcc.captchaVerify(dto.getMobile(), dto.getSmsCode())) {
return R.error("验证码不正确!");
}
// 赋值家长角色
dto.setPostId(RoleEnum.PARENT.getCode());
return R.ok(userService.add(dto));
}
@PostMapping("/bind-student")
@ApiOperation(value = "绑定学生")
public R bindStudent(@Valid @RequestBody UserStudentBindDto dto) {
User user = userService.getOne(Wrappers.query().lambda()
.eq(User::getName, dto.getName())
.eq(User::getCredentialNumber, dto.getIdCard()));
UserStudentAddDto userStudentAddDto = new UserStudentAddDto();
if (user == null) {
return R.error("学生不存在!");
}
userStudentAddDto.setUserId(dto.getUserId());
userStudentAddDto.setStudentId(user.getId());
return R.ok(userStudentService.add(userStudentAddDto));
}
@DeleteMapping("/unbind-student")
@ApiOperation(value = "解绑学生")
public R unBindStudent(@Valid @RequestBody UserStudentDeleteDto dto) {
return R.ok(userStudentService.delete(dto));
}
@GetMapping("/student")
@ApiOperation(value = "获取绑定学生")
public R unBindStudent(@Valid @RequestParam Long id) {
return R.ok(baseClassService.getStudents(id));
}
}