Files
Edu/apps/portal-shell/src/features/admin/teachers/teacher-detail-dialog.tsx
SpecialX 04b7a40bdc feat(portal-shell): 学生域全页面迁移与规范合规修复
- 学生域 32 页全量迁移(含作答/自动保存/提交/诊断)

- 补齐 4 个 MSW mock 缺口,修 diagnostic case 名

- 修 4 处 Tailwind 任意值;新增共享组件与路由
2026-08-31 11:25:21 +08:00

113 lines
3.1 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 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>
);
}