This commit is contained in:
2025-12-22 13:08:08 +08:00
parent 85e4513284
commit f0a6e03989
26 changed files with 2023 additions and 627 deletions

View File

@@ -0,0 +1,42 @@
package org.xyzh.workcase.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.xyzh.api.workcase.constant.WorkcaseConstant;
import org.xyzh.workcase.listener.ChatMessageListener;
/**
* @description Redis Pub/Sub订阅配置
* @filename RedisSubscriberConfig.java
* @author cascade
* @copyright xyzh
* @since 2025-12-22
*/
@Configuration
public class RedisSubscriberConfig {
@Autowired
private ChatMessageListener chatMessageListener;
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
// 订阅聊天室消息频道,使用通配符匹配所有聊天室
// 频道格式: chat:room:*
container.addMessageListener(chatMessageListener,
new PatternTopic(WorkcaseConstant.REDIS_CHAT_PREFIX + "*"));
// 订阅聊天室列表更新频道
container.addMessageListener(chatMessageListener,
new PatternTopic(WorkcaseConstant.REDIS_CHAT_LIST_UPDATE));
return container;
}
}

View File

@@ -0,0 +1,63 @@
package org.xyzh.workcase.listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson2.JSON;
import org.xyzh.api.workcase.constant.WorkcaseConstant;
import org.xyzh.api.workcase.dto.TbChatRoomMessageDTO;
/**
* @description 聊天消息Redis监听器接收Pub/Sub消息并通过STOMP转发到WebSocket客户端
* @filename ChatMessageListener.java
* @author cascade
* @copyright xyzh
* @since 2025-12-22
*/
@Component
public class ChatMessageListener implements MessageListener {
private static final Logger logger = LoggerFactory.getLogger(ChatMessageListener.class);
@Autowired(required = false)
private SimpMessagingTemplate messagingTemplate;
@Override
public void onMessage(Message message, byte[] pattern) {
try {
String channel = new String(message.getChannel());
String body = new String(message.getBody());
logger.debug("收到Redis消息: channel={}", channel);
// 反序列化消息
TbChatRoomMessageDTO chatMessage = JSON.parseObject(body, TbChatRoomMessageDTO.class);
if (messagingTemplate == null) {
logger.warn("SimpMessagingTemplate未初始化无法转发消息");
return;
}
// 处理聊天室消息频道: chat:room:{roomId}
if (channel.startsWith(WorkcaseConstant.REDIS_CHAT_PREFIX)) {
String roomId = channel.substring(WorkcaseConstant.REDIS_CHAT_PREFIX.length());
// 转发到聊天窗口订阅者
messagingTemplate.convertAndSend("/topic/chat/" + roomId, chatMessage);
logger.debug("消息已转发到STOMP: /topic/chat/{}", roomId);
}
// 处理列表更新频道: chat:list:update
else if (WorkcaseConstant.REDIS_CHAT_LIST_UPDATE.equals(channel)) {
// 转发到聊天室列表订阅者,前端刷新列表状态
messagingTemplate.convertAndSend("/topic/chat/list-update", chatMessage);
logger.debug("列表更新已转发到STOMP: /topic/chat/list-update");
}
} catch (Exception e) {
logger.error("处理Redis消息失败", e);
}
}
}

View File

@@ -4,8 +4,8 @@ import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.xyzh.api.workcase.dto.TbChatMessageDTO;
import org.xyzh.api.workcase.vo.ChatMessageVO;
import org.xyzh.api.workcase.dto.TbChatRoomMessageDTO;
import org.xyzh.api.workcase.vo.ChatRoomMessageVO;
import org.xyzh.common.core.page.PageParam;
/**
@@ -21,36 +21,36 @@ public interface TbChatMessageMapper {
/**
* 插入聊天消息
*/
int insertChatMessage(TbChatMessageDTO message);
int insertChatMessage(TbChatRoomMessageDTO message);
/**
* 更新聊天消息只更新非null字段
*/
int updateChatMessage(TbChatMessageDTO message);
int updateChatMessage(TbChatRoomMessageDTO message);
/**
* 删除聊天消息
*/
int deleteChatMessage(TbChatMessageDTO message);
int deleteChatMessage(TbChatRoomMessageDTO message);
/**
* 根据ID查询聊天消息
*/
TbChatMessageDTO selectChatMessageById(@Param("messageId") String messageId);
TbChatRoomMessageDTO selectChatMessageById(@Param("messageId") String messageId);
/**
* 查询聊天消息列表
*/
List<ChatMessageVO> selectChatMessageList(@Param("filter") TbChatMessageDTO filter);
List<ChatRoomMessageVO> selectChatMessageList(@Param("filter") TbChatRoomMessageDTO filter);
/**
* 分页查询聊天消息
*/
List<ChatMessageVO> selectChatMessagePage(@Param("filter") TbChatMessageDTO filter, @Param("pageParam") PageParam pageParam);
List<ChatRoomMessageVO> selectChatMessagePage(@Param("filter") TbChatRoomMessageDTO filter, @Param("pageParam") PageParam pageParam);
/**
* 统计聊天消息数量
*/
long countChatMessages(@Param("filter") TbChatMessageDTO filter);
long countChatMessages(@Param("filter") TbChatRoomMessageDTO filter);
}

View File

