feat(admin-portal): 完成参考项目差距闭环 - 4 批次补齐 + Vitest 测试
差距分析闭环(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 已更新
This commit is contained in:
77
apps/admin-portal/src/app/admin/school/departments/page.tsx
Normal file
77
apps/admin-portal/src/app/admin/school/departments/page.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
"use client";
|
||||
|
||||
import { type ReactNode, useState } from "react";
|
||||
import { useDepartments, useSchools } from "@/hooks/use-school";
|
||||
import {
|
||||
PaperCard,
|
||||
Select,
|
||||
LoadingState,
|
||||
ErrorState,
|
||||
EmptyState,
|
||||
Table,
|
||||
TableRow,
|
||||
TableCell,
|
||||
} from "@/components/ui";
|
||||
import { t } from "@/lib/i18n";
|
||||
|
||||
export default function DepartmentsPage(): ReactNode {
|
||||
const [schoolId, setSchoolId] = useState<string>("");
|
||||
const { data: schools, loading: schoolsLoading } = useSchools();
|
||||
const { data, loading, error } = useDepartments(schoolId || undefined);
|
||||
|
||||
return (
|
||||
<>
|
||||
<PaperCard className="p-4 mb-4">
|
||||
<Select
|
||||
value={schoolId}
|
||||
onChange={(e) => setSchoolId(e.target.value)}
|
||||
disabled={schoolsLoading}
|
||||
>
|
||||
<option value="">
|
||||
{t("admin.common.all")}
|
||||
{t("admin.common.school")}
|
||||
</option>
|
||||
{schools.map((s) => (
|
||||
<option key={s.id} value={s.id}>
|
||||
{s.name}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</PaperCard>
|
||||
|
||||
<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.common.school"),
|
||||
t("admin.school.leader"),
|
||||
t("admin.school.memberCount"),
|
||||
t("admin.school.subject"),
|
||||
]}
|
||||
>
|
||||
{data.map((dept) => (
|
||||
<TableRow key={dept.id}>
|
||||
<TableCell style={{ fontWeight: 500 }}>
|
||||
{dept.name}
|
||||
</TableCell>
|
||||
<TableCell>{dept.schoolName}</TableCell>
|
||||
<TableCell>{dept.leaderName ?? "—"}</TableCell>
|
||||
<TableCell>{dept.memberCount}</TableCell>
|
||||
<TableCell>{dept.subject ?? "—"}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</Table>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</PaperCard>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user