| | |
| | | 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; |
| | |
| | | Path dir = resolveAvatarUploadDir(); |
| | | String fileName = UUID.randomUUID().toString().replace("-", "") + ext; |
| | | Path target = dir.resolve(fileName); |
| | | try { |
| | | try (InputStream in = file.getInputStream()) { |
| | | Files.createDirectories(dir); |
| | | Files.copy(file.getInputStream(), target, StandardCopyOption.REPLACE_EXISTING); |
| | | Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING); |
| | | } catch (IOException ex) { |
| | | throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "头像上传失败"); |
| | | } |
| | |
| | | q.like(StringUtils.hasText(staffNo), MpUser::getStaffNo, staffNo != null ? staffNo.trim() : null); |
| | | q.like(StringUtils.hasText(mobile), MpUser::getMobile, mobile != null ? mobile.trim() : null); |
| | | if ("LEADER".equalsIgnoreCase(position)) { |
| | | q.eq(MpUser::getDeptLeaderFlag, true); |
| | | q.apply("1 = 0"); |
| | | } else if ("STAFF".equalsIgnoreCase(position)) { |
| | | q.and( |
| | | w -> |
| | |
| | | q.notIn(MpUser::getId, inGroup); |
| | | } |
| | | } |
| | | q.orderByDesc(MpUser::getCreateTime); |
| | | q.orderByAsc(MpUser::getNickName).orderByAsc(MpUser::getId); |
| | | Page<MpUser> p = mpUserMapper.selectPage(new Page<>(page, size), q); |
| | | Set<Long> deptIds = new HashSet<>(); |
| | | Set<Long> userIds = new HashSet<>(); |
| | |
| | | } |
| | | userIds.add(u.getId()); |
| | | } |
| | | List<SysDept> allDepts = sysDeptMapper.selectList( |
| | | new LambdaQueryWrapper<SysDept>().eq(SysDept::getDelFlag, 0)); |
| | | Map<Long, String> deptPaths = buildDeptPathById(allDepts); |
| | | Map<Long, String> deptNames = deptNamesByIds(deptIds); |
| | | Map<Long, String> groupDisplay = groupDisplayByMpUserIds(userIds); |
| | | return p.convert(u -> toListVo(u, deptNames, groupDisplay.getOrDefault(u.getId(), "—"))); |
| | | return p.convert(u -> toListVo(u, deptNames, deptPaths, groupDisplay.getOrDefault(u.getId(), "—"))); |
| | | } |
| | | |
| | | private Set<Long> mpUserIdsInStaffGroup(Long staffGroupId) { |
| | |
| | | u.setMobile(mobileRaw); |
| | | u.setAvatarUrl(trimToNull(req.getAvatarUrl())); |
| | | u.setDeptId(req.getDeptId()); |
| | | u.setDeptLeaderFlag(Boolean.TRUE.equals(req.getDeptLeader())); |
| | | u.setDeptLeaderFlag(false); |
| | | u.setStatus(1); |
| | | mpUserMapper.insert(u); |
| | | MpUser fresh = mpUserMapper.selectById(u.getId()); |
| | |
| | | u.setAvatarUrl(trimToNull(req.getAvatarUrl())); |
| | | u.setMobile(mobileRaw); |
| | | u.setDeptId(req.getDeptId()); |
| | | u.setDeptLeaderFlag(Boolean.TRUE.equals(req.getDeptLeader())); |
| | | u.setDeptLeaderFlag(false); |
| | | mpUserMapper.updateById(u); |
| | | } |
| | | |
| | |
| | | .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); |
| | | boolean leader = parseDeptLeader(position); |
| | | Long deptId = parseDeptId(dept, deptPathToId, deptNameToIds); |
| | | parseDeptLeader(position); |
| | | |
| | | StaffCreateRequest req = new StaffCreateRequest(); |
| | | req.setNickName(name); |
| | | req.setStaffNo(StringUtils.hasText(staffNo) ? staffNo : null); |
| | | req.setMobile(mobile); |
| | | req.setDeptId(deptId); |
| | | req.setDeptLeader(leader); |
| | | req.setDeptLeader(false); |
| | | Map<String, Object> created = create(req); |
| | | Object idObj = created.get("id"); |
| | | Long uid = idObj instanceof Number ? ((Number) idObj).longValue() : null; |
| | |
| | | |
| | | 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 pos = i == 0 ? "部门负责人" : (i == 1 ? "员工" : ""); |
| | | String dept = i < deptPaths.size() ? deptPaths.get(i) : ""; |
| | | String pos = i == 0 ? "员工" : ""; |
| | | 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"); |
| | | posRange.setRefersToFormula("字典!$B$1:$B$2"); |
| | | posRange.setRefersToFormula("字典!$B$1:$B$1"); |
| | | if (!groupNames.isEmpty()) { |
| | | Name groupRange = wb.createName(); |
| | | groupRange.setNameName("group_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) { |
| | |
| | | return false; |
| | | } |
| | | String t = position.trim(); |
| | | if ("部门负责人".equals(t) || "LEADER".equalsIgnoreCase(t)) { |
| | | return true; |
| | | } |
| | | if ("员工".equals(t) || "STAFF".equalsIgnoreCase(t)) { |
| | | return false; |
| | | } |
| | |
| | | exist.setAvatarUrl(trimToNull(req.getAvatarUrl())); |
| | | exist.setMobile(mobileRaw); |
| | | exist.setDeptId(req.getDeptId()); |
| | | exist.setDeptLeaderFlag(Boolean.TRUE.equals(req.getDeptLeader())); |
| | | exist.setDeptLeaderFlag(false); |
| | | exist.setStatus(1); |
| | | mpUserMapper.updateById(exist); |
| | | } |
| | |
| | | return m; |
| | | } |
| | | |
| | | private StaffListVo toListVo(MpUser u, Map<Long, String> deptNames, String groupDisplay) { |
| | | private StaffListVo toListVo(MpUser u, Map<Long, String> deptNames, Map<Long, String> deptPaths, String groupDisplay) { |
| | | StaffListVo vo = new StaffListVo(); |
| | | vo.setId(u.getId()); |
| | | vo.setUuid(u.getUuid()); |
| | |
| | | vo.setDeptId(u.getDeptId()); |
| | | vo.setDeptName( |
| | | u.getDeptId() == null ? "—" : deptNames.getOrDefault(u.getDeptId(), "—")); |
| | | vo.setPositionLabel(Boolean.TRUE.equals(u.getDeptLeaderFlag()) ? "部门负责人" : "员工"); |
| | | vo.setDeptPath( |
| | | u.getDeptId() == null ? "—" : deptPaths.getOrDefault(u.getDeptId(), "—")); |
| | | vo.setPositionLabel("员工"); |
| | | vo.setGroupDisplay(groupDisplay); |
| | | vo.setStatus(u.getStatus() == null ? 1 : u.getStatus()); |
| | | vo.setCreateTime(u.getCreateTime()); |
| | |
| | | vo.setAvatarUrl(u.getAvatarUrl()); |
| | | vo.setMobile(u.getMobile()); |
| | | vo.setDeptId(u.getDeptId()); |
| | | vo.setDeptLeader(Boolean.TRUE.equals(u.getDeptLeaderFlag())); |
| | | vo.setDeptLeader(false); |
| | | vo.setStatus(u.getStatus() == null ? 1 : u.getStatus()); |
| | | vo.setGroupNames(loadGroupNamesForUser(u.getId())); |
| | | return vo; |