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
167 lines
5.0 KiB
TypeScript
167 lines
5.0 KiB
TypeScript
"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)
|
||
}
|
||
}
|
||
|