'use client'; import { useEffect, useMemo, useState } from 'react'; import { Plus, X, Shield } from 'lucide-react'; import { useMemberStore } from '@/stores/useMemberStore'; import { PERMISSION_GROUPS, ALL_PERMISSIONS } from '@/lib/permissions'; import { RouteGuard, useHasPermission } from '@/components/auth/Guard'; import type { RoleItem } from '@/lib/members'; export default function RolesPage() { return ( ); } function RolesPageContent() { const { roles, fetchMembers, createRole, updateRole, deleteRole } = useMemberStore(); const [showModal, setShowModal] = useState(false); const [editing, setEditing] = useState(null); const canCreate = useHasPermission('role:create'); const canEdit = useHasPermission('role:edit'); const canDelete = useHasPermission('role:delete'); useEffect(() => { fetchMembers(); }, [fetchMembers]); return ( 角色管理 {roles.length} { setEditing(null); setShowModal(true); }} disabled={!canCreate} className="flex h-8 items-center gap-1.5 rounded-lg bg-[var(--accent)] px-3 text-[13px] font-medium text-white shadow-[var(--shadow-sm)] hover:bg-[var(--accent-hover)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"> 新建角色 {roles.map((role) => ( {role.name} {role.isSystem && ( 系统 )} {role.permissions.includes('*') ? '全部权限' : `${role.permissions.length} 项权限`} {role.description && ( {role.description} )} { setEditing(role); setShowModal(true); }} className="h-7 px-2.5 rounded-md text-[11px] font-medium text-[var(--ink-soft)] hover:bg-[var(--bg-subtle)] transition-colors">{role.isSystem || !canEdit ? '查看' : '编辑'} {!role.isSystem && canDelete && ( deleteRole(role.id)} className="h-7 px-2.5 rounded-md text-[11px] font-medium text-red-500 hover:bg-red-50 transition-colors">删除 )} ))} {showModal && ( setShowModal(false)} onSubmit={(data) => { if (editing) updateRole(editing.id, data); else createRole(data); setShowModal(false); }} /> )} ); } function RoleModal({ initial, onClose, onSubmit }: { initial: RoleItem | null; onClose: () => void; onSubmit: (data: { name: string; description?: string; permissions: string[] }) => void; }) { const [name, setName] = useState(initial?.name ?? ''); const [description, setDescription] = useState(initial?.description ?? ''); const [permissions, setPermissions] = useState>(new Set(initial?.permissions ?? [])); const isReadOnly = !!initial?.isSystem; const isAdminWildcard = permissions.has('*'); const togglePerm = (p: string) => { if (isReadOnly) return; const next = new Set(permissions); if (next.has(p)) next.delete(p); else next.add(p); setPermissions(next); }; const handleSelectAll = () => setPermissions(new Set(ALL_PERMISSIONS)); const handleSelectNone = () => setPermissions(new Set()); const handleViewOnly = () => { const viewOnly = ALL_PERMISSIONS.filter((p) => p.endsWith(':view')); setPermissions(new Set(viewOnly)); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!name.trim() || isReadOnly) return; onSubmit({ name: name.trim(), description: description.trim() || undefined, permissions: Array.from(permissions) }); }; const mainGroups = useMemo(() => PERMISSION_GROUPS.filter((g) => g.category === 'main'), []); const tabGroups = useMemo(() => PERMISSION_GROUPS.filter((g) => g.category === 'version_tab'), []); return ( e.stopPropagation()}> {initial ? (isReadOnly ? '查看角色' : '编辑角色') : '新建角色'} {isReadOnly && ( 系统角色不可修改,权限为系统预设 )} 角色名称 * setName(e.target.value)} required disabled={isReadOnly} placeholder="如:项目经理" className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[13px] focus:border-[var(--accent)] focus:outline-none disabled:bg-zinc-50 disabled:text-[var(--ink-soft)]" /> 描述 setDescription(e.target.value)} disabled={isReadOnly} placeholder="可选" className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[13px] focus:border-[var(--accent)] focus:outline-none disabled:bg-zinc-50 disabled:text-[var(--ink-soft)]" /> 权限 {!isReadOnly && ( 全选 仅查看 反选 )} {isAdminWildcard ? ( 此角色拥有所有权限(通配符 *) ) : ( )} {isReadOnly ? '关闭' : '取消'} {!isReadOnly && ( {initial ? '保存' : '创建'} )} ); } function PermissionSection({ title, groups, permissions, togglePerm, disabled }: { title: string; groups: typeof PERMISSION_GROUPS; permissions: Set; togglePerm: (p: string) => void; disabled: boolean; }) { return ( {title} {groups.map((g) => ( {g.moduleLabel} {g.actions.map((a) => ( togglePerm(a.permission)} disabled={disabled} className="h-3.5 w-3.5 rounded border-[var(--line)]" /> {a.label} ))} ))} ); }
{role.description}