jianghu-ui 1.0.1

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 (112) hide show
  1. package/README.md +376 -0
  2. package/dist/jianghu-ui.css +2318 -0
  3. package/dist/jianghu-ui.js +2 -0
  4. package/dist/jianghu-ui.js.LICENSE.txt +1 -0
  5. package/package.json +56 -0
  6. package/src/Design.stories.mdx +195 -0
  7. package/src/Introduction.stories.mdx +148 -0
  8. package/src/components/JhAddressSelect/JhAddressSelect.md +250 -0
  9. package/src/components/JhAddressSelect/JhAddressSelect.stories.js +282 -0
  10. package/src/components/JhAddressSelect/JhAddressSelect.vue +261 -0
  11. package/src/components/JhCard/JhCard.md +246 -0
  12. package/src/components/JhCard/JhCard.stories.js +688 -0
  13. package/src/components/JhCard/JhCard.vue +604 -0
  14. package/src/components/JhCheckCard/JhCheckCard.md +245 -0
  15. package/src/components/JhCheckCard/JhCheckCard.stories.js +750 -0
  16. package/src/components/JhCheckCard/JhCheckCard.vue +476 -0
  17. package/src/components/JhConfirmDialog/JhConfirmDialog.md +70 -0
  18. package/src/components/JhConfirmDialog/JhConfirmDialog.stories.js +550 -0
  19. package/src/components/JhConfirmDialog/JhConfirmDialog.vue +181 -0
  20. package/src/components/JhDateRangePicker/JhDateRangePicker.md +56 -0
  21. package/src/components/JhDateRangePicker/JhDateRangePicker.stories.js +320 -0
  22. package/src/components/JhDateRangePicker/JhDateRangePicker.vue +307 -0
  23. package/src/components/JhDescriptions/JhDescriptions.md +724 -0
  24. package/src/components/JhDescriptions/JhDescriptions.stories.js +858 -0
  25. package/src/components/JhDescriptions/JhDescriptions.vue +933 -0
  26. package/src/components/JhDraggable/JhDraggable.md +66 -0
  27. package/src/components/JhDraggable/JhDraggable.stories.js +161 -0
  28. package/src/components/JhDraggable/JhDraggable.vue +254 -0
  29. package/src/components/JhDrawer/JhDrawer.md +68 -0
  30. package/src/components/JhDrawer/JhDrawer.stories.js +478 -0
  31. package/src/components/JhDrawer/JhDrawer.vue +281 -0
  32. package/src/components/JhDrawerForm/JhDrawerForm.md +69 -0
  33. package/src/components/JhDrawerForm/JhDrawerForm.stories.js +492 -0
  34. package/src/components/JhDrawerForm/JhDrawerForm.vue +297 -0
  35. package/src/components/JhEditableTable/JhEditableTable.md +507 -0
  36. package/src/components/JhEditableTable/JhEditableTable.stories.js +615 -0
  37. package/src/components/JhEditableTable/JhEditableTable.vue +685 -0
  38. package/src/components/JhFileInput/JhFileInput.md +56 -0
  39. package/src/components/JhFileInput/JhFileInput.stories.js +103 -0
  40. package/src/components/JhFileInput/JhFileInput.vue +253 -0
  41. package/src/components/JhForm/JhForm.md +676 -0
  42. package/src/components/JhForm/JhForm.stories.js +1375 -0
  43. package/src/components/JhForm/JhForm.vue +657 -0
  44. package/src/components/JhFormField/JhFormField.stories.js +217 -0
  45. package/src/components/JhFormField/JhFormField.vue +439 -0
  46. package/src/components/JhFormFields/JhFormFields.md +647 -0
  47. package/src/components/JhFormFields/JhFormFields.stories.js +922 -0
  48. package/src/components/JhFormFields/JhFormFields.vue +998 -0
  49. package/src/components/JhFormList/JhFormList.md +303 -0
  50. package/src/components/JhFormList/JhFormList.stories.js +661 -0
  51. package/src/components/JhFormList/JhFormList.vue +1127 -0
  52. package/src/components/JhJsonEditor/JhJsonEditor.md +54 -0
  53. package/src/components/JhJsonEditor/JhJsonEditor.stories.js +157 -0
  54. package/src/components/JhJsonEditor/JhJsonEditor.vue +178 -0
  55. package/src/components/JhLayout/JhLayout.md +580 -0
  56. package/src/components/JhLayout/JhLayout.stories.js +414 -0
  57. package/src/components/JhLayout/JhLayout.vue +387 -0
  58. package/src/components/JhList/JhList.md +441 -0
  59. package/src/components/JhList/JhList.stories.js +524 -0
  60. package/src/components/JhList/JhList.vue +571 -0
  61. package/src/components/JhMarkdownEditor/JhMarkdownEditor.md +56 -0
  62. package/src/components/JhMarkdownEditor/JhMarkdownEditor.stories.js +191 -0
  63. package/src/components/JhMarkdownEditor/JhMarkdownEditor.vue +188 -0
  64. package/src/components/JhMask/JhMask.md +62 -0
  65. package/src/components/JhMask/JhMask.stories.js +270 -0
  66. package/src/components/JhMask/JhMask.vue +123 -0
  67. package/src/components/JhMenu/JhMenu.md +85 -0
  68. package/src/components/JhMenu/JhMenu.stories.js +384 -0
  69. package/src/components/JhMenu/JhMenu.vue +545 -0
  70. package/src/components/JhModal/JhModal.md +68 -0
  71. package/src/components/JhModal/JhModal.stories.js +562 -0
  72. package/src/components/JhModal/JhModal.vue +235 -0
  73. package/src/components/JhModalForm/JhModalForm.md +69 -0
  74. package/src/components/JhModalForm/JhModalForm.stories.js +592 -0
  75. package/src/components/JhModalForm/JhModalForm.vue +298 -0
  76. package/src/components/JhPageContainer/JhPageContainer.md +409 -0
  77. package/src/components/JhPageContainer/JhPageContainer.stories.js +209 -0
  78. package/src/components/JhPageContainer/JhPageContainer.vue +72 -0
  79. package/src/components/JhQueryFilter/JhQueryFilter.md +77 -0
  80. package/src/components/JhQueryFilter/JhQueryFilter.stories.js +684 -0
  81. package/src/components/JhQueryFilter/JhQueryFilter.vue +429 -0
  82. package/src/components/JhScene/JhScene.md +64 -0
  83. package/src/components/JhScene/JhScene.stories.js +317 -0
  84. package/src/components/JhScene/JhScene.vue +376 -0
  85. package/src/components/JhStatisticCard/JhStatisticCard.md +363 -0
  86. package/src/components/JhStatisticCard/JhStatisticCard.stories.js +847 -0
  87. package/src/components/JhStatisticCard/JhStatisticCard.vue +459 -0
  88. package/src/components/JhStepsForm/JhStepsForm.md +666 -0
  89. package/src/components/JhStepsForm/JhStepsForm.stories.js +1224 -0
  90. package/src/components/JhStepsForm/JhStepsForm.vue +749 -0
  91. package/src/components/JhTable/JhTable.md +730 -0
  92. package/src/components/JhTable/JhTable.stories.js +1444 -0
  93. package/src/components/JhTable/JhTable.vue +2298 -0
  94. package/src/components/JhTableAttachment/JhTableAttachment.md +70 -0
  95. package/src/components/JhTableAttachment/JhTableAttachment.stories.js +198 -0
  96. package/src/components/JhTableAttachment/JhTableAttachment.vue +264 -0
  97. package/src/components/JhToast/JhToast.md +67 -0
  98. package/src/components/JhToast/JhToast.stories.js +386 -0
  99. package/src/components/JhToast/JhToast.vue +239 -0
  100. package/src/components/JhTreeSelect/JhTreeSelect.md +82 -0
  101. package/src/components/JhTreeSelect/JhTreeSelect.stories.js +391 -0
  102. package/src/components/JhTreeSelect/JhTreeSelect.vue +727 -0
  103. package/src/components/JhWaterMark/JhWaterMark.md +190 -0
  104. package/src/components/JhWaterMark/JhWaterMark.stories.js +675 -0
  105. package/src/components/JhWaterMark/JhWaterMark.vue +351 -0
  106. package/src/components/README.md +52 -0
  107. package/src/index.js +135 -0
  108. package/src/style/globalCSSJHV4.css +348 -0
  109. package/src/style/globalCSSVuetifyV4.css +637 -0
  110. package/src/style/storybook.css +4 -0
  111. package/src/tailwind.css +3 -0
  112. package/src/utils/vuetify.js +31 -0
