feat: 唤醒语料文件上传和试听
This commit is contained in:
parent
e3e2e4a0d4
commit
de09c4cef9
38
src/hooks/usePlayAudio.ts
Normal file
38
src/hooks/usePlayAudio.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { computed } from "vue";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 播放音频
|
||||||
|
*/
|
||||||
|
export function usePlayAudio() {
|
||||||
|
let audio: HTMLAudioElement | null = new Audio();
|
||||||
|
// 播放结束后自动清理
|
||||||
|
// 先定义cleanup,再绑定事件(避免作用域问题)
|
||||||
|
let cleanup: any;
|
||||||
|
cleanup = () => {
|
||||||
|
// 1. 先移除所有事件监听器,切断循环触发链路
|
||||||
|
audio!.removeEventListener("ended", cleanup);
|
||||||
|
audio!.removeEventListener("error", cleanup);
|
||||||
|
// 2. 停止播放(而非清空src),避免触发新error
|
||||||
|
audio!.pause();
|
||||||
|
// 可选:解除引用,帮助GC(若后续无其他引用)
|
||||||
|
audio = null;
|
||||||
|
console.log("音频资源已清理");
|
||||||
|
};
|
||||||
|
|
||||||
|
audio.addEventListener("ended", cleanup);
|
||||||
|
|
||||||
|
// 播放错误时也清理
|
||||||
|
audio.addEventListener("error", cleanup);
|
||||||
|
|
||||||
|
const playAudio = (url: string) => {
|
||||||
|
audio!.src = url
|
||||||
|
audio!.play().catch((error) => {
|
||||||
|
console.error("播放失败:", error);
|
||||||
|
cleanup();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
playAudio
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -388,3 +388,20 @@ export function isNumberStr(str) {
|
|||||||
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
|
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isAudioByMimeType(mimeType) {
|
||||||
|
const audioMimeTypes = [
|
||||||
|
'audio/mpeg',
|
||||||
|
'audio/wav',
|
||||||
|
'audio/x-wav',
|
||||||
|
'audio/flac',
|
||||||
|
'audio/aac',
|
||||||
|
'audio/ogg',
|
||||||
|
'audio/mp4',
|
||||||
|
'audio/webm',
|
||||||
|
'audio/x-m4a',
|
||||||
|
'audio/amr',
|
||||||
|
'audio/midi'
|
||||||
|
];
|
||||||
|
|
||||||
|
return audioMimeTypes.includes(mimeType.toLowerCase());
|
||||||
|
}
|
||||||
65
src/views/vi/components/UploadFile.vue
Normal file
65
src/views/vi/components/UploadFile.vue
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-button link type="primary" icon="Upload" @click="handleUpload">上传</el-button>
|
||||||
|
<el-dialog
|
||||||
|
v-model="fileDialog"
|
||||||
|
title="上传音频"
|
||||||
|
append-to-body
|
||||||
|
class="file-upload"
|
||||||
|
width="500px"
|
||||||
|
>
|
||||||
|
<el-upload
|
||||||
|
:action="`${baseUrl}/system/file/upload`"
|
||||||
|
:before-upload="beforeAvatarUpload"
|
||||||
|
:data="{ fileType: 3 }"
|
||||||
|
:headers="{
|
||||||
|
authorization: getToken(),
|
||||||
|
}"
|
||||||
|
:limit="1"
|
||||||
|
:show-file-list="false"
|
||||||
|
:on-error="uploadError"
|
||||||
|
:on-success="uploadSuccess"
|
||||||
|
class="file-uploader"
|
||||||
|
>
|
||||||
|
<template #trigger>
|
||||||
|
<el-button type="primary">选择文件</el-button>
|
||||||
|
</template>
|
||||||
|
<template #tip>
|
||||||
|
<div class="el-upload__tip">支持格式:wav / mp3</div>
|
||||||
|
</template>
|
||||||
|
</el-upload>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { getToken } from "@/utils/auth.js";
|
||||||
|
import { isAudioByMimeType } from "@/utils/index.js";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
const emits = defineEmits(['success', 'error'])
|
||||||
|
|
||||||
|
const baseUrl = ref(import.meta.env.VITE_APP_BASE_API);
|
||||||
|
const fileDialog = ref(false);
|
||||||
|
const handleUpload = () => {
|
||||||
|
fileDialog.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const beforeAvatarUpload = (rawFile) => {
|
||||||
|
if (isAudioByMimeType(rawFile.type)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
ElMessage.error(`不支持上传格式为${rawFile.type}的文件`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadSuccess = (e) => {
|
||||||
|
fileDialog.value = false
|
||||||
|
ElMessage.success('音频文件上传成功')
|
||||||
|
emits('success', e.msg)
|
||||||
|
}
|
||||||
|
const uploadError = (e) => {
|
||||||
|
console.log("uploadError", e)
|
||||||
|
emits('error')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -116,12 +116,12 @@
|
|||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
height="100%"
|
height="100%"
|
||||||
|
style="width: 100%"
|
||||||
:data="corpusList"
|
:data="corpusList"
|
||||||
table-layout="auto"
|
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
>
|
>
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="语料名称" align="center" prop="corpusName" />
|
<el-table-column label="语料名称" width="200" align="center" prop="corpusName" />
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="语音文本"
|
label="语音文本"
|
||||||
align="center"
|
align="center"
|
||||||
@ -129,6 +129,13 @@
|
|||||||
min-width="200"
|
min-width="200"
|
||||||
show-overflow-tooltip
|
show-overflow-tooltip
|
||||||
/>
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="音频地址"
|
||||||
|
align="center"
|
||||||
|
prop="minioUrl"
|
||||||
|
min-width="200"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="语音文件路径"
|
label="语音文件路径"
|
||||||
align="center"
|
align="center"
|
||||||
@ -136,8 +143,8 @@
|
|||||||
min-width="150"
|
min-width="150"
|
||||||
show-overflow-tooltip
|
show-overflow-tooltip
|
||||||
/>
|
/>
|
||||||
<el-table-column label="音色" align="center" prop="voiceType" />
|
<el-table-column width="80" label="音色" align="center" prop="voiceType" />
|
||||||
<el-table-column label="语种" align="center" prop="dialect" />
|
<el-table-column width="100" label="语种" align="center" prop="dialect" />
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="预期结果"
|
label="预期结果"
|
||||||
align="center"
|
align="center"
|
||||||
@ -145,8 +152,8 @@
|
|||||||
min-width="150"
|
min-width="150"
|
||||||
show-overflow-tooltip
|
show-overflow-tooltip
|
||||||
/>
|
/>
|
||||||
<el-table-column label="顺序" align="center" prop="sortOrder" />
|
<el-table-column width="80" label="顺序" align="center" prop="sortOrder" />
|
||||||
<el-table-column label="状态" align="center" prop="status" />
|
<el-table-column width="80" label="状态" align="center" prop="status" />
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="备注"
|
label="备注"
|
||||||
align="center"
|
align="center"
|
||||||
@ -156,9 +163,8 @@
|
|||||||
/>
|
/>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="操作"
|
label="操作"
|
||||||
align="center"
|
|
||||||
class-name="small-padding fixed-width"
|
class-name="small-padding fixed-width"
|
||||||
width="280"
|
width="200"
|
||||||
fixed="right"
|
fixed="right"
|
||||||
>
|
>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@ -180,17 +186,10 @@
|
|||||||
>
|
>
|
||||||
<el-button
|
<el-button
|
||||||
link
|
link
|
||||||
type="primary"
|
v-if="scope.row.minioUrl"
|
||||||
icon="Upload"
|
|
||||||
@click="handleUpload(scope.row)"
|
|
||||||
v-hasPermi="['vi:corpus:upload']"
|
|
||||||
>上传</el-button
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
link
|
|
||||||
type="primary"
|
type="primary"
|
||||||
icon="VideoPlay"
|
icon="VideoPlay"
|
||||||
@click="handlePlay(scope.row)"
|
@click="handlePlay(scope.row.minioUrl)"
|
||||||
v-hasPermi="['vi:corpus:play']"
|
v-hasPermi="['vi:corpus:play']"
|
||||||
>试听</el-button
|
>试听</el-button
|
||||||
>
|
>
|
||||||
@ -220,6 +219,17 @@
|
|||||||
placeholder="请输入内容"
|
placeholder="请输入内容"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="上传文件">
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
:content="form.minioUrl"
|
||||||
|
placement="top-start"
|
||||||
|
>
|
||||||
|
<span class="minioUrl" v-if="form.minioUrl">{{ form.minioUrl }}</span>
|
||||||
|
</el-tooltip>
|
||||||
|
<UploadFile @success="uploadSuccess" @error="uploadError" />
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="文件路径" prop="audioPath">
|
<el-form-item label="文件路径" prop="audioPath">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="form.audioPath"
|
v-model="form.audioPath"
|
||||||
@ -294,6 +304,8 @@ import {
|
|||||||
updateCorpus,
|
updateCorpus,
|
||||||
} from "@/api/vi/corpus";
|
} from "@/api/vi/corpus";
|
||||||
import { useContainerHeight } from "@/hooks/tableHeight";
|
import { useContainerHeight } from "@/hooks/tableHeight";
|
||||||
|
import { usePlayAudio } from '@/hooks/usePlayAudio'
|
||||||
|
import UploadFile from "../../components/UploadFile.vue"
|
||||||
|
|
||||||
const topContainerRef = ref();
|
const topContainerRef = ref();
|
||||||
const containerHeight = useContainerHeight(topContainerRef);
|
const containerHeight = useContainerHeight(topContainerRef);
|
||||||
@ -367,6 +379,7 @@ function reset() {
|
|||||||
form.value = {
|
form.value = {
|
||||||
corpusId: null,
|
corpusId: null,
|
||||||
corpusName: null,
|
corpusName: null,
|
||||||
|
minioUrl: null,
|
||||||
type: "WAKEUP",
|
type: "WAKEUP",
|
||||||
textContent: null,
|
textContent: null,
|
||||||
audioPath: null,
|
audioPath: null,
|
||||||
@ -457,12 +470,17 @@ function handleDelete(row) {
|
|||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleUpload = (row) => {
|
const uploadSuccess = (data) => {
|
||||||
console.log("上传");
|
form.value.minioUrl = data
|
||||||
};
|
}
|
||||||
|
|
||||||
const handlePlay = () => {
|
const uploadError = () => {
|
||||||
console.log("播放");
|
console.log("uploadError")
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePlay = (url) => {
|
||||||
|
const { playAudio } = usePlayAudio()
|
||||||
|
playAudio(url)
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
@ -478,3 +496,12 @@ function handleExport() {
|
|||||||
|
|
||||||
getList();
|
getList();
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.minioUrl {
|
||||||
|
display: inline-block;
|
||||||
|
width: 80%;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -116,8 +116,8 @@
|
|||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
height="100%"
|
height="100%"
|
||||||
|
style="width: 100%"
|
||||||
:data="corpusList"
|
:data="corpusList"
|
||||||
table-layout="auto"
|
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
>
|
>
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
@ -129,6 +129,13 @@
|
|||||||
min-width="200"
|
min-width="200"
|
||||||
show-overflow-tooltip
|
show-overflow-tooltip
|
||||||
/>
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="音频地址"
|
||||||
|
align="center"
|
||||||
|
prop="minioUrl"
|
||||||
|
min-width="200"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="语音文件路径"
|
label="语音文件路径"
|
||||||
align="center"
|
align="center"
|
||||||
@ -155,9 +162,8 @@
|
|||||||
/>
|
/>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="操作"
|
label="操作"
|
||||||
align="center"
|
|
||||||
class-name="small-padding fixed-width"
|
class-name="small-padding fixed-width"
|
||||||
width="280"
|
width="200"
|
||||||
fixed="right"
|
fixed="right"
|
||||||
>
|
>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@ -180,8 +186,9 @@
|
|||||||
<el-button
|
<el-button
|
||||||
link
|
link
|
||||||
type="primary"
|
type="primary"
|
||||||
|
v-if="scope.row.minioUrl"
|
||||||
icon="VideoPlay"
|
icon="VideoPlay"
|
||||||
@click="handlePlay(scope.row)"
|
@click="handlePlay(scope.row.minioUrl)"
|
||||||
v-hasPermi="['vi:corpus:play']"
|
v-hasPermi="['vi:corpus:play']"
|
||||||
>试听</el-button
|
>试听</el-button
|
||||||
>
|
>
|
||||||
@ -211,6 +218,17 @@
|
|||||||
placeholder="请输入内容"
|
placeholder="请输入内容"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="上传文件">
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
:content="form.minioUrl"
|
||||||
|
placement="top-start"
|
||||||
|
>
|
||||||
|
<span class="minioUrl" v-if="form.minioUrl">{{ form.minioUrl }}</span>
|
||||||
|
</el-tooltip>
|
||||||
|
<UploadFile @success="uploadSuccess" @error="uploadError" />
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="文件路径" prop="audioPath">
|
<el-form-item label="文件路径" prop="audioPath">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="form.audioPath"
|
v-model="form.audioPath"
|
||||||
@ -285,6 +303,8 @@ import {
|
|||||||
updateCorpus,
|
updateCorpus,
|
||||||
} from "@/api/vi/corpus";
|
} from "@/api/vi/corpus";
|
||||||
import { useContainerHeight } from "@/hooks/tableHeight";
|
import { useContainerHeight } from "@/hooks/tableHeight";
|
||||||
|
import { usePlayAudio } from '@/hooks/usePlayAudio'
|
||||||
|
import UploadFile from "../../../components/UploadFile.vue";
|
||||||
|
|
||||||
const topContainerRef = ref();
|
const topContainerRef = ref();
|
||||||
const containerHeight = useContainerHeight(topContainerRef);
|
const containerHeight = useContainerHeight(topContainerRef);
|
||||||
@ -361,6 +381,7 @@ function reset() {
|
|||||||
form.value = {
|
form.value = {
|
||||||
corpusId: null,
|
corpusId: null,
|
||||||
corpusName: null,
|
corpusName: null,
|
||||||
|
minioUrl: null,
|
||||||
type: "TEST",
|
type: "TEST",
|
||||||
textContent: null,
|
textContent: null,
|
||||||
audioPath: null,
|
audioPath: null,
|
||||||
@ -451,8 +472,17 @@ function handleDelete(row) {
|
|||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePlay = () => {
|
const uploadSuccess = (data) => {
|
||||||
console.log("播放");
|
form.value.minioUrl = data
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadError = () => {
|
||||||
|
console.log("uploadError")
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePlay = (url) => {
|
||||||
|
const { playAudio } = usePlayAudio()
|
||||||
|
playAudio(url)
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
@ -478,4 +508,12 @@ defineExpose({
|
|||||||
.app-container {
|
.app-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.minioUrl {
|
||||||
|
display: inline-block;
|
||||||
|
width: 80%;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
Loading…
Reference in New Issue
Block a user