From feba6375240dfd29565eecb1bb00cb07d14f6b3f Mon Sep 17 00:00:00 2001 From: Lyca Date: Tue, 15 Feb 2022 13:32:40 +0800 Subject: [PATCH] feat(next): support checkStrictly props in SelectTable (#2824) --- packages/antd/docs/components/SelectTable.md | 16 +++ .../antd/docs/components/SelectTable.zh-CN.md | 18 ++- packages/next/docs/components/SelectTable.md | 16 +++ .../next/docs/components/SelectTable.zh-CN.md | 18 ++- packages/next/src/select-table/index.tsx | 28 +++- .../next/src/select-table/useCheckSlackly.tsx | 131 ++++++++++++++++++ .../next/src/select-table/useTitleAddon.tsx | 9 +- 7 files changed, 229 insertions(+), 7 deletions(-) create mode 100644 packages/next/src/select-table/useCheckSlackly.tsx diff --git a/packages/antd/docs/components/SelectTable.md b/packages/antd/docs/components/SelectTable.md index bc269854895..6ddb86ee6ce 100644 --- a/packages/antd/docs/components/SelectTable.md +++ b/packages/antd/docs/components/SelectTable.md @@ -448,6 +448,9 @@ const schema = { .toLowerCase() .localeCompare(optionB.description.toLowerCase()), optionAsValue: true, + rowSelection: { + checkStrictly: false, + }, }, enum: [ { key: '1', name: 'title-1', description: 'A-description' }, @@ -468,6 +471,11 @@ const schema = { }, ], }, + { + key: '2-2', + name: 'title2-2', + description: 'YY-description', + }, ], }, { key: '3', name: 'title-3', description: 'C-description' }, @@ -608,6 +616,14 @@ export default () => ( `TableProps` type definition reference antd https://ant.design/components/table/ +### rowSelection + +| Property name | Type | Description | Default value | +| ------------- | ------- | -------------------------------------------------------------------------- | ------------- | +| checkStrictly | boolean | Check table row precisely; parent row and children rows are not associated | true | + +`rowSelectionProps` type definition reference antd https://ant.design/components/table/#rowSelection + ### SelectTable.Column `ColumnProps` type definition reference antd https://ant.design/components/table/ Table.Column diff --git a/packages/antd/docs/components/SelectTable.zh-CN.md b/packages/antd/docs/components/SelectTable.zh-CN.md index 19748284961..551003fdd1b 100644 --- a/packages/antd/docs/components/SelectTable.zh-CN.md +++ b/packages/antd/docs/components/SelectTable.zh-CN.md @@ -448,6 +448,9 @@ const schema = { .toLowerCase() .localeCompare(optionB.description.toLowerCase()), optionAsValue: true, + rowSelection: { + checkStrictly: false, + }, }, enum: [ { key: '1', name: '标题1', description: 'A-描述' }, @@ -464,6 +467,11 @@ const schema = { { key: '2-1-1', name: '标题2-1-1', description: 'Z-描述' }, ], }, + { + key: '2-2', + name: '标题2-2', + description: 'YY-描述', + }, ], }, { key: '3', name: '标题3', description: 'C-描述' }, @@ -602,7 +610,15 @@ export default () => ( | filterSort | (optionA, optionB) => number | 搜索时对筛选结果项的排序函数, 类似 Array.sort 里的 compareFunction | - | | onSearch | 文本框值变化时回调 | (inputValue) => void | - | -其余参考 https://ant.design/components/table-cn/ +参考 https://ant.design/components/table-cn/ + +### rowSelection + +| 属性名 | 类型 | 描述 | 默认值 | +| ------------- | ------- | ------------------------------------------------------------ | ------ | +| checkStrictly | boolean | checkable 状态下节点选择完全受控(父子数据选中状态不再关联) | true | + +参考 https://ant.design/components/table/#rowSelection ### SelectTable.Column diff --git a/packages/next/docs/components/SelectTable.md b/packages/next/docs/components/SelectTable.md index 0c8fcec41ce..d10158e4b94 100644 --- a/packages/next/docs/components/SelectTable.md +++ b/packages/next/docs/components/SelectTable.md @@ -452,6 +452,9 @@ const schema = { .toLowerCase() .localeCompare(optionB.description.toLowerCase()), optionAsValue: true, + rowSelection: { + checkStrictly: false, + }, }, enum: [ { key: '1', name: 'title-1', description: 'A-description' }, @@ -472,6 +475,11 @@ const schema = { }, ], }, + { + key: '2-2', + name: 'title2-2', + description: 'YY-description', + }, ], }, { key: '3', name: 'title-3', description: 'C-description' }, @@ -613,6 +621,14 @@ export default () => ( `TableProps` type definition reference fusion https://fusion.design/pc/component/basic/table +### rowSelection + +| Property name | Type | Description | Default value | +| ------------- | ------- | -------------------------------------------------------------------------- | ------------- | +| checkStrictly | boolean | Check table row precisely; parent row and children rows are not associated | true | + +`rowSelectionProps` type definition reference fusion https://fusion.design/pc/component/basic/table rowSelection + ### SelectTable.Column `ColumnProps` type definition reference fusion https://fusion.design/pc/component/basic/table Table.Column diff --git a/packages/next/docs/components/SelectTable.zh-CN.md b/packages/next/docs/components/SelectTable.zh-CN.md index 771a68db0ac..c68b815846c 100644 --- a/packages/next/docs/components/SelectTable.zh-CN.md +++ b/packages/next/docs/components/SelectTable.zh-CN.md @@ -452,6 +452,9 @@ const schema = { .toLowerCase() .localeCompare(optionB.description.toLowerCase()), optionAsValue: true, + rowSelection: { + checkStrictly: false, + }, }, enum: [ { key: '1', name: '标题1', description: 'A-描述' }, @@ -468,6 +471,11 @@ const schema = { { key: '2-1-1', name: '标题2-1-1', description: 'Z-描述' }, ], }, + { + key: '2-2', + name: '标题2-2', + description: 'YY-描述', + }, ], }, { key: '3', name: '标题3', description: 'C-描述' }, @@ -607,7 +615,15 @@ export default () => ( | filterSort | (optionA, optionB) => number | 搜索时对筛选结果项的排序函数, 类似 Array.sort 里的 compareFunction | - | | onSearch | 文本框值变化时回调 | (inputValue) => void | - | -其余参考 https://fusion.design/pc/component/basic/table +参考 https://fusion.design/pc/component/basic/table + +### rowSelection + +| 属性名 | 类型 | 描述 | 默认值 | +| ------------- | ------- | ------------------------------------------------------------ | ------ | +| checkStrictly | boolean | checkable 状态下节点选择完全受控(父子数据选中状态不再关联) | true | + +参考 https://fusion.design/pc/component/basic/table rowSelection ### SelectTable.Column diff --git a/packages/next/src/select-table/index.tsx b/packages/next/src/select-table/index.tsx index a9a078ac837..e62701f4f2b 100644 --- a/packages/next/src/select-table/index.tsx +++ b/packages/next/src/select-table/index.tsx @@ -9,6 +9,7 @@ import { useFilterOptions } from './useFilterOptions' import { useFlatOptions } from './useFlatOptions' import { useTitleAddon } from './useTitleAddon' import { useSize } from './useSize' +import { useCheckSlackly, getCheckedProps } from './useCheckSlackly' import { usePrefixCls } from '../__builtins__' type IFilterOption = boolean | ((option: any, keyword: string) => boolean) @@ -32,6 +33,9 @@ export interface ISelectTableProps extends Omit { onSearch?: (keyword: string) => void onChange?: (value: any) => void value?: any + rowSelection?: TableProps['rowSelection'] & { + checkStrictly?: boolean + } } type ComposedSelectTable = React.FC & { @@ -180,6 +184,22 @@ export const SelectTable: ComposedSelectTable = observer((props) => { selectedRowKeys.includes(item?.[primaryKey]) ) } + if (rowSelection?.checkStrictly !== false) { + onInnerChange(selectedRowKeys, records) + } else { + onSlacklyChange(selectedRowKeys) + } + } + + // Fusion TreeData SlacklyChange + const onSlacklyChange = (prevSelectedRowKeys: any[]) => { + const { selectedRowKeys, records } = useCheckSlackly( + prevSelectedRowKeys, + selected, + primaryKey, + flatDataSource + ) + onInnerChange(selectedRowKeys, records) } @@ -232,10 +252,16 @@ export const SelectTable: ComposedSelectTable = observer((props) => { ...rowSelection, getProps: (record, index) => ({ ...(rowSelection?.getProps?.(record, index) as any), + ...(rowSelection?.checkStrictly !== false + ? {} + : getCheckedProps(record, primaryKey, selected)), // 父子关联模式indeterminate值 disabled, }), // fusion selectedRowKeys: selected, - onChange: onInnerChange, + onChange: + rowSelection?.checkStrictly !== false + ? onInnerChange + : onSlacklyChange, mode, ...titleAddon, } diff --git a/packages/next/src/select-table/useCheckSlackly.tsx b/packages/next/src/select-table/useCheckSlackly.tsx new file mode 100644 index 00000000000..86b9de24e56 --- /dev/null +++ b/packages/next/src/select-table/useCheckSlackly.tsx @@ -0,0 +1,131 @@ +/** + * 获取该字段Checkbox的indeterminate属性 + * @param record 字段项 + * @param primaryKey 键名称 + * @param selected 当前选中的字段值集合 + * @returns indeterminate属性值 + */ +const getCheckedProps = (record: any, primaryKey: string, selected: any[]) => { + if (record.children?.length) { + const childrenDataSource = record.children + const selectedChildren = childrenDataSource.filter((item) => + selected?.includes(item[primaryKey]) + ) + return { + // checked受控,此处配置在rowSelection并不会生效,供getFinalTreeKeys使用 + checked: selectedChildren.length === childrenDataSource.length, + indeterminate: !!( + selectedChildren.length && + selectedChildren.length !== childrenDataSource.length + ), + } + } + return {} +} + +/** + * 获取树列表某个键值的集合 + * @param tree 树列表 + * @param primaryKey 键名称 + * @returns 键值数组集合 + */ +const getTreeKeys = (tree: any[] = [], primaryKey: string) => + tree.reduce( + (prev, current) => [ + ...prev, + current[primaryKey], + ...getTreeKeys(current?.children, primaryKey), + ], + [] + ) + +/** + * 获取最终选中值(添加选中所有子元素的父元素,或移除未选中所有子元素的父元素) + * @param tree 树列表 + * @param primaryKey 键名称 + * @param selectedRowKeys 当前选中的字段值集合 + * @returns 最终选中的字段值集合 + */ +const getFinalTreeKeys = ( + tree: any[] = [], + primaryKey: string, + selectedRowKeys: any[] +) => { + let finalSelectedRowKeys = [...selectedRowKeys] + + tree.forEach((item) => { + if (item.children?.length) { + // 优先递归子元素 + finalSelectedRowKeys = getFinalTreeKeys( + item.children, + primaryKey, + finalSelectedRowKeys + ) + if (getCheckedProps(item, primaryKey, finalSelectedRowKeys)?.checked) { + // 如果该元素的子元素全部选中,则也选中该项(即包含全选子元素的父元素) + finalSelectedRowKeys = [ + ...new Set([...finalSelectedRowKeys, item[primaryKey]]), + ] + } else { + // 如果该元素的子元素未全部选中,则移除该项 + finalSelectedRowKeys = finalSelectedRowKeys.filter( + (key) => key !== item[primaryKey] + ) + } + } + }) + + return finalSelectedRowKeys +} + +interface ICheckSlackly { + ( + selectedRowKeys: any[], + selected: any[], + primaryKey: string, + flatDataSource: any[] + ): { + selectedRowKeys: any[] + records: any[] + } +} + +const useCheckSlackly: ICheckSlackly = ( + selectedRowKeys, + selected, + primaryKey, + flatDataSource +) => { + const isSelected = selectedRowKeys.length > selected.length + const currentKey = [...selectedRowKeys, ...selected].find( + (key) => !(selectedRowKeys.includes(key) && selected.includes(key)) + ) + const currentRecords = flatDataSource.find( + (item) => item[primaryKey] === currentKey + ) + const currentTreeKeys = getTreeKeys([currentRecords], primaryKey) + let newSelectedRowKeys = [] + + if (isSelected) { + newSelectedRowKeys = [...new Set([...selected, ...currentTreeKeys])] + } else { + newSelectedRowKeys = selected.filter( + (key) => !currentTreeKeys.includes(key) + ) + } + // 添加选中所有子元素的父元素,或移除未选中所有子元素的父元素 + newSelectedRowKeys = getFinalTreeKeys( + flatDataSource, + primaryKey, + newSelectedRowKeys + ) + + return { + selectedRowKeys: newSelectedRowKeys, + records: flatDataSource.filter((item) => + newSelectedRowKeys.includes(item[primaryKey]) + ), + } +} + +export { useCheckSlackly, getCheckedProps } diff --git a/packages/next/src/select-table/useTitleAddon.tsx b/packages/next/src/select-table/useTitleAddon.tsx index f810f9981d9..e2d4e8d3421 100644 --- a/packages/next/src/select-table/useTitleAddon.tsx +++ b/packages/next/src/select-table/useTitleAddon.tsx @@ -6,17 +6,18 @@ const newCheckbox = (selected, flatDataSource, primaryKey, disabled, readOnly, onChange) => () => { const allDataSourceKeys = flatDataSource.map((item) => item?.[primaryKey]) + const indeterminate = !!( + selected?.length && selected.length !== allDataSourceKeys.length + ) return ( { if (!readOnly) { - if (checked) { + if (checked || indeterminate) { onChange?.(allDataSourceKeys, flatDataSource) } else { onChange?.([], [])