Merge pull request '[lisa]fix: bugs' (#12) from lisa into main
Reviewed-on: http://gitea.xhzone.cn/felix/miniprogram-1/pulls/12
This commit is contained in:
@@ -52,6 +52,9 @@ interface IPageData {
|
||||
playIconSrc: string // 播放图标图片源
|
||||
showDictPopup: boolean // 控制弹窗是否显示
|
||||
showDictExtended: boolean // 控制扩展内容是否显示
|
||||
wordAudioPlaying: boolean // 单词音频是否播放中
|
||||
wordAudioIconName: string // sound/sound-low/sound-mute
|
||||
activeWordAudioType: string // 'uk' | 'us' 当前播放的音频类型
|
||||
wordDict: {
|
||||
ee: any
|
||||
ec: any
|
||||
@@ -141,6 +144,9 @@ interface IPageInstance extends IPageMethods {
|
||||
data: IPageData
|
||||
audioContext?: WechatMiniprogram.InnerAudioContext
|
||||
playIconTimer?: number
|
||||
// 新增:单词音频上下文与图标轮播定时器
|
||||
wordAudioContext?: WechatMiniprogram.InnerAudioContext
|
||||
wordAudioIconTimer?: number
|
||||
}
|
||||
|
||||
Page<IPageData, IPageInstance>({
|
||||
@@ -198,6 +204,10 @@ Page<IPageData, IPageInstance>({
|
||||
playIconSrc: '/static/play.png',
|
||||
showDictPopup: false, // 控制弹窗是否显示
|
||||
showDictExtended: false, // 控制扩展内容是否显示
|
||||
// 新增:单词音频播放与图标轮播状态
|
||||
wordAudioPlaying: false,
|
||||
wordAudioIconName: 'sound',
|
||||
activeWordAudioType: '',
|
||||
processedSentences: [], // 处理后的句子数据
|
||||
transDisplayMode: 'en', // 默认显示模式为英文 only
|
||||
isScoreModalOpen: false, // 评分结果弹窗是否打开
|
||||
@@ -292,22 +302,30 @@ Page<IPageData, IPageInstance>({
|
||||
resetAudioState() {
|
||||
// 隐藏可能存在的加载提示
|
||||
wx.hideLoading()
|
||||
|
||||
|
||||
if (this.audioContext) {
|
||||
this.audioContext.stop()
|
||||
// 清空音频源以取消当前加载
|
||||
this.audioContext.src = ''
|
||||
}
|
||||
this.setData({
|
||||
isPlaying: false,
|
||||
currentTime: 0,
|
||||
sliderValue: 0,
|
||||
audioDuration: 0
|
||||
})
|
||||
if (this.playIconTimer) {
|
||||
clearInterval(this.playIconTimer)
|
||||
this.playIconTimer = undefined
|
||||
// iOS 真机上,直接 stop 可能无法立即中断播放;需先 pause,再 seek(0),并关闭自动播放
|
||||
try { (this.audioContext as any).autoplay = false } catch (e) {}
|
||||
try { this.audioContext.pause() } catch (e) {}
|
||||
try { this.audioContext.seek(0) } catch (e) {}
|
||||
try { this.audioContext.stop() } catch (e) {}
|
||||
|
||||
// 解绑所有事件,避免旧回调在切换句子后再次触发导致误播上一个音频
|
||||
try {
|
||||
this.audioContext.offPlay()
|
||||
this.audioContext.offTimeUpdate()
|
||||
this.audioContext.offEnded()
|
||||
this.audioContext.offError()
|
||||
this.audioContext.offCanplay && this.audioContext.offCanplay()
|
||||
} catch (e) {}
|
||||
|
||||
// 清空音源并销毁上下文,确保下次播放重新创建,避免残留状态
|
||||
try { this.audioContext.src = '' } catch (e) {}
|
||||
try { this.audioContext.destroy() } catch (e) {}
|
||||
this.audioContext = undefined
|
||||
}
|
||||
|
||||
// 重置界面状态
|
||||
this.setData({
|
||||
isPlaying: false,
|
||||
currentTime: 0,
|
||||
@@ -568,6 +586,7 @@ Page<IPageData, IPageInstance>({
|
||||
|
||||
if (!this.audioContext) {
|
||||
this.audioContext = wx.createInnerAudioContext()
|
||||
try { (this.audioContext as any).autoplay = false } catch (e) {}
|
||||
this.audioContext.onCanplay(() => {
|
||||
setTimeout(() => {
|
||||
const duration = this.audioContext!.duration
|
||||
@@ -626,33 +645,18 @@ Page<IPageData, IPageInstance>({
|
||||
})
|
||||
})
|
||||
this.audioContext.onError(() => {
|
||||
// 出错时清除动画并复位图标,不再自动重试,避免误播上一个音频
|
||||
if (this.playIconTimer) {
|
||||
clearInterval(this.playIconTimer)
|
||||
this.playIconTimer = undefined
|
||||
}
|
||||
this.setData({
|
||||
isPlaying: false,
|
||||
currentTime: 0,
|
||||
sliderValue: 0
|
||||
})
|
||||
// 播放失败时重新尝试
|
||||
if (this.audioContext?.src) {
|
||||
wx.showLoading({ title: '正在重试...' })
|
||||
setTimeout(() => {
|
||||
try {
|
||||
this.audioContext?.play()
|
||||
wx.hideLoading()
|
||||
this.setData({ isPlaying: true })
|
||||
} catch (error) {
|
||||
wx.hideLoading()
|
||||
wx.showToast({
|
||||
title: '播放失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}, 1000)
|
||||
return
|
||||
}
|
||||
wx.showToast({
|
||||
title: '播放失败',
|
||||
icon: 'none'
|
||||
sliderValue: 0,
|
||||
playIconSrc: '/static/play.png'
|
||||
})
|
||||
wx.showToast({ title: '播放失败', icon: 'none' })
|
||||
})
|
||||
this.audioContext.onTimeUpdate(() => {
|
||||
const currentTime = this.audioContext!.currentTime
|
||||
@@ -667,13 +671,10 @@ Page<IPageData, IPageInstance>({
|
||||
}
|
||||
|
||||
if (this.audioContext.src !== audioUrl) {
|
||||
// 重置状态
|
||||
this.setData({
|
||||
currentTime: 0,
|
||||
sliderValue: 0,
|
||||
audioDuration: 0
|
||||
})
|
||||
// 设置新的音频源
|
||||
// 切换音源前,先暂停并复位进度,避免 iOS 上继续播放旧音源
|
||||
try { this.audioContext.pause() } catch (e) {}
|
||||
try { this.audioContext.seek(0) } catch (e) {}
|
||||
this.setData({ currentTime: 0, sliderValue: 0, audioDuration: 0 })
|
||||
this.audioContext.src = audioUrl
|
||||
}
|
||||
|
||||
@@ -848,7 +849,8 @@ Page<IPageData, IPageInstance>({
|
||||
accuracyScore: pronAccuracy > 0 ? pronAccuracy : 0,
|
||||
completenessScore: pronCompletion > 0 ? pronCompletion : 0,
|
||||
fluencyScore: pronFluency > 0 ? pronFluency : 0,
|
||||
justSelectedByWord: true
|
||||
justSelectedByWord: true,
|
||||
prototypeWord: ''
|
||||
})
|
||||
this.updateCircleProgress()
|
||||
return
|
||||
@@ -863,6 +865,9 @@ Page<IPageData, IPageInstance>({
|
||||
// 清理单词,移除标点符号
|
||||
const cleanedWord = word.replace(/[.,?!*;:]/g, '').trim()
|
||||
if (!cleanedWord) return
|
||||
|
||||
// 先清空 prototypeWord,避免新词没有原型时保留旧值
|
||||
this.setData({ prototypeWord: '' })
|
||||
|
||||
try {
|
||||
// 调用API获取单词详情
|
||||
@@ -882,7 +887,7 @@ Page<IPageData, IPageInstance>({
|
||||
relWord: wordDetail['rel_word'], syno: wordDetail['syno'],
|
||||
discriminate: wordDetail['discriminate']
|
||||
},
|
||||
prototypeWord: wordDetail['ec'].word[0]?.prototype
|
||||
prototypeWord: (wordDetail?.ec?.word?.[0]?.prototype) || ''
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('获取单词详情失败:', error)
|
||||
@@ -935,7 +940,8 @@ Page<IPageData, IPageInstance>({
|
||||
completenessScore: pronCompletion >= 0 ? Number((pronCompletion * 100).toFixed(2)) : 0,
|
||||
fluencyScore: pronFluency >= 0 ? Number((pronFluency * 100).toFixed(2)) : 0,
|
||||
wordScores,
|
||||
justSelectedByWord: false
|
||||
justSelectedByWord: false,
|
||||
prototypeWord: ''
|
||||
})
|
||||
|
||||
// 预加载并绑定新的标准语音
|
||||
@@ -1102,6 +1108,26 @@ Page<IPageData, IPageInstance>({
|
||||
if (this.audioContext) {
|
||||
this.audioContext.destroy()
|
||||
}
|
||||
// 销毁单词音频实例与清理定时器
|
||||
try { this.wordAudioContext && this.wordAudioContext.stop() } catch (e) {}
|
||||
try {
|
||||
if (this.wordAudioContext) {
|
||||
this.wordAudioContext.offPlay()
|
||||
this.wordAudioContext.offEnded()
|
||||
this.wordAudioContext.offError()
|
||||
this.wordAudioContext.destroy()
|
||||
this.wordAudioContext = undefined
|
||||
}
|
||||
} catch (e) {}
|
||||
if (this.wordAudioIconTimer) {
|
||||
clearInterval(this.wordAudioIconTimer)
|
||||
this.wordAudioIconTimer = undefined
|
||||
}
|
||||
this.setData({
|
||||
wordAudioPlaying: false,
|
||||
wordAudioIconName: 'sound',
|
||||
activeWordAudioType: ''
|
||||
})
|
||||
},
|
||||
|
||||
onReady() {
|
||||
@@ -1117,10 +1143,31 @@ Page<IPageData, IPageInstance>({
|
||||
|
||||
// 点击“x”按钮,关闭弹窗
|
||||
handleDictClose() {
|
||||
// 关闭弹窗
|
||||
this.setData({
|
||||
showDictExtended: false,
|
||||
showDictPopup: false
|
||||
})
|
||||
// 停止并销毁单词音频,重置轮播状态
|
||||
try { this.wordAudioContext && this.wordAudioContext.stop() } catch (e) {}
|
||||
try {
|
||||
if (this.wordAudioContext) {
|
||||
this.wordAudioContext.offPlay()
|
||||
this.wordAudioContext.offEnded()
|
||||
this.wordAudioContext.offError()
|
||||
this.wordAudioContext.destroy()
|
||||
this.wordAudioContext = undefined
|
||||
}
|
||||
} catch (e) {}
|
||||
if (this.wordAudioIconTimer) {
|
||||
clearInterval(this.wordAudioIconTimer)
|
||||
this.wordAudioIconTimer = undefined
|
||||
}
|
||||
this.setData({
|
||||
wordAudioPlaying: false,
|
||||
wordAudioIconName: 'sound',
|
||||
activeWordAudioType: ''
|
||||
})
|
||||
},
|
||||
|
||||
onTabsChange(event: any) {
|
||||
@@ -1131,37 +1178,104 @@ Page<IPageData, IPageInstance>({
|
||||
console.log(`Click tab, tab-panel value is ${event.detail.value}.`);
|
||||
},
|
||||
|
||||
// 播放单词音频
|
||||
// 播放单词音频(带图标轮播)
|
||||
playWordAudio(e: any) {
|
||||
const { audio } = e.currentTarget.dataset
|
||||
const { audio, type } = e.currentTarget.dataset
|
||||
if (!audio) return
|
||||
|
||||
// 如果点击同一类型且正在播放,则切换为停止
|
||||
if (this.data.wordAudioPlaying && this.data.activeWordAudioType === type) {
|
||||
try { this.wordAudioContext && this.wordAudioContext.stop() } catch (err) {}
|
||||
try {
|
||||
if (this.wordAudioContext) {
|
||||
this.wordAudioContext.offPlay()
|
||||
this.wordAudioContext.offEnded()
|
||||
this.wordAudioContext.offError()
|
||||
this.wordAudioContext.destroy()
|
||||
this.wordAudioContext = undefined
|
||||
}
|
||||
} catch (err) {}
|
||||
if (this.wordAudioIconTimer) {
|
||||
clearInterval(this.wordAudioIconTimer)
|
||||
this.wordAudioIconTimer = undefined
|
||||
}
|
||||
this.setData({
|
||||
wordAudioPlaying: false,
|
||||
wordAudioIconName: 'sound',
|
||||
activeWordAudioType: ''
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 先清理上一次的上下文与定时器
|
||||
try { this.wordAudioContext && this.wordAudioContext.stop() } catch (err) {}
|
||||
try {
|
||||
if (this.wordAudioContext) {
|
||||
this.wordAudioContext.offPlay()
|
||||
this.wordAudioContext.offEnded()
|
||||
this.wordAudioContext.offError()
|
||||
this.wordAudioContext.destroy()
|
||||
this.wordAudioContext = undefined
|
||||
}
|
||||
} catch (err) {}
|
||||
if (this.wordAudioIconTimer) {
|
||||
clearInterval(this.wordAudioIconTimer)
|
||||
this.wordAudioIconTimer = undefined
|
||||
}
|
||||
|
||||
// 构造音频URL
|
||||
const audioUrl = `https://dict.youdao.com/dictvoice?audio=${audio}`
|
||||
|
||||
// 创建音频上下文
|
||||
const wordAudioContext = wx.createInnerAudioContext()
|
||||
|
||||
wordAudioContext.onPlay(() => {
|
||||
console.log('开始播放单词音频')
|
||||
this.wordAudioContext = wx.createInnerAudioContext()
|
||||
try { (this.wordAudioContext as any).autoplay = false } catch (err) {}
|
||||
|
||||
// 绑定事件
|
||||
this.wordAudioContext.onPlay(() => {
|
||||
// 开始轮播图标
|
||||
const seq = ['sound', 'sound-low']
|
||||
let i = 0
|
||||
this.setData({ wordAudioPlaying: true, activeWordAudioType: type, wordAudioIconName: seq[0] })
|
||||
this.wordAudioIconTimer = setInterval(() => {
|
||||
i = (i + 1) % seq.length
|
||||
this.setData({ wordAudioIconName: seq[i] })
|
||||
}, 400) as any
|
||||
})
|
||||
|
||||
wordAudioContext.onError((res) => {
|
||||
console.error('播放单词音频失败:', res)
|
||||
wx.showToast({
|
||||
title: '播放失败',
|
||||
icon: 'none'
|
||||
|
||||
const finalize = () => {
|
||||
if (this.wordAudioIconTimer) {
|
||||
clearInterval(this.wordAudioIconTimer)
|
||||
this.wordAudioIconTimer = undefined
|
||||
}
|
||||
this.setData({
|
||||
wordAudioPlaying: false,
|
||||
wordAudioIconName: 'sound',
|
||||
activeWordAudioType: ''
|
||||
})
|
||||
try {
|
||||
if (this.wordAudioContext) {
|
||||
this.wordAudioContext.offPlay()
|
||||
this.wordAudioContext.offEnded()
|
||||
this.wordAudioContext.offError()
|
||||
this.wordAudioContext.destroy()
|
||||
this.wordAudioContext = undefined
|
||||
}
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
this.wordAudioContext.onEnded(() => {
|
||||
finalize()
|
||||
})
|
||||
|
||||
wordAudioContext.onEnded(() => {
|
||||
console.log('单词音频播放结束')
|
||||
wordAudioContext.destroy()
|
||||
|
||||
this.wordAudioContext.onError((res) => {
|
||||
console.error('播放单词音频失败:', res)
|
||||
wx.showToast({ title: '播放失败', icon: 'none' })
|
||||
finalize()
|
||||
})
|
||||
|
||||
// 设置音频源并播放
|
||||
wordAudioContext.src = audioUrl
|
||||
wordAudioContext.play()
|
||||
this.wordAudioContext.src = audioUrl
|
||||
this.wordAudioContext.play()
|
||||
},
|
||||
|
||||
onScoreTap() {
|
||||
|
||||
@@ -156,13 +156,13 @@
|
||||
<span class="pron-item-text" wx:if="{{wordDict.simple.word[0].ukphone}}">
|
||||
UK:[{{wordDict.simple.word[0].ukphone}}]
|
||||
</span>
|
||||
<t-icon class="ipa-audio" wx:if="{{wordDict.simple.word[0].ukspeech}}" bind:click="playWordAudio" data-audio="{{wordDict.simple.word[0].ukspeech}}" name="sound" size="30rpx" />
|
||||
<t-icon class="ipa-audio" wx:if="{{wordDict.simple.word[0].ukspeech}}" bind:click="playWordAudio" data-type="uk" data-audio="{{wordDict.simple.word[0].ukspeech}}" name="{{(activeWordAudioType === 'uk' && wordAudioPlaying) ? wordAudioIconName : 'sound'}}" size="30rpx" />
|
||||
</view>
|
||||
<view class="pron-item" wx:if="{{wordDict.simple && wordDict.simple.word && wordDict.simple.word.length > 0}}">
|
||||
<span class="pron-item-text" wx:if="{{wordDict.simple.word[0].usphone}}">
|
||||
US:[{{wordDict.simple.word[0].usphone}}]
|
||||
</span>
|
||||
<t-icon class="ipa-audio" wx:if="{{wordDict.simple.word[0].usspeech}}" bind:click="playWordAudio" data-audio="{{wordDict.simple.word[0].usspeech}}" name="sound" size="30rpx" />
|
||||
<t-icon class="ipa-audio" wx:if="{{wordDict.simple.word[0].usspeech}}" bind:click="playWordAudio" data-type="us" data-audio="{{wordDict.simple.word[0].usspeech}}" name="{{(activeWordAudioType === 'us' && wordAudioPlaying) ? wordAudioIconName : 'sound'}}" size="30rpx" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- 基础词性释义 -->
|
||||
|
||||
Reference in New Issue
Block a user