Эх сурвалжийг харах

Merge branch 'follow' into dev_suwenjiang

# Conflicts:
#	src/pages/profile/my-news/index.vue
suwenjiang 2 сар өмнө
parent
commit
85fdb2d57b

+ 2 - 1
src/pages/chat/chat-input/index.vue

@@ -194,7 +194,6 @@ const handleClickOutside = (event) => {
 
   if (!isChatInputCompEl) {
     showTool.value = false
-    console.log(inputRef.value.$el.blur, 'inputValue.valueblur')
     inputRef.value.$el.blur()
   }
 };
@@ -251,6 +250,8 @@ onMounted(() => {
     box-sizing: border-box;
     justify-content: center;
     align-content: center;
+    justify-items: center;
+    align-items: center;
   }
 }
 

+ 4 - 4
src/pages/chat/chat-message/index.vue

@@ -41,6 +41,7 @@ import TextMessage from "~/pages/chat/chat-message/text-message/index.vue";
 import ImageMessage from "~/pages/chat/chat-message/image-message/index.vue";
 import AudioMessage from "~/pages/chat/chat-message/audio-message/index.vue";
 import LinkMessage from "~/pages/chat/chat-message/link-message/index.vue";
+import {findHyperlinks} from "~/pages/chat/chat-message/link-message/handle";
 
 const userInfoStore = useUserInfoStore();
 const {userInfo} = storeToRefs(userInfoStore);
