import { DownOutlined, PlusOutlined, ReloadOutlined, SearchOutlined } from '@ant-design/icons' import { Alert, App, Button, Card, Dropdown, Empty, Form, Input, Result, Select, Space, Table, Tag, Typography, } from 'antd' import type { MenuProps, TableColumnsType } from 'antd' import { useQuery, useQueryClient } from '@tanstack/react-query' import { useMemo, useState } from 'react' import { useSearchParams } from 'react-router' import PageHeader from '@/components/admin/PageHeader' import StatusTag from '@/components/admin/StatusTag' import { createAdminUser, fetchAdminUsers, resetAdminUserPassword, updateAdminUserRole, updateAdminUserStatus, } from '@/services/admin' import type { AdminRole, AdminUserListItem } from '@/types/admin' import { getAdminUserId, hasAdminRole } from '@/utils/admin-auth' import { adminUserRoleOptions, adminUserStatusOptions } from '@/utils/admin-options' import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination, resolveAdminPageSize, } from '@/utils/admin-pagination' import { formatAdminDateTime } from '@/utils/admin-time' type UserFilterForm = { username?: string role?: string status?: string } type CreateUserForm = { username: string password: string role: AdminRole } const USER_ROLE_OPTIONS = [ { label: '普通运营', value: 'operator' }, { label: '客服', value: 'support' }, { label: '管理员', value: 'admin' }, ] export default function AdminUsersPage() { const isAdmin = hasAdminRole('admin') const currentUserId = getAdminUserId() const queryClient = useQueryClient() const { message, modal } = App.useApp() const [searchParams, setSearchParams] = useSearchParams() const [createForm] = Form.useForm() const [creating, setCreating] = useState(false) const [actionLoadingId, setActionLoadingId] = useState(null) const page = Number(searchParams.get('page') || 1) || 1 const pageSize = resolveAdminPageSize(searchParams.get('pageSize'), ADMIN_DEFAULT_PAGE_SIZE) const filters = { username: searchParams.get('username') || '', role: searchParams.get('role') || '', status: searchParams.get('status') || '', } const queryParams = useMemo( () => ({ page, pageSize, ...filters }), [filters.role, filters.status, filters.username, page, pageSize], ) const query = useQuery({ queryKey: ['admin-users', queryParams], enabled: isAdmin, queryFn: () => fetchAdminUsers(queryParams), }) const data = query.data?.data async function reloadUsers() { await queryClient.invalidateQueries({ queryKey: ['admin-users'] }) } async function submitCreate(values: CreateUserForm) { setCreating(true) try { await createAdminUser({ username: values.username.trim(), password: values.password.trim(), role: values.role, status: 'active', }) message.success('后台用户已创建') createForm.resetFields() setSearchParams(cleanParams({ ...filters, page: 1, pageSize })) await reloadUsers() } catch (error) { message.error(error instanceof Error ? error.message : '创建后台用户失败') } finally { setCreating(false) } } function confirmUpdateRole(item: AdminUserListItem, nextRole: AdminRole) { if (item.role === nextRole) return modal.confirm({ title: '确认操作', content: `确认将 ${item.username} 调整为${formatRoleLabel(nextRole)}吗?`, okText: '继续执行', cancelText: '取消', centered: true, onOk: async () => { setActionLoadingId(item.userId) try { await updateAdminUserRole(item.userId, { role: nextRole }) message.success('用户角色已更新') await reloadUsers() } catch (error) { message.error(error instanceof Error ? error.message : '更新用户角色失败') } finally { setActionLoadingId(null) } }, }) } function confirmToggleStatus(item: AdminUserListItem) { const nextStatus = item.status === 'active' ? 'disabled' : 'active' modal.confirm({ title: '确认操作', content: `确认将 ${item.username}${nextStatus === 'active' ? '启用' : '停用'}吗?`, okText: '继续执行', cancelText: '取消', centered: true, onOk: async () => { setActionLoadingId(item.userId) try { await updateAdminUserStatus(item.userId, { status: nextStatus }) message.success('用户状态已更新') await reloadUsers() } catch (error) { message.error(error instanceof Error ? error.message : '更新用户状态失败') } finally { setActionLoadingId(null) } }, }) } function openResetPasswordModal(item: AdminUserListItem) { const form = ModalFormStore.create<{ password: string }>() modal.confirm({ title: '重置密码', content: (
), okText: '提交', cancelText: '取消', centered: true, onOk: async () => { const values = await form.validate() setActionLoadingId(item.userId) try { await resetAdminUserPassword(item.userId, { password: values.password.trim() }) message.success('用户密码已重置') await reloadUsers() } catch (error) { message.error(error instanceof Error ? error.message : '重置密码失败') } finally { setActionLoadingId(null) } }, }) } function applyFilters(values: UserFilterForm) { setSearchParams(cleanParams({ ...values, page: 1, pageSize })) } function resetFilters() { setSearchParams(cleanParams({ page: 1, pageSize })) } if (!isAdmin) { return (
) } const columns: TableColumnsType = [ { title: 'ID', dataIndex: 'userId', width: 72, align: 'center', }, { title: '账号', dataIndex: 'username', minWidth: 150, render: (value, row) => ( {value} {row.userId === currentUserId ? 当前账号 : null} ), }, { title: '角色', dataIndex: 'role', width: 120, render: (value: AdminRole) => formatRoleLabel(value), }, { title: '状态', dataIndex: 'status', width: 140, render: (value) => , }, { title: '创建时间', dataIndex: 'createdAt', width: 170, render: (value) => formatAdminDateTime(value), }, { title: '更新时间', dataIndex: 'updatedAt', width: 170, render: (value) => formatAdminDateTime(value), }, { title: '操作', width: 310, render: (_, row) => { const isCurrent = row.userId === currentUserId const roleMenuItems: MenuProps['items'] = USER_ROLE_OPTIONS.map((item) => ({ key: item.value, label: `设为${item.label}`, disabled: row.role === item.value, })) return ( confirmUpdateRole(row, key as AdminRole), }} > ) }, }, ] return (
筛选用户
layout="inline" initialValues={filters} onFinish={applyFilters} className="filter-form users-action-form" >
新增用户
form={createForm} layout="inline" initialValues={{ role: 'operator' }} onFinish={submitCreate} className="filter-form users-action-form" >