Files
im-uniapp/pages/conversation/chating/components/MessageItem/MediaMessageRender.vue
2025-09-05 15:24:42 +08:00

182 lines
4.1 KiB
Vue

<template>
<view class="media_message_container" @click="clickMediaItem">
<u-image
@load="onLoaded"
:showLoading="true"
width="120"
:height="maxHeight"
mode="widthFix"
:src="getImgUrl"
@click="clickMediaItem"
>
<template v-slot:loading>
<view class="custom-loading" :style="{ width: '120px', height: maxHeight + 'px' }">
<view class="loading-content">
<view class="loading-spinner">
<view class="spinner-ring"></view>
<view class="spinner-ring"></view>
<view class="spinner-ring"></view>
</view>
<text class="loading-text">加载中...</text>
</view>
</view>
</template>
</u-image>
</view>
</template>
<script>
export default {
name: "",
props: {
message: Object,
},
data() {
return {
loadingWidth: "120px",
};
},
computed: {
getImgUrl() {
if (!this.message || !this.message.pictureElem) {
return '';
}
return (
this.message.pictureElem.snapshotPicture && this.message.pictureElem.snapshotPicture.url ?
this.getFixedSourceUrl(this.message.pictureElem.snapshotPicture.url) :
this.getFixedSourceUrl(this.message.pictureElem.sourcePicture.url)
);
},
maxHeight() {
if (!this.message || !this.message.pictureElem || !this.message.pictureElem.sourcePicture) {
return 120;
}
const imageHeight = this.message.pictureElem.sourcePicture.height;
const imageWidth = this.message.pictureElem.sourcePicture.width;
const aspectRatio = imageHeight / imageWidth;
return 120 * aspectRatio;
},
},
methods: {
getFixedSourceUrl(url) {
// 如果 url 以 http://49.232.154.205/api/object/ 开头,则替换为带端口的
if (typeof url === 'string' && url.startsWith('http://49.232.154.205/api/object/')) {
return url.replace('http://49.232.154.205/api/object/', 'http://49.232.154.205:10006/api/object/');
}
else if (typeof url === 'string' && url.startsWith('http://47.117.71.33/api/object/')) {
return url.replace('http://47.117.71.33/api/object/', 'http://49.232.154.205:10006/api/object/');
}
return url;
},
clickMediaItem() {
if (!this.message || !this.message.pictureElem || !this.message.pictureElem.sourcePicture) {
return;
}
uni.previewImage({
current: 0,
urls: [this.getFixedSourceUrl(this.message.pictureElem.sourcePicture.url)],
indicator: "none",
});
},
onLoaded() {
this.loadingWidth = "auto";
},
},
};
</script>
<style lang="scss" scoped>
.media_message_container {
position: relative;
border-radius: 16rpx;
overflow: hidden;
display: inline-block;
.play_icon {
width: 48px;
height: 48px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.video_duration {
position: absolute;
bottom: 12rpx;
right: 24rpx;
color: #fff;
}
}
.custom-loading {
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(4px);
border-radius: 16rpx;
box-sizing: border-box;
}
.loading-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.loading-spinner {
position: relative;
width: 40px;
height: 40px;
margin-bottom: 8px;
}
.spinner-ring {
position: absolute;
width: 100%;
height: 100%;
border: 3px solid transparent;
border-top: 3px solid #4a9cfc;
border-radius: 50%;
animation: spin 1.2s linear infinite;
&:nth-child(2) {
width: 80%;
height: 80%;
top: 10%;
left: 10%;
border-top-color: #6bb6ff;
animation-delay: -0.4s;
}
&:nth-child(3) {
width: 60%;
height: 60%;
top: 20%;
left: 20%;
border-top-color: #8cc8ff;
animation-delay: -0.8s;
}
}
.loading-text {
font-size: 12px;
color: #666;
font-weight: 500;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>