Files
Edu/apps/admin-portal/src/app/admin/permissions/page.tsx
SpecialX b3511910d1 feat(admin-portal): 完整实现 admin-portal 管理端微前端
包含 src 全部实现、Dockerfile、配置文件等
2026-07-10 19:09:12 +08:00

116 lines
3.4 KiB
TypeScript

"use client";
import { type ReactNode, useState } from "react";
import { usePermissions } from "@/hooks/use-permissions";
import {
PageHeader,
PaperCard,
Input,
Select,
LoadingState,
ErrorState,
EmptyState,
Table,
TableRow,
TableCell,
Badge,
} from "@/components/ui";
import { t } from "@/lib/i18n";
export default function PermissionsPage(): ReactNode {
const { data: permissions, loading, error } = usePermissions();
const [search, setSearch] = useState("");
const [resourceFilter, setResourceFilter] = useState("all");
const resources = Array.from(new Set(permissions.map((p) => p.resource)));
const filtered = permissions.filter((p) => {
if (resourceFilter !== "all" && p.resource !== resourceFilter) return false;
if (search) {
const q = search.toLowerCase();
return (
p.code.toLowerCase().includes(q) ||
p.name.toLowerCase().includes(q) ||
p.description.toLowerCase().includes(q)
);
}
return true;
});
return (
<div style={{ padding: 32, maxWidth: 1200, margin: "0 auto" }}>
<PageHeader
title={t("admin.permissions.title")}
description="查看所有权限点定义"
/>
<PaperCard className="p-4 mb-4">
<div className="flex gap-3 items-center">
<Input
type="search"
placeholder={t("admin.common.search")}
value={search}
onChange={(e) => setSearch(e.target.value)}
style={{ width: 240 }}
/>
<Select
value={resourceFilter}
onChange={(e) => setResourceFilter(e.target.value)}
>
<option value="all">{t("admin.common.all")}</option>
{resources.map((r) => (
<option key={r} value={r}>
{r}
</option>
))}
</Select>
</div>
</PaperCard>
<PaperCard className="p-4">
{loading && <LoadingState />}
{error && <ErrorState message={error.message} />}
{!loading && !error && (
<>
{filtered.length === 0 ? (
<EmptyState message={t("admin.common.empty")} />
) : (
<Table
headers={[
t("admin.permissions.code"),
t("admin.permissions.resource"),
t("admin.permissions.action"),
"名称",
"说明",
"系统",
]}
>
{filtered.map((perm) => (
<TableRow key={perm.id}>
<TableCell
style={{ fontFamily: "var(--font-mono)", fontSize: 12 }}
>
{perm.code}
</TableCell>
<TableCell>{perm.resource}</TableCell>
<TableCell>{perm.action}</TableCell>
<TableCell>{perm.name}</TableCell>
<TableCell
style={{ color: "var(--color-ink-muted)", fontSize: 12 }}
>
{perm.description}
</TableCell>
<TableCell>
{perm.isSystem ? <Badge status="active" /> : "—"}
</TableCell>
</TableRow>
))}
</Table>
)}
</>
)}
</PaperCard>
</div>
);
}