Преглед на файлове

企微聊天-回调消息调整、会话列表增加黑名单、重粉、待处理参数

Long преди 6 дни
родител
ревизия
fd675f23a9

+ 12 - 6
fs-company/src/main/java/com/fs/company/controller/qw/QwMsgController.java

@@ -10,7 +10,6 @@ import com.fs.common.enums.BusinessType;
 import com.fs.common.exception.CustomException;
 import com.fs.common.exception.ServiceException;
 import com.fs.common.utils.ServletUtils;
-import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.course.param.FsCourseLinkMiniParam;
 import com.fs.course.param.FsCourseListBySidebarParam;
@@ -26,7 +25,6 @@ import com.fs.his.domain.FsStoreOrder;
 import com.fs.his.domain.FsUserOperationLog;
 import com.fs.his.service.IFsStoreOrderService;
 import com.fs.his.service.IFsUserOperationLogService;
-import com.fs.his.vo.FsStoreOrderListVO;
 import com.fs.his.vo.FsUserOperationLogVo;
 import com.fs.qw.domain.*;
 import com.fs.qw.param.QwMsgSendParam;
@@ -159,15 +157,23 @@ public class QwMsgController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         //员工userId
         Long userId = loginUser.getUser().getUserId();
-        List<QwUser> qwUsers = qwMsgService.qwUserList(userId);
-        return R.ok().put("data",qwUsers);
+        return R.ok().put("data", qwUserService.selectQwUserVoListByCompanyUserId(userId));
     }
     //获取会话
     @GetMapping("/conversationList/{userId}")
     @ApiOperation("获取会话")
-    public R conversations(@PathVariable("userId")Long qwUserId){
+    public R conversations(@PathVariable("userId") Long qwUserId,
+                           @RequestParam(required = false) Boolean isBlack,
+                           @RequestParam(required = false) Boolean isRepeat,
+                           @RequestParam(required = false) Boolean isPend){
+        Map<String, Object> params = new HashMap<>();
+        params.put("qwUserId", qwUserId.toString());
+        params.put("isBlack", isBlack);
+        params.put("isRepeat", isRepeat);
+        params.put("isPend", isPend);
+
         startPage();
-        List<QwContactListVO> list = qwMsgService.selectQwConversationByUserId(qwUserId);
+        List<QwContactListVO> list = qwMsgService.selectQwConversationByMap(params);
         PageInfo<QwContactListVO> result = new PageInfo<>(list);
         return R.ok().put("data", result);
     }

+ 60 - 62
fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java

@@ -315,7 +315,7 @@ public class QwMsgController {
                         // 接收处理群消息
                         processRoomMessage(wxWorkMsgResp, wxWorkMessageDTO, id, serverId);
                     } catch (Exception e) {
-                        log.error("接收处理群消息失败 err: {}", e.getMessage(), e);
+                        log.error("接收处理群消息失败 info: {} err: {}", json, e.getMessage(), e);
                     }
                     break;
                 }
@@ -455,25 +455,29 @@ public class QwMsgController {
                     qwUserVoiceLogService.addQuUserVoiceByIpadCallback(id,extId,recordType,totalSeconds,wxWorkMsgResp.getUuid());
                 }
 
