用户管理: 导入导出修改
This commit is contained in:
furongxin 2024-03-27 00:58:58 +08:00
parent c04332336c
commit 461dbae2a1
26 changed files with 576 additions and 184 deletions

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.framework.common.util.string.DTO;
import lombok.Data;
import java.time.LocalDate;
@Data
public class IdCardDO {
/**
* 性别
*/
private Integer sex;
/**
* 年龄
*/
private Integer age;
/**
* 出生日期
*/
private LocalDate date;
}

View File

@ -2,10 +2,11 @@ package cn.iocoder.yudao.framework.common.util.string;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.string.DTO.IdCardDO;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -66,4 +67,27 @@ public class StrUtils {
.collect(Collectors.joining("\n"));
}
/**
* 解析身份证号码获取年龄性别出生日期
* @param idCard
* @return
*/
public static IdCardDO IdCardAnalysis(String idCard) {
IdCardDO idCardDO = new IdCardDO();
//通过身份证号码 获得出生日期
LocalDate date = LocalDate.parse(idCard.substring(6,14), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//通过身份证号码 获得性别
Integer sex = Integer.parseInt(idCard.substring(16,17)) % 2 == 0 ? 2 : 1;
//通过身份证号码 获得年龄
Integer age = LocalDate.now().getYear() - date.getYear();
idCardDO.setAge(age);
idCardDO.setSex(sex);
idCardDO.setDate(date);
return idCardDO;
}
}

View File

@ -24,6 +24,8 @@ public class ValidationUtils {
private static final Pattern PATTERN_XML_NCNAME = Pattern.compile("[a-zA-Z_][\\-_.0-9_a-zA-Z$]*");
private static final Pattern PATTERN_IDCARD = Pattern.compile("^([1-9]\\d{5})(\\d{4})(\\d{2})(\\d{2})(\\d{3})(\\d|X)$");
public static boolean isMobile(String mobile) {
return StringUtils.hasText(mobile)
&& PATTERN_MOBILE.matcher(mobile).matches();
@ -39,6 +41,11 @@ public class ValidationUtils {
&& PATTERN_XML_NCNAME.matcher(str).matches();
}
public static boolean isIdCard(String idCard) {
return StringUtils.hasText(idCard)
&&PATTERN_IDCARD.matcher(idCard).matches();
}
public static void validate(Object object, Class<?>... groups) {
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Assert.notNull(validator);

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.framework.common.validation;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdCardValidator.class)
public @interface IdCard {
String message() default "身份证格式不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,22 @@
package cn.iocoder.yudao.framework.common.validation;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class IdCardValidator implements ConstraintValidator<IdCard, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 如果身份证为空默认不校验即校验通过
if (StrUtil.isEmpty(value)) {
return true;
}
// 检验身份证
return ValidationUtils.isIdCard(value);
}
}

View File

@ -31,12 +31,31 @@ public class ExcelUtils {
*/
public static <T> void write(HttpServletResponse response, String filename, String sheetName,
Class<T> head, List<T> data) throws IOException {
// 输出 Excel
// 输出excel
EasyExcel.write(response.getOutputStream(), head)
.autoCloseStream(false) // 不要自动关闭交给 Servlet 自己处理
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度自动适配最大 255 宽度
.registerWriteHandler(new SpinnerWriteHandler())
.registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度
.sheet(sheetName).doWrite(data);
// 设置 header contentType写在最后的原因是避免报错时响应 contentType 已经被修改了
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name()));
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
}
public static <T> void write(HttpServletResponse response, String filename, String sheetName,
Class<T> head, List<T> data, List<String> deptName, List<String> postName) throws IOException {
// 输出excel
EasyExcel.write(response.getOutputStream(), head)
.autoCloseStream(false) // 不要自动关闭交给 Servlet 自己处理
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度自动适配最大 255 宽度
.registerWriteHandler(new SpinnerWriteHandler(deptName, postName))
.registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度
.sheet(sheetName).doWrite(data);
// 设置 header contentType写在最后的原因是避免报错时响应 contentType 已经被修改了
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name()));
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
@ -48,4 +67,18 @@ public class ExcelUtils {
.doReadAllSync();
}
// public static class UserData {
// @ExcelProperty("User Name")
// private String name;
// @ExcelProperty(value = "Options", combo = {"Option 1", "Option 2", "Option 3"})
// private String option;
//
// public UserData(String name, String option) {
// this.name = name;
// this.option = option;
// }
//
// // Getters and setters
// }
}

