186 lines
5.5 KiB
TypeScript
186 lines
5.5 KiB
TypeScript
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
||
import { Table, Input, Button, Space, message } from 'antd';
|
||
import { SearchOutlined } from '@ant-design/icons';
|
||
import { getUserList } from '@/servers/api/user';
|
||
import './EvaluateTaskPersonnelSelector.less';
|
||
|
||
const { Search } = Input;
|
||
|
||
/**
|
||
* 评价任务人员选择组件属性接口
|
||
* @interface EvaluateTaskPersonnelSelectorProps
|
||
* @property {Function} onSelect - 选择确认后的回调函数,返回所选人员数组
|
||
* @property {API.PersonnelItem[]} selectedPersonnel - 已选择的人员列表
|
||
*/
|
||
interface EvaluateTaskPersonnelSelectorProps {
|
||
onSelect: (personnel: API.PersonnelItem[]) => void; // 选择确认后的回调函数
|
||
selectedPersonnel?: API.PersonnelItem[]; // 已选择的人员列表(用于回显)
|
||
}
|
||
|
||
/**
|
||
* 评价任务人员选择组件
|
||
* 用于在评价任务管理中选择评价人员,显示为简单表格
|
||
*
|
||
* @component
|
||
* @example
|
||
* ```jsx
|
||
* <EvaluateTaskPersonnelSelector
|
||
* onSelect={(selected) => console.log('已选择人员:', selected)}
|
||
* selectedPersonnel={[]}
|
||
* />
|
||
* ```
|
||
*/
|
||
const EvaluateTaskPersonnelSelector: React.FC<EvaluateTaskPersonnelSelectorProps> = ({
|
||
onSelect,
|
||
selectedPersonnel = []
|
||
}) => {
|
||
// 搜索关键词
|
||
const [keyword, setKeyword] = useState<string>('');
|
||
|
||
// 所有可选人员列表
|
||
const [personnel, setPersonnel] = useState<API.PersonnelItem[]>([]);
|
||
|
||
// 已选择人员ID列表
|
||
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
|
||
|
||
// 加载状态
|
||
const [loading, setLoading] = useState<boolean>(false);
|
||
|
||
// 初始化时根据传入的selectedPersonnel设置选中状态
|
||
useEffect(() => {
|
||
// 直接使用传入的selectedPersonnel更新选中状态
|
||
// 如果为空数组,则清空选择
|
||
const newSelectedIds = selectedPersonnel?.map(item => item.id) || [];
|
||
setSelectedKeys(newSelectedIds);
|
||
}, [selectedPersonnel]); // 依赖selectedPersonnel而不是selectedPersonnelIds
|
||
|
||
/**
|
||
* 从API获取用户列表数据
|
||
*/
|
||
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依赖
|
||
|
||
/**
|
||
* 初始化人员数据
|
||
*/
|
||
useEffect(() => {
|
||
// 加载人员数据(API请求)
|
||
fetchPersonnelData();
|
||
}, [fetchPersonnelData]);
|
||
|
||
/**
|
||
* 处理搜索
|
||
* @param {string} value - 搜索关键词
|
||
*/
|
||
const handleSearch = (value: string) => {
|
||
setKeyword(value);
|
||
};
|
||
|
||
/**
|
||
* 处理行选择变化
|
||
* @param {string[]} selectedRowKeys - 选中的行keys
|
||
* @param {API.PersonnelItem[]} selectedRows - 选中的行数据
|
||
*/
|
||
const handleSelectChange = (selectedRowKeys: React.Key[], selectedRows: API.PersonnelItem[]) => {
|
||
setSelectedKeys(selectedRowKeys as string[]);
|
||
};
|
||
|
||
/**
|
||
* 处理确认选择
|
||
*/
|
||
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',
|
||
},
|
||
];
|
||
|
||
|
||
return (
|
||
<div className="evaluate-task-personnel-selector">
|
||
<div className="selector-header">
|
||
<div className="search-bar">
|
||
<Search
|
||
placeholder="请输入姓名搜索"
|
||
onSearch={handleSearch}
|
||
enterButton={<Button icon={<SearchOutlined />}>搜索</Button>}
|
||
/>
|
||
</div>
|
||
<div className="selected-count">
|
||
已选择: <span className="count">{selectedKeys.length}</span> 人
|
||
</div>
|
||
</div>
|
||
<Table
|
||
rowSelection={{
|
||
selectedRowKeys: selectedKeys,
|
||
onChange: handleSelectChange,
|
||
}}
|
||
columns={columns}
|
||
dataSource={personnel}
|
||
rowKey="id"
|
||
size="small"
|
||
loading={loading}
|
||
pagination={{ pageSize: 10 }}
|
||
/>
|
||
<div className="selector-footer">
|
||
<Space>
|
||
<Button onClick={() => setSelectedKeys([])}>清空</Button>
|
||
<Button type="primary" onClick={handleConfirm}>
|
||
确定
|
||
</Button>
|
||
</Space>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default EvaluateTaskPersonnelSelector;
|