@@ -0,0 +1,628 @@
package org.xyzh.workcase.service;
import java.util.Date;
import java.util.List;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.xyzh.common.redis.service.RedisService;
import org.springframework.transaction.annotation.Transactional;
import org.xyzh.api.workcase.dto.TbChatRoomMessageDTO;
import org.xyzh.api.workcase.dto.TbChatRoomDTO;
import org.xyzh.api.workcase.dto.TbChatRoomMemberDTO;
import org.xyzh.api.workcase.dto.TbCustomerServiceDTO;
import org.xyzh.api.workcase.service.ChatRoomService;
import org.xyzh.api.workcase.vo.ChatMemberVO;
import org.xyzh.api.workcase.vo.ChatRoomMessageVO;
import org.xyzh.api.workcase.vo.ChatRoomVO;
import org.xyzh.api.workcase.vo.CustomerServiceVO;
import org.xyzh.api.workcase.constant.WorkcaseConstant;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageDomain;
import org.xyzh.common.core.page.PageParam;
import org.xyzh.common.core.page.PageRequest;
import org.xyzh.common.utils.id.IdUtil;
import org.xyzh.workcase.mapper.TbChatMessageMapper;
import org.xyzh.workcase.mapper.TbChatRoomMapper;
import org.xyzh.workcase.mapper.TbChatRoomMemberMapper;
import org.xyzh.workcase.mapper.TbCustomerServiceMapper;
/**
* @description 聊天室服务实现类
* @filename ChatRoomServiceImpl.java
* @author cascade
* @copyright xyzh
* @since 2025-12-22
*/
@DubboService(version = "1.0.0", group = "workcase", timeout = 30000, retries = 0)
public class ChatRoomServiceImpl implements ChatRoomService {
private static final Logger logger = LoggerFactory.getLogger(ChatRoomServiceImpl.class);
@Autowired
private TbChatRoomMapper chatRoomMapper;
@Autowired
private TbChatRoomMemberMapper chatRoomMemberMapper;
@Autowired
private TbChatMessageMapper chatMessageMapper;
@Autowired
private TbCustomerServiceMapper customerServiceMapper;
@Autowired
private RedisService redisService;
// ========================= 聊天室管理 ==========================
@Override
@Transactional
public ResultDomain<TbChatRoomDTO> createChatRoom(TbChatRoomDTO chatRoom) {
logger.info("创建聊天室: workcaseId={}, roomType={}", chatRoom.getWorkcaseId(), chatRoom.getRoomType());
// 一个工单只能创建一个聊天室
if (chatRoom.getWorkcaseId() != null && !chatRoom.getWorkcaseId().isEmpty()) {
TbChatRoomDTO filter = new TbChatRoomDTO();
filter.setWorkcaseId(chatRoom.getWorkcaseId());
List<ChatRoomVO> existingRooms = chatRoomMapper.selectChatRoomList(filter);
if (existingRooms != null && !existingRooms.isEmpty()) {
return ResultDomain.failure("该工单已存在聊天室");
}
}
if (chatRoom.getRoomId() == null || chatRoom.getRoomId().isEmpty()) {
chatRoom.setRoomId(IdUtil.generateUUID());
}
if (chatRoom.getOptsn() == null || chatRoom.getOptsn().isEmpty()) {
chatRoom.setOptsn(IdUtil.getOptsn());
}
if (chatRoom.getStatus() == null || chatRoom.getStatus().isEmpty()) {
chatRoom.setStatus("active");
}
int rows = chatRoomMapper.insertChatRoom(chatRoom);
if (rows > 0) {
logger.info("聊天室创建成功: roomId={}", chatRoom.getRoomId());
// 添加来客到成员表
if (chatRoom.getGuestId() != null && !chatRoom.getGuestId().isEmpty()) {
TbChatRoomMemberDTO guestMember = new TbChatRoomMemberDTO();
guestMember.setMemberId(IdUtil.generateUUID());
guestMember.setOptsn(IdUtil.getOptsn());
guestMember.setRoomId(chatRoom.getRoomId());
guestMember.setUserId(chatRoom.getGuestId());
guestMember.setUserName(chatRoom.getGuestName());
guestMember.setUserType("guest");
guestMember.setStatus("active");
guestMember.setJoinTime(new Date());
guestMember.setUnreadCount(0);
chatRoomMemberMapper.insertChatRoomMember(guestMember);
}
// 自动分配客服并添加到成员表
ResultDomain<CustomerServiceVO> assignResult = assignCustomerService(chatRoom.getRoomId());
if (Boolean.TRUE.equals(assignResult.getSuccess()) && assignResult.getData() != null) {
// 更新聊天室当前客服ID
TbChatRoomDTO updateRoom = new TbChatRoomDTO();
updateRoom.setRoomId(chatRoom.getRoomId());
updateRoom.setCurrentAgentId(assignResult.getData().getUserId());
chatRoomMapper.updateChatRoom(updateRoom);
}
return ResultDomain.success("创建成功", chatRoom);
}
return ResultDomain.failure("创建失败");
}
@Override
public ResultDomain<TbChatRoomDTO> updateChatRoom(TbChatRoomDTO chatRoom) {
logger.info("更新聊天室: roomId={}", chatRoom.getRoomId());
TbChatRoomDTO existing = chatRoomMapper.selectChatRoomById(chatRoom.getRoomId());
if (existing == null) {
return ResultDomain.failure("聊天室不存在");
}
int rows = chatRoomMapper.updateChatRoom(chatRoom);
if (rows > 0) {
TbChatRoomDTO updated = chatRoomMapper.selectChatRoomById(chatRoom.getRoomId());
return ResultDomain.success("更新成功", updated);
}
return ResultDomain.failure("更新失败");
}
@Override
public ResultDomain<Boolean> closeChatRoom(String roomId, String closedBy) {
logger.info("关闭聊天室: roomId={}, closedBy={}", roomId, closedBy);
TbChatRoomDTO existing = chatRoomMapper.selectChatRoomById(roomId);
if (existing == null) {
return ResultDomain.failure("聊天室不存在");
}
TbChatRoomDTO chatRoom = new TbChatRoomDTO();
chatRoom.setRoomId(roomId);
chatRoom.setStatus("closed");
chatRoom.setClosedBy(closedBy);
chatRoom.setClosedTime(new Date());
int rows = chatRoomMapper.updateChatRoom(chatRoom);
if (rows > 0) {
// 清理Redis中的在线用户
String onlineUsersKey = WorkcaseConstant.REDIS_CHAT_ONLINE + roomId;
redisService.delete(onlineUsersKey);
return ResultDomain.success("关闭成功", true);
}
return ResultDomain.failure("关闭失败");
}
@Override
public ResultDomain<Boolean> deleteChatRoom(String roomId) {
logger.info("删除聊天室: roomId={}", roomId);
TbChatRoomDTO existing = chatRoomMapper.selectChatRoomById(roomId);
if (existing == null) {
return ResultDomain.failure("聊天室不存在");
}
TbChatRoomDTO chatRoom = new TbChatRoomDTO();
chatRoom.setRoomId(roomId);
int rows = chatRoomMapper.deleteChatRoom(chatRoom);
if (rows > 0) {
return ResultDomain.success("删除成功", true);
}
return ResultDomain.failure("删除失败");
}
@Override
public ResultDomain<TbChatRoomDTO> getChatRoomById(String roomId) {
TbChatRoomDTO chatRoom = chatRoomMapper.selectChatRoomById(roomId);
if (chatRoom != null) {
return ResultDomain.success("查询聊天室成功", chatRoom);
}
return ResultDomain.failure("聊天室不存在");
}
@Override
public ResultDomain<ChatRoomVO> getChatRoomPage(PageRequest<TbChatRoomDTO> pageRequest) {
TbChatRoomDTO filter = pageRequest.getFilter();
if (filter == null) {
filter = new TbChatRoomDTO();
}
PageParam pageParam = pageRequest.getPageParam();
List<ChatRoomVO> list = chatRoomMapper.selectChatRoomPage(filter, pageParam);
long total = chatRoomMapper.countChatRooms(filter);
pageParam.setTotal((int)total);
PageDomain<ChatRoomVO> pageDomain = new PageDomain<>(pageParam, list);
return ResultDomain.success("查询聊天室成功", pageDomain);
}
// ========================= 聊天室成员管理 ==========================
@Override
public ResultDomain<TbChatRoomMemberDTO> addChatRoomMember(TbChatRoomMemberDTO member) {
logger.info("添加聊天室成员: roomId={}, userId={}", member.getRoomId(), member.getUserId());
// 检查聊天室是否存在
TbChatRoomDTO room = chatRoomMapper.selectChatRoomById(member.getRoomId());
if (room == null) {
return ResultDomain.failure("聊天室不存在");
}
// 检查是否已是成员
TbChatRoomMemberDTO filter = new TbChatRoomMemberDTO();
filter.setRoomId(member.getRoomId());
filter.setUserId(member.getUserId());
List<ChatMemberVO> existingMembers = chatRoomMemberMapper.selectChatRoomMemberList(filter);
if (existingMembers != null && !existingMembers.isEmpty()) {
return ResultDomain.failure("用户已是聊天室成员");
}
if (member.getMemberId() == null || member.getMemberId().isEmpty()) {
member.setMemberId(IdUtil.generateUUID());
}
if (member.getOptsn() == null || member.getOptsn().isEmpty()) {
member.setOptsn(IdUtil.getOptsn());
}
if (member.getStatus() == null || member.getStatus().isEmpty()) {
member.setStatus("active");
}
member.setJoinTime(new Date());
int rows = chatRoomMemberMapper.insertChatRoomMember(member);
if (rows > 0) {
// 更新聊天室成员数
TbChatRoomDTO updateRoom = new TbChatRoomDTO();
updateRoom.setRoomId(member.getRoomId());
updateRoom.setAgentCount(room.getAgentCount() != null ? room.getAgentCount() + 1 : 1);
chatRoomMapper.updateChatRoom(updateRoom);
return ResultDomain.success("添加成功", member);
}
return ResultDomain.failure("添加失败");
}
@Override
public ResultDomain<Boolean> removeChatRoomMember(String memberId) {
logger.info("移除聊天室成员: memberId={}", memberId);
TbChatRoomMemberDTO existing = chatRoomMemberMapper.selectChatRoomMemberById(memberId);
if (existing == null) {
return ResultDomain.failure("成员不存在");
}
TbChatRoomMemberDTO member = new TbChatRoomMemberDTO();
member.setMemberId(memberId);
int rows = chatRoomMemberMapper.deleteChatRoomMember(member);
if (rows > 0) {
// 更新聊天室成员数
TbChatRoomDTO room = chatRoomMapper.selectChatRoomById(existing.getRoomId());
if (room != null && room.getAgentCount() != null && room.getAgentCount() > 0) {
TbChatRoomDTO updateRoom = new TbChatRoomDTO();
updateRoom.setRoomId(existing.getRoomId());
updateRoom.setAgentCount(room.getAgentCount() - 1);
chatRoomMapper.updateChatRoom(updateRoom);
}
// 从Redis移除在线状态
String onlineUsersKey = WorkcaseConstant.REDIS_CHAT_ONLINE + existing.getRoomId();
redisService.sRemove(onlineUsersKey, existing.getUserId());
return ResultDomain.success("移除成功", true);
}
return ResultDomain.failure("移除失败");
}
@Override
public ResultDomain<TbChatRoomMemberDTO> updateChatRoomMember(TbChatRoomMemberDTO member) {
logger.info("更新聊天室成员: memberId={}", member.getMemberId());
TbChatRoomMemberDTO existing = chatRoomMemberMapper.selectChatRoomMemberById(member.getMemberId());
if (existing == null) {
return ResultDomain.failure("成员不存在");
}
int rows = chatRoomMemberMapper.updateChatRoomMember(member);
if (rows > 0) {
TbChatRoomMemberDTO updated = chatRoomMemberMapper.selectChatRoomMemberById(member.getMemberId());
return ResultDomain.success("更新成功", updated);
}
return ResultDomain.failure("更新失败");
}
@Override
public ResultDomain<ChatMemberVO> getChatRoomMemberList(String roomId) {
TbChatRoomMemberDTO filter = new TbChatRoomMemberDTO();
filter.setRoomId(roomId);
List<ChatMemberVO> list = chatRoomMemberMapper.selectChatRoomMemberList(filter);
return ResultDomain.success("查询成功", list);
}
@Override
public ResultDomain<Boolean> updateMemberReadStatus(String memberId, String lastReadMsgId) {
logger.info("更新已读状态: memberId={}, lastReadMsgId={}", memberId, lastReadMsgId);
TbChatRoomMemberDTO member = new TbChatRoomMemberDTO();
member.setMemberId(memberId);
member.setLastReadMsgId(lastReadMsgId);
member.setLastReadTime(new Date());
int rows = chatRoomMemberMapper.updateChatRoomMember(member);
if (rows > 0) {
return ResultDomain.success("更新成功", true);
}
return ResultDomain.failure("更新失败");
}
// ========================= 聊天消息管理 ==========================
@Override
public ResultDomain<TbChatRoomMessageDTO> sendMessage(TbChatRoomMessageDTO message) {
logger.info("发送消息: roomId={}, senderId={}, messageType={}",
message.getRoomId(), message.getSenderId(), message.getMessageType());
// 检查聊天室是否存在
TbChatRoomDTO room = chatRoomMapper.selectChatRoomById(message.getRoomId());
if (room == null) {
return ResultDomain.failure("聊天室不存在");
}
if ("closed".equals(room.getStatus())) {
return ResultDomain.failure("聊天室已关闭");
}
if (message.getMessageId() == null || message.getMessageId().isEmpty()) {
message.setMessageId(IdUtil.generateUUID());
}
if (message.getOptsn() == null || message.getOptsn().isEmpty()) {
message.setOptsn(IdUtil.getOptsn());
}
if (message.getStatus() == null || message.getStatus().isEmpty()) {
message.setStatus("sent");
}
// 使用Redis保证消息时间戳递增避免并发乱序
String lockKey = WorkcaseConstant.REDIS_CHAT_LOCK + message.getRoomId();
String timeKey = WorkcaseConstant.REDIS_CHAT_LASTTIME + message.getRoomId();
try {
// 获取分布式锁简单实现SETNX + 过期时间)
int maxRetry = 10;
int retry = 0;
while (retry < maxRetry) {
Boolean locked = redisService.setIfAbsent(lockKey, "1", 5);
if (Boolean.TRUE.equals(locked)) {
break;
}
retry++;
Thread.sleep(50);
}
if (retry >= maxRetry) {
return ResultDomain.failure("消息发送繁忙,请稍后重试");
}
// 获取上一条消息的时间戳,确保时间递增
long currentTime = System.currentTimeMillis();
Object lastTimeObj = redisService.get(timeKey);
if (lastTimeObj != null) {
long lastTime = Long.parseLong(lastTimeObj.toString());
if (currentTime <= lastTime) {
currentTime = lastTime + 1;
}
}
message.setSendTime(new Date(currentTime));
// 更新Redis中的最后消息时间
redisService.set(timeKey, String.valueOf(currentTime));
int rows = chatMessageMapper.insertChatMessage(message);
if (rows > 0) {
// 更新聊天室最后消息信息
TbChatRoomDTO updateRoom = new TbChatRoomDTO();
updateRoom.setRoomId(message.getRoomId());
updateRoom.setLastMessage(message.getContent());
updateRoom.setLastMessageTime(message.getSendTime());
updateRoom.setMessageCount(room.getMessageCount() != null ? room.getMessageCount() + 1 : 1);
chatRoomMapper.updateChatRoom(updateRoom);
// 发布消息到Redis Pub/Sub聊天窗口
publishMessageToRedis(message);
// 发布列表更新通知(聊天室列表)
publishListUpdateToRedis(message);
return ResultDomain.success("发送成功", message);
}
return ResultDomain.failure("发送失败");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return ResultDomain.failure("消息发送被中断");
} finally {
// 释放锁
redisService.delete(lockKey);
}
}
@Override
public ResultDomain<ChatRoomMessageVO> getChatMessagePage(PageRequest<TbChatRoomMessageDTO> pageRequest) {
TbChatRoomMessageDTO filter = pageRequest.getFilter();
if (filter == null) {
filter = new TbChatRoomMessageDTO();
}
PageParam pageParam = pageRequest.getPageParam();
List<ChatRoomMessageVO> list = chatMessageMapper.selectChatMessagePage(filter, pageParam);
long total = chatMessageMapper.countChatMessages(filter);
pageParam.setTotal((int) total);
PageDomain<ChatRoomMessageVO> pageDomain = new PageDomain<>(pageParam, list);
return ResultDomain.success("查询成功", pageDomain);
}
@Override
public ResultDomain<Boolean> deleteMessage(String messageId) {
logger.info("删除消息: messageId={}", messageId);
TbChatRoomMessageDTO existing = chatMessageMapper.selectChatMessageById(messageId);
if (existing == null) {
return ResultDomain.failure("消息不存在");
}
TbChatRoomMessageDTO message = new TbChatRoomMessageDTO();
message.setMessageId(messageId);
int rows = chatMessageMapper.deleteChatMessage(message);
if (rows > 0) {
return ResultDomain.success("删除成功", true);
}
return ResultDomain.failure("删除失败");
}
// ========================= 客服人员管理 ==========================
@Override
public ResultDomain<TbCustomerServiceDTO> addCustomerService(TbCustomerServiceDTO customerService) {
logger.info("添加客服人员: userId={}, username={}", customerService.getUserId(), customerService.getUsername());
// 检查是否已存在
TbCustomerServiceDTO existing = customerServiceMapper.selectCustomerServiceById(customerService.getUserId());
if (existing != null) {
return ResultDomain.failure("该员工已是客服人员");
}
if (customerService.getOptsn() == null || customerService.getOptsn().isEmpty()) {
customerService.setOptsn(IdUtil.getOptsn());
}
if (customerService.getStatus() == null || customerService.getStatus().isEmpty()) {
customerService.setStatus("offline");
}
if (customerService.getMaxConcurrent() == null) {
customerService.setMaxConcurrent(5);
}
if (customerService.getCurrentWorkload() == null) {
customerService.setCurrentWorkload(0);
}
int rows = customerServiceMapper.insertCustomerService(customerService);
if (rows > 0) {
return ResultDomain.success("添加成功", customerService);
}
return ResultDomain.failure("添加失败");
}
@Override
public ResultDomain<TbCustomerServiceDTO> updateCustomerService(TbCustomerServiceDTO customerService) {
logger.info("更新客服人员: userId={}", customerService.getUserId());
TbCustomerServiceDTO existing = customerServiceMapper.selectCustomerServiceById(customerService.getUserId());
if (existing == null) {
return ResultDomain.failure("客服人员不存在");
}
int rows = customerServiceMapper.updateCustomerService(customerService);
if (rows > 0) {
TbCustomerServiceDTO updated = customerServiceMapper.selectCustomerServiceById(customerService.getUserId());
return ResultDomain.success("更新成功", updated);
}
return ResultDomain.failure("更新失败");
}
@Override
public ResultDomain<Boolean> deleteCustomerService(String userId) {
logger.info("删除客服人员: userId={}", userId);
TbCustomerServiceDTO existing = customerServiceMapper.selectCustomerServiceById(userId);
if (existing == null) {
return ResultDomain.failure("客服人员不存在");
}
TbCustomerServiceDTO customerService = new TbCustomerServiceDTO();
customerService.setUserId(userId);
int rows = customerServiceMapper.deleteCustomerService(customerService);
if (rows > 0) {
return ResultDomain.success("删除成功", true);
}
return ResultDomain.failure("删除失败");
}
@Override
public ResultDomain<CustomerServiceVO> getCustomerServicePage(PageRequest<TbCustomerServiceDTO> pageRequest) {
TbCustomerServiceDTO filter = pageRequest.getFilter();
if (filter == null) {
filter = new TbCustomerServiceDTO();
}
PageParam pageParam = pageRequest.getPageParam();
List<CustomerServiceVO> list = customerServiceMapper.selectCustomerServicePage(filter, pageParam);
long total = customerServiceMapper.countCustomerServices(filter);
pageParam.setTotal((int) total);
PageDomain<CustomerServiceVO> pageDomain = new PageDomain<>(pageParam, list);
return ResultDomain.success("查询成功", pageDomain);
}
@Override
public ResultDomain<Boolean> updateCustomerServiceStatus(String userId, String status) {
logger.info("更新客服状态: userId={}, status={}", userId, status);
TbCustomerServiceDTO customerService = new TbCustomerServiceDTO();
customerService.setUserId(userId);
customerService.setStatus(status);
int rows = customerServiceMapper.updateCustomerService(customerService);
if (rows > 0) {
return ResultDomain.success("更新成功", true);
}
return ResultDomain.failure("更新失败");
}
@Override
public ResultDomain<CustomerServiceVO> getAvailableCustomerServices() {
TbCustomerServiceDTO filter = new TbCustomerServiceDTO();
filter.setStatus("online");
List<CustomerServiceVO> list = customerServiceMapper.selectCustomerServiceList(filter);
// 过滤工作量未满的客服
List<CustomerServiceVO> availableList = list.stream()
.filter(cs -> cs.getCurrentWorkload() == null ||
cs.getMaxConcurrent() == null ||
cs.getCurrentWorkload() < cs.getMaxConcurrent())
.toList();
return ResultDomain.success("查询成功", availableList);
}
@Override
@Transactional
public ResultDomain<CustomerServiceVO> assignCustomerService(String roomId) {
logger.info("分配所有客服到聊天室: roomId={}", roomId);
// 获取所有在线客服列表
TbCustomerServiceDTO filter = new TbCustomerServiceDTO();
filter.setStatus("online");
List<CustomerServiceVO> allServices = customerServiceMapper.selectCustomerServiceList(filter);
if (allServices == null || allServices.isEmpty()) {
return ResultDomain.failure("当前没有在线的客服人员");
}
// 把所有客服都加入聊天室
int addedCount = 0;
for (CustomerServiceVO service : allServices) {
TbChatRoomMemberDTO member = new TbChatRoomMemberDTO();
member.setMemberId(IdUtil.generateUUID());
member.setOptsn(IdUtil.getOptsn());
member.setRoomId(roomId);
member.setUserId(service.getUserId());
member.setUserType("staff");
member.setUserName(service.getUsername());
member.setStatus("active");
member.setJoinTime(new Date());
member.setUnreadCount(0);
chatRoomMemberMapper.insertChatRoomMember(member);
// 更新客服工作量
TbCustomerServiceDTO updateService = new TbCustomerServiceDTO();
updateService.setUserId(service.getUserId());
updateService.setCurrentWorkload(
(service.getCurrentWorkload() != null ? service.getCurrentWorkload() : 0) + 1);
customerServiceMapper.updateCustomerService(updateService);
addedCount++;
}
// 更新聊天室客服人数
TbChatRoomDTO updateRoom = new TbChatRoomDTO();
updateRoom.setRoomId(roomId);
updateRoom.setAgentCount(addedCount);
chatRoomMapper.updateChatRoom(updateRoom);
logger.info("已添加{}名客服到聊天室: roomId={}", addedCount, roomId);
return ResultDomain.success("分配成功,共添加" + addedCount + "名客服", allServices.get(0));
}
// ========================= 私有方法 ==========================
private void publishMessageToRedis(TbChatRoomMessageDTO message) {
try {
String channel = WorkcaseConstant.REDIS_CHAT_PREFIX + message.getRoomId();
// RedisService内部已配置FastJson2JsonRedisSerializer会自动序列化
redisService.publish(channel, message);
logger.debug("消息已发布到Redis频道: {}", channel);
} catch (Exception e) {
logger.error("发布消息到Redis失败", e);
}
}
private void publishListUpdateToRedis(TbChatRoomMessageDTO message) {
try {
// 发布到列表更新频道,前端订阅此频道刷新聊天室列表
redisService.publish(WorkcaseConstant.REDIS_CHAT_LIST_UPDATE, message);
logger.debug("列表更新已发布到Redis频道: {}", WorkcaseConstant.REDIS_CHAT_LIST_UPDATE);
} catch (Exception e) {
logger.error("发布列表更新到Redis失败", e);
}
}
}

