feat: 优化用户导入失败反馈与模板说明

- 支持按字段返回用户导入失败明细

- 补充导入模板填写说明与名称匹配规则

- 优化管理端导入失败弹窗与错误展示
This commit is contained in:
2026-04-09 17:25:50 +08:00
parent 4e565aef99
commit cfbeaf11fe
7 changed files with 652 additions and 161 deletions

View File

@@ -0,0 +1,67 @@
package tech.easyflow.system.entity.vo;
/**
* 用户导入失败明细。
*/
public class SysAccountImportErrorDetailVo {
private String fieldName;
private String fieldValue;
private String reason;
/**
* 获取问题字段名。
*
* @return 字段名
*/
public String getFieldName() {
return fieldName;
}
/**
* 设置问题字段名。
*
* @param fieldName 字段名
*/
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
/**
* 获取用户填写值。
*
* @return 用户填写值
*/
public String getFieldValue() {
return fieldValue;
}
/**
* 设置用户填写值。
*
* @param fieldValue 用户填写值
*/
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
/**
* 获取失败原因。
*
* @return 失败原因
*/
public String getReason() {
return reason;
}
/**
* 设置失败原因。
*
* @param reason 失败原因
*/
public void setReason(String reason) {
this.reason = reason;
}
}

View File

@@ -1,5 +1,8 @@
package tech.easyflow.system.entity.vo;
import java.util.ArrayList;
import java.util.List;
/**
* 用户导入失败行。
*/
@@ -7,41 +10,141 @@ public class SysAccountImportErrorRowVo {
private Integer rowNumber;
private String deptCode;
private String deptName;
private String loginName;
private String reason;
private String nickname;
private String roleNames;
private String positionNames;
private List<SysAccountImportErrorDetailVo> details = new ArrayList<>();
/**
* 获取行号。
*
* @return 行号
*/
public Integer getRowNumber() {
return rowNumber;
}
/**
* 设置行号。
*
* @param rowNumber 行号
*/
public void setRowNumber(Integer rowNumber) {
this.rowNumber = rowNumber;
}
public String getDeptCode() {
return deptCode;
/**
* 获取部门名称。
*
* @return 部门名称
*/
public String getDeptName() {
return deptName;
}
public void setDeptCode(String deptCode) {
this.deptCode = deptCode;
/**
* 设置部门名称。
*
* @param deptName 部门名称
*/
public void setDeptName(String deptName) {
this.deptName = deptName;
}
/**
* 获取登录账号。
*
* @return 登录账号
*/
public String getLoginName() {
return loginName;
}
/**
* 设置登录账号。
*
* @param loginName 登录账号
*/
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getReason() {
return reason;
/**
* 获取昵称。
*
* @return 昵称
*/
public String getNickname() {
return nickname;
}
public void setReason(String reason) {
this.reason = reason;
/**
* 设置昵称。
*
* @param nickname 昵称
*/
public void setNickname(String nickname) {
this.nickname = nickname;
}
/**
* 获取角色名称集合文本。
*
* @return 角色名称集合文本
*/
public String getRoleNames() {
return roleNames;
}
/**
* 设置角色名称集合文本。
*
* @param roleNames 角色名称集合文本
*/
public void setRoleNames(String roleNames) {
this.roleNames = roleNames;
}
/**
* 获取岗位名称集合文本。
*
* @return 岗位名称集合文本
*/
public String getPositionNames() {
return positionNames;
}
/**
* 设置岗位名称集合文本。
*
* @param positionNames 岗位名称集合文本
*/
public void setPositionNames(String positionNames) {
this.positionNames = positionNames;
}
/**
* 获取失败明细。
*
* @return 失败明细
*/
public List<SysAccountImportErrorDetailVo> getDetails() {
return details;
}
/**
* 设置失败明细。
*
* @param details 失败明细
*/
public void setDetails(List<SysAccountImportErrorDetailVo> details) {
this.details = details;
}
}

View File

@@ -3,10 +3,12 @@ package tech.easyflow.system.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.idev.excel.EasyExcel;
import cn.idev.excel.ExcelWriter;
import cn.idev.excel.FastExcel;
import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.metadata.data.ReadCellData;
import cn.idev.excel.read.listener.ReadListener;
import cn.idev.excel.write.metadata.WriteSheet;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
@@ -28,6 +30,7 @@ import tech.easyflow.system.entity.SysPosition;
import tech.easyflow.system.entity.SysRole;
import tech.easyflow.system.entity.vo.SysAccountBatchActionErrorItemVo;
import tech.easyflow.system.entity.vo.SysAccountBatchActionResultVo;
import tech.easyflow.system.entity.vo.SysAccountImportErrorDetailVo;
import tech.easyflow.system.entity.vo.SysAccountImportErrorRowVo;
import tech.easyflow.system.entity.vo.SysAccountImportResultVo;
import tech.easyflow.system.mapper.SysAccountMapper;
@@ -53,6 +56,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
/**
* 用户表 服务层实现。
@@ -69,15 +73,27 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
private static final String DEFAULT_RESET_PASSWORD = "123456";
private static final long MAX_IMPORT_FILE_SIZE_BYTES = 10L * 1024 * 1024;
private static final int MAX_IMPORT_ROWS = 5000;
private static final String IMPORT_HEAD_DEPT_CODE = "部门编码";
private static final String IMPORT_HEAD_LOGIN_NAME = "登录账号";
private static final String IMPORT_HEAD_NICKNAME = "昵称";
private static final String IMPORT_HEAD_DEPT_NAME = "部门名称*";
private static final String IMPORT_HEAD_LOGIN_NAME = "登录账号*";
private static final String IMPORT_HEAD_NICKNAME = "昵称*";
private static final String IMPORT_HEAD_MOBILE = "手机号";
private static final String IMPORT_HEAD_EMAIL = "邮箱";
private static final String IMPORT_HEAD_STATUS = "状态";
private static final String IMPORT_HEAD_ROLE_KEYS = "角色编码";
private static final String IMPORT_HEAD_POSITION_CODES = "岗位编码";
private static final String IMPORT_HEAD_ROLE_NAMES = "角色名称";
private static final String IMPORT_HEAD_POSITION_NAMES = "岗位名称";
private static final String IMPORT_HEAD_REMARK = "备注";
private static final String IMPORT_GUIDE_HEAD_ITEM = "说明项";
private static final String IMPORT_GUIDE_HEAD_CONTENT = "内容";
private static final String IMPORT_FIELD_DEPT_NAME = "部门名称";
private static final String IMPORT_FIELD_LOGIN_NAME = "登录账号";
private static final String IMPORT_FIELD_NICKNAME = "昵称";
private static final String IMPORT_FIELD_MOBILE = "手机号";
private static final String IMPORT_FIELD_EMAIL = "邮箱";
private static final String IMPORT_FIELD_STATUS = "状态";
private static final String IMPORT_FIELD_ROLE_NAME = "角色名称";
private static final String IMPORT_FIELD_POSITION_NAME = "岗位名称";
private static final String IMPORT_FIELD_SYSTEM = "系统";
private static final String IMPORT_ERROR_DUPLICATED_RESOURCE = "存在重名,请先在管理端处理";
@Resource
private SysAccountRoleMapper sysAccountRoleMapper;
@@ -244,16 +260,25 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
return result;
}
Map<String, SysDept> deptMap = buildDeptCodeMap();
Map<String, SysRole> roleMap = buildRoleKeyMap();
Map<String, SysPosition> positionMap = buildPositionCodeMap();
ImportNameLookup<SysDept> deptLookup = buildImportNameLookup(
sysDeptMapper.selectListByQuery(QueryWrapper.create()),
SysDept::getDeptName
);
ImportNameLookup<SysRole> roleLookup = buildImportNameLookup(
sysRoleMapper.selectListByQuery(QueryWrapper.create()),
SysRole::getRoleName
);
ImportNameLookup<SysPosition> positionLookup = buildImportNameLookup(
sysPositionMapper.selectListByQuery(QueryWrapper.create()),
SysPosition::getPositionName
);
for (SysAccountImportRow row : rows) {
try {
executeInRowTransaction(() -> importSingleRow(row, loginAccount, deptMap, roleMap, positionMap));
executeInRowTransaction(() -> importSingleRow(row, loginAccount, deptLookup, roleLookup, positionLookup));
result.setSuccessCount(result.getSuccessCount() + 1);
} catch (Exception e) {
result.setErrorCount(result.getErrorCount() + 1);
appendImportError(result, row, extractImportErrorMessage(e));
appendImportError(result, row, e);
}
}
return result;
@@ -261,10 +286,20 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
@Override
public void writeImportTemplate(OutputStream outputStream) {
EasyExcel.write(outputStream)
.head(buildImportHeadList())
.sheet("模板")
.doWrite(new ArrayList<>());
ExcelWriter excelWriter = EasyExcel.write(outputStream).build();
try {
WriteSheet templateSheet = EasyExcel.writerSheet("模板")
.head(buildImportHeadList())
.build();
excelWriter.write(new ArrayList<>(), templateSheet);
WriteSheet guideSheet = EasyExcel.writerSheet("填写说明")
.head(buildImportGuideHeadList())
.build();
excelWriter.write(buildImportGuideRows(), guideSheet);
} finally {
excelWriter.finish();
}
}
private void executeInRowTransaction(Runnable action) {
@@ -281,29 +316,54 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
private void importSingleRow(SysAccountImportRow row,
LoginAccount loginAccount,
Map<String, SysDept> deptMap,
Map<String, SysRole> roleMap,
Map<String, SysPosition> positionMap) {
String deptCode = trimToNull(row.getDeptCode());
ImportNameLookup<SysDept> deptLookup,
ImportNameLookup<SysRole> roleLookup,
ImportNameLookup<SysPosition> positionLookup) {
List<SysAccountImportErrorDetailVo> details = new ArrayList<>();
String deptName = trimToNull(row.getDeptName());
String loginName = trimToNull(row.getLoginName());
String nickname = trimToNull(row.getNickname());
if (deptCode == null) {
throw new BusinessException("部门编码不能为空");
String mobile = trimToNull(row.getMobile());
String email = trimToNull(row.getEmail());
if (deptName == null) {
addImportDetail(details, IMPORT_FIELD_DEPT_NAME, row.getDeptName(), "部门名称不能为空");
}
if (loginName == null) {
throw new BusinessException("登录账号不能为空");
addImportDetail(details, IMPORT_FIELD_LOGIN_NAME, row.getLoginName(), "登录账号不能为空");
} else if (isLoginNameExists(loginName)) {
addImportDetail(details, IMPORT_FIELD_LOGIN_NAME, row.getLoginName(), "登录账号已存在");
}
if (nickname == null) {
throw new BusinessException("昵称不能为空");
addImportDetail(details, IMPORT_FIELD_NICKNAME, row.getNickname(), "昵称不能为空");
}
SysDept dept = deptMap.get(deptCode);
if (dept == null) {
throw new BusinessException("部门编码不存在: " + deptCode);
if (mobile != null && !StringUtil.isMobileNumber(mobile)) {
addImportDetail(details, IMPORT_FIELD_MOBILE, row.getMobile(), "手机号格式不正确");
}
if (email != null && !StringUtil.isEmail(email)) {
addImportDetail(details, IMPORT_FIELD_EMAIL, row.getEmail(), "邮箱格式不正确");
}
ensureLoginNameNotExists(loginName);
List<BigInteger> roleIds = resolveRoleIds(row.getRoleKeys(), roleMap);
List<BigInteger> positionIds = resolvePositionIds(row.getPositionCodes(), positionMap);
SysDept dept = resolveSingleResource(deptName, deptLookup, IMPORT_FIELD_DEPT_NAME, details);
Integer status = parseStatus(row.getStatus(), details);
List<BigInteger> roleIds = resolveResourceIds(
row.getRoleNames(),
roleLookup,
SysRole::getId,
IMPORT_FIELD_ROLE_NAME,
details
);
List<BigInteger> positionIds = resolveResourceIds(
row.getPositionNames(),
positionLookup,
SysPosition::getId,
IMPORT_FIELD_POSITION_NAME,
details
);
if (!details.isEmpty()) {
throw new ImportRowValidationException(details);
}
SysAccount entity = new SysAccount();
entity.setDeptId(dept.getId());
@@ -313,9 +373,9 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
entity.setPasswordResetRequired(true);
entity.setAccountType(EnumAccountType.NORMAL.getCode());
entity.setNickname(nickname);
entity.setMobile(trimToNull(row.getMobile()));
entity.setEmail(trimToNull(row.getEmail()));
entity.setStatus(parseStatus(row.getStatus()));
entity.setMobile(mobile);
entity.setEmail(email);
entity.setStatus(status);
entity.setRemark(trimToNull(row.getRemark()));
entity.setCreated(new Date());
entity.setCreatedBy(loginAccount.getId());
@@ -327,15 +387,26 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
syncRelations(entity);
}
private void ensureLoginNameNotExists(String loginName) {
/**
* 校验登录账号是否已存在。
*
* @param loginName 登录账号
* @return 是否已存在
*/
private boolean isLoginNameExists(String loginName) {
QueryWrapper wrapper = QueryWrapper.create();
wrapper.eq(SysAccount::getLoginName, loginName);
if (count(wrapper) > 0) {
throw new BusinessException("登录账号已存在: " + loginName);
}
return count(wrapper) > 0;
}
private Integer parseStatus(String rawStatus) {
/**
* 解析导入状态列。
*
* @param rawStatus 原始状态文本
* @param details 错误明细收集器
* @return 解析后的状态编码
*/
private Integer parseStatus(String rawStatus, List<SysAccountImportErrorDetailVo> details) {
String status = trimToNull(rawStatus);
if (status == null) {
return EnumDataStatus.AVAILABLE.getCode();
@@ -346,39 +417,38 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
if ("0".equals(status) || "未启用".equals(status) || "停用".equals(status) || "禁用".equals(status)) {
return EnumDataStatus.UNAVAILABLE.getCode();
}
throw new BusinessException("状态不合法,仅支持 1/0 或 已启用/未启");
addImportDetail(details, IMPORT_FIELD_STATUS, rawStatus, "状态不合法,仅支持 1/0/已启用/启用/未启用/停用/禁");
return null;
}
private List<BigInteger> resolveRoleIds(String roleKeysText, Map<String, SysRole> roleMap) {
List<String> roleKeys = splitCodes(roleKeysText);
if (roleKeys.isEmpty()) {
/**
* 解析名称列表并映射为主键集合。
*
* @param rawNames 原始名称文本
* @param lookup 名称查找表
* @param fieldName 字段名称
* @param details 错误明细收集器
* @param <T> 资源类型
* @return 匹配到的主键集合
*/
private <T> List<BigInteger> resolveResourceIds(
String rawNames,
ImportNameLookup<T> lookup,
Function<T, BigInteger> idExtractor,
String fieldName,
List<SysAccountImportErrorDetailVo> details) {
List<String> names = splitCodes(rawNames);
if (names.isEmpty()) {
return Collections.emptyList();
}
List<BigInteger> roleIds = new ArrayList<>(roleKeys.size());
for (String roleKey : roleKeys) {
SysRole role = roleMap.get(roleKey);
if (role == null) {
throw new BusinessException("角色编码不存在: " + roleKey);
List<BigInteger> ids = new ArrayList<>(names.size());
for (String name : names) {
T resource = resolveSingleResource(name, lookup, fieldName, details);
if (resource != null) {
ids.add(idExtractor.apply(resource));
}
roleIds.add(role.getId());
}
return roleIds;
}
private List<BigInteger> resolvePositionIds(String positionCodesText, Map<String, SysPosition> positionMap) {
List<String> positionCodes = splitCodes(positionCodesText);
if (positionCodes.isEmpty()) {
return Collections.emptyList();
}
List<BigInteger> positionIds = new ArrayList<>(positionCodes.size());
for (String positionCode : positionCodes) {
SysPosition position = positionMap.get(positionCode);
if (position == null) {
throw new BusinessException("岗位编码不存在: " + positionCode);
}
positionIds.add(position.getId());
}
return positionIds;
return ids;
}
private List<String> splitCodes(String rawCodes) {
@@ -398,40 +468,32 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
return result;
}
private Map<String, SysDept> buildDeptCodeMap() {
List<SysDept> deptList = sysDeptMapper.selectListByQuery(QueryWrapper.create());
Map<String, SysDept> deptMap = new HashMap<>();
for (SysDept dept : deptList) {
String deptCode = trimToNull(dept.getDeptCode());
if (deptCode != null) {
deptMap.putIfAbsent(deptCode, dept);
/**
* 构建导入名称查找表,并标记重名数据。
*
* @param resources 资源集合
* @param nameExtractor 名称提取器
* @param <T> 资源类型
* @return 名称查找表
*/
private <T> ImportNameLookup<T> buildImportNameLookup(List<T> resources, Function<T, String> nameExtractor) {
Map<String, T> uniqueMap = new HashMap<>();
Set<String> duplicateNames = new LinkedHashSet<>();
for (T resource : resources) {
String name = trimToNull(nameExtractor.apply(resource));
if (name == null) {
continue;
}
if (uniqueMap.containsKey(name)) {
duplicateNames.add(name);
uniqueMap.remove(name);
continue;
}
if (!duplicateNames.contains(name)) {
uniqueMap.put(name, resource);
}
}
return deptMap;
}
private Map<String, SysRole> buildRoleKeyMap() {
List<SysRole> roleList = sysRoleMapper.selectListByQuery(QueryWrapper.create());
Map<String, SysRole> roleMap = new HashMap<>();
for (SysRole role : roleList) {
String roleKey = trimToNull(role.getRoleKey());
if (roleKey != null) {
roleMap.putIfAbsent(roleKey, role);
}
}
return roleMap;
}
private Map<String, SysPosition> buildPositionCodeMap() {
List<SysPosition> positionList = sysPositionMapper.selectListByQuery(QueryWrapper.create());
Map<String, SysPosition> positionMap = new HashMap<>();
for (SysPosition position : positionList) {
String positionCode = trimToNull(position.getPositionCode());
if (positionCode != null) {
positionMap.putIfAbsent(positionCode, position);
}
}
return positionMap;
return new ImportNameLookup<>(uniqueMap, duplicateNames);
}
private List<SysAccountImportRow> parseImportRows(MultipartFile file) {
@@ -462,12 +524,21 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
}
}
private void appendImportError(SysAccountImportResultVo result, SysAccountImportRow row, String reason) {
private void appendImportError(SysAccountImportResultVo result, SysAccountImportRow row, Exception exception) {
SysAccountImportErrorRowVo errorRow = new SysAccountImportErrorRowVo();
errorRow.setRowNumber(row.getRowNumber());
errorRow.setDeptCode(row.getDeptCode());
errorRow.setDeptName(row.getDeptName());
errorRow.setLoginName(row.getLoginName());
errorRow.setReason(reason);
errorRow.setNickname(row.getNickname());
errorRow.setRoleNames(row.getRoleNames());
errorRow.setPositionNames(row.getPositionNames());
if (exception instanceof ImportRowValidationException validationException) {
errorRow.setDetails(validationException.getDetails());
} else {
List<SysAccountImportErrorDetailVo> details = new ArrayList<>(1);
addImportDetail(details, IMPORT_FIELD_SYSTEM, null, extractImportErrorMessage(exception));
errorRow.setDetails(details);
}
result.getErrorRows().add(errorRow);
}
@@ -537,18 +608,69 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
private List<List<String>> buildImportHeadList() {
List<List<String>> headList = new ArrayList<>(9);
headList.add(Collections.singletonList(IMPORT_HEAD_DEPT_CODE));
headList.add(Collections.singletonList(IMPORT_HEAD_DEPT_NAME));
headList.add(Collections.singletonList(IMPORT_HEAD_LOGIN_NAME));
headList.add(Collections.singletonList(IMPORT_HEAD_NICKNAME));
headList.add(Collections.singletonList(IMPORT_HEAD_MOBILE));
headList.add(Collections.singletonList(IMPORT_HEAD_EMAIL));
headList.add(Collections.singletonList(IMPORT_HEAD_STATUS));
headList.add(Collections.singletonList(IMPORT_HEAD_ROLE_KEYS));
headList.add(Collections.singletonList(IMPORT_HEAD_POSITION_CODES));
headList.add(Collections.singletonList(IMPORT_HEAD_ROLE_NAMES));
headList.add(Collections.singletonList(IMPORT_HEAD_POSITION_NAMES));
headList.add(Collections.singletonList(IMPORT_HEAD_REMARK));
return headList;
}
private List<List<String>> buildImportGuideHeadList() {
List<List<String>> headList = new ArrayList<>(2);
headList.add(Collections.singletonList(IMPORT_GUIDE_HEAD_ITEM));
headList.add(Collections.singletonList(IMPORT_GUIDE_HEAD_CONTENT));
return headList;
}
private List<List<String>> buildImportGuideRows() {
List<List<String>> rows = new ArrayList<>();
rows.add(List.of("填写规则", "请按名称填写部门、角色、岗位。"));
rows.add(List.of("必填字段", "部门名称*、登录账号*、昵称*"));
rows.add(List.of("可选字段", "手机号、邮箱、状态、角色名称、岗位名称、备注"));
rows.add(List.of("状态可选值", "可留空,或填写 1/0/已启用/启用/未启用/停用/禁用"));
rows.add(List.of("多值分隔", "角色名称、岗位名称支持使用英文逗号,或中文逗号,分隔多个名称"));
rows.add(List.of("导入后初始密码", "导入成功的账号默认密码为 123456首次登录需要修改密码"));
rows.add(List.of("示例行", "市场部 | zhangsan | 张三 | 13800138000 | zhangsan@example.com | 已启用 | 普通员工,审批专员 | 产品经理 | 示例导入"));
return rows;
}
private void addImportDetail(List<SysAccountImportErrorDetailVo> details,
String fieldName,
String fieldValue,
String reason) {
SysAccountImportErrorDetailVo detail = new SysAccountImportErrorDetailVo();
detail.setFieldName(fieldName);
detail.setFieldValue(trimToNull(fieldValue));
detail.setReason(reason);
details.add(detail);
}
private <T> T resolveSingleResource(
String rawName,
ImportNameLookup<T> lookup,
String fieldName,
List<SysAccountImportErrorDetailVo> details) {
String name = trimToNull(rawName);
if (name == null) {
return null;
}
if (lookup.getDuplicateNames().contains(name)) {
addImportDetail(details, fieldName, rawName, fieldName + IMPORT_ERROR_DUPLICATED_RESOURCE);
return null;
}
T resource = lookup.getUniqueMap().get(name);
if (resource == null) {
addImportDetail(details, fieldName, rawName, fieldName + "不存在");
return null;
}
return resource;
}
private String trimToNull(String value) {
if (!StringUtil.hasText(value)) {
return null;
@@ -558,14 +680,14 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
private static class SysAccountImportRow {
private Integer rowNumber;
private String deptCode;
private String deptName;
private String loginName;
private String nickname;
private String mobile;
private String email;
private String status;
private String roleKeys;
private String positionCodes;
private String roleNames;
private String positionNames;
private String remark;
public Integer getRowNumber() {
@@ -576,12 +698,12 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
this.rowNumber = rowNumber;
}
public String getDeptCode() {
return deptCode;
public String getDeptName() {
return deptName;
}
public void setDeptCode(String deptCode) {
this.deptCode = deptCode;
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getLoginName() {
@@ -624,20 +746,20 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
this.status = status;
}
public String getRoleKeys() {
return roleKeys;
public String getRoleNames() {
return roleNames;
}
public void setRoleKeys(String roleKeys) {
this.roleKeys = roleKeys;
public void setRoleNames(String roleNames) {
this.roleNames = roleNames;
}
public String getPositionCodes() {
return positionCodes;
public String getPositionNames() {
return positionNames;
}
public void setPositionCodes(String positionCodes) {
this.positionCodes = positionCodes;
public void setPositionNames(String positionNames) {
this.positionNames = positionNames;
}
public String getRemark() {
@@ -658,23 +780,23 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
@Override
public void invoke(LinkedHashMap<Integer, Object> data, AnalysisContext context) {
sheetRowNo++;
String deptCode = getCellValue(data, IMPORT_HEAD_DEPT_CODE);
String deptName = getCellValue(data, IMPORT_HEAD_DEPT_NAME);
String loginName = getCellValue(data, IMPORT_HEAD_LOGIN_NAME);
String nickname = getCellValue(data, IMPORT_HEAD_NICKNAME);
String mobile = getCellValue(data, IMPORT_HEAD_MOBILE);
String email = getCellValue(data, IMPORT_HEAD_EMAIL);
String status = getCellValue(data, IMPORT_HEAD_STATUS);
String roleKeys = getCellValue(data, IMPORT_HEAD_ROLE_KEYS);
String positionCodes = getCellValue(data, IMPORT_HEAD_POSITION_CODES);
String roleNames = getCellValue(data, IMPORT_HEAD_ROLE_NAMES);
String positionNames = getCellValue(data, IMPORT_HEAD_POSITION_NAMES);
String remark = getCellValue(data, IMPORT_HEAD_REMARK);
if (!StringUtil.hasText(deptCode)
if (!StringUtil.hasText(deptName)
&& !StringUtil.hasText(loginName)
&& !StringUtil.hasText(nickname)
&& !StringUtil.hasText(mobile)
&& !StringUtil.hasText(email)
&& !StringUtil.hasText(status)
&& !StringUtil.hasText(roleKeys)
&& !StringUtil.hasText(positionCodes)
&& !StringUtil.hasText(roleNames)
&& !StringUtil.hasText(positionNames)
&& !StringUtil.hasText(remark)) {
return;
}
@@ -683,14 +805,14 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
}
SysAccountImportRow row = new SysAccountImportRow();
row.setRowNumber(sheetRowNo + 1);
row.setDeptCode(deptCode);
row.setDeptName(deptName);
row.setLoginName(loginName);
row.setNickname(nickname);
row.setMobile(mobile);
row.setEmail(email);
row.setStatus(status);
row.setRoleKeys(roleKeys);
row.setPositionCodes(positionCodes);
row.setRoleNames(roleNames);
row.setPositionNames(positionNames);
row.setRemark(remark);
rows.add(row);
}
@@ -705,15 +827,9 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
}
}
List<String> requiredHeads = List.of(
IMPORT_HEAD_DEPT_CODE,
IMPORT_HEAD_DEPT_NAME,
IMPORT_HEAD_LOGIN_NAME,
IMPORT_HEAD_NICKNAME,
IMPORT_HEAD_MOBILE,
IMPORT_HEAD_EMAIL,
IMPORT_HEAD_STATUS,
IMPORT_HEAD_ROLE_KEYS,
IMPORT_HEAD_POSITION_CODES,
IMPORT_HEAD_REMARK
IMPORT_HEAD_NICKNAME
);
for (String requiredHead : requiredHeads) {
if (!headIndex.containsKey(requiredHead)) {
@@ -740,4 +856,35 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
return value == null ? null : String.valueOf(value).trim();
}
}
private static class ImportNameLookup<T> {
private final Map<String, T> uniqueMap;
private final Set<String> duplicateNames;
private ImportNameLookup(Map<String, T> uniqueMap, Set<String> duplicateNames) {
this.uniqueMap = uniqueMap;
this.duplicateNames = duplicateNames;
}
public Map<String, T> getUniqueMap() {
return uniqueMap;
}
public Set<String> getDuplicateNames() {
return duplicateNames;
}
}
private static class ImportRowValidationException extends RuntimeException {
private final List<SysAccountImportErrorDetailVo> details;
private ImportRowValidationException(List<SysAccountImportErrorDetailVo> details) {
super("导入数据校验失败");
this.details = details;
}
public List<SysAccountImportErrorDetailVo> getDetails() {
return details;
}
}
}