Browse Source

fix:1.聊天的会话创建时机在获取到token之后,会话列表消息已读接口对接,单聊的页面渲染。

suwenjiang 2 months ago
parent
commit
3960393e9e

+ 8 - 0
src/assets/img/chat/weixin-shake.svg

@@ -0,0 +1,8 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Weixin-shake (&#229;&#190;&#174;&#228;&#191;&#161;&#230;&#145;&#135;&#228;&#184;&#128;&#230;&#145;&#135;)">
+<path id="Vector" d="M21 9.5L14.5 3L3 14.5L9.5 21L21 9.5Z" fill="white" stroke="white" stroke-width="0.666667" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="Vector_2" d="M8 14.5L9.5 16" stroke="white" stroke-width="0.666667" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="Vector_3" d="M15 21L21 15" stroke="white" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="Vector_4" d="M3 9L9 3" stroke="white" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

+ 7 - 1
src/components/Chat/Item.vue → src/components/Chat/LeftItemMessage.vue

@@ -1,7 +1,13 @@
 <template>
   <div style="width: calc(100vw - 74px)" class="flex justify-start items-start">
     <div class="shrink-0 w-40 h-40 border rounded-[4px]">
-      <img class="w-full h-full" :src="itemData.haeadImage" alt="" />
+      <img
+        v-if="itemData?.haeadImage"
+        class="w-full h-full object-cover"
+        :src="itemData.haeadImage"
+        alt=""
+      />
+      <img v-else class="w-full h-full object-cover" src="~/assets/img/default_avatar.png" alt="" />
     </div>
     <template v-if="itemData?.type == 'text'">
       <div class="inline-block w-0 h-0 mt-10 border-[8px] border-transparent border-r-white"></div>

+ 15 - 0
src/components/Chat/MsgStatus.vue

@@ -0,0 +1,15 @@
+<template>
+  <van-icon v-if="status == 'loading'" name="warning" size="16" color="#FF476A" />
+  <div v-else class="text-black-9 text-[10px]">发送失败</div>
+</template>
+<script setup>
+const chatStore = useChatStore()
+const { ws, curConversiton, receive, receiveGetter, isConnect, onNewMessage } =
+  storeToRefs(chatStore)
+const status = ref('loading')
+onMounted(() => {
+  setTimeout(() => {
+    status.value = 'fail'
+  }, 10000)
+})
+</script>

+ 59 - 0
src/components/Chat/RightItemMessage.vue

@@ -0,0 +1,59 @@
+<template>
+  <div style="width: calc(100vw - 74px)" class="flex justify-end items-start mb-16">
+    <!-- 文字消息 -->
+    <template v-if="itemData?.messageType == 0 && itemData.messageContent.trim()">
+      <div
+        class="text-left inline-block min-h-40 max-w-full break-words overflow-auto rounded-[4px] relative bg-white box-border text-base p-5 text-wrap"
+      >
+        {{ messageContentParse(itemData.messageContent) }}
+      </div>
+      <div class="inline-block w-0 h-0 mt-10 border-[8px] border-transparent border-l-white"></div>
+    </template>
+    <!-- 图片消息 -->
+    <template v-if="item.messageType == 1">
+      <div class="ml-10 max-w-251 border right left">
+        <img
+          @click="handleimagePreview"
+          class="w-full h-full object-contain"
+          src="../../assets/img/comment/H5_default.png"
+          alt=""
+        />
+        <!-- <ChatImage :item-data="_default" @on-delete="$emit('onDelete')" /> -->
+      </div>
+    </template>
+
+    <div class="shrink-0 w-40 h-40 rounded-[4px]">
+      <img
+        v-if="itemData?.haeadImage"
+        class="w-full h-full object-cover"
+        :src="itemData.haeadImage"
+        alt=""
+      />
+      <img v-else class="w-full h-full object-cover" src="~/assets/img/default_avatar.png" alt="" />
+    </div>
+  </div>
+</template>
+
+<script setup>
+defineProps({
+  itemData: {
+    type: Object,
+    default: () => ({})
+  }
+})
+
+defineEmits(['onDelete'])
+
+// 图片预览
+const handleimagePreview = () => {
+  showImagePreview({
+    images: [
+      'https://fastly.jsdelivr.net/npm/@vant/assets/apple-1.jpeg',
+      'https://fastly.jsdelivr.net/npm/@vant/assets/apple-2.jpeg'
+    ],
+    startPosition: 1
+  })
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 67 - 60
src/components/Profile/News/ChatInput.vue

@@ -1,12 +1,8 @@
 <template>
-  <!-- <div
-    v-if="showInput"
-    class="w-[100vw] h-[100vh] fixed top-0 border-[#000] left-0 z-100 bg-[#000]/[0.1]"
-  > -->
   <div @click.stop="" class="fixed bottom-0 left-0 w-full bg-[#fff] pt-10 pb-30 z-52">
-    <div :class="`flex ${commentValue.length > 13 ? 'items-end' : 'items-center'} px-15 pb-10`">
+    <div :class="`flex ${inputValue.length > 13 ? 'items-end' : 'items-center'} px-15 pb-10`">
+      <!--   @click="showVoice = !showVoice" -->
       <span
-        @click="showVoice = !showVoice"
         v-if="!showVoice"
         :class="`iconfont icon-voice-one text-black-6 `"
         style="font-size: 32px"
@@ -26,18 +22,19 @@
       <div
         v-else
         style="overflow-y: scroll; -webkit-scrollbar-width: 0px; -webkit-scrollbar: none"
-        class="box-border rounded-full bg-[#F3F3F3] justify-between px-16 py-8 flex-1 mx-12 h-40 border flex items-center"
+        class="box-border rounded-full bg-[#F3F3F3] justify-between px-16 py-8 flex-1 mx-12 min-h-40 border flex items-center"
       >
         <textarea
-          v-model="commentValue"
+          v-model="inputValue"
           ref="textareaRef"
           placeholder="请输入"
           @focus="textareaFocus"
+          @blur="handleBlur"
           class="ml-8 flex-1 box-border w-full h-full bg-[#F3F3F3]"
           maxlength="5000"
-          style="resize: none"
-          @keydown.enter="commentValue ? addComment : () => {}"
+          style="height: 100%; resize: none; border: none; outline: none"
         ></textarea>
+        <!-- @keydown.enter="addComment" -->
       </div>
       <span
         @click="openEmoji"
@@ -49,13 +46,6 @@
         class="iconfont icon-close-one text-black-6"
         style="font-size: 32px"
       ></span>
-
-      <!-- <div
-          @click="addComment"
-          class="py-6 px-16 mr-12 bg-[#FD9A00] text-[#fff] flex items-center justify-center rounded-full shrink-0"
-        >
-          发送
-        </div> -->
     </div>
 
     <div v-if="showEmoji" class="w-full h-300 bg-[#fff] overflow-auto">
@@ -69,25 +59,44 @@
           <div @click="selectEmoji(index)" v-html="item.emoji"></div>
         </div>
       </div>
+      <div class="fixed bottom-45 right-20 flex">
+        <div
+          @click="delteMessage"
+          class="text-sm py-5 px-16 mr-12 bg-[#FD9A00] text-[#fff] flex items-center justify-center rounded-full shrink-0"
+        >
+          删除
+        </div>
+        <div
+          @click="addComment"
+          class="text-sm py-5 px-16 mr-12 bg-[#FD9A00] text-[#fff] flex items-center justify-center rounded-full shrink-0"
+        >
+          发送
+        </div>
+      </div>
     </div>
     <div v-if="showOther" class="w-full h-200 bg-[#fff] overflow-auto">
       <div class="flex items-start flex-wrap w-full h-full py-15 px-8 bg-white">
         <template v-for="(item, index) in otherList" :key="index">
           <div
-            @click="item.fn"
+            @click="index == 0 ? () => {} : item.fn"
             v-if="item?.isShow"
-            class="mx-10 text-4xl active:text-[#FF9300] w-[15%] aspect-[1/1] flex flex-wrap items-center justify-center"
+            class="mx-10 text-4xl relative active:text-[#FF9300] w-[15%] aspect-[1/1] flex flex-wrap items-center justify-center"
           >
             <div
               class="w-54 h-54 active:bg-[#FF9300]/[0.1] bg-[#F3F3F3] shrink-0 rounded-full mb-5 overflow-auto flex justify-center items-center"
             >
-              <img :src="item.icon" alt="" />
               <span
                 :class="`iconfont ${item.icon} text-black-6 active:text-[#FF9300] `"
                 style="font-size: 32px"
               ></span>
             </div>
             <p class="text-sm w-full text-center">{{ item.title }}</p>
+            <input
+              type="file"
+              @change="item.fn"
+              class="absolute top-0 left-0 w-full h-full"
+              style="position: absolute; top: 0; left: 0; z-index: 10; opacity: 0"
+            />
           </div>
         </template>
       </div>
@@ -99,12 +108,13 @@ import emojiJson from './emoji.js'
 
 const shareGroup = defineModel('shareGroup')
 
+const emit = defineEmits(['onSendMessage', 'onSelectImg'])
 const textareaRef = ref(null)
 
 // 显示输入框
 // const showInput = ref(true)
 // 是否展示表情
-const showEmoji = ref(false)
+const showEmoji = ref(true)
 // 是否展示其他功能
 const showOther = ref(false)
 
@@ -115,7 +125,7 @@ const showVoice = ref(false)
 const isRecording = ref(false)
 const transcript = ref('') // 存储语音识别结果
 // 输入的内容
-const commentValue = ref('')
+const inputValue = ref('')
 
 const addContent = ref(true)
 
@@ -232,6 +242,7 @@ const otherList = reactive([
     title: '相册',
     icon: 'icon-pic',
     isShow: true,
+    // fn: emit('onSelectImg')
     fn: uploadPictures
   },
   {
@@ -256,41 +267,29 @@ const otherList = reactive([
 //   })
 // }
 
-async function addComment() {
-  console.log(commentValue.value, '111')
-
-  //   if (!addContent.value) return
-  //   if (!token.value) {
-  //     showConfirmDialog({
-  //       showConfirmDialog: true,
-  //       title: '提示',
-  //       message: '登录后可以发布评论',
-  //       theme: 'round-button'
-  //     }).then(async () => {
-  //       navigateTo({ path: '/login' })
-  //     })
-  //     return
-  //   }
-  if (!commentValue.value.trim()) {
-    showToast('输入内容不能为空!')
+function addComment() {
+  if (!inputValue.value.trim()) {
+    showToast('发送内容不能为空!')
     return
   }
-  //   canAddComment.value = false
-  //   const body = { travelNoteId: replyComment.value.travelNoteId, commentContent: commentValue.value }
-  //   if (replyComment.value.id) {
-  //     body.replyCommentId = replyComment.value.id
-  //     body.replyUserId = replyComment.value.createUserId
-  //     body.parentId = replyComment.value.parentId
-  //   }
-  //   request('website/comment/tourTravelNotesComment/add', { method: 'post', body })
-  //     .then(() => {
-  //       commentValue.value = ''
-  //       showToast('评论成功')
-  //       // getMyCommentList()
-  //       showInput.value = false
-  //       showEmoji.value = false
-  //     })
-  //     .finally(() => (canAddComment.value = true), (replyComment.value = {}), (cursorIndex.value = 0))
+  emit('onSendMessage', inputValue.value)
+  inputValue.value = ''
+}
+
+// 监听输入框的enter事件
+function addEventListenerTextarea() {
+  nextTick(() => {
+    if (textareaRef.value) {
+      textareaRef.value.removeEventListener('keydown', () => {})
+      textareaRef.value.addEventListener('keydown', function (event) {
+        if (event.key === 'Enter') {
+          event.preventDefault()
+          emit('onSendMessage', inputValue.value)
+          inputValue.value = ''
+        }
+      })
+    }
+  })
 }
 
 // 获取焦点
@@ -303,9 +302,8 @@ function textareaFocus() {
 // 文本域失焦
 function handleBlur() {
   showEmoji.value = false
+  showOther.value = false
   textareaRef.value?.blur()
-  // showInput.value = false
-  replyComment.value = {}
 }
 
 // 打开表情
@@ -334,16 +332,25 @@ function closeEmojiBox() {
 // 选择表情
 function selectEmoji(emojiStr = '') {
   const length = emojiStr.length
-  commentValue.value =
-    commentValue.value.slice(0, cursorIndex.value) +
+  inputValue.value =
+    inputValue.value.slice(0, cursorIndex.value) +
     emojiJson[emojiStr].emoji +
-    commentValue.value.slice(cursorIndex.value)
+    inputValue.value.slice(cursorIndex.value)
 
   nextTick(() => {
     cursorIndex.value += length
     textareaRef.value.setSelectionRange(cursorIndex.value, cursorIndex.value)
   })
 }
+
+// 删除内容
+const delteMessage = () => {
+  inputValue.value = inputValue.value.slice(1, inputValue.value.length)
+}
+
+watch(() => {
+  addEventListenerTextarea()
+})
 </script>
 
 <style lang="scss" scoped>

+ 1 - 1
src/components/Profile/News/GroupChat.vue

@@ -22,7 +22,7 @@
           {{ itemData?.groupName }}
         </h1>
         <p class="line-clamp-1 w-full h-20 text-base text-black/[0.6] leading-3xl">
-          {{ itemData?.lastMessage?.messageContent }}
+          {{ messageContentParse(itemData?.lastMessage?.messageContent) }}
         </p>
       </div>
 

+ 9 - 4
src/components/Profile/News/SingleChat.vue

@@ -40,7 +40,7 @@
             class="w-48 h-48 rounded-full overflow-hidden flex justify-center items-center"
           >
             <img
-              class="w-24 h-24 shrink-0 object-cover"
+              class="w-full h-full shrink-0 object-cover"
               src="~/assets/img/default_avatar.png"
               alt=""
             />
@@ -49,14 +49,17 @@
       </div>
 
       <div class="h-48 w-245 ml-12 flex flex-wrap">
-        <h1 class="line-clamp-1 mb-8 w-full text-xl text-black-3 font-semibold">单个会话</h1>
-        <p class="line-clamp-1 w-full h-20 text-base text-black/[0.6] leading-3xl">你吃饭了么</p>
+        <h1 class="line-clamp-1 mb-8 w-full text-xl text-black-3 font-semibold">
+          {{ itemData?.groupRemark }}
+        </h1>
+        <p class="line-clamp-1 w-full h-20 text-base text-black/[0.6] leading-3xl">
+          <!-- {{ messageContentParse(itemData?.lastMessage?.messageContent) }} -->
+        </p>
       </div>
 
       <div class="w-35 h-48 shrink-0">
         <p class="text-black/[0.6] text-sm text-end">{{ itemData?.updateTime }}</p>
 
-        <!-- <span class="iconfont icon-close-remind text-black-6" style="font-size: 16px"></span> -->
         <div v-if="itemData?.isNotDisturb == 1" class="w-full h-16 shrink-0 mt-12 flex justify-end">
           <span class="iconfont icon-close-remind text-black-6" style="font-size: 16px"></span>
         </div>
@@ -100,6 +103,8 @@
 </template>
 
 <script setup>
+import { messageContentParse } from '~/utils/detalTime.js'
+
 defineProps({
   itemData: {
     type: Object,

+ 37 - 16
src/middleware/auth.global.js

@@ -1,27 +1,48 @@
 export default defineNuxtRouteMiddleware((to, from) => {
-  if (import.meta.server) return;
+  if (import.meta.server) return
 
-  const authStore = useAuthStore();
-  const { token } = storeToRefs(authStore);
+  const authStore = useAuthStore()
+  const { token } = storeToRefs(authStore)
+  const chatStore = useChatStore()
+  const { user } = storeToRefs(chatStore)
 
-  if (token.value) return;
+  // 建立链接
+  async function getUserInfo() {
+    const { data } = await request('/website/tourism/user/view')
+    chatStore.user = data
+    user.value = data
+    console.log(data, 'createConnection')
 
-  if (to.fullPath.includes("/profile")) {
-    return navigateTo("/login", {
+    await chatStore.createConnection(data.pass)
+
+    // chatStore.reqChatList()
+
+    // console.log('用户信息:', chatStore.user)
+
+    // console.log('会话列表:', chatStore.chatList.value)
+  }
+
+  if (token.value) {
+    getUserInfo()
+    return
+  }
+
+  if (to.fullPath.includes('/profile')) {
+    return navigateTo('/login', {
       replace: true,
       query: {
-        redirect: to.fullPath,
-      },
-    });
+        redirect: to.fullPath
+      }
+    })
   }
 
-  if (to.fullPath.includes("/note-create")) {
-    return navigateTo("/login", {
+  if (to.fullPath.includes('/note-create')) {
+    return navigateTo('/login', {
       replace: true,
       query: {
-        redirect: to.fullPath,
-      },
-    });
+        redirect: to.fullPath
+      }
+    })
   }
-  return;
-});
+  return
+})

+ 2 - 4
src/pages/chat/group-square.vue

@@ -271,13 +271,11 @@ function chageState(state) {
 // 获取数据
 const getList = async () => {
   try {
-    let url = `/website/tourGroup/list`
     loading.value = true
     let {
       data: { dataList, totalCount }
-    } = await request(url, {
-      method: 'post',
-      body: {
+    } = await request('/website/tourGroup/list', {
+      query: {
         ...queryParams
       }
     })

+ 58 - 15
src/pages/chat/set-single.vue

@@ -10,10 +10,21 @@
       <van-row>
         <van-col style="width: 54px" span="4" class="mb-12 mr-10">
           <div class="w-40 h-40 rounded-full mx-auto overflow-hidden mb-4">
-            <img class="w-full h-full object-cover" :src="itemData?.avatar" alt="" />
+            <img
+              v-if="itemData?.headImage"
+              class="w-full h-full object-cover"
+              :src="itemData?.headImage"
+              alt=""
+            />
+            <img
+              v-else
+              class="w-full h-full object-cover"
+              src="~/assets/img/default_avatar.png"
+              alt=""
+            />
           </div>
           <p class="w-full line-clamp-1 lin text-sm text-center text-black-6">
-            {{ itemData?.nickname }}
+            {{ itemData?.groupRemark }}
           </p>
         </van-col>
         <van-col style="width: 54px" span="4" class="mb-12 mr-10">
@@ -28,6 +39,7 @@
       </van-row>
     </van-cell-group>
 
+    {{ itemData }}
     <van-cell-group style="margin-bottom: 12px" class="box-border" inset>
       <van-cell
         v-for="(item, index) in list"
@@ -73,13 +85,26 @@
   </div>
 </template>
 <script setup>
+const chatStore = useChatStore()
+const { ws, chatList } = storeToRefs(chatStore)
+
+const route = useRoute()
+
 definePageMeta({
   layout: false
 })
 
-const itemData = ref(null)
-const isNotDisturb = ref(false)
-const isTop = ref(false)
+// const itemData = ref(null)
+
+const itemData = computed(
+  () => chatList.value.filter((el) => el.toUserId == route.query.toUserId)[0]
+)
+
+// const isNotDisturb = ref(false)
+// const isTop = ref(false)
+
+const isNotDisturb = computed(() => (itemData?.isNotDisturb ? true : false))
+const isTop = computed(() => (itemData?.isTop ? true : false))
 
 const dialogParmas = reactive({
   show: false,
@@ -91,11 +116,9 @@ const dialogParmas = reactive({
 
 // 弹窗确认的事件
 const confirm = async () => {
-  try {
-    let { data } = await request('', {})
-  } catch (error) {}
+  changeGroupName({ groupName: dialogParmas.remark })
   dialogParmas.show = false
-  itemData.value.remark = dialogParmas.remark
+  // itemData.value.remark = dialogParmas.remark
 }
 
 const cancel = () => {
@@ -119,6 +142,26 @@ const modifyNoteName = () => {
   }
 }
 
+// 修我在群里的昵称 修改群名称
+const changeGroupName = async (body) => {
+  try {
+    const { data } = await request('/website/tourGroup/updateGroup', {
+      method: 'post',
+      body: {
+        groupId: itemData.value.id,
+        ...body
+      }
+    })
+
+    if (data) {
+      // userGroupData.value[Object.keys(body)[0]] = groupName.value
+      // showSuccessToast('修改成功')
+    } else {
+      // showFailToast('修改失败')
+    }
+  } catch (error) {}
+}
+
 // 查找聊天记录
 const findChatHistory = () => {
   navigateTo('/chat/set-sub', {
@@ -168,7 +211,7 @@ const list = reactive([
   {
     title: '设置备注名',
     // icon: setting,
-    icon: 'icon-setting-one',
+    // icon: 'icon-setting-one',
     isLink: true,
     vModel: null,
     fn: modifyNoteName,
@@ -177,7 +220,7 @@ const list = reactive([
   {
     title: '查找聊天记录',
     value: '',
-    icon: 'icon-log',
+    // icon: 'icon-log',
     isLink: true,
     vModel: null,
     fn: findChatHistory
@@ -186,7 +229,7 @@ const list = reactive([
     title: '消息面打扰',
     value: '',
 
-    icon: 'icon-close-remind',
+    // icon: 'icon-close-remind',
     isLink: false,
     vModel: isNotDisturb.value,
     fn: notDisturb
@@ -194,7 +237,7 @@ const list = reactive([
   {
     title: '置顶聊天',
     value: '',
-    icon: 'icon-set-top',
+    // icon: 'icon-set-top',
     isLink: false,
     vModel: isTop.value,
     fn: topChat
@@ -202,7 +245,7 @@ const list = reactive([
   {
     title: '举报该用户',
     value: '',
-    icon: 'icon-jubaoguanli',
+    // icon: 'icon-jubaoguanli',
     isLink: true,
     vModel: null,
     fn: reportUser
@@ -210,7 +253,7 @@ const list = reactive([
   {
     title: '清空聊天记录',
     value: '',
-    icon: 'icon-delete-one',
+    // icon: 'icon-delete-one',
     isLink: true,
     vModel: null,
     fn: clearChatHistory

+ 407 - 13
src/pages/chat/single.vue

@@ -1,42 +1,236 @@
 <template>
   <div>
-    <van-nav-bar title="单聊" fixed @click-left="onClickLeft" @click-right="onClickRight">
+    <van-nav-bar fixed @click-left="onClickLeft" @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>
 
     <van-pull-refresh v-model="loading" @refresh="onRefresh">
-      <div class="w-full h-full border">12231</div>
+      <div class="w-full h-[100vh] pt-55">
+        <div ref="messageBoxRef" class="w-full box-border px-12 overflow-y-auto scrollbar">
+          <van-list
+            v-model:loading="loading"
+            :finished="finished"
+            finished-text="没有更多了"
+            @load="onLoad"
+          >
+            <template v-for="(item, index) in receiveGetter" :key="index">
+              <!-- 右侧是自己的消息 -->
+
+              <template v-if="item.sendUserId == user.pass">
+                <!-- 右侧消息 图片 -->
+                <template v-if="item.messageType == 1">
+                  <div class="w-full text-center text-black/[0.4] mt-24 text-sm">
+                    {{ item.createTime }}
+                  </div>
+
+                  <div class="flex justify-end items-start">
+                    <div
+                      class="mr-10 text-left inline-block min-h-46 max-w-full break-words overflow-auto bg-[#FEF4E6] box-border text-base p-12 text-wrap"
+                    >
+                      {{ item.messageContent }}
+                    </div>
+
+                    <div class="w-40 h-40 rounded-full overflow-hidden shrink-0">
+                      <img
+                        v-if="user?.headImageUrl"
+                        class="w-full h-full object-cover"
+                        :src="user?.headImageUrl"
+                        alt=""
+                      />
+                      <img
+                        v-else
+                        class="w-full h-full object-cover"
+                        src="~/assets/img/default_avatar.png"
+                        alt=""
+                      />
+                    </div>
+                  </div>
+                </template>
+
+                <!-- 文字消息 -->
+                <template v-if="item.messageType == 0 && item.messageContent.trim()">
+                  <div class="w-full text-center text-black/[0.4] mt-24 text-sm">
+                    {{ formatTimestamp(item.createTime) }}
+                  </div>
+
+                  <div class="flex justify-end items-start">
+                    <div
+                      class="mr-10 text-left inline-block min-h-46 max-w-full break-words overflow-auto rounded-b-2xl rounded-tl-2xl bg-white box-border text-base p-12 text-wrap"
+                    >
+                      {{ messageContentParse(item.messageContent) }}
+                    </div>
+                  </div>
+
+                  <div class="w-40 h-40 rounded-full overflow-hidden shrink-0">
+                    <img
+                      v-if="user?.headImageUrl"
+                      class="w-full h-full object-cover"
+                      :src="user?.headImageUrl"
+                      alt=""
+                    />
+                    <img
+                      v-else
+                      class="w-full h-full object-cover"
+                      src="~/assets/img/default_avatar.png"
+                      alt=""
+                    />
+                  </div>
+                </template>
+              </template>
+
+              <!-- 左侧他人的消息 -->
+              <template v-else>
+                <!-- 左侧消息 图片 -->
+                <template v-if="item.messageType == 1">
+                  <div class="w-full text-center text-black/[0.4] mt-24 text-sm">
+                    {{ item.createTime }}
+                  </div>
+
+                  <div class="flex justify-end items-start">
+                    <div
+                      class="mr-10 text-left inline-block min-h-46 max-w-full break-words overflow-auto rounded-[4px] bg-white box-border text-base p-12 text-wrap"
+                    >
+                      <!-- {{ item.messageContent }} -->
+                    </div>
+
+                    <div class="w-40 h-40 rounded-full overflow-hidden shrink-0">
+                      <img
+                        v-if="user?.headImageUrl"
+                        class="w-full h-full object-cover"
+                        :src="user?.headImageUrl"
+                        alt=""
+                      />
+                      <img
+                        v-else
+                        class="w-full h-full object-cover"
+                        src="~/assets/img/default_avatar.png"
+                        alt=""
+                      />
+                    </div>
+                  </div>
+                </template>
+
+                <!-- 左侧文字 -->
+                <!-- <template v-if="item.messageType == 0 && item.messageContent.trim()"> -->
+                <div class="w-full text-center text-black/[0.4] mt-24 text-sm">
+                  {{ formatTimestamp(item.createTime) }}
+                </div>
+
+                <div class="flex justify-start items-start">
+                  <div class="w-40 h-40 rounded-full overflow-hidden shrink-0">
+                    <img
+                      v-if="user?.headImageUrl"
+                      class="w-full h-full object-cover"
+                      :src="user?.headImageUrl"
+                      alt=""
+                    />
+                    <img
+                      v-else
+                      class="w-full h-full object-cover"
+                      src="~/assets/img/default_avatar.png"
+                      alt=""
+                    />
+                  </div>
+
+                  <div
+                    class="ml-8 inline-block rounded-b-2xl rounded-tr-2xl min-h-46 max-w-full break-words overflow-auto bg-[#F3F3F3] box-border text-base p-12 text-wrap"
+                  >
+                    {{ messageContentParse(item.messageContent) }}
+                  </div>
+                </div>
+                <!-- </template> -->
+              </template>
+            </template>
+
+            <div ref="msgBottomRef"></div>
+          </van-list>
+        </div>
+      </div>
     </van-pull-refresh>
 
-    <ProfileNewsChatInput :shareGroup="false"></ProfileNewsChatInput>
+    <ProfileNewsChatInput
+      :shareGroup="false"
+      @on-select-Img="selectImg"
+      @on-send-message="sendMessage"
+    ></ProfileNewsChatInput>
   </div>
 </template>
 <script setup>
+import { messageContentParse, formatTimestamp } from '~/utils/detalTime'
 const route = useRoute()
 const router = useRouter()
 
-definePageMeta({
-  layout: false
+const uploadUrl = `${import.meta.env.VITE_APP_BASE_URL}/website/tourMessage/upload`
+const chatStore = useChatStore()
+const { ws, curConversiton, receive, receiveGetter, connectSta, onNewMessage } =
+  storeToRefs(chatStore)
+const user = computed(() => chatStore.user)
+
+// 消息接收者的用户id
+const getUserId = computed(() => curConversiton.value.toUserId)
+
+// 消息发送者:当前登录用户的加密id
+const sendUserId = computed(() => user.value.pass)
+
+// 会话id
+const groupId = computed(() => route.query.groupId)
+
+// 用户在群聊中艾特的人
+const specialUserId = ref('')
+
+// 用户输入的文本消息
+const messageContent = ref('')
+
+// 聊天类型 1单聊 2群聊 3系统消息 4关注信息
+const noticeType = computed(() => curConversiton.value.noticeType)
+
+const messageBoxRef = ref(null)
+const msgBottomRef = ref(null)
+const inputBoxRef = ref(null)
+
+// 当前websocket连接状态 0: 未连接 1: 连接中 2: 已连接 3: 已断开
+const wsConnect = computed(() => connectSta.value)
+
+const followStatus = ref(0)
+
+const querySwParams = reactive({
+  getUserId: computed(() => route.query.getUserId ?? ''),
+  groupId: computed(() => route.query.groupId ?? ''),
+  sendUserId: computed(() => route.query.sendUserId ?? '')
 })
 
+// 本地生成一个唯一消息id
+function getLocalId() {
+  const random = Math.floor(Math.random() * 10000)
+  return Date.now() + '' + random
+}
+
 // 刷新次数
 const count = ref(0)
 const loading = ref(false)
+const finished = ref(false)
+const messageList = ref([])
+
+// 单聊的标题
+const title = computed(() => route.query.groupRemark)
+
 // 刷新
-const onRefresh = () => {
-  setTimeout(() => {
-    showToast('刷新成功')
-    loading.value = false
-    count.value++
-  }, 1000)
-}
+const onRefresh = () => {}
 
 const onClickLeft = () => router.back()
 
@@ -44,9 +238,209 @@ const onClickRight = () => {
   navigateTo({
     path: '/chat/set-single',
     query: {
-      userId: route.query.userId
+      toUserId: route.query.getUserId
     }
   })
 }
+
+// 发送消息的方法
+// 发送文本消息
+function sendMessage(messageParams) {
+  console.log(messageParams, 'messageParams')
+  console.log(getUserId.value, '5555')
+  console.log(noticeType, '5555')
+
+  if (!messageParams.trim()) return
+  let msg = {
+    // getUserId: getUserId.value,
+    // sendUserId: sendUserId.value,
+    // groupId: groupId.value,
+    ...querySwParams,
+    specialUserId: specialUserId.value,
+    messageContent: messageParams,
+    messageType: 0,
+    noticeType: 1,
+    object: {
+      id: getLocalId()
+    }
+  }
+
+  receive.value.push({
+    ...msg,
+    messageContent: JSON.stringify({ messageContent: msg.messageContent })
+  })
+  messageContent.value = ''
+  messageBoxRef.value.scrollTop = messageBoxRef.value.scrollHeight
+
+  msg = JSON.stringify(msg)
+  ws.value.send(msg)
+}
+
+const pageSize = ref(10)
+
+const messageCount = ref(0)
+
+// 获取聊天记录
+async function getChatHistory(messageId = '') {
+  if (curConversiton.value.isLocal) return
+
+  if (!groupId.value) return
+
+  if (receive.value.length >= messageCount.value && receive.value.length > 0) return
+
+  if (receive.value.length && !messageId) return
+
+  const query = {
+    pageSize: pageSize.value,
+    groupId: groupId.value,
+    messageId
+  }
+
+  const {
+    data: { data = [], count = [] }
+  } = await request('/website/tourMessage/getMessageByGroupId', { query })
+
+  messageCount.value = count || 0
+
+  if (Array.isArray(data)) {
+    receive.value = [...data, ...receive.value]
+  }
+
+  // 获取到数据后,滚动到底部
+  if (!messageId) {
+    nextTick(() => {
+      setTimeout(() => {
+        messageBoxRef.value && messageBoxRef.value.scrollTo({ top: msgBottomRef.value.offsetTop })
+      }, 100)
+    })
+  }
+  console.log('历史记录:', data)
+}
+
+// 监听输入框的enter事件
+function addEventListenerTextarea() {
+  nextTick(() => {
+    if (inputBoxRef.value) {
+      inputBoxRef.value.removeEventListener('keydown', () => {})
+      inputBoxRef.value.addEventListener('keydown', function (event) {
+        if (event.key === 'Enter') {
+          event.preventDefault()
+          sendMessage()
+        }
+      })
+    }
+  })
+}
+
+// 监听消息列表的滚动事件
+function addEventListenerMessage() {
+  nextTick(() => {
+    if (messageBoxRef.value) {
+      messageBoxRef.value.removeEventListener('scroll', () => {})
+
+      messageBoxRef.value.addEventListener('scroll', (e) => {
+        if (messageBoxRef.value.scrollTop == 0 && receive.value[0]?.id) {
+          console.log('滚动到顶部了')
+          console.log(receive.value[0].id)
+          getChatHistory(receive.value[0].id)
+        }
+      })
+    }
+  })
+}
+
+// 选择发送图片
+function selectImg(e) {
+  const file = e.target.files[0]
+
+  const { size, type, name } = file
+  const IMIETypes = ['image/jpeg', 'image/png', 'image/gif']
+
+  if (!IMIETypes.includes(type)) {
+    showToast('请上传图片')
+
+    return
+  }
+
+  const maxSize = 1024 * 1024 * 20
+
+  if (size > maxSize) {
+    showFailToast('图片大小不能超过10M')
+    return
+  }
+
+  const formData = new FormData()
+
+  formData.append('uploadFile', file)
+  formData.append('fieldName', 'messageContent')
+  formData.append('asImage', true)
+
+  request(uploadUrl, { method: 'post', body: formData }).then((res) => {
+    const {
+      data: { fileUrl }
+    } = res
+    if (fileUrl) {
+      const msg = {
+        getUserId: getUserId.value,
+        sendUserId: sendUserId.value,
+        specialUserId: '',
+        groupId: groupId.value,
+        messageContent: fileUrl,
+        messageType: 1,
+        noticeType: noticeType.value,
+        object: {
+          id: getLocalId()
+        }
+      }
+      ws.value.send(JSON.stringify(msg))
+    }
+  })
+}
+
+// 获取我与对方的关注情况
+async function isFollow() {
+  if (noticeType.value !== 1) return //只有单聊中才需要获取关注情况
+
+  const query = {
+    userId: curConversiton.value.toUserId
+  }
+  const { data: status = 0 } = await request('/website/tourGroup/isFollow', { query })
+  followStatus.value = status
+  console.log('关注情况:', status)
+}
+
+watch(groupId, async () => {
+  // 消息置空
+  receive.value = []
+
+  // 监听消息输入框键盘enter事件
+  addEventListenerTextarea()
+
+  // 监听聊天框消息滚动事件
+  addEventListenerMessage()
+
+  // 获取与当前会话用户的关注状态
+  isFollow()
+
+  // 获取前会话用户的聊天记录
+  getChatHistory()
+})
+
+watch(onNewMessage, getUserId, sendUserId, () => {})
+
+onMounted(() => {
+  // 获取前会话用户的聊天记录
+  getChatHistory()
+
+  addEventListenerTextarea()
+  addEventListenerMessage()
+
+  // 获取与当前会话用户的关注状态
+  isFollow()
+})
+
+definePageMeta({
+  layout: false
+})
 </script>
 <style lang="scss" scoped></style>

+ 296 - 251
src/pages/profile/my-news/index.vue

@@ -7,136 +7,130 @@
       style="opacity: 0; z-index: -1"
     ></audio>
 
-    <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
-      <van-sticky :offset-top="50">
-        <div
-          class="w-full text-xl font-semibold px-16 h-48 flex justify-start items-center bg-white"
+    <!-- <van-pull-refresh v-model="refreshing" @refresh="onRefresh"> -->
+    <van-sticky :offset-top="50">
+      <div class="w-full text-xl font-semibold px-16 h-48 flex justify-start items-center bg-white">
+        <span
+          @click="showPopover = true"
+          v-if="showPopover"
+          class="iconfont icon-plus text-[#FF9300]"
+          style="font-size: 24px"
+        ></span>
+        <span v-else class="iconfont icon-plus text-black" style="font-size: 24px"></span>
+
+        <van-popover
+          v-model:show="showPopover"
+          placement="bottom"
+          theme="dark"
+          offset="[5,20]"
+          :actions="actionsList"
+          @select="onSelect"
         >
-          <span
-            @click="showPopover = true"
-            v-if="showPopover"
-            class="iconfont icon-plus text-[#FF9300]"
-            style="font-size: 24px"
-          ></span>
-          <span v-else class="iconfont icon-plus text-black" style="font-size: 24px"></span>
-
-          <van-popover
-            v-model:show="showPopover"
-            placement="bottom"
-            theme="dark"
-            offset="[5,20]"
-            :actions="actionsList"
-            @select="onSelect"
-          >
-            <template #reference>
-              <span :class="`${showPopover ? 'text-[#FF9300]' : 'text-black-3'}`">添加</span>
-            </template>
-          </van-popover>
-        </div>
-      </van-sticky>
-
-      <div
-        @click="onChatPage('/profile/system-message', {})"
-        class="w-full relative h-82 flex justify-start items-center px-16"
+          <template #reference>
+            <span :class="`${showPopover ? 'text-[#FF9300]' : 'text-black-3'}`">添加</span>
+          </template>
+        </van-popover>
+      </div>
+    </van-sticky>
+
+    <div
+      @click="onChatPage('/profile/system-message', {})"
+      class="w-full relative h-82 flex justify-start items-center px-16"
+    >
+      <van-badge
+        v-if="chatList[0]?.unreadMessageCount"
+        v-bind="messageNumber(chatList[0]?.unreadMessageCount)"
+        max="99"
       >
-        <van-badge
-          v-if="chatList[0]?.unreadMessageCount"
-          v-bind="messageNumber(chatList[0]?.unreadMessageCount)"
-          max="99"
-        >
-          <div
-            class="w-48 h-48 bg-[#0052D9] rounded-full overflow-hidden flex justify-center items-center"
-          >
-            <img
-              class="w-24 h-24 shrink-0 object-cover"
-              src="~/assets/img/chat/remind.svg"
-              alt=""
-            />
-          </div>
-        </van-badge>
-
         <div
-          v-else
           class="w-48 h-48 bg-[#0052D9] rounded-full overflow-hidden flex justify-center items-center"
         >
           <img class="w-24 h-24 shrink-0 object-cover" src="~/assets/img/chat/remind.svg" alt="" />
         </div>
+      </van-badge>
 
-        <div class="h-48 w-245 shrink-0 ml-12 flex flex-wrap items-end">
-          <h1 class="line-clamp-1 w-full text-base text-black-3 font-semibold mb-4">
-            {{ chatList[0]?.groupName }}
-          </h1>
-          <p class="line-clamp-1 h-20 text-sm text-black-6 leading-3xl">
-            {{ messageContentParse(chatList[0]?.lastMessage?.messageContent) }}
-          </p>
-        </div>
+      <div
+        v-else
+        class="w-48 h-48 bg-[#0052D9] rounded-full overflow-hidden flex justify-center items-center"
+      >
+        <img class="w-24 h-24 shrink-0 object-cover" src="~/assets/img/chat/remind.svg" alt="" />
+      </div>
 
-        <div class="w-35 h-48 shrink-0">
-          <p class="text-black/[0.6] text-sm text-end">
-            {{ createTimeSplit(chatList[0]?.lastMessage?.createTime) }}
-          </p>
-        </div>
-        <div class="absolute bottom-0 right-0 w-[96%] h-1 border-b-[1px]"></div>
+      <div class="h-48 w-245 shrink-0 ml-12 flex flex-wrap items-start">
+        <h1 class="line-clamp-1 w-full text-base text-black-3 font-semibold mb-4">
+          {{ chatList[0]?.groupName }}
+        </h1>
+        <p class="line-clamp-1 h-20 text-sm text-black-6 leading-3xl">
+          {{
+            chatList[0]?.lastMessage
+              ? messageContentParse(chatList[0]?.lastMessage?.messageContent)
+              : ''
+          }}
+        </p>
       </div>
 
-      <div
-        @click="navigateTo('/follow?listType=fans')"
-        class="w-full relative h-82 flex justify-start items-center px-16"
+      <div class="w-35 h-48 shrink-0">
+        <p class="text-black/[0.6] text-sm text-end">
+          {{
+            chatList[0]?.lastMessage ? createTimeSplit(chatList[0]?.lastMessage?.createTime) : ''
+          }}
+        </p>
+      </div>
+      <div class="absolute bottom-0 right-0 w-[96%] h-1 border-b-[1px]"></div>
+    </div>
+
+    <div
+      @click="navigateTo('/follow?listType=fans')"
+      class="w-full relative h-82 flex justify-start items-center px-16"
+    >
+      <van-badge
+        v-if="chatList[1]?.unreadMessageCount"
+        v-bind="messageNumber(chatList[1]?.unreadMessageCount)"
+        max="99"
       >
-        <van-badge
-          v-if="chatList[1]?.unreadMessageCount"
-          v-bind="messageNumber(chatList[1]?.unreadMessageCount)"
-          max="99"
-        >
-          <div
-            class="w-48 h-48 bg-[#FF9300] rounded-full overflow-hidden flex justify-center items-center"
-          >
-            <img class="w-24 h-24 shrink-0 object-cover" src="~/assets/img/chat/user.svg" alt="" />
-          </div>
-        </van-badge>
-
         <div
-          v-else
-          @click="navigateTo('/follow?listType=fans')"
-          class="w-48 h-48 bg-[#0052D9] rounded-full overflow-hidden flex justify-center items-center"
+          class="w-48 h-48 bg-[#FF9300] rounded-full overflow-hidden flex justify-center items-center"
         >
           <img class="w-24 h-24 shrink-0 object-cover" src="~/assets/img/chat/user.svg" alt="" />
         </div>
+      </van-badge>
 
-        <div class="h-48 w-245 shrink-0 ml-12 flex flex-wrap items-end">
-          <h1 class="line-clamp-1 w-full text-base text-black-3 font-semibold mb-4">
-            {{ chatList[1]?.groupName }}
-          </h1>
-          <p class="line-clamp-1 h-20 text-sm text-black-6 leading-3xl">
-            {{ messageContentParse(chatList[1]?.lastMessage?.messageContent) }}
-          </p>
-        </div>
-
-        <div class="w-35 h-48 shrink-0">
-          <p class="text-black/[0.6] text-sm text-end">
-            {{ createTimeSplit(chatList[1]?.lastMessage?.createTime) }}
-          </p>
-        </div>
-        <div class="absolute bottom-0 right-0 w-[96%] h-1 border-b-[1px]"></div>
-      </div>
       <div
-        @click="onChatPage('/profile/interaction-message', {})"
-        class="w-full relative h-82 flex justify-start items-center px-16"
+        v-else
+        @click="navigateTo('/follow?listType=fans')"
+        class="w-48 h-48 bg-[#0052D9] rounded-full overflow-hidden flex justify-center items-center"
       >
-        <van-badge v-if="messagesNumber > 0" v-bind="messageNumber(messagesNumber)" max="99">
-          <div
-            class="w-48 h-48 bg-[#FF476A] rounded-full overflow-hidden flex justify-center items-center"
-          >
-            <img
-              class="w-24 h-24 shrink-0 object-cover"
-              src="~/assets/img/chat/weixin-shake.svg"
-              alt=""
-            />
-          </div>
-        </van-badge>
+        <img class="w-24 h-24 shrink-0 object-cover" src="~/assets/img/chat/user.svg" alt="" />
+      </div>
+
+      <div class="h-48 w-245 shrink-0 ml-12 flex flex-wrap items-start">
+        <h1 class="line-clamp-1 w-full text-base text-black-3 font-semibold mb-4">
+          {{ chatList[1]?.groupName }}
+        </h1>
+        <p class="line-clamp-1 h-20 text-sm text-black-6 leading-3xl">
+          {{
+            chatList[1]?.lastMessage
+              ? messageContentParse(chatList[1]?.lastMessage?.messageContent)
+              : ''
+          }}
+        </p>
+      </div>
 
+      <div class="w-35 h-48 shrink-0">
+        <p class="text-black/[0.6] text-sm text-end">
+          {{
+            chatList[1]?.lastMessage ? createTimeSplit(chatList[1]?.lastMessage?.createTime) : ''
+          }}
+        </p>
+      </div>
+      <div class="absolute bottom-0 right-0 w-[96%] h-1 border-b-[1px]"></div>
+    </div>
+    <div
+      @click="onChatPage('/profile/interaction-message', {})"
+      class="w-full relative h-82 flex justify-start items-center px-16"
+    >
+      <van-badge v-if="messagesNumber > 0" v-bind="messageNumber(messagesNumber)" max="99">
         <div
-          v-else
           class="w-48 h-48 bg-[#FF476A] rounded-full overflow-hidden flex justify-center items-center"
         >
           <img
@@ -145,104 +139,137 @@
             alt=""
           />
         </div>
+      </van-badge>
 
-        <div class="h-48 w-245 shrink-0 ml-12 flex flex-wrap items-end">
-          <h1 class="line-clamp-1 w-full text-base text-black-3 font-semibold mb-4">
-            {{ chatList[2]?.groupName }}
-          </h1>
-          <p class="line-clamp-1 h-20 text-sm text-black-6 leading-3xl">
-            {{ messageContentParse(chatList[2]?.lastMessage?.messageContent) }}
-          </p>
-        </div>
-
-        <div class="w-35 h-48 shrink-0">
-          <p class="text-black/[0.6] text-sm text-end">
-            {{ createTimeSplit(chatList[2]?.lastMessage?.createTime) }}
-          </p>
-        </div>
-        <div class="absolute bottom-0 right-0 w-[96%] h-1 border-b-[1px]"></div>
+      <div
+        v-else
+        class="w-48 h-48 bg-[#FF476A] rounded-full overflow-hidden flex justify-center items-center"
+      >
+        <img
+          class="w-24 h-24 shrink-0 object-cover"
+          src="~/assets/img/chat/weixin-shake.svg"
+          alt=""
+        />
       </div>
 
-      <!-- 置顶绘画列表  "-->
-      <div v-if="isTopList?.length && activeNames" class="w-full">
-        <template v-for="(item, index) in isTopList" :key="item?.id">
-          <template v-if="index > 2">
-            <!-- 单聊会话 -->
-            <ProfileNewsGroupChat
-              v-if="item?.noticeType == 2"
-              :item-data="{
-                ...item,
-                updateTime: createTimeSplit(item?.lastMessage?.updateTime)
-              }"
-              @on-chat-page="
-                onChatPage('/chat/group', { userId: user.userId, groupId: item?.groupId })
-              "
-              @on-no-bother="noBother(item)"
-              @on-is-top="onIsTop(item)"
-              @on-conv-delete="onIsShow(item)"
-            />
-
-            <!-- 群聊会话 -->
-            <ProfileNewsSingleChat
-              v-if="item?.noticeType == 1"
-              :item-data="{
-                ...item,
-                updateTime: createTimeSplit(item?.lastMessage?.updateTime)
-              }"
-              @on-chat-page="
-                onChatPage('/chat/single', { userId: userInfo.userId, groupId: item?.groupId })
-              "
-              @on-no-bother="noBother(item)"
-              @on-is-top="onIsTop(item)"
-              @on-conv-delete="onIsShow(item)"
-            />
-          </template>
-          <template v-else></template>
-        </template>
+      <div class="h-48 w-245 shrink-0 ml-12 flex flex-wrap items-start">
+        <h1 class="line-clamp-1 w-full text-base text-black-3 font-semibold mb-4">
+          {{ chatList[2]?.groupName }}
+        </h1>
+        <p class="line-clamp-1 h-20 text-sm text-black-6 leading-3xl">
+          {{
+            chatList[2]?.lastMessage
+              ? messageContentParse(chatList[2]?.lastMessage?.messageContent)
+              : ''
+          }}
+        </p>
       </div>
 
-      <div
-        v-if="isTopList.length >= 6"
-        @click="activeNames = !activeNames"
-        class="flex justify-between border items-center h-20 w-full p-16 box-border"
-      >
-        <div class="shrink-0 flex items-center">
-          <van-icon name="bars" size="16" class="mr-5" />
-          <span class="text-sm">{{ collapseTitle }}</span>
-        </div>
-        <div class="w-16 h-16 shrink-0">
-          <van-icon name="arrow" size="16" />
-        </div>
+      <div class="w-35 h-48 shrink-0">
+        <p class="text-black/[0.6] text-sm text-end">
+          {{
+            chatList[2]?.lastMessage ? createTimeSplit(chatList[2]?.lastMessage?.createTime) : ''
+          }}
+        </p>
       </div>
+      <div class="absolute bottom-0 right-0 w-[96%] h-1 border-b-[1px]"></div>
+    </div>
+
+    <!-- 置顶绘画列表  "-->
+    <div v-if="isTopList?.length && activeNames" class="w-full">
+      <template v-for="(item, index) in isTopList" :key="item?.id">
+        <template v-if="index > 2">
+          <!-- 单聊会话 -->
+          <ProfileNewsGroupChat
+            v-if="item?.noticeType == 2"
+            :item-data="{
+              ...item,
+              updateTime: item?.lastMessage ? createTimeSplit(item?.lastMessage?.updateTime) : ''
+            }"
+            @on-chat-page="
+              onChatPage('/chat/group', { userId: user.userId, groupId: item?.groupId })
+            "
+            @on-no-bother="noBother(item)"
+            @on-is-top="onIsTop(item)"
+            @on-conv-delete="onIsShow(item)"
+          />
 
-      <!-- 不置顶的会话列表 -->
-      <template v-for="(item, index) in pinnedList" :key="item?.id">
-        <ProfileNewsGroupChat
-          v-if="item?.noticeType == 2"
-          :item-data="{
-            ...item,
-            updateTime: createTimeSplit(item?.lastMessage?.updateTime)
-          }"
-          @on-chat-page="onChatPage('/chat/group', { userId: user.userId, groupId: item?.groupId })"
-          @on-no-bother="noBother(item)"
-          @on-is-top="onIsTop(item)"
-          @on-conv-delete="onIsShow(item)"
-        />
-        <ProfileNewsSingleChat
-          v-if="item?.noticeType == 1"
-          :item-data="{
-            ...item,
-            updateTime: createTimeSplit(item?.lastMessage?.updateTime)
-          }"
-          @on-chat-page="
-            onChatPage('/chat/single', { userId: user.userId, groupId: item?.groupId })
-          "
-          @on-no-bother="noBother(item)"
-          @on-is-top="onIsTop(item)"
-          @on-conv-delete="onIsShow(item)"
-        />
+          <!-- 群聊会话 -->
+          <ProfileNewsSingleChat
+            v-if="item?.noticeType == 1"
+            :item-data="{
+              ...item,
+              updateTime: item?.lastMessage ? createTimeSplit(item?.lastMessage?.updateTime) : ''
+            }"
+            @on-chat-page="
+              onChatPage('/chat/single', {
+                sendUserId: userInfo.userId,
+                groupId: item?.groupId,
+                getUserId: item?.toUserId,
+                groupRemark: item?.groupRemark
+              })
+            "
+            @on-no-bother="noBother(item)"
+            @on-is-top="onIsTop(item)"
+            @on-conv-delete="onIsShow(item)"
+          />
+        </template>
+        <template v-else></template>
       </template>
-    </van-pull-refresh>
+    </div>
+
+    <div
+      v-if="isTopList.length >= 6"
+      @click="activeNames = !activeNames"
+      class="flex justify-between border items-center h-20 w-full p-16 box-border"
+    >
+      <div class="shrink-0 flex items-center">
+        <van-icon name="bars" size="16" class="mr-5" />
+        <span class="text-sm">{{ collapseTitle }}</span>
+      </div>
+      <div class="w-16 h-16 shrink-0">
+        <van-icon name="arrow" size="16" />
+      </div>
+    </div>
+
+    <!-- 不置顶的会话列表 -->
+    <template v-for="(item, index) in pinnedList" :key="item?.id">
+      <ProfileNewsGroupChat
+        v-if="item?.noticeType == 2"
+        :item-data="{
+          ...item,
+          updateTime: item?.lastMessage ? createTimeSplit(item?.lastMessage?.updateTime) : ''
+        }"
+        @on-chat-page="
+          onChatPage('/chat/group', {
+            userId: userInfo.userId,
+            groupId: item?.groupId
+          })
+        "
+        @on-no-bother="noBother(item)"
+        @on-is-top="onIsTop(item)"
+        @on-conv-delete="onIsShow(item)"
+      />
+      <ProfileNewsSingleChat
+        v-if="item?.noticeType == 1"
+        :item-data="{
+          ...item,
+          updateTime: item?.lastMessage ? createTimeSplit(item?.lastMessage?.updateTime) : ''
+        }"
+        @on-chat-page="
+          onChatPage('/chat/single', {
+            sendUserId: userInfo.userId,
+            groupId: item?.groupId,
+            getUserId: item?.toUserId,
+            groupRemark: item?.groupRemark
+          })
+        "
+        @on-no-bother="noBother(item)"
+        @on-is-top="onIsTop(item)"
+        @on-conv-delete="onIsShow(item)"
+      />
+    </template>
+    <!-- </van-pull-refresh> -->
   </div>
 </template>
 
@@ -263,16 +290,13 @@ const userInfoStore = useUserInfoStore()
 const { userInfo } = storeToRefs(userInfoStore)
 // const uploadUrl = `${import.meta.env.VITE_APP_BASE_URL}/website/tourMessage/upload`
 const chatStore = useChatStore()
-const { messages, user, connectSta, chatList, curConversiton, onNewMessage } =
-  storeToRefs(chatStore)
-
-// const user = computed(() => chatStore.user)
-
-// // 聊天类型 1单聊 2群聊 3系统消息 4关注信息
-// const noticeType = computed(() => curConversiton.value.noticeType)
+const { messages, connectSta, chatList, curConversiton, onNewMessage } = storeToRefs(chatStore)
 
+// 链接的状态
 const wsConnect = computed(() => connectSta.value)
 
+const chatLists = computed(() => chatList.value)
+
 const audioRef = ref(null)
 
 const finished = ref(false)
@@ -286,8 +310,8 @@ const showPopover = ref(false)
 const messagesNumber = ref(10)
 
 // 置顶列表
-const isTopList = ref([])
-const pinnedList = ref([])
+const isTopList = computed(() => chatList.value.filter((el) => el.isTop != 1))
+const pinnedList = computed(() => chatList.value.filter((el) => el?.isTop == 1) ?? [])
 const pinnedSystemList = ref([]) //三个固定的消息
 
 // 个置顶聊天
@@ -301,53 +325,24 @@ const collapseTitle = ref(collapse_text)
 const refreshing = ref(false)
 
 // 建立链接
-async function getUserInfo() {
-  const { data } = await request('/website/tourism/user/view')
-  chatStore.user = data
-  user.value = data
-  console.log(data, 'createConnection')
+// async function getUserInfo() {
+//   const { data } = await request('/website/tourism/user/view')
+//   chatStore.user = data
+//   user.value = data
+//   console.log(data, 'createConnection')
 
-  await chatStore.createConnection(data.pass)
-  chatStore.reqChatList()
+//   await chatStore.createConnection(data.pass)
+//   chatStore.reqChatList()
 
-  console.log('用户信息:', chatStore.user)
-
-  // console.log('会话列表:', chatStore.chatList.value)
-}
-
-onMounted(() => {
-  getUserInfo()
-  if (wsConnect == 0) {
-    showToast('聊天网络连接中...')
-  } else if (wsConnect == 1) {
-    showToast(' 聊天正在连接中...')
-  } else if (wsConnect == 3) {
-    showToast(' 聊天连接已断开,请刷新页面重新连接,或稍后重试!')
-  } else if (wsConnect == 2) {
-  }
+//   console.log('用户信息:', chatStore.user)
 
-  // chatStore.reqChatList()
-})
+//   // console.log('会话列表:', chatStore.chatList.value)
+// }
 
 useSeoMeta({
   title: '我的消息'
 })
 
-watch(
-  chatList.value,
-  (newList, oldList) => {
-    // pinnedSystemList.value = newList.filter((el) => el.noticeType == 3)
-    pinnedList.value = newList.filter((el) => el.isTop != 1)
-    isTopList.value = newList.filter((el) => el.isTop == 1)
-
-    console.log(pinnedList.value, 'pinnedList')
-    console.log(isTopList.value, 'isTopList')
-    // console.log(newList, 'newList')
-    console.log(oldList, 'oldList')
-  },
-  { immediate: true }
-)
-
 // 时间的转换
 const createTimeSplit = (timer) => {
   if (timer) {
@@ -358,6 +353,7 @@ const createTimeSplit = (timer) => {
 const onRefresh = () => {
   refreshing.value = true
   chatStore.reqChatList()
+  refreshing.value = false
 }
 
 // 打扰和免打扰得
@@ -419,11 +415,19 @@ const messageNumber = (content) => {
 }
 
 // 跳转聊天页面
-const onChatPage = (path, query) => {
-  navigateTo({
-    path,
-    query
+const onChatPage = async (path, query) => {
+  const res = await request('/website/tourMessage/updateRead', {
+    query: {
+      groupId: query.groupId
+    }
   })
+
+  if (res && res?.success) {
+    navigateTo({
+      path,
+      query
+    })
+  }
 }
 
 // 选中的是那个页面
@@ -433,6 +437,47 @@ const onSelect = (action) => {
   if (action.text == '加入群聊') onChatPage('/scan', {})
   if (action.text == '添加用户') onChatPage('/chat/user-add', {})
 }
+
+onMounted(() => {
+  if (wsConnect == 0) {
+    showToast('聊天网络连接中...')
+  } else if (wsConnect == 1) {
+    showToast(' 聊天正在连接中...')
+  } else if (wsConnect == 3) {
+    showToast(' 聊天连接已断开,请刷新页面重新连接,或稍后重试!')
+  } else if (wsConnect == 2) {
+  }
+  chatStore.reqChatList()
+  // chatStore.reqChatList()
+})
+
+// watch(
+//   wsConnect,
+//   async (newValue, oldValue) => {
+//     console.log(newValue, 'wsConnect')
+//     console.log(chatLists.value, 'chatLists')
+
+//     if (newValue == 2) {
+//       pinnedList.value = chatList.value.filter((el) => el.isTop != 1)
+//       isTopList.value = chatList.value.filter((el) => el.isTop == 1)
+//     }
+//   },
+//   { immediate: true }
+// )
+// watch(
+//   chatList.value,
+//   (newList, oldList) => {
+//     // pinnedSystemList.value = newList.filter((el) => el.noticeType == 3)
+//     pinnedList.value = newList.filter((el) => el.isTop != 1)
+//     isTopList.value = newList.filter((el) => el.isTop == 1)
+
+//     console.log(pinnedList.value, 'pinnedList')
+//     console.log(isTopList.value, 'isTopList')
+//     // console.log(newList, 'newList')
+//     console.log(oldList, 'oldList')
+//   },
+//   { immediate: true }
+// )
 </script>
 
 <style lang="scss" scoped></style>

+ 10 - 4
src/utils/detalTime.js

@@ -119,9 +119,15 @@ export function formatTimestamp(timestamp) {
 
 // 消息的内容转换
 export function messageContentParse(messageContent) {
-  let content = ''
-  if (messageContent) {
-    content = JSON.parse(messageContent)
+  try {
+    let content = {}
+    if (messageContent) {
+      content = JSON.parse(messageContent)
+      return content.messageContent
+    } else {
+      return ''
+    }
+  } catch (error) {
+    console.log(error)
   }
-  return content?.messageContent
 }