首页、学情、任务绑定接口
This commit is contained in:
+294
-31
@@ -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<ApiResponse<{ students: BoundStud
|
||||
* 获取指定学生的首页今日学习概览。
|
||||
*/
|
||||
export function apiGetStudentHomeMetrics(studentId: string, showLoading: boolean = true): Promise<ApiResponse<StudentHomeMetrics> | null> {
|
||||
return get<any>(`/api/v1/ParentStudentToday/GetTodayInfo?userId=${studentId}`, undefined, { showLoading }).then((res) => {
|
||||
return get<ParentStudentTodayInfoResult>(`/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<ApiResponse<StudentAlertList> | null> {
|
||||
return get<any>(`/api/v1/ParentLearningWarning/GetTodayList?userId=${studentId}`, undefined, { showLoading }).then((res) => {
|
||||
export function apiGetStudentLearningWarnings(studentId: string, showLoading: boolean = true, limit?: number): 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 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<ApiResponse<StudentStudyReport> | null> {
|
||||
return get<StudentStudyReport>(`/api/parent/study-report?studentId=${studentId}`, undefined, { showLoading })
|
||||
export async function apiGetStudentStudyReport(studentId: string, showLoading: boolean = true): Promise<ApiResponse<StudentStudyReport> | null> {
|
||||
const weekRes = await get<ParentLearningReportResult>(`/api/v1/ParentLearningReport/Get?userId=${encodeURIComponent(studentId)}&reportType=1`, undefined, { showLoading })
|
||||
const monthRes = await get<ParentLearningReportResult>(`/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<ApiResponse<StudentVocabulary> | 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<ApiResponse<StudentLearningTasks> | null> {
|
||||
return get<any>(`/api/v1/ParentStudyPack/GetTodayList?UserId=${studentId}&Status=${status}`, undefined, { showLoading }).then((res) => {
|
||||
return get<any>(`/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<ApiResponse<StudentAlertList> | null> {
|
||||
const suffix = limit ? `limit=${limit}` : `page=${page}&pageSize=${pageSize}`
|
||||
return get<StudentAlertList>(`/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<ApiResponse<StudentAlertList> | null> {
|
||||
return apiGetStudentLearningWarnings(studentId, showLoading, limit)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user