@agile-team/wl-skills-kit 2.11.1 → 2.11.3

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 (91) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +38 -21
  3. package/bin/wl-skills.js +27 -3
  4. package/files/.wl-skills/docs/jh-pagination.md +505 -505
  5. package/files/.wl-skills/docs/request.md +940 -940
  6. package/files/.wl-skills/docs/validate-exempt.md +113 -0
  7. package/files/.wl-skills/guides/architecture.md +1 -1
  8. package/files/.wl-skills/skills/_compat/headers/cursor-mdc.txt +1 -1
  9. package/files/.wl-skills/skills/_compat/headers/kiro.txt +1 -1
  10. package/files/.wl-skills/skills/_compat/headers/trae.txt +1 -1
  11. package/files/.wl-skills/skills/core/convention-audit/SKILL.md +3 -3
  12. package/files/.wl-skills/skills/core/spec-doc-parse/SKILL.md +332 -332
  13. package/files/.wl-skills/skills/core/spec-doc-parse/USAGE.md +97 -97
  14. package/files/.wl-skills/skills/sync/permission-sync/USAGE.md +107 -107
  15. package/files/.wl-skills/src/components/global/C_ParentView/index.vue +3 -3
  16. package/files/.wl-skills/src/components/global/C_RightToolbar/index.vue +157 -157
  17. package/files/.wl-skills/src/components/global/C_SvgIcon/index.vue +31 -31
  18. package/files/.wl-skills/src/components/global/C_SvgIcon/svgicon.js +10 -10
  19. package/files/.wl-skills/src/components/global/C_TagStatus/README.md +264 -264
  20. package/files/.wl-skills/src/components/global/C_TagStatus/config.ts +192 -192
  21. package/files/.wl-skills/src/components/global/C_TagStatus/index.vue +106 -106
  22. package/files/.wl-skills/src/components/global/C_TagStatus/types.ts +64 -64
  23. package/files/.wl-skills/src/components/global/C_Tree/README.md +153 -153
  24. package/files/.wl-skills/src/components/global/C_Tree/index.scss +42 -42
  25. package/files/.wl-skills/src/components/global/C_Tree/index.vue +78 -78
  26. package/files/.wl-skills/src/components/global/C_Tree/types.ts +59 -59
  27. package/files/.wl-skills/src/components/local/c_formModal/README.md +235 -235
  28. package/files/.wl-skills/src/components/local/c_formModal/data.ts +95 -95
  29. package/files/.wl-skills/src/components/local/c_formModal/index.scss +8 -8
  30. package/files/.wl-skills/src/components/local/c_formModal/index.vue +107 -107
  31. package/files/.wl-skills/src/components/local/c_formSections/data.ts +175 -175
  32. package/files/.wl-skills/src/components/local/c_formSections/index.scss +280 -280
  33. package/files/.wl-skills/src/components/local/c_formSections/index.vue +429 -429
  34. package/files/.wl-skills/src/components/local/c_listModal/data.ts +41 -41
  35. package/files/.wl-skills/src/components/local/c_listModal/index.vue +136 -136
  36. package/files/.wl-skills/src/components/local/c_spliterTitle/index.scss +25 -25
  37. package/files/.wl-skills/src/components/local/c_spliterTitle/index.vue +21 -21
  38. package/files/.wl-skills/src/components/remote/AGGrid/README.md +530 -530
  39. package/files/.wl-skills/src/components/remote/BaseForm/README.md +508 -508
  40. package/files/.wl-skills/src/components/remote/BaseQuery/README.md +865 -865
  41. package/files/.wl-skills/src/components/remote/BaseTable/README.md +941 -941
  42. package/files/.wl-skills/src/components/remote/BaseToolbar/README.md +496 -496
  43. package/files/.wl-skills/src/types/page.ts +24 -24
  44. package/files/.wl-skills/standards/04-coding-basics.md +39 -1
  45. package/files/.wl-skills/standards/09-typescript.md +26 -3
  46. package/files/.wl-skills/standards/12-base-table.md +56 -4
  47. package/files/.wl-skills/standards/13-platform-components.md +1 -0
  48. package/files/.wl-skills/standards/index.md +2 -2
  49. package/files/.wl-skills/templates/README.md +44 -44
  50. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/api.md +54 -54
  51. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/data.ts +346 -346
  52. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/index.scss +1 -1
  53. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add/index.vue +28 -28
  54. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/data.ts +115 -115
  55. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/index.scss +44 -44
  56. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-add-form/index.vue +43 -43
  57. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/data.ts +338 -338
  58. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/index.scss +1 -1
  59. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change/index.vue +28 -28
  60. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/data.ts +115 -115
  61. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/index.scss +44 -44
  62. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-apply-change-form/index.vue +43 -43
  63. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/api.md +88 -88
  64. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/data.ts +601 -601
  65. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/index.scss +1 -1
  66. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-archive/index.vue +64 -64
  67. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/api.md +67 -67
  68. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/data.ts +286 -286
  69. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/index.scss +139 -139
  70. package/files/.wl-skills/templates/produce/aiflow/mmwr-customer-detail/index.vue +318 -318
  71. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/api.md +98 -98
  72. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/data.ts +543 -543
  73. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/index.scss +1 -1
  74. package/files/.wl-skills/templates/produce/aiflow/mmwr-temp-customer-archive/index.vue +52 -52
  75. package/files/.wl-skills/templates/sale/demo/add-demo/data.ts +518 -518
  76. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/data.ts +524 -524
  77. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/index.scss +154 -154
  78. package/files/.wl-skills/templates/sale/demo/billet-flame-cut-plan/index.vue +117 -117
  79. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/data.ts +308 -308
  80. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/index.scss +99 -99
  81. package/files/.wl-skills/templates/sale/demo/domestic-trade-order/index.vue +77 -77
  82. package/files/.wl-skills/templates/sale/demo/heat-batch-return/data.ts +367 -367
  83. package/files/.wl-skills/templates/sale/demo/heat-batch-return/index.scss +100 -100
  84. package/files/.wl-skills/templates/sale/demo/heat-batch-return/index.vue +170 -170
  85. package/files/.wl-skills/templates/sale/demo/heat-batch-return/meltDialog.vue +320 -320
  86. package/files/.wl-skills/templates/sale/demo/metallurgical-spec/data.ts +824 -824
  87. package/lib/ast-rules.js +395 -12
  88. package/mcp/config.js +46 -46
  89. package/mcp/registry.js +6 -1
  90. package/mcp/tools/projectTools.js +9 -1
  91. package/package.json +2 -2
