xt-element-ui 1.2.3 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/docs/README.md +201 -0
  2. package/docs/components/base/xt-button.md +114 -0
  3. package/docs/components/base/xt-card-item.md +104 -0
  4. package/docs/components/base/xt-card.md +108 -0
  5. package/docs/components/base/xt-config-provider.md +199 -0
  6. package/docs/components/base/xt-flex-box.md +115 -0
  7. package/docs/components/base/xt-grid-box.md +303 -0
  8. package/docs/components/base/xt-input.md +150 -0
  9. package/docs/components/base/xt-text.md +212 -0
  10. package/docs/components/extend/ex-bar.md +68 -0
  11. package/docs/components/extend/ex-button.md +62 -0
  12. package/docs/components/extend/ex-card.md +86 -0
  13. package/docs/components/extend/ex-chart.md +355 -0
  14. package/docs/components/extend/ex-icon.md +190 -0
  15. package/docs/components/extend/ex-line.md +71 -0
  16. package/docs/components/extend/ex-multi.md +156 -0
  17. package/docs/components/extend/ex-page.md +75 -0
  18. package/docs/components/extend/ex-pie.md +70 -0
  19. package/docs/components/extend/ex-select-tree.md +210 -0
  20. package/docs/components/extend/ex-table.md +591 -0
  21. package/docs/components/extend/ex-upload.md +134 -0
  22. package/docs/components/utils/size.md +148 -0
  23. package/docs/components/utils/theme.md +183 -0
  24. package/lib/index.common.js +449 -429
  25. package/lib/index.css +1 -1
  26. package/lib/index.umd.js +449 -429
  27. package/lib/index.umd.min.js +4 -4
  28. package/package.json +4 -2
  29. package/src/components/ex-chart/ExMulti.vue +44 -32
  30. package/src/components/ex-chart/ExPie.vue +6 -8
  31. package/src/components/ex-chart/index.vue +1 -4
  32. package/src/components/ex-chart/theme/dark.js +14 -12
  33. package/src/components/ex-chart/utils.js +1 -1
  34. package/src/components/ex-icon/index.js +2 -0
  35. package/src/components/ex-icon/index.vue +168 -0
  36. package/src/components/ex-icon/style/index.scss +7 -0
  37. package/src/components/ex-table/index.vue +3 -3
  38. package/src/components/index.scss +4 -1
  39. package/src/components/xt-button/index.vue +2 -2
  40. package/src/components/xt-button/style/index.scss +524 -614
  41. package/src/components/xt-card-item/images/bar.svg +1 -0
  42. package/src/components/xt-card-item/images/line.svg +1 -0
  43. package/src/components/xt-card-item/images/pie.svg +1 -0
  44. package/src/components/xt-card-item/index copy.vue +93 -0
  45. package/src/components/xt-card-item/index.vue +23 -83
  46. package/src/components/xt-card-item/style/index copy.scss +72 -0
  47. package/src/components/xt-card-item/style/index.scss +51 -40
  48. package/src/components/xt-config-provider/index.vue +2 -2
  49. package/src/components/xt-text/index.vue +58 -29
  50. package/src/index.js +3 -0
  51. package/src/components/ex-chart/ExTrend.vue +0 -124
