223 lines
19 KiB
Plaintext
223 lines
19 KiB
Plaintext
<view class="container">
|
||
<view wx:if="{{loading}}" class="loading">
|
||
<view class="loading-spinner"></view>
|
||
<text>加载中...</text>
|
||
</view>
|
||
|
||
<block wx:else>
|
||
<view wx:if="{{problems.length === 0}}" class="empty-state">
|
||
<text>暂无题目数据</text>
|
||
</view>
|
||
|
||
<!-- 双层布局:背景层全部材料 + 前景层问题面板 -->
|
||
<view wx:else class="detail-wrap" style="height: {{swiperHeight}}px;">
|
||
<!-- 背景层:有材料时始终显示(申论题所有题目共享全部材料) -->
|
||
<view class="layer-back" wx:if="{{materials.length > 0}}" style="height: {{swiperHeight}}px;">
|
||
<view class="material-title-fixed">
|
||
<!-- 单材料显示"资料",多材料显示 tab 切换 -->
|
||
<block wx:if="{{materials.length <= 1}}">
|
||
<text class="section-title">资料</text>
|
||
<view class="section-title-underline"></view>
|
||
</block>
|
||
<block wx:else>
|
||
<scroll-view scroll-x class="material-tabs-scroll" enhanced="{{true}}" show-scrollbar="{{false}}">
|
||
<view class="material-tabs-inner">
|
||
<view class="material-tab {{currentMaterialIndex === index ? 'active' : ''}}"
|
||
wx:for="{{materialTabLabels}}"
|
||
wx:key="index"
|
||
data-index="{{index}}"
|
||
bindtap="onMaterialTabTap">
|
||
<text>{{item}}</text>
|
||
<view class="material-tab-underline"></view>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</block>
|
||
</view>
|
||
<!-- 单材料:直接 scroll-view -->
|
||
<scroll-view wx:if="{{materials.length <= 1}}"
|
||
scroll-y
|
||
class="material-scroll-below-title"
|
||
style="height: {{materialScrollHeight}}px;"
|
||
enhanced="{{true}}"
|
||
show-scrollbar="{{true}}"
|
||
bounces="{{true}}">
|
||
<view class="section section-material">
|
||
<view class="material-body">
|
||
<rich-text nodes="{{currentMaterial.content}}" selectable="{{true}}" class="material-rich"></rich-text>
|
||
</view>
|
||
</view>
|
||
<view class="material-placeholder"></view>
|
||
</scroll-view>
|
||
<!-- 多材料:swiper 支持左右滑动切换 -->
|
||
<swiper wx:else
|
||
class="material-swiper"
|
||
style="height: {{materialScrollHeight}}px;"
|
||
current="{{currentMaterialIndex}}"
|
||
bindchange="onMaterialSwiperChange">
|
||
<swiper-item wx:for="{{materials}}" wx:key="id" wx:for-item="mat" wx:for-index="matIdx">
|
||
<scroll-view scroll-y
|
||
class="material-scroll-below-title"
|
||
style="height: {{materialScrollHeight}}px;"
|
||
enhanced="{{true}}"
|
||
show-scrollbar="{{true}}"
|
||
bounces="{{true}}">
|
||
<view class="section section-material">
|
||
<view class="material-body">
|
||
<rich-text nodes="{{mat.content}}" selectable="{{true}}" class="material-rich"></rich-text>
|
||
</view>
|
||
</view>
|
||
<view class="material-placeholder"></view>
|
||
</scroll-view>
|
||
</swiper-item>
|
||
</swiper>
|
||
</view>
|
||
|
||
<!-- 前置层:问题面板 -->
|
||
<view class="movable-area panel-area" style="height: {{movableAreaHeight}}px;">
|
||
<view class="movable-panel question-panel-wrap" style="height: {{panelHeight}}px; transform: translateY({{panelY}}px);">
|
||
<!-- 有材料时显示拖拽条 -->
|
||
<view class="panel-drag-handle"
|
||
wx:if="{{materials.length > 0}}"
|
||
bindtouchstart="onPanelDragStart"
|
||
catchtouchmove="onPanelDragMove"
|
||
bindtouchend="onPanelDragEnd"
|
||
bindtouchcancel="onPanelDragEnd">
|
||
<view class="panel-drag-bar"></view>
|
||
</view>
|
||
<view class="section section-question">
|
||
<!-- 多问题:tab 列表,与资料区域相同逻辑 -->
|
||
<view class="question-title-fixed" wx:if="{{problems.length > 1}}">
|
||
<scroll-view scroll-x class="material-tabs-scroll" enhanced="{{true}}" show-scrollbar="{{false}}">
|
||
<view class="material-tabs-inner">
|
||
<view class="material-tab {{currentProblemIndex === index ? 'active' : ''}}"
|
||
wx:for="{{problemTabLabels}}"
|
||
wx:key="index"
|
||
data-index="{{index}}"
|
||
bindtap="onProblemTabTap">
|
||
<text>{{item}}</text>
|
||
<view class="material-tab-underline"></view>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
<swiper class="content-swiper question-content-swiper"
|
||
current="{{currentProblemIndex}}"
|
||
bindchange="onQuestionChange"
|
||
bindanimationfinish="onQuestionAnimationFinish">
|
||
<swiper-item wx:for="{{problems}}"
|
||
wx:key="problem_id"
|
||
wx:for-index="qIndex"
|
||
wx:for-item="problem"
|
||
class="content-swiper-item">
|
||
<scroll-view scroll-y class="question-body-scroll" enhanced="{{true}}" show-scrollbar="{{true}}" bounces="{{true}}">
|
||
<view class="question-container">
|
||
<!-- 题干内容 -->
|
||
<view class="card question-card">
|
||
<view class="problem-content">
|
||
<rich-text nodes="{{problem.problem_content}}" selectable="{{true}}"></rich-text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 我的答案卡片 -->
|
||
<view class="card answer-card">
|
||
<view class="card-title-row">
|
||
<view class="card-title">我的答案</view>
|
||
<view class="review-tip {{problem.auditTextStyle}}">{{problem.auditText}}</view>
|
||
</view>
|
||
<view class="image-upload-container">
|
||
<view class="image-list">
|
||
<block wx:if="{{problem.submittedImages && problem.submittedImages.length > 0}}">
|
||
<block wx:for="{{problem.submittedImages}}" wx:key="id" wx:for-item="img" wx:for-index="imgIndex">
|
||
<view class="image-item">
|
||
<image class="preview-image" src="{{img.path || img}}" mode="aspectFit" bindtap="previewImage" data-url="{{img.path || img}}" data-problem-index="{{qIndex}}"></image>
|
||
</view>
|
||
</block>
|
||
</block>
|
||
<block wx:elif="{{problem.tempImages && problem.tempImages.length > 0}}">
|
||
<block wx:for="{{problem.tempImages}}" wx:key="*this" wx:for-item="tempImg" wx:for-index="tempIndex">
|
||
<view class="image-item">
|
||
<image class="preview-image" src="{{tempImg}}" mode="aspectFit" bindtap="previewImage" data-url="{{tempImg}}" data-problem-index="{{qIndex}}"></image>
|
||
<view class="delete-btn" bindtap="deleteImage" data-index="{{tempIndex}}" data-problem-index="{{qIndex}}">
|
||
<text class="delete-icon">×</text>
|
||
</view>
|
||
</view>
|
||
</block>
|
||
<view class="upload-btn" bindtap="chooseImage" data-problem-index="{{qIndex}}" wx:if="{{problem.totalImageCount < 6}}">
|
||
<view class="upload-icon">+</view>
|
||
<text class="upload-text">上传图片</text>
|
||
</view>
|
||
</block>
|
||
<block wx:else>
|
||
<view class="upload-btn" bindtap="chooseImage" data-problem-index="{{qIndex}}">
|
||
<view class="upload-icon">+</view>
|
||
<text class="upload-text">上传图片</text>
|
||
</view>
|
||
</block>
|
||
</view>
|
||
<view class="image-tip">最多可上传6张图片</view>
|
||
</view>
|
||
<view class="submit-btn-container submit-btn-row" wx:if="{{problems.length > 0 && ((problem.tempImages && problem.tempImages.length > 0) || (problem.submittedImages && problem.submittedImages.length > 0) || problem.allowResubmit)}}">
|
||
<button class="btn-resubmit" bindtap="handleResubmit" data-problem-index="{{qIndex}}" wx:if="{{problem.submittedImages && problem.submittedImages.length > 0}}">重答</button>
|
||
<button class="btn-submit-one {{problem.submittedImages && problem.submittedImages.length > 0 ? 'btn-submit-disabled' : ''}}" disabled="{{problem.submittedImages && problem.submittedImages.length > 0}}" bindtap="submitOneQuestion" data-problem-index="{{qIndex}}" data-is-last="{{qIndex === problems.length - 1}}">{{qIndex === problems.length - 1 ? '提交' : '确定'}}</button>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 老师批复:顺延在答案下方,同一块内 -->
|
||
<view class="teacher-feedback-inline" wx:if="{{problem.teacherFeedback && (problem.teacherFeedback.comment || (problem.teacherFeedback.images && problem.teacherFeedback.images.length > 0))}}">
|
||
<view class="card teacher-card">
|
||
<view class="section-header">
|
||
<text class="section-title">老师批复</text>
|
||
</view>
|
||
<text class="review-time">批复时间: {{problem.teacherFeedback.review_time}}</text>
|
||
<view class="feedback-content">
|
||
<view wx:if="{{problem.teacherFeedback.comment}}" class="feedback-text">{{problem.teacherFeedback.comment}}</view>
|
||
<view class="feedback-images" wx:if="{{problem.teacherFeedback.images && problem.teacherFeedback.images.length > 0}}">
|
||
<image wx:for="{{problem.teacherFeedback.images}}" wx:key="index" wx:for-item="image" src="{{image}}" mode="widthFix" bindtap="previewTeacherImage" data-url="{{image}}"></image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 解析:回答完成且(审批通过或不需要审核)后展示 -->
|
||
<view class="explanation-inline" wx:if="{{problem.submittedImages && problem.submittedImages.length > 0 && (problem.auditText === '审核通过' || problem.auditText === '不需要审核') && problem.explanation}}">
|
||
<view class="card explanation-card">
|
||
<view class="section-header">
|
||
<text class="section-title">解析</text>
|
||
</view>
|
||
<view class="explanation-content">
|
||
<rich-text nodes="{{problem.explanation}}" selectable="{{true}}"></rich-text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="bottom-spacing"></view>
|
||
</view>
|
||
</scroll-view>
|
||
</swiper-item>
|
||
</swiper>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</block>
|
||
</view>
|
||
|
||
<!-- 上传方式选择弹窗 -->
|
||
<view class="popup" wx:if="{{showUploadOptions}}">
|
||
<view class="popup-mask" bindtap="hideUploadOptions"></view>
|
||
<view class="popup-content">
|
||
<view class="popup-header">
|
||
<text>选择提交方式</text>
|
||
<view class="popup-close" bindtap="hideUploadOptions">×</view>
|
||
</view>
|
||
<view class="upload-options">
|
||
<button class="upload-btn" bindtap="handleTakePhoto">
|
||
<text>拍照</text>
|
||
</button>
|
||
<button class="upload-btn" bindtap="handleChooseImage">
|
||
<text>从相册选择</text>
|
||
</button>
|
||
</view>
|
||
</view>
|
||
</view> |