xlx_teacher_app/src/components/marking/MarkingMonitor.vue

262 lines
9.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 阅卷监控组件 -->
<script lang="ts" setup>
import type { MarkingProgressResponse } from '@/service/types'
import { computed, onMounted, ref } from 'vue'
import { markingProgressUsingGet } from '@/service/yuejuanjindu'
defineOptions({
name: 'MarkingMonitor',
})
const props = defineProps<{
subjectId: number
}>()
// API数据
const markingData = ref<MarkingProgressResponse>()
const loading = ref(false)
const error = ref<string | null>(null)
// 计算总进度数据
const totalProgress = computed(() => {
const progress = markingData.value?.total_progress
if (!progress)
return { percentage: 0, completed: 0, total: 0 }
const total = (progress.marked_quantity || 0) + (progress.unmerged_quantity || 0)
const completed = progress.marked_quantity || 0
const percentage = total > 0 ? Math.round((completed / total) * 100) : 0
return { percentage, completed, total }
})
// 计算单评进度数据
const singleReviewProgress = computed(() => {
const progress = markingData.value?.single_progress
if (!progress)
return { percentage: 0, completed: 0, total: 0 }
const total = (progress.marked_quantity || 0) + (progress.unmerged_quantity || 0)
const completed = progress.marked_quantity || 0
const percentage = total > 0 ? Math.round((completed / total) * 100) : 0
return { percentage, completed, total }
})
// 计算终评进度数据
const finalReviewProgress = computed(() => {
const progress = markingData.value?.final_progress
if (!progress)
return { percentage: 0, completed: 0, total: 0 }
const total = (progress.marked_quantity || 0) + (progress.unmerged_quantity || 0)
const completed = progress.marked_quantity || 0
const percentage = total > 0 ? Math.round((completed / total) * 100) : 0
return { percentage, completed, total }
})
// 获取阅卷进度数据
async function fetchMarkingProgress() {
try {
loading.value = true
error.value = null
markingData.value = await markingProgressUsingGet({
params: {
exam_subject_id: props.subjectId,
},
})
}
catch (err) {
console.error('获取阅卷进度失败:', err)
error.value = '获取阅卷进度失败,请重试'
}
finally {
loading.value = false
}
}
// 计算剩余数量
function getRemaining(completed: number, total: number) {
return total - completed
}
// 跳转到阅卷进度页面
function navigateToProgress(questionId: number) {
uni.navigateTo({
url: `/pages/marking/marking-progress?examSubjectId=${props.subjectId}&questionId=${questionId}`,
})
}
// 跳转到阅卷质量页面
function navigateToQuality(questionId: number) {
uni.navigateTo({
url: `/pages/marking/marking-quality?examSubjectId=${props.subjectId}&questionId=${questionId}`,
})
}
// 组件挂载时获取数据
onMounted(() => {
fetchMarkingProgress()
})
</script>
<template>
<view class="p-2">
<!-- 三个进度环形图 -->
<view class="mx-2 mb-4 border border-slate-100 rounded-2xl bg-white p-6 shadow-md">
<view class="grid grid-cols-3 gap-4">
<!-- 总进度 -->
<view class="flex flex-col items-center">
<view class="relative mb-3 h-20 w-20">
<!-- 背景圆环 -->
<view class="absolute inset-0 border-4 border-gray-200 rounded-full" />
<!-- 进度圆环 -->
<view
class="absolute inset-0 transform border-4 border-blue-500 rounded-full -rotate-90"
:style="{
background: `conic-gradient(#3B82F6 ${totalProgress.percentage * 3.6}deg, transparent ${totalProgress.percentage * 3.6}deg)`,
borderRadius: '50%',
mask: 'radial-gradient(circle at center, transparent 32px, black 32px)',
WebkitMask: 'radial-gradient(circle at center, transparent 32px, black 32px)',
}"
/>
<!-- 百分比文字 -->
<view class="absolute inset-0 flex items-center justify-center">
<text class="text-lg font-bold">{{ totalProgress.percentage }}%</text>
</view>
</view>
<text class="mb-2 text-sm font-medium">总进度</text>
<text class="text-xs text-gray-600">已合分{{ totalProgress.completed }}</text>
<text class="text-xs text-gray-600">未合分{{ getRemaining(totalProgress.completed, totalProgress.total) }}</text>
</view>
<!-- 单评进度 -->
<view class="flex flex-col items-center">
<view class="relative mb-3 h-20 w-20">
<!-- 背景圆环 -->
<view class="absolute inset-0 border-4 border-gray-200 rounded-full" />
<!-- 进度圆环 -->
<view
class="absolute inset-0 transform border-4 border-green-500 rounded-full -rotate-90"
:style="{
background: `conic-gradient(#10B981 ${singleReviewProgress.percentage * 3.6}deg, transparent ${singleReviewProgress.percentage * 3.6}deg)`,
borderRadius: '50%',
mask: 'radial-gradient(circle at center, transparent 32px, black 32px)',
WebkitMask: 'radial-gradient(circle at center, transparent 32px, black 32px)',
}"
/>
<!-- 百分比文字 -->
<view class="absolute inset-0 flex items-center justify-center">
<text class="text-lg font-bold">{{ singleReviewProgress.percentage }}%</text>
</view>
</view>
<text class="mb-2 text-sm font-medium">单评进度</text>
<text class="text-xs text-gray-600">已阅卷{{ singleReviewProgress.completed }}</text>
<text class="text-xs text-gray-600">未合分{{ getRemaining(singleReviewProgress.completed, singleReviewProgress.total) }}</text>
</view>
<!-- 终评进度 -->
<view class="flex flex-col items-center">
<view class="relative mb-3 h-20 w-20">
<!-- 背景圆环 -->
<view class="absolute inset-0 border-4 border-gray-200 rounded-full" />
<!-- 进度圆环 -->
<view
class="absolute inset-0 transform border-4 border-orange-500 rounded-full -rotate-90"
:style="{
background: `conic-gradient(#F59E0B ${finalReviewProgress.percentage * 3.6}deg, transparent ${finalReviewProgress.percentage * 3.6}deg)`,
borderRadius: '50%',
mask: 'radial-gradient(circle at center, transparent 32px, black 32px)',
WebkitMask: 'radial-gradient(circle at center, transparent 32px, black 32px)',
}"
/>
<!-- 百分比文字 -->
<view class="absolute inset-0 flex items-center justify-center">
<text class="text-lg font-bold">{{ finalReviewProgress.percentage }}%</text>
</view>
</view>
<text class="mb-2 text-sm font-medium">终评进度</text>
<text class="text-xs text-gray-600">已阅卷{{ finalReviewProgress.completed }}</text>
<text class="text-xs text-gray-600">未合分{{ getRemaining(finalReviewProgress.completed, finalReviewProgress.total) }}</text>
</view>
</view>
</view>
<!-- 主观题列表 -->
<view class="mx-2">
<text class="mb-2 block text-lg font-semibold">主观题</text>
<!-- 加载状态 -->
<view v-if="loading" class="flex items-center justify-center py-8">
<text class="text-gray-500">加载中...</text>
</view>
<!-- 错误状态 -->
<view v-else-if="error" class="flex flex-col items-center justify-center py-8">
<text class="mb-2 text-red-500">{{ error }}</text>
<view
class="rounded-md bg-blue-100 px-4 py-2"
@click="fetchMarkingProgress"
>
<text class="text-blue-600">重新加载</text>
</view>
</view>
<!-- 主观题列表 -->
<view
v-for="question in markingData.questions"
v-else
:key="question.question_id"
class="mb-2 border border-slate-100 rounded-2xl bg-white p-4 shadow-md"
>
<!-- 题目信息 -->
<view class="mb-3 flex items-center justify-between">
<text class="text-base font-medium">{{ question.question_major }}.{{ question.question_minor }}</text>
<text class="text-sm text-gray-600">总分:{{ question.full_score }}分 平均分:{{ question.average_score }}分</text>
</view>
<!-- 进度条 -->
<view class="mb-3">
<view class="mb-2 flex items-center justify-between">
<text class="text-sm text-gray-600">阅卷进度</text>
<view class="h-4 w-[70%] rounded-full bg-gray-200">
<view
class="h-4 rounded-full bg-blue-500 transition-all duration-300"
:style="{ width: `${question.progress_percent}%` }"
/>
</view>
<!-- <text class="text-sm font-medium">{{ question.progress_percent }}%</text> -->
<text class="text-sm font-medium">{{ question.task_marked_num }}/{{ question.task_total_num }}</text>
</view>
<!-- <view class="mt-1 flex justify-center">
<text class="text-xs text-gray-500">{{ question.task_marked_num }}/{{ question.task_total_num }}</text>
</view> -->
</view>
<!-- 操作按钮 -->
<view class="flex items-center justify-end space-x-3">
<view
class="rounded-md bg-orange-100 px-3 py-1"
@click="navigateToProgress(question.question_id)"
>
<text class="flex items-center text-sm text-orange-600">
阅卷进度
</text>
</view>
<view
class="rounded-md bg-blue-100 px-3 py-1"
@click="navigateToQuality(question.question_id)"
>
<text class="flex items-center text-sm text-blue-600">
阅卷质量
</text>
</view>
</view>
</view>
</view>
</view>
</template>