This commit is contained in:
hexi
2026-11-06 16:56:49 +08:00
4 changed files with 166 additions and 142 deletions
+97 -14
View File
@@ -255,6 +255,14 @@ export type StudentGrowth = {
records: GrowthPointRecord[]
}
export type StudentPointRecordsPage = {
records: GrowthPointRecord[]
total: number
pageIndex: number
pageSize: number
lastId: number | null
}
export type LearningTaskItem = {
id: string
title: string
@@ -333,6 +341,15 @@ export type StudentLearningWarningResult = {
items: StudentLearningWarningItem[]
}
const learningWarningTypeMap: { [key: number]: { title: string, level: StudentAlertLevel } } = {
1: { title: '今日未打卡', level: 'high' },
2: { title: '仅学无交', level: 'medium' },
3: { title: '作业未完成', level: 'high' },
4: { title: '攻克失败', level: 'critical' },
5: { title: '连续 3 天未学习', level: 'high' },
6: { title: '正确率明显下滑', level: 'medium' }
}
// 验证学生二维码请求参数
export type VerifyQRCodeParams = {
qrCode: string
@@ -433,26 +450,30 @@ export function apiGetStudentHomeMetrics(studentId: string, showLoading: boolean
}
/**
* 获取指定学生今日学习预警。已触发预警优先,其后展示未触发规则。
* 获取指定学生今日学习预警。已触发预警优先,其后展示未触发规则,可按数量裁剪。
*/
export function apiGetStudentLearningWarnings(studentId: string, showLoading: boolean = true, limit?: number): Promise<ApiResponse<StudentAlertList> | null> {
export function apiGetStudentLearningWarnings(studentId: string, showLoading: boolean = true, limit?: number, onlyTriggered: boolean = false): Promise<ApiResponse<StudentAlertList> | null> {
return get<StudentLearningWarningResult>(`/api/v1/ParentLearningWarning/GetTodayList?userId=${encodeURIComponent(studentId)}`, undefined, { showLoading }).then((res) => {
if (!res || !res.data || !Array.isArray(res.data.items)) return null
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 orderedItems = triggeredItems.concat(normalItems)
const sourceItems = onlyTriggered ? triggeredItems : orderedItems
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 || ''
}))
const list: StudentAlert[] = visibleItems.map((item: StudentLearningWarningItem, index: number) => {
const warningType = learningWarningTypeMap[Number(item.type)]
return {
id: `${studentId}-${item.type ?? index}`,
level: item.isTriggered ? warningType?.level ?? 'high' : 'low',
title: item.title || warningType?.title || '学习预警',
content: item.description || item.statusName || '',
occurredAt: warningData.date || '',
isRead: !item.isTriggered,
isTriggered: Boolean(item.isTriggered),
statusName: item.statusName || (item.isTriggered ? '已触发' : '正常')
}
})
return {
code: res.code,
message: res.message,
@@ -684,7 +705,69 @@ export function apiGetStudentVocabulary(studentId: string, showLoading: boolean
}
export function apiGetStudentGrowth(studentId: string, showLoading: boolean = true): Promise<ApiResponse<StudentGrowth> | null> {
return get<StudentGrowth>(`/api/parent/growth?studentId=${studentId}`, undefined, { showLoading })
return get<any>(`/api/v1/StudentPoints/GetStudentPointSummary/${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),
studentName: '',
studentGrade: '',
studentClass: '',
pointsBalance: Number(res.data.totalPoints) || 0,
level: Number(res.data.level) || 0,
rank: Number(res.data.classRank) || 0,
streakDays: Number(res.data.noPointDays) || 0,
totalPoints: Number(res.data.todayPoints) || 0,
records: []
}
}
})
}
/**
* 分页获取学生积分流水。
*/
export function apiGetStudentPointRecords(studentId: string, pageIndex: number = 1, pageSize: number = 20, prevPageId?: number, showLoading: boolean = true): Promise<ApiResponse<StudentPointRecordsPage> | null> {
const prevPageQuery = prevPageId === undefined || prevPageId === null ? '' : `&PrevPageId=${prevPageId}`
return get<any>(`/api/v1/StudentPoints/GetStudentPointRecords?UserId=${studentId}&PageIndex=${pageIndex}&PageSize=${pageSize}${prevPageQuery}`, undefined, { showLoading }).then((res) => {
if (!res || !res.data) return null
const page = res.data
const records: GrowthPointRecord[] = (Array.isArray(page.data) ? page.data : []).map((item: any) => ({
id: String(item.id),
title: item.pointMessage || '积分变动',
timeText: formatPointRecordTime(item.bizTime),
points: Number(item.points) || 0,
icon: pointRecordIcon(Number(item.type))
}))
return {
code: res.code,
message: res.message,
data: {
records,
total: Number(page.total) || 0,
pageIndex: Number(page.pageIndex) || pageIndex,
pageSize: Number(page.pageSize) || pageSize,
lastId: page.id === null || page.id === undefined ? null : Number(page.id)
}
}
})
}
function pointRecordIcon(type: number): GrowthPointRecord['icon'] {
if (type === 1) return 'calendar'
if (type === 2 || type === 3) return 'assignment'
if (type === 4) return 'streak'
if (type === 5 || type === 6) return 'accuracy'
if (type === 7 || type === 8) return 'mastery'
return 'note'
}
function formatPointRecordTime(value: any): string {
if (!value) return '--'
const text = String(value)
return text.length >= 16 ? text.substring(5, 16).replace('T', ' ') : text
}
export function apiGetStudentLearningTasks(studentId: string, showLoading: boolean = true): Promise<ApiResponse<StudentLearningTasks> | null> {