"use client" import * as React from "react" import { useQuery, useMutation, gql } from '@apollo/client'; import { ColumnDef, ColumnFiltersState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, SortingState, useReactTable, VisibilityState, } from "@tanstack/react-table" import { z } from "zod" import { IconKey, IconPlus, IconDotsVertical, IconPencil, IconTrash, IconShield, IconChevronLeft, IconChevronRight, IconChevronsLeft, IconChevronsRight, } from "@tabler/icons-react" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Textarea } from "@/components/ui/textarea" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { toast } from "sonner" const permissionSchema = z.object({ id: z.string(), name: z.string(), code: z.string(), description: z.string().optional(), module: z.string(), action: z.string(), resource: z.string(), level: z.number(), isActive: z.boolean(), roleCount: z.number(), createdAt: z.string(), updatedAt: z.string(), }) type Permission = z.infer const GET_PERMISSIONS = gql` query GetPermissions($pagination: PaginationInput) { permissions(pagination: $pagination) { items { id name code description module action resource level isActive roleCount createdAt updatedAt } total page perPage totalPages } } ` const CREATE_PERMISSION = gql` mutation CreatePermission($input: CreatePermissionInput!) { createPermission(input: $input) { id name code module action resource isActive } } ` const UPDATE_PERMISSION = gql` mutation UpdatePermission($id: UUID!, $input: UpdatePermissionInput!) { updatePermission(id: $id, input: $input) { id name code isActive updatedAt } } ` const DELETE_PERMISSION = gql` mutation DeletePermission($id: UUID!) { deletePermission(id: $id) } ` const getActionColor = (action: string) => { switch (action.toLowerCase()) { case 'create': return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300' case 'read': return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300' case 'update': return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300' case 'delete': return 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300' default: return 'bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300' } } const columns: ColumnDef[] = [ { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Select row" /> ), enableSorting: false, enableHiding: false, }, { accessorKey: "name", header: "权限名称", cell: ({ row }) => { const permission = row.original return (
{permission.name}
{permission.code}
) }, }, { accessorKey: "description", header: "描述", cell: ({ row }) => { const description = row.getValue("description") as string return (
{description || "无描述"}
) }, }, { accessorKey: "module", header: "模块", cell: ({ row }) => { const module = row.getValue("module") as string return ( {module} ) }, }, { accessorKey: "action", header: "操作", cell: ({ row }) => { const action = row.getValue("action") as string return ( {action} ) }, }, { accessorKey: "resource", header: "资源", cell: ({ row }) => { const resource = row.getValue("resource") as string return ( {resource} ) }, }, { accessorKey: "level", header: "级别", cell: ({ row }) => { const level = row.getValue("level") as number const getLevelColor = (level: number) => { if (level >= 90) return "text-red-600" if (level >= 70) return "text-orange-600" if (level >= 50) return "text-yellow-600" return "text-green-600" } return ( {level} ) }, }, { accessorKey: "roleCount", header: "角色数", cell: ({ row }) => { const count = row.getValue("roleCount") as number return (
{count}
) }, }, { accessorKey: "isActive", header: "状态", cell: ({ row }) => { const isActive = row.getValue("isActive") as boolean return ( {isActive ? "启用" : "禁用"} ) }, }, { id: "actions", cell: ({ row, table }) => { const permission = row.original const updatePermission = (table.options.meta as any)?.updatePermission const deletePermission = (table.options.meta as any)?.deletePermission return ( 编辑权限 角色分配 { updatePermission({ variables: { id: permission.id, input: { isActive: !permission.isActive } } }) }} > {permission.isActive ? "禁用" : "启用"} { if (confirm('确定要删除这个权限吗?此操作不可撤销。')) { deletePermission({ variables: { id: permission.id } }) } }} > 删除权限 ) }, }, ] function CreatePermissionDialog({ onSuccess }: { onSuccess: () => void }) { const [open, setOpen] = React.useState(false) const [loading, setLoading] = React.useState(false) const [createPermission] = useMutation(CREATE_PERMISSION) const [formData, setFormData] = React.useState({ name: "", code: "", description: "", module: "", action: "", resource: "", level: 50, isActive: true, }) const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!formData.name || !formData.code || !formData.module || !formData.action || !formData.resource) { toast.error("请填写所有必需字段") return } setLoading(true) try { await createPermission({ variables: { input: formData } }) toast.success("权限创建成功") setOpen(false) setFormData({ name: "", code: "", description: "", module: "", action: "", resource: "", level: 50, isActive: true, }) onSuccess() } catch (error) { toast.error("创建失败") } finally { setLoading(false) } } return ( 创建新权限 创建一个新的系统权限,可以分配给角色使用。
setFormData(prev => ({ ...prev, name: e.target.value }))} placeholder="查看用户" required />
setFormData(prev => ({ ...prev, code: e.target.value.toUpperCase() }))} placeholder="USER_READ" required />