vue3-components-plus 3.0.10

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.
@@ -0,0 +1,714 @@
1
+ <template>
2
+ <div class="demo-container">
3
+ <div class="control-panel">
4
+ <h3>动态表单组件演示</h3>
5
+ <!-- 配置文件选择 -->
6
+ <el-form :model="state" ref="formRef" label-position="left">
7
+ <el-button type="primary" @click="getFormData">获取表单数据</el-button>
8
+ <el-button type="default" @click="resetFormData">重置表单</el-button>
9
+ <br />
10
+ <span style="color: red"> 结果:{{ state.formData }} </span>
11
+ <br />
12
+ <br />
13
+ <NsFormTitle title="模型参数">
14
+ <NsForm
15
+ ref="row1Ref"
16
+ :readOnly="state.readOnly"
17
+ backgroundColor="#fff"
18
+ :model="state.model"
19
+ :rows="state.rows"
20
+ formPropKey="rows"
21
+ labelColor="#606266"
22
+ labelWidth="150"
23
+ gapH="20px"
24
+ gapV="10px"
25
+ ></NsForm>
26
+ </NsFormTitle>
27
+ <NsFormTitle title="视频配置">
28
+ <NsForm
29
+ ref="row2Ref"
30
+ :readOnly="state.readOnly"
31
+ backgroundColor="#fff"
32
+ :model="state.model"
33
+ :rows="state.rows2"
34
+ formPropKey="rows2"
35
+ labelColor="#606266"
36
+ labelWidth="150"
37
+ gapH="20px"
38
+ gapV="10px"
39
+ ></NsForm>
40
+ </NsFormTitle>
41
+ <NsFormTitle title="结果保存">
42
+ <NsForm
43
+ ref="row3Ref"
44
+ :readOnly="state.readOnly"
45
+ backgroundColor="#fff"
46
+ :model="state.model"
47
+ :rows="state.rows3"
48
+ formPropKey="rows3"
49
+ labelColor="#606266"
50
+ labelWidth="150"
51
+ gapH="20px"
52
+ gapV="10px"
53
+ ></NsForm>
54
+ </NsFormTitle>
55
+ <NsFormTitle title="级联选择器测试">
56
+ <NsForm
57
+ ref="row4Ref"
58
+ :readOnly="state.readOnly"
59
+ backgroundColor="#fff"
60
+ :model="state.model"
61
+ :rows="state.rows4"
62
+ formPropKey="rows4"
63
+ labelColor="#606266"
64
+ labelWidth="150"
65
+ gapH="20px"
66
+ gapV="10px"
67
+ ></NsForm>
68
+ </NsFormTitle>
69
+ </el-form>
70
+ </div>
71
+ </div>
72
+ </template>
73
+
74
+ <script setup lang="ts">
75
+ import { h, onMounted, reactive, ref } from 'vue'
76
+ import { cloneDeep } from 'lodash-es'
77
+ import { nextTick } from 'vue'
78
+ import { ElMessage } from 'element-plus'
79
+
80
+ // ------------全局的函数(不需要引入直接使用)------------
81
+ // import { getAllFormKvData, getAllFormNodeByKey, getAllFormNodeRefByKey } from "vue3-components-plus";
82
+ // 获取表单数据
83
+ // const allFormData = getAllFormKvData(state.rows)
84
+ // 获取表单"isEnable"节点数据
85
+ // const isEnableData = getAllFormNodeByKey(state.rows, 'isEnable')
86
+ // 获取表单"isEnable"节点ref实例
87
+ // const isEnableRef = getAllFormNodeRefByKey(state.rows, 'isEnable')
88
+ // ------------NsForm实例的方法------------
89
+ // 重置表单resetForm()
90
+ // row1Ref.value.resetForm()
91
+ // 设置NsForm表单数据 setFormData(data)
92
+ // row1Ref.value.setFormData(data)
93
+ // 获取NsForm表单数据 getFormKvData() 等同于 getAllFormKvData(state.rows)
94
+ // row1Ref.value.getFormKvData()
95
+ // 获取NsForm表单"isEnable"节点数据 getFormNodeByKey('isEnable') 等同于 getAllFormNodeByKey(state.rows, 'isEnable')
96
+ // row1Ref.value.getFormNodeRefByKey('isEnable')
97
+ // 「可选」 初始化表单默认值, 建议使用resetForm()
98
+ // row1Ref.value.initDefaultValues()
99
+ // 「可选」 获取只读模式下的显示值
100
+ // row1Ref.value.getReadOnlyDisplayValue(getAllFormNodeByKey(state.rows, 'isEnable'))
101
+
102
+ const props = defineProps({
103
+ readOnly: {
104
+ type: Boolean,
105
+ default: false,
106
+ },
107
+ row: {
108
+ type: Object,
109
+ default: () => ({}),
110
+ },
111
+ })
112
+
113
+ const formRef = ref()
114
+ const row1Ref = ref()
115
+ const row2Ref = ref()
116
+ const row3Ref = ref()
117
+ const row4Ref = ref()
118
+
119
+ const state = reactive({
120
+ formData: {},
121
+ readOnly: props.readOnly,
122
+ model: props.readOnly ? '' : 'vertical',
123
+ rows: [
124
+ [
125
+ {
126
+ key: 'isEnable',
127
+ label: '是否启用',
128
+ value: false,
129
+ component: 'ElSwitch',
130
+ events: {
131
+ change: changeHandler,
132
+ },
133
+ params: {
134
+ rules: [
135
+ {
136
+ required: true,
137
+ message: '请选择',
138
+ },
139
+ ],
140
+ width: 60,
141
+ 'inline-prompt': true,
142
+ 'active-text': '启用',
143
+ 'inactive-text': '禁用',
144
+ },
145
+ },
146
+ ],
147
+ ],
148
+ rows2: [
149
+ [
150
+ {
151
+ key: 'timeInterval',
152
+ label: '时间间隔(秒)',
153
+ value: '',
154
+ component: 'ElInput',
155
+ params: {
156
+ 'v-length.range': {
157
+ min: 0,
158
+ max: 6000,
159
+ int: true,
160
+ },
161
+ rules: [
162
+ {
163
+ required: true,
164
+ message: '请输入',
165
+ },
166
+ ],
167
+ },
168
+ },
169
+ {
170
+ key: "stuck_threshold",
171
+ label: "所属工程",
172
+ value: "",
173
+ component: "el-cascader",
174
+ params: {
175
+ props: {
176
+ showPrefix: false,
177
+ checkStrictly: true,
178
+ checkOnClickNode: true,
179
+ },
180
+ options: [
181
+ {
182
+ value: "guide",
183
+ label: "Guide",
184
+ children: [
185
+ {
186
+ value: "disciplines",
187
+ label: "Disciplines",
188
+ children: [
189
+ {
190
+ value: "consistency",
191
+ label: "Consistency",
192
+ },
193
+ ],
194
+ },
195
+ {
196
+ value: "navigation",
197
+ label: "Navigation",
198
+ children: [
199
+ {
200
+ value: "side nav",
201
+ label: "Side Navigation",
202
+ },
203
+ ],
204
+ },
205
+ ],
206
+ },
207
+ {
208
+ value: "component",
209
+ label: "测试",
210
+ children: [
211
+ {
212
+ value: "basic",
213
+ label: "Basic",
214
+ children: [
215
+ {
216
+ value: "layout",
217
+ label: "Layout",
218
+ },
219
+ ],
220
+ },
221
+ {
222
+ value: "form",
223
+ label: "中文",
224
+ children: [
225
+ {
226
+ value: "radio",
227
+ label: "Radio",
228
+ },
229
+ ],
230
+ },
231
+ ],
232
+ },
233
+ {
234
+ value: "resource",
235
+ label: "Resource",
236
+ children: [
237
+ {
238
+ value: "axure",
239
+ label: "Axure Components",
240
+ },
241
+ ],
242
+ },
243
+ ],
244
+ rules: [
245
+ {
246
+ required: true,
247
+ message: "请选择",
248
+ },
249
+ ],
250
+ },
251
+ }
252
+ ],
253
+ [
254
+ {
255
+ key: 'max_retries',
256
+ label: '最大重连次数',
257
+ value: '',
258
+ component: 'ElInput',
259
+ params: {
260
+ 'v-length.range': {
261
+ min: 0,
262
+ max: 100,
263
+ int: true,
264
+ },
265
+ rules: [
266
+ {
267
+ required: true,
268
+ message: '请输入',
269
+ },
270
+ ],
271
+ },
272
+ },
273
+ {
274
+ value: ' ',
275
+ },
276
+ ],
277
+ ],
278
+ rows3: [
279
+ [
280
+ {
281
+ key: 'save_video',
282
+ label: '是否保存视频',
283
+ value: false,
284
+ component: 'ElRadioGroup',
285
+ params: {
286
+ rules: [
287
+ {
288
+ required: true,
289
+ message: '请选择',
290
+ trigger: 'change',
291
+ },
292
+ ],
293
+ options: [
294
+ {
295
+ value: true,
296
+ label: '是',
297
+ },
298
+ {
299
+ value: false,
300
+ label: '否',
301
+ },
302
+ ],
303
+ },
304
+ },
305
+ {
306
+ key: 'pre_buffer_second',
307
+ label: '帧前缓存(秒)',
308
+ value: '',
309
+ component: 'ElInput',
310
+ params: {
311
+ 'v-length.range': {
312
+ min: 0,
313
+ max: 1000,
314
+ int: true,
315
+ },
316
+ rules: [
317
+ {
318
+ required: true,
319
+ message: '请输入',
320
+ },
321
+ ],
322
+ },
323
+ },
324
+ ],
325
+ [
326
+ {
327
+ key: 'det_area_mode',
328
+ label: '检测区域工作模式',
329
+ value: 'normal',
330
+ component: 'ElRadioGroup',
331
+ events: {
332
+ change: detAreaModeChange,
333
+ },
334
+ params: {
335
+ rules: [
336
+ {
337
+ required: true,
338
+ message: '请选择',
339
+ trigger: 'change',
340
+ },
341
+ ],
342
+ options: [
343
+ {
344
+ value: 'normal',
345
+ label: '常规检测(normal)',
346
+ },
347
+ {
348
+ value: 'abnormal',
349
+ label: '非常规检测(abnormal)',
350
+ },
351
+ ],
352
+ },
353
+ },
354
+ ],
355
+ ],
356
+ rows4: [
357
+ [
358
+ {
359
+ key: 'region',
360
+ label: '地区选择',
361
+ value: ['beijing', 'chaoyang'],
362
+ component: 'ElCascader',
363
+ params: {
364
+ showAllLevels: false,
365
+ rules: [
366
+ {
367
+ required: true,
368
+ message: '请选择地区',
369
+ trigger: 'change',
370
+ },
371
+ ],
372
+ props: {
373
+ multiple: true,
374
+ showPrefix: false,
375
+ checkStrictly: true,
376
+ checkOnClickNode: true,
377
+ },
378
+ options: [
379
+ {
380
+ value: 'beijing',
381
+ label: '北京市',
382
+ children: [
383
+ {
384
+ value: 'chaoyang',
385
+ label: '朝阳区',
386
+ children: [
387
+ {
388
+ value: 'chaoyangmen',
389
+ label: '朝阳门街道',
390
+ },
391
+ ],
392
+ },
393
+ {
394
+ value: 'haidian',
395
+ label: '海淀区',
396
+ },
397
+ ],
398
+ },
399
+ {
400
+ value: 'shanghai',
401
+ label: '上海市',
402
+ children: [
403
+ {
404
+ value: 'pudong',
405
+ label: '浦东新区',
406
+ },
407
+ ],
408
+ },
409
+ ],
410
+ },
411
+ },
412
+ {
413
+ key: 'department',
414
+ label: '部门选择',
415
+ value: ['company'],
416
+ component: 'ElCascader',
417
+ params: {
418
+ props: {
419
+ value: 'code',
420
+ label: 'name',
421
+ children: 'subDepartments',
422
+ showPrefix: false,
423
+ checkStrictly: true,
424
+ checkOnClickNode: true,
425
+ },
426
+ separator: ',',
427
+ options: [
428
+ {
429
+ code: 'company',
430
+ name: '公司总部',
431
+ subDepartments: [
432
+ {
433
+ code: 'tech',
434
+ name: '技术部',
435
+ subDepartments: [
436
+ {
437
+ code: 'frontend',
438
+ name: '前端组',
439
+ },
440
+ {
441
+ code: 'backend',
442
+ name: '后端组',
443
+ },
444
+ ],
445
+ },
446
+ {
447
+ code: 'sales',
448
+ name: '销售部',
449
+ },
450
+ ],
451
+ },
452
+ ],
453
+ },
454
+ },
455
+ ],
456
+ [
457
+ {
458
+ key: 'single_level_cascader',
459
+ label: '单层级联',
460
+ value: 'beijing',
461
+ component: 'ElCascader',
462
+ params: {
463
+ options: [
464
+ {
465
+ value: 'beijing',
466
+ label: '北京市',
467
+ },
468
+ {
469
+ value: 'shanghai',
470
+ label: '上海市',
471
+ },
472
+ {
473
+ value: 'guangzhou',
474
+ label: '广州市',
475
+ },
476
+ ],
477
+ },
478
+ },
479
+ {
480
+ value: ' ',
481
+ },
482
+ ],
483
+ ],
484
+ })
485
+
486
+ function changeHandler(v) {
487
+ ElMessage.info(v)
488
+ }
489
+
490
+ function detAreaModeChange(value: any) {
491
+ if (state.rows3?.length && state.rows3[state.rows3.length - 1]?.[0]?.key === 'det_area_json') {
492
+ state.rows3.pop()
493
+ }
494
+
495
+ if (value === 'abnormal') {
496
+ state.rows3.push([
497
+ {
498
+ key: 'det_area_json',
499
+ label: '感兴趣区域',
500
+ value: '',
501
+ readOnlyUseComponent: true,
502
+ component: CustomUIs,
503
+ span: 6,
504
+ },
505
+ { value: ' ' },
506
+ ])
507
+ }
508
+ }
509
+
510
+ function CustomUIs() {
511
+ return h('div', { style: 'color: red', class: 'xx' }, 'xxx')
512
+ }
513
+
514
+ /**
515
+ * 保存
516
+ */
517
+ async function getFormData() {
518
+ try {
519
+ await formRef.value.validate()
520
+ } catch (error: any) {
521
+ console.log(error)
522
+ ElMessage.error('表单校验失败')
523
+ state.formData = {}
524
+ return false
525
+ }
526
+ const data1 = row1Ref.value?.getFormKvData?.()
527
+ const data2 = row2Ref.value?.getFormKvData?.()
528
+ const data3 = row3Ref.value?.getFormKvData?.()
529
+ const data4 = row4Ref.value?.getFormKvData?.()
530
+ const data = { ...data1, ...data2, ...data3, ...data4 }
531
+ state.formData = data
532
+ ElMessage.success('表单校验成功')
533
+ return data
534
+ }
535
+
536
+ /**
537
+ * 重置表单
538
+ */
539
+ async function resetFormData() {
540
+ // 使用组件内置的 resetForm 方法
541
+ row1Ref.value?.resetForm?.()
542
+ row2Ref.value?.resetForm?.()
543
+ row3Ref.value?.resetForm?.()
544
+ row4Ref.value?.resetForm?.()
545
+ setTimeout(() => {
546
+ // 重置表单验证状态
547
+ formRef.value?.clearValidate?.()
548
+ // 清空结果显示
549
+ state.formData = {}
550
+ ElMessage.success('表单重置成功')
551
+ }, 0)
552
+ }
553
+
554
+ async function getDetail() {
555
+ setTimeout(() => {
556
+ const res = {
557
+ isEnable: true,
558
+ confidence: 'aaa1',
559
+ iou: '1',
560
+ timeInterval: '2',
561
+ stuck_threshold: ['component','form'],
562
+ max_retries: '4',
563
+ save_video: true,
564
+ pre_buffer_second: '5',
565
+ det_area_mode: 'abnormal',
566
+ det_area_json: '6',
567
+ region: 'haidian,pudong', //['beijing', 'haidian'],
568
+ department: ['company', 'tech', 'frontend'],
569
+ single_level_cascader: 'shanghai',
570
+ }
571
+ row1Ref.value?.resetForm()
572
+ row2Ref.value?.resetForm()
573
+ row3Ref.value?.resetForm()
574
+ row4Ref.value?.resetForm()
575
+ setTimeout(() => {
576
+ row1Ref.value?.setFormData?.(res)
577
+ row2Ref.value?.setFormData?.(res)
578
+ row3Ref.value?.setFormData?.(res)
579
+ row4Ref.value?.setFormData?.(res)
580
+ }, 10)
581
+ return
582
+ // 特殊处理
583
+ // if (res.det_area_mode === 'abnormal') {
584
+ // detAreaModeChange('abnormal')
585
+ // }
586
+
587
+ setTimeout(() => {
588
+ const res = {
589
+ isEnable: false,
590
+ confidence: 'aaa1',
591
+ iou: '1',
592
+ timeInterval: '2',
593
+ stuck_threshold: 'component,form',
594
+ max_retries: '4',
595
+ save_video: true,
596
+ pre_buffer_second: '5',
597
+ det_area_mode: 'normal',
598
+ det_area_json: '6',
599
+ region: ['beijing', 'haidian'],
600
+ department: ['company', 'tech', 'frontend'],
601
+ single_level_cascader: 'shanghai',
602
+ }
603
+
604
+ row1Ref.value?.resetForm()
605
+ setTimeout(() => {
606
+ row1Ref.value?.setFormData?.(res)
607
+ }, 10)
608
+ // 特殊处理
609
+ }, 2000)
610
+ }, 2000)
611
+ }
612
+
613
+ onMounted(() => {
614
+ getDetail()
615
+ })
616
+ </script>
617
+
618
+ <style lang="scss" scoped>
619
+ .demo-container {
620
+ padding: 20px;
621
+ max-width: 1400px;
622
+ margin: 0 auto;
623
+ }
624
+
625
+ .control-panel {
626
+ background: #f5f5f5;
627
+ padding: 20px;
628
+ border-radius: 8px;
629
+ margin-bottom: 20px;
630
+
631
+ h3 {
632
+ margin: 0 0 20px 0;
633
+ color: #333;
634
+ }
635
+
636
+ h4 {
637
+ margin: 15px 0 10px 0;
638
+ color: #666;
639
+ font-size: 14px;
640
+ }
641
+ }
642
+
643
+ .config-section,
644
+ .upload-section,
645
+ .action-section {
646
+ margin-bottom: 20px;
647
+ padding: 15px;
648
+ background: white;
649
+ border-radius: 6px;
650
+ border: 1px solid #e0e0e0;
651
+
652
+ .config-select {
653
+ width: 300px;
654
+ margin-right: 10px;
655
+ }
656
+
657
+ input[type='file'] {
658
+ margin-right: 10px;
659
+ }
660
+
661
+ .el-button {
662
+ margin-right: 10px;
663
+ margin-bottom: 5px;
664
+ }
665
+ }
666
+
667
+ .form-container {
668
+ background: white;
669
+ padding: 20px;
670
+ border-radius: 8px;
671
+ border: 1px solid #e0e0e0;
672
+ margin-bottom: 20px;
673
+ }
674
+
675
+ .empty-state {
676
+ text-align: center;
677
+ padding: 60px 20px;
678
+ background: white;
679
+ border-radius: 8px;
680
+ border: 1px solid #e0e0e0;
681
+ }
682
+
683
+ .data-card {
684
+ margin-top: 20px;
685
+
686
+ .card-header {
687
+ display: flex;
688
+ justify-content: space-between;
689
+ align-items: center;
690
+ }
691
+
692
+ .form-data-display {
693
+ background-color: #f5f7fa;
694
+ padding: 15px;
695
+ border-radius: 4px;
696
+ font-size: 12px;
697
+ line-height: 1.5;
698
+ max-height: 400px;
699
+ overflow-y: auto;
700
+ }
701
+ }
702
+
703
+ @media (max-width: 768px) {
704
+ .config-select {
705
+ width: 100% !important;
706
+ margin-bottom: 10px;
707
+ }
708
+
709
+ .el-button {
710
+ width: 100%;
711
+ margin-bottom: 10px;
712
+ }
713
+ }
714
+ </style>