Files
NextEdu/src/app/(dashboard)/parent/leave/page.tsx
SpecialX fc150e1e14 feat(app,styles): update dashboard pages and global styles
- Update parent: children/[studentId]/page, elective/page, leave/page

- Update student: error-book/student-error-book-list-client

- Update teacher: classes/schedule/schedule-filters, classes/students/students-filters

- Update src/app/globals.css
2026-07-07 16:22:27 +08:00

119 lines
4.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.
import Link from "next/link"
import { getTranslations } from "next-intl/server"
import { ArrowLeft, CalendarDays } from "lucide-react"
import { getAuthContext } from "@/shared/lib/auth-guard"
import { Button } from "@/shared/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/shared/components/ui/card"
import { getChildrenAction, getChildBasicInfoAction } from "@/modules/parent/actions"
import { getLeaveRequests } from "@/modules/leave-requests/data-access"
import {
LeaveRequestForm,
type ChildOption,
} from "@/modules/leave-requests/components/leave-request-form"
import { LeaveRequestList } from "@/modules/leave-requests/components/leave-request-list"
export const dynamic = "force-dynamic"
/**
* 家长在线请假页面。
*
* L-5 功能:
* - 顶部:请假申请表单(下拉选择子女,自动写入 classId
* - 底部:该家长所有子女的请假申请列表(按 dataScope=children 过滤)
*/
export default async function ParentLeavePage() {
const t = await getTranslations("leave")
const ctx = await getAuthContext()
if (ctx.dataScope.type !== "children" || ctx.dataScope.childrenIds.length === 0) {
return (
<div className="p-6 md:p-8 space-y-6">
<div className="space-y-1">
<h1 className="text-2xl font-bold tracking-tight">{t("title.parent")}</h1>
<p className="text-sm text-muted-foreground">{t("description.parent")}</p>
</div>
<Card>
<CardContent className="py-10 text-center text-sm text-muted-foreground">
{t("empty.parentDesc")}
</CardContent>
</Card>
<Button asChild variant="ghost" size="sm" className="gap-2 -ml-2">
<Link href="/parent/dashboard">{t("backToDashboard")}</Link>
</Button>
</div>
)
}
// 并行:子女关系列表 + 已有请假申请列表
// 审计 v1 P0 修复G4-002改调 Server Action统一权限校验入口
const [relations, leaveResult] = await Promise.all([
getChildrenAction(),
getLeaveRequests({
scope: ctx.dataScope,
currentUserId: ctx.userId,
page: 1,
pageSize: 50,
}),
])
// 构造子女选项(含 activeClass供表单下拉使用
const childOptions: ChildOption[] = []
for (const r of relations) {
const basic = await getChildBasicInfoAction(r.studentId, r.relation)
if (basic && basic.classId && basic.className) {
childOptions.push({
id: basic.id,
name: basic.name ?? "Unknown",
classId: basic.classId,
className: basic.className,
})
}
}
return (
<div className="p-6 md:p-8 space-y-6">
<div className="space-y-1">
<h1 className="text-2xl font-bold tracking-tight">{t("title.parent")}</h1>
<p className="text-sm text-muted-foreground">{t("description.parent")}</p>
</div>
<Button asChild variant="ghost" size="sm" className="gap-2 -ml-2">
<Link href="/parent/dashboard" aria-label={t("backToDashboard")}>
<ArrowLeft className="h-4 w-4" />
{t("backToDashboard")}
</Link>
</Button>
{childOptions.length > 0 ? (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-base">
<CalendarDays className="h-4 w-4 text-muted-foreground" aria-hidden />
{t("onlineLeave")}
</CardTitle>
</CardHeader>
<CardContent>
<LeaveRequestForm childOptions={childOptions} />
</CardContent>
</Card>
) : (
<Card>
<CardContent className="py-10 text-center text-sm text-muted-foreground">
{t("empty.parentDesc")}
</CardContent>
</Card>
)}
<div className="space-y-3">
<h2 className="text-lg font-semibold">{t("onlineLeave")}</h2>
<LeaveRequestList
items={leaveResult.items}
emptyTitle={t("empty.parentTitle")}
emptyDescription={t("empty.parentDesc")}
/>
</div>
</div>
)
}