742 lines
23 KiB
TypeScript
742 lines
23 KiB
TypeScript
/**
|
||
* filekorolheader: 员工管理页面 - 企业员工账户管理页面
|
||
* 功能:员工列表查询、添加编辑、状态管理、角色分配
|
||
* 路径:/central-config/user/employee
|
||
* 规范:遵循crop-x/docs/开发项目规范.md,使用事件驱动模式,SearchFormPagination重构
|
||
*/
|
||
'use client';
|
||
|
||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||
import { toast } from 'sonner';
|
||
import { Button } from '@/components/ui/button';
|
||
import { Plus, Eye, Edit, Trash2, Power, PowerOff } from 'lucide-react';
|
||
import { Badge } from '@/components/ui/badge';
|
||
|
||
import { EmployeeManagementHeader } from './components/EmployeeManagementHeader';
|
||
import { EmployeeManagementStatsCards } from './components/EmployeeManagementStatsCards';
|
||
import { EmployeeFormDialog } from './components/EmployeeFormDialog';
|
||
import { EmployeeDetailDialog } from './components/EmployeeDetailDialog';
|
||
import { SearchFormPagination, type SearchFieldConfig, type TableColumnConfig } from '@/components/common/searchFormPagination';
|
||
import {
|
||
AlertDialog,
|
||
AlertDialogAction,
|
||
AlertDialogCancel,
|
||
AlertDialogContent,
|
||
AlertDialogDescription,
|
||
AlertDialogFooter,
|
||
AlertDialogHeader,
|
||
AlertDialogTitle,
|
||
} from '@/components/ui/alert-dialog';
|
||
import { Employee, Role, EmployeeFormData } from './types';
|
||
import {
|
||
fetchEmployees,
|
||
transformEmployeesList,
|
||
createEmployee,
|
||
updateEmployee,
|
||
activateUser,
|
||
deactivateUser,
|
||
deleteUser,
|
||
CreateEmployeeRequest,
|
||
UpdateEmployeeRequest,
|
||
PaginationState,
|
||
EmployeesQueryParams
|
||
} from './components/employeeApi';
|
||
import {
|
||
fetchRoles,
|
||
transformRolesList
|
||
} from '../role/components/roleApi';
|
||
|
||
export default function EmployeeManagementPage() {
|
||
const [employees, setEmployees] = useState<Employee[]>([]);
|
||
const [roles, setRoles] = useState<Role[]>([]);
|
||
const [loading, setLoading] = useState(false);
|
||
const [creating, setCreating] = useState(false);
|
||
const [updating, setUpdating] = useState(false);
|
||
const [toggling, setToggling] = useState<string | null>(null); // 记录正在操作的用户ID
|
||
const isFirstLoad = useRef(true);
|
||
|
||
// 确认对话框状态
|
||
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
|
||
const [userToDelete, setUserToDelete] = useState<Employee | null>(null);
|
||
const [deactivateConfirmOpen, setDeactivateConfirmOpen] = useState(false);
|
||
const [userToDeactivate, setUserToDeactivate] = useState<Employee | null>(null);
|
||
const [pagination, setPagination] = useState<PaginationState>({
|
||
page: 1,
|
||
size: 10,
|
||
total: 0,
|
||
totalPages: 0,
|
||
hasNext: false,
|
||
hasPrev: false,
|
||
});
|
||
const [searchFilters, setSearchFilters] = useState<Record<string, string>>({
|
||
search: '',
|
||
status: 'all'
|
||
});
|
||
const [showForm, setShowForm] = useState(false);
|
||
const [showDetailDialog, setShowDetailDialog] = useState(false);
|
||
const [formKey, setFormKey] = useState(0); // 添加key来强制重新渲染表单
|
||
const [editingEmployee, setEditingEmployee] = useState<Employee | null>(null);
|
||
const [selectedEmployee, setSelectedEmployee] = useState<Employee | null>(null);
|
||
const [formData, setFormData] = useState<EmployeeFormData>({
|
||
enterpriseId: 'ent-2',
|
||
enterpriseName: '丰收现代农业集团',
|
||
status: 'active',
|
||
auditStatus: 'pending',
|
||
roleIds: [],
|
||
idCard: '',
|
||
address: '',
|
||
});
|
||
|
||
// 搜索字段配置
|
||
const searchFields: SearchFieldConfig[] = [
|
||
{
|
||
key: 'search',
|
||
label: '搜索',
|
||
type: 'text',
|
||
placeholder: '搜索用户名、姓名、手机号...',
|
||
},
|
||
{
|
||
key: 'status',
|
||
label: '账户状态',
|
||
type: 'select',
|
||
defaultValue: 'all',
|
||
options: [
|
||
{ value: 'all', label: '全部状态' },
|
||
{ value: 'active', label: '正常' },
|
||
{ value: 'frozen', label: '停用' },
|
||
],
|
||
},
|
||
];
|
||
|
||
// 表格列配置
|
||
const columns: TableColumnConfig[] = [
|
||
{
|
||
key: 'username',
|
||
label: '用户名',
|
||
render: (value: string) => (
|
||
<div className="font-medium text-foreground">{value}</div>
|
||
),
|
||
},
|
||
{
|
||
key: 'fullName',
|
||
label: '姓名',
|
||
render: (value: string) => (
|
||
<div className="text-foreground">{value || '-'}</div>
|
||
),
|
||
},
|
||
{
|
||
key: 'phone',
|
||
label: '手机号',
|
||
render: (value: string) => (
|
||
<div className="font-mono text-sm">{value || '-'}</div>
|
||
),
|
||
},
|
||
{
|
||
key: 'roles',
|
||
label: '角色',
|
||
render: (value: string[]) => (
|
||
<div className="flex flex-wrap gap-1">
|
||
{value && value.length > 0 ? (
|
||
value.map((role, index) => (
|
||
<Badge key={index} variant="secondary" className="font-light">
|
||
{role}
|
||
</Badge>
|
||
))
|
||
) : (
|
||
<span className="text-muted-foreground">-</span>
|
||
)}
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
key: 'department',
|
||
label: '部门',
|
||
render: (value: string) => (
|
||
<div className="text-sm text-muted-foreground">{value || '-'}</div>
|
||
),
|
||
},
|
||
{
|
||
key: 'isActive',
|
||
label: '状态',
|
||
render: (value: boolean) => (
|
||
<Badge className={`font-light ${
|
||
value
|
||
? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200'
|
||
: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200'
|
||
}`}>
|
||
{value ? '正常' : '停用'}
|
||
</Badge>
|
||
),
|
||
},
|
||
{
|
||
key: 'createdAt',
|
||
label: '创建时间',
|
||
render: (value: string) => (
|
||
<div className="text-sm text-muted-foreground">
|
||
{value ? new Date(value).toLocaleDateString('zh-CN') : '-'}
|
||
</div>
|
||
),
|
||
},
|
||
{
|
||
key: 'actions',
|
||
label: '操作',
|
||
render: (_: any, row: Employee) => (
|
||
<div className="flex gap-2">
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
onClick={() => handleViewDetail(row)}
|
||
className="h-8 px-2"
|
||
>
|
||
<Eye className="w-3 h-3 mr-1" />
|
||
查看
|
||
</Button>
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
onClick={() => handleEdit(row)}
|
||
className="h-8 px-2"
|
||
>
|
||
<Edit className="w-3 h-3 mr-1" />
|
||
编辑
|
||
</Button>
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
onClick={() => handleToggleStatus(row)}
|
||
disabled={toggling === row.id}
|
||
className={`h-8 px-2 ${
|
||
row.isActive
|
||
? 'text-orange-600 border-orange-300 hover:bg-orange-50'
|
||
: 'text-green-600 border-green-300 hover:bg-green-50'
|
||
}`}
|
||
>
|
||
{row.isActive ? (
|
||
<PowerOff className="w-3 h-3 mr-1" />
|
||
) : (
|
||
<Power className="w-3 h-3 mr-1" />
|
||
)}
|
||
{row.isActive ? '停用' : '启用'}
|
||
</Button>
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
onClick={() => handleDelete(row.id)}
|
||
disabled={toggling === row.id}
|
||
className="h-8 px-2 text-red-600 border-red-300 hover:bg-red-50"
|
||
>
|
||
<Trash2 className="w-3 h-3 mr-1" />
|
||
删除
|
||
</Button>
|
||
</div>
|
||
),
|
||
},
|
||
];
|
||
|
||
// 加载角色数据 - 事件驱动
|
||
const loadRoles = useCallback(async () => {
|
||
try {
|
||
const response = await fetchRoles({
|
||
page: 1,
|
||
size: 100,
|
||
sort_order: 'desc'
|
||
});
|
||
const transformedRoles = transformRolesList(response.data);
|
||
setRoles(transformedRoles);
|
||
} catch (error) {
|
||
console.error('Failed to load roles:', error);
|
||
setRoles([]);
|
||
}
|
||
}, []);
|
||
|
||
// 加载员工数据 - 事件驱动,移除依赖项
|
||
const loadEmployees = useCallback(async (params?: {
|
||
filters?: Record<string, string>;
|
||
pagination?: { page: number; size: number };
|
||
resetPage?: boolean;
|
||
}) => {
|
||
try {
|
||
setLoading(true);
|
||
const queryParams: EmployeesQueryParams = {
|
||
page: params?.resetPage ? 1 : (params?.pagination?.page || pagination.page),
|
||
size: params?.pagination?.size || pagination.size,
|
||
sort_order: 'desc'
|
||
};
|
||
|
||
// 搜索关键词
|
||
const searchKeyword = params?.filters?.search ?? searchFilters.search;
|
||
if (searchKeyword) {
|
||
queryParams.search = searchKeyword;
|
||
}
|
||
|
||
const response = await fetchEmployees(queryParams);
|
||
const transformedEmployees = transformEmployeesList(response.data);
|
||
|
||
// 状态筛选(客户端过滤)
|
||
const statusFilter = params?.filters?.status ?? searchFilters.status;
|
||
const filteredEmployees = statusFilter === 'all'
|
||
? transformedEmployees
|
||
: transformedEmployees.filter(emp => {
|
||
const status = emp.isActive ? 'active' : 'frozen';
|
||
return status === statusFilter;
|
||
});
|
||
|
||
setEmployees(filteredEmployees);
|
||
setPagination({
|
||
page: response.page,
|
||
size: response.size,
|
||
total: response.total,
|
||
totalPages: response.total_pages,
|
||
hasNext: response.has_next,
|
||
hasPrev: response.has_prev,
|
||
});
|
||
} catch (error) {
|
||
console.error('Failed to load employees:', error);
|
||
toast.error('加载员工数据失败');
|
||
setEmployees([]);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}, [pagination.page, pagination.size, searchFilters]);
|
||
|
||
// 初始化数据 - 只在组件挂载时执行一次
|
||
useEffect(() => {
|
||
if (isFirstLoad.current) {
|
||
isFirstLoad.current = false;
|
||
loadRoles();
|
||
loadEmployees({ resetPage: true });
|
||
}
|
||
}, [loadRoles, loadEmployees]);
|
||
|
||
// 事件处理器 - 事件驱动模式
|
||
const handleSearch = useCallback((filters: Record<string, string>) => {
|
||
setSearchFilters(filters);
|
||
loadEmployees({
|
||
filters,
|
||
pagination: { page: 1, size: pagination.size }
|
||
});
|
||
}, [loadEmployees, pagination.size]);
|
||
|
||
const handlePageChange = useCallback((page: number) => {
|
||
setPagination(prev => ({ ...prev, page }));
|
||
loadEmployees({
|
||
filters: searchFilters,
|
||
pagination: { page, size: pagination.size }
|
||
});
|
||
}, [loadEmployees, searchFilters, pagination.size]);
|
||
|
||
const handleSizeChange = useCallback((size: number) => {
|
||
setPagination(prev => ({ ...prev, size, page: 1 }));
|
||
loadEmployees({
|
||
filters: searchFilters,
|
||
pagination: { page: 1, size }
|
||
});
|
||
}, [loadEmployees, searchFilters]);
|
||
|
||
const handleAddEmployee = () => {
|
||
setEditingEmployee(null);
|
||
clearForm();
|
||
setFormKey(prev => prev + 1); // 增加key强制重新渲染
|
||
setShowForm(true);
|
||
};
|
||
|
||
const clearForm = () => {
|
||
// 直接设置空表单,无需setTimeout
|
||
const emptyForm = {
|
||
enterpriseId: 'ent-2',
|
||
enterpriseName: '丰收现代农业集团',
|
||
status: 'active' as const,
|
||
auditStatus: 'pending' as const,
|
||
roleIds: [],
|
||
username: '',
|
||
name: '',
|
||
phone: '',
|
||
email: '',
|
||
department: '',
|
||
position: '',
|
||
};
|
||
setFormData(emptyForm);
|
||
};
|
||
|
||
const handleEdit = (employee: Employee) => {
|
||
setEditingEmployee(employee);
|
||
setFormData(employee);
|
||
setShowForm(true);
|
||
};
|
||
|
||
const handleSave = async () => {
|
||
if (!formData.username || !formData.name || !formData.phone) {
|
||
toast.error('请填写必填项');
|
||
return;
|
||
}
|
||
|
||
// 验证角色选择
|
||
if (!formData.roleIds || formData.roleIds.length === 0) {
|
||
toast.error('请至少选择一个角色');
|
||
return;
|
||
}
|
||
|
||
// 根据角色ID设置角色名称
|
||
const selectedRoles = roles.filter(r => formData.roleIds?.includes(r.id));
|
||
const roleNames = selectedRoles.map(r => r.name);
|
||
|
||
if (editingEmployee) {
|
||
// 更新 - 调用API
|
||
setUpdating(true);
|
||
try {
|
||
// 构建API请求参数
|
||
const updateRequest: UpdateEmployeeRequest = {
|
||
email: formData.email || '',
|
||
username: formData.username,
|
||
full_name: formData.name,
|
||
phone: formData.phone,
|
||
password: '', // 编辑时不传密码
|
||
tenant_id: formData.enterpriseId,
|
||
scope: 'tenant',
|
||
department_id: formData.departmentId || '',
|
||
is_superuser: formData.isSuperuser || false,
|
||
};
|
||
|
||
// 调用API更新用户
|
||
const updatedEmployee = await updateEmployee(editingEmployee.id, updateRequest);
|
||
|
||
// 更新本地列表中的员工数据
|
||
const updated = employees.map(emp =>
|
||
emp.id === editingEmployee.id
|
||
? {
|
||
...emp,
|
||
...updatedEmployee,
|
||
roles: roleNames,
|
||
updatedAt: new Date().toISOString(),
|
||
}
|
||
: emp
|
||
);
|
||
setEmployees(updated);
|
||
|
||
toast.success('员工信息更新成功');
|
||
setShowForm(false);
|
||
clearForm();
|
||
|
||
// 立即刷新员工列表数据,无需延迟
|
||
loadEmployees({ resetPage: true });
|
||
} catch (error) {
|
||
console.error('更新员工失败:', error);
|
||
|
||
// 处理错误,显示具体的错误消息
|
||
const errorMessage = error instanceof Error ? error.message : '员工信息更新失败';
|
||
toast.error(errorMessage);
|
||
} finally {
|
||
setUpdating(false);
|
||
}
|
||
} else {
|
||
// 新增 - 调用API
|
||
setCreating(true);
|
||
try {
|
||
// 构建API请求参数
|
||
const createRequest: CreateEmployeeRequest = {
|
||
email: formData.email || '', // 没有邮箱就传空字符串
|
||
username: formData.username,
|
||
full_name: formData.name,
|
||
phone: formData.phone,
|
||
password: '', // 传递空字符串给后端
|
||
tenant_id: formData.enterpriseId,
|
||
scope: 'tenant',
|
||
department_id: formData.departmentId || '',
|
||
is_superuser: formData.isSuperuser || false,
|
||
};
|
||
|
||
// 调用API创建用户
|
||
const newEmployee = await createEmployee(createRequest);
|
||
|
||
// 将新员工添加到列表
|
||
const updated = [newEmployee, ...employees];
|
||
setEmployees(updated);
|
||
|
||
toast.success('员工添加成功');
|
||
setShowForm(false);
|
||
clearForm();
|
||
|
||
// 立即刷新员工列表数据,无需延迟
|
||
loadEmployees({ resetPage: true });
|
||
} catch (error) {
|
||
console.error('创建员工失败:', error);
|
||
|
||
// 处理错误,显示具体的错误消息
|
||
const errorMessage = error instanceof Error ? error.message : '员工添加失败';
|
||
toast.error(errorMessage);
|
||
} finally {
|
||
setCreating(false);
|
||
}
|
||
}
|
||
};
|
||
|
||
const handleDelete = (userId: string) => {
|
||
// 防止重复操作
|
||
if (toggling) {
|
||
toast.warning('操作进行中,请稍候...');
|
||
return;
|
||
}
|
||
|
||
// 查找要删除的员工信息
|
||
const employeeToDelete = employees.find(emp => emp.id === userId);
|
||
if (!employeeToDelete) {
|
||
toast.error('未找到要删除的用户');
|
||
return;
|
||
}
|
||
|
||
// 设置要删除的用户并显示确认对话框
|
||
setUserToDelete(employeeToDelete);
|
||
setDeleteConfirmOpen(true);
|
||
};
|
||
|
||
const executeDelete = async (userId: string) => {
|
||
setToggling(userId);
|
||
|
||
try {
|
||
// 调用API删除用户
|
||
await deleteUser(userId);
|
||
|
||
// 成功后从本地列表中移除
|
||
const updated = employees.filter(emp => emp.id !== userId);
|
||
setEmployees(updated);
|
||
|
||
toast.success('用户删除成功');
|
||
|
||
// 立即刷新列表确保数据同步
|
||
loadEmployees({ resetPage: true });
|
||
|
||
// 关闭确认对话框
|
||
setDeleteConfirmOpen(false);
|
||
setUserToDelete(null);
|
||
} catch (error) {
|
||
console.error('删除用户失败:', error);
|
||
|
||
// 处理错误,显示具体的错误消息
|
||
const errorMessage = error instanceof Error ? error.message : '删除失败,请稍后重试';
|
||
toast.error(errorMessage);
|
||
|
||
// 失败时不关闭确认对话框,用户可以重试
|
||
} finally {
|
||
setToggling(null);
|
||
}
|
||
};
|
||
|
||
const handleToggleStatus = (employee: Employee) => {
|
||
if (toggling) {
|
||
toast.warning('操作进行中,请稍候...');
|
||
return;
|
||
}
|
||
|
||
if (employee.isActive) {
|
||
// 当前是激活状态,进行停用操作,需要二次确认
|
||
setUserToDeactivate(employee);
|
||
setDeactivateConfirmOpen(true);
|
||
} else {
|
||
// 当前是停用状态,进行激活操作(不需要确认)
|
||
executeToggleStatus(employee);
|
||
}
|
||
};
|
||
|
||
const executeToggleStatus = async (employee: Employee) => {
|
||
setToggling(employee.id);
|
||
|
||
try {
|
||
if (employee.isActive) {
|
||
// 当前是激活状态,进行停用操作
|
||
await deactivateUser(employee.id);
|
||
toast.success('账户已停用');
|
||
} else {
|
||
// 当前是停用状态,进行激活操作
|
||
await activateUser(employee.id);
|
||
toast.success('账户已激活');
|
||
}
|
||
|
||
// 成功后立即刷新列表
|
||
loadEmployees({ resetPage: true });
|
||
|
||
// 关闭停用确认对话框
|
||
if (deactivateConfirmOpen) {
|
||
setDeactivateConfirmOpen(false);
|
||
setUserToDeactivate(null);
|
||
}
|
||
} catch (error) {
|
||
console.error('切换用户状态失败:', error);
|
||
|
||
// 处理错误,显示具体的错误消息
|
||
const errorMessage = error instanceof Error ? error.message : '操作失败,请稍后重试';
|
||
toast.error(errorMessage);
|
||
|
||
// 失败时不关闭确认对话框,用户可以重试
|
||
} finally {
|
||
setToggling(null);
|
||
}
|
||
};
|
||
|
||
|
||
const handleViewDetail = (employee: Employee) => {
|
||
setSelectedEmployee(employee);
|
||
setShowDetailDialog(true);
|
||
};
|
||
|
||
const handleAudit = (employee: Employee, action: 'approve' | 'reject') => {
|
||
if (action === 'approve') {
|
||
const updated = employees.map(emp =>
|
||
emp.id === employee.id
|
||
? {
|
||
...emp,
|
||
auditStatus: 'approved' as const,
|
||
auditTime: new Date().toISOString(),
|
||
auditor: '当前用户',
|
||
updatedAt: new Date().toISOString(),
|
||
}
|
||
: emp
|
||
);
|
||
setEmployees(updated);
|
||
toast.success('审核通过');
|
||
} else {
|
||
const reason = prompt('请输入驳回原因:');
|
||
if (reason) {
|
||
const updated = employees.map(emp =>
|
||
emp.id === employee.id
|
||
? {
|
||
...emp,
|
||
auditStatus: 'rejected' as const,
|
||
auditReason: reason,
|
||
auditTime: new Date().toISOString(),
|
||
auditor: '当前用户',
|
||
updatedAt: new Date().toISOString(),
|
||
}
|
||
: emp
|
||
);
|
||
setEmployees(updated);
|
||
toast.success('已驳回');
|
||
}
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
<EmployeeManagementHeader
|
||
onAddEmployee={handleAddEmployee}
|
||
/>
|
||
|
||
{/* 统计卡片 - 保留原有功能 */}
|
||
<EmployeeManagementStatsCards employees={employees} />
|
||
|
||
{/* 搜索、表格和分页 - 使用重构后的组件 */}
|
||
<SearchFormPagination
|
||
formTitle="员工列表"
|
||
formRightContent={
|
||
<Button onClick={handleAddEmployee} disabled={loading}>
|
||
<Plus className="w-4 h-4 mr-2" />
|
||
添加员工
|
||
</Button>
|
||
}
|
||
searchFields={searchFields}
|
||
columns={columns}
|
||
data={employees}
|
||
loading={loading}
|
||
error={null}
|
||
pagination={pagination}
|
||
onPageChange={handlePageChange}
|
||
onSizeChange={handleSizeChange}
|
||
onSearch={handleSearch}
|
||
emptyIcon={<div className="w-12 h-12 mx-auto mb-4 opacity-20" />}
|
||
emptyText="暂无员工数据"
|
||
showSizeSelector={true}
|
||
showPageInfo={true}
|
||
sizeOptions={[10, 20, 50, 100]}
|
||
/>
|
||
|
||
{/* 添加/编辑表单 - 保留原有功能 */}
|
||
<EmployeeFormDialog
|
||
key={formKey} // 使用key强制重新渲染,清除浏览器缓存
|
||
open={showForm}
|
||
onOpenChange={setShowForm}
|
||
editingEmployee={editingEmployee}
|
||
formData={formData}
|
||
onFormDataChange={setFormData}
|
||
onSave={handleSave}
|
||
roles={roles}
|
||
creating={creating}
|
||
updating={updating}
|
||
onClearForm={clearForm}
|
||
/>
|
||
|
||
{/* 详情对话框 - 保留原有功能 */}
|
||
<EmployeeDetailDialog
|
||
open={showDetailDialog}
|
||
onOpenChange={setShowDetailDialog}
|
||
selectedEmployee={selectedEmployee}
|
||
/>
|
||
|
||
{/* 删除确认对话框 - 保留原有功能 */}
|
||
<AlertDialog open={deleteConfirmOpen} onOpenChange={setDeleteConfirmOpen}>
|
||
<AlertDialogContent>
|
||
<AlertDialogHeader>
|
||
<AlertDialogTitle>确认删除用户</AlertDialogTitle>
|
||
<AlertDialogDescription>
|
||
确定要删除用户 "
|
||
{userToDelete?.displayName || userToDelete?.fullName || userToDelete?.username || ''}
|
||
" 吗?
|
||
<br /><br />
|
||
<span className="text-red-600 font-semibold">
|
||
删除后该用户将无法恢复,所有相关数据将被清除。
|
||
</span>
|
||
</AlertDialogDescription>
|
||
</AlertDialogHeader>
|
||
<AlertDialogFooter>
|
||
<AlertDialogCancel disabled={toggling !== null}>
|
||
取消
|
||
</AlertDialogCancel>
|
||
<AlertDialogAction
|
||
onClick={() => {
|
||
if (userToDelete) {
|
||
executeDelete(userToDelete.id);
|
||
}
|
||
}}
|
||
disabled={toggling !== null}
|
||
className="bg-red-600 hover:bg-red-700"
|
||
>
|
||
{toggling ? '删除中...' : '确认删除'}
|
||
</AlertDialogAction>
|
||
</AlertDialogFooter>
|
||
</AlertDialogContent>
|
||
</AlertDialog>
|
||
|
||
{/* 停用确认对话框 - 保留原有功能 */}
|
||
<AlertDialog open={deactivateConfirmOpen} onOpenChange={setDeactivateConfirmOpen}>
|
||
<AlertDialogContent>
|
||
<AlertDialogHeader>
|
||
<AlertDialogTitle>确认停用用户</AlertDialogTitle>
|
||
<AlertDialogDescription>
|
||
确定要停用用户 "
|
||
{userToDeactivate?.displayName || userToDeactivate?.fullName || userToDeactivate?.username || ''}
|
||
" 吗?
|
||
<br /><br />
|
||
<span className="text-orange-600 font-semibold">
|
||
停用后,该用户将无法登录系统。
|
||
</span>
|
||
</AlertDialogDescription>
|
||
</AlertDialogHeader>
|
||
<AlertDialogFooter>
|
||
<AlertDialogCancel disabled={toggling !== null}>
|
||
取消
|
||
</AlertDialogCancel>
|
||
<AlertDialogAction
|
||
onClick={() => {
|
||
if (userToDeactivate) {
|
||
executeToggleStatus(userToDeactivate);
|
||
}
|
||
}}
|
||
disabled={toggling !== null}
|
||
className="bg-orange-600 hover:bg-orange-700"
|
||
>
|
||
{toggling ? '停用中...' : '确认停用'}
|
||
</AlertDialogAction>
|
||
</AlertDialogFooter>
|
||
</AlertDialogContent>
|
||
</AlertDialog>
|
||
</div>
|
||
);
|
||
} |