vue2-components-plus 1.0.16 → 1.0.18

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.
@@ -1,851 +0,0 @@
1
- <template>
2
- <div class="demo-page">
3
- <el-card shadow="never" class="demo-card">
4
- <div slot="header" class="demo-card__header">
5
- <div>
6
- <div class="demo-card__title">NsForm 动态表单预览</div>
7
- <div class="demo-card__desc">覆盖校验、回填、只读、级联、上传和动态表单项等常见场景。</div>
8
- </div>
9
- <el-tag size="small" :type="demoReadOnly ? 'info' : 'success'">
10
- {{ demoReadOnly ? '只读模式' : '编辑模式' }}
11
- </el-tag>
12
- </div>
13
-
14
- <el-alert
15
- v-if="hintText"
16
- :title="hintText"
17
- type="info"
18
- :closable="false"
19
- class="demo-alert"
20
- />
21
-
22
- <div class="toolbar">
23
- <el-button type="primary" @click="getFormData">获取表单数据</el-button>
24
- <el-button @click="loadDetailData()">模拟详情回填</el-button>
25
- <el-button @click="resetFormData()">重置表单</el-button>
26
- <el-button @click="toggleReadOnly">切换只读</el-button>
27
- <el-button @click="notifyInnerButton">触发自定义事件</el-button>
28
- <el-button v-if="insideDialog" type="danger" plain @click="$emit('close')">从内容区关闭弹窗</el-button>
29
- </div>
30
-
31
- <el-form ref="shellForm" :model="formState" label-position="top" class="shell-form">
32
- <NsFormTitle title="模型参数">
33
- <NsForm
34
- ref="row1Ref"
35
- :readOnly="demoReadOnly"
36
- :model="demoReadOnly ? '' : 'vertical'"
37
- :rows="formState.rows"
38
- formPropKey="rows"
39
- backgroundColor="#fff"
40
- labelColor="#606266"
41
- labelWidth="140"
42
- gapH="20px"
43
- gapV="10px"
44
- />
45
- </NsFormTitle>
46
-
47
- <NsFormTitle title="视频配置">
48
- <NsForm
49
- ref="row2Ref"
50
- :readOnly="demoReadOnly"
51
- :model="demoReadOnly ? '' : 'vertical'"
52
- :rows="formState.rows2"
53
- formPropKey="rows2"
54
- backgroundColor="#fff"
55
- labelColor="#606266"
56
- labelWidth="140"
57
- gapH="20px"
58
- gapV="10px"
59
- />
60
- </NsFormTitle>
61
-
62
- <NsFormTitle title="结果保存">
63
- <NsForm
64
- ref="row3Ref"
65
- :readOnly="demoReadOnly"
66
- :model="demoReadOnly ? '' : 'vertical'"
67
- :rows="formState.rows3"
68
- formPropKey="rows3"
69
- backgroundColor="#fff"
70
- labelColor="#606266"
71
- labelWidth="140"
72
- gapH="20px"
73
- gapV="10px"
74
- />
75
- </NsFormTitle>
76
-
77
- <NsFormTitle title="级联选择器">
78
- <NsForm
79
- ref="row4Ref"
80
- :readOnly="demoReadOnly"
81
- :model="demoReadOnly ? '' : 'vertical'"
82
- :rows="formState.rows4"
83
- formPropKey="rows4"
84
- backgroundColor="#fff"
85
- labelColor="#606266"
86
- labelWidth="140"
87
- gapH="20px"
88
- gapV="10px"
89
- />
90
- </NsFormTitle>
91
-
92
- <NsFormTitle title="文件上传">
93
- <NsForm
94
- ref="rowUploadRef"
95
- :readOnly="demoReadOnly"
96
- :model="demoReadOnly ? '' : 'vertical'"
97
- :rows="formState.rowsUpload"
98
- formPropKey="rowsUpload"
99
- backgroundColor="#fff"
100
- labelColor="#606266"
101
- labelWidth="140"
102
- gapH="20px"
103
- gapV="10px"
104
- />
105
- </NsFormTitle>
106
- </el-form>
107
- </el-card>
108
-
109
- <el-card shadow="never" class="result-card">
110
- <div slot="header" class="result-card__header">
111
- <span>输出结果</span>
112
- <el-button type="text" @click="showToast('已通过组件实例调用方法')">调用实例方法示例</el-button>
113
- </div>
114
- <pre class="result-content">{{ outputText || '点击“获取表单数据”后在此查看结果。' }}</pre>
115
- </el-card>
116
- </div>
117
- </template>
118
-
119
- <script>
120
- const CustomRegionEditor = {
121
- name: 'CustomRegionEditor',
122
- props: {
123
- value: {
124
- type: String,
125
- default: '',
126
- },
127
- },
128
- methods: {
129
- handleInput(value) {
130
- this.$emit('input', value)
131
- },
132
- },
133
- render(h) {
134
- return h('div', { class: 'custom-region-editor' }, [
135
- h('div', { class: 'custom-region-editor__label' }, '模拟区域编辑器'),
136
- h('el-input', {
137
- props: {
138
- type: 'textarea',
139
- rows: 3,
140
- value: this.value,
141
- placeholder: '请输入区域 JSON 或坐标信息',
142
- },
143
- on: {
144
- input: this.handleInput,
145
- },
146
- }),
147
- ])
148
- },
149
- }
150
-
151
- function createRows() {
152
- return [
153
- [
154
- {
155
- key: 'isEnable',
156
- label: '是否启用',
157
- value: false,
158
- component: 'ElSwitch',
159
- events: {},
160
- params: {
161
- activeText: '启用',
162
- inactiveText: '禁用',
163
- },
164
- },
165
- {
166
- key: 'modelName',
167
- label: '模型名称',
168
- value: 'demo-detector',
169
- component: 'ElInput',
170
- params: {
171
- clearable: true,
172
- maxlength: 30,
173
- rules: [{ required: true, message: '请输入模型名称', trigger: 'blur' }],
174
- },
175
- },
176
- ],
177
- [
178
- {
179
- key: 'confidence',
180
- label: '置信度阈值',
181
- value: '0.60',
182
- component: 'ElInput',
183
- params: {
184
- clearable: true,
185
- 'v-length.range': { min: 0, max: 1 },
186
- rules: [{ required: true, message: '请输入置信度', trigger: 'blur' }],
187
- },
188
- },
189
- {
190
- key: 'iou',
191
- label: 'IOU 阈值',
192
- value: '0.45',
193
- component: 'ElInput',
194
- params: {
195
- clearable: true,
196
- 'v-length.range': { min: 0, max: 1 },
197
- rules: [{ required: true, message: '请输入 IOU', trigger: 'blur' }],
198
- },
199
- },
200
- ],
201
- ]
202
- }
203
-
204
- function createRows2() {
205
- return [
206
- [
207
- {
208
- key: 'timeInterval',
209
- label: '时间间隔(秒)',
210
- value: '5',
211
- component: 'ElInput',
212
- params: {
213
- clearable: true,
214
- 'v-length.range': { min: 0, max: 6000, int: true },
215
- rules: [{ required: true, message: '请输入时间间隔', trigger: 'blur' }],
216
- },
217
- },
218
- {
219
- key: 'stuck_threshold',
220
- label: '所属工程',
221
- value: ['component', 'form'],
222
- component: 'ElCascader',
223
- params: {
224
- clearable: true,
225
- props: {
226
- checkStrictly: true,
227
- emitPath: true,
228
- },
229
- options: [
230
- {
231
- value: 'guide',
232
- label: 'Guide',
233
- children: [
234
- { value: 'disciplines', label: 'Disciplines' },
235
- { value: 'navigation', label: 'Navigation' },
236
- ],
237
- },
238
- {
239
- value: 'component',
240
- label: '组件库',
241
- children: [
242
- { value: 'form', label: 'Form' },
243
- { value: 'table', label: 'Table' },
244
- ],
245
- },
246
- ],
247
- rules: [{ required: true, message: '请选择所属工程', trigger: 'change' }],
248
- },
249
- },
250
- ],
251
- [
252
- {
253
- key: 'maxRetries',
254
- label: '最大重连次数',
255
- value: '3',
256
- component: 'ElInput',
257
- params: {
258
- clearable: true,
259
- 'v-length.range': { min: 0, max: 20, int: true },
260
- rules: [{ required: true, message: '请输入重连次数', trigger: 'blur' }],
261
- },
262
- },
263
- {
264
- key: 'streamUrl',
265
- label: '视频流地址',
266
- value: 'rtsp://example.com/live/001',
267
- component: 'ElInput',
268
- params: {
269
- clearable: true,
270
- rules: [{ required: true, message: '请输入视频流地址', trigger: 'blur' }],
271
- },
272
- },
273
- ],
274
- ]
275
- }
276
-
277
- function createRows3() {
278
- return [
279
- [
280
- {
281
- key: 'saveVideo',
282
- label: '是否保存视频',
283
- value: true,
284
- component: 'ElRadioGroup',
285
- params: {
286
- options: [
287
- { label: '是', value: true },
288
- { label: '否', value: false },
289
- ],
290
- rules: [{ required: true, message: '请选择是否保存视频', trigger: 'change' }],
291
- },
292
- },
293
- {
294
- key: 'preBufferSecond',
295
- label: '帧前缓存(秒)',
296
- value: '10',
297
- component: 'ElInput',
298
- params: {
299
- clearable: true,
300
- 'v-length.range': { min: 0, max: 120, int: true },
301
- rules: [{ required: true, message: '请输入缓存时长', trigger: 'blur' }],
302
- },
303
- },
304
- ],
305
- [
306
- {
307
- key: 'det_area_mode',
308
- label: '检测区域模式',
309
- value: 'normal',
310
- component: 'ElRadioGroup',
311
- events: {},
312
- params: {
313
- options: [
314
- { label: '常规检测', value: 'normal' },
315
- { label: '非常规检测', value: 'abnormal' },
316
- ],
317
- rules: [{ required: true, message: '请选择区域模式', trigger: 'change' }],
318
- },
319
- },
320
- ],
321
- ]
322
- }
323
-
324
- function createRows4() {
325
- return [
326
- [
327
- {
328
- key: 'region',
329
- label: '地区选择',
330
- value: ['beijing', 'chaoyang'],
331
- component: 'ElCascader',
332
- params: {
333
- props: {
334
- multiple: false,
335
- checkStrictly: true,
336
- emitPath: true,
337
- },
338
- showAllLevels: false,
339
- options: [
340
- {
341
- value: 'beijing',
342
- label: '北京市',
343
- children: [
344
- { value: 'chaoyang', label: '朝阳区' },
345
- { value: 'haidian', label: '海淀区' },
346
- ],
347
- },
348
- {
349
- value: 'shanghai',
350
- label: '上海市',
351
- children: [{ value: 'pudong', label: '浦东新区' }],
352
- },
353
- ],
354
- },
355
- },
356
- {
357
- key: 'department',
358
- label: '部门选择',
359
- value: ['company', 'tech', 'frontend'],
360
- component: 'ElCascader',
361
- params: {
362
- props: {
363
- value: 'code',
364
- label: 'name',
365
- children: 'children',
366
- checkStrictly: true,
367
- emitPath: true,
368
- },
369
- separator: ' / ',
370
- options: [
371
- {
372
- code: 'company',
373
- name: '公司总部',
374
- children: [
375
- {
376
- code: 'tech',
377
- name: '技术部',
378
- children: [
379
- { code: 'frontend', name: '前端组' },
380
- { code: 'backend', name: '后端组' },
381
- ],
382
- },
383
- { code: 'sales', name: '销售部' },
384
- ],
385
- },
386
- ],
387
- },
388
- },
389
- ],
390
- [
391
- {
392
- key: 'singleLevelCascader',
393
- label: '单层级联',
394
- value: 'shanghai',
395
- component: 'ElCascader',
396
- params: {
397
- options: [
398
- { value: 'beijing', label: '北京市' },
399
- { value: 'shanghai', label: '上海市' },
400
- { value: 'guangzhou', label: '广州市' },
401
- ],
402
- },
403
- },
404
- {
405
- key: 'notifyEmails',
406
- label: '通知邮箱',
407
- value: 'demo@example.com',
408
- component: 'ElInput',
409
- params: {
410
- clearable: true,
411
- },
412
- },
413
- ],
414
- ]
415
- }
416
-
417
- function createRowsUpload() {
418
- return [
419
- [
420
- {
421
- key: 'upload_file',
422
- label: '上传模型文件',
423
- value: [],
424
- component: 'ElUpload',
425
- events: {},
426
- params: {
427
- drag: true,
428
- multiple: true,
429
- action: '#',
430
- limit: 2,
431
- fileList: [],
432
- accept: '.txt,.md,.json,.jpg,.png,.pdf',
433
- autoUpload: true,
434
- httpRequest: null,
435
- rules: [{ required: true, message: '请上传至少一个文件', trigger: 'change' }],
436
- },
437
- slots: {},
438
- },
439
- ],
440
- ]
441
- }
442
-
443
- function createDetailData() {
444
- return {
445
- isEnable: true,
446
- modelName: 'helmet-detector-v2',
447
- confidence: '0.72',
448
- iou: '0.33',
449
- timeInterval: '3',
450
- stuck_threshold: ['component', 'table'],
451
- maxRetries: '5',
452
- streamUrl: 'rtsp://example.com/live/demo',
453
- saveVideo: true,
454
- preBufferSecond: '8',
455
- det_area_mode: 'abnormal',
456
- det_area_json: '{"x":10,"y":12,"width":320,"height":180}',
457
- region: ['shanghai', 'pudong'],
458
- department: ['company', 'tech', 'backend'],
459
- singleLevelCascader: 'guangzhou',
460
- notifyEmails: 'ops@example.com',
461
- upload_file: [
462
- {
463
- name: '示例说明.md',
464
- url: 'https://cdn.jsdelivr.net/gh/vuejs/art@master/logo.png',
465
- fileName: '示例说明.md',
466
- filePath: 'https://cdn.jsdelivr.net/gh/vuejs/art@master/logo.png',
467
- fileSize: 2048,
468
- },
469
- ],
470
- }
471
- }
472
-
473
- export default {
474
- name: 'FormDemo',
475
- props: {
476
- readOnly: {
477
- type: Boolean,
478
- default: false,
479
- },
480
- insideDialog: {
481
- type: Boolean,
482
- default: false,
483
- },
484
- hintText: {
485
- type: String,
486
- default: '',
487
- },
488
- },
489
- data() {
490
- return {
491
- demoReadOnly: this.readOnly,
492
- outputText: '',
493
- uploadFileList: [],
494
- formState: {
495
- rows: createRows(),
496
- rows2: createRows2(),
497
- rows3: createRows3(),
498
- rows4: createRows4(),
499
- rowsUpload: createRowsUpload(),
500
- },
501
- }
502
- },
503
- watch: {
504
- readOnly: {
505
- immediate: true,
506
- handler(value) {
507
- this.demoReadOnly = value
508
- this.syncUploadDisabled()
509
- },
510
- },
511
- demoReadOnly() {
512
- this.syncUploadDisabled()
513
- },
514
- },
515
- mounted() {
516
- this.bindFieldEvents()
517
- this.setUploadSlots()
518
- this.loadDetailData(false)
519
- },
520
- methods: {
521
- bindFieldEvents() {
522
- this.formState.rows[0][0].events.change = this.handleEnableChange
523
- this.formState.rows3[1][0].events.change = this.detAreaModeChange
524
-
525
- const uploadField = this.getUploadField()
526
- uploadField.params.httpRequest = this.mockUploadRequest
527
- uploadField.events = {
528
- success: this.handleUploadSuccess,
529
- change: this.handleUploadChange,
530
- remove: this.handleUploadRemove,
531
- }
532
- this.syncUploadDisabled()
533
- },
534
- setUploadSlots() {
535
- const uploadField = this.getUploadField()
536
- this.$set(uploadField, 'slots', {
537
- default: () =>
538
- this.$createElement('div', { class: 'upload-trigger' }, [
539
- this.$createElement('i', { class: 'el-icon-upload upload-trigger__icon' }),
540
- this.$createElement('div', { class: 'upload-trigger__title' }, '点击或拖拽文件到此处上传'),
541
- this.$createElement('div', { class: 'upload-trigger__sub' }, '仅做本地模拟,不会真正请求后台'),
542
- ]),
543
- tip: () =>
544
- this.$createElement('div', { class: 'el-upload__tip' }, '支持 txt / md / json / jpg / png / pdf,最多 2 个文件'),
545
- })
546
- },
547
- getUploadField() {
548
- return this.formState.rowsUpload[0][0]
549
- },
550
- getFormRefs() {
551
- return ['row1Ref', 'row2Ref', 'row3Ref', 'row4Ref', 'rowUploadRef']
552
- .map((name) => this.$refs[name])
553
- .filter(Boolean)
554
- },
555
- syncUploadDisabled() {
556
- const uploadField = this.getUploadField()
557
- if (uploadField && uploadField.params) {
558
- this.$set(uploadField.params, 'disabled', this.demoReadOnly)
559
- }
560
- },
561
- toggleReadOnly() {
562
- this.demoReadOnly = !this.demoReadOnly
563
- },
564
- showToast(message) {
565
- this.$message.info(message || '来自 FormDemo 的实例方法调用')
566
- return true
567
- },
568
- handleEnableChange(value) {
569
- this.$message.info(value ? '已启用模型能力' : '已停用模型能力')
570
- },
571
- ensureAbnormalField(mode) {
572
- const lastRow = this.formState.rows3[this.formState.rows3.length - 1]
573
- const lastKey = lastRow && lastRow[0] && lastRow[0].key
574
- if (lastKey === 'det_area_json') {
575
- this.formState.rows3.pop()
576
- }
577
- if (mode === 'abnormal') {
578
- this.formState.rows3.push([
579
- {
580
- key: 'det_area_json',
581
- label: '感兴趣区域',
582
- value: '',
583
- component: CustomRegionEditor,
584
- span: 24,
585
- params: {
586
- rules: [{ required: true, message: '请输入感兴趣区域', trigger: 'blur' }],
587
- },
588
- },
589
- ])
590
- }
591
- },
592
- detAreaModeChange(value) {
593
- this.ensureAbnormalField(value)
594
- },
595
- validateShellForm() {
596
- return new Promise((resolve, reject) => {
597
- this.$refs.shellForm.validate((valid) => {
598
- if (valid) {
599
- resolve(true)
600
- return
601
- }
602
- reject(new Error('表单校验失败'))
603
- })
604
- })
605
- },
606
- collectFormData() {
607
- return this.getFormRefs().reduce((result, ref) => {
608
- if (ref && typeof ref.getFormKvData === 'function') {
609
- return Object.assign(result, ref.getFormKvData())
610
- }
611
- return result
612
- }, {})
613
- },
614
- async getFormData() {
615
- try {
616
- await this.validateShellForm()
617
- const data = this.collectFormData()
618
- this.outputText = JSON.stringify(data, null, 2)
619
- this.$message.success('表单校验成功')
620
- return data
621
- } catch (error) {
622
- this.outputText = ''
623
- this.$message.error('表单校验失败,请先完善必填项')
624
- return false
625
- }
626
- },
627
- resetFormData(showMessage = true) {
628
- this.getFormRefs().forEach((ref) => {
629
- if (ref && typeof ref.resetForm === 'function') {
630
- ref.resetForm()
631
- }
632
- })
633
- this.ensureAbnormalField('normal')
634
- this.uploadFileList = []
635
- const uploadField = this.getUploadField()
636
- this.$set(uploadField.params, 'fileList', [])
637
- this.$set(uploadField, 'value', [])
638
- this.$set(uploadField, 'delValue', [])
639
- this.$nextTick(() => {
640
- this.$refs.shellForm.clearValidate()
641
- this.outputText = ''
642
- if (showMessage) {
643
- this.$message.success('表单已重置')
644
- }
645
- })
646
- },
647
- loadDetailData(showMessage = true) {
648
- if (showMessage) {
649
- this.$message.info('开始模拟详情回填')
650
- }
651
- setTimeout(() => {
652
- const detail = createDetailData()
653
- this.resetFormData(false)
654
- this.ensureAbnormalField(detail.det_area_mode)
655
- this.$nextTick(() => {
656
- this.getFormRefs().forEach((ref) => {
657
- if (ref && typeof ref.setFormData === 'function') {
658
- ref.setFormData(detail)
659
- }
660
- })
661
- this.uploadFileList = detail.upload_file.slice()
662
- this.$set(this.getUploadField().params, 'fileList', detail.upload_file.slice())
663
- if (showMessage) {
664
- this.$message.success('详情已回填')
665
- }
666
- })
667
- }, 300)
668
- },
669
- notifyInnerButton() {
670
- this.$emit('btnClick', this.collectFormData())
671
- this.$message.success('已触发自定义事件')
672
- },
673
- normalizeUploadList(fileList) {
674
- return (fileList || []).map((item) => {
675
- const responseData = item && item.response && item.response.data ? item.response.data : item
676
- const fileName = responseData.fileName || item.name || '未命名文件'
677
- const filePath = responseData.filePath || item.url || ''
678
- const fileSize = responseData.fileSize || item.size || (item.raw && item.raw.size) || 0
679
- return {
680
- name: fileName,
681
- url: filePath,
682
- fileName,
683
- filePath,
684
- fileSize,
685
- }
686
- })
687
- },
688
- syncUploadFieldValue(fileList, removedFile) {
689
- const uploadField = this.getUploadField()
690
- const normalizedList = this.normalizeUploadList(fileList)
691
- this.uploadFileList = (fileList || []).slice()
692
- this.$set(uploadField.params, 'fileList', (fileList || []).slice())
693
- this.$set(uploadField, 'value', normalizedList)
694
- if (removedFile) {
695
- const removed = this.normalizeUploadList([removedFile])[0]
696
- const delValue = Array.isArray(uploadField.delValue) ? uploadField.delValue.slice() : []
697
- delValue.push(Object.assign({}, removed, { isDelete: 1 }))
698
- this.$set(uploadField, 'delValue', delValue)
699
- }
700
- this.$nextTick(() => {
701
- this.$refs.shellForm.validateField('rowsUpload.0.0.value', function () {})
702
- })
703
- },
704
- mockUploadRequest(options) {
705
- const file = options.file
706
- const timer = setTimeout(() => {
707
- const filePath = URL.createObjectURL(file)
708
- const response = {
709
- code: 0,
710
- data: {
711
- fileName: file.name,
712
- filePath,
713
- fileSize: file.size || 0,
714
- },
715
- }
716
- if (typeof options.onSuccess === 'function') {
717
- options.onSuccess(response, file)
718
- }
719
- }, 400)
720
-
721
- return {
722
- abort() {
723
- clearTimeout(timer)
724
- if (typeof options.onError === 'function') {
725
- options.onError(new Error('上传已取消'))
726
- }
727
- },
728
- }
729
- },
730
- handleUploadSuccess(_response, _file, fileList) {
731
- this.syncUploadFieldValue(fileList)
732
- this.$message.success('文件上传成功')
733
- },
734
- handleUploadChange(_file, fileList) {
735
- this.syncUploadFieldValue(fileList)
736
- },
737
- handleUploadRemove(file, fileList) {
738
- this.syncUploadFieldValue(fileList, file)
739
- this.$message.warning('已移除文件')
740
- },
741
- },
742
- }
743
- </script>
744
-
745
- <style scoped>
746
- .demo-page {
747
- display: flex;
748
- flex-direction: column;
749
- gap: 20px;
750
- }
751
-
752
- .demo-card,
753
- .result-card {
754
- border-radius: 12px;
755
- }
756
-
757
- .demo-card__header,
758
- .result-card__header {
759
- display: flex;
760
- align-items: center;
761
- justify-content: space-between;
762
- }
763
-
764
- .demo-card__title {
765
- font-size: 18px;
766
- font-weight: 700;
767
- color: #303133;
768
- }
769
-
770
- .demo-card__desc {
771
- margin-top: 6px;
772
- font-size: 13px;
773
- color: #909399;
774
- }
775
-
776
- .demo-alert {
777
- margin-bottom: 16px;
778
- }
779
-
780
- .toolbar {
781
- display: flex;
782
- flex-wrap: wrap;
783
- gap: 12px;
784
- margin-bottom: 20px;
785
- }
786
-
787
- .shell-form {
788
- display: flex;
789
- flex-direction: column;
790
- gap: 16px;
791
- }
792
-
793
- .result-content {
794
- margin: 0;
795
- padding: 16px;
796
- min-height: 180px;
797
- max-height: 360px;
798
- overflow: auto;
799
- white-space: pre-wrap;
800
- word-break: break-all;
801
- background: #0f172a;
802
- border-radius: 10px;
803
- color: #e2e8f0;
804
- font-size: 13px;
805
- line-height: 1.6;
806
- }
807
-
808
- .custom-region-editor {
809
- border: 1px dashed #dcdfe6;
810
- border-radius: 8px;
811
- padding: 12px;
812
- background: #fafafa;
813
- }
814
-
815
- .custom-region-editor__label {
816
- margin-bottom: 8px;
817
- font-size: 12px;
818
- font-weight: 600;
819
- color: #409eff;
820
- }
821
-
822
- .upload-trigger {
823
- padding: 12px;
824
- text-align: center;
825
- color: #606266;
826
- }
827
-
828
- .upload-trigger__icon {
829
- font-size: 28px;
830
- color: #409eff;
831
- }
832
-
833
- .upload-trigger__title {
834
- margin-top: 8px;
835
- font-size: 14px;
836
- font-weight: 600;
837
- }
838
-
839
- .upload-trigger__sub {
840
- margin-top: 6px;
841
- font-size: 12px;
842
- color: #909399;
843
- }
844
-
845
- @media (max-width: 960px) {
846
- .toolbar {
847
- flex-direction: column;
848
- align-items: stretch;
849
- }
850
- }
851
- </style>