2025-06-23 21:39:51 +08:00
|
|
|
|
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
|
2025-06-23 19:15:13 +08:00
|
|
|
|
import { Card, Row, Col, Input, Select, Radio, Table, Button, Space, Pagination, Form } from 'antd';
|
|
|
|
|
import { SearchOutlined, ArrowRightOutlined } from '@ant-design/icons';
|
|
|
|
|
import styles from '../supplierTaskManageAdd.less';
|
|
|
|
|
|
|
|
|
|
const { Option } = Select;
|
|
|
|
|
|
|
|
|
|
interface SupplierSelectStepProps {
|
|
|
|
|
formData: any;
|
|
|
|
|
onFormDataChange: (data: any) => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface SupplierItem {
|
|
|
|
|
key: string;
|
|
|
|
|
supplierName: string;
|
|
|
|
|
socialCreditCode: string;
|
|
|
|
|
category: string;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-23 21:39:51 +08:00
|
|
|
|
const SupplierSelectStep = forwardRef<any, SupplierSelectStepProps>(({ formData, onFormDataChange }, ref) => {
|
2025-06-23 19:15:13 +08:00
|
|
|
|
const [filterForm] = Form.useForm();
|
|
|
|
|
const [categoryKeyword, setCategoryKeyword] = useState<string>('');
|
|
|
|
|
const [selectedCategory, setSelectedCategory] = useState<string | undefined>(undefined);
|
|
|
|
|
const [hasPaymentLastYear, setHasPaymentLastYear] = useState<string>('是');
|
|
|
|
|
const [department, setDepartment] = useState<string | undefined>(undefined);
|
|
|
|
|
|
|
|
|
|
const [pendingSuppliers, setPendingSuppliers] = useState<SupplierItem[]>([]);
|
|
|
|
|
const [selectedSuppliers, setSelectedSuppliers] = useState<SupplierItem[]>([]);
|
|
|
|
|
|
|
|
|
|
const [pendingKeyword, setPendingKeyword] = useState<string>('');
|
|
|
|
|
const [selectedKeyword, setSelectedKeyword] = useState<string>('');
|
|
|
|
|
|
|
|
|
|
const [pendingSelectedRowKeys, setPendingSelectedRowKeys] = useState<React.Key[]>([]);
|
|
|
|
|
const [selectedSelectedRowKeys, setSelectedSelectedRowKeys] = useState<React.Key[]>([]);
|
|
|
|
|
|
2025-06-23 21:39:51 +08:00
|
|
|
|
// 暴露表单方法给父组件
|
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
|
|
|
validateFields: () => {
|
|
|
|
|
// 这里可以添加自定义验证逻辑
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
},
|
|
|
|
|
getFieldsValue: () => {
|
|
|
|
|
return {
|
|
|
|
|
selectedSuppliers,
|
|
|
|
|
supplierIds: selectedSuppliers.map(supplier => ({ id: supplier.key }))
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
setFieldsValue: (values: any) => {
|
|
|
|
|
if (values.selectedSuppliers) {
|
|
|
|
|
setSelectedSuppliers(values.selectedSuppliers);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}));
|
|
|
|
|
|
2025-06-23 19:15:13 +08:00
|
|
|
|
// 初始化数据
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
// 从formData中恢复已选供应商
|
|
|
|
|
if (formData.selectedSuppliers) {
|
|
|
|
|
setSelectedSuppliers(formData.selectedSuppliers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 初始化筛选表单
|
|
|
|
|
filterForm.setFieldsValue({
|
|
|
|
|
category: selectedCategory,
|
|
|
|
|
categoryKeyword: categoryKeyword,
|
|
|
|
|
categoryRange: undefined,
|
|
|
|
|
hasPaymentLastYear: hasPaymentLastYear,
|
|
|
|
|
department: department
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 模拟获取待选供应商列表
|
|
|
|
|
const mockPendingSuppliers: SupplierItem[] = [
|
|
|
|
|
{ key: '1', supplierName: '供应商A', socialCreditCode: '2425322525', category: '润滑油' },
|
|
|
|
|
{ key: '2', supplierName: '供应商B', socialCreditCode: '2425322525', category: '燃油' },
|
|
|
|
|
{ key: '3', supplierName: '供应商C', socialCreditCode: '2425322525', category: '备件' },
|
|
|
|
|
{ key: '4', supplierName: '供应商D', socialCreditCode: '2425322525', category: '润滑油' },
|
|
|
|
|
{ key: '5', supplierName: '供应商E', socialCreditCode: '2425322525', category: '燃油' },
|
|
|
|
|
{ key: '6', supplierName: '供应商F', socialCreditCode: '2425322525', category: '备件' },
|
|
|
|
|
{ key: '7', supplierName: '供应商G', socialCreditCode: '2425322525', category: '润滑油' },
|
|
|
|
|
{ key: '8', supplierName: '供应商H', socialCreditCode: '2425322525', category: '燃油' },
|
|
|
|
|
{ key: '9', supplierName: '供应商I', socialCreditCode: '2425322525', category: '备件' },
|
|
|
|
|
{ key: '10', supplierName: '供应商J', socialCreditCode: '2425322525', category: '计算机' },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 模拟已选供应商列表
|
|
|
|
|
const mockSelectedSuppliers: SupplierItem[] = [
|
|
|
|
|
{ key: '11', supplierName: '供应商A', socialCreditCode: '4636373737', category: '润滑油' },
|
|
|
|
|
{ key: '12', supplierName: '供应商B', socialCreditCode: '4636373737', category: '燃油' },
|
|
|
|
|
{ key: '13', supplierName: '供应商C', socialCreditCode: '4636373737', category: '备件' },
|
|
|
|
|
{ key: '14', supplierName: '供应商D', socialCreditCode: '4636373737', category: '润滑油' },
|
|
|
|
|
{ key: '15', supplierName: '供应商E', socialCreditCode: '4636373737', category: '燃油' },
|
|
|
|
|
{ key: '16', supplierName: '供应商F', socialCreditCode: '4636373737', category: '备件' },
|
|
|
|
|
{ key: '17', supplierName: '供应商G', socialCreditCode: '4636373737', category: '润滑油' },
|
|
|
|
|
{ key: '18', supplierName: '供应商H', socialCreditCode: '4636373737', category: '燃油' },
|
|
|
|
|
{ key: '19', supplierName: '供应商I', socialCreditCode: '4636373737', category: '备件' },
|
|
|
|
|
{ key: '20', supplierName: '供应商J', socialCreditCode: '4636373737', category: '计算机' },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
setPendingSuppliers(mockPendingSuppliers);
|
|
|
|
|
|
|
|
|
|
// 如果没有从formData中恢复,则使用模拟数据
|
|
|
|
|
if (!formData.selectedSuppliers) {
|
|
|
|
|
setSelectedSuppliers(mockSelectedSuppliers);
|
|
|
|
|
}
|
|
|
|
|
}, [formData]);
|
|
|
|
|
|
|
|
|
|
// 更新表单数据
|
|
|
|
|
const updateFormData = (suppliers: SupplierItem[]) => {
|
2025-06-23 21:39:51 +08:00
|
|
|
|
onFormDataChange({
|
|
|
|
|
selectedSuppliers: suppliers,
|
|
|
|
|
supplierIds: suppliers.map(supplier => ({ id: supplier.key }))
|
|
|
|
|
});
|
2025-06-23 19:15:13 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 处理筛选条件变化
|
|
|
|
|
const handleFilterChange = (changedValues: any, allValues: any) => {
|
|
|
|
|
if ('category' in changedValues) {
|
|
|
|
|
setSelectedCategory(changedValues.category);
|
|
|
|
|
}
|
|
|
|
|
if ('categoryKeyword' in changedValues) {
|
|
|
|
|
setCategoryKeyword(changedValues.categoryKeyword);
|
|
|
|
|
}
|
|
|
|
|
if ('hasPaymentLastYear' in changedValues) {
|
|
|
|
|
setHasPaymentLastYear(changedValues.hasPaymentLastYear);
|
|
|
|
|
}
|
|
|
|
|
if ('department' in changedValues) {
|
|
|
|
|
setDepartment(changedValues.department);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 这里可以添加筛选逻辑,根据筛选条件更新待选供应商列表
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 处理添加供应商
|
|
|
|
|
const handleAddSuppliers = () => {
|
|
|
|
|
if (pendingSelectedRowKeys.length === 0) return;
|
|
|
|
|
|
|
|
|
|
// 找出选中的供应商
|
|
|
|
|
const suppliersToAdd = pendingSuppliers.filter(item =>
|
|
|
|
|
pendingSelectedRowKeys.includes(item.key)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// 更新已选供应商列表
|
|
|
|
|
const newSelectedSuppliers = [...selectedSuppliers, ...suppliersToAdd];
|
|
|
|
|
setSelectedSuppliers(newSelectedSuppliers);
|
|
|
|
|
|
|
|
|
|
// 从待选列表中移除
|
|
|
|
|
const newPendingSuppliers = pendingSuppliers.filter(item =>
|
|
|
|
|
!pendingSelectedRowKeys.includes(item.key)
|
|
|
|
|
);
|
|
|
|
|
setPendingSuppliers(newPendingSuppliers);
|
|
|
|
|
|
|
|
|
|
// 清空选中状态
|
|
|
|
|
setPendingSelectedRowKeys([]);
|
|
|
|
|
|
|
|
|
|
// 更新表单数据
|
|
|
|
|
updateFormData(newSelectedSuppliers);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 处理移除供应商
|
|
|
|
|
const handleRemoveSuppliers = () => {
|
|
|
|
|
if (selectedSelectedRowKeys.length === 0) return;
|
|
|
|
|
|
|
|
|
|
// 找出选中的供应商
|
|
|
|
|
const suppliersToRemove = selectedSuppliers.filter(item =>
|
|
|
|
|
selectedSelectedRowKeys.includes(item.key)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// 更新待选供应商列表
|
|
|
|
|
const newPendingSuppliers = [...pendingSuppliers, ...suppliersToRemove];
|
|
|
|
|
setPendingSuppliers(newPendingSuppliers);
|
|
|
|
|
|
|
|
|
|
// 从已选列表中移除
|
|
|
|
|
const newSelectedSuppliers = selectedSuppliers.filter(item =>
|
|
|
|
|
!selectedSelectedRowKeys.includes(item.key)
|
|
|
|
|
);
|
|
|
|
|
setSelectedSuppliers(newSelectedSuppliers);
|
|
|
|
|
|
|
|
|
|
// 清空选中状态
|
|
|
|
|
setSelectedSelectedRowKeys([]);
|
|
|
|
|
|
|
|
|
|
// 更新表单数据
|
|
|
|
|
updateFormData(newSelectedSuppliers);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 过滤待选供应商
|
|
|
|
|
const filteredPendingSuppliers = pendingSuppliers.filter(item => {
|
|
|
|
|
// 按关键词过滤
|
|
|
|
|
const matchKeyword = pendingKeyword ?
|
|
|
|
|
(item.supplierName.includes(pendingKeyword) ||
|
|
|
|
|
item.socialCreditCode.includes(pendingKeyword)) : true;
|
|
|
|
|
|
|
|
|
|
return matchKeyword;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 过滤已选供应商
|
|
|
|
|
const filteredSelectedSuppliers = selectedSuppliers.filter(item => {
|
|
|
|
|
// 按关键词过滤
|
|
|
|
|
const matchKeyword = selectedKeyword ?
|
|
|
|
|
(item.supplierName.includes(selectedKeyword) ||
|
|
|
|
|
item.socialCreditCode.includes(selectedKeyword)) : true;
|
|
|
|
|
|
|
|
|
|
return matchKeyword;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 表格列定义
|
|
|
|
|
const columns = [
|
|
|
|
|
{
|
|
|
|
|
title: '供应商名称',
|
|
|
|
|
dataIndex: 'supplierName',
|
|
|
|
|
key: 'supplierName',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '统一社会信用代码',
|
|
|
|
|
dataIndex: 'socialCreditCode',
|
|
|
|
|
key: 'socialCreditCode',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '准入品类',
|
|
|
|
|
dataIndex: 'category',
|
|
|
|
|
key: 'category',
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 待选表格行选择配置
|
|
|
|
|
const pendingRowSelection = {
|
|
|
|
|
selectedRowKeys: pendingSelectedRowKeys,
|
|
|
|
|
onChange: (selectedRowKeys: React.Key[]) => {
|
|
|
|
|
setPendingSelectedRowKeys(selectedRowKeys);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 已选表格行选择配置
|
|
|
|
|
const selectedRowSelection = {
|
|
|
|
|
selectedRowKeys: selectedSelectedRowKeys,
|
|
|
|
|
onChange: (selectedRowKeys: React.Key[]) => {
|
|
|
|
|
setSelectedSelectedRowKeys(selectedRowKeys);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 部门选项
|
|
|
|
|
const departmentOptions = [
|
|
|
|
|
{ value: '1', label: '采购部' },
|
|
|
|
|
{ value: '2', label: '技术部' },
|
|
|
|
|
{ value: '3', label: '质量部' },
|
|
|
|
|
{ value: '4', label: '生产部' },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 类别选项
|
|
|
|
|
const categoryOptions = [
|
|
|
|
|
{ value: '润滑油', label: '润滑油' },
|
|
|
|
|
{ value: '燃油', label: '燃油' },
|
|
|
|
|
{ value: '备件', label: '备件' },
|
|
|
|
|
{ value: '计算机', label: '计算机' },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className={styles.supplierSelectStep}>
|
|
|
|
|
<Card title="筛选条件" bordered={false} className="inner-card">
|
|
|
|
|
<Form
|
|
|
|
|
form={filterForm}
|
|
|
|
|
layout="horizontal"
|
|
|
|
|
labelCol={{ span: 6 }}
|
|
|
|
|
wrapperCol={{ span: 18 }}
|
|
|
|
|
onValuesChange={handleFilterChange}
|
|
|
|
|
>
|
|
|
|
|
<Row gutter={24}>
|
2025-06-23 21:39:51 +08:00
|
|
|
|
<Col span={8}>
|
2025-06-23 19:15:13 +08:00
|
|
|
|
<Form.Item label="选择类别" name="category">
|
|
|
|
|
<Select
|
|
|
|
|
placeholder="请选择"
|
|
|
|
|
allowClear
|
|
|
|
|
>
|
|
|
|
|
{categoryOptions.map(option => (
|
|
|
|
|
<Option key={option.value} value={option.value}>{option.label}</Option>
|
|
|
|
|
))}
|
|
|
|
|
</Select>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
2025-06-23 21:39:51 +08:00
|
|
|
|
<Col span={8}>
|
2025-06-23 19:15:13 +08:00
|
|
|
|
<Form.Item label="品类关键字" name="categoryKeyword">
|
|
|
|
|
<Input placeholder="请输入" allowClear />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
2025-06-23 21:39:51 +08:00
|
|
|
|
<Col span={8}>
|
2025-06-23 19:15:13 +08:00
|
|
|
|
<Form.Item label="品类范围" name="categoryRange">
|
|
|
|
|
<Input placeholder="请输入" allowClear />
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
2025-06-23 21:39:51 +08:00
|
|
|
|
<Col span={8}>
|
2025-06-23 19:15:13 +08:00
|
|
|
|
<Form.Item label="近一年有付款" name="hasPaymentLastYear" initialValue="是">
|
|
|
|
|
<Radio.Group>
|
|
|
|
|
<Radio value="是">是</Radio>
|
|
|
|
|
<Radio value="否">否</Radio>
|
|
|
|
|
</Radio.Group>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
2025-06-23 21:39:51 +08:00
|
|
|
|
<Col span={8}>
|
2025-06-23 19:15:13 +08:00
|
|
|
|
<Form.Item label="准入部门" name="department">
|
|
|
|
|
<Select
|
|
|
|
|
placeholder="请选择"
|
|
|
|
|
allowClear
|
|
|
|
|
>
|
|
|
|
|
{departmentOptions.map(option => (
|
|
|
|
|
<Option key={option.value} value={option.value}>{option.label}</Option>
|
|
|
|
|
))}
|
|
|
|
|
</Select>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
2025-06-23 21:39:51 +08:00
|
|
|
|
<Col span={8}>
|
2025-06-23 19:15:13 +08:00
|
|
|
|
<Form.Item wrapperCol={{ offset: 6, span: 18 }}>
|
|
|
|
|
<Button type="primary" onClick={() => filterForm.submit()}>
|
|
|
|
|
查询
|
|
|
|
|
</Button>
|
|
|
|
|
<Button style={{ marginLeft: 8 }} onClick={() => filterForm.resetFields()}>
|
|
|
|
|
重置
|
|
|
|
|
</Button>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
|
|
|
|
</Row>
|
|
|
|
|
</Form>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
<Row gutter={24} style={{ marginTop: '16px' }}>
|
|
|
|
|
<Col span={11}>
|
|
|
|
|
<Card
|
|
|
|
|
title="待选列表"
|
|
|
|
|
bordered={false}
|
|
|
|
|
className="inner-card"
|
|
|
|
|
extra={<span>2/50项</span>}
|
|
|
|
|
>
|
|
|
|
|
<div className="search-bar">
|
|
|
|
|
<Input
|
|
|
|
|
placeholder="输入关键词"
|
|
|
|
|
prefix={<SearchOutlined />}
|
|
|
|
|
value={pendingKeyword}
|
|
|
|
|
onChange={e => setPendingKeyword(e.target.value)}
|
|
|
|
|
allowClear
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<Table
|
|
|
|
|
rowSelection={pendingRowSelection}
|
|
|
|
|
columns={columns}
|
|
|
|
|
dataSource={filteredPendingSuppliers}
|
|
|
|
|
pagination={false}
|
|
|
|
|
size="middle"
|
|
|
|
|
rowKey="key"
|
|
|
|
|
/>
|
|
|
|
|
<div className="pagination-container">
|
|
|
|
|
<Pagination
|
|
|
|
|
size="small"
|
|
|
|
|
total={50}
|
|
|
|
|
current={1}
|
|
|
|
|
pageSize={10}
|
|
|
|
|
showSizeChanger={false}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</Card>
|
|
|
|
|
</Col>
|
|
|
|
|
<Col span={2} style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
|
|
|
|
<Space direction="vertical">
|
|
|
|
|
<Button
|
|
|
|
|
type="primary"
|
|
|
|
|
icon={<ArrowRightOutlined />}
|
|
|
|
|
onClick={handleAddSuppliers}
|
|
|
|
|
disabled={pendingSelectedRowKeys.length === 0}
|
|
|
|
|
/>
|
|
|
|
|
<Button
|
|
|
|
|
icon={<ArrowRightOutlined style={{ transform: 'rotate(180deg)' }} />}
|
|
|
|
|
onClick={handleRemoveSuppliers}
|
|
|
|
|
disabled={selectedSelectedRowKeys.length === 0}
|
|
|
|
|
/>
|
|
|
|
|
</Space>
|
|
|
|
|
</Col>
|
|
|
|
|
<Col span={11}>
|
|
|
|
|
<Card
|
|
|
|
|
title="已选列表"
|
|
|
|
|
bordered={false}
|
|
|
|
|
className="inner-card"
|
|
|
|
|
extra={<span>2/50项</span>}
|
|
|
|
|
>
|
|
|
|
|
<div className="search-bar">
|
|
|
|
|
<Input
|
|
|
|
|
placeholder="输入关键词"
|
|
|
|
|
prefix={<SearchOutlined />}
|
|
|
|
|
value={selectedKeyword}
|
|
|
|
|
onChange={e => setSelectedKeyword(e.target.value)}
|
|
|
|
|
allowClear
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<Table
|
|
|
|
|
rowSelection={selectedRowSelection}
|
|
|
|
|
columns={columns}
|
|
|
|
|
dataSource={filteredSelectedSuppliers}
|
|
|
|
|
pagination={false}
|
|
|
|
|
size="middle"
|
|
|
|
|
rowKey="key"
|
|
|
|
|
/>
|
|
|
|
|
<div className="pagination-container">
|
|
|
|
|
<Pagination
|
|
|
|
|
size="small"
|
|
|
|
|
total={50}
|
|
|
|
|
current={1}
|
|
|
|
|
pageSize={10}
|
|
|
|
|
showSizeChanger={false}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</Card>
|
|
|
|
|
</Col>
|
|
|
|
|
</Row>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2025-06-23 21:39:51 +08:00
|
|
|
|
});
|
2025-06-23 19:15:13 +08:00
|
|
|
|
|
|
|
|
|
export default SupplierSelectStep;
|