View File

@ -0,0 +1,59 @@
package cn.iocoder.yudao.framework.excel.core.util;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SpinnerWriteHandler implements SheetWriteHandler {
private List<String> deptName;
private List<String> postName;
public SpinnerWriteHandler() {
}
public SpinnerWriteHandler(List<String> deptName, List<String> postName) {
this.deptName = deptName;
this.postName = postName;
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
Map<Integer, String[]> mapDropDown = new HashMap<>();
// 这里的key值 对应导出列的顺序 从0开始
mapDropDown.put(1, deptName.toArray(new String[0]));
mapDropDown.put(2, postName.toArray(new String[0]));
Sheet sheet = writeSheetHolder.getSheet();
/// 开始设置下拉框
DataValidationHelper helper = sheet.getDataValidationHelper();// 设置下拉框
for (Map.Entry<Integer, String[]> entry : mapDropDown.entrySet()) {
/*** 起始行、终止行、起始列、终止列 **/
CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, entry.getKey(), entry.getKey());
/*** 设置下拉框数据 **/
DataValidationConstraint constraint = helper.createExplicitListConstraint(entry.getValue());
DataValidation dataValidation = helper.createValidation(constraint, addressList);
/*** 处理Excel兼容性问题 **/
if (dataValidation instanceof XSSFDataValidation) {
dataValidation.setSuppressDropDownArrow(true);
dataValidation.setShowErrorBox(true);
} else {
dataValidation.setSuppressDropDownArrow(false);
}
sheet.addValidationData(dataValidation);
}
}
}

View File

@ -4,8 +4,6 @@ import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOABaseRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.upload.UploadUserFile;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
@ -19,8 +17,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
*/
@Schema(description = "管理后台 - 合同审批 请求Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmOAContractRespVO extends BpmOABaseRespVO {
@Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED)

View File

@ -46,6 +46,10 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
//插入OA 出差申请
BpmOAContractDO contract = BpmOAContractConvert.INSTANCE.convert(createReqVO).setUserId(userId)
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
contract.setMCompanyName(createReqVO.getmCompanyName());
contract.setMHeadName(createReqVO.getmHeadName());
contract.setOCompanyName(createReqVO.getoCompanyName());
contract.setOHeadName(createReqVO.getoHeadName());
contractMapper.insert(contract) ;
// 发起 BPM 流程

View File