@@ -55,11 +56,9 @@ const props = defineProps({
 const msg = computed(() => {
   try {
     const {createTime, getUserId, sendUserId, messageContent, messageType} = props.message
-    console.log(messageType, 'props.message')
-    console.log(sendUserId, userInfo?.value, 'userInfouserInfouserInfo', sendUserId === userInfo?.value.pass)
     return {
       messageContent: messageContent,
-      type: getMessageType(messageType),
+      type: getMessageType(messageType, messageContent),
       viewType: sendUserId === userInfo?.value.pass ? 0 : 1,
       createTime: createTime,
       showName: props.message?.showName
@@ -69,8 +68,9 @@ const msg = computed(() => {
     return null
   }
 })
-const getMessageType = (messageType) => {
+const getMessageType = (messageType, messageContent) => {
   const types = ['text', 'image', 'audio', 'video', 'link']
+  if(messageType === 0 && findHyperlinks(messageContent)) return types[4]
   return types[messageType]
 }
 </script>

+ 294 - 0
src/pages/chat/group-chat.vue

@@ -0,0 +1,294 @@
+<template>
+  <div class="single-page h-full w-full" style="height: 100vh">
+    <van-nav-bar @click-left="router.back()" @click-right="onClickRight">
+      <template #left>
+        <div>
+          <van-icon name="arrow-left" color="black" size="18"/>
+        </div>
+      </template>
+      <template #title>
+        <div class="text-2xl text-black-3 text-semibold">
+          <div class="inline-block w-220 line-clamp-1">
+            {{ title }}
+          </div>
+          <!-- <span class="ml-7 iconfont icon-close-remind text-black-9" style="font-size: 16px"></span> -->
+        </div>
+      </template>
+      <template #right>
+        <van-icon name="ellipsis" color="black" size="18"/>
+      </template>
+    </van-nav-bar>
+    <template v-if="showPage">
+      <van-list
+          ref="chatListRef"
+          class="flex-1 overflow-y-auto px-12 flex flex-col"
+          :finished="true"
+          finished-text=""
+      >
+        <template v-for="(message, index) in currConversationChatList" :key="index">
+          <ChatMessage :show-name="true" :message="message" ></ChatMessage>
+        </template>
+      </van-list>
+      <!--  <van-pull-refresh v-model="refreshing" @refresh="loadMore" class="flex-1">
+            </van-pull-refresh>-->
+      <!--      <div class="fixed bottom-0 left-0 right-0 w-full">-->
+      <ChatInput :operates="['image', 'share-group']" @focus="scrollToBottom" @send="handleSendMessage"></ChatInput>
+      <!--      </div>-->
+    </template>
+    <template v-else>
+      <div class="flex-1 grid place-items-center text-black-9">
+        <div v-if="pageLoading">创建会话中...</div>
+        <div v-else class="grid place-items-center">
+          <div v-if="groupId">创建成功</div>
+          <div v-else class="grid place-items-center">
+            <div  class="mb-10">创建会话失败</div>
+            <van-button size="small" @click="initGroupId">点击重试</van-button>
+          </div>
+        </div>
+      </div>
+    </template>
+  </div>
+</template>
+<script setup>
+import ChatMessage from './chat-message'
+import ChatInput from "./chat-input";
+import {findHyperlinks} from "~/pages/chat/chat-message/link-message/handle";
+import {XYWebSocket} from "~/utils/XYWebSocket";
+import {isValidJson} from "~/utils";
+
+const route = useRoute()
+const router = useRouter()
+
+const chatsStore = useChatsStore();
+const userInfoStore = useUserInfoStore();
+
+const {userInfo} = storeToRefs(userInfoStore);
+// 单聊的标题
+const title = computed(() => route.query.groupRemark)
+
+// 聊天列表
+const chatListRef = ref(null);
+
+const pageLoading = ref(true);
+const getUserId = ref(null); // 消息接收者的用户id
+const sendUserId = computed(() => userInfo?.value.pass) // 消息发送者:当前登录用户的加密id
+const groupId = ref(route.query?.groupId); // 会话ID
+const showPage = computed(() => groupId.value)
+
+const initGroupId = async () => {
+  try {
+/*    if (!groupId.value) return;
+    pageLoading.value = true;
+    const res = await chatsStore.getCurrConversationId(getUserId.value)
+    await handleResponse(res)
+    groupId.value = res.data;*/
+    await getChatList('init')
+  } catch (e) {
+
+  } finally {
+    pageLoading.value = false;
+  }
+}
+
+let pageNum = ref(0)
+const currConversationChatList = ref([]);
+/**
+ * 加载当前聊天信息
+ * @param type init|more
+ * @returns {Promise<void>}
+ */
+const getChatList = async (type = 'init') => {
+  try {
+    const page = type === 'init' ? 1 : pageNum.value + 1;
+    const res = await chatsStore.getChatHistory({
+      pageNum: page,
+      pageSize: 100,
+      groupId: groupId.value,
+    })
+    pageNum.value = page;
+    await handleResponse(res);
+    currConversationChatList.value = handleChatList(res.data?.data)
+    console.log(currConversationChatList.value, 'currConversationChatList')
+    if (type === 'init') await scrollToBottom()
+  } catch (e) {
+    console.error(e)
+  } finally {
+
+  }
+}
+const handleChatList = (list = []) => {
+  return (list ?? []).filter(o => isValidJson(o.messageContent)).map(o => JSON.parse(o.messageContent));
+}
+
+// 发送文本消息
+const sendTextMessage = async (text) => {
+  try {
+    console.log(text, 'sendTextMessage')
+    if (!text) return
+    let msg = {
+      groupId: groupId.value,
+      getUserId: getUserId.value,
+      sendUserId: sendUserId.value,
+      specialUserId: '',
+      messageContent: text,
+      messageType: 0,
+      noticeType: 1,
+      object: {
+        id: getLocalId()
+      }
+    }
+    const isLink = !!findHyperlinks(text)
+    if (isLink) msg.messageType = 4;
+    currConversationChatList.value.push(msg)
+    await scrollToBottom()
+    const res = await chatsStore.sendSocketMessage(msg)
+    console.log('luck:', res)
+  } catch (e) {
+    console.log(e, '2')
+  } finally {
+
+  }
+}
+
+// 选择发送图片
+const sendImageMessage = async (file) => {
+  try {
+    const formData = new FormData()
+    formData.append('uploadFile', file)
+    formData.append('asImage', true)
+    formData.append('fieldName', 'messageContent')
+    const {data} = await request('/website/tourMessage/upload', {
+      method: 'post',
+      body: formData
+    })
+
+    let msg = {
+      groupId: groupId.value,
+      getUserId: getUserId.value,
+      sendUserId: sendUserId.value,
+      specialUserId: '',
+      messageContent: data.fileUrl,
+      messageType: 1,
+      noticeType: 1,
+      object: {
+        id: getLocalId()
+      }
+    }
+    currConversationChatList.value.push(msg)
+    await scrollToBottom()
+    await chatsStore.sendSocketMessage(msg)
+  } catch (e) {
+    console.error(e, '??')
+  } finally {
+
+  }
+}
+
+const handleSendMessage = async ({type, messageContent}) => {
+  try {
+    switch (type) {
+      case 'text':
+        await sendTextMessage(messageContent)
+        break;
+      case 'image':
+        await sendImageMessage(messageContent)
+        break;
+
+      default:
+
+        break;
+    }
+
+  } catch (e) {
+
+  } finally {
+
+  }
+}
+
+const scrollToBottom = async () => {
+  setTimeout(async () => {
+    await nextTick(); // 确保DOM已经更新
+    const listElement = chatListRef.value?.$el;
+    if (listElement) {
+      const scrollContainer = listElement;
+      scrollContainer.scrollTop = scrollContainer.scrollHeight;
+    }
+  }, 200)
+};
+
+
+
+// 加载更多
+const refreshing = ref(false)
+const loadMore = async () => {
+  try {
+    refreshing.value = true
+    await getChatList('more')
+  } catch (e) { } finally {
+    refreshing.value = false
+  }
+}
+
+const onClickRight = () => {
+  navigateTo({
+    path: '/chat/set-single',
+    query: {
+      toUserId: route.query.getUserId
+    }
+  })
+}
+
+
+// 本地生成一个唯一消息id
+function getLocalId() {
+  const random = Math.floor(Math.random() * 10000)
+  return Date.now() + '' + random
+}
+
+onMounted(() => {
+  initGroupId()
+  XYWebSocket.SocketEventsBus.on(XYWebSocket.SocketEvents.chatEvent, async (chat) => {
+    const isCurrGroupId = chat.groupId && chat.groupId === groupId.value;
+    const isOtherUserMessage = chat.sendUserId && chatsStore.isRealMessage(chat.sendUserId);
+    if (isCurrGroupId && isOtherUserMessage) {
+      currConversationChatList.value.push(chat)
+      await scrollToBottom()
+    }
+  })
+})
+
+// 用户删除消息
+const delMessage = (messageId) => {
+  showConfirmDialog({
+    width: 260,
+    message: '是否删除这条消息?',
+    confirmButtonColor: '#FF9300'
+  })
+      .then(async () => {
+        const res = await request('/website/tourMessage/delMessage', {
+          method: 'post',
+          body: {
+            messageId: [messageId]
+          }
+        })
+
+        if (res && res?.success) {
+        }
+      })
+      .catch(() => {
+      })
+}
+
+definePageMeta({
+  layout: false
+})
+</script>
+<style lang="scss" scoped>
+.single-page {
+  height: 100vh;
+  display: flex;
+  flex-direction: column;
+  min-height: 0;
+}
+</style>

+ 21 - 15
src/pages/chat/single.vue → src/pages/chat/single-chat.vue

@@ -32,10 +32,11 @@
           {{ followStatus }}在对方关注或回复前,最多只能发送1条信息
         </div>
       </van-list>
-<!--      <van-pull-refresh v-model="refreshing" @refresh="loadMore">-->
-<!--        -->
-<!--      </van-pull-refresh>-->
-      <ChatInput :operates="['image']" @focus="scrollToBottom" @send="handleSendMessage"></ChatInput>
+<!--  <van-pull-refresh v-model="refreshing" @refresh="loadMore" class="flex-1">
+      </van-pull-refresh>-->
+<!--      <div class="fixed bottom-0 left-0 right-0 w-full">-->
+        <ChatInput :operates="['image']" @focus="scrollToBottom" @send="handleSendMessage"></ChatInput>
+<!--      </div>-->
     </template>
     <template v-else>
       <div class="flex-1 grid place-items-center text-black-9">
@@ -111,7 +112,7 @@ const getChatList = async (type = 'init') => {
     })
     pageNum.value = page;
     await handleResponse(res);
-    currConversationChatList.value = handleChatList(res.data?.dataList)
+    currConversationChatList.value = handleChatList(res.data?.data)
     console.log(currConversationChatList.value, 'currConversationChatList')
     if (type === 'init') await scrollToBottom()
     await getFollowStatus()
@@ -145,6 +146,7 @@ const sendTextMessage = async (text) => {
     const isLink = !!findHyperlinks(text)
     if (isLink) msg.messageType = 4;
     currConversationChatList.value.push(msg)
+    await scrollToBottom()
     const res = await chatsStore.sendSocketMessage(msg)
     console.log('luck:', res)
   } catch (e) {
@@ -179,6 +181,7 @@ const sendImageMessage = async (file) => {
       }
     }
    currConversationChatList.value.push(msg)
+    await scrollToBottom()
    await chatsStore.sendSocketMessage(msg)
   } catch (e) {
     console.error(e, '??')
@@ -201,7 +204,7 @@ const handleSendMessage = async ({type, messageContent}) => {
 
         break;
     }
-    await scrollToBottom()
+
   } catch (e) {
 
   } finally {
@@ -210,12 +213,14 @@ const handleSendMessage = async ({type, messageContent}) => {
 }
 
 const scrollToBottom = async () => {
-  await nextTick(); // 确保DOM已经更新
-  const listElement = chatListRef.value?.$el;
-  if (listElement) {
-    const scrollContainer = listElement;
-    scrollContainer.scrollTop = scrollContainer.scrollHeight;
-  }
+ setTimeout(async () => {
+   await nextTick(); // 确保DOM已经更新
+   const listElement = chatListRef.value?.$el;
+   if (listElement) {
+     const scrollContainer = listElement;
+     scrollContainer.scrollTop = scrollContainer.scrollHeight;
+   }
+ }, 200)
 };
 
 // 获取我与对方的关注情况
@@ -258,10 +263,11 @@ function getLocalId() {
 onMounted(() => {
   initGroupId()
   XYWebSocket.SocketEventsBus.on(XYWebSocket.SocketEvents.chatEvent, async (chat) => {
-    console.log('XYWebSocket', chat)
-    if (chat.groupId && chat.groupId === groupId.value) {
-     // await getChatList()
+    const isCurrGroupId = chat.groupId && chat.groupId === groupId.value;
+    const isOtherUserMessage = chat.sendUserId && chatsStore.isRealMessage(chat.sendUserId)
+    if (isCurrGroupId && isOtherUserMessage) {
       currConversationChatList.value.push(chat)
+      await scrollToBottom()
     }
   })
 })

+ 37 - 23
src/pages/profile/my-news/index.vue

@@ -14,7 +14,7 @@
           v-model:show="showPopover"
           placement="bottom"
           theme="dark"
-          :offset="[5, 20]"
+          :offset="[5,20]"
           :actions="actionsList"
           @select="onSelect"
         >
@@ -227,9 +227,7 @@
                       ? createTimeSplit(item?.lastMessage?.updateTime)
                       : ''
                   }"
-                  @on-chat-page="
-                    onChatPage('/chat/group', { userId: user.userId, groupId: item?.groupId })
-                  "
+                  @on-chat-page="goDetails('group', item)"
                   @on-no-bother="noBother(item)"
                   @on-is-top="onIsTop(item)"
                   @on-conv-delete="onIsShow(item)"
@@ -244,10 +242,10 @@
                       ? createTimeSplit(item?.lastMessage?.updateTime)
                       : ''
                   }"
-                  @on-chat-page="goDetails('single', item)"
-                  @on-no-bother="noBother(item)"
-                  @on-is-top="onIsTop(item)"
-                  @on-conv-delete="onIsShow(item)"
+                    @on-chat-page="goDetails('single', item)"
+                    @on-no-bother="noBother(item)"
+                    @on-is-top="onIsTop(item)"
+                    @on-conv-delete="onIsShow(item)"
                 />
               </template>
               <template v-else></template>
@@ -276,12 +274,7 @@
                 ...item,
                 updateTime: item?.lastMessage ? createTimeSplit(item?.lastMessage?.updateTime) : ''
               }"
-              @on-chat-page="
-                onChatPage('/chat/group', {
-                  userId: userInfo.userId,
-                  groupId: item?.groupId
-                })
-              "
+              @on-chat-page="goDetails('group', item)"
               @on-no-bother="noBother(item)"
               @on-is-top="onIsTop(item)"
               @on-conv-delete="onIsShow(item)"
@@ -292,10 +285,10 @@
                 ...item,
                 updateTime: item?.lastMessage ? createTimeSplit(item?.lastMessage?.updateTime) : ''
               }"
-              @on-chat-page="goDetails('single', item)"
-              @on-no-bother="noBother(item)"
-              @on-is-top="onIsTop(item)"
-              @on-conv-delete="onIsShow(item)"
+                @on-chat-page="goDetails('single', item)"
+                @on-no-bother="noBother(item)"
+                @on-is-top="onIsTop(item)"
+                @on-conv-delete="onIsShow(item)"
             />
           </template>
         </van-list>
@@ -321,7 +314,7 @@ const actionsList = [
 const userInfoStore = useUserInfoStore()
 const { userInfo } = storeToRefs(userInfoStore)
 
-const chatsStore = useChatsStore()
+const chatsStore = useChatsStore();
 const { chatList, chatListLoading } = storeToRefs(chatsStore)
 
 const showPopover = ref(false)
@@ -442,23 +435,44 @@ const onSelect = (action) => {
   if (action.text === '添加用户') onChatPage('/chat/user-add', {})
 }
 
+
 const goDetails = (type, item) => {
   console.log(type, item, 'itemitem')
   switch (type) {
     case 'single': // 单聊消息
+      readMessage(item.groupId)
       navigateTo({
-        path: '/chat/single',
-        query: {
+        path: '/chat/single-chat', query: {
           getUserId: item?.toUserId,
           groupRemark: item?.groupRemark
         }
       })
-      break
+      break;
+    case 'group': // 群聊消息
+      readMessage(item.groupId)
+      navigateTo({
+        path: '/chat/group-chat', query: {
+          groupId: item?.groupId,
+          groupRemark: item?.groupRemark
+        }
+      })
+      break;
     default:
-      break
+
+      break;
   }
 }
 
+const readMessage = async (groupId) => {
+  const res = await request('/website/tourMessage/updateRead', {
+    query: {
+      groupId: groupId
+    }
+  })
+  await handleResponse(res, false)
+  await chatsStore.getChatList()
+}
+
 // 消息的内容转换
 function messageShowName(messageContent) {
   try {

+ 10 - 0
src/stores/useChats.js

@@ -1,6 +1,9 @@
 import {XYWebSocket} from "~/utils/XYWebSocket";
 
 export const useChatsStore = defineStore('chats', () => {
+  const userInfoStore = useUserInfoStore();
+  const {userInfo} = storeToRefs(userInfoStore);
+
   let socket = null;
   const initWebSocket = (url) => {
     if (!socket) {
@@ -40,6 +43,10 @@ export const useChatsStore = defineStore('chats', () => {
     return await request('/website/tourMessage/getMessageByGroupId', {query})
   }
 
+  const isRealMessage = (sendUserId) => {
+    return sendUserId !== userInfo.value.pass
+  }
+
 
   // 会话列表
   let chatList = ref([]);
@@ -96,5 +103,8 @@ export const useChatsStore = defineStore('chats', () => {
     chatListLoading,
     getChatList,
 
+
+    isRealMessage
+
   }
 })

+ 2 - 2
src/utils/XYWebSocket.ts

@@ -59,9 +59,9 @@ export namespace XYWebSocket {
                 /**
                  * 2、 服务端主动发起消息
                  */
-                if (!web_request_id) {
+                // if (!web_request_id) {
                     SocketEventsBus.emit(SocketEvents.chatEvent, messagePackage)
-                }
+                // }
             } catch (e) {
 
             }