import { useEffect, type FormEvent } from "react"; import { type Employee } from "../../services/api"; import { useAuth } from "../../context/AuthContext"; import Icon from "../../components/common/Icon"; import { useAdminStore } from "../../features/admin/state/adminStore"; import "../../styles/admin.css"; type Notice = { tone: "success" | "error" | "info"; message: string; }; export function UserManagementPage({ onNotify, onConnectionChange, }: { onNotify: (notice: Notice) => void; onConnectionChange: (online: boolean) => void; }) { const { user, currentWorkspace } = useAuth(); const employees = useAdminStore((s) => s.employees); const loading = useAdminStore((s) => s.usersLoading); const saving = useAdminStore((s) => s.usersSaving); const editing = useAdminStore((s) => s.editingUser); const dialogOpen = useAdminStore((s) => s.userDialogOpen); const form = useAdminStore((s) => s.userForm); const userSearchTerm = useAdminStore((s) => s.userSearchTerm); const setEditingUser = useAdminStore((s) => s.setEditingUser); const setUserDialogOpen = useAdminStore((s) => s.setUserDialogOpen); const setUserForm = useAdminStore((s) => s.setUserForm); const setUserSearchTerm = useAdminStore((s) => s.setUserSearchTerm); const loadEmployees = useAdminStore((s) => s.loadEmployees); const createEmployee = useAdminStore((s) => s.createEmployee); const updateEmployee = useAdminStore((s) => s.updateEmployee); const deleteEmployee = useAdminStore((s) => s.deleteEmployee); const reset = useAdminStore((s) => s.reset); const canManage = user?.role_code === "admin"; const wsId = currentWorkspace?.workspace_id; useEffect(() => { reset(); void loadEmployees(); }, [loadEmployees, reset, wsId]); const openCreate = (): void => { setEditingUser(null); setUserForm({ username: "", display_name: "", email: "", role_code: "developer", password: "", status: "active", }); setUserDialogOpen(true); }; const openEdit = (employee: Employee): void => { setEditingUser(employee); setUserForm({ username: employee.username, display_name: employee.display_name, email: employee.email ?? "", role_code: employee.role_code, password: "", status: employee.status, }); setUserDialogOpen(true); }; const submit = async (event: FormEvent): Promise => { event.preventDefault(); if (!form.display_name.trim() || (!editing && !form.username.trim())) return; if (!editing && !form.password.trim()) { onNotify({ tone: "error", message: "请输入密码" }); return; } if (editing) { const editingSelf = editing.user_id === user?.user_id; const targetIsAdmin = editing.role_code === "admin"; if (editingSelf && form.status !== editing.status) { onNotify({ tone: "error", message: "不能停用当前登录账号" }); return; } if (targetIsAdmin && form.status !== editing.status) { onNotify({ tone: "error", message: "不能停用或锁定管理员账号" }); return; } if (targetIsAdmin && form.role_code !== editing.role_code) { onNotify({ tone: "error", message: "不能降级管理员账号" }); return; } if (editingSelf && form.role_code !== editing.role_code) { onNotify({ tone: "error", message: "不能降级自身管理员角色" }); return; } } if (form.password && (form.password.length < 8 || form.password.length > 72)) { onNotify({ tone: "error", message: "密码长度必须在 8~72 字符之间" }); return; } if (editing) { await updateEmployee( editing, { display_name: form.display_name.trim(), email: form.email.trim() || null, role_code: form.role_code, status: form.status, }, onNotify, onConnectionChange, ); } else { await createEmployee( { username: form.username.trim(), display_name: form.display_name.trim(), email: form.email.trim() || null, role_code: form.role_code, password: form.password, }, onNotify, onConnectionChange, ); } }; const remove = async (employee: Employee): Promise => { if (!window.confirm(`确定从当前 Workspace 删除用户"${employee.display_name}"吗?`)) return; await deleteEmployee(employee, onNotify, onConnectionChange); }; return (
setUserSearchTerm(event.target.value)} />
{!canManage &&
当前为开发人员,只能查看用户列表。
}
用户账号角色状态操作
{loading ? (

正在加载用户…

) : ( employees .filter((employee) => { const term = userSearchTerm.toLowerCase().trim(); if (!term) return true; return ( employee.display_name.toLowerCase().includes(term) || employee.username.toLowerCase().includes(term) || (employee.email && employee.email.toLowerCase().includes(term)) ); }) .map((employee) => { const isProtectedAdmin = employee.role_code === "admin"; return (
{employee.display_name.slice(0, 1)}{employee.display_name}{employee.email ?? "未设置邮箱"} {employee.username} {employee.role_name} {employee.status === "active" ? "正常" : employee.status === "disabled" ? "已停用" : "已锁定"}
); }) )}
{dialogOpen && (
EMPLOYEE

{editing ? "编辑用户" : "添加用户"}

void submit(event)}> {!editing && ( )} {editing && ( )}
)}
); }