MES本地审批共用钉钉审批等配置
This commit is contained in:
@@ -61,6 +61,11 @@ public interface ISysImChatService {
|
||||
* @return 消息VO,发送失败返回 null
|
||||
*/
|
||||
SysImMessageVO sendSystemSingleMessage(String fromUserId, String toUserId, Integer tenantId, String content, String msgType);
|
||||
|
||||
/**
|
||||
* 审批待办卡片:从「工作通知」公众号推送给处理人。
|
||||
*/
|
||||
SysImMessageVO sendApprovalHandlerMessage(String toUserId, Integer tenantId, String content, String msgType);
|
||||
//update-end---author:GHT ---date:2026-05-29 for:【QH-MES审批流设计】系统单聊消息(绕过同部门校验,供审批等系统通知场景)-----
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.jeecg.modules.system.mapper.SysUserTenantMapper;
|
||||
import org.jeecg.modules.system.service.ISysPermissionService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -64,6 +65,13 @@ public class SysImChatServiceImpl implements ISysImChatService {
|
||||
private static final String MSG_IMAGE_PREVIEW = "[图片]";
|
||||
private static final String MSG_BIZ_RECORD_PREVIEW = "[业务数据]";
|
||||
private static final String IM_RECORD_QUERY_KEY = "imRecordId";
|
||||
/** IM 工作通知公众号账号(审批等系统消息统一从此账号推送) */
|
||||
private static final String WORK_NOTIFY_USERNAME = "im_work_notify";
|
||||
private static final String WORK_NOTIFY_REALNAME = "工作通知";
|
||||
private static final String WORK_NOTIFY_USER_ID = "1995000000000000999";
|
||||
private static final String CONTACT_TYPE_WORK_NOTIFY = "work_notify";
|
||||
private static final String CONTACT_TYPE_USER = "user";
|
||||
private volatile String workNotifyUserIdCache;
|
||||
|
||||
@Autowired
|
||||
private ISysPermissionService sysPermissionService;
|
||||
@@ -107,7 +115,11 @@ public class SysImChatServiceImpl implements ISysImChatService {
|
||||
if (conversation != null) {
|
||||
return buildConversationVo(conversation, userId, targetUserId);
|
||||
}
|
||||
validateTenantChat(userId, tenantId, orgCode, targetUserId);
|
||||
//update-begin---author:GHT ---date:20260610 for:【IM审批通用化】工作通知公众号会话免同部门校验-----------
|
||||
if (!isWorkNotifyUser(targetUserId)) {
|
||||
validateTenantChat(userId, tenantId, orgCode, targetUserId);
|
||||
}
|
||||
//update-end---author:GHT ---date:20260610 for:【IM审批通用化】工作通知公众号会话免同部门校验-----------
|
||||
//update-end---author:cursor ---date:20260528 for:【IM聊天-OA】已有会话快速打开-----------
|
||||
conversation = new SysImConversation();
|
||||
conversation.setConvType(CONV_TYPE_SINGLE);
|
||||
@@ -439,6 +451,11 @@ public class SysImChatServiceImpl implements ISysImChatService {
|
||||
throw new JeecgBootException("消息内容不能为空");
|
||||
}
|
||||
assertMember(userId, dto.getConversationId());
|
||||
//update-begin---author:GHT ---date:20260610 for:【IM审批通用化】工作通知公众号只读,禁止用户发消息-----------
|
||||
if (isWorkNotifyConversation(dto.getConversationId())) {
|
||||
throw new JeecgBootException("工作通知为系统消息通道,不支持发送消息");
|
||||
}
|
||||
//update-end---author:GHT ---date:20260610 for:【IM审批通用化】工作通知公众号只读,禁止用户发消息-----------
|
||||
Date now = new Date();
|
||||
SysImMessage message = new SysImMessage();
|
||||
message.setConversationId(dto.getConversationId());
|
||||
@@ -480,8 +497,8 @@ public class SysImChatServiceImpl implements ISysImChatService {
|
||||
if (oConvertUtils.isEmpty(fromUserId) || oConvertUtils.isEmpty(toUserId) || oConvertUtils.isEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
// 不给自己发送
|
||||
if (fromUserId.equals(toUserId)) {
|
||||
log.warn("IM系统消息跳过:收发为同一人 toUserId={}", toUserId);
|
||||
return null;
|
||||
}
|
||||
Integer tenant = tenantId == null ? 0 : tenantId;
|
||||
@@ -500,8 +517,17 @@ public class SysImChatServiceImpl implements ISysImChatService {
|
||||
conversation.setCreateTime(now);
|
||||
conversation.setUpdateTime(now);
|
||||
conversationMapper.insert(conversation);
|
||||
createMember(conversation.getId(), fromUserId, now);
|
||||
createMember(conversation.getId(), toUserId, now);
|
||||
ensureMember(conversation.getId(), fromUserId, now);
|
||||
if (!fromUserId.equals(toUserId)) {
|
||||
ensureMember(conversation.getId(), toUserId, now);
|
||||
}
|
||||
} else {
|
||||
//update-begin---author:GHT ---date:20260610 for:【IM审批通用化】已有会话补全缺失成员-----------
|
||||
ensureMember(conversation.getId(), fromUserId, now);
|
||||
if (!fromUserId.equals(toUserId)) {
|
||||
ensureMember(conversation.getId(), toUserId, now);
|
||||
}
|
||||
//update-end---author:GHT ---date:20260610 for:【IM审批通用化】已有会话补全缺失成员-----------
|
||||
}
|
||||
// 写入消息
|
||||
SysImMessage message = new SysImMessage();
|
||||
@@ -522,6 +548,22 @@ public class SysImChatServiceImpl implements ISysImChatService {
|
||||
pushChatMessage(conversation.getId(), fromUserId, messageVo, conversation.getConvType());
|
||||
return messageVo;
|
||||
}
|
||||
|
||||
//update-begin---author:GHT ---date:20260610 for:【IM审批通用化】审批待办统一由系统账号发给处理人-----------
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||||
public SysImMessageVO sendApprovalHandlerMessage(String toUserId, Integer tenantId, String content, String msgType) {
|
||||
if (oConvertUtils.isEmpty(toUserId) || oConvertUtils.isEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
String fromUserId = ensureWorkNotifyUserId();
|
||||
if (fromUserId.equals(toUserId)) {
|
||||
log.warn("审批待办IM发送失败:接收人不能是工作通知公众号 toUserId={}", toUserId);
|
||||
return null;
|
||||
}
|
||||
return sendSystemSingleMessage(fromUserId, toUserId, tenantId, content, msgType);
|
||||
}
|
||||
//update-end---author:GHT ---date:20260610 for:【IM审批通用化】审批待办统一由系统账号发给处理人-----------
|
||||
//update-end---author:GHT ---date:2026-05-29 for:【QH-MES审批流设计】系统单聊消息(绕过同部门校验)-----
|
||||
|
||||
//update-begin---author:cursor ---date:20260528 for:【IM聊天-OA】标记已读-----------
|
||||
@@ -541,13 +583,19 @@ public class SysImChatServiceImpl implements ISysImChatService {
|
||||
//update-begin---author:cursor ---date:20260528 for:【IM聊天-OA】本部门成员列表(含会话摘要)-----------
|
||||
@Override
|
||||
public List<SysImContactVO> listDeptMembers(String userId, Integer tenantId, String orgCode, String keyword) {
|
||||
List<SysImContactVO> result = new ArrayList<>();
|
||||
//update-begin---author:GHT ---date:20260610 for:【IM审批通用化】同事列表置顶工作通知公众号-----------
|
||||
if (matchWorkNotifyKeyword(keyword)) {
|
||||
result.add(buildWorkNotifyContact(userId, tenantId));
|
||||
}
|
||||
String workNotifyId = ensureWorkNotifyUserId();
|
||||
String resolvedOrgCode = resolveOrgCode(userId, tenantId, orgCode);
|
||||
if (oConvertUtils.isEmpty(resolvedOrgCode)) {
|
||||
throw new JeecgBootException("未获取到当前部门,请切换部门后重试");
|
||||
return result;
|
||||
}
|
||||
List<SysUser> users = userDepartMapper.querySameDepartUserList(resolvedOrgCode, userId, tenantId, keyword);
|
||||
if (users == null || users.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
return result;
|
||||
}
|
||||
Map<String, SysImConversationVO> convMap = new HashMap<>(16);
|
||||
if (tenantId != null && tenantId > 0) {
|
||||
@@ -557,20 +605,26 @@ public class SysImChatServiceImpl implements ISysImChatService {
|
||||
}
|
||||
}
|
||||
}
|
||||
List<SysImContactVO> result = users.stream().map(user -> {
|
||||
SysImContactVO vo = toContactVo(user);
|
||||
SysImConversationVO conv = convMap.get(user.getId());
|
||||
if (conv != null) {
|
||||
vo.setConversationId(conv.getConversationId());
|
||||
vo.setLastContent(conv.getLastContent());
|
||||
vo.setLastTime(conv.getLastTime());
|
||||
vo.setUnreadCount(conv.getUnreadCount());
|
||||
}
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
result.sort(Comparator
|
||||
List<SysImContactVO> colleagues = users.stream()
|
||||
.filter(user -> !workNotifyId.equals(user.getId()) && !WORK_NOTIFY_USERNAME.equals(user.getUsername()))
|
||||
.map(user -> {
|
||||
SysImContactVO vo = toContactVo(user);
|
||||
vo.setContactType(CONTACT_TYPE_USER);
|
||||
SysImConversationVO conv = convMap.get(user.getId());
|
||||
if (conv != null) {
|
||||
vo.setConversationId(conv.getConversationId());
|
||||
vo.setLastContent(conv.getLastContent());
|
||||
vo.setLastTime(conv.getLastTime());
|
||||
vo.setUnreadCount(conv.getUnreadCount());
|
||||
}
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
colleagues.sort(Comparator
|
||||
.comparing(SysImContactVO::getLastTime, Comparator.nullsLast(Comparator.reverseOrder()))
|
||||
.thenComparing(item -> oConvertUtils.getString(item.getRealname(), item.getUsername())));
|
||||
result.addAll(colleagues);
|
||||
//update-end---author:GHT ---date:20260610 for:【IM审批通用化】同事列表置顶工作通知公众号-----------
|
||||
return result;
|
||||
}
|
||||
//update-end---author:cursor ---date:20260528 for:【IM聊天-OA】本部门成员列表(含会话摘要)-----------
|
||||
@@ -583,9 +637,111 @@ public class SysImChatServiceImpl implements ISysImChatService {
|
||||
vo.setAvatar(user.getAvatar());
|
||||
vo.setOrgCodeTxt(user.getOrgCodeTxt());
|
||||
vo.setUnreadCount(0);
|
||||
vo.setContactType(CONTACT_TYPE_USER);
|
||||
return vo;
|
||||
}
|
||||
|
||||
private SysImContactVO buildWorkNotifyContact(String userId, Integer tenantId) {
|
||||
String workNotifyId = ensureWorkNotifyUserId();
|
||||
SysImContactVO vo = new SysImContactVO();
|
||||
vo.setId(workNotifyId);
|
||||
vo.setUsername(WORK_NOTIFY_USERNAME);
|
||||
vo.setRealname(WORK_NOTIFY_REALNAME);
|
||||
vo.setUnreadCount(0);
|
||||
vo.setContactType(CONTACT_TYPE_WORK_NOTIFY);
|
||||
if (tenantId != null && tenantId > 0) {
|
||||
SysImConversationVO conv = findSingleConversationSummary(userId, tenantId, workNotifyId);
|
||||
if (conv != null) {
|
||||
vo.setConversationId(conv.getConversationId());
|
||||
vo.setLastContent(conv.getLastContent());
|
||||
vo.setLastTime(conv.getLastTime());
|
||||
vo.setUnreadCount(conv.getUnreadCount());
|
||||
}
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
private SysImConversationVO findSingleConversationSummary(String userId, Integer tenantId, String targetUserId) {
|
||||
String pairKey = buildPairKey(userId, targetUserId);
|
||||
SysImConversation conversation = conversationMapper.selectOne(new LambdaQueryWrapper<SysImConversation>()
|
||||
.eq(SysImConversation::getTenantId, tenantId)
|
||||
.eq(SysImConversation::getUserPairKey, pairKey));
|
||||
if (conversation == null) {
|
||||
return null;
|
||||
}
|
||||
SysImConversationMember member = getMember(userId, conversation.getId());
|
||||
SysImConversationVO vo = buildConversationVo(conversation, userId, targetUserId);
|
||||
vo.setUnreadCount(member == null ? 0 : member.getUnreadCount());
|
||||
return vo;
|
||||
}
|
||||
|
||||
private boolean matchWorkNotifyKeyword(String keyword) {
|
||||
if (oConvertUtils.isEmpty(keyword)) {
|
||||
return true;
|
||||
}
|
||||
String key = keyword.trim().toLowerCase();
|
||||
return WORK_NOTIFY_REALNAME.contains(keyword.trim())
|
||||
|| WORK_NOTIFY_REALNAME.toLowerCase().contains(key)
|
||||
|| WORK_NOTIFY_USERNAME.contains(key)
|
||||
|| key.contains("工作")
|
||||
|| key.contains("通知");
|
||||
}
|
||||
|
||||
private String ensureWorkNotifyUserId() {
|
||||
if (oConvertUtils.isNotEmpty(workNotifyUserIdCache)) {
|
||||
return workNotifyUserIdCache;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (oConvertUtils.isNotEmpty(workNotifyUserIdCache)) {
|
||||
return workNotifyUserIdCache;
|
||||
}
|
||||
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
|
||||
.eq(SysUser::getUsername, WORK_NOTIFY_USERNAME)
|
||||
.eq(SysUser::getDelFlag, 0)
|
||||
.last("LIMIT 1"));
|
||||
if (user == null) {
|
||||
user = userMapper.selectById(WORK_NOTIFY_USER_ID);
|
||||
}
|
||||
if (user == null) {
|
||||
user = createWorkNotifyUser();
|
||||
}
|
||||
workNotifyUserIdCache = user.getId();
|
||||
return workNotifyUserIdCache;
|
||||
}
|
||||
}
|
||||
|
||||
private SysUser createWorkNotifyUser() {
|
||||
SysUser user = new SysUser();
|
||||
user.setId(WORK_NOTIFY_USER_ID);
|
||||
user.setUsername(WORK_NOTIFY_USERNAME);
|
||||
user.setRealname(WORK_NOTIFY_REALNAME);
|
||||
user.setPassword("disabled");
|
||||
user.setSalt("");
|
||||
user.setStatus(2);
|
||||
user.setDelFlag(0);
|
||||
user.setCreateBy("system");
|
||||
user.setCreateTime(new Date());
|
||||
userMapper.insert(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
private boolean isWorkNotifyUser(String userId) {
|
||||
return oConvertUtils.isNotEmpty(userId) && userId.equals(ensureWorkNotifyUserId());
|
||||
}
|
||||
|
||||
private boolean isWorkNotifyConversation(String conversationId) {
|
||||
if (oConvertUtils.isEmpty(conversationId)) {
|
||||
return false;
|
||||
}
|
||||
SysImConversation conversation = conversationMapper.selectById(conversationId);
|
||||
if (conversation == null || !CONV_TYPE_SINGLE.equals(conversation.getConvType())) {
|
||||
return false;
|
||||
}
|
||||
String workNotifyId = ensureWorkNotifyUserId();
|
||||
String pairKey = conversation.getUserPairKey();
|
||||
return oConvertUtils.isNotEmpty(pairKey) && pairKey.contains(workNotifyId);
|
||||
}
|
||||
|
||||
private String resolveOrgCode(String userId, Integer tenantId, String orgCode) {
|
||||
if (oConvertUtils.isNotEmpty(orgCode)) {
|
||||
return orgCode;
|
||||
@@ -610,6 +766,17 @@ public class SysImChatServiceImpl implements ISysImChatService {
|
||||
}
|
||||
|
||||
private void createMember(String conversationId, String userId, Date now) {
|
||||
ensureMember(conversationId, userId, now);
|
||||
}
|
||||
|
||||
/** 幂等创建会话成员,避免 uk_im_member 重复插入 */
|
||||
private void ensureMember(String conversationId, String userId, Date now) {
|
||||
if (oConvertUtils.isEmpty(conversationId) || oConvertUtils.isEmpty(userId)) {
|
||||
return;
|
||||
}
|
||||
if (getMember(userId, conversationId) != null) {
|
||||
return;
|
||||
}
|
||||
SysImConversationMember member = new SysImConversationMember();
|
||||
member.setConversationId(conversationId);
|
||||
member.setUserId(userId);
|
||||
@@ -742,7 +909,11 @@ public class SysImChatServiceImpl implements ISysImChatService {
|
||||
sender = userMapper.selectById(message.getSenderId());
|
||||
}
|
||||
if (sender != null) {
|
||||
vo.setSenderName(sender.getRealname());
|
||||
if (WORK_NOTIFY_USERNAME.equals(sender.getUsername())) {
|
||||
vo.setSenderName(WORK_NOTIFY_REALNAME);
|
||||
} else {
|
||||
vo.setSenderName(sender.getRealname());
|
||||
}
|
||||
vo.setSenderAvatar(sender.getAvatar());
|
||||
}
|
||||
return vo;
|
||||
|
||||
@@ -28,4 +28,6 @@ public class SysImContactVO {
|
||||
private java.util.Date lastTime;
|
||||
@Schema(description = "未读数")
|
||||
private Integer unreadCount;
|
||||
@Schema(description = "联系人类型 user=同事 work_notify=工作通知公众号")
|
||||
private String contactType;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user