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,1375 @@
1
+ import JhForm from './JhForm.vue';
2
+ import JhFormFields from '../JhFormFields/JhFormFields.vue';
3
+
4
+ export default {
5
+ title: '数据录入/JhForm - 高级表单',
6
+ component: JhForm,
7
+ tags: ['autodocs'],
8
+ argTypes: {
9
+ showLabels: {
10
+ control: 'boolean',
11
+ description: '是否显示标签',
12
+ },
13
+ labelPosition: {
14
+ control: 'select',
15
+ options: ['top', 'left'],
16
+ description: '标签位置',
17
+ },
18
+ defaultDense: {
19
+ control: 'boolean',
20
+ description: '默认紧凑模式',
21
+ },
22
+ defaultFilled: {
23
+ control: 'boolean',
24
+ description: '默认填充样式',
25
+ },
26
+ defaultOutlined: {
27
+ control: 'boolean',
28
+ description: '默认轮廓样式',
29
+ },
30
+ defaultColsMd: {
31
+ control: 'select',
32
+ options: [3, 4, 6, 12],
33
+ description: '默认列宽(md断点)',
34
+ },
35
+ },
36
+ };
37
+
38
+ // 基础示例
39
+ export const 基础示例 = {
40
+ args: {
41
+ fields: [
42
+ {
43
+ key: 'username',
44
+ label: '用户名',
45
+ type: 'text',
46
+ placeholder: '请输入用户名',
47
+ required: true,
48
+ },
49
+ {
50
+ key: 'email',
51
+ label: '邮箱',
52
+ type: 'text',
53
+ placeholder: '请输入邮箱',
54
+ rules: 'email',
55
+ },
56
+ {
57
+ key: 'phone',
58
+ label: '手机号',
59
+ type: 'text',
60
+ placeholder: '请输入手机号',
61
+ rules: 'phone',
62
+ },
63
+ {
64
+ key: 'age',
65
+ label: '年龄',
66
+ type: 'number',
67
+ placeholder: '请输入年龄',
68
+ rules: 'integer',
69
+ },
70
+ ],
71
+ initialData: {
72
+ username: '',
73
+ email: '',
74
+ phone: '',
75
+ age: '',
76
+ },
77
+ },
78
+ render: (args) => ({
79
+ components: { JhForm },
80
+ setup() {
81
+ return { args };
82
+ },
83
+ template: `
84
+ <JhForm v-bind="args">
85
+ <template #actions="{ validate, resetForm }">
86
+ <v-row class="mt-4">
87
+ <v-col cols="12" class="text-right">
88
+ <v-btn class="mr-2" @click="resetForm">重置</v-btn>
89
+ <v-btn color="success" @click="validate">验证</v-btn>
90
+ </v-col>
91
+ </v-row>
92
+ </template>
93
+ </JhForm>
94
+ `,
95
+ }),
96
+ };
97
+
98
+ // 完整示例
99
+ export const 完整示例 = {
100
+ args: {
101
+ fields: [
102
+ {
103
+ key: 'name',
104
+ label: '姓名',
105
+ type: 'text',
106
+ placeholder: '请输入姓名',
107
+ required: true,
108
+ cols: { xs: 12, sm: 6, md: 6 },
109
+ },
110
+ {
111
+ key: 'gender',
112
+ label: '性别',
113
+ type: 'select',
114
+ placeholder: '请选择性别',
115
+ required: true,
116
+ options: [
117
+ { text: '男', value: 'male' },
118
+ { text: '女', value: 'female' },
119
+ ],
120
+ cols: { xs: 12, sm: 6, md: 6 },
121
+ },
122
+ {
123
+ key: 'birthday',
124
+ label: '出生日期',
125
+ type: 'date',
126
+ placeholder: '请选择日期',
127
+ cols: { xs: 12, sm: 6, md: 6 },
128
+ },
129
+ {
130
+ key: 'email',
131
+ label: '邮箱',
132
+ type: 'text',
133
+ placeholder: '请输入邮箱',
134
+ rules: 'email',
135
+ cols: { xs: 12, sm: 6, md: 6 },
136
+ },
137
+ {
138
+ key: 'phone',
139
+ label: '手机号',
140
+ type: 'text',
141
+ placeholder: '请输入手机号',
142
+ rules: 'phone',
143
+ cols: { xs: 12, sm: 6, md: 6 },
144
+ },
145
+ {
146
+ key: 'department',
147
+ label: '部门',
148
+ type: 'autocomplete',
149
+ placeholder: '请选择部门',
150
+ options: [
151
+ { text: '技术部', value: 'tech' },
152
+ { text: '产品部', value: 'product' },
153
+ { text: '运营部', value: 'operation' },
154
+ ],
155
+ cols: { xs: 12, sm: 6, md: 6 },
156
+ },
157
+ {
158
+ key: 'status',
159
+ label: '状态',
160
+ type: 'radio',
161
+ required: true,
162
+ options: [
163
+ { text: '激活', value: 'active' },
164
+ { text: '禁用', value: 'inactive' },
165
+ ],
166
+ cols: { xs: 12, sm: 12, md: 12 },
167
+ },
168
+ {
169
+ key: 'receiveEmail',
170
+ label: '接收邮件通知',
171
+ type: 'switch',
172
+ switchLabel: '接收邮件通知',
173
+ cols: { xs: 12, sm: 6, md: 6 },
174
+ },
175
+ {
176
+ key: 'agree',
177
+ label: '同意协议',
178
+ type: 'checkbox',
179
+ checkboxLabel: '我已阅读并同意用户协议',
180
+ cols: { xs: 12, sm: 6, md: 6 },
181
+ },
182
+ {
183
+ key: 'bio',
184
+ label: '个人简介',
185
+ type: 'textarea',
186
+ placeholder: '请输入个人简介',
187
+ rows: 4,
188
+ cols: { xs: 12, sm: 12, md: 12 },
189
+ },
190
+ ],
191
+ initialData: {
192
+ name: '',
193
+ gender: '',
194
+ birthday: '',
195
+ email: '',
196
+ phone: '',
197
+ department: '',
198
+ status: 'active',
199
+ receiveEmail: true,
200
+ agree: false,
201
+ bio: '',
202
+ },
203
+ },
204
+ render: (args) => ({
205
+ components: { JhForm },
206
+ setup() {
207
+ return { args };
208
+ },
209
+ template: `
210
+ <JhForm v-bind="args" @submit="handleSubmit" @reset="handleReset">
211
+ <template #actions="{ validate, resetForm, formData }">
212
+ <v-row class="mt-4">
213
+ <v-col cols="12" class="text-right">
214
+ <v-btn class="mr-2" @click="resetForm">重置</v-btn>
215
+ <v-btn color="success" @click="handleValidate(validate, formData)">提交</v-btn>
216
+ </v-col>
217
+ </v-row>
218
+ </template>
219
+ </JhForm>
220
+ `,
221
+ methods: {
222
+ handleSubmit(data) {
223
+ console.log('表单提交:', data);
224
+ alert('表单提交成功!请查看控制台');
225
+ },
226
+ handleReset(data) {
227
+ console.log('表单重置:', data);
228
+ },
229
+ async handleValidate(validate, formData) {
230
+ const isValid = await validate();
231
+ if (isValid) {
232
+ console.log('验证通过:', formData);
233
+ alert('验证通过!请查看控制台');
234
+ } else {
235
+ alert('验证失败,请检查表单');
236
+ }
237
+ },
238
+ },
239
+ }),
240
+ };
241
+
242
+ // Grid 自动布局
243
+ export const Grid栅格布局 = {
244
+ args: {
245
+ layout: 'grid',
246
+ grid: true,
247
+ colProps: { span: 8, lg: 6 },
248
+ rowProps: { dense: true },
249
+ fields: [
250
+ { type: 'group', title: '项目信息' },
251
+ {
252
+ key: 'projectCode',
253
+ label: '项目编号',
254
+ type: 'text',
255
+ placeholder: '请输入编号',
256
+ colSpan: 6,
257
+ },
258
+ {
259
+ key: 'projectName',
260
+ label: '项目名称',
261
+ type: 'text',
262
+ placeholder: '请输入名称',
263
+ colSpan: 12,
264
+ required: true,
265
+ },
266
+ {
267
+ key: 'owner',
268
+ label: '负责人',
269
+ type: 'text',
270
+ placeholder: '请输入负责人',
271
+ colProps: { md: 4 },
272
+ },
273
+ {
274
+ key: 'status',
275
+ label: '状态',
276
+ type: 'select',
277
+ options: [
278
+ { text: '未开始', value: 'todo' },
279
+ { text: '进行中', value: 'doing' },
280
+ { text: '已完成', value: 'done' },
281
+ ],
282
+ colProps: { md: 4 },
283
+ },
284
+ {
285
+ key: 'publish',
286
+ label: '发布时间',
287
+ type: 'date',
288
+ colProps: { md: 4 },
289
+ },
290
+ ],
291
+ initialData: {
292
+ projectCode: 'PRJ-2024-001',
293
+ status: 'doing',
294
+ },
295
+ },
296
+ render: (args) => ({
297
+ components: { JhForm },
298
+ setup() {
299
+ return { args };
300
+ },
301
+ template: `
302
+ <JhForm v-bind="args">
303
+ <template #actions="{ validate, resetForm }">
304
+ <v-btn class="mr-2" text @click="resetForm">重置</v-btn>
305
+ <v-btn color="primary" @click="validate">提交</v-btn>
306
+ </template>
307
+ </JhForm>
308
+ `,
309
+ }),
310
+ };
311
+
312
+ // 三列布局
313
+ export const 三列布局 = {
314
+ args: {
315
+ fields: [
316
+ {
317
+ key: 'field1',
318
+ label: '字段1',
319
+ type: 'text',
320
+ placeholder: '请输入',
321
+ cols: { md: 4 },
322
+ },
323
+ {
324
+ key: 'field2',
325
+ label: '字段2',
326
+ type: 'text',
327
+ placeholder: '请输入',
328
+ cols: { md: 4 },
329
+ },
330
+ {
331
+ key: 'field3',
332
+ label: '字段3',
333
+ type: 'text',
334
+ placeholder: '请输入',
335
+ cols: { md: 4 },
336
+ },
337
+ {
338
+ key: 'field4',
339
+ label: '字段4',
340
+ type: 'select',
341
+ placeholder: '请选择',
342
+ options: [
343
+ { text: '选项1', value: '1' },
344
+ { text: '选项2', value: '2' },
345
+ ],
346
+ cols: { md: 4 },
347
+ },
348
+ {
349
+ key: 'field5',
350
+ label: '字段5',
351
+ type: 'date',
352
+ placeholder: '请选择日期',
353
+ cols: { md: 4 },
354
+ },
355
+ {
356
+ key: 'field6',
357
+ label: '字段6',
358
+ type: 'text',
359
+ placeholder: '请输入',
360
+ cols: { md: 4 },
361
+ },
362
+ ],
363
+ defaultColsMd: 4,
364
+ },
365
+ };
366
+
367
+ // 无标签模式
368
+ export const 无标签模式 = {
369
+ args: {
370
+ showLabels: false,
371
+ fields: [
372
+ {
373
+ key: 'name',
374
+ type: 'text',
375
+ placeholder: '姓名',
376
+ },
377
+ {
378
+ key: 'email',
379
+ type: 'text',
380
+ placeholder: '邮箱',
381
+ },
382
+ {
383
+ key: 'phone',
384
+ type: 'text',
385
+ placeholder: '手机号',
386
+ },
387
+ {
388
+ key: 'message',
389
+ type: 'textarea',
390
+ placeholder: '留言内容',
391
+ rows: 3,
392
+ cols: { md: 12 },
393
+ },
394
+ ],
395
+ },
396
+ };
397
+
398
+ // 轮廓样式
399
+ export const 轮廓样式 = {
400
+ args: {
401
+ defaultFilled: false,
402
+ defaultOutlined: true,
403
+ fields: [
404
+ {
405
+ key: 'username',
406
+ label: '用户名',
407
+ type: 'text',
408
+ placeholder: '请输入用户名',
409
+ },
410
+ {
411
+ key: 'password',
412
+ label: '密码',
413
+ type: 'text',
414
+ placeholder: '请输入密码',
415
+ props: {
416
+ type: 'password',
417
+ },
418
+ },
419
+ {
420
+ key: 'role',
421
+ label: '角色',
422
+ type: 'select',
423
+ placeholder: '请选择角色',
424
+ options: [
425
+ { text: '管理员', value: 'admin' },
426
+ { text: '普通用户', value: 'user' },
427
+ ],
428
+ },
429
+ ],
430
+ },
431
+ };
432
+
433
+ // 预填充数据
434
+ export const 预填充数据 = {
435
+ args: {
436
+ fields: [
437
+ {
438
+ key: 'username',
439
+ label: '用户名',
440
+ type: 'text',
441
+ placeholder: '请输入用户名',
442
+ required: true,
443
+ },
444
+ {
445
+ key: 'email',
446
+ label: '邮箱',
447
+ type: 'text',
448
+ placeholder: '请输入邮箱',
449
+ rules: 'email',
450
+ },
451
+ {
452
+ key: 'status',
453
+ label: '状态',
454
+ type: 'select',
455
+ options: [
456
+ { text: '激活', value: 'active' },
457
+ { text: '禁用', value: 'inactive' },
458
+ ],
459
+ },
460
+ {
461
+ key: 'receiveNotification',
462
+ label: '接收通知',
463
+ type: 'switch',
464
+ switchLabel: '接收通知',
465
+ },
466
+ ],
467
+ initialData: {
468
+ username: '张三',
469
+ email: 'zhangsan@example.com',
470
+ status: 'active',
471
+ receiveNotification: true,
472
+ },
473
+ },
474
+ };
475
+
476
+ // 单列布局
477
+ export const 单列布局 = {
478
+ args: {
479
+ defaultColsMd: 12,
480
+ fields: [
481
+ {
482
+ key: 'title',
483
+ label: '标题',
484
+ type: 'text',
485
+ placeholder: '请输入标题',
486
+ required: true,
487
+ },
488
+ {
489
+ key: 'category',
490
+ label: '分类',
491
+ type: 'select',
492
+ placeholder: '请选择分类',
493
+ options: [
494
+ { text: '技术', value: 'tech' },
495
+ { text: '生活', value: 'life' },
496
+ { text: '工作', value: 'work' },
497
+ ],
498
+ },
499
+ {
500
+ key: 'tags',
501
+ label: '标签',
502
+ type: 'select',
503
+ placeholder: '请选择标签',
504
+ multiple: true,
505
+ chips: true,
506
+ options: [
507
+ { text: 'Vue', value: 'vue' },
508
+ { text: 'React', value: 'react' },
509
+ { text: 'Angular', value: 'angular' },
510
+ ],
511
+ },
512
+ {
513
+ key: 'content',
514
+ label: '内容',
515
+ type: 'textarea',
516
+ placeholder: '请输入内容',
517
+ rows: 6,
518
+ },
519
+ ],
520
+ },
521
+ };
522
+
523
+ // 时间字段
524
+ export const 时间字段 = {
525
+ args: {
526
+ fields: [
527
+ {
528
+ key: 'startDate',
529
+ label: '开始日期',
530
+ type: 'date',
531
+ placeholder: '请选择开始日期',
532
+ required: true,
533
+ },
534
+ {
535
+ key: 'endDate',
536
+ label: '结束日期',
537
+ type: 'date',
538
+ placeholder: '请选择结束日期',
539
+ required: true,
540
+ },
541
+ {
542
+ key: 'startTime',
543
+ label: '开始时间',
544
+ type: 'time',
545
+ placeholder: '请选择开始时间',
546
+ },
547
+ {
548
+ key: 'endTime',
549
+ label: '结束时间',
550
+ type: 'time',
551
+ placeholder: '请选择结束时间',
552
+ },
553
+ ],
554
+ },
555
+ };
556
+
557
+ // 水平布局
558
+ export const 水平布局 = {
559
+ args: {
560
+ layout: 'horizontal',
561
+ labelWidth: 'auto',
562
+ labelAlign: 'right',
563
+ fields: [
564
+ {
565
+ key: 'username',
566
+ label: '用户名',
567
+ type: 'text',
568
+ placeholder: '请输入用户名',
569
+ required: true,
570
+ cols: { md: 12 },
571
+ },
572
+ {
573
+ key: 'realname',
574
+ label: '真实姓名',
575
+ type: 'text',
576
+ placeholder: '请输入真实姓名',
577
+ cols: { md: 12 },
578
+ },
579
+ {
580
+ key: 'email',
581
+ label: '邮箱地址',
582
+ type: 'text',
583
+ placeholder: '请输入邮箱',
584
+ rules: 'email',
585
+ cols: { md: 12 },
586
+ },
587
+ {
588
+ key: 'phone',
589
+ label: '手机号',
590
+ type: 'text',
591
+ placeholder: '请输入手机号',
592
+ rules: 'phone',
593
+ cols: { md: 12 },
594
+ },
595
+ {
596
+ key: 'status',
597
+ label: '状态',
598
+ type: 'radio',
599
+ options: [
600
+ { text: '激活', value: 'active' },
601
+ { text: '禁用', value: 'inactive' },
602
+ ],
603
+ defaultValue: 'active',
604
+ cols: { md: 12 },
605
+ },
606
+ {
607
+ key: 'bio',
608
+ label: '个人简介',
609
+ type: 'textarea',
610
+ placeholder: '请输入个人简介',
611
+ rows: 3,
612
+ cols: { md: 12 },
613
+ },
614
+ ],
615
+ },
616
+ };
617
+
618
+ // 行内布局
619
+ export const 行内布局 = {
620
+ args: {
621
+ layout: 'inline',
622
+ defaultColsMd: 'auto',
623
+ defaultDense: true,
624
+ fields: [
625
+ {
626
+ key: 'keyword',
627
+ label: '关键词',
628
+ type: 'text',
629
+ placeholder: '请输入关键词',
630
+ },
631
+ {
632
+ key: 'status',
633
+ label: '状态',
634
+ type: 'select',
635
+ placeholder: '请选择状态',
636
+ options: [
637
+ { text: '全部', value: '' },
638
+ { text: '激活', value: 'active' },
639
+ { text: '禁用', value: 'inactive' },
640
+ ],
641
+ },
642
+ {
643
+ key: 'date',
644
+ label: '日期',
645
+ type: 'date',
646
+ placeholder: '请选择日期',
647
+ },
648
+ ],
649
+ },
650
+ render: (args) => ({
651
+ components: { JhForm },
652
+ setup() {
653
+ return { args };
654
+ },
655
+ template: `
656
+ <div>
657
+ <JhForm v-bind="args">
658
+ <template #actions="{ validate, resetForm }">
659
+ <v-btn color="primary" class="ml-2" @click="validate">查询</v-btn>
660
+ <v-btn text class="ml-2" @click="resetForm">重置</v-btn>
661
+ </template>
662
+ </JhForm>
663
+ </div>
664
+ `,
665
+ }),
666
+ };
667
+
668
+ // 字段分组
669
+ export const 字段分组 = {
670
+ args: {
671
+ fields: [
672
+ { type: 'group', title: '基本信息', divider: false },
673
+ {
674
+ key: 'username',
675
+ label: '用户名',
676
+ type: 'text',
677
+ placeholder: '请输入用户名',
678
+ required: true,
679
+ cols: { md: 6 },
680
+ },
681
+ {
682
+ key: 'realname',
683
+ label: '真实姓名',
684
+ type: 'text',
685
+ placeholder: '请输入真实姓名',
686
+ required: true,
687
+ cols: { md: 6 },
688
+ },
689
+ {
690
+ key: 'email',
691
+ label: '邮箱',
692
+ type: 'text',
693
+ placeholder: '请输入邮箱',
694
+ rules: 'email',
695
+ cols: { md: 6 },
696
+ },
697
+ {
698
+ key: 'phone',
699
+ label: '手机号',
700
+ type: 'text',
701
+ placeholder: '请输入手机号',
702
+ rules: 'phone',
703
+ cols: { md: 6 },
704
+ },
705
+
706
+ { type: 'group', title: '账户设置', divider: true, description: '设置账户相关信息' },
707
+ {
708
+ key: 'role',
709
+ label: '角色',
710
+ type: 'select',
711
+ placeholder: '请选择角色',
712
+ options: [
713
+ { text: '管理员', value: 'admin' },
714
+ { text: '普通用户', value: 'user' },
715
+ ],
716
+ required: true,
717
+ cols: { md: 6 },
718
+ },
719
+ {
720
+ key: 'status',
721
+ label: '状态',
722
+ type: 'radio',
723
+ options: [
724
+ { text: '激活', value: 'active' },
725
+ { text: '禁用', value: 'inactive' },
726
+ ],
727
+ defaultValue: 'active',
728
+ cols: { md: 6 },
729
+ },
730
+ {
731
+ key: 'receiveNotification',
732
+ label: '接收通知',
733
+ type: 'switch',
734
+ switchLabel: '接收邮件通知',
735
+ cols: { md: 6 },
736
+ },
737
+
738
+ { type: 'group', title: '其他信息', divider: true },
739
+ {
740
+ key: 'bio',
741
+ label: '个人简介',
742
+ type: 'textarea',
743
+ placeholder: '请输入个人简介',
744
+ rows: 4,
745
+ cols: { md: 12 },
746
+ },
747
+ ],
748
+ },
749
+ };
750
+
751
+ // 字段联动
752
+ export const 字段联动 = {
753
+ args: {
754
+ fields: [
755
+ {
756
+ key: 'userType',
757
+ label: '用户类型',
758
+ type: 'radio',
759
+ options: [
760
+ { text: '个人用户', value: 'personal' },
761
+ { text: '企业用户', value: 'company' },
762
+ ],
763
+ required: true,
764
+ defaultValue: 'personal',
765
+ cols: { md: 12 },
766
+ },
767
+
768
+ // 个人用户字段
769
+ {
770
+ key: 'personalName',
771
+ label: '姓名',
772
+ type: 'text',
773
+ placeholder: '请输入姓名',
774
+ required: true,
775
+ visible: (formData) => formData.userType === 'personal',
776
+ cols: { md: 6 },
777
+ },
778
+ {
779
+ key: 'idCard',
780
+ label: '身份证号',
781
+ type: 'text',
782
+ placeholder: '请输入身份证号',
783
+ visible: (formData) => formData.userType === 'personal',
784
+ cols: { md: 6 },
785
+ },
786
+
787
+ // 企业用户字段
788
+ {
789
+ key: 'companyName',
790
+ label: '公司名称',
791
+ type: 'text',
792
+ placeholder: '请输入公司名称',
793
+ required: true,
794
+ visible: (formData) => formData.userType === 'company',
795
+ cols: { md: 6 },
796
+ },
797
+ {
798
+ key: 'businessLicense',
799
+ label: '营业执照号',
800
+ type: 'text',
801
+ placeholder: '请输入营业执照号',
802
+ visible: (formData) => formData.userType === 'company',
803
+ cols: { md: 6 },
804
+ },
805
+ {
806
+ key: 'legalPerson',
807
+ label: '法人代表',
808
+ type: 'text',
809
+ placeholder: '请输入法人代表',
810
+ visible: (formData) => formData.userType === 'company',
811
+ cols: { md: 6 },
812
+ },
813
+
814
+ // 共同字段
815
+ {
816
+ key: 'phone',
817
+ label: '联系电话',
818
+ type: 'text',
819
+ placeholder: '请输入联系电话',
820
+ rules: 'phone',
821
+ required: true,
822
+ cols: { md: 6 },
823
+ },
824
+ {
825
+ key: 'email',
826
+ label: '邮箱',
827
+ type: 'text',
828
+ placeholder: '请输入邮箱',
829
+ rules: 'email',
830
+ cols: { md: 6 },
831
+ },
832
+
833
+ // 条件禁用示例
834
+ {
835
+ key: 'agreeTerms',
836
+ label: '同意条款',
837
+ type: 'checkbox',
838
+ checkboxLabel: '我已阅读并同意用户协议',
839
+ cols: { md: 12 },
840
+ },
841
+ {
842
+ key: 'remarks',
843
+ label: '备注',
844
+ type: 'textarea',
845
+ placeholder: '请输入备注信息',
846
+ rows: 3,
847
+ disabled: (formData) => !formData.agreeTerms,
848
+ cols: { md: 12 },
849
+ },
850
+ ],
851
+ initialData: {
852
+ userType: 'personal',
853
+ agreeTerms: false,
854
+ },
855
+ },
856
+ };
857
+ // 混合布局
858
+ export const 混合布局 = {
859
+ args: {
860
+ layout: 'vertical',
861
+ fields: [
862
+ {
863
+ key: 'title',
864
+ label: '标题',
865
+ type: 'text',
866
+ placeholder: '请输入标题',
867
+ required: true,
868
+ cols: { md: 12 },
869
+ },
870
+ {
871
+ key: 'category',
872
+ label: '分类',
873
+ type: 'select',
874
+ placeholder: '请选择分类',
875
+ layout: 'horizontal',
876
+ labelWidth: 'auto',
877
+ options: [
878
+ { text: '技术', value: 'tech' },
879
+ { text: '生活', value: 'life' },
880
+ ],
881
+ cols: { md: 6 },
882
+ },
883
+ {
884
+ key: 'priority',
885
+ label: '优先级',
886
+ type: 'select',
887
+ placeholder: '请选择优先级',
888
+ layout: 'horizontal',
889
+ labelWidth: 'auto',
890
+ options: [
891
+ { text: '高', value: 'high' },
892
+ { text: '中', value: 'medium' },
893
+ { text: '低', value: 'low' },
894
+ ],
895
+ cols: { md: 6 },
896
+ },
897
+ {
898
+ key: 'content',
899
+ label: '内容',
900
+ type: 'textarea',
901
+ placeholder: '请输入内容',
902
+ rows: 6,
903
+ cols: { md: 12 },
904
+ },
905
+ ],
906
+ },
907
+ };
908
+
909
+ // 提示信息示例
910
+ export const 提示信息 = {
911
+ args: {
912
+ fields: [
913
+ {
914
+ key: 'username',
915
+ label: '用户名',
916
+ type: 'text',
917
+ placeholder: '请输入用户名',
918
+ required: true,
919
+ tooltip: '用户名用于登录系统,长度4-20个字符',
920
+ extra: '用户名一旦设置不可修改',
921
+ cols: { md: 6 },
922
+ },
923
+ {
924
+ key: 'password',
925
+ label: '密码',
926
+ type: 'text',
927
+ placeholder: '请输入密码',
928
+ required: true,
929
+ tooltip: '密码长度至少8位,包含字母、数字和特殊字符',
930
+ extra: '建议使用强密码以保护账户安全',
931
+ props: { type: 'password' },
932
+ cols: { md: 6 },
933
+ },
934
+ {
935
+ key: 'email',
936
+ label: '邮箱',
937
+ type: 'text',
938
+ placeholder: '请输入邮箱',
939
+ rules: 'email',
940
+ tooltip: '用于接收系统通知和找回密码',
941
+ cols: { md: 6 },
942
+ },
943
+ {
944
+ key: 'phone',
945
+ label: '手机号',
946
+ type: 'text',
947
+ placeholder: '请输入手机号',
948
+ rules: 'phone',
949
+ tooltip: '用于接收短信验证码',
950
+ extra: '请确保手机号真实有效',
951
+ cols: { md: 6 },
952
+ },
953
+ ],
954
+ },
955
+ };
956
+
957
+ // 数据转换示例
958
+ export const 数据转换 = {
959
+ args: {
960
+ fields: [
961
+ {
962
+ key: 'price',
963
+ label: '价格(元)',
964
+ type: 'number',
965
+ placeholder: '请输入价格',
966
+ required: true,
967
+ tooltip: '输入金额,提交时会自动转换为分',
968
+ // 提交时转换为分
969
+ transform: (value) => value ? Math.round(value * 100) : 0,
970
+ cols: { md: 6 },
971
+ },
972
+ {
973
+ key: 'tags',
974
+ label: '标签',
975
+ type: 'select',
976
+ placeholder: '请选择标签',
977
+ multiple: true,
978
+ chips: true,
979
+ options: [
980
+ { text: 'Vue', value: 'vue' },
981
+ { text: 'React', value: 'react' },
982
+ { text: 'Angular', value: 'angular' },
983
+ { text: 'Node.js', value: 'nodejs' },
984
+ ],
985
+ tooltip: '可以选择多个标签',
986
+ // 提交时转换为逗号分隔的字符串
987
+ transform: (value) => Array.isArray(value) ? value.join(',') : value,
988
+ cols: { md: 6 },
989
+ },
990
+ {
991
+ key: 'discount',
992
+ label: '折扣(%)',
993
+ type: 'number',
994
+ placeholder: '请输入折扣',
995
+ tooltip: '输入百分比,提交时会转换为小数',
996
+ // 提交时转换为小数
997
+ transform: (value) => value ? value / 100 : 0,
998
+ cols: { md: 6 },
999
+ },
1000
+ {
1001
+ key: 'description',
1002
+ label: '描述',
1003
+ type: 'textarea',
1004
+ placeholder: '请输入描述',
1005
+ rows: 3,
1006
+ // 提交时去除首尾空格
1007
+ transform: (value) => value ? value.trim() : '',
1008
+ cols: { md: 12 },
1009
+ },
1010
+ ],
1011
+ initialData: {
1012
+ price: 99.99,
1013
+ tags: ['vue', 'react'],
1014
+ discount: 15,
1015
+ description: ' 这是一个示例描述 ',
1016
+ },
1017
+ omitNil: true,
1018
+ },
1019
+ render: (args) => ({
1020
+ components: { JhForm },
1021
+ setup() {
1022
+ return { args };
1023
+ },
1024
+ template: `
1025
+ <div>
1026
+ <JhForm v-bind="args" ref="form">
1027
+ <template #actions="{ validate, resetForm, formData }">
1028
+ <v-row class="mt-4">
1029
+ <v-col cols="12" class="text-right">
1030
+ <v-btn class="mr-2" @click="resetForm">重置</v-btn>
1031
+ <v-btn color="success" @click="handleSubmit">查看转换后的数据</v-btn>
1032
+ </v-col>
1033
+ </v-row>
1034
+ </template>
1035
+ </JhForm>
1036
+ <v-divider class="my-4"></v-divider>
1037
+ <div class="pa-4 grey lighten-4">
1038
+ <h4 class="mb-2">说明:</h4>
1039
+ <ul>
1040
+ <li>价格: 99.99元 → 9999分</li>
1041
+ <li>标签: ['vue', 'react'] → 'vue,react'</li>
1042
+ <li>折扣: 15% → 0.15</li>
1043
+ <li>描述: 自动去除首尾空格</li>
1044
+ </ul>
1045
+ </div>
1046
+ </div>
1047
+ `,
1048
+ methods: {
1049
+ async handleSubmit() {
1050
+ const isValid = await this.$refs.form.validate();
1051
+ if (isValid) {
1052
+ const transformedData = this.$refs.form.getTransformedData();
1053
+ console.log('原始数据:', this.$refs.form.getFormData());
1054
+ console.log('转换后数据:', transformedData);
1055
+ alert('转换后的数据已打印到控制台,请查看');
1056
+ }
1057
+ },
1058
+ },
1059
+ }),
1060
+ };
1061
+
1062
+ // onFinish 回调示例
1063
+ export const 提交回调 = {
1064
+ args: {
1065
+ fields: [
1066
+ {
1067
+ key: 'title',
1068
+ label: '标题',
1069
+ type: 'text',
1070
+ placeholder: '请输入标题',
1071
+ required: true,
1072
+ },
1073
+ {
1074
+ key: 'content',
1075
+ label: '内容',
1076
+ type: 'textarea',
1077
+ placeholder: '请输入内容',
1078
+ required: true,
1079
+ rows: 4,
1080
+ cols: { md: 12 },
1081
+ },
1082
+ ],
1083
+ initialData: {
1084
+ title: '',
1085
+ content: '',
1086
+ },
1087
+ },
1088
+ render: (args) => ({
1089
+ components: { JhForm },
1090
+ data() {
1091
+ return {
1092
+ args: {
1093
+ ...args,
1094
+ onFinish: this.handleFinish,
1095
+ onFinishFailed: this.handleFinishFailed,
1096
+ },
1097
+ loading: false,
1098
+ };
1099
+ },
1100
+ template: `
1101
+ <div>
1102
+ <JhForm v-bind="args">
1103
+ <template #actions="{ validate, resetForm }">
1104
+ <v-row class="mt-4">
1105
+ <v-col cols="12" class="text-right">
1106
+ <v-btn class="mr-2" @click="resetForm" :disabled="loading">重置</v-btn>
1107
+ <v-btn
1108
+ color="success"
1109
+ @click="validate"
1110
+ :loading="loading"
1111
+ >
1112
+ 提交
1113
+ </v-btn>
1114
+ </v-col>
1115
+ </v-row>
1116
+ </template>
1117
+ </JhForm>
1118
+ <v-alert v-if="submitResult" :type="submitResult.type" class="mt-4">
1119
+ {{ submitResult.message }}
1120
+ </v-alert>
1121
+ </div>
1122
+ `,
1123
+ data() {
1124
+ return {
1125
+ submitResult: null,
1126
+ };
1127
+ },
1128
+ methods: {
1129
+ async handleFinish(values) {
1130
+ this.loading = true;
1131
+ this.submitResult = null;
1132
+
1133
+ // 模拟 API 调用
1134
+ await new Promise(resolve => setTimeout(resolve, 1500));
1135
+
1136
+ console.log('提交成功:', values);
1137
+ this.submitResult = {
1138
+ type: 'success',
1139
+ message: '提交成功! 数据: ' + JSON.stringify(values),
1140
+ };
1141
+ this.loading = false;
1142
+ },
1143
+ handleFinishFailed(values) {
1144
+ console.log('验证失败:', values);
1145
+ this.submitResult = {
1146
+ type: 'error',
1147
+ message: '表单验证失败,请检查必填项',
1148
+ };
1149
+ },
1150
+ },
1151
+ }),
1152
+ };
1153
+
1154
+ // 只读模式示例
1155
+ export const 只读模式 = {
1156
+ args: {
1157
+ readonly: true,
1158
+ fields: [
1159
+ {
1160
+ key: 'username',
1161
+ label: '用户名',
1162
+ type: 'text',
1163
+ cols: { md: 6 },
1164
+ },
1165
+ {
1166
+ key: 'email',
1167
+ label: '邮箱',
1168
+ type: 'text',
1169
+ cols: { md: 6 },
1170
+ },
1171
+ {
1172
+ key: 'role',
1173
+ label: '角色',
1174
+ type: 'select',
1175
+ options: [
1176
+ { text: '管理员', value: 'admin' },
1177
+ { text: '普通用户', value: 'user' },
1178
+ ],
1179
+ cols: { md: 6 },
1180
+ },
1181
+ {
1182
+ key: 'status',
1183
+ label: '状态',
1184
+ type: 'radio',
1185
+ options: [
1186
+ { text: '激活', value: 'active' },
1187
+ { text: '禁用', value: 'inactive' },
1188
+ ],
1189
+ cols: { md: 6 },
1190
+ },
1191
+ {
1192
+ key: 'receiveNotification',
1193
+ label: '接收通知',
1194
+ type: 'switch',
1195
+ switchLabel: '接收邮件通知',
1196
+ cols: { md: 6 },
1197
+ },
1198
+ {
1199
+ key: 'tags',
1200
+ label: '标签',
1201
+ type: 'select',
1202
+ multiple: true,
1203
+ options: [
1204
+ { text: 'Vue', value: 'vue' },
1205
+ { text: 'React', value: 'react' },
1206
+ { text: 'Angular', value: 'angular' },
1207
+ ],
1208
+ cols: { md: 6 },
1209
+ },
1210
+ {
1211
+ key: 'bio',
1212
+ label: '个人简介',
1213
+ type: 'textarea',
1214
+ rows: 3,
1215
+ cols: { md: 12 },
1216
+ },
1217
+ ],
1218
+ initialData: {
1219
+ username: '张三',
1220
+ email: 'zhangsan@example.com',
1221
+ role: 'admin',
1222
+ status: 'active',
1223
+ receiveNotification: true,
1224
+ tags: ['vue', 'react'],
1225
+ bio: '这是一段个人简介,用于展示只读模式下的文本域显示效果。',
1226
+ },
1227
+ },
1228
+ };
1229
+
1230
+ // 使用 JhFormFields 组合表单
1231
+ export const 使用JhFormFields组合 = () => ({
1232
+ components: { JhFormFields },
1233
+ data() {
1234
+ return {
1235
+ formData: {
1236
+ userType: 'personal',
1237
+ },
1238
+ basicFields: [
1239
+ {
1240
+ key: 'username',
1241
+ label: '用户名',
1242
+ type: 'text',
1243
+ placeholder: '请输入用户名',
1244
+ required: true,
1245
+ },
1246
+ {
1247
+ key: 'email',
1248
+ label: '邮箱',
1249
+ type: 'text',
1250
+ placeholder: '请输入邮箱',
1251
+ rules: 'email',
1252
+ },
1253
+ ],
1254
+ typeFields: [
1255
+ {
1256
+ key: 'userType',
1257
+ label: '用户类型',
1258
+ type: 'radio',
1259
+ options: [
1260
+ { text: '个人用户', value: 'personal' },
1261
+ { text: '企业用户', value: 'company' },
1262
+ ],
1263
+ defaultValue: 'personal',
1264
+ cols: { md: 12 },
1265
+ },
1266
+ {
1267
+ key: 'personalName',
1268
+ label: '真实姓名',
1269
+ type: 'text',
1270
+ placeholder: '请输入真实姓名',
1271
+ required: true,
1272
+ visible: (values) => values.userType === 'personal',
1273
+ dependencies: ['userType'],
1274
+ },
1275
+ {
1276
+ key: 'idCard',
1277
+ label: '身份证号',
1278
+ type: 'text',
1279
+ placeholder: '请输入身份证号',
1280
+ visible: (values) => values.userType === 'personal',
1281
+ dependencies: ['userType'],
1282
+ },
1283
+ {
1284
+ key: 'companyName',
1285
+ label: '公司名称',
1286
+ type: 'text',
1287
+ placeholder: '请输入公司名称',
1288
+ required: true,
1289
+ visible: (values) => values.userType === 'company',
1290
+ dependencies: ['userType'],
1291
+ },
1292
+ {
1293
+ key: 'businessLicense',
1294
+ label: '营业执照号',
1295
+ type: 'text',
1296
+ placeholder: '请输入营业执照号',
1297
+ visible: (values) => values.userType === 'company',
1298
+ dependencies: ['userType'],
1299
+ },
1300
+ ],
1301
+ contactFields: [
1302
+ {
1303
+ key: 'phone',
1304
+ label: '手机号',
1305
+ type: 'text',
1306
+ placeholder: '请输入手机号',
1307
+ rules: 'phone',
1308
+ },
1309
+ {
1310
+ key: 'address',
1311
+ label: '地址',
1312
+ type: 'textarea',
1313
+ placeholder: '请输入地址',
1314
+ rows: 3,
1315
+ cols: { md: 12 },
1316
+ },
1317
+ ],
1318
+ };
1319
+ },
1320
+ template: `
1321
+ <v-container>
1322
+ <v-form>
1323
+ <!-- 基本信息字段集 -->
1324
+ <JhFormFields
1325
+ v-model="formData"
1326
+ :fields="basicFields"
1327
+ title="基本信息"
1328
+ description="请填写您的基本信息"
1329
+ bordered
1330
+ />
1331
+
1332
+ <!-- 用户类型字段集 (带依赖联动) -->
1333
+ <JhFormFields
1334
+ v-model="formData"
1335
+ :fields="typeFields"
1336
+ title="用户类型"
1337
+ description="根据用户类型显示不同的字段"
1338
+ tooltip="字段会根据选择动态显示"
1339
+ bordered
1340
+ class="mt-4"
1341
+ />
1342
+
1343
+ <!-- 联系方式字段集 -->
1344
+ <JhFormFields
1345
+ v-model="formData"
1346
+ :fields="contactFields"
1347
+ title="联系方式"
1348
+ bordered
1349
+ class="mt-4"
1350
+ />
1351
+
1352
+ <!-- 提交按钮 -->
1353
+ <v-row class="mt-4">
1354
+ <v-col cols="12" class="text-right">
1355
+ <v-btn class="mr-2" @click="resetForm">重置</v-btn>
1356
+ <v-btn color="primary" @click="submitForm">提交</v-btn>
1357
+ </v-col>
1358
+ </v-row>
1359
+ </v-form>
1360
+
1361
+ <v-divider class="my-4"></v-divider>
1362
+ <div class="text-caption grey--text">表单数据:</div>
1363
+ <pre class="mt-2 pa-3 grey lighten-4 rounded">{{ formData }}</pre>
1364
+ </v-container>
1365
+ `,
1366
+ methods: {
1367
+ submitForm() {
1368
+ console.log('提交数据:', this.formData);
1369
+ alert('提交成功! 请查看控制台');
1370
+ },
1371
+ resetForm() {
1372
+ this.formData = { userType: 'personal' };
1373
+ },
1374
+ },
1375
+ });