Bläddra i källkod

修改:私聊消息判断发送状态

安浩浩 1 år sedan
förälder
incheckning
77f3131ef3

+ 28 - 0
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageStatusEnum.java

@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.im.enums.message;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+@RequiredArgsConstructor
+@Getter
+public enum ImMessageStatusEnum implements IntArrayValuable {
+
+    SENDING(1, "发送中"),
+    SUCCESS(2, "发送成功"),
+    FAILURE(3, "发送失败"),
+    DELETED(4, "已删除"),
+    RECALL(5, "已撤回");
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ImMessageStatusEnum::getStatus).toArray();
+    private final Integer status;
+    private final String name;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+}

+ 10 - 2
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageTypeEnum.java

@@ -1,18 +1,21 @@
 package cn.iocoder.yudao.module.im.enums.message;
 
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
+import java.util.Arrays;
+
 /**
  * IM 消息的类型枚举
- *
+ * <p>
  * 参考 <a href="https://doc.yunxin.163.com/messaging/docs/zg3NzA3NTA?platform=web#消息类型">“消息类型”</a> 文档
  *
  * @author 芋道源码
  */
 @Getter
 @AllArgsConstructor
-public enum ImMessageTypeEnum {
+public enum ImMessageTypeEnum implements IntArrayValuable {
 
     TEXT(1, "文本"), // 消息内容为普通文本
     IMAGE(2, "图片"), // 消息内容为图片 URL 地址、尺寸、图片大小等信息
@@ -25,6 +28,7 @@ public enum ImMessageTypeEnum {
     NOTIFICATION(8, "通知"), // 主要用于群组、聊天室和超大群的事件通知,由服务端下发,客户端无法发送事件通知消息。通知类消息有在线、离线、漫游机制;没有通知栏提醒
     ;
 
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ImMessageTypeEnum::getType).toArray();
     /**
      * 类型
      */
@@ -34,4 +38,8 @@ public enum ImMessageTypeEnum {
      */
     private final String name;
 
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
 }

+ 4 - 0
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessagePageReqVO.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.im.controller.admin.message.vo;
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import com.alibaba.excel.annotation.ExcelProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -55,4 +56,7 @@ public class ImMessagePageReqVO extends PageParam {
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;
 
+    @Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED)
+    private Integer messageStatus;
+
 }

+ 10 - 0
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessageRespVO.java

@@ -1,8 +1,12 @@
 package cn.iocoder.yudao.module.im.controller.admin.message.vo;
 
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum;
 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.alibaba.excel.annotation.ExcelProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
 import java.time.LocalDateTime;
@@ -46,6 +50,7 @@ public class ImMessageRespVO {
 
     @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @ExcelProperty("消息类型")
+    @InEnum(ImMessageTypeEnum.class)
     private Integer contentType;
 
     @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED)
@@ -64,4 +69,9 @@ public class ImMessageRespVO {
     @ExcelProperty("创建时间")
     private LocalDateTime createTime;
 
+    @Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("消息状态")
+    @InEnum(ImMessageStatusEnum.class)
+    private Integer messageStatus;
+
 }

+ 4 - 1
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessageSaveReqVO.java

@@ -38,7 +38,7 @@ public class ImMessageSaveReqVO {
     @NotNull(message = "会话类型不能为空")
     private Integer conversationType;
 
-    @Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "会话标志 conversation_no = a_b", requiredMode = Schema.RequiredMode.REQUIRED)
     @NotEmpty(message = "会话标志不能为空")
     private String conversationNo;
 
@@ -57,4 +57,7 @@ public class ImMessageSaveReqVO {
     @NotNull(message = "消息来源 100-用户发送;200-系统发送(一般是通知);不能为空")
     private Integer sendFrom;
 
+    @Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "消息状态不能为空")
+    private Integer messageStatus;
 }

+ 5 - 0
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImMessageDO.java

@@ -73,4 +73,9 @@ public class ImMessageDO extends BaseDO {
      */
     private Integer sendFrom;
 
+    /**
+     * 消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回
+     */
+    private Integer messageStatus;
+
 }

+ 8 - 0
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImMessageService.java

@@ -61,4 +61,12 @@ public interface ImMessageService {
      * @return id
      */
     Long savePrivateMessage(ImSendMessage imSendMessage, Long fromUserId);
+
+    /**
+     * 更新消息状态
+     *
+     * @param messageId     消息id
+     * @param messageStatus 消息状态
+     */
+    void updateMessageStatus(Long messageId, Integer messageStatus);
 }

+ 19 - 4
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImMessageServiceImpl.java

@@ -6,10 +6,12 @@ import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessagePageReqVO
 import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageSaveReqVO;
 import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO;
 import cn.iocoder.yudao.module.im.dal.mysql.message.ImMessageMapper;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
 import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 import jakarta.annotation.Resource;