View File

@@ -0,0 +1,450 @@
package org.xyzh.workcase.service;
import java.util.Date;
import java.util.List;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.xyzh.api.workcase.dto.TbVideoMeetingDTO;
import org.xyzh.api.workcase.dto.TbMeetingParticipantDTO;
import org.xyzh.api.workcase.dto.TbMeetingTranscriptionDTO;
import org.xyzh.api.workcase.service.MeetService;
import org.xyzh.api.workcase.vo.VideoMeetingVO;
import org.xyzh.api.workcase.vo.MeetingParticipantVO;
import org.xyzh.api.workcase.vo.MeetingTranscriptionVO;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageDomain;
import org.xyzh.common.core.page.PageParam;
import org.xyzh.common.core.page.PageRequest;
import org.xyzh.common.utils.id.IdUtil;
import org.xyzh.workcase.mapper.TbVideoMeetingMapper;
import org.xyzh.workcase.mapper.TbMeetingParticipantMapper;
import org.xyzh.workcase.mapper.TbMeetingTranscriptionMapper;
/**
* @description 视频会议服务实现类(伪代码)
* @filename MeetServiceImpl.java
* @author cascade
* @copyright xyzh
* @since 2025-12-22
*/
@DubboService(version = "1.0.0", group = "workcase", timeout = 30000, retries = 0)
public class MeetServiceImpl implements MeetService {
private static final Logger logger = LoggerFactory.getLogger(MeetServiceImpl.class);
@Autowired
private TbVideoMeetingMapper videoMeetingMapper;
@Autowired
private TbMeetingParticipantMapper meetingParticipantMapper;
@Autowired
private TbMeetingTranscriptionMapper meetingTranscriptionMapper;
// TODO: 注入Jitsi配置和JWT工具类
// @Autowired
// private JitsiConfig jitsiConfig;
// @Autowired
// private JwtTokenUtil jwtTokenUtil;
// ========================= 会议管理 ==========================
@Override
@Transactional
public ResultDomain<TbVideoMeetingDTO> createMeeting(TbVideoMeetingDTO meeting) {
logger.info("创建会议: roomId={}, meetingName={}", meeting.getRoomId(), meeting.getMeetingName());
// TODO: 生成唯一的Jitsi房间名
// String jitsiRoomName = "meet_" + IdUtil.generateUUID().replace("-", "");
if (meeting.getMeetingId() == null || meeting.getMeetingId().isEmpty()) {
meeting.setMeetingId(IdUtil.generateUUID());
}
if (meeting.getOptsn() == null || meeting.getOptsn().isEmpty()) {
meeting.setOptsn(IdUtil.getOptsn());
}
if (meeting.getStatus() == null || meeting.getStatus().isEmpty()) {
meeting.setStatus("scheduled");
}
// TODO: 设置Jitsi相关配置
// meeting.setJitsiRoomName(jitsiRoomName);
// meeting.setJitsiServerUrl(jitsiConfig.getServerUrl());
int rows = videoMeetingMapper.insertVideoMeeting(meeting);
if (rows > 0) {
logger.info("会议创建成功: meetingId={}", meeting.getMeetingId());
return ResultDomain.success("创建成功", meeting);
}
return ResultDomain.failure("创建失败");
}
@Override
public ResultDomain<TbVideoMeetingDTO> updateMeeting(TbVideoMeetingDTO meeting) {
logger.info("更新会议: meetingId={}", meeting.getMeetingId());
TbVideoMeetingDTO existing = videoMeetingMapper.selectVideoMeetingById(meeting.getMeetingId());
if (existing == null) {
return ResultDomain.failure("会议不存在");
}
int rows = videoMeetingMapper.updateVideoMeeting(meeting);
if (rows > 0) {
TbVideoMeetingDTO updated = videoMeetingMapper.selectVideoMeetingById(meeting.getMeetingId());
return ResultDomain.success("更新成功", updated);
}
return ResultDomain.failure("更新失败");
}
@Override
public ResultDomain<TbVideoMeetingDTO> startMeeting(String meetingId) {
logger.info("开始会议: meetingId={}", meetingId);
TbVideoMeetingDTO existing = videoMeetingMapper.selectVideoMeetingById(meetingId);
if (existing == null) {
return ResultDomain.failure("会议不存在");
}
if ("ongoing".equals(existing.getStatus())) {
return ResultDomain.failure("会议已在进行中");
}
TbVideoMeetingDTO meeting = new TbVideoMeetingDTO();
meeting.setMeetingId(meetingId);
meeting.setStatus("ongoing");
meeting.setActualStartTime(new Date());
int rows = videoMeetingMapper.updateVideoMeeting(meeting);
if (rows > 0) {
TbVideoMeetingDTO updated = videoMeetingMapper.selectVideoMeetingById(meetingId);
return ResultDomain.success("会议已开始", updated);
}
return ResultDomain.failure("开始会议失败");
}
@Override
public ResultDomain<TbVideoMeetingDTO> endMeeting(String meetingId) {
logger.info("结束会议: meetingId={}", meetingId);
TbVideoMeetingDTO existing = videoMeetingMapper.selectVideoMeetingById(meetingId);
if (existing == null) {
return ResultDomain.failure("会议不存在");
}
TbVideoMeetingDTO meeting = new TbVideoMeetingDTO();
meeting.setMeetingId(meetingId);
meeting.setStatus("ended");
meeting.setActualEndTime(new Date());
// TODO: 计算会议时长
// if (existing.getActualStartTime() != null) {
// long durationMs = new Date().getTime() - existing.getActualStartTime().getTime();
// meeting.setDurationSeconds((int)(durationMs / 1000));
// }
int rows = videoMeetingMapper.updateVideoMeeting(meeting);
if (rows > 0) {
// TODO: 更新所有参与者离开时间
// updateAllParticipantsLeaveTime(meetingId);
TbVideoMeetingDTO updated = videoMeetingMapper.selectVideoMeetingById(meetingId);
return ResultDomain.success("会议已结束", updated);
}
return ResultDomain.failure("结束会议失败");
}
@Override
public ResultDomain<Boolean> deleteMeeting(String meetingId) {
logger.info("删除会议: meetingId={}", meetingId);
TbVideoMeetingDTO existing = videoMeetingMapper.selectVideoMeetingById(meetingId);
if (existing == null) {
return ResultDomain.failure("会议不存在");
}
TbVideoMeetingDTO meeting = new TbVideoMeetingDTO();
meeting.setMeetingId(meetingId);
int rows = videoMeetingMapper.deleteVideoMeeting(meeting);
if (rows > 0) {
return ResultDomain.success("删除成功", true);
}
return ResultDomain.failure("删除失败");
}
@Override
public ResultDomain<TbVideoMeetingDTO> getMeetingById(String meetingId) {
TbVideoMeetingDTO meeting = videoMeetingMapper.selectVideoMeetingById(meetingId);
if (meeting != null) {
return ResultDomain.success("查询成功", meeting);
}
return ResultDomain.failure("会议不存在");
}
@Override
public ResultDomain<VideoMeetingVO> getMeetingPage(PageRequest<TbVideoMeetingDTO> pageRequest) {
TbVideoMeetingDTO filter = pageRequest.getFilter();
if (filter == null) {
filter = new TbVideoMeetingDTO();
}
PageParam pageParam = pageRequest.getPageParam();
List<VideoMeetingVO> list = videoMeetingMapper.selectVideoMeetingPage(filter, pageParam);
long total = videoMeetingMapper.countVideoMeetings(filter);
pageParam.setTotal((int) total);
PageDomain<VideoMeetingVO> pageDomain = new PageDomain<>(pageParam, list);
return ResultDomain.success("查询成功", pageDomain);
}
@Override
public ResultDomain<String> generateMeetingJoinUrl(String meetingId, String userId, String userName) {
logger.info("生成会议加入链接: meetingId={}, userId={}", meetingId, userId);
TbVideoMeetingDTO meeting = videoMeetingMapper.selectVideoMeetingById(meetingId);
if (meeting == null) {
return ResultDomain.failure("会议不存在");
}
// TODO: 生成Jitsi iframe URL
// String jwtToken = generateMeetingToken(meetingId, userId, false).getData();
// String baseUrl = meeting.getJitsiServerUrl();
// String roomName = meeting.getJitsiRoomName();
// String iframeUrl = String.format("%s/%s?jwt=%s#userInfo.displayName=%s",
// baseUrl, roomName, jwtToken, URLEncoder.encode(userName, "UTF-8"));
String iframeUrl = "TODO: 生成Jitsi iframe URL";
return ResultDomain.success("生成成功", iframeUrl);
}
@Override
public ResultDomain<String> generateMeetingToken(String meetingId, String userId, boolean isModerator) {
logger.info("生成会议JWT: meetingId={}, userId={}, isModerator={}", meetingId, userId, isModerator);
TbVideoMeetingDTO meeting = videoMeetingMapper.selectVideoMeetingById(meetingId);
if (meeting == null) {
return ResultDomain.failure("会议不存在");
}
// TODO: 使用Jitsi JWT规范生成Token
// JitsiTokenPayload payload = new JitsiTokenPayload();
// payload.setRoom(meeting.getJitsiRoomName());
// payload.setModerator(isModerator);
// payload.setUserId(userId);
// String token = jwtTokenUtil.generateJitsiToken(payload);
String token = "TODO: 生成Jitsi JWT Token";
return ResultDomain.success("生成成功", token);
}
// ========================= 参与者管理 ==========================
@Override
public ResultDomain<TbMeetingParticipantDTO> joinMeeting(TbMeetingParticipantDTO participant) {
logger.info("参与者加入会议: meetingId={}, userId={}", participant.getMeetingId(), participant.getUserId());
// 检查会议是否存在
TbVideoMeetingDTO meeting = videoMeetingMapper.selectVideoMeetingById(participant.getMeetingId());
if (meeting == null) {
return ResultDomain.failure("会议不存在");
}
if (participant.getParticipantId() == null || participant.getParticipantId().isEmpty()) {
participant.setParticipantId(IdUtil.generateUUID());
}
if (participant.getOptsn() == null || participant.getOptsn().isEmpty()) {
participant.setOptsn(IdUtil.getOptsn());
}
participant.setJoinTime(new Date());
int rows = meetingParticipantMapper.insertMeetingParticipant(participant);
if (rows > 0) {
// 更新会议参与人数
TbVideoMeetingDTO updateMeeting = new TbVideoMeetingDTO();
updateMeeting.setMeetingId(participant.getMeetingId());
updateMeeting.setParticipantCount(meeting.getParticipantCount() != null ? meeting.getParticipantCount() + 1 : 1);
videoMeetingMapper.updateVideoMeeting(updateMeeting);
return ResultDomain.success("加入成功", participant);
}
return ResultDomain.failure("加入失败");
}
@Override
public ResultDomain<Boolean> leaveMeeting(String participantId) {
logger.info("参与者离开会议: participantId={}", participantId);
TbMeetingParticipantDTO existing = meetingParticipantMapper.selectMeetingParticipantById(participantId);
if (existing == null) {
return ResultDomain.failure("参与者不存在");
}
TbMeetingParticipantDTO participant = new TbMeetingParticipantDTO();
participant.setParticipantId(participantId);
participant.setLeaveTime(new Date());
// TODO: 计算参与时长
// if (existing.getJoinTime() != null) {
// long durationMs = new Date().getTime() - existing.getJoinTime().getTime();
// participant.setDurationSeconds((int)(durationMs / 1000));
// }
int rows = meetingParticipantMapper.updateMeetingParticipant(participant);
if (rows > 0) {
return ResultDomain.success("离开成功", true);
}
return ResultDomain.failure("离开失败");
}
@Override
public ResultDomain<MeetingParticipantVO> getMeetingParticipantList(String meetingId) {
TbMeetingParticipantDTO filter = new TbMeetingParticipantDTO();
filter.setMeetingId(meetingId);
List<MeetingParticipantVO> list = meetingParticipantMapper.selectMeetingParticipantList(filter);
return ResultDomain.success("查询成功", list);
}
@Override
public ResultDomain<TbMeetingParticipantDTO> updateParticipant(TbMeetingParticipantDTO participant) {
logger.info("更新参与者: participantId={}", participant.getParticipantId());
TbMeetingParticipantDTO existing = meetingParticipantMapper.selectMeetingParticipantById(participant.getParticipantId());
if (existing == null) {
return ResultDomain.failure("参与者不存在");
}
int rows = meetingParticipantMapper.updateMeetingParticipant(participant);
if (rows > 0) {
TbMeetingParticipantDTO updated = meetingParticipantMapper.selectMeetingParticipantById(participant.getParticipantId());
return ResultDomain.success("更新成功", updated);
}
return ResultDomain.failure("更新失败");
}
@Override
public ResultDomain<Boolean> setModerator(String participantId, boolean isModerator) {
logger.info("设置主持人: participantId={}, isModerator={}", participantId, isModerator);
TbMeetingParticipantDTO participant = new TbMeetingParticipantDTO();
participant.setParticipantId(participantId);
participant.setIsModerator(isModerator);
int rows = meetingParticipantMapper.updateMeetingParticipant(participant);
if (rows > 0) {
return ResultDomain.success("设置成功", true);
}
return ResultDomain.failure("设置失败");
}
// ========================= 转录管理 ==========================
@Override
public ResultDomain<TbMeetingTranscriptionDTO> addTranscription(TbMeetingTranscriptionDTO transcription) {
logger.info("添加转录记录: meetingId={}, speakerId={}", transcription.getMeetingId(), transcription.getSpeakerId());
if (transcription.getTranscriptionId() == null || transcription.getTranscriptionId().isEmpty()) {
transcription.setTranscriptionId(IdUtil.generateUUID());
}
if (transcription.getOptsn() == null || transcription.getOptsn().isEmpty()) {
transcription.setOptsn(IdUtil.getOptsn());
}
int rows = meetingTranscriptionMapper.insertMeetingTranscription(transcription);
if (rows > 0) {
return ResultDomain.success("添加成功", transcription);
}
return ResultDomain.failure("添加失败");
}
@Override
public ResultDomain<MeetingTranscriptionVO> getTranscriptionPage(PageRequest<TbMeetingTranscriptionDTO> pageRequest) {
TbMeetingTranscriptionDTO filter = pageRequest.getFilter();
if (filter == null) {
filter = new TbMeetingTranscriptionDTO();
}
PageParam pageParam = pageRequest.getPageParam();
List<MeetingTranscriptionVO> list = meetingTranscriptionMapper.selectMeetingTranscriptionPage(filter, pageParam);
long total = meetingTranscriptionMapper.countMeetingTranscriptions(filter);
pageParam.setTotal((int) total);
PageDomain<MeetingTranscriptionVO> pageDomain = new PageDomain<>(pageParam, list);
return ResultDomain.success("查询成功", pageDomain);
}
@Override
public ResultDomain<String> getFullTranscriptionText(String meetingId) {
logger.info("获取完整转录文本: meetingId={}", meetingId);
TbMeetingTranscriptionDTO filter = new TbMeetingTranscriptionDTO();
filter.setMeetingId(meetingId);
filter.setIsFinal(true);
List<MeetingTranscriptionVO> list = meetingTranscriptionMapper.selectMeetingTranscriptionList(filter);
// TODO: 拼接转录文本
StringBuilder sb = new StringBuilder();
for (MeetingTranscriptionVO transcription : list) {
// 格式:[说话人名称] 内容
sb.append("[").append(transcription.getSpeakerName()).append("] ");
sb.append(transcription.getContent()).append("\n");
}
return ResultDomain.success("查询成功", sb.toString());
}
@Override
public ResultDomain<Boolean> deleteTranscription(String transcriptionId) {
logger.info("删除转录记录: transcriptionId={}", transcriptionId);
TbMeetingTranscriptionDTO existing = meetingTranscriptionMapper.selectMeetingTranscriptionById(transcriptionId);
if (existing == null) {
return ResultDomain.failure("转录记录不存在");
}
TbMeetingTranscriptionDTO transcription = new TbMeetingTranscriptionDTO();
transcription.setTranscriptionId(transcriptionId);
int rows = meetingTranscriptionMapper.deleteMeetingTranscription(transcription);
if (rows > 0) {
return ResultDomain.success("删除成功", true);
}
return ResultDomain.failure("删除失败");
}
// ========================= 会议统计 ==========================
@Override
public ResultDomain<VideoMeetingVO> getMeetingStatistics(String meetingId) {
logger.info("获取会议统计: meetingId={}", meetingId);
TbVideoMeetingDTO meeting = videoMeetingMapper.selectVideoMeetingById(meetingId);
if (meeting == null) {
return ResultDomain.failure("会议不存在");
}
// TODO: 查询并组装统计信息
// - 参与人数
// - 会议时长
// - 转录记录数
// - 各参与者参与时长等
TbMeetingParticipantDTO participantFilter = new TbMeetingParticipantDTO();
participantFilter.setMeetingId(meetingId);
List<MeetingParticipantVO> participants = meetingParticipantMapper.selectMeetingParticipantList(participantFilter);
VideoMeetingVO vo = new VideoMeetingVO();
vo.setMeetingId(meeting.getMeetingId());
vo.setMeetingName(meeting.getMeetingName());
vo.setStatus(meeting.getStatus());
vo.setParticipantCount(participants.size());
vo.setActualStartTime(meeting.getActualStartTime());
vo.setActualEndTime(meeting.getActualEndTime());
vo.setDurationSeconds(meeting.getDurationSeconds());
// TODO: 格式化时长
// if (meeting.getDurationSeconds() != null) {
// vo.setDurationFormatted(formatDuration(meeting.getDurationSeconds()));
// }
return ResultDomain.success("查询成功", vo);
}
}

