Selaa lähdekoodia

Merge branch 'im-dev' into single-im-chat

wkw 1 kuukausi sitten
vanhempi
sitoutus
e36da9d64d

+ 64 - 36
src/stores/modules/webSocketStore.js

@@ -334,11 +334,11 @@ export const useWebSocketStore = defineStore("webSocketStore", {
 
       // 构造完整消息
       const fullMessage = {
+        fromUsername: this.toUserInfo.nickname,
+        avatar: walletStore.avatar,
         to: this.toUserInfo.uuid,
         from: walletStore.account,
         ...messageData,
-        fromUsername: walletStore.username,
-        avatar: walletStore.avatar,
         timestamp: Date.now(),
       };
 
@@ -461,7 +461,7 @@ export const useWebSocketStore = defineStore("webSocketStore", {
       if (!systemStore.messageList[sessionId]) {
         systemStore.messageList[sessionId] = [];
         if (sessionId == message.from){
-          this.getMessages({ uuid: message.from, friendUsername: message.to, messageType: message.messageType },true);
+          // this.getMessages({ uuid: message.from, friendUsername: message.to, messageType: message.messageType },true);
         }
       }
       systemStore.messageList[sessionId].push(message);
@@ -470,12 +470,13 @@ export const useWebSocketStore = defineStore("webSocketStore", {
         this.messages.push(message);
         this.indexs +=1;
       }
-      console.log('pushMessage', systemStore.messageList, this.messages)
+      // console.log('pushMessage', systemStore.messageList, this.messages)
       // 更新会话最新消息
       this.updateSessionNewMessage(message, sessionId)
     },
     // 更新本地真实消息id
     modifyMessageId(message, msg, sessionId = null) { 
+      // console.log(msg, message, sessionId)
       const systemStore = useSystemStore();
       if(!sessionId){
         sessionId = message.from;
@@ -483,20 +484,25 @@ export const useWebSocketStore = defineStore("webSocketStore", {
       if (!systemStore.messageList[sessionId]) {
         systemStore.messageList[sessionId] = [];
       }
-      systemStore.messageList[sessionId] = systemStore.messageList[sessionId].map(item => {
-        if (!item.id && item.msgId + '' === msg?.msgId + '') return {...item, id: msg.id, msgId: undefined, err: !msg.id?true:undefined};
-        if (item.id + '' === msg?.msgId + '') return {...item, content: "", url: ""};
+      systemStore.messageList[sessionId] = [...systemStore.messageList[sessionId]].map(item => {
+        // 消息发送成功确认
+        if (!item.id && msg.msgId && item.msgId + '' === msg.msgId + '') return {...item, id: msg.id, msgId: undefined, err: !msg.id?true:undefined};
+        // 阅后即焚
+        // console.log(item.id, msg?.id)
+        if (item.id + '' === msg?.id + '') return {...item, isTemp: true, content: "", url: ""};
         return item;
       });
       // 检测当前消息
       if (this.toUserInfo.uuid === sessionId) { 
-        this.messages = this.messages.map(item => {
-          if (!item.id && item.msgId + '' === msg?.msgId + '') return {...item, id: msg.id, msgId: undefined, err: !msg.id?true:undefined};
-          if (item.id + '' === msg?.msgId + '') return {...item, content: "", url: ""};
+        this.messages = [...this.messages].map(item => {
+          // 消息发送成功确认
+          if (!item.id && msg.msgId && item.msgId + '' === msg?.msgId + '') return { ...item, id: msg.id, msgId: undefined, err: !msg.id?true:undefined};
+          // 阅后即焚
+          if (item.id + '' === msg?.id + '') return { ...item, isTemp: true, content: "", url: ""};
           return item;
         });
       }
-      // console.log("修改消息", message, sessionId, systemStore.messageList, this.toUserInfo.uuid, this.messages);
+      console.log("修改消息", message, sessionId, systemStore.messageList,this.messages);
     },
     // 更新本地消息
     modifyMessage(message, msgId, sessionId = null) { 
@@ -507,26 +513,26 @@ export const useWebSocketStore = defineStore("webSocketStore", {
       if (!systemStore.messageList[sessionId]) {
         systemStore.messageList[sessionId] = [];
       }
-      systemStore.messageList[sessionId] = systemStore.messageList[sessionId].map(item => {
+      systemStore.messageList[sessionId] = [...systemStore.messageList[sessionId]].map(item => {
         if(typeof msgId === 'function'){
           let msg = {};
           if(msg = msgId(item, sessionId)){
-            return {...item,...msg};
+            return { ...item, ...msg};
           }
         }
-        else if (item.id + '' === msgId + '') return {...item, ...message, content: "", url: ""};
+        else if (item.id + '' === msgId + '') return {...item, ...message};
         return item;
       });
       // 检测当前消息
       if (this.toUserInfo.uuid === sessionId) { 
-        this.messages = this.messages.map(item => {
+        this.messages = [...this.messages].map(item => {
           if(typeof msgId === 'function'){
             let msg = {};
             if(msg = msgId(item, sessionId)){
               return {...item,...msg};
             }
           }
-          else if (item.id + '' === msgId + '') return {...item, ...message, content: "", url: ""};
+          else if (item.id + '' === msgId + '') return {...item, ...message};
           return item;
         });
       }
@@ -576,7 +582,7 @@ export const useWebSocketStore = defineStore("webSocketStore", {
           timestamp: Date.now(),
         }),
       };
-      console.log("systemReceiptMessage", response);
+      // console.log("systemReceiptMessage", response);
       this.sendMessage(response)
     },
     // 获取会话消息
@@ -595,7 +601,7 @@ export const useWebSocketStore = defineStore("webSocketStore", {
         systemStore.messageList[sessionId] = [];
       }
       if(all){
-        systemStore.messageList[sessionId] =  data.filter(val=>!systemStore.messageList[sessionId].find(v=>v.id == val.id))
+        systemStore.messageList[sessionId] =  data //.filter(val=>!systemStore.messageList[sessionId].find(v=>v.id == val.id))
         return;
       }
       systemStore.messageList[sessionId] = data;
@@ -660,21 +666,21 @@ export const useWebSocketStore = defineStore("webSocketStore", {
 
       const time = new Date(ts).toLocaleString().replaceAll("/", "-");
       // 消息类型映射
-      // const mapSet = {
-      //   [MsgType.MSG_TYPE.FILE]: '[文件]',
-      //   [MsgType.MSG_TYPE.IMAGE]: '[图片]',
-      //   [MsgType.MSG_TYPE.AUDIO]: '[音频]',
-      //   [MsgType.MSG_TYPE.VIDEO]: '[视频]',
-      //   [MsgType.MSG_TYPE.AUDIO_ONLINE]: '[语音通话]',
-      //   [MsgType.MSG_TYPE.VIDEO_ONLINE]: '[视频通话]',
-      //   // [Constant.CANCELL_AUDIO_ONLINE]:'[通话结束]',
-      //   // [Constant.REJECT_AUDIO_ONLINE]: '[对方拒绝]',
-      //   // [Constant.CANCELL_VIDEO_ONLINE]: '[通话结束]',
-      //   // [Constant.REJECT_VIDEO_ONLINE]: '[对方拒绝]',
-      // };
+      const mapSet = {
+        [MsgType.MSG_TYPE.FILE]: '[文件]',
+        [MsgType.MSG_TYPE.IMAGE]: '[图片]',
+        [MsgType.MSG_TYPE.AUDIO]: '[音频]',
+        [MsgType.MSG_TYPE.VIDEO]: '[视频]',
+        [MsgType.MSG_TYPE.AUDIO_ONLINE]: '[语音通话]',
+        [MsgType.MSG_TYPE.VIDEO_ONLINE]: '[视频通话]',
+        // [Constant.CANCELL_AUDIO_ONLINE]:'[通话结束]',
+        // [Constant.REJECT_AUDIO_ONLINE]: '[对方拒绝]',
+        // [Constant.CANCELL_VIDEO_ONLINE]: '[通话结束]',
+        // [Constant.REJECT_VIDEO_ONLINE]: '[对方拒绝]',
+      };
       // 检测最新消息
-      // let lastMsg = message.contentType === MsgType.MSG_TYPE.TEXT || message.contentType === MsgType.MSG_TYPE.NOTICE ? (msg?msg.content : message.content) : (mapSet[message.contentType] || '[语音视频]');
-      let lastMsg = msg ? msg.content : message.content;
+      let lastMsg = message.contentType === MsgType.MSG_TYPE.TEXT || message.contentType === MsgType.MSG_TYPE.NOTICE ? (msg?msg.content : message.content) : (mapSet[message.contentType] || '[语音视频]');
+      // let lastMsg = msg ? msg.content : message.content;
       // 阅后即焚消息
       if(message.isTemp){
         lastMsg = '[阅后即焚]';
@@ -714,6 +720,19 @@ export const useWebSocketStore = defineStore("webSocketStore", {
       // 强制刷新会话列表
       this.chatRefresh += 1;
     },
+    // 修改好友备注后,将好友会话名称更改
+    updateNote(newName,uuid){
+      const systemStore = useSystemStore();
+      systemStore.ImsessionList = [...systemStore.ImsessionList].map((item) => {
+        if (item.uuid == uuid) {
+          return { ...item, sessionName: newName };
+        }
+        return item;
+      })
+      if (this.toUserInfo.uuid == uuid){
+        this.toUserInfo.sessionName = newName;
+      }
+    },
 
 
     // ************ 接收方 方法 ************//
@@ -763,7 +782,7 @@ export const useWebSocketStore = defineStore("webSocketStore", {
           this.funRestoreDelAuth(message.from);
         }
         // 刷新会话列表
-        // this.needRefreshIm += 1;
+        this.chatRefresh += 1;
       }
       // 群通知
       if (message.messageType == MsgType.MESSAGE_NOTICE_GROUP) {
@@ -790,7 +809,14 @@ export const useWebSocketStore = defineStore("webSocketStore", {
           } : (msg.uuid == val.toUuid ? {
             toUsername: msg.name
           }:{})
-        })
+        });
+        // 个人群昵称
+        if (msg.name) {
+          this.updateSessionNewMessage({ name: msg.name }, msg.uuid);
+          if (this.toUserInfo.uuid === msg.uuid) {
+            this.toUserInfo.nickname = msg.name
+          }
+        }
       }
     },
 
@@ -863,12 +889,13 @@ export const useWebSocketStore = defineStore("webSocketStore", {
       this.unread = true;
     },
     // 初始化好友申请记录
-    async funInitfriend(uuid){
+    async funInitfriend(uuid,force=false){
       console.log('好友申请数据',this.applyfriend)
-      if (Object.keys(this.applyfriend).length > 0){
+      if (!force && Object.keys(this.applyfriend).length > 0){
         this.unread = true;
         return
       };
+      this.applyfriend = {}
       const res = await friendRequest({ uuid, status: 1,state:1 });
       this.updateFriendApply(res.data || []);
     },
@@ -954,6 +981,7 @@ export const useWebSocketStore = defineStore("webSocketStore", {
       this.messages = [];
       this.groupMembersList = {};
       this.toUserInfo = {};
+      this.toUserAudioInfo = {};
       this.messageQueue = [];
       systemStore.ImsessionList = [];
       this.onMessageCallbacks = [];

+ 6 - 0
src/stores/modules/webrtcStore.js

@@ -128,6 +128,10 @@ export const useWebRTCStore = defineStore("webrtc", {
             wsStore.sendMessage({
               content: JSON.stringify(candidate),
               type: Constant.MESSAGE_TRANS_TYPE,
+              fromUsername: wsStore.toUserAudioInfo.fromUsername,
+              avatar: wsStore.toUserAudioInfo.fromAvatar,
+              to: wsStore.toUserAudioInfo.toUuid,
+              from: wsStore.toUserAudioInfo.fromUuid,
             });
             // 本地缓存ice
             this.iceCandidates.push(event.candidate);
@@ -283,6 +287,8 @@ export const useWebRTCStore = defineStore("webrtc", {
 
       this.iceCandidates = [];
       this.connectionState = "disconnected";
+
+      this.isCaller = false;
     },
 
     // 获取视频流

+ 141 - 106
src/views/im/chat/index.vue

@@ -8,7 +8,7 @@
     <div class="header-chat">
       <svg-icon class="page-icon" name="lf-arrow" @click="goBack" />
       <div class="header-title" v-if="wsStore.toUserInfo.type == 'group'"><span class="m-ellipsis">{{ wsStore.toUserInfo.sessionName || '群聊' }}</span>({{ groupMembersArr.length }})</div>
-      <div v-else class="header-title">{{ wsStore.toUserInfo.nickname }}</div>
+      <div v-else class="header-title">{{ wsStore.toUserInfo.sessionName }}</div>
       <svg-icon class="page-icon" name="more" @click="goDetail" />
     </div>
 
@@ -17,120 +17,121 @@
       <div class="m-ellipsis">群公告:{{ wsStore.toUserInfo.notice }}</div>
       <svg-icon class="item-icon" name="right1" />
     </div>
-
     <!-- 聊天消息区域 -->
     <div class="chat-list" ref="chatListRef">
       <van-loading class="load-box" size="24px" v-if="wsStore.loading">加载中...</van-loading>
       <template v-else>
-      <div v-for="(item, index) in imMessages" :key="index">
-        <div class="chat-time">
-          {{ item.createDate || formatTime(Date.now()) }}
-        </div>
-        <div class="box" v-if="item.contentType !== MsgType.MSG_TYPE.NOTICE">
-          <div
-            class="list-item"
-            :class="isSender(item) ? '' : 'flex-reverse'"
-          >
-            <!-- 头像 -->
-            <van-image
-              class="list-img"
-              :class="isSender(item) ? 'mr12' : 'ml12'"
-              round
-              :src="formatAvatarUrl(item)"
-              @click="goToPage(item)"
-            />
-            <!-- 内容 -->
-            <div class="list-cont">
-              <div>{{ item.sender?item.sender.nickname: (item.nickname || item.fromUsername || "匿名用户") }}</div>
-
-              <div v-if="!item.isTemp || item.from == walletStore.account" style="position: relative;"> 
-                <!-- 文本消息 -->
-                <div class="content" v-if="item.contentType === MsgType.MSG_TYPE.TEXT" @click="onLongPress(item)">
-                  <span v-if="item.err" style="color: red;font-size: small;">{{item.messageType == MsgType.MESSAGE_TYPE_USER?'对方已不是您的好友':'您已不在群里'}}</span>
-                  {{ item.content }}
-                </div>
-
-                <!-- 图片消息 -->
-                <div
-                  class="img-message"
-                  v-else-if="item.contentType === MsgType.MSG_TYPE.IMAGE"
-                >
-                  <van-image
-                    :src="item?.localUrl || IM_PATH + item.url"
-                    style="max-width: 120px; border-radius: 8px"
-                    @click="previewImage(item)"
-                  />
-                </div>
-
-                <!-- 名片消息 -->
-                <div
-                  class="content card-message"
-                  v-else-if="item.contentType === 3"
-                >
-                  <div class="card-title">名片</div>
-                  <div class="card-name">{{ item.content }}</div>
-                </div>
+        <van-pull-refresh v-model="refreshLoading" @refresh="onRefresh" style="overflow: initial;">
+        <div v-for="(item, index) in imMessages" :key="index">
+          <div class="chat-time">
+            {{ item.createDate || formatTime(Date.now()) }}
+          </div>
+          <div class="box" v-if="item.contentType !== MsgType.MSG_TYPE.NOTICE">
+            <div
+              class="list-item"
+              :class="isSender(item) ? '' : 'flex-reverse'"
+            >
+              <!-- 头像 -->
+              <van-image
+                class="list-img"
+                :class="isSender(item) ? 'mr12' : 'ml12'"
+                round
+                :src="formatAvatarUrl(item)"
+                @click="goToPage(item)"
+              />
+              <!-- 内容 -->
+              <div class="list-cont">
+                <div>{{ item.sender?item.sender.nickname: (item.nickname || item.fromUsername || "匿名用户") }}</div>
+
+                <div v-if="!item.isTemp " style="position: relative;"> 
+                  <!-- 文本消息 -->
+                  <div class="content" v-if="item.contentType === MsgType.MSG_TYPE.TEXT" @click="onLongPress(item)">
+                    <span v-if="item.err" style="color: red;font-size: small;">{{item.messageType == MsgType.MESSAGE_TYPE_USER?'对方已不是您的好友':'您已不在群里'}}</span>
+                    {{ item.content }}
+                  </div>
 
-                <!-- 录音消息 -->
-                <div
-                  class="audio-message"
-                  v-else-if="item.contentType === MsgType.MSG_TYPE.AUDIO"
-                >
-                  <messageAudio
-                    :src="item?.localUrl || IM_PATH + item.url"
-                    :isSender="isSender(item)"
-                  />
-                </div>
-                <!-- 拍摄 -->
-                <video class="video-message" :isSender="isSender(item)" controls v-else-if="item.contentType === MsgType.MSG_TYPE.VIDEO" :src="item?.localUrl || IM_PATH + item.url"></video>
-
-                <!-- 语音消息 -->
-                <div class="content" v-if="item.contentType === Constant.REJECT_AUDIO_ONLINE || item.contentType === Constant.REJECT_VIDEO_ONLINE">[对方拒绝]</div>
-                <div class="content" v-if="item.contentType === Constant.CANCELL_AUDIO_ONLINE || item.contentType === Constant.CANCELL_VIDEO_ONLINE">[通话结束]</div>
-                
-                <div v-if="item.quote > 0" class="quotation">{{ item.quoteMsg?.content }}</div>
-              </div>
-              <!-- 阅后即焚消息 -->
-              <div
-                v-else
-                class="burn-message"
-                @click="viewBurnMessage(item)"
-              >
-                <!-- 未查看 -->
-                <div v-if="!item.view && item.content" class="burn-mask">
-                  阅后即焚,点击查看
-                </div>
+                  <!-- 图片消息 -->
+                  <div
+                    class="img-message"
+                    v-else-if="item.contentType === MsgType.MSG_TYPE.IMAGE"
+                  >
+                    <van-image fit="cover"
+                      :src="item?.localUrl || IM_PATH + item.url"
+                      style="width: 120px;height: 150px; border-radius: 8px"
+                      @click="previewImage(item)"
+                    />
+                  </div>
 
-                <!-- 已查看且正在倒计时 -->
-                <template v-else-if="item.view && item.countdown > 0 && item.content">
-                  <!-- 文本类型 -->
-                  <div v-if="item.contentType === MsgType.MSG_TYPE.TEXT" class="burn-content">
-                    {{ item.content }}
-                    <span class="burn-countdown">{{ item.countdown }}s</span>
+                  <!-- 名片消息 -->
+                  <div
+                    class="content card-message"
+                    v-else-if="item.contentType === 3"
+                  >
+                    <div class="card-title">名片</div>
+                    <div class="card-name">{{ item.content }}</div>
                   </div>
 
-                  <!-- 录音类型 -->
-                  <div v-else-if="item.contentType === MsgType.MSG_TYPE.AUDIO" class="burn-audio">
+                  <!-- 录音消息 -->
+                  <div
+                    class="audio-message"
+                    v-else-if="item.contentType === MsgType.MSG_TYPE.AUDIO"
+                  >
                     <messageAudio
                       :src="item?.localUrl || IM_PATH + item.url"
                       :isSender="isSender(item)"
                     />
-                    <span class="burn-countdown">{{ item.countdown }}s</span>
                   </div>
-                </template>
+                  <!-- 拍摄 -->
+                  <video class="video-message" :isSender="isSender(item)" controls v-else-if="item.contentType === MsgType.MSG_TYPE.VIDEO" :src="item?.localUrl || IM_PATH + item.url"></video>
+
+                  <!-- 语音消息 -->
+                  <div class="content" v-if="item.contentType === Constant.REJECT_AUDIO_ONLINE || item.contentType === Constant.REJECT_VIDEO_ONLINE">[对方拒绝]</div>
+                  <div class="content" v-if="item.contentType === Constant.CANCELL_AUDIO_ONLINE || item.contentType === Constant.CANCELL_VIDEO_ONLINE">[通话结束]</div>
+                  
+                  <div v-if="item.quote > 0" class="quotation">{{ item.quoteMsg?.content }}</div>
+                </div>
+                <!-- 阅后即焚消息 -->
+                <div
+                  v-else
+                  class="burn-message"
+                  @click="viewBurnMessage(item)"
+                >
+                  <!-- 未查看 -->
+                  <div v-if="!item.view && item.content" class="burn-mask">
+                    阅后即焚,点击查看
+                  </div>
 
-                <!-- 倒计时结束 -->
-                <div v-else class="burn-destroyed">
-                  该消息已焚毁
+                  <!-- 已查看且正在倒计时 -->
+                  <template v-else-if="item.view && item.countdown > 0 && item.content">
+                    <!-- 文本类型 -->
+                    <div v-if="item.contentType === MsgType.MSG_TYPE.TEXT" class="burn-content">
+                      {{ item.content }}
+                      <span class="burn-countdown">{{ item.countdown }}s</span>
+                    </div>
+
+                    <!-- 录音类型 -->
+                    <div v-else-if="item.contentType === MsgType.MSG_TYPE.AUDIO" class="burn-audio">
+                      <messageAudio
+                        :src="item?.localUrl || IM_PATH + item.url"
+                        :isSender="isSender(item)"
+                      />
+                      <span class="burn-countdown">{{ item.countdown }}s</span>
+                    </div>
+                  </template>
+
+                  <!-- 倒计时结束 -->
+                  <div v-else class="burn-destroyed">
+                    该消息已焚毁
+                  </div>
                 </div>
               </div>
             </div>
           </div>
+          <div class="chat-time" v-if="item.contentType === MsgType.MSG_TYPE.NOTICE">
+            {{ item.content }}
+          </div>
         </div>
-        <div class="chat-time" v-if="item.contentType === MsgType.MSG_TYPE.NOTICE">
-          {{ item.content }}
-        </div>
-      </div>
+      </van-pull-refresh>
       </template>
     </div>
     <!-- 群公告组件 -->
@@ -326,6 +327,7 @@ const rtcStore = useWebRTCStore();
 const text = ref("");
 
 // 状态管理
+const refreshLoading = ref(false);
 const keyboardHeight = ref(0);
 const showEmoji = ref(false);
 const showTools = ref(false);
@@ -357,6 +359,15 @@ const showActionSheet = ref(false)
 const actions = ref([])
 const chatVideo = ref(false);
 
+// 下拉刷新
+const onRefresh = async () => {
+  await wsStore.getMessages({
+    uuid: route.query.uuid,
+    messageType: wsStore.toUserInfo.type == 'user'?1:2, //1:个人  2:群组
+    friendUsername: walletStore.account
+  },true);
+};
+
 const formatAvatarUrl = (item) => {
   const url = item?.sender?.avatar || item?.fromAvatar || ''
   if (/^https?:\/\//.test(url)) {
@@ -585,7 +596,7 @@ const destroyMessage = (message) => {
   if (message.messageType ==  MsgType.MESSAGE_TYPE_GROUP) {
     const msg = {isTemp: true, content: '', contentType: message.contentType, messageType: message.messageType};
     // 更新消息
-    wsStore.modifyMessage(msg, message.id, wsStore.toUserInfo.uuid);
+    wsStore.modifyMessageId(msg, message, wsStore.toUserInfo.uuid);
     // 更新会话列表
     wsStore.updateSessionNewMessage(msg, wsStore.toUserInfo.uuid);
     return;
@@ -868,25 +879,47 @@ const handleSendVideo = async (blob) =>{
 // ==== 1. 发起语音通话 ====
 const startAudioOnline = async (contentType, streamType) => {
   // 清理被呼叫者信息
-  wsStore.toUserInfo.sender = null;
+  wsStore.toUserAudioInfo = {
+    uuid:walletStore.account,
+    type: "user",
+    // 自己的信息
+    fromUuid: walletStore.account,
+    fromAvatar: walletStore.avatar,
+    fromUsername: wsStore.toUserInfo.nickname,
+    // 拨号目标信息
+    toUuid: wsStore.toUserInfo.uuid,
+    toUsername:wsStore.toUserInfo.sessionName,
+    toAvatar:wsStore.toUserInfo.avatar,
+    // 发送者信息
+    sender: {
+      uuid: walletStore.account,
+      avatar: walletStore.avatar,
+      nickname: wsStore.toUserInfo.nickname,
+    },
+  };
+  // wsStore.toUserInfo.sender = null;
   // 调起通话界面
   rtcStore.streamType = streamType
   rtcStore.imSate.videoCallModal = true;
   // 设置被呼叫对象
-  rtcStore.imSate.callAvatar = wsStore.toUserInfo.avatar;
-  rtcStore.imSate.callName = wsStore.toUserInfo.nickname;
+  rtcStore.imSate.callAvatar = wsStore.toUserAudioInfo.toAvatar;
+  rtcStore.imSate.callName = wsStore.toUserAudioInfo.toUsername;
   // 设置呼叫者/被呼叫者
   rtcStore.isCaller = true;
-  // 通知被呼叫者
+  // 通知被呼叫者(接听者)
   wsStore.sendMessage({
     messageType: wsStore.toUserInfo.type == 'user'?MsgType.MESSAGE_TYPE_USER:MsgType.MESSAGE_TYPE_GROUP,
     contentType,
     type: Constant.MESSAGE_TRANS_TYPE,
-    avatar: walletStore.avatar,
+    // avatar: walletStore.avatar,
     content: JSON.stringify({
       content: walletStore.username,
       sender: walletStore.account,
-    })
+    }),
+    fromUsername: wsStore.toUserAudioInfo.fromUsername,
+    avatar: wsStore.toUserAudioInfo.fromAvatar,
+    to: wsStore.toUserAudioInfo.toUuid,
+    from: wsStore.toUserAudioInfo.fromUuid,
   });
   // 播放铃声
   soundVoice.play() 
@@ -1412,11 +1445,13 @@ const goDetail = () =>{
   }
 }
 .sendText{
-  border-radius: 5px;
+  border: none !important;
+  height: 25px !important;
+  line-height: 25px !important;
+  border-radius: 4px;
   background-color: #4765dd;
   padding: 0 16px;
-  height: 30px;
-  line-height: 30px;
+  box-sizing: border-box;
 }
 :deep(.van-button:before){
   border: none;

+ 28 - 5
src/views/im/components/CallController/index.vue

@@ -157,7 +157,6 @@ const statusText = computed(() => {
 // 接收消息处理
 function onMessage(message) {
   if (message.type !== Constant.MESSAGE_TRANS_TYPE) return;
-
   switch (message.contentType) {
     case Constant.DIAL_AUDIO_ONLINE:
       rtcStore.streamType = "audio";
@@ -198,6 +197,11 @@ async function acceptCall() {
         rtcStore.streamType !== "video"
           ? Constant.ACCEPT_AUDIO_ONLINE
           : Constant.ACCEPT_VIDEO_ONLINE,
+
+      fromUsername: wsStore.toUserAudioInfo.fromUsername,
+      avatar: wsStore.toUserAudioInfo.fromAvatar,
+      to: wsStore.toUserAudioInfo.toUuid,
+      from: wsStore.toUserAudioInfo.fromUuid,
     });
   } catch (err) {
     console.error("接听失败", err);
@@ -210,14 +214,19 @@ function rejectCall() {
   soundVoice.stop();
   stopTimer();
   rtcStore.cleanup();
-  const sender = wsStore.toUserInfo.sender
-    ? wsStore.toUserInfo.sender.uuid
+  const sender = wsStore.toUserAudioInfo.sender
+    ? wsStore.toUserAudioInfo.sender.uuid
     : walletStore.account;
   wsStore.sendMessage({
     messageType: MESSAGE_TYPE_USER,
     contentType: Constant.REJECT_AUDIO_ONLINE,
     type: Constant.MESSAGE_TRANS_TYPE,
     content: JSON.stringify({ content: "", sender }),
+    
+    fromUsername: wsStore.toUserAudioInfo.fromUsername,
+    avatar: wsStore.toUserAudioInfo.fromAvatar,
+    to: wsStore.toUserAudioInfo.toUuid,
+    from: wsStore.toUserAudioInfo.fromUuid,
   });
   rtcStore.imSate.videoCallModal = false;
   inCall.value = false;
@@ -227,14 +236,19 @@ function rejectCall() {
 function hangupCall() {
   soundVoice.stop();
   rtcStore.cleanup();
-  const sender = wsStore.toUserInfo.sender
-    ? wsStore.toUserInfo.sender.uuid
+  const sender = wsStore.toUserAudioInfo.sender
+    ? wsStore.toUserAudioInfo.sender.uuid
     : walletStore.account;
   wsStore.sendMessage({
     messageType: MESSAGE_TYPE_USER,
     contentType: Constant.CANCELL_AUDIO_ONLINE,
     type: Constant.MESSAGE_TRANS_TYPE,
     content: JSON.stringify({ content: "", sender,callDuration:callDurations.value }),
+    
+    fromUsername: wsStore.toUserAudioInfo.fromUsername,
+    avatar: wsStore.toUserAudioInfo.fromAvatar,
+    to: wsStore.toUserAudioInfo.toUuid,
+    from: wsStore.toUserAudioInfo.fromUuid,
   });
   stopTimer();
   rtcStore.imSate.videoCallModal = false;
@@ -271,6 +285,15 @@ function assignStreamsToVideo() {
   if (mainVideo.value) mainVideo.value.srcObject = mainStream.value;
   if (pipVideo.value) pipVideo.value.srcObject = pipStream.value;
 }
+
+watch(
+  () => rtcStore.isCaller,
+  (val) => {
+    console.log("isCaller", val);
+  },
+  { immediate: true }
+);
+
 // 监听远程流
 watch(
   () => rtcStore.connectionState,

+ 1 - 0
src/views/im/contactList/invitation/index.vue

@@ -128,6 +128,7 @@ const changeFun = async (val) => {
 }
 onMounted(()=>{
     getfriendRequest();
+    wsStore.funInitfriend(walletStore.account, true);
 })
 </script>
 

+ 1 - 1
src/views/im/detail/addMember/index.vue

@@ -169,7 +169,7 @@ const submit = async () => {
             });
             wsStore.toUserInfo = res.data;
             const message = {
-                content: `${uname}加入了群聊`,
+                content: `${walletStore.username}创建了群聊`,
                 contentType: MsgType.MSG_TYPE.TEXT,
                 messageType: MsgType.CREATE_GROUP
             };

+ 1 - 1
src/views/im/detail/index.vue

@@ -18,7 +18,7 @@
                         round
                         :src="IM_PATH + wsStore.toUserInfo.avatar"
                     />
-                    <div>{{ wsStore.toUserInfo.nickname }}</div>
+                    <div>{{ wsStore.toUserInfo.sessionName }}</div>
                 </div>
                 <!-- 群聊 -->
                 <template v-if="status == 2">

+ 62 - 39
src/views/im/hook/messagesHook.js

@@ -15,6 +15,7 @@ const formatMessageExt = (message, ext) => {
       ...message,
       content:ext.content,
       msgId: ext.msgId,
+      // fromUuids: ext.fromUuid,
       cc : ext.cc, // @群成员  0:全部
       id : ext.id, // 真实消息id
       quote : ext.quote, //引用的消息id
@@ -68,7 +69,7 @@ export const setMessageHook = (message, wsStore) => {
     // console.log('消息撤回',message)
     // 更新消息
     if (msg && msg.isTemp) {
-      wsStore.modifyMessage({isTemp: true}, msg.id, message.to)
+      wsStore.modifyMessageId({isTemp: true}, msg, message.to)
     } else {
       wsStore.deleteMessage(message, msg.id, message.to);
     }
@@ -89,14 +90,14 @@ export const setMessageHook = (message, wsStore) => {
   
   // 语音和视频挂断/拒接消息处理
   if (Constant.MSG_AUDIO_GROUP.includes(message.contentType)) {
-    let sender = wsStore.toUserInfo.sender || {
+    let sender = wsStore.toUserAudioInfo.sender || {
       uuid: walletStore.account,
       nickname: walletStore.username,
       avatar: walletStore.avatar,
     }
     wsStore.pushMessage({
       ...message,
-      align: sender.uuid != wsStore.toUserInfo.uuid ? 'right' : 'left',
+      align: sender.uuid == message.from ? 'right' : 'left',
       fromAvatar: message.avatar,
       toUuid: message.to,
       fromUuid: message.from,
@@ -106,16 +107,18 @@ export const setMessageHook = (message, wsStore) => {
   }
   // 文本消息
   if (message.contentType == MsgType.MSG_TYPE.TEXT) {
+    msg.isTemp=false;
     wsStore.pushMessage(formatMessageExt({
       ...message,
       align: 'right',
       fromAvatar: message.avatar,
       toUuid:message.to,
-      fromUuid:message.from
+      fromUuid:message.from,
     }, msg), message.to);
   }
   // 音频消息
   if (message.contentType === MsgType.MSG_TYPE.AUDIO) {
+    msg.isTemp = false;
     const blob = new Blob([message.file], { type: message.fileSuffix });
     const url = URL.createObjectURL(blob);
     wsStore.pushMessage(formatMessageExt({
@@ -191,7 +194,7 @@ export const handleMessageHook = async (payload, wsStore) => {
   // 处理消息回执, 更新消息id
   if (message.messageType === MsgType.MESSAGE_RECEIPT) { 
     // 检测是否在群内或是好友
-    wsStore.modifyMessageId(message, msg)
+    wsStore.modifyMessageId(message, { id: msg.id, uniqueId: msg.uniqueId, msgId: msg.msgId }, message.from)
     return;
   }
   
@@ -201,7 +204,7 @@ export const handleMessageHook = async (payload, wsStore) => {
     wsStore.systemReceiptMessage(message, msg)
     // 更新消息
     if (msg && msg.isTemp) {
-      wsStore.modifyMessage({isTemp: true}, msg.id)
+      wsStore.modifyMessageId({isTemp: true}, msg,message.from)
     } else {
       wsStore.deleteMessage(message, msg.id);
     }
@@ -212,8 +215,9 @@ export const handleMessageHook = async (payload, wsStore) => {
     else {
       wsStore.pushMessage({
         ...message,
-        toUuid: message.to,
-        fromUuid: message.from,
+        toUuid: wsStore.toUserInfo.type == 'user' ? message.to : message.from,
+        fromUuid: wsStore.toUserInfo.type == 'user' ? message.from : message.to,
+        // fromUuids: msg?.fromUuid,
         align: 'left',
         content: `${(msg.fromUsername || '对方')}撤回了一条消息`,
         fromAvatar: message.avatar,
@@ -263,8 +267,9 @@ export const handleMessageHook = async (payload, wsStore) => {
       contentType,
       messageType: MsgType.MESSAGE_TYPE_GROUP,
       fromAvatar: message.avatar,
-      toUuid: message.to,
-      fromUuid: message.from,
+      toUuid: wsStore.toUserInfo.type == 'user' ? message.to : message.from,
+      fromUuid: wsStore.toUserInfo.type == 'user' ? message.from : message.to,
+      // fromUuids: msg?.fromUuid,
     });
     notifications(wsStore);
     return;
@@ -274,7 +279,7 @@ export const handleMessageHook = async (payload, wsStore) => {
   if (Constant.MSG_AUDIO_GROUP.includes(message.contentType)) {
     // 消息送达回执发送
     wsStore.systemReceiptMessage(message, msg)
-    let sender = wsStore.toUserInfo.sender || {
+    let sender = wsStore.toUserAudioInfo.sender || {
       uuid: walletStore.account,
       nickname: walletStore.username,
       avatar: walletStore.avatar,
@@ -282,9 +287,10 @@ export const handleMessageHook = async (payload, wsStore) => {
     // 语音消息
     wsStore.pushMessage({
       ...message,
-      align: sender.uuid != wsStore.toUserInfo.uuid?'right':'left',
-      toUuid: message.to,
-      fromUuid: message.from,
+      align: sender.uuid != message.from?'right':'left',
+      toUuid: wsStore.toUserAudioInfo.type == 'user' ? message.to : message.from,
+      fromUuid: wsStore.toUserInfo.type == 'user' ? message.from : msg.fromUuid,
+      // fromUuids: msg?.fromUuid,
       content: message.contentType === Constant.REJECT_AUDIO_ONLINE || message.contentType === Constant.REJECT_VIDEO_ONLINE ? '[对方拒绝]' : '[通话结束]',
       sender,
       fromAvatar: message.avatar,
@@ -297,8 +303,9 @@ export const handleMessageHook = async (payload, wsStore) => {
     wsStore.systemReceiptMessage(message, msg)
     wsStore.pushMessage(formatMessageExt({
       ...message,
-      toUuid: message.to,
-      fromUuid: message.from,
+      toUuid: wsStore.toUserInfo.type == 'user' ? message.to : message.from,
+      fromUuid: wsStore.toUserInfo.type == 'user' ? message.from : msg.fromUuid,
+      // fromUuids: msg?.fromUuid,
       align: 'left',
       fromAvatar: message.avatar,
     }, msg));
@@ -317,8 +324,9 @@ export const handleMessageHook = async (payload, wsStore) => {
     wsStore.pushMessage(formatMessageExt({
       ...message,
       file: audioUrl,
-      toUuid: message.to,
-      fromUuid: message.from,
+      toUuid: wsStore.toUserInfo.type == 'user' ? message.to : message.from,
+      fromUuid: wsStore.toUserInfo.type == 'user' ? message.from : msg.fromUuid,
+      // fromUuids: msg?.fromUuid,
       align: 'left',
       fromAvatar: message.avatar,
     }, msg));
@@ -334,8 +342,9 @@ export const handleMessageHook = async (payload, wsStore) => {
     wsStore.pushMessage(formatMessageExt({
       ...message,
       file: url,
-      toUuid: message.to,
-      fromUuid: message.from,
+      toUuid: wsStore.toUserInfo.type == 'user' ? message.to : message.from,
+      fromUuid: wsStore.toUserInfo.type == 'user' ? message.from : msg.fromUuid,
+      // fromUuids: msg?.fromUuid,
       align: 'left',
       fromAvatar: message.avatar,
     }, msg));
@@ -351,8 +360,9 @@ export const handleMessageHook = async (payload, wsStore) => {
     wsStore.pushMessage(formatMessageExt({
       ...message,
       file: url,
-      toUuid: message.to,
-      fromUuid: message.from,
+      toUuid: wsStore.toUserInfo.type == 'user' ? message.to : message.from,
+      fromUuid: wsStore.toUserInfo.type == 'user' ? message.from : msg.fromUuid,
+      // fromUuids: msg?.fromUuid,
       align: 'left',
       fromAvatar: message.avatar,
     }, msg));
@@ -372,10 +382,14 @@ export const handleMessageHook = async (payload, wsStore) => {
     wsStore.toUserAudioInfo = {
       uuid: message.from,
       type: "user",
-      // 接收到来自谁的拨号请求
-      fromUuid: message.from,
-      fromAvatar: message.avatar,
-      fromUsername: message.fromUsername,
+      // 接收到来自谁的拨号请求信息
+      toUuid: message.from,
+      toAvatar: message.avatar,
+      toUsername: message.fromUsername,
+      // 自己的信息
+      fromUuid: message.to,
+      fromAvatar: walletStore.avatar,
+      fromUsername: wsStore.toUserInfo.nickname,
       // 发送者信息
       sender: {
         uuid: message.from,
@@ -383,17 +397,17 @@ export const handleMessageHook = async (payload, wsStore) => {
         nickname: message.fromUsername,
       },
     };
-    wsStore.toUserInfo = {
-      ...wsStore.toUserInfo,
-      uuid: message.from,
-      type: "user",
-      unReadNum: 1,
-      sender: {
-        uuid: message.from,
-        avatar: message.avatar,
-        nickname: message.fromUsername,
-      },
-    };
+    // wsStore.toUserInfo = {
+    //   ...wsStore.toUserInfo,
+    //   uuid: message.from,
+    //   type: "user",
+    //   unReadNum: 1,
+    //   sender: {
+    //     uuid: message.from,
+    //     avatar: message.avatar,
+    //     nickname: message.fromUsername,
+    //   },
+    // };
     // 调起通话界面
     const rtcStore = useWebRTCStore();
     rtcStore.streamType = message.contentType == Constant.DIAL_AUDIO_ONLINE ? 'audio' :'video'
@@ -529,11 +543,15 @@ export const handleMessageHook = async (payload, wsStore) => {
         .then(() => rtcStore.createAnswer())
         .then((answer) => {
           console.log('发送answer给呼叫者', answer)
-          // 发送给呼叫者
+          // 发送给呼叫者(拨打者)
           wsStore.sendMessage({
             content: JSON.stringify(answer),
             type: Constant.MESSAGE_TRANS_TYPE,
             messageType: message.contentType,
+            fromUsername: wsStore.toUserAudioInfo.fromUsername,
+            avatar: wsStore.toUserAudioInfo.fromAvatar,
+            to: wsStore.toUserAudioInfo.toUuid,
+            from: wsStore.toUserAudioInfo.fromUuid,
           });
         })
         .catch((error) => {
@@ -556,6 +574,7 @@ const messageCallback = (contentType, state)=>{
 // 创建呼叫:开启语音电话
 const startAudioOnline = (video, state) => { 
   const rtcStore = useWebRTCStore();
+  const wsStore = useWebSocketStore();
   // 初始化webrtc连接
   rtcStore.initConnection(true, video);
   // 获取音视频数据流
@@ -571,11 +590,15 @@ const startAudioOnline = (video, state) => {
     })
   .then((offer) => {
       console.log('caller', offer)
-      // 发送offer给被呼叫者
+      // 发送offer给被呼叫者(接听者)
       state.sendMessage({
         contentType: video? Constant.VIDEO_ONLINE: Constant.AUDIO_ONLINE, // 消息内容类型
         content: JSON.stringify(offer),
         type: Constant.MESSAGE_TRANS_TYPE,
+        fromUsername: wsStore.toUserAudioInfo.fromUsername,
+        avatar: wsStore.toUserAudioInfo.fromAvatar,
+        to: wsStore.toUserAudioInfo.toUuid,
+        from: wsStore.toUserAudioInfo.fromUuid,
       });
     })
     .catch((error) => {

+ 2 - 1
src/views/im/personal/index.vue

@@ -110,6 +110,7 @@ const getfriendRemark = async () => {
         console.log(res);
         if(res.code == 200){
             noteValue.value = note.value;
+            wsStore.updateNote(note.value,route.query.uuid);
             showToast('更改成功');
         }else{
             showToast('更改失败');
@@ -147,7 +148,7 @@ const getuserFriend = async () => {
 }
 // 发消息
 const goToPage = (url) => {
-    wsStore.toUserInfo = userInfo.value;
+    wsStore.toUserInfo = userInfo.value.ChatSession;
     router.push({
         path: 'chat',
         query:{ uuid:route.query.uuid }