Skip to content

Commit f7b5d64

Browse files
committed
fix: refactor logic
1 parent 331484f commit f7b5d64

File tree

4 files changed

+502
-103
lines changed

4 files changed

+502
-103
lines changed

packages/components/table/EnhancedTable.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ const EnhancedTable = forwardRef<EnhancedTableRef, TEnhancedTableProps>((props,
2020
// treeInstanceFunctions 属于对外暴露的 Ref 方法
2121
const { store, dataSource, formatTreeColumn, swapData, onExpandFoldIconClick, ...treeInstanceFunctions } =
2222
useTreeData(props);
23-
2423
const treeDataMap = store?.treeDataMap;
2524

26-
const { tIndeterminateSelectedRowKeys, onInnerSelectChange } = useTreeSelect(props, treeDataMap);
25+
const { innerIndeterminateSelectedRowKeys, innerSelectedRowKeys, onInnerSelectChange } = useTreeSelect(props, {
26+
treeDataMap,
27+
});
2728

2829
// 影响列和单元格内容的因素有:树形节点需要添加操作符 [+] [-]
2930
const getColumns = (columns: PrimaryTableCol<TableRowData>[]) => {
@@ -84,8 +85,8 @@ const EnhancedTable = forwardRef<EnhancedTableRef, TEnhancedTableProps>((props,
8485
...props,
8586
data: dataSource,
8687
columns: tColumns,
87-
// 半选状态节点
88-
indeterminateSelectedRowKeys: tIndeterminateSelectedRowKeys,
88+
selectedRowKeys: isTreeData ? innerSelectedRowKeys : props.selectedRowKeys,
89+
indeterminateSelectedRowKeys: innerIndeterminateSelectedRowKeys,
8990
// 树形结构不允许本地数据分页
9091
disableDataPage: isTreeData,
9192
reserveSelectedRowOnPaginate: isTreeData ? true : props.reserveSelectedRowOnPaginate,
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
import React from 'react';
2+
import { vi } from '@test/utils';
3+
import { fireEvent, render } from '@testing-library/react';
4+
import { EnhancedTable, Table } from '..';
5+
6+
const columns = [
7+
{
8+
colKey: 'row-select',
9+
type: 'multiple' as const,
10+
disabled: ({ row }) => row.disabled === true,
11+
},
12+
{ colKey: 'key', title: 'Key' },
13+
];
14+
15+
describe('Table', () => {
16+
function getTableData({ withDisabled = true } = {}) {
17+
const data = [];
18+
for (let i = 0; i <= 5; i++) {
19+
data.push({
20+
key: `${i}`,
21+
...(withDisabled && i === 2 ? { disabled: true } : {}),
22+
});
23+
}
24+
return data;
25+
}
26+
27+
const TestPrimaryTable = ({ defaultSelectedRowKeys = [], onSelectChange = vi.fn(), data = getTableData() }) => (
28+
<Table
29+
rowKey="key"
30+
columns={columns}
31+
data={data}
32+
defaultSelectedRowKeys={defaultSelectedRowKeys}
33+
onSelectChange={onSelectChange}
34+
/>
35+
);
36+
37+
it('全选(不存在 disabled 行)', async () => {
38+
const onSelectChange = vi.fn();
39+
40+
const { container } = render(
41+
<TestPrimaryTable data={getTableData({ withDisabled: false })} onSelectChange={onSelectChange} />,
42+
);
43+
44+
const selectAllCheckbox = container.querySelector('th[data-colkey="row-select"] .t-checkbox');
45+
expect(selectAllCheckbox).not.toHaveClass('t-is-checked');
46+
expect(selectAllCheckbox).not.toHaveClass('t-is-indeterminate');
47+
48+
// 全选
49+
await fireEvent.click(selectAllCheckbox);
50+
expect(selectAllCheckbox).toHaveClass('t-is-checked');
51+
expect(onSelectChange).toHaveBeenCalledWith(['0', '1', '2', '3', '4', '5'], expect.any(Object));
52+
53+
// 取消全选
54+
onSelectChange.mockClear();
55+
await fireEvent.click(selectAllCheckbox);
56+
expect(selectAllCheckbox).not.toHaveClass('t-is-checked');
57+
expect(onSelectChange).toHaveBeenCalledWith([], expect.any(Object));
58+
});
59+
60+
it('全选(存在 disabled 行)', async () => {
61+
const onSelectChange = vi.fn();
62+
63+
const { container } = render(<TestPrimaryTable onSelectChange={onSelectChange} />);
64+
65+
const selectAllCheckbox = container.querySelector('th[data-colkey="row-select"] .t-checkbox');
66+
expect(selectAllCheckbox).not.toHaveClass('t-is-checked');
67+
expect(selectAllCheckbox).not.toHaveClass('t-is-indeterminate');
68+
69+
// 全选
70+
await fireEvent.click(selectAllCheckbox);
71+
expect(selectAllCheckbox).toHaveClass('t-is-indeterminate');
72+
expect(onSelectChange).toHaveBeenCalledWith(expect.arrayContaining(['0', '1', '3', '4', '5']), expect.any(Object));
73+
expect(onSelectChange.mock.calls[0][0]).not.toContain('2'); // 禁用行不应该被选中
74+
75+
// 取消全选
76+
onSelectChange.mockClear();
77+
await fireEvent.click(selectAllCheckbox);
78+
expect(selectAllCheckbox).not.toHaveClass('t-is-indeterminate');
79+
expect(onSelectChange).toHaveBeenCalledWith([], expect.any(Object));
80+
});
81+
82+
it('全选(初始化选中 disabled 行)', async () => {
83+
const onSelectChange = vi.fn();
84+
85+
const { container } = render(<TestPrimaryTable defaultSelectedRowKeys={['2']} onSelectChange={onSelectChange} />);
86+
87+
const selectAllCheckbox = container.querySelector('th[data-colkey="row-select"] .t-checkbox');
88+
expect(selectAllCheckbox).toHaveClass('t-is-indeterminate');
89+
90+
// 全选
91+
await fireEvent.click(selectAllCheckbox);
92+
expect(selectAllCheckbox).toHaveClass('t-is-checked');
93+
expect(onSelectChange).toHaveBeenCalledWith(
94+
expect.arrayContaining(['0', '1', '2', '3', '4', '5']),
95+
expect.any(Object),
96+
);
97+
98+
// 取消全选
99+
onSelectChange.mockClear();
100+
await fireEvent.click(selectAllCheckbox);
101+
expect(selectAllCheckbox).toHaveClass('t-is-indeterminate');
102+
expect(onSelectChange).toHaveBeenCalledWith(['2'], expect.any(Object)); // 禁用行保留
103+
});
104+
});
105+
106+
describe('EnhancedTable', () => {
107+
function getTreeData() {
108+
const data = [];
109+
110+
for (let i = 0; i <= 2; i++) {
111+
const parentItem = {
112+
key: `${i}`,
113+
children: [],
114+
};
115+
116+
for (let j = 0; j <= 2; j++) {
117+
const childItem = {
118+
key: `${i}-${j}`,
119+
children: [],
120+
};
121+
122+
for (let k = 0; k <= 2; k++) {
123+
childItem.children.push({
124+
key: `${i}-${j}-${k}`,
125+
});
126+
}
127+
128+
parentItem.children.push(childItem);
129+
}
130+
131+
data.push(parentItem);
132+
}
133+
134+
return data;
135+
}
136+
137+
function getTreeDataWithDisabled() {
138+
const data = getTreeData();
139+
data[1].children[1].children[0].disabled = true;
140+
return data;
141+
}
142+
143+
const TestEnhancedTable = ({ checkStrictly = false, defaultSelectedRowKeys = [], onSelectChange = vi.fn() }) => (
144+
<EnhancedTable
145+
rowKey="key"
146+
data={getTreeDataWithDisabled()}
147+
columns={columns}
148+
defaultSelectedRowKeys={defaultSelectedRowKeys}
149+
onSelectChange={onSelectChange}
150+
tree={{
151+
checkStrictly,
152+
}}
153+
/>
154+
);
155+
156+
it('全选(存在 disabled 行)', async () => {
157+
const onSelectChange = vi.fn();
158+
159+
const { container } = render(<TestEnhancedTable onSelectChange={onSelectChange} />);
160+
161+
const selectAllCheckbox = container.querySelector('th[data-colkey="row-select"] .t-checkbox');
162+
163+
// 初始状态
164+
expect(selectAllCheckbox).not.toHaveClass('t-is-checked');
165+
expect(selectAllCheckbox).not.toHaveClass('t-is-indeterminate');
166+
167+
await fireEvent.click(selectAllCheckbox);
168+
const selectedKeys = onSelectChange.mock.calls[0][0];
169+
170+
expect(selectAllCheckbox).toHaveClass('t-is-indeterminate');
171+
expect(selectedKeys).toHaveLength(38); // 39 - 1
172+
expect(selectedKeys).not.toContain('1-1-0'); // 不包含禁用项
173+
});
174+
175+
it('全选(初始化选中 disabled 行)', async () => {
176+
const onSelectChange = vi.fn();
177+
178+
const { container } = render(
179+
<TestEnhancedTable defaultSelectedRowKeys={['1-1-0']} onSelectChange={onSelectChange} />,
180+
);
181+
182+
const selectAllCheckbox = container.querySelector('th[data-colkey="row-select"] .t-checkbox');
183+
184+
expect(selectAllCheckbox).toHaveClass('t-is-indeterminate');
185+
186+
// 全选
187+
await fireEvent.click(selectAllCheckbox);
188+
189+
const selectedKeys = onSelectChange.mock.calls[0][0];
190+
191+
// 全选 + 禁用行存在 → checked
192+
expect(selectAllCheckbox).toHaveClass('t-is-checked');
193+
194+
expect(selectedKeys).toHaveLength(39);
195+
expect(selectedKeys).toContain('1-1-0');
196+
197+
// 取消全选
198+
onSelectChange.mockClear();
199+
await fireEvent.click(selectAllCheckbox);
200+
201+
const afterUncheck = onSelectChange.mock.calls[0][0];
202+
203+
// 只剩禁用行
204+
expect(afterUncheck).toEqual(['1-1-0']);
205+
expect(selectAllCheckbox).toHaveClass('t-is-indeterminate');
206+
});
207+
208+
it('父节点选择 (checkStrictly=false)', async () => {
209+
const onSelectChange = vi.fn();
210+
const { container } = render(
211+
<TestEnhancedTable defaultSelectedRowKeys={['1-1-0']} onSelectChange={onSelectChange} />,
212+
);
213+
214+
const rows = container.querySelectorAll('tr.t-table-tr--level-0');
215+
const parentCheckbox = rows[1].querySelector('.t-checkbox');
216+
217+
expect(parentCheckbox).toHaveClass('t-is-indeterminate');
218+
219+
await fireEvent.click(parentCheckbox);
220+
221+
const selectedKeys = onSelectChange.mock.calls[0][0];
222+
223+
expect(parentCheckbox).toHaveClass('t-is-checked');
224+
expect(selectedKeys).toContain('1');
225+
expect(selectedKeys).toContain('1-1-0');
226+
expect(selectedKeys).toHaveLength(13);
227+
228+
onSelectChange.mockClear();
229+
await fireEvent.click(parentCheckbox);
230+
231+
expect(onSelectChange).toHaveBeenCalledWith(['1-1-0'], expect.any(Object));
232+
});
233+
234+
it('父节点选择 (checkStrictly=true)', async () => {
235+
const onSelectChange = vi.fn();
236+
const { container } = render(
237+
<TestEnhancedTable defaultSelectedRowKeys={['1-1-0']} onSelectChange={onSelectChange} checkStrictly />,
238+
);
239+
const rows = container.querySelectorAll('tr.t-table-tr--level-0');
240+
241+
const parentCheckbox = rows[1].querySelector('.t-checkbox');
242+
expect(parentCheckbox).not.toHaveClass('t-is-indeterminate');
243+
expect(parentCheckbox).not.toHaveClass('t-is-checked');
244+
245+
await fireEvent.click(parentCheckbox);
246+
expect(onSelectChange).toHaveBeenCalledWith(expect.arrayContaining(['1-1-0', '1']), expect.any(Object));
247+
248+
const childCheckbox = rows[2].querySelector('.t-checkbox');
249+
onSelectChange.mockClear();
250+
await fireEvent.click(childCheckbox);
251+
expect(onSelectChange).toHaveBeenCalledWith(expect.arrayContaining(['1-1-0', '1', '2']), expect.any(Object));
252+
});
253+
});

0 commit comments

Comments
 (0)