This commit is contained in:
Felix
2025-11-05 22:12:02 +08:00
parent ebbaf04cfa
commit 6c5df5faf9
3 changed files with 368 additions and 248 deletions

View File

@@ -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 || ''
}
})
}
})

View File

@@ -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">

View File

@@ -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;