325 lines
9.8 KiB
TypeScript
325 lines
9.8 KiB
TypeScript
'use client';
|
||
|
||
import { useState, useEffect } from 'react';
|
||
import { toast } from 'sonner';
|
||
|
||
import { EmployeeManagementHeader } from './components/EmployeeManagementHeader';
|
||
import { EmployeeManagementStatsCards } from './components/EmployeeManagementStatsCards';
|
||
import { EmployeeManagementFilters } from './components/EmployeeManagementFilters';
|
||
import { EmployeeList } from './components/EmployeeList';
|
||
import { EmployeeFormDialog } from './components/EmployeeFormDialog';
|
||
import { EmployeeDetailDialog } from './components/EmployeeDetailDialog';
|
||
import { Employee, Role, EmployeeFilters, EmployeeFormData } from './types';
|
||
import {
|
||
fetchEmployees,
|
||
transformEmployeesList,
|
||
PaginationState,
|
||
EmployeesQueryParams
|
||
} from './components/employeeApi';
|
||
|
||
export default function EmployeeManagementPage() {
|
||
const [employees, setEmployees] = useState<Employee[]>([]);
|
||
const [roles, setRoles] = useState<Role[]>([]);
|
||
const [loading, setLoading] = useState(false);
|
||
const [pagination, setPagination] = useState<PaginationState>({
|
||
page: 1,
|
||
size: 10,
|
||
total: 0,
|
||
totalPages: 0,
|
||
hasNext: false,
|
||
hasPrev: false,
|
||
});
|
||
const [filters, setFilters] = useState<EmployeeFilters>({
|
||
searchKeyword: '',
|
||
statusFilter: 'all'
|
||
});
|
||
const [showForm, setShowForm] = useState(false);
|
||
const [showDetailDialog, setShowDetailDialog] = useState(false);
|
||
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: '',
|
||
});
|
||
|
||
useEffect(() => {
|
||
loadEmployees();
|
||
loadRoles();
|
||
}, [pagination.page, pagination.size,filters.searchKeyword, filters.statusFilter]);
|
||
|
||
const loadRoles = () => {
|
||
const data = localStorage.getItem('smart_agriculture_roles');
|
||
if (data) {
|
||
setRoles(JSON.parse(data));
|
||
}
|
||
};
|
||
|
||
const loadEmployees = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const queryParams: EmployeesQueryParams = {
|
||
page: pagination.page,
|
||
size: pagination.size,
|
||
sort_order: 'desc'
|
||
};
|
||
|
||
// 如果有搜索关键词,添加到查询参数
|
||
if (filters.searchKeyword) {
|
||
queryParams.search = filters.searchKeyword;
|
||
}
|
||
|
||
// 如果有状态筛选,添加到查询参数
|
||
if (filters.statusFilter !== 'all') {
|
||
// 注意:API可能不支持直接的状态筛选,这里暂时在客户端过滤
|
||
}
|
||
|
||
const response = await fetchEmployees(queryParams);
|
||
|
||
// 转换数据格式
|
||
const transformedEmployees = transformEmployeesList(response.data);
|
||
|
||
// 应用状态筛选(如果API不支持)
|
||
const filteredEmployees = filters.statusFilter === 'all'
|
||
? transformedEmployees
|
||
: transformedEmployees.filter(emp => {
|
||
const status = emp.isActive ? 'active' : 'frozen';
|
||
return status === filters.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('加载员工数据失败');
|
||
// 如果API失败,使用localStorage中的数据
|
||
setEmployees([]);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
// 搜索处理函数
|
||
const handleSearch = (searchKeyword: string) => {
|
||
setFilters(prev => ({ ...prev, searchKeyword }));
|
||
// 重置到第一页
|
||
setPagination(prev => ({ ...prev, page: 1 }));
|
||
};
|
||
|
||
// 状态筛选处理函数
|
||
const handleStatusFilter = (statusFilter: string) => {
|
||
setFilters(prev => ({ ...prev, statusFilter }));
|
||
// 重置到第一页
|
||
setPagination(prev => ({ ...prev, page: 1 }));
|
||
};
|
||
|
||
// 分页处理函数
|
||
const handlePageChange = (page: number) => {
|
||
setPagination(prev => ({ ...prev, page }));
|
||
};
|
||
|
||
const handlePageSizeChange = (size: number) => {
|
||
setPagination(prev => ({ ...prev, size, page: 1 }));
|
||
};
|
||
|
||
const handleAddEmployee = () => {
|
||
setEditingEmployee(null);
|
||
setFormData({
|
||
enterpriseId: 'ent-2',
|
||
enterpriseName: '丰收现代农业集团',
|
||
status: 'active',
|
||
auditStatus: 'pending',
|
||
roleIds: [],
|
||
idCard: '',
|
||
address: '',
|
||
});
|
||
setShowForm(true);
|
||
};
|
||
|
||
const handleEdit = (employee: Employee) => {
|
||
setEditingEmployee(employee);
|
||
setFormData(employee);
|
||
setShowForm(true);
|
||
};
|
||
|
||
const handleSave = () => {
|
||
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) {
|
||
// 更新
|
||
const updated = employees.map(emp =>
|
||
emp.id === editingEmployee.id
|
||
? {
|
||
...emp,
|
||
...formData,
|
||
roles: roleNames,
|
||
updatedAt: new Date().toISOString(),
|
||
}
|
||
: emp
|
||
);
|
||
setEmployees(updated);
|
||
localStorage.setItem('smart_agriculture_employees', JSON.stringify(updated));
|
||
toast.success('员工信息更新成功');
|
||
} else {
|
||
// 新增
|
||
const newEmployee: Employee = {
|
||
id: `emp-${Date.now()}`,
|
||
...formData as Employee,
|
||
roles: roleNames,
|
||
auditStatus: 'pending',
|
||
createdAt: new Date().toISOString(),
|
||
updatedAt: new Date().toISOString(),
|
||
};
|
||
const updated = [...employees, newEmployee];
|
||
setEmployees(updated);
|
||
localStorage.setItem('smart_agriculture_employees', JSON.stringify(updated));
|
||
toast.success('员工添加成功');
|
||
}
|
||
|
||
setShowForm(false);
|
||
};
|
||
|
||
const handleDelete = (id: string) => {
|
||
if (!confirm('确定要删除该员工吗?')) return;
|
||
|
||
const updated = employees.filter(emp => emp.id !== id);
|
||
setEmployees(updated);
|
||
localStorage.setItem('smart_agriculture_employees', JSON.stringify(updated));
|
||
toast.success('员工删除成功');
|
||
};
|
||
|
||
const handleToggleStatus = (employee: Employee) => {
|
||
const newStatus = employee.status === 'active' ? 'frozen' : 'active';
|
||
const updated = employees.map(emp =>
|
||
emp.id === employee.id
|
||
? { ...emp, status: newStatus, updatedAt: new Date().toISOString() }
|
||
: emp
|
||
);
|
||
setEmployees(updated);
|
||
localStorage.setItem('smart_agriculture_employees', JSON.stringify(updated));
|
||
toast.success(newStatus === 'active' ? '账户已激活' : '账户已冻结');
|
||
};
|
||
|
||
const handleResetPassword = (employee: Employee) => {
|
||
if (!confirm(`确定要重置 ${employee.name} 的密码吗?`)) return;
|
||
toast.success('密码已重置为:123456');
|
||
};
|
||
|
||
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);
|
||
localStorage.setItem('smart_agriculture_employees', JSON.stringify(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);
|
||
localStorage.setItem('smart_agriculture_employees', JSON.stringify(updated));
|
||
toast.success('已驳回');
|
||
}
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
<EmployeeManagementHeader
|
||
onAddEmployee={handleAddEmployee}
|
||
/>
|
||
|
||
{/* 统计卡片 */}
|
||
<EmployeeManagementStatsCards employees={employees} />
|
||
|
||
{/* 搜索和筛选 */}
|
||
<EmployeeManagementFilters
|
||
filters={filters}
|
||
onSearchChange={handleSearch}
|
||
onStatusFilterChange={handleStatusFilter}
|
||
/>
|
||
|
||
{/* 员工列表 */}
|
||
<EmployeeList
|
||
employees={employees}
|
||
loading={loading}
|
||
pagination={pagination}
|
||
onPageChange={handlePageChange}
|
||
onPageSizeChange={handlePageSizeChange}
|
||
onViewDetail={handleViewDetail}
|
||
onEdit={handleEdit}
|
||
onResetPassword={handleResetPassword}
|
||
onToggleStatus={handleToggleStatus}
|
||
onDelete={handleDelete}
|
||
onAudit={handleAudit}
|
||
/>
|
||
|
||
{/* 添加/编辑表单 */}
|
||
<EmployeeFormDialog
|
||
open={showForm}
|
||
onOpenChange={setShowForm}
|
||
editingEmployee={editingEmployee}
|
||
formData={formData}
|
||
onFormDataChange={setFormData}
|
||
onSave={handleSave}
|
||
roles={roles}
|
||
/>
|
||
|
||
{/* 详情对话框 */}
|
||
<EmployeeDetailDialog
|
||
open={showDetailDialog}
|
||
onOpenChange={setShowDetailDialog}
|
||
selectedEmployee={selectedEmployee}
|
||
/>
|
||
</div>
|
||
);
|
||
} |