@ -42,6 +42,10 @@ public interface DeptApi {
@Parameter(name = "leaderUserId", description = "部门负责人", example = "12", required = true)
CommonResult<List<DeptRespDTO>> getDeptByLeaderId(@RequestParam("leaderUserId")Long leaderUserId);
@GetMapping(PREFIX + "/getList")
@Operation(summary = "获取所有部门信息")
CommonResult<List<DeptRespDTO>> getDeptList();
/**
* 获得指定编号的部门 Map
*

View File

@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Collection;
import java.util.List;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Tag(name = "RPC 服务 - 岗位")
@ -27,4 +28,8 @@ public interface PostApi {
@Operation(summary = "获得部门信息")
@Parameter(name = "id", description = "岗位编号", example = "1024", required = true)
CommonResult<PostRespVO> getPost(@RequestParam("id") Long id);
@GetMapping(PREFIX + "/getList")
@Operation(summary = "获得所有部门信息")
CommonResult<List<PostRespVO>> getPostList();
}

View File

@ -1,9 +1,11 @@
package cn.iocoder.yudao.module.system.api.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import org.springframework.validation.annotation.Validated;
@ -49,4 +51,14 @@ public class DeptApiImpl implements DeptApi {
List<DeptDO> deptDO = deptService.getDeptByLeaderId(leaderUserId);
return success(BeanUtils.toBean(deptDO, DeptRespDTO.class));
}
@Override
public CommonResult<List<DeptRespDTO>> getDeptList() {
//获取部门名称信息
List<DeptDO> deptDOs = deptService.getDeptList(new DeptListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
return success(BeanUtils.toBean(deptDOs, DeptRespDTO.class));
}
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.system.api.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.dept.dto.PostRespVO;
@ -10,6 +11,9 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -32,4 +36,12 @@ public class PostApiImpl implements PostApi {
return success(BeanUtils.toBean(postDO, PostRespVO.class));
}
@Override
public CommonResult<List<PostRespVO>> getPostList() {
List<PostDO> postDO = postService.getPostList(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus()));
postDO.sort(Comparator.comparing(PostDO::getSort));
return success(BeanUtils.toBean(postDO, PostRespVO.class));
}
}

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.system.controller.admin.user;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
@ -11,16 +10,15 @@ import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.*;
import cn.iocoder.yudao.module.system.convert.user.UserConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.common.SexEnum;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.social.SocialClientService;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.ibatis.annotations.Param;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -30,9 +28,11 @@ import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@ -49,6 +49,9 @@ public class UserController {
@Resource
private DeptService deptService;
@Resource
private PostService postService;
@PostMapping("/create")
@Operation(summary = "新增用户")
@PreAuthorize("@ss.hasPermission('system:user:create')")
@ -100,9 +103,10 @@ public class UserController {
return success(new PageResult<>(pageResult.getTotal()));
}
// 拼接数据
Map<Long, DeptDO> deptMap = deptService.getDeptMap(
convertList(pageResult.getList(), AdminUserDO::getDeptId));
return success(new PageResult<>(UserConvert.INSTANCE.convertList(pageResult.getList(), deptMap),
Map<Long, DeptDO> deptMap = deptService.getDeptMap(convertList(pageResult.getList(), AdminUserDO::getDeptId));
Map<Long, PostDO> postMap = postService.getDeptMap(convertList(pageResult.getList(), AdminUserDO::getPostIds));
return success(new PageResult<>(UserConvert.INSTANCE.convertList(pageResult.getList(), deptMap, postMap),
pageResult.getTotal()));
}
@ -124,6 +128,7 @@ public class UserController {
AdminUserDO user = userService.getUser(id);
// 拼接数据
DeptDO dept = deptService.getDept(user.getDeptId());
return success(UserConvert.INSTANCE.convert(user, dept));
}
@ -135,25 +140,46 @@ public class UserController {
HttpServletResponse response) throws IOException {
exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<AdminUserDO> list = userService.getUserPage(exportReqVO).getList();
Map<Long, DeptDO> deptMap = deptService.getDeptMap(convertList(list, AdminUserDO::getDeptId));
Map<Long, PostDO> postMap = postService.getDeptMap(convertList(list, AdminUserDO::getPostIds));
//获取部门名称
List<DeptDO> deptDO = deptService.getDeptTree();
List<String> deptName = deptDO.stream().map(DeptDO::getName).collect(Collectors.toList());
//获取岗位名称
List<PostDO> postDO = postService.getPostList(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus()));
postDO.sort(Comparator.comparing(PostDO::getSort));
List<String> postName = postDO.stream().map(PostDO::getName).collect(Collectors.toList());
// 输出 Excel
Map<Long, DeptDO> deptMap = deptService.getDeptMap(
convertList(list, AdminUserDO::getDeptId));
ExcelUtils.write(response, "用户数据.xls", "数据", UserRespVO.class,
UserConvert.INSTANCE.convertList(list, deptMap));
UserConvert.INSTANCE.convertList(list, deptMap, postMap), deptName, postName);
}
@GetMapping("/get-import-template")
@Operation(summary = "获得导入用户模板")
public void importTemplate(HttpServletResponse response) throws IOException {
// 手动创建导出 demo
List<UserImportExcelVO> list = Arrays.asList(
UserImportExcelVO.builder().username("yunai").deptId(1L).email("yunai@iocoder.cn").mobile("15601691300")
.nickname("芋道").status(CommonStatusEnum.ENABLE.getStatus()).sex(SexEnum.MALE.getSex()).build(),
UserImportExcelVO.builder().username("yuanma").deptId(2L).email("yuanma@iocoder.cn").mobile("15601701300")
.nickname("源码").status(CommonStatusEnum.DISABLE.getStatus()).sex(SexEnum.FEMALE.getSex()).build()
);
// // 手动创建导出 demo
// List<UserImportExcelVO> list = Arrays.asList(
// UserImportExcelVO.builder().nickname("XXXX").deptName(1L).email("yunai@iocoder.cn").mobile("15601691300")
// .nickname("芋道").status(CommonStatusEnum.ENABLE.getStatus()).sex(SexEnum.MALE.getSex()).build(),
// UserImportExcelVO.builder().username("yuanma").deptId(2L).email("yuanma@iocoder.cn").mobile("15601701300")
// .nickname("源码").status(CommonStatusEnum.DISABLE.getStatus()).sex(SexEnum.FEMALE.getSex()).build()
// );
//获取部门名称
List<DeptDO> deptDO = deptService.getDeptTree();
List<String> deptName = deptDO.stream().map(DeptDO::getName).collect(Collectors.toList());
//获取岗位名称
List<PostDO> postDO = postService.getPostList(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus()));
postDO.sort(Comparator.comparing(PostDO::getSort));
List<String> postName = postDO.stream().map(PostDO::getName).collect(Collectors.toList());
// 输出
ExcelUtils.write(response, "用户导入模板.xls", "用户列表", UserImportExcelVO.class, list);
ExcelUtils.write(response, "用户导入模板.xls", "用户列表", UserImportExcelVO.class, null, deptName, postName);
}
@PostMapping("/import")
@ -168,5 +194,4 @@ public class UserController {
List<UserImportExcelVO> list = ExcelUtils.read(file, UserImportExcelVO.class);
return success(userService.importUserList(list, updateSupport));
}
}

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.user.vo.user;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
import cn.iocoder.yudao.framework.common.validation.IdCard;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -20,27 +19,31 @@ import lombok.experimental.Accessors;
@Accessors(chain = false) // 设置 chain = false避免用户导入有问题
public class UserImportExcelVO {
@ExcelProperty("登录名称")
private String username;
// @ExcelProperty("登录名称")
// private String username;
@ExcelProperty("用户名称")
private String nickname;
@ExcelProperty("部门编号")
private Long deptId;
@ExcelProperty("部门名称")
private String deptName;
@ExcelProperty("岗位名称")
private String postName;
@ExcelProperty("手机号码")
@Mobile
private String mobile;
@ExcelProperty("身份证号码")
@IdCard
private String idcard;
@ExcelProperty("用户邮箱")
private String email;
@ExcelProperty("手机号码")
private String mobile;
@ExcelProperty(value = "用户性别", converter = DictConvert.class)
@DictFormat(DictTypeConstants.USER_SEX)
private Integer sex;
@ExcelProperty(value = "账号状态", converter = DictConvert.class)
@DictFormat(DictTypeConstants.COMMON_STATUS)
private Integer status;
// @ExcelProperty(value = "账号状态", converter = DictConvert.class)
// @DictFormat(DictTypeConstants.COMMON_STATUS)
// private Integer status;
}

View File

@ -7,21 +7,25 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - 用户信息 Response VO")
@Data
@ExcelIgnoreUnannotated
public class UserRespVO{
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty("用户编号")
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1")
// @ExcelProperty("用户编号")
private Long id;
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
@ExcelProperty("用户名称")
// @ExcelProperty("用户名称")
private String username;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
@ -33,6 +37,7 @@ public class UserRespVO{
@Schema(description = "部门ID", example = "我是一个用户")
private Long deptId;
@Schema(description = "部门名称", example = "IT 部")
@ExcelProperty("部门名称")
private String deptName;
@ -40,19 +45,36 @@ public class UserRespVO{
@Schema(description = "岗位编号数组", example = "1")
private Set<Long> postIds;
@Schema(description = "用户邮箱", example = "yudao@iocoder.cn")
@ExcelProperty("用户邮箱")
private String email;
@Schema(description = "岗位名称", example = "总裁")
@ExcelProperty("岗位")
private String postName;
@Schema(description = "手机号码", example = "15601691300")
@ExcelProperty("手机号码")
private String mobile;
@Schema(description = "身份证号码")
@ExcelProperty("身份证号码")
private String idcard;
@Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1")
@ExcelProperty(value = "用户性别", converter = DictConvert.class)
@DictFormat(DictTypeConstants.USER_SEX)
private Integer sex;
@Schema(description = "年龄", example = "23")
@ExcelProperty("年龄")
private Integer age;
@Schema(description = "生日日期", example = "03-23")
@ExcelProperty("出生日期")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate birthdayDay;
@Schema(description = "用户邮箱", example = "yudao@iocoder.cn")
@ExcelProperty("用户邮箱")
private String email;
@Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png")
private String avatar;
@ -62,11 +84,11 @@ public class UserRespVO{
private Integer status;
@Schema(description = "最后登录 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "192.168.1.1")
@ExcelProperty("最后登录IP")
// @ExcelProperty("最后登录IP")
private String loginIp;
@Schema(description = "最后登录时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
@ExcelProperty("最后登录时间")
// @ExcelProperty("最后登录时间")
private LocalDateTime loginDate;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")

View File

@ -1,15 +1,22 @@
package cn.iocoder.yudao.module.system.controller.admin.user.vo.user;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.validation.IdCard;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.*;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.Email;
import javax.validation.constraints.Size;
import java.time.LocalDate;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - 用户创建/修改 Request VO")
@Data
public class UserSaveReqVO {
@ -17,10 +24,9 @@ public class UserSaveReqVO {
@Schema(description = "用户编号", example = "1024")
private Long id;
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
@NotBlank(message = "用户账号不能为空")
@Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由 数字、字母 组成")
@Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符")
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "yudao")
// @Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由 数字、字母 组成")
// @Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符")
private String username;
@Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
@ -51,6 +57,17 @@ public class UserSaveReqVO {
@Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png")
private String avatar;
@Schema(description = "身份证号码")
@IdCard
private String idcard;
@Schema(description = "年龄", example = "23")
private Integer age;
@Schema(description = "生日日期", example = "03-23")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate birthdayDay;
// ========== 创建需要传递的字段 ==========
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")

View File

@ -25,8 +25,9 @@ public interface UserConvert {
UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);
default List<UserRespVO> convertList(List<AdminUserDO> list, Map<Long, DeptDO> deptMap) {
return CollectionUtils.convertList(list, user -> convert(user, deptMap.get(user.getDeptId())));
default List<UserRespVO> convertList(List<AdminUserDO> list, Map<Long, DeptDO> deptMap, Map<Long, PostDO> postMap) {
return CollectionUtils.convertList(list, user -> convert(user, deptMap.get(user.getDeptId()), postMap.get(user.getPostIds().stream().findFirst().orElse(null))));
}
default UserRespVO convert(AdminUserDO user, DeptDO dept) {
@ -34,6 +35,18 @@ public interface UserConvert {
if (dept != null) {
userVO.setDeptName(dept.getName());
}
return userVO;
}
default UserRespVO convert(AdminUserDO user, DeptDO dept, PostDO postDO) {
UserRespVO userVO = BeanUtils.toBean(user, UserRespVO.class);
if (dept != null) {
userVO.setDeptName(dept.getName());
}
if (postDO != null) {
userVO.setPostName(postDO.getName());
}
return userVO;
}

View File

@ -11,6 +11,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Set;
@ -68,6 +69,18 @@ public class AdminUserDO extends TenantBaseDO {
* 手机号码
*/
private String mobile;
/**
* 身份证号码
*/
private String idcard;
/**
* 年龄
*/
private Integer age;
/**
* 生日日期
*/
private LocalDate birthdayDay;
/**
* 用户性别
*

View File

@ -41,4 +41,9 @@ public interface DeptMapper extends BaseMapperX<DeptDO> {
return selectList(new LambdaQueryWrapperX<DeptDO>().like(DeptDO::getFlag, flag));
}
default List<DeptDO> selectTree() {
return selectList(new LambdaQueryWrapperX<DeptDO>().orderByAsc(DeptDO::getFlag));
}
}

View File

@ -103,4 +103,6 @@ public interface DeptService {
* 根据用户ID 检索该用户所担任负责人的部门list
*/
List<DeptDO> getDeptByLeaderId(Long leaderUserId);
List<DeptDO> getDeptTree();
}

