diff --git a/api/student.ts b/api/student.ts index c720006..f20c8ee 100644 --- a/api/student.ts +++ b/api/student.ts @@ -50,10 +50,22 @@ export type StudentHomeMetrics = { accuracyToday: number | null learningDaysThisWeek: number shouldStudyDaysThisWeek: number - pendingHomeworkCount: number + pendingPackCount: number updatedAt: string } +export type ParentStudentTodayInfoResult = { + userId: number | string + date: string + todayOnline: boolean + todayCheckIn: boolean + todayStudyDuration: number + todayAccuracyRate: number + weekStudyDays: number + weekShouldStudyDays: number + pendingPackCount: number +} + export type TodayLearningCourse = { id: string time: string @@ -136,10 +148,53 @@ export type StudentStudyReport = { studentClass: string updatedAtText: string subjects: StudyReportSubject[] + hasWeekReport: boolean + hasMonthReport: boolean week: StudyReportPeriod month: StudyReportPeriod } +export type ParentLearningReportType = 1 | 2 + +export type ParentLearningDurationDetail = { + StartDate: string + EndDate: string + StudyDurationTime: number + OvercomeStudyDurationTime: number + UnOvercomeStudyDurationTime: number +} + +export type ParentLearningReportDetailItem = { + SubjectId: string + SubjectName: string | null + NewKnowledgePointCount: number + OvercomeKnowledgePointCount: number + ContinuousStudyDays: number + AverageAccuracy: number + StudyDurationTime: number + OvercomeStudyDurationTime: number + UnOvercomeStudyDurationTime: number + StudyDurationDetails: ParentLearningDurationDetail[] +} + +export type ParentLearningReportResult = { + UserId: string + UserName: string | null + ClassId: string + ClassName: string | null + SchoolId: string + SchoolName: string | null + CloudSchoolId: string + CloudSchoolName: string | null + ReportType: ParentLearningReportType + ReportTypeName: string + HasReport: boolean + PeriodStart: string | null + PeriodEnd: string | null + Summary: ParentLearningReportDetailItem | null + Subjects: ParentLearningReportDetailItem[] +} + export type TodayLearningDetail = { studentId: string studentName: string @@ -205,9 +260,12 @@ export type LearningTaskItem = { title: string status: 'not_started' | 'in_progress' | 'success' | 'failed' statusText: string + resultText: string accuracyText: string answerText: string + attemptText: string deadlineText: string + metaText: string } export type LearningTaskGroup = { @@ -227,6 +285,7 @@ export type StudentLearningTasks = { studentName: string studentGrade: string studentClass: string + totalCount: number pendingCount: number completedCount: number failedCount: number @@ -244,6 +303,8 @@ export type StudentAlert = { content: string occurredAt: string isRead: boolean + isTriggered: boolean + statusName: string } export type StudentAlertList = { @@ -265,7 +326,7 @@ export type StudentLearningWarningItem = { } export type StudentLearningWarningResult = { - userId: string + userId: number | string date: string totalCount: number triggeredCount: number @@ -351,7 +412,7 @@ export function apiGetBoundStudents(): Promise | null> { - return get(`/api/v1/ParentStudentToday/GetTodayInfo?userId=${studentId}`, undefined, { showLoading }).then((res) => { + return get(`/api/v1/ParentStudentToday/GetTodayInfo?userId=${encodeURIComponent(studentId)}`, undefined, { showLoading }).then((res) => { if (!res || !res.data) return null return { code: res.code, @@ -360,11 +421,11 @@ export function apiGetStudentHomeMetrics(studentId: string, showLoading: boolean studentId: String(res.data.userId ?? studentId), onlineToday: Boolean(res.data.todayOnline), checkedInToday: Boolean(res.data.todayCheckIn), - learningMinutesToday: Math.floor((Number(res.data.todayStudyDuration) || 0) / 60), - accuracyToday: Number(res.data.todayAccuracyRate) || 0, + learningMinutesToday: Math.floor(Number(res.data.todayStudyDuration) || 0), + accuracyToday: res.data.todayAccuracyRate === null || res.data.todayAccuracyRate === undefined ? null : Number(res.data.todayAccuracyRate) || 0, learningDaysThisWeek: Number(res.data.weekStudyDays) || 0, shouldStudyDaysThisWeek: Number(res.data.weekShouldStudyDays) || 0, - pendingHomeworkCount: Number(res.data.pendingPackCount) || 0, + pendingPackCount: Number(res.data.pendingPackCount) || 0, updatedAt: res.data.date || '' } } @@ -372,21 +433,26 @@ export function apiGetStudentHomeMetrics(studentId: string, showLoading: boolean } /** - * 获取指定学生今日学习预警,仅返回已触发的预警规则。 + * 获取指定学生今日学习预警。已触发预警优先,其后展示未触发规则。 */ -export function apiGetStudentLearningWarnings(studentId: string, showLoading: boolean = true): Promise | null> { - return get(`/api/v1/ParentLearningWarning/GetTodayList?userId=${studentId}`, undefined, { showLoading }).then((res) => { +export function apiGetStudentLearningWarnings(studentId: string, showLoading: boolean = true, limit?: number): Promise | null> { + return get(`/api/v1/ParentLearningWarning/GetTodayList?userId=${encodeURIComponent(studentId)}`, undefined, { showLoading }).then((res) => { if (!res || !res.data || !Array.isArray(res.data.items)) return null - const list: StudentAlert[] = res.data.items - .filter((item: any) => Boolean(item.isTriggered)) - .map((item: any, index: number) => ({ - id: `${studentId}-${item.type ?? index}`, - level: 'high', - title: item.title || '学习预警', - content: item.description || item.statusName || '', - occurredAt: res.data.date || '', - isRead: false - })) + const warningData = res.data + const triggeredItems = warningData.items.filter((item: StudentLearningWarningItem) => Boolean(item.isTriggered)) + const normalItems = warningData.items.filter((item: StudentLearningWarningItem) => !Boolean(item.isTriggered)) + const sourceItems = triggeredItems.concat(normalItems) + const visibleItems = limit === undefined ? sourceItems : sourceItems.slice(0, limit) + const list: StudentAlert[] = visibleItems.map((item: StudentLearningWarningItem, index: number) => ({ + id: `${studentId}-${item.type ?? index}`, + level: item.isTriggered ? 'high' : 'low', + title: item.title || '学习预警', + content: item.description || item.statusName || '', + occurredAt: warningData.date || '', + isRead: !item.isTriggered, + isTriggered: Boolean(item.isTriggered), + statusName: item.statusName || '' + })) return { code: res.code, message: res.message, @@ -395,8 +461,8 @@ export function apiGetStudentLearningWarnings(studentId: string, showLoading: bo pagination: { page: 1, pageSize: list.length, - total: list.length, - hasMore: false + total: sourceItems.length, + hasMore: limit !== undefined && sourceItems.length > list.length } } } @@ -411,10 +477,176 @@ export function apiGetTodayLearningDetail(studentId: string, showLoading: boolea } /** - * 获取学生学情报告。接口一次返回周报、月报和全部科目趋势数据。 + * 获取学生最新一期学情报告。新接口按报告类型分别返回周报、月报,这里转换为页面统一结构。 */ -export function apiGetStudentStudyReport(studentId: string, showLoading: boolean = true): Promise | null> { - return get(`/api/parent/study-report?studentId=${studentId}`, undefined, { showLoading }) +export async function apiGetStudentStudyReport(studentId: string, showLoading: boolean = true): Promise | null> { + const weekRes = await get(`/api/v1/ParentLearningReport/Get?userId=${encodeURIComponent(studentId)}&reportType=1`, undefined, { showLoading }) + const monthRes = await get(`/api/v1/ParentLearningReport/Get?userId=${encodeURIComponent(studentId)}&reportType=2`, undefined, { showLoading: false }) + const weekData = weekRes?.data ?? null + const monthData = monthRes?.data ?? null + if (!weekData && !monthData) return null + + const sourceData = weekData ?? monthData + return { + code: weekRes?.code ?? monthRes?.code ?? 200, + message: weekRes?.message ?? monthRes?.message ?? 'SUCCESS', + data: { + studentId: String(sourceData?.UserId ?? studentId), + studentName: sourceData?.UserName ?? '', + studentGrade: '', + studentClass: sourceData?.ClassName ?? '', + updatedAtText: formatReportDate(sourceData?.PeriodEnd), + subjects: buildStudyReportSubjects(weekData, monthData), + hasWeekReport: Boolean(weekData?.HasReport && weekData.Summary), + hasMonthReport: Boolean(monthData?.HasReport && monthData.Summary), + week: buildStudyReportPeriod(weekData, 1), + month: buildStudyReportPeriod(monthData, 2) + } + } +} + +function buildStudyReportSubjects(weekData: ParentLearningReportResult | null, monthData: ParentLearningReportResult | null): StudyReportSubject[] { + const subjects: StudyReportSubject[] = [{ id: '0', name: '全部科目' }] + const sourceSubjects = weekData?.Subjects?.length ? weekData.Subjects : monthData?.Subjects ?? [] + sourceSubjects.forEach((item: ParentLearningReportDetailItem) => { + const id = String(item.SubjectId ?? '') + if (id && subjects.every((subject: StudyReportSubject) => subject.id !== id)) { + subjects.push({ id, name: item.SubjectName ?? '未命名科目' }) + } + }) + return subjects +} + +function buildStudyReportPeriod(report: ParentLearningReportResult | null, reportType: ParentLearningReportType): StudyReportPeriod { + if (!report?.HasReport || !report.Summary) return createEmptyStudyReportPeriod(reportType) + const summary = report.Summary + const detailItems = [summary].concat(Array.isArray(report.Subjects) ? report.Subjects : []) + let maxMinutes = 1 + detailItems.forEach((item: ParentLearningReportDetailItem) => { + const details = Array.isArray(item.StudyDurationDetails) ? item.StudyDurationDetails : [] + details.forEach((detail: ParentLearningDurationDetail) => { + maxMinutes = Math.max(maxMinutes, secondsToMinutes(detail.StudyDurationTime)) + }) + }) + return { + rangeText: formatReportRange(report.PeriodStart, report.PeriodEnd), + statusTitle: `${report.ReportTypeName || (reportType === 1 ? '周报' : '月报')}已攻克 ${summary.OvercomeKnowledgePointCount || 0} 个知识点`, + statusDescription: `新增 ${summary.NewKnowledgePointCount || 0} 个知识点,累计学习 ${formatSecondsDuration(summary.StudyDurationTime)},其中攻克成功学习 ${formatSecondsDuration(summary.OvercomeStudyDurationTime)}。`, + newMasteredPoints: Number(summary.OvercomeKnowledgePointCount) || 0, + consecutiveDays: Number(summary.ContinuousStudyDays) || 0, + averageAccuracy: Number(summary.AverageAccuracy) || 0, + scaleLabels: buildDurationScaleLabels(maxMinutes), + trends: detailItems.map((item: ParentLearningReportDetailItem) => buildStudyReportTrend(item, maxMinutes, reportType)), + activity: buildStudyReportActivity(summary, maxMinutes, reportType), + subjectMasteries: (Array.isArray(report.Subjects) ? report.Subjects : []).map((item: ParentLearningReportDetailItem) => buildStudyReportSubjectMastery(item)) + } +} + +function createEmptyStudyReportPeriod(reportType: ParentLearningReportType): StudyReportPeriod { + return { + rangeText: reportType === 1 ? '暂无周报' : '暂无月报', + statusTitle: '暂无学情报告', + statusDescription: '当前周期暂无报告数据。', + newMasteredPoints: 0, + consecutiveDays: 0, + averageAccuracy: 0, + scaleLabels: ['120分', '80分', '40分', '0分'], + trends: [], + activity: { summary: '暂无学习时长数据', activeDays: 0, totalDurationText: '0分钟', points: [] }, + subjectMasteries: [] + } +} + +function buildStudyReportTrend(item: ParentLearningReportDetailItem, maxMinutes: number, reportType: ParentLearningReportType): StudyReportTrend { + const details = Array.isArray(item.StudyDurationDetails) ? item.StudyDurationDetails : [] + return { + subjectId: String(item.SubjectId ?? '0'), + points: details.map((detail: ParentLearningDurationDetail, index: number) => { + const studyMinutes = secondsToMinutes(detail.StudyDurationTime) + const overcomeMinutes = secondsToMinutes(detail.OvercomeStudyDurationTime) + return { + label: formatDurationDetailLabel(detail, index, reportType), + value: studyMinutes, + average: overcomeMinutes, + valueHeight: scaleChartHeight(studyMinutes, maxMinutes, 72), + averageHeight: scaleChartHeight(overcomeMinutes, maxMinutes, 72) + } + }) + } +} + +function buildStudyReportActivity(summary: ParentLearningReportDetailItem, maxMinutes: number, reportType: ParentLearningReportType): StudyReportActivity { + const details = Array.isArray(summary.StudyDurationDetails) ? summary.StudyDurationDetails : [] + return { + summary: `总学习 ${formatSecondsDuration(summary.StudyDurationTime)},未攻克学习 ${formatSecondsDuration(summary.UnOvercomeStudyDurationTime)}。`, + activeDays: Number(summary.ContinuousStudyDays) || 0, + totalDurationText: formatSecondsDuration(summary.StudyDurationTime), + points: details.map((detail: ParentLearningDurationDetail, index: number) => { + const studyMinutes = secondsToMinutes(detail.StudyDurationTime) + const overcomeMinutes = secondsToMinutes(detail.OvercomeStudyDurationTime) + const unOvercomeMinutes = secondsToMinutes(detail.UnOvercomeStudyDurationTime) + return { + label: formatDurationDetailLabel(detail, index, reportType), + studyMinutes, + plannedMinutes: overcomeMinutes, + newMasteredCount: unOvercomeMinutes, + studyHeight: scaleChartHeight(studyMinutes, maxMinutes, 90), + plannedHeight: scaleChartHeight(overcomeMinutes, maxMinutes, 90), + newMasteredHeight: unOvercomeMinutes > 0 ? scaleChartHeight(unOvercomeMinutes, maxMinutes, 72) : 0 + } + }) + } +} + +function buildStudyReportSubjectMastery(item: ParentLearningReportDetailItem): StudyReportSubjectMastery { + const newCount = Number(item.NewKnowledgePointCount) || 0 + const overcomeCount = Number(item.OvercomeKnowledgePointCount) || 0 + return { + subjectName: item.SubjectName ?? '未命名科目', + masteredCount: overcomeCount, + totalCount: newCount, + masteredPercent: newCount > 0 ? Math.min(100, Math.round(overcomeCount / newCount * 100)) : 0 + } +} + +function secondsToMinutes(seconds: number): number { + return Math.round((Number(seconds) || 0) / 60) +} + +function scaleChartHeight(value: number, maxValue: number, maxHeight: number): number { + if (value <= 0 || maxValue <= 0) return 0 + return Math.max(4, Math.round(value / maxValue * maxHeight)) +} + +function buildDurationScaleLabels(maxMinutes: number): string[] { + const top = Math.max(60, Math.ceil(maxMinutes / 30) * 30) + return [`${top}分`, `${Math.round(top * 2 / 3)}分`, `${Math.round(top / 3)}分`, '0分'] +} + +function formatSecondsDuration(seconds: number): string { + const totalMinutes = secondsToMinutes(seconds) + const hours = Math.floor(totalMinutes / 60) + const minutes = totalMinutes % 60 + if (hours > 0 && minutes > 0) return `${hours}小时${minutes}分` + if (hours > 0) return `${hours}小时` + return `${minutes}分钟` +} + +function formatReportRange(start: string | null | undefined, end: string | null | undefined): string { + if (!start || !end) return '暂无统计周期' + return `${formatReportDate(start)} - ${formatReportDate(end)}` +} + +function formatReportDate(value: string | null | undefined): string { + if (!value) return '--' + const text = String(value) + if (text.length >= 10) return text.substring(5, 10).replace('-', '月') + '日' + return text +} + +function formatDurationDetailLabel(detail: ParentLearningDurationDetail, index: number, reportType: ParentLearningReportType): string { + if (reportType === 2) return `第${index + 1}周` + return formatReportDate(detail.StartDate) } export function apiGetStudentVocabulary(studentId: string, showLoading: boolean = true): Promise | null> { @@ -463,7 +695,7 @@ export function apiGetStudentLearningTasks(studentId: string, showLoading: boole * 获取学生当天学习包任务。Status: 0 全部,1 待完成,2 已完成,3 未通过。 */ export function apiGetParentStudyPacks(studentId: string, status: ParentStudyPackStatus = 0, showLoading: boolean = true): Promise | null> { - return get(`/api/v1/ParentStudyPack/GetTodayList?UserId=${studentId}&Status=${status}`, undefined, { showLoading }).then((res) => { + return get(`/api/v1/ParentStudyPack/GetTodayList?userId=${encodeURIComponent(studentId)}&status=${status}`, undefined, { showLoading }).then((res) => { if (!res || !res.data) return null const statusMap: { [key: number]: LearningTaskItem['status'] } = { 0: 'not_started', @@ -482,14 +714,38 @@ export function apiGetParentStudyPacks(studentId: string, status: ParentStudyPac const tasks: LearningTaskItem[] = (Array.isArray(course.packs) ? course.packs : []).map((pack: any) => { const taskStatus = statusMap[Number(pack.status)] || 'not_started' const accuracy = pack.latestAccuracyRate === null || pack.latestAccuracyRate === undefined ? '--' : `${Number(pack.latestAccuracyRate) || 0}%` + const maxCount = Number(pack.maxOvercomeCount) || 0 + const currentCount = Number(pack.currentAttemptNo || pack.completedAttemptCount) || 0 + const remainingCount = Number(pack.remainingAttemptCount) || 0 + const durationSecond = Number(pack.answerDurationSecond) || 0 + const durationMinute = Math.floor(durationSecond / 60) + const attemptText = taskStatus === 'not_started' + ? `尚未开始 · 最多 ${maxCount || 2} 次机会` + : `第 ${currentCount || 1} 次攻克 · 共 ${maxCount || currentCount || 1} 次` + const resultText = taskStatus === 'success' + ? `第 ${currentCount || 1} 次攻克成功 · 共 ${maxCount || currentCount || 1} 次` + : taskStatus === 'failed' + ? `攻克失败 · 剩余 ${remainingCount} 次机会` + : taskStatus === 'in_progress' + ? `攻克中 · 剩余 ${remainingCount} 次机会` + : attemptText + const answerText = durationMinute > 0 ? `答题时长 ${durationMinute} 分钟` : '暂无答题时长' + const recordTime = formatTaskDateTime(pack.latestRecordTime) + const deadlineText = formatTaskDateTime(pack.deadlineTime) + const metaParts: string[] = [`正确率 ${accuracy}`, answerText] + if (recordTime !== '--') metaParts.push(`${recordTime} 完成`) + else if (deadlineText !== '--') metaParts.push(`${deadlineText} 截止`) return { id: String(pack.packId ?? pack.knowledgePointId ?? ''), title: pack.name || '未命名学习任务', status: taskStatus, statusText: pack.statusName || statusTextMap[taskStatus], + resultText, accuracyText: accuracy, - answerText: pack.completedAttemptCount ? `已完成 ${pack.completedAttemptCount} 次` : '尚未完成', - deadlineText: pack.deadlineTime || '' + answerText, + attemptText, + deadlineText, + metaText: metaParts.join(' · ') } }) return { @@ -513,6 +769,7 @@ export function apiGetParentStudyPacks(studentId: string, status: ParentStudyPac studentGrade: '', studentClass: '', pendingCount: Number(res.data.pendingCount) || 0, + totalCount: Number(res.data.totalCount) || groups.reduce((total: number, group: LearningTaskGroup) => total + group.tasks.length, 0), completedCount: Number(res.data.completedCount) || 0, failedCount: Number(res.data.failedCount) || 0, groups @@ -527,10 +784,16 @@ function formatTaskTime(value: any): string { return text.length >= 16 ? text.substring(11, 16) : text } +function formatTaskDateTime(value: any): string { + if (!value) return '--' + const text = String(value) + if (text.length < 16) return text + return `今天 ${text.substring(11, 16)}` +} + /** - * 获取当前学生的预警信息。首页调用时 limit 固定为 3。 + * 兼容旧调用签名,实际统一使用今日学习预警接口。 */ -export function apiGetStudentAlerts(studentId: string, page: number = 1, pageSize: number = 20, limit?: number, showLoading: boolean = true): Promise | null> { - const suffix = limit ? `limit=${limit}` : `page=${page}&pageSize=${pageSize}` - return get(`/api/parent/alerts?studentId=${studentId}&${suffix}`, undefined, { showLoading }) +export function apiGetStudentAlerts(studentId: string, _page: number = 1, _pageSize: number = 20, limit?: number, showLoading: boolean = true): Promise | null> { + return apiGetStudentLearningWarnings(studentId, showLoading, limit) } diff --git a/components/qr-scanner.uvue b/components/qr-scanner.uvue index 5d16463..9892ecd 100644 --- a/components/qr-scanner.uvue +++ b/components/qr-scanner.uvue @@ -16,11 +16,6 @@ diff --git a/pages/growth/index.uvue b/pages/growth/index.uvue index 11521b7..3ccfbb8 100644 --- a/pages/growth/index.uvue +++ b/pages/growth/index.uvue @@ -8,14 +8,23 @@ @@ -412,18 +448,25 @@ .student-picker-list { max-height: 340px; padding: 0 20px; } .student-picker-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 150px; } .student-picker-empty-text { font-size: 13px; color: #8992a5; } - .student-picker-item { display: flex; flex-direction: row; align-items: center; padding: 14px 12px; margin-bottom: 10px; border-radius: 13px; background-color: #f7f9fc; } + .student-picker-item { display: flex; flex-direction: row; align-items: center; padding: 10px; margin-bottom: 10px; border: 1px solid #edf0f5; border-radius: 15px; background-color: #ffffff; } .student-picker-item-selected { background-color: #f0efff; } .student-picker-avatar { display: flex; flex-direction: column; align-items: center; justify-content: center; width: 46px; height: 46px; border-radius: 14px; background-color: #7161ed; } + .student-picker-avatar-0 { background-color: #6558e9; } + .student-picker-avatar-1 { background-color: #12a9df; } + .student-picker-avatar-2 { background-color: #e63a9c; } .student-picker-avatar-image { width: 46px; height: 46px; border-radius: 14px; } .student-picker-avatar-text { font-size: 18px; font-weight: 700; color: #ffffff; } .student-picker-info { display: flex; flex-direction: column; flex: 1; margin-left: 11px; } .student-picker-name-row { display: flex; flex-direction: row; align-items: center; margin-bottom: 5px; } .student-picker-name { margin-right: 8px; font-size: 15px; font-weight: 700; color: #2a3042; } .student-picker-grade { padding: 2px 6px; border-radius: 7px; font-size: 10px; color: #554be9; background-color: #e8e7ff; } + .student-picker-role { margin-left: 7px; padding: 2px 6px; border-radius: 8px; font-size: 9px; color: #7c8ba1; background-color: #f1f4f8; } + .student-picker-status { margin-left: 7px; padding: 2px 6px; border-radius: 8px; font-size: 9px; color: #16a979; background-color: #e7faf2; } .student-picker-detail { margin-top: 2px; font-size: 11px; color: #7e8799; } .student-picker-check { padding: 4px 7px; border-radius: 9px; background-color: #554be9; } .student-picker-check-text { font-size: 10px; color: #ffffff; } + .student-picker-action { flex-shrink: 0; padding: 5px 8px; border-radius: 10px; font-size: 9px; color: #6e7c91; background-color: #f1f4f8; } + .student-picker-action-selected { color: #ffffff; background-color: #554be9; } .student-picker-footer { display: flex; flex-direction: row; padding: 12px 20px calc(12px + var(--uni-safe-area-inset-bottom)); border-top: 1px solid #edf0f5; } .student-picker-cancel, .student-picker-confirm { display: flex; flex-direction: column; align-items: center; justify-content: center; flex: 1; height: 44px; border-radius: 11px; } .student-picker-cancel { margin-right: 10px; background-color: #f0f2f7; } diff --git a/pages/login/index.uvue b/pages/login/index.uvue index 28b0c00..1c6aeef 100644 --- a/pages/login/index.uvue +++ b/pages/login/index.uvue @@ -68,7 +68,7 @@ import { apiLogin } from '../../api/auth' import { apiGetBoundStudents, type BoundStudentSummary } from '../../api/student' import { setUserInfo, saveRememberInfo, getRememberInfo } from '../../store/user' - import { applyBoundStudent, saveSelectedStudent } from '../../store/home' + import { switchBoundStudent } from '../../store/home' type LoginForm = { phone: string @@ -144,8 +144,7 @@ ? res.data.students.find((item) => item.id === savedStudent.id)! : res.data.students[0] - saveSelectedStudent(selectedStudent) - applyBoundStudent(selectedStudent) + switchBoundStudent(selectedStudent) } /** diff --git a/pages/profile/index.uvue b/pages/profile/index.uvue index a0af78c..6cab88a 100644 --- a/pages/profile/index.uvue +++ b/pages/profile/index.uvue @@ -62,7 +62,7 @@ diff --git a/pages/tasks/index.uvue b/pages/tasks/index.uvue index 630e28a..c5143ea 100644 --- a/pages/tasks/index.uvue +++ b/pages/tasks/index.uvue @@ -1,100 +1,270 @@ diff --git a/pages/today-learning/index.uvue b/pages/today-learning/index.uvue index 9de7a83..c556b4e 100644 --- a/pages/today-learning/index.uvue +++ b/pages/today-learning/index.uvue @@ -56,7 +56,7 @@ import MainTabBar from '../../components/main-tab-bar.uvue' import UniIcons from '../../uni_modules/uni-icons-x/components/uni-icons/uni-icons.uvue' import { apiGetTodayLearningDetail, type TodayLearningDetail } from '../../api/student' - import { homeStudentProfile } from '../../store/home' + import { homeStudentProfile, selectedStudentChangeVersion } from '../../store/home' const isLoading = ref(true) const detail = ref({ @@ -64,12 +64,21 @@ answerCount: 0, completedPackages: 0, totalPackages: 0, masteredPoints: 0, courses: [], score: { accuracy: 0, yesterdayAccuracy: 0, change: 0 }, pointsTotal: 0, pointDetails: [] }) + const observedStudentVersion = ref(selectedStudentChangeVersion.value) onLoad(() => { loadTodayLearning() }) + onShow(() => { + if (observedStudentVersion.value !== selectedStudentChangeVersion.value) { + observedStudentVersion.value = selectedStudentChangeVersion.value + loadTodayLearning() + } + }) + async function loadTodayLearning() { + isLoading.value = true const studentId = homeStudentProfile.value?.id ?? '' if (!studentId) { isLoading.value = false diff --git a/pages/vocabulary/index.uvue b/pages/vocabulary/index.uvue index 8b3d3d9..20c0e54 100644 --- a/pages/vocabulary/index.uvue +++ b/pages/vocabulary/index.uvue @@ -8,14 +8,23 @@