fix: 增加缓存和修复查看成绩部分问题
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
fee76ec061
commit
115d118d42
|
|
@ -0,0 +1,79 @@
|
||||||
|
import { useUserStore } from '@/store/user'
|
||||||
|
import { watch } from 'vue'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于用户ID的响应式存储
|
||||||
|
* 自动根据当前登录用户隔离数据
|
||||||
|
*
|
||||||
|
* @param key - 存储键名
|
||||||
|
* @param defaultValue - 默认值
|
||||||
|
* @returns 响应式引用
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const selectedExamId = useUserStorage('selectedExamId', 0);
|
||||||
|
* // 使用方式和普通 ref 完全一样
|
||||||
|
* selectedExamId.value = 123;
|
||||||
|
*/
|
||||||
|
export function useUserStorage<T>(key: string, defaultValue: T) {
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const valueRef = ref<T>(defaultValue)
|
||||||
|
|
||||||
|
// 生成基于用户ID的存储键
|
||||||
|
const getStorageKey = () => {
|
||||||
|
const userId = userStore.info?.id || 'default'
|
||||||
|
return `user_${userId}_${key}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从 uni.storage 加载数据
|
||||||
|
const loadFromStorage = () => {
|
||||||
|
const storageKey = getStorageKey()
|
||||||
|
const stored = uni.getStorageSync(storageKey)
|
||||||
|
|
||||||
|
if (stored) {
|
||||||
|
try {
|
||||||
|
valueRef.value = JSON.parse(stored)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
// 如果是数字类型,直接转换
|
||||||
|
if (typeof defaultValue === 'number') {
|
||||||
|
valueRef.value = Number(stored) as T
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
valueRef.value = stored as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
valueRef.value = defaultValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存到 uni.storage
|
||||||
|
const saveToStorage = (value: T) => {
|
||||||
|
const storageKey = getStorageKey()
|
||||||
|
if (value === undefined || value === null || value === 0 || value === '') {
|
||||||
|
uni.removeStorageSync(storageKey)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const toStore = typeof value === 'object' ? JSON.stringify(value) : String(value)
|
||||||
|
uni.setStorageSync(storageKey, toStore)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听值变化,自动保存
|
||||||
|
watch(valueRef, (newValue) => {
|
||||||
|
saveToStorage(newValue)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 监听用户变化,自动重新加载
|
||||||
|
watch(
|
||||||
|
() => userStore.info?.id,
|
||||||
|
() => {
|
||||||
|
loadFromStorage()
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
|
||||||
|
return valueRef
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type * as API from '@/service/types'
|
import type * as API from '@/service/types'
|
||||||
import { useQuery, useQueryClient } from '@tanstack/vue-query'
|
import { useQuery, useQueryClient } from '@tanstack/vue-query'
|
||||||
|
import { whenever } from '@vueuse/core'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import OverviewSettingsDialog from '@/components/score/OverviewSettingsDialog.vue'
|
import OverviewSettingsDialog from '@/components/score/OverviewSettingsDialog.vue'
|
||||||
import RankSettingsDialog from '@/components/score/RankSettingsDialog.vue'
|
import RankSettingsDialog from '@/components/score/RankSettingsDialog.vue'
|
||||||
|
|
@ -73,9 +74,6 @@ const showRankSettingsDialog = ref(false)
|
||||||
// 进步/退步学生显示数量(基础显示)
|
// 进步/退步学生显示数量(基础显示)
|
||||||
const keyStudentCount = ref(5)
|
const keyStudentCount = ref(5)
|
||||||
|
|
||||||
// 分页大小(展开后使用)
|
|
||||||
const pageSize = ref(20)
|
|
||||||
|
|
||||||
// 考试选择选项
|
// 考试选择选项
|
||||||
const examOptions = computed(() => homeStore.examOptions.map(exam => ({
|
const examOptions = computed(() => homeStore.examOptions.map(exam => ({
|
||||||
label: exam.label,
|
label: exam.label,
|
||||||
|
|
@ -88,14 +86,6 @@ const classColumns = computed(() => homeStore.classOptions.map(cls => ({
|
||||||
value: cls.value.toString(), // 转为字符串类型
|
value: cls.value.toString(), // 转为字符串类型
|
||||||
})))
|
})))
|
||||||
|
|
||||||
// 当前选中的考试ID
|
|
||||||
const selectedExamId = computed({
|
|
||||||
get: () => homeStore.selectedExamId,
|
|
||||||
set: (value) => {
|
|
||||||
homeStore.onExamChange(value)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// 当前选中的考试名称
|
// 当前选中的考试名称
|
||||||
const selectedExamName = computed(() => {
|
const selectedExamName = computed(() => {
|
||||||
if (!homeStore.selectedExamId) {
|
if (!homeStore.selectedExamId) {
|
||||||
|
|
@ -247,9 +237,9 @@ const {
|
||||||
query_mode: 'class',
|
query_mode: 'class',
|
||||||
statistics_mode: 'cumulative',
|
statistics_mode: 'cumulative',
|
||||||
rank_ranges: [
|
rank_ranges: [
|
||||||
{ name: `前${scoreSettings.value.rank_top_1}名`, start: 1, end: scoreSettings.value.rank_top_1 },
|
{ name: `前${scoreSettings.value.rank_top_1}名`, start: 1, end: Number(scoreSettings.value.rank_top_1) },
|
||||||
{ name: `前${scoreSettings.value.rank_top_2}名`, start: 1, end: scoreSettings.value.rank_top_2 },
|
{ name: `前${scoreSettings.value.rank_top_2}名`, start: 1, end: Number(scoreSettings.value.rank_top_2) },
|
||||||
{ name: `前${scoreSettings.value.rank_top_3}名`, start: 1, end: scoreSettings.value.rank_top_3 },
|
{ name: `前${scoreSettings.value.rank_top_3}名`, start: 1, end: Number(scoreSettings.value.rank_top_3) },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
})).data as any || []
|
})).data as any || []
|
||||||
|
|
@ -258,39 +248,6 @@ const {
|
||||||
staleTime: 30000,
|
staleTime: 30000,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 使用 TanStack Query 获取重点学生数据(基础显示)
|
|
||||||
const {
|
|
||||||
data: keyStudentsData,
|
|
||||||
isLoading: isLoadingKeyStudents,
|
|
||||||
} = useQuery({
|
|
||||||
queryKey: computed(() => [
|
|
||||||
'key-students',
|
|
||||||
homeStore.selectedClassId,
|
|
||||||
homeStore.selectedExamId,
|
|
||||||
homeStore.selectedGradeKey,
|
|
||||||
selectedSubjectId.value,
|
|
||||||
keyStudentType.value,
|
|
||||||
keyStudentCount.value,
|
|
||||||
]),
|
|
||||||
queryFn: async () => {
|
|
||||||
const response = await teacherAnalysisKeyStudentUsingPost({
|
|
||||||
body: {
|
|
||||||
class_key: homeStore.selectedClassId,
|
|
||||||
exam_id: homeStore.selectedExamId,
|
|
||||||
grade_key: homeStore.selectedGradeKey,
|
|
||||||
subject_id: selectedSubjectId.value || undefined,
|
|
||||||
emphasis_type: keyStudentType.value,
|
|
||||||
page: 1,
|
|
||||||
page_size: keyStudentCount.value,
|
|
||||||
},
|
|
||||||
}) as any
|
|
||||||
|
|
||||||
return response?.list || []
|
|
||||||
},
|
|
||||||
enabled: computed(() => isQueryEnabled.value && !showMoreStudents.value),
|
|
||||||
staleTime: 30000,
|
|
||||||
})
|
|
||||||
|
|
||||||
// 获取重点学生数据(分页加载)
|
// 获取重点学生数据(分页加载)
|
||||||
async function fetchKeyStudentsPaging(pageNo: number, pageSize: number) {
|
async function fetchKeyStudentsPaging(pageNo: number, pageSize: number) {
|
||||||
if (!homeStore.selectedClassId || !homeStore.selectedExamId || !homeStore.selectedGradeKey) {
|
if (!homeStore.selectedClassId || !homeStore.selectedExamId || !homeStore.selectedGradeKey) {
|
||||||
|
|
@ -307,7 +264,7 @@ async function fetchKeyStudentsPaging(pageNo: number, pageSize: number) {
|
||||||
subject_id: selectedSubjectId.value || undefined,
|
subject_id: selectedSubjectId.value || undefined,
|
||||||
emphasis_type: keyStudentType.value,
|
emphasis_type: keyStudentType.value,
|
||||||
page: pageNo,
|
page: pageNo,
|
||||||
page_size: pageSize,
|
page_size: Number(pageSize),
|
||||||
},
|
},
|
||||||
}) as any
|
}) as any
|
||||||
|
|
||||||
|
|
@ -331,7 +288,7 @@ function goBack() {
|
||||||
|
|
||||||
// 考试选择变化处理
|
// 考试选择变化处理
|
||||||
function handleExamChange(event: { value: string | number, selectedItem: Record<string, any> }) {
|
function handleExamChange(event: { value: string | number, selectedItem: Record<string, any> }) {
|
||||||
selectedExamId.value = typeof event.value === 'string' ? Number.parseInt(event.value) : event.value
|
homeStore.selectedExamId = typeof event.value === 'string' ? Number.parseInt(event.value) : event.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// 科目切换处理
|
// 科目切换处理
|
||||||
|
|
@ -397,25 +354,11 @@ function toggleKeyStudentType(type: 'up' | 'down') {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示更多进步/退步学生
|
|
||||||
function handleShowMoreKeyStudents() {
|
|
||||||
if (!homeStore.selectedClassId || !homeStore.selectedExamId || !homeStore.selectedGradeKey) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '请先选择班级和考试',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
showMoreStudents.value = true
|
|
||||||
setTimeout(() => {
|
|
||||||
keyStudentsPaging.value?.reload()
|
|
||||||
}, 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 收起更多学生列表
|
// 收起更多学生列表
|
||||||
function handleHideMoreKeyStudents() {
|
function handleHideMoreKeyStudents() {
|
||||||
showMoreStudents.value = false
|
showMoreStudents.value = false
|
||||||
|
// 清空列表数据
|
||||||
|
keyStudentsList.value = []
|
||||||
}
|
}
|
||||||
|
|
||||||
// 班级选择变化处理
|
// 班级选择变化处理
|
||||||
|
|
@ -423,336 +366,272 @@ function handleClassChange({ value }: { value: string[] }) {
|
||||||
selectedClassIds.value = value
|
selectedClassIds.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载状态
|
whenever(() => [selectedSubjectId.value, homeStore.selectedExamId, keyStudentType.value, keyStudentCount.value], () => {
|
||||||
const loading = computed(() =>
|
keyStudentsPaging.value?.reload()
|
||||||
isLoadingStats.value || isLoadingComparison.value || isLoadingRank.value || isLoadingKeyStudents.value,
|
})
|
||||||
)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="score-page min-h-screen bg-slate-50">
|
<view class="score-page min-h-screen bg-slate-50">
|
||||||
<!-- 导航栏 -->
|
<!-- z-paging 包裹整个内容 -->
|
||||||
<wd-navbar placeholder fixed>
|
<z-paging
|
||||||
<template #left>
|
ref="keyStudentsPaging"
|
||||||
<div class="flex items-center" @tap="goBack">
|
v-model="keyStudentsList"
|
||||||
<wd-icon name="arrow-left" size="20px" />
|
:default-page-size="keyStudentCount"
|
||||||
</div>
|
:refresher-enabled="true"
|
||||||
</template>
|
:auto="true"
|
||||||
<template #title>
|
@query="fetchKeyStudentsPaging"
|
||||||
<div class="title items-center">
|
|
||||||
<wd-drop-menu>
|
|
||||||
<wd-drop-menu-item
|
|
||||||
v-model="selectedExamId"
|
|
||||||
:options="examOptions"
|
|
||||||
@change="handleExamChange"
|
|
||||||
/>
|
|
||||||
</wd-drop-menu>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</wd-navbar>
|
|
||||||
|
|
||||||
<!-- 科目选择标签栏 -->
|
|
||||||
<wd-tabs
|
|
||||||
v-model="activeTab"
|
|
||||||
sticky
|
|
||||||
class="bg-white"
|
|
||||||
@click="handleTabClick"
|
|
||||||
>
|
>
|
||||||
<wd-tab
|
<template #top>
|
||||||
v-for="tab in subjectTabs"
|
<!-- 导航栏 -->
|
||||||
:key="tab.name"
|
<wd-navbar placeholder fixed>
|
||||||
:name="tab.name"
|
<template #left>
|
||||||
:title="tab.title"
|
<div class="flex items-center" @tap="goBack">
|
||||||
/>
|
<wd-icon name="arrow-left" size="20px" />
|
||||||
</wd-tabs>
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #title>
|
||||||
|
<div class="title items-center">
|
||||||
|
<wd-drop-menu>
|
||||||
|
<wd-drop-menu-item
|
||||||
|
v-model="homeStore.selectedExamId"
|
||||||
|
:options="homeStore.examOptions"
|
||||||
|
@change="handleExamChange"
|
||||||
|
/>
|
||||||
|
</wd-drop-menu>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</wd-navbar>
|
||||||
|
|
||||||
<!-- 主要内容区域 -->
|
<!-- 科目选择标签栏 -->
|
||||||
<view class="p-4 space-y-4">
|
<wd-tabs
|
||||||
<!-- 整体概况卡片 -->
|
v-model="activeTab"
|
||||||
<view class="rounded-xl bg-white p-3 shadow-sm">
|
sticky
|
||||||
<view class="mb-4 flex items-center justify-between">
|
class="bg-white"
|
||||||
<text class="text-lg text-slate-800 font-semibold">整体概况</text>
|
@click="handleTabClick"
|
||||||
<view class="i-mingcute:filter-line text-lg text-cyan-500" @tap="handleOverviewSettings" />
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 统计数据网格 - 2行3列 -->
|
|
||||||
<view class="grid grid-cols-3 gap-1">
|
|
||||||
<!-- 考试人数 -->
|
|
||||||
<view class="border border-blue-100 rounded-xl from-white to-blue-50 bg-gradient-to-br p-3">
|
|
||||||
<view class="mb-2 flex items-center">
|
|
||||||
<text class="text-xs text-slate-600">考试人数</text>
|
|
||||||
</view>
|
|
||||||
<text class="text-lg text-slate-800 font-bold">{{ statsData?.class_total_count || 0 }}</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 平均分/满分 -->
|
|
||||||
<view class="border border-blue-100 rounded-xl from-white to-blue-50 bg-gradient-to-br p-3">
|
|
||||||
<view class="mb-2 flex items-center">
|
|
||||||
<text class="text-xs text-slate-600">平均分/满分</text>
|
|
||||||
</view>
|
|
||||||
<text class="text-lg text-slate-800 font-bold">{{ Math.round(statsData?.class_average_score || 0) }}/{{ statsData?.full_score || 100 }}</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 最高分/最低分 -->
|
|
||||||
<view class="border border-cyan-100 rounded-xl from-white to-cyan-50 bg-gradient-to-br p-3">
|
|
||||||
<view class="mb-2 flex items-center">
|
|
||||||
<text class="text-xs text-slate-600">最高分/最低分</text>
|
|
||||||
</view>
|
|
||||||
<text class="text-lg text-slate-800 font-bold">{{ statsData?.class_highest_score || 0 }}/{{ statsData?.class_lowest_score || 0 }}</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 优秀率 -->
|
|
||||||
<view class="border border-sky-100 rounded-xl from-white to-sky-50 bg-gradient-to-br p-3">
|
|
||||||
<view class="mb-2 flex items-center">
|
|
||||||
<text class="text-xs text-slate-600">优秀率</text>
|
|
||||||
</view>
|
|
||||||
<text class="text-lg text-slate-800 font-bold">{{ Math.round((statsData?.excellent_class_scoring_rate || 0) * 100) }}%</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 良好率 -->
|
|
||||||
<view class="border border-sky-100 rounded-xl from-white to-sky-50 bg-gradient-to-br p-3">
|
|
||||||
<view class="mb-2 flex items-center">
|
|
||||||
<text class="text-xs text-slate-600">良好率</text>
|
|
||||||
</view>
|
|
||||||
<text class="text-lg text-slate-800 font-bold">{{ Math.round((statsData?.good_class_scoring_rate || 0) * 100) }}%</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 及格率 -->
|
|
||||||
<view class="border border-blue-100 rounded-xl from-white to-blue-50 bg-gradient-to-br p-3">
|
|
||||||
<view class="mb-2 flex items-center">
|
|
||||||
<text class="text-xs text-slate-600">及格率</text>
|
|
||||||
</view>
|
|
||||||
<text class="text-lg text-slate-800 font-bold">{{ Math.round((statsData?.pass_class_scoring_rate || 0) * 100) }}%</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 查看成绩单按钮 -->
|
|
||||||
<view class="mt-6">
|
|
||||||
<wd-button
|
|
||||||
type="primary"
|
|
||||||
size="medium"
|
|
||||||
class="w-full"
|
|
||||||
@click="handleViewScoreList"
|
|
||||||
>
|
|
||||||
查看成绩单
|
|
||||||
</wd-button>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 学科均分对比卡片 -->
|
|
||||||
<view class="rounded-xl bg-white p-4 shadow-sm">
|
|
||||||
<view class="mb-4 flex items-center justify-between">
|
|
||||||
<text class="text-lg text-slate-800 font-semibold">学科均分对比</text>
|
|
||||||
<view class="flex items-center gap-2">
|
|
||||||
<text
|
|
||||||
class="rounded px-2 py-1 text-sm"
|
|
||||||
:class="comparisonMode === 'horizontal' ? 'bg-blue-100 text-blue-600' : 'text-gray-500'"
|
|
||||||
@tap="toggleComparisonMode('horizontal')"
|
|
||||||
>
|
|
||||||
横向
|
|
||||||
</text>
|
|
||||||
<text
|
|
||||||
class="rounded px-2 py-1 text-sm"
|
|
||||||
:class="comparisonMode === 'vertical' ? 'bg-blue-100 text-blue-600' : 'text-gray-500'"
|
|
||||||
@tap="toggleComparisonMode('vertical')"
|
|
||||||
>
|
|
||||||
纵向
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 对比数据表头 -->
|
|
||||||
<view class="mb-2 border-b border-gray-200 pb-2">
|
|
||||||
<view class="grid grid-cols-4 gap-2 text-center">
|
|
||||||
<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>
|
|
||||||
<text class="text-sm text-gray-600 font-medium">{{ comparisonMode === 'horizontal' ? '班级排名' : '班级标准分' }}</text>
|
|
||||||
</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
|
|
||||||
v-for="(item, index) in comparisonData"
|
|
||||||
:key="index"
|
|
||||||
class="grid grid-cols-4 gap-2 border-b border-gray-100 py-2 text-center last:border-b-0"
|
|
||||||
>
|
|
||||||
<text class="text-ellipsis text-sm text-gray-800">{{ comparisonMode === 'horizontal' ? item.subject_name : item.exam_name || '-' }}</text>
|
|
||||||
<text class="text-ellipsis text-sm text-gray-800 font-medium">{{ item.class_average || '-' }}</text>
|
|
||||||
<text class="text-ellipsis text-sm text-gray-600">{{ comparisonMode === 'horizontal' ? item.grade_average || '-' : 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 class="rounded-xl bg-white p-4 shadow-sm">
|
|
||||||
<view class="mb-4 flex items-center justify-between">
|
|
||||||
<text class="no-wrap w-fit flex-shrink-0 text-lg text-slate-800 font-semibold">名次分析</text>
|
|
||||||
<!-- 班级多选 -->
|
|
||||||
<wd-select-picker
|
|
||||||
v-model="selectedClassIds"
|
|
||||||
class="classes-picker flex-grow"
|
|
||||||
:columns="classColumns"
|
|
||||||
:show-confirm="false"
|
|
||||||
@confirm="handleClassChange"
|
|
||||||
/>
|
|
||||||
<view class="i-mingcute:filter-line text-lg text-cyan-500" @tap="handleRankSettings" />
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 名次统计表头 -->
|
|
||||||
<view class="mb-2 border-b border-gray-200 pb-2">
|
|
||||||
<view class="grid grid-cols-4 gap-2 text-center">
|
|
||||||
<text class="text-sm text-gray-600 font-medium">班级</text>
|
|
||||||
<text class="text-sm text-gray-600 font-medium">前{{ scoreSettings.rank_top_1 }}名</text>
|
|
||||||
<text class="text-sm text-gray-600 font-medium">前{{ scoreSettings.rank_top_2 }}名</text>
|
|
||||||
<text class="text-sm text-gray-600 font-medium">前{{ scoreSettings.rank_top_3 }}名</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 名次统计数据 -->
|
|
||||||
<view class="space-y-2">
|
|
||||||
<view
|
|
||||||
v-for="(item, index) in rankStatsData"
|
|
||||||
:key="index"
|
|
||||||
class="grid grid-cols-4 gap-2 border-b border-gray-100 py-2 text-center last:border-b-0"
|
|
||||||
>
|
|
||||||
<text class="text-ellipsis text-sm text-gray-800 font-medium">{{ item.name || '-' }}</text>
|
|
||||||
<text class="text-ellipsis text-sm text-gray-800">
|
|
||||||
{{ item.rank_stats?.find(r => r.end === scoreSettings.rank_top_1)?.count || 0 }}
|
|
||||||
</text>
|
|
||||||
<text class="text-ellipsis text-sm text-gray-800">
|
|
||||||
{{ item.rank_stats?.find(r => r.end === scoreSettings.rank_top_2)?.count || 0 }}
|
|
||||||
</text>
|
|
||||||
<text class="text-ellipsis text-sm text-gray-800">
|
|
||||||
{{ item.rank_stats?.find(r => r.end === scoreSettings.rank_top_3)?.count || 0 }}
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 暂无数据提示 -->
|
|
||||||
<view v-if="!rankStatsData || rankStatsData.length === 0" class="py-8 text-center">
|
|
||||||
<text class="text-sm text-gray-500">暂无名次数据</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 进步/退步学生卡片 -->
|
|
||||||
<view class="rounded-xl bg-white p-4 shadow-sm">
|
|
||||||
<view class="mb-4 flex items-center justify-between">
|
|
||||||
<view class="flex items-center gap-2">
|
|
||||||
<text class="text-lg text-slate-800 font-semibold">
|
|
||||||
班级{{ keyStudentType === 'up' ? '进步' : '退步' }}前
|
|
||||||
</text>
|
|
||||||
<wd-input
|
|
||||||
v-model="keyStudentCount"
|
|
||||||
type="number"
|
|
||||||
placeholder="5"
|
|
||||||
class="w-12 text-center"
|
|
||||||
:border="true"
|
|
||||||
/>
|
|
||||||
<text class="text-lg text-slate-800 font-semibold">名</text>
|
|
||||||
</view>
|
|
||||||
<view class="flex items-center gap-2">
|
|
||||||
<text
|
|
||||||
class="rounded px-2 py-1 text-sm"
|
|
||||||
:class="keyStudentType === 'up' ? 'bg-green-100 text-green-600' : 'text-gray-500'"
|
|
||||||
@tap="toggleKeyStudentType('up')"
|
|
||||||
>
|
|
||||||
进步
|
|
||||||
</text>
|
|
||||||
<text
|
|
||||||
class="rounded px-2 py-1 text-sm"
|
|
||||||
:class="keyStudentType === 'down' ? 'bg-red-100 text-red-600' : 'text-gray-500'"
|
|
||||||
@tap="toggleKeyStudentType('down')"
|
|
||||||
>
|
|
||||||
退步
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 学生表头 -->
|
|
||||||
<view class="mb-2 border-b border-gray-200 pb-2">
|
|
||||||
<view class="grid grid-cols-3 gap-2 text-center">
|
|
||||||
<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">
|
|
||||||
{{ keyStudentType === 'up' ? '进步' : '退步' }}名次
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 学生数据列表 -->
|
|
||||||
<view class="space-y-2">
|
|
||||||
<view
|
|
||||||
v-for="(student, index) in keyStudentsData"
|
|
||||||
:key="index"
|
|
||||||
class="grid grid-cols-3 gap-2 border-b border-gray-100 py-2 text-center last:border-b-0"
|
|
||||||
>
|
|
||||||
<text class="text-ellipsis text-sm text-gray-800 font-medium">{{ student.student_name || '-' }}</text>
|
|
||||||
<text class="text-ellipsis text-sm text-gray-800">{{ student.class_rank || '-' }}</text>
|
|
||||||
<text
|
|
||||||
class="text-ellipsis text-sm font-medium"
|
|
||||||
:class="keyStudentType === 'up' ? 'text-green-600' : 'text-red-600'"
|
|
||||||
>
|
|
||||||
{{ keyStudentType === 'up' ? '+' : '-' }}{{ student.class_diff_rank || 0 }}
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 暂无数据提示 -->
|
|
||||||
<view v-if="!keyStudentsData || keyStudentsData.length === 0" class="py-8 text-center">
|
|
||||||
<text class="text-sm text-gray-500">暂无{{ keyStudentType === 'up' ? '进步' : '退步' }}学生数据</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 显示更多按钮 -->
|
|
||||||
<view v-if="keyStudentsData && keyStudentsData.length > 0 && !showMoreStudents" class="mt-4">
|
|
||||||
<wd-button
|
|
||||||
type="info"
|
|
||||||
size="medium"
|
|
||||||
class="w-full"
|
|
||||||
@click="handleShowMoreKeyStudents"
|
|
||||||
>
|
|
||||||
显示更多{{ keyStudentType === 'up' ? '进步' : '退步' }}学生
|
|
||||||
</wd-button>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 收起按钮 -->
|
|
||||||
<view v-if="showMoreStudents" class="mt-4">
|
|
||||||
<wd-button
|
|
||||||
type="info"
|
|
||||||
size="medium"
|
|
||||||
class="w-full"
|
|
||||||
@click="handleHideMoreKeyStudents"
|
|
||||||
>
|
|
||||||
收起列表
|
|
||||||
</wd-button>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 更多学生列表(z-paging) -->
|
|
||||||
<view v-if="showMoreStudents" class="rounded-xl bg-white shadow-sm">
|
|
||||||
<view class="border-b border-gray-100 p-4">
|
|
||||||
<text class="text-lg text-slate-800 font-semibold">
|
|
||||||
{{ keyStudentType === 'up' ? '进步' : '退步' }}学生详细列表
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<z-paging
|
|
||||||
ref="keyStudentsPaging"
|
|
||||||
v-model="keyStudentsList"
|
|
||||||
:default-page-size="pageSize"
|
|
||||||
:auto="false"
|
|
||||||
@query="fetchKeyStudentsPaging"
|
|
||||||
>
|
>
|
||||||
<!-- 表头 -->
|
<wd-tab
|
||||||
<view class="border-b border-gray-200 p-4">
|
v-for="tab in subjectTabs"
|
||||||
|
:key="tab.name"
|
||||||
|
:name="tab.name"
|
||||||
|
:title="tab.title"
|
||||||
|
/>
|
||||||
|
</wd-tabs>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 主要内容区域 -->
|
||||||
|
<view class="p-4 space-y-4">
|
||||||
|
<!-- 整体概况卡片 -->
|
||||||
|
<view class="rounded-xl bg-white p-3 shadow-sm">
|
||||||
|
<view class="mb-4 flex items-center justify-between">
|
||||||
|
<text class="text-lg text-slate-800 font-semibold">整体概况</text>
|
||||||
|
<view class="i-mingcute:filter-line text-lg text-cyan-500" @tap="handleOverviewSettings" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 统计数据网格 - 2行3列 -->
|
||||||
|
<view class="grid grid-cols-3 gap-1">
|
||||||
|
<!-- 考试人数 -->
|
||||||
|
<view class="border border-blue-100 rounded-xl from-white to-blue-50 bg-gradient-to-br p-3">
|
||||||
|
<view class="mb-2 flex items-center">
|
||||||
|
<text class="text-xs text-slate-600">考试人数</text>
|
||||||
|
</view>
|
||||||
|
<text class="text-lg text-slate-800 font-bold">{{ statsData?.class_total_count || 0 }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 平均分/满分 -->
|
||||||
|
<view class="border border-blue-100 rounded-xl from-white to-blue-50 bg-gradient-to-br p-3">
|
||||||
|
<view class="mb-2 flex items-center">
|
||||||
|
<text class="text-xs text-slate-600">平均分/满分</text>
|
||||||
|
</view>
|
||||||
|
<text class="text-lg text-slate-800 font-bold">{{ Math.round(statsData?.class_average_score || 0) }}/{{ statsData?.full_score || 100 }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 最高分/最低分 -->
|
||||||
|
<view class="border border-cyan-100 rounded-xl from-white to-cyan-50 bg-gradient-to-br p-3">
|
||||||
|
<view class="mb-2 flex items-center">
|
||||||
|
<text class="text-xs text-slate-600">最高分/最低分</text>
|
||||||
|
</view>
|
||||||
|
<text class="text-lg text-slate-800 font-bold">{{ statsData?.class_highest_score || 0 }}/{{ statsData?.class_lowest_score || 0 }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 优秀率 -->
|
||||||
|
<view class="border border-sky-100 rounded-xl from-white to-sky-50 bg-gradient-to-br p-3">
|
||||||
|
<view class="mb-2 flex items-center">
|
||||||
|
<text class="text-xs text-slate-600">优秀率</text>
|
||||||
|
</view>
|
||||||
|
<text class="text-lg text-slate-800 font-bold">{{ Math.round((statsData?.excellent_class_scoring_rate || 0) * 100) }}%</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 良好率 -->
|
||||||
|
<view class="border border-sky-100 rounded-xl from-white to-sky-50 bg-gradient-to-br p-3">
|
||||||
|
<view class="mb-2 flex items-center">
|
||||||
|
<text class="text-xs text-slate-600">良好率</text>
|
||||||
|
</view>
|
||||||
|
<text class="text-lg text-slate-800 font-bold">{{ Math.round((statsData?.good_class_scoring_rate || 0) * 100) }}%</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 及格率 -->
|
||||||
|
<view class="border border-blue-100 rounded-xl from-white to-blue-50 bg-gradient-to-br p-3">
|
||||||
|
<view class="mb-2 flex items-center">
|
||||||
|
<text class="text-xs text-slate-600">及格率</text>
|
||||||
|
</view>
|
||||||
|
<text class="text-lg text-slate-800 font-bold">{{ Math.round((statsData?.pass_class_scoring_rate || 0) * 100) }}%</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 查看成绩单按钮 -->
|
||||||
|
<view class="mt-6">
|
||||||
|
<wd-button
|
||||||
|
type="primary"
|
||||||
|
size="medium"
|
||||||
|
class="w-full"
|
||||||
|
@click="handleViewScoreList"
|
||||||
|
>
|
||||||
|
查看成绩单
|
||||||
|
</wd-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 学科均分对比卡片 -->
|
||||||
|
<view class="rounded-xl bg-white p-4 shadow-sm">
|
||||||
|
<view class="mb-4 flex items-center justify-between">
|
||||||
|
<text class="text-lg text-slate-800 font-semibold">学科均分对比</text>
|
||||||
|
<view class="flex items-center gap-2">
|
||||||
|
<text
|
||||||
|
class="rounded px-2 py-1 text-sm"
|
||||||
|
:class="comparisonMode === 'horizontal' ? 'bg-blue-100 text-blue-600' : 'text-gray-500'"
|
||||||
|
@tap="toggleComparisonMode('horizontal')"
|
||||||
|
>
|
||||||
|
横向
|
||||||
|
</text>
|
||||||
|
<text
|
||||||
|
class="rounded px-2 py-1 text-sm"
|
||||||
|
:class="comparisonMode === 'vertical' ? 'bg-blue-100 text-blue-600' : 'text-gray-500'"
|
||||||
|
@tap="toggleComparisonMode('vertical')"
|
||||||
|
>
|
||||||
|
纵向
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 对比数据表头 -->
|
||||||
|
<view class="mb-2 border-b border-gray-200 pb-2">
|
||||||
|
<view class="grid grid-cols-4 gap-2 text-center">
|
||||||
|
<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>
|
||||||
|
<text class="text-sm text-gray-600 font-medium">{{ comparisonMode === 'horizontal' ? '班级排名' : '班级标准分' }}</text>
|
||||||
|
</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
|
||||||
|
v-for="(item, index) in comparisonData"
|
||||||
|
:key="index"
|
||||||
|
class="grid grid-cols-4 gap-2 border-b border-gray-100 py-2 text-center last:border-b-0"
|
||||||
|
>
|
||||||
|
<text class="text-ellipsis text-sm text-gray-800">{{ comparisonMode === 'horizontal' ? item.subject_name : item.exam_name || '-' }}</text>
|
||||||
|
<text class="text-ellipsis text-sm text-gray-800 font-medium">{{ item.class_average || '-' }}</text>
|
||||||
|
<text class="text-ellipsis text-sm text-gray-600">{{ comparisonMode === 'horizontal' ? item.grade_average || '-' : 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 class="rounded-xl bg-white p-4 shadow-sm">
|
||||||
|
<view class="mb-4 flex items-center justify-between">
|
||||||
|
<text class="no-wrap w-fit flex-shrink-0 text-lg text-slate-800 font-semibold">名次分析</text>
|
||||||
|
<!-- 班级多选 -->
|
||||||
|
<wd-select-picker
|
||||||
|
v-model="selectedClassIds"
|
||||||
|
class="classes-picker flex-grow"
|
||||||
|
:columns="classColumns"
|
||||||
|
:show-confirm="false"
|
||||||
|
@confirm="handleClassChange"
|
||||||
|
/>
|
||||||
|
<view class="i-mingcute:filter-line text-lg text-cyan-500" @tap="handleRankSettings" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 名次统计表头 -->
|
||||||
|
<view class="mb-2 border-b border-gray-200 pb-2">
|
||||||
|
<view class="grid grid-cols-4 gap-2 text-center">
|
||||||
|
<text class="text-sm text-gray-600 font-medium">班级</text>
|
||||||
|
<text class="text-sm text-gray-600 font-medium">前{{ scoreSettings.rank_top_1 }}名</text>
|
||||||
|
<text class="text-sm text-gray-600 font-medium">前{{ scoreSettings.rank_top_2 }}名</text>
|
||||||
|
<text class="text-sm text-gray-600 font-medium">前{{ scoreSettings.rank_top_3 }}名</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 名次统计数据 -->
|
||||||
|
<view class="space-y-2">
|
||||||
|
<view
|
||||||
|
v-for="(item, index) in rankStatsData"
|
||||||
|
:key="index"
|
||||||
|
class="grid grid-cols-4 gap-2 border-b border-gray-100 py-2 text-center last:border-b-0"
|
||||||
|
>
|
||||||
|
<text class="text-ellipsis text-sm text-gray-800 font-medium">{{ item.name || '-' }}</text>
|
||||||
|
<text class="text-ellipsis text-sm text-gray-800">
|
||||||
|
{{ item.rank_stats?.find(r => r.end === scoreSettings.rank_top_1)?.count || 0 }}
|
||||||
|
</text>
|
||||||
|
<text class="text-ellipsis text-sm text-gray-800">
|
||||||
|
{{ item.rank_stats?.find(r => r.end === scoreSettings.rank_top_2)?.count || 0 }}
|
||||||
|
</text>
|
||||||
|
<text class="text-ellipsis text-sm text-gray-800">
|
||||||
|
{{ item.rank_stats?.find(r => r.end === scoreSettings.rank_top_3)?.count || 0 }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 暂无数据提示 -->
|
||||||
|
<view v-if="!rankStatsData || rankStatsData.length === 0" class="py-8 text-center">
|
||||||
|
<text class="text-sm text-gray-500">暂无名次数据</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 进步/退步学生卡片 -->
|
||||||
|
<view class="rounded-xl bg-white p-4 shadow-sm">
|
||||||
|
<view class="mb-4 flex items-center justify-between">
|
||||||
|
<view class="flex items-center gap-2">
|
||||||
|
<text class="text-lg text-slate-800 font-semibold">
|
||||||
|
班级{{ keyStudentType === 'up' ? '进步' : '退步' }}前
|
||||||
|
</text>
|
||||||
|
<wd-input
|
||||||
|
v-model="keyStudentCount"
|
||||||
|
type="number"
|
||||||
|
placeholder="5"
|
||||||
|
class="w-12 text-center"
|
||||||
|
:border="true"
|
||||||
|
/>
|
||||||
|
<text class="text-lg text-slate-800 font-semibold">名</text>
|
||||||
|
</view>
|
||||||
|
<view class="flex items-center gap-2">
|
||||||
|
<text
|
||||||
|
class="rounded px-2 py-1 text-sm"
|
||||||
|
:class="keyStudentType === 'up' ? 'bg-green-100 text-green-600' : 'text-gray-500'"
|
||||||
|
@tap="toggleKeyStudentType('up')"
|
||||||
|
>
|
||||||
|
进步
|
||||||
|
</text>
|
||||||
|
<text
|
||||||
|
class="rounded px-2 py-1 text-sm"
|
||||||
|
:class="keyStudentType === 'down' ? 'bg-red-100 text-red-600' : 'text-gray-500'"
|
||||||
|
@tap="toggleKeyStudentType('down')"
|
||||||
|
>
|
||||||
|
退步
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 学生表头 -->
|
||||||
|
<view class="mb-2 border-b border-gray-200 pb-2">
|
||||||
<view class="grid grid-cols-3 gap-2 text-center">
|
<view class="grid grid-cols-3 gap-2 text-center">
|
||||||
<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">本次排名</text>
|
||||||
|
|
@ -763,11 +642,11 @@ const loading = computed(() =>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 学生数据列表 -->
|
<!-- 学生数据列表 -->
|
||||||
<view class="divide-y divide-gray-100">
|
<view class="space-y-2">
|
||||||
<view
|
<view
|
||||||
v-for="(student, index) in keyStudentsList"
|
v-for="(student, index) in keyStudentsList"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="grid grid-cols-3 gap-2 p-4 text-center"
|
class="grid grid-cols-3 gap-2 border-b border-gray-100 py-2 text-center last:border-b-0"
|
||||||
>
|
>
|
||||||
<text class="text-ellipsis 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-ellipsis text-sm text-gray-800">{{ student.class_rank || '-' }}</text>
|
<text class="text-ellipsis text-sm text-gray-800">{{ student.class_rank || '-' }}</text>
|
||||||
|
|
@ -779,9 +658,14 @@ const loading = computed(() =>
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</z-paging>
|
|
||||||
|
<!-- 暂无数据提示 -->
|
||||||
|
<view v-if="!keyStudentsList || keyStudentsList.length === 0" class="py-8 text-center">
|
||||||
|
<text class="text-sm text-gray-500">暂无{{ keyStudentType === 'up' ? '进步' : '退步' }}学生数据</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</z-paging>
|
||||||
|
|
||||||
<!-- 整体概况设置弹窗 -->
|
<!-- 整体概况设置弹窗 -->
|
||||||
<OverviewSettingsDialog
|
<OverviewSettingsDialog
|
||||||
|
|
@ -796,14 +680,6 @@ const loading = computed(() =>
|
||||||
:settings="scoreSettings"
|
:settings="scoreSettings"
|
||||||
@confirm="confirmRankSettings"
|
@confirm="confirmRankSettings"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 加载状态 -->
|
|
||||||
<!-- <view v-if="loading" class="fixed inset-0 z-50 flex items-center justify-center bg-black/20">
|
|
||||||
<view class="rounded-xl bg-white p-4">
|
|
||||||
<wd-loading size="24" />
|
|
||||||
<text class="mt-2 block text-sm text-gray-600">加载中...</text>
|
|
||||||
</view>
|
|
||||||
</view> -->
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { whenever } from '@vueuse/core'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { teacherScoreAnalysisApi } from '@/api'
|
import { teacherScoreAnalysisApi } from '@/api'
|
||||||
|
import { useUserStorage } from '@/composables/useUserStorage'
|
||||||
|
|
||||||
export interface SelectOption {
|
export interface SelectOption {
|
||||||
label: string
|
label: string
|
||||||
|
|
@ -30,11 +31,11 @@ export const useHomeStore = defineStore(
|
||||||
const classList = ref<ClassItem[]>([])
|
const classList = ref<ClassItem[]>([])
|
||||||
const classGradeMap = ref<Map<number, number>>(new Map())
|
const classGradeMap = ref<Map<number, number>>(new Map())
|
||||||
|
|
||||||
// 已选择的数据
|
// 已选择的数据(使用 useUserStorage 实现基于用户的持久化)
|
||||||
const selectedClassId = ref<number | null>(null)
|
const selectedClassId = useUserStorage<number>('home_selectedClassId', 0)
|
||||||
const selectedExamId = ref<number | null>(null)
|
const selectedExamId = useUserStorage<number>('home_selectedExamId', 0)
|
||||||
const selectedSubjectId = ref<number | null>(null)
|
const selectedSubjectId = useUserStorage<number>('home_selectedSubjectId', 0)
|
||||||
const selectedExamSubjectId = ref<number | null>(null)
|
const selectedExamSubjectId = useUserStorage<number>('home_selectedExamSubjectId', 0)
|
||||||
const selectedGradeKey = computed(() => classGradeMap.value.get(selectedClassId.value || 0) || null)
|
const selectedGradeKey = computed(() => classGradeMap.value.get(selectedClassId.value || 0) || null)
|
||||||
|
|
||||||
// 计算属性:考试选项
|
// 计算属性:考试选项
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue