201 lines
10 KiB
Plaintext
201 lines
10 KiB
Plaintext
<view class="qa-exercise-container">
|
|
<view wx:if="{{!contentReady}}" class="page-loading-mask">
|
|
<view class="loading-center">
|
|
<view class="scanner scanner-visible">
|
|
<view class="star star1"></view>
|
|
<view class="star star2"></view>
|
|
<view class="star star3"></view>
|
|
</view>
|
|
<view class="status-text">{{statusText}}</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="container {{contentVisible ? 'fade-in' : 'fade-out'}}" wx:if="{{contentReady}}">
|
|
<view class="process-container" wx:if="{{qaList && qaList.length > 0}}">
|
|
<block wx:for="{{qaList}}" wx:key="index">
|
|
<view class="process-dot {{processDotClasses[index]}} {{index === currentIndex ? 'current' : ''}}"></view>
|
|
</block>
|
|
</view>
|
|
<view class="image-card">
|
|
<image wx:if="{{imageLocalUrl}}" class="image" src="{{imageLocalUrl}}" mode="aspectFill" bindtap="previewImage" bindload="onImageLoad" binderror="onImageError"></image>
|
|
<view class="view-full" wx:if="{{imageLocalUrl}}" bindtap="previewImage">
|
|
<t-icon name="zoom-in" size="32rpx" />
|
|
<!-- <text>View Full</text> -->
|
|
</view>
|
|
</view>
|
|
<view class="question-title">
|
|
<text wx:for="{{questionWords}}" wx:key="index" class="word-item" data-word="{{item}}" bindtap="handleWordClick">{{item}}</text>
|
|
</view>
|
|
<!-- <view class="progress-text">{{progressText}}</view> -->
|
|
<scroll-view class="question-scroll" scroll-y="true">
|
|
<view class="question-content {{modeAnim}}" wx:if="{{questionMode === 'choice'}}">
|
|
<view class="choice-title">Select the correct answer ({{selectedCount}}/{{choiceRequiredCount}})</view>
|
|
<view class="option-list">
|
|
<view wx:for="{{choiceOptions}}" wx:key="index" class="option-item {{evalClasses[index]}} {{(!choiceSubmitted && !selectedFlags[index] && selectedCount >= choiceRequiredCount) ? 'disabled' : ''}} {{resultDisplayed ? 'disabled' : ''}}" data-index="{{index}}" data-word="{{item.content}}" bindtap="selectOption" bindlongpress="onOptionLongPress">
|
|
<view class="option-radio">
|
|
<view class="radio-dot {{selectedFlags[index] ? 'on' : ''}} {{(evalClasses[index] === 'opt-incorrect' && selectedFlags[index]) ? 'red' : ''}}"></view>
|
|
</view>
|
|
<text class="option-text">{{item.content}}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="question-content {{modeAnim}}" wx:if="{{questionMode === 'cloze'}}">
|
|
<view class="choice-title">Select the correct word to complete the sentence:</view>
|
|
<view class="cloze-sentence">
|
|
<text class="cloze-text">{{clozeParts[0]}}</text>
|
|
<text class="cloze-fill">_____</text>
|
|
<text class="cloze-text">{{clozeParts[1]}}</text>
|
|
</view>
|
|
<view class="option-list">
|
|
<view wx:for="{{clozeOptions}}" wx:key="index" class="option-item {{evalClasses[index]}} {{resultDisplayed ? 'disabled' : ''}}" data-index="{{index}}" data-word="{{item}}" bindtap="selectClozeOption" bindlongpress="onOptionLongPress">
|
|
<view class="option-radio">
|
|
<view class="radio-dot {{selectedClozeIndex === index ? 'on' : ''}} {{(evalClasses[index] === 'opt-incorrect' && selectedClozeIndex === index) ? 'red' : ''}}"></view>
|
|
</view>
|
|
<text class="option-text">{{item}}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="question-content {{modeAnim}}" wx:if="{{questionMode === 'free_text'}}">
|
|
<view class="tip-row">
|
|
<t-icon name="info-circle" size="32rpx" />
|
|
<text class="tip-text">Tip: Be specific about the object type.</text>
|
|
</view>
|
|
<view class="answer-row">
|
|
<text class="answer-label">Your Answer</text>
|
|
<text class="answer-hint" bindtap="onHintTap">Need a hint?</text>
|
|
</view>
|
|
<view class="input-card">
|
|
<textarea class="answer-input" placeholder="Type your answer here..." maxlength="200" bindinput="inputChange" value="{{freeTextInput}}" />
|
|
<text class="input-type">English input</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="submit-row">
|
|
<button class="submit-btn" bindtap="onSubmitTap" disabled="{{submitDisabled}}" wx:if="{{retryDisabled}}">提交</button>
|
|
<button class="submit-btn" bindtap="onRetryTap" disabled="{{retryDisabled}}" wx:else>重试</button>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<view class="bottom-bar {{contentVisible ? 'show' : ''}}">
|
|
<t-icon name="chevron-left" class="bottom-btn {{currentIndex <= 0 ? 'disabled' : ''}}" size="48rpx" bind:tap="onPrevTap" />
|
|
<t-icon name="{{isPlaying ? 'pause' : 'play'}}" class="bottom-btn" size="48rpx" bind:tap="playStandardVoice" />
|
|
<!-- <t-icon name="swap" class="bottom-btn" size="48rpx" bind:tap="toggleMode" /> -->
|
|
<t-icon name="fact-check" class="bottom-btn {{resultDisplayed ? '' : 'disabled'}}" size="48rpx" bind:tap="onScoreTap" />
|
|
<t-icon name="{{nextButtonIcon || 'chevron-right'}}" class="bottom-btn {{(qaList && (currentIndex >= qaList.length - 1)) ? 'disabled' : ''}}" size="48rpx" bind:tap="onNextTap" />
|
|
</view>
|
|
|
|
<word-dictionary
|
|
id="wordDict"
|
|
visible="{{showDictPopup}}"
|
|
expanded="{{showDictExtended}}"
|
|
loading="{{dictLoading}}"
|
|
wordDict="{{wordDict}}"
|
|
showBackIcon="{{showBackIcon}}"
|
|
prototypeWord="{{prototypeWord}}"
|
|
forceHidePrototype="{{forceHidePrototype}}"
|
|
isWordEmptyResult="{{isWordEmptyResult}}"
|
|
dictDefaultTabValue="{{dictDefaultTabValue}}"
|
|
activeWordAudioType="{{activeWordAudioType}}"
|
|
wordAudioPlaying="{{wordAudioPlaying}}"
|
|
wordAudioIconName="{{wordAudioIconName}}"
|
|
bind:close="handleDictClose"
|
|
bind:more="handleDictMore"
|
|
bind:tabsChange="onTabsChange"
|
|
bind:tabsClick="onTabsClick"
|
|
bind:back="handleBackToPreviousWord"
|
|
bind:wordTap="handleWordClick"
|
|
/>
|
|
<view class="word-popup-mask" wx:if="{{showDictPopup}}" bindtap="handleDictClose"></view>
|
|
<view class="qa-detail-overlay" wx:if="{{qaDetailVisible}}" bindtap="onCloseDetailModal"></view>
|
|
<view class="qa-detail-modal {{qaDetailVisible ? 'show' : ''}}" wx:if="{{qaDetailVisible}}">
|
|
<view class="modal-header">
|
|
<text class="modal-title">题目解析</text>
|
|
<t-icon name="close" class="modal-close" size="40rpx" bind:tap="onCloseDetailModal" />
|
|
</view>
|
|
<scroll-view class="detail-body" scroll-y="true">
|
|
<view class="section">
|
|
<text class="question-text">{{qaDetailQuestionText}}</text>
|
|
</view>
|
|
<view class="section">
|
|
<view class="overview-card {{qaDetailResultStatus}}">
|
|
<view class="overview-icon">
|
|
<t-icon name="{{qaDetailIconName}}" size="40rpx" color="#fff" />
|
|
</view>
|
|
<view class="overview-content">
|
|
<text class="overview-label">评估详情 (EVALUATION DETAIL)</text>
|
|
<text class="overview-text">{{qaDetailOverviewText}}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<block wx:for="{{qaDetailBlocks}}" wx:key="index">
|
|
<view class="section" wx:if="{{item.items && item.items.length}}">
|
|
<!-- <text class="section-title">{{item.title}}</text> -->
|
|
<view wx:if="{{item.variant === 'incorrect'}}" class="detail-row incorrect">
|
|
<view class="detail-icon">
|
|
<t-icon name="{{item.iconName || 'data-error' }}" size="40rpx" color="#fff" />
|
|
</view>
|
|
<view class="detail-content">
|
|
<text class="detail-label">错误选项</text>
|
|
<view class="detail-items incorrect-list">
|
|
<view class="incorrect-item" wx:for="{{item.items}}" wx:key="index">
|
|
<view class="incorrect-head">
|
|
<view class="chip incorrect">{{item.content}}</view>
|
|
<text class="error-type">{{item.error_type}}</text>
|
|
</view>
|
|
<text class="error-reason">{{item.error_reason}}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view wx:if="{{item.variant === 'info'}}" class="detail-row your-choice {{qaDetailResultStatus}}">
|
|
<view class="detail-icon">
|
|
<t-icon name="{{item.iconName || 'info-circle' }}" size="40rpx" color="#fff" />
|
|
</view>
|
|
<view class="detail-content">
|
|
<text class="detail-label">{{item.title}}</text>
|
|
<view class="detail-items">
|
|
<text class="detail-item" wx:for="{{item.items}}" wx:key="index">{{item}}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view wx:if="{{item.variant !== 'incorrect' && item.variant !== 'info'}}" class="detail-row {{item.variant}}">
|
|
<view class="detail-icon">
|
|
<t-icon name="{{item.iconName || 'info-circle' }}" size="40rpx" color="#fff" />
|
|
</view>
|
|
<view class="detail-content">
|
|
<text class="detail-label">{{item.title}}</text>
|
|
<view class="detail-items">
|
|
<text class="detail-item" wx:for="{{item.items}}" wx:key="index">{{item}}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</block>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<view class="completion-popup-mask" wx:if="{{showCompletionPopup}}">
|
|
<view class="completion-card">
|
|
<view class="completion-close" bindtap="handleCompletionPopupClose">
|
|
<t-icon name="close" size="48rpx" color="#ccc" />
|
|
</view>
|
|
<view class="completion-trophy">
|
|
<view class="trophy-circle">
|
|
<t-icon name="thumb-up-2" size="80rpx" color="#001858" />
|
|
</view>
|
|
<view class="confetti c1"></view>
|
|
<view class="confetti c2"></view>
|
|
<view class="confetti c3"></view>
|
|
</view>
|
|
<view class="completion-title">Excellent Job!</view>
|
|
<!-- <view class="completion-subtitle">You've mastered the vocabulary for this photo scene.</view> -->
|
|
<button class="completion-share-btn" open-type="share" data-type="achievement">
|
|
<t-icon name="share" size="36rpx" color="#fff" style="margin-right: 12rpx;" />
|
|
Share Achievement
|
|
</button>
|
|
</view>
|
|
</view>
|
|
<vx-confetti id="confetti" class="confetti-canvas" width="{{canvasWidth}}" height="{{canvasHeight}}"></vx-confetti>
|
|
</view>
|