-                // 处理文本消息
-                if (wxWorkMessageDTO.getMsgtype() == 2 || wxWorkMessageDTO.getMsgtype() == 0) {
-                    processTextMessage(id, userId, wxWorkMessageDTO.getContent(), wxWorkMsgResp, sendType, false, null, null);
-                }
-                // 语音消息
-                if (wxWorkMessageDTO.getMsgtype() == 16) {
-                    processVoiceMessage(serverId, wxWorkMessageDTO.getContent(), wxWorkMessageDTO, wxWorkMsgResp, id, userId, sendType, false, null, null);
-                }
-                // 图片消息
-                if (wxWorkMessageDTO.getMsgtype() == 101){
-                    processImageMessage(serverId, wxWorkMessageDTO, wxWorkMsgResp, id, userId, sendType, false, null, null);
-                }
-                // gif 表情消息
-                if (wxWorkMessageDTO.getMsgtype() == 104){
-                    processEmotionDynamicMessage(wxWorkMessageDTO, wxWorkMsgResp, id, userId, sendType, false, null, null);
-                }
-                // 小程序消息
-                if (wxWorkMessageDTO.getMsgtype() == 78) {
-                    processMiniAppMessage(serverId, wxWorkMessageDTO, wxWorkMsgResp, id, userId, sendType, false, null, null);
+                try {
+                    // 处理文本消息
+                    if (wxWorkMessageDTO.getMsgtype() == 2 || wxWorkMessageDTO.getMsgtype() == 0) {
+                        processTextMessage(id, sender, receiver, serverId, wxWorkMessageDTO.getContent(), wxWorkMsgResp, false, null, null);
+                    }
+                    // 语音消息
+                    if (wxWorkMessageDTO.getMsgtype() == 16) {
+                        processVoiceMessage(id, sender, receiver, serverId, wxWorkMessageDTO.getContent(), wxWorkMessageDTO, wxWorkMsgResp, false, null, null);
+                    }
+                    // 图片消息
+                    if (wxWorkMessageDTO.getMsgtype() == 101){
+                        processImageMessage(id, sender, receiver, serverId, wxWorkMessageDTO, wxWorkMsgResp, false, null, null);
+                    }
+                    // gif 表情消息
+                    if (wxWorkMessageDTO.getMsgtype() == 104){
+                        processEmotionDynamicMessage(id, sender, receiver, serverId, wxWorkMessageDTO, wxWorkMsgResp, false, null, null);
+                    }
+                    // 小程序消息
+                    if (wxWorkMessageDTO.getMsgtype() == 78) {
+                        processMiniAppMessage(id, sender, receiver, serverId, wxWorkMessageDTO, wxWorkMsgResp, false, null, null);
+                    }
+                } catch (Exception e) {
+                    log.error("接收处理个微消息失败 info: {} err: {}", json, e.getMessage(), e);
                 }
 
                 break;
@@ -602,35 +606,36 @@ public class QwMsgController {
 
     /**
      * 处理文本消息
-     * @param id                企微用户ID
-     * @param userId            消息发送者ID
+     * @param qwUserId          企微用户ID
+     * @param senderVid         消息发送者ID
+     * @param receiverVid       消息接收者ID
+     * @param serverId          服务器ID
      * @param content           消息内容
      * @param wxWorkMsgResp     回调信息对象
-     * @param sendType          发送者类型 1客户 2销售
      * @param isRoom            是否群聊
      * @param chatId            会话ID(群聊才有)
      * @param chatAvatar        群头像(群聊才有)
      */
-    private void processTextMessage(Long id, Long userId, String content, WxWorkMsgResp wxWorkMsgResp, Integer sendType, boolean isRoom, String chatId, String chatAvatar) {
+    private void processTextMessage(Long qwUserId, Long senderVid, Long receiverVid, Long serverId, String content, WxWorkMsgResp wxWorkMsgResp, boolean isRoom, String chatId, String chatAvatar) {
         // 保存聊天消息
-        QwMessageListVO message = aiHookService.saveQwMsg(id, userId, content, wxWorkMsgResp.getUuid(), sendType, wxWorkMsgResp.getJson(), 1, isRoom, chatId, chatAvatar);
+        QwMessageListVO message = aiHookService.saveQwMsg(qwUserId, senderVid, receiverVid, serverId, content, wxWorkMsgResp.getUuid(), wxWorkMsgResp.getJson(), 1, isRoom, chatId, chatAvatar);
         QwImSocket.broadcast(message);
     }
 
     /**
      * 处理语音消息
+     * @param qwUserId          企微用户ID
+     * @param senderVid         消息发送者ID
+     * @param receiverVid       消息接收者ID
      * @param serverId          服务器ID
      * @param wxWorkMessageDTO  消息DTO
      * @param content           翻译后的内容
      * @param wxWorkMsgResp     回调信息对象
-     * @param id                企微用户ID
-     * @param userId            消息发送者ID
-     * @param sendType          发送者类型 1客户 2销售
      * @param isRoom            是否群聊
      * @param chatId            会话ID(群聊才有)
      * @param chatAvatar        群头像(群聊才有)
      */
-    private void processVoiceMessage(Long serverId, String content, WxWorkMessageDTO wxWorkMessageDTO, WxWorkMsgResp wxWorkMsgResp, Long id, Long userId, Integer sendType, boolean isRoom, String chatId, String chatAvatar) {
+    private void processVoiceMessage(Long qwUserId, Long senderVid, Long receiverVid, Long serverId, String content, WxWorkMessageDTO wxWorkMessageDTO, WxWorkMsgResp wxWorkMsgResp, boolean isRoom, String chatId, String chatAvatar) {
         String voiceFileName = IdUtils.fastSimpleUUID() + ".silk";
         WxWorkResponseDTO<String> fileUrlResp =
                 aiHookService.getFileUrl(wxWorkMsgResp.getUuid(), wxWorkMessageDTO.getVoice_id(), wxWorkMessageDTO.getAes_key(), 5, voiceFileName, wxWorkMessageDTO.getVoice_size(), serverId);
@@ -652,31 +657,33 @@ public class QwMsgController {
             ste.setMsgid(wxWorkMessageDTO.getMsg_id());
             ste.setUuid(wxWorkMsgResp.getUuid());
             WxWorkResponseDTO<WxwSpeechToTextEntityRespDTO> dto = wxWorkService.SpeechToTextEntity(ste, serverId);
-            content = dto.getData().getText();
+            if (dto.getErrcode() == 0) {
+                content = dto.getData().getText();
+            }
         }
 
-        com.alibaba.fastjson.JSONObject json = new com.alibaba.fastjson.JSONObject();
+        JSONObject json = new JSONObject();
         json.put("url", url);
         json.put("content", content);
 
         // 保存聊天消息
-        QwMessageListVO message = aiHookService.saveQwMsg(id, userId, json.toString(), wxWorkMsgResp.getUuid(), sendType, wxWorkMsgResp.getJson(), 4, isRoom, chatId, chatAvatar);
+        QwMessageListVO message = aiHookService.saveQwMsg(qwUserId, senderVid, receiverVid, serverId, json.toString(), wxWorkMsgResp.getUuid(), wxWorkMsgResp.getJson(), 4, isRoom, chatId, chatAvatar);
         QwImSocket.broadcast(message);
     }
 
     /**
      * 处理图片消息
+     * @param qwUserId          企微用户ID
+     * @param senderVid         消息发送者ID
+     * @param receiverVid       消息接收者ID
      * @param serverId          服务器ID
      * @param wxWorkMessageDTO  消息DTO
      * @param wxWorkMsgResp     回调信息对象
-     * @param id                企微用户ID
-     * @param userId            消息发送者ID
-     * @param sendType          发送者类型 1客户 2销售
      * @param isRoom            是否群聊
      * @param chatId            会话ID(群聊才有)
      * @param chatAvatar        群头像(群聊才有)
      */
-    private void processImageMessage(Long serverId, WxWorkMessageDTO wxWorkMessageDTO, WxWorkMsgResp wxWorkMsgResp, Long id, Long userId, Integer sendType, boolean isRoom, String chatId, String chatAvatar) {
+    private void processImageMessage(Long qwUserId, Long senderVid, Long receiverVid, Long serverId, WxWorkMessageDTO wxWorkMessageDTO, WxWorkMsgResp wxWorkMsgResp, boolean isRoom, String chatId, String chatAvatar) {
         String fileName = IdUtils.fastSimpleUUID() + ".jpg";
         WxWorkResponseDTO<String> fileUrlResp =
                 aiHookService.getFileUrl(wxWorkMsgResp.getUuid(), wxWorkMessageDTO.getFile_id(), wxWorkMessageDTO.getAes_key(), wxWorkMessageDTO.getOpenim_cdn_authkey(), fileName, wxWorkMessageDTO.getFile_size(), serverId);
@@ -687,41 +694,42 @@ public class QwMsgController {
 
         String content = fileUrlResp.getData();
         // 保存聊天消息
-        QwMessageListVO message = aiHookService.saveQwMsg(id, userId, content, wxWorkMsgResp.getUuid(), sendType, wxWorkMsgResp.getJson(), 2, isRoom, chatId, chatAvatar);
+        QwMessageListVO message = aiHookService.saveQwMsg(qwUserId, senderVid, receiverVid, serverId, content, wxWorkMsgResp.getUuid(), wxWorkMsgResp.getJson(), 2, isRoom, chatId, chatAvatar);
         QwImSocket.broadcast(message);
     }
 
     /**
      * 处理动态表情消息
+     * @param qwUserId          企微用户ID
+     * @param senderVid         消息发送者ID
+     * @param receiverVid       消息接收者ID
+     * @param serverId          服务器ID
      * @param wxWorkMessageDTO  消息DTO
      * @param wxWorkMsgResp     回调信息对象
-     * @param id                企微用户ID
-     * @param userId            消息发送者ID
-     * @param sendType          发送者类型 1客户 2销售
      * @param isRoom            是否群聊
      * @param chatId            会话ID(群聊才有)
      * @param chatAvatar        群头像(群聊才有)
      */
-    private void processEmotionDynamicMessage(WxWorkMessageDTO wxWorkMessageDTO, WxWorkMsgResp wxWorkMsgResp, Long id, Long userId, int sendType, boolean isRoom, String chatId, String chatAvatar) {
+    private void processEmotionDynamicMessage(Long qwUserId, Long senderVid, Long receiverVid, Long serverId, WxWorkMessageDTO wxWorkMessageDTO, WxWorkMsgResp wxWorkMsgResp, boolean isRoom, String chatId, String chatAvatar) {
         String content = wxWorkMessageDTO.getUrl();
         // 保存聊天消息
-        QwMessageListVO message = aiHookService.saveQwMsg(id, userId, content, wxWorkMsgResp.getUuid(), sendType, wxWorkMsgResp.getJson(), 3, isRoom, chatId, chatAvatar);
+        QwMessageListVO message = aiHookService.saveQwMsg(qwUserId, senderVid, receiverVid, serverId, content, wxWorkMsgResp.getUuid(), wxWorkMsgResp.getJson(), 3, isRoom, chatId, chatAvatar);
         QwImSocket.broadcast(message);
     }
 
     /**
      * 小程序消息处理
+     * @param qwUserId          企微用户ID
+     * @param senderVid         消息发送者ID
+     * @param receiverVid       消息接收者ID
      * @param serverId          服务器ID
      * @param wxWorkMessageDTO  消息DTO
      * @param wxWorkMsgResp     回调信息对象
-     * @param id                企微用户ID
-     * @param userId            消息发送者ID
-     * @param sendType          发送者类型 1客户 2销售
      * @param isRoom            是否群聊
      * @param chatId            会话ID(群聊才有)
      * @param chatAvatar        群头像(群聊才有)
      */
-    private void processMiniAppMessage(Long serverId, WxWorkMessageDTO wxWorkMessageDTO, WxWorkMsgResp wxWorkMsgResp, Long id, Long userId, int sendType, boolean isRoom, String chatId, String chatAvatar) {
+    private void processMiniAppMessage(Long qwUserId, Long senderVid, Long receiverVid, Long serverId, WxWorkMessageDTO wxWorkMessageDTO, WxWorkMsgResp wxWorkMsgResp, boolean isRoom, String chatId, String chatAvatar) {
         String thumbName = IdUtils.fastSimpleUUID() + ".jpg";
         WxWorkResponseDTO<String> fileUrlResp =
                 aiHookService.getFileUrl(wxWorkMsgResp.getUuid(), wxWorkMessageDTO.getThumbFileId(), wxWorkMessageDTO.getThumbAESKey(), 1, thumbName, wxWorkMessageDTO.getSize(), serverId);
@@ -740,7 +748,7 @@ public class QwMsgController {
         json.put("thumbnail", fileUrlResp.getData());
 
         // 保存聊天消息
-        QwMessageListVO message = aiHookService.saveQwMsg(id, userId, json.toString(), wxWorkMsgResp.getUuid(), sendType, wxWorkMsgResp.getJson(), 5, isRoom, chatId, chatAvatar);
+        QwMessageListVO message = aiHookService.saveQwMsg(qwUserId, senderVid, receiverVid, serverId, json.toString(), wxWorkMsgResp.getUuid(), wxWorkMsgResp.getJson(), 5, isRoom, chatId, chatAvatar);
         QwImSocket.broadcast(message);
     }
 
@@ -752,16 +760,6 @@ public class QwMsgController {
         Long receiver = wxWorkMessageDTO.getReceiver();
         Long sender = wxWorkMessageDTO.getSender();
 
-        // 1客户 2销售
-        int sendType = 2;
-
-        // 消息发送者用户ID
-        Long userId = receiver;
-        if (receiver != 0 && 2000000000000000L - receiver > 0){
-            sendType = 1;
-            userId = sender;
-        }
-
         WxWorkRoomId2ChatIdDTO roomId2ChatIdDTO = new WxWorkRoomId2ChatIdDTO();
         roomId2ChatIdDTO.setUuid(wxWorkMsgResp.getUuid());
         roomId2ChatIdDTO.setRoom_id(wxWorkMessageDTO.getRoom_conversation_id());
@@ -783,23 +781,23 @@ public class QwMsgController {
 
         // 处理文本消息
         if (wxWorkMessageDTO.getMsgtype() == 2 || wxWorkMessageDTO.getMsgtype() == 0) {
-            processTextMessage(qwUserId, userId, wxWorkMessageDTO.getContent(), wxWorkMsgResp, sendType, true, chatId, chatAvatar);
+            processTextMessage(qwUserId, sender, receiver, serverId, wxWorkMessageDTO.getContent(), wxWorkMsgResp, true, chatId, chatAvatar);
         }
         // 语音消息
         if (wxWorkMessageDTO.getMsgtype() == 16) {
-            processVoiceMessage(serverId, wxWorkMessageDTO.getContent(), wxWorkMessageDTO, wxWorkMsgResp, qwUserId, userId, sendType, true, chatId, chatAvatar);
+            processVoiceMessage(qwUserId, sender, receiver, serverId, wxWorkMessageDTO.getContent(), wxWorkMessageDTO, wxWorkMsgResp, true, chatId, chatAvatar);
         }
         // 图片消息
         if (wxWorkMessageDTO.getMsgtype() == 101){
-            processImageMessage(serverId, wxWorkMessageDTO, wxWorkMsgResp, qwUserId, userId, sendType, true, chatId, chatAvatar);
+            processImageMessage(qwUserId, sender, receiver, serverId, wxWorkMessageDTO, wxWorkMsgResp, true, chatId, chatAvatar);
         }
         // gif 表情消息
         if (wxWorkMessageDTO.getMsgtype() == 104){
-            processEmotionDynamicMessage(wxWorkMessageDTO, wxWorkMsgResp, qwUserId, userId, sendType, true, chatId, chatAvatar);
+            processEmotionDynamicMessage(qwUserId, sender, receiver, serverId, wxWorkMessageDTO, wxWorkMsgResp, true, chatId, chatAvatar);
         }
         // 小程序消息
         if (wxWorkMessageDTO.getMsgtype() == 78) {
-            processMiniAppMessage(serverId, wxWorkMessageDTO, wxWorkMsgResp, qwUserId, userId, sendType, true, chatId, chatAvatar);
+            processMiniAppMessage(qwUserId, sender, receiver, serverId, wxWorkMessageDTO, wxWorkMsgResp, true, chatId, chatAvatar);
         }
     }
 

+ 4 - 3
fs-service/src/main/java/com/fs/fastGpt/service/AiHookService.java

@@ -42,15 +42,16 @@ public interface AiHookService {
      * 保存企微聊天信息
      *
      * @param qwUserId      企微用户ID
-     * @param userId        用户ID
+     * @param senderVid     消息发送者ID
+     * @param receiverVid   消息接收者ID
+     * @param serverId      服务器ID
      * @param content       聊天内容
      * @param uuid          UUID
-     * @param sendType      发送者类型 1用户 2客服
      * @param json          消息json
      * @param msgType       消息类型 1文本 2图片 3动态表情 4语音 5小程序
      * @param isRoom        是否群聊
      * @param chatId        会话ID(群聊才有)
      * @param chatAvatar    群头像(群聊才有)
      */
-    QwMessageListVO saveQwMsg(Long qwUserId, Long userId, String content, String uuid, int sendType, String json, int msgType, boolean isRoom, String chatId, String chatAvatar);
+    QwMessageListVO saveQwMsg(Long qwUserId, Long senderVid, Long receiverVid, Long serverId, String content, String uuid, String json, int msgType, boolean isRoom, String chatId, String chatAvatar);
 }

+ 193 - 81
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java

@@ -42,6 +42,7 @@ import com.fs.his.service.IFsExpressService;
 import com.fs.his.service.IFsStoreOrderService;
 import com.fs.im.vo.OpenImMsgCallBackVO;
 import com.fs.qw.domain.*;
+import com.fs.qw.dto.QwImUserDTO;
 import com.fs.qw.enums.MsgType;
 import com.fs.qw.mapper.*;
 import com.fs.qw.param.QwAutoTagsRulesTags;
@@ -64,6 +65,8 @@ import com.vdurmont.emoji.EmojiParser;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.jetbrains.annotations.Nullable;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.scheduling.annotation.Async;
@@ -170,6 +173,8 @@ public class AiHookServiceImpl implements AiHookService {
     private QwMsgMapper qwMsgMapper;
     @Autowired
     private QwGroupChatMapper qwGroupChatMapper;
+    @Autowired
+    private RedissonClient redissonClient;
 
     private static final String AI_REPLY = "AI_REPLY:";
     private static final String AI_REPLY_TAG = "AI_REPLY_TAG:";
@@ -2078,10 +2083,11 @@ public class AiHookServiceImpl implements AiHookService {
      * 保存企微聊天信息
      *
      * @param qwUserId      企微用户ID
-     * @param userId        用户ID
+     * @param senderVid     消息发送者ID
+     * @param receiverVid   消息接收者ID
+     * @param serverId      服务器ID
      * @param content       聊天内容
      * @param uuid          UUID
-     * @param sendType      发送者类型 1用户 2客服
      * @param json          消息json
      * @param msgType       消息类型 1文本 2图片 3动态表情 4语音 5小程序
      * @param isRoom        是否群聊
@@ -2090,88 +2096,56 @@ public class AiHookServiceImpl implements AiHookService {
      */
     @Transactional(rollbackFor = Exception.class)
     @Override
-    public QwMessageListVO saveQwMsg(Long qwUserId, Long userId, String content, String uuid, int sendType, String json, int msgType, boolean isRoom, String chatId, String chatAvatar) {
+    public QwMessageListVO saveQwMsg(Long qwUserId, Long senderVid, Long receiverVid, Long serverId, String content, String uuid, String json, int msgType, boolean isRoom, String chatId, String chatAvatar) {
         // 查询企微用户
         QwUser qwUser = qwUserService.selectQwUserById(qwUserId);
-        if (Objects.isNull(qwUser)){
+        if (Objects.isNull(qwUser)) {
             log.warn("企微用户不存在 qwUserId: {}", qwUserId);
             return null;
         }
 
-        // 查询外部联系
-        QwExternalContact qwExternalContact = getExternalContact(userId, uuid, qwUser.getServerId(), qwUser.getCorpId(), qwUser.getQwUserId());
-        if (Objects.isNull(qwExternalContact) && !isRoom) {
-            log.warn("外部联系人不存在 userId: {}, uuid: {}, serverId: {}, corpId: {}, qwUserId: {}", userId, uuid, qwUser.getServerId(), qwUser.getCorpId(), qwUser.getQwUserId());
+        // 获取发送
+        QwImUserDTO sender = getUserByVid(senderVid, uuid, serverId, qwUser.getCorpId(), qwUser.getQwUserId());
+        if (Objects.isNull(sender)) {
+            log.warn("sender用户不存在 senderVid: {}", senderVid);
             return null;
         }
 
+        // 获取接收者
+        QwImUserDTO receiver = getUserByVid(receiverVid, uuid, serverId, qwUser.getCorpId(), qwUser.getQwUserId());
+
         // 查询会话
-        QwSession qwSession;
+        QwSession qwSession = null;
         if (isRoom) {
-            QwGroupChat qwGroupChat = qwGroupChatMapper.selectQwGroupChatByChatId(chatId);
-            if (Objects.isNull(qwGroupChat)){
-                log.warn("群聊不存在 userId: {}, uuid: {}, serverId: {}, corpId: {}, qwUserId: {}, chatId: {}", userId, uuid, qwUser.getServerId(), qwUser.getCorpId(), qwUser.getQwUserId(), chatId);
-                return null;
-            }
+            qwSession = getGroupQwSession(chatId, chatAvatar, qwUser);
+        } else {
+            QwImUserDTO extUser = null;
+            Long extWxId = null;
 
-            qwSession = qwSessionMapper.selectQwSessionByChatIdAndQwUserId(chatId, qwUser.getId());
-            String firstLetter = PinYinUtil.getFirstLetter(qwGroupChat.getName());
-            if (qwSession == null) {
-                qwSession = new QwSession();
-                qwSession.setChatId(chatId);
-                qwSession.setCorpId(qwGroupChat.getCorpId());
-                qwSession.setQwUserId(qwUser.getId().toString());
-                qwSession.setStatus(1);
-                qwSession.setAvatar(chatAvatar);
-                qwSession.setNickName(qwGroupChat.getName());
-                qwSession.setCompanyId(qwUser.getCompanyId());
-                qwSession.setCreateTime(new Date());
-                qwSession.setUpdateTime(new Date());
-                qwSession.setIsRoom(1);
-                qwSession.setFirstLetter(firstLetter);
-                qwSessionMapper.insertQwSession(qwSession);
-            }else {
-                qwSession.setUpdateTime(new Date());
-                qwSession.setQwUserId(qwUser.getId().toString());
-                qwSession.setNickName(qwGroupChat.getName());
-                qwSession.setAvatar(chatAvatar);
-                qwSession.setFirstLetter(firstLetter);
-                qwSessionMapper.updateQwSession(qwSession);
+            // 获取外部联系人
+            if (sender.getUserType() == 1) {
+                extUser = sender;
+                extWxId = senderVid;
             }
-        } else {
-            qwSession = qwSessionMapper.selectQwSessionByExtIdAndQwUserId(qwExternalContact.getId(), qwUser.getId());
-            String firstLetter = PinYinUtil.getFirstLetter(qwExternalContact.getName());
-            if (qwSession == null) {
-                qwSession = new QwSession();
-                chatId = UUID.randomUUID().toString();
-                qwSession.setChatId(chatId);
-                qwSession.setCorpId(qwUser.getCorpId());
-                qwSession.setQwExtWxId(String.valueOf(userId));
-                qwSession.setQwExtId(qwExternalContact.getId().toString());
-                qwSession.setQwUserId(qwUser.getId().toString());
-                qwSession.setStatus(1);
-                qwSession.setAvatar(qwExternalContact.getAvatar());
-                qwSession.setNickName(qwExternalContact.getName());
-                qwSession.setCompanyId(qwUser.getCompanyId());
-                qwSession.setCompanyUserId(qwUser.getCompanyUserId());
-                qwSession.setCreateTime(new Date());
-                qwSession.setUpdateTime(new Date());
-                qwSession.setIsRoom(0);
-                qwSession.setFirstLetter(firstLetter);
-                qwSessionMapper.insertQwSession(qwSession);
-            }else {
-                qwSession.setUpdateTime(new Date());
-                qwSession.setNickName(qwExternalContact.getName());
-                qwSession.setFirstLetter(firstLetter);
-                qwSessionMapper.updateQwSession(qwSession);
+            if (receiver != null && receiver.getUserType() == 1) {
+                extUser = receiver;
+                extWxId = receiverVid;
+            }
+            if (extUser != null) {
+                qwSession = getQwSession(qwUserId, extUser, qwUser, extWxId);
             }
         }
 
+        if (qwSession == null) {
+            log.warn("获取session失败 senderVid: {}, receiverVid: {}", senderVid, receiverVid);
+            return null;
+        }
+
         // 保存聊天消息
         QwMsg qwMsg = new QwMsg();
         qwMsg.setContent(content);
         qwMsg.setSessionId(qwSession.getSessionId());
-        qwMsg.setSendType(sendType);
+        qwMsg.setSendType(sender.getUserType());
         qwMsg.setCompanyId(qwUser.getCompanyId());
         qwMsg.setCompanyUserId(qwUser.getCompanyUserId());
         qwMsg.setMsgType(msgType);
@@ -2179,30 +2153,20 @@ public class AiHookServiceImpl implements AiHookService {
         qwMsg.setStatus(0);
         qwMsg.setQwUserId(qwSession.getQwUserId());
         qwMsg.setCreateTime(new Date());
-
-        if (Objects.isNull(qwExternalContact)) {
-            qwMsg.setAvatar(qwUser.getAvatar());
-            qwMsg.setNickName(qwUser.getQwUserName());
-        } else {
-            qwMsg.setQwExtId(qwExternalContact.getId().toString());
-            qwMsg.setAvatar(qwExternalContact.getAvatar());
-            qwMsg.setNickName(qwExternalContact.getName());
+        if (sender.getUserType() == 1) {
+            qwMsg.setQwExtId(sender.getUserId().toString());
         }
+        qwMsg.setAvatar(sender.getAvatar());
+        qwMsg.setNickName(sender.getUserName());
         qwMsgMapper.insertQwMsg(qwMsg);
         log.debug("保存企微聊天记录 msgId: {}", qwMsg.getMsgId());
 
         // 组装返回消息结构
         QwMessageListVO listVO = new QwMessageListVO();
         QWFromUser qwFromUser = new QWFromUser();
-        if (sendType == 1) {
-            qwFromUser.setId(qwExternalContact.getId());
-            qwFromUser.setAvatar(qwMsg.getAvatar());
-            qwFromUser.setDisplayName(qwMsg.getNickName());
-        }else if(sendType == 2){
-            qwFromUser.setId(Long.parseLong(qwMsg.getQwUserId()));
-            qwFromUser.setDisplayName(qwUser.getQwUserName());
-            qwFromUser.setAvatar(qwUser.getAvatar());
-        }
+        qwFromUser.setId(sender.getUserId());
+        qwFromUser.setAvatar(sender.getAvatar());
+        qwFromUser.setDisplayName(sender.getUserName());
 
         listVO.setCompanyId(qwUser.getCompanyId());
         String type = "text";
@@ -2223,6 +2187,114 @@ public class AiHookServiceImpl implements AiHookService {
         return listVO;
     }
 
+    /**
+     * 获取单聊session
+     */
+    private QwSession getQwSession(Long qwUserId, QwImUserDTO extUser, QwUser qwUser, Long extWxId) {
+        QwSession qwSession;
+        String chatId;
+        qwSession = qwSessionMapper.selectQwSessionByExtIdAndQwUserId(extUser.getUserId(), qwUser.getId());
+        String firstLetter = PinYinUtil.getFirstLetter(extUser.getUserName());
+        if (qwSession == null) {
+
+            RLock lock = redissonClient.getLock("addSession" + extUser.getUserId() + qwUserId);
+            try {
+                boolean tryLock = lock.tryLock(2, 3, TimeUnit.SECONDS);
+                if (!tryLock) {
+                    log.warn("添加单聊Session获取锁失败");
+                    return null;
+                }
+
+                qwSession = qwSessionMapper.selectQwSessionByExtIdAndQwUserId(extUser.getUserId(), qwUser.getId());
+                if (qwSession == null) {
+                    qwSession = new QwSession();
+                    chatId = UUID.randomUUID().toString();
+                    qwSession.setChatId(chatId);
+                    qwSession.setCorpId(qwUser.getCorpId());
+                    qwSession.setQwExtWxId(String.valueOf(extWxId));
+                    qwSession.setQwExtId(extUser.getUserId().toString());
+                    qwSession.setQwUserId(qwUser.getId().toString());
+                    qwSession.setStatus(1);
+                    qwSession.setAvatar(extUser.getAvatar());
+                    qwSession.setNickName(extUser.getUserName());
+                    qwSession.setCompanyId(qwUser.getCompanyId());
+                    qwSession.setCompanyUserId(qwUser.getCompanyUserId());
+                    qwSession.setCreateTime(new Date());
+                    qwSession.setUpdateTime(new Date());
+                    qwSession.setIsRoom(0);
+                    qwSession.setFirstLetter(firstLetter);
+                    qwSessionMapper.insertQwSession(qwSession);
+                }
+            } catch (InterruptedException e) {
+                log.warn("获取锁失败 err: {}", e.getMessage(), e);
+                return null;
+            } finally {
+                lock.unlock();
+            }
+        }else {
+            qwSession.setUpdateTime(new Date());
+            qwSession.setNickName(extUser.getUserName());
+            qwSession.setFirstLetter(firstLetter);
+            qwSessionMapper.updateQwSession(qwSession);
+        }
+        return qwSession;
+    }
+
+    /**
+     * 获取群聊session
+     */
+    private QwSession getGroupQwSession(String chatId, String chatAvatar, QwUser qwUser) {
+        QwSession qwSession;
+        QwGroupChat qwGroupChat = qwGroupChatMapper.selectQwGroupChatByChatId(chatId);
+        if (Objects.isNull(qwGroupChat)){
+            log.warn("群聊不存在 serverId: {}, corpId: {}, qwUserId: {}, chatId: {}", qwUser.getServerId(), qwUser.getCorpId(), qwUser.getQwUserId(), chatId);
+            return null;
+        }
+
+        qwSession = qwSessionMapper.selectQwSessionByChatIdAndQwUserId(chatId, qwUser.getId());
+        String firstLetter = PinYinUtil.getFirstLetter(qwGroupChat.getName());
+        if (qwSession == null) {
+            RLock lock = redissonClient.getLock("addSession" + qwGroupChat.getChatId() + qwUser.getId());
+            try {
+                boolean tryLock = lock.tryLock(2, 3, TimeUnit.SECONDS);
+                if (!tryLock) {
+                    log.warn("添加群聊Session获取锁失败");
+                    return null;
+                }
+
+                qwSession = qwSessionMapper.selectQwSessionByChatIdAndQwUserId(chatId, qwUser.getId());
+                if (qwSession == null) {
+                    qwSession = new QwSession();
+                    qwSession.setChatId(chatId);
+                    qwSession.setCorpId(qwGroupChat.getCorpId());
+                    qwSession.setQwUserId(qwUser.getId().toString());
+                    qwSession.setStatus(1);
+                    qwSession.setAvatar(chatAvatar);
+                    qwSession.setNickName(qwGroupChat.getName());
+                    qwSession.setCompanyId(qwUser.getCompanyId());
+                    qwSession.setCreateTime(new Date());
+                    qwSession.setUpdateTime(new Date());
+                    qwSession.setIsRoom(1);
+                    qwSession.setFirstLetter(firstLetter);
+                    qwSessionMapper.insertQwSession(qwSession);
+                }
+            } catch (InterruptedException e) {
+                log.warn("获取锁失败 err: {}", e.getMessage(), e);
+                return null;
+            } finally {
+                lock.unlock();
+            }
+        }else {
+            qwSession.setUpdateTime(new Date());
+            qwSession.setQwUserId(qwUser.getId().toString());
+            qwSession.setNickName(qwGroupChat.getName());
+            qwSession.setAvatar(chatAvatar);
+            qwSession.setFirstLetter(firstLetter);
+            qwSessionMapper.updateQwSession(qwSession);
+        }
+        return qwSession;
+    }
+
     /**
      * 查询外部联系人
      * @param userId    用户ID
@@ -2236,4 +2308,44 @@ public class AiHookServiceImpl implements AiHookService {
         return qwExternalContactMapper.selectQwExternalContactByExternalUserIdAndQwUserId(getExtId(userId, uuid, serverId), corpId, qwUserId);
     }
 
+    /**
+     * 根据vid获取用户信息
+     */
+    private QwImUserDTO getUserByVid(Long vid, String uuid, Long serverId, String corpId, String qwUserId) {
+        if (vid == 0) {
+            return null;
+        }
+
+        // 外部联系人
+        if (vid > 2000000000000000L) {
+            QwExternalContact qwExternalContact = getExternalContact(vid, uuid, serverId, corpId, qwUserId);
+            if (Objects.isNull(qwExternalContact)) {
+                log.warn("外部联系人不存在 vid: {}, uuid: {}, serverId: {}, corpId: {}, qwUserId: {}", vid, uuid, serverId, corpId, qwUserId);
+                return null;
+            }
+
+            QwImUserDTO userDTO = new QwImUserDTO();
+            userDTO.setUserId(qwExternalContact.getId());
+            userDTO.setUserName(qwExternalContact.getName());
+            userDTO.setAvatar(qwExternalContact.getAvatar());
+            userDTO.setUserType(1);
+            return userDTO;
+        }
+        // 企微用户
+        else {
+            QwUser qwUser = qwUserService.selectQwUserByVid(vid);
+            if (Objects.isNull(qwUser)){
+                log.warn("企微用户不存在 vid: {}", vid);
+                return null;
+            }
+
+            QwImUserDTO userDTO = new QwImUserDTO();
+            userDTO.setUserId(qwUser.getId());
+            userDTO.setUserName(qwUser.getQwUserName());
+            userDTO.setAvatar(qwUser.getAvatar());
+            userDTO.setUserType(2);
+            return userDTO;
+        }
+    }
+
 }

+ 23 - 0
fs-service/src/main/java/com/fs/qw/dto/QwImUserDTO.java

@@ -0,0 +1,23 @@
+package com.fs.qw.dto;
+
+import lombok.Data;
+
+@Data
+public class QwImUserDTO {
+    /**
+     * 用户ID
+     */
+    private Long userId;
+    /**
+     * 用户类型 1外部联系人 2企微用户
+     */
+    private Integer userType;
+    /**
+     * 昵称
+     */
+    private String userName;
+    /**
+     * 头像
+     */
+    private String avatar;
+}

+ 3 - 4
fs-service/src/main/java/com/fs/qw/mapper/QwSessionMapper.java

@@ -7,6 +7,7 @@ import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 企微会话Mapper接口
@@ -67,15 +68,13 @@ public interface QwSessionMapper extends BaseMapper<QwSession>
     /**
      * 查询单聊会话
      */
-    @Select("select * from qw_session where qw_ext_id = #{qwExtId} and qw_user_id = #{qwUserId} and is_room = 0")
+    @Select("select * from qw_session where qw_ext_id = #{qwExtId} and qw_user_id = #{qwUserId, jdbcType=VARCHAR} and is_room = 0")
     QwSession selectQwSessionByExtIdAndQwUserId(@Param("qwExtId") Long qwExtId, @Param("qwUserId") Long id);
 
     /**
      * 根据企微用户ID查询会话列表
-     * @param qwUserId  企微用户ID
-     * @return  list
      */
-    List<QwContactListVO> selectContactListByQwUserId(@Param("qwUserId") Long qwUserId);
+    List<QwContactListVO> selectQwConversationByMap(@Param("params") Map<String, Object> params);
 
     /**
      * 查询群聊会话

+ 7 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java

@@ -442,4 +442,11 @@ public interface QwUserMapper extends BaseMapper<QwUser>
 
     List<QwOptionsVO> selectQwCompanyListOptionsVOBySys();
 
+    /**
+     * 根据销售ID查询企微用户列表
+     */
+    List<QwUserVO> selectQwUserVoListByCompanyUserId(@Param("companyUserId") Long companyUserId);
+
+    @Select("select * from qw_user where vid = #{vid}")
+    QwUser selectQwUserByVid(@Param("vid") Long vid);
 }

+ 4 - 6
fs-service/src/main/java/com/fs/qw/service/IQwMsgService.java

@@ -13,6 +13,7 @@ import com.fs.qw.vo.QwMessageListVO;
 import com.fs.qwHookApi.vo.QwHookMsgVO;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 企微聊天记录Service接口
@@ -77,12 +78,11 @@ public interface IQwMsgService extends IService<QwMsg>
      * @return
      */
     List<QwMsg> getQwMessageList(Long companyId);
+
     /**
-     * 查询会话
-     * @param userId
-     * @return
+     * 查询会话列表
      */
-    List<QwContactListVO> selectQwConversationByUserId(Long userId);
+    List<QwContactListVO> selectQwConversationByMap(Map<String, Object> params);
 
     List<QwMsg> selectQwMsgBySession(QwSessionParam param);
 
@@ -92,8 +92,6 @@ public interface IQwMsgService extends IService<QwMsg>
 
     R addAiMsg(QwSession session, String content, Integer msgType,QwUser user);
 
-    List<QwUser> qwUserList(Long userId);
-
     R sendMsg(QwMsgSendParam param);
 
     QwContactListVO selectQwSessionBycId(String conversationId, Long qwUserId);

+ 9 - 0
fs-service/src/main/java/com/fs/qw/service/IQwUserService.java

@@ -199,4 +199,13 @@ public interface IQwUserService
 
     List<QwOptionsVO> selectQwCompanyListOptionsVOBySys();
 
+    /**
+     * 根据销售ID查询企微用户列表
+     */
+    List<QwUserVO> selectQwUserVoListByCompanyUserId(Long companyUserId);
+
+    /**
+     * 根据Vid查询企微用户
+     */
+    QwUser selectQwUserByVid(Long vid);
 }

+ 7 - 55
fs-service/src/main/java/com/fs/qw/service/impl/QwMsgServiceImpl.java

@@ -12,9 +12,7 @@ import com.fs.common.exception.ServiceException;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.PinYinUtil;
 import com.fs.common.utils.StringUtils;
-import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyMiniapp;
-import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.mapper.CompanyMiniappMapper;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
@@ -487,15 +485,6 @@ public class QwMsgServiceImpl extends ServiceImpl<QwMsgMapper, QwMsg> implements
         return R.ok().put("data", listVO);
     }
 
-    @Override
-    public List<QwUser> qwUserList(Long userId) {
-        LambdaQueryWrapper<QwUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
-        lambdaQueryWrapper.eq(QwUser::getCompanyUserId, userId);
-        List<QwUser> qwUsers = qwUserMapper.selectList(lambdaQueryWrapper);
-        return qwUsers;
-    }
-
-
     @Override
     public List<QwMsg> getQwMessageList(Long companyId) {
         LambdaQueryWrapper<QwUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
@@ -519,49 +508,12 @@ public class QwMsgServiceImpl extends ServiceImpl<QwMsgMapper, QwMsg> implements
         return qwMsgs;
     }
 
+    /**
+     * 查询会话列表
+     */
     @Override
-    public List<QwContactListVO> selectQwConversationByUserId(Long userId) {
-        // 查询会话列表
-        List<QwContactListVO> contactList = qwSessionMapper.selectContactListByQwUserId(userId);
-        if (contactList.isEmpty()) {
-            return new ArrayList<>();
-        }
-
-        ArrayList<QwContactListVO> qwContactListVOS = new ArrayList<>();
-        for (QwContactListVO listVO : contactList) {
-            LambdaQueryWrapper<QwMsg> lambdaQueryWrapper = new LambdaQueryWrapper<>();
-            lambdaQueryWrapper.select(QwMsg.class, q -> !q.getColumn().equals("remark"));
-            lambdaQueryWrapper.eq(QwMsg::getSessionId, Integer.parseInt(listVO.getConversationId()));
-            lambdaQueryWrapper.orderByDesc(QwMsg::getMsgId);
-            lambdaQueryWrapper.last("limit 1");
-            List<QwMsg> qwMsgs = qwMsgMapper.selectList(lambdaQueryWrapper);
-            if (CollectionUtil.isEmpty(qwMsgs)){
-                listVO.setType("text");
-                listVO.setLastContent("");
-                listVO.setLastSendTime(null);
-                listVO.setUnread(0);
-                qwContactListVOS.add(listVO);
-                break;
-            }
-            QwMsg qwMsg = qwMsgs.get(0);
-            if (qwMsg.getMsgType() == 1) {
-                listVO.setType("text");
-            } else if (qwMsg.getMsgType() == 2) {
-                listVO.setType("image");
-            } else if (qwMsg.getMsgType() == 3) {
-                listVO.setType("emotionDynamic");
-            } else if (qwMsg.getMsgType() == 4) {
-                listVO.setType("voice");
-            } else if (qwMsg.getMsgType() == 5) {
-                listVO.setType("miniprogram");
-            }
-            listVO.setMsgId(qwMsg.getMsgId());
-            listVO.setLastContent(qwMsgs.get(0).getContent());
-            listVO.setLastSendTime(qwMsgs.get(0).getCreateTime().getTime());
-            listVO.setUnread(0);
-            qwContactListVOS.add(listVO);
-        }
-        return qwContactListVOS;
+    public List<QwContactListVO> selectQwConversationByMap(Map<String, Object> params) {
+        return qwSessionMapper.selectQwConversationByMap(params);
     }
 
     @Override
@@ -675,7 +627,7 @@ public class QwMsgServiceImpl extends ServiceImpl<QwMsgMapper, QwMsg> implements
                     throw new ServiceException("群聊不存在");
                 }
 
-                RLock lock = redissonClient.getLock("addSession" + id + qwUser);
+                RLock lock = redissonClient.getLock("addSession" + id + qwUserId);
                 try {
                     boolean tryLock = lock.tryLock(2, 3, TimeUnit.SECONDS);
                     if (!tryLock) {
@@ -713,7 +665,7 @@ public class QwMsgServiceImpl extends ServiceImpl<QwMsgMapper, QwMsg> implements
                     throw new ServiceException("外部联系人不存在");
                 }
 
-                RLock lock = redissonClient.getLock("addSession" + id + qwUser);
+                RLock lock = redissonClient.getLock("addSession" + id + qwUserId);
                 try {
                     boolean tryLock = lock.tryLock(2, 3, TimeUnit.SECONDS);
                     if (!tryLock) {

+ 16 - 0
fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceImpl.java

@@ -1559,6 +1559,22 @@ public class QwUserServiceImpl implements IQwUserService
         return qwUserMapper.selectQwCompanyListOptionsVOBySys();
     }
 
+    /**
+     * 根据销售ID查询企微用户列表
+     */
+    @Override
+    public List<QwUserVO> selectQwUserVoListByCompanyUserId(Long companyUserId) {
+        return qwUserMapper.selectQwUserVoListByCompanyUserId(companyUserId);
+    }
+
+    /**
+     * 根据Vid查询企微用户
+     */
+    @Override
+    public QwUser selectQwUserByVid(Long vid) {
+        return qwUserMapper.selectQwUserByVid(vid);
+    }
+
 
     /**
      * 构建查询条件

+ 2 - 0
fs-service/src/main/java/com/fs/qw/vo/QwContactListVO.java

@@ -24,4 +24,6 @@ public class QwContactListVO {
     private Boolean isBlack;
     // 是否重粉
     private Boolean isRepeat;
+    // 是否待处理
+    private Boolean isPend;
 }

+ 3 - 0
fs-service/src/main/java/com/fs/qw/vo/QwUserVO.java

@@ -22,6 +22,9 @@ public class QwUserVO {
     @Excel(name = "企微昵称")
     private String qwUserName;
 
+    /** 头像 **/
+    private String avatar;
+
     private String department;
 
     private String departmentName;

+ 9 - 9
fs-service/src/main/resources/mapper/qw/QwExternalContactMapper.xml

@@ -796,15 +796,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="getContactListByQwUserId" resultType="com.fs.qw.vo.QwContactVO">
         select
-            qec.id                                  as id,
-            qs.session_id                           as conversationId,
-            ifnull(qec.name, qs.avatar)             as displayName,
-            ifnull(qec.avatar, qs.avatar)           as avatar,
-            ifnull(qs.first_letter, '未定义')        as `index`,
-            0                                       as unread,
-            unix_timestamp(qm.create_time) * 1000   as lastSendTime,
-            qm.content                              as lastContent,
-            false                                   as isGroup
+            qec.id                                              as id,
+            qs.session_id                                       as conversationId,
+            ifnull(qec.name, qs.avatar)                         as displayName,
+            ifnull(qec.avatar, qs.avatar)                       as avatar,
+            ifnull(nullif(qs.first_letter, ''), '未定义')        as `index`,
+            0                                                   as unread,
+            unix_timestamp(qm.create_time) * 1000               as lastSendTime,
+            qm.content                                          as lastContent,
+            false                                               as isGroup
         from qw_external_contact qec
         left join qw_session qs on qec.id = qs.qw_ext_id and qs.is_room = 0
         left join (

+ 9 - 9
fs-service/src/main/resources/mapper/qw/QwGroupChatMapper.xml

@@ -211,15 +211,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="getGroupListByQwUserId" resultType="com.fs.qw.vo.QwContactVO">
         select
-            qgc.chat_id                             as id,
-            qs.session_id                           as conversationId,
-            ifnull(qgc.name, qs.avatar)             as displayName,
-            qs.avatar                               as avatar,
-            ifnull(qs.first_letter, '未定义')        as `index`,
-            0                                       as unread,
-            unix_timestamp(qm.create_time) * 1000   as lastSendTime,
-            qm.content                              as lastContent,
-            true                                    as isGroup
+            qgc.chat_id                                         as id,
+            qs.session_id                                       as conversationId,
+            ifnull(qgc.name, qs.avatar)                         as displayName,
+            qs.avatar                                           as avatar,
+            ifnull(nullif(qs.first_letter, ''), '未定义')        as `index`,
+            0                                                   as unread,
+            unix_timestamp(qm.create_time) * 1000               as lastSendTime,
+            qm.content                                          as lastContent,
+            true                                                as isGroup
         from qw_group_chat qgc
         inner join qw_user qu on qu.qw_user_id = qgc.owner
         left join qw_session qs on qgc.chat_id = qs.chat_id and qs.is_room = 1

+ 37 - 10
fs-service/src/main/resources/mapper/qw/QwSessionMapper.xml

@@ -50,21 +50,48 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where session_id = #{sessionId}
     </select>
 
-    <select id="selectContactListByQwUserId" resultType="com.fs.qw.vo.QwContactListVO">
+    <select id="selectQwConversationByMap" resultType="com.fs.qw.vo.QwContactListVO">
         select
-            s.session_id as id,
-            s.qw_ext_id extId,
+            s.session_id                                            as id,
+            s.qw_ext_id                                             as extId,
             s.avatar,
-            s.session_id conversationId,
-            s.nick_name displayName,
-            ec.comment_status isBlack,
-            s.is_room isGroup,
-            if(u.qw_repeat = 1 OR u.user_repeat = 1, true, false) isRepeat
+            s.session_id                                            as conversationId,
+            s.nick_name                                             as displayName,
+            ec.comment_status = 1                                   as isBlack,
+            s.is_room                                               as isGroup,
+            (u.qw_repeat = 1 OR u.user_repeat = 1)                  as isRepeat,
+            qwk.status = 0                                          as isPend,
+            qm.msg_id                                               as msgId,
+            case qm.msg_type
+                when 1 then 'text'
+                when 2 then 'image'
+                when 3 then 'emotiondynamic'
+                when 4 then 'voice'
+                when 5 then 'miniprogram'
+                else 'text'
+            end                                                     as type,
+            qm.content                                              as lastContent,
+            unix_timestamp(qm.create_time) * 1000                   as lastSendTime,
+            0                                                       as unread
         from qw_session s
         left join qw_external_contact ec on s.qw_ext_id = ec.id
         left join fs_user u on ec.fs_user_id = u.user_id
-        where s.qw_user_id = #{qwUserId}
-        order by s.update_time desc
+        left join qw_work_task qwk on qwk.ext_id = ec.id
+        left join (
+            select session_id, max(msg_id) as max_msg_id from qw_msg group by session_id
+        ) latest_msg on latest_msg.session_id = s.session_id
+        left join qw_msg qm on qm.msg_id = latest_msg.max_msg_id
+        where s.qw_user_id = #{params.qwUserId}
+        <if test="params.isBlack != null and params.isBlack">
+            and ec.comment_status = 1
+        </if>
+        <if test="params.isRepeat != null and params.isRepeat">
+            and (u.qw_repeat = 1 OR u.user_repeat = 1)
+        </if>
+        <if test="params.isPend != null and params.isPend">
+            and qwk.status = 0
+        </if>
+        order by qwk.status is null, qwk.status, s.update_time desc
     </select>
 
     <insert id="insertQwSession" parameterType="QwSession" useGeneratedKeys="true" keyProperty="sessionId">

+ 10 - 0
fs-service/src/main/resources/mapper/qw/QwUserMapper.xml

@@ -295,4 +295,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </if>
     </select>
 
+    <select id="selectQwUserVoListByCompanyUserId" resultType="com.fs.qw.vo.QwUserVO">
+        select
+            qu.*,
+            qc.corp_name
+        from qw_user qu
+        inner join qw_company qc on qu.corp_id = qc.corp_id
+        where qu.is_del = 0 and qu.app_key is not null
+        and qu.company_user_id = #{companyUserId}
+    </select>
+
 </mapper>