修改语音播放等三个bug
This commit is contained in:
@@ -80,7 +80,9 @@
|
||||
<script setup>
|
||||
import { computed, unref, ref, toRefs, watch, onMounted, nextTick } from 'vue';
|
||||
import { onUnload } from '@dcloudio/uni-app';
|
||||
import { useAudioStore } from '@/store/audioStore';
|
||||
// import { useinnerAudio, useAudioFun } from '@/store/innerAudio';
|
||||
|
||||
import { useAudio } from './useAudio.js';
|
||||
import {downloadFile} from '@/api/common.js'
|
||||
const props = defineProps({
|
||||
dataInfo: {
|
||||
@@ -124,8 +126,9 @@
|
||||
type: Boolean
|
||||
}
|
||||
});
|
||||
const audioStore = useAudioStore();
|
||||
const { dataInfo } = toRefs(props);
|
||||
|
||||
const innerAudio = useAudio();
|
||||
|
||||
const status = computed(() => props.status);
|
||||
watch(
|
||||
() => props.status,
|
||||
@@ -142,7 +145,7 @@
|
||||
return props.text || props.dataInfo.anserResult || '';
|
||||
});
|
||||
|
||||
const isPlaying = ref(false);
|
||||
const isPlaying = innerAudio.isPlaying;
|
||||
const textLoading = ref(false);
|
||||
const textShow = ref(props.defaultDisplayText); // 翻译文字展示状态
|
||||
const voiceTime = ref('');
|
||||
@@ -170,57 +173,54 @@
|
||||
textShow.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const initVoice = () => {
|
||||
innerAudioContext.onEnded(() => {
|
||||
innerAudioContext.src = '';
|
||||
});
|
||||
innerAudioContext.onError(() => {
|
||||
innerAudioContext.src = '';
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const playVoice = () => {
|
||||
// isPlaying.value = true;
|
||||
console.log('点击播放');
|
||||
audioStore.playAudio();
|
||||
innerAudio.playAudio();
|
||||
};
|
||||
let unsubscribe = () => {};
|
||||
onMounted(() => {
|
||||
// 2. 监听 Store 中 isPlaying 的变化,实时同步
|
||||
unsubscribe = audioStore.$subscribe((mutation, state) => {
|
||||
isPlaying.value = state.isPlaying;
|
||||
});
|
||||
// unsubscribe = innerAudio.$subscribe((mutation, state) => {
|
||||
// isPlaying.value = state.isPlaying;
|
||||
// });
|
||||
// 注册播放完成回调
|
||||
audioStore.onAudioEnded(() => {
|
||||
innerAudio.onAudioEnded(() => {
|
||||
console.log('播放完成(通过回调)');
|
||||
setTimeout(() => {
|
||||
isPlaying.value = false;
|
||||
}, 60);
|
||||
});
|
||||
// 注册播放错误回调
|
||||
audioStore.onAudioError((error) => {
|
||||
innerAudio.onAudioError((error) => {
|
||||
console.error('播放错误(通过回调):', error);
|
||||
});
|
||||
// 声音加载完毕
|
||||
audioStore.onAudioLoaded((e) => {
|
||||
innerAudio.onAudioLoaded((e) => {
|
||||
console.log('声音加载完毕', e.duration);
|
||||
// 计算原始时长
|
||||
const originalTime = Math.ceil(e.duration) || 1;
|
||||
// 判断是否在118-123秒范围内
|
||||
const displayTime = originalTime >= 118 && originalTime <= 124 ? 120 : originalTime;
|
||||
// 赋值显示
|
||||
console.log('displayTime', displayTime);
|
||||
voiceTime.value = displayTime + 's';
|
||||
console.log('displayTime', voiceTime.value);
|
||||
});
|
||||
watch(
|
||||
() => props.dataInfo.voicePath,
|
||||
(newVal) => {
|
||||
console.log('newVal', newVal);
|
||||
if(newVal === '' && props.dataInfo.ossKey) { // 去下载oss内容
|
||||
console.log('去下载oss内容');
|
||||
downloadFile(props.dataInfo.ossKey).then(res => {
|
||||
audioStore.setAudioSrc(res.tempFilePath);
|
||||
innerAudio.setAudioSrc(res.tempFilePath);
|
||||
})
|
||||
} else if(newVal === undefined){
|
||||
innerAudio.stopAudio();
|
||||
} else {
|
||||
audioStore.setAudioSrc(newVal);
|
||||
innerAudio.setAudioSrc(newVal);
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
@@ -228,9 +228,9 @@
|
||||
});
|
||||
onUnload(() => {
|
||||
// 1. 停止当前播放(优先处理,避免音频继续播放)
|
||||
audioStore.stopAudio();
|
||||
innerAudio.stopAudio();
|
||||
// 2. 移除当前组件注册的回调(避免内存泄漏)
|
||||
audioStore.removeCallbacks();
|
||||
innerAudio.removeCallbacks();
|
||||
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
|
||||
<view
|
||||
class="analysis_div"
|
||||
v-if="!clearResult && ['study', 'mistake', 'settlement', 'practice'].includes(props.mode)"
|
||||
v-if="!clearResult && ['study', 'mistake', 'settlement', 'practice', 'practice_record'].includes(props.mode)"
|
||||
>
|
||||
<view class="analysis_title" v-if="qnsTyp !== 'ES'">
|
||||
<view class="success_answer">正确答案:{{ correctResultLabel.join('') }}</view>
|
||||
@@ -141,7 +141,8 @@
|
||||
// 错题本: mistake
|
||||
// 学习: study
|
||||
// 考试结算页 settlement
|
||||
return ['examination', 'practice', 'mistake', 'study', 'settlement'].includes(value);
|
||||
// 练习记录页 practice_record
|
||||
return ['examination', 'practice', 'mistake', 'study', 'settlement', 'practice_record'].includes(value);
|
||||
}
|
||||
},
|
||||
// 是否预览模式
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
import {
|
||||
computed,
|
||||
reactive,
|
||||
nextTick,
|
||||
ref
|
||||
} from 'vue';
|
||||
|
||||
|
||||
// const innerAudioContext = uni.createInnerAudioContext();
|
||||
// // 当前播放状态
|
||||
const audioStopFun = ref(null)
|
||||
|
||||
|
||||
export const useAudio = () => {
|
||||
|
||||
const audioInstance = uni.createInnerAudioContext();
|
||||
const callbacks = reactive({
|
||||
onEnded: null, // 播放完成回调
|
||||
onError: null, // 播放错误回调
|
||||
onLoaded: null, // 音频加载完成回调(可获取时长)
|
||||
onStop: null
|
||||
})
|
||||
const isPlaying = ref(false)
|
||||
// 加载状态
|
||||
const isLoading = ref(false)
|
||||
// 当前播放的音频地址
|
||||
const currentSrc = ref('')
|
||||
const errorMsg = ref('')
|
||||
|
||||
// 初始化音频实例(确保全局唯一)
|
||||
const initAudio = () => {
|
||||
bindAudioEvents();
|
||||
}
|
||||
|
||||
const bindAudioEvents = () => {
|
||||
if (!audioInstance) return;
|
||||
// 播放开始事件
|
||||
audioInstance.onPlay(() => {
|
||||
isPlaying.value = true;
|
||||
isLoading.value = false;
|
||||
errorMsg.value = '';
|
||||
});
|
||||
|
||||
audioInstance.onStop(() => {
|
||||
console.log('音频停止事件');
|
||||
isPlaying.value = false;
|
||||
isLoading.value = false;
|
||||
// 清空地址避免残留
|
||||
|
||||
// 触发自定义回调
|
||||
if (callbacks.onStop && typeof callbacks.onStop === 'function') {
|
||||
callbacks.onStop();
|
||||
}
|
||||
});
|
||||
|
||||
// 播放结束事件
|
||||
audioInstance.onEnded(() => {
|
||||
console.log('播放结束事件');
|
||||
|
||||
// 清空地址避免残留
|
||||
// if (audioInstance) {
|
||||
// audioInstance.src = '';
|
||||
// }
|
||||
// 触发自定义回调
|
||||
if (callbacks.onEnded && typeof callbacks.onEnded === 'function') {
|
||||
callbacks.onEnded();
|
||||
}
|
||||
});
|
||||
|
||||
// 音频可以播放时触发(此时通常能获取到时长)
|
||||
audioInstance.onCanplay(() => {
|
||||
// 尝试获取时长(部分环境需要延迟一点)
|
||||
// console.log('尝试获取时长(部分环境需要延迟一点)');
|
||||
isLoading.value = false;
|
||||
setTimeout(() => {
|
||||
const duration = audioInstance.duration || 0;
|
||||
console.log('尝试获duration', duration);
|
||||
if (duration > 0) {
|
||||
// 触发加载完成回调(此时已获取时长)
|
||||
if (callbacks.onLoaded && typeof callbacks.onLoaded === 'function') {
|
||||
callbacks.onLoaded({
|
||||
duration: duration
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 100); // 短暂延迟确保时长已加载
|
||||
});
|
||||
|
||||
// 错误事件
|
||||
audioInstance.onError((err) => {
|
||||
isPlaying.value = false;
|
||||
isLoading.value = false;
|
||||
console.error('音频错误:', err);
|
||||
if (callbacks.onError && typeof callbacks.onError === 'function') {
|
||||
callbacks.onError(err); // 把错误信息传给外部
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 新增:预设置音频地址并加载(此时不播放,仅获取时长)
|
||||
const setAudioSrc = (src) => {
|
||||
console.log('预设置音频地址并加载', src);
|
||||
if (!src || src === currentSrc.value) return; // 地址不变则不重复加载
|
||||
initAudio();
|
||||
isLoading.value = true;
|
||||
currentSrc.value = src;
|
||||
errorMsg.value = '';
|
||||
|
||||
try {
|
||||
// 先停止当前播放并清空旧地址
|
||||
// audioInstance.stop();
|
||||
// audioInstance.src = '';
|
||||
// 设置新地址并加载(不自动播放)
|
||||
audioInstance.src = src;
|
||||
// audioInstance.load(); // 手动触发加载
|
||||
} catch (err) {
|
||||
isLoading.value = false;
|
||||
errorMsg.value = `设置音频失败: ${err.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
// 修改:播放当前已设置的音频(需先调用setAudioSrc)
|
||||
const playAudio = async (src) => {
|
||||
console.log('播放当前已设置的音频', currentSrc.value);
|
||||
if (!currentSrc.value) {
|
||||
errorMsg.value = '请先设置音频地址';
|
||||
return;
|
||||
}
|
||||
// 已在播放则暂停
|
||||
console.log('已在播放则暂停', isPlaying.value);
|
||||
const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
if (isPlaying.value) {
|
||||
pauseAudio();
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('当前是是否暂停或停止状态', audioStopFun.value?.paused);
|
||||
if (!audioStopFun.value?.paused) { // 当前是是否暂停或停止状态,true 表示暂停或停止,false 表示正在播放
|
||||
audioStopFun.value?.stop();
|
||||
wait(100)
|
||||
}
|
||||
|
||||
// 执行播放
|
||||
try {
|
||||
// 哪个函数的实例正在播放,就把他挂在全局
|
||||
audioStopFun.value = audioInstance
|
||||
audioInstance.play();
|
||||
isPlaying.value = true;
|
||||
isLoading.value = false;
|
||||
} catch (err) {
|
||||
isLoading.value = false;
|
||||
errorMsg.value = `播放失败: ${err.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
// 暂停播放
|
||||
const pauseAudio = () => {
|
||||
if (audioInstance && isPlaying.value) {
|
||||
console.log('暂停播放');
|
||||
audioInstance.pause();
|
||||
isPlaying.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 停止播放并重置状态
|
||||
const stopAudio = () => {
|
||||
|
||||
if (audioInstance && isPlaying.value) {
|
||||
audioInstance.stop();
|
||||
// todo
|
||||
}
|
||||
}
|
||||
|
||||
// 移除所有回调(组件卸载时调用)
|
||||
const removeCallbacks = () => {
|
||||
callbacks.onEnded = null;
|
||||
callbacks.onError = null;
|
||||
callbacks.onLoaded = null;
|
||||
callbacks.onStop = null;
|
||||
}
|
||||
// 注册播放完成回调
|
||||
const onAudioEnded = (callback) => {
|
||||
if (typeof callback === 'function') {
|
||||
callbacks.onEnded = callback;
|
||||
}
|
||||
}
|
||||
|
||||
// 注册播放错误回调
|
||||
const onAudioError = (callback) => {
|
||||
if (typeof callback === 'function') {
|
||||
callbacks.onError = callback;
|
||||
}
|
||||
}
|
||||
// 新增:注册音频加载完成回调(用于获取时长)
|
||||
const onAudioLoaded = (callback) => {
|
||||
if (typeof callback === 'function') {
|
||||
callbacks.onLoaded = callback;
|
||||
}
|
||||
}
|
||||
const onAudioStop = (callback) => {
|
||||
if (typeof callback === 'function') {
|
||||
callbacks.onStop = callback;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
isPlaying,
|
||||
playAudio,
|
||||
pauseAudio,
|
||||
stopAudio,
|
||||
setAudioSrc,
|
||||
removeCallbacks,
|
||||
onAudioEnded,
|
||||
onAudioError,
|
||||
onAudioLoaded,
|
||||
onAudioStop
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user