From c71714508fbe3ace3543423c7700d7bbcca90056 Mon Sep 17 00:00:00 2001 From: cuilei <ray_tsu1@163.com> Date: 星期二, 12 八月 2025 13:41:37 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- src/main/java/org/jeecg/modules/mes/job/FeishuUserService.java | 327 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 327 insertions(+), 0 deletions(-) diff --git a/src/main/java/org/jeecg/modules/mes/job/FeishuUserService.java b/src/main/java/org/jeecg/modules/mes/job/FeishuUserService.java new file mode 100644 index 0000000..b5b3991 --- /dev/null +++ b/src/main/java/org/jeecg/modules/mes/job/FeishuUserService.java @@ -0,0 +1,327 @@ +package org.jeecg.modules.mes.job; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.util.PasswordUtil; +import org.jeecg.common.util.RestUtil; +import org.jeecg.common.util.oConvertUtils; +import org.jeecg.modules.mes.entity.FeishuUser; +import org.jeecg.modules.system.entity.SysUser; +import org.jeecg.modules.system.service.ISysUserService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +@Slf4j +public class FeishuUserService { + + @Resource + private ISysUserService sysUserService; + + @Resource + private RestTemplate restTemplate; // 鏂板RestTemplate渚濊禆娉ㄥ叆 + + @Value("${feishu.appId:}") + private String appId; + + @Value("${feishu.appSecret:}") + private String appSecret; + + @Value("${feishu.url:}") + private String feishuUrl; + + /** + * 鍚屾椋炰功閮ㄩ棬鐢ㄦ埛鍒扮郴缁熺敤鎴疯〃 + * @param departmentId 椋炰功閮ㄩ棬ID + */ + public void syncFeishuDepartmentUsers(String departmentId) { + try { + log.info("寮�濮嬪悓姝ラ涔﹂儴闂ㄧ敤鎴凤紝閮ㄩ棬ID: {}", departmentId); + + // 1. 鑾峰彇椋炰功璁块棶浠ょ墝 + String accessToken = getFeishuAccessToken(); + if (oConvertUtils.isEmpty(accessToken)) { + log.error("鑾峰彇椋炰功璁块棶浠ょ墝澶辫触锛岀粓姝㈠悓姝ユ祦绋�"); + return; // 浠ょ墝鑾峰彇澶辫触鐩存帴杩斿洖锛岄伩鍏嶅悗缁棤鏁堟搷浣� + } + + // 2. 鑾峰彇閮ㄩ棬涓嬬殑鐢ㄦ埛鍒楄〃 + List<FeishuUser> feishuUsers = getDepartmentUsers(accessToken, departmentId); + log.info("鑾峰彇鍒伴涔﹂儴闂ㄧ敤鎴锋暟閲�: {}", feishuUsers.size()); + + // 3. 鍚屾鍒扮郴缁熺敤鎴疯〃 + int successCount = 0; + int updateCount = 0; + int addCount = 0; + + for (FeishuUser feishuUser : feishuUsers) { + try { + boolean isUpdated = syncFeishuUserToSystem(feishuUser); + successCount++; + if (isUpdated) { + updateCount++; + } else { + addCount++; + } + } catch (Exception e) { + log.error("鍚屾椋炰功鐢ㄦ埛澶辫触锛岀敤鎴稩D: {}", feishuUser.getUserId(), e); + } + } + + log.info("椋炰功鐢ㄦ埛鍚屾瀹屾垚锛屾�诲鐞�: {}锛屾柊澧�: {}锛屾洿鏂�: {}", successCount, addCount, updateCount); + } catch (Exception e) { + log.error("鍚屾椋炰功閮ㄩ棬鐢ㄦ埛澶辫触锛岄儴闂↖D: {}", departmentId, e); + throw new RuntimeException("鍚屾椋炰功鐢ㄦ埛澶辫触: " + e.getMessage()); + } + } + + private String getFeishuAccessToken() { + try { + String url = feishuUrl + "open-apis/auth/v3/tenant_access_token/internal"; + + log.info("寮�濮嬭幏鍙栭涔﹁闂护鐗岋紝AppId: {}", + appId != null ? appId.substring(0, Math.min(appId.length(), 10)) + "..." : "null"); + + JSONObject params = new JSONObject(); + params.put("app_id", appId); + params.put("app_secret", appSecret); + + log.debug("鑾峰彇浠ょ墝璇锋眰鍙傛暟: {}", params.toJSONString()); + + JSONObject result = RestUtil.post(url, params); + + log.info("鑾峰彇椋炰功璁块棶浠ょ墝鍝嶅簲: {}", result != null ? result.toJSONString() : "null"); + + if (result != null && result.getInteger("code") == 0) { + String accessToken = result.getString("tenant_access_token"); + log.info("鎴愬姛鑾峰彇椋炰功璁块棶浠ょ墝锛屼护鐗岄暱搴�: {}", accessToken != null ? accessToken.length() : 0); + return accessToken; + } else { + log.error("鑾峰彇椋炰功璁块棶浠ょ墝澶辫触锛屽搷搴�: {}", result != null ? result.toJSONString() : "null"); + if (result != null) { + log.error("閿欒鐮�: {}, 閿欒淇℃伅: {}", result.getInteger("code"), result.getString("msg")); + } + return null; + } + } catch (Exception e) { + log.error("鑾峰彇椋炰功璁块棶浠ょ墝寮傚父", e); + return null; + } + } + + /** + * 鑾峰彇閮ㄩ棬鐢ㄦ埛鍒楄〃锛堢洿灞炲憳宸ワ級 + */ + private List<FeishuUser> getDepartmentUsers(String accessToken, String departmentId) { + List<FeishuUser> userList = new ArrayList<>(); + try { + log.info("寮�濮嬭幏鍙栭涔﹂儴闂ㄧ敤鎴峰垪琛紝閮ㄩ棬ID: {}", departmentId); + + // 楠岃瘉璁块棶浠ょ墝 + if (accessToken == null || accessToken.isEmpty()) { + log.error("璁块棶浠ょ墝涓虹┖锛屾棤娉曠户缁墽琛�"); + return userList; + } + log.info("浣跨敤鐨勮闂护鐗屽墠缂�: Bearer {}", accessToken.substring(0, Math.min(20, accessToken.length())) + "..."); + + // 椋炰功API绔偣 + String url = feishuUrl + "open-apis/contact/v3/users/find_by_department"; + + String pageToken = null; + int pageNumber = 1; + + do { + // 鏋勫缓璇锋眰URL鍜屽弬鏁� + StringBuilder urlBuilder = new StringBuilder(url); + urlBuilder.append("?department_id=").append(departmentId); + urlBuilder.append("&department_id_type=open_department_id"); + urlBuilder.append("&page_size=50"); + urlBuilder.append("&user_id_type=open_id"); + + if (pageToken != null && !pageToken.isEmpty()) { + urlBuilder.append("&page_token=").append(pageToken); + } + + log.info("璇锋眰绗瑊}椤垫暟鎹紝URL: {}", pageNumber, urlBuilder.toString()); + + // 璁剧疆璇锋眰澶� - 鍏抽敭淇鐐癸細浣跨敤HttpHeaders纭繚澶翠俊鎭纭缃� + HttpHeaders headers = new HttpHeaders(); + String authHeader = "Bearer " + accessToken; + headers.add("Authorization", authHeader); + headers.add("Content-Type", "application/json; charset=utf-8"); + log.info("璁剧疆璇锋眰澶�: Authorization = {}", authHeader.substring(0, Math.min(30, authHeader.length())) + "..."); + + // 浣跨敤RestTemplate鍙戦�佽姹傦紝纭繚澶翠俊鎭姝g‘浼犻�� + HttpEntity<String> requestEntity = new HttpEntity<>(headers); + ResponseEntity<String> response = restTemplate.exchange( + urlBuilder.toString(), + HttpMethod.GET, + requestEntity, + String.class + ); + + // 瑙f瀽鍝嶅簲 + JSONObject result = JSONObject.parseObject(response.getBody()); + log.debug("绗瑊}椤礎PI鍝嶅簲: {}", pageNumber, result != null ? result.toJSONString() : "null"); + + if (result != null && result.getInteger("code") == 0) { + JSONObject data = result.getJSONObject("data"); + if (data != null) { + // 瑙f瀽鐢ㄦ埛鍒楄〃 + Object items = data.get("items"); + log.info("绗瑊}椤靛師濮嬬敤鎴锋暟鎹暟閲�: {}", pageNumber, items instanceof List ? ((List<?>) items).size() : 0); + + if (items != null) { + List<FeishuUser> pageUsers = parseUsers(items); + userList.addAll(pageUsers); + log.info("绗瑊}椤佃В鏋愬悗鐢ㄦ埛鏁伴噺: {}", pageNumber, pageUsers.size()); + } + + // 妫�鏌ユ槸鍚︽湁涓嬩竴椤� + pageToken = data.getString("page_token"); + boolean hasMore = data.getBooleanValue("has_more"); + log.info("绗瑊}椤礹as_more: {}, page_token: {}", pageNumber, hasMore, pageToken); + pageNumber++; + } else { + log.warn("绗瑊}椤礵ata涓虹┖", pageNumber); + break; + } + } else { + log.error("鑾峰彇椋炰功閮ㄩ棬鐢ㄦ埛鍒楄〃澶辫触锛屽搷搴�: {}", result != null ? result.toJSONString() : "null"); + if (result != null) { + log.error("閿欒鐮�: {}, 閿欒淇℃伅: {}", result.getInteger("code"), result.getString("msg")); + } + break; + } + } while (pageToken != null && !pageToken.isEmpty()); + + log.info("鑾峰彇椋炰功閮ㄩ棬鐢ㄦ埛瀹屾垚锛屾�荤敤鎴锋暟閲�: {}", userList.size()); + + } catch (Exception e) { + log.error("鑾峰彇椋炰功閮ㄩ棬鐢ㄦ埛鍒楄〃寮傚父", e); + } + return userList; + } + + /** + * 瑙f瀽鐢ㄦ埛鏁版嵁 + */ + /** + * 瑙f瀽鐢ㄦ埛鏁版嵁 + */ + @SuppressWarnings("unchecked") + private List<FeishuUser> parseUsers(Object items) { + Logger log = LoggerFactory.getLogger(FeishuUserService.class); + List<FeishuUser> userList = new ArrayList<>(); + if (!(items instanceof List)) { + log.warn("瑙f瀽鐢ㄦ埛鏁版嵁澶辫触锛宨tems涓嶆槸鍒楄〃绫诲瀷: {}", items); + return userList; + } + List<?> userItems = (List<?>) items; + log.info("寮�濮嬭В鏋愰涔︾敤鎴峰垪琛紝鍏眥}鏉¤褰�", userItems.size()); + for (Object item : userItems) { + if (item == null || !(item instanceof Map)) { + log.warn("璺宠繃鏃犳晥鐢ㄦ埛鏁版嵁椤癸紝绫诲瀷涓嶅尮閰�: {}", item != null ? item.getClass() : "null"); + continue; + } + Map<String, Object> userMap = (Map<String, Object>) item; + FeishuUser user = new FeishuUser(); + // 瑙f瀽open_id + user.setOpenId((String) userMap.getOrDefault("open_id", "")); + // 瑙f瀽name骞舵媶鍒� + String name = (String) userMap.getOrDefault("name", ""); + if (name.contains(" ")) { + String[] parts = name.split(" "); + if (parts.length == 2) { + user.setUsername(parts[0].trim()); // 宸ュ彿閮ㄥ垎瀛樺埌username + user.setRealname(parts[1].trim()); // 濮撳悕閮ㄥ垎瀛樺埌realname + user.setWorkNo(parts[0].trim()); // 宸ュ彿涔熷瓨鍒皐orkNo + } else { + // 鎷嗗垎寮傚父鏃讹紝榛樿澶勭悊 + user.setUsername(name); + user.setRealname(name); + user.setWorkNo(""); + log.warn("椋炰功鐢ㄦ埛name瀛楁鏍煎紡寮傚父锛屾棤娉曟媶鍒嗭紝鍘熷鍊硷細{}", name); + } + } else { + user.setUsername(name); + user.setRealname(name); + user.setWorkNo(""); + log.warn("椋炰功鐢ㄦ埛name瀛楁鏃犵┖鏍煎垎闅旓紝鏃犳硶鎷嗗垎锛屽師濮嬪�硷細{}", name); + } + // 瑙f瀽鍏朵粬鍩烘湰淇℃伅 + user.setEnName((String) userMap.getOrDefault("en_name", "")); + user.setDescription((String) userMap.getOrDefault("description", "")); + Object mobileVisibleObj = userMap.get("mobile_visible"); + user.setMobileVisible(mobileVisibleObj instanceof Boolean ? (Boolean) mobileVisibleObj : false); + // 瑙f瀽澶村儚淇℃伅 + Object avatarObj = userMap.get("avatar"); + if (avatarObj instanceof Map) { + Map<String, Object> avatarMap = (Map<String, Object>) avatarObj; + user.setAvatar240((String) avatarMap.getOrDefault("avatar_240", "")); + user.setAvatar640((String) avatarMap.getOrDefault("avatar_640", "")); + user.setAvatar72((String) avatarMap.getOrDefault("avatar_72", "")); + user.setAvatarOrigin((String) avatarMap.getOrDefault("avatar_origin", "")); + } else { + log.info("鐢ㄦ埛[{}]鏈缃ご鍍忔垨澶村儚鏍煎紡寮傚父", user.getRealname()); + } + // 璁剧疆榛樿鍔犲瘑瀵嗙爜锛堣繖閲屽亣璁惧瘑鐮佹槸绠�鍗曞姞瀵嗗瓨鍌紝瀹為檯寤鸿鐢ㄦ洿瀹夊叏鐨勫姞瀵嗘柟寮忥級 + user.setPassword("123456"); // 浣犺姹傜殑榛樿瀵嗙爜 + // 灏唎pen_id瀛樺埌瀵瑰簲鐨勫瓧娈碉紙鏍规嵁浣犵殑鐢ㄦ埛琛ㄧ粨鏋勶紝鍋囪鐢ㄦ埛琛ㄦ湁open_id瀛楁锛� + user.setOpenId((String) userMap.getOrDefault("open_id", "")); + userList.add(user); + } + + return userList; + } + + /** + * 鍚屾鍗曚釜椋炰功鐢ㄦ埛鍒扮郴缁� + * @param feishuUser 椋炰功鐢ㄦ埛 + * @return true琛ㄧず鏇存柊锛宖alse琛ㄧず鏂板 + * + * 鍚庢湡澧炲姞锛� 鐢ㄦ埛鍚屾瀵规瘮锛岄涔︾鑱屽憳宸ラ渶瑕佸湪鏈湴鐢ㄦ埛琛ㄩ噷闈㈠皢璇ョ敤鎴风姸鎬佺鐢� + */ + private boolean syncFeishuUserToSystem(FeishuUser feishuUser) { + // 杩欓噷鏍规嵁鎷嗗垎鍚庣殑username锛堝伐鍙凤級鍘绘煡璇㈢郴缁熺敤鎴� + String username = feishuUser.getUsername(); + SysUser existUser = sysUserService.getUserByName(username); + SysUser sysUser = new SysUser(); + sysUser.setUsername(username); + sysUser.setStatus(1); + sysUser.setDelFlag(0); + sysUser.setAvatar(feishuUser.getAvatar640()); + sysUser.setRealname(feishuUser.getRealname()); + sysUser.setWorkNo(feishuUser.getWorkNo()); + String password = "123456", salt = oConvertUtils.randomGen(8); + String passwordEncode = PasswordUtil.encrypt(sysUser.getUsername(), password, salt); + sysUser.setSalt(salt); + sysUser.setPassword(passwordEncode); + sysUser.setOpenId(feishuUser.getOpenId()); + + if (existUser == null) { + + sysUserService.addUserWithRole(sysUser, "5"); + log.info("鏂板鐢ㄦ埛: {}", username); + return false; + } else { + sysUser.setId(existUser.getId()); + sysUserService.editUser(sysUser); + log.info("鏇存柊鐢ㄦ埛: {}", username); + return true; + } + } +} -- Gitblit v1.9.3