Files
NextEdu/src/modules/dashboard/actions.ts
SpecialX 138b6f1b00 feat(dashboard,diagnostic,elective): add widgets, layout, parent dashboard, role-config, services, elective components
dashboard:

- Add comparison-badge, dashboard-notification-widget, dashboard-responsive-layout, dashboard-time-range-filter

- Add parent-dashboard components directory

- Add config, hooks, and services directories

diagnostic:

- Add role-config and services directory

elective:

- Add elective-course-detail, elective-stats-cards, parent-selection-view components

- Add data-access-settings and data-access-stats
2026-07-03 10:25:46 +08:00

167 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use server"
import { requirePermission } from "@/shared/lib/auth-guard"
import { Permissions } from "@/shared/types/permissions"
import type { ActionState } from "@/shared/types/action-state"
import { handleActionError } from "@/shared/lib/action-utils"
import { getClassSchedule, getStudentClasses, getStudentSchedule, getTeacherClasses, getTeacherIdForMutations } from "@/modules/classes/data-access"
import {
getHomeworkAssignments,
getHomeworkSubmissions,
} from "@/modules/homework/data-access"
import { getStudentHomeworkAssignments } from "@/modules/homework/data-access-student"
import { getStudentDashboardGrades, getTeacherGradeTrends } from "@/modules/homework/stats-service"
import { getCurrentStudentUser, getUserBasicInfo } from "@/modules/users/data-access"
import { getParentDashboardData } from "@/modules/parent/data-access"
import { getAdminDashboardData } from "./data-access"
import type {
AdminDashboardData,
StudentDashboardProps,
TeacherDashboardData,
} from "./types"
import type { ParentDashboardData } from "@/modules/parent/types"
import {
computeTeacherMetrics,
countStudentAssignments,
sortUpcomingAssignments,
toWeekday,
filterTodaySchedule,
type TeacherDashboardMetrics,
} from "./lib/dashboard-utils"
/**
* 获取管理员仪表盘数据。
* 权限DASHBOARD_ADMIN_READ
*/
export async function getAdminDashboardAction(): Promise<ActionState<AdminDashboardData>> {
try {
const ctx = await requirePermission(Permissions.DASHBOARD_ADMIN_READ)
const data = await getAdminDashboardData(ctx.dataScope)
return { success: true, data }
} catch (e) {
return handleActionError(e)
}
}
/**
* 获取教师仪表盘数据(含派生指标)。
* 权限DASHBOARD_TEACHER_READ
*/
export async function getTeacherDashboardAction(): Promise<ActionState<TeacherDashboardData & {
metrics: TeacherDashboardMetrics
}>> {
try {
await requirePermission(Permissions.DASHBOARD_TEACHER_READ)
const teacherId = await getTeacherIdForMutations()
const [classes, schedule, assignments, submissions, teacherProfile, gradeTrends] = await Promise.all([
getTeacherClasses({ teacherId }),
getClassSchedule({ teacherId }),
getHomeworkAssignments({ creatorId: teacherId }),
getHomeworkSubmissions({ creatorId: teacherId }),
getUserBasicInfo(teacherId),
getTeacherGradeTrends(teacherId),
])
const metrics = computeTeacherMetrics(
classes,
schedule,
assignments,
submissions,
gradeTrends,
new Date(),
)
return {
success: true,
data: {
classes,
schedule,
assignments,
submissions,
teacherName: teacherProfile?.name ?? "",
gradeTrends,
metrics,
},
}
} catch (e) {
return handleActionError(e)
}
}
/**
* 获取学生仪表盘数据(含派生指标)。
* 权限DASHBOARD_STUDENT_READ
*/
export async function getStudentDashboardAction(): Promise<ActionState<{
student: { id: string; name: string } | null
dashboardProps: Omit<StudentDashboardProps, "studentName"> | null
}>> {
try {
await requirePermission(Permissions.DASHBOARD_STUDENT_READ)
const student = await getCurrentStudentUser()
if (!student) {
return { success: true, data: { student: null, dashboardProps: null } }
}
const [classes, schedule, assignments, grades] = await Promise.all([
getStudentClasses(student.id),
getStudentSchedule(student.id),
getStudentHomeworkAssignments(student.id),
getStudentDashboardGrades(student.id),
])
const now = new Date()
const stats = countStudentAssignments(assignments, now)
const todayWeekday = toWeekday(now)
const todayScheduleItems = filterTodaySchedule(schedule, todayWeekday)
const upcomingAssignments = sortUpcomingAssignments(assignments, 6)
return {
success: true,
data: {
student: { id: student.id, name: student.name },
dashboardProps: {
enrolledClassCount: classes.length,
dueSoonCount: stats.dueSoonCount,
overdueCount: stats.overdueCount,
gradedCount: stats.gradedCount,
todayScheduleItems,
upcomingAssignments,
grades,
},
},
}
} catch (e) {
return handleActionError(e)
}
}
/**
* 获取家长仪表盘数据。
* 权限DASHBOARD_PARENT_READ
*/
export async function getParentDashboardAction(): Promise<ActionState<{
data: ParentDashboardData | null
hasChildren: boolean
}>> {
try {
const ctx = await requirePermission(Permissions.DASHBOARD_PARENT_READ)
// 非 admin 且 dataScope 非 children 类型时,无孩子数据
if (
ctx.dataScope.type !== "all" &&
!(ctx.dataScope.type === "children" && ctx.dataScope.childrenIds.length > 0)
) {
return { success: true, data: { data: null, hasChildren: false } }
}
const data = await getParentDashboardData(ctx.userId)
return { success: true, data: { data, hasChildren: data.children.length > 0 } }
} catch (e) {
return handleActionError(e)
}
}