完成图片、文件兼容修改语音icon 回复头像显示
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<view class="file-message" @click="downloadFile">
|
||||
<image
|
||||
:src="fileIcon"
|
||||
class="file-icon"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<view class="file-info">
|
||||
<text class="file-name">{{ fileName }}</text>
|
||||
<text class="file-size">{{ fileSizeText }}</text>
|
||||
</view>
|
||||
<image
|
||||
:src="downloadIcon"
|
||||
class="download-icon"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
source: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fileName: function() {
|
||||
return this.source && this.source.fileElem && this.source.fileElem.fileName || '未知文件';
|
||||
},
|
||||
fileSizeText: function() {
|
||||
const size = this.source && this.source.fileElem && this.source.fileElem.fileSize;
|
||||
if (!size) return '';
|
||||
if (size < 1024) {
|
||||
return size + ' B';
|
||||
} else if (size < 1024 * 1024) {
|
||||
return (size / 1024).toFixed(1) + ' KB';
|
||||
} else {
|
||||
return (size / (1024 * 1024)).toFixed(1) + ' MB';
|
||||
}
|
||||
},
|
||||
fileIcon: function() {
|
||||
const fileName = this.fileName.toLowerCase();
|
||||
if (fileName.endsWith('.pdf')) {
|
||||
return '/static/images/file_message/file_pdf.png';
|
||||
} else if (fileName.endsWith('.doc') || fileName.endsWith('.docx')) {
|
||||
return '/static/images/file_message/file_word.png';
|
||||
} else if (fileName.endsWith('.xls') || fileName.endsWith('.xlsx')) {
|
||||
return '/static/images/file_message/file_excel.png';
|
||||
} else if (fileName.endsWith('.ppt') || fileName.endsWith('.pptx')) {
|
||||
return '/static/images/file_message/file_ppt.png';
|
||||
} else if (fileName.endsWith('.zip') || fileName.endsWith('.rar') || fileName.endsWith('.7z')) {
|
||||
return '/static/images/file_message/file_zip.png';
|
||||
} else if (fileName.endsWith('.jpg') || fileName.endsWith('.jpeg') || fileName.endsWith('.png') || fileName.endsWith('.gif')) {
|
||||
return '/static/images/file_message/file_image.png';
|
||||
} else {
|
||||
return '/static/images/file_message/file_unknown.png';
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
downloadIcon: '/static/images/file_message/file_download.png'
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getFixedSourceUrl: function(url) {
|
||||
// 如果 url 以 http://47.117.71.33/api/object/ 开头,则替换为带端口的
|
||||
if (typeof url === 'string' && url.startsWith('http://47.117.71.33/api/object/')) {
|
||||
return url.replace('http://47.117.71.33/api/object/', 'http://47.117.71.33:15219/api/object/');
|
||||
}
|
||||
return url;
|
||||
},
|
||||
downloadFile: function() {
|
||||
const sourceUrl = this.source && this.source.fileElem && this.source.fileElem.sourceUrl;
|
||||
if (!sourceUrl) {
|
||||
uni.showToast({
|
||||
title: '文件链接无效',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const fixedUrl = this.getFixedSourceUrl(sourceUrl);
|
||||
|
||||
// 在APP环境下直接下载
|
||||
// #ifdef APP-PLUS
|
||||
uni.downloadFile({
|
||||
url: fixedUrl,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
uni.saveFile({
|
||||
tempFilePath: res.tempFilePath,
|
||||
success: (saveRes) => {
|
||||
uni.showToast({
|
||||
title: '文件已保存',
|
||||
icon: 'success'
|
||||
});
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '保存失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '下载失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
|
||||
// 在其他环境下打开链接
|
||||
// #ifndef APP-PLUS
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '是否打开文件链接?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// #ifdef H5
|
||||
window.open(fixedUrl);
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.setClipboardData({
|
||||
data: fixedUrl,
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: '链接已复制',
|
||||
icon: 'success'
|
||||
});
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.file-message {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f5f6fa;
|
||||
border-radius: 12px;
|
||||
padding: 12px 16px;
|
||||
margin: 4px 0;
|
||||
min-width: 200px;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.file-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.file-size {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.download-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -10,7 +10,16 @@
|
||||
@click="clickMediaItem"
|
||||
>
|
||||
<template v-slot:loading>
|
||||
<u-loading-icon color="red"></u-loading-icon>
|
||||
<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>
|
||||
@@ -28,13 +37,22 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
getImgUrl() {
|
||||
|
||||
|
||||
getImgUrl() {
|
||||
if (!this.message || !this.message.pictureElem) {
|
||||
return '';
|
||||
}
|
||||
return (
|
||||
this.message.pictureElem.snapshotPicture?.url ??
|
||||
this.message.pictureElem.sourcePath
|
||||
);
|
||||
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;
|
||||
@@ -42,10 +60,20 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getFixedSourceUrl(url) {
|
||||
if (typeof url === 'string' && url.startsWith('http://47.117.71.33/api/object/')) {
|
||||
return url.replace('http://47.117.71.33/api/object/', 'http://47.117.71.33:15219/api/object/');
|
||||
}
|
||||
return url;
|
||||
},
|
||||
|
||||
clickMediaItem() {
|
||||
if (!this.message || !this.message.pictureElem || !this.message.pictureElem.sourcePicture) {
|
||||
return;
|
||||
}
|
||||
uni.previewImage({
|
||||
current: 0,
|
||||
urls: [this.message.pictureElem.sourcePicture.url],
|
||||
urls: [this.getFixedSourceUrl(this.message.pictureElem.sourcePicture.url)],
|
||||
indicator: "none",
|
||||
});
|
||||
},
|
||||
@@ -61,6 +89,7 @@ export default {
|
||||
position: relative;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
|
||||
.play_icon {
|
||||
width: 48px;
|
||||
@@ -78,4 +107,71 @@ export default {
|
||||
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>
|
||||
|
||||
@@ -20,8 +20,8 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
getContent() {
|
||||
console.log(this.message);
|
||||
return parseBr(this.message.textElem.content);
|
||||
return this.message && this.message.textElem && this.message.textElem.content ?
|
||||
parseBr(this.message.textElem.content) : '';
|
||||
},
|
||||
},
|
||||
data() {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<view class="voice-message" @click="playVoice">
|
||||
<image
|
||||
:src="isPlaying ? audioIcon : recordIcon"
|
||||
class="audio-icon flipped"
|
||||
:class="['audio-icon', { 'flipped': isSender }]"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<text class="duration">{{ durationText }}</text>
|
||||
@@ -15,11 +15,15 @@ export default {
|
||||
source: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isSender: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
durationText() {
|
||||
const d = this.source.soundElem && this.source.soundElem.duration;
|
||||
const d = this.source && this.source.soundElem && this.source.soundElem.duration;
|
||||
return d ? `${d}''` : '';
|
||||
}
|
||||
},
|
||||
@@ -46,7 +50,7 @@ export default {
|
||||
this.innerAudioContext = null;
|
||||
}
|
||||
this.innerAudioContext = uni.createInnerAudioContext();
|
||||
const rawUrl = this.source.soundElem && this.source.soundElem.sourceUrl || '';
|
||||
const rawUrl = this.source && this.source.soundElem && this.source.soundElem.sourceUrl || '';
|
||||
this.innerAudioContext.src = this.getFixedSourceUrl(rawUrl);
|
||||
this.isPlaying = true;
|
||||
this.innerAudioContext.play();
|
||||
|
||||
@@ -41,16 +41,16 @@
|
||||
<TextMessageRender :message="source" />
|
||||
</template>
|
||||
<template v-else-if="source.contentType === 102">
|
||||
<MediaMessageRender :source="source" />
|
||||
<MediaMessageRender :message="source" />
|
||||
</template>
|
||||
<template v-else-if="source.contentType === 103">
|
||||
<VoiceMessageRender :source="source" />
|
||||
<VoiceMessageRender :source="source" :isSender="isSender" />
|
||||
</template>
|
||||
<template v-else-if="source.contentType === 104">
|
||||
<view style="color:#999">[暂未实现] 视频消息</view>
|
||||
</template>
|
||||
<template v-else-if="source.contentType === 105">
|
||||
<view style="color:#999">[暂未实现] 文件消息</view>
|
||||
<FileMessageRender :source="source" />
|
||||
</template>
|
||||
<template v-else-if="source.contentType === 106">
|
||||
<view style="color:#999">[暂未实现] @消息</view>
|
||||
@@ -93,6 +93,7 @@ import TextMessageRender from "./TextMessageRender.vue";
|
||||
import MediaMessageRender from "./MediaMessageRender.vue";
|
||||
import ErrorMessageRender from "./ErrorMessageRender.vue";
|
||||
import VoiceMessageRender from './VoiceMessageRender.vue'
|
||||
import FileMessageRender from './FileMessageRender.vue'
|
||||
import { noticeMessageTypes } from "@/constant";
|
||||
import { tipMessaggeFormat, formatMessageTime } from "@/util/imCommon";
|
||||
|
||||
@@ -106,7 +107,8 @@ export default {
|
||||
TextMessageRender,
|
||||
MediaMessageRender,
|
||||
ErrorMessageRender,
|
||||
VoiceMessageRender
|
||||
VoiceMessageRender,
|
||||
FileMessageRender
|
||||
},
|
||||
props: {
|
||||
source: Object,
|
||||
@@ -131,15 +133,18 @@ export default {
|
||||
);
|
||||
},
|
||||
formattedMessageTime() {
|
||||
return formatMessageTime(this.source.sendTime);
|
||||
return this.source && this.source.sendTime ? formatMessageTime(this.source.sendTime) : '';
|
||||
},
|
||||
showTextRender() {
|
||||
return textRenderTypes.includes(this.source.contentType);
|
||||
return this.source && this.source.contentType ? textRenderTypes.includes(this.source.contentType) : false;
|
||||
},
|
||||
showMediaRender() {
|
||||
return mediaRenderTypes.includes(this.source.contentType);
|
||||
return this.source && this.source.contentType ? mediaRenderTypes.includes(this.source.contentType) : false;
|
||||
},
|
||||
getNoticeContent() {
|
||||
if (!this.source || !this.source.contentType) {
|
||||
return "";
|
||||
}
|
||||
const isNoticeMessage = noticeMessageTypes.includes(
|
||||
this.source.contentType
|
||||
);
|
||||
@@ -151,13 +156,13 @@ export default {
|
||||
);
|
||||
},
|
||||
isSuccessMessage() {
|
||||
return this.source.status === MessageStatus.Succeed;
|
||||
return this.source && this.source.status === MessageStatus.Succeed;
|
||||
},
|
||||
isFailedMessage() {
|
||||
return this.source.status === MessageStatus.Failed;
|
||||
return this.source && this.source.status === MessageStatus.Failed;
|
||||
},
|
||||
showSending() {
|
||||
return this.source.status === MessageStatus.Sending && !this.sendingDelay;
|
||||
return this.source && this.source.status === MessageStatus.Sending && !this.sendingDelay;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
@@ -166,7 +171,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
setSendingDelay() {
|
||||
if (this.source.status === MessageStatus.Sending) {
|
||||
if (this.source && this.source.status === MessageStatus.Sending) {
|
||||
setTimeout(() => {
|
||||
this.sendingDelay = false;
|
||||
}, 2000);
|
||||
|
||||
Reference in New Issue
Block a user