5252 </template >
5353 </el-table-column >
5454
55- <el-table-column :label =" $t('voiceClone.action')" align =" center" width =" 180 " >
55+ <el-table-column :label =" $t('voiceClone.action')" align =" center" width =" 230 " >
5656 <template slot-scope="scope">
5757 <el-button v-if =" scope.row.hasVoice" size =" mini" type =" text"
5858 @click =" handlePlay(scope.row)" >
59- {{ $t('voiceClone.play') }}
59+ {{ playingRowId === scope.row.id ? $t('voiceClone.stop') : $t('voiceClone.play') }}
6060 </el-button >
6161 <el-button size =" mini" type =" text" @click =" handleUpload(scope.row)" >
6262 {{ $t('voiceClone.upload') }}
6363 </el-button >
6464 <el-button v-if =" scope.row.hasVoice" size =" mini" type =" text"
65- @click =" handleClone(scope.row)" >
65+ @click =" handleClone(scope.row)" :loading = " scope.row._cloning " >
6666 {{ $t('voiceClone.clone') }}
6767 </el-button >
6868 </template >
@@ -149,7 +149,10 @@ export default {
149149 modelId: " " ,
150150 voiceIds: [],
151151 userId: null
152- }
152+ },
153+ // 音频播放相关
154+ currentAudio: null , // 当前正在播放的音频对象
155+ playingRowId: null // 当前正在播放的行 ID
153156 };
154157 },
155158 created () {
@@ -284,10 +287,10 @@ export default {
284287 // 处理复刻操作
285288 handleClone (row ) {
286289 // 防止重复提交
287- if (row ._submitting ) {
290+ if (row ._cloning ) {
288291 return ;
289292 }
290- row . _submitting = true ;
293+ this . $set (row, ' _cloning ' , true ) ;
291294
292295 const params = {
293296 cloneId: row .id
@@ -313,21 +316,21 @@ export default {
313316 this .$message .error (' 处理响应时出错' );
314317 this .fetchVoiceCloneList ();
315318 } finally {
316- row . _submitting = false ;
319+ this . $set (row, ' _cloning ' , false ) ;
317320 }
318321 }, (error ) => {
319322 // API调用失败,刷新列表以获取最新状态
320323 console .error (' API调用失败:' , error);
321324 this .$message .error (' 克隆失败,请将鼠标悬停在错误提示上,查看错误详情' );
322325 this .fetchVoiceCloneList ();
323- row . _submitting = false ;
326+ this . $set (row, ' _cloning ' , false ) ;
324327 });
325328 } catch (error) {
326329 // 调用API时出错,刷新列表
327330 console .error (' 调用API时出错:' , error);
328331 this .$message .error (' 调用API时出错' );
329332 this .fetchVoiceCloneList ();
330- row . _submitting = false ;
333+ this . $set (row, ' _cloning ' , false ) ;
331334 }
332335 },
333336
@@ -427,6 +430,15 @@ export default {
427430 },
428431 // 播放音频
429432 handlePlay (row ) {
433+ // 如果点击的是正在播放的行,则停止播放
434+ if (this .playingRowId === row .id && this .currentAudio ) {
435+ this .stopCurrentAudio ();
436+ return ;
437+ }
438+
439+ // 停止当前正在播放的音频(如果有)
440+ this .stopCurrentAudio ();
441+
430442 // 先获取音频下载ID
431443 Api .voiceClone .getAudioId (row .id , (res ) => {
432444 res = res .data ;
@@ -435,15 +447,43 @@ export default {
435447 // 使用获取到的uuid播放音频
436448 const audioUrl = Api .voiceClone .getPlayVoiceUrl (uuid);
437449 const audio = new Audio (audioUrl);
450+
451+ // 设置当前播放状态
452+ this .currentAudio = audio;
453+ this .playingRowId = row .id ;
454+
455+ // 播放结束时清除状态
456+ audio .addEventListener (' ended' , () => {
457+ this .playingRowId = null ;
458+ this .currentAudio = null ;
459+ });
460+
461+ // 播放出错时清除状态
462+ audio .addEventListener (' error' , () => {
463+ this .playingRowId = null ;
464+ this .currentAudio = null ;
465+ });
466+
438467 audio .play ().catch (err => {
439468 console .error (' 播放失败:' , err);
440469 this .$message .error (this .$t (' voiceClone.playFailed' ) || ' 播放失败' );
470+ this .playingRowId = null ;
471+ this .currentAudio = null ;
441472 });
442473 } else {
443474 this .$message .error (res .msg || this .$t (' voiceClone.audioNotExist' ) || ' 音频不存在' );
444475 }
445476 });
446477 },
478+ // 停止当前音频播放
479+ stopCurrentAudio () {
480+ if (this .currentAudio ) {
481+ this .currentAudio .pause ();
482+ this .currentAudio .currentTime = 0 ;
483+ this .currentAudio = null ;
484+ }
485+ this .playingRowId = null ;
486+ },
447487 // 上传音频
448488 handleUpload (row ) {
449489 this .currentVoiceClone = row;
0 commit comments