126 lines
5.7 KiB
Plaintext
126 lines
5.7 KiB
Plaintext
<view class="page-shell feedback-page">
|
|
<text class="eyebrow">课堂反馈</text>
|
|
<view class="page-heading">
|
|
<text class="page-title">反馈生成</text>
|
|
</view>
|
|
<text class="page-subtitle">填写课堂表现并保存到教学反馈记录。</text>
|
|
|
|
<view wx:if="{{errorMessage}}" class="status-banner">
|
|
<view class="status-copy">
|
|
<text>{{errorMessage}}</text>
|
|
<view wx:if="{{errorRequestId}}" class="status-request-id">
|
|
<text>请求编号:{{errorRequestId}}</text>
|
|
<text class="status-action" bindtap="copyRequestId">复制</text>
|
|
</view>
|
|
</view>
|
|
<text class="status-action" bindtap="retryLoad">重试</text>
|
|
</view>
|
|
|
|
<view class="feedback-form surface">
|
|
<picker class="feedback-field" mode="selector" range="{{profileOptions}}" value="{{selectedProfileIndex}}" disabled="{{loading || recording || voiceBusy}}" bindchange="onProfileChange">
|
|
<text class="form-label">学生档案</text>
|
|
<text class="form-value">{{loading ? '正在加载...' : profileOptions[selectedProfileIndex]}}</text>
|
|
</picker>
|
|
|
|
<picker class="feedback-field" mode="date" value="{{draft.feedbackDate}}" disabled="{{recording || voiceBusy}}" bindchange="onDateChange">
|
|
<text class="form-label">反馈日期</text>
|
|
<text class="form-value">{{draft.feedbackDate}}</text>
|
|
</picker>
|
|
|
|
<view class="content-field">
|
|
<view class="content-label-row">
|
|
<text class="form-label">反馈内容</text>
|
|
<view class="content-actions">
|
|
<text class="content-count">{{contentLength}} / 2000</text>
|
|
<button
|
|
wx:if="{{contentLength > 0}}"
|
|
class="content-clear-button"
|
|
disabled="{{recording || voiceBusy}}"
|
|
bindtap="clearFeedbackContent"
|
|
>清空</button>
|
|
</view>
|
|
</view>
|
|
<textarea
|
|
class="feedback-textarea"
|
|
value="{{draft.content}}"
|
|
maxlength="2000"
|
|
disabled="{{recording || voiceBusy}}"
|
|
placeholder="记录课堂完成情况、进步与后续建议"
|
|
bindinput="onContentInput"
|
|
/>
|
|
|
|
<view class="voice-input-row">
|
|
<button
|
|
class="voice-button {{recording ? 'voice-button-recording' : ''}}"
|
|
disabled="{{saving || voiceBusy}}"
|
|
bindtap="toggleRecording"
|
|
aria-label="{{recording ? '结束录音' : '开始录音'}}"
|
|
>
|
|
<text class="voice-button-icon">{{recording ? '■' : '●'}}</text>
|
|
<text>{{recording ? '结束录音' : '语音录入'}}</text>
|
|
</button>
|
|
<view class="voice-state {{voiceActionable ? 'voice-state-actionable' : ''}}" bindtap="toggleVoiceDetails">
|
|
<text class="voice-status">{{voiceStatus}}</text>
|
|
<text wx:if="{{recording}}" class="recording-time">{{recordingTime}}</text>
|
|
<text wx:elif="{{voiceActionable}}" class="voice-state-arrow">{{voiceDetailsExpanded ? '⌃' : '⌄'}}</text>
|
|
</view>
|
|
<view wx:if="{{voiceDetailsExpanded}}" class="voice-record-list">
|
|
<view class="voice-record-list-heading">
|
|
<text>语音记录</text>
|
|
<text>{{voiceLessonViews.length}}节</text>
|
|
</view>
|
|
<view
|
|
wx:for="{{voiceLessonViews}}"
|
|
wx:key="id"
|
|
wx:for-item="lesson"
|
|
class="voice-record-item"
|
|
>
|
|
<view class="voice-record-header">
|
|
<view>
|
|
<text class="voice-record-title">第{{lesson.sequence}}节</text>
|
|
<text class="voice-record-duration">{{lesson.durationText}} · {{lesson.transcriptLength}}字</text>
|
|
</view>
|
|
<text class="voice-record-status">{{lesson.statusText}}</text>
|
|
</view>
|
|
<text
|
|
wx:if="{{lesson.transcript}}"
|
|
selectable
|
|
class="voice-record-transcript {{expandedVoiceLessonId === lesson.id ? 'voice-record-transcript-expanded' : ''}}"
|
|
>{{lesson.transcript}}</text>
|
|
<text wx:else class="voice-record-empty">{{lesson.emptyText}}</text>
|
|
<view wx:if="{{lesson.transcript}}" class="voice-record-actions">
|
|
<button
|
|
wx:if="{{lesson.transcriptExpandable}}"
|
|
class="voice-record-text-button"
|
|
data-lesson-id="{{lesson.id}}"
|
|
bindtap="toggleVoiceLessonTranscript"
|
|
>{{expandedVoiceLessonId === lesson.id ? '收起' : '展开'}}</button>
|
|
<button
|
|
class="voice-record-add-button"
|
|
data-lesson-id="{{lesson.id}}"
|
|
disabled="{{!lesson.canAdd || voiceBusy}}"
|
|
bindtap="addVoiceLessonToDraft"
|
|
>{{lesson.addActionText}}</button>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view wx:if="{{session && session.failedSegmentCount > 0}}" class="voice-failure-recovery">
|
|
<text class="voice-failure-hint">{{voiceFailureHint}}</text>
|
|
<button
|
|
class="voice-discard-button"
|
|
disabled="{{saving || generating || recording || voiceBusy}}"
|
|
bindtap="discardFailedSegments"
|
|
>放弃失败录音</button>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<button class="save-feedback primary-button" loading="{{saving || generating}}" disabled="{{saving || generating || recording || voiceBusy || (session && session.processingSegmentCount > 0 && session.failedSegmentCount === 0)}}" bindtap="saveFeedback">{{primaryActionText}}</button>
|
|
</view>
|
|
|
|
<view wx:if="{{!loading && profiles.length === 0}}" class="profiles-hint">
|
|
<text>当前没有学生档案,反馈仍可不关联学生直接保存。</text>
|
|
<text class="status-action" bindtap="goStudents">新建档案</text>
|
|
</view>
|
|
</view>
|