feat(dashboard): optimize teacher dashboard ui and layout
- Refactor layout: move Needs Grading to main column, Homework to sidebar - Enhance TeacherStats: replace static counts with actionable metrics (Needs Grading, Active Assignments, Avg Score, Submission Rate) - Update RecentSubmissions: table view with quick grade actions and late status - Update TeacherSchedule: vertical timeline view with scroll hints - Update TeacherHomeworkCard: compact list view - Integrate Recharts: add TeacherGradeTrends chart and shared chart component - Update documentation
This commit is contained in:
@@ -29,8 +29,69 @@ import type {
|
||||
StudentDashboardGradeProps,
|
||||
StudentHomeworkScoreAnalytics,
|
||||
StudentRanking,
|
||||
TeacherGradeTrendItem,
|
||||
} from "./types"
|
||||
|
||||
export const getTeacherGradeTrends = cache(async (teacherId: string, limit: number = 5): Promise<TeacherGradeTrendItem[]> => {
|
||||
const recentAssignments = await db.query.homeworkAssignments.findMany({
|
||||
where: and(
|
||||
eq(homeworkAssignments.creatorId, teacherId),
|
||||
or(eq(homeworkAssignments.status, "published"), eq(homeworkAssignments.status, "archived"))
|
||||
),
|
||||
orderBy: [desc(homeworkAssignments.createdAt)],
|
||||
limit: limit,
|
||||
})
|
||||
|
||||
if (recentAssignments.length === 0) return []
|
||||
|
||||
const assignmentIds = recentAssignments.map((a) => a.id)
|
||||
|
||||
const [maxScoreMap, targetCountRows, submissionStats] = await Promise.all([
|
||||
getAssignmentMaxScoreById(assignmentIds),
|
||||
db
|
||||
.select({
|
||||
assignmentId: homeworkAssignmentTargets.assignmentId,
|
||||
count: count(homeworkAssignmentTargets.studentId),
|
||||
})
|
||||
.from(homeworkAssignmentTargets)
|
||||
.where(inArray(homeworkAssignmentTargets.assignmentId, assignmentIds))
|
||||
.groupBy(homeworkAssignmentTargets.assignmentId),
|
||||
db
|
||||
.select({
|
||||
assignmentId: homeworkSubmissions.assignmentId,
|
||||
avgScore: sql<number>`AVG(${homeworkSubmissions.score})`,
|
||||
count: count(homeworkSubmissions.id),
|
||||
})
|
||||
.from(homeworkSubmissions)
|
||||
.where(
|
||||
and(
|
||||
inArray(homeworkSubmissions.assignmentId, assignmentIds),
|
||||
eq(homeworkSubmissions.status, "graded")
|
||||
)
|
||||
)
|
||||
.groupBy(homeworkSubmissions.assignmentId),
|
||||
])
|
||||
|
||||
const targetCountMap = new Map<string, number>()
|
||||
for (const r of targetCountRows) targetCountMap.set(r.assignmentId, r.count)
|
||||
|
||||
const statsMap = new Map<string, { avg: number; count: number }>()
|
||||
for (const r of submissionStats) statsMap.set(r.assignmentId, { avg: Number(r.avgScore), count: Number(r.count) })
|
||||
|
||||
return recentAssignments.map((a) => {
|
||||
const stats = statsMap.get(a.id) ?? { avg: 0, count: 0 }
|
||||
return {
|
||||
id: a.id,
|
||||
title: a.title,
|
||||
averageScore: stats.avg,
|
||||
maxScore: maxScoreMap.get(a.id) ?? 0,
|
||||
submissionCount: stats.count,
|
||||
totalStudents: targetCountMap.get(a.id) ?? 0,
|
||||
createdAt: a.createdAt.toISOString(),
|
||||
}
|
||||
}).reverse() // Reverse to show trend from left (older) to right (newer)
|
||||
})
|
||||
|
||||
const isRecord = (v: unknown): v is Record<string, unknown> => typeof v === "object" && v !== null
|
||||
|
||||
const toQuestionContent = (v: unknown): HomeworkQuestionContent | null => {
|
||||
|
||||
Reference in New Issue
Block a user