280 lines
6.8 KiB
Vue
280 lines
6.8 KiB
Vue
|
|
<!-- 阅卷页面 -->
|
||
|
|
<route lang="jsonc">
|
||
|
|
{
|
||
|
|
"style": {
|
||
|
|
"navigationStyle": "custom"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</route>
|
||
|
|
|
||
|
|
<script lang="ts" setup>
|
||
|
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||
|
|
import ScoreSettingsDialog from '@/components/marking/components/dialog/ScoreSettingsDialog.vue'
|
||
|
|
import QuickScorePanel from '@/components/marking/components/QuickScorePanel.vue'
|
||
|
|
import MarkingImageViewerNew from '@/components/marking/components/renderer/MarkingImageViewerNew.vue'
|
||
|
|
import { provideMarkingData } from '@/components/marking/composables/useMarkingData'
|
||
|
|
import MarkingLayout from '@/components/marking/MarkingLayout.vue'
|
||
|
|
|
||
|
|
defineOptions({
|
||
|
|
name: 'GradingPage',
|
||
|
|
})
|
||
|
|
|
||
|
|
// 获取路由参数
|
||
|
|
const examId = ref<number>()
|
||
|
|
const subjectId = ref<number>()
|
||
|
|
const questionId = ref<number>()
|
||
|
|
const taskId = ref<number>()
|
||
|
|
const evaluationType = ref<'single' | 'double'>('single')
|
||
|
|
|
||
|
|
// 屏幕方向状态
|
||
|
|
const isLandscape = ref(false)
|
||
|
|
|
||
|
|
const markingData = provideMarkingData({
|
||
|
|
taskId,
|
||
|
|
questionId,
|
||
|
|
isLandscape,
|
||
|
|
})
|
||
|
|
const { questionData: questions } = markingData
|
||
|
|
|
||
|
|
// 全屏状态
|
||
|
|
const isFullscreen = ref(false)
|
||
|
|
|
||
|
|
const currentQuestionIndex = ref(0)
|
||
|
|
const totalQuestions = computed(() => questions.value.length)
|
||
|
|
|
||
|
|
// 分数数据
|
||
|
|
const myScore = computed(() => {
|
||
|
|
const data = markingData.avgScoreData.value
|
||
|
|
return data?.teacher_score.average_score || 0
|
||
|
|
})
|
||
|
|
const avgScore = computed(() => {
|
||
|
|
const data = markingData.avgScoreData.value
|
||
|
|
return data?.all_teachers_score.average_score || 0
|
||
|
|
})
|
||
|
|
|
||
|
|
// 页面加载时获取参数
|
||
|
|
onLoad((options) => {
|
||
|
|
examId.value = Number(options.examId)
|
||
|
|
subjectId.value = Number(options.subjectId)
|
||
|
|
questionId.value = Number(options.questionId)
|
||
|
|
taskId.value = Number(options.taskId) // 从路由参数获取taskId
|
||
|
|
evaluationType.value = options.type as 'single' | 'double' || 'single'
|
||
|
|
})
|
||
|
|
|
||
|
|
// 监听屏幕方向变化
|
||
|
|
function handleOrientationChange() {
|
||
|
|
// #ifdef H5
|
||
|
|
const orientation = window.screen.orientation?.angle || 0
|
||
|
|
isLandscape.value = orientation === 90 || orientation === 270
|
||
|
|
// #endif
|
||
|
|
|
||
|
|
// #ifdef APP-PLUS
|
||
|
|
// plus.screen.lockOrientation('portrait-primary')
|
||
|
|
// #endif
|
||
|
|
}
|
||
|
|
|
||
|
|
// 监听全屏状态变化
|
||
|
|
function handleFullscreenChange() {
|
||
|
|
// #ifdef H5
|
||
|
|
isFullscreen.value = !!document.fullscreenElement
|
||
|
|
// #endif
|
||
|
|
}
|
||
|
|
|
||
|
|
onMounted(() => {
|
||
|
|
// #ifdef H5
|
||
|
|
window.addEventListener('orientationchange', handleOrientationChange)
|
||
|
|
document.addEventListener('fullscreenchange', handleFullscreenChange)
|
||
|
|
handleOrientationChange()
|
||
|
|
// #endif
|
||
|
|
})
|
||
|
|
|
||
|
|
onUnmounted(() => {
|
||
|
|
// #ifdef H5
|
||
|
|
window.removeEventListener('orientationchange', handleOrientationChange)
|
||
|
|
document.removeEventListener('fullscreenchange', handleFullscreenChange)
|
||
|
|
// #endif
|
||
|
|
})
|
||
|
|
|
||
|
|
// 切换屏幕方向
|
||
|
|
function toggleOrientation() {
|
||
|
|
// #ifdef H5
|
||
|
|
if (document.fullscreenElement) {
|
||
|
|
if (screen.orientation && 'lock' in screen.orientation) {
|
||
|
|
if (isLandscape.value) {
|
||
|
|
(screen.orientation as any).lock('portrait-primary')
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
(screen.orientation as any).lock('landscape-primary')
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// #endif
|
||
|
|
|
||
|
|
// #ifdef APP-PLUS
|
||
|
|
if (isLandscape.value) {
|
||
|
|
plus.screen.lockOrientation('portrait-primary')
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
plus.screen.lockOrientation('landscape-primary')
|
||
|
|
}
|
||
|
|
// #endif
|
||
|
|
|
||
|
|
isLandscape.value = !isLandscape.value
|
||
|
|
}
|
||
|
|
|
||
|
|
// 全屏切换
|
||
|
|
function toggleFullscreen() {
|
||
|
|
// #ifdef H5
|
||
|
|
if (!document.fullscreenElement) {
|
||
|
|
document.documentElement.requestFullscreen().then(() => {
|
||
|
|
isFullscreen.value = true
|
||
|
|
}).catch((err) => {
|
||
|
|
console.error('进入全屏失败:', err)
|
||
|
|
uni.showToast({
|
||
|
|
title: '全屏功能不支持',
|
||
|
|
icon: 'none',
|
||
|
|
})
|
||
|
|
})
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
document.exitFullscreen().then(() => {
|
||
|
|
isFullscreen.value = false
|
||
|
|
})
|
||
|
|
}
|
||
|
|
// #endif
|
||
|
|
|
||
|
|
// #ifdef APP-PLUS
|
||
|
|
// App端可以通过设置状态栏来模拟全屏
|
||
|
|
if (isFullscreen.value) {
|
||
|
|
plus.navigator.setStatusBarStyle('dark')
|
||
|
|
plus.navigator.setStatusBarBackground('#000000')
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
plus.navigator.setStatusBarStyle('light')
|
||
|
|
plus.navigator.setStatusBarBackground('#ffffff')
|
||
|
|
}
|
||
|
|
isFullscreen.value = !isFullscreen.value
|
||
|
|
// #endif
|
||
|
|
}
|
||
|
|
|
||
|
|
// 返回上一页
|
||
|
|
function goBack() {
|
||
|
|
uni.navigateBack()
|
||
|
|
}
|
||
|
|
|
||
|
|
// 题目选择
|
||
|
|
function selectQuestion(index: number) {
|
||
|
|
currentQuestionIndex.value = index
|
||
|
|
}
|
||
|
|
|
||
|
|
// 打分设置弹窗状态
|
||
|
|
const showScoreSettings = ref(false)
|
||
|
|
|
||
|
|
// 打分设置
|
||
|
|
function openScoreSettings() {
|
||
|
|
showScoreSettings.value = true
|
||
|
|
}
|
||
|
|
|
||
|
|
// 打分设置确认
|
||
|
|
function handleScoreSettingsConfirm(data: { stepSize: number, commonScores: number[] }) {
|
||
|
|
console.log('打分设置已确认:', data)
|
||
|
|
uni.showToast({
|
||
|
|
title: '设置已保存',
|
||
|
|
icon: 'success',
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// 查看均分
|
||
|
|
function viewAvgScore() {
|
||
|
|
uni.showToast({
|
||
|
|
title: '查看均分功能开发中',
|
||
|
|
icon: 'none',
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// 查看答案
|
||
|
|
function viewAnswer() {
|
||
|
|
uni.showToast({
|
||
|
|
title: '查看答案功能开发中',
|
||
|
|
icon: 'none',
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// 当前题目信息
|
||
|
|
const currentQuestion = computed(() => questions.value[currentQuestionIndex.value])
|
||
|
|
|
||
|
|
// 提交阅卷
|
||
|
|
async function handleSubmitMarking(data: { score: number, remark: string }) {
|
||
|
|
try {
|
||
|
|
await markingData.submitRecord({
|
||
|
|
score: data.score,
|
||
|
|
remark: data.remark,
|
||
|
|
status: 'submitted',
|
||
|
|
})
|
||
|
|
}
|
||
|
|
catch (error) {
|
||
|
|
console.error('提交阅卷失败:', error)
|
||
|
|
uni.showToast({
|
||
|
|
title: '提交失败',
|
||
|
|
icon: 'none',
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 快捷打分选择
|
||
|
|
function handleQuickScoreSelect(score: number) {
|
||
|
|
console.log('选择分数:', score)
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<template>
|
||
|
|
<div class="relative h-screen">
|
||
|
|
<MarkingLayout
|
||
|
|
:is-landscape="isLandscape"
|
||
|
|
:is-fullscreen="isFullscreen"
|
||
|
|
:current-question-index="currentQuestionIndex"
|
||
|
|
:total-questions="totalQuestions"
|
||
|
|
:questions="questions"
|
||
|
|
:my-score="myScore"
|
||
|
|
:avg-score="avgScore"
|
||
|
|
@go-back="goBack"
|
||
|
|
@select-question="selectQuestion"
|
||
|
|
@open-score-settings="openScoreSettings"
|
||
|
|
@view-avg-score="viewAvgScore"
|
||
|
|
@view-answer="viewAnswer"
|
||
|
|
@toggle-orientation="toggleOrientation"
|
||
|
|
@toggle-fullscreen="toggleFullscreen"
|
||
|
|
>
|
||
|
|
<template #content>
|
||
|
|
<MarkingImageViewerNew
|
||
|
|
v-if="questions[0]?.image_urls?.length"
|
||
|
|
v-model:question-data="questions"
|
||
|
|
:image-size="100"
|
||
|
|
/>
|
||
|
|
</template>
|
||
|
|
</MarkingLayout>
|
||
|
|
|
||
|
|
<!-- 快捷打分面板 - 固定定位在右侧 -->
|
||
|
|
<div
|
||
|
|
class="fixed bottom-0 z-10"
|
||
|
|
:class="{
|
||
|
|
'right-16px h-[calc(100vh-80px)]': isLandscape,
|
||
|
|
'right-8px h-[calc(100vh-100px)]': !isLandscape,
|
||
|
|
}"
|
||
|
|
>
|
||
|
|
<QuickScorePanel
|
||
|
|
:is-landscape="isLandscape"
|
||
|
|
:full-score="12"
|
||
|
|
@score-selected="handleQuickScoreSelect"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- 打分设置弹窗 -->
|
||
|
|
<ScoreSettingsDialog
|
||
|
|
v-model="showScoreSettings"
|
||
|
|
:full-score="12"
|
||
|
|
@confirm="handleScoreSettingsConfirm"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</template>
|