差距分析闭环(workline §7-§8): - P0:审计子模块 3 页 + 学校组织 7 页 - P1:系统设置 4 Card + 公告管理 + 邀请码管理 - P2:文件管理 + AI 配置 - P6:5 测试文件 / 69 用例全过 共享基础设施: - permissions +11 权限点 +14 路由 - view-models +20 接口 - i18n +100 key - graphql-client +25 operation - fixtures/handlers +15 mock +20 handler 质量:typecheck + lint 零错误,vitest 69/69 通过,arch.db 已更新
107 lines
3.0 KiB
TypeScript
107 lines
3.0 KiB
TypeScript
"use client";
|
|
|
|
import { type ReactNode } from "react";
|
|
import { useAcademicYears } from "@/hooks/use-school";
|
|
import {
|
|
PaperCard,
|
|
LoadingState,
|
|
ErrorState,
|
|
EmptyState,
|
|
Table,
|
|
TableRow,
|
|
TableCell,
|
|
} from "@/components/ui";
|
|
import { t } from "@/lib/i18n";
|
|
import type { AcademicYearViewModel } from "@/types/view-models";
|
|
|
|
function CurrentBadge(): ReactNode {
|
|
const color = "var(--color-success)";
|
|
return (
|
|
<span
|
|
style={{
|
|
display: "inline-block",
|
|
padding: "2px 8px",
|
|
fontSize: 11,
|
|
borderRadius: 10,
|
|
background: `${color}20`,
|
|
color,
|
|
border: `1px solid ${color}40`,
|
|
fontWeight: 500,
|
|
}}
|
|
>
|
|
{t("admin.school.currentYear")}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
export default function AcademicYearPage(): ReactNode {
|
|
const { data, loading, error } = useAcademicYears();
|
|
|
|
return (
|
|
<PaperCard className="p-4">
|
|
{loading && <LoadingState />}
|
|
{error && <ErrorState message={error.message} />}
|
|
{!loading && !error && (
|
|
<>
|
|
{data.length === 0 ? (
|
|
<EmptyState message={t("admin.common.empty")} />
|
|
) : (
|
|
<Table
|
|
headers={[
|
|
"学年",
|
|
t("admin.school.startDate"),
|
|
t("admin.school.endDate"),
|
|
"第一学期",
|
|
"第二学期",
|
|
t("admin.common.status"),
|
|
]}
|
|
>
|
|
{data.map((year: AcademicYearViewModel) => (
|
|
<TableRow key={year.id}>
|
|
<TableCell
|
|
style={{
|
|
fontWeight: year.isCurrent ? 600 : 500,
|
|
color: year.isCurrent
|
|
? "var(--color-accent)"
|
|
: "var(--color-ink)",
|
|
}}
|
|
>
|
|
{year.name}
|
|
</TableCell>
|
|
<TableCell style={{ whiteSpace: "nowrap" }}>
|
|
{year.startDate}
|
|
</TableCell>
|
|
<TableCell style={{ whiteSpace: "nowrap" }}>
|
|
{year.endDate}
|
|
</TableCell>
|
|
<TableCell
|
|
style={{
|
|
whiteSpace: "nowrap",
|
|
fontFamily: "var(--font-mono)",
|
|
fontSize: 12,
|
|
}}
|
|
>
|
|
{year.firstSemesterStart} ~ {year.firstSemesterEnd}
|
|
</TableCell>
|
|
<TableCell
|
|
style={{
|
|
whiteSpace: "nowrap",
|
|
fontFamily: "var(--font-mono)",
|
|
fontSize: 12,
|
|
}}
|
|
>
|
|
{year.secondSemesterStart} ~ {year.secondSemesterEnd}
|
|
</TableCell>
|
|
<TableCell>
|
|
{year.isCurrent ? <CurrentBadge /> : "—"}
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</Table>
|
|
)}
|
|
</>
|
|
)}
|
|
</PaperCard>
|
|
);
|
|
}
|