mirror of
https://github.com/woodchen-ink/Q58Connect.git
synced 2025-07-18 14:01:55 +08:00
添加"授权管理页面"
This commit is contained in:
parent
b01890e2cf
commit
3782ec8ca0
163
src/app/(admin)/admin/authorizations/page.tsx
Normal file
163
src/app/(admin)/admin/authorizations/page.tsx
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
import { redirect } from "next/navigation";
|
||||||
|
import { Search } from "lucide-react";
|
||||||
|
|
||||||
|
import { prisma } from "@/lib/prisma";
|
||||||
|
import { getCurrentUser } from "@/lib/session";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardDescription,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from "@/components/ui/card";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table";
|
||||||
|
import { AuthorizationStatusToggle } from "@/components/admin/authorization-status-toggle";
|
||||||
|
|
||||||
|
async function getAuthorizations(search?: string) {
|
||||||
|
const where = search
|
||||||
|
? {
|
||||||
|
OR: [
|
||||||
|
{
|
||||||
|
user: {
|
||||||
|
OR: [
|
||||||
|
{ username: { contains: search } },
|
||||||
|
{ email: { contains: search } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
client: {
|
||||||
|
OR: [
|
||||||
|
{ name: { contains: search } },
|
||||||
|
{ clientId: { contains: search } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
|
return prisma.authorization.findMany({
|
||||||
|
where,
|
||||||
|
include: {
|
||||||
|
user: {
|
||||||
|
select: {
|
||||||
|
username: true,
|
||||||
|
email: true,
|
||||||
|
name: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
client: {
|
||||||
|
select: {
|
||||||
|
name: true,
|
||||||
|
clientId: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
createdAt: "desc",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function AuthorizationsPage({
|
||||||
|
searchParams,
|
||||||
|
}: {
|
||||||
|
searchParams: { search?: string };
|
||||||
|
}) {
|
||||||
|
const user = await getCurrentUser();
|
||||||
|
if (!user || user.role !== "ADMIN") {
|
||||||
|
redirect("/dashboard");
|
||||||
|
}
|
||||||
|
|
||||||
|
const authorizations = await getAuthorizations(searchParams.search);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<CardTitle>授权管理</CardTitle>
|
||||||
|
<CardDescription>管理所有用户的授权记录</CardDescription>
|
||||||
|
</div>
|
||||||
|
<div className="relative w-64">
|
||||||
|
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||||
|
<form>
|
||||||
|
<Input
|
||||||
|
placeholder="搜索授权记录..."
|
||||||
|
name="search"
|
||||||
|
defaultValue={searchParams.search}
|
||||||
|
className="pl-8"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead>用户</TableHead>
|
||||||
|
<TableHead>应用</TableHead>
|
||||||
|
<TableHead>授权时间</TableHead>
|
||||||
|
<TableHead>最后使用</TableHead>
|
||||||
|
<TableHead>状态</TableHead>
|
||||||
|
<TableHead className="text-right">操作</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{authorizations.map((auth) => (
|
||||||
|
<TableRow key={auth.id}>
|
||||||
|
<TableCell>
|
||||||
|
<div>
|
||||||
|
<p className="font-medium">
|
||||||
|
{auth.user.name || auth.user.username}
|
||||||
|
</p>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
{auth.user.email}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<div>
|
||||||
|
<p className="font-medium">{auth.client.name}</p>
|
||||||
|
<p className="font-mono text-sm text-muted-foreground">
|
||||||
|
{auth.client.clientId}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{new Date(auth.createdAt).toLocaleString()}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{auth.lastUsedAt
|
||||||
|
? new Date(auth.lastUsedAt).toLocaleString()
|
||||||
|
: "从未使用"}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Badge variant={auth.enabled ? "default" : "destructive"}>
|
||||||
|
{auth.enabled ? "已授权" : "已禁用"}
|
||||||
|
</Badge>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right">
|
||||||
|
<AuthorizationStatusToggle authorization={auth} />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user