组件按照功能拆分为三个组件
TableFilter组件ToolBar组件antd中的table组件
TableFilter主要实现的功能为根据columns参数,来动态配置需要作为条件筛选的参数,从而实现对表格数据的多重筛选功能,以及点击查询和重置按钮的功能
ToolBar实现的功能为配置表格名称,表格按钮,工具栏等相关
ProTable组件
const {
columns,
disabled = false,
expandButton,
extraParams = {},
pagination = {},
title = undefined,
dataSource = [],
request = () => {},
options = {
size: false, // 控制表格size
list: false, // 选择控制表格显示列数
fullScreen: false, //控制表格全屏显示
},
...rest
} = props;
const [searchProps, setSearchProps] = useState({}); //用于记录filter组件搜索字段,方便切换分页保存搜索条件
//用于控制保存工具栏中列表列数选项状态,保存全屏状态以及保存表格密度状态
const [toolBarProps, setToolBarProps] = useState({
fullScreen: false,
headerList: columns
?.filter((item: any) => !item?.hidden)
?.map((item: any) => item?.title), // 控制表单可选展示列
density: 'default',
}) as any;
const onChangeToolBar: any = (value: any) => {
setToolBarProps(value);
};
const myColumns = useMemo(() => {
return columns?.filter((item: any) =>
toolBarProps.headerList?.some((o: any) => o === item?.title),
);
}, [toolBarProps]);
const onFinish = (v: any) => {
setSearchProps({
...searchProps,
...v,
});
request({
...extraParams,
...searchProps,
...v,
pageNum: v?.pageNum || 1,
});
};
const refresh = () => {
setSearchProps({});
request(extraParams);
};
const uniqueFunc = (arr: any[], uniId: string | number) => {
const res = new Map();
return (
arr?.filter((item) => !res.has(item[uniId]) && res.set(item[uniId], 1)) ||
[]
);
};
return (
<div id="proTableId">
<TableFilter
columns={columns}
onFinish={onFinish}
refresh={refresh}
disabled={disabled}
/>
<ToolBar
columns={columns}
options={options}
onChangeToolBar={onChangeToolBar}
value={toolBarProps}
title={title}
expandButton={expandButton}
/>
<Table
columns={myColumns}
pagination={{
...pagination,
onChange: (pageNum, pageSize) => {
if (pagination?.onChange) {
pagination.onChange(pageNum, pageSize);
} else {
onFinish({ pageNum, pageSize });
}
},
}}
size={rest?.size || toolBarProps?.density}
rowKey={'id'}
{...rest}
dataSource={uniqueFunc(dataSource, 'id')}
/>
</div>
);
TableFilter组件
const TableFilter: FC<TableFilterProps> = ({
columns = [],
onFinish = () => {},
initialValues = {},
disabled = false,
expandButton = () => {},
refresh = () => {},
loading = false,
datePickerFooterText = '',
}) => {
const [form] = Form.useForm();
const getComponent = (item: any) => {
if (item?.searchOptions && item?.searchOptions?.length) {
return (
<Select allowClear placeholder="请选择" options={item?.searchOptions} />
);
}
if (item?.dateTime) {
return (
<DatePicker
style={{ width: '100%' }}
format="YYYY-MM-DD HH:mm:ss"
showTime={showTime}
renderExtraFooter={() => (
<div>
<Button size="small" onClick={handleChooseTime}>
选择时间
</Button>
{datePickerFooterText && (
<span style={{ marginLeft: 20 }}>{datePickerFooterText}</span>
)}
</div>
)}
/>
);
}
return <Input allowClear placeholder={item?.placeholder || '请输入'} />;
};
const length =
columns?.filter((item: any) => item?.showSearch || item?.dateTime)
?.length || 0;
const getFields = () => {
const children: any = [];
columns
?.filter((item: any) => item?.showSearch || item?.dateTime)
?.map((item: any) => {
children.push(
<div className={styles.colStyle} key={item?.dataIndex}>
<Form.Item
key={item?.dataIndex}
label={item?.title}
name={item?.dataIndex}
rules={item?.rules}
>
{getComponent(item)}
</Form.Item>
</div>,
);
return item;
});
return children;
};
const onMyFinish = (values: any) => {
Object.keys(values).forEach((item) => {
const key = values[item];
if (key === '' || key === undefined || key === null) {
delete values[item];
}
});
onFinish(values);
};
const offset = () => {
if (length % 4 === 0) {
return 18;
}
return length % 3 === 1 ? 12 : length % 3 === 2 ? 6 : 0;
};
return (
<div
className={!length ? styles.null : styles.TableFilterBox}
style={offset() < 18 ? { paddingBottom: '0' } : undefined}
>
<Form
form={form}
initialValues={initialValues}
onFinish={onMyFinish}
style={{ width: '100%' }}
autoComplete="off"
>
<div className={styles.RowStyle}>
{getFields()}
{Array(length < 4 ? 0 : 3 - (length % 4))
?.fill(null)
.map((_, i) => (
<div
className={styles.colStyle}
style={{ opacity: 0, height: 0, padding: 0, marginBottom: 0 }}
key={i?.toString()}
/>
))}
<Form.Item>
<div className={styles.colStyle}>
<Button
style={{ margin: '0 8px' }}
onClick={() => {
form.resetFields();
refresh();
}}
disabled={disabled}
loading={loading}
>
重置
</Button>
<Button
style={{ margin: '0 8px' }}
type="primary"
htmlType="submit"
disabled={disabled}
loading={loading}
>
查询
</Button>
{expandButton()}
</div>
</Form.Item>
</div>
</Form>
</div>
);
};
export default memo(TableFilter);
ToolBar组件
const ToolBar: FC<ToolBarProps> = ({
columns = [],
onChangeToolBar = () => {},
value = {},
options = {
size: false,
list: false,
fullscreen: false,
},
className = '',
title = '',
expandButton = () => {},
}) => {
const defaultHeaderList = useMemo(() => {
//column增加hidden属性即可在工具栏中默认展示列表中排除该项
return columns
?.filter((item: any) => !item?.hidden)
?.map((item: any) => item?.title);
}, [columns]);
const [indeterminate, setIndeterminate] = React.useState(true);
const [checkAll, setCheckAll] = React.useState(false);
const plainOptions = useMemo(() => {
return columns?.map((item: any) => item?.title);
}, [columns]);
const onChangeCheck = (list: Array<any>) => {
onChangeToolBar({
...value,
headerList: list,
});
setIndeterminate(!!list.length && list.length < plainOptions.length);
setCheckAll(list.length === plainOptions.length);
};
const onCheckAllChange = (e: any) => {
onChangeToolBar({
...value,
headerList: e.target.checked ? plainOptions : [],
});
setIndeterminate(false);
setCheckAll(e.target.checked);
};
const CheckboxGroupRef = useRef() as any;
const PopoverTitle = (
<div className={`${styles.PopoverTitle}`}>
<Checkbox
indeterminate={indeterminate}
onChange={onCheckAllChange}
checked={checkAll}
>
全选
</Checkbox>
<Button
type="link"
onClick={() => {
onChangeToolBar({
...value,
headerList: defaultHeaderList,
});
}}
>
重置
</Button>
</div>
);
const Popovercontent = (
<div className={`${className} ${styles.Popovercontent}`}>
<CheckboxGroup
ref={CheckboxGroupRef}
options={plainOptions}
style={{ maxWidth: '172px' }}
value={value?.headerList || []}
onChange={onChangeCheck}
/>
</div>
);
const menu = (
<Menu>
<Menu.Item
key="default"
onClick={() => {
onChangeToolBar({
...value,
density: 'default',
});
}}
>
默认
</Menu.Item>
<Menu.Item
key="middle"
onClick={() => {
onChangeToolBar({
...value,
density: 'middle',
});
}}
>
中等
</Menu.Item>
<Menu.Item
key="small"
onClick={() => {
onChangeToolBar({
...value,
density: 'small',
});
}}
>
紧凑
</Menu.Item>
</Menu>
);
const lunchFullScreen: any = (e: any) => {
if (e.requestFullscreen) {
e.requestFullscreen();
} else if (e.webkitRequestFullscreen) {
e.webkitRequestFullscreen();
} else if (e.mozRequestFullScreen) {
e.mozRequestFullScreen();
} else if (e.msRequestFullscreen) {
e.msRequestFullscreen();
}
};
const exitFullScreen = () => {
const mydocument = document as any;
if (mydocument.exitFullscreen) {
mydocument.exitFullscreen();
} else if (mydocument?.webkitExitFullscreen) {
mydocument?.webkitExitFullscreen();
} else if (mydocument?.mozCancelFullScreen) {
mydocument?.mozCancelFullScreen();
} else if (mydocument?.msExitFullscreen) {
mydocument?.msExitFullscreen();
}
};
const checkParams = () => {
return (
title ||
Object.values(options).filter((i: any) => i).length ||
!!expandButton
);
};
return (
<div className={checkParams() ? styles.toolBar : styles.hidden}>
<div className={styles.leftBar}>
<div className={styles.TableTitle}>{title}</div>
</div>
<div className={styles.rightBar}>
<div className={styles.btnBox}>{expandButton()}</div>
<div className={styles.expandBtn}>
{options?.size && (
<div className={styles.density} id="ColumnHeightOutlined">
<Tooltip placement="top" title="密度">
<Popover
placement="bottom"
className={styles.Popover}
content={menu}
trigger="click"
getPopupContainer={() =>
document.getElementById('ColumnHeightOutlined') as any
}
>
<ColumnHeightOutlined
style={{
fontSize: '16px',
margin: '0 8px',
cursor: 'pointer',
}}
/>
</Popover>
</Tooltip>
</div>
)}
{options?.list && columns?.length !== 0 && (
<div className={styles.headerlist} id="SettingOutlined">
<Tooltip placement="top" title="列表">
<Popover
placement="bottom"
className={styles.Popover}
title={PopoverTitle}
content={Popovercontent}
trigger="click"
getPopupContainer={() =>
document.getElementById('SettingOutlined') as any
}
>
<SettingOutlined
style={{
fontSize: '16px',
margin: '0 8px',
cursor: 'pointer',
}}
/>
</Popover>
</Tooltip>
</div>
)}
{options?.fullScreen && (
<div className={styles.fullScreen}>
<Tooltip placement="top" title="全屏">
<Popover
placement="bottom"
className={styles.Popover}
trigger="click"
getPopupContainer={() =>
document.getElementById('SettingOutlined') as any
}
>
<div>
{!value?.fullscreen && (
<FullscreenOutlined
onClick={() => {
onChangeToolBar({
...value,
fullscreen: true,
});
lunchFullScreen(
document.getElementById('proTableId'),
);
}}
style={{
fontSize: '16px',
margin: '0 8px',
cursor: 'pointer',
}}
/>
)}
{value?.fullscreen && (
<FullscreenExitOutlined
onClick={() => {
exitFullScreen();
onChangeToolBar({
...value,
fullscreen: false,
});
}}
style={{
fontSize: '16px',
margin: '0 8px',
cursor: 'pointer',
}}
/>
)}
</div>
</Popover>
</Tooltip>
</div>
)}
</div>
</div>
</div>
);
};
export default memo(ToolBar);