Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Table] 树形结构支持半选状态 #1142

Merged
merged 1 commit into from
Jul 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 17 additions & 12 deletions examples/table/demos/editable-cell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,23 @@ const columns = computed(() => [
edit: {
component: Select,
// props, 透传全部属性到 Select 组件
props: {
multiple: true,
minCollapsedNum: 1,
options: [
{ label: 'A', value: 'A' },
{ label: 'B', value: 'B' },
{ label: 'C', value: 'C' },
{ label: 'D', value: 'D' },
{ label: 'E', value: 'E' },
{ label: 'G', value: 'G' },
{ label: 'H', value: 'H' },
],
// props 为函数时,参数有:col, row, rowIndex, colIndex, editedRow。一般用于实现编辑组件之间的联动
props: ({ col, row, rowIndex, colIndex, editedRow }) => {
console.log(col, row, rowIndex, colIndex, editedRow);
return {
multiple: true,
minCollapsedNum: 1,
options: [
{ label: 'A', value: 'A' },
{ label: 'B', value: 'B' },
{ label: 'C', value: 'C' },
{ label: 'D', value: 'D' },
{ label: 'E', value: 'E' },
// 如果框架选择了 React,则 Letters 隐藏 G 和 H
{ label: 'G', value: 'G', show: () => editedRow.framework !== 'React' },
{ label: 'H', value: 'H', show: () => editedRow.framework !== 'React' },
].filter((t) => (t.show === undefined ? true : t.show())),
};
},
// abortEditOnEvent: ['onChange'],
onEdited: (context) => {
Expand Down
2 changes: 1 addition & 1 deletion examples/table/demos/tree-select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const columns = [

// 禁用行选中方式二:使用 checkProps 禁用行(示例代码有效,勿删)
// 这种方式禁用行选中,行文本不会变灰
checkProps: ({ row }) => ({ disabled: row.status !== 0 }),
checkProps: ({ row }) => ({ disabled: !row.childrenList && row.status !== 0 }),
// 自由调整宽度,如果发现元素看不见,请加大宽度
width: 20,
},
Expand Down
9 changes: 5 additions & 4 deletions examples/table/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,19 @@ defaultDisplayColumns | Array | - | 列配置功能中,当前显示的列。
dragSort | String | - | 拖拽排序方式,值为 `row` 表示行拖拽排序,这种方式无法进行文本复制,慎用。值为`row-handler` 表示通过专门的 拖拽手柄 进行 行拖拽排序。值为 `col` 表示列顺序拖拽。`drag-col` 已废弃,请勿使用。可选项:row/row-handler/col/drag-col | N
dragSortOptions | Object | - | 拖拽排序扩展参数,具体参数见 [Sortable](https://github.com/SortableJS/Sortable)。TS 类型:`SortableOptions` | N
expandedRow | String / Slot / Function | - | 展开行内容,泛型 T 指表格数据类型。TS 类型:`TNode<TableExpandedRowParams<T>>` `interface TableExpandedRowParams<T> { row: T; index: number; columns: PrimaryTableCol<T>[] | BaseTableCol<T>[] }`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts)。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N
expandedRowKeys | Array | [] | 展开行。支持语法糖 `v-model:expandedRowKeys`。TS 类型:`Array<string | number>` | N
defaultExpandedRowKeys | Array | [] | 展开行。非受控属性。TS 类型:`Array<string | number>` | N
expandedRowKeys | Array | - | 展开行。支持语法糖 `v-model:expandedRowKeys`。TS 类型:`Array<string | number>` | N
defaultExpandedRowKeys | Array | - | 展开行。非受控属性。TS 类型:`Array<string | number>` | N
expandIcon | Boolean / Slot / Function | true | 用于控制是否显示「展开图标列」,值为 `false` 则不会显示。可以精确到某一行是否显示,还可以自定义展开图标内容。`expandedRow` 存在时,该参数有效。支持全局配置 `GlobalConfigProvider`。TS 类型:`boolean | TNode<ExpandArrowRenderParams<T>>` `interface ExpandArrowRenderParams<T> { row: T; index: number }`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts)。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N
expandOnRowClick | Boolean | - | 是否允许点击行展开 | N
filterIcon | Slot / Function | - | 自定义过滤图标,支持全局配置 `GlobalConfigProvider`。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N
filterRow | String / Slot / Function | - | 自定义过滤状态行及清空筛选等。TS 类型:`string | TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N
filterValue | Object | - | 过滤数据的值。支持语法糖 `v-model:filterValue`。TS 类型:`FilterValue` `type FilterValue = { [key: string]: any }`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N
defaultFilterValue | Object | - | 过滤数据的值。非受控属性。TS 类型:`FilterValue` `type FilterValue = { [key: string]: any }`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N
hideSortTips | Boolean | - | 隐藏排序文本提示,支持全局配置 `GlobalConfigProvider`,默认全局配置值为 `false` | N
indeterminateSelectedRowKeys | Array | - | 半选状态行。选中行请更为使用 `selectedRowKeys` 控制。TS 类型:`Array<string | number>` | N
multipleSort | Boolean | false | 是否支持多列排序 | N
selectedRowKeys | Array | - | 选中的行,控制属性。支持语法糖 `v-model:selectedRowKeys`。TS 类型:`Array<string | number>` | N
defaultSelectedRowKeys | Array | - | 选中的行,控制属性。非受控属性。TS 类型:`Array<string | number>` | N
selectedRowKeys | Array | - | 选中的行,控制属性。半选状态行请更为使用 `indeterminateSelectedRowKeys` 控制。支持语法糖 `v-model:selectedRowKeys`。TS 类型:`Array<string | number>` | N
defaultSelectedRowKeys | Array | - | 选中的行,控制属性。半选状态行请更为使用 `indeterminateSelectedRowKeys` 控制。非受控属性。TS 类型:`Array<string | number>` | N
sort | Object / Array | - | 排序控制。sortBy 排序字段;descending 是否进行降序排列。值为数组时,表示正进行多字段排序。支持语法糖 `v-model:sort`。TS 类型:`TableSort` `type TableSort = SortInfo | Array<SortInfo>` `interface SortInfo { sortBy: string; descending: boolean }`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N
defaultSort | Object / Array | - | 排序控制。sortBy 排序字段;descending 是否进行降序排列。值为数组时,表示正进行多字段排序。非受控属性。TS 类型:`TableSort` `type TableSort = SortInfo | Array<SortInfo>` `interface SortInfo { sortBy: string; descending: boolean }`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/table/type.ts) | N
sortIcon | Slot / Function | - | 自定义排序图标,支持全局配置 `GlobalConfigProvider`。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N
Expand Down
1 change: 1 addition & 0 deletions src/select/select-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export default defineComponent({
`${COMPONENT_NAME.value}__dropdown-inner`,
`${COMPONENT_NAME.value}__dropdown-inner--size-${dropdownInnerSize.value}`,
]}
onClick={(e) => e.stopPropagation()}
>
{renderTNodeJSX('panelTopContent')}
{/* create option */}
Expand Down
5 changes: 4 additions & 1 deletion src/table/enhanced-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default defineComponent({

const treeDataMap = ref(store.value.treeDataMap);

const { onInnerSelectChange } = useTreeSelect(props, treeDataMap);
const { tIndeterminateSelectedRowKeys, onInnerSelectChange } = useTreeSelect(props, treeDataMap);

// 影响列和单元格内容的因素有:树形节点需要添加操作符 [+] [-]
const getColumns = (columns: PrimaryTableCol<TableRowData>[]) => {
Expand Down Expand Up @@ -61,6 +61,7 @@ export default defineComponent({
store,
dataSource,
tColumns,
tIndeterminateSelectedRowKeys,
onDragSortChange,
onInnerSelectChange,
/** 对外暴露的方法 */
Expand All @@ -73,6 +74,8 @@ export default defineComponent({
...this.$props,
data: this.dataSource,
columns: this.tColumns,
// 半选状态节点
indeterminateSelectedRowKeys: this.tIndeterminateSelectedRowKeys,
// 树形结构不允许本地数据分页
disableDataPage: Boolean(this.tree && Object.keys(this.tree).length),
onSelectChange: this.onInnerSelectChange,
Expand Down
15 changes: 15 additions & 0 deletions src/table/hooks/tree-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ class TableTreeStore<T extends TableRowData = TableRowData> {
this.initialTreeDataMap(this.treeDataMap, dataSource, columns[0], keys);
}

/**
* 获取所有节点的唯一标识
*/
getAllUniqueKeys(data: T[], keys: KeysType, arr: T[] = []) {
for (let i = 0, len = data.length; i < len; i++) {
const item = data[i];
arr.push(get(item, keys.rowKey));
const children = get(item, keys.childrenKey);
if (children?.length) {
this.getAllUniqueKeys(children, keys, arr);
}
}
return arr;
}

toggleExpandData(p: { rowIndex: number; row: T }, dataSource: T[], keys: KeysType) {
if (!p) {
log.error('EnhancedTable', 'the node you want to toggleExpand doest not exist in `data`');
Expand Down
2 changes: 1 addition & 1 deletion src/table/hooks/useRowExpand.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default function useRowExpand(props: TdPrimaryTableProps, context: SetupC
// controlled and uncontrolled
const [tExpandedRowKeys, setTExpandedRowKeys] = useDefaultValue(
expandedRowKeys,
props.defaultExpandedRowKeys,
props.defaultExpandedRowKeys || [],
props.onExpandChange,
'expandedRowKeys',
);
Expand Down
9 changes: 7 additions & 2 deletions src/table/hooks/useRowSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@ export default function useRowSelect(props: TdPrimaryTableProps) {
onChange: () => handleSelectChange(row),
};
if (column.type === 'single') return <Radio {...selectBoxProps} />;
if (column.type === 'multiple') return <Checkbox {...selectBoxProps} />;
if (column.type === 'multiple') {
const isIndeterminate = props.indeterminateSelectedRowKeys?.length
? props.indeterminateSelectedRowKeys.includes(get(row, props.rowKey))
: false;
return <Checkbox indeterminate={isIndeterminate} {...selectBoxProps} />;
}
return null;
}

Expand Down Expand Up @@ -126,7 +131,7 @@ export default function useRowSelect(props: TdPrimaryTableProps) {
const disabledSelectedRowKeys = selectedRowKeys.value?.filter((id) => !canSelectedRowKeys.includes(id)) || [];
const allIds = checked ? [...disabledSelectedRowKeys, ...canSelectedRowKeys] : [...disabledSelectedRowKeys];
setTSelectedRowKeys(allIds, {
selectedRowData: filterDataByIds(props.data, allIds, reRowKey),
selectedRowData: checked ? filterDataByIds(props.data, allIds, reRowKey) : [],
type: checked ? 'check' : 'uncheck',
currentRowKey: 'CHECK_ALL_BOX',
});
Expand Down
18 changes: 10 additions & 8 deletions src/table/hooks/useTreeData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,18 @@ export default function useTreeData(props: TdEnhancedTableProps, context: SetupC
});
};

const uniqueKeys = computed(() => store.value?.getAllUniqueKeys(data.value, rowDataKeys.value)?.join() || '');

watch(
[data],
([data]) => {
if (!data) return;
[uniqueKeys],
() => {
if (!data.value) return;
// 如果没有树形解构,则不需要相关逻辑
if (!props.tree || !Object.keys(props.tree).length) {
dataSource.value = data;
if (!props.tree) {
dataSource.value = data.value;
return;
}
let newVal = cloneDeep(data);
let newVal = cloneDeep(data.value);
store.value.initialTreeStore(newVal, props.columns, rowDataKeys.value);
if (props.tree?.defaultExpandAll) {
newVal = store.value.expandAll(newVal, rowDataKeys.value);
Expand All @@ -80,7 +82,7 @@ export default function useTreeData(props: TdEnhancedTableProps, context: SetupC
// });

onUnmounted(() => {
if (!props.tree || !Object.keys(props.tree).length) return;
if (!props.tree) return;
store.value.treeDataMap?.clear();
store.value = null;
});
Expand Down Expand Up @@ -130,7 +132,7 @@ export default function useTreeData(props: TdEnhancedTableProps, context: SetupC
}

function formatTreeColumn(col: PrimaryTableCol): PrimaryTableCol {
if (!props.tree || !Object.keys(props.tree).length || col.colKey !== treeNodeCol.value.colKey) return col;
if (!props.tree || col.colKey !== treeNodeCol.value.colKey) return col;
const newCol = { ...treeNodeCol.value };
newCol.cell = (h, p) => {
const cellInfo = renderCell({ ...p, col: { ...treeNodeCol.value } }, context.slots);
Expand Down
Loading