View File

@ -271,4 +271,10 @@ public class DeptServiceImpl implements DeptService {
return deptMapper.selectByLeaderId(leaderUserId);
}
@Override
public List<DeptDO> getDeptTree() {
return deptMapper.selectTree();
}
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.service.dept;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
@ -8,6 +9,9 @@ import org.springframework.lang.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 岗位 Service 接口
@ -38,6 +42,21 @@ public interface PostService {
*/
void deletePost(Long id);
/**
* 获得指定编号的岗位 Map
*
* @param setIds 部门编号数组
* @return 部门 Map
*/
default Map<Long, PostDO> getDeptMap(Collection<Set<Long>> setIds) {
Collection<Long> ids = setIds.stream()
.flatMap(Set::stream) // 展开嵌套集合
.collect(Collectors.toList()); // 收集展开后的元素到新的集合中
List<PostDO> list = getPostList(ids);
return CollectionUtils.convertMap(list, PostDO::getId);
}
/**
* 获得岗位列表
*
@ -81,4 +100,6 @@ public interface PostService {
*/
void validatePostList(Collection<Long> ids);
PostDO getByPostName(String postName);
}

View File

@ -150,4 +150,10 @@ public class PostServiceImpl implements PostService {
}
});
}
@Override
public PostDO getByPostName(String postName) {
return postMapper.selectOne(PostDO::getName, postName);
}
}

