文件方式上传音频消息重做

This commit is contained in:
bob
2025-03-25 16:58:45 +08:00
parent 658822588a
commit a918678543
10 changed files with 116 additions and 18 deletions

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1742888981247" class="svg-icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10532" id="mx_n_1742888981248" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M945.587697 291.972171v653.744416c0 42.592457-35.23398 77.439766-78.306847 77.439766H156.812889C113.740022 1023.156353 78.506042 988.309044 78.506042 945.716587V78.916148C78.506042 36.323691 113.751739 1.476382 156.812889 1.476382h503.141706" fill="#409eff" p-id="10533" data-spm-anchor-id="a313x.search_index.0.i24.20d13a81QCpEmN" class=""></path><path d="M659.954595 1.476382L945.587697 291.983889H691.884291s-25.778103-9.830831-31.929696-39.335042z" fill="#f5f5f5" p-id="10534"></path><path d="M666.153057 358.268766l-266.53387 41.549616a5.143903 5.143903 0 0 0-2.343464 0.632735h-9.502746c-6.456243 0-11.881362 4.757232-11.881362 11.096302v284.379348a73.44416 73.44416 0 0 0-35.316002-8.881729c-39.053826 0-70.632003 29.480776-70.632003 65.945076s31.636763 65.945075 70.632003 65.945075 70.632003-29.480776 70.632003-65.945075c0-2.530941-0.339802-5.389967-0.339802-7.932626a10.05346 10.05346 0 0 0 0.339802-3.163676V510.781399l247.551813-40.893446v160.093739a73.39729 73.39729 0 0 0-35.339436-8.870011c-39.053826 0-70.632003 29.480776-70.632003 65.945075s31.636763 65.945075 70.632003 65.945075 70.632003-29.480776 70.632003-65.945075c0-2.530941-0.339802-5.389967-0.339803-7.920908a10.10033 10.10033 0 0 0 0.339803-3.175394V368.439399c0-5.389967-4.077627-9.830831-9.842549-10.779934a10.70963 10.70963 0 0 0-7.135848-1.26547l-6.11644 0.949103h-0.679605z m0 0" fill="#F5F5F5" p-id="10535"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -16,9 +16,10 @@ export const msgContentType = {
MIX: 0, // 组合,包含多种类型
TEXT: 1, // 文本
IMAGE: 2, // 图片
AUDIO: 3, // 音
VIDEO: 4, // 视频
EMOJI: 5 //表情
RECORDING: 3, //
AUDIO: 4, // 音频文件
VIDEO: 5, // 视频
EMOJI: 6 //表情
}
// 消息发送状态

View File

@@ -227,3 +227,15 @@ export const base64ToFile = (base64Data, fileName) => {
}
return new File([u8arr], fileName, { type: mimeType })
}
export const formatFileSize = (size) => {
if (!size) {
return ''
} else if (size < 1024) {
return size + ' B'
} else if (size < 1024 * 1024) {
return (size / 1024).toFixed(2) + ' KB'
} else {
return (size / (1024 * 1024)).toFixed(2) + ' MB'
}
}

View File

