diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue index c4feed7..01449b6 100644 --- a/src/pages/index/index.vue +++ b/src/pages/index/index.vue @@ -90,16 +90,17 @@ const teacherName = computed(() => { return userInfo.nickname || '教师' }) -const teacherSubject = computed(() => { - const userInfo = userStore.info - // 从角色信息中获取学科,假设角色名包含学科信息 - const roleName = userInfo.roles?.[0]?.name - if (roleName) { - // 提取学科信息,例如"语文教师"中的"语文" - const subjectMatch = roleName.match(/^(.+?)教师$/) - return subjectMatch ? subjectMatch[1] : '学科' - } - return '学科' +const currentRoleText = computed(() => { + const role = userStore.selectedRole + if (!role) + return '暂无角色' + const parts = [ + role.grade, + role.class, + role.subject, + role.role, + ].filter(Boolean) + return parts.join(' ') || '教师' }) // 计算当前选中的班级名称 @@ -245,13 +246,6 @@ const showClassPicker = ref(false) // 班级选择处理 function handleClassChange() { - if (homeStore.classOptions.length === 0) { - uni.showToast({ - title: '暂无班级数据', - icon: 'none', - }) - return - } showClassPicker.value = true } @@ -259,8 +253,6 @@ function handleClassChange() { watch(() => homeStore.selectedClassKey, () => { // 选择班级后重新获取统计数据 fetchExamStats() - // 关闭弹窗 - showClassPicker.value = false }) // 设置按钮处理 @@ -400,7 +392,7 @@ onMounted(async () => { {{ teacherName }} - {{ teacherSubject }}教师 + {{ currentRoleText }} @@ -625,26 +617,54 @@ onMounted(async () => { - - 切换班级 - - - - - {{ classItem.label }} + + + 切换班级 + + + v-for="classItem in homeStore.classOptions" + :key="classItem.value" + class="flex items-center justify-between rounded-lg px-3 py-2 transition-colors" + :class="homeStore.selectedClassId === classItem.value ? 'bg-blue-50 text-blue-600' : 'hover:bg-slate-50 text-slate-600'" + @tap="homeStore.selectedClassId = classItem.value;showClassPicker = false" + > + {{ classItem.label }} + + - - + + 当前角色无可选班级 + + + + + + + 切换角色 + + + + + {{ roleItem.grade }}{{ roleItem.class }} + {{ roleItem.subject }} + {{ roleItem.role }} + + + + + + + 关闭 diff --git a/src/store/home.ts b/src/store/home.ts index 1d703bc..208eb03 100644 --- a/src/store/home.ts +++ b/src/store/home.ts @@ -1,9 +1,10 @@ -import type { ModelTeacherAnalysisClassInfo, ModelTeacherAnalysisExamInfo } from '@/api/data-contracts' +import type { ModelTeacherAnalysisExamInfo } from '@/api/data-contracts' import { whenever } from '@vueuse/core' import { defineStore } from 'pinia' -import { computed, ref } from 'vue' +import { computed, onMounted, ref } from 'vue' import { teacherScoreAnalysisApi } from '@/api' import { useUserStorage } from '@/composables/useUserStorage' +import { useUserStore } from '@/store/user' export interface SelectOption { label: string @@ -14,23 +15,18 @@ export interface SelectOption { gradeKey?: number } -// 班级信息类型 -export interface ClassItem { - label: string - value: number - gradeKey: number -} - /** * 首页状态管理 */ export const useHomeStore = defineStore( 'homeStore', () => { + // 获取 userStore + const userStore = useUserStore() + // 数据存储 const loading = ref(false) const examDataMap = ref>(new Map()) - const classList = ref([]) // 已选择的数据(使用 useUserStorage 实现基于用户的持久化) const selectedClassId = useUserStorage('home_selectedClassId', 0) @@ -46,14 +42,53 @@ export const useHomeStore = defineStore( })) }) - // 计算属性:班级选项 + // 计算属性:班级选项(带角色权限筛选) const classOptions = computed((): SelectOption[] => { - return classList.value.map((item, index) => ({ - label: item.label, + if (!selectedExamId.value) { + return [] + } + const examData = examDataMap.value.get(selectedExamId.value) + if (!examData?.classes) { + return [] + } + const allClasses = examData.classes.map((item, index) => ({ + label: `${item.grade_name || ''} ${item.class_name || ''}`.trim(), value: index, - classKey: item.value, - gradeKey: item.gradeKey, - })) + classKey: item.class_key, + gradeKey: Number(item.grade_key), + })) || [] + + // 如果没有选择角色,返回所有班级 + const currentRole = userStore.selectedRole + if (!currentRole) { + return allClasses + } + + // 根据角色类型筛选班级 + return allClasses.filter((classItem) => { + // 1. 任课老师 (role_key: 1): 只能访问特定科目的特定班级 + if (currentRole.role_key === 1) { + return currentRole.grade_key === classItem.gradeKey && currentRole.class_key === classItem.classKey + } + + // 2. 班主任 (role_key: 2): 可以访问管理的班级 + if (currentRole.role_key === 2) { + return currentRole.grade_key === classItem.gradeKey && currentRole.class_key === classItem.classKey + } + + // 3. 年级主任 (role_key: 3): 可以访问对应年级的所有班级 + if (currentRole.role_key === 3) { + return currentRole.grade_key === classItem.gradeKey + } + + // 4. 学科组长 (role_key: 4): 可以访问对应科目的所有班级(在当前角色的年级内) + if (currentRole.role_key === 4) { + // 学科组长可以看当前角色年级的所有班级 + return currentRole.grade_key === classItem.gradeKey + } + + return false + }) }) const selectedClassKey = computed(() => { @@ -64,7 +99,7 @@ export const useHomeStore = defineStore( return classOptions.value.find(item => item.value === selectedClassId.value)?.gradeKey || 0 }) - // 计算属性:根据选中考试获取科目选项 + // 计算属性:根据选中考试获取科目选项(带角色权限筛选) const subjectOptions = computed((): SelectOption[] => { if (!selectedExamId.value) { return [] @@ -73,12 +108,45 @@ export const useHomeStore = defineStore( if (!examData?.subjects) { return [] } - return examData.subjects.map(subject => ({ + + // 先生成所有科目选项 + const allSubjects = examData.subjects.map(subject => ({ label: subject.subject_name || '', value: subject.exam_subject_id || 0, examSubjectId: subject.exam_subject_id || 0, subjectId: subject.subject_id || 0, })) + + // 如果没有选择角色,返回所有科目 + const currentRole = userStore.selectedRole + if (!currentRole) { + return allSubjects + } + + // 根据角色类型筛选科目 + return allSubjects.filter((subjectItem) => { + // 1. 任课老师 (role_key: 1): 只能访问特定科目 + if (currentRole.role_key === 1) { + return currentRole.subject_id === subjectItem.subjectId + } + + // 2. 班主任 (role_key: 2): 可以访问所有科目 + if (currentRole.role_key === 2) { + return true + } + + // 3. 年级主任 (role_key: 3): 可以访问所有科目 + if (currentRole.role_key === 3) { + return true + } + + // 4. 学科组长 (role_key: 4): 只能访问负责的科目 + if (currentRole.role_key === 4) { + return currentRole.subject_id === subjectItem.subjectId + } + + return false + }) }) /** @@ -90,31 +158,19 @@ export const useHomeStore = defineStore( const response = await teacherScoreAnalysisApi.dataList() if (response) { - // 处理班级数据并建立班级到年级的映射 - classList.value = (response.class_list || []).map((item: ModelTeacherAnalysisClassInfo) => { - if (!item.class_key || !item.grade_key) { - return null - } - const classKey = item.class_key - const gradeKey = item.grade_key - - return { - label: `${item.grade || ''} ${item.class || ''}`.trim(), - value: classKey, - gradeKey, - } - }).filter(item => item !== null) as ClassItem[] - // 处理考试数据,存储到 map 中 - examDataMap.value.clear() - ;(response.exam_list || []).forEach((exam: ModelTeacherAnalysisExamInfo) => { + examDataMap.value.clear(); + (response.exam_list || []).forEach((exam: ModelTeacherAnalysisExamInfo) => { if (exam.exam_id) { examDataMap.value.set(exam.exam_id, exam) } }) + if (!selectedExamId.value) { + selectedExamId.value = examOptions.value[0]?.value as number + } + console.log('数据获取完成:') - console.log('classList数量:', classList.value.length) console.log('examDataMap数量:', examDataMap.value.size) } } @@ -132,8 +188,10 @@ export const useHomeStore = defineStore( */ const onExamChange = (examId: number | null) => { selectedExamId.value = examId - selectedSubjectId.value = subjectOptions.value[0].subjectId || null - selectedExamSubjectId.value = subjectOptions.value[0].examSubjectId || null + if (subjectOptions.value.length > 0) { + selectedSubjectId.value = subjectOptions.value[0].subjectId || null + selectedExamSubjectId.value = subjectOptions.value[0].examSubjectId || null + } } /** @@ -158,7 +216,6 @@ export const useHomeStore = defineStore( * 重置store状态 */ const reset = () => { - classList.value = [] examDataMap.value.clear() loading.value = false clearSelections() @@ -166,8 +223,10 @@ export const useHomeStore = defineStore( // 监听考试ID变化,自动选择第一个科目 whenever(selectedExamId, (examId) => { - selectedSubjectId.value = subjectOptions.value[0].subjectId || null - selectedExamSubjectId.value = subjectOptions.value[0].examSubjectId || null + if (subjectOptions.value.length > 0) { + selectedSubjectId.value = subjectOptions.value[0].subjectId || null + selectedExamSubjectId.value = subjectOptions.value[0].examSubjectId || null + } }) onMounted(async () => { diff --git a/src/store/user.ts b/src/store/user.ts index 476075b..a306b5e 100644 --- a/src/store/user.ts +++ b/src/store/user.ts @@ -1,8 +1,9 @@ -import type { ModelSysUser, ModelTeacherListResponse, ModelUserProfileResponse } from '@/api' +import type { ModelSysUser, ModelTeacherListResponse, ModelTeacherRoleClassInfo, ModelUserProfileResponse } from '@/api' import type { LoginRequest, SysUser } from '@/service/types' import { defineStore } from 'pinia' import { computed, ref } from 'vue' import { authApi } from '@/api' +import { useUserStorage } from '@/composables/useUserStorage' import { authCodeLoginUsingPost, authLoginUsingPost, @@ -24,6 +25,8 @@ export const useUserStore = defineStore( const info = ref>({}) // 教师信息 const teacherInfo = ref>({}) + // 当前选择的角色 + const selectedRole = useUserStorage('selectedRole', null) // 访问令牌 const accessToken = ref('') // 刷新令牌 @@ -46,6 +49,18 @@ export const useUserStore = defineStore( const setUserInfo = (newInfo: ModelUserProfileResponse) => { info.value = newInfo.sys_user teacherInfo.value = newInfo.teacher + // 自动选择第一个角色作为默认值 + if (newInfo.teacher?.role_class_list && newInfo.teacher.role_class_list.length > 0) { + selectedRole.value = newInfo.teacher.role_class_list[0] + } + } + + /** + * 设置当前选择的角色 + * @param role 角色信息 + */ + const setSelectedRole = (role: ModelTeacherRoleClassInfo) => { + selectedRole.value = role } /** @@ -242,11 +257,14 @@ export const useUserStore = defineStore( isLogin, isTeacher, info, + teacherInfo, + selectedRole, accessToken, refreshToken, tokenExpireTime, getUserInfo, setUserInfo, + setSelectedRole, setLoginStatus, setToken, isTokenNearExpiry,