View File

@ -9,8 +9,11 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.string.DTO.IdCardDO;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserImportExcelVO;
@ -18,6 +21,7 @@ import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserImportRe
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper;
@ -36,6 +40,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@ -52,7 +57,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
@Slf4j
public class AdminUserServiceImpl implements AdminUserService {
@Value("${sys.user.init-password:yudaoyuanma}")
@Value("${sys.user.init-password:123456}")
private String userInitPassword;
@Resource
@ -415,34 +420,56 @@ public class AdminUserServiceImpl implements AdminUserService {
if (CollUtil.isEmpty(importUsers)) {
throw exception(USER_IMPORT_LIST_IS_EMPTY);
}
UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>())
.updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();
UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>()).updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();
importUsers.forEach(importUser -> {
//校验判断是否有不符合的原因
try {
validateUserForCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(),
importUser.getDeptId(), null);
validateUserForCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(), null, null);
} catch (ServiceException ex) {
respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
respVO.getFailureUsernames().put(importUser.getNickname(), ex.getMessage());
return;
}
AdminUserDO updateUser = BeanUtils.toBean(importUser, AdminUserDO.class);
//解析身份证号码
IdCardDO idCardDO = StrUtils.IdCardAnalysis(updateUser.getIdcard());
//设置 性别年龄出生日期
updateUser.setSex(idCardDO.getSex());
updateUser.setAge(idCardDO.getAge());
updateUser.setBirthdayDay(idCardDO.getDate());
//根据部门名称获取 部门ID
List<DeptDO> deptDO = deptService.getDeptList(new DeptListReqVO().setName(importUser.getDeptName()));
//设置部门ID
updateUser.setDeptId(deptDO.get(0).getId());
//根据岗位名称获取 岗位ID
PostDO postDO = postService.getByPostName(importUser.getPostName());
//设置岗位ID
updateUser.setPostIds(Collections.singleton(postDO.getId()));
// 判断如果不存在在进行插入
AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername());
AdminUserDO existUser = userMapper.selectByUsername(importUser.getMobile());
if (existUser == null) {
userMapper.insert(BeanUtils.toBean(importUser, AdminUserDO.class)
.setPassword(encodePassword(userInitPassword)).setPostIds(new HashSet<>())); // 设置默认密码及空岗位编号数组
respVO.getCreateUsernames().add(importUser.getUsername());
userMapper.insert(updateUser.setPassword(encodePassword(userInitPassword)).setPostIds(new HashSet<>())); // 设置默认密码及空岗位编号数组
respVO.getCreateUsernames().add(importUser.getNickname());
return;
}
// 如果存在判断是否允许更新
if (!isUpdateSupport) {
respVO.getFailureUsernames().put(importUser.getUsername(), USER_USERNAME_EXISTS.getMsg());
respVO.getFailureUsernames().put(importUser.getNickname(), USER_USERNAME_EXISTS.getMsg());
return;
}
AdminUserDO updateUser = BeanUtils.toBean(importUser, AdminUserDO.class);
updateUser.setId(existUser.getId());
userMapper.updateById(updateUser);
respVO.getUpdateUsernames().add(importUser.getUsername());
respVO.getUpdateUsernames().add(importUser.getNickname());
});
return respVO;
}
@ -477,4 +504,18 @@ public class AdminUserServiceImpl implements AdminUserService {
return passwordEncoder.encode(password);
}
private void IdCardAnalysis(AdminUserDO updateUser) {
LocalDate nowDate = LocalDate.now();
String idCard = updateUser.getIdcard();
//通过身份证号码 获得出生日期
LocalDate date = LocalDate.parse(idCard.substring(6,14));
//通过身份证号码 获得性别
Integer sex = Integer.parseInt(idCard.substring(16,17)) % 2 == 0 ? 2 : 1;
//通过身份证号码 获得年龄
Integer age = nowDate.getYear() - date.getYear();
}
}

