| | |
| | | import java.util.Collections; |
| | | import java.util.HashMap; |
| | | import java.util.HashSet; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | |
| | | .eq(SysDept::getStatus, 1) |
| | | .orderByAsc(SysDept::getSortOrder) |
| | | .orderByAsc(SysDept::getId)); |
| | | List<String> deptNames = |
| | | Map<Long, String> deptPathById = buildDeptPathById(depts); |
| | | List<String> deptPaths = |
| | | depts.stream() |
| | | .map(SysDept::getDeptName) |
| | | .map(SysDept::getId) |
| | | .map(deptPathById::get) |
| | | .filter(StringUtils::hasText) |
| | | .map(String::trim) |
| | | .distinct() |
| | | .toList(); |
| | | List<String> groupNames = loadActiveGroupNames(); |
| | | |
| | |
| | | ex.setRealName("张三"); |
| | | ex.setStaffNo("EMP001"); |
| | | ex.setMobile("13800138000"); |
| | | if (!deptNames.isEmpty()) { |
| | | ex.setDept(deptNames.get(0)); |
| | | if (!deptPaths.isEmpty()) { |
| | | ex.setDept(deptPaths.get(0)); |
| | | } |
| | | ex.setPosition("员工"); |
| | | if (!groupNames.isEmpty()) { |
| | |
| | | EasyExcel.writerSheet("员工导入") |
| | | .head(StaffImportExcelRow.class) |
| | | .registerWriteHandler( |
| | | new StaffTemplateDropdownHandler(deptNames, groupNames)) |
| | | new StaffTemplateDropdownHandler(deptPaths, groupNames)) |
| | | .build(); |
| | | writer.write(demo, dataSheet); |
| | | |
| | | var dictSheet = EasyExcel.writerSheet("字典").needHead(false).build(); |
| | | writer.write(buildDictRows(deptNames, groupNames), dictSheet); |
| | | writer.write(buildDictRows(deptPaths, groupNames), dictSheet); |
| | | } finally { |
| | | writer.finish(); |
| | | } |
| | |
| | | vo.getErrors().add("文件为空"); |
| | | return vo; |
| | | } |
| | | Map<String, Long> deptNameToId = new HashMap<>(); |
| | | Map<String, Long> deptPathToId = new HashMap<>(); |
| | | Map<String, List<Long>> deptNameToIds = new HashMap<>(); |
| | | List<SysDept> depts = |
| | | sysDeptMapper.selectList( |
| | | new LambdaQueryWrapper<SysDept>() |
| | | .eq(SysDept::getDelFlag, 0) |
| | | .eq(SysDept::getStatus, 1)); |
| | | Map<Long, String> deptPathById = buildDeptPathById(depts); |
| | | for (SysDept d : depts) { |
| | | String path = deptPathById.get(d.getId()); |
| | | if (StringUtils.hasText(path)) { |
| | | deptPathToId.put(path.trim(), d.getId()); |
| | | } |
| | | if (StringUtils.hasText(d.getDeptName())) { |
| | | deptNameToId.put(d.getDeptName().trim(), d.getId()); |
| | | String deptName = d.getDeptName().trim(); |
| | | deptNameToIds.computeIfAbsent(deptName, k -> new ArrayList<>()).add(d.getId()); |
| | | } |
| | | } |
| | | |
| | |
| | | public void invoke(StaffImportExcelRow row, AnalysisContext context) { |
| | | rowIndex++; |
| | | try { |
| | | handleImportRow(rowIndex, row, deptNameToId); |
| | | handleImportRow(rowIndex, row, deptPathToId, deptNameToIds); |
| | | vo.setSuccess(vo.getSuccess() + 1); |
| | | } catch (StopRowException ignored) { |
| | | } catch (BizException e) { |
| | |
| | | return vo; |
| | | } |
| | | |
| | | private void handleImportRow(int lineNo, StaffImportExcelRow row, Map<String, Long> deptNameToId) { |
| | | private void handleImportRow( |
| | | int lineNo, |
| | | StaffImportExcelRow row, |
| | | Map<String, Long> deptPathToId, |
| | | Map<String, List<Long>> deptNameToIds) { |
| | | String name = row.getRealName() == null ? "" : row.getRealName().trim(); |
| | | String staffNo = row.getStaffNo() == null ? "" : row.getStaffNo().trim(); |
| | | String mobile = row.getMobile() == null ? "" : row.getMobile().trim(); |
| | |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "员工姓名、联系方式、所属部门不能为空"); |
| | | } |
| | | |
| | | Long deptId = parseDeptId(dept, deptNameToId); |
| | | Long deptId = parseDeptId(dept, deptPathToId, deptNameToIds); |
| | | boolean leader = parseDeptLeader(position); |
| | | |
| | | StaffCreateRequest req = new StaffCreateRequest(); |
| | |
| | | |
| | | private static final class StopRowException extends RuntimeException {} |
| | | |
| | | private static List<List<String>> buildDictRows(List<String> deptNames, List<String> groupNames) { |
| | | int max = Math.max(Math.max(deptNames.size(), groupNames.size()), 2); |
| | | private static List<List<String>> buildDictRows(List<String> deptPaths, List<String> groupNames) { |
| | | int max = Math.max(Math.max(deptPaths.size(), groupNames.size()), 2); |
| | | List<List<String>> rows = new ArrayList<>(); |
| | | for (int i = 0; i < max; i++) { |
| | | String dept = i < deptNames.size() ? deptNames.get(i) : ""; |
| | | String dept = i < deptPaths.size() ? deptPaths.get(i) : ""; |
| | | String pos = i == 0 ? "部门负责人" : (i == 1 ? "员工" : ""); |
| | | String grp = i < groupNames.size() ? groupNames.get(i) : ""; |
| | | rows.add(java.util.Arrays.asList(dept, pos, grp)); |
| | |
| | | } |
| | | |
| | | private static final class StaffTemplateDropdownHandler implements SheetWriteHandler { |
| | | private final List<String> deptNames; |
| | | private final List<String> deptPaths; |
| | | private final List<String> groupNames; |
| | | |
| | | private StaffTemplateDropdownHandler(List<String> deptNames, List<String> groupNames) { |
| | | this.deptNames = deptNames != null ? deptNames : List.of(); |
| | | private StaffTemplateDropdownHandler(List<String> deptPaths, List<String> groupNames) { |
| | | this.deptPaths = deptPaths != null ? deptPaths : List.of(); |
| | | this.groupNames = groupNames != null ? groupNames : List.of(); |
| | | } |
| | | |
| | |
| | | Sheet sheet = writeSheetHolder.getSheet(); |
| | | Workbook wb = writeWorkbookHolder.getWorkbook(); |
| | | |
| | | if (!deptNames.isEmpty()) { |
| | | if (!deptPaths.isEmpty()) { |
| | | Name deptRange = wb.createName(); |
| | | deptRange.setNameName("dept_list"); |
| | | deptRange.setRefersToFormula("字典!$A$1:$A$" + deptNames.size()); |
| | | deptRange.setRefersToFormula("字典!$A$1:$A$" + deptPaths.size()); |
| | | } |
| | | Name posRange = wb.createName(); |
| | | posRange.setNameName("pos_list"); |
| | |
| | | int startRow = 1; |
| | | int endRow = 500; |
| | | |
| | | if (!deptNames.isEmpty()) { |
| | | if (!deptPaths.isEmpty()) { |
| | | DataValidationConstraint deptConstraint = helper.createFormulaListConstraint("dept_list"); |
| | | CellRangeAddressList deptAddr = new CellRangeAddressList(startRow, endRow, 3, 3); |
| | | DataValidation dvDept = helper.createValidation(deptConstraint, deptAddr); |
| | |
| | | } |
| | | } |
| | | |
| | | private static Long parseDeptId(String dept, Map<String, Long> deptNameToId) { |
| | | private static Long parseDeptId( |
| | | String dept, Map<String, Long> deptPathToId, Map<String, List<Long>> deptNameToIds) { |
| | | if (!StringUtils.hasText(dept)) { |
| | | return null; |
| | | } |
| | |
| | | return Long.parseLong(t); |
| | | } catch (Exception ignored) { |
| | | } |
| | | Long id = deptNameToId.get(t); |
| | | if (id == null) { |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "所属部门不存在: " + t); |
| | | Long pathMatchedId = deptPathToId.get(t); |
| | | if (pathMatchedId != null) { |
| | | return pathMatchedId; |
| | | } |
| | | return id; |
| | | List<Long> nameMatchedIds = deptNameToIds.getOrDefault(t, List.of()); |
| | | if (nameMatchedIds.size() == 1) { |
| | | return nameMatchedIds.get(0); |
| | | } |
| | | if (nameMatchedIds.size() > 1) { |
| | | throw new BizException( |
| | | BizErrorCode.AUTH_INVALID_CREDENTIALS, |
| | | "所属部门名称重复,请使用全路径(示例:A公司/财务部): " + t); |
| | | } |
| | | throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "所属部门不存在: " + t); |
| | | } |
| | | |
| | | private static Map<Long, String> buildDeptPathById(List<SysDept> depts) { |
| | | if (depts == null || depts.isEmpty()) { |
| | | return Map.of(); |
| | | } |
| | | Map<Long, SysDept> byId = new LinkedHashMap<>(); |
| | | for (SysDept dept : depts) { |
| | | byId.put(dept.getId(), dept); |
| | | } |
| | | Map<Long, String> cache = new HashMap<>(); |
| | | for (SysDept dept : depts) { |
| | | resolveDeptPath(dept.getId(), byId, cache, new HashSet<>()); |
| | | } |
| | | return cache; |
| | | } |
| | | |
| | | private static String resolveDeptPath( |
| | | Long deptId, |
| | | Map<Long, SysDept> byId, |
| | | Map<Long, String> cache, |
| | | Set<Long> visiting) { |
| | | if (deptId == null || deptId <= 0) { |
| | | return ""; |
| | | } |
| | | String cached = cache.get(deptId); |
| | | if (cached != null) { |
| | | return cached; |
| | | } |
| | | SysDept current = byId.get(deptId); |
| | | if (current == null) { |
| | | return ""; |
| | | } |
| | | String self = StringUtils.hasText(current.getDeptName()) ? current.getDeptName().trim() : ""; |
| | | Long parentId = current.getParentId(); |
| | | if (parentId == null || parentId <= 0 || parentId.equals(deptId) || !visiting.add(deptId)) { |
| | | cache.put(deptId, self); |
| | | return self; |
| | | } |
| | | String parentPath = resolveDeptPath(parentId, byId, cache, visiting); |
| | | visiting.remove(deptId); |
| | | String path = StringUtils.hasText(parentPath) ? (parentPath + "/" + self) : self; |
| | | cache.put(deptId, path); |
| | | return path; |
| | | } |
| | | |
| | | private static boolean parseDeptLeader(String position) { |