@@ -1,941 +1,941 @@
1
- # BaseTable 表格组件
2
-
3
- > 来源:`@jhlc/common-core` 远程组件
4
-
5
- BaseTable 是一个功能强大的表格组件,支持数据展示、排序、筛选、选择、操作按钮、可编辑单元格等功能。支持 DataTable 和 AGGrid 两种渲染模式。
6
-
7
- ## 📦 导入方式
8
-
9
- ```typescript
10
- // 全局注册(已在项目中配置)
11
- // 直接使用 <BaseTable /> 即可
12
-
13
- // 类型导入
14
- import type { TableColumnDesc } from "@jhlc/common-core/.wl-skills/src/components/table/base-table/type";
15
- ```
16
-
17
- ## 🚀 基本用法
18
-
19
- ```vue
20
- <template>
21
- <BaseTable
22
- ref="tableRef"
23
- :data="list"
24
- :columns="columns"
25
- showToolbar
26
- border
27
- />
28
- </template>
29
-
30
- <script setup lang="ts">
31
- import { ref, computed } from "vue";
32
-
33
- const tableRef = ref();
34
- const list = ref([
35
- { id: 1, name: "张三", age: 25, status: "在职" },
36
- { id: 2, name: "李四", age: 30, status: "离职" }
37
- ]);
38
-
39
- const columns = computed(() => [
40
- { type: "selection" },
41
- { type: "index" },
42
- { label: "姓名", name: "name" },
43
- { label: "年龄", name: "age" },
44
- { label: "状态", name: "status" }
45
- ]);
46
- </script>
47
- ```
48
-
49
- ---
50
-
51
- ## 📋 Props 属性
52
-
53
- ### 基础属性
54
-
55
- | 属性名 | 类型 | 默认值 | 说明 |
56
- | ----------------------------- | -------------------------------- | ------------------- | -------------------------- |
57
- | `data` | `Array` | `[]` | 表格数据源 |
58
- | `columns` | `TableColumnDesc[]` | `[]` | 列配置数组 |
59
- | `renderType` | `'' \| 'dataTable' \| 'agGrid'` | `''` | 渲染类型 |
60
- | `rowId` | `string` | `'_id'` | 行数据唯一标识字段 |
61
- | `rowKey` | `string` | `'_id'` | 行数据的键(树形表格必需) |
62
- | `childrenKey` | `string` | `'children'` | 子节点字段名 |
63
-
64
- ### 外观属性
65
-
66
- | 属性名 | 类型 | 默认值 | 说明 |
67
- | ----------------------------- | -------------------------------- | ------------------- | -------------------------- |
68
- | `border` | `boolean` | `true` | 是否显示边框 |
69
- | `stripe` | `boolean` | `true` | 是否显示斑马纹 |
70
- | `size` | `'small' \| 'default' \| 'large'`| - | 表格尺寸 |
71
- | `height` | `number` | - | 表格高度 |
72
- | `maxHeight` | `number` | - | 表格最大高度 |
73
- | `autoHeight` | `boolean` | `false` | 自动调整高度 |
74
- | `showHeader` | `boolean` | `true` | 是否显示表头 |
75
- | `showToolbar` | `boolean` | `false` | 是否显示工具栏 |
76
- | `fixed` | `boolean` | - | 是否固定表头 |
77
-
78
- ### 选择相关
79
-
80
- | 属性名 | 类型 | 默认值 | 说明 |
81
- | ----------------------------- | -------------------------------- | ------------------- | -------------------------- |
82
- | `selectMethod` | `'dblclick' \| 'click' \| ''` | `''` | 选中方式 |
83
- | `selectedRow` | `string \| number` | - | 单选选中行 |
84
- | `selectedValue` | `string \| number` | - | 单选选中值 |
85
- | `selectionRows` | `Array` | `[]` | 多选选中的行 |
86
- | `selectionType` | `number` | `2` | 多选类型 2:全选 1:半选和全选 |
87
- | `persistSelect` | `boolean` | `false` | 持久化选择 |
88
- | `autoCheckedChildren` | `boolean` | `true` | 自动勾选子节点 |
89
- | `highlightCurrentRow` | `boolean` | `false` | 高亮当前行 |
90
- | `currentRowSelectMethod` | `'dblclick' \| 'click'` | - | 当前行选中方式 |
91
-
92
- ### 功能相关
93
-
94
- | 属性名 | 类型 | 默认值 | 说明 |
95
- | ----------------------------- | -------------------------------- | ------------------- | -------------------------- |
96
- | `disabled` | `boolean` | `false` | 禁用输入框 |
97
- | `showSummary` | `boolean` | `false` | 显示汇总行 |
98
- | `summaryMethod` | `Function` | - | 自定义汇总方法 |
99
- | `defaultExpandAll` | `boolean` | `false` | 默认展开所有行 |
100
- | `virtual` | `boolean` | `true` | 虚拟滚动 |
101
- | `frontSort` | `boolean` | `false` | 前端排序 |
102
- | `frontFiltering` | `boolean` | `false` | 前端过滤 |
103
- | `manualFiltering` | `boolean` | `false` | 手动过滤 |
104
- | `manualSorting` | `boolean` | `false` | 手动排序 |
105
- | `grouping` | `boolean` | `false` | 分组 |
106
- | `groupFields` | `string[]` | - | 分组字段 |
107
- | `columnVisibility` | `boolean` | `false` | 列可见性控制 |
108
- | `showEditIcon` | `boolean` | `true` | 显示编辑图标 |
109
-
110
- ### AGGrid 专用
111
-
112
- | 属性名 | 类型 | 默认值 | 说明 |
113
- | ----------------------------- | -------------------------------- | ------------------- | -------------------------- |
114
- | `tree` | `boolean` | `false` | 树形结构 |
115
- | `quickEditCursor` | `boolean` | `true` | 快速编辑光标 |
116
- | `selection` | `Array` | - | 选中项 |
117
- | `isRowSelectable` | `Function` | - | 行是否可选 |
118
- | `isGroupOpenByDefault` | `Function` | - | 分组默认展开 |
119
- | `rowGroupPanelShow` | `'never' \| 'onlyWhenGrouping' \| 'always'` | `'onlyWhenGrouping'` | 行分组面板显示 |
120
- | `grandTotalRow` | `string` | - | 总计行位置 |
121
- | `pinnedTopRowData` | `Array` | - | 固定顶部行数据 |
122
- | `pinnedBottomRowData` | `Array` | - | 固定底部行数据 |
123
- | `isRowPinned` | `Function` | - | 行是否固定 |
124
- | `suppressRowClickSelection` | `boolean` | `false` | 禁止行点击选择 |
125
- | `rowClass` | `Function` | - | 行样式类 |
126
- | `rowStyle` | `Function` | - | 行样式 |
127
- | `rowClassRules` | `Object` | - | 行样式规则 |
128
- | `stopEditingWhenCellsLoseFocus` | `boolean` | `false` | 失焦停止编辑 |
129
- | `isRowValidDropPosition` | `Function` | - | 行是否为有效拖放位置 |
130
-
131
- ---
132
-
133
- ## 📋 Events 事件
134
-
135
- | 事件名 | 参数 | 说明 |
136
- | ------------------- | --------------------------------------- | ------------------ |
137
- | `selectionChange` | `selection: any[]` | 多选项发生变化 |
138
- | `select` | `selection, row, status, params` | 选择某一行 |
139
- | `selectAll` | `selection, status` | 全选/取消全选 |
140
- | `currentChange` | `currentRow` | 当前行变化 |
141
- | `row-click` | `row, column, event` | 行点击事件 |
142
- | `row-dblclick` | `row, column, event` | 行双击事件 |
143
- | `expand-change` | `row, expanded` | 展开/收起变化 |
144
- | `filterModified` | - | 过滤条件修改 |
145
- | `filterChanged` | - | 过滤条件变化 |
146
- | `update:selectedRow`| `row` | 单选行更新 |
147
- | `update:selectedValue`| `value` | 单选值更新 |
148
- | `mounted` | `{ parentEl }` | 组件挂载完成 |
149
-
150
- ---
151
-
152
- ## 📋 Expose 方法 (通过 ref 调用)
153
-
154
- ### 选择相关
155
-
156
- | 方法名 | 参数 | 返回值 | 说明 |
157
- | --------------------- | --------------------------------- | --------- | -------------------------- |
158
- | `getSelection` | `check?: 1\|2, firstLevel?: boolean` | `any[]` | 获取选中行 (2:全选,1:半选+全选) |
159
- | `getVisibleSelection` | `check?: 1\|2, firstLevel?: boolean` | `any[]` | 获取可见选中行 |
160
- | `getRootSelection` | `check?: 1\|2` | `any[]` | 获取根节点选中行 |
161
- | `getAllSelection` | `check?: 1\|2` | `any[]` | 获取所有选中行 |
162
- | `getTreeSelection` | `type?: 'flat'\|'tree'` | `any[]` | 获取树形选中行 |
163
- | `getSingleSelectRow` | - | `object` | 获取单选行 |
164
- | `getSelectionRows` | - | `any[]` | 获取选中的行 |
165
- | `toggleRowSelection` | `row, selected: boolean` | - | 切换行选中状态 |
166
- | `toggleAllSelection` | - | - | 切换全选状态 |
167
- | `setCurrentRow` | `row` | - | 设置当前高亮行 |
168
- | `clearSelection` | - | - | 清空选中 |
169
- | `setSelect` | `row, status: boolean` | - | 设置行选中状态 |
170
- | `setSelection` | - | - | 设置选中 |
171
- | `selectAll` | - | - | 全选 |
172
- | `deselectAll` | - | - | 取消全选 |
173
-
174
- ### 验证相关
175
-
176
- | 方法名 | 参数 | 返回值 | 说明 |
177
- | -------------------- | --------------------------------- | --------- | -------------------------- |
178
- | `validate` | `callback: (valid: boolean) => void` | - | 验证整个表格 |
179
- | `validateRow` | - | - | 验证单行 |
180
- | `validateRows` | `rows, cb: (valid: boolean) => void` | - | 验证多行 |
181
- | `clearValidation` | - | - | 清除验证 |
182
- | `clearRowValidation` | - | - | 清除行验证 |
183
-
184
- ### 数据操作
185
-
186
- | 方法名 | 参数 | 返回值 | 说明 |
187
- | -------------------- | --------------------------------- | --------- | -------------------------- |
188
- | `setRowValue` | `row, name, index, value` | - | 设置行字段值 |
189
- | `setDataValue` | `row, key, value` | - | 设置数据值 |
190
- | `updateRow` | `data` | - | 更新行数据 |
191
- | `getTableData` | - | `any[]` | 获取表格数据 |
192
- | `getParentRow` | `row` | `object` | 获取父行 |
193
- | `isTableReady` | `row` | `boolean` | 表格是否就绪 |
194
-
195
- ### 编辑状态
196
-
197
- | 方法名 | 参数 | 返回值 | 说明 |
198
- | -------------------- | --------------------------------- | --------- | -------------------------- |
199
- | `resetRowEditState` | - | - | 重置行编辑状态 |
200
- | `resetEditState` | - | - | 重置编辑状态 |
201
-
202
- ### 刷新相关
203
-
204
- | 方法名 | 参数 | 返回值 | 说明 |
205
- | -------------------- | --------------------------------- | --------- | -------------------------- |
206
- | `refresh` | - | - | 刷新表格 |
207
- | `forceRefresh` | - | - | 强制刷新 |
208
- | `forceRefreshTable` | - | - | 强制刷新表格 |
209
- | `forceRefreshNode` | `node` | - | 强制刷新节点 |
210
- | `refreshColumnVisible` | - | - | 刷新列可见性 |
211
- | `refreshHeader` | - | - | 刷新表头 |
212
-
213
- ### 展开/折叠
214
-
215
- | 方法名 | 参数 | 返回值 | 说明 |
216
- | -------------------- | --------------------------------- | --------- | -------------------------- |
217
- | `expandAll` | - | - | 展开所有行 |
218
- | `collapseAll` | - | - | 折叠所有行 |
219
- | `expandRow` | `rowList` | - | 展开指定行 |
220
- | `collRow` | `row` | - | 折叠指定行 |
221
-
222
- ### 滚动/定位
223
-
224
- | 方法名 | 参数 | 返回值 | 说明 |
225
- | -------------------- | --------------------------------- | --------- | -------------------------- |
226
- | `goToRow` | `index: number` | - | 滚动到指定行 |
227
- | `goToColumn` | `name: string` | - | 滚动到指定列 |
228
-
229
- ### 导出
230
-
231
- | 方法名 | 参数 | 返回值 | 说明 |
232
- | -------------------- | --------------------------------- | --------- | -------------------------- |
233
- | `exportExcel` | `option: ExportTableExcelOption` | - | 导出 Excel |
234
-
235
- ### 其他
236
-
237
- | 方法名 | 参数 | 返回值 | 说明 |
238
- | -------------------- | --------------------------------- | --------- | -------------------------- |
239
- | `loading` | `time?: number` | - | 显示加载状态(默认6000ms) |
240
- | `closeLoading` | - | - | 关闭加载状态 |
241
- | `clearFilters` | - | - | 清除过滤 |
242
- | `setSuppressRowDrag` | `flag: boolean` | - | 设置是否可拖拽 |
243
- | `getRowKey` | - | `string` | 获取行键 |
244
- | `currentRow` | - | `object` | 当前高亮行 (computed) |
245
- | `data` | - | `any[]` | 表格数据 (computed) |
246
-
247
- ---
248
-
249
- ## 📋 列配置 TableColumnDesc
250
-
251
- ### 基础属性
252
-
253
- ```typescript
254
- interface TableColumnDesc<T = any> {
255
- // 列名(字段名)⚠️ 重要:使用 name 而非 prop
256
- name?: string;
257
- // 列标题
258
- label?: string;
259
- // 列类型
260
- type?: "index" | "selection" | "radio" | "expand";
261
- // 列宽
262
- width?: number;
263
- // 最小列宽
264
- minWidth?: number;
265
- // 弹性宽度
266
- flex?: number;
267
- // 对齐方式
268
- align?: "left" | "center" | "right";
269
- // 表头对齐
270
- headerAlign?: "left" | "center" | "right";
271
- // 固定列
272
- fixed?: "left" | "right";
273
- // 列宽可调整
274
- resizable?: boolean;
275
- // 是否可排序
276
- sortable?: boolean;
277
- // 超出省略号
278
- showOverflowTooltip?: boolean;
279
- // 允许换行
280
- wrapText?: boolean;
281
- // 自动调整行高
282
- autoHeight?: boolean;
283
- // 是否可过滤
284
- filterable?: boolean;
285
- }
286
- ```
287
-
288
- ### 自定义渲染 (⚠️ 重要)
289
-
290
- BaseTable 支持多种自定义渲染方式:
291
-
292
- #### 1. defaultSlot - 默认插槽 (推荐)
293
-
294
- ```typescript
295
- import { h } from "vue";
296
-
297
- {
298
- name: "title",
299
- label: "标题",
300
- // ✅ 正确方式:使用 defaultSlot + h 函数
301
- defaultSlot: ({ row, $index }) => {
302
- return h(
303
- "span",
304
- { style: "color: #409eff; cursor: pointer;" },
305
- row.title
306
- );
307
- }
308
- }
309
- ```
310
-
311
- #### 2. defaultNode - 低代码插槽
312
-
313
- ```typescript
314
- {
315
- name: "status",
316
- label: "状态",
317
- defaultNode: ({ row, $index, params }) => {
318
- return {
319
- tag: "el-tag",
320
- props: { type: row.status === 1 ? "success" : "danger" },
321
- children: row.status === 1 ? "启用" : "禁用"
322
- };
323
- }
324
- }
325
- ```
326
-
327
- #### 3. formatter - 文本格式化
328
-
329
- ```typescript
330
- {
331
- name: "amount",
332
- label: "金额",
333
- // ⚠️ formatter 返回纯文本,不支持 HTML
334
- formatter: (row, params) => {
335
- return `¥${Number(row.amount).toLocaleString()}`;
336
- }
337
- }
338
- ```
339
-
340
- #### 4. headerSlot - 表头插槽
341
-
342
- ```typescript
343
- import { h } from "vue";
344
-
345
- {
346
- name: "price",
347
- label: "价格",
348
- headerSlot: () => {
349
- return h("span", { class: "custom-header" }, [
350
- h("span", "价格"),
351
- h("el-tooltip", { content: "含税价格" }, h("i", { class: "el-icon-info" }))
352
- ]);
353
- }
354
- }
355
- ```
356
-
357
- ### 可编辑列
358
-
359
- ```typescript
360
- {
361
- name: "quantity",
362
- label: "数量",
363
- // 开启编辑
364
- editable: true,
365
- // 或条件编辑
366
- editable: (row) => row.status !== "locked",
367
- // 单击编辑
368
- singleClickEdit: true,
369
- // 始终显示编辑框
370
- alwaysEditable: true,
371
- // 自动聚焦
372
- autoFocusInput: true,
373
- // 校验规则
374
- rules: [{ required: true, message: "请输入数量" }],
375
- required: true,
376
- // 生效校验规则
377
- effectRule: (row) => row.needValidate,
378
- // 自定义编辑组件
379
- editComponent: (row, value, params) => ({
380
- tag: "el-input-number",
381
- props: { min: 0, max: 100 }
382
- })
383
- }
384
- ```
385
-
386
- ### 操作列
387
-
388
- ```typescript
389
- {
390
- label: "操作",
391
- width: 200,
392
- fixed: "right",
393
- operations: [
394
- {
395
- name: "edit",
396
- label: "编辑",
397
- type: "primary",
398
- // 权限控制
399
- permission: ["user:edit"],
400
- // 点击事件
401
- onClick: (row, index, params) => {
402
- console.log("编辑", row);
403
- }
404
- },
405
- {
406
- name: "delete",
407
- label: "删除",
408
- type: "danger",
409
- // 禁用条件
410
- disabled: (row) => row.status === "locked",
411
- // 显示条件
412
- show: (row, index) => row.canDelete,
413
- onClick: (row, index) => {
414
- console.log("删除", row);
415
- }
416
- }
417
- ]
418
- }
419
- ```
420
-
421
- ### 逻辑数据类型
422
-
423
- ```typescript
424
- {
425
- name: "status",
426
- label: "状态",
427
- // 自动从字典获取显示值
428
- logicType: "ORDER_STATUS",
429
- logicValue: "status"
430
- }
431
- ```
432
-
433
- ### 行合并配置
434
-
435
- BaseTable 支持在列配置中直接定义行合并规则,无需手动编写 `span-method`。
436
-
437
- #### 方式一:使用 `spanOnceRow` 自动合并相同值
438
-
439
- ```typescript
440
- {
441
- name: "category",
442
- label: "类别",
443
- width: 120,
444
- // 自动合并相邻相同值的单元格
445
- spanOnceRow: true
446
- }
447
- ```
448
-
449
- #### 方式二:使用 `span` 函数自定义合并逻辑(推荐)
450
-
451
- ```typescript
452
- {
453
- name: "testCategory",
454
- label: "试验种类",
455
- width: 150,
456
- align: "center",
457
- // 自定义行合并逻辑
458
- span: ({ rowIndex, data }: any) => {
459
- if (!data || data.length === 0) {
460
- return { rowSpan: 1, colSpan: 1 };
461
- }
462
-
463
- const currentCategory = data[rowIndex]?.testCategory;
464
- const prevCategory = rowIndex > 0 ? data[rowIndex - 1]?.testCategory : null;
465
-
466
- // 如果是分组的第一行,计算需要合并的行数
467
- if (rowIndex === 0 || currentCategory !== prevCategory) {
468
- let rowSpan = 1;
469
- for (let i = rowIndex + 1; i < data.length; i++) {
470
- if (data[i].testCategory === currentCategory) {
471
- rowSpan++;
472
- } else {
473
- break;
474
- }
475
- }
476
- return { rowSpan, colSpan: 1 };
477
- }
478
-
479
- // 非第一行则隐藏
480
- return { rowSpan: 0, colSpan: 0 };
481
- }
482
- }
483
- ```
484
-
485
- #### 完整示例:分组合并表格
486
-
487
- ```vue
488
- <template>
489
- <BaseTable
490
- :data="experimentData"
491
- :columns="columns"
492
- border
493
- />
494
- </template>
495
-
496
- <script setup lang="ts">
497
- import { ref, computed } from "vue";
498
- import { h } from "vue";
499
-
500
- const experimentData = ref([
501
- { id: 1, testCategory: "化学成分", testItem: "C", value: "0.15" },
502
- { id: 2, testCategory: "化学成分", testItem: "Si", value: "0.30" },
503
- { id: 3, testCategory: "化学成分", testItem: "Mn", value: "1.20" },
504
- { id: 4, testCategory: "力学性能", testItem: "抗拉强度", value: "≥500" },
505
- { id: 5, testCategory: "力学性能", testItem: "屈服强度", value: "≥350" }
506
- ]);
507
-
508
- const columns = computed(() => [
509
- {
510
- type: "index",
511
- label: "序号",
512
- width: 60,
513
- // 序号列也需要合并
514
- span: ({ rowIndex, data }: any) => {
515
- if (!data || data.length === 0) return { rowSpan: 1, colSpan: 1 };
516
-
517
- const currentCategory = data[rowIndex]?.testCategory;
518
- const prevCategory = rowIndex > 0 ? data[rowIndex - 1]?.testCategory : null;
519
-
520
- if (rowIndex === 0 || currentCategory !== prevCategory) {
521
- let rowSpan = 1;
522
- for (let i = rowIndex + 1; i < data.length; i++) {
523
- if (data[i].testCategory === currentCategory) {
524
- rowSpan++;
525
- } else {
526
- break;
527
- }
528
- }
529
- return { rowSpan, colSpan: 1 };
530
- }
531
- return { rowSpan: 0, colSpan: 0 };
532
- }
533
- },
534
- {
535
- name: "testCategory",
536
- label: "试验种类",
537
- width: 120,
538
- align: "center",
539
- span: ({ rowIndex, data }: any) => {
540
- if (!data || data.length === 0) return { rowSpan: 1, colSpan: 1 };
541
-
542
- const currentCategory = data[rowIndex]?.testCategory;
543
- const prevCategory = rowIndex > 0 ? data[rowIndex - 1]?.testCategory : null;
544
-
545
- if (rowIndex === 0 || currentCategory !== prevCategory) {
546
- let rowSpan = 1;
547
- for (let i = rowIndex + 1; i < data.length; i++) {
548
- if (data[i].testCategory === currentCategory) {
549
- rowSpan++;
550
- } else {
551
- break;
552
- }
553
- }
554
- return { rowSpan, colSpan: 1 };
555
- }
556
- return { rowSpan: 0, colSpan: 0 };
557
- }
558
- },
559
- {
560
- name: "testItem",
561
- label: "试验项目",
562
- width: 150
563
- },
564
- {
565
- name: "value",
566
- label: "标准值",
567
- width: 100
568
- }
569
- ]);
570
- </script>
571
- ```
572
-
573
- #### span 函数参数说明
574
-
575
- ```typescript
576
- interface SpanParams {
577
- rowIndex: number; // 当前行索引
578
- columnIndex: number; // 当前列索引
579
- row: any; // 当前行数据
580
- column: any; // 当前列配置
581
- data: any[]; // 全部表格数据
582
- }
583
-
584
- // 返回值
585
- interface SpanResult {
586
- rowSpan: number; // 行合并数量,0 表示隐藏
587
- colSpan: number; // 列合并数量,0 表示隐藏
588
- }
589
- ```
590
-
591
- #### 行合并最佳实践
592
-
593
- 1. **使用 `spanOnceRow: true`** - 适用于简单的相邻相同值合并
594
- 2. **使用 `span` 函数** - 适用于复杂的分组合并逻辑
595
- 3. **多列合并** - 需要合并的每一列都要配置 `span` 函数
596
- 4. **注意性能** - `span` 函数会在每次渲染时调用,避免复杂计算
597
- 5. **数据排序** - 确保数据按分组字段排序,否则合并效果不正确
598
-
599
- ### 样式控制
600
-
601
- ```typescript
602
- {
603
- name: "amount",
604
- label: "金额",
605
- // 单元格样式类
606
- cellClass: (params) => {
607
- return params.value < 0 ? "negative-amount" : "";
608
- },
609
- // 单元格样式
610
- cellStyle: (params) => {
611
- return { color: params.value < 0 ? "red" : "green" };
612
- },
613
- // 链接样式
614
- isLink: (row) => true,
615
- // 单元格点击
616
- onCellClick: (params) => {
617
- console.log("点击", params.data);
618
- },
619
- onCellDblclick: (params) => {
620
- console.log("双击", params.data);
621
- }
622
- }
623
- ```
624
-
625
- ### 分组与汇总
626
-
627
- ```typescript
628
- {
629
- name: "amount",
630
- label: "金额",
631
- // 聚合函数
632
- aggregationFn: ["sum", "avg"],
633
- // 行分组
634
- rowGroup: true
635
- }
636
- ```
637
-
638
- ### 数字精度
639
-
640
- ```typescript
641
- {
642
- name: "price",
643
- label: "单价",
644
- logicType: "number",
645
- // 保留2位小数
646
- precision: 2,
647
- // 不足自动补0
648
- precisionAutoFillZero: true
649
- }
650
- ```
651
-
652
- ---
653
-
654
- ## 🎯 操作按钮配置 TableRowOperation
655
-
656
- ```typescript
657
- interface TableRowOperation {
658
- // 按钮标识
659
- name?: string;
660
- // 按钮文本
661
- label: string;
662
- // 主题颜色
663
- type?: "primary" | "success" | "warning" | "danger" | "info";
664
- // 图标
665
- icon?: string;
666
- // 自动加载状态
667
- autoLoading?: boolean;
668
- // 禁用
669
- disabled?: boolean | ((row) => boolean);
670
- // 显示条件
671
- show?: (row, index) => boolean;
672
- // 点击事件
673
- onClick?: (row, index, params) => void;
674
- // 按钮权限
675
- permission?: string[];
676
- }
677
- ```
678
-
679
- ---
680
-
681
- ## 💡 完整示例
682
-
683
- ### 基础列表页
684
-
685
- ```vue
686
- <template>
687
- <div class="app-container">
688
- <BaseTable
689
- ref="tableRef"
690
- :data="list"
691
- :columns="columns"
692
- :loading="loading"
693
- showToolbar
694
- border
695
- @selectionChange="handleSelectionChange"
696
- />
697
-
698
- <jh-pagination
699
- v-show="page.total > 0"
700
- :total="page.total"
701
- v-model:currentPage="page.current"
702
- v-model:pageSize="page.size"
703
- @current-change="loadData"
704
- @size-change="loadData"
705
- />
706
- </div>
707
- </template>
708
-
709
- <script setup lang="ts">
710
- import { ref, computed, onMounted, h } from "vue";
711
- import type { TableColumnDesc } from "@jhlc/common-core/.wl-skills/src/components/table/base-table/type";
712
-
713
- const tableRef = ref();
714
- const list = ref([]);
715
- const loading = ref(false);
716
- const selectedRows = ref([]);
717
- const page = ref({ current: 1, size: 10, total: 0 });
718
-
719
- const columns = computed<TableColumnDesc[]>(() => [
720
- { type: "selection", width: 40 },
721
- { type: "index", label: "序号", width: 60 },
722
- {
723
- name: "orderNo",
724
- label: "订单号",
725
- width: 150,
726
- // 蓝色链接样式
727
- defaultSlot: ({ row }) => {
728
- return h(
729
- "span",
730
- {
731
- style: "color: #409eff; cursor: pointer;",
732
- onClick: () => viewDetail(row)
733
- },
734
- row.orderNo
735
- );
736
- }
737
- },
738
- {
739
- name: "customerName",
740
- label: "客户名称",
741
- showOverflowTooltip: true
742
- },
743
- {
744
- name: "amount",
745
- label: "金额",
746
- align: "right",
747
- formatter: (row) => `¥${Number(row.amount).toLocaleString()}`
748
- },
749
- {
750
- name: "status",
751
- label: "状态",
752
- logicType: "ORDER_STATUS"
753
- },
754
- {
755
- name: "createTime",
756
- label: "创建时间",
757
- width: 180
758
- },
759
- {
760
- label: "操作",
761
- width: 180,
762
- fixed: "right",
763
- operations: [
764
- {
765
- name: "view",
766
- label: "查看",
767
- onClick: (row) => viewDetail(row)
768
- },
769
- {
770
- name: "edit",
771
- label: "编辑",
772
- type: "primary",
773
- permission: ["order:edit"],
774
- onClick: (row) => editRecord(row)
775
- },
776
- {
777
- name: "delete",
778
- label: "删除",
779
- type: "danger",
780
- permission: ["order:delete"],
781
- disabled: (row) => row.status !== "draft",
782
- onClick: (row) => deleteRecord(row)
783
- }
784
- ]
785
- }
786
- ]);
787
-
788
- const handleSelectionChange = (selection) => {
789
- selectedRows.value = selection;
790
- };
791
-
792
- const viewDetail = (row) => {
793
- // 查看详情
794
- };
795
-
796
- const editRecord = (row) => {
797
- // 编辑记录
798
- };
799
-
800
- const deleteRecord = (row) => {
801
- // 删除记录
802
- };
803
-
804
- const loadData = async () => {
805
- loading.value = true;
806
- try {
807
- // 加载数据
808
- } finally {
809
- loading.value = false;
810
- }
811
- };
812
-
813
- onMounted(() => {
814
- loadData();
815
- });
816
- </script>
817
- ```
818
-
819
- ### 可编辑表格
820
-
821
- ```vue
822
- <template>
823
- <BaseTable
824
- ref="tableRef"
825
- :data="list"
826
- :columns="editableColumns"
827
- border
828
- />
829
- <el-button @click="handleValidate">验证</el-button>
830
- <el-button @click="handleSave">保存</el-button>
831
- </template>
832
-
833
- <script setup lang="ts">
834
- import { ref, computed } from "vue";
835
-
836
- const tableRef = ref();
837
- const list = ref([
838
- { id: 1, name: "", quantity: 0, price: 0 }
839
- ]);
840
-
841
- const editableColumns = computed(() => [
842
- { type: "index", label: "序号", width: 60 },
843
- {
844
- name: "name",
845
- label: "名称",
846
- editable: true,
847
- rules: [{ required: true, message: "请输入名称" }]
848
- },
849
- {
850
- name: "quantity",
851
- label: "数量",
852
- editable: true,
853
- editComponent: () => ({
854
- tag: "el-input-number",
855
- props: { min: 1 }
856
- })
857
- },
858
- {
859
- name: "price",
860
- label: "单价",
861
- editable: true,
862
- precision: 2
863
- }
864
- ]);
865
-
866
- const handleValidate = () => {
867
- tableRef.value?.validate((valid) => {
868
- console.log("验证结果:", valid);
869
- });
870
- };
871
-
872
- const handleSave = () => {
873
- const data = tableRef.value?.getTableData();
874
- console.log("保存数据:", data);
875
- };
876
- </script>
877
- ```
878
-
879
- ---
880
-
881
- ## ⚠️ 注意事项
882
-
883
- 1. **列字段名使用 `name` 而非 `prop`**
884
-
885
- ```typescript
886
- // ✅ 正确
887
- { label: "姓名", name: "userName" }
888
-
889
- // ❌ 错误
890
- { label: "姓名", prop: "userName" }
891
- ```
892
-
893
- 2. **自定义渲染使用 `defaultSlot` 而非 `render`**
894
-
895
- ```typescript
896
- // ✅ 正确
897
- {
898
- name: "title",
899
- defaultSlot: ({ row }) => h("span", { style: "color: blue;" }, row.title)
900
- }
901
-
902
- // ❌ 错误
903
- {
904
- name: "title",
905
- render: (value) => `<span style="color: blue;">${value}</span>`
906
- }
907
- ```
908
-
909
- 3. **formatter 只能返回纯文本**
910
-
911
- ```typescript
912
- // ✅ 正确 - 返回文本
913
- formatter: (row) => `¥${row.amount}`
914
-
915
- // ❌ 错误 - 返回 HTML(不会解析)
916
- formatter: (row) => `<span class="red">${row.amount}</span>`
917
- ```
918
-
919
- 4. **操作按钮的权限控制**
920
-
921
- - 使用 `permission` 属性配置权限标识数组
922
- - 系统会自动根据用户权限显示/隐藏按钮
923
-
924
- 5. **表格高度设置**
925
-
926
- - 固定高度:`height="400"`
927
- - 自适应:配合 flex 布局,设置 `height="100%"` 或 `autoHeight`
928
-
929
- 6. **树形数据必须设置 `rowKey`**
930
-
931
- ```vue
932
- <BaseTable :data="treeData" :columns="columns" rowKey="id" />
933
- ```
934
-
935
- ---
936
-
937
- ## 📚 相关文档
938
-
939
- - [AGGrid 高级表格](../AGGrid/README.md)
940
- - [BaseToolbar 工具栏](../BaseToolbar/README.md)
941
- - [BaseQuery 查询组件](../BaseQuery/README.md)
1
+ # BaseTable 表格组件
2
+
3
+ > 来源:`@jhlc/common-core` 远程组件
4
+
5
+ BaseTable 是一个功能强大的表格组件,支持数据展示、排序、筛选、选择、操作按钮、可编辑单元格等功能。支持 DataTable 和 AGGrid 两种渲染模式。
6
+
7
+ ## 📦 导入方式
8
+
9
+ ```typescript
10
+ // 全局注册(已在项目中配置)
11
+ // 直接使用 <BaseTable /> 即可
12
+
13
+ // 类型导入
14
+ import type { TableColumnDesc } from "@jhlc/common-core/.wl-skills/src/components/table/base-table/type";
15
+ ```
16
+
17
+ ## 🚀 基本用法
18
+
19
+ ```vue
20
+ <template>
21
+ <BaseTable
22
+ ref="tableRef"
23
+ :data="list"
24
+ :columns="columns"
25
+ showToolbar
26
+ border
27
+ />
28
+ </template>
29
+
30
+ <script setup lang="ts">
31
+ import { ref, computed } from "vue";
32
+
33
+ const tableRef = ref();
34
+ const list = ref([
35
+ { id: 1, name: "张三", age: 25, status: "在职" },
36
+ { id: 2, name: "李四", age: 30, status: "离职" }
37
+ ]);
38
+
39
+ const columns = computed(() => [
40
+ { type: "selection" },
41
+ { type: "index" },
42
+ { label: "姓名", name: "name" },
43
+ { label: "年龄", name: "age" },
44
+ { label: "状态", name: "status" }
45
+ ]);
46
+ </script>
47
+ ```
48
+
49
+ ---
50
+
51
+ ## 📋 Props 属性
52
+
53
+ ### 基础属性
54
+
55
+ | 属性名 | 类型 | 默认值 | 说明 |
56
+ | ----------------------------- | -------------------------------- | ------------------- | -------------------------- |
57
+ | `data` | `Array` | `[]` | 表格数据源 |
58
+ | `columns` | `TableColumnDesc[]` | `[]` | 列配置数组 |
59
+ | `renderType` | `'' \| 'dataTable' \| 'agGrid'` | `''` | 渲染类型 |
60
+ | `rowId` | `string` | `'_id'` | 行数据唯一标识字段 |
61
+ | `rowKey` | `string` | `'_id'` | 行数据的键(树形表格必需) |
62
+ | `childrenKey` | `string` | `'children'` | 子节点字段名 |
63
+
64
+ ### 外观属性
65
+
66
+ | 属性名 | 类型 | 默认值 | 说明 |
67
+ | ----------------------------- | -------------------------------- | ------------------- | -------------------------- |
68
+ | `border` | `boolean` | `true` | 是否显示边框 |
69
+ | `stripe` | `boolean` | `true` | 是否显示斑马纹 |
70
+ | `size` | `'small' \| 'default' \| 'large'`| - | 表格尺寸 |
71
+ | `height` | `number` | - | 表格高度 |
72
+ | `maxHeight` | `number` | - | 表格最大高度 |
73
+ | `autoHeight` | `boolean` | `false` | 自动调整高度 |
74
+ | `showHeader` | `boolean` | `true` | 是否显示表头 |
75
+ | `showToolbar` | `boolean` | `false` | 是否显示工具栏 |
76
+ | `fixed` | `boolean` | - | 是否固定表头 |
77
+
78
+ ### 选择相关
79
+
80
+ | 属性名 | 类型 | 默认值 | 说明 |
81
+ | ----------------------------- | -------------------------------- | ------------------- | -------------------------- |
82
+ | `selectMethod` | `'dblclick' \| 'click' \| ''` | `''` | 选中方式 |
83
+ | `selectedRow` | `string \| number` | - | 单选选中行 |
84
+ | `selectedValue` | `string \| number` | - | 单选选中值 |
85
+ | `selectionRows` | `Array` | `[]` | 多选选中的行 |
86
+ | `selectionType` | `number` | `2` | 多选类型 2:全选 1:半选和全选 |
87
+ | `persistSelect` | `boolean` | `false` | 持久化选择 |
88
+ | `autoCheckedChildren` | `boolean` | `true` | 自动勾选子节点 |
89
+ | `highlightCurrentRow` | `boolean` | `false` | 高亮当前行 |
90
+ | `currentRowSelectMethod` | `'dblclick' \| 'click'` | - | 当前行选中方式 |
91
+
92
+ ### 功能相关
93
+
94
+ | 属性名 | 类型 | 默认值 | 说明 |
95
+ | ----------------------------- | -------------------------------- | ------------------- | -------------------------- |
96
+ | `disabled` | `boolean` | `false` | 禁用输入框 |
97
+ | `showSummary` | `boolean` | `false` | 显示汇总行 |
98
+ | `summaryMethod` | `Function` | - | 自定义汇总方法 |
99
+ | `defaultExpandAll` | `boolean` | `false` | 默认展开所有行 |
100
+ | `virtual` | `boolean` | `true` | 虚拟滚动 |
101
+ | `frontSort` | `boolean` | `false` | 前端排序 |
102
+ | `frontFiltering` | `boolean` | `false` | 前端过滤 |
103
+ | `manualFiltering` | `boolean` | `false` | 手动过滤 |
104
+ | `manualSorting` | `boolean` | `false` | 手动排序 |
105
+ | `grouping` | `boolean` | `false` | 分组 |
106
+ | `groupFields` | `string[]` | - | 分组字段 |
107
+ | `columnVisibility` | `boolean` | `false` | 列可见性控制 |
108
+ | `showEditIcon` | `boolean` | `true` | 显示编辑图标 |
109
+
110
+ ### AGGrid 专用
111
+
112
+ | 属性名 | 类型 | 默认值 | 说明 |
113
+ | ----------------------------- | -------------------------------- | ------------------- | -------------------------- |
114
+ | `tree` | `boolean` | `false` | 树形结构 |
115
+ | `quickEditCursor` | `boolean` | `true` | 快速编辑光标 |
116
+ | `selection` | `Array` | - | 选中项 |
117
+ | `isRowSelectable` | `Function` | - | 行是否可选 |
118
+ | `isGroupOpenByDefault` | `Function` | - | 分组默认展开 |
119
+ | `rowGroupPanelShow` | `'never' \| 'onlyWhenGrouping' \| 'always'` | `'onlyWhenGrouping'` | 行分组面板显示 |
120
+ | `grandTotalRow` | `string` | - | 总计行位置 |
121
+ | `pinnedTopRowData` | `Array` | - | 固定顶部行数据 |
122
+ | `pinnedBottomRowData` | `Array` | - | 固定底部行数据 |
123
+ | `isRowPinned` | `Function` | - | 行是否固定 |
124
+ | `suppressRowClickSelection` | `boolean` | `false` | 禁止行点击选择 |
125
+ | `rowClass` | `Function` | - | 行样式类 |
126
+ | `rowStyle` | `Function` | - | 行样式 |
127
+ | `rowClassRules` | `Object` | - | 行样式规则 |
128
+ | `stopEditingWhenCellsLoseFocus` | `boolean` | `false` | 失焦停止编辑 |
129
+ | `isRowValidDropPosition` | `Function` | - | 行是否为有效拖放位置 |
130
+
131
+ ---
132
+
133
+ ## 📋 Events 事件
134
+
135
+ | 事件名 | 参数 | 说明 |
136
+ | ------------------- | --------------------------------------- | ------------------ |
137
+ | `selectionChange` | `selection: any[]` | 多选项发生变化 |
138
+ | `select` | `selection, row, status, params` | 选择某一行 |
139
+ | `selectAll` | `selection, status` | 全选/取消全选 |
140
+ | `currentChange` | `currentRow` | 当前行变化 |
141
+ | `row-click` | `row, column, event` | 行点击事件 |
142
+ | `row-dblclick` | `row, column, event` | 行双击事件 |
143
+ | `expand-change` | `row, expanded` | 展开/收起变化 |
144
+ | `filterModified` | - | 过滤条件修改 |
145
+ | `filterChanged` | - | 过滤条件变化 |
146
+ | `update:selectedRow`| `row` | 单选行更新 |
147
+ | `update:selectedValue`| `value` | 单选值更新 |
148
+ | `mounted` | `{ parentEl }` | 组件挂载完成 |
149
+
150
+ ---
151
+
152
+ ## 📋 Expose 方法 (通过 ref 调用)
153
+
154
+ ### 选择相关
155
+
156
+ | 方法名 | 参数 | 返回值 | 说明 |
157
+ | --------------------- | --------------------------------- | --------- | -------------------------- |
158
+ | `getSelection` | `check?: 1\|2, firstLevel?: boolean` | `any[]` | 获取选中行 (2:全选,1:半选+全选) |
159
+ | `getVisibleSelection` | `check?: 1\|2, firstLevel?: boolean` | `any[]` | 获取可见选中行 |
160
+ | `getRootSelection` | `check?: 1\|2` | `any[]` | 获取根节点选中行 |
161
+ | `getAllSelection` | `check?: 1\|2` | `any[]` | 获取所有选中行 |
162
+ | `getTreeSelection` | `type?: 'flat'\|'tree'` | `any[]` | 获取树形选中行 |
163
+ | `getSingleSelectRow` | - | `object` | 获取单选行 |
164
+ | `getSelectionRows` | - | `any[]` | 获取选中的行 |
165
+ | `toggleRowSelection` | `row, selected: boolean` | - | 切换行选中状态 |
166
+ | `toggleAllSelection` | - | - | 切换全选状态 |
167
+ | `setCurrentRow` | `row` | - | 设置当前高亮行 |
168
+ | `clearSelection` | - | - | 清空选中 |
169
+ | `setSelect` | `row, status: boolean` | - | 设置行选中状态 |
170
+ | `setSelection` | - | - | 设置选中 |
171
+ | `selectAll` | - | - | 全选 |
172
+ | `deselectAll` | - | - | 取消全选 |
173
+
174
+ ### 验证相关
175
+
176
+ | 方法名 | 参数 | 返回值 | 说明 |
177
+ | -------------------- | --------------------------------- | --------- | -------------------------- |
178
+ | `validate` | `callback: (valid: boolean) => void` | - | 验证整个表格 |
179
+ | `validateRow` | - | - | 验证单行 |
180
+ | `validateRows` | `rows, cb: (valid: boolean) => void` | - | 验证多行 |
181
+ | `clearValidation` | - | - | 清除验证 |
182
+ | `clearRowValidation` | - | - | 清除行验证 |
183
+
184
+ ### 数据操作
185
+
186
+ | 方法名 | 参数 | 返回值 | 说明 |
187
+ | -------------------- | --------------------------------- | --------- | -------------------------- |
188
+ | `setRowValue` | `row, name, index, value` | - | 设置行字段值 |
189
+ | `setDataValue` | `row, key, value` | - | 设置数据值 |
190
+ | `updateRow` | `data` | - | 更新行数据 |
191
+ | `getTableData` | - | `any[]` | 获取表格数据 |
192
+ | `getParentRow` | `row` | `object` | 获取父行 |
193
+ | `isTableReady` | `row` | `boolean` | 表格是否就绪 |
194
+
195
+ ### 编辑状态
196
+
197
+ | 方法名 | 参数 | 返回值 | 说明 |
198
+ | -------------------- | --------------------------------- | --------- | -------------------------- |
199
+ | `resetRowEditState` | - | - | 重置行编辑状态 |
200
+ | `resetEditState` | - | - | 重置编辑状态 |
201
+
202
+ ### 刷新相关
203
+
204
+ | 方法名 | 参数 | 返回值 | 说明 |
205
+ | -------------------- | --------------------------------- | --------- | -------------------------- |
206
+ | `refresh` | - | - | 刷新表格 |
207
+ | `forceRefresh` | - | - | 强制刷新 |
208
+ | `forceRefreshTable` | - | - | 强制刷新表格 |
209
+ | `forceRefreshNode` | `node` | - | 强制刷新节点 |
210
+ | `refreshColumnVisible` | - | - | 刷新列可见性 |
211
+ | `refreshHeader` | - | - | 刷新表头 |
212
+
213
+ ### 展开/折叠
214
+
215
+ | 方法名 | 参数 | 返回值 | 说明 |
216
+ | -------------------- | --------------------------------- | --------- | -------------------------- |
217
+ | `expandAll` | - | - | 展开所有行 |
218
+ | `collapseAll` | - | - | 折叠所有行 |
219
+ | `expandRow` | `rowList` | - | 展开指定行 |
220
+ | `collRow` | `row` | - | 折叠指定行 |
221
+
222
+ ### 滚动/定位
223
+
224
+ | 方法名 | 参数 | 返回值 | 说明 |
225
+ | -------------------- | --------------------------------- | --------- | -------------------------- |
226
+ | `goToRow` | `index: number` | - | 滚动到指定行 |
227
+ | `goToColumn` | `name: string` | - | 滚动到指定列 |
228
+
229
+ ### 导出
230
+
231
+ | 方法名 | 参数 | 返回值 | 说明 |
232
+ | -------------------- | --------------------------------- | --------- | -------------------------- |
233
+ | `exportExcel` | `option: ExportTableExcelOption` | - | 导出 Excel |
234
+
235
+ ### 其他
236
+
237
+ | 方法名 | 参数 | 返回值 | 说明 |
238
+ | -------------------- | --------------------------------- | --------- | -------------------------- |
239
+ | `loading` | `time?: number` | - | 显示加载状态(默认6000ms) |
240
+ | `closeLoading` | - | - | 关闭加载状态 |
241
+ | `clearFilters` | - | - | 清除过滤 |
242
+ | `setSuppressRowDrag` | `flag: boolean` | - | 设置是否可拖拽 |
243
+ | `getRowKey` | - | `string` | 获取行键 |
244
+ | `currentRow` | - | `object` | 当前高亮行 (computed) |
245
+ | `data` | - | `any[]` | 表格数据 (computed) |
246
+
247
+ ---
248
+
249
+ ## 📋 列配置 TableColumnDesc
250
+
251
+ ### 基础属性
252
+
253
+ ```typescript
254
+ interface TableColumnDesc<T = any> {
255
+ // 列名(字段名)⚠️ 重要:使用 name 而非 prop
256
+ name?: string;
257
+ // 列标题
258
+ label?: string;
259
+ // 列类型
260
+ type?: "index" | "selection" | "radio" | "expand";
261
+ // 列宽
262
+ width?: number;
263
+ // 最小列宽
264
+ minWidth?: number;
265
+ // 弹性宽度
266
+ flex?: number;
267
+ // 对齐方式
268
+ align?: "left" | "center" | "right";
269
+ // 表头对齐
270
+ headerAlign?: "left" | "center" | "right";
271
+ // 固定列
272
+ fixed?: "left" | "right";
273
+ // 列宽可调整
274
+ resizable?: boolean;
275
+ // 是否可排序
276
+ sortable?: boolean;
277
+ // 超出省略号
278
+ showOverflowTooltip?: boolean;
279
+ // 允许换行
280
+ wrapText?: boolean;
281
+ // 自动调整行高
282
+ autoHeight?: boolean;
283
+ // 是否可过滤
284
+ filterable?: boolean;
285
+ }
286
+ ```
287
+
288
+ ### 自定义渲染 (⚠️ 重要)
289
+
290
+ BaseTable 支持多种自定义渲染方式:
291
+
292
+ #### 1. defaultSlot - 默认插槽 (推荐)
293
+
294
+ ```typescript
295
+ import { h } from "vue";
296
+
297
+ {
298
+ name: "title",
299
+ label: "标题",
300
+ // ✅ 正确方式:使用 defaultSlot + h 函数
301
+ defaultSlot: ({ row, $index }) => {
302
+ return h(
303
+ "span",
304
+ { style: "color: #409eff; cursor: pointer;" },
305
+ row.title
306
+ );
307
+ }
308
+ }
309
+ ```
310
+
311
+ #### 2. defaultNode - 低代码插槽
312
+
313
+ ```typescript
314
+ {
315
+ name: "status",
316
+ label: "状态",
317
+ defaultNode: ({ row, $index, params }) => {
318
+ return {
319
+ tag: "el-tag",
320
+ props: { type: row.status === 1 ? "success" : "danger" },
321
+ children: row.status === 1 ? "启用" : "禁用"
322
+ };
323
+ }
324
+ }
325
+ ```
326
+
327
+ #### 3. formatter - 文本格式化
328
+
329
+ ```typescript
330
+ {
331
+ name: "amount",
332
+ label: "金额",
333
+ // ⚠️ formatter 返回纯文本,不支持 HTML
334
+ formatter: (row, params) => {
335
+ return `¥${Number(row.amount).toLocaleString()}`;
336
+ }
337
+ }
338
+ ```
339
+
340
+ #### 4. headerSlot - 表头插槽
341
+
342
+ ```typescript
343
+ import { h } from "vue";
344
+
345
+ {
346
+ name: "price",
347
+ label: "价格",
348
+ headerSlot: () => {
349
+ return h("span", { class: "custom-header" }, [
350
+ h("span", "价格"),
351
+ h("el-tooltip", { content: "含税价格" }, h("i", { class: "el-icon-info" }))
352
+ ]);
353
+ }
354
+ }
355
+ ```
356
+
357
+ ### 可编辑列
358
+
359
+ ```typescript
360
+ {
361
+ name: "quantity",
362
+ label: "数量",
363
+ // 开启编辑
364
+ editable: true,
365
+ // 或条件编辑
366
+ editable: (row) => row.status !== "locked",
367
+ // 单击编辑
368
+ singleClickEdit: true,
369
+ // 始终显示编辑框
370
+ alwaysEditable: true,
371
+ // 自动聚焦
372
+ autoFocusInput: true,
373
+ // 校验规则
374
+ rules: [{ required: true, message: "请输入数量" }],
375
+ required: true,
376
+ // 生效校验规则
377
+ effectRule: (row) => row.needValidate,
378
+ // 自定义编辑组件
379
+ editComponent: (row, value, params) => ({
380
+ tag: "el-input-number",
381
+ props: { min: 0, max: 100 }
382
+ })
383
+ }
384
+ ```
385
+
386
+ ### 操作列
387
+
388
+ ```typescript
389
+ {
390
+ label: "操作",
391
+ width: 200,
392
+ fixed: "right",
393
+ operations: [
394
+ {
395
+ name: "edit",
396
+ label: "编辑",
397
+ type: "primary",
398
+ // 权限控制
399
+ permission: ["user:edit"],
400
+ // 点击事件
401
+ onClick: (row, index, params) => {
402
+ console.log("编辑", row);
403
+ }
404
+ },
405
+ {
406
+ name: "delete",
407
+ label: "删除",
408
+ type: "danger",
409
+ // 禁用条件
410
+ disabled: (row) => row.status === "locked",
411
+ // 显示条件
412
+ show: (row, index) => row.canDelete,
413
+ onClick: (row, index) => {
414
+ console.log("删除", row);
415
+ }
416
+ }
417
+ ]
418
+ }
419
+ ```
420
+
421
+ ### 逻辑数据类型
422
+
423
+ ```typescript
424
+ {
425
+ name: "status",
426
+ label: "状态",
427
+ // 自动从字典获取显示值
428
+ logicType: "ORDER_STATUS",
429
+ logicValue: "status"
430
+ }
431
+ ```
432
+
433
+ ### 行合并配置
434
+
435
+ BaseTable 支持在列配置中直接定义行合并规则,无需手动编写 `span-method`。
436
+
437
+ #### 方式一:使用 `spanOnceRow` 自动合并相同值
438
+
439
+ ```typescript
440
+ {
441
+ name: "category",
442
+ label: "类别",
443
+ width: 120,
444
+ // 自动合并相邻相同值的单元格
445
+ spanOnceRow: true
446
+ }
447
+ ```
448
+
449
+ #### 方式二:使用 `span` 函数自定义合并逻辑(推荐)
450
+
451
+ ```typescript
452
+ {
453
+ name: "testCategory",
454
+ label: "试验种类",
455
+ width: 150,
456
+ align: "center",
457
+ // 自定义行合并逻辑
458
+ span: ({ rowIndex, data }: any) => {
459
+ if (!data || data.length === 0) {
460
+ return { rowSpan: 1, colSpan: 1 };
461
+ }
462
+
463
+ const currentCategory = data[rowIndex]?.testCategory;
464
+ const prevCategory = rowIndex > 0 ? data[rowIndex - 1]?.testCategory : null;
465
+
466
+ // 如果是分组的第一行,计算需要合并的行数
467
+ if (rowIndex === 0 || currentCategory !== prevCategory) {
468
+ let rowSpan = 1;
469
+ for (let i = rowIndex + 1; i < data.length; i++) {
470
+ if (data[i].testCategory === currentCategory) {
471
+ rowSpan++;
472
+ } else {
473
+ break;
474
+ }
475
+ }
476
+ return { rowSpan, colSpan: 1 };
477
+ }
478
+
479
+ // 非第一行则隐藏
480
+ return { rowSpan: 0, colSpan: 0 };
481
+ }
482
+ }
483
+ ```
484
+
485
+ #### 完整示例:分组合并表格
486
+
487
+ ```vue
488
+ <template>
489
+ <BaseTable
490
+ :data="experimentData"
491
+ :columns="columns"
492
+ border
493
+ />
494
+ </template>
495
+
496
+ <script setup lang="ts">
497
+ import { ref, computed } from "vue";
498
+ import { h } from "vue";
499
+
500
+ const experimentData = ref([
501
+ { id: 1, testCategory: "化学成分", testItem: "C", value: "0.15" },
502
+ { id: 2, testCategory: "化学成分", testItem: "Si", value: "0.30" },
503
+ { id: 3, testCategory: "化学成分", testItem: "Mn", value: "1.20" },
504
+ { id: 4, testCategory: "力学性能", testItem: "抗拉强度", value: "≥500" },
505
+ { id: 5, testCategory: "力学性能", testItem: "屈服强度", value: "≥350" }
506
+ ]);
507
+
508
+ const columns = computed(() => [
509
+ {
510
+ type: "index",
511
+ label: "序号",
512
+ width: 60,
513
+ // 序号列也需要合并
514
+ span: ({ rowIndex, data }: any) => {
515
+ if (!data || data.length === 0) return { rowSpan: 1, colSpan: 1 };
516
+
517
+ const currentCategory = data[rowIndex]?.testCategory;
518
+ const prevCategory = rowIndex > 0 ? data[rowIndex - 1]?.testCategory : null;
519
+
520
+ if (rowIndex === 0 || currentCategory !== prevCategory) {
521
+ let rowSpan = 1;
522
+ for (let i = rowIndex + 1; i < data.length; i++) {
523
+ if (data[i].testCategory === currentCategory) {
524
+ rowSpan++;
525
+ } else {
526
+ break;
527
+ }
528
+ }
529
+ return { rowSpan, colSpan: 1 };
530
+ }
531
+ return { rowSpan: 0, colSpan: 0 };
532
+ }
533
+ },
534
+ {
535
+ name: "testCategory",
536
+ label: "试验种类",
537
+ width: 120,
538
+ align: "center",
539
+ span: ({ rowIndex, data }: any) => {
540
+ if (!data || data.length === 0) return { rowSpan: 1, colSpan: 1 };
541
+
542
+ const currentCategory = data[rowIndex]?.testCategory;
543
+ const prevCategory = rowIndex > 0 ? data[rowIndex - 1]?.testCategory : null;
544
+
545
+ if (rowIndex === 0 || currentCategory !== prevCategory) {
546
+ let rowSpan = 1;
547
+ for (let i = rowIndex + 1; i < data.length; i++) {
548
+ if (data[i].testCategory === currentCategory) {
549
+ rowSpan++;
550
+ } else {
551
+ break;
552
+ }
553
+ }
554
+ return { rowSpan, colSpan: 1 };
555
+ }
556
+ return { rowSpan: 0, colSpan: 0 };
557
+ }
558
+ },
559
+ {
560
+ name: "testItem",
561
+ label: "试验项目",
562
+ width: 150
563
+ },
564
+ {
565
+ name: "value",
566
+ label: "标准值",
567
+ width: 100
568
+ }
569
+ ]);
570
+ </script>
571
+ ```
572
+
573
+ #### span 函数参数说明
574
+
575
+ ```typescript
576
+ interface SpanParams {
577
+ rowIndex: number; // 当前行索引
578
+ columnIndex: number; // 当前列索引
579
+ row: any; // 当前行数据
580
+ column: any; // 当前列配置
581
+ data: any[]; // 全部表格数据
582
+ }
583
+
584
+ // 返回值
585
+ interface SpanResult {
586
+ rowSpan: number; // 行合并数量,0 表示隐藏
587
+ colSpan: number; // 列合并数量,0 表示隐藏
588
+ }
589
+ ```
590
+
591
+ #### 行合并最佳实践
592
+
593
+ 1. **使用 `spanOnceRow: true`** - 适用于简单的相邻相同值合并
594
+ 2. **使用 `span` 函数** - 适用于复杂的分组合并逻辑
595
+ 3. **多列合并** - 需要合并的每一列都要配置 `span` 函数
596
+ 4. **注意性能** - `span` 函数会在每次渲染时调用,避免复杂计算
597
+ 5. **数据排序** - 确保数据按分组字段排序,否则合并效果不正确
598
+
599
+ ### 样式控制
600
+
601
+ ```typescript
602
+ {
603
+ name: "amount",
604
+ label: "金额",
605
+ // 单元格样式类
606
+ cellClass: (params) => {
607
+ return params.value < 0 ? "negative-amount" : "";
608
+ },
609
+ // 单元格样式
610
+ cellStyle: (params) => {
611
+ return { color: params.value < 0 ? "red" : "green" };
612
+ },
613
+ // 链接样式
614
+ isLink: (row) => true,
615
+ // 单元格点击
616
+ onCellClick: (params) => {
617
+ console.log("点击", params.data);
618
+ },
619
+ onCellDblclick: (params) => {
620
+ console.log("双击", params.data);
621
+ }
622
+ }
623
+ ```
624
+
625
+ ### 分组与汇总
626
+
627
+ ```typescript
628
+ {
629
+ name: "amount",
630
+ label: "金额",
631
+ // 聚合函数
632
+ aggregationFn: ["sum", "avg"],
633
+ // 行分组
634
+ rowGroup: true
635
+ }
636
+ ```
637
+
638
+ ### 数字精度
639
+
640
+ ```typescript
641
+ {
642
+ name: "price",
643
+ label: "单价",
644
+ logicType: "number",
645
+ // 保留2位小数
646
+ precision: 2,
647
+ // 不足自动补0
648
+ precisionAutoFillZero: true
649
+ }
650
+ ```
651
+
652
+ ---
653
+
654
+ ## 🎯 操作按钮配置 TableRowOperation
655
+
656
+ ```typescript
657
+ interface TableRowOperation {
658
+ // 按钮标识
659
+ name?: string;
660
+ // 按钮文本
661
+ label: string;
662
+ // 主题颜色
663
+ type?: "primary" | "success" | "warning" | "danger" | "info";
664
+ // 图标
665
+ icon?: string;
666
+ // 自动加载状态
667
+ autoLoading?: boolean;
668
+ // 禁用
669
+ disabled?: boolean | ((row) => boolean);
670
+ // 显示条件
671
+ show?: (row, index) => boolean;
672
+ // 点击事件
673
+ onClick?: (row, index, params) => void;
674
+ // 按钮权限
675
+ permission?: string[];
676
+ }
677
+ ```
678
+
679
+ ---
680
+
681
+ ## 💡 完整示例
682
+
683
+ ### 基础列表页
684
+
685
+ ```vue
686
+ <template>
687
+ <div class="app-container">
688
+ <BaseTable
689
+ ref="tableRef"
690
+ :data="list"
691
+ :columns="columns"
692
+ :loading="loading"
693
+ showToolbar
694
+ border
695
+ @selectionChange="handleSelectionChange"
696
+ />
697
+
698
+ <jh-pagination
699
+ v-show="page.total > 0"
700
+ :total="page.total"
701
+ v-model:currentPage="page.current"
702
+ v-model:pageSize="page.size"
703
+ @current-change="loadData"
704
+ @size-change="loadData"
705
+ />
706
+ </div>
707
+ </template>
708
+
709
+ <script setup lang="ts">
710
+ import { ref, computed, onMounted, h } from "vue";
711
+ import type { TableColumnDesc } from "@jhlc/common-core/.wl-skills/src/components/table/base-table/type";
712
+
713
+ const tableRef = ref();
714
+ const list = ref([]);
715
+ const loading = ref(false);
716
+ const selectedRows = ref([]);
717
+ const page = ref({ current: 1, size: 10, total: 0 });
718
+
719
+ const columns = computed<TableColumnDesc[]>(() => [
720
+ { type: "selection", width: 40 },
721
+ { type: "index", label: "序号", width: 60 },
722
+ {
723
+ name: "orderNo",
724
+ label: "订单号",
725
+ width: 150,
726
+ // 蓝色链接样式
727
+ defaultSlot: ({ row }) => {
728
+ return h(
729
+ "span",
730
+ {
731
+ style: "color: #409eff; cursor: pointer;",
732
+ onClick: () => viewDetail(row)
733
+ },
734
+ row.orderNo
735
+ );
736
+ }
737
+ },
738
+ {
739
+ name: "customerName",
740
+ label: "客户名称",
741
+ showOverflowTooltip: true
742
+ },
743
+ {
744
+ name: "amount",
745
+ label: "金额",
746
+ align: "right",
747
+ formatter: (row) => `¥${Number(row.amount).toLocaleString()}`
748
+ },
749
+ {
750
+ name: "status",
751
+ label: "状态",
752
+ logicType: "ORDER_STATUS"
753
+ },
754
+ {
755
+ name: "createTime",
756
+ label: "创建时间",
757
+ width: 180
758
+ },
759
+ {
760
+ label: "操作",
761
+ width: 180,
762
+ fixed: "right",
763
+ operations: [
764
+ {
765
+ name: "view",
766
+ label: "查看",
767
+ onClick: (row) => viewDetail(row)
768
+ },
769
+ {
770
+ name: "edit",
771
+ label: "编辑",
772
+ type: "primary",
773
+ permission: ["order:edit"],
774
+ onClick: (row) => editRecord(row)
775
+ },
776
+ {
777
+ name: "delete",
778
+ label: "删除",
779
+ type: "danger",
780
+ permission: ["order:delete"],
781
+ disabled: (row) => row.status !== "draft",
782
+ onClick: (row) => deleteRecord(row)
783
+ }
784
+ ]
785
+ }
786
+ ]);
787
+
788
+ const handleSelectionChange = (selection) => {
789
+ selectedRows.value = selection;
790
+ };
791
+
792
+ const viewDetail = (row) => {
793
+ // 查看详情
794
+ };
795
+
796
+ const editRecord = (row) => {
797
+ // 编辑记录
798
+ };
799
+
800
+ const deleteRecord = (row) => {
801
+ // 删除记录
802
+ };
803
+
804
+ const loadData = async () => {
805
+ loading.value = true;
806
+ try {
807
+ // 加载数据
808
+ } finally {
809
+ loading.value = false;
810
+ }
811
+ };
812
+
813
+ onMounted(() => {
814
+ loadData();
815
+ });
816
+ </script>
817
+ ```
818
+
819
+ ### 可编辑表格
820
+
821
+ ```vue
822
+ <template>
823
+ <BaseTable
824
+ ref="tableRef"
825
+ :data="list"
826
+ :columns="editableColumns"
827
+ border
828
+ />
829
+ <el-button @click="handleValidate">验证</el-button>
830
+ <el-button @click="handleSave">保存</el-button>
831
+ </template>
832
+
833
+ <script setup lang="ts">
834
+ import { ref, computed } from "vue";
835
+
836
+ const tableRef = ref();
837
+ const list = ref([
838
+ { id: 1, name: "", quantity: 0, price: 0 }
839
+ ]);
840
+
841
+ const editableColumns = computed(() => [
842
+ { type: "index", label: "序号", width: 60 },
843
+ {
844
+ name: "name",
845
+ label: "名称",
846
+ editable: true,
847
+ rules: [{ required: true, message: "请输入名称" }]
848
+ },
849
+ {
850
+ name: "quantity",
851
+ label: "数量",
852
+ editable: true,
853
+ editComponent: () => ({
854
+ tag: "el-input-number",
855
+ props: { min: 1 }
856
+ })
857
+ },
858
+ {
859
+ name: "price",
860
+ label: "单价",
861
+ editable: true,
862
+ precision: 2
863
+ }
864
+ ]);
865
+
866
+ const handleValidate = () => {
867
+ tableRef.value?.validate((valid) => {
868
+ console.log("验证结果:", valid);
869
+ });
870
+ };
871
+
872
+ const handleSave = () => {
873
+ const data = tableRef.value?.getTableData();
874
+ console.log("保存数据:", data);
875
+ };
876
+ </script>
877
+ ```
878
+
879
+ ---
880
+
881
+ ## ⚠️ 注意事项
882
+
883
+ 1. **列字段名使用 `name` 而非 `prop`**
884
+
885
+ ```typescript
886
+ // ✅ 正确
887
+ { label: "姓名", name: "userName" }
888
+
889
+ // ❌ 错误
890
+ { label: "姓名", prop: "userName" }
891
+ ```
892
+
893
+ 2. **自定义渲染使用 `defaultSlot` 而非 `render`**
894
+
895
+ ```typescript
896
+ // ✅ 正确
897
+ {
898
+ name: "title",
899
+ defaultSlot: ({ row }) => h("span", { style: "color: blue;" }, row.title)
900
+ }
901
+
902
+ // ❌ 错误
903
+ {
904
+ name: "title",
905
+ render: (value) => `<span style="color: blue;">${value}</span>`
906
+ }
907
+ ```
908
+
909
+ 3. **formatter 只能返回纯文本**
910
+
911
+ ```typescript
912
+ // ✅ 正确 - 返回文本
913
+ formatter: (row) => `¥${row.amount}`
914
+
915
+ // ❌ 错误 - 返回 HTML(不会解析)
916
+ formatter: (row) => `<span class="red">${row.amount}</span>`
917
+ ```
918
+
919
+ 4. **操作按钮的权限控制**
920
+
921
+ - 使用 `permission` 属性配置权限标识数组
922
+ - 系统会自动根据用户权限显示/隐藏按钮
923
+
924
+ 5. **表格高度设置**
925
+
926
+ - 固定高度:`height="400"`
927
+ - 自适应:配合 flex 布局,设置 `height="100%"` 或 `autoHeight`
928
+
929
+ 6. **树形数据必须设置 `rowKey`**
930
+
931
+ ```vue
932
+ <BaseTable :data="treeData" :columns="columns" rowKey="id" />
933
+ ```
934
+
935
+ ---
936
+
937
+ ## 📚 相关文档
938
+
939
+ - [AGGrid 高级表格](../AGGrid/README.md)
940
+ - [BaseToolbar 工具栏](../BaseToolbar/README.md)
941
+ - [BaseQuery 查询组件](../BaseQuery/README.md)