| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- package com.malk.lanyun.service.impl;
- import com.alibaba.fastjson.JSON;
- import com.malk.lanyun.service.DingTalkService;
- import com.malk.server.dingtalk.DDConf;
- import com.malk.server.dingtalk.DDR;
- import com.malk.service.dingtalk.DDClient;
- import com.malk.service.dingtalk.DDClient_Personnel;
- import com.malk.service.dingtalk.DDClient_Workflow;
- import com.malk.utils.UtilMap;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.stereotype.Service;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.HashSet;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- @Service
- @Slf4j
- public class DingTalkServiceImpl implements DingTalkService {
- private final DDClient ddClient;
- private final DDClient_Workflow ddClientWorkflow;
- private final DDClient_Personnel ddClientPersonnel;
- private final DDConf ddConf;
- public DingTalkServiceImpl(DDClient ddClient, DDClient_Workflow ddClientWorkflow,
- DDClient_Personnel ddClientPersonnel, DDConf ddConf) {
- this.ddClient = ddClient;
- this.ddClientWorkflow = ddClientWorkflow;
- this.ddClientPersonnel = ddClientPersonnel;
- this.ddConf = ddConf;
- }
- @Override
- public Map getAllUserIdInfo(String access_token, String status_list, Number offset, Number size) {
- Map param = UtilMap.map("access_token", access_token);
- Map body = UtilMap.map("status_list, offset, size", status_list, offset, size);
- return (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/queryonjob", null, param, body).getResult();
- }
- @Override
- public List<Map> getDDUserInfoById(String access_token, String userId, Number appAgentId) {
- Map param = UtilMap.map("access_token", access_token);
- Map body = UtilMap.map("userid_list, agentid", userId, appAgentId);
- return (List<Map>) DDR.doPost("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/v2/list", null, param, body).getResult();
- }
- /**
- * 审批通过后: 将审批单字段按名称回写到发起人的人员花名册
- *
- * @param processInstanceId 审批实例ID
- * @return 成功写入花名册的字段数量
- */
- @Override
- public int syncApprovalFormToRoster(String processInstanceId) {
- if (isBlank(processInstanceId)) {
- throw new IllegalArgumentException("processInstanceId不能为空");
- }
- // 审批应用凭证: 用于查询审批实例
- String approvalAccessToken = this.ddClient.getAccessToken(this.ddConf.getApprovalAppKey(), this.ddConf.getApprovalAppSecret());
- Map processData = this.ddClientWorkflow.getProcessInstanceId(approvalAccessToken, processInstanceId);
- if (processData == null || processData.isEmpty()) {
- throw new IllegalStateException("未查询到审批实例, processInstanceId=" + processInstanceId);
- }
- String userId = stringValue(processData.get("originatorUserId"));
- if (isBlank(userId)) {
- throw new IllegalStateException("审批实例缺少发起人, processInstanceId=" + processInstanceId);
- }
- // 花名册应用凭证: 用于读写智能人事花名册
- String personnelAccessToken = this.ddClient.getAccessToken(this.ddConf.getAppKey(), this.ddConf.getAppSecret());
- List<Map> formComponentValues = asMapList(processData.get("formComponentValues"));
- List<Map> metadataGroups = this.ddClientPersonnel.getPersonnelMeta(personnelAccessToken, this.ddConf.getAgentId());
- // 花名册字段: 按字段名称建索引, 名称重复或为派生字段时忽略
- Map<String, FieldMeta> metadataByName = indexMetadata(metadataGroups);
- Map<String, LinkedHashMap<String, String>> fieldsByGroup = new LinkedHashMap<>();
- int matchedCount = 0;
- for (Map component : formComponentValues) {
- String name = stringValue(component.get("name"));
- String value = fieldValue(component.get("value"));
- if (isBlank(name) || value == null) {
- continue;
- }
- FieldMeta metadata = metadataByName.get(name.trim());
- if (metadata == null) {
- continue;
- }
- LinkedHashMap<String, String> groupFields = fieldsByGroup.computeIfAbsent(metadata.groupId, key -> new LinkedHashMap<>());
- if (!groupFields.containsKey(metadata.fieldCode)) {
- matchedCount++;
- }
- groupFields.put(metadata.fieldCode, value);
- }
- if (matchedCount == 0) {
- log.info("审批单无匹配的花名册字段, processInstanceId={}", processInstanceId);
- return 0;
- }
- List<Map> groups = buildUpdateGroups(fieldsByGroup);
- boolean updated = this.ddClientPersonnel.updateEmployeeRoster(personnelAccessToken, userId, this.ddConf.getAgentId(), groups);
- if (!updated) {
- throw new IllegalStateException("花名册更新失败, processInstanceId=" + processInstanceId);
- }
- return matchedCount;
- }
- /**
- * 花名册字段索引: 字段名称 -> 分组ID + 字段编码
- */
- private Map<String, FieldMeta> indexMetadata(List<Map> metadataGroups) {
- Map<String, FieldMeta> metadataByName = new LinkedHashMap<>();
- Set<String> ambiguousNames = new HashSet<>();
- for (Map group : safeList(metadataGroups)) {
- String groupId = stringValue(group.get("group_id"));
- if (isBlank(groupId)) {
- continue;
- }
- for (Map field : metadataFields(group)) {
- String fieldName = stringValue(field.get("field_name"));
- String fieldCode = stringValue(field.get("field_code"));
- if (isBlank(fieldName) || isBlank(fieldCode) || isDerived(field.get("derived"))) {
- continue;
- }
- String normalizedName = fieldName.trim();
- FieldMeta existing = metadataByName.get(normalizedName);
- if (existing != null && (!existing.groupId.equals(groupId) || !existing.fieldCode.equals(fieldCode))) {
- ambiguousNames.add(normalizedName);
- continue;
- }
- if (existing == null) {
- metadataByName.put(normalizedName, new FieldMeta(groupId, fieldCode));
- }
- }
- }
- for (String ambiguousName : ambiguousNames) {
- metadataByName.remove(ambiguousName);
- log.warn("花名册字段名称存在歧义, 已忽略: {}", ambiguousName);
- }
- return metadataByName;
- }
- private List<Map> metadataFields(Map group) {
- Object detail = group.get("detail");
- if (detail instanceof Map) {
- return asMapList(((Map) detail).get("field_meta_info_list"));
- }
- if (detail instanceof List) {
- return asMapList(detail);
- }
- return asMapList(group.get("field_meta_info_list"));
- }
- /**
- * 组装花名册更新入参: groups[].sections[].section[].{field_code, value}
- */
- private List<Map> buildUpdateGroups(Map<String, LinkedHashMap<String, String>> fieldsByGroup) {
- List<Map> groups = new ArrayList<>();
- for (Map.Entry<String, LinkedHashMap<String, String>> groupEntry : fieldsByGroup.entrySet()) {
- List<Map> fields = new ArrayList<>();
- for (Map.Entry<String, String> fieldEntry : groupEntry.getValue().entrySet()) {
- fields.add(UtilMap.map("field_code, value", fieldEntry.getKey(), fieldEntry.getValue()));
- }
- Map section = UtilMap.map("section", fields);
- groups.add(UtilMap.map("group_id, sections", groupEntry.getKey(), Collections.singletonList(section)));
- }
- return groups;
- }
- private String fieldValue(Object value) {
- if (value == null) {
- return null;
- }
- if (value instanceof String) {
- String string = (String) value;
- return isBlank(string) ? null : string;
- }
- return JSON.toJSONString(value);
- }
- private boolean isDerived(Object value) {
- return (Boolean.TRUE.equals(value) || "true".equalsIgnoreCase(String.valueOf(value)));
- }
- private List<Map> asMapList(Object value) {
- if (!(value instanceof List)) {
- return Collections.emptyList();
- }
- List<Map> result = new ArrayList<>();
- for (Object item : (List) value) {
- if (item instanceof Map) {
- result.add((Map) item);
- }
- }
- return result;
- }
- private List<Map> safeList(List<Map> value) {
- return (value == null) ? Collections.<Map>emptyList() : value;
- }
- private String stringValue(Object value) {
- return (value == null) ? null : String.valueOf(value);
- }
- private boolean isBlank(String value) {
- return (value == null || value.trim().isEmpty());
- }
- /**
- * 花名册字段元信息
- */
- private static final class FieldMeta {
- private final String groupId;
- private final String fieldCode;
- private FieldMeta(String groupId, String fieldCode) {
- this.groupId = groupId;
- this.fieldCode = fieldCode;
- }
- }
- }
|