2025-06-23 21:39:51 +08:00
|
|
|
|
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
2025-06-24 18:58:43 +08:00
|
|
|
|
import { Table, Input, Button, Space, message } from 'antd';
|
|
|
|
|
import { SearchOutlined } from '@ant-design/icons';
|
|
|
|
|
import { getUserList } from '@/servers/api/user';
|
2025-06-23 19:15:13 +08:00
|
|
|
|
import './EvaluateTaskPersonnelSelector.less';
|
|
|
|
|
|
|
|
|
|
const { Search } = Input;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 评价任务人员选择组件属性接口
|
|
|
|
|
* @interface EvaluateTaskPersonnelSelectorProps
|
|
|
|
|
* @property {Function} onSelect - 选择确认后的回调函数,返回所选人员数组
|
2025-06-24 18:58:43 +08:00
|
|
|
|
* @property {API.PersonnelItem[]} selectedPersonnel - 已选择的人员列表
|
2025-06-23 19:15:13 +08:00
|
|
|
|
*/
|
|
|
|
|
interface EvaluateTaskPersonnelSelectorProps {
|
2025-06-24 18:58:43 +08:00
|
|
|
|
onSelect: (personnel: API.PersonnelItem[]) => void; // 选择确认后的回调函数
|
|
|
|
|
selectedPersonnel?: API.PersonnelItem[]; // 已选择的人员列表(用于回显)
|
2025-06-23 19:15:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 评价任务人员选择组件
|
2025-06-24 18:58:43 +08:00
|
|
|
|
* 用于在评价任务管理中选择评价人员,显示为简单表格
|
2025-06-23 19:15:13 +08:00
|
|
|
|
*
|
|
|
|
|
* @component
|
|
|
|
|
* @example
|
|
|
|
|
* ```jsx
|
|
|
|
|
* <EvaluateTaskPersonnelSelector
|
|
|
|
|
* onSelect={(selected) => console.log('已选择人员:', selected)}
|
|
|
|
|
* selectedPersonnel={[]}
|
|
|
|
|
* />
|
|
|
|
|
* ```
|
|
|
|
|
*/
|
|
|
|
|
const EvaluateTaskPersonnelSelector: React.FC<EvaluateTaskPersonnelSelectorProps> = ({
|
|
|
|
|
onSelect,
|
|
|
|
|
selectedPersonnel = []
|
|
|
|
|
}) => {
|
|
|
|
|
// 搜索关键词
|
|
|
|
|
const [keyword, setKeyword] = useState<string>('');
|
2025-06-24 18:58:43 +08:00
|
|
|
|
|
2025-06-23 19:15:13 +08:00
|
|
|
|
// 所有可选人员列表
|
2025-06-24 18:58:43 +08:00
|
|
|
|
const [personnel, setPersonnel] = useState<API.PersonnelItem[]>([]);
|
|
|
|
|
|
2025-06-23 19:15:13 +08:00
|
|
|
|
// 已选择人员ID列表
|
|
|
|
|
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
|
|
|
|
|
|
2025-06-24 18:58:43 +08:00
|
|
|
|
// 加载状态
|
|
|
|
|
const [loading, setLoading] = useState<boolean>(false);
|
|
|
|
|
|
|
|
|
|
// 初始化时根据传入的selectedPersonnel设置选中状态
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
// 直接使用传入的selectedPersonnel更新选中状态
|
|
|
|
|
// 如果为空数组,则清空选择
|
|
|
|
|
const newSelectedIds = selectedPersonnel?.map(item => item.id) || [];
|
|
|
|
|
setSelectedKeys(newSelectedIds);
|
|
|
|
|
}, [selectedPersonnel]); // 依赖selectedPersonnel而不是selectedPersonnelIds
|
2025-06-23 19:15:13 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2025-06-24 18:58:43 +08:00
|
|
|
|
* 从API获取用户列表数据
|
2025-06-23 19:15:13 +08:00
|
|
|
|
*/
|
2025-06-24 18:58:43 +08:00
|
|
|
|
const fetchPersonnelData = useCallback(async () => {
|
|
|
|
|
setLoading(true);
|
|
|
|
|
try {
|
|
|
|
|
const params: API.UserListRequest = {
|
|
|
|
|
basePageRequest: {
|
|
|
|
|
pageNo: 1,
|
|
|
|
|
pageSize: 100, // 获取足够多的数据
|
|
|
|
|
},
|
|
|
|
|
keyword: keyword || undefined,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const response = await getUserList(params);
|
|
|
|
|
|
|
|
|
|
if (response && response.code === 200 && response.data) {
|
|
|
|
|
const users = response.data as API.UserItem[];
|
|
|
|
|
|
|
|
|
|
// 转换API返回的用户数据为组件所需格式
|
|
|
|
|
const personnelData: API.PersonnelItem[] = users.map((user) => ({
|
|
|
|
|
id: user.userId, // 用户ID
|
|
|
|
|
name: user.userName, // 用户名称
|
|
|
|
|
department: user.userDept, // 用户部门
|
|
|
|
|
position: '', // API中没有提供职位信息
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
setPersonnel(personnelData);
|
|
|
|
|
} else {
|
|
|
|
|
message.error(response?.message || '获取用户列表失败');
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取人员数据失败:', error);
|
|
|
|
|
message.error('获取人员数据失败,请稍后重试');
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
|
|
|
|
}, [keyword]); // 移除selectedPersonnelIds依赖
|
2025-06-23 21:39:51 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2025-06-24 18:58:43 +08:00
|
|
|
|
* 初始化人员数据
|
2025-06-23 21:39:51 +08:00
|
|
|
|
*/
|
|
|
|
|
useEffect(() => {
|
2025-06-24 18:58:43 +08:00
|
|
|
|
// 加载人员数据(API请求)
|
2025-06-23 21:39:51 +08:00
|
|
|
|
fetchPersonnelData();
|
2025-06-24 18:58:43 +08:00
|
|
|
|
}, [fetchPersonnelData]);
|
2025-06-23 19:15:13 +08:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理搜索
|
|
|
|
|
* @param {string} value - 搜索关键词
|
|
|
|
|
*/
|
2025-06-24 18:58:43 +08:00
|
|
|
|
const handleSearch = (value: string) => {
|
2025-06-23 19:15:13 +08:00
|
|
|
|
setKeyword(value);
|
2025-06-24 18:58:43 +08:00
|
|
|
|
};
|
2025-06-23 19:15:13 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2025-06-24 18:58:43 +08:00
|
|
|
|
* 处理行选择变化
|
|
|
|
|
* @param {string[]} selectedRowKeys - 选中的行keys
|
|
|
|
|
* @param {API.PersonnelItem[]} selectedRows - 选中的行数据
|
2025-06-23 19:15:13 +08:00
|
|
|
|
*/
|
2025-06-24 18:58:43 +08:00
|
|
|
|
const handleSelectChange = (selectedRowKeys: React.Key[], selectedRows: API.PersonnelItem[]) => {
|
|
|
|
|
setSelectedKeys(selectedRowKeys as string[]);
|
|
|
|
|
};
|
2025-06-23 19:15:13 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2025-06-24 18:58:43 +08:00
|
|
|
|
* 处理确认选择
|
2025-06-23 19:15:13 +08:00
|
|
|
|
*/
|
2025-06-24 18:58:43 +08:00
|
|
|
|
const handleConfirm = () => {
|
|
|
|
|
// 根据选中的ID筛选出完整的人员数据
|
|
|
|
|
const selectedData = personnel.filter(item => selectedKeys.includes(item.id));
|
|
|
|
|
|
|
|
|
|
// 回调传递给父组件
|
|
|
|
|
onSelect(selectedData);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 表格列定义
|
|
|
|
|
const columns = [
|
|
|
|
|
{
|
|
|
|
|
title: '姓名', // 列标题
|
|
|
|
|
dataIndex: 'name', // 数据字段名
|
|
|
|
|
key: 'name', // 列唯一标识
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '部门',
|
|
|
|
|
dataIndex: 'department',
|
|
|
|
|
key: 'department',
|
|
|
|
|
},
|
|
|
|
|
];
|
2025-06-23 19:15:13 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="evaluate-task-personnel-selector">
|
|
|
|
|
<div className="selector-header">
|
2025-06-24 18:58:43 +08:00
|
|
|
|
<div className="search-bar">
|
|
|
|
|
<Search
|
|
|
|
|
placeholder="请输入姓名搜索"
|
|
|
|
|
onSearch={handleSearch}
|
|
|
|
|
enterButton={<Button icon={<SearchOutlined />}>搜索</Button>}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2025-06-23 19:15:13 +08:00
|
|
|
|
<div className="selected-count">
|
2025-06-24 18:58:43 +08:00
|
|
|
|
已选择: <span className="count">{selectedKeys.length}</span> 人
|
2025-06-23 19:15:13 +08:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-06-24 18:58:43 +08:00
|
|
|
|
<Table
|
|
|
|
|
rowSelection={{
|
|
|
|
|
selectedRowKeys: selectedKeys,
|
|
|
|
|
onChange: handleSelectChange,
|
|
|
|
|
}}
|
|
|
|
|
columns={columns}
|
|
|
|
|
dataSource={personnel}
|
|
|
|
|
rowKey="id"
|
|
|
|
|
size="small"
|
|
|
|
|
loading={loading}
|
|
|
|
|
pagination={{ pageSize: 10 }}
|
|
|
|
|
/>
|
2025-06-23 19:15:13 +08:00
|
|
|
|
<div className="selector-footer">
|
2025-06-24 18:58:43 +08:00
|
|
|
|
<Space>
|
|
|
|
|
<Button onClick={() => setSelectedKeys([])}>清空</Button>
|
|
|
|
|
<Button type="primary" onClick={handleConfirm}>
|
|
|
|
|
确定
|
|
|
|
|
</Button>
|
|
|
|
|
</Space>
|
2025-06-23 19:15:13 +08:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default EvaluateTaskPersonnelSelector;
|