@@ -32,7 +32,10 @@ export const audioStore = defineStore('anylink-audio', () => {
msgRecords.forEach((item) => {
const content = item.content
const contentJson = jsonParseSafe(content)
if (contentJson && contentJson['type'] === msgContentType.AUDIO) {
if (
(contentJson && contentJson['type'] === msgContentType.RECORDING) ||
(contentJson && contentJson['type'] === msgContentType.AUDIO)
) {
const objectId = contentJson['value'].slice(1, -1)
if (!audio.value[objectId]) {
audioIds.add(objectId)

View File

@@ -968,6 +968,10 @@ const onSendAudio = ({ objectId }) => {
handleSendMessage(JSON.stringify({ type: msgContentType.AUDIO, value: `(${objectId})` }))
}
const onSendRecording = ({ objectId }) => {
handleSendMessage(JSON.stringify({ type: msgContentType.RECORDING, value: `(${objectId})` }))
}
const isShowRecorder = ref(false)
const onShowRecorder = () => {
isShowRecorder.value = true
@@ -1157,7 +1161,7 @@ const onShowRecorder = () => {
<InputRecorder
:sessionId="selectedSessionId"
@exit="isShowRecorder = false"
@sendRecord="onSendAudio"
@sendRecording="onSendRecording"
></InputRecorder>
</el-container>
<el-container v-else class="input-box-container">

View File

@@ -0,0 +1,62 @@
<script setup>
import { onMounted, computed } from 'vue'
import AudioFileIcon from '@/assets/svg/audiofile.svg'
import { formatFileSize } from '@/js/utils/common'
const props = defineProps(['url', 'fileName', 'size'])
const emits = defineEmits(['load'])
const formatSize = computed(() => {
return formatFileSize(props.size)
})
onMounted(() => {
emits('load') //向父组件暴露load事件
})
</script>
<template>
<div class="audio-msg-wrapper">
<AudioFileIcon />
<div class="main">
<span class="file-name text-ellipsis" :title="props.fileName || '未知'">
{{ props.fileName || '未知' }}
</span>
<div class="footer">
<div class="size" :title="formatSize">{{ formatSize }}</div>
<a :href="props.url" :download="props.fileName">下载</a>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.audio-msg-wrapper {
padding: 4px 8px 4px 8px;
display: flex;
gap: 10px;
.svg-icon {
width: 48px;
height: 48px;
}
.main {
width: 140px;
display: flex;
flex-direction: column;
justify-content: space-around;
gap: 8px;
.file-name {
font-size: 14px;
}
.footer {
display: flex;
justify-content: space-between;
font-size: 12px;
}
}
}
</style>

View File

@@ -1,6 +1,7 @@
<script setup>
import { computed } from 'vue'
import { ElImage } from 'element-plus'
import { formatFileSize } from '@/js/utils/common'
const props = defineProps(['url', 'imgId', 'srcList', 'initialIndex', 'fileName', 'size'])
const emits = defineEmits(['load'])
@@ -28,15 +29,7 @@ const onLoad = (e) => {
}
const formatSize = computed(() => {
if (!props.size) {
return ''
} else if (props.size < 1024) {
return props.size + ' B'
} else if (props.size < 1024 * 1024) {
return (props.size / 1024).toFixed(2) + ' KB'
} else {
return (props.size / (1024 * 1024)).toFixed(2) + ' MB'
}
return formatFileSize(props.size)
})
</script>

View File

@@ -8,7 +8,7 @@ import { el_loading_options } from '@/const/commonConst'
import { v4 as uuidv4 } from 'uuid'
const props = defineProps(['sessionId'])
const emit = defineEmits(['exit', 'sendRecord'])
const emit = defineEmits(['exit', 'sendRecording'])
const audioData = audioStore()
const spaceDown = ref(false) // 空格键是否被按下
@@ -151,7 +151,7 @@ const uploadRecord = () => {
.then((res) => {
if (res.data.code === 0) {
audioData.setAudio(props.sessionId, res.data.data) // 缓存audio的数据
emit('sendRecord', res.data.data)
emit('sendRecording', res.data.data)
}
})
.finally(() => {

View File

@@ -16,6 +16,7 @@ import { emojis } from '@/js/utils/emojis'
import { msgContentType, msgSendStatus } from '@/const/msgConst'
import RecordingMsgBox from '@/views/message/components/RecordingMsgBox.vue'
import ImageMsgBox from '@/views/message/components/ImageMsgBox.vue'
import AudioMsgBox from '@/views/message/components/AudioMsgBox.vue'
const props = defineProps([
'sessionId',
@@ -78,6 +79,8 @@ const renderComponent = async (content) => {
return await renderMix(value)
case msgContentType.TEXT:
return renderText(value)
case msgContentType.RECORDING:
return renderRecording(value)
case msgContentType.AUDIO:
return renderAudio(value)
case msgContentType.IMAGE:
@@ -162,7 +165,7 @@ const renderImage = (content, ishowInfo = true) => {
}
}
const renderAudio = (content) => {
const renderRecording = (content) => {
const audioId = content.slice(1, -1)
const url = audioData.audio[audioId]?.url
const duration = audioData.audio[audioId]?.duration
@@ -179,6 +182,23 @@ const renderAudio = (content) => {
}
}
const renderAudio = (content) => {
const audioId = content.slice(1, -1)
const url = audioData.audio[audioId]?.url
if (url) {
return h(AudioMsgBox, {
url: import.meta.env.VITE_OSS_CORS_FLAG + url,
fileName: audioData.audio[audioId].fileName,
size: audioData.audio[audioId].size,
onLoad: () => {
emit('loadFinished')
}
})
} else {
return h('span', content)
}
}
const msg = computed(() => {
return reactive({ ...messageData.getMsg(props.sessionId, props.msgId) })
})

View File

@@ -226,7 +226,9 @@ const showDetailContent = computed(() => {
const jsonContent = jsonParseSafe(lastMsg.value.content)
if (
jsonContent &&
(jsonContent['type'] == msgContentType.IMAGE || jsonContent['type'] == msgContentType.AUDIO)
(jsonContent['type'] == msgContentType.IMAGE ||
jsonContent['type'] == msgContentType.AUDIO ||
jsonContent['type'] == msgContentType.RECORDING)
) {
return jsonContent['value'].replace(/\{\d+\}/g, '{图片}').replace(/\(\d+\)/g, '(音频)')
}