View File

@@ -2,7 +2,7 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.xyzh.workcase.mapper.TbChatMessageMapper">
<resultMap id="BaseResultMap" type="org.xyzh.api.workcase.dto.TbChatMessageDTO">
<resultMap id="BaseResultMap" type="org.xyzh.api.workcase.dto.TbChatRoomMessageDTO">
<id column="message_id" property="messageId" jdbcType="VARCHAR"/>
<result column="optsn" property="optsn" jdbcType="VARCHAR"/>
<result column="room_id" property="roomId" jdbcType="VARCHAR"/>
@@ -24,7 +24,7 @@
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
</resultMap>
<resultMap id="VOResultMap" type="org.xyzh.api.workcase.vo.ChatMessageVO">
<resultMap id="VOResultMap" type="org.xyzh.api.workcase.vo.ChatRoomMessageVO">
<id column="message_id" property="messageId" jdbcType="VARCHAR"/>
<result column="optsn" property="optsn" jdbcType="VARCHAR"/>
<result column="room_id" property="roomId" jdbcType="VARCHAR"/>
@@ -52,8 +52,8 @@
status, read_count, send_time, creator, create_time, update_time
</sql>
<insert id="insertChatMessage" parameterType="org.xyzh.api.workcase.dto.TbChatMessageDTO">
INSERT INTO workcase.tb_chat_message (
<insert id="insertChatMessage" parameterType="org.xyzh.api.workcase.dto.TbChatRoomMessageDTO">
INSERT INTO workcase.tb_chat_room_message (
optsn, message_id, room_id, sender_id, sender_type, sender_name, content, creator
<if test="messageType != null">, message_type</if>
<if test="files != null">, files</if>
@@ -74,8 +74,8 @@
)
</insert>
<update id="updateChatMessage" parameterType="org.xyzh.api.workcase.dto.TbChatMessageDTO">
UPDATE workcase.tb_chat_message
<update id="updateChatMessage" parameterType="org.xyzh.api.workcase.dto.TbChatRoomMessageDTO">
UPDATE workcase.tb_chat_room_message
<set>
<if test="content != null">content = #{content},</if>
<if test="status != null and status != ''">status = #{status},</if>
@@ -85,20 +85,20 @@
WHERE message_id = #{messageId}
</update>
<delete id="deleteChatMessage" parameterType="org.xyzh.api.workcase.dto.TbChatMessageDTO">
DELETE FROM workcase.tb_chat_message
<delete id="deleteChatMessage" parameterType="org.xyzh.api.workcase.dto.TbChatRoomMessageDTO">
DELETE FROM workcase.tb_chat_room_message
WHERE message_id = #{messageId}
</delete>
<select id="selectChatMessageById" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List"/>
FROM workcase.tb_chat_message
FROM workcase.tb_chat_room_message
WHERE message_id = #{messageId}
</select>
<select id="selectChatMessageList" resultMap="VOResultMap">
SELECT <include refid="Base_Column_List"/>
FROM workcase.tb_chat_message
FROM workcase.tb_chat_room_message
<where>
<if test="filter.messageId != null and filter.messageId != ''">AND message_id = #{filter.messageId}</if>
<if test="filter.roomId != null and filter.roomId != ''">AND room_id = #{filter.roomId}</if>
@@ -113,7 +113,7 @@
<select id="selectChatMessagePage" resultMap="VOResultMap">
SELECT <include refid="Base_Column_List"/>
FROM workcase.tb_chat_message
FROM workcase.tb_chat_room_message
<where>
<if test="filter.messageId != null and filter.messageId != ''">AND message_id = #{filter.messageId}</if>
<if test="filter.roomId != null and filter.roomId != ''">AND room_id = #{filter.roomId}</if>
@@ -129,7 +129,7 @@
<select id="countChatMessages" resultType="long">
SELECT COUNT(*)
FROM workcase.tb_chat_message
FROM workcase.tb_chat_room_message
<where>
<if test="filter.messageId != null and filter.messageId != ''">AND message_id = #{filter.messageId}</if>
<if test="filter.roomId != null and filter.roomId != ''">AND room_id = #{filter.roomId}</if>

View File

@@ -9,7 +9,6 @@
<result column="user_id" property="userId" jdbcType="VARCHAR"/>
<result column="user_type" property="userType" jdbcType="VARCHAR"/>
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
<result column="role" property="role" jdbcType="VARCHAR"/>
<result column="status" property="status" jdbcType="VARCHAR"/>
<result column="unread_count" property="unreadCount" jdbcType="INTEGER"/>
<result column="last_read_time" property="lastReadTime" jdbcType="TIMESTAMP"/>
@@ -28,7 +27,6 @@
<result column="user_id" property="userId" jdbcType="VARCHAR"/>
<result column="user_type" property="userType" jdbcType="VARCHAR"/>
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
<result column="role" property="role" jdbcType="VARCHAR"/>
<result column="status" property="status" jdbcType="VARCHAR"/>
<result column="unread_count" property="unreadCount" jdbcType="INTEGER"/>
<result column="last_read_time" property="lastReadTime" jdbcType="TIMESTAMP"/>
@@ -41,7 +39,7 @@
</resultMap>
<sql id="Base_Column_List">
member_id, optsn, room_id, user_id, user_type, user_name, role, status,
member_id, optsn, room_id, user_id, user_type, user_name, status,
unread_count, last_read_time, last_read_msg_id, join_time, leave_time,
creator, create_time, update_time
</sql>
@@ -49,12 +47,10 @@
<insert id="insertChatRoomMember" parameterType="org.xyzh.api.workcase.dto.TbChatRoomMemberDTO">
INSERT INTO workcase.tb_chat_room_member (
optsn, member_id, room_id, user_id, user_type, user_name, creator
<if test="role != null">, role</if>
<if test="status != null">, status</if>
<if test="unreadCount != null">, unread_count</if>
) VALUES (
#{optsn}, #{memberId}, #{roomId}, #{userId}, #{userType}, #{userName}, #{creator}
<if test="role != null">, #{role}</if>
<if test="status != null">, #{status}</if>
<if test="unreadCount != null">, #{unreadCount}</if>
)
@@ -63,7 +59,6 @@
<update id="updateChatRoomMember" parameterType="org.xyzh.api.workcase.dto.TbChatRoomMemberDTO">
UPDATE workcase.tb_chat_room_member
<set>
<if test="role != null and role != ''">role = #{role},</if>
<if test="status != null and status != ''">status = #{status},</if>
<if test="unreadCount != null">unread_count = #{unreadCount},</if>
<if test="lastReadTime != null">last_read_time = #{lastReadTime},</if>
@@ -94,7 +89,6 @@
<if test="filter.userId != null and filter.userId != ''">AND user_id = #{filter.userId}</if>
<if test="filter.userType != null and filter.userType != ''">AND user_type = #{filter.userType}</if>
<if test="filter.userName != null and filter.userName != ''">AND user_name LIKE CONCAT('%', #{filter.userName}, '%')</if>
<if test="filter.role != null and filter.role != ''">AND role = #{filter.role}</if>
<if test="filter.status != null and filter.status != ''">AND status = #{filter.status}</if>
</where>
ORDER BY join_time DESC
@@ -109,7 +103,6 @@
<if test="filter.userId != null and filter.userId != ''">AND user_id = #{filter.userId}</if>
<if test="filter.userType != null and filter.userType != ''">AND user_type = #{filter.userType}</if>
<if test="filter.userName != null and filter.userName != ''">AND user_name LIKE CONCAT('%', #{filter.userName}, '%')</if>
<if test="filter.role != null and filter.role != ''">AND role = #{filter.role}</if>
<if test="filter.status != null and filter.status != ''">AND status = #{filter.status}</if>
</where>
ORDER BY join_time DESC
@@ -125,7 +118,6 @@
<if test="filter.userId != null and filter.userId != ''">AND user_id = #{filter.userId}</if>
<if test="filter.userType != null and filter.userType != ''">AND user_type = #{filter.userType}</if>
<if test="filter.userName != null and filter.userName != ''">AND user_name LIKE CONCAT('%', #{filter.userName}, '%')</if>
<if test="filter.role != null and filter.role != ''">AND role = #{filter.role}</if>
<if test="filter.status != null and filter.status != ''">AND status = #{filter.status}</if>
</where>
</select>