diff --git a/backend/src/main/java/com/designhub/controller/DingTalkController.java b/backend/src/main/java/com/designhub/controller/DingTalkController.java index d18c461..1c468e5 100644 --- a/backend/src/main/java/com/designhub/controller/DingTalkController.java +++ b/backend/src/main/java/com/designhub/controller/DingTalkController.java @@ -152,6 +152,17 @@ public class DingTalkController { return Result.success(dingTalkService.getDepartmentList()); } + @Operation(summary = "同步钉钉部门") + @PostMapping("/sync-departments") + public Result syncDepartments() { + try { + return Result.success(dingTalkService.syncDepartments()); + } catch (Exception e) { + log.error("同步钉钉部门失败", e); + return Result.error("同步钉钉部门失败: " + e.getMessage()); + } + } + @Operation(summary = "同步钉钉用户") @PostMapping("/sync-users") public Result syncUsers() { diff --git a/backend/src/main/java/com/designhub/service/DingTalkService.java b/backend/src/main/java/com/designhub/service/DingTalkService.java index a254f79..873450e 100644 --- a/backend/src/main/java/com/designhub/service/DingTalkService.java +++ b/backend/src/main/java/com/designhub/service/DingTalkService.java @@ -2,8 +2,10 @@ package com.designhub.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.designhub.common.ResultCode; +import com.designhub.entity.Department; import com.designhub.entity.DingTalkConfig; import com.designhub.exception.BusinessException; +import com.designhub.mapper.DepartmentMapper; import com.designhub.mapper.DingTalkConfigMapper; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -32,6 +34,7 @@ public class DingTalkService { private final DingTalkConfigMapper configMapper; private final ObjectMapper objectMapper; private final RestTemplate restTemplate = new RestTemplate(); + private final DepartmentMapper departmentMapper; private static final String DINGTALK_API_BASE = "https://oapi.dingtalk.com"; @@ -441,17 +444,24 @@ public class DingTalkService { Map result = (Map) body.get("result"); // 获取部门信息 - List deptIdList = (List) result.get("dept_id_list"); - if (deptIdList != null && !deptIdList.isEmpty()) { + Object deptIdListObj = result.get("dept_id_list"); + if (deptIdListObj != null) { List> departments = new ArrayList<>(); - for (Long deptId : deptIdList) { - Map deptInfo = getDepartmentInfo(deptId.toString()); - if (deptInfo != null) { - departments.add(deptInfo); + List deptIdList = (List) deptIdListObj; + if (!deptIdList.isEmpty()) { + for (Object deptIdObj : deptIdList) { + // 处理Integer或Long类型 + String deptIdStr = deptIdObj != null ? deptIdObj.toString() : null; + if (deptIdStr != null) { + Map deptInfo = getDepartmentInfo(deptIdStr); + if (deptInfo != null) { + departments.add(deptInfo); + } + } } + result.put("departments", departments); + log.info("获取到用户部门信息: userId={}, departments={}", userId, departments.size()); } - result.put("departments", departments); - log.info("获取到用户部门信息: userId={}, departments={}", userId, departments.size()); } return result; @@ -503,6 +513,127 @@ public class DingTalkService { } } + /** + * 同步钉钉部门到系统数据库 + * 递归获取所有部门,保存或更新到数据库,并设置ding_dept_id + */ + @Transactional(rollbackFor = Exception.class) + public int syncDepartments() { + DingTalkConfig config = getConfig(); + if (config == null) { + throw new BusinessException(ResultCode.PARAM_ERROR, "钉钉未配置"); + } + + log.info("开始同步钉钉部门..."); + int syncCount = 0; + + try { + String accessToken = getAccessToken(config); + if (accessToken == null) { + throw new BusinessException(ResultCode.PARAM_ERROR, "获取钉钉访问令牌失败"); + } + + // 递归获取所有部门(从根部门开始) + List> allDepartments = getAllDepartmentsRecursive(accessToken, 1L); + + log.info("从钉钉获取到 {} 个部门", allDepartments.size()); + + // 同步每个部门到数据库 + for (Map dingDept : allDepartments) { + Object deptIdObj = dingDept.get("dept_id"); + String dingDeptId = deptIdObj != null ? deptIdObj.toString() : null; + String deptName = (String) dingDept.get("name"); + Object parentIdObj = dingDept.get("parent_id"); + String parentDingDeptId = parentIdObj != null ? parentIdObj.toString() : null; + + if (dingDeptId == null || deptName == null) { + log.warn("跳过无效的部门信息: {}", dingDept); + continue; + } + + // 查找系统部门(通过ding_dept_id或名称) + com.designhub.entity.Department sysDept = departmentMapper.selectOne( + new LambdaQueryWrapper() + .eq(com.designhub.entity.Department::getDingDeptId, dingDeptId) + .eq(com.designhub.entity.Department::getDeleted, 0) + .last("LIMIT 1") + ); + + if (sysDept == null) { + // 通过名称查找 + sysDept = departmentMapper.selectOne( + new LambdaQueryWrapper() + .eq(com.designhub.entity.Department::getDeptName, deptName) + .eq(com.designhub.entity.Department::getDeleted, 0) + .last("LIMIT 1") + ); + } + + if (sysDept != null) { + // 更新现有部门:设置ding_dept_id + sysDept.setDingDeptId(dingDeptId); + departmentMapper.updateById(sysDept); + log.info("更新部门: id={}, name={}, ding_dept_id={}", sysDept.getId(), deptName, dingDeptId); + } else { + // 部门不存在,可以选择创建或跳过 + // 这里选择跳过,因为部门应该先在系统中创建 + log.warn("系统部门不存在,跳过同步: name={}, ding_dept_id={}", deptName, dingDeptId); + } + syncCount++; + } + + log.info("同步钉钉部门完成,共处理 {} 个部门", syncCount); + return syncCount; + } catch (Exception e) { + log.error("同步钉钉部门失败", e); + throw new BusinessException(ResultCode.DINGTALK_API_ERROR, "同步钉钉部门失败: " + e.getMessage()); + } + } + + /** + * 递归获取所有部门 + */ + private List> getAllDepartmentsRecursive(String accessToken, Long parentDeptId) { + List> allDepartments = new ArrayList<>(); + + try { + String url = String.format("%s/topapi/v2/department/listsub?access_token=%s", + DINGTALK_API_BASE, accessToken); + + Map request = new HashMap<>(); + request.put("dept_id", parentDeptId); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + HttpEntity> entity = new HttpEntity<>(request, headers); + + ResponseEntity response = restTemplate.postForEntity(url, entity, Map.class); + Map body = response.getBody(); + + if (body != null) { + Object errcode = body.get("errcode"); + if (errcode != null && (errcode.equals(0) || errcode.equals(0L) || "0".equals(errcode.toString()))) { + List> subDepts = (List>) body.get("result"); + if (subDepts != null) { + for (Map dept : subDepts) { + allDepartments.add(dept); + // 递归获取子部门 + Object deptIdObj = dept.get("dept_id"); + if (deptIdObj != null) { + Long deptId = deptIdObj instanceof Long ? (Long) deptIdObj : Long.parseLong(deptIdObj.toString()); + allDepartments.addAll(getAllDepartmentsRecursive(accessToken, deptId)); + } + } + } + } + } + } catch (Exception e) { + log.error("获取部门列表失败: parentDeptId={}", parentDeptId, e); + } + + return allDepartments; + } + /** * 同步钉钉用户 */