فهرست منبع

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

wkw 1 ماه پیش
والد
کامیت
95b6c022f8
1فایلهای تغییر یافته به همراه190 افزوده شده و 118 حذف شده
  1. 190 118
      src/views/im/detail/chatLog/index.vue

+ 190 - 118
src/views/im/detail/chatLog/index.vue

@@ -2,32 +2,61 @@
     <div class="container">
         <div class="content">
             <div class="tab-box">
-                <div v-for="(item,i) in tabList" :key="i"
-                    class="tab-text" 
-                    :class="type == i?'active-color':''" 
-                    @click="changeTab(i)">{{ item }}
+                <div
+                    v-for="(item, i) in tabList"
+                    :key="i"
+                    class="tab-text"
+                    :class="type == i ? 'active-color' : ''"
+                    @click="changeTab(i)"
+                >
+                    {{ item }}
                 </div>
             </div>
+
             <div class="list-box">
-                <div class="box-item" v-for="(item,i) in msgList" :key="i">
-                    <van-image class="box-img" round :src="formatAvatarUrl(item)"/>
+                <!-- 加载中 -->
+                <van-loading v-if="loading" class="load-box" size="24px">
+                    加载中...
+                </van-loading>
+
+                <!-- 消息列表 -->
+                <div
+                    class="box-item"
+                    v-for="(item, i) in msgList"
+                    :key="i"
+                    v-else
+                >
+                    <van-image
+                        class="box-img"
+                        round
+                        :src="formatAvatarUrl(item)"
+                    />
                     <div class="list-cont">
-                        <div class="box-name">{{ item.sender?item.sender.nickname: (item.nickname || item.fromUsername || "匿名用户") }}<span class="ml12">{{item.createDate}}</span></div>
-                        <!-- 名片 -->
-                        <!-- <div class="business-card" v-if="i % 2 === 0">
-                            <div class="business-card-cont" >
-                                <van-image class="list-img" round src="https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg"/>
-                                <div>名字名字</div>
-                            </div>
-                            <div class="line"></div>
-                            <div class="business-card-text">个人名片</div>
-                        </div> -->
+                        <div class="box-name">
+                            {{
+                                item.sender
+                                    ? item.sender.nickname
+                                    : item.nickname ||
+                                      item.fromUsername ||
+                                      '匿名用户'
+                            }}
+                            <span class="ml12">{{ item.createDate }}</span>
+                        </div>
+
                         <!-- 文本信息 -->
-                        <div class="box-content" v-if="item.contentType === MsgType.MSG_TYPE.TEXT">{{ item.content }}</div>
+                        <div
+                            class="box-content"
+                            v-if="item.contentType === MsgType.MSG_TYPE.TEXT"
+                        >
+                            {{ item.content }}
+                        </div>
+
                         <!-- 图片消息 -->
                         <div
                             class="img-message"
-                            v-else-if="item.contentType === MsgType.MSG_TYPE.IMAGE"
+                            v-else-if="
+                                item.contentType === MsgType.MSG_TYPE.IMAGE
+                            "
                         >
                             <van-image
                                 :src="item?.localUrl || IM_PATH + item.url"
@@ -35,146 +64,174 @@
                                 @click="previewImage(item)"
                             />
                         </div>
+
                         <!-- 录音消息 -->
                         <div
                             class="audio-message"
-                            v-else-if="item.contentType === MsgType.MSG_TYPE.AUDIO"
+                            v-else-if="
+                                item.contentType === MsgType.MSG_TYPE.AUDIO
+                            "
                         >
-                            <messageAudio :src="item?.localUrl || IM_PATH + item.url" />
+                            <messageAudio
+                                :src="item?.localUrl || IM_PATH + item.url"
+                            />
                         </div>
+
+                        <!-- 视频消息 -->
+                        <video
+                            class="video-message"
+                            controls
+                            v-else-if="
+                                item.contentType === MsgType.MSG_TYPE.VIDEO
+                            "
+                            :src="item?.localUrl || IM_PATH + item.url"
+                        ></video>
                     </div>
                 </div>
-                <template v-if="msgList && msgList.length == 0 && isShowLoading">
+
+                <!-- 暂无数据 -->
+                <template v-if="!loading && msgList && msgList.length === 0">
                     <div class="no-more">
                         <svg-icon class="no-more-img" name="no-more" />
                         <div>暂无数据</div>
                     </div>
                 </template>
             </div>
-           <!-- <div class="foot-page">
-                <van-button class="foot-btn" size="mini">上一页</van-button>
-                <div class="foot-total">1/1</div>
-                <van-button class="foot-btn" size="mini">下一页</van-button>
-           </div> -->
         </div>
     </div>
 </template>
 
 <script setup>
