"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 { IconShield, IconPlus, IconDotsVertical, IconPencil, IconTrash, IconUsers, IconKey, IconChevronDown, 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 roleSchema = z.object({ id: z.string(), name: z.string(), code: z.string(), description: z.string().optional(), level: z.number(), isActive: z.boolean(), userCount: z.number(), permissionCount: z.number(), createdAt: z.string(), updatedAt: z.string(), }) type Role = z.infer const GET_ROLES = gql` query GetRoles($pagination: PaginationInput) { roles(pagination: $pagination) { items { id name code description level isActive userCount permissionCount createdAt updatedAt } total page perPage totalPages } } ` const CREATE_ROLE = gql` mutation CreateRole($input: CreateRoleInput!) { createRole(input: $input) { id name code isActive } } ` const UPDATE_ROLE = gql` mutation UpdateRole($id: UUID!, $input: UpdateRoleInput!) { updateRole(id: $id, input: $input) { id name code isActive updatedAt } } ` const DELETE_ROLE = gql` mutation DeleteRole($id: UUID!) { deleteRole(id: $id) } ` 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 role = row.original return (
{role.name}
{role.code}
) }, }, { accessorKey: "description", header: "描述", cell: ({ row }) => { const description = row.getValue("description") as string return (
{description || "无描述"}
) }, }, { 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: "userCount", header: ({ column }) => (
用户数
), cell: ({ row }) => { const count = row.getValue("userCount") as number return (
{count}
) }, }, { accessorKey: "permissionCount", header: ({ column }) => (
权限数
), cell: ({ row }) => { const count = row.getValue("permissionCount") as number return (
{count}
) }, }, { accessorKey: "isActive", header: "状态", cell: ({ row }) => { const isActive = row.getValue("isActive") as boolean return ( {isActive ? "启用" : "禁用"} ) }, }, { id: "actions", cell: ({ row, table }) => { const role = row.original const updateRole = (table.options.meta as any)?.updateRole const deleteRole = (table.options.meta as any)?.deleteRole return ( 编辑角色 权限配置 用户分配 { updateRole({ variables: { id: role.id, input: { isActive: !role.isActive } } }) }} > {role.isActive ? "禁用" : "启用"} { if (confirm('确定要删除这个角色吗?此操作不可撤销。')) { deleteRole({ variables: { id: role.id } }) } }} > 删除角色 ) }, }, ] function CreateRoleDialog({ onSuccess }: { onSuccess: () => void }) { const [open, setOpen] = React.useState(false) const [loading, setLoading] = React.useState(false) const [createRole] = useMutation(CREATE_ROLE) const [formData, setFormData] = React.useState({ name: "", code: "", description: "", level: 10, roleType: "CUSTOM", // 默认为自定义角色 isActive: true, }) const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!formData.name || !formData.code) { toast.error("请填写角色名称和代码") return } setLoading(true) try { await createRole({ variables: { input: formData } }) toast.success("角色创建成功") setOpen(false) setFormData({ name: "", code: "", description: "", level: 10, roleType: "CUSTOM", 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="ADMIN" required />