503 lines
27 KiB
Plaintext
503 lines
27 KiB
Plaintext
<view class="qa-exercise-container">
|
|
|
|
<view wx:if="{{!contentReady || loadingMaskVisible}}" 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="type-container" wx:if="{{fixedMode}}">
|
|
<view class="type-item {{fixedMode === 'cloze' ? 'active' : ''}}" hover-class="type-item-hover" bindtap="switchMode" data-mode="cloze">填空</view>
|
|
<view class="type-item {{fixedMode === 'choice' ? 'active' : ''}}" hover-class="type-item-hover" bindtap="switchMode" data-mode="choice">问答</view>
|
|
<!-- <view class="type-item {{fixedMode === 'variation' ? 'active' : ''}}" hover-class="type-item-hover" bindtap="switchMode" data-mode="variation">识图</view> -->
|
|
<view class="type-item {{fixedMode === 'conversation' ? 'active' : ''}}" hover-class="type-item-hover" bindtap="switchMode" data-mode="conversation">对话</view>
|
|
</view>
|
|
|
|
<view class="container {{contentVisible ? 'fade-in' : 'fade-out'}}" wx:if="{{contentReady && !loadingMaskVisible}}">
|
|
<view class="process-container" wx:if="{{qaList && qaList.length > 0 && questionMode !== 'conversation'}}">
|
|
<block wx:for="{{qaList}}" wx:key="index">
|
|
<view class="process-dot {{processDotClasses[index]}} {{index === currentIndex ? 'current' : ''}}"></view>
|
|
</block>
|
|
</view>
|
|
<view class="question-scroll-wrapper {{questionMode === 'conversation' && conversationViewMode === 'chat' && isChatInputVisible && !isMicrophoneMode ? 'chat-input-mode-scroll' : 'chat-mode-scroll'}}">
|
|
<scroll-view class="inner-scroll" scroll-y >
|
|
<view class="image-card" wx:if="{{questionMode !== 'variation'}}">
|
|
<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" />
|
|
</view>
|
|
</view>
|
|
<view class="question-title" wx:if="{{questionMode !== 'conversation'}}">
|
|
<text wx:for="{{questionWords}}" wx:key="index" class="word-item" data-word="{{item}}" bindtap="handleWordClick">{{item}}</text>
|
|
</view>
|
|
<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="cloze-sentence">
|
|
<text wx:for="{{clozeSentenceTokens}}" wx:key="index" class="{{item.isBlank ? 'cloze-fill' : 'cloze-text'}}" data-word="{{item.word}}" bindtap="handleWordClick">{{item.text}}</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 === 'variation'}}">
|
|
<view class="variation-container">
|
|
<view class="variation-grid">
|
|
<view class="variation-item" wx:for="{{variationQaList}}" wx:key="index">
|
|
<view class="variation-image-wrapper {{index === variationSelectedIndex ? 'selected' : ''}}" data-index="{{index}}" bindtap="selectVariationOption">
|
|
<cloud-image
|
|
file-id="{{item.file_id}}"
|
|
mode="widthFix"
|
|
height="auto"
|
|
radius="24rpx"
|
|
bind:load="onVariationImageLoad"
|
|
data-fileid="{{item.file_id}}"
|
|
/>
|
|
<view class="view-full" wx:if="{{variationImageLoaded[item.file_id]}}" data-fileid="{{item.file_id}}" catchtap="previewVariationImage">
|
|
<t-icon name="zoom-in" size="32rpx" />
|
|
</view>
|
|
<view wx:if="{{variationImageLoaded[item.file_id]}}" class="selection-badge {{variationResultStatus === 'incorrect' && index === variationSelectedIndex ? 'incorrect' : (index === variationSelectedIndex ? 'selected' : 'unselected')}}">
|
|
<t-icon name="{{variationResultStatus === 'incorrect' && index === variationSelectedIndex ? 'close-circle' : 'check-circle'}}" size="36rpx" color="#fff" />
|
|
</view>
|
|
<view wx:if="{{variationResultStatus && index === variationSelectedIndex}}" class="variation-border {{variationResultStatus}}"></view>
|
|
</view>
|
|
<!-- <view class="variation-text">{{item.question}}</view> -->
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="conversation-content {{modeAnim}}" wx:if="{{questionMode === 'conversation' && conversationViewMode === 'setup'}}">
|
|
<view class="conversation-section">
|
|
<view class="conversation-label">难度选择</view>
|
|
<view class="conversation-tags">
|
|
<t-check-tag
|
|
wx:for="{{difficultyOptions}}"
|
|
wx:key="value"
|
|
variant="outline"
|
|
size="medium"
|
|
data-level="{{item.value}}"
|
|
checked="{{conversationDifficulty === item.value}}"
|
|
bindtap="selectConversationDifficulty"
|
|
content="{{ [conversationSceneLang === 'zh' ? item.label_zh : item.label_en] }}"
|
|
/>
|
|
</view>
|
|
</view>
|
|
<view class="conversation-section">
|
|
<view class="conversation-label">场景标签</view>
|
|
<view class="conversation-tags" wx:if="{{conversationSetting && conversationSetting.all_possible_scenes && conversationSetting.all_possible_scenes.length}}">
|
|
<t-check-tag
|
|
wx:for="{{conversationSetting.all_possible_scenes}}"
|
|
wx:key="scene_en"
|
|
variant="outline"
|
|
size="medium"
|
|
data-scene="{{item.scene_en}}"
|
|
checked="{{conversationSelectedScenesMap && conversationSelectedScenesMap[item.scene_en]}}"
|
|
bindtap="toggleConversationScene"
|
|
>
|
|
{{conversationSceneLang === 'zh' ? item.scene_zh : item.scene_en}}
|
|
</t-check-tag>
|
|
<t-check-tag
|
|
wx:for="{{conversationCustomScenes}}"
|
|
wx:key="key"
|
|
variant="outline"
|
|
size="medium"
|
|
data-scene="{{item.key}}"
|
|
checked="{{conversationSelectedScenesMap && conversationSelectedScenesMap[item.key]}}"
|
|
bindtap="toggleConversationScene"
|
|
>
|
|
<view class="custom-scene-tag">
|
|
<text class="custom-scene-text">{{item.text}}</text>
|
|
<t-icon name="close" size="24rpx" data-key="{{item.key}}" catchtap="onConversationCustomSceneDelete" />
|
|
</view>
|
|
</t-check-tag>
|
|
<view wx:if="{{conversationCustomSceneEditing}}" class="conversation-custom-scene-input-wrapper">
|
|
<input
|
|
class="conversation-custom-scene-input {{conversationCustomSceneOverLimit ? 'conversation-custom-scene-input-error' : ''}}"
|
|
value="{{conversationCustomSceneText}}"
|
|
placeholder="自定义场景"
|
|
maxlength="60"
|
|
focus="{{true}}"
|
|
bindinput="onConversationCustomSceneInput"
|
|
bindblur="onConversationCustomSceneBlur"
|
|
/>
|
|
</view>
|
|
<t-check-tag
|
|
wx:if="{{!conversationCustomSceneEditing}}"
|
|
variant="outline"
|
|
size="medium"
|
|
bindtap="onConversationCustomSceneAdd"
|
|
>
|
|
+
|
|
</t-check-tag>
|
|
</view>
|
|
</view>
|
|
<view class="conversation-section">
|
|
<view class="conversation-label">事件标签</view>
|
|
<view class="conversation-tags" wx:if="{{conversationSetting && conversationSetting.all_possible_events && conversationSetting.all_possible_events.length}}">
|
|
<t-check-tag
|
|
wx:for="{{conversationSetting.all_possible_events}}"
|
|
wx:key="event_en"
|
|
variant="outline"
|
|
size="medium"
|
|
data-event="{{item.event_en}}"
|
|
checked="{{conversationSelectedEventsMap && conversationSelectedEventsMap[item.event_en]}}"
|
|
bindtap="toggleConversationEvent"
|
|
>
|
|
{{conversationSceneLang === 'zh' ? item.event_zh : item.event_en}}
|
|
</t-check-tag>
|
|
<t-check-tag
|
|
wx:for="{{conversationCustomEvents}}"
|
|
wx:key="key"
|
|
variant="outline"
|
|
size="medium"
|
|
data-event="{{item.key}}"
|
|
checked="{{conversationSelectedEventsMap && conversationSelectedEventsMap[item.key]}}"
|
|
bindtap="toggleConversationEvent"
|
|
>
|
|
<view class="custom-scene-tag">
|
|
<text class="custom-scene-text">{{item.text}}</text>
|
|
<t-icon name="close" size="24rpx" data-key="{{item.key}}" catchtap="onConversationCustomEventDelete" />
|
|
</view>
|
|
</t-check-tag>
|
|
<view wx:if="{{conversationCustomEventEditing}}" class="conversation-custom-scene-input-wrapper">
|
|
<input
|
|
class="conversation-custom-scene-input {{conversationCustomEventOverLimit ? 'conversation-custom-scene-input-error' : ''}}"
|
|
value="{{conversationCustomEventText}}"
|
|
placeholder="自定义事件"
|
|
maxlength="60"
|
|
focus="{{true}}"
|
|
bindinput="onConversationCustomEventInput"
|
|
bindblur="onConversationCustomEventBlur"
|
|
/>
|
|
</view>
|
|
<t-check-tag
|
|
wx:if="{{!conversationCustomEventEditing}}"
|
|
variant="outline"
|
|
size="medium"
|
|
bindtap="onConversationCustomEventAdd"
|
|
>
|
|
+
|
|
</t-check-tag>
|
|
</view>
|
|
</view>
|
|
<view class="conversation-section" wx:if="{{conversationSuggestedRoles && conversationSuggestedRoles.length}}">
|
|
<view class="conversation-label">角色扮演</view>
|
|
<view class="conversation-tags">
|
|
<block wx:for="{{conversationSuggestedRoles}}" wx:key="key" wx:for-index="idx">
|
|
<view style="display: flex; align-items: center;">
|
|
<t-check-tag
|
|
checked="{{selectedRole && selectedRole.roleIndex === idx && selectedRole.roleSide === 1}}"
|
|
bind:change="onRoleSelect"
|
|
data-index="{{idx}}"
|
|
data-side="{{1}}"
|
|
variant="outline"
|
|
size="medium"
|
|
>{{conversationSceneLang === 'zh' ? item.role1_zh : item.role1_en}}</t-check-tag>
|
|
<t-check-tag
|
|
checked="{{selectedRole && selectedRole.roleIndex === idx && selectedRole.roleSide === 2}}"
|
|
bind:change="onRoleSelect"
|
|
data-index="{{idx}}"
|
|
data-side="{{2}}"
|
|
variant="outline"
|
|
size="medium"
|
|
>{{conversationSceneLang === 'zh' ? item.role2_zh : item.role2_en}}</t-check-tag>
|
|
</view>
|
|
</block>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="conversation-section">
|
|
<view class="conversation-label-row">
|
|
<text class="conversation-label">额外说明</text>
|
|
<text class="conversation-count">{{(conversationExtraNote && conversationExtraNote.length) || 0}}/200</text>
|
|
</view>
|
|
<view class="conversation-note-card">
|
|
<textarea
|
|
class="conversation-note-input"
|
|
placeholder="例如:描述一下图片中的人物关系或具体发生的事件,这将帮助 AI 更好地生成对话内容..."
|
|
maxlength="200"
|
|
value="{{conversationExtraNote}}"
|
|
bindinput="onConversationNoteInput"
|
|
/>
|
|
</view>
|
|
</view>
|
|
<view class="conversation-start-row">
|
|
<button class="conversation-start-btn" bindtap="onStartConversationTap">
|
|
开始对话
|
|
<t-icon name="chat" size="32rpx" style="margin-left: 12rpx;" />
|
|
</button>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="conversation-content {{modeAnim}}" wx:if="{{questionMode === 'conversation' && conversationViewMode === 'chat'}}">
|
|
<block wx:if="{{conversationMessages && conversationMessages.length}}">
|
|
<view class="conversation-block {{item.role === 'user' ? 'user' : 'default'}}" wx:for="{{conversationMessages}}" wx:key="index"
|
|
>
|
|
<t-chat-message
|
|
role="{{item.role}}"
|
|
placement="{{item.role === 'user' ? 'right' : 'left'}}"
|
|
content="{{item.content}}"
|
|
/>
|
|
</view>
|
|
</block>
|
|
<view class="conversation-block" wx:if="{{replyLoading}}">
|
|
<t-chat-loading animation="dots" />
|
|
</view>
|
|
<view id="bottom-anchor" style="height: 1rpx;"></view>
|
|
</view>
|
|
|
|
<view class="submit-row" wx:if="{{questionMode !== 'conversation'}}">
|
|
<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>
|
|
|
|
<view class="bottom-bar {{contentVisible ? 'show' : ''}}" wx:if="{{questionMode !== 'conversation'}}">
|
|
<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="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>
|
|
<t-drawer visible="{{historyVisible}}" placement="left" bind:visible-change="onHistoryDrawerClose" close-btn="{{true}}">
|
|
<scroll-view scroll-y class="history-drawer-scroll" bindscrolltolower="onHistoryScrollBottom">
|
|
<view class="history-list">
|
|
<t-cell
|
|
wx:for="{{historyList}}"
|
|
wx:key="session_id"
|
|
title="{{item.created_at}}"
|
|
hover
|
|
class="history-item {{conversationLatestSession && conversationLatestSession.session_id === item.session_id ? 'active' : ''}}"
|
|
bind:click="chatItemClick"
|
|
data-item="{{item}}"
|
|
>
|
|
<view slot="description" class="history-tags">
|
|
<block wx:for="{{item.scene}}" wx:for-item="scene" wx:key="index">
|
|
<view class="history-tag" wx:if="{{scene.en || scene.zh}}">
|
|
{{conversationSceneLang === 'zh' ? (scene.zh || scene.en) : (scene.en || scene.zh)}}
|
|
</view>
|
|
</block>
|
|
<block wx:for="{{item.event}}" wx:for-item="ev" wx:key="index">
|
|
<view class="history-tag" wx:if="{{ev.en || ev.zh}}">
|
|
{{conversationSceneLang === 'zh' ? (ev.zh || ev.en) : (ev.en || ev.zh)}}
|
|
</view>
|
|
</block>
|
|
</view>
|
|
</t-cell>
|
|
<view class="history-loading" wx:if="{{historyLoading}}">
|
|
<t-loading theme="spinner" size="40rpx" text="加载中..." />
|
|
</view>
|
|
<view class="history-no-more" wx:if="{{!historyHasMore && historyList.length > 0}}">没有更多内容</view>
|
|
<view class="history-no-more" wx:if="{{!historyHasMore && historyList.length === 0}}">暂无历史记录</view>
|
|
</view>
|
|
</scroll-view>
|
|
</t-drawer>
|
|
|
|
<view wx:if="{{isRecording}}" class="microphone-mask">
|
|
<view class="microphone-bars">
|
|
<view class="microphone-bar"></view>
|
|
<view class="microphone-bar"></view>
|
|
<view class="microphone-bar"></view>
|
|
<view class="microphone-bar"></view>
|
|
<view class="microphone-bar"></view>
|
|
<view class="microphone-bar"></view>
|
|
<view class="microphone-bar"></view>
|
|
<view class="microphone-bar"></view>
|
|
<view class="microphone-bar"></view>
|
|
<view class="microphone-bar"></view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="chat-sender-wrapper {{isChatInputVisible ? 'show' : ''}}" style="bottom: {{inputBottom}}px" wx:if="{{questionMode === 'conversation' && conversationViewMode === 'chat'}}">
|
|
<view class="suggestion-bar {{showChatSuggestions ? 'show' : ''}}"
|
|
wx:if="{{chatSuggestions.length > 0 && !isMicrophoneMode}}"
|
|
bind:touchstart="handleSuggestionTouchStart"
|
|
bind:touchend="handleSuggestionTouchEnd">
|
|
<scroll-view scroll-x class="suggestion-scroll" enable-flex>
|
|
<view class="suggestion-item" wx:for="{{chatSuggestions}}" wx:key="index" bindtap="handleSuggestionTap" data-text="{{item.text}}">
|
|
{{item.label}}
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
<t-chat-sender
|
|
wx:if="{{!isMicrophoneMode}}"
|
|
value="{{chatInputValue}}"
|
|
placeholder="{{chatPlaceholder}}"
|
|
loading="{{replyLoading}}"
|
|
focus="{{isChatInputVisible}}"
|
|
renderPresets="{{renderPresets}}"
|
|
bind:send="onSendMessage"
|
|
bind:input="onChatInput"
|
|
bind:blur="onChatBlur"
|
|
>
|
|
<view slot="footer-prefix" class="footer-prefix">
|
|
<view class="chat-icon-block" bind:tap="onChatCloseTap">
|
|
<t-icon name="close-circle" size="64rpx" color="#dcdcdc"/>
|
|
</view>
|
|
<!-- <view class="chat-icon-block" bind:tap="switchToVoiceMode">
|
|
<t-icon name="microphone-1" size="64rpx" color="#dcdcdc"/>
|
|
</view> -->
|
|
</view>
|
|
</t-chat-sender>
|
|
<view class="voice-mode-panel" wx:if="{{isMicrophoneMode}}">
|
|
<view class="voice-panel-controls">
|
|
<view class="chat-icon-block" bind:tap="switchToTextMode">
|
|
<t-icon name="keyboard" size="64rpx" color="#666"/>
|
|
</view>
|
|
<view class="microphone-btn {{isRecording ? 'recording' : ''}}"
|
|
bind:touchstart="handleRecordStart"
|
|
bind:touchend="handleRecordEnd">
|
|
{{isRecording ? '松开发送' : '按住说话'}}
|
|
</view>
|
|
<view class="chat-icon-block" bind:tap="onChatCloseTap">
|
|
<t-icon name="close-circle" size="64rpx" color="#666"/>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="bottom-bar {{contentVisible && !isChatInputVisible ? 'show' : ''}}" wx:if="{{questionMode === 'conversation'}}">
|
|
<view class="bottom-btn bottom-button-img-wrap" bind:tap="toggleConversationSceneLang">
|
|
<t-icon name="translate" class="trans-button left-half {{conversationSceneLang === 'en' ? 'trans-active' : 'trans-deactive'}}" size="48rpx" />
|
|
<t-icon name="translate" class="trans-button right-half {{conversationSceneLang === 'zh' ? 'trans-active' : 'trans-deactive'}}" size="48rpx" />
|
|
</view>
|
|
<t-icon name="microphone-1" class="bottom-btn {{conversationLatestSession && conversationViewMode !== 'setup' ? '' : 'disabled'}}" size="48rpx" bind:tap="switchToVoiceMode" />
|
|
<t-icon name="keyboard" class="bottom-btn {{conversationLatestSession && conversationViewMode !== 'setup' ? '' : 'disabled'}}" size="48rpx" bind:tap="showChatInput" />
|
|
<t-icon name="{{conversationLatestSession && conversationViewMode === 'chat' ? 'chat-bubble-add' : 'chat-bubble-1'}}" class="bottom-btn {{conversationLatestSession ? '' : 'disabled'}}" size="48rpx" bind:tap="toggleConversationView" />
|
|
<!-- <t-icon name="fact-check" class="bottom-btn {{resultDisplayed ? '' : 'disabled'}}" size="48rpx" bind:tap="" /> -->
|
|
<t-icon name="chat-bubble-history" class="bottom-btn" size="48rpx" bind:tap="onHistoryTap" />
|
|
</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 {{showConfetti ? 'show' : ''}}" width="{{canvasWidth}}" height="{{canvasHeight}}"></vx-confetti>
|
|
</view>
|