Browse Source

feat(语音管理): 实现音色列表的全局状态管理及优化音频控制

- 将音色列表和默认音色ID移至Vuex全局状态管理
- 实现音色列表的预加载和缓存机制
- 优化音频控制逻辑,当所有音频为导语时不自动播放
- 移除不必要的用户提示,提升用户体验
- 在多个页面组件中统一音色列表获取逻辑
main
前端-胡立永 1 day ago
parent
commit
6d2d0976b0
7 changed files with 142 additions and 39 deletions
  1. +10
    -1
      App.vue
  2. +35
    -1
      stores/index.js
  3. +25
    -23
      subPages/home/AudioControls.vue
  4. +1
    -1
      subPages/home/articleDetail.vue
  5. +41
    -8
      subPages/home/book.vue
  6. +28
    -4
      subPages/home/music.vue
  7. +2
    -1
      utils/share.js

+ 10
- 1
App.vue View File

@ -25,10 +25,12 @@
} }
}, },
}, },
onLaunch() {
async onLaunch() {
// //
this.getQrcode() this.getQrcode()
//
this.$store.dispatch('getVoiceList')
}, },
async onShow() { async onShow() {
// if(!uni.getStorageSync('token')){ // if(!uni.getStorageSync('token')){
@ -36,9 +38,16 @@
// url: '/subPages/login/login', // url: '/subPages/login/login',
// }) // })
// } // }
//
await this.$store.dispatch('initData') await this.$store.dispatch('initData')
console.log('配置数据初始化完成') console.log('配置数据初始化完成')
//
if (this.$store.state.voiceList.length === 0) {
this.$store.dispatch('getVoiceList')
}
if(uni.getStorageSync('token')){ if(uni.getStorageSync('token')){
this.getUserInfo() this.getUserInfo()
} }


+ 35
- 1
stores/index.js View File

@ -15,7 +15,9 @@ const store = new Vuex.Store({
departmentList: [], departmentList: [],
categoryList: [], categoryList: [],
userInfo: {}, userInfo: {},
Qrcode: ''
Qrcode: '',
voiceList: [], // 音色列表
defaultVoiceId: null // 默认音色ID
}, },
mutations: { mutations: {
// 构造用于uv-picker的树状结构数组 // 构造用于uv-picker的树状结构数组
@ -71,6 +73,16 @@ const store = new Vuex.Store({
setQrcode(state, data) { setQrcode(state, data) {
state.Qrcode = data state.Qrcode = data
}, },
setVoiceList(state, data) {
state.voiceList = data
// 如果有音色数据且还没有设置默认音色ID,则设置第一个音色为默认
if (data && data.length > 0 && !state.defaultVoiceId) {
state.defaultVoiceId = Number(data[0].voiceType)
}
},
setDefaultVoiceId(state, voiceId) {
state.defaultVoiceId = Number(voiceId)
},
// //
}, },
actions: { actions: {
@ -124,6 +136,7 @@ const store = new Vuex.Store({
try { try {
await Promise.all([ await Promise.all([
dispatch('getConfig'), dispatch('getConfig'),
dispatch('getVoiceList'), // 添加音色列表初始化
// dispatch('getDepartment'), // dispatch('getDepartment'),
// dispatch('getCategory'), // dispatch('getCategory'),
]) ])
@ -142,6 +155,27 @@ const store = new Vuex.Store({
commit('setUserInfo', res.result); commit('setUserInfo', res.result);
} }
}, },
// 获取音色列表
async getVoiceList({ commit }) {
try {
const res = await api.music.list()
if (res.code === 200) {
console.log('音色列表加载成功:', res.result);
commit('setVoiceList', res.result)
return res.result
} else {
console.error('音色列表加载失败:', res);
return []
}
} catch (error) {
console.error('音色列表加载异常:', error);
return []
}
},
// 设置默认音色
setDefaultVoice({ commit }, voiceId) {
commit('setDefaultVoiceId', voiceId)
},
} }
}) })

+ 25
- 23
subPages/home/AudioControls.vue View File

@ -287,9 +287,9 @@ export default {
} }
} }
//
console.log('🎵 findFirstNonLeadAudio: 所有音频都是导语,返回第一个音频索引=0');
return 0;
// -1
console.log('🎵 findFirstNonLeadAudio: 所有音频都是导语,返回 -1 不播放');
return -1;
}, },
// //
@ -324,7 +324,7 @@ export default {
// //
const firstNonLeadIndex = this.findFirstNonLeadAudio(); const firstNonLeadIndex = this.findFirstNonLeadAudio();
this.currentAudioIndex = firstNonLeadIndex >= 0 ? firstNonLeadIndex : 0;
this.currentAudioIndex = firstNonLeadIndex;
this.currentTime = 0; this.currentTime = 0;
this.currentHighlightIndex = -1; this.currentHighlightIndex = -1;
@ -618,7 +618,7 @@ export default {
// //
const firstNonLeadIndex = this.findFirstNonLeadAudio(); const firstNonLeadIndex = this.findFirstNonLeadAudio();
this.currentAudioIndex = firstNonLeadIndex >= 0 ? firstNonLeadIndex : 0;
this.currentAudioIndex = firstNonLeadIndex;
this.isPlaying = false; this.isPlaying = false;
this.currentTime = 0; this.currentTime = 0;
this.hasAudioData = true; this.hasAudioData = true;
@ -932,10 +932,10 @@ export default {
// ID // ID
if (cachedData.voiceId && cachedData.voiceId !== this.localVoiceId) { if (cachedData.voiceId && cachedData.voiceId !== this.localVoiceId) {
console.warn('缓存音色不匹配:', cachedData.voiceId, '!=', this.localVoiceId); console.warn('缓存音色不匹配:', cachedData.voiceId, '!=', this.localVoiceId);
uni.showToast({
title: '音色已切换,请重新获取音频',
icon: 'none'
});
// uni.showToast({
// title: '',
// icon: 'none'
// });
return; return;
} }
@ -982,10 +982,10 @@ export default {
// ID // ID
if (!this.localVoiceId) { if (!this.localVoiceId) {
uni.showToast({
title: '音色未加载,请稍后重试',
icon: 'none'
});
// uni.showToast({
// title: '',
// icon: 'none'
// });
return; return;
} }
@ -2112,16 +2112,12 @@ export default {
} }
} }
// //
uni.showToast({
title: '✅ 倍速功能可用',
icon: 'none',
duration: 1500
});
// uni.showToast({
// title: ' ',
// icon: 'none',
// duration: 1500
// });
} catch (error) { } catch (error) {
console.error('💥 检测播放速度支持时出错:', error); console.error('💥 检测播放速度支持时出错:', error);
@ -2829,12 +2825,18 @@ export default {
// //
const firstNonLeadIndex = this.findFirstNonLeadAudio(); const firstNonLeadIndex = this.findFirstNonLeadAudio();
this.currentAudioIndex = firstNonLeadIndex >= 0 ? firstNonLeadIndex : 0;
this.currentAudioIndex = firstNonLeadIndex;
this.currentTime = 0; this.currentTime = 0;
this.isPlaying = false; this.isPlaying = false;
console.log(`🎵 autoPlayCachedAudio: 设置起始索引为${this.currentAudioIndex}(跳过导语)`); console.log(`🎵 autoPlayCachedAudio: 设置起始索引为${this.currentAudioIndex}(跳过导语)`);
//
if (firstNonLeadIndex < 0) {
console.log('🎵 autoPlayCachedAudio: 所有音频都是导语,不播放');
return;
}
// UI // UI
setTimeout(() => { setTimeout(() => {
this.playAudio(); this.playAudio();


+ 1
- 1
subPages/home/articleDetail.vue View File

@ -144,7 +144,7 @@ export default {
if (res.result.audios && Object.keys(res.result.audios).length > 0) { if (res.result.audios && Object.keys(res.result.audios).length > 0) {
// URL // URL
const audioKeys = Object.keys(res.result.audios) const audioKeys = Object.keys(res.result.audios)
this.audioUrl = res.result.audios[audioKeys[0]]
this.audioUrl = res.result.audios['501008'] || res.result.audios[audioKeys[0]]
this.hasAudio = true this.hasAudio = true
} }
} else { } else {


+ 41
- 8
subPages/home/book.vue View File

@ -221,11 +221,22 @@ export default {
displayCourseList() { displayCourseList() {
return this.isReversed ? [...this.courseList].reverse() : this.courseList; return this.isReversed ? [...this.courseList].reverse() : this.courseList;
}, },
// Vuex
voiceList() {
return this.$store.state.voiceList;
},
// VuexID
defaultVoiceId() {
return this.$store.state.defaultVoiceId;
},
// //
isTextPage() { isTextPage() {
// type'1' // type'1'
if (this.currentPageType === '1') { if (this.currentPageType === '1') {
return false;
return true;
} }
const currentPageData = this.bookPages[this.currentPage - 1]; const currentPageData = this.bookPages[this.currentPage - 1];
@ -1183,15 +1194,37 @@ export default {
// id // id
async getVoiceList() { async getVoiceList() {
const voiceRes = await this.$api.music.list()
if (voiceRes.code === 200) {
// console.log('API:', voiceRes.result);
// console.log(':', voiceRes.result[0]);
this.voiceId = Number(voiceRes.result[0].voiceType)
// console.log('ID:', this.voiceId, ':', typeof this.voiceId);
// Vuex
if (this.voiceList && this.voiceList.length > 0) {
console.log('从Vuex获取音色列表:', this.voiceList);
this.voiceId = this.defaultVoiceId || Number(this.voiceList[0].voiceType);
console.log('使用Vuex中的默认音色ID:', this.voiceId);
// audioManager // audioManager
audioManager.setGlobalVoiceId(this.voiceId); audioManager.setGlobalVoiceId(this.voiceId);
return;
}
// VuexAPI
console.log('Vuex中无音色数据,从API获取...');
try {
const voiceRes = await this.$api.music.list()
if (voiceRes.code === 200) {
console.log('音色列表API返回:', voiceRes.result);
// Vuex
this.$store.commit('setVoiceList', voiceRes.result);
this.voiceId = Number(voiceRes.result[0].voiceType)
console.log('获取默认音色ID:', this.voiceId, '类型:', typeof this.voiceId);
// audioManager
audioManager.setGlobalVoiceId(this.voiceId);
} else {
console.error('获取音色列表失败:', voiceRes);
}
} catch (error) {
console.error('获取音色列表异常:', error);
} }
}, },
toggleNavbar() { toggleNavbar() {


+ 28
- 4
subPages/home/music.vue View File

@ -60,6 +60,12 @@ export default {
] ]
} }
}, },
computed: {
// Vuex
storeVoiceList() {
return this.$store.state.voiceList;
}
},
methods: { methods: {
goBack() { goBack() {
uni.navigateBack() uni.navigateBack()
@ -71,12 +77,30 @@ export default {
}, },
confirmSelection() { confirmSelection() {
this.selectVoice(this.selectedVoiceId) this.selectVoice(this.selectedVoiceId)
//
// Vuex
this.$store.dispatch('setDefaultVoice', this.selectedVoiceId);
}, },
async getVoice(){ async getVoice(){
const listRes = await this.$api.music.list()
if (listRes.code === 200) {
this.voiceList = listRes.result
// Vuex
if (this.storeVoiceList && this.storeVoiceList.length > 0) {
console.log('从Vuex获取音色列表:', this.storeVoiceList);
this.voiceList = this.storeVoiceList;
return;
}
// VuexAPI
console.log('Vuex中无音色数据,从API获取...');
try {
const listRes = await this.$api.music.list()
if (listRes.code === 200) {
this.voiceList = listRes.result
// Vuex
this.$store.commit('setVoiceList', listRes.result);
} else {
console.error('获取音色列表失败:', listRes);
}
} catch (error) {
console.error('获取音色列表异常:', error);
} }
} }
}, },


+ 2
- 1
utils/share.js View File

@ -94,4 +94,5 @@ function addQueryParams(url) {
} }
} }
export default share
export default function(){}
// export default share

Loading…
Cancel
Save