diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/ImConversationController.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/ImConversationController.java deleted file mode 100755 index 9f8c3a4..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/ImConversationController.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.iocoder.yudao.module.im.controller.admin.conversation; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationCreateReqVO; -import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationUpdateLastReadTimeReqVO; -import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationRespVO; -import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationUpdatePinnedReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationDO; -import cn.iocoder.yudao.module.im.service.conversation.ImConversationService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; - -@Tag(name = "管理后台 - IM 会话") -@RestController -@RequestMapping("/im/conversation") -@Validated -public class ImConversationController { - - @Resource - private ImConversationService imConversationService; - - // TODO @芋艿:头像和昵称的聚合应交给前端完成 - @GetMapping("/list") - @Operation(summary = "获得用户的会话列表") - public CommonResult> getConversationList() { - List conversationList = imConversationService.getConversationList(getLoginUserId()); - List imConversationRespVOList = BeanUtils.toBean(conversationList, ImConversationRespVO.class); - return success(imConversationRespVOList); - } - - @PostMapping("/update-pinned") - @Operation(summary = "置顶会话") - public CommonResult updatePinned(@Valid @RequestBody ImConversationUpdatePinnedReqVO updateReqVO) { - imConversationService.updatePinned(getLoginUserId(),updateReqVO); - return success(true); - } - - @PostMapping("/update-last-read-time") - @Operation(summary = "更新最后已读时间") - public CommonResult updateLastReadTime(@Valid @RequestBody ImConversationUpdateLastReadTimeReqVO updateReqVO) { - imConversationService.updateLastReadTime(getLoginUserId(),updateReqVO); - return success(true); - } - - @PostMapping("/create") - @Operation(summary = "创建会话") - public CommonResult createConversation(@Valid @RequestBody ImConversationCreateReqVO createReqVO) { - ImConversationDO conversation = imConversationService.createConversation(getLoginUserId(), createReqVO); - return success(conversation); - } - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationCreateReqVO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationCreateReqVO.java deleted file mode 100755 index a86ee56..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationCreateReqVO.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.im.controller.admin.conversation.vo; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - 会话最后已读时间 Request VO") -@Data -public class ImConversationCreateReqVO { - - @Schema(description = "聊天对象编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Long targetId; - - @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @InEnum(value = ImConversationTypeEnum.class, message = "会话类型必须是 {value}") - private Integer type; - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationRespVO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationRespVO.java deleted file mode 100755 index 95264ae..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationRespVO.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.iocoder.yudao.module.im.controller.admin.conversation.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - 会话 Response VO") -@Data -public class ImConversationRespVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13905") - private Long id; - - @Schema(description = "所属用户", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Long userId; - - @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer type; - - @Schema(description = "聊天对象编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Long targetId; - - @Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "s_1_2") - private String no; - - @Schema(description = "是否置顶", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Boolean pinned; - - @Schema(description = "最后已读时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-03-01 00:00:00") - private LocalDateTime lastReadTime; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime createTime; - - // TODO @dylan:这块,交给前端聚合哈。im 这块,我们重前端,后端更多解决消息的通信和存储。 - // 1. 基础信息:根据会话类型,查询会话接受者的头像、昵称 - // 2. 未读信息:前端自己增量拉取,基于本地 db 查看 - - @Schema(description = "会话接受者头像", requiredMode = Schema.RequiredMode.REQUIRED) - private String avatar; - - @Schema(description = "会话接受者昵称", requiredMode = Schema.RequiredMode.REQUIRED) - private String nickname; - - @Schema(description = "最后一条消息的描述", requiredMode = Schema.RequiredMode.REQUIRED) - private String lastMessageDescription; - - @Schema(description = "未读消息条数", requiredMode = Schema.RequiredMode.REQUIRED) - private String unreadMessagesCount; - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationUpdateLastReadTimeReqVO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationUpdateLastReadTimeReqVO.java deleted file mode 100755 index cec9ad5..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationUpdateLastReadTimeReqVO.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.im.controller.admin.conversation.vo; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - 会话最后已读时间 Request VO") -@Data -public class ImConversationUpdateLastReadTimeReqVO { - - @Schema(description = "最后已读时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-03-01 00:00:00") - @NotNull(message = "最后已读时间不能为空") - private LocalDateTime lastReadTime; - - @Schema(description = "聊天对象编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Long targetId; - - @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @InEnum(value = ImConversationTypeEnum.class, message = "会话类型必须是 {value}") - private Integer type; - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationUpdatePinnedReqVO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationUpdatePinnedReqVO.java deleted file mode 100755 index 8c1e526..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationUpdatePinnedReqVO.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.im.controller.admin.conversation.vo; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -@Schema(description = "管理后台 - 会话置顶 Request VO") -@Data -public class ImConversationUpdatePinnedReqVO { - - @Schema(description = "是否置顶", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "是否置顶不能为空") - private Boolean pinned; - - @Schema(description = "聊天对象编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Long targetId; - - @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @InEnum(value = ImConversationTypeEnum.class, message = "会话类型必须是 {value}") - private Integer type; - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ImConversationDO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ImConversationDO.java deleted file mode 100755 index 273b99a..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ImConversationDO.java +++ /dev/null @@ -1,67 +0,0 @@ -package cn.iocoder.yudao.module.im.dal.dataobject.conversation; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.time.LocalDateTime; - -/** - * IM 会话 DO - * - * @author 芋道源码 - */ -@TableName("im_conversation") -@KeySequence("im_conversation_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class ImConversationDO extends BaseDO { - - /** - * 编号 - */ - @TableId - private Long id; - - /** - * 所属用户 - */ - private Long userId; - - /** - * 会话类型 - *

- * 枚举 {@link ImConversationTypeEnum} - */ - private Integer type; - /** - * 聊天对象编号 - *

- * 1. 单聊时,用户编号; - * 2. 群聊时,群编号 - */ - private Long targetId; - /** - * 会话标志 - * - * 1. 单聊:s_{userId}_{targetId},需要排序 userId 和 targetId - * 2. 群聊:g_groupId - */ - private String no; - /** - * 是否置顶 - */ - private Boolean pinned; - /** - * 最后已读时间 - */ - private LocalDateTime lastReadTime; - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationMapper.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationMapper.java deleted file mode 100755 index f19a556..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.module.im.dal.mysql.conversation; - -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationDO; -import org.apache.ibatis.annotations.Mapper; - -/** - * IM 会话 Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface ImConversationMapper extends BaseMapperX { - - default ImConversationDO selectByNo(String no){ - return selectOne(ImConversationDO::getNo, no); - } -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationService.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationService.java deleted file mode 100755 index 73ac5e5..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationService.java +++ /dev/null @@ -1,42 +0,0 @@ -package cn.iocoder.yudao.module.im.service.conversation; - -import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationCreateReqVO; -import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationUpdateLastReadTimeReqVO; -import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationUpdatePinnedReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationDO; - -import java.util.List; - -/** - * IM 会话 Service 接口 - * - * @author 芋道源码 - */ -public interface ImConversationService { - - /** - * 获得用户的会话列表 - * - * @return 会话列表 - */ - List getConversationList(Long loginUserId); - - /** - * 置顶会话 - * - * @param loginUserId 登录用户编号 - * @param updateReqVO 更新信息 - */ - void updatePinned(Long loginUserId, ImConversationUpdatePinnedReqVO updateReqVO); - - /** - * 更新最后已读时间 - * - * @param loginUserId 登录用户编号 - * @param updateReqVO 更新信息 - */ - void updateLastReadTime(Long loginUserId, ImConversationUpdateLastReadTimeReqVO updateReqVO); - - ImConversationDO createConversation(Long loginUserId, ImConversationCreateReqVO createReqVO); - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationServiceImpl.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationServiceImpl.java deleted file mode 100755 index c19167c..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationServiceImpl.java +++ /dev/null @@ -1,122 +0,0 @@ -package cn.iocoder.yudao.module.im.service.conversation; - -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; -import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationCreateReqVO; -import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationUpdateLastReadTimeReqVO; -import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationUpdatePinnedReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationDO; -import cn.iocoder.yudao.module.im.dal.mysql.conversation.ImConversationMapper; -import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum; -import jakarta.annotation.Resource; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import java.util.List; - -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; - -/** - * IM 会话 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class ImConversationServiceImpl implements ImConversationService { - - private final String IM_CONVERSATION_ADD = "im-conversation-add"; - - @Resource - private ImConversationMapper imConversationMapper; - - @Resource - WebSocketMessageSender webSocketMessageSender; - - @Override - public List getConversationList(Long loginUserId) { - // 根据loginUserId判断targetId, 自己不能做targetId - // 如果loginUserId和targetId相同,则需要调换userId和targetId - List conversationList = imConversationMapper.selectList(); - - // 过滤和自己无关的会话 - List conversationFilteredList = conversationList.stream().filter(item -> loginUserId.equals(item.getUserId()) || loginUserId.equals(item.getTargetId())).toList(); - // 遍历判断loginUserId和targetId相同,相同则将userId设置为targetId, targetId设置为userId - conversationFilteredList.forEach(item -> { - if (item.getTargetId().equals(loginUserId)) { - Long targetId = item.getTargetId(); - Long userId = item.getUserId(); - item.setTargetId(userId); - item.setUserId(targetId); - } - }); - return conversationFilteredList; - } - - @Override - public void updatePinned(Long loginUserId, ImConversationUpdatePinnedReqVO updateReqVO) { - // 1. 获得会话编号 - String no = ImConversationTypeEnum.generateConversationNo(loginUserId, updateReqVO.getTargetId(), updateReqVO.getType()); - // 2. 查询会话 - ImConversationDO conversation = imConversationMapper.selectByNo(no); - if (conversation == null) { - // 2.1. 不存在,则插入 - conversation = insertConversation(no, loginUserId, updateReqVO.getTargetId(), updateReqVO.getType()); - } - // 3. 更新会话 - conversation.setPinned(updateReqVO.getPinned()); - imConversationMapper.updateById(conversation); - // 4. 做对应更新的 notify 推送 - } - - private ImConversationDO insertConversation(String no, Long userId, Long targetId, Integer type) { - ImConversationDO imConversationDO = new ImConversationDO(); - imConversationDO.setNo(no); - imConversationDO.setUserId(userId); - imConversationDO.setTargetId(targetId); - imConversationDO.setType(type); - imConversationMapper.insert(imConversationDO); - return imConversationDO; - } - - @Override - public void updateLastReadTime(Long loginUserId, ImConversationUpdateLastReadTimeReqVO updateReqVO) { - // 1. 获得会话编号 - String no = ImConversationTypeEnum.generateConversationNo(loginUserId, updateReqVO.getTargetId(), updateReqVO.getType()); - // 2. 查询会话 - ImConversationDO conversation = imConversationMapper.selectByNo(no); - if (conversation == null) { - // 2.1. 不存在,则插入 - conversation = insertConversation(no, loginUserId, updateReqVO.getTargetId(), updateReqVO.getType()); - } - // 3. 更新会话 - conversation.setLastReadTime(updateReqVO.getLastReadTime()); - imConversationMapper.updateById(conversation); - // 4. 做对应更新的 notify 推送 - } - - @Override - public ImConversationDO createConversation(Long loginUserId, ImConversationCreateReqVO createReqVO) { - // 1. 获得会话编号 - String no = ImConversationTypeEnum.generateConversationNo(loginUserId, createReqVO.getTargetId(), createReqVO.getType()); - // 2. 查询会话 - ImConversationDO conversation = imConversationMapper.selectByNo(no); - - if (conversation == null) { - // 2.1. 不存在,则插入 - conversation = insertConversation(no, loginUserId, createReqVO.getTargetId(), createReqVO.getType()); - } - - // 发送打开会话的通知,并推送会话实体 - // 给自己发送创建会话成功的通知, 方便多端登录的时候保持会话同时更新 - webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), getLoginUserId(), - IM_CONVERSATION_ADD, conversation); - - // 给接受者发送创建会话的通知 - // TODO:[dylan] 接受者,在接收到消息的时候本地发现没有回话,就按照会话编号创建一个,因此可以不需要发送这个通知 - webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), createReqVO.getTargetId(), - IM_CONVERSATION_ADD, conversation); - return conversation; - } - -} \ No newline at end of file