@@ -0,0 +1,591 @@
1
+ ## ExTable - 扩展表格组件
2
+
3
+ 基于 ElementUI Table 二次封装的增强表格组件,支持虚拟滚动、多级表头、行合并、小计/总计等高级功能。
4
+
5
+ ## 基本用法
6
+
7
+ ::: demo 基本用法
8
+ ```vue
9
+ <template>
10
+ <ExTable
11
+ :height="300"
12
+ title="用户列表"
13
+ :tableData="tableData"
14
+ :columns="columns"
15
+ :pagination="pagination"
16
+ :total="total"
17
+ >
18
+ <template #toolbar>
19
+ <el-button size="small" @click="handleRefresh">刷新</el-button>
20
+ <el-button size="small" type="primary" @click="handleExport">导出</el-button>
21
+ </template>
22
+ </ExTable>
23
+ </template>
24
+
25
+ <script>
26
+ export default {
27
+ data() {
28
+ return {
29
+ tableData: [
30
+ { name: '张三', age: 25, score: 65 },
31
+ { name: '李四', age: 30, score: 78 },
32
+ { name: '王五', age: 28, score: 89 },
33
+ { name: '赵六', age: 22, score: 95 },
34
+ { name: '钱七', age: 26, score: 72 }
35
+ ],
36
+ columns: [
37
+ { prop: 'name', label: '姓名' },
38
+ { prop: 'age', label: '年龄' },
39
+ { prop: 'score', label: '分数' }
40
+ ],
41
+ pagination: {
42
+ pageNum: 1,
43
+ pageSize: 2
44
+ },
45
+ total: 5
46
+ }
47
+ },
48
+ methods: {
49
+ handleRefresh() {
50
+ console.log('刷新数据')
51
+ },
52
+ handleExport() {
53
+ // 自定义导出逻辑
54
+ console.log('导出数据:', this.tableData)
55
+ }
56
+ }
57
+ }
58
+ </script>
59
+ ```
60
+ :::
61
+
62
+ ## 属性说明
63
+
64
+ | 属性 | 类型 | 默认值 | 说明 |
65
+ |------|------|--------|------|
66
+ | `tableData` | Array | [] | 表格数据 |
67
+ | `columns` | Array | [] | 列配置(支持 children 多级表头) |
68
+ | `groupColumns` | Array | [] | 分组列配置,按配置的层级相同且父级相同的数据合并单元格 |
69
+ | `title` | String | '' | 表格标题 |
70
+ | `height` | Number/String | null | 表格高度 |
71
+ | `virtualScroll` | Boolean | false | 是否启用虚拟滚动 |
72
+ | `rowInitHeight` | Number | 48 | 预估行高(单位:px) |
73
+ | `bufferSize` | Number | 5 | 缓冲区行数(前后各n行) |
74
+ | `pagination` | Object | null | 分页配置,包含 `pageNum`(当前页)、`pageSize`(每页条数) |
75
+ | `total` | Number | 0 | 总条数 |
76
+ | `showIndex` | Boolean | false | 是否显示序号列 |
77
+ | `selection` | Boolean | false | 是否显示选择列 |
78
+ | `selectionFixed` | String/Boolean | false | 选择列固定位置('left'/'right'/false) |
79
+ | `indexFixed` | String/Boolean | false | 序号列固定位置('left'/'right'/false) |
80
+ | `loading` | Boolean | false | 加载状态 |
81
+ | `emptyText` | String | '暂无数据' | 空数据文案 |
82
+ | `subtotalConfig` | Object | { enabled: false } | 小计配置,详见下文 |
83
+ | `totalConfig` | Object | { enabled: false } | 总计配置,详见下文 |
84
+
85
+ ## 事件说明
86
+
87
+ | 事件名 | 参数 | 说明 |
88
+ |--------|------|------|
89
+ | `page-change` | pageNum | 页码改变 |
90
+ | `size-change` | pageSize | 每页条数改变 |
91
+ | `selection-change` | rows | 选择项改变 |
92
+ | `sort-change` | { prop, order } | 排序改变 |
93
+
94
+ ## 方法说明
95
+
96
+ | 方法名 | 参数 | 说明 |
97
+ |--------|------|------|
98
+ | `getSelection()` | - | 获取选中行 |
99
+ | `clearSelection()` | - | 清除选中状态 |
100
+ | `toggleRowSelection(row, selected)` | row: Object, selected: Boolean | 切换行选中状态 |
101
+ | `toggleRowsSelection(rows, selected)` | rows: Array/Object, selected: Boolean | 批量切换选中状态 |
102
+ | `doLayout()` | - | 重新布局 |
103
+
104
+ ## 多级表头
105
+
106
+ 支持通过 `children` 嵌套实现多级表头:
107
+
108
+ ::: demo 多级表头
109
+ ```vue
110
+ <template>
111
+ <ExTable
112
+ :height="300"
113
+ :tableData="tableData"
114
+ :columns="columns"
115
+ ></ExTable>
116
+ </template>
117
+
118
+ <script>
119
+ export default {
120
+ data() {
121
+ return {
122
+ columns: [
123
+ { prop: 'name', label: '姓名' },
124
+ {
125
+ label: '成绩',
126
+ children: [
127
+ { prop: 'math', label: '数学' },
128
+ { prop: 'english', label: '英语' },
129
+ { prop: 'chinese', label: '语文' }
130
+ ]
131
+ },
132
+ { prop: 'total', label: '总分' }
133
+ ],
134
+ tableData: [
135
+ { name: '张三', math: 90, english: 85, chinese: 92, total: 267 },
136
+ { name: '李四', math: 88, english: 90, chinese: 85, total: 263 },
137
+ { name: '王五', math: 95, english: 88, chinese: 90, total: 273 }
138
+ ]
139
+ }
140
+ }
141
+ }
142
+ </script>
143
+ ```
144
+ :::
145
+
146
+ ## 行合并(分组列)
147
+
148
+ 通过 `groupColumns` 配置按指定列分组合并单元格:
149
+
150
+ ::: demo 行合并
151
+ ```vue
152
+ <template>
153
+ <ExTable
154
+ :height="300"
155
+ :tableData="tableData"
156
+ :columns="columns"
157
+ :groupColumns="['department', 'team']"
158
+ ></ExTable>
159
+ </template>
160
+
161
+ <script>
162
+ export default {
163
+ data() {
164
+ return {
165
+ columns: [
166
+ { prop: 'department', label: '部门' },
167
+ { prop: 'team', label: '团队' },
168
+ { prop: 'name', label: '姓名' },
169
+ { prop: 'position', label: '职位' }
170
+ ],
171
+ tableData: [
172
+ { department: '研发部', team: '前端组', name: '张三', position: '前端工程师' },
173
+ { department: '研发部', team: '前端组', name: '李四', position: '前端工程师' },
174
+ { department: '研发部', team: '后端组', name: '王五', position: '后端工程师' },
175
+ { department: '产品部', team: '产品组', name: '赵六', position: '产品经理' },
176
+ { department: '产品部', team: '设计组', name: '钱七', position: 'UI设计师' }
177
+ ]
178
+ }
179
+ }
180
+ }
181
+ </script>
182
+ ```
183
+ :::
184
+
185
+ ## 小计与总计
186
+
187
+ 通过 `subtotalConfig` 和 `totalConfig` 配置小计和总计行:
188
+
189
+ ::: demo 小计与总计
190
+ ```vue
191
+ <template>
192
+ <ExTable
193
+ :height="300"
194
+ :tableData="tableData"
195
+ :columns="columns"
196
+ :subtotalConfig="subtotalConfig"
197
+ :totalConfig="totalConfig"
198
+ ></ExTable>
199
+ </template>
200
+
201
+ <script>
202
+ export default {
203
+ data() {
204
+ return {
205
+ columns: [
206
+ { prop: 'region', label: '区域' },
207
+ { prop: 'product', label: '产品' },
208
+ { prop: 'quantity', label: '数量' },
209
+ { prop: 'amount', label: '金额' }
210
+ ],
211
+ tableData: [
212
+ { region: '华东区', product: 'A产品', quantity: 10, amount: 1000 },
213
+ { region: '华东区', product: 'B产品', quantity: 20, amount: 2000 },
214
+ { region: '华南区', product: 'A产品', quantity: 15, amount: 1500 },
215
+ { region: '华南区', product: 'B产品', quantity: 25, amount: 2500 },
216
+ { region: '华北区', product: 'A产品', quantity: 12, amount: 1200 },
217
+ { region: '华北区', product: 'B产品', quantity: 18, amount: 1800 }
218
+ ],
219
+ subtotalConfig: {
220
+ enabled: true,
221
+ groupBy: ['region'],
222
+ labelText: '小计',
223
+ columns: {
224
+ quantity: 'sum',
225
+ amount: 'sum'
226
+ }
227
+ },
228
+ totalConfig: {
229
+ enabled: true,
230
+ labelText: '总计',
231
+ columns: {
232
+ quantity: 'sum',
233
+ amount: 'sum'
234
+ }
235
+ }
236
+ }
237
+ }
238
+ }
239
+ </script>
240
+ ```
241
+ :::
242
+
243
+ ### 小计/总计配置说明
244
+
245
+ **subtotalConfig 配置项:**
246
+ | 字段 | 类型 | 说明 |
247
+ |------|------|------|
248
+ | `enabled` | Boolean | 是否启用小计 |
249
+ | `groupBy` | Array | 分组字段数组 |
250
+ | `labelText` | String | 小计行标签文字,默认 `${分组值} 小计` |
251
+ | `columns` | Object | 各列的聚合配置 |
252
+
253
+ **totalConfig 配置项:**
254
+ | 字段 | 类型 | 说明 |
255
+ |------|------|------|
256
+ | `enabled` | Boolean | 是否启用总计 |
257
+ | `labelText` | String | 总计行标签文字,默认 `总计` |
258
+ | `columns` | Object | 各列的聚合配置 |
259
+
260
+ **columns 聚合配置方式:**
261
+ - 字符串简写:`'sum'`、`'avg'`、`'count'`、`'min'`、`'max'`
262
+ - 对象配置:`{ prop: 'field', type: 'sum' }`
263
+ - 自定义函数:`(rows) => customCalc(rows)`
264
+
265
+ ## 虚拟滚动
266
+
267
+ ::: demo 虚拟滚动
268
+ ```vue
269
+ <template>
270
+ <ExTable
271
+ :height="300"
272
+ :virtual-scroll="true"
273
+ :row-init-height="48"
274
+ :buffer-size="5"
275
+ :tableData="largeData"
276
+ :columns="columns"
277
+ ></ExTable>
278
+ </template>
279
+
280
+ <script>
281
+
282
+
283
+ export default {
284
+ data() {
285
+ return {
286
+ columns: [
287
+ { prop: 'id', label: 'ID', width: "200", fixed: 'left' },
288
+ { prop: 'name', label: '姓名', width: "200", fixed: 'left' },
289
+ { prop: 'department', label: '部门', minWidth: "300" },
290
+ { prop: 'position', label: '职位', width: "200" },
291
+ { prop: 'salary', label: '薪资', minWidth: "200" },
292
+ { prop: 'status', label: '状态', width: "200", fixed: 'right' }
293
+ ],
294
+ largeData: this.createVirtualScrollData(10000)
295
+ }
296
+ }
297
+ }
298
+ </script>
299
+ ```
300
+ :::
301
+
302
+ ### 虚拟滚动演示数据
303
+
304
+ 提供 `createVirtualScrollData` 工具函数,快速生成大量测试数据:
305
+
306
+ ```javascript
307
+ import { createVirtualScrollData, virtualScrollColumns } from 'xt-element-ui'
308
+
309
+ // 生成 10000 条演示数据
310
+ const tableData = createVirtualScrollData(10000)
311
+
312
+ // 或使用预设列配置
313
+ const columns = virtualScrollColumns
314
+ ```
315
+
316
+ ## 自定义插槽
317
+
318
+ ### 工具栏插槽
319
+
320
+ ::: demo 工具栏插槽
321
+ ```vue
322
+ <template>
323
+ <ExTable
324
+ title="用户管理"
325
+ :tableData="tableData"
326
+ :columns="columns"
327
+ >
328
+ <template #toolbar>
329
+ <el-button size="small" type="primary">新增</el-button>
330
+ <el-button size="small">导入</el-button>
331
+ <el-button size="small" type="danger">批量删除</el-button>
332
+ </template>
333
+ </ExTable>
334
+ </template>
335
+
336
+ <script>
337
+ export default {
338
+ data() {
339
+ return {
340
+ columns: [
341
+ { prop: 'name', label: '姓名' },
342
+ { prop: 'age', label: '年龄' },
343
+ { prop: 'email', label: '邮箱' }
344
+ ],
345
+ tableData: [
346
+ { name: '张三', age: 25, email: 'zhangsan@example.com' },
347
+ { name: '李四', age: 30, email: 'lisi@example.com' }
348
+ ]
349
+ }
350
+ }
351
+ }
352
+ </script>
353
+ ```
354
+ :::
355
+
356
+ ### 自定义列插槽
357
+
358
+ ::: demo 自定义列插槽
359
+ ```vue
360
+ <template>
361
+ <ExTable
362
+ :height="300"
363
+ :tableData="tableData"
364
+ :columns="columns"
365
+ >
366
+ <template #action="{ row }">
367
+ <el-button size="small" @click="handleEdit(row)">编辑</el-button>
368
+ <el-button size="small" type="danger" @click="handleDelete(row)">删除</el-button>
369
+ </template>
370
+ </ExTable>
371
+ </template>
372
+
373
+ <script>
374
+ export default {
375
+ data() {
376
+ return {
377
+ columns: [
378
+ { prop: 'name', label: '姓名' },
379
+ { prop: 'age', label: '年龄' },
380
+ { slot: 'action', label: '操作', width: '150' }
381
+ ],
382
+ tableData: [
383
+ { name: '张三', age: 25 },
384
+ { name: '李四', age: 30 },
385
+ { name: '王五', age: 28 }
386
+ ]
387
+ }
388
+ },
389
+ methods: {
390
+ handleEdit(row) {
391
+ console.log('编辑:', row)
392
+ },
393
+ handleDelete(row) {
394
+ console.log('删除:', row)
395
+ }
396
+ }
397
+ }
398
+ </script>
399
+ ```
400
+ :::
401
+
402
+ ## 选择功能
403
+
404
+ ::: demo 选择功能
405
+ ```vue
406
+ <template>
407
+ <div>
408
+ <el-button size="small" @click="handleGetSelection">获取选中</el-button>
409
+ <el-button size="small" @click="handleClearSelection">清除选中</el-button>
410
+ <ExTable
411
+ :height="300"
412
+ :tableData="tableData"
413
+ :columns="columns"
414
+ :selection="true"
415
+ :selectionFixed="'left'"
416
+ @selection-change="handleSelectionChange"
417
+ ></ExTable>
418
+ </div>
419
+ </template>
420
+
421
+ <script>
422
+ export default {
423
+ data() {
424
+ return {
425
+ columns: [
426
+ { prop: 'name', label: '姓名' },
427
+ { prop: 'age', label: '年龄' },
428
+ { prop: 'department', label: '部门' }
429
+ ],
430
+ tableData: [
431
+ { name: '张三', age: 25, department: '研发部' },
432
+ { name: '李四', age: 30, department: '产品部' },
433
+ { name: '王五', age: 28, department: '运营部' }
434
+ ]
435
+ }
436
+ },
437
+ methods: {
438
+ handleSelectionChange(rows) {
439
+ console.log('选中:', rows)
440
+ },
441
+ handleGetSelection() {
442
+ console.log('获取选中:', this.$refs.table.getSelection())
443
+ },
444
+ handleClearSelection() {
445
+ this.$refs.table.clearSelection()
446
+ }
447
+ }
448
+ }
449
+ </script>
450
+ ```
451
+ :::
452
+
453
+ ## 自定义 formatter 渲染
454
+
455
+ 通过 `formatter` 属性可以实现自定义单元格渲染,支持返回字符串、数字或 VNode:
456
+
457
+ ::: demo 自定义 formatter 渲染
458
+ ```vue
459
+ <template>
460
+ <ExTable
461
+ :height="300"
462
+ :tableData="tableData"
463
+ :columns="columns"
464
+ ></ExTable>
465
+ </template>
466
+
467
+ <script>
468
+ export default {
469
+ data() {
470
+ return {
471
+ columns: [
472
+ { prop: 'name', label: '姓名' },
473
+ {
474
+ prop: 'status',
475
+ label: '状态',
476
+ formatter: (h, { row }) => {
477
+ const map = {
478
+ active: { text: '在职', color: '#67c23a' },
479
+ leave: { text: '休假', color: '#e6a23c' },
480
+ quit: { text: '离职', color: '#f56c6c' }
481
+ }
482
+ const info = map[row.status] || { text: row.status, color: '#909399' }
483
+ return h('span', {
484
+ style: { color: info.color, fontWeight: '500' }
485
+ }, info.text)
486
+ }
487
+ },
488
+ {
489
+ prop: 'score',
490
+ label: '分数',
491
+ formatter: (h, { row }) => {
492
+ if (row.score >= 90) return h('el-tag', { props: { type: 'success', size: 'mini' }}, '优秀')
493
+ if (row.score >= 60) return h('el-tag', { props: { type: 'warning', size: 'mini' }}, '合格')
494
+ return h('el-tag', { props: { type: 'danger', size: 'mini' }}, '不及格')
495
+ }
496
+ }
497
+ ],
498
+ tableData: [
499
+ { name: '张三', status: 'active', score: 92 },
500
+ { name: '李四', status: 'leave', score: 75 },
501
+ { name: '王五', status: 'active', score: 88 },
502
+ { name: '赵六', status: 'quit', score: 55 }
503
+ ]
504
+ }
505
+ }
506
+ }
507
+ </script>
508
+ ```
509
+ :::
510
+
511
+ ## 虚拟滚动(大数据场景)
512
+
513
+ 当数据量超过 **1000 条** 时,建议开启虚拟滚动以提升性能。虚拟滚动只会渲染可视区域内的行,大大减少 DOM 节点数量。
514
+
515
+ ::: demo 虚拟滚动
516
+ ```vue
517
+ <template>
518
+ <ExTable
519
+ :height="400"
520
+ :virtual-scroll="true"
521
+ :row-init-height="48"
522
+ :buffer-size="5"
523
+ :tableData="largeData"
524
+ :columns="columns"
525
+ ></ExTable>
526
+ </template>
527
+
528
+ <script>
529
+ export default {
530
+ data() {
531
+ const depts = ['研发部', '产品部', '运营部', '财务部', '市场部']
532
+ const positions = ['工程师', '产品经理', '运营专员', '财务主管', '市场经理']
533
+ return {
534
+ columns: [
535
+ { prop: 'id', label: 'ID', width: 80, fixed: 'left' },
536
+ { prop: 'name', label: '姓名', width: 120, fixed: 'left' },
537
+ { prop: 'department', label: '部门', width: 150 },
538
+ { prop: 'position', label: '职位', width: 150 },
539
+ { prop: 'email', label: '邮箱', width: 200 },
540
+ { prop: 'phone', label: '电话', width: 130 },
541
+ { prop: 'salary', label: '薪资', width: 120 },
542
+ { prop: 'status', label: '状态', width: 100, fixed: 'right' }
543
+ ],
544
+ largeData: Array.from({ length: 5000 }, (_, i) => ({
545
+ id: i + 1,
546
+ name: `用户${i + 1}`,
547
+ department: depts[i % depts.length],
548
+ position: positions[i % positions.length],
549
+ email: `user${i + 1}@example.com`,
550
+ phone: `13800138${String(i).padStart(4, '0')}`,
551
+ salary: 5000 + Math.floor(Math.random() * 10000),
552
+ status: ['在职', '休假', '离职'][i % 3]
553
+ }))
554
+ }
555
+ }
556
+ }
557
+ </script>
558
+ ```
559
+ :::
560
+
561
+ ## 列配置详解
562
+
563
+ | 属性 | 类型 | 说明 |
564
+ |------|------|------|
565
+ | `prop` | String | 数据字段名 |
566
+ | `label` | String | 表头文字 |
567
+ | `width` | Number/String | 列宽(数字单位为 px) |
568
+ | `minWidth` | Number/String | 最小列宽 |
569
+ | `fixed` | String/Boolean | 固定列位置,可选 `'left'` / `'right'` / `true` |
570
+ | `align` | String | 对齐方式,可选 `'left'` / `'center'` / `'right'` |
571
+ | `children` | Array | 多级表头子列配置(嵌套使用) |
572
+ | `formatter` | Function | 自定义渲染函数,签名:`(h, { row, index, column }) => VNode \| String` |
573
+ | `slot` | String | 自定义插槽名,配合组件的具名插槽使用 |
574
+
575
+ ## 虚拟滚动注意事项
576
+
577
+ - 必须设置表格高度(`height` 属性),否则虚拟滚动无法计算可视区域
578
+ - `rowInitHeight` 建议与实际行高一致,否则会出现滚动偏移
579
+ - 虚拟滚动模式下**不支持**行合并(`groupColumns`)和小计/总计功能
580
+ - 数据量大于 5000 条时建议配合后端分页使用
581
+
582
+ ## 常见问题
583
+
584
+ **Q: 表格渲染空白?**
585
+ - A: 检查是否设置了 `height` 属性,特别是开启虚拟滚动时必须设置高度。
586
+
587
+ **Q: 分页切换时数据不更新?**
588
+ - A: 确保 `tableData` 是响应式数据,更新时使用赋值方式(`this.tableData = newData`)。
589
+
590
+ **Q: 选择功能返回的数据包含小计/总计行?**
591
+ - A: `getSelection()` 方法和 `selection-change` 事件已自动过滤掉 `_rowType` 标记的小计/总计行,无需额外处理。