@@ -0,0 +1,507 @@
1
+ # JhEditableTable 组件
2
+
3
+ 基于 Ant Design EditableProTable 设计的可编辑表格组件,支持行内编辑、新增、删除等操作。
4
+
5
+ ## 功能特性
6
+
7
+ ### 核心功能
8
+ - ✅ **行内编辑**: 支持单行/多行同时编辑
9
+ - ✅ **多种字段类型**: text、number、select、date、switch、enum 等
10
+ - ✅ **新增行**: 支持动态添加新行
11
+ - ✅ **删除行**: 支持删除指定行
12
+ - ✅ **数据验证**: 支持字段级验证规则
13
+ - ✅ **自定义渲染**: 支持自定义单元格和操作列渲染
14
+
15
+ ### EditableProTable 风格特性
16
+ - ✅ **编辑类型控制**: single(单行编辑)/ multiple(多行编辑)
17
+ - ✅ **最大行数限制**: maxRows 限制表格行数
18
+ - ✅ **操作守卫**: beforeAddRow、beforeRemoveRow 守卫函数
19
+ - ✅ **回调函数**: onSave、onDelete、onValuesChange
20
+ - ✅ **受控模式**: editableKeys 受控编辑状态
21
+ - ✅ **自定义操作**: actionRender 自定义操作列
22
+
23
+ ## 基础用法
24
+
25
+ ```vue
26
+ <template>
27
+ <jh-editable-table
28
+ v-model="dataSource"
29
+ :columns="columns"
30
+ :record-creator="true"
31
+ :editable="true"
32
+ :deletable="true"
33
+ />
34
+ </template>
35
+
36
+ <script>
37
+ export default {
38
+ data() {
39
+ return {
40
+ dataSource: [
41
+ { id: 1, name: '张三', age: 25, status: 'active' },
42
+ { id: 2, name: '李四', age: 30, status: 'inactive' }
43
+ ],
44
+ columns: [
45
+ {
46
+ key: 'name',
47
+ label: '姓名',
48
+ type: 'text',
49
+ editable: true,
50
+ rules: [(v) => !!v || '姓名必填']
51
+ },
52
+ {
53
+ key: 'age',
54
+ label: '年龄',
55
+ type: 'number',
56
+ editable: true
57
+ },
58
+ {
59
+ key: 'status',
60
+ label: '状态',
61
+ type: 'enum',
62
+ editable: true,
63
+ enum: {
64
+ active: { text: '激活', color: 'success' },
65
+ inactive: { text: '未激活', color: 'grey' }
66
+ }
67
+ }
68
+ ]
69
+ };
70
+ }
71
+ };
72
+ </script>
73
+ ```
74
+
75
+ ## 编辑模式
76
+
77
+ ### 单行编辑模式
78
+ 同一时间只能编辑一行,编辑新行时自动保存当前编辑行。
79
+
80
+ ```vue
81
+ <jh-editable-table
82
+ v-model="dataSource"
83
+ :columns="columns"
84
+ editable-type="single"
85
+ />
86
+ ```
87
+
88
+ ### 多行编辑模式(默认)
89
+ 可以同时编辑多行数据。
90
+
91
+ ```vue
92
+ <jh-editable-table
93
+ v-model="dataSource"
94
+ :columns="columns"
95
+ editable-type="multiple"
96
+ />
97
+ ```
98
+
99
+ ## 字段类型
100
+
101
+ ### 文本输入
102
+ ```javascript
103
+ {
104
+ key: 'name',
105
+ label: '姓名',
106
+ type: 'text',
107
+ editable: true,
108
+ placeholder: '请输入姓名',
109
+ rules: [(v) => !!v || '必填']
110
+ }
111
+ ```
112
+
113
+ ### 数字输入
114
+ ```javascript
115
+ {
116
+ key: 'age',
117
+ label: '年龄',
118
+ type: 'number',
119
+ editable: true,
120
+ rules: [(v) => v >= 0 || '年龄不能为负数']
121
+ }
122
+ ```
123
+
124
+ ### 下拉选择
125
+ ```javascript
126
+ {
127
+ key: 'department',
128
+ label: '部门',
129
+ type: 'select',
130
+ editable: true,
131
+ options: ['技术部', '产品部', '运营部']
132
+ }
133
+ ```
134
+
135
+ ### 日期选择
136
+ ```javascript
137
+ {
138
+ key: 'birthday',
139
+ label: '生日',
140
+ type: 'date',
141
+ editable: true
142
+ }
143
+ ```
144
+
145
+ ### 开关
146
+ ```javascript
147
+ {
148
+ key: 'enabled',
149
+ label: '启用',
150
+ type: 'switch',
151
+ editable: true
152
+ }
153
+ ```
154
+
155
+ ### 枚举类型
156
+ ```javascript
157
+ {
158
+ key: 'status',
159
+ label: '状态',
160
+ type: 'enum',
161
+ editable: true,
162
+ enum: {
163
+ pending: { text: '待处理', color: 'warning' },
164
+ approved: { text: '已批准', color: 'success' },
165
+ rejected: { text: '已拒绝', color: 'error' }
166
+ }
167
+ }
168
+ ```
169
+
170
+ ## 高级功能
171
+
172
+ ### 操作守卫
173
+ ```vue
174
+ <jh-editable-table
175
+ v-model="dataSource"
176
+ :columns="columns"
177
+ :before-add-row="async () => {
178
+ const confirmed = await confirmAdd();
179
+ return confirmed;
180
+ }"
181
+ :before-remove-row="async (item, index) => {
182
+ const confirmed = await confirmDelete(item);
183
+ return confirmed;
184
+ }"
185
+ />
186
+ ```
187
+
188
+ ### 保存和删除回调
189
+ ```vue
190
+ <jh-editable-table
191
+ v-model="dataSource"
192
+ :columns="columns"
193
+ :on-save="async (key, item, originRow) => {
194
+ await saveToServer(item);
195
+ console.log('保存成功', item);
196
+ }"
197
+ :on-delete="async (key, item) => {
198
+ await deleteFromServer(key);
199
+ console.log('删除成功', item);
200
+ }"
201
+ :on-values-change="(item, allData) => {
202
+ console.log('数据变化', item, allData);
203
+ }"
204
+ />
205
+ ```
206
+
207
+ ### 受控编辑状态
208
+ ```vue
209
+ <template>
210
+ <jh-editable-table
211
+ v-model="dataSource"
212
+ :columns="columns"
213
+ :editable-keys.sync="editingKeys"
214
+ />
215
+ </template>
216
+
217
+ <script>
218
+ export default {
219
+ data() {
220
+ return {
221
+ dataSource: [],
222
+ editingKeys: ['row-1', 'row-2'] // 控制哪些行处于编辑状态
223
+ };
224
+ }
225
+ };
226
+ </script>
227
+ ```
228
+
229
+ ### 自定义操作列
230
+ ```vue
231
+ <jh-editable-table
232
+ v-model="dataSource"
233
+ :columns="columns"
234
+ :action-render="({ item, index, isEditing }) => {
235
+ if (isEditing) {
236
+ return h('div', [
237
+ h('v-btn', {
238
+ props: { small: true, color: 'success' },
239
+ on: { click: () => handleSave(item) }
240
+ }, '保存'),
241
+ h('v-btn', {
242
+ props: { small: true, color: 'error' },
243
+ on: { click: () => handleCancel(item) }
244
+ }, '取消')
245
+ ]);
246
+ }
247
+ return h('div', [
248
+ h('v-btn', {
249
+ props: { small: true },
250
+ on: { click: () => handleEdit(item) }
251
+ }, '编辑')
252
+ ]);
253
+ }"
254
+ />
255
+ ```
256
+
257
+ ### 自定义单元格渲染
258
+ ```vue
259
+ <jh-editable-table
260
+ v-model="dataSource"
261
+ :columns="columns"
262
+ >
263
+ <template #cell.status="{ item, value }">
264
+ <v-chip :color="getStatusColor(value)" small>
265
+ {{ value }}
266
+ </v-chip>
267
+ </template>
268
+ </jh-editable-table>
269
+ ```
270
+
271
+ ### 最大行数限制
272
+ ```vue
273
+ <jh-editable-table
274
+ v-model="dataSource"
275
+ :columns="columns"
276
+ :max-rows="10"
277
+ @max-rows="handleMaxRows"
278
+ />
279
+ ```
280
+
281
+ ## API
282
+
283
+ ### Props
284
+
285
+ | 属性 | 类型 | 默认值 | 说明 |
286
+ |------|------|--------|------|
287
+ | value (v-model) | Array | `[]` | 表格数据 |
288
+ | columns | Array | `[]` | 列配置(必填) |
289
+ | editable | Boolean | `true` | 是否可编辑 |
290
+ | deletable | Boolean | `true` | 是否可删除 |
291
+ | recordCreator | Boolean | `true` | 是否显示新增按钮 |
292
+ | recordCreatorProps | Object | `{}` | 新增按钮配置 |
293
+ | itemsPerPage | Number | `-1` | 每页显示数量 |
294
+ | hideFooter | Boolean | `true` | 是否隐藏底部分页 |
295
+ | dense | Boolean | `false` | 紧凑模式 |
296
+ | sortable | Boolean | `false` | 是否可排序 |
297
+ | rowKey | String | `'id'` | 行唯一标识字段 |
298
+ | **editableType** | String | `'multiple'` | 编辑类型: `single` \| `multiple` |
299
+ | **maxRows** | Number | `Infinity` | 最大行数 |
300
+ | **onValuesChange** | Function | `null` | 值变化回调 |
301
+ | **beforeAddRow** | Function | `null` | 添加行前守卫 |
302
+ | **beforeRemoveRow** | Function | `null` | 删除行前守卫 |
303
+ | **actionRender** | Function | `null` | 自定义操作渲染 |
304
+ | **editableKeys** | Array | `null` | 受控模式的编辑行keys |
305
+ | **onSave** | Function | `null` | 保存数据时的回调 |
306
+ | **onDelete** | Function | `null` | 删除数据时的回调 |
307
+
308
+ ### Column 配置
309
+
310
+ | 属性 | 类型 | 说明 |
311
+ |------|------|------|
312
+ | key | String | 字段键名(必填) |
313
+ | label | String | 列标题 |
314
+ | type | String | 字段类型: `text` \| `number` \| `select` \| `date` \| `switch` \| `enum` |
315
+ | editable | Boolean | 是否可编辑,默认 true |
316
+ | rules | Array | 验证规则数组 |
317
+ | options | Array | select 类型的选项 |
318
+ | enum | Object | enum 类型的映射 |
319
+ | placeholder | String | 占位符 |
320
+ | width | Number | 列宽度 |
321
+ | align | String | 对齐方式 |
322
+ | sortable | Boolean | 是否可排序 |
323
+
324
+ ### Events
325
+
326
+ | 事件名 | 参数 | 说明 |
327
+ |--------|------|------|
328
+ | input | `(value: Array)` | v-model 更新事件 |
329
+ | change | `(value: Array)` | 数据变化 |
330
+ | edit | `(item: Object)` | 开始编辑行 |
331
+ | save | `(item: Object)` | 保存行 |
332
+ | cancel | `(item: Object)` | 取消编辑 |
333
+ | delete | `(item: Object, index: Number)` | 删除行 |
334
+ | add | `(item: Object)` | 添加新行 |
335
+ | validation-error | `{ item, column, message }` | 验证错误 |
336
+ | max-rows | `(max: Number)` | 达到最大行数 |
337
+ | update:editableKeys | `(keys: Array)` | 编辑状态变化(受控模式) |
338
+
339
+ ### Methods
340
+
341
+ | 方法名 | 参数 | 返回值 | 说明 |
342
+ |--------|------|--------|------|
343
+ | getData | - | `Array` | 获取当前数据 |
344
+ | setData | `(data: Array)` | `void` | 设置数据 |
345
+ | clearData | - | `void` | 清空数据 |
346
+
347
+ ### Slots
348
+
349
+ | 插槽名 | 参数 | 说明 |
350
+ |--------|------|------|
351
+ | cell.{key} | `{ item, value }` | 自定义单元格渲染 |
352
+ | actions | `{ item }` | 自定义操作按钮(显示状态) |
353
+ | footer | - | 自定义底部内容 |
354
+
355
+ ## 完整示例
356
+
357
+ ```vue
358
+ <template>
359
+ <div>
360
+ <jh-editable-table
361
+ v-model="dataSource"
362
+ :columns="columns"
363
+ editable-type="single"
364
+ :max-rows="20"
365
+ :record-creator-props="{
366
+ creatorButtonText: '添加用户'
367
+ }"
368
+ :before-add-row="beforeAdd"
369
+ :before-remove-row="beforeRemove"
370
+ :on-save="handleSave"
371
+ :on-delete="handleDelete"
372
+ :on-values-change="handleValuesChange"
373
+ @max-rows="handleMaxRows"
374
+ >
375
+ <!-- 自定义状态列 -->
376
+ <template #cell.status="{ item, value }">
377
+ <v-chip :color="getStatusColor(value)" small>
378
+ {{ getStatusText(value) }}
379
+ </v-chip>
380
+ </template>
381
+ </jh-editable-table>
382
+ </div>
383
+ </template>
384
+
385
+ <script>
386
+ export default {
387
+ data() {
388
+ return {
389
+ dataSource: [],
390
+ columns: [
391
+ {
392
+ key: 'name',
393
+ label: '姓名',
394
+ type: 'text',
395
+ editable: true,
396
+ rules: [(v) => !!v || '姓名必填'],
397
+ width: 150
398
+ },
399
+ {
400
+ key: 'age',
401
+ label: '年龄',
402
+ type: 'number',
403
+ editable: true,
404
+ rules: [
405
+ (v) => v >= 0 || '年龄不能为负数',
406
+ (v) => v <= 150 || '年龄不能超过150'
407
+ ],
408
+ width: 100
409
+ },
410
+ {
411
+ key: 'department',
412
+ label: '部门',
413
+ type: 'select',
414
+ editable: true,
415
+ options: ['技术部', '产品部', '运营部'],
416
+ width: 150
417
+ },
418
+ {
419
+ key: 'status',
420
+ label: '状态',
421
+ type: 'enum',
422
+ editable: true,
423
+ enum: {
424
+ active: { text: '激活', color: 'success' },
425
+ inactive: { text: '未激活', color: 'grey' },
426
+ pending: { text: '待审核', color: 'warning' }
427
+ },
428
+ width: 120
429
+ },
430
+ {
431
+ key: 'enabled',
432
+ label: '启用',
433
+ type: 'switch',
434
+ editable: true,
435
+ width: 100
436
+ }
437
+ ]
438
+ };
439
+ },
440
+ methods: {
441
+ async beforeAdd() {
442
+ const confirmed = await this.$confirm('确定要添加新用户吗?');
443
+ return confirmed;
444
+ },
445
+ async beforeRemove(item, index) {
446
+ const confirmed = await this.$confirm(`确定要删除 ${item.name} 吗?`);
447
+ return confirmed;
448
+ },
449
+ async handleSave(key, item, originRow) {
450
+ try {
451
+ await this.$api.saveUser(item);
452
+ this.$message.success('保存成功');
453
+ } catch (error) {
454
+ this.$message.error('保存失败');
455
+ return false; // 返回 false 阻止保存
456
+ }
457
+ },
458
+ async handleDelete(key, item) {
459
+ try {
460
+ await this.$api.deleteUser(key);
461
+ this.$message.success('删除成功');
462
+ } catch (error) {
463
+ this.$message.error('删除失败');
464
+ return false;
465
+ }
466
+ },
467
+ handleValuesChange(item, allData) {
468
+ console.log('数据变化:', item);
469
+ console.log('全部数据:', allData);
470
+ },
471
+ handleMaxRows(max) {
472
+ this.$message.warning(`最多只能添加 ${max} 行数据`);
473
+ },
474
+ getStatusColor(status) {
475
+ const colors = {
476
+ active: 'success',
477
+ inactive: 'grey',
478
+ pending: 'warning'
479
+ };
480
+ return colors[status] || 'grey';
481
+ },
482
+ getStatusText(status) {
483
+ const texts = {
484
+ active: '激活',
485
+ inactive: '未激活',
486
+ pending: '待审核'
487
+ };
488
+ return texts[status] || status;
489
+ }
490
+ }
491
+ };
492
+ </script>
493
+ ```
494
+
495
+ ## 注意事项
496
+
497
+ 1. **唯一标识**: 确保每行数据有唯一的 `rowKey` 字段
498
+ 2. **验证规则**: rules 数组中的函数返回 true 表示通过,返回字符串表示错误信息
499
+ 3. **异步操作**: onSave、onDelete 等回调支持异步函数,返回 false 可阻止操作
500
+ 4. **性能优化**: 大数据量时建议启用分页(设置 itemsPerPage)
501
+ 5. **编辑模式**: single 模式适合表单场景,multiple 模式适合批量编辑
502
+
503
+ ## 相关组件
504
+
505
+ - [JhFormList](../JhFormList/JhFormList.md) - 动态表单列表组件
506
+ - [JhTable](../JhTable/JhTable.md) - 高级表格组件
507
+ - [JhForm](../JhForm/JhForm.md) - 表单组件