接入学生学习数据接口

This commit is contained in:
tanxin
2026-11-05 11:01:12 +08:00
parent d1d44e250e
commit af73453035
15 changed files with 336 additions and 48 deletions
+196 -6
View File
@@ -14,7 +14,8 @@ export type StudentInfo = {
account: string
avatar: string
grade: string
class: string
className: string
schoolName: string
}
// 首页当前学生基础信息
@@ -24,6 +25,7 @@ export type StudentHomeProfile = {
account: string
grade: string
school: string
className: string
avatar: string
comprehensiveLevel: 'excellent' | 'good' | 'qualified' | 'needs_improvement'
}
@@ -35,6 +37,7 @@ export type BoundStudentSummary = {
account: string
grade: string
school: string
className: string
avatar: string
}
@@ -46,6 +49,7 @@ export type StudentHomeMetrics = {
learningMinutesToday: number
accuracyToday: number | null
learningDaysThisWeek: number
shouldStudyDaysThisWeek: number
pendingHomeworkCount: number
updatedAt: string
}
@@ -156,6 +160,7 @@ export type TodayLearningDetail = {
export type VocabularyBook = {
id: string
name: string
cover: string
subtitle: string
totalWords: number
learnedWords: number
@@ -228,6 +233,8 @@ export type StudentLearningTasks = {
groups: LearningTaskGroup[]
}
export type ParentStudyPackStatus = 0 | 1 | 2 | 3
export type StudentAlertLevel = 'critical' | 'high' | 'medium' | 'low'
export type StudentAlert = {
@@ -249,6 +256,22 @@ export type StudentAlertList = {
}
}
export type StudentLearningWarningItem = {
type: number
title: string
description: string
isTriggered: boolean
statusName: string
}
export type StudentLearningWarningResult = {
userId: string
date: string
totalCount: number
triggeredCount: number
items: StudentLearningWarningItem[]
}
// 验证学生二维码请求参数
export type VerifyQRCodeParams = {
qrCode: string
@@ -277,7 +300,7 @@ export function apiVerifyStudentQRCode(params: VerifyQRCodeParams): Promise<ApiR
export function apiVerifyStudentAccount(params: VerifyAccountParams): Promise<ApiResponse<StudentInfo> | null> {
return get<any>('/api/v1/Parents/VerifyStudent', { RealName: params.name, Account: params.account }).then((res) => {
if (!res || !res.data) return null
return { code: res.code, message: res.message, data: { id: String(res.data.userId), name: res.data.name, account: res.data.account, avatar: res.data.avatar || '', grade: res.data.gradeLevel || '', class: res.data.className || '' } }
return { code: res.code, message: res.message, data: { id: String(res.data.userId), name: res.data.name, account: res.data.account, avatar: res.data.avatar || '', grade: res.data.gradeLevel || '', className: res.data.className || '', schoolName: res.data.schoolName || '' } }
})
}
@@ -301,14 +324,83 @@ export function apiGetStudentHomeProfile(studentId?: string, showLoading: boolea
* 获取当前家长绑定的全部学生,用于首页切换学生。
*/
export function apiGetBoundStudents(): Promise<ApiResponse<{ students: BoundStudentSummary[], currentStudentId: string | null }> | null> {
return get<{ students: BoundStudentSummary[], currentStudentId: string | null }>('/api/parent/students')
return get<any>('/api/v1/Parents/GetBoundStudents').then((res) => {
if (!res || !res.data) return null
const items = Array.isArray(res.data) ? res.data : res.data.students
if (!Array.isArray(items)) return null
return {
code: res.code,
message: res.message,
data: {
students: items.map((item: any) => ({
id: String(item.userId),
name: item.name || '',
account: item.account || '',
grade: item.gradeLevel || '',
school: item.schoolName || '',
className: item.className || '',
avatar: item.avatar || ''
})),
currentStudentId: null
}
}
})
}
/**
* 获取指定学生的首页今日学习概览。
*/
export function apiGetStudentHomeMetrics(studentId: string, showLoading: boolean = true): Promise<ApiResponse<StudentHomeMetrics> | null> {
return get<StudentHomeMetrics>(`/api/parent/home-metrics?studentId=${studentId}`, undefined, { showLoading })
return get<any>(`/api/v1/ParentStudentToday/GetTodayInfo?userId=${studentId}`, undefined, { showLoading }).then((res) => {
if (!res || !res.data) return null
return {
code: res.code,
message: res.message,
data: {
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,
learningDaysThisWeek: Number(res.data.weekStudyDays) || 0,
shouldStudyDaysThisWeek: Number(res.data.weekShouldStudyDays) || 0,
pendingHomeworkCount: Number(res.data.pendingPackCount) || 0,
updatedAt: res.data.date || ''
}
}
})
}
/**
* 获取指定学生今日学习预警,仅返回已触发的预警规则。
*/
export function apiGetStudentLearningWarnings(studentId: string, showLoading: boolean = true): Promise<ApiResponse<StudentAlertList> | null> {
return get<any>(`/api/v1/ParentLearningWarning/GetTodayList?userId=${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
}))
return {
code: res.code,
message: res.message,
data: {
list,
pagination: {
page: 1,
pageSize: list.length,
total: list.length,
hasMore: false
}
}
}
})
}
/**
@@ -326,7 +418,37 @@ export function apiGetStudentStudyReport(studentId: string, showLoading: boolean
}
export function apiGetStudentVocabulary(studentId: string, showLoading: boolean = true): Promise<ApiResponse<StudentVocabulary> | null> {
return get<StudentVocabulary>(`/api/parent/vocabulary?studentId=${studentId}`, undefined, { showLoading })
return get<any>(`/api/v1/Parents/GetAllLexiconBooks/${studentId}`, undefined, { showLoading }).then((res) => {
if (!res || !Array.isArray(res.data)) return null
const books: VocabularyBook[] = res.data.map((item: any) => {
const learnedWords = Number(item.lexiconCount) || 0
const totalWords = Number(item.totalCount) || learnedWords
const status: VocabularyBook['status'] = totalWords > 0 && learnedWords >= totalWords
? 'completed'
: item.isStudying
? 'learning'
: learnedWords > 0
? 'unfinished'
: 'not_started'
return {
id: String(item.id ?? item.title ?? ''),
name: item.title || '',
cover: item.cover || '',
subtitle: `总词量 ${totalWords} 词`,
totalWords,
learnedWords,
status,
statusText: status === 'completed' ? '已完成' : status === 'learning' ? '学习中' : status === 'unfinished' ? '未学完' : '未开始',
levelText: item.slogan || '',
color: status === 'learning' ? 'green' : status === 'unfinished' ? 'yellow' : status === 'completed' ? 'blue' : 'gray'
}
})
return {
code: res.code,
message: res.message,
data: { studentId, studentName: '', studentGrade: '', studentClass: '', bookCount: books.length, books }
}
})
}
export function apiGetStudentGrowth(studentId: string, showLoading: boolean = true): Promise<ApiResponse<StudentGrowth> | null> {
@@ -334,7 +456,75 @@ export function apiGetStudentGrowth(studentId: string, showLoading: boolean = tr
}
export function apiGetStudentLearningTasks(studentId: string, showLoading: boolean = true): Promise<ApiResponse<StudentLearningTasks> | null> {
return get<StudentLearningTasks>(`/api/parent/learning-tasks?studentId=${studentId}`, undefined, { showLoading })
return apiGetParentStudyPacks(studentId, 0, showLoading)
}
/**
* 获取学生当天学习包任务。Status: 0 全部,1 待完成,2 已完成,3 未通过。
*/
export function apiGetParentStudyPacks(studentId: string, status: ParentStudyPackStatus = 0, showLoading: boolean = true): Promise<ApiResponse<StudentLearningTasks> | null> {
return get<any>(`/api/v1/ParentStudyPack/GetTodayList?UserId=${studentId}&Status=${status}`, undefined, { showLoading }).then((res) => {
if (!res || !res.data) return null
const statusMap: { [key: number]: LearningTaskItem['status'] } = {
0: 'not_started',
1: 'in_progress',
2: 'success',
3: 'failed'
}
const statusTextMap: { [key: string]: string } = {
not_started: '待完成',
in_progress: '进行中',
success: '已完成',
failed: '未通过'
}
const courses = Array.isArray(res.data.courses) ? res.data.courses : []
const groups: LearningTaskGroup[] = courses.map((course: any) => {
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}%`
return {
id: String(pack.packId ?? pack.knowledgePointId ?? ''),
title: pack.name || '未命名学习任务',
status: taskStatus,
statusText: pack.statusName || statusTextMap[taskStatus],
accuracyText: accuracy,
answerText: pack.completedAttemptCount ? `已完成 ${pack.completedAttemptCount} 次` : '尚未完成',
deadlineText: pack.deadlineTime || ''
}
})
return {
id: String(course.courseId ?? course.sectionCount ?? ''),
subject: course.baseSubjectName || '',
unit: course.studyStageName || '',
lesson: course.courseName || course.sectionName || '',
startText: formatTaskTime(course.planStartTime),
endText: formatTaskTime(course.planEndTime),
knowledgeCount: Number(course.knowledgePointCount) || tasks.length,
note: course.deadlineTime ? `截止时间:${formatTaskTime(course.deadlineTime)}` : '',
tasks
}
})
return {
code: res.code,
message: res.message,
data: {
studentId: String(res.data.userId ?? studentId),
studentName: res.data.userName || '',
studentGrade: '',
studentClass: '',
pendingCount: Number(res.data.pendingCount) || 0,
completedCount: Number(res.data.completedCount) || 0,
failedCount: Number(res.data.failedCount) || 0,
groups
}
}
})
}
function formatTaskTime(value: any): string {
if (!value) return '--'
const text = String(value)
return text.length >= 16 ? text.substring(11, 16) : text
}
/**