fix: 除了没接口的部分,其他大体完成
continuous-integration/drone/push Build is failing Details

This commit is contained in:
张哲铜 2025-10-07 16:45:10 +08:00
parent 95e05b37d6
commit dece1db47c
2 changed files with 61 additions and 75 deletions

View File

@ -191,8 +191,9 @@ onMounted(async () => {
<!-- 班次/校次列 --> <!-- 班次/校次列 -->
<wd-table-col prop="rank" label="班次/校次" :width="`${40}%`"> <wd-table-col prop="rank" label="班次/校次" :width="`${40}%`">
<template #value="{ row }"> <template #value="{ row }">
<view class="text-xs"> <view class="flex gap-2 text-xs">
<view>{{ row.class_rank || '--' }}</view> <view>{{ row.class_rank || '--' }}</view>
/
<view class="text-gray-500"> <view class="text-gray-500">
{{ row.grade_rank || '--' }} {{ row.grade_rank || '--' }}
</view> </view>

View File

@ -23,8 +23,6 @@ import {
import { useHomeStore } from '@/store/home' import { useHomeStore } from '@/store/home'
// //
type ExamComparisonItem = API.ExamComparisonItem
type RankStatisticsItem = API.RankStatisticsItem
type KeyStudentInfo = API.KeyStudentInfo type KeyStudentInfo = API.KeyStudentInfo
defineOptions({ defineOptions({
@ -161,7 +159,7 @@ const {
scoreSettings.value.top_n, scoreSettings.value.top_n,
]), ]),
queryFn: async () => { queryFn: async () => {
const response = await teacherAnalysisRecentExamStatsUsingPost({ return await teacherAnalysisRecentExamStatsUsingPost({
body: { body: {
class_key: homeStore.selectedClassId, class_key: homeStore.selectedClassId,
exam_id: homeStore.selectedExamId, exam_id: homeStore.selectedExamId,
@ -172,38 +170,14 @@ const {
pass_scoring_rate: scoreSettings.value.pass_scoring_rate, pass_scoring_rate: scoreSettings.value.pass_scoring_rate,
top_n: scoreSettings.value.top_n, top_n: scoreSettings.value.top_n,
}, },
}) as any })
if (response?.data) {
const data = response.data
return {
examCount: data.class_total_count || 0,
averageScore: Math.round(data.class_average_score || 0),
totalScore: data.full_score || 100,
highestScore: data.class_highest_score || 0,
lowestScore: data.class_lowest_score || 0,
excellentRate: Math.round((data.excellent_class_scoring_rate || 0) * 100),
goodRate: Math.round((data.good_class_scoring_rate || 0) * 100),
passRate: Math.round((data.pass_class_scoring_rate || 0) * 100),
}
}
return {
examCount: 0,
averageScore: 0,
totalScore: 100,
highestScore: 0,
lowestScore: 0,
excellentRate: 0,
goodRate: 0,
passRate: 0,
}
}, },
enabled: isQueryEnabled, enabled: isQueryEnabled,
staleTime: 30000, // 30 staleTime: 30000, // 30
}) })
// 使 TanStack Query type ExamComparisonItem = API.ExamComparisonItem & API.ExamComparisonItemH
const { const {
data: comparisonData, data: comparisonData,
isLoading: isLoadingComparison, isLoading: isLoadingComparison,
@ -218,26 +192,23 @@ const {
]), ]),
queryFn: async () => { queryFn: async () => {
if (comparisonMode.value === 'horizontal') { if (comparisonMode.value === 'horizontal') {
const response = await teacherAnalysisClassExamComparisonHorizontalUsingPost({ return (await teacherAnalysisClassExamComparisonHorizontalUsingPost({
body: { body: {
exam_id: homeStore.selectedExamId, exam_id: homeStore.selectedExamId,
class_key: homeStore.selectedClassId, class_key: homeStore.selectedClassId,
grade_key: homeStore.selectedGradeKey, grade_key: homeStore.selectedGradeKey,
subject_id: selectedSubjectId.value || undefined, subject_id: selectedSubjectId.value || undefined,
}, },
}) })).exam_list as ExamComparisonItem[] || []
return []
} }
else { else {
const response = await teacherAnalysisClassExamComparisonUsingPost({ return (await teacherAnalysisClassExamComparisonUsingPost({
body: { body: {
class_key: homeStore.selectedClassId, class_key: homeStore.selectedClassId,
grade_key: homeStore.selectedGradeKey, grade_key: homeStore.selectedGradeKey,
subject_id: selectedSubjectId.value || undefined, subject_id: selectedSubjectId.value || undefined,
}, },
}) as any })).exam_list as ExamComparisonItem[] || []
return response?.exam_list || []
} }
}, },
enabled: computed(() => !!homeStore.selectedClassId && !!homeStore.selectedGradeKey), enabled: computed(() => !!homeStore.selectedClassId && !!homeStore.selectedGradeKey),
@ -255,25 +226,33 @@ const {
homeStore.selectedClassId, homeStore.selectedClassId,
homeStore.selectedExamId, homeStore.selectedExamId,
selectedSubjectId.value, selectedSubjectId.value,
scoreSettings.value.rank_top_1,
scoreSettings.value.rank_top_2,
scoreSettings.value.rank_top_3,
]), ]),
queryFn: async () => { queryFn: async () => {
const classIds = selectedClassIds.value.length > 0 const classIds = selectedClassIds.value.length > 0
? selectedClassIds.value.map(id => Number.parseInt(id)) ? selectedClassIds.value
: (homeStore.selectedClassId ? [homeStore.selectedClassId] : []) : (homeStore.selectedClassId ? [homeStore.selectedClassId.toString()] : [])
if (classIds.length === 0) { if (classIds.length === 0) {
return [] return []
} }
const response = await teacherAnalysisRankStatisticsUsingPost({ return (await teacherAnalysisRankStatisticsUsingPost({
body: { body: {
class_id: classIds[0], class_ids: classIds,
exam_id: homeStore.selectedExamId, exam_id: homeStore.selectedExamId,
subject_id: selectedSubjectId.value || undefined, subject_id: selectedSubjectId.value || 0,
query_mode: 'class',
statistics_mode: 'cumulative',
rank_ranges: [
{ name: `${scoreSettings.value.rank_top_1}`, start: 1, end: scoreSettings.value.rank_top_1 },
{ name: `${scoreSettings.value.rank_top_2}`, start: 1, end: scoreSettings.value.rank_top_2 },
{ name: `${scoreSettings.value.rank_top_3}`, start: 1, end: scoreSettings.value.rank_top_3 },
],
}, },
}) as any })).data as any || []
return response?.data || []
}, },
enabled: computed(() => !!homeStore.selectedExamId), enabled: computed(() => !!homeStore.selectedExamId),
staleTime: 30000, staleTime: 30000,
@ -503,7 +482,7 @@ const loading = computed(() =>
<view class="mb-2 flex items-center"> <view class="mb-2 flex items-center">
<text class="text-xs text-slate-600">考试人数</text> <text class="text-xs text-slate-600">考试人数</text>
</view> </view>
<text class="text-lg text-slate-800 font-bold">{{ statsData?.examCount || 0 }}</text> <text class="text-lg text-slate-800 font-bold">{{ statsData?.class_total_count || 0 }}</text>
</view> </view>
<!-- 平均分/满分 --> <!-- 平均分/满分 -->
@ -511,7 +490,7 @@ const loading = computed(() =>
<view class="mb-2 flex items-center"> <view class="mb-2 flex items-center">
<text class="text-xs text-slate-600">平均分/满分</text> <text class="text-xs text-slate-600">平均分/满分</text>
</view> </view>
<text class="text-lg text-slate-800 font-bold">{{ statsData?.averageScore || 0 }}/{{ statsData?.totalScore || 100 }}</text> <text class="text-lg text-slate-800 font-bold">{{ Math.round(statsData?.class_average_score || 0) }}/{{ statsData?.full_score || 100 }}</text>
</view> </view>
<!-- 最高分/最低分 --> <!-- 最高分/最低分 -->
@ -519,7 +498,7 @@ const loading = computed(() =>
<view class="mb-2 flex items-center"> <view class="mb-2 flex items-center">
<text class="text-xs text-slate-600">最高分/最低分</text> <text class="text-xs text-slate-600">最高分/最低分</text>
</view> </view>
<text class="text-lg text-slate-800 font-bold">{{ statsData?.highestScore || 0 }}/{{ statsData?.lowestScore || 0 }}</text> <text class="text-lg text-slate-800 font-bold">{{ statsData?.class_highest_score || 0 }}/{{ statsData?.class_lowest_score || 0 }}</text>
</view> </view>
<!-- 优秀率 --> <!-- 优秀率 -->
@ -527,7 +506,7 @@ const loading = computed(() =>
<view class="mb-2 flex items-center"> <view class="mb-2 flex items-center">
<text class="text-xs text-slate-600">优秀率</text> <text class="text-xs text-slate-600">优秀率</text>
</view> </view>
<text class="text-lg text-slate-800 font-bold">{{ statsData?.excellentRate || 0 }}%</text> <text class="text-lg text-slate-800 font-bold">{{ Math.round((statsData?.excellent_class_scoring_rate || 0) * 100) }}%</text>
</view> </view>
<!-- 良好率 --> <!-- 良好率 -->
@ -535,7 +514,7 @@ const loading = computed(() =>
<view class="mb-2 flex items-center"> <view class="mb-2 flex items-center">
<text class="text-xs text-slate-600">良好率</text> <text class="text-xs text-slate-600">良好率</text>
</view> </view>
<text class="text-lg text-slate-800 font-bold">{{ statsData?.goodRate || 0 }}%</text> <text class="text-lg text-slate-800 font-bold">{{ Math.round((statsData?.good_class_scoring_rate || 0) * 100) }}%</text>
</view> </view>
<!-- 及格率 --> <!-- 及格率 -->
@ -543,7 +522,7 @@ const loading = computed(() =>
<view class="mb-2 flex items-center"> <view class="mb-2 flex items-center">
<text class="text-xs text-slate-600">及格率</text> <text class="text-xs text-slate-600">及格率</text>
</view> </view>
<text class="text-lg text-slate-800 font-bold">{{ statsData?.passRate || 0 }}%</text> <text class="text-lg text-slate-800 font-bold">{{ Math.round((statsData?.pass_class_scoring_rate || 0) * 100) }}%</text>
</view> </view>
</view> </view>
@ -589,29 +568,28 @@ const loading = computed(() =>
{{ comparisonMode === 'horizontal' ? '学科' : '考试' }} {{ comparisonMode === 'horizontal' ? '学科' : '考试' }}
</text> </text>
<text class="text-sm text-gray-600 font-medium">班级平均分</text> <text class="text-sm text-gray-600 font-medium">班级平均分</text>
<text class="text-sm text-gray-600 font-medium">年级平均分</text> <text class="text-sm text-gray-600 font-medium">{{ comparisonMode === 'horizontal' ? '年级平均分' : '平均分排名' }}</text>
<text class="text-sm text-gray-600 font-medium">班级排名</text> <text class="text-sm text-gray-600 font-medium">{{ comparisonMode === 'horizontal' ? '班级排名' : '班级标准分' }}</text>
</view> </view>
</view> </view>
<!-- 对比数据列表 -->
<!-- 暂无数据提示 -->
<view v-if="comparisonData.length === 0" class="py-8 text-center">
<text class="text-sm text-gray-500">暂无对比数据</text>
</view>
<!-- 对比数据列表 --> <view v-else class="space-y-2">
<view class="space-y-2">
<view <view
v-for="(item, index) in comparisonData" v-for="(item, index) in comparisonData"
:key="index" :key="index"
class="grid grid-cols-4 gap-2 border-b border-gray-100 py-2 text-center last:border-b-0" class="grid grid-cols-4 gap-2 border-b border-gray-100 py-2 text-center last:border-b-0"
> >
<text class="text-sm text-gray-800">{{ item.exam_name || '-' }}</text> <text class="text-ellipsis text-sm text-gray-800">{{ comparisonMode === 'horizontal' ? item.subject_name : item.exam_name || '-' }}</text>
<text class="text-sm text-gray-800 font-medium">{{ item.class_average || '-' }}</text> <text class="text-ellipsis text-sm text-gray-800 font-medium">{{ item.class_average || '-' }}</text>
<text class="text-sm text-gray-600">{{ item.class_standard || '-' }}</text> <text class="text-ellipsis text-sm text-gray-600">{{ comparisonMode === 'horizontal' ? item.grade_average || '-' : item.average_rank || '-' }}</text>
<text class="text-sm text-gray-600">{{ item.average_rank || '-' }}</text> <text class="text-ellipsis text-sm text-gray-600">{{ comparisonMode === 'horizontal' ? item.class_rank || '-' : item.class_standard || '-' }}</text>
</view> </view>
</view> </view>
<!-- 暂无数据提示 -->
<view v-if="!comparisonData || comparisonData.length === 0" class="py-8 text-center">
<text class="text-sm text-gray-500">暂无对比数据</text>
</view>
</view> </view>
<!-- 名次分析卡片 --> <!-- 名次分析卡片 -->
@ -646,14 +624,14 @@ const loading = computed(() =>
:key="index" :key="index"
class="grid grid-cols-4 gap-2 border-b border-gray-100 py-2 text-center last:border-b-0" class="grid grid-cols-4 gap-2 border-b border-gray-100 py-2 text-center last:border-b-0"
> >
<text class="text-sm text-gray-800 font-medium">{{ item.name || '-' }}</text> <text class="text-ellipsis text-sm text-gray-800 font-medium">{{ item.name || '-' }}</text>
<text class="text-sm text-gray-800"> <text class="text-ellipsis text-sm text-gray-800">
{{ item.rank_stats?.find(r => r.end === scoreSettings.rank_top_1)?.count || 0 }} {{ item.rank_stats?.find(r => r.end === scoreSettings.rank_top_1)?.count || 0 }}
</text> </text>
<text class="text-sm text-gray-800"> <text class="text-ellipsis text-sm text-gray-800">
{{ item.rank_stats?.find(r => r.end === scoreSettings.rank_top_2)?.count || 0 }} {{ item.rank_stats?.find(r => r.end === scoreSettings.rank_top_2)?.count || 0 }}
</text> </text>
<text class="text-sm text-gray-800"> <text class="text-ellipsis text-sm text-gray-800">
{{ item.rank_stats?.find(r => r.end === scoreSettings.rank_top_3)?.count || 0 }} {{ item.rank_stats?.find(r => r.end === scoreSettings.rank_top_3)?.count || 0 }}
</text> </text>
</view> </view>
@ -717,10 +695,10 @@ const loading = computed(() =>
:key="index" :key="index"
class="grid grid-cols-3 gap-2 border-b border-gray-100 py-2 text-center last:border-b-0" class="grid grid-cols-3 gap-2 border-b border-gray-100 py-2 text-center last:border-b-0"
> >
<text class="text-sm text-gray-800 font-medium">{{ student.student_name || '-' }}</text> <text class="text-ellipsis text-sm text-gray-800 font-medium">{{ student.student_name || '-' }}</text>
<text class="text-sm text-gray-800">{{ student.class_rank || '-' }}</text> <text class="text-ellipsis text-sm text-gray-800">{{ student.class_rank || '-' }}</text>
<text <text
class="text-sm font-medium" class="text-ellipsis text-sm font-medium"
:class="keyStudentType === 'up' ? 'text-green-600' : 'text-red-600'" :class="keyStudentType === 'up' ? 'text-green-600' : 'text-red-600'"
> >
{{ keyStudentType === 'up' ? '+' : '-' }}{{ student.class_diff_rank || 0 }} {{ keyStudentType === 'up' ? '+' : '-' }}{{ student.class_diff_rank || 0 }}
@ -791,10 +769,10 @@ const loading = computed(() =>
:key="index" :key="index"
class="grid grid-cols-3 gap-2 p-4 text-center" class="grid grid-cols-3 gap-2 p-4 text-center"
> >
<text class="text-sm text-gray-800 font-medium">{{ student.student_name || '-' }}</text> <text class="text-ellipsis text-sm text-gray-800 font-medium">{{ student.student_name || '-' }}</text>
<text class="text-sm text-gray-800">{{ student.class_rank || '-' }}</text> <text class="text-ellipsis text-sm text-gray-800">{{ student.class_rank || '-' }}</text>
<text <text
class="text-sm font-medium" class="text-ellipsis text-sm font-medium"
:class="keyStudentType === 'up' ? 'text-green-600' : 'text-red-600'" :class="keyStudentType === 'up' ? 'text-green-600' : 'text-red-600'"
> >
{{ keyStudentType === 'up' ? '+' : '-' }}{{ student.class_diff_rank || 0 }} {{ keyStudentType === 'up' ? '+' : '-' }}{{ student.class_diff_rank || 0 }}
@ -839,4 +817,11 @@ const loading = computed(() =>
white-space: nowrap; white-space: nowrap;
} }
} }
//
.text-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style> </style>