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

Merge branch 'dev' of http://1.94.207.143:3000/xyy/xyy-m into dev

qiao преди 1 месец
родител
ревизия
b2be939b6a

+ 8 - 3
.env.development

@@ -1,9 +1,13 @@
 VITE_APP_ENV=development
 
+
+# 测试服
 # VITE_APP_BASE_URL=https://service.xiaoyaotravel.com/api/
-# VITE_APP_BASE_URL=http://101.126.146.250:8082/
-# VITE_APP_IM_URL=ws://101.126.146.250:8082/system/message
-# # 测试服
+VITE_APP_BASE_URL=http://101.126.146.250:8082/
+VITE_APP_IM_URL=ws://101.126.146.250:8082/system/message
+
+
+
 
 
 
@@ -30,6 +34,7 @@ VITE_APP_IM_URL=ws://192.168.1.44:8082/system/message
 # VITE_APP_BASE_URL=http://4eqxwr.natappfree.cc
 # VITE_APP_IM_URL=ws://4eqxwr.natappfree.cc/system/message
 
+
 # VITE_APP_BASE_URL=http://192.168.1.204:8082
 VITE_APP_EMOJI_API=https://v.xiaoyaotravel.com/emoji/
 VITE_APP_IM_USER_SUFFIX=dev

+ 1 - 1
.env.production

@@ -9,5 +9,5 @@ VITE_APP_WEBSITE_BASE_URL=https://www.xiaoyaotravel.com/
 
 VITE_APP_IM_USER_SUFFIX=''
 
-VITE_APP_IM_URL=wss://www.xiaoyaotravel.com/system/message
+VITE_APP_IM_URL=wss://service.xiaoyaotravel.com/system/message
 

+ 1 - 1
src/middleware/02.auth.global.js

