<template>
|
<Teleport to=".content-container">
|
<div class="shoutingMask">
|
{{nowPlaying}}
|
<van-icon name="cross" class="closeDlg" @click="closeDlgFun" />
|
<div class="playBox">
|
<div>
|
<img
|
:src="speakerInfo.play_mode === 0 ? bigPlayOne : bigXunHuan"
|
@click="setModelPlay(speakerInfo.play_mode === 0 ? 1 : 0)"
|
alt=""
|
/>
|
<div>{{ playMode?.[speakerInfo.play_mode] }}</div>
|
</div>
|
<div>
|
<img v-if="speakerInfo.system_state === 2" :src="videoStopImg" alt="" @click="suspendDrone" />
|
<div v-else-if="speakerInfo.system_state === 1" class="intermediateState">
|
<img :src="videoPlayImg" alt="" />
|
<van-loading color="#0E0E0EFF" />
|
</div>
|
|
<img v-else :src="videoPlayImg" alt="" @click="pushToDrone(checkRow)" />
|
<div>{{ systemState?.[speakerInfo?.system_state] }}</div>
|
</div>
|
<div>
|
<img :src="bigVolume" alt="" @click="showVolumeAdjustment = !showVolumeAdjustment" />
|
<div>音量</div>
|
</div>
|
</div>
|
<VolumeAdjustment v-if="showVolumeAdjustment" />
|
|
<div class="searchBox">
|
<el-input
|
size="small"
|
v-model="searchParams.name"
|
placeholder="请输入文件名称"
|
:suffix-icon="null"
|
v-focusDisableKeys
|
/>
|
<div class="whiteBtn" @click="getFileList('search')">搜索</div>
|
<div class="whiteBtn">
|
<el-upload
|
action="/upload"
|
accept=".FLAC,.ALAC,.WAV,.MP3,.AAC,.AIFF"
|
:show-file-list="false"
|
:before-upload="handleUpload"
|
>
|
上传音频
|
</el-upload>
|
</div>
|
</div>
|
|
<div class="listBoxBlock">
|
<div class="listItem title">
|
<div class="serialNumber">序号</div>
|
<div class="fileName">文件名称</div>
|
<div class="operation">操作</div>
|
</div>
|
<van-list
|
class="listBox"
|
v-model:loading="loading"
|
:finished="finished"
|
finished-text=" "
|
@load="onLoad"
|
offset="5"
|
>
|
<div
|
class="listItem"
|
v-for="(item, index) in tableList"
|
:class="{ checked: item.checked }"
|
:key="item.id"
|
@click="pushToDrone(item)"
|
>
|
<div class="serialNumber">{{ index + 1 }}</div>
|
<div class="fileName">{{ item.name }}</div>
|
<div class="operation">
|
<img @click.stop="deleteVideo(item)" :src="deleteImg" alt="" />
|
<img v-if="item.isTryListren" @click.stop="stopTryListren(item)" :src="litterTryPlayImg" alt="" />
|
<img v-else @click.stop="playTryListren(item)" :src="litterTryListrenImg" alt="" />
|
</div>
|
</div>
|
</van-list>
|
</div>
|
</div>
|
</Teleport>
|
</template>
|
|
<script setup>
|
import videoStopImg from '@/assets/images/taskManagement/taskIntermediateContent/video-stop.svg'
|
import videoPlayImg from '@/assets/images/taskManagement/taskIntermediateContent/video-play.svg'
|
import { getVoiceFile, playAudio, stopVoiceApi, uploadSpeak, voiceMode } from '@/api/payload'
|
import bigPlayOne from '@/assets/images/taskManagement/taskIntermediateContent/play-one-big.svg'
|
import bigXunHuan from '@/assets/images/taskManagement/taskIntermediateContent/xunhuan-big.svg'
|
import bigVolume from '@/assets/images/taskManagement/taskIntermediateContent/volume-big.svg'
|
import VolumeAdjustment from '@/components/CurrentTaskDetails/AppConsoleRight/VolumeAdjustment.vue'
|
import deleteImg from '@/assets/images/taskManagement/taskIntermediateContent/delete.svg'
|
import litterTryListrenImg from '@/assets/images/taskManagement/taskIntermediateContent/little-try-listren.svg'
|
import litterTryPlayImg from '@/assets/images/taskManagement/taskIntermediateContent/litter-try-play.svg'
|
import { deleteSpeakVoiceByIdApi } from '@/api/routePlan'
|
import { showConfirmDialog, showToast } from 'vant'
|
|
const showBlock = defineModel('show')
|
const dockSn = inject('dockSn')
|
const searchParams = ref({
|
sn: dockSn.value,
|
name: '',
|
page: 0,
|
page_size: 999,
|
})
|
const loading = ref(false)
|
const finished = ref(true)
|
const total = ref(0)
|
const speakerInfo = inject('speakerInfo')
|
const showVolumeAdjustment = ref(false)
|
const tableList = ref([])
|
const checkRow = computed(() => {
|
return tableList.value.find(item => item.checked === true)
|
})
|
let audioPlayer = null
|
const playMode = { 0: '单次播放', 1: '循环播放' }
|
const systemState = { 0: '空闲中', 1: '传输中', 2: '播放中', 3: '异常', 4: '文本转换中', 99: '下载中' }
|
// 正在播放
|
const nowPlaying = computed(()=>{
|
return speakerInfo.value.system_state === 2 && !checkRow.value ? '正在播放上一次音频' : ''
|
})
|
|
// 停止播放
|
function suspendDrone() {
|
stopVoiceApi({ sn: dockSn.value, psdk_index: 2 }).then(res => {
|
// speakerInfo.value.system_state = 0
|
})
|
}
|
|
function closeDlgFun() {
|
showBlock.value = false
|
}
|
|
function setModelPlay(type) {
|
const data = {
|
psdk_index: 2,
|
play_mode: type, // 1:是循环播放,0:单次播放
|
}
|
voiceMode({ sn: dockSn.value }, data)
|
}
|
|
// 删除音频
|
function deleteVideo(row) {
|
showConfirmDialog({ title: '提示', message: '确定删除该条音频文件?' }).then(() => {
|
deleteSpeakVoiceByIdApi(row.id).then(res => {
|
if (res.data.code === 0) {
|
showToast('删除成功')
|
loading.value = true
|
getFileList()
|
}
|
})
|
})
|
}
|
|
// 上传
|
function handleUpload(file) {
|
let formData = new FormData()
|
formData.append('file', file)
|
formData.append('sn', dockSn.value)
|
uploadSpeak(formData).then(res => {
|
showToast('上传成功')
|
// 获取文件接口
|
getFileList()
|
})
|
}
|
|
// 获取音频列表
|
function getFileList() {
|
getVoiceFile(searchParams.value).then(res => {
|
tableList.value = res.data.data.records
|
// if (!checkRow.value) {
|
// if (speakerInfo.value?.play_file_md5 && speakerInfo.value?.system_state === 2){
|
// const row = tableList.value.find(item => item.md5 === speakerInfo.value?.play_file_md5)
|
// playTryListren(row)
|
// }
|
// }
|
total.value = res.data.data.total
|
nextTick(() => {
|
loading.value = false
|
})
|
})
|
}
|
|
function onLoad() {
|
searchParams.value.page = searchParams.value.page + 1
|
getFileList()
|
}
|
|
// 本地试听
|
function playTryListren(row) {
|
// 先播放本地音频
|
if (row.url) {
|
if (!audioPlayer) {
|
audioPlayer = new Audio()
|
}
|
tableList.value.forEach(item => {
|
item.isTryListren = false
|
item.checked = false
|
})
|
row.isTryListren = true
|
row.checked = true
|
audioPlayer.src = row.url
|
// speakerInfo.play_mode
|
audioPlayer.loop = !!speakerInfo.value.play_mode
|
audioPlayer.play()
|
audioPlayer.addEventListener('ended', () => {
|
row.isTryListren = false
|
})
|
}
|
}
|
|
// 停止试听
|
function stopTryListren(row) {
|
tableList.value.forEach(item => {
|
item.isTryListren = false
|
})
|
if (audioPlayer) {
|
audioPlayer.pause()
|
// audioPlayer = null
|
}
|
}
|
|
let duration = null
|
let timeout = null
|
|
// 获取当前音频时长
|
function getDuration(url) {
|
return new Promise((resolve, reject) => {
|
try {
|
let audio = new Audio()
|
audio.src = url
|
audio.addEventListener('loadedmetadata', () => {
|
resolve(audio.duration)
|
audio = null
|
})
|
} catch (e) {
|
reject(e)
|
}
|
})
|
}
|
|
// 推送到无人机
|
async function pushToDrone(item) {
|
const { sn, name, url, md5, voice } = item || {}
|
if (!name) return showToast('请先选择音频')
|
if (!url) return showToast('文件已损坏,请选择其他音频')
|
|
// await stopVoiceApi({ sn: dockSn.value, psdk_index: 2 })
|
playAudio({ sn, name, url, md5, voice }).then(async res => {
|
tableList.value.forEach(item => (item.checked = false))
|
item.checked = true
|
// speakerInfo.value.system_state = 1
|
// playTryListren(item)
|
showToast('推送成功')
|
// const duration = await getDuration(item.url)
|
// if (speakerInfo.value.play_mode === 0) {
|
// timeout && clearTimeout(timeout)
|
// timeout = setTimeout(() => {
|
// }, (duration || 0) * 1000)
|
// }
|
})
|
}
|
|
watch(
|
() => speakerInfo.value,
|
(newValue, oldValue) => {
|
const new_system_state = newValue?.system_state
|
const old_system_state = oldValue?.system_state
|
if (new_system_state !== old_system_state) {
|
if (new_system_state === 2) {
|
const row = tableList.value.find(item => item.md5 === speakerInfo.value?.play_file_md5)
|
row && playTryListren(row)
|
} else {
|
stopTryListren()
|
}
|
}
|
if (audioPlayer) {
|
audioPlayer.loop = !!speakerInfo.value?.play_mode
|
}
|
},
|
{ immediate: true, deep: true }
|
)
|
|
onMounted(() => {
|
getFileList()
|
})
|
|
onBeforeUnmount(() => {
|
if (audioPlayer) {
|
audioPlayer.pause()
|
audioPlayer = null
|
}
|
})
|
</script>
|
|
<style scoped lang="scss">
|
.shoutingMask {
|
position: absolute;
|
width: half(313);
|
height: 100%;
|
top: half(0);
|
right: half(0);
|
padding-top: half(20);
|
z-index: 1;
|
background: rgba(0, 0, 0, 0.4);
|
backdrop-filter: blur(0.5rem);
|
display: flex;
|
gap: half(10) 0;
|
flex-direction: column;
|
align-items: center;
|
font-family: Source Han Sans CN, Source Han Sans CN;
|
font-size: half(13);
|
color: #ffffff;
|
|
.van-overlay {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
}
|
|
.playBox {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
text-align: center;
|
gap: half(25);
|
|
>div{
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
gap: half(5);
|
}
|
|
.intermediateState {
|
position: relative;
|
width: half(42);
|
height: half(42);
|
|
> img {
|
opacity: 0.5;
|
}
|
|
.van-loading {
|
position: absolute;
|
left: 50%;
|
top: 50%;
|
transform: translate(-50%, -50%);
|
width: half(35);
|
height: half(35);
|
}
|
}
|
|
//>div{
|
// width: half(42);
|
// height: half(42);
|
//}
|
|
img {
|
width: half(42);
|
height: half(42);
|
}
|
}
|
|
.listItem {
|
flex-shrink: 0;
|
width: 100%;
|
height: half(45);
|
display: flex;
|
align-items: center;
|
background: rgba(15, 15, 15, 0.9);
|
color: #ffffff;
|
|
&.title {
|
border-radius: half(10) half(10) 0 0;
|
}
|
|
&.checked {
|
background: rgba(255, 255, 255, 0.4);
|
color: #000000;
|
}
|
|
> div {
|
display: flex;
|
justify-content: center;
|
}
|
|
.serialNumber {
|
width: 25%;
|
}
|
|
.fileName {
|
width: 50%;
|
text-wrap: wrap;
|
text-align: center;
|
}
|
|
.operation {
|
width: 25%;
|
}
|
}
|
|
.closeDlg {
|
font-size: half(20);
|
position: absolute;
|
right: half(5);
|
top: half(5);
|
color: #ffffff;
|
}
|
|
.searchBox {
|
display: flex;
|
height: half(38);
|
gap: 0 half(6);
|
padding: 0 half(20);
|
|
.el-input {
|
height: 100%;
|
font-size: half(15);
|
}
|
}
|
|
.listBoxBlock {
|
padding: 0 half(20);
|
border-radius: half(10) half(10) 0 0;
|
overflow: hidden;
|
flex-grow: 1;
|
width: 100%;
|
display: flex;
|
flex-direction: column;
|
|
.listBox {
|
flex-grow: 1;
|
overflow: auto;
|
width: 100%;
|
|
:deep() {
|
.van-list__finished-text {
|
background: rgba(15, 15, 15, 0.9);
|
color: #ffffff;
|
font-size: half(13);
|
height: half(45);
|
line-height: half(45);
|
}
|
}
|
}
|
}
|
}
|
</style>
|