!93 czh-20260725-getDistinctHandlerNames同时返回工号+姓名

* czh-20260725-getDistinctHandlerNames同时返回工号+姓名
* czh-20260725-移除linkOpenMode和dataFormat默认值
* czh-20260725-移除接收人上限限制
* czh-20260725-IM模块code-review补充修复
* czh-20260725-code-review问题修复
This commit is contained in:
陈志浩
2026-07-25 02:52:19 +00:00
parent fbd91f8337
commit e31b7dbb28
5 changed files with 143 additions and 113 deletions
@@ -21,16 +21,14 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 审批意见快照 Service 实现。
@@ -54,7 +52,6 @@ public class TaskApprovalOpinionServiceImpl extends ServiceImpl<TaskApprovalOpin
private IKsimMessageService ksimMessageService;
@Override
@Transactional(rollbackFor = Exception.class)
public Map<String, Object> saveSupplementOpinion(SupplementApprovalOpinionDTO supplementDTO) {
if (supplementDTO == null || oConvertUtils.isEmpty(supplementDTO.getProcessInstId())) {
throw new JeecgBootException("流程实例ID不能为空");
@@ -93,41 +90,61 @@ public class TaskApprovalOpinionServiceImpl extends ServiceImpl<TaskApprovalOpin
opinion.setSysOrgCode(deptInfo.code);
fillBusinessSnapshot(opinion);
save(opinion);
if (!save(opinion)) {
throw new JeecgBootException("保存增补审批意见失败");
}
// --- 所领导增补意见 → 即时通推送 ---
// --- 所领导增补意见 → 即时通推送(DB 事务外执行,避免 HTTP 调用占用连接池)---
return doPushNotification(opinion, deptInfo, loginUser, opinionText, supplementDTO.getBizTitle());
}
/**
* 所领导增补意见即时通推送。在 DB 事务外执行,避免 HTTP 调用占用数据库连接。
*/
private Map<String, Object> doPushNotification(TaskApprovalOpinion opinion, ApprovalDeptInfo deptInfo,
LoginUser loginUser, String opinionText, String frontendBizTitle) {
Map<String, Object> pushResult = new HashMap<>();
// 确保所有代码路径返回一致的 key 集合
pushResult.put("pushed", false);
pushResult.put("toUsers", Collections.emptyList());
pushResult.put("content", "");
pushResult.put("title", "");
pushResult.put("error", "");
try {
if (isSuoLeader(loginUser, deptInfo.id)) {
String bizTitle = oConvertUtils.isNotEmpty(supplementDTO.getBizTitle())
? supplementDTO.getBizTitle()
: getBizTitle(opinion.getTaskTaskId(), opinion.getProcessInstId());
String content = "所领导" + (oConvertUtils.isNotEmpty(loginUser.getRealname()) ? loginUser.getRealname() : loginUser.getUsername())
+ "增补意见:" + opinionText;
List<String> handlerNames = getDistinctHandlerNames(opinion.getProcessInstId(), loginUser.getUsername(), loginUser.getRealname());
pushResult.put("pushed", !handlerNames.isEmpty());
pushResult.put("toUsers", handlerNames);
pushResult.put("content", content);
pushResult.put("title", bizTitle);
if (!handlerNames.isEmpty()) {
Result<String> sendResult = ksimMessageService.sendBatch("Account", handlerNames, bizTitle, content,
null, null, null, null, null);
if (sendResult != null && sendResult.isSuccess()) {
log.info("【增补意见-即时通推送】已发送, processInstId: {}, toUserCount: {}, toUsers: {}, title: {}, content: {}",
opinion.getProcessInstId(), handlerNames.size(), handlerNames, bizTitle, content);
} else {
log.warn("【增补意见-即时通推送】发送失败, reason: {}",
sendResult != null ? sendResult.getMessage() : "null");
pushResult.put("pushed", false);
}
if (!isSuoLeader(deptInfo)) {
return pushResult;
}
String bizTitle = oConvertUtils.isNotEmpty(frontendBizTitle)
? frontendBizTitle
: getBizTitle(opinion.getTaskTaskId(), opinion.getProcessInstId());
String content = "所领导" + (oConvertUtils.isNotEmpty(loginUser.getRealname()) ? loginUser.getRealname() : loginUser.getUsername())
+ "增补意见:" + opinionText;
LinkedHashMap<String, String> handlerMap = getDistinctHandlerNames(opinion.getProcessInstId(), loginUser.getUsername(), loginUser.getRealname());
List<String> handlerIds = new ArrayList<>(handlerMap.keySet());
List<String> handlerNames = new ArrayList<>(handlerMap.values());
pushResult.put("pushed", !handlerIds.isEmpty());
pushResult.put("toUsers", handlerNames);
pushResult.put("content", content);
pushResult.put("title", bizTitle);
if (!handlerIds.isEmpty()) {
Result<String> sendResult = ksimMessageService.sendBatch("Account", handlerIds, bizTitle, content,
null, null, null, null, null);
if (sendResult != null && sendResult.isSuccess()) {
log.info("【增补意见-即时通推送】已发送, processInstId: {}, toUserCount: {}, toUsers: {}, title: {}, content: {}",
opinion.getProcessInstId(), handlerIds.size(), handlerNames, bizTitle, content);
} else {
String reason = sendResult != null ? sendResult.getMessage() : "null";
log.warn("【增补意见-即时通推送】发送失败, reason: {}", reason);
pushResult.put("pushed", false);
pushResult.put("error", reason);
}
} else {
pushResult.put("pushed", false);
}
} catch (Exception e) {
log.warn("【增补意见-即时通推送】失败,不影响增补意见保存, error: {}", e.getMessage());
String errMsg = e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName();
log.warn("【增补意见-即时通推送】失败,不影响增补意见保存, error: {}", errMsg);
pushResult.put("pushed", false);
pushResult.put("error", e.getMessage());
pushResult.put("error", errMsg);
}
return pushResult;
}
@@ -144,6 +161,7 @@ public class TaskApprovalOpinionServiceImpl extends ServiceImpl<TaskApprovalOpin
String deptId = user != null ? user.getOrgId() : null;
String deptCode = user != null ? user.getOrgCode() : null;
String deptName = null;
String departType = null;
if (oConvertUtils.isNotEmpty(deptCode)) {
try {
@@ -157,16 +175,33 @@ public class TaskApprovalOpinionServiceImpl extends ServiceImpl<TaskApprovalOpin
if (oConvertUtils.isEmpty(deptName)) {
deptName = depart.getString("depart_name");
}
// 一次查询同时捕获 departType,避免 isSuoLeader 再查 sys_depart
departType = depart.getString("departType");
if (oConvertUtils.isEmpty(departType)) {
departType = depart.getString("depart_type");
}
}
} catch (Exception e) {
log.debug("获取当前登录部门失败, username={}, orgCode={}", username, deptCode, e);
log.warn("【增补意见-审批意见】获取当前登录部门失败, username={}, orgCode={}", username, deptCode, e);
}
}
if (oConvertUtils.isEmpty(deptName) && oConvertUtils.isNotEmpty(username)) {
deptName = resolveDeptName(username);
}
return new ApprovalDeptInfo(deptId, deptName, deptCode);
// 若 departType 仍未获取到,回退查 sys_depart 表(补回退,通常不会执行)
if (oConvertUtils.isEmpty(departType) && oConvertUtils.isNotEmpty(deptId) && jdbcTemplate != null) {
try {
List<Map<String, Object>> rows = jdbcTemplate.queryForList(
"SELECT depart_type FROM sys_depart WHERE id = ?", deptId);
if (!rows.isEmpty()) {
departType = getStringValue(rows.get(0), "depart_type");
}
} catch (Exception e) {
log.warn("【增补意见-审批意见】查询部门类型失败, deptId={}", deptId, e);
}
}
return new ApprovalDeptInfo(deptId, deptName, deptCode, departType);
}
private String resolveDeptName(String username) {
@@ -176,7 +211,7 @@ public class TaskApprovalOpinionServiceImpl extends ServiceImpl<TaskApprovalOpin
return names.get(0);
}
} catch (Exception e) {
log.debug("获取部门名称失败, username={}", username, e);
log.warn("【增补意见-审批意见】获取部门名称失败, username={}", username, e);
}
return null;
}
@@ -239,24 +274,8 @@ public class TaskApprovalOpinionServiceImpl extends ServiceImpl<TaskApprovalOpin
return null;
}
private boolean isSuoLeader(LoginUser user, String deptId) {
if (oConvertUtils.isEmpty(deptId)) {
return false;
}
try {
if (jdbcTemplate == null) {
return false;
}
List<Map<String, Object>> rows = jdbcTemplate.queryForList(
"select depart_type from sys_depart where id = ?", deptId);
if (!rows.isEmpty()) {
Object val = rows.get(0).get("depart_type");
return val != null && "1".equals(String.valueOf(val));
}
} catch (Exception e) {
log.debug("查询部门类型失败, deptId={}", deptId, e);
}
return false;
private boolean isSuoLeader(ApprovalDeptInfo deptInfo) {
return "1".equals(deptInfo.departType);
}
private String getBizTitle(String taskTaskId, String processInstId) {
@@ -287,15 +306,16 @@ public class TaskApprovalOpinionServiceImpl extends ServiceImpl<TaskApprovalOpin
return "";
}
private List<String> getDistinctHandlerNames(String processInstId, String excludeUserId, String excludeRealName) {
/** userId → userName 映射,保持插入顺序 */
private LinkedHashMap<String, String> getDistinctHandlerNames(String processInstId, String excludeUserId, String excludeRealName) {
if (jdbcTemplate == null || oConvertUtils.isEmpty(processInstId)) {
return Collections.emptyList();
return new LinkedHashMap<>();
}
try {
List<Map<String, Object>> rows = jdbcTemplate.queryForList(
"select distinct op_user_id, op_user_name from task_approval_opinion where process_inst_id = ?",
"SELECT DISTINCT op_user_id, op_user_name FROM task_approval_opinion WHERE process_inst_id = ?",
processInstId);
Set<String> userIds = new LinkedHashSet<>();
LinkedHashMap<String, String> handlerMap = new LinkedHashMap<>();
for (Map<String, Object> row : rows) {
Object idVal = row.get("op_user_id");
Object nameVal = row.get("op_user_name");
@@ -318,14 +338,14 @@ public class TaskApprovalOpinionServiceImpl extends ServiceImpl<TaskApprovalOpin
log.info("【增补意见-即时通推送】排除本人(姓名匹配), name: {}, userId: {}", name, userId);
continue;
}
userIds.add(userId);
handlerMap.putIfAbsent(userId, name);
}
log.info("【增补意见-即时通推送】查询经办人完成, processInstId: {}, DB记录数: {}, 排除后: {}",
processInstId, rows.size(), userIds.size());
return userIds.stream().collect(Collectors.toList());
processInstId, rows.size(), handlerMap.size());
return handlerMap;
} catch (Exception e) {
log.debug("查询经办人失败, processInstId={}", processInstId, e);
return Collections.emptyList();
log.warn("【增补意见-即时通推送】查询经办人失败, processInstId={}", processInstId, e);
return new LinkedHashMap<>();
}
}
@@ -333,11 +353,13 @@ public class TaskApprovalOpinionServiceImpl extends ServiceImpl<TaskApprovalOpin
private final String id;
private final String name;
private final String code;
private final String departType;
private ApprovalDeptInfo(String id, String name, String code) {
private ApprovalDeptInfo(String id, String name, String code, String departType) {
this.id = id;
this.name = name;
this.code = code;
this.departType = departType;
}
}
}