Files
miniprogram-1/miniprogram/pages/assessment/assessment.wxml
2025-11-25 20:40:05 +08:00

274 lines
16 KiB
Plaintext

<!-- assessment.wxml - 评估页面 -->
<view class="assessment-container">
<!-- 顶部图片区域 -->
<view class="image-section" bindtap="handleImagePreview">
<t-skeleton wx:if="{{!imagePath}}" class="assessment-image {{imageSmall ? 'small' : ''}}" theme="image" animation="gradient" loading="{{true}}"></t-skeleton>
<image wx:else class="assessment-image {{imageSmall ? 'small' : ''}}" src="{{imagePath}}" mode="{{imageMode}}" />
</view>
<!-- 中间例句区域 -->
<view class="sentence-section">
<view class="sentence-container">
<!-- 例句内容 -->
<view class="sentence-content">
<view class="sentence-wrapper {{selectedSentenceIndex === index ? 'selected' : ''}}" wx:for="{{processedSentences}}" wx:key="index" data-index="{{index}}" bindtap="handleSentenceSelect">
<view class="sentence-content-wrapper">
<view class="word-wrapper" wx:for="{{item.words}}" wx:for-item="word" wx:for-index="windex" wx:key="windex">
<span class="sentence-text" data-word="{{word}}" data-index="{{index}}" catchtap="handleWordClick">
{{word}}
</span>
<span wx:if="{{transDisplayMode === 'en_ipa' && item.ipas && item.ipas[windex]}}" class="sentence-ipa">
{{item.ipas[windex]}}
</span>
<span wx:else class="sentence-ipa"></span>
</view>
</view>
<view wx:if="{{transDisplayMode === 'en_zh'}}" class="word-zh">
<span>{{item.zh}}</span>
</view>
</view>
</view>
</view>
</view>
<!-- 底部按钮区域 -->
<view class="bottom-button-area">
<view wx:if="{{isMoreMenuOpen}}" class="more-menu-modal"></view>
<view class="button-row">
<t-icon name="{{isPlaying ? 'pause' : 'play'}}" class="bottom-button" size="48rpx" bind:tap="playStandardVoice" />
<view class="bottom-button-img-wrap bottom-button" bind:tap="onTransTap">
<t-icon name="translate" class="trans-button left-half {{transDisplayMode === 'en_ipa' ? 'trans-active' : 'trans-deactive'}}" size="48rpx" />
<t-icon name="translate" class="trans-button right-half {{transDisplayMode === 'en_zh' ? 'trans-active' : 'trans-deactive'}}" size="48rpx" />
</view>
<view class="bottom-button mic-wrap">
<t-icon name="microphone-1" color="{{isRecording ? '#FFFFFF' : '#333333'}}" class="microphone {{isRecording ? 'recording' : 'bottom-button'}}" size="48rpx" bind:longpress="handleRecordStart" bind:touchend="handleRecordEnd" bind:touchcancel="handleRecordEnd" />
<view wx:if="{{isRecording}}" class="mic">
<view class="mic-shadow"></view>
</view>
</view>
<t-icon name="fact-check" class="bottom-button {{hasScoreInfo ? '' : 'disabled'}}" size="48rpx" bind:tap="onScoreTap" />
<t-icon name="ellipsis" class="bottom-button {{isMoreMenuOpen ? 'more-open' : ''}}" size="48rpx" bind:tap="onMoreTap" />
</view>
</view>
<!-- 评分结果弹窗 -->
<view wx:if="{{isScoreModalOpen && hasScoreInfo}}">
<view class="score-modal-mask" bindtap="onCloseScoreModal"></view>
<view class="score-modal-content" catchtouchmove="true">
<view class="score-modal-header">
<view class="score-modal-title">
<!-- <span>口语评分结果</span> -->
</view>
<t-icon name="close" class="score-modal-close" size="40rpx" bind:tap="onCloseScoreModal" />
</view>
<view class="score-container">
<view class="score-image-container">
<t-icon wx:if="{{currentSentence && currentSentence.file_id}}" name="{{playIconName}}" class="score-modal-play" size="80rpx" bind:tap="playAssessmentVoice"></t-icon>
<!-- <image wx:if="{{currentSentence && currentSentence.file_id}}" src="{{playIconSrc}}" class="score-modal-play" bind:tap="playAssessmentVoice" mode="aspectFit" /> -->
<span class="score-text">{{currentSentence.content}}</span>
</view>
<view class="score-overview">
<view class="score-circles">
<view class="circle-item">
<view class="circle-progress" style="{{circleProgressStyle}}">
<canvas canvas-id="totalCircleCanvas" class="circle-canvas"></canvas>
<text class="total-score-value">{{totalScore}}</text>
<text class="total-score-label">总分</text>
</view>
</view>
<view class="circle-item">
<view class="circle-progress" style="{{accuracyCircleStyle}}">
<canvas canvas-id="accuracyCircleCanvas" class="circle-canvas"></canvas>
<text class="total-score-value">{{accuracyScore}}</text>
<text class="total-score-label">准确性</text>
</view>
</view>
<view class="circle-item">
<view class="circle-progress" style="{{completenessCircleStyle}}">
<canvas canvas-id="completenessCircleCanvas" class="circle-canvas"></canvas>
<text class="total-score-value">{{completenessScore}}</text>
<text class="total-score-label">完整性</text>
</view>
</view>
<view class="circle-item">
<view class="circle-progress" style="{{fluencyCircleStyle}}">
<canvas canvas-id="fluencyCircleCanvas" class="circle-canvas"></canvas>
<text class="total-score-value">{{fluencyScore}}</text>
<text class="total-score-label">流利度</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>
<!-- 单词评分列表 -->
<scroll-view scroll-y 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>
</scroll-view>
</view>
</view>
</view>
<!-- 单词查询展示区域 -->
<view class="word-popup {{showDictExtended ? 'expanded' : ''}}" wx:if="{{showDictPopup}}">
<!-- 弹窗头部:单词 + more 按钮 -->
<view class="popup-header">
<!-- 频率标签 -->
<view class="frequency-tags">
<t-tag wx:if="{{wordDict.ec.exam_type && wordDict.ec.exam_type.length > 0}}" wx:for="{{wordDict.ec.exam_type}}" wx:key="index" variant="light" theme="success">
{{item}}
</t-tag>
</view>
<view class="close-btn" bindtap="handleDictClose">
<t-icon name="close" size="36rpx" />
</view>
</view>
<view class="popup-header">
<text wx:if="{{wordDict.simple.query}}" class="word-title">{{wordDict.simple.query}}</text>
<text class="word-title" wx:if="{{prototypeWord}}">{{prototypeWord}}</text>
<view class="more-btn" bindtap="handleDictMore">
<text wx:if="{{!showDictExtended}}">More</text>
<!-- <text wx:if="{{!showDictExtended}}">Less</text> -->
<t-icon wx:if="{{!showDictExtended}}" name="chevron-up" size="48rpx"></t-icon>
<!-- <t-icon wx:else name="chevron-down" size="32rpx"></t-icon> -->
</view>
</view>
<!-- 发音区域 -->
<view class="pronounce">
<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].ukphone}}">
UK:[{{wordDict.simple.word[0].ukphone}}]
</span>
<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-type="us" data-audio="{{wordDict.simple.word[0].usspeech}}" name="{{(activeWordAudioType === 'us' && wordAudioPlaying) ? wordAudioIconName : 'sound'}}" size="30rpx" />
</view>
</view>
<!-- 基础词性释义 -->
<view class="word-meanings">
<block wx:if="{{wordDict.ec && wordDict.ec.word && wordDict.ec.word.length > 0}}">
<block wx:for="{{wordDict.ec.word[0].trs}}" wx:key="index">
<block wx:for="{{item.tr}}" wx:key="index">
<block wx:for="{{item.l.i}}" wx:key="index">
<text>{{item}}</text>
</block>
</block>
</block>
</block>
</view>
<!-- 扩展内容(默认隐藏,点击 more 后显示) -->
<t-tabs class="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.collins && wordDict.collins.collins_entries && wordDict.collins.collins_entries.length > 0 && wordDict.collins.collins_entries[0].entries && wordDict.collins.collins_entries[0].entries.entry}}">
<view class="dictionary">
<block wx:for="{{wordDict.collins.collins_entries[0].entries.entry}}" wx:key="index">
<block wx:if="{{item.tran_entry && item.tran_entry.length > 0}}">
<view class="dictionary-content" wx:for="{{item.tran_entry}}" wx:key="tindex">
<view class="dictionary-pos" wx:if="{{item.pos_entry && item.pos_entry.pos && item.pos_entry.pos_tips}}">
<t-tag variant="light" theme="primary">
{{item.pos_entry.pos}} {{item.pos_entry.pos_tips}}
</t-tag>
</view>
<view class="dictionary-tran" wx:if="{{item.tranParts && item.tranParts.length > 0}}">
<block wx:for="{{item.tranParts}}" wx:key="pindex">
<text wx:if="{{!item.bold}}" class="normal-text">{{item.text}}</text>
<text wx:if="{{item.bold}}" class="dictionary-tran-bold">{{item.text}}</text>
</block>
</view>
<view class="dictionary-tran" wx:elif="{{item.tran}}">{{item.tran}}</view>
<view class="dictionary-list" wx:if="{{item.exam_sents && item.exam_sents.sent && item.exam_sents.sent.length > 0}}">
<block wx:for="{{item.exam_sents.sent}}" wx:key="index">
<view class="word-sent-en" wx:if="{{item.eng_sent}}">{{item.eng_sent}}</view>
<view class="word-sent-zh" wx:if="{{item.chn_sent}}">{{item.chn_sent}}</view>
</block>
</view>
</view>
</block>
</block>
</view>
</t-tab-panel>
<t-tab-panel wx:if="{{wordDict.phrs && wordDict.phrs.phrs && wordDict.phrs.phrs.length > 0}}" label="短语" value="0">
<block wx:for="{{wordDict.phrs.phrs}}" wx:key="index">
<t-cell title="{{item.phr.headword.l.i}}" description="{{item.phr.trs[0].tr.l.i}}" />
</block>
</t-tab-panel>
<t-tab-panel wx:if="{{wordDict.individual && wordDict.individual.pastExamSents && wordDict.individual.pastExamSents.length > 0}}" label="真题" value="1">
<view wx:for="{{wordDict.individual.pastExamSents}}" wx:key="index" class="exam-sent">
<view class="exam-sent-en">{{item.en}}</view>
<view class="exam-sent-zh">{{item.zh}}</view>
<view class="exam-sent-source">--摘自《{{item.source}}》</view>
</view>
</t-tab-panel>
<t-tab-panel label="相关" value="2">
<view wx:if="{{(wordDict.syno && wordDict.syno.synos && wordDict.syno.synos.length > 0) || (wordDict.relWord && wordDict.relWord.rels && wordDict.relWord.rels.length > 0) || (wordDict.discriminate && wordDict.discriminate.data && wordDict.discriminate.data.length > 0)}}">
<view class="syno" wx:if="{{wordDict.syno && wordDict.syno.synos && wordDict.syno.synos.length > 0}}">
<view class="syno-title">同义词</view>
<view class="syno-list" wx:for="{{wordDict.syno.synos}}" wx:key="index">
<view class="syno-pos">
<t-tag wx:if="{{item.syno.pos}}" variant="light" theme="primary">
{{item.syno.pos}}
</t-tag>
<view class="syno-tran">{{item.syno.tran}}</view>
</view>
<t-tag class="syno-item" wx:for="{{item.syno.ws}}" wx:key="w" variant="light">
{{item.w}}
</t-tag>
</view>
</view>
<view class="rel-word" wx:if="{{wordDict.relWord && wordDict.relWord.rels && wordDict.relWord.rels.length > 0}}">
<view class="rel-word-title">相关单词</view>
<view class="rel-word-list" wx:for="{{wordDict.relWord.rels}}" wx:key="index">
<view class="rel-word-pos">{{item.rel.pos}}</view>
<view class="rel-word-item" wx:for="{{item.rel.words}}" wx:key="word">
<view class="rel-word-tran">{{item.tran}}</view>
<view class="rel-word-word">{{item.word}}</view>
</view>
</view>
</view>
<view class="discriminate" wx:if="{{wordDict.discriminate && wordDict.discriminate.data && wordDict.discriminate.data.length > 0}}">
<view class="discriminate-title">区分单词</view>
<view class="discriminate-list" wx:for="{{wordDict.discriminate.data}}" wx:key="index">
<view class="discriminate-item" wx:for="{{item.usages}}" wx:key="headword">
<view class="discriminate-tran">{{item.usage}}</view>
<view class="discriminate-headword">{{item.headword}}</view>
</view>
</view>
</view>
</view>
<view wx:else class="no-related-words">
<text class="no-related-words-text">暂无相关单词信息</text>
</view>
</t-tab-panel>
</t-tabs>
</view>
</view>