|
|
@@ -1,357 +0,0 @@
|
|
|
-package com.malk.minglei.service.impl;
|
|
|
-
|
|
|
-import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
-import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
-import com.malk.minglei.config.YidaApplicationsProperties;
|
|
|
-import com.malk.minglei.dto.MingleiDocumentQueryRequest;
|
|
|
-import com.malk.minglei.service.MingleiDocumentService;
|
|
|
-import com.malk.server.aliwork.YDConf;
|
|
|
-import com.malk.server.aliwork.YDParam;
|
|
|
-import com.malk.server.dingtalk.DDR_New;
|
|
|
-import com.malk.server.dingtalk.DDConf;
|
|
|
-import com.malk.service.aliwork.YDClient;
|
|
|
-import com.malk.service.dingtalk.DDClient;
|
|
|
-import com.malk.service.dingtalk.DDClient_Contacts;
|
|
|
-import org.springframework.beans.factory.annotation.Qualifier;
|
|
|
-import org.springframework.stereotype.Service;
|
|
|
-
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.Collections;
|
|
|
-import java.util.LinkedHashSet;
|
|
|
-import java.util.LinkedHashMap;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.Set;
|
|
|
-
|
|
|
-@Service
|
|
|
-public class MingleiDocumentServiceImpl implements MingleiDocumentService {
|
|
|
-
|
|
|
- private static final String MINGLEI_DOCUMENT_FORM_UUID = "FORM-8F527F696C5B4AF7AB7A53979527FBA23USO";
|
|
|
- private static final String DEPARTMENT_ID_FIELD_ID = "textField_msztwhs2";
|
|
|
- private static final String DEPARTMENT_NAME_FIELD_ID = "textField_mszr6tuz";
|
|
|
- private static final String FIRST_LEVEL_DEPARTMENT_MANAGER_FIELD_ID = "employeeField_mszdqrl8";
|
|
|
- private static final String SECOND_LEVEL_DEPARTMENT_MANAGER_FIELD_ID = "employeeField_mszdqrl9";
|
|
|
- private static final String THIRD_LEVEL_DEPARTMENT_MANAGER_FIELD_ID = "employeeField_mszdqrla";
|
|
|
- private static final String FOURTH_LEVEL_DEPARTMENT_MANAGER_FIELD_ID = "employeeField_mszdqrlb";
|
|
|
- private static final String DEPARTMENT_LEADER_FIELD_ID = "employeeField_mszdqrl3";
|
|
|
- private static final String[] DEPARTMENT_MANAGER_FIELD_IDS = {
|
|
|
- FIRST_LEVEL_DEPARTMENT_MANAGER_FIELD_ID,
|
|
|
- SECOND_LEVEL_DEPARTMENT_MANAGER_FIELD_ID,
|
|
|
- THIRD_LEVEL_DEPARTMENT_MANAGER_FIELD_ID,
|
|
|
- FOURTH_LEVEL_DEPARTMENT_MANAGER_FIELD_ID,
|
|
|
- DEPARTMENT_LEADER_FIELD_ID
|
|
|
- };
|
|
|
- private static final int PRECISE_QUERY_PAGE_SIZE = 100;
|
|
|
-
|
|
|
- private final YDClient yidaClient;
|
|
|
- private final DDClient dingTalkClient;
|
|
|
- private final DDClient_Contacts dingTalkContactsClient;
|
|
|
- private final DDConf dingTalkConfiguration;
|
|
|
- private final YidaApplicationsProperties.ApplicationCredentials masterDataConfiguration;
|
|
|
- private final ObjectMapper objectMapper;
|
|
|
-
|
|
|
- public MingleiDocumentServiceImpl(@Qualifier("masterDataYidaClient") YDClient yidaClient,
|
|
|
- DDClient dingTalkClient,
|
|
|
- DDClient_Contacts dingTalkContactsClient,
|
|
|
- DDConf dingTalkConfiguration,
|
|
|
- YidaApplicationsProperties applications,
|
|
|
- ObjectMapper objectMapper) {
|
|
|
- this.yidaClient = yidaClient;
|
|
|
- this.dingTalkClient = dingTalkClient;
|
|
|
- this.dingTalkContactsClient = dingTalkContactsClient;
|
|
|
- this.dingTalkConfiguration = dingTalkConfiguration;
|
|
|
- this.masterDataConfiguration = applications.getMasterData();
|
|
|
- this.objectMapper = objectMapper;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 使用明磊表单 UUID 组装查询条件,并通过 malk 的普通表单查询接口返回分页单据。
|
|
|
- *
|
|
|
- * @param page 页码,从 1 开始
|
|
|
- * @param size 每页记录数
|
|
|
- * @return 包含记录列表、总数和页码的分页查询结果
|
|
|
- */
|
|
|
- @Override
|
|
|
- public Map<String, Object> queryDocuments(int page, int size) {
|
|
|
- return executeQuery(null, null, page, size);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 根据请求参数的优先级生成精准筛选条件:部门编号、用户所属部门、部门名称。
|
|
|
- *
|
|
|
- * @param request 包含 user_id、dept_id、dept_name 的查询参数
|
|
|
- * @return 仅包含各级部门主管和部门分管领导用户 ID 的单层结果
|
|
|
- */
|
|
|
- @Override
|
|
|
- public Map<String, Object> queryDocuments(MingleiDocumentQueryRequest request) {
|
|
|
- if (request == null) {
|
|
|
- throw new IllegalArgumentException("Query request must not be null");
|
|
|
- }
|
|
|
-
|
|
|
- String departmentId = trimToNull(request.getDeptId());
|
|
|
- if (departmentId != null) {
|
|
|
- return extractDepartmentManagers(executeQuery(DEPARTMENT_ID_FIELD_ID, departmentId, 1, PRECISE_QUERY_PAGE_SIZE));
|
|
|
- }
|
|
|
-
|
|
|
- String userId = trimToNull(request.getUserId());
|
|
|
- if (userId != null) {
|
|
|
- return extractDepartmentManagers(executeQuery(DEPARTMENT_ID_FIELD_ID, resolveDepartmentId(userId), 1, PRECISE_QUERY_PAGE_SIZE));
|
|
|
- }
|
|
|
-
|
|
|
- String departmentName = trimToNull(request.getDeptName());
|
|
|
- if (departmentName != null) {
|
|
|
- return extractDepartmentManagers(executeQuery(DEPARTMENT_NAME_FIELD_ID, departmentName, 1, PRECISE_QUERY_PAGE_SIZE));
|
|
|
- }
|
|
|
-
|
|
|
- throw new IllegalArgumentException("One of dept_id, user_id or dept_name must be provided");
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 按查询范围读取部门成员 ID,并按成员首次出现顺序去重。
|
|
|
- *
|
|
|
- * @param departmentId 钉钉部门 ID
|
|
|
- * @param type 查询范围,0 表示包含子部门,1 表示仅当前部门
|
|
|
- * @return 去重后的钉钉 userid 列表
|
|
|
- */
|
|
|
- @Override
|
|
|
- public List<String> listDepartmentUserIds(long departmentId, int type) {
|
|
|
- String accessToken = dingTalkClient.getAccessToken();
|
|
|
- require(accessToken, "Unable to obtain DingTalk access token");
|
|
|
-
|
|
|
- Set<Long> departmentIds = new LinkedHashSet<Long>();
|
|
|
- departmentIds.add(departmentId);
|
|
|
-
|
|
|
- // 仅 type 为 0 时查询子部门,type 为 1 时保留当前部门。
|
|
|
- if (type == 0) {
|
|
|
- List<Long> childDepartmentIds = dingTalkContactsClient.getDepartmentId_all(accessToken, false, departmentId);
|
|
|
- if (childDepartmentIds != null) {
|
|
|
- departmentIds.addAll(childDepartmentIds);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Set<String> userIds = new LinkedHashSet<String>();
|
|
|
- for (Long currentDepartmentId : departmentIds) {
|
|
|
- if (currentDepartmentId == null) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- List<String> departmentUserIds = dingTalkContactsClient.listDepartmentUserId(accessToken, currentDepartmentId.longValue());
|
|
|
- if (departmentUserIds == null) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- for (String userId : departmentUserIds) {
|
|
|
- String normalizedUserId = trimToNull(userId);
|
|
|
- if (normalizedUserId != null) {
|
|
|
- userIds.add(normalizedUserId);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return new ArrayList<String>(userIds);
|
|
|
- }
|
|
|
-
|
|
|
- private Map<String, Object> executeQuery(String fieldId, String fieldValue, int page, int size) {
|
|
|
- validateConfiguration();
|
|
|
-
|
|
|
- YDParam parameter = new YDParam();
|
|
|
- parameter.setAppType(masterDataConfiguration.getAppType());
|
|
|
- parameter.setSystemToken(masterDataConfiguration.getSystemToken());
|
|
|
- parameter.setFormUuid(MINGLEI_DOCUMENT_FORM_UUID);
|
|
|
- parameter.setCurrentPage(page);
|
|
|
- parameter.setPageSize(size);
|
|
|
- if (fieldId != null) {
|
|
|
- parameter.setSearchFieldJson(createExactSearchFieldJson(fieldId, fieldValue));
|
|
|
- }
|
|
|
-
|
|
|
- DDR_New response = yidaClient.queryData(parameter, YDConf.FORM_QUERY.retrieve_search_form);
|
|
|
- if (response == null) {
|
|
|
- throw new IllegalStateException("Yida form query returned an empty response");
|
|
|
- }
|
|
|
- response.assertSuccess();
|
|
|
-
|
|
|
- Map<String, Object> result = new LinkedHashMap<String, Object>();
|
|
|
- Object records = response.getRecords();
|
|
|
- if (records == null) {
|
|
|
- records = response.getResult();
|
|
|
- }
|
|
|
- if (records == null) {
|
|
|
- records = response.getData();
|
|
|
- }
|
|
|
- result.put("records", records);
|
|
|
- result.put("totalCount", response.getTotalCount());
|
|
|
- result.put("pageNumber", response.getPageNumber());
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 从精准查询命中的首条单据提取五个主管字段对应的用户 ID,并直接返回到顶层。
|
|
|
- *
|
|
|
- * @param queryResult 宜搭列表查询结果
|
|
|
- * @return 仅包含一级至四级部门主管和部门分管领导的单层结果
|
|
|
- */
|
|
|
- private Map<String, Object> extractDepartmentManagers(Map<String, Object> queryResult) {
|
|
|
- Map formData = firstFormData(queryResult.get("records"));
|
|
|
- if (formData == null) {
|
|
|
- return Collections.emptyMap();
|
|
|
- }
|
|
|
-
|
|
|
- Map<String, Object> result = new LinkedHashMap<String, Object>();
|
|
|
- for (String fieldId : DEPARTMENT_MANAGER_FIELD_IDS) {
|
|
|
- result.put(fieldId, firstEmployeeUserId(formData.get(fieldId + "_id")));
|
|
|
- }
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- private Map firstFormData(Object records) {
|
|
|
- if (!(records instanceof Iterable)) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- for (Object record : (Iterable<?>) records) {
|
|
|
- if (!(record instanceof Map)) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- Object formData = ((Map) record).get("formData");
|
|
|
- return formData instanceof Map ? (Map) formData : null;
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- private Object firstValue(Object values) {
|
|
|
- if (values instanceof Iterable) {
|
|
|
- for (Object value : (Iterable<?>) values) {
|
|
|
- return value;
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
- return values;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 从宜搭成员字段对应的 ID 数组中提取首个钉钉 userid。
|
|
|
- *
|
|
|
- * @param employeeIds 宜搭成员字段对应的 ID 数组
|
|
|
- * @return 钉钉 userid;字段未填写或无法识别时为 null
|
|
|
- */
|
|
|
- private String firstEmployeeUserId(Object employeeIds) {
|
|
|
- Object employee = firstValue(employeeIds);
|
|
|
- if (employee == null) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- if (!(employee instanceof Map)) {
|
|
|
- return toStringValue(employee);
|
|
|
- }
|
|
|
-
|
|
|
- Map employeeInfo = (Map) employee;
|
|
|
- String userId = toStringValue(employeeInfo.get("userid"));
|
|
|
- if (userId == null) {
|
|
|
- userId = toStringValue(employeeInfo.get("userId"));
|
|
|
- }
|
|
|
- if (userId == null) {
|
|
|
- userId = toStringValue(employeeInfo.get("user_id"));
|
|
|
- }
|
|
|
- return userId == null ? toStringValue(employeeInfo.get("id")) : userId;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 调用钉钉通讯录接口读取员工所属部门,并取返回列表中的首个部门编号作为查询条件。
|
|
|
- *
|
|
|
- * @param userId 钉钉用户编号
|
|
|
- * @return 员工所属的部门编号
|
|
|
- */
|
|
|
- private String resolveDepartmentId(String userId) {
|
|
|
- Map userInfo = dingTalkContactsClient.getUserInfoById(dingTalkClient.getAccessToken(), userId);
|
|
|
- if (userInfo == null) {
|
|
|
- throw new IllegalArgumentException("No DingTalk user information was found for user_id");
|
|
|
- }
|
|
|
-
|
|
|
- String mainDepartmentId = toStringValue(userInfo.get("main_dept_id"));
|
|
|
- if (mainDepartmentId != null) {
|
|
|
- return mainDepartmentId;
|
|
|
- }
|
|
|
-
|
|
|
- String departmentId = firstDepartmentId(userInfo.get("department"));
|
|
|
- if (departmentId == null) {
|
|
|
- departmentId = firstDepartmentId(userInfo.get("dept_id_list"));
|
|
|
- }
|
|
|
- if (departmentId == null) {
|
|
|
- throw new IllegalArgumentException("No department was found for user_id");
|
|
|
- }
|
|
|
- return departmentId;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 按宜搭普通文本字段的等值查询格式生成 searchFieldJson。
|
|
|
- *
|
|
|
- * @param fieldId 宜搭字段 ID
|
|
|
- * @param value 需要精确匹配的字段值
|
|
|
- * @return 宜搭搜索条件 JSON
|
|
|
- */
|
|
|
- private String createExactSearchFieldJson(String fieldId, String value) {
|
|
|
- Map<String, String> condition = new LinkedHashMap<String, String>();
|
|
|
- condition.put("key", fieldId);
|
|
|
- condition.put("value", value);
|
|
|
- condition.put("type", "TEXT");
|
|
|
- condition.put("operator", "eq");
|
|
|
- condition.put("componentName", "TextField");
|
|
|
- try {
|
|
|
- return objectMapper.writeValueAsString(Collections.singletonList(condition));
|
|
|
- } catch (JsonProcessingException exception) {
|
|
|
- throw new IllegalStateException("Unable to create Yida search condition", exception);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private String firstDepartmentId(Object departmentIds) {
|
|
|
- if (departmentIds instanceof Iterable) {
|
|
|
- for (Object departmentId : (Iterable<?>) departmentIds) {
|
|
|
- String value = toStringValue(departmentId);
|
|
|
- if (value != null) {
|
|
|
- return value;
|
|
|
- }
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
- if (departmentIds != null && departmentIds.getClass().isArray()) {
|
|
|
- Object[] values = (Object[]) departmentIds;
|
|
|
- for (Object departmentId : values) {
|
|
|
- String value = toStringValue(departmentId);
|
|
|
- if (value != null) {
|
|
|
- return value;
|
|
|
- }
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
- return toStringValue(departmentIds);
|
|
|
- }
|
|
|
-
|
|
|
- private String toStringValue(Object value) {
|
|
|
- return value == null ? null : trimToNull(String.valueOf(value));
|
|
|
- }
|
|
|
-
|
|
|
- private String trimToNull(String value) {
|
|
|
- if (value == null) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- String trimmedValue = value.trim();
|
|
|
- return trimmedValue.isEmpty() ? null : trimmedValue;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 校验调用宜搭所需的应用级鉴权配置是否完整。
|
|
|
- */
|
|
|
- private void validateConfiguration() {
|
|
|
- require(dingTalkConfiguration.getAppKey(), "DINGTALK_APP_KEY is not configured");
|
|
|
- require(dingTalkConfiguration.getAppSecret(), "DINGTALK_APP_SECRET is not configured");
|
|
|
- require(masterDataConfiguration.getAppType(), "YIDA_MASTER_DATA_APP_TYPE is not configured");
|
|
|
- require(masterDataConfiguration.getSystemToken(), "YIDA_MASTER_DATA_SYSTEM_TOKEN is not configured");
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 校验单个配置值非空,避免以不完整配置调用远端接口。
|
|
|
- *
|
|
|
- * @param value 待校验配置值
|
|
|
- * @param message 配置缺失时抛出的错误信息
|
|
|
- */
|
|
|
- private void require(String value, String message) {
|
|
|
- if (value == null || value.trim().isEmpty()) {
|
|
|
- throw new IllegalStateException(message);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|