116 lines
3.4 KiB
TypeScript
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>
|
|
);
|
|
}
|