import React, { useState, useEffect } from 'react'; import { Input, Button, Badge, Avatar, Space, Tabs, Checkbox, Row, Col, Card, Empty, Divider, Alert } from 'antd'; import { SearchOutlined, UserOutlined, TeamOutlined, CheckCircleOutlined } from '@ant-design/icons'; import './EvaluateTaskPersonnelSelector.less'; const { TabPane } = Tabs; const { Search } = Input; /** * 评价任务人员选择组件属性接口 * @interface EvaluateTaskPersonnelSelectorProps * @property {Function} onSelect - 选择确认后的回调函数,返回所选人员数组 * @property {PersonnelItem[]} selectedPersonnel - 已选择的人员列表 */ interface EvaluateTaskPersonnelSelectorProps { onSelect: (personnel: PersonnelItem[]) => void; selectedPersonnel?: PersonnelItem[]; } /** * 人员信息接口 * @interface PersonnelItem * @property {string} id - 人员唯一标识 * @property {string} name - 人员姓名 * @property {string} department - 所属部门 * @property {string} position - 职位信息 * @property {boolean} selected - 是否被选中 */ export interface PersonnelItem { id: string; name: string; department: string; position?: string; selected?: boolean; } /** * 部门信息接口 * @interface Department * @property {string} id - 部门ID * @property {string} name - 部门名称 */ interface Department { id: string; name: string; } /** * 评价任务人员选择组件 * 用于在评价任务管理中选择评价人员,按部门分类展示 * * @component * @example * ```jsx * console.log('已选择人员:', selected)} * selectedPersonnel={[]} * /> * ``` */ const EvaluateTaskPersonnelSelector: React.FC = ({ onSelect, selectedPersonnel = [] }) => { // 搜索关键词 const [keyword, setKeyword] = useState(''); // 所有可选人员列表 const [personnel, setPersonnel] = useState([]); // 已选择人员ID列表 const [selectedKeys, setSelectedKeys] = useState([]); // 当前选中的部门Tab const [activeTab, setActiveTab] = useState('1'); /** * 部门数据列表 * 实际项目中可通过API获取 */ const departments: Department[] = [ { id: '1', name: '采购部' }, { id: '2', name: '技术部' }, { id: '3', name: '质量部' }, { id: '4', name: '生产部' }, { id: '5', name: '财务部' }, ]; /** * 初始化人员数据和已选状态 */ useEffect(() => { // 加载人员数据(模拟API请求) fetchPersonnelData(); // 设置已选人员 if (selectedPersonnel && selectedPersonnel.length > 0) { const selectedIds = selectedPersonnel.map(item => item.id); setSelectedKeys(selectedIds); } }, [selectedPersonnel]); /** * 模拟获取人员数据 * 实际项目中替换为API调用 */ const fetchPersonnelData = () => { // 模拟API调用获取评价人员 const mockPersonnel: PersonnelItem[] = [ { id: '1', name: '张三', department: '采购部', position: '采购经理' }, { id: '2', name: '李四', department: '技术部', position: '技术专家' }, { id: '3', name: '王五', department: '质量部', position: '质量工程师' }, { id: '4', name: '赵六', department: '采购部', position: '高级采购' }, { id: '5', name: '钱七', department: '技术部', position: '部门经理' }, { id: '6', name: '孙八', department: '质量部', position: '质量总监' }, { id: '7', name: '周九', department: '生产部', position: '生产主管' }, { id: '8', name: '吴十', department: '财务部', position: '财务经理' }, { id: '9', name: '郑十一', department: '采购部', position: '采购专员' }, { id: '10', name: '王十二', department: '技术部', position: '工程师' }, { id: '11', name: '刘十三', department: '财务部', position: '财务专员' }, { id: '12', name: '陈十四', department: '生产部', position: '技术员' }, ]; setPersonnel(mockPersonnel); }; /** * 处理搜索 * @param {string} value - 搜索关键词 */ const handleSearch = (value: string) => { setKeyword(value); }; /** * 处理Tab切换 * @param {string} key - 选中的Tab键值 */ const handleTabChange = (key: string) => { setActiveTab(key); }; /** * 处理单个人员选择 * @param {string} personnelId - 人员ID * @param {boolean} checked - 是否选中 */ const handleSelect = (personnelId: string, checked: boolean) => { let newSelectedKeys = [...selectedKeys]; if (checked) { newSelectedKeys.push(personnelId); } else { newSelectedKeys = newSelectedKeys.filter(id => id !== personnelId); } setSelectedKeys(newSelectedKeys); }; /** * 处理部门人员全选 * @param {string} deptId - 部门ID * @param {boolean} checked - 是否全选 */ const handleSelectAll = (deptId: string, checked: boolean) => { const deptName = departments.find(d => d.id === deptId)?.name || ''; const deptPersonnel = personnel.filter(p => p.department === deptName && (keyword ? p.name.includes(keyword) : true) ); const deptPersonnelIds = deptPersonnel.map(p => p.id); let newSelectedKeys = [...selectedKeys]; if (checked) { // 添加该部门所有人员 deptPersonnelIds.forEach(id => { if (!newSelectedKeys.includes(id)) { newSelectedKeys.push(id); } }); } else { // 移除该部门所有人员 newSelectedKeys = newSelectedKeys.filter(id => !deptPersonnelIds.includes(id)); } setSelectedKeys(newSelectedKeys); }; /** * 确认选择 * 将选中的人员ID列表转换为人员对象列表 */ const handleConfirm = () => { const selectedItems = personnel.filter(item => selectedKeys.includes(item.id)); onSelect(selectedItems); }; /** * 渲染部门下的人员列表 * @param {string} deptId - 部门ID * @returns {React.ReactNode} - 渲染结果 */ const renderDepartmentPersonnel = (deptId: string) => { // 获取部门名称 const deptName = departments.find(d => d.id === deptId)?.name || ''; // 过滤出当前部门且符合搜索条件的人员 const deptPersonnel = personnel.filter(p => p.department === deptName && (keyword ? p.name.includes(keyword) : true) ); // 检查该部门是否全部选中 const deptPersonnelIds = deptPersonnel.map(p => p.id); const isAllSelected = deptPersonnelIds.length > 0 && deptPersonnelIds.every(id => selectedKeys.includes(id)); // 如果没有符合条件的人员,显示空状态 if (deptPersonnel.length === 0) { return ; } return (
{deptName} handleSelectAll(deptId, e.target.checked)} > 全选 (共{deptPersonnel.length}人)
{deptPersonnel.map(person => ( handleSelect(person.id, e.target.checked)} > } size="small" className={selectedKeys.includes(person.id) ? 'selected-avatar' : ''} />
{person.name} {selectedKeys.includes(person.id) && ( )}
{person.position}
))}
); }; /** * 计算各部门已选人数 * @param {string} deptId - 部门ID * @returns {number} - 已选人数 */ const getSelectedCountByDept = (deptId: string) => { const deptName = departments.find(d => d.id === deptId)?.name || ''; const deptPersonnel = personnel.filter(p => p.department === deptName); const selectedCount = deptPersonnel.filter(p => selectedKeys.includes(p.id)).length; return selectedCount; }; /** * 渲染Tab标签 * @param {Department} dept - 部门信息 * @returns {React.ReactNode} - 渲染结果 */ const renderTabTitle = (dept: Department) => { const selectedCount = getSelectedCountByDept(dept.id); return ( 0 ? selectedCount : 0} size="small" offset={[5, -3]} style={{ backgroundColor: selectedCount > 0 ? '#1890ff' : '#d9d9d9' }} > {dept.name} ); }; return (
{/* 顶部搜索和统计区域 */}
搜索} onSearch={handleSearch} onChange={(e) => setKeyword(e.target.value)} className="search-input" />
已选人员
{/* 显示已选人员数量的提示 */} {selectedKeys.length > 0 && ( )} {/* 部门分类标签页 */} {departments.map(dept => ( {renderDepartmentPersonnel(dept.id)} ))} {/* 底部确认按钮区域 */}
); }; export default EvaluateTaskPersonnelSelector;