-import { getMessageApi } from "@/api/path/im.api";
-import messageAudio from "@/views/im/components/messageAudio/index.vue";
-import { useWebSocketStore } from "@/stores/modules/webSocketStore.js";
-import { useWalletStore } from "@/stores/modules/walletStore.js";
-import * as MsgType from "@/common/constant/msgType";
-import { showToast,showImagePreview } from "vant";
+import { getMessageApi } from '@/api/path/im.api';
+import messageAudio from '@/views/im/components/messageAudio/index.vue';
+import { useWebSocketStore } from '@/stores/modules/webSocketStore.js';
+import { useWalletStore } from '@/stores/modules/walletStore.js';
+import * as MsgType from '@/common/constant/msgType';
+import { showImagePreview } from 'vant';
+
 const IM_PATH = import.meta.env.VITE_IM_PATH_FIlE;
 const walletStore = useWalletStore();
 const wsStore = useWebSocketStore();
 
-
 const type = ref(0);
-const tabList = ['全部','文本','图片','视频'];
-const isShowLoading = ref(false)
+const tabList = ['全部', '文本', '图片', '视频'];
+const loading = ref(false); // 👈 新增 loading
+const msgList = ref([]);
+
 const contentTypeMap = {
-  0: -1,
-  1: MsgType.MSG_TYPE.TEXT,
-  2: MsgType.MSG_TYPE.IMAGE,
-  3:MsgType.MSG_TYPE.VIDEO
+    0: -1,
+    1: MsgType.MSG_TYPE.TEXT,
+    2: MsgType.MSG_TYPE.IMAGE,
+    3: MsgType.MSG_TYPE.VIDEO
 };
-const msgList = ref([])
 
 const getMessage = async () => {
     msgList.value = [];
+    loading.value = true; // 👈 请求前显示 loading
+
     let params = {
-        uuid:wsStore.toUserInfo.uuid,
-        messageType:wsStore.toUserInfo.type == 'user'?1:2,
-        friendUsername:walletStore.account,
-        contentType:contentTypeMap[type.value] ?? ''
-    }
+        uuid: wsStore.toUserInfo.uuid,
+        messageType: wsStore.toUserInfo.type == 'user' ? 1 : 2,
+        friendUsername: walletStore.account,
+        contentType: contentTypeMap[type.value] ?? ''
+    };
+
     try {
         const res = await getMessageApi(params);
-        if(res.code == 200){
+        if (res.code == 200) {
             msgList.value = res.data || [];
-            if(res.data.length == 0){
-                isShowLoading.value = true;
-            }
         }
     } catch (error) {
-        console.log(error)
+        console.error(error);
+    } finally {
+        loading.value = false; // 👈 请求结束隐藏 loading
     }
-}
-const changeTab = (i) => {
+};
+
+const changeTab = i => {
     type.value = i;
     getMessage();
-}
-const formatAvatarUrl = (item) => {
-  const url = item?.sender?.avatar || item?.fromAvatar || ''
-  if (/^https?:\/\//.test(url)) {
-    return url
-  }
-  return IM_PATH + url
-}
+};
+
+const formatAvatarUrl = item => {
+    const url = item?.sender?.avatar || item?.fromAvatar || '';
+    if (/^https?:\/\//.test(url)) {
+        return url;
+    }
+    return IM_PATH + url;
+};
+
 // 预览图片
