package cn.iocoder.yudao.module.im.dal.mysql.message; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.group.ImGroupMessageManagerPageReqVO; import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO; import cn.iocoder.yudao.module.im.enums.message.ImMessageReceiptStatusEnum; import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum; import org.apache.ibatis.annotations.Mapper; import java.time.LocalDateTime; import java.util.Collection; import java.util.List; /** * IM 群聊消息 Mapper * * @author 芋道源码 */ @Mapper public interface ImGroupMessageMapper extends BaseMapperX { /** * 根据 minId + 时间窗口增量拉取群聊消息 * * @param userId 当前用户编号 * @param groupIds 候选群编号集合(当前在群 ∪ 窗口内退群),不能为空 * @param minId 最小消息 id(不含) * @param minSendTime 最早发送时间(不含),限制离线消息时间窗口 * @param size 拉取数量 * @return 消息列表(按 id 升序) */ default List selectListByMinId(Long userId, Collection groupIds, Long minId, LocalDateTime minSendTime, Integer size) { QueryWrapperX wrapper = new QueryWrapperX<>(); wrapper.in("group_id", groupIds) .gt("id", minId) .gt("send_time", minSendTime) .apply(MyBatisUtils.findInSet("receiver_user_ids"), userId) .orderByAsc("id"); wrapper.limitN(size); return selectList(wrapper); } /** * 查询群聊历史消息(游标拉取) * * @param userId 当前用户编号 * @param groupId 群编号 * @param maxId 起始消息 id(不含),为空则从最新开始 * @param limit 拉取数量 * @return 消息列表(按 id 倒序) */ default List selectHistoryListByUser(Long userId, Long groupId, Long maxId, Integer limit) { QueryWrapperX wrapper = new QueryWrapperX<>(); wrapper.eq("group_id", groupId) .lt(maxId != null, "id", maxId) .apply(MyBatisUtils.findInSet("receiver_user_ids"), userId) .orderByDesc("id"); wrapper.limitN(limit); return selectList(wrapper); } default ImGroupMessageDO selectBySenderIdAndClientMessageId(Long senderId, String clientMessageId) { return selectOne(new LambdaQueryWrapperX() .eq(ImGroupMessageDO::getSenderId, senderId) .eq(ImGroupMessageDO::getClientMessageId, clientMessageId)); } /** * 查询群内指定范围内待回执的消息 *

* 仅在用户"已读位置前进"时调用,避免全量扫描: * 只有位于 (minId, maxId] 范围内、且仍处于 PENDING 的回执消息可能因本次已读而状态变化。 * * @param groupId 群编号 * @param minId 起始消息 id(不含,上一次已读位置) * @param maxId 结束消息 id(含,本次已读位置) * @return 待回执消息列表 */ default List selectListByGroupIdAndPendingReceipt(Long groupId, Long minId, Long maxId) { return selectList(new LambdaQueryWrapperX() .eq(ImGroupMessageDO::getGroupId, groupId) .eq(ImGroupMessageDO::getReceiptStatus, ImMessageReceiptStatusEnum.PENDING.getStatus()) .gt(minId != null, ImGroupMessageDO::getId, minId) .le(ImGroupMessageDO::getId, maxId) .ne(ImGroupMessageDO::getStatus, ImMessageStatusEnum.RECALL.getStatus())); } default PageResult selectPage(ImGroupMessageManagerPageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .eqIfPresent(ImGroupMessageDO::getGroupId, reqVO.getGroupId()) .eqIfPresent(ImGroupMessageDO::getSenderId, reqVO.getSenderId()) .eqIfPresent(ImGroupMessageDO::getType, reqVO.getType()) .likeIfPresent(ImGroupMessageDO::getContent, reqVO.getContent()) .eqIfPresent(ImGroupMessageDO::getStatus, reqVO.getStatus()) .betweenIfPresent(ImGroupMessageDO::getSendTime, reqVO.getSendTime()) .orderByDesc(ImGroupMessageDO::getId)); } }