/** * 自然写互动课堂PC端应用软件 V1.0 * * index.ts - Pinia状态管理(全局Store) * * 功能说明: * - 用户认证状态管理 * - 课堂状态管理(当前课堂/学生列表/笔迹数据) * - 设备连接状态管理 * - 作业批改状态管理 * - WebSocket实时数据同步 * - 持久化存储(electron-store) */ import { defineStore } from 'pinia'; import { ref, computed, reactive } from 'vue'; /* ======================== 类型定义 ======================== */ /** 应用视图模式 */ type ViewMode = 'prepare' | 'lesson' | 'grade' | 'report'; /** 设备信息 */ interface DeviceState { id: string; name: string; type: 'usb' | 'ble'; status: 'connected' | 'disconnected' | 'error'; battery: number; } /** 学生在线状态 */ interface StudentOnlineState { studentId: string; name: string; penId: string; online: boolean; lastActive: number; strokeCount: number; } /** 课堂互动数据 */ interface ClassroomLiveData { classroomId: string; className: string; startTime: number; onlineStudents: StudentOnlineState[]; totalStrokes: number; isRecording: boolean; } /** 批改任务 */ interface GradeTask { assignmentId: string; studentId: string; studentName: string; status: 'pending' | 'ai_graded' | 'reviewed' | 'completed'; aiScore: number; teacherScore: number; feedback: string; } /* ======================== 用户Store ======================== */ /** * 用户认证与信息状态管理 */ export const useUserStore = defineStore('user', () => { /** 是否已登录 */ const isLoggedIn = ref(false); /** 当前用户信息 */ const userInfo = ref<{ userId: string; name: string; role: string; phone: string; schoolId: string; schoolName: string; avatar: string; } | null>(null); /** 登录时间 */ const loginTime = ref(0); /** Token过期时间 */ const tokenExpiresAt = ref(0); /** 用户角色显示名 */ const roleLabel = computed(() => { const roleMap: Record = { admin: '管理员', teacher: '教师', student: '学生', parent: '家长' }; return roleMap[userInfo.value?.role || ''] || '未知'; }); /** * 登录成功后设置用户状态 */ function setLoggedIn(user: typeof userInfo.value, expiresAt: number): void { isLoggedIn.value = true; userInfo.value = user; loginTime.value = Date.now(); tokenExpiresAt.value = expiresAt; console.log(`[Store] 用户登录: ${user?.name} (${user?.role})`); } /** * 退出登录 */ function logout(): void { isLoggedIn.value = false; userInfo.value = null; loginTime.value = 0; tokenExpiresAt.value = 0; console.log('[Store] 用户已退出'); } return { isLoggedIn, userInfo, loginTime, tokenExpiresAt, roleLabel, setLoggedIn, logout }; }); /* ======================== 课堂Store ======================== */ /** * 课堂状态管理 * 管理当前课堂的实时数据 */ export const useClassroomStore = defineStore('classroom', () => { /** 当前视图模式 */ const viewMode = ref('prepare'); /** 当前课堂数据 */ const liveData = ref(null); /** 是否在课堂中 */ const isInClass = ref(false); /** WebSocket连接状态 */ const wsConnected = ref(false); /** 在线学生数 */ const onlineCount = computed(() => liveData.value?.onlineStudents.filter(s => s.online).length || 0 ); /** 总学生数 */ const totalStudents = computed(() => liveData.value?.onlineStudents.length || 0 ); /** 在线率 */ const onlineRate = computed(() => { const total = totalStudents.value; return total > 0 ? Math.round((onlineCount.value / total) * 100) : 0; }); /** * 开始课堂 */ function startClass(classroomId: string, className: string, students: StudentOnlineState[]): void { liveData.value = { classroomId, className, startTime: Date.now(), onlineStudents: students, totalStrokes: 0, isRecording: false }; isInClass.value = true; viewMode.value = 'lesson'; console.log(`[Store] 课堂开始: ${className}, 学生${students.length}人`); } /** * 结束课堂 */ function endClass(): void { const duration = liveData.value ? Date.now() - liveData.value.startTime : 0; console.log(`[Store] 课堂结束, 时长=${Math.round(duration / 60000)}分钟, ` + `笔迹=${liveData.value?.totalStrokes}`); isInClass.value = false; liveData.value = null; } /** * 更新学生在线状态 */ function updateStudentStatus(studentId: string, online: boolean): void { const student = liveData.value?.onlineStudents.find(s => s.studentId === studentId); if (student) { student.online = online; student.lastActive = Date.now(); } } /** * 累加笔迹数据计数 */ function addStrokeCount(count: number): void { if (liveData.value) { liveData.value.totalStrokes += count; } } /** * 切换视图模式 */ function setViewMode(mode: ViewMode): void { viewMode.value = mode; console.log(`[Store] 视图切换: ${mode}`); } return { viewMode, liveData, isInClass, wsConnected, onlineCount, totalStudents, onlineRate, startClass, endClass, updateStudentStatus, addStrokeCount, setViewMode }; }); /* ======================== 设备Store ======================== */ /** * 设备连接状态管理 */ export const useDeviceStore = defineStore('device', () => { /** 已连接设备列表 */ const devices = ref([]); /** 正在扫描BLE */ const isScanning = ref(false); /** 已连接设备数 */ const connectedCount = computed(() => devices.value.filter(d => d.status === 'connected').length ); /** * 添加或更新设备 */ function upsertDevice(device: DeviceState): void { const idx = devices.value.findIndex(d => d.id === device.id); if (idx >= 0) { devices.value[idx] = device; } else { devices.value.push(device); } } /** * 移除设备 */ function removeDevice(deviceId: string): void { devices.value = devices.value.filter(d => d.id !== deviceId); } /** * 更新设备电量 */ function updateBattery(deviceId: string, battery: number): void { const device = devices.value.find(d => d.id === deviceId); if (device) { device.battery = battery; } } return { devices, isScanning, connectedCount, upsertDevice, removeDevice, updateBattery }; }); /* ======================== 批改Store ======================== */ /** * 作业批改状态管理 */ export const useGradeStore = defineStore('grade', () => { /** 当前批改的作业ID */ const currentAssignmentId = ref(''); /** 批改任务列表 */ const gradeTasks = ref([]); /** 当前批改的学生索引 */ const currentTaskIndex = ref(0); /** 待批改数 */ const pendingCount = computed(() => gradeTasks.value.filter(t => t.status === 'ai_graded' || t.status === 'pending').length ); /** 已完成数 */ const completedCount = computed(() => gradeTasks.value.filter(t => t.status === 'completed' || t.status === 'reviewed').length ); /** 总体进度百分比 */ const progressPercent = computed(() => { const total = gradeTasks.value.length; return total > 0 ? Math.round((completedCount.value / total) * 100) : 0; }); /** 当前批改任务 */ const currentTask = computed(() => gradeTasks.value[currentTaskIndex.value] || null); /** * 加载批改任务列表 */ function loadTasks(assignmentId: string, tasks: GradeTask[]): void { currentAssignmentId.value = assignmentId; gradeTasks.value = tasks; currentTaskIndex.value = 0; console.log(`[Store] 加载批改任务: ${tasks.length}份作业`); } /** * 提交教师批改结果 */ function submitGrade(studentId: string, score: number, feedback: string): void { const task = gradeTasks.value.find(t => t.studentId === studentId); if (task) { task.teacherScore = score; task.feedback = feedback; task.status = 'reviewed'; console.log(`[Store] 批改完成: ${task.studentName}, 分数=${score}`); } } /** * 切换到下一个待批改任务 */ function nextTask(): boolean { for (let i = currentTaskIndex.value + 1; i < gradeTasks.value.length; i++) { if (gradeTasks.value[i].status !== 'completed' && gradeTasks.value[i].status !== 'reviewed') { currentTaskIndex.value = i; return true; } } return false; } /** * 切换到上一个任务 */ function prevTask(): boolean { if (currentTaskIndex.value > 0) { currentTaskIndex.value--; return true; } return false; } return { currentAssignmentId, gradeTasks, currentTaskIndex, pendingCount, completedCount, progressPercent, currentTask, loadTasks, submitGrade, nextTask, prevTask }; });