-const previewImage = (item) => {
-  const imageList = msgList.value
-    .filter((m) => m.contentType === MsgType.MSG_TYPE.IMAGE)
-    .map((m) => m.localUrl || IM_PATH + m.url);
+const previewImage = item => {
+    const imageList = msgList.value
+        .filter(m => m.contentType === MsgType.MSG_TYPE.IMAGE)
+        .map(m => m.localUrl || IM_PATH + m.url);
 
-  const index = imageList.findIndex(
-    (url) => url === (item.localUrl || IM_PATH + item.url)
-  );
+    const index = imageList.findIndex(
+        url => url === (item.localUrl || IM_PATH + item.url)
+    );
 
-  showImagePreview({
-    images: imageList,
-    startPosition: index,
-  });
+    showImagePreview({
+        images: imageList,
+        startPosition: index
+    });
 };
-onMounted(()=>{
+
+onMounted(() => {
     getMessage();
-})
+});
 </script>
 
 <style lang="less" scoped>
-.container{
+.container {
     height: 100%;
     display: flex;
     flex-direction: column;
-    .content{
+    .content {
         display: flex;
         flex-direction: column;
         height: 100%;
-        .tab-box{
+        .tab-box {
             display: flex;
             align-items: center;
-            font-family: PingFang SC, PingFang SC;
+            font-family:
+                PingFang SC,
+                PingFang SC;
             font-weight: 400;
             font-size: 15px;
-            color: #4F4F4F;
+            color: #4f4f4f;
             height: 42px;
             line-height: 42px;
             background-color: #fff;
-            .tab-text{
+            .tab-text {
                 width: 25%;
                 text-align: center;
             }
-            .active-color{
+            .active-color {
                 font-weight: 500;
-                color: #4765DD;
+                color: #4765dd;
             }
         }
-        .list-box{
+        .list-box {
             margin: 16px;
             flex: 1;
             overflow: auto;
-            .box-item{
+            .load-box{
+                text-align: center;
+            }
+            .box-item {
                 display: flex;
                 margin-bottom: 16px;
-                font-family: PingFang SC, PingFang SC;
+                font-family:
+                    PingFang SC,
+                    PingFang SC;
                 font-weight: 400;
                 font-size: 12px;
-                color: #8D8D8D;
-                .list-cont{
-                    font-family:PingFang SC, PingFang SC;
+                color: #8d8d8d;
+                .list-cont {
+                    font-family:
+                        PingFang SC,
+                        PingFang SC;
                     font-weight: 400;
                     font-size: 12px;
                     color: #8d8d8d;
@@ -183,53 +240,57 @@ onMounted(()=>{
                     flex-direction: column;
                     align-items: flex-start;
                 }
-                .box-img{
+                .box-img {
                     width: 44px;
                     height: 44px;
                     margin-right: 12px;
                     flex-shrink: 0;
                 }
-                .box-name{
+                .box-name {
                     margin-bottom: 8px;
-                    .ml12{
+                    .ml12 {
                         margin-left: 12px;
                     }
                 }
-                .business-card{
+                .business-card {
                     width: 199px;
                     height: 93px;
-                    background: #FFFFFF;
+                    background: #ffffff;
                     border-radius: 10px;
                     margin-top: 8px;
                     padding: 10px;
                     box-sizing: border-box;
-                    .business-card-cont{
+                    .business-card-cont {
                         display: flex;
                         align-items: center;
-                        font-family: PingFang SC, PingFang SC;
+                        font-family:
+                            PingFang SC,
+                            PingFang SC;
                         font-weight: 400;
                         font-size: 15px;
                         color: #000000;
                     }
-                    .list-img{
+                    .list-img {
                         width: 44px;
                         height: 44px;
                         flex-shrink: 0;
                         margin-right: 12px;
                     }
-                    .line{
+                    .line {
                         height: 1px;
-                        background: #F2F2F2;
+                        background: #f2f2f2;
                         margin: 10px 0 6px;
                     }
-                    .business-card-text{
-                        font-family: PingFang SC, PingFang SC;
+                    .business-card-text {
+                        font-family:
+                            PingFang SC,
+                            PingFang SC;
                         font-weight: 400;
                         font-size: 10px;
-                        color: #8D8D8D;
+                        color: #8d8d8d;
                     }
                 }
-                .box-content{
+                .box-content {
                     background: #ffffff;
                     color: #000;
                     border-radius: 10px;
@@ -239,58 +300,69 @@ onMounted(()=>{
                     white-space: pre-wrap;
                     max-width: 100%;
                     font-family:
-                    PingFang SC,
-                    PingFang SC;
+                        PingFang SC,
+                        PingFang SC;
                     font-weight: 400;
                     font-size: 15px;
                 }
                 .img-message {
                     margin-top: 8px;
                 }
+                .video-message {
+                    // margin-top: 8px;
+                    // width: 200px;
+                    height: 200px;
+                }
             }
-            .no-more{
+            .no-more {
                 margin-top: 178px;
                 text-align: center;
-                font-family: PingFang SC, PingFang SC;
+                font-family:
+                    PingFang SC,
+                    PingFang SC;
                 font-weight: 400;
                 font-size: 15px;
-                color: #8D8D8D;
-                .no-more-img{
+                color: #8d8d8d;
+                .no-more-img {
                     width: 302px;
                     height: 222px;
                 }
             }
         }
-        .list-box::-webkit-scrollbar{
+        .list-box::-webkit-scrollbar {
             width: 0;
         }
-        .foot-page{
+        .foot-page {
             display: flex;
             align-items: center;
             height: 44px;
-            background: #FFFFFF;
+            background: #ffffff;
             padding: 10px 16px;
             box-sizing: border-box;
-            .foot-btn{
+            .foot-btn {
                 box-sizing: border-box;
                 width: 50px;
                 border-radius: 4px;
                 padding: 4px 6px;
-                background: #F2F2F2;
-                font-family: PingFang SC, PingFang SC;
+                background: #f2f2f2;
+                font-family:
+                    PingFang SC,
+                    PingFang SC;
                 font-weight: 400;
                 font-size: 12px;
-                color: #4F4F4F;
+                color: #4f4f4f;
             }
-            .foot-total{
+            .foot-total {
                 flex: 1;
                 text-align: center;
-                font-family: PingFang SC, PingFang SC;
+                font-family:
+                    PingFang SC,
+                    PingFang SC;
                 font-weight: 400;
                 font-size: 12px;
-                color: #4F4F4F;
+                color: #4f4f4f;
             }
         }
     }
 }
-</style>
+</style>