import { ProTable, ProTableProps } from '@ant-design/pro-components'; import type { ParamsType } from '@ant-design/pro-provider'; import { Modal, ModalProps, type TableProps } from 'antd'; import React, { forwardRef, useEffect, useImperativeHandle, useState, } from 'react'; export interface ISelectModalProps< DataType extends Record, Params extends ParamsType = ParamsType, > { rowKey: string; type: 'checkbox' | 'radio' | undefined; onFinish: (selectId: DataType[]) => void; num?: number; selectedList?: DataType[]; modalProps: ModalProps; tableProps: ProTableProps; ghost?: boolean; disabled?: (record: DataType) => boolean; } export type SelectModalHandle = { onFinish: () => void; getSelectedList: () => DataType[]; }; const SelectModal = forwardRef< SelectModalHandle, ISelectModalProps >( < DataType extends Record, Params extends ParamsType = ParamsType, >( props: ISelectModalProps, ref: React.Ref>, ) => { const { rowKey, type: selectType, num, onFinish, modalProps, tableProps, ghost = false, disabled, } = props; const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [selectedList, setSelectedList] = useState([]); const [open, setOpen] = useState(); useEffect(() => { setOpen(modalProps?.open); }, [modalProps?.open]); useImperativeHandle(ref, () => ({ getSelectedList: () => selectedList, onFinish: () => { onFinish(selectedList); if (!selectedList || selectedList.length === 0) { return; } setSelectedRowKeys([]); setSelectedList([]); setOpen(false); }, })); useEffect(() => { const initSelectedList = props.selectedList; if (initSelectedList) { setSelectedRowKeys( initSelectedList?.map((v) => { return v?.[rowKey] || ''; }), ); setSelectedList(initSelectedList); } else { setSelectedRowKeys([]); setSelectedList([]); } }, [props.selectedList]); const rowSelection: TableProps['rowSelection'] = { selectedRowKeys, preserveSelectedRowKeys: true, type: selectType || 'checkbox', onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => { const dataTypes = [...selectedList, ...selectedRows]; const newSelectList = selectedRowKeys .map((v) => dataTypes.find((item: DataType) => { return item?.[rowKey] === v; }), ) .filter((item) => item !== undefined); setSelectedRowKeys(selectedRowKeys.slice(0, num || 1)); setSelectedList(newSelectList.slice(0, num || 1) as any); }, getCheckboxProps: (record: DataType) => ({ disabled: ((selectType || 'checkbox') === 'checkbox' && selectedList.length >= (num || 1) && !selectedRowKeys.includes(record?.[rowKey] || '')) || disabled?.(record), }), }; const renderTable = () => { return ( ghost={true} search={false} scroll={{ x: 'max-content' }} onRow={(data) => ({ onClick: () => { if (disabled?.(data)) { return; } if (selectType === 'radio') { setSelectedRowKeys([data[rowKey]]); setSelectedList([data]); } if (selectType === 'checkbox') { if (selectedList.length >= (num || 1)) { return; } if (selectedRowKeys.length === 0) { setSelectedRowKeys([data[rowKey]]); setSelectedList([data]); } else { if (selectedRowKeys.includes(data[rowKey])) { setSelectedRowKeys( selectedRowKeys .filter((v) => v !== data[rowKey]) .slice(0, num || 1), ); setSelectedList( selectedList .filter((v) => v?.[rowKey] !== data[rowKey]) .slice(0, num || 1), ); } else { setSelectedRowKeys( [...selectedRowKeys, data[rowKey]].slice(0, num || 1), ); setSelectedList([...selectedList, data].slice(0, num || 1)); } } } if (ghost) { onFinish([data]); } }, })} rowSelection={rowSelection} {...tableProps} /> ); }; if (ghost) { return renderTable(); } return ( { onFinish(selectedList); if (!selectedList || selectedList.length === 0) { return; } modalProps.onOk?.(event); if (selectedList && !modalProps.open) { setSelectedRowKeys([]); setSelectedList([]); } }} > {renderTable()} ); }, ) as < DataType extends Record, Params extends ParamsType = ParamsType, >( props: ISelectModalProps & React.RefAttributes, ) => JSX.Element; export default SelectModal;