@@ -22,7 +22,7 @@ export default defineNuxtRouteMiddleware((to, from) => {
 
      userInfoStore.getUserInfo().then(() => {
       // chatsStore.initWebSocket(baseIM + '?token=' + userInfo.value.pass)
-      chatsStore.initWebSocket(baseIM + '?token=' + userInfo.value.pass)
+      chatsStore.initWebSocket(baseIM + '?token=' + userInfo.value.userId)
     })
     return
   }

+ 14 - 8
src/pages/chat/components/chat-message/index.vue

@@ -12,9 +12,12 @@
         radius="100%"
         class="mr-8"
       ></van-image>
-      <div v-if="false" class="self-center text-sm mx-5 text-black-9">
-        <van-loading v-if="sendStatus === 'loading'" size="16" />
-        <van-icon v-if="sendStatus === 'error'" name="warning" size="16" />
+<!--      <template v-if="msg.web_message_status">
+        <div class="w-16 h-16 rounded-full bg-amber-950 text-sm grid place-content-center text-white">!</div>
+      </template>-->
+      <div v-if="msg.viewType === 0 && msg.web_message_status" class="self-center text-sm mx-5 text-black-9">
+        <van-loading v-if="msg.web_message_status === chatsStore.WEB_MESSAGE_STATUS.loading" size="16" />
+        <van-icon v-if="msg.web_message_status === chatsStore.WEB_MESSAGE_STATUS.error" name="warning" size="16"  color="#fa9819"/>
       </div>
       <div class="flex flex-col" :class="msg.viewType ? 'items-start' : 'items-end'">
         <div v-if="showName && msg.viewType === 1" class="text-black-9 text-sm mb-2">
@@ -43,7 +46,7 @@
           ></LinkMessage>
         </div>
       </div>
-      <!--      <div class="self-center text-sm mx-5 text-black-9">发送中</div>-->
+
       <van-image
         v-if="msg.viewType === 0"
         :src="msg.headImageUrl"
@@ -65,6 +68,7 @@ import { findHyperlinks } from '~/pages/chat/components/chat-message/link-messag
 
 const userInfoStore = useUserInfoStore()
 const { userInfo } = storeToRefs(userInfoStore)
+const chatsStore = useChatsStore()
 
 const props = defineProps({
   message: Object,
@@ -75,23 +79,25 @@ const props = defineProps({
 })
 const msg = computed(() => {
   try {
-    // console.log(props.message, 'msg')
+    // console.log(props.message, moreLoading)
     const {
       createTime,
       getUserId,
       sendUserId,
       messageContent,
       messageType,
-      object = { headImageUrl: defaultAvatar, showName: '无名大侠' }
+      web_message_status,
+      object = { headImageUrl: defaultAvatar, showName: '无名大侠', web_message_status: chatsStore.WEB_MESSAGE_STATUS.success }
     } = props.message
-    const headImageUrl = props.message.headImageUrl || object.headImageUrl;
+    const headImageUrl = props.message.headImageUrl || object.headImageUrl
     return {
       messageContent: messageContent,
       type: getMessageType(messageType, messageContent),
       viewType: sendUserId === userInfo?.value.pass ? 0 : 1,
       createTime: createTime,
       headImageUrl: headImageUrl,
-      nickName: object.showName
+      nickName: object.showName,
+      web_message_status: object.web_message_status
     }
   } catch (e) {
     console.log(e, '??')

+ 1 - 1
src/pages/chat/components/chat-message/link-message/handle.js

@@ -1,5 +1,5 @@
 
-const IN_STATION_LINK = ['xiaoyaotravel.com']// 站内链接
+const IN_STATION_LINK = ['www.xiaoyaotravel.com']// 站内链接
 export const findHyperlinks = (text) => {
   try {
     const urlPattern = /https?:\/\/[^\s]+/g;

+ 1 - 1
src/pages/chat/components/chat-message/link-message/index.vue

@@ -47,7 +47,7 @@ onMounted(() => {
       </template>
     </div>
     <template v-if="linkInfo">
-      <div v-if="linkInfo.isInStation"
+      <div v-if="!linkInfo.isInStation"
            class="bg-[#F3F3F3] rounded-[25px] px-12 py-4 text-black-9 mt-4 text-sm w-max grid place-items-center"
       >
         转自 第三方链接

+ 3 - 0
src/pages/chat/create-group.vue

@@ -223,6 +223,7 @@ const handleTypeClick = (item) => {
     subTypeList.value = item.children
     if (item.children == 0) {
       childrenIndex.value = item.id
+      formData.belongTypeId = item.id
       groupTypeName.value = item.typeName
     } else {
       childrenIndex.value = null
@@ -249,6 +250,8 @@ const changeBelongTypeId = () => {
   if (groupTypeName.value && childrenIndex.value) {
     if (childrenIndex.value != formData.belongTypeId) {
       show.value = false
+    } else {
+      show.value = false
     }
   } else {
     showDialog({

+ 0 - 7
src/pages/chat/group-add.vue

@@ -208,8 +208,6 @@ const getList = async () => {
     })
 
     if (Array.isArray(data) && data?.length) {
-      // const { sortListMap } = sortStringToAZ.sort(data, 'showName')
-
       addDataList.value = data
       filterDataList.value = data
     } else {
@@ -247,11 +245,6 @@ async function handleCreateGroup() {
     if (data) {
       getList()
       router.back()
-      // navigateTo({
-      //   path: '/chat/group-chat',
-      //   query: data,
-      //   replace: true
-      // })
     }
   } catch (error) {
   } finally {

+ 40 - 14
src/pages/chat/group-chat.vue

@@ -9,7 +9,7 @@
       <template #title>
         <div class="text-2xl text-black-3 text-semibold flex items-center">
           <div style="min-width: 50px; max-width: 200px" class="inline-block line-clamp-1">
-            {{ groupInfo?.groupName }}
+            {{ groupMemberInfo?.groupName }}
           </div>
           <span
             v-if="groupMemberInfo.isNotDisturb"
@@ -69,10 +69,13 @@
         <template v-for="(message, index) in currConversationChatList" :key="index">
           <ChatMessage :show-name="true" :message="message"></ChatMessage>
         </template>
+        <div v-if="chatErrorText" class="text-[#979797] text-sm text-center mt-auto mb-10">
+          {{ chatErrorText }}
+        </div>
         <!-- </div> -->
       </van-list>
       <!-- </van-pull-refresh> -->
-      <div class="h-70 w-full bg-[#fff] border"></div>
+      <div class="h-70 w-full bg-[#fff]"></div>
       <div class="fixed bottom-0 left-0 right-0 w-full bg-[#fff]">
         <ChatInput
           :operates="['image', 'share-group']"
@@ -101,6 +104,7 @@ import ChatInput from './components/chat-input'
 import { findHyperlinks } from '~/pages/chat/components/chat-message/link-message/handle'
 import { XYWebSocket } from '~/utils/XYWebSocket'
 import { isValidJson } from '~/utils'
+import defaultAvatar from '@/assets/img/default_avatar.png'
 
 const finished = ref(false)
 const loading = ref(false)
@@ -201,16 +205,21 @@ const sendTextMessage = async (text) => {
       object: {
         id: getLocalId(),
         // TODO 聊天时候改了头像昵称 会出现找不到的情况
-        headImageUrl: userInfo?.value.headImageUrl,
-        showName: userInfo?.value.showName
+        headImageUrl: userInfo.value.headImageUrl ? userInfo.value?.headImageUrl : defaultAvatar,
+        showName: userInfo?.value.showName,
+        web_message_status: chatsStore.WEB_MESSAGE_STATUS.loading
       }
     }
     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)
+    const backMessage = await chatsStore.sendSocketMessage(msg)
+    const { index, message } = chatsStore.updateBackMessage(
+      currConversationChatList.value,
+      backMessage
+    )
+    currConversationChatList.value[index] = message
   } catch (e) {
     // console.log(e, '2')
   } finally {
@@ -244,15 +253,21 @@ const sendImageMessage = async (file) => {
       object: {
         id: getLocalId(),
         // TODO 聊天时候改了头像昵称 会出现找不到的情况
-        headImageUrl: userInfo?.value.headImageUrl,
-        showName: userInfo?.value.showName
+        headImageUrl: userInfo.value.headImageUrl ? userInfo.value?.headImageUrl : defaultAvatar,
+        showName: userInfo?.value.showName,
+        web_message_status: chatsStore.WEB_MESSAGE_STATUS.loading
       }
     }
 
     closeToast()
     currConversationChatList.value.push(msg)
     await scrollToBottom()
-    await chatsStore.sendSocketMessage(msg)
+    const backMessage = await chatsStore.sendSocketMessage(msg)
+    const { index, message } = chatsStore.updateBackMessage(
+      currConversationChatList.value,
+      backMessage
+    )
+    currConversationChatList.value[index] = message
   } catch (e) {
     console.error(e, '??')
   } finally {
@@ -286,7 +301,6 @@ const scrollToBottom = async () => {
       const scrollContainer = listElement
 
       scrollContainer.scrollTop = scrollContainer.scrollHeight
-      // console.log(scrollContainer.scrollTop, '6666')
     }
   }, 200)
 }
@@ -323,6 +337,10 @@ const onClickRight = () => {
     })
 }
 
+const chatErrorText = computed(() => {
+  return chatsStore.getChatErrorText(currConversationChatList.value)
+})
+
 // 本地生成一个唯一消息id
 function getLocalId() {
   const random = Math.floor(Math.random() * 10000)
@@ -338,19 +356,18 @@ onMounted(() => {
       const isOtherUserMessage = chat.sendUserId && chatsStore.isRealMessage(chat.sendUserId)
       if (isCurrGroupId) {
         if (isOtherUserMessage) {
-          currConversationChatList.value.push(chat)
+          const { message } = chatsStore.updateBackMessage([chat], chat)
+          currConversationChatList.value.push(message)
           await scrollToBottom()
         }
         if (!isOtherUserMessage) {
-          await getChatList('init')
+          // 这里就不做处理,因为本地发送后就立马更新了currConversationChatList
         }
       }
     })
   } catch (error) {}
 })
 
-watchEffect(() => {})
-
 // 查寻群公告
 async function getAnnouncement() {
   let { data } = await request('/website/tourGroup/getGroupInfoAndMemberByGroupId', {
@@ -362,6 +379,15 @@ async function getAnnouncement() {
     if (Array.isArray(data.memberList) && data?.memberList?.length) {
       data.memberList.map((el) => {
         if (el.userId == userInfo.value.userId) {
+          console.log(el, 'el  前')
+          // 头部的名称已自己的备注名优先
+          if (el?.groupRemark) {
+            el.groupName = el.groupRemark
+          } else {
+            el.groupName = data?.groupName
+          }
+
+          console.log(el, 'el  后')
           groupMemberInfo.value = el
         }
       })

+ 3 - 3
src/pages/chat/set-single.vue

@@ -162,8 +162,8 @@ const getFriendInfo = async () => {
   const { list } = data || {}
   if (Array.isArray(list) && list?.length) {
     itemData.value = list.filter((el) => el.toUserId == toUserId.value)[0]
-    isNotDisturb.value = itemData.value
-    isTop.value = itemData.value
+    isNotDisturb.value = itemData.value?.isNotDisturb
+    isTop.value = itemData.value?.isTop
   }
 }
 
@@ -249,7 +249,7 @@ const handleBoolean = async (params) => {
         isTop.value ? showToast('已置顶') : showToast('置顶取消')
       }
       if (Object.keys(params)[0] == 'isNotDisturb') {
-        isNotDisturb.value ? showToast('已开启面打扰') : showToast('已关闭面打扰')
+        isNotDisturb.value ? showToast('已开启免打扰') : showToast('已关闭免打扰')
       }
     }
   } catch (error) {}

+ 2 - 1
src/pages/chat/set.vue

@@ -758,8 +758,9 @@ const handleBoolean = async (params) => {
         isTop.value ? showToast('已置顶') : showToast('置顶取消')
       }
       if (Object.keys(params)[0] == 'isNotDisturb') {
-        isNotDisturb.value ? showToast('已开启面打扰') : showToast('已关闭面打扰')
+        isNotDisturb.value ? showToast('已开启免打扰') : showToast('已关闭免打扰')
       }
+      getGroupSetData()
     }
   } catch (error) {}
 }

+ 14 - 2
src/pages/chat/single-add.vue

@@ -122,6 +122,7 @@
 </template>
 <script setup>
 const route = useRoute()
+const router = useRouter()
 
 definePageMeta({
   layout: false
@@ -131,7 +132,7 @@ onMounted(() => {
   getList()
 })
 // 对方的那个id
-const toUserId = computed(() => route.query.toUserId ?? '')
+const toUserId = computed(() => route.query?.toUserId ?? '')
 const refreshing = ref(false)
 const loading = ref(false)
 const finished = ref(false)
@@ -166,6 +167,7 @@ const toggle = (item) => {
   } else {
     checkedList.value.push(item)
   }
+
   checkboxRefs.value[item?.attentionIdDictMap?.userId].toggle()
 }
 
@@ -204,6 +206,16 @@ const getList = async () => {
 
     if (Array.isArray(dataList) && dataList?.length) {
       addDataList.value = dataList
+
+      nextTick(() => {
+        checkboxRefs.value[toUserId.value].toggle()
+        let item = dataList.find((el) => el?.attentionIdDictMap?.userId == toUserId.value)
+        if (item) {
+          checkedList.value.push(item)
+        } else {
+          router.back()
+        }
+      })
     } else {
       addDataList.value = []
     }
@@ -247,7 +259,7 @@ async function handleCreateGroup() {
         method: 'post',
         body: {
           createType: 2,
-          ids: [...checked.value, toUserId.value]
+          ids: [...checked.value]
         }
       })
 

+ 77 - 64
src/pages/chat/single-chat.vue

@@ -39,8 +39,8 @@
           <template v-for="(message, index) in currConversationChatList" :key="index">
             <ChatMessage :message="message"></ChatMessage>
           </template>
-          <div v-if="false" class="text-[#979797] text-sm text-center mt-auto mb-10">
-            {{ followStatus }}在对方关注或回复前,最多只能发送1条信息
+          <div v-if="chatErrorText" class="text-[#979797] text-sm text-center mt-auto mb-10">
+            {{ chatErrorText }}
           </div>
         </van-list>
       </van-pull-refresh>
@@ -72,7 +72,7 @@ import ChatMessage from './components/chat-message'
 import ChatInput from './components/chat-input'
 import { findHyperlinks } from '~/pages/chat/components/chat-message/link-message/handle'
 import { XYWebSocket } from '~/utils/XYWebSocket'
-
+import defaultAvatar from '@/assets/img/default_avatar.png'
 const route = useRoute()
 const router = useRouter()
 
@@ -103,7 +103,7 @@ const initGroupId = async () => {
     const res = await chatsStore.getCurrConversationId(getUserId.value)
     await handleResponse(res)
     groupId.value = res.data
-    getAnnouncement()
+    memberInfo.value = await getAnnouncement()
     await getChatList('init')
     await getFollowStatus()
   } catch (e) {
@@ -176,17 +176,24 @@ const sendTextMessage = async (text) => {
       object: {
         id: getLocalId(),
         // TODO 聊天时候改了头像昵称 会出现找不到的情况
-        headImageUrl: userInfo?.value.headImageUrl,
-        showName: userInfo?.value.showName
+        headImageUrl: userInfo.value.headImageUrl ? userInfo.value?.headImageUrl : defaultAvatar,
+        showName: userInfo?.value.showName,
+        web_message_status: chatsStore.WEB_MESSAGE_STATUS.loading
       }
     }
     const isLink = !!findHyperlinks(text)
     if (isLink) msg.messageType = 4
+    // console.log(currConversationChatList.value, '1122')
     currConversationChatList.value.push(msg)
     await scrollToBottom()
-    await chatsStore.sendSocketMessage(msg)
+    const backMessage = await chatsStore.sendSocketMessage(msg)
+    const { index, message } = chatsStore.updateBackMessage(
+      currConversationChatList.value,
+      backMessage
+    )
+    currConversationChatList.value[index] = message
   } catch (e) {
-    // console.log(e, '2')
+    console.log(e, '2')
   } finally {
   }
 }
@@ -218,14 +225,21 @@ const sendImageMessage = async (file) => {
       object: {
         id: getLocalId(),
         // TODO 聊天时候改了头像昵称 会出现找不到的情况
-        headImageUrl: userInfo?.value.headImageUrl,
-        showName: userInfo?.value.showName
+        headImageUrl: userInfo.value.headImageUrl ? userInfo.value?.headImageUrl : defaultAvatar,
+        showName: userInfo?.value.showName,
+        web_message_status: chatsStore.WEB_MESSAGE_STATUS.loading
       }
     }
     closeToast()
     currConversationChatList.value.push(msg)
     await scrollToBottom()
     await chatsStore.sendSocketMessage(msg)
+    const backMessage = await chatsStore.sendSocketMessage(msg)
+    const { index, message } = chatsStore.updateBackMessage(
+      currConversationChatList.value,
+      backMessage
+    )
+    currConversationChatList.value[index] = message
   } catch (e) {
     console.error(e, '??')
   } finally {
@@ -233,6 +247,8 @@ const sendImageMessage = async (file) => {
 }
 
 const handleSendMessage = async ({ type, messageContent }) => {
+  console.log(131)
+
   try {
     switch (type) {
       case 'text':
@@ -250,34 +266,12 @@ const handleSendMessage = async ({ type, messageContent }) => {
   }
 }
 
-const scrollToBottom = async () => {
-  // 操作向上加载不滚动 TODO 判断用户是否有向上滑的操作更准确
-  if (moreLoading.value) return
-  setTimeout(async () => {
-    await nextTick() // 确保DOM已经更新
-    const listElement = chatListRef.value?.$el
-    if (listElement) {
-      const scrollContainer = listElement
-      scrollContainer.scrollTop = scrollContainer.scrollHeight
-    }
-  }, 200)
-}
-
-// 获取我与对方的关注情况
-const getFollowStatus = async () => {
-  const query = {
-    userId: getUserId.value
-  }
-  const { data: status = 0 } = await request('/website/tourGroup/isFollow', { query })
-  followStatus.value = status
-}
-
 // 加载更多
 const moreLoading = ref(false)
 const moreDisabled = ref(false)
 
 const loadMore = async () => {
-  console.warn('loadMore')
+  // console.warn('loadMore')
   try {
     moreLoading.value = true
     if (currConversationChatList.value.length) {
@@ -307,6 +301,45 @@ const onClickRight = () => {
     }
   })
 }
+// async
+const scrollToBottom = () => {
+  // 操作向上加载不滚动 TODO 判断用户是否有向上滑的操作更准确
+  if (moreLoading.value) return
+  // setTimeout(async () => {
+  //   await nextTick() // 确保DOM已经更新
+  //   const listElement = chatListRef.value?.$el
+  //   if (listElement) {
+  //     const scrollContainer = listElement
+  //     scrollContainer.scrollTop = scrollContainer.scrollHeight + 100
+  //   }
+  // }, 200)
+
+  // await nextTick() // 确保DOM已经更新
+  // const listElement = chatListRef.value?.$el
+  // if (listElement) {
+  //   const scrollContainer = listElement
+  //   scrollContainer.scrollTop = scrollContainer.scrollHeight
+  // }
+  nextTick(() => {
+    const listElement = chatListRef.value?.$el
+    setTimeout(() => {
+      listElement && (listElement.scrollTop = listElement.scrollHeight + 100)
+    }, 200)
+  })
+}
+
+// 获取我与对方的关注情况
+const getFollowStatus = async () => {
+  const query = {
+    userId: getUserId.value
+  }
+  const { data: status = 0 } = await request('/website/tourGroup/isFollow', { query })
+  followStatus.value = status
+}
+
+const chatErrorText = computed(() => {
+  return chatsStore.getChatErrorText(currConversationChatList.value)
+})
 
 // 本地生成一个唯一消息id
 function getLocalId() {
@@ -317,52 +350,32 @@ function getLocalId() {
 onMounted(() => {
   initGroupId()
   XYWebSocket.SocketEventsBus.on('chat-event', async (chat) => {
-    // console.log('单聊页面消息订阅', chat)
+    console.log('单聊页面消息订阅', chat)
     const isCurrGroupId = chat.groupId && chat.groupId === groupId.value
     const isOtherUserMessage = chat.sendUserId && chatsStore.isRealMessage(chat.sendUserId)
     if (isCurrGroupId) {
       if (isOtherUserMessage) {
-        currConversationChatList.value.push(chat)
+        const { message } = chatsStore.updateBackMessage([chat], chat)
+        currConversationChatList.value.push(message)
         await scrollToBottom()
       }
       if (!isOtherUserMessage) {
-        await getChatList('init')
+        // 这里就不做处理,因为本地发送后就立马更新了currConversationChatList
       }
     }
   })
 })
 
-watchEffect(() => {})
-
 // 会话好友的信息
-async function getAnnouncement() {
-  let { data } = await request('/website/tourMember/getOneWayMember', {
-    query: { groupId: groupId.value }
-  })
-
-  if (Array.isArray(data) && data?.length) {
-    data.map((el) => {
-      if (el.partnerId == getUserId.value) {
-        memberInfo.value = el
-      }
+const getAnnouncement = () => {
+  return new Promise((resolve) => {
+    request('/website/tourMember/getOneWayMember', {
+      query: { groupId: groupId.value }
+    }).then(({ data = [] }) => {
+      resolve(data.find((o) => o.userId === userInfo.value.userId) ?? {})
     })
-  }
+  })
 }
-// async function getAnnouncement() {
-//   let { data } = await request('/website/tourMember/getGroupUserListVo', {
-//     query: { groupId: groupId.value }
-//   })
-
-//   if (data) {
-//     if (Array.isArray(data.memberList) && data?.memberList?.length) {
-//       data.memberList.map((el) => {
-//         if (el.userId == userInfo.value.userId) {
-//           memberInfo.value = el
-//         }
-//       })
-//     }
-//   }
-// }
 
 // 用户删除消息
 const delMessage = (messageId) => {

+ 4 - 1
src/pages/chat/user-add.vue

@@ -153,15 +153,18 @@ const search = () => {
   getList()
 }
 
+const concernLoading = ref(false)
+
 // 关注
 const handleFollow = async (item, i) => {
+  if (concernLoading.value) return
   try {
     const { data } = await request('/website/tourism/fans/saveConcern', {
       method: 'post',
       body: {
         attentionId: item.tourUserVo.userId
       }
-    })
+    }).finally(() => (concernLoading.value = false))
 
     list.value[i].fansStatus = data.fansStatus
 

+ 191 - 200
src/pages/profile/my-news/index.vue

@@ -1,4 +1,5 @@
 <template>
+  <!-- <van-pull-refresh v-model="refreshing" head-height="50" @refresh="onRefresh"> -->
   <div class="w-full h-[100vh]">
     <van-sticky :offset-top="48">
       <div class="w-full text-xl font-semibold px-16 h-48 flex justify-start items-center bg-white">
@@ -25,35 +26,22 @@
       </div>
     </van-sticky>
 
-    <van-pull-refresh v-model="refreshing" head-height="100" @refresh="onRefresh">
-      <div class="h-[100vh] overflow-y-auto">
-        <van-list class="h-full" :finished="true" finished-text="">
-          <div
-            @click="
-              onChatPage('/profile/system-message', {
-                groupId: chatList[0]?.groupId
-              })
-            "
-            class="w-full relative h-82 flex justify-start items-center px-16"
+    <div class="h-[100vh] overflow-y-auto">
+      <van-list class="h-full" :finished="true" finished-text="">
+        <div
+          @click="
+            onChatPage('/profile/system-message', {
+              groupId: chatList[0]?.groupId
+            })
+          "
+          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
@@ -62,60 +50,59 @@
                 alt=""
               />
             </div>
+          </van-badge>
 
-            <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
-                    ? chatList[0]?.lastMessage?.messageContent?.messageContent
-                    : '暂无系统消息'
-                }}
-              </p>
-            </div>
-
-            <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>
-          <!-- navigateTo('/follow?listType=fans') -->
           <div
-            @click="
-              onChatPage('/follow', {
-                listType: 'fans',
-                groupId: chatList[1]?.groupId
-              })
-            "
-            class="w-full relative h-82 flex justify-start items-center px-16"
+            v-else
+            class="w-48 h-48 bg-[#0052D9] rounded-full overflow-hidden flex justify-center items-center"
           >
-            <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>
+            <img
+              class="w-24 h-24 shrink-0 object-cover"
+              src="~/assets/img/chat/remind.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[0]?.groupName }}
+            </h1>
+            <p class="line-clamp-1 h-20 text-sm text-black-6 leading-3xl">
+              {{
+                chatList[0]?.lastMessage
+                  ? chatList[0]?.lastMessage?.messageContent?.messageContent
+                  : '暂无系统消息'
+              }}
+            </p>
+          </div>
+
+          <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>
+        <!-- navigateTo('/follow?listType=fans') -->
+        <div
+          @click="
+            onChatPage('/follow', {
+              listType: 'fans',
+              groupId: chatList[1]?.groupId
+            })
+          "
+          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"
+          >
             <div
-              v-else
-              @click="navigateTo('/follow?listType=fans')"
               class="w-48 h-48 bg-[#FF9300] rounded-full overflow-hidden flex justify-center items-center"
             >
               <img
@@ -124,58 +111,55 @@
                 alt=""
               />
             </div>
+          </van-badge>
 
-            <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
-                    ? chatList[1]?.lastMessage?.messageContent?.messageContent
-                    : '暂无新增关注消息'
-                }}
-              </p>
-            </div>
+          <div
+            v-else
+            @click="navigateTo('/follow?listType=fans')"
+            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>
 
-            <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 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
+                  ? chatList[1]?.lastMessage?.messageContent?.messageContent
+                  : '暂无新增关注消息'
+              }}
+            </p>
           </div>
 
-          <div
-            @click="
-              onChatPage('/profile/interaction-message', {
-                groupId: chatList[2]?.groupId
-              })
-            "
-            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[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', {
+              groupId: chatList[2]?.groupId
+            })
+          "
+          class="w-full relative h-82 flex justify-start items-center px-16"
+        >
+          <van-badge
+            v-if="chatList[2]?.unreadMessageCount > 0"
+            v-bind="messageNumber(chatList[2]?.unreadMessageCount)"
+            max="99"
           >
-            <van-badge
-              v-if="chatList[2]?.unreadMessageCount > 0"
-              v-bind="messageNumber(chatList[2]?.unreadMessageCount)"
-              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>
-
             <div
-              v-else
               class="w-48 h-48 bg-[#FF476A] rounded-full overflow-hidden flex justify-center items-center"
             >
               <img
@@ -184,86 +168,49 @@
                 alt=""
               />
             </div>
+          </van-badge>
 
-            <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
-                    ? chatList[2]?.lastMessage?.messageContent?.messageContent
-                    : '暂无互动消息'
-                }}
-              </p>
-            </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
+            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: item?.lastMessage
-                    ? createTimeSplit(item?.lastMessage?.updateTime)
-                    : ''
-                }"
-                @on-chat-page="goDetails('group', item)"
-                @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="goDetails('single', item)"
-                @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
+                  ? chatList[2]?.lastMessage?.messageContent?.messageContent
+                  : '暂无互动消息'
+              }}
+            </p>
           </div>
 
-          <div
-            v-if="isTopList.length >= 6"
-            @click="activeNames = !activeNames"
-            class="flex justify-between items-center h-20 -mt-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>
-
-          <!-- 不置顶的会话列表 -->
-          <template v-for="(item, index) in pinnedList" :key="item?.id">
+          <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="{
@@ -275,6 +222,8 @@
               @on-is-top="onIsTop(item)"
               @on-conv-delete="onIsShow(item)"
             />
+
+            <!-- 单聊会话 -->
             <ProfileNewsSingleChat
               v-if="item?.noticeType == 1"
               :item-data="{
@@ -286,11 +235,54 @@
               @on-is-top="onIsTop(item)"
               @on-conv-delete="onIsShow(item)"
             />
+            <!-- </template> -->
+            <!-- <template v-else></template> -->
           </template>
-        </van-list>
-      </div>
-    </van-pull-refresh>
+        </div>
+
+        <div
+          v-if="isTopList.length >= 6"
+          @click="activeNames = !activeNames"
+          class="flex justify-between items-center h-20 -mt-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="goDetails('group', item)"
+            @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="goDetails('single', item)"
+            @on-no-bother="noBother(item)"
+            @on-is-top="onIsTop(item)"
+            @on-conv-delete="onIsShow(item)"
+          />
+        </template>
+      </van-list>
+    </div>
   </div>
+  <!-- </van-pull-refresh> -->
 </template>
 
 <script setup>
@@ -453,7 +445,6 @@ const goDetails = (type, item) => {
         path: '/chat/group-chat',
         query: {
           groupId: item?.groupId
-          // groupRemark: item?.groupRemark
         }
       })
       break

+ 2 - 6
src/pages/scan/index.vue

@@ -36,16 +36,12 @@ const openQrcode = async () => {
           width: 250,
           height: 250
         },
-        videoConstraints: {
-          // width: window.visualViewport.width,
-          width: 375,
-          aspectRatio: 6 / 18
-          // aspectRatio: window.visualViewport.height / window.visualViewport.width
-        }
+        aspectRatio: window.visualViewport.height / window.visualViewport.width
       }
       if (devices && devices.length) {
         // 当前环境下能识别出摄像头,并且摄像头的数据可能不止一个
         let cameraId = devices[devices.length - 1].id //后置摄像头,一般最后一个是后置摄像头
+        cameraIds.value = cameraId
         scanInstance
           .start({ deviceId: { exact: cameraId } }, config, handleSuccess)
           .catch((errorMessage) => {

+ 57 - 8
src/stores/useChats.js

@@ -2,6 +2,15 @@ import { XYWebSocket } from '~/utils/XYWebSocket'
 import { isValidJson } from '~/utils'
 
 export const useChatsStore = defineStore('chats', () => {
+  const MESSAGE_TYPE = {
+    text: 0,
+    image: 1,
+    audio: 2,
+    video: 3,
+    link: 4
+  }
+  const NOTICE_TYPE = []
+
   const userInfoStore = useUserInfoStore()
   const { userInfo } = storeToRefs(userInfoStore)
 
@@ -83,19 +92,54 @@ export const useChatsStore = defineStore('chats', () => {
         messageContent.sendUserId = o.sendUserId
         messageContent.messageId = o.id
         messageContent.headImageUrl = o.headImageUrl
+        messageContent.object.web_message_status = WEB_MESSAGE_STATUS.success // 后端接口过来的消息都标记成功
         // console.log(messageContent, 'messageContent')
         return messageContent
       })
   }
 
-  const MESSAGE_TYPE = {
-    text: 0,
-    image: 1,
-    audio: 2,
-    video: 3,
-    link: 4
+  const WEB_MESSAGE_STATUS = {
+    loading: 'loading',
+    success: 'success',
+    error: 'error'
+  }
+  /**
+   * 本地发送消息后,收到后端返回消息就更新本地消息 (写成hooks更好)
+   * @param list
+   * @param message
+   * @returns {{index: number, message}}
+   */
+  const updateBackMessage = (list = [], message) => {
+    const index = list.findIndex((o) => o.object?.id === message?.object?.id)
+    if (index < 0) throw Error('')
+    const status =
+      message.messageLimit > 0 && message.messageLimit < 5
+        ? WEB_MESSAGE_STATUS.error
+        : WEB_MESSAGE_STATUS.success
+    message.object.web_message_status = status
+
+    return {
+      index,
+      message
+    }
+  }
+
+  const getChatErrorText = (list = []) => {
+    // const errorTextArr = ['','在对方关注或回复前,最多只能发送1条信息', '您已被踢出群', '该已被群解散', '该群已被封禁']
+    const errorTextArr = [
+      '',
+      '在对方关注或回复前,最多只能发送1条信息',
+      '您已被移除该群聊,或该群已解散',
+      '您已被移除该群聊,或该群已解散',
+      '该群已被封禁'
+    ]
+    const errorIndex = list.findIndex(
+      (o) => o.object?.web_message_status === WEB_MESSAGE_STATUS.error
+    )
+    if (errorIndex < 0) return ''
+    const errorMessage = list[errorIndex]
+    return errorTextArr[errorMessage.messageLimit] ?? ''
   }
-  const NOTICE_TYPE = []
 
   return {
     // 注册socket
@@ -117,6 +161,11 @@ export const useChatsStore = defineStore('chats', () => {
 
     // 排除自己发的消息
     isRealMessage,
-    handleMessageList
+    handleMessageList,
+
+    WEB_MESSAGE_STATUS,
+    updateBackMessage,
+
+    getChatErrorText
   }
 })

+ 0 - 1
src/utils/XYWebSocket.ts

@@ -8,7 +8,6 @@ export namespace XYWebSocket {
         public socketUrl: string;
         public options: SocketOptions = {
             apiTimeout: 10, // 接口请求超时 s
-            connectionTimeout: 10 * 1000, // 超时连接 ms
             maxRetries: 5, // 最大重连次数
         };
         private eventPoll: Map<string, SocketResponseType> = new Map();