<template> <div> <div class="msg-detail voice-message d-flex align-items-center" :class="{ playing: playing, 'can-play': messageRealUrl }" @click.stop="play" :style="{ width: getVoiceMessageWidth + 'px' }" > <div class="d-flex align-items-center" v-if="messageRealUrl"> <voice-icon :loading="playing"></voice-icon> <audio ref="audio" @play="onPlay" @pause="onPause"> <source type="audio/aac" :src="messageRealUrl" /> </audio> <span v-if="duration" class="duration text-nowrap text-hint" >{{ durationInSecond }}s</span > </div> <i class="el-icon-warning-outline" v-else-if="fileFailed2Load" title="[语音加载失败]" ></i> </div> <text-message v-model="value" v-if="backend" /> </div> </template> <script lang="ts"> import { Component, Ref } from "vue-property-decorator"; import BaseMessage from "./index"; import VoiceIcon from "./voice.vue"; import TextMessage from "./text-message.vue"; import Chat from "@/customer-service/xim"; @Component({ components: { VoiceIcon, TextMessage } }) export default class Index extends BaseMessage { @Ref("audio") private readonly audioRef!: HTMLAudioElement; private readonly backend = Chat.isBackend(); private playing = false; private get duration() { const v = this.messageBody.msg.duration as number; return v || 0; } private get durationInSecond() { return Math.round(this.duration / 1000); } private get getVoiceMessageWidth() { if (this.fileFailed2Load) { return 35; } const d = this.duration / 1000; if (d <= 3) { return 60; } if (d >= 60) { return 200; } return 60 + d; } private play() { if (this.audioRef?.paused) { this.audioRef?.load(); this.audioRef?.play(); } else { this.audioRef?.pause(); } } private onPlay() { this.playing = true; } private onPause() { this.playing = false; } mounted() { this.buildMessageUrl(); } } </script> <style lang="less" scoped> .voice-message { width: 200px; background-color: #eee; border-radius: 6px; padding: 8px 10px; &.can-play { cursor: pointer; } i { font-size: 16px; } } .my-message { .voice-message { > div { flex-flow: row-reverse; } svg { transform: rotateY(180deg); } } } </style>