Files
fe_supplier_frontend/src/components/SupplierSelector/SupplierSelector.tsx

358 lines
10 KiB
TypeScript
Raw Normal View History

import React, { useState, useEffect } from 'react';
import { Input, Select, Row, Col, Table, Button, Form, Tooltip, message } from 'antd';
import { RightOutlined, LeftOutlined } from '@ant-design/icons';
import { getSupplierPage } from '@/servers/api/supplier';
2025-06-24 18:58:43 +08:00
import CategorySelector from '@/components/CategorySelector/CategorySelector';
import './SupplierSelector.less';
const { Option } = Select;
/**
* SupplierSelector
* @interface SupplierSelectorProps
* @property {Function} [onSelect] -
* @property {any[]} [selectedSuppliers] -
*/
interface SupplierSelectorProps {
onSelect?: (selected: any[]) => void;
selectedSuppliers?: any[];
}
/**
* SupplierPageVo
* @interface SupplierItem
* @property {string} id - ID
* @property {string} name -
* @property {string} [deptId] - ID
* @property {string} [deptName] -
* @property {string} [companyName] -
* @property {string} [categoryName] -
* @property {string} [levelName] -
* @property {Date} [admissionTime] -
* @property {Date} [evaluationTime] -
* @property {any} [key: string] -
*/
interface SupplierItem {
id: string;
name: string;
deptId?: string;
deptName?: string;
companyName?: string;
categoryName?: string;
levelName?: string;
admissionTime?: Date;
evaluationTime?: Date;
[key: string]: any;
}
/**
*
*
*
* @param {SupplierSelectorProps} props -
* @returns {React.ReactElement}
*/
const SupplierSelector: React.FC<SupplierSelectorProps> = ({
onSelect,
selectedSuppliers: initialSelectedSuppliers = [],
}) => {
// 表单实例,用于管理查询条件
const [form] = Form.useForm();
// 待选供应商数据列表
const [tableListData, setTableListData] = useState<SupplierItem[]>([]);
// 分页信息
const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 });
// 加载状态
const [loading, setLoading] = useState(false);
// 左侧待选列表中已选中的项的ID
const [leftSelected, setLeftSelected] = useState<React.Key[]>([]);
// 右侧已选列表中选中的项的ID
const [rightSelected, setRightSelected] = useState<React.Key[]>([]);
// 最终已选择的供应商列表
const [chosenSuppliers, setChosenSuppliers] = useState<SupplierItem[]>(initialSelectedSuppliers);
2025-06-24 18:58:43 +08:00
// 查询参数
const [queryParams, setQueryParams] = useState({
pageNo: 1,
pageSize: 10
});
/**
*
*/
useEffect(() => {
setChosenSuppliers(initialSelectedSuppliers);
}, [initialSelectedSuppliers]);
/**
*
* @param {SupplierItem[]} suppliers -
* @param {SupplierItem[]} selected -
* @returns {SupplierItem[]}
*/
const filteredData = (suppliers: SupplierItem[], selected: SupplierItem[]) => {
// 创建已有供应商ID的集合用于快速查找
const ids = new Set(suppliers.map((item: SupplierItem) => item.id));
// 过滤出未在原列表中出现的供应商
const newSelected = selected.filter((item: SupplierItem) => !ids.has(item.id));
// 合并列表
return [...suppliers, ...newSelected];
};
/**
*
*/
const moveToRight = () => {
// 获取左侧选中的供应商数据
const selected = tableListData.filter((item: SupplierItem) => leftSelected.includes(item.id));
// 合并到已选列表并去重
const chosenSuppliersNew = filteredData(chosenSuppliers, selected);
// 更新已选列表
setChosenSuppliers(chosenSuppliersNew);
// 清空左侧选择状态
setLeftSelected([]);
// 触发外部回调
onSelect?.(chosenSuppliersNew);
};
/**
*
*/
const moveToLeft = () => {
// 过滤掉右侧选中的供应商
const remaining = chosenSuppliers.filter((item: SupplierItem) => !rightSelected.includes(item.id));
// 更新已选列表
setChosenSuppliers(remaining);
// 清空右侧选择状态
setRightSelected([]);
// 触发外部回调
onSelect?.(remaining);
};
/**
*
*/
2025-06-24 18:58:43 +08:00
const fetchTableData = async () => {
if (loading) return;
setLoading(true);
try {
// 调用API获取供应商列表
2025-06-24 18:58:43 +08:00
const response = await getSupplierPage(queryParams);
if (response && response.code === 200) {
// 请求成功,更新数据和分页信息
setTableListData(response.data.records.map((item: any) => ({
...item,
supplierName: item.name,
})));
setPagination({
2025-06-24 18:58:43 +08:00
current: queryParams.pageNo,
pageSize: queryParams.pageSize,
total: response.data.total || 0
});
} else {
// 请求失败,显示错误信息
message.error(response?.message || '获取供应商列表失败');
2025-06-24 18:58:43 +08:00
setTableListData([]);
setPagination({ current: 1, pageSize: 10, total: 0 });
}
} catch (error) {
// 处理异常情况
console.error('获取供应商列表出错:', error);
message.error('获取供应商列表失败,请稍后重试');
2025-06-24 18:58:43 +08:00
setTableListData([]);
setPagination({ current: 1, pageSize: 10, total: 0 });
} finally {
setLoading(false);
}
};
/**
2025-06-24 18:58:43 +08:00
*
*/
useEffect(() => {
fetchTableData();
}, [queryParams]);
/**
*
*/
useEffect(() => {
const values = form.getFieldsValue();
2025-06-24 18:58:43 +08:00
setQueryParams(prev => ({
...prev,
...values,
pageNo: 1
}));
}, []); // 空依赖数组,只在组件挂载时执行一次
/**
*
* @param {any} values -
*/
const handleSearch = (values: any) => {
2025-06-24 18:58:43 +08:00
setQueryParams(prev => ({
...prev,
...values,
pageNo: 1
}));
};
/**
*
*/
const handleReset = () => {
form.resetFields();
const values = form.getFieldsValue();
2025-06-24 18:58:43 +08:00
setQueryParams(prev => ({
...prev,
...values,
pageNo: 1
}));
};
/**
*
* @param {any} paginationInfo -
*/
const handleTableChange = (paginationInfo: any) => {
2025-06-24 18:58:43 +08:00
setQueryParams(prev => ({
...prev,
pageNo: paginationInfo.current,
pageSize: paginationInfo.pageSize
}));
};
// 表格列定义
const columns = [
{
title: '供应商名称',
dataIndex: 'supplierName',
ellipsis: true,
render: (supplierName: string) => (
<Tooltip placement="topLeft" title={supplierName}>
{supplierName}
</Tooltip>
),
},
{
title: '统一社会信用代码',
dataIndex: 'socialCreditCode',
ellipsis: true,
render: (socialCreditCode: string) => (
<Tooltip placement="topLeft" title={socialCreditCode}>
{socialCreditCode || '-'}
</Tooltip>
),
},
{
title: '准入品类',
dataIndex: 'categoryName',
ellipsis: true,
render: (categoryName: string) => (
<Tooltip placement="topLeft" title={categoryName}>
{categoryName || '-'}
</Tooltip>
),
2025-06-24 18:58:43 +08:00
},
2025-06-24 18:58:43 +08:00
];
return (
<div className="supplier-selector">
{/* 查询表单 */}
2025-06-24 18:58:43 +08:00
<Form layout="inline" form={form} onFinish={handleSearch} style={{ marginBottom: 30 }}>
<Form.Item name="name" label="供应商名称">
<Input placeholder="供应商名称" allowClear />
</Form.Item>
2025-06-24 18:58:43 +08:00
<Form.Item name="deptId" label="部门">
<Select placeholder="请选择部门" allowClear style={{ width: 150 }}>
<Option value="1"></Option>
<Option value="2"></Option>
<Option value="3"></Option>
</Select>
</Form.Item>
<Form.Item name="categoryId" label="所属品类">
<CategorySelector multiple={false} style={{ width: 150 }} />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit"></Button>
</Form.Item>
<Form.Item>
<Button onClick={handleReset}></Button>
</Form.Item>
</Form>
{/* 供应商选择区域 */}
<Row gutter={16} className="supplier-lists">
{/* 左侧待选列表 */}
<Col span={10}>
<div className="list-title">
<span className="search-count">{pagination.total}</span>
</div>
<Table
rowSelection={{
type: 'checkbox',
onChange: setLeftSelected,
selectedRowKeys: leftSelected
}}
rowKey="id"
dataSource={tableListData}
columns={columns}
loading={loading}
pagination={pagination}
onChange={handleTableChange}
/>
</Col>
{/* 中间操作按钮 */}
<Col span={4} className="transfer-buttons">
<Button
type="primary"
icon={<RightOutlined />}
onClick={moveToRight}
disabled={leftSelected.length === 0}
/>
<Button
icon={<LeftOutlined />}
onClick={moveToLeft}
disabled={rightSelected.length === 0}
/>
</Col>
{/* 右侧已选列表 */}
<Col span={10}>
<div className="list-title">
<span className="search-count">{chosenSuppliers.length}</span>
</div>
<Table
rowSelection={{
type: 'checkbox',
onChange: setRightSelected,
selectedRowKeys: rightSelected
}}
columns={columns}
dataSource={chosenSuppliers}
rowKey="id"
pagination={false}
/>
</Col>
</Row>
</div>
);
};
export default SupplierSelector;