+import org.dromara.hutool.core.date.TimeUtil;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
@@ -74,22 +76,35 @@ public class ImMessageServiceImpl implements ImMessageService {
 
 
     @Override
-    public Long savePrivateMessage(ImSendMessage message, Long fromUserId) {
+    public Long savePrivateMessage(ImSendMessage message, Long senderId) {
         ImMessageSaveReqVO imMessageSaveReqVO = new ImMessageSaveReqVO();
         imMessageSaveReqVO.setClientMessageId(message.getClientMessageId());
-        imMessageSaveReqVO.setSenderId(fromUserId);
+        imMessageSaveReqVO.setSenderId(senderId);
         imMessageSaveReqVO.setReceiverId(message.getReceiverId());
         //查询发送人昵称和发送人头像
-        AdminUserRespDTO user = adminUserApi.getUser(fromUserId);
+        AdminUserRespDTO user = adminUserApi.getUser(senderId);
         imMessageSaveReqVO.setSenderNickname(user.getNickname());
         imMessageSaveReqVO.setSenderAvatar(user.getAvatar());
         imMessageSaveReqVO.setConversationType(message.getConversationType());
         imMessageSaveReqVO.setContentType(message.getContentType());
-        imMessageSaveReqVO.setConversationNo("1");
+        imMessageSaveReqVO.setConversationNo(senderId + "_" + message.getReceiverId());
         imMessageSaveReqVO.setContent(message.getContent());
         //消息来源 100-用户发送;200-系统发送(一般是通知);不能为空
         imMessageSaveReqVO.setSendFrom(100);
+        imMessageSaveReqVO.setSendTime(TimeUtil.now());
+        imMessageSaveReqVO.setMessageStatus(ImMessageStatusEnum.SENDING.getStatus());
         return createMessage(imMessageSaveReqVO);
     }
 
+    @Override
+    public void updateMessageStatus(Long messageId, Integer messageStatus) {
+        //校验 id 是否存在
+        validateMessageExists(messageId);
+        //更新消息状态
+        ImMessageDO imMessageDO = new ImMessageDO();
+        imMessageDO.setId(messageId);
+        imMessageDO.setMessageStatus(messageStatus);
+        imMessageMapper.updateById(imMessageDO);
+    }
+
 }

+ 20 - 1
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/ImWebSocketMessageListener.java

@@ -3,25 +3,31 @@ package cn.iocoder.yudao.module.im.websocket;
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener;
 import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
+import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager;
 import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils;
 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO;
 import cn.iocoder.yudao.module.im.dal.redis.inbox.SequenceGeneratorRedisDao;
 import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
 import cn.iocoder.yudao.module.im.service.conversation.ImConversationService;
 import cn.iocoder.yudao.module.im.service.inbox.ImInboxService;
 import cn.iocoder.yudao.module.im.service.message.ImMessageService;
 import cn.iocoder.yudao.module.im.websocket.message.ImReceiveMessage;
 import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage;
 import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 import org.springframework.web.socket.WebSocketSession;
 
+import java.util.List;
+
 /**
- * WebSocket 示例:单发消息
+ * WebSocket im
  *
  * @author 芋道源码
  */
 @Component
+@Slf4j
 public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSendMessage> {
 
     @Resource
@@ -34,6 +40,8 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSe
     private ImInboxService imInboxService;
     @Resource
     private SequenceGeneratorRedisDao sequenceGeneratorRedisDao;
+    @Resource
+    private WebSocketSessionManager webSocketSessionManager;
 
     @Override
     public void onMessage(WebSocketSession session, ImSendMessage message) {
@@ -48,6 +56,14 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSe
             imInboxService.createInbox(new ImInboxSaveReqVO(fromUserId, messageId, sequenceGeneratorRedisDao.generateSequence(fromUserId)));
 
             //3、推送消息
+            // 3.1判断是否在线
+            List<WebSocketSession> sessions = (List<WebSocketSession>) webSocketSessionManager.getSessionList(UserTypeEnum.ADMIN.getValue(), message.getReceiverId());
+            if (sessions.isEmpty()) {
+                //更新消息状态,为发送失败
+                imMessageService.updateMessageStatus(messageId, ImMessageStatusEnum.FAILURE.getStatus());
+                return;
+            }
+            //3.2发送
             ImReceiveMessage toMessage = new ImReceiveMessage();
             toMessage.setFromId(fromUserId);
             toMessage.setConversationType(ImConversationTypeEnum.PRIVATE.getType());
@@ -55,6 +71,9 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSe
             toMessage.setContent(message.getContent());
             webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), message.getReceiverId(), // 给指定用户
                     "im-message-receive", toMessage);
+            //4、更新消息状态,为发送成功
+            imMessageService.updateMessageStatus(messageId, ImMessageStatusEnum.SUCCESS.getStatus());
+
         }
     }