n20-common-lib 2.7.0-beta.18 → 2.7.0-beta.19

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,14 +1,16 @@
1
1
  <script>
2
+ import asciiWidth from '../../utils/asciiWidth'
2
3
  import axios from '../../utils/axios'
4
+ import forEachs from '../../utils/forEachs'
5
+ import { $lc } from '../../utils/i18n/index.js'
6
+ import datePickerPor from '../DatePicker/por.vue'
3
7
  import inputNumber from '../InputNumber/index.vue'
4
8
  import InputNumberRange from '../InputNumber/numberRange.vue'
5
- import datePickerPor from '../DatePicker/por.vue'
6
9
  import selectTree from '../SelectTree/index.vue'
7
10
  import selectTreePro from '../SelectTree/pro.vue'
8
- import { $lc } from '../../utils/i18n/index.js'
9
- import asciiWidth from '../../utils/asciiWidth'
10
11
  const canvas = document.createElement('canvas')
11
12
  const context = canvas.getContext('2d')
13
+ context.font = '14px Ping Fang SC'
12
14
  export default {
13
15
  name: 'formItemRender',
14
16
  components: {
@@ -80,7 +82,7 @@ export default {
80
82
  },
81
83
  render(h) {
82
84
  const { item, form, context } = this
83
- const MAX_WIDTH = 312
85
+
84
86
  let elementDom = null
85
87
 
86
88
  let typeEnum = (type) => {
@@ -106,24 +108,58 @@ export default {
106
108
  }
107
109
  }
108
110
 
109
- let w = asciiWidth(item.placeholder || typeEnum(item.type)) + 34
110
- if (/px$/.test(item.width)) {
111
- w = item.width.replace(/px$/, '')
111
+ // 获取文本宽度
112
+ const getWidth = (label, type) => {
113
+ if (!label) {
114
+ return 0
115
+ }
116
+ if (!type) {
117
+ return context.measureText(label).width
118
+ }
119
+ return (context.measureText(label).width * 1.4 + 100) * 2
112
120
  }
113
121
 
114
- const getWidth = (value, type) => {
115
- if (!type) {
116
- return context.measureText(value).width * 1.4 + 55
122
+ let w = 76
123
+ if (item.placeholder) {
124
+ w = asciiWidth(item.placeholder || typeEnum(item.type)) + 34
125
+ if (/px$/.test(item.width)) {
126
+ w = item.width.replace(/px$/, '')
117
127
  }
118
- return (context.measureText(value).width * 1.4 + 100) * 2
119
128
  }
120
129
 
121
- const calcWidth = (value, type) => {
130
+ // 计算text框内容宽度
131
+ const calcTextWidth = (item, value) => {
132
+ let textMaxWidth,
133
+ textMinWidth = 76
134
+ if (item.required) {
135
+ textMaxWidth = 426 - getWidth(item.label) - 33
136
+ } else {
137
+ textMaxWidth = 426 - getWidth(item.label) - 14
138
+ }
139
+
140
+ // 没有内容时
141
+ if (!value) {
142
+ return textMinWidth + 'px'
143
+ }
144
+ // 输入内容+边距小于最小默认值时
145
+ if (getWidth(value) + 32 < textMinWidth) {
146
+ return textMinWidth + 'px'
147
+ }
148
+ // 输入内容+边距大于最大默认值时
149
+ if (getWidth(value) + 32 > textMaxWidth) {
150
+ return textMaxWidth + 'px'
151
+ }
152
+
153
+ return getWidth(value) + 32 + 'px'
154
+ }
155
+
156
+ const calcWidth = (value, type, label) => {
157
+ let MAX_WIDTH = 426 - getWidth(label) - 16
122
158
  let W = null
123
159
  if (!Array.isArray(value)) {
124
160
  if (!value) {
125
161
  if (type) {
126
- return Number(w) + 104 + 'px'
162
+ return Number(w) + 110 + 'px'
127
163
  }
128
164
  return w + 'px'
129
165
  }
@@ -156,29 +192,147 @@ export default {
156
192
 
157
193
  return W + 'px'
158
194
  }
195
+ const recursionFind = (data, value, key, name) => {
196
+ let found
197
+ forEachs(data, (item) => {
198
+ if (item[key] === value) {
199
+ found = item[name]
200
+ }
201
+ if (item.children && !found) {
202
+ found = recursionFind(item.children, value, key, name)
203
+ }
204
+ })
159
205
 
160
- const calcSelectWidth = (value, type) => {
161
- let W = null
162
- if (!value) {
163
- return w + 'px'
206
+ return found
207
+ }
208
+
209
+ // 计算selectTree内容宽度
210
+ const calcSelectTreeWidth = (item, value) => {
211
+ let textMaxWidth = 346 - getWidth(item.label) - 16
212
+ const multiple = item?.props?.multiple
213
+ const textMinWidth = 76
214
+
215
+ if (!multiple) {
216
+ if (!value) {
217
+ return textMinWidth + 'px'
218
+ } else {
219
+ let selectedName = ''
220
+ selectedName = recursionFind(
221
+ item.options,
222
+ value,
223
+ item?.props?.props?.value || item?.props?.defineProps?.value || 'value',
224
+ item?.props?.props?.label || item?.props?.defineProps?.label || 'label'
225
+ )
226
+
227
+ return getWidth(selectedName) + 'px'
228
+ }
164
229
  } else {
165
- let label = item.options.find((res) => (res.value || res[item.props.valueKey]) === value)?.label
166
- const width = getWidth(label)
167
- if (width > w) {
168
- if (width > MAX_WIDTH) {
169
- W = MAX_WIDTH
230
+ if (!value?.length) {
231
+ return textMinWidth + 'px'
232
+ } else {
233
+ let selectedName = recursionFind(
234
+ item.options,
235
+ value[0],
236
+ item?.props?.props?.value || item?.props?.defineProps?.value || 'value',
237
+ item?.props?.props?.label || item?.props?.defineProps?.label || 'label'
238
+ )
239
+ if (value?.length > 1) {
240
+ return getWidth(selectedName) + 32 > textMaxWidth
241
+ ? textMaxWidth + 'px'
242
+ : getWidth(selectedName) + 110 + 'px'
170
243
  } else {
171
- if (type) {
172
- W = width + 45
173
- } else {
174
- W = width
175
- }
244
+ return getWidth(selectedName) + 32 < textMinWidth ? textMinWidth + 'px' : getWidth(selectedName) + 84 + 'px'
245
+ }
246
+ }
247
+ }
248
+ }
249
+ // 计算select内容宽度
250
+ const calcSelectWidth = (item, value) => {
251
+ let textMaxWidth = 426 - getWidth(item.label) - 16
252
+ let textMinWidth = 76
253
+ const multiple = item.props?.multiple || false
254
+ if (!multiple) {
255
+ if (!value) {
256
+ return textMinWidth + 'px'
257
+ } else {
258
+ let selectedName = recursionFind(
259
+ item.options,
260
+ value,
261
+ item.props?.valueKey || 'value',
262
+ item.props?.labelKey || 'label'
263
+ )
264
+ if (getWidth(selectedName) + 32 > textMaxWidth) {
265
+ return textMaxWidth + 'px'
266
+ }
267
+ if (getWidth(selectedName) + 32 < textMinWidth) {
268
+ return textMinWidth + 'px'
176
269
  }
270
+ return getWidth(selectedName) + 32 + 'px'
271
+ }
272
+ } else {
273
+ if (!value?.length) {
274
+ return textMinWidth + 'px'
177
275
  } else {
178
- W = w
276
+ let selectedName = recursionFind(
277
+ item.options,
278
+ value[0],
279
+ item.props?.valueKey || 'value',
280
+ item.props?.labelKey || 'label'
281
+ )
282
+ if (value?.length > 1) {
283
+ return getWidth(selectedName) + 32 > textMaxWidth
284
+ ? textMaxWidth + 'px'
285
+ : getWidth(selectedName) + 110 + 'px'
286
+ } else {
287
+ return getWidth(selectedName) + 32 < textMinWidth ? textMinWidth + 'px' : getWidth(selectedName) + 84 + 'px'
288
+ }
289
+ }
290
+ }
291
+ }
292
+ // 计算区间内容宽度
293
+ const calcRangeWidth = (item, value, value2) => {
294
+ let textMaxWidth = 284 - getWidth(item.label) - 16
295
+ let textMinWidth = 160
296
+ if (!value && !value2) {
297
+ return textMinWidth + 'px'
298
+ } else {
299
+ console.log(value, value2, getWidth(value))
300
+ if (!value || !value2) {
301
+ let widthMax = (getWidth(value) + getWidth(value2) + 72) * 2
302
+ if (widthMax < textMinWidth) {
303
+ return textMinWidth + 'px'
304
+ }
305
+ if (widthMax > textMaxWidth) {
306
+ return textMaxWidth + 'px'
307
+ }
308
+ return widthMax + 'px'
309
+ } else {
310
+ let widthMax = getWidth(value) + getWidth(value2) + 140
311
+ if (widthMax < textMinWidth) {
312
+ return textMinWidth + 'px'
313
+ }
314
+ if (widthMax > textMaxWidth) {
315
+ return textMaxWidth + 'px'
316
+ }
317
+ return widthMax + 'px'
179
318
  }
180
319
  }
181
- return W + 'px'
320
+ }
321
+
322
+ const calcDateWidth = (item, value) => {
323
+ let textMaxWidth = 282 - getWidth(item.label) - 16
324
+ let textMinWidth = 76
325
+ if (!value) {
326
+ return textMinWidth + 'px'
327
+ } else {
328
+ if (getWidth(value) + 32 < textMinWidth) {
329
+ return textMinWidth + 'px'
330
+ }
331
+ if (getWidth(value) + 32 > textMaxWidth) {
332
+ return textMaxWidth + 'px'
333
+ }
334
+ return getWidth(value) + 32 + 'px'
335
+ }
182
336
  }
183
337
 
184
338
  const keyup = (ev) => {
@@ -196,7 +350,7 @@ export default {
196
350
  {
197
351
  attrs: {
198
352
  style: {
199
- width:calcWidth(form[item.value])
353
+ width: calcTextWidth(item, form[item.value])
200
354
  },
201
355
  ruleField: true,
202
356
  'rule-form': 'ruleValidate',
@@ -291,7 +445,7 @@ export default {
291
445
  collapseTags: true
292
446
  },
293
447
  style: {
294
- width: calcSelectWidth(form[item.value], item.multiple)
448
+ width: calcSelectWidth(item, form[item.value])
295
449
  },
296
450
  props: selectProps,
297
451
 
@@ -356,7 +510,7 @@ export default {
356
510
  ruleErrorHide: item.ruleErrorHide
357
511
  },
358
512
  style: {
359
- width: calcWidth([form[item.startValue], form[item.endValue]], true)
513
+ width: calcRangeWidth(item, form[item.startValue], form[item.endValue])
360
514
  },
361
515
  props: inputRangeProps,
362
516
  on: {
@@ -400,7 +554,7 @@ export default {
400
554
  ruleErrorHide: item.ruleErrorHide
401
555
  },
402
556
  style: {
403
- width: calcWidth(form[item.value])
557
+ width: calcDateWidth(item, form[item.value])
404
558
  },
405
559
  props: datePickerProps,
406
560
  model: {
@@ -439,7 +593,7 @@ export default {
439
593
  },
440
594
  props: pickerProps,
441
595
  style: {
442
- width: calcWidth(form[item.startDate], true)
596
+ width: calcRangeWidth(item, form[item.startDate], form[item.endDate])
443
597
  },
444
598
  on: {
445
599
  'update:start-date': (val) => {
@@ -532,7 +686,7 @@ export default {
532
686
  elementDom = h('selectTree', {
533
687
  directives: [{ name: 'rule-key' }],
534
688
  style: {
535
- width: calcSelectWidth(form[item.value])
689
+ width: calcSelectTreeWidth(item, form[item.value])
536
690
  },
537
691
  attrs: {
538
692
  ruleField: true,
@@ -577,7 +731,7 @@ export default {
577
731
  clearable: (item.props && item.props.clearable) ?? true
578
732
  },
579
733
  style: {
580
- width: item.width || '200px'
734
+ width: calcSelectTreeWidth(item, form[item.value])
581
735
  },
582
736
  model: {
583
737
  value: form[item.value],
@@ -605,7 +759,7 @@ export default {
605
759
  elementDom = h('el-input', {
606
760
  attrs: {
607
761
  style: {
608
- width: item.width || '224px'
762
+ width: calcTextWidth(item.label, form[item.value])
609
763
  },
610
764
  ruleField: true,
611
765
  'rule-form': 'ruleValidate',
@@ -1,15 +1,16 @@
1
1
  <template>
2
2
  <div :class="prefixCls">
3
- <div ref="advancedFilter" v-show="visible" :class="prefixCls + '-body'">
3
+ <el-form ref="advancedFilter" v-show="visible" :class="prefixCls + '-body'">
4
4
  <slot name="prefix"></slot>
5
- <FormItem
5
+ <el-form-item
6
6
  v-for="item in GroupData"
7
7
  :key="getOnlyKey(item)"
8
- :class="[activeClass(item)]"
8
+ :class="[prefixCls + '-item', activeClass(item)]"
9
9
  :label="item.label"
10
- :required="item.required !== undefined || true ? item.required : false"
10
+ :required="item.required !== undefined || item.required !== null ? item.required : false"
11
11
  :disabled="item.props && item.props.disabled"
12
12
  >
13
+ <div :class="prefixCls + '-content'">
13
14
  <slot v-if="item.slotName" :name="item.slotName"></slot>
14
15
  <formItemRender
15
16
  v-else
@@ -20,36 +21,48 @@
20
21
  @enter="$emit('enter')"
21
22
  @filter="$emit('filter', model)"
22
23
  />
23
- <!-- <i
24
+ </div>
25
+ <i
24
26
  v-if="!item.isNotClose"
25
27
  :key="getOnlyKey(item)"
26
- :class="[prefixCls + '-item-close', 'n20-icon-yichu']"
28
+ :class="['filter_remove', 'n20-icon-yichu']"
27
29
  @click="handleClose(item)"
28
- ></i>-->
29
- </FormItem>
30
+ ></i>
31
+ </el-form-item>
30
32
  <slot name="suffix"></slot>
31
- <div :class="prefixCls + '-add'">
33
+ <el-form-item :class="prefixCls + '-add'">
32
34
  <el-button v-popover:advanced_popover onlyicon plain icon="el-icon-plus" />
33
35
  <el-popover ref="advanced_popover" placement="bottom-start" trigger="click">
34
36
  <el-input v-model="keyword" clearable class="input-w m-b-s" :placeholder="$lc('搜索筛选条件')" />
35
- <filterItem :filter-list="filterListS" :check-array.sync="checkList" @checked="check" />
37
+ <div class="flex-box flex-lr">
38
+ <el-button type="text" @click="allCheck">全选</el-button>
39
+ <el-button type="text" @click="defaultCheck"> 恢复默认</el-button>
40
+ </div>
41
+ <filterItem
42
+ :filter-list="filterListS"
43
+ :maxLength="maxLength"
44
+ :check-array.sync="checkList"
45
+ @checked="check"
46
+ />
47
+ <div class="flex-box flex-c m-t-m">
48
+ <el-button size="mini" type="primary" @click="savaCheck">确认</el-button>
49
+ <el-button plain type="primary" @click="cancel">取消</el-button>
50
+ </div>
36
51
  </el-popover>
37
- <el-link class="m-l-s f-s-s color-primary" :underline="false" icon="n20-icon-query" @click="$emit('search')">
52
+ <el-link class="m-l-s color-primary" :underline="false" icon="n20-icon-query" @click="$emit('search')">
38
53
  {{ '查询' | $lc }}</el-link
39
54
  >
40
- <el-link class="m-l-s f-s-s" :underline="false" icon="n20-icon-qingchu" @click="cleared">
41
- {{ '清空' | $lc }}</el-link
42
- >
43
- </div>
44
- </div>
55
+ <el-link class="m-l-s" :underline="false" icon="n20-icon-qingchu" @click="cleared"> {{ '清空' | $lc }}</el-link>
56
+ </el-form-item>
57
+ </el-form>
45
58
  </div>
46
59
  </template>
47
60
 
48
61
  <script>
62
+ // import formItemInput from './form-item-input.vue'
49
63
  import formItemRender from './formItemRender.vue'
50
64
  import InputSearch from '../InputSearch/index.vue'
51
65
  import filterItem from './filterItem.vue'
52
- import FormItem from './FormItem.vue'
53
66
  import axios from '../../utils/axios.js'
54
67
  import { $lc } from '../../utils/i18n/index.js'
55
68
  import cloneDeep from 'lodash/cloneDeep'
@@ -62,14 +75,27 @@ export default {
62
75
  // formItemInput,
63
76
  formItemRender,
64
77
  InputSearch,
65
- filterItem,
66
- FormItem
78
+ // FormItem,
79
+ filterItem
80
+ },
81
+ provide() {
82
+ return {
83
+ prefixCls,
84
+ nFilter: this
85
+ }
67
86
  },
68
87
  props: {
69
88
  isNotClose: {
70
89
  type: Boolean,
71
90
  default: false
72
91
  },
92
+ maxLength: {
93
+ type: Number
94
+ },
95
+ removeLoad: {
96
+ type: Boolean,
97
+ default: true
98
+ },
73
99
  visible: {
74
100
  type: Boolean,
75
101
  default: false
@@ -98,7 +124,7 @@ export default {
98
124
  remoteList: [],
99
125
  GroupData: [],
100
126
  checkList: [],
101
- checkC: [],
127
+ defineCheckList: [],
102
128
  userNo: sessionStorage.getItem('userNo')
103
129
  }
104
130
  },
@@ -253,14 +279,27 @@ export default {
253
279
  }
254
280
  }
255
281
  },
256
- check: _debounce(function (keys) {
257
- // 保存当前选择的过滤条件
258
- this.checkList = keys
282
+ allCheck() {
283
+ if (this.maxLength) {
284
+ this.checkList = this.filterListS.slice(0, this.maxLength)?.map((res) => res[this.onlyKey])
285
+ console.log(this.checkList, this.filterListS)
286
+ } else {
287
+ this.checkList = this.filterListS?.map((res) => res[this.onlyKey])
288
+ }
289
+ },
290
+ defaultCheck() {
291
+ this.checkList = this.defineCheckList
292
+ },
293
+ cancel() {
294
+ this.checkList = this.defineCheckList
295
+ this.$refs.advanced_popover.showPopper = false
296
+ },
297
+ savaCheck() {
259
298
  let saveCheckArr = []
260
299
  // 如果keys数组不为空
261
- if (keys.length > 0) {
300
+ if (this.checkList.length > 0) {
262
301
  this.filterList.forEach((item) => {
263
- if (keys.includes(item.id)) {
302
+ if (this.checkList.includes(item[this.onlyKey])) {
264
303
  saveCheckArr.push(item)
265
304
  }
266
305
  })
@@ -273,8 +312,12 @@ export default {
273
312
  this.getFilterList()
274
313
  }
275
314
  })
315
+ this.$refs.advanced_popover.showPopper = false
276
316
  this.$emit('check')
277
- }, 1000),
317
+ },
318
+ check(keys) {
319
+ this.checkList = keys
320
+ },
278
321
  /**
279
322
  * 保存筛选条件
280
323
  * @param data
@@ -315,7 +358,7 @@ export default {
315
358
  this.GroupData = _data.map((item) => {
316
359
  for (let i = 0; i < this.filterList.length; i++) {
317
360
  const originItem = this.filterList[i]
318
- if (originItem.id === item.id) {
361
+ if (originItem[this.onlyKey] === item[this.onlyKey]) {
319
362
  item.label = originItem.label
320
363
  if (item.options && originItem.options) {
321
364
  item.options = originItem.options
@@ -325,14 +368,28 @@ export default {
325
368
  return item
326
369
  })
327
370
  } else {
328
- this.GroupData = this.filterList.filter((item) => {
329
- if (item.isDefault) {
330
- return item
331
- }
332
- })
371
+ if (this.removeLoad) {
372
+ this.GroupData = this.filterList.filter((item) => {
373
+ if (item.isDefault) {
374
+ return item
375
+ }
376
+ })
377
+ } else {
378
+ this.GroupData = []
379
+ }
333
380
  }
334
381
  this.checkList = this.GroupData.map((res) => res.id)
335
- this.checkC = cloneDeep(this.checkList)
382
+ this.defineCheckList = cloneDeep(this.checkList)
383
+ // 查找排序,在this.filterList中查找this.checkList中的每一项,并将其排在前面
384
+ this.filterList = this.filterList.sort((a, b) => {
385
+ if (this.checkList.includes(a[this.onlyKey]) && !this.checkList.includes(b[this.onlyKey])) {
386
+ return -1
387
+ }
388
+ if (!this.checkList.includes(a[this.onlyKey]) && this.checkList.includes(b[this.onlyKey])) {
389
+ return 1
390
+ }
391
+ return 0
392
+ })
336
393
  })
337
394
  .finally(() => {
338
395
  for (const key in getOptionsMap()) {
@@ -0,0 +1,87 @@
1
+ <template>
2
+ <div class="n20-form-item">
3
+ <label class="n20-form-item__label">{{ label }}</label>
4
+ <div class="n20-form-item__value">
5
+ <slot></slot>
6
+ </div>
7
+ <i class="filter_remove n20-icon-yichu"></i>
8
+ </div>
9
+ </template>
10
+
11
+ <script>
12
+ export default {
13
+ name: 'FormItem',
14
+ inject: ['Form'],
15
+ props: {
16
+ label: {
17
+ type: String,
18
+ default: ''
19
+ },
20
+ item: {
21
+ type: Object
22
+ }
23
+ }
24
+ }
25
+ </script>
26
+
27
+ <style lang="scss">
28
+ .n20-form-item {
29
+ position: relative;
30
+ display: inline-block;
31
+ vertical-align: middle;
32
+ max-width: 426px;
33
+ height: 32px;
34
+ line-height: 32px;
35
+ margin-right: 8px;
36
+ margin-bottom: 8px;
37
+ padding-left: 8px;
38
+ border-radius: 4px;
39
+ border: 1px solid #dcdfe5;
40
+ background: #fff;
41
+ cursor: pointer;
42
+ &__label {
43
+ display: inline-block;
44
+ vertical-align: middle;
45
+ white-space: nowrap;
46
+ overflow: hidden;
47
+ max-width: 168px;
48
+ margin-right: 6px;
49
+ color: #182b50;
50
+ }
51
+ &__value {
52
+ display: inline-block;
53
+ vertical-align: middle;
54
+ white-space: nowrap;
55
+ overflow: hidden;
56
+ text-overflow: ellipsis;
57
+ .el-input .el-input__inner {
58
+ border: none;
59
+ padding-left: 0;
60
+ background-color: transparent;
61
+ }
62
+
63
+ .el-input__inner:focus {
64
+ box-shadow: none;
65
+ }
66
+ }
67
+ .filter_remove {
68
+ display: none;
69
+ position: absolute;
70
+ height: 13px;
71
+ width: 13px;
72
+ background: #f1f1f1;
73
+ right: -5px;
74
+ top: -7px;
75
+ font-size: 14px;
76
+ z-index: 1;
77
+ border-radius: 50%;
78
+ cursor: pointer;
79
+ }
80
+
81
+ &:hover {
82
+ .filter_remove {
83
+ display: block;
84
+ }
85
+ }
86
+ }
87
+ </style>
@@ -0,0 +1,59 @@
1
+ <template>
2
+ <form class="n20-form">
3
+ <FormItem v-for="(item, i) in list" :key="i" :label="item.label" :item="item">
4
+ <slot v-if="item.slotName" :name="item.slotName"></slot>
5
+ <FormItemRender
6
+ v-else
7
+ :key="i"
8
+ :form="model"
9
+ :item="item"
10
+ @blur="$emit('blur')"
11
+ @clean="$emit('clean')"
12
+ @enter="$emit('enter')"
13
+ @filter="$emit('filter', model)"
14
+ ></FormItemRender>
15
+ </FormItem>
16
+ </form>
17
+ </template>
18
+
19
+ <script>
20
+ import FormItem from './form-item.vue'
21
+ import FormItemRender from '../../formItemRender.vue'
22
+ export default {
23
+ name: 'Form',
24
+ components: {
25
+ FormItem,
26
+ FormItemRender
27
+ },
28
+ props: {
29
+ model: {
30
+ type: Object,
31
+ default: () => ({})
32
+ },
33
+ rules: {
34
+ type: Object,
35
+ default: () => ({})
36
+ },
37
+ list: {
38
+ type: Array,
39
+ default: () => []
40
+ }
41
+ },
42
+ provide() {
43
+ return {
44
+ Form: this
45
+ }
46
+ }
47
+ }
48
+ </script>
49
+
50
+ <style lang="scss">
51
+ .n20-form {
52
+ box-sizing: border-box;
53
+ position: relative;
54
+ display: flex;
55
+ align-items: center;
56
+ flex-wrap: wrap;
57
+ padding: 8px 0;
58
+ }
59
+ </style>