- 学生域 32 页全量迁移(含作答/自动保存/提交/诊断) - 补齐 4 个 MSW mock 缺口,修 diagnostic case 名 - 修 4 处 Tailwind 任意值;新增共享组件与路由
113 lines
3.1 KiB
TypeScript
113 lines
3.1 KiB
TypeScript
"use client";
|
||
|
||
/**
|
||
* 教师详情对话框(ARCHITECTURE.md §7.3 详情页 / §9.4 / §10 P5)
|
||
*
|
||
* 数据契约:
|
||
* - 详情数据复用列表中的 AdminTeacher 对象(@contract-pending:单查契约待补齐)
|
||
*
|
||
* 关联:ARCHITECTURE.md §5.5 / §7.3 / §9.4 / §10 P5 / §11.3
|
||
*/
|
||
import { School } from "lucide-react";
|
||
import { useTranslations } from "next-intl";
|
||
|
||
import type { AdminTeacher } from "@/lib/api/admin-p5";
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogDescription,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
} from "@/shared/components/ui/dialog";
|
||
import { DetailField, DetailSection } from "@/shared/components/page-templates";
|
||
import {
|
||
formatTeacherCount,
|
||
formatTeacherStatus,
|
||
teacherStatusToBadgeClass,
|
||
} from "@/features/admin/teachers/transformations";
|
||
|
||
/**
|
||
* 教师详情对话框。受控组件,由父组件管理 open 状态与选中数据。
|
||
*/
|
||
export function TeacherDetailDialog({
|
||
open,
|
||
onOpenChange,
|
||
teacher,
|
||
}: {
|
||
open: boolean;
|
||
onOpenChange: (open: boolean) => void;
|
||
teacher: AdminTeacher | null;
|
||
}): React.ReactElement {
|
||
const t = useTranslations("admin.teachers.detail");
|
||
|
||
return (
|
||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||
<DialogContent className="sm:max-w-lg">
|
||
<DialogHeader>
|
||
<DialogTitle className="flex items-center gap-2">
|
||
<School className="size-5" />
|
||
{t("title")}
|
||
</DialogTitle>
|
||
<DialogDescription>{t("description")}</DialogDescription>
|
||
</DialogHeader>
|
||
|
||
{teacher ? <TeacherDetailBody teacher={teacher} /> : null}
|
||
</DialogContent>
|
||
</Dialog>
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 详情内容区(基本信息 + 教学信息)。
|
||
*/
|
||
function TeacherDetailBody({
|
||
teacher,
|
||
}: {
|
||
teacher: AdminTeacher;
|
||
}): React.ReactElement {
|
||
const t = useTranslations("admin.teachers.detail");
|
||
|
||
return (
|
||
<div className="space-y-4">
|
||
<DetailSection title={t("sectionBasic")}>
|
||
<DetailField label={t("fieldName")} value={teacher.name} />
|
||
<DetailField label={t("fieldStaffNo")} value={teacher.staffNo} />
|
||
<DetailField label={t("fieldEmail")} value={teacher.email} />
|
||
<DetailField
|
||
label={t("fieldStatus")}
|
||
value={<StatusBadge status={teacher.status} />}
|
||
/>
|
||
</DetailSection>
|
||
|
||
<DetailSection title={t("sectionTeaching")}>
|
||
<DetailField label={t("fieldDepartment")} value={teacher.department} />
|
||
<DetailField label={t("fieldTitle")} value={teacher.title} />
|
||
<DetailField
|
||
label={t("fieldClassCount")}
|
||
value={formatTeacherCount(teacher.classCount)}
|
||
/>
|
||
<DetailField
|
||
label={t("fieldSubjectCount")}
|
||
value={String(teacher.subjectCount)}
|
||
/>
|
||
<DetailField label={t("fieldId")} value={teacher.id} />
|
||
</DetailSection>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 状态徽章(按状态色阶展示)。
|
||
*/
|
||
function StatusBadge({ status }: { status: string }): React.ReactElement {
|
||
const label = formatTeacherStatus(status);
|
||
const cls = teacherStatusToBadgeClass(status);
|
||
return (
|
||
<span
|
||
className={`inline-flex h-6 items-center rounded-full px-2 text-xs font-medium ${cls}`}
|
||
>
|
||
{label}
|
||
</span>
|
||
);
|
||
}
|