|
@@ -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>
|