View File

@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.system.service.user;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
@ -10,8 +9,6 @@ import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserImportExcelVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserImportRespVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
@ -418,113 +415,113 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest {
/**
* 情况一校验不通过导致插入失败
*/
@Test
public void testImportUserList_01() {
// 准备参数
UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> {
});
// mock 方法模拟失败
doThrow(new ServiceException(DEPT_NOT_FOUND)).when(deptService).validateDeptList(any());
// 调用
UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), true);
// 断言
assertEquals(0, respVO.getCreateUsernames().size());
assertEquals(0, respVO.getUpdateUsernames().size());
assertEquals(1, respVO.getFailureUsernames().size());
assertEquals(DEPT_NOT_FOUND.getMsg(), respVO.getFailureUsernames().get(importUser.getUsername()));
}
/**
* 情况二不存在进行插入
*/
@Test
public void testImportUserList_02() {
// 准备参数
UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> {
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围
});
// mock deptService 的方法
DeptDO dept = randomPojo(DeptDO.class, o -> {
o.setId(importUser.getDeptId());
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
});
when(deptService.getDept(eq(dept.getId()))).thenReturn(dept);
// mock passwordEncoder 的方法
when(passwordEncoder.encode(eq("yudaoyuanma"))).thenReturn("java");
// 调用
UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), true);
// 断言
assertEquals(1, respVO.getCreateUsernames().size());
AdminUserDO user = userMapper.selectByUsername(respVO.getCreateUsernames().get(0));
assertPojoEquals(importUser, user);
assertEquals("java", user.getPassword());
assertEquals(0, respVO.getUpdateUsernames().size());
assertEquals(0, respVO.getFailureUsernames().size());
}
/**
* 情况三存在但是不强制更新
*/
@Test
public void testImportUserList_03() {
// mock 数据
AdminUserDO dbUser = randomAdminUserDO();
userMapper.insert(dbUser);
// 准备参数
UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> {
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围
o.setUsername(dbUser.getUsername());
});
// mock deptService 的方法
DeptDO dept = randomPojo(DeptDO.class, o -> {
o.setId(importUser.getDeptId());
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
});
when(deptService.getDept(eq(dept.getId()))).thenReturn(dept);
// 调用
UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), false);
// 断言
assertEquals(0, respVO.getCreateUsernames().size());
assertEquals(0, respVO.getUpdateUsernames().size());
assertEquals(1, respVO.getFailureUsernames().size());
assertEquals(USER_USERNAME_EXISTS.getMsg(), respVO.getFailureUsernames().get(importUser.getUsername()));
}
/**
* 情况四存在强制更新
*/
@Test
public void testImportUserList_04() {
// mock 数据
AdminUserDO dbUser = randomAdminUserDO();
userMapper.insert(dbUser);
// 准备参数
UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> {
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围
o.setUsername(dbUser.getUsername());
});
// mock deptService 的方法
DeptDO dept = randomPojo(DeptDO.class, o -> {
o.setId(importUser.getDeptId());
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
});
when(deptService.getDept(eq(dept.getId()))).thenReturn(dept);
// 调用
UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), true);
// 断言
assertEquals(0, respVO.getCreateUsernames().size());
assertEquals(1, respVO.getUpdateUsernames().size());
AdminUserDO user = userMapper.selectByUsername(respVO.getUpdateUsernames().get(0));
assertPojoEquals(importUser, user);
assertEquals(0, respVO.getFailureUsernames().size());
}
// @Test
// public void testImportUserList_01() {
// // 准备参数
// UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> {
// });
// // mock 方法模拟失败
// doThrow(new ServiceException(DEPT_NOT_FOUND)).when(deptService).validateDeptList(any());
//
// // 调用
// UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), true);
// // 断言
// assertEquals(0, respVO.getCreateUsernames().size());
// assertEquals(0, respVO.getUpdateUsernames().size());
// assertEquals(1, respVO.getFailureUsernames().size());
// assertEquals(DEPT_NOT_FOUND.getMsg(), respVO.getFailureUsernames().get(importUser.getUsername()));
// }
//
// /**
// * 情况二不存在进行插入
// */
// @Test
// public void testImportUserList_02() {
// // 准备参数
// UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> {
// o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
// o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围
// });
// // mock deptService 的方法
// DeptDO dept = randomPojo(DeptDO.class, o -> {
// o.setId(importUser.getDeptId());
// o.setStatus(CommonStatusEnum.ENABLE.getStatus());
// });
// when(deptService.getDept(eq(dept.getId()))).thenReturn(dept);
// // mock passwordEncoder 的方法
// when(passwordEncoder.encode(eq("yudaoyuanma"))).thenReturn("java");
//
// // 调用
// UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), true);
// // 断言
// assertEquals(1, respVO.getCreateUsernames().size());
// AdminUserDO user = userMapper.selectByUsername(respVO.getCreateUsernames().get(0));
// assertPojoEquals(importUser, user);
// assertEquals("java", user.getPassword());
// assertEquals(0, respVO.getUpdateUsernames().size());
// assertEquals(0, respVO.getFailureUsernames().size());
// }
//
// /**
// * 情况三存在但是不强制更新
// */
// @Test
// public void testImportUserList_03() {
// // mock 数据
// AdminUserDO dbUser = randomAdminUserDO();
// userMapper.insert(dbUser);
// // 准备参数
// UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> {
// o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
// o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围
// o.setUsername(dbUser.getUsername());
// });
// // mock deptService 的方法
// DeptDO dept = randomPojo(DeptDO.class, o -> {
// o.setId(importUser.getDeptId());
// o.setStatus(CommonStatusEnum.ENABLE.getStatus());
// });
// when(deptService.getDept(eq(dept.getId()))).thenReturn(dept);
//
// // 调用
// UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), false);
// // 断言
// assertEquals(0, respVO.getCreateUsernames().size());
// assertEquals(0, respVO.getUpdateUsernames().size());
// assertEquals(1, respVO.getFailureUsernames().size());
// assertEquals(USER_USERNAME_EXISTS.getMsg(), respVO.getFailureUsernames().get(importUser.getUsername()));
// }
//
// /**
// * 情况四存在强制更新
// */
// @Test
// public void testImportUserList_04() {
// // mock 数据
// AdminUserDO dbUser = randomAdminUserDO();
// userMapper.insert(dbUser);
// // 准备参数
// UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> {
// o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
// o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围
// o.setUsername(dbUser.getUsername());
// });
// // mock deptService 的方法
// DeptDO dept = randomPojo(DeptDO.class, o -> {
// o.setId(importUser.getDeptId());
// o.setStatus(CommonStatusEnum.ENABLE.getStatus());
// });
// when(deptService.getDept(eq(dept.getId()))).thenReturn(dept);
//
// // 调用
// UserImportRespVO respVO = userService.importUserList(newArrayList(importUser), true);
// // 断言
// assertEquals(0, respVO.getCreateUsernames().size());
// assertEquals(1, respVO.getUpdateUsernames().size());
// AdminUserDO user = userMapper.selectByUsername(respVO.getUpdateUsernames().get(0));
// assertPojoEquals(importUser, user);
// assertEquals(0, respVO.getFailureUsernames().size());
// }
@Test
public void testValidateUserExists_notExists() {