IM聊天功能优化

This commit is contained in:
geht
2026-05-28 17:08:34 +08:00
parent 3539eab924
commit a63cd6ad1a
29 changed files with 3565 additions and 203 deletions

View File

@@ -22,12 +22,14 @@ import org.jeecg.modules.im.vo.SysImConversationVO;
import org.jeecg.modules.im.vo.SysImMessageVO;
import org.jeecg.modules.message.websocket.WebSocket;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysPermission;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.entity.SysUserDepart;
import org.jeecg.modules.system.mapper.SysDepartMapper;
import org.jeecg.modules.system.mapper.SysUserDepartMapper;
import org.jeecg.modules.system.mapper.SysUserMapper;
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.Transactional;
@@ -50,7 +52,14 @@ public class SysImChatServiceImpl implements ISysImChatService {
private static final String CONV_TYPE_SINGLE = "single";
private static final String MSG_TYPE_TEXT = "text";
private static final String MSG_TYPE_IMAGE = "image";
private static final String MSG_TYPE_BIZ_RECORD = "biz_record";
private static final String MSG_IMAGE_PREVIEW = "[图片]";
private static final String MSG_BIZ_RECORD_PREVIEW = "[业务数据]";
private static final String IM_RECORD_QUERY_KEY = "imRecordId";
@Autowired
private ISysPermissionService sysPermissionService;
@Autowired
private SysImConversationMapper conversationMapper;
@Autowired
@@ -169,13 +178,16 @@ public class SysImChatServiceImpl implements ISysImChatService {
messageMapper.insert(message);
SysImConversation conversation = conversationMapper.selectById(dto.getConversationId());
conversation.setLastContent(truncate(message.getContent(), 200));
//update-begin---author:cursor ---date:20260528 for【IM聊天-OA】图片消息会话摘要-----------
conversation.setLastContent(truncate(resolveLastContent(message.getMsgType(), message.getContent()), 200));
//update-end---author:cursor ---date:20260528 for【IM聊天-OA】图片消息会话摘要-----------
conversation.setLastTime(now);
conversation.setUpdateTime(now);
conversationMapper.updateById(conversation);
memberMapper.incrementUnreadExceptSender(dto.getConversationId(), userId);
SysImMessageVO messageVo = toMessageVo(message, userId);
fillBizRecordReceiverPermission(messageVo, message, userId, new HashMap<>(4));
pushChatMessage(dto.getConversationId(), userId, messageVo);
return messageVo;
}
@@ -376,8 +388,11 @@ public class SysImChatServiceImpl implements ISysImChatService {
}
}
List<SysImMessageVO> result = new ArrayList<>(messages.size());
Map<String, Boolean> receiverPermissionCache = new HashMap<>(16);
for (SysImMessage message : messages) {
result.add(toMessageVo(message, currentUserId, userMap));
SysImMessageVO vo = toMessageVo(message, currentUserId, userMap);
fillBizRecordReceiverPermission(vo, message, currentUserId, receiverPermissionCache);
result.add(vo);
}
return result;
}
@@ -401,6 +416,97 @@ public class SysImChatServiceImpl implements ISysImChatService {
}
return vo;
}
//update-begin---author:xsl ---date:20260528 for【IM聊天-OA】发送方提示接收方无功能权限-----------
private void fillBizRecordReceiverPermission(SysImMessageVO vo, SysImMessage message, String currentUserId, Map<String, Boolean> cache) {
if (!Boolean.TRUE.equals(vo.getMine()) || !MSG_TYPE_BIZ_RECORD.equals(vo.getMsgType())) {
return;
}
String pagePath = extractBizRecordPagePath(vo.getContent());
if (oConvertUtils.isEmpty(pagePath)) {
return;
}
String peerUserId = resolvePeerUserId(message.getConversationId(), currentUserId);
if (oConvertUtils.isEmpty(peerUserId)) {
return;
}
String cacheKey = peerUserId + "|" + normalizeBizPagePath(pagePath);
Boolean hasPermission = cache.get(cacheKey);
if (hasPermission == null) {
hasPermission = hasUserPagePathPermission(peerUserId, pagePath);
cache.put(cacheKey, hasPermission);
}
vo.setReceiverHasBizPagePermission(hasPermission);
}
private String resolvePeerUserId(String conversationId, String currentUserId) {
List<SysImConversationMember> members = memberMapper.selectList(new LambdaQueryWrapper<SysImConversationMember>()
.eq(SysImConversationMember::getConversationId, conversationId));
if (members == null || members.isEmpty()) {
return null;
}
for (SysImConversationMember member : members) {
if (!currentUserId.equals(member.getUserId())) {
return member.getUserId();
}
}
return null;
}
private String extractBizRecordPagePath(String content) {
if (oConvertUtils.isEmpty(content)) {
return null;
}
try {
JSONObject obj = JSONObject.parseObject(content);
return obj.getString("pagePath");
} catch (Exception e) {
log.debug("解析业务明细 pagePath 失败: {}", e.getMessage());
return null;
}
}
private String normalizeBizPagePath(String pagePath) {
if (oConvertUtils.isEmpty(pagePath)) {
return "";
}
String path = pagePath.split("\\?")[0];
if (path.contains("&" + IM_RECORD_QUERY_KEY + "=") || path.contains("?" + IM_RECORD_QUERY_KEY + "=")) {
path = path.replaceAll("[?&]" + IM_RECORD_QUERY_KEY + "=[^&]*", "");
if (path.endsWith("?") || path.endsWith("&")) {
path = path.substring(0, path.length() - 1);
}
}
if (path.endsWith("/") && path.length() > 1) {
path = path.substring(0, path.length() - 1);
}
return path;
}
private boolean hasUserPagePathPermission(String userId, String pagePath) {
String targetPath = normalizeBizPagePath(pagePath);
if (oConvertUtils.isEmpty(userId) || oConvertUtils.isEmpty(targetPath)) {
return false;
}
List<SysPermission> permissions = sysPermissionService.queryByUser(userId);
if (permissions == null || permissions.isEmpty()) {
return false;
}
for (SysPermission permission : permissions) {
if (permission == null || oConvertUtils.isEmpty(permission.getUrl())) {
continue;
}
if (permission.getMenuType() != null && permission.getMenuType() == 2) {
continue;
}
String url = normalizeBizPagePath(permission.getUrl());
if (targetPath.equals(url)) {
return true;
}
}
return false;
}
//update-end---author:xsl ---date:20260528 for【IM聊天-OA】发送方提示接收方无功能权限-----------
//update-end---author:cursor ---date:20260528 for【IM聊天-OA】消息列表批量填充发送人-----------
private void pushChatMessage(String conversationId, String senderId, SysImMessageVO messageVo) {
@@ -433,4 +539,34 @@ public class SysImChatServiceImpl implements ISysImChatService {
}
return content.length() <= maxLen ? content : content.substring(0, maxLen);
}
//update-begin---author:cursor ---date:20260528 for【IM聊天-OA】图片消息会话摘要-----------
private String resolveLastContent(String msgType, String content) {
if (MSG_TYPE_IMAGE.equals(msgType)) {
return MSG_IMAGE_PREVIEW;
}
//update-begin---author:xsl ---date:20260528 for【IM聊天-OA】业务明细消息会话摘要-----------
if (MSG_TYPE_BIZ_RECORD.equals(msgType)) {
return resolveBizRecordPreview(content);
}
//update-end---author:xsl ---date:20260528 for【IM聊天-OA】业务明细消息会话摘要-----------
return content;
}
private String resolveBizRecordPreview(String content) {
if (oConvertUtils.isEmpty(content)) {
return MSG_BIZ_RECORD_PREVIEW;
}
try {
JSONObject obj = JSONObject.parseObject(content);
String pageTitle = obj.getString("pageTitle");
if (oConvertUtils.isNotEmpty(pageTitle)) {
return MSG_BIZ_RECORD_PREVIEW + pageTitle;
}
} catch (Exception e) {
log.debug("解析业务明细消息摘要失败: {}", e.getMessage());
}
return MSG_BIZ_RECORD_PREVIEW;
}
//update-end---author:cursor ---date:20260528 for【IM聊天-OA】图片消息会话摘要-----------
}

View File

@@ -30,6 +30,8 @@ public class SysImMessageVO {
private String msgType;
@Schema(description = "是否本人发送")
private Boolean mine;
@Schema(description = "业务明细接收方是否有对应功能权限(仅发送方可见)")
private Boolean receiverHasBizPagePermission;
@Schema(description = "发送时间")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")