fix ui
This commit is contained in:
@@ -85,14 +85,22 @@ interface IPageData {
|
||||
}
|
||||
}
|
||||
prototypeWord: string
|
||||
// 添加处理后的单词和音标数组
|
||||
processedSentences: Array<{
|
||||
words: string[]
|
||||
ipas: string[]
|
||||
zh: string
|
||||
}>
|
||||
// 添加翻译显示模式状态
|
||||
transDisplayMode: 'en' | 'en_ipa' | 'en_zh' // 翻译显示模式
|
||||
}
|
||||
|
||||
type IPageMethods = {
|
||||
updateCircleProgress: () => void
|
||||
startRecording: () => void
|
||||
stopRecording: () => void
|
||||
prevSentence: () => void
|
||||
nextSentence: () => void
|
||||
// prevSentence: () => void
|
||||
// nextSentence: () => void
|
||||
handleRecordStart: () => void
|
||||
handleRecordEnd: () => void
|
||||
updateWordsAndIpas: (content: string, ipa: string) => void
|
||||
@@ -108,6 +116,13 @@ type IPageMethods = {
|
||||
playWordAudio: (e: any) => void
|
||||
onTabsChange: (event: any) => void
|
||||
onTabsClick: (event: any) => void
|
||||
onSearchTap: () => void
|
||||
onHistoryTap: () => void
|
||||
onTransTap: () => void
|
||||
// 新增方法:处理句子数据,分割单词和音标
|
||||
processSentences: (sentences: any[]) => Array<{ words: string[], ipas: string[], zh: string }>
|
||||
// 获取翻译按钮图标名称
|
||||
getTransIconName: () => string
|
||||
}
|
||||
|
||||
interface IPageInstance extends IPageMethods {
|
||||
@@ -162,8 +177,10 @@ Page<IPageData, IPageInstance>({
|
||||
audioDuration: 0, // 音频总时长
|
||||
currentTime: 0, // 当前播放时间
|
||||
sliderValue: 0, // 进度条值(0-100)
|
||||
showDictPopup: true, // 控制弹窗是否显示
|
||||
showDictExtended: false // 控制扩展内容是否显示
|
||||
showDictPopup: false, // 控制弹窗是否显示
|
||||
showDictExtended: false, // 控制扩展内容是否显示
|
||||
processedSentences: [], // 处理后的句子数据
|
||||
transDisplayMode: 'en' // 默认显示模式为英文 only
|
||||
},
|
||||
|
||||
// 切换评分区域展开状态
|
||||
@@ -210,106 +227,106 @@ Page<IPageData, IPageInstance>({
|
||||
},
|
||||
|
||||
// 切换到上一个例句
|
||||
prevSentence() {
|
||||
const { currentIndex, sentences } = this.data
|
||||
if (currentIndex <= 0) return;
|
||||
// prevSentence() {
|
||||
// const { currentIndex, sentences } = this.data
|
||||
// if (currentIndex <= 0) return;
|
||||
|
||||
// 重置音频播放状态
|
||||
this.resetAudioState()
|
||||
if (currentIndex > 0) {
|
||||
const currentSentence = sentences[currentIndex - 1]
|
||||
const assessmentResult = currentSentence?.details?.assessment?.result
|
||||
const suggestedScore = assessmentResult?.SuggestedScore
|
||||
const pronAccuracy = assessmentResult?.PronAccuracy
|
||||
const pronCompletion = assessmentResult?.PronCompletion
|
||||
const pronFluency = assessmentResult?.PronFluency
|
||||
// // 重置音频播放状态
|
||||
// this.resetAudioState()
|
||||
// if (currentIndex > 0) {
|
||||
// const currentSentence = sentences[currentIndex - 1]
|
||||
// const assessmentResult = currentSentence?.details?.assessment?.result
|
||||
// const suggestedScore = assessmentResult?.SuggestedScore
|
||||
// const pronAccuracy = assessmentResult?.PronAccuracy
|
||||
// const pronCompletion = assessmentResult?.PronCompletion
|
||||
// const pronFluency = assessmentResult?.PronFluency
|
||||
|
||||
// 检查是否所有评分都为负数
|
||||
const allNegative = [suggestedScore, pronAccuracy, pronCompletion, pronFluency].every(score => score < 0)
|
||||
// // 检查是否所有评分都为负数
|
||||
// const allNegative = [suggestedScore, pronAccuracy, pronCompletion, pronFluency].every(score => score < 0)
|
||||
|
||||
// 处理单词评分数据
|
||||
const wordScores = assessmentResult?.Words?.map((word: any) => ({
|
||||
word: word.Word,
|
||||
pronAccuracy: Number(word.PronAccuracy.toFixed(2)),
|
||||
pronFluency: Number(word.PronFluency.toFixed(2)),
|
||||
matchTag: word.MatchTag || 0,
|
||||
phoneInfos: word.PhoneInfos?.map((phone: any) => ({
|
||||
phone: phone.Phone,
|
||||
pronAccuracy: Number(phone.PronAccuracy.toFixed(2)),
|
||||
matchTag: phone.MatchTag || 0
|
||||
})) || []
|
||||
})) || []
|
||||
// // 处理单词评分数据
|
||||
// const wordScores = assessmentResult?.Words?.map((word: any) => ({
|
||||
// word: word.Word,
|
||||
// pronAccuracy: Number(word.PronAccuracy.toFixed(2)),
|
||||
// pronFluency: Number(word.PronFluency.toFixed(2)),
|
||||
// matchTag: word.MatchTag || 0,
|
||||
// phoneInfos: word.PhoneInfos?.map((phone: any) => ({
|
||||
// phone: phone.Phone,
|
||||
// pronAccuracy: Number(phone.PronAccuracy.toFixed(2)),
|
||||
// matchTag: phone.MatchTag || 0
|
||||
// })) || []
|
||||
// })) || []
|
||||
|
||||
this.setData({
|
||||
currentIndex: currentIndex - 1,
|
||||
currentSentence: currentSentence,
|
||||
hasScoreInfo: !allNegative && !!currentSentence.details,
|
||||
totalScore: suggestedScore >= 0 ? Number(suggestedScore.toFixed(2)) : 0,
|
||||
accuracyScore: pronAccuracy >= 0 ? Number(pronAccuracy.toFixed(2)) : 0,
|
||||
completenessScore: pronCompletion >= 0 ? Number((pronCompletion * 100).toFixed(2)) : 0,
|
||||
fluencyScore: pronFluency >= 0 ? Number((pronFluency * 100).toFixed(2)) : 0,
|
||||
wordScores
|
||||
})
|
||||
this.updateWordsAndIpas(currentSentence.content, currentSentence.ipa)
|
||||
// 获取当前例句的标准语音
|
||||
if (currentSentence.id) {
|
||||
this.getStandardVoice(currentSentence.id)
|
||||
}
|
||||
this.updateCircleProgress()
|
||||
// this.setData({
|
||||
// currentIndex: currentIndex - 1,
|
||||
// currentSentence: currentSentence,
|
||||
// hasScoreInfo: !allNegative && !!currentSentence.details,
|
||||
// totalScore: suggestedScore >= 0 ? Number(suggestedScore.toFixed(2)) : 0,
|
||||
// accuracyScore: pronAccuracy >= 0 ? Number(pronAccuracy.toFixed(2)) : 0,
|
||||
// completenessScore: pronCompletion >= 0 ? Number((pronCompletion * 100).toFixed(2)) : 0,
|
||||
// fluencyScore: pronFluency >= 0 ? Number((pronFluency * 100).toFixed(2)) : 0,
|
||||
// wordScores
|
||||
// })
|
||||
// this.updateWordsAndIpas(currentSentence.content, currentSentence.ipa)
|
||||
// // 获取当前例句的标准语音
|
||||
// if (currentSentence.id) {
|
||||
// this.getStandardVoice(currentSentence.id)
|
||||
// }
|
||||
// this.updateCircleProgress()
|
||||
|
||||
}
|
||||
},
|
||||
// }
|
||||
// },
|
||||
|
||||
// 切换到下一个例句
|
||||
nextSentence() {
|
||||
const { currentIndex, sentences } = this.data
|
||||
if (currentIndex >= sentences.length - 1) return;
|
||||
// nextSentence() {
|
||||
// const { currentIndex, sentences } = this.data
|
||||
// if (currentIndex >= sentences.length - 1) return;
|
||||
|
||||
// 重置音频播放状态
|
||||
this.resetAudioState()
|
||||
if (currentIndex < sentences.length - 1) {
|
||||
const index = currentIndex + 1
|
||||
const currentSentence = sentences[index]
|
||||
const assessmentResult = currentSentence?.details?.assessment?.result
|
||||
const suggestedScore = assessmentResult?.SuggestedScore
|
||||
const pronAccuracy = assessmentResult?.PronAccuracy
|
||||
const pronCompletion = assessmentResult?.PronCompletion
|
||||
const pronFluency = assessmentResult?.PronFluency
|
||||
// // 重置音频播放状态
|
||||
// this.resetAudioState()
|
||||
// if (currentIndex < sentences.length - 1) {
|
||||
// const index = currentIndex + 1
|
||||
// const currentSentence = sentences[index]
|
||||
// const assessmentResult = currentSentence?.details?.assessment?.result
|
||||
// const suggestedScore = assessmentResult?.SuggestedScore
|
||||
// const pronAccuracy = assessmentResult?.PronAccuracy
|
||||
// const pronCompletion = assessmentResult?.PronCompletion
|
||||
// const pronFluency = assessmentResult?.PronFluency
|
||||
|
||||
// 检查是否所有评分都为负数
|
||||
const allNegative = [suggestedScore, pronAccuracy, pronCompletion, pronFluency].every(score => score < 0)
|
||||
// // 检查是否所有评分都为负数
|
||||
// const allNegative = [suggestedScore, pronAccuracy, pronCompletion, pronFluency].every(score => score < 0)
|
||||
|
||||
// 处理单词评分数据
|
||||
const wordScores = assessmentResult?.Words?.map((word: any) => ({
|
||||
word: word.Word,
|
||||
pronAccuracy: Number(word.PronAccuracy.toFixed(2)),
|
||||
pronFluency: Number(word.PronFluency.toFixed(2)),
|
||||
matchTag: word.MatchTag || 0,
|
||||
phoneInfos: word.PhoneInfos?.map((phone: any) => ({
|
||||
phone: phone.Phone,
|
||||
pronAccuracy: Number(phone.PronAccuracy.toFixed(2)),
|
||||
matchTag: phone.MatchTag || 0
|
||||
})) || []
|
||||
})) || []
|
||||
// // 处理单词评分数据
|
||||
// const wordScores = assessmentResult?.Words?.map((word: any) => ({
|
||||
// word: word.Word,
|
||||
// pronAccuracy: Number(word.PronAccuracy.toFixed(2)),
|
||||
// pronFluency: Number(word.PronFluency.toFixed(2)),
|
||||
// matchTag: word.MatchTag || 0,
|
||||
// phoneInfos: word.PhoneInfos?.map((phone: any) => ({
|
||||
// phone: phone.Phone,
|
||||
// pronAccuracy: Number(phone.PronAccuracy.toFixed(2)),
|
||||
// matchTag: phone.MatchTag || 0
|
||||
// })) || []
|
||||
// })) || []
|
||||
|
||||
this.setData({
|
||||
currentIndex: index,
|
||||
currentSentence: currentSentence,
|
||||
hasScoreInfo: !allNegative && !!currentSentence.details,
|
||||
totalScore: suggestedScore >= 0 ? Number(suggestedScore.toFixed(2)) : 0,
|
||||
accuracyScore: pronAccuracy >= 0 ? Number(pronAccuracy.toFixed(2)) : 0,
|
||||
completenessScore: pronCompletion >= 0 ? Number((pronCompletion * 100).toFixed(2)) : 0,
|
||||
fluencyScore: pronFluency >= 0 ? Number((pronFluency * 100).toFixed(2)) : 0,
|
||||
wordScores
|
||||
})
|
||||
this.updateWordsAndIpas(currentSentence.content, currentSentence.ipa)
|
||||
// 获取当前例句的标准语音
|
||||
if (currentSentence.id) {
|
||||
this.getStandardVoice(currentSentence.id)
|
||||
}
|
||||
this.updateCircleProgress()
|
||||
}
|
||||
},
|
||||
// this.setData({
|
||||
// currentIndex: index,
|
||||
// currentSentence: currentSentence,
|
||||
// hasScoreInfo: !allNegative && !!currentSentence.details,
|
||||
// totalScore: suggestedScore >= 0 ? Number(suggestedScore.toFixed(2)) : 0,
|
||||
// accuracyScore: pronAccuracy >= 0 ? Number(pronAccuracy.toFixed(2)) : 0,
|
||||
// completenessScore: pronCompletion >= 0 ? Number((pronCompletion * 100).toFixed(2)) : 0,
|
||||
// fluencyScore: pronFluency >= 0 ? Number((pronFluency * 100).toFixed(2)) : 0,
|
||||
// wordScores
|
||||
// })
|
||||
// this.updateWordsAndIpas(currentSentence.content, currentSentence.ipa)
|
||||
// // 获取当前例句的标准语音
|
||||
// if (currentSentence.id) {
|
||||
// this.getStandardVoice(currentSentence.id)
|
||||
// }
|
||||
// this.updateCircleProgress()
|
||||
// }
|
||||
// },
|
||||
|
||||
// 开始录音
|
||||
startRecording() {
|
||||
@@ -573,8 +590,10 @@ Page<IPageData, IPageInstance>({
|
||||
const { word } = e.currentTarget.dataset
|
||||
if (!word) return
|
||||
|
||||
const cleanedWord = word.replace(/[.,?!*]/g, '')
|
||||
// 清理单词,移除标点符号
|
||||
const cleanedWord = word.replace(/[.,?!*;:]/g, '').trim()
|
||||
if (!cleanedWord) return
|
||||
|
||||
try {
|
||||
// 调用API获取单词详情
|
||||
const wordDetail: any = await apiManager.getWordDetail(cleanedWord)
|
||||
@@ -600,61 +619,6 @@ Page<IPageData, IPageInstance>({
|
||||
}
|
||||
},
|
||||
|
||||
// 点击“more”按钮,展开/收起扩展内容
|
||||
handleDictMore() {
|
||||
this.setData({
|
||||
showDictExtended: !this.data.showDictExtended
|
||||
})
|
||||
},
|
||||
|
||||
// 点击“x”按钮,关闭弹窗
|
||||
handleDictClose() {
|
||||
this.setData({
|
||||
showDictPopup: false
|
||||
})
|
||||
},
|
||||
|
||||
onTabsChange(event: any) {
|
||||
console.log(`Change tab, tab-panel value is ${event.detail.value}.`);
|
||||
},
|
||||
|
||||
onTabsClick(event: any) {
|
||||
console.log(`Click tab, tab-panel value is ${event.detail.value}.`);
|
||||
},
|
||||
|
||||
// 播放单词音频
|
||||
playWordAudio(e: any) {
|
||||
const { audio } = e.currentTarget.dataset
|
||||
if (!audio) return
|
||||
|
||||
// 构造音频URL
|
||||
const audioUrl = `https://dict.youdao.com/dictvoice?audio=${audio}`
|
||||
|
||||
// 创建音频上下文
|
||||
const wordAudioContext = wx.createInnerAudioContext()
|
||||
|
||||
wordAudioContext.onPlay(() => {
|
||||
console.log('开始播放单词音频')
|
||||
})
|
||||
|
||||
wordAudioContext.onError((res) => {
|
||||
console.error('播放单词音频失败:', res)
|
||||
wx.showToast({
|
||||
title: '播放失败',
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
wordAudioContext.onEnded(() => {
|
||||
console.log('单词音频播放结束')
|
||||
wordAudioContext.destroy()
|
||||
})
|
||||
|
||||
// 设置音频源并播放
|
||||
wordAudioContext.src = audioUrl
|
||||
wordAudioContext.play()
|
||||
},
|
||||
|
||||
onLoad(options: Record<string, string>) {
|
||||
//如果有图片ID,调用接口获取文本和评分信息
|
||||
if (options.index) {
|
||||
@@ -671,6 +635,8 @@ Page<IPageData, IPageInstance>({
|
||||
// 更新例句和评分信息
|
||||
if (res.assessments && res.assessments.length > 0) {
|
||||
const sentences = res.assessments
|
||||
// 处理句子数据
|
||||
const processedSentences = this.processSentences(sentences)
|
||||
const index = this.data.currentIndex || 0
|
||||
const currentSentence = sentences[index]
|
||||
const assessmentResult = currentSentence?.details?.assessment?.result
|
||||
@@ -697,6 +663,7 @@ Page<IPageData, IPageInstance>({
|
||||
|
||||
this.setData({
|
||||
sentences,
|
||||
processedSentences,
|
||||
currentSentence,
|
||||
currentIndex: index,
|
||||
hasScoreInfo: !allNegative && !!currentSentence.details,
|
||||
@@ -706,7 +673,7 @@ Page<IPageData, IPageInstance>({
|
||||
fluencyScore: pronFluency >= 0 ? Number((pronFluency * 100).toFixed(2)) : 0,
|
||||
wordScores
|
||||
})
|
||||
this.updateWordsAndIpas(currentSentence.content, currentSentence.ipa)
|
||||
// this.updateWordsAndIpas(currentSentence.content, currentSentence.ipa)
|
||||
// 获取当前例句的标准语音
|
||||
if (currentSentence.id) {
|
||||
this.getStandardVoice(currentSentence.id)
|
||||
@@ -826,5 +793,135 @@ Page<IPageData, IPageInstance>({
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 点击“more”按钮,展开/收起扩展内容
|
||||
handleDictMore() {
|
||||
this.setData({
|
||||
showDictExtended: !this.data.showDictExtended
|
||||
})
|
||||
},
|
||||
|
||||
// 点击“x”按钮,关闭弹窗
|
||||
handleDictClose() {
|
||||
this.setData({
|
||||
showDictPopup: false
|
||||
})
|
||||
},
|
||||
|
||||
onTabsChange(event: any) {
|
||||
console.log(`Change tab, tab-panel value is ${event.detail.value}.`);
|
||||
},
|
||||
|
||||
onTabsClick(event: any) {
|
||||
console.log(`Click tab, tab-panel value is ${event.detail.value}.`);
|
||||
},
|
||||
|
||||
// 播放单词音频
|
||||
playWordAudio(e: any) {
|
||||
const { audio } = e.currentTarget.dataset
|
||||
if (!audio) return
|
||||
|
||||
// 构造音频URL
|
||||
const audioUrl = `https://dict.youdao.com/dictvoice?audio=${audio}`
|
||||
|
||||
// 创建音频上下文
|
||||
const wordAudioContext = wx.createInnerAudioContext()
|
||||
|
||||
wordAudioContext.onPlay(() => {
|
||||
console.log('开始播放单词音频')
|
||||
})
|
||||
|
||||
wordAudioContext.onError((res) => {
|
||||
console.error('播放单词音频失败:', res)
|
||||
wx.showToast({
|
||||
title: '播放失败',
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
wordAudioContext.onEnded(() => {
|
||||
console.log('单词音频播放结束')
|
||||
wordAudioContext.destroy()
|
||||
})
|
||||
|
||||
// 设置音频源并播放
|
||||
wordAudioContext.src = audioUrl
|
||||
wordAudioContext.play()
|
||||
},
|
||||
|
||||
onSearchTap() {
|
||||
console.log('Search button tapped')
|
||||
// Navigate to search page or show search modal
|
||||
},
|
||||
|
||||
onHistoryTap() {
|
||||
console.log('History button tapped')
|
||||
// Navigate to history page
|
||||
},
|
||||
|
||||
onTransTap() {
|
||||
console.log('User button tapped')
|
||||
// Cycle through translation display modes
|
||||
const currentMode = this.data.transDisplayMode
|
||||
let nextMode: 'en' | 'en_ipa' | 'en_zh' = 'en'
|
||||
|
||||
switch (currentMode) {
|
||||
case 'en':
|
||||
nextMode = 'en_ipa'
|
||||
break
|
||||
case 'en_ipa':
|
||||
nextMode = 'en_zh'
|
||||
break
|
||||
case 'en_zh':
|
||||
nextMode = 'en'
|
||||
break
|
||||
default:
|
||||
nextMode = 'en'
|
||||
}
|
||||
|
||||
this.setData({
|
||||
transDisplayMode: nextMode
|
||||
})
|
||||
},
|
||||
|
||||
// 获取翻译按钮图标名称
|
||||
getTransIconName() {
|
||||
switch (this.data.transDisplayMode) {
|
||||
case 'en':
|
||||
return 'file-teams'
|
||||
case 'en_ipa':
|
||||
return 'file-search'
|
||||
case 'en_zh':
|
||||
return 'translate'
|
||||
default:
|
||||
return 'file-teams'
|
||||
}
|
||||
},
|
||||
|
||||
// 处理句子数据,分割单词和音标
|
||||
processSentences(sentences: any[]) {
|
||||
return sentences.map(sentence => {
|
||||
// 分割内容和音标
|
||||
const words = sentence.content ? sentence.content.split(' ') : []
|
||||
const ipas = sentence.ipa ? sentence.ipa.split(' ') : []
|
||||
|
||||
// 处理标点符号,确保单词末尾的标点符号保留在正确位置
|
||||
const processedWords = words.map((word: string, index: number) => {
|
||||
// 如果是最后一个单词,保留可能的句号或逗号
|
||||
if (index === words.length - 1) {
|
||||
// 保留句末标点符号
|
||||
return word
|
||||
}
|
||||
// 对于其他单词,移除常见的标点符号
|
||||
return word.replace(/[.,;:!?]/g, '')
|
||||
})
|
||||
|
||||
return {
|
||||
words: processedWords,
|
||||
ipas,
|
||||
zh: sentence.zh || ''
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -7,37 +7,30 @@
|
||||
<!-- 中间例句区域 -->
|
||||
<view class="sentence-section">
|
||||
<view class="sentence-container">
|
||||
<!-- 左箭头 -->
|
||||
<view class="arrow-btn left {{currentIndex <= 0 ? 'disabled' : ''}}" bindtap="prevSentence">
|
||||
<t-icon name="chevron-left" size="48rpx" color="#fef6e4" />
|
||||
</view>
|
||||
<!-- 例句内容 -->
|
||||
<view class="sentence-content">
|
||||
<view class="sentence-wrapper">
|
||||
<view class="sentence-wrapper" wx:for="{{processedSentences}}" wx:key="index">
|
||||
<view class="sentence-content-wrapper">
|
||||
<view class="word-wrapper" wx:for="{{words}}" wx:key="index">
|
||||
<text class="sentence-text" data-word="{{item}}" bindtap="handleWordClick">
|
||||
{{item}}
|
||||
<view class="word-wrapper" wx:for="{{item.words}}" wx:for-item="word" wx:for-index="windex" wx:key="windex">
|
||||
<text class="sentence-text" data-word="{{word}}" bindtap="handleWordClick">
|
||||
{{word}}
|
||||
</text>
|
||||
<text wx:if="{{ipas[index] && ipas[index] !== '*'}}" class="sentence-ipa">
|
||||
{{ipas[index]}}
|
||||
<text wx:if="{{transDisplayMode === 'en_ipa' && item.ipas && item.ipas[windex]}}" class="sentence-ipa">
|
||||
{{item.ipas[windex]}}
|
||||
</text>
|
||||
<text wx:else class="sentence-ipa"></text>
|
||||
</view>
|
||||
<view wx:if="{{transDisplayMode === 'en_zh'}}" class="word-zh">
|
||||
<text>{{item.zh}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<text class="page-indicator">{{currentIndex + 1}}/{{sentences.length}}</text>
|
||||
</view>
|
||||
<!-- 右箭头 -->
|
||||
<view class="arrow-btn right {{currentIndex >= sentences.length - 1 ? 'disabled' : ''}}" bindtap="nextSentence">
|
||||
<t-icon name="chevron-right" size="48rpx" color="#fef6e4" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- 话筒图标和倒计时 -->
|
||||
<view class="microphone-container">
|
||||
<!-- <view class="microphone-container">
|
||||
<t-icon name="microphone-1" class="microphone {{isRecording ? 'recording' : ''}}" size="80rpx" bind:longpress="handleRecordStart" bind:touchend="handleRecordEnd" bind:touchcancel="handleRecordEnd" />
|
||||
<text wx:if="{{isRecording}}" class="countdown">{{remainingTime}}s</text>
|
||||
<!-- 音频播放控制区域 -->
|
||||
<view class="audio-control">
|
||||
<view class="audio-title">标准音频</view>
|
||||
<view class="audio-player">
|
||||
@@ -47,99 +40,104 @@
|
||||
<t-slider class="progress-slider" value="{{sliderValue}}" bind:change="handleSliderChange" theme="primary" max="100" step="1" />
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
<!-- 底部按钮区域 -->
|
||||
<view class="bottom-button-area">
|
||||
<view class="button-row">
|
||||
<t-icon name="{{isPlaying ? 'pause' : 'play'}}" class="bottom-button" size="48rpx" bind:tap="playStandardVoice" />
|
||||
<t-icon name="play-circle-stroke-add" class="bottom-button" size="48rpx" bind:tap="onSearchTap" />
|
||||
<t-icon name="microphone-1" class="microphone {{isRecording ? 'recording' : ''}}" size="48rpx" bind:longpress="handleRecordStart" bind:touchend="handleRecordEnd" bind:touchcancel="handleRecordEnd" />
|
||||
<t-icon name="file-search" class="bottom-button" size="48rpx" bind:tap="onHistoryTap" />
|
||||
<t-icon name="{{transDisplayMode === 'en' ? 'file-teams' : transDisplayMode === 'en_ipa' ? 'file-search' : 'translate'}}" class="bottom-button" size="48rpx" bind:tap="onTransTap" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- 底部评分结果区域 -->
|
||||
<view class="score-section {{isScoreExpanded ? 'expanded' : ''}}" bindtap="toggleScoreSection">
|
||||
<block wx:if="{{hasScoreInfo}}">
|
||||
<view class="score-container">
|
||||
<view class="score-overview">
|
||||
<view class="total-score">
|
||||
<view class="circle-progress" style="{{circleProgressStyle}}">
|
||||
<text class="total-score-value">{{totalScore}}</text>
|
||||
<text class="total-score-label">总分</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="score-details">
|
||||
<view class="score-item">
|
||||
<text class="score-label">准确性</text>
|
||||
<view class="score-content">
|
||||
<block wx:if="{{accuracyScore >= 0}}">
|
||||
<view class="progress-bar">
|
||||
<view class="progress-fill" style="width: {{accuracyScore}}%"></view>
|
||||
</view>
|
||||
<text class="score-value">{{accuracyScore}}</text>
|
||||
</block>
|
||||
<text wx:else class="no-score-text">暂无评分</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="score-item">
|
||||
<text class="score-label">完整性</text>
|
||||
<view class="score-content">
|
||||
<block wx:if="{{completenessScore >= 0}}">
|
||||
<view class="progress-bar">
|
||||
<view class="progress-fill" style="width: {{completenessScore}}%"></view>
|
||||
</view>
|
||||
<text class="score-value">{{completenessScore}}</text>
|
||||
</block>
|
||||
<text wx:else class="no-score-text">暂无评分</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="score-item">
|
||||
<text class="score-label">流利度</text>
|
||||
<view class="score-content">
|
||||
<block wx:if="{{fluencyScore >= 0}}">
|
||||
<view class="progress-bar">
|
||||
<view class="progress-fill" style="width: {{fluencyScore}}%"></view>
|
||||
</view>
|
||||
<text class="score-value">{{fluencyScore}}</text>
|
||||
</block>
|
||||
<text wx:else class="no-score-text">暂无评分</text>
|
||||
</view>
|
||||
</view>
|
||||
<view wx:if="{{hasScoreInfo}}" class="score-section {{isScoreExpanded ? 'expanded' : ''}}" bindtap="toggleScoreSection">
|
||||
<view class="score-container">
|
||||
<view class="score-overview">
|
||||
<view class="total-score">
|
||||
<view class="circle-progress" style="{{circleProgressStyle}}">
|
||||
<text class="total-score-value">{{totalScore}}</text>
|
||||
<text class="total-score-label">总分</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- MatchTag 说明 -->
|
||||
<view class="match-tag-legend">
|
||||
<view class="legend-header">
|
||||
<text class="legend-title">匹配说明:</text>
|
||||
<view class="legend-items">
|
||||
<view class="legend-item" wx:for="{{matchTagLegend}}" wx:key="tag">
|
||||
<view class="color-box" style="background-color: {{item.color}}"></view>
|
||||
<text class="legend-text">{{item.description}}</text>
|
||||
</view>
|
||||
<view class="score-details">
|
||||
<view class="score-item">
|
||||
<text class="score-label">准确性</text>
|
||||
<view class="score-content">
|
||||
<block wx:if="{{accuracyScore >= 0}}">
|
||||
<view class="progress-bar">
|
||||
<view class="progress-fill" style="width: {{accuracyScore}}%"></view>
|
||||
</view>
|
||||
<text class="score-value">{{accuracyScore}}</text>
|
||||
</block>
|
||||
<text wx:else class="no-score-text">暂无评分</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 单词评分列表 -->
|
||||
<view class="word-scores-list">
|
||||
<view class="word-score-item" wx:for="{{wordScores}}" wx:key="word" style="background-color: {{matchTagLegend[item.matchTag || 0].color}}">
|
||||
<view class="word-header">
|
||||
<text class="word-text">{{item.word}}</text>
|
||||
<view class="word-score-details">
|
||||
<view class="word-score-row">
|
||||
<text class="word-score-label">准确性</text>
|
||||
<text class="word-score-value">{{item.pronAccuracy}}</text>
|
||||
<view class="score-item">
|
||||
<text class="score-label">完整性</text>
|
||||
<view class="score-content">
|
||||
<block wx:if="{{completenessScore >= 0}}">
|
||||
<view class="progress-bar">
|
||||
<view class="progress-fill" style="width: {{completenessScore}}%"></view>
|
||||
</view>
|
||||
<view class="word-score-row">
|
||||
<text class="word-score-label">流利度</text>
|
||||
<text class="word-score-value">{{item.pronFluency}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="score-value">{{completenessScore}}</text>
|
||||
</block>
|
||||
<text wx:else class="no-score-text">暂无评分</text>
|
||||
</view>
|
||||
<!-- 音标信息 -->
|
||||
<view class="phone-infos" wx:if="{{item.phoneInfos && item.phoneInfos.length > 0}}">
|
||||
<view class="phone-info-item" wx:for="{{item.phoneInfos}}" wx:for-item="phoneInfo" wx:key="phone" style="background-color: {{matchTagLegend[phoneInfo.matchTag || 0].color}}">
|
||||
<text class="phone-text">[{{phoneInfo.phone}}]</text>
|
||||
<text class="phone-score">{{phoneInfo.pronAccuracy}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="score-item">
|
||||
<text class="score-label">流利度</text>
|
||||
<view class="score-content">
|
||||
<block wx:if="{{fluencyScore >= 0}}">
|
||||
<view class="progress-bar">
|
||||
<view class="progress-fill" style="width: {{fluencyScore}}%"></view>
|
||||
</view>
|
||||
<text class="score-value">{{fluencyScore}}</text>
|
||||
</block>
|
||||
<text wx:else class="no-score-text">暂无评分</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- MatchTag 说明 -->
|
||||
<view class="match-tag-legend">
|
||||
<view class="legend-header">
|
||||
<text class="legend-title">匹配说明:</text>
|
||||
<view class="legend-items">
|
||||
<view class="legend-item" wx:for="{{matchTagLegend}}" wx:key="tag">
|
||||
<view class="color-box" style="background-color: {{item.color}}"></view>
|
||||
<text class="legend-text">{{item.description}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 单词评分列表 -->
|
||||
<view class="word-scores-list">
|
||||
<view class="word-score-item" wx:for="{{wordScores}}" wx:key="word" style="background-color: {{matchTagLegend[item.matchTag || 0].color}}">
|
||||
<view class="word-header">
|
||||
<text class="word-text">{{item.word}}</text>
|
||||
<view class="word-score-details">
|
||||
<view class="word-score-row">
|
||||
<text class="word-score-label">准确性</text>
|
||||
<text class="word-score-value">{{item.pronAccuracy}}</text>
|
||||
</view>
|
||||
<view class="word-score-row">
|
||||
<text class="word-score-label">流利度</text>
|
||||
<text class="word-score-value">{{item.pronFluency}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 音标信息 -->
|
||||
<view class="phone-infos" wx:if="{{item.phoneInfos && item.phoneInfos.length > 0}}">
|
||||
<view class="phone-info-item" wx:for="{{item.phoneInfos}}" wx:for-item="phoneInfo" wx:key="phone" style="background-color: {{matchTagLegend[phoneInfo.matchTag || 0].color}}">
|
||||
<text class="phone-text">[{{phoneInfo.phone}}]</text>
|
||||
<text class="phone-score">{{phoneInfo.pronAccuracy}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view wx:else class="no-score">
|
||||
<text class="no-score-text">暂无评分</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 单词查询展示区域 -->
|
||||
@@ -194,7 +192,7 @@
|
||||
</block>
|
||||
</view>
|
||||
<!-- 扩展内容(默认隐藏,点击 more 后显示) -->
|
||||
<t-tabs animation="{{ { duration: 0.1 } }}" defaultValue="{{0}}" bind:change="onTabsChange" bind:click="onTabsClick" wx:if="{{showDictExtended}}">
|
||||
<t-tabs animation="{{ { duration: 0.1 } }}" defaultValue="{{3}}" bind:change="onTabsChange" bind:click="onTabsClick" wx:if="{{showDictExtended}}">
|
||||
<t-tab-panel label="词典" value="3" wx:if="{{wordDict.ee && wordDict.ee.word && wordDict.ee.word.trs && wordDict.ee.word.trs.length > 0}}">
|
||||
<view class="dictionary">
|
||||
<view class="dictionary-content" wx:for="{{wordDict.ee.word.trs}}" wx:key="index">
|
||||
|
||||
@@ -849,6 +849,31 @@
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 底部按钮区域 */
|
||||
.bottom-button-area {
|
||||
padding: 20rpx 0;
|
||||
background: #ffffff;
|
||||
border-top: 1rpx solid #e0e0e0;
|
||||
}
|
||||
|
||||
.button-row {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bottom-button {
|
||||
padding: 20rpx;
|
||||
border-radius: 50%;
|
||||
background: #f5f5f5;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.bottom-button:active {
|
||||
background: #e0e0e0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 词典样式 */
|
||||
.dictionary {
|
||||
padding: 20rpx;
|
||||
|
||||
Reference in New Issue
Block a user