新增IM聊天群管理接口,包括群聊详情、添加成员、移除成员、修改群名称、转让群主、退出群聊及解散群聊功能,提升群聊管理体验。
This commit is contained in:
@@ -12,10 +12,12 @@ import org.jeecg.common.system.vo.LoginUser;
|
||||
import org.jeecg.common.util.TokenUtils;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.modules.im.dto.SysImCreateGroupDTO;
|
||||
import org.jeecg.modules.im.dto.SysImGroupMembersDTO;
|
||||
import org.jeecg.modules.im.dto.SysImSendMessageDTO;
|
||||
import org.jeecg.modules.im.service.ISysImChatService;
|
||||
import org.jeecg.modules.im.vo.SysImContactVO;
|
||||
import org.jeecg.modules.im.vo.SysImConversationVO;
|
||||
import org.jeecg.modules.im.vo.SysImGroupDetailVO;
|
||||
import org.jeecg.modules.im.vo.SysImMessageVO;
|
||||
import org.jeecg.modules.system.entity.SysUser;
|
||||
import org.jeecg.modules.system.service.ISysUserService;
|
||||
@@ -155,4 +157,69 @@ public class SysImChatController {
|
||||
return Result.OK(imChatService.createGroupConversation(user.getId(), resolveTenantId(user, request), user.getOrgCode(), dto));
|
||||
}
|
||||
//update-end---author:xsl ---date:20260528 for:【IM聊天-OA】群聊接口-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260529 for:【IM聊天-OA】群设置-群管理接口-----------
|
||||
@Operation(summary = "IM聊天-群聊详情")
|
||||
@RequiresPermissions("sys:im:chat:list")
|
||||
@GetMapping("/group/detail")
|
||||
public Result<SysImGroupDetailVO> groupDetail(@RequestParam(name = "conversationId") String conversationId) {
|
||||
LoginUser user = currentUser();
|
||||
return Result.OK(imChatService.getGroupDetail(user.getId(), conversationId));
|
||||
}
|
||||
|
||||
@Operation(summary = "IM聊天-添加群成员")
|
||||
@RequiresPermissions("sys:im:chat:list")
|
||||
@PostMapping("/group/addMembers")
|
||||
public Result<SysImConversationVO> addGroupMembers(@RequestBody SysImGroupMembersDTO dto, HttpServletRequest request) {
|
||||
LoginUser user = currentUser();
|
||||
return Result.OK(imChatService.addGroupMembers(user.getId(), resolveTenantId(user, request), user.getOrgCode(), dto));
|
||||
}
|
||||
|
||||
@Operation(summary = "IM聊天-移除群成员")
|
||||
@RequiresPermissions("sys:im:chat:list")
|
||||
@PostMapping("/group/removeMember")
|
||||
public Result<String> removeGroupMember(@RequestParam(name = "conversationId") String conversationId,
|
||||
@RequestParam(name = "memberUserId") String memberUserId) {
|
||||
LoginUser user = currentUser();
|
||||
imChatService.removeGroupMember(user.getId(), conversationId, memberUserId);
|
||||
return Result.OK("移除成功");
|
||||
}
|
||||
|
||||
@Operation(summary = "IM聊天-修改群名称")
|
||||
@RequiresPermissions("sys:im:chat:list")
|
||||
@PostMapping("/group/rename")
|
||||
public Result<SysImConversationVO> renameGroup(@RequestParam(name = "conversationId") String conversationId,
|
||||
@RequestParam(name = "groupName") String groupName) {
|
||||
LoginUser user = currentUser();
|
||||
return Result.OK(imChatService.renameGroup(user.getId(), conversationId, groupName));
|
||||
}
|
||||
|
||||
@Operation(summary = "IM聊天-转让群主")
|
||||
@RequiresPermissions("sys:im:chat:list")
|
||||
@PostMapping("/group/transfer")
|
||||
public Result<String> transferGroupOwner(@RequestParam(name = "conversationId") String conversationId,
|
||||
@RequestParam(name = "newOwnerId") String newOwnerId) {
|
||||
LoginUser user = currentUser();
|
||||
imChatService.transferGroupOwner(user.getId(), conversationId, newOwnerId);
|
||||
return Result.OK("转让成功");
|
||||
}
|
||||
|
||||
@Operation(summary = "IM聊天-退出群聊")
|
||||
@RequiresPermissions("sys:im:chat:list")
|
||||
@PostMapping("/group/quit")
|
||||
public Result<String> quitGroup(@RequestParam(name = "conversationId") String conversationId) {
|
||||
LoginUser user = currentUser();
|
||||
imChatService.quitGroup(user.getId(), conversationId);
|
||||
return Result.OK("已退出群聊");
|
||||
}
|
||||
|
||||
@Operation(summary = "IM聊天-解散群聊")
|
||||
@RequiresPermissions("sys:im:chat:list")
|
||||
@PostMapping("/group/dismiss")
|
||||
public Result<String> dismissGroup(@RequestParam(name = "conversationId") String conversationId) {
|
||||
LoginUser user = currentUser();
|
||||
imChatService.dismissGroup(user.getId(), conversationId);
|
||||
return Result.OK("群聊已解散");
|
||||
}
|
||||
//update-end---author:cursor ---date:20260529 for:【IM聊天-OA】群设置-群管理接口-----------
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.jeecg.modules.im.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IM 群聊添加成员
|
||||
*/
|
||||
//update-begin---author:cursor ---date:20260529 for:【IM聊天-OA】群设置-添加群成员-----------
|
||||
@Data
|
||||
@Schema(description = "IM群聊添加成员")
|
||||
public class SysImGroupMembersDTO {
|
||||
|
||||
@Schema(description = "会话ID")
|
||||
private String conversationId;
|
||||
|
||||
@Schema(description = "新增成员用户ID")
|
||||
private List<String> memberUserIds;
|
||||
}
|
||||
//update-end---author:cursor ---date:20260529 for:【IM聊天-OA】群设置-添加群成员-----------
|
||||
@@ -5,12 +5,15 @@ package org.jeecg.modules.im.service;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
|
||||
import org.jeecg.modules.im.dto.SysImCreateGroupDTO;
|
||||
import org.jeecg.modules.im.dto.SysImGroupMembersDTO;
|
||||
import org.jeecg.modules.im.dto.SysImSendMessageDTO;
|
||||
|
||||
import org.jeecg.modules.im.vo.SysImContactVO;
|
||||
|
||||
import org.jeecg.modules.im.vo.SysImConversationVO;
|
||||
|
||||
import org.jeecg.modules.im.vo.SysImGroupDetailVO;
|
||||
|
||||
import org.jeecg.modules.im.vo.SysImMessageVO;
|
||||
|
||||
|
||||
@@ -53,5 +56,28 @@ public interface ISysImChatService {
|
||||
|
||||
List<SysImContactVO> listDeptMembers(String userId, Integer tenantId, String orgCode, String keyword);
|
||||
|
||||
//update-begin---author:cursor ---date:20260529 for:【IM聊天-OA】群设置-群管理接口-----------
|
||||
/** 群聊详情(含成员列表,区分群主) */
|
||||
SysImGroupDetailVO getGroupDetail(String userId, String conversationId);
|
||||
|
||||
/** 添加群成员(所有群成员可操作) */
|
||||
SysImConversationVO addGroupMembers(String userId, Integer tenantId, String orgCode, SysImGroupMembersDTO dto);
|
||||
|
||||
/** 移除群成员(仅群主) */
|
||||
void removeGroupMember(String userId, String conversationId, String memberUserId);
|
||||
|
||||
/** 修改群名称(仅群主) */
|
||||
SysImConversationVO renameGroup(String userId, String conversationId, String groupName);
|
||||
|
||||
/** 转让群主(仅群主) */
|
||||
void transferGroupOwner(String userId, String conversationId, String newOwnerId);
|
||||
|
||||
/** 退出群聊(非群主成员) */
|
||||
void quitGroup(String userId, String conversationId);
|
||||
|
||||
/** 解散群聊(仅群主) */
|
||||
void dismissGroup(String userId, String conversationId);
|
||||
//update-end---author:cursor ---date:20260529 for:【IM聊天-OA】群设置-群管理接口-----------
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jeecg.common.exception.JeecgBootException;
|
||||
import org.jeecg.common.util.DateUtils;
|
||||
import org.jeecg.common.util.oConvertUtils;
|
||||
import org.jeecg.modules.im.dto.SysImCreateGroupDTO;
|
||||
import org.jeecg.modules.im.dto.SysImGroupMembersDTO;
|
||||
import org.jeecg.modules.im.dto.SysImSendMessageDTO;
|
||||
import org.jeecg.modules.im.entity.SysImConversation;
|
||||
import org.jeecg.modules.im.entity.SysImConversationMember;
|
||||
@@ -20,6 +21,8 @@ import org.jeecg.modules.im.mapper.SysImMessageMapper;
|
||||
import org.jeecg.modules.im.service.ISysImChatService;
|
||||
import org.jeecg.modules.im.vo.SysImContactVO;
|
||||
import org.jeecg.modules.im.vo.SysImConversationVO;
|
||||
import org.jeecg.modules.im.vo.SysImGroupDetailVO;
|
||||
import org.jeecg.modules.im.vo.SysImGroupMemberVO;
|
||||
import org.jeecg.modules.im.vo.SysImMessageVO;
|
||||
import org.jeecg.modules.message.websocket.WebSocket;
|
||||
import org.jeecg.modules.system.entity.SysDepart;
|
||||
@@ -198,6 +201,193 @@ public class SysImChatServiceImpl implements ISysImChatService {
|
||||
}
|
||||
//update-end---author:xsl ---date:20260528 for:【IM聊天-OA】群聊会话列表与创建-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260529 for:【IM聊天-OA】群设置-群管理-----------
|
||||
private static final int GROUP_MEMBER_MAX = 50;
|
||||
|
||||
@Override
|
||||
public SysImGroupDetailVO getGroupDetail(String userId, String conversationId) {
|
||||
SysImConversation conversation = assertGroupConversation(userId, conversationId);
|
||||
List<SysImConversationMember> members = memberMapper.selectList(new LambdaQueryWrapper<SysImConversationMember>()
|
||||
.eq(SysImConversationMember::getConversationId, conversationId)
|
||||
.orderByAsc(SysImConversationMember::getCreateTime));
|
||||
List<String> memberUserIds = members.stream()
|
||||
.map(SysImConversationMember::getUserId)
|
||||
.filter(oConvertUtils::isNotEmpty)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
Map<String, SysUser> userMap = new HashMap<>(memberUserIds.size());
|
||||
if (!memberUserIds.isEmpty()) {
|
||||
List<SysUser> users = userMapper.selectBatchIds(memberUserIds);
|
||||
if (users != null) {
|
||||
for (SysUser user : users) {
|
||||
userMap.put(user.getId(), user);
|
||||
}
|
||||
}
|
||||
}
|
||||
String ownerId = conversation.getOwnerId();
|
||||
List<SysImGroupMemberVO> memberVoList = new ArrayList<>(members.size());
|
||||
for (SysImConversationMember member : members) {
|
||||
SysUser user = userMap.get(member.getUserId());
|
||||
SysImGroupMemberVO memberVo = new SysImGroupMemberVO();
|
||||
memberVo.setUserId(member.getUserId());
|
||||
memberVo.setOwner(member.getUserId() != null && member.getUserId().equals(ownerId));
|
||||
if (user != null) {
|
||||
memberVo.setRealname(user.getRealname());
|
||||
memberVo.setUsername(user.getUsername());
|
||||
memberVo.setAvatar(user.getAvatar());
|
||||
}
|
||||
memberVoList.add(memberVo);
|
||||
}
|
||||
// 群主排在最前
|
||||
memberVoList.sort(Comparator.comparingInt(item -> Boolean.TRUE.equals(item.getOwner()) ? 0 : 1));
|
||||
SysImGroupDetailVO detail = new SysImGroupDetailVO();
|
||||
detail.setConversationId(conversation.getId());
|
||||
detail.setGroupName(conversation.getGroupName());
|
||||
detail.setOwnerId(ownerId);
|
||||
detail.setMemberCount(memberVoList.size());
|
||||
detail.setOwner(userId.equals(ownerId));
|
||||
detail.setMembers(memberVoList);
|
||||
return detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public SysImConversationVO addGroupMembers(String userId, Integer tenantId, String orgCode, SysImGroupMembersDTO dto) {
|
||||
if (dto == null || oConvertUtils.isEmpty(dto.getConversationId())) {
|
||||
throw new JeecgBootException("会话不存在");
|
||||
}
|
||||
SysImConversation conversation = assertGroupConversation(userId, dto.getConversationId());
|
||||
if (dto.getMemberUserIds() == null || dto.getMemberUserIds().isEmpty()) {
|
||||
throw new JeecgBootException("请选择要添加的成员");
|
||||
}
|
||||
// 已在群成员
|
||||
Set<String> existIds = memberMapper.selectList(new LambdaQueryWrapper<SysImConversationMember>()
|
||||
.eq(SysImConversationMember::getConversationId, conversation.getId()))
|
||||
.stream().map(SysImConversationMember::getUserId).collect(Collectors.toSet());
|
||||
// 去重并过滤已存在成员
|
||||
List<String> toAdd = new ArrayList<>();
|
||||
Set<String> seen = new LinkedHashSet<>();
|
||||
for (String memberId : dto.getMemberUserIds()) {
|
||||
if (oConvertUtils.isEmpty(memberId) || existIds.contains(memberId) || !seen.add(memberId)) {
|
||||
continue;
|
||||
}
|
||||
toAdd.add(memberId);
|
||||
}
|
||||
if (toAdd.isEmpty()) {
|
||||
throw new JeecgBootException("所选成员已在群内");
|
||||
}
|
||||
if (existIds.size() + toAdd.size() > GROUP_MEMBER_MAX) {
|
||||
throw new JeecgBootException("群成员不能超过" + GROUP_MEMBER_MAX + "人");
|
||||
}
|
||||
// 校验同租户、同部门
|
||||
for (String memberId : toAdd) {
|
||||
validateTenantChat(userId, tenantId, orgCode, memberId);
|
||||
}
|
||||
Date now = new Date();
|
||||
for (String memberId : toAdd) {
|
||||
createMember(conversation.getId(), memberId, now);
|
||||
}
|
||||
return buildGroupConversationVo(conversation, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void removeGroupMember(String userId, String conversationId, String memberUserId) {
|
||||
SysImConversation conversation = assertGroupConversation(userId, conversationId);
|
||||
assertGroupOwner(userId, conversation);
|
||||
if (oConvertUtils.isEmpty(memberUserId)) {
|
||||
throw new JeecgBootException("请选择要移除的成员");
|
||||
}
|
||||
if (memberUserId.equals(conversation.getOwnerId())) {
|
||||
throw new JeecgBootException("群主不能被移除");
|
||||
}
|
||||
memberMapper.delete(new LambdaQueryWrapper<SysImConversationMember>()
|
||||
.eq(SysImConversationMember::getConversationId, conversationId)
|
||||
.eq(SysImConversationMember::getUserId, memberUserId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public SysImConversationVO renameGroup(String userId, String conversationId, String groupName) {
|
||||
SysImConversation conversation = assertGroupConversation(userId, conversationId);
|
||||
assertGroupOwner(userId, conversation);
|
||||
if (oConvertUtils.isEmpty(groupName)) {
|
||||
throw new JeecgBootException("群名称不能为空");
|
||||
}
|
||||
String name = groupName.trim();
|
||||
if (name.length() > 30) {
|
||||
throw new JeecgBootException("群名称不能超过30字");
|
||||
}
|
||||
conversation.setGroupName(name);
|
||||
conversation.setUpdateBy(userId);
|
||||
conversation.setUpdateTime(new Date());
|
||||
conversationMapper.updateById(conversation);
|
||||
return buildGroupConversationVo(conversation, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void transferGroupOwner(String userId, String conversationId, String newOwnerId) {
|
||||
SysImConversation conversation = assertGroupConversation(userId, conversationId);
|
||||
assertGroupOwner(userId, conversation);
|
||||
if (oConvertUtils.isEmpty(newOwnerId)) {
|
||||
throw new JeecgBootException("请选择新群主");
|
||||
}
|
||||
if (newOwnerId.equals(userId)) {
|
||||
throw new JeecgBootException("不能转让给自己");
|
||||
}
|
||||
if (getMember(newOwnerId, conversationId) == null) {
|
||||
throw new JeecgBootException("新群主必须是群成员");
|
||||
}
|
||||
conversation.setOwnerId(newOwnerId);
|
||||
conversation.setUpdateBy(userId);
|
||||
conversation.setUpdateTime(new Date());
|
||||
conversationMapper.updateById(conversation);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void quitGroup(String userId, String conversationId) {
|
||||
SysImConversation conversation = assertGroupConversation(userId, conversationId);
|
||||
if (userId.equals(conversation.getOwnerId())) {
|
||||
throw new JeecgBootException("群主不能退出群聊,请先转让群主或解散群聊");
|
||||
}
|
||||
memberMapper.delete(new LambdaQueryWrapper<SysImConversationMember>()
|
||||
.eq(SysImConversationMember::getConversationId, conversationId)
|
||||
.eq(SysImConversationMember::getUserId, userId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void dismissGroup(String userId, String conversationId) {
|
||||
SysImConversation conversation = assertGroupConversation(userId, conversationId);
|
||||
assertGroupOwner(userId, conversation);
|
||||
memberMapper.delete(new LambdaQueryWrapper<SysImConversationMember>()
|
||||
.eq(SysImConversationMember::getConversationId, conversationId));
|
||||
conversationMapper.deleteById(conversationId);
|
||||
}
|
||||
|
||||
/** 校验会话存在、为群聊且当前用户是群成员 */
|
||||
private SysImConversation assertGroupConversation(String userId, String conversationId) {
|
||||
if (oConvertUtils.isEmpty(conversationId)) {
|
||||
throw new JeecgBootException("会话不存在");
|
||||
}
|
||||
SysImConversation conversation = conversationMapper.selectById(conversationId);
|
||||
if (conversation == null || !CONV_TYPE_GROUP.equals(conversation.getConvType())) {
|
||||
throw new JeecgBootException("群聊不存在");
|
||||
}
|
||||
assertMember(userId, conversationId);
|
||||
return conversation;
|
||||
}
|
||||
|
||||
/** 校验当前用户是群主 */
|
||||
private void assertGroupOwner(String userId, SysImConversation conversation) {
|
||||
if (!userId.equals(conversation.getOwnerId())) {
|
||||
throw new JeecgBootException("仅群主可执行该操作");
|
||||
}
|
||||
}
|
||||
//update-end---author:cursor ---date:20260529 for:【IM聊天-OA】群设置-群管理-----------
|
||||
|
||||
//update-begin---author:cursor ---date:20260528 for:【IM聊天-OA】消息分页-----------
|
||||
@Override
|
||||
public IPage<SysImMessageVO> listMessages(String userId, String conversationId, Integer pageNo, Integer pageSize, String startTime, String beforeTime) {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.jeecg.modules.im.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IM 群聊详情(群设置)
|
||||
*/
|
||||
//update-begin---author:cursor ---date:20260529 for:【IM聊天-OA】群设置-群详情-----------
|
||||
@Data
|
||||
@Schema(description = "IM群聊详情")
|
||||
public class SysImGroupDetailVO {
|
||||
|
||||
@Schema(description = "会话ID")
|
||||
private String conversationId;
|
||||
@Schema(description = "群名称")
|
||||
private String groupName;
|
||||
@Schema(description = "群主用户ID")
|
||||
private String ownerId;
|
||||
@Schema(description = "群成员数")
|
||||
private Integer memberCount;
|
||||
@Schema(description = "当前用户是否群主")
|
||||
private Boolean owner;
|
||||
@Schema(description = "群成员列表")
|
||||
private List<SysImGroupMemberVO> members;
|
||||
}
|
||||
//update-end---author:cursor ---date:20260529 for:【IM聊天-OA】群设置-群详情-----------
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.jeecg.modules.im.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IM 群成员
|
||||
*/
|
||||
//update-begin---author:cursor ---date:20260529 for:【IM聊天-OA】群设置-群成员展示-----------
|
||||
@Data
|
||||
@Schema(description = "IM群成员")
|
||||
public class SysImGroupMemberVO {
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private String userId;
|
||||
@Schema(description = "姓名")
|
||||
private String realname;
|
||||
@Schema(description = "账号")
|
||||
private String username;
|
||||
@Schema(description = "头像")
|
||||
private String avatar;
|
||||
@Schema(description = "是否群主")
|
||||
private Boolean owner;
|
||||
}
|
||||
//update-end---author:cursor ---date:20260529 for:【IM聊天-OA】群设置-群成员展示-----------
|
||||
Reference in New Issue
Block a user