@netang/quasar 0.0.24 → 0.0.27

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.
@@ -2,41 +2,56 @@
2
2
  <!--:class="fieldFocused ? 'q-field&#45;&#45;float q-field&#45;&#45;focused q-field&#45;&#45;highlighted' : ''"-->
3
3
  <q-field
4
4
  class="n-field-table"
5
- :model-value="modelValue"
5
+ :model-value="showValue"
6
6
  :readonly="readonly"
7
- :clearable="clearable && ! multiple"
7
+ :clearable="clearable && (! multiple || collapseTags)"
8
+ @focus="onFieldFocus"
9
+ @blur="onFieldBlur"
8
10
  @clear="onFieldClear"
9
11
  v-bind="$attrs"
10
12
  >
11
13
  <template v-slot:control>
12
14
 
13
15
  <template v-if="multiple">
16
+ <template v-if="selected.length">
17
+
18
+ <!-- 多选插槽 -->
19
+ <slot
20
+ name="selected"
21
+ :selected="selected"
22
+ :remove="onRemoveSelected"
23
+ v-if="$slots.selected"
24
+ />
14
25
 
15
- <!-- 多选插槽 -->
16
- <slot
17
- name="selected"
18
- :selected="selected"
19
- :remove="onRemoveSelected"
20
- v-if="$slots.selected"
21
- />
22
-
23
- <!-- 多选标签 -->
24
- <template v-else>
26
+ <!-- 显示折叠的值数量 -->
25
27
  <q-chip
26
- v-for="(item, index) in selected"
27
- :key="`options-${index}`"
28
- :label="item[labelKey || rowKey]"
29
- removable
30
- @remove="onRemoveSelected(item, index)"
31
28
  dense
29
+ :label="`+${selected.length}`"
30
+ v-else-if="collapseTags"
32
31
  />
32
+
33
+ <!-- 多选标签 -->
34
+ <template v-else>
35
+ <q-chip
36
+ v-for="(item, index) in selected"
37
+ :key="`options-${index}`"
38
+ :label="currentFormatLabel(item)"
39
+ dense
40
+ removable
41
+ @remove="onRemoveSelected(index)"
42
+ />
43
+ </template>
33
44
  </template>
45
+
46
+ <!-- 占位符-->
47
+ <span class="n-placeholder" v-else-if="placeholder">{{placeholder}}</span>
34
48
  </template>
35
49
 
36
50
  <!-- 显示文字 -->
37
- <span v-else>
38
- {{showValue}}
39
- </span>
51
+ <span v-else-if="showValue">{{showValue}}</span>
52
+
53
+ <!-- 占位符-->
54
+ <span class="n-placeholder" v-else-if="placeholder">{{placeholder}}</span>
40
55
 
41
56
  <!-- 筛选输入框 -->
42
57
  <input
@@ -62,8 +77,10 @@
62
77
  ref="popupRef"
63
78
  no-refocus
64
79
  no-focus
65
- @show="onPopupShow"
80
+ fit
66
81
  @focus="onPopupFocus"
82
+ @show="onPopupShow"
83
+ @before-hide="onPopupBeforeHide"
67
84
  v-if="! readonly"
68
85
  >
69
86
  <!-- 快捷表格 -->
@@ -142,7 +159,7 @@
142
159
  </template>
143
160
 
144
161
  <script>
145
- import { ref, computed, watch, onMounted } from 'vue'
162
+ import { ref, computed, watch, onMounted, onUpdated } from 'vue'
146
163
 
147
164
  export default {
148
165
 
@@ -157,8 +174,6 @@ export default {
157
174
  props: {
158
175
  // 值
159
176
  modelValue: [ String, Number, Array ],
160
- // 是否可清除
161
- clearable: Boolean,
162
177
  // 表格请求路径
163
178
  path: String,
164
179
  // 表格请求参数
@@ -177,16 +192,10 @@ export default {
177
192
  type: String,
178
193
  required: true,
179
194
  },
180
- // 标签字段(必填)
181
- labelKey: {
182
- type: String,
183
- required: true,
184
- },
185
- // 表格行唯一键值
186
- rowKey: {
187
- type: String,
188
- default: 'id',
189
- },
195
+ // 标签字段
196
+ labelKey: String,
197
+ // 格式化显示标签
198
+ formatLabel: Function,
190
199
  // 快捷表格显示的字段数组(空为:[值字段, 标签字段])
191
200
  showKeys: Array,
192
201
  // 隐藏搜索字段数组
@@ -200,10 +209,6 @@ export default {
200
209
  // 对话框声明属性
201
210
  dialogProps: Object,
202
211
 
203
- // 占位符
204
- placeholder: String,
205
- // 是否只读
206
- readonly: Boolean,
207
212
  // 值是否为数组
208
213
  valueArray: Boolean,
209
214
  // 关闭对话框
@@ -215,6 +220,14 @@ export default {
215
220
  rows: Array,
216
221
  // 是否多选
217
222
  multiple: Boolean,
223
+ // 多选模式下是否折叠 Tag
224
+ collapseTags: Boolean,
225
+ // 占位符
226
+ placeholder: String,
227
+ // 是否可清除
228
+ clearable: Boolean,
229
+ // 是否只读
230
+ readonly: Boolean,
218
231
  // 输入防抖(毫秒)
219
232
  inputDebounce: {
220
233
  type: [ Number, String ],
@@ -244,20 +257,27 @@ export default {
244
257
  return utils.isValidObject(slots) ? Object.keys(slots) : []
245
258
  })
246
259
 
260
+ /**
261
+ * 当前标签字段
262
+ */
263
+ const currentlabelKey = computed(function() {
264
+ return props.labelKey || props.valueKey
265
+ })
266
+
247
267
  /**
248
268
  * 当前显示字段
249
269
  */
250
270
  const currentShowKeys = computed(function() {
251
- return utils.isValidArray(props.showKeys)
271
+ return _.uniq(utils.isValidArray(props.showKeys)
252
272
  ? props.showKeys
253
- : [ props.rowKey, props.labelKey ]
273
+ : [ props.valueKey, currentlabelKey.value ])
254
274
  })
255
275
 
256
276
  /**
257
277
  * 当前搜索字段
258
278
  */
259
- const currentFilterKeys = computed(function() {
260
- return props.filterKey || props.labelKey
279
+ const currentFilterKey = computed(function() {
280
+ return props.filterKey || currentlabelKey.value
261
281
  })
262
282
 
263
283
  /**
@@ -265,12 +285,11 @@ export default {
265
285
  */
266
286
  const showValue = computed(function () {
267
287
 
268
- // 如果是单选
269
- if (! props.multiple && utils.isValidArray(selected.value)) {
270
- return selected.value[0][props.labelKey || props.rowKey]
271
- }
272
-
273
- return ''
288
+ // 如果有已选数据
289
+ return utils.isValidArray(selected.value)
290
+ // 取已选数据第一条
291
+ ? currentFormatLabel(selected.value[0])
292
+ : ''
274
293
  })
275
294
 
276
295
  // ==========【数据】============================================================================================
@@ -299,7 +318,7 @@ export default {
299
318
  // 获取表格列数据
300
319
  columns: getTableColumns(),
301
320
  // 表格行唯一键值
302
- rowKey: props.rowKey,
321
+ rowKey: props.valueKey,
303
322
  // 行数据
304
323
  rows: props.rows,
305
324
  // 选择类型, 可选值 single multiple none
@@ -333,6 +352,9 @@ export default {
333
352
  // 是否显示对话框
334
353
  const showDialog = ref(false)
335
354
 
355
+ // 是否显示弹出层
356
+ const showPopup = ref(false)
357
+
336
358
  // 当前已选数据
337
359
  const selected = ref([...$table.tableSelected.value])
338
360
 
@@ -366,7 +388,7 @@ export default {
366
388
  // 已选数据值数组
367
389
  const selectedValues = utils.isValidArray(selected.value)
368
390
  // 如果有已选数据
369
- ? _.uniq(selected.value.map(e => e[props.rowKey]))
391
+ ? _.uniq(selected.value.map(e => e[props.valueKey]))
370
392
  // 否则为空
371
393
  : []
372
394
 
@@ -374,7 +396,7 @@ export default {
374
396
  const removeValues = selectedValues.filter(e => values.indexOf(e) === -1)
375
397
  if (removeValues.length) {
376
398
  utils.forEachRight(selected.value, function (item, index) {
377
- if (removeValues.indexOf(item[props.rowKey]) > -1) {
399
+ if (removeValues.indexOf(item[props.valueKey]) > -1) {
378
400
  selected.value.splice(index, 1)
379
401
  }
380
402
  })
@@ -395,13 +417,17 @@ export default {
395
417
  if (val !== selected.value) {
396
418
  // 设置选择数据
397
419
  selected.value = val
420
+
421
+ // 检查值更新
422
+ checkModelValueChange()
398
423
  }
399
- // 检查值更新
400
- checkModelValueChange()
401
424
 
402
425
  // 设置输入框焦点
403
426
  setInputFocus()
404
427
 
428
+ // 设置输入框文字选中
429
+ setInputSelection()
430
+
405
431
  }, {
406
432
  // 深度监听
407
433
  deep: true
@@ -412,8 +438,19 @@ export default {
412
438
  */
413
439
  watch(selected, function(val) {
414
440
  if (val !== props.selected) {
441
+
442
+ // 更新选择数据
415
443
  emit('update:selected', val)
444
+
445
+ // 检查值更新
446
+ checkModelValueChange()
416
447
  }
448
+
449
+ // 设置输入框焦点
450
+ setInputFocus()
451
+
452
+ // 设置输入框文字选中
453
+ setInputSelection()
417
454
  }, {
418
455
  // 深度监听
419
456
  deep: true,
@@ -427,10 +464,11 @@ export default {
427
464
  // 取消延迟执行
428
465
  sleep.cancel()
429
466
 
430
- if (utils.isValidValue(val)) {
467
+ const hasValue = utils.isValidValue(val)
468
+ if (hasValue) {
431
469
 
432
470
  const n_search = {}
433
- n_search[currentFilterKeys.value] = [
471
+ n_search[currentFilterKey.value] = [
434
472
  {
435
473
  // 比较类型
436
474
  type: dicts.SEARCH_TYPE__LIKE,
@@ -450,12 +488,34 @@ export default {
450
488
  // 延迟执行
451
489
  await sleep(props.inputDebounce)
452
490
 
491
+ if (
492
+ // 如果弹出层是隐藏的
493
+ ! showPopup.value
494
+ // 如果输入框有值
495
+ && hasValue
496
+ ) {
497
+ // 显示弹出层
498
+ popupRef.value.show()
499
+ }
500
+
453
501
  // 表格重新加载
454
502
  await $table.tableReload()
455
503
  })
456
504
 
457
505
  // ==========【方法】=============================================================================================
458
506
 
507
+ /**
508
+ * 当前格式化显示标签
509
+ */
510
+ function currentFormatLabel(item) {
511
+ // 如果有格式化显示标签方法
512
+ return _.isFunction(props.formatLabel)
513
+ // 执行格式化显示标签方法
514
+ ? props.formatLabel(item)
515
+ // 否则显示该值的标签字段
516
+ : item[currentlabelKey.value]
517
+ }
518
+
459
519
  /**
460
520
  * 格式化值
461
521
  */
@@ -497,7 +557,7 @@ export default {
497
557
  // 查看字段
498
558
  n_view: {
499
559
  // 查看字段
500
- field: props.rowKey,
560
+ field: props.valueKey,
501
561
  // 查看值
502
562
  value,
503
563
  },
@@ -548,9 +608,9 @@ export default {
548
608
  ? (
549
609
  props.multiple
550
610
  // 如果是多选
551
- ? selected.value.map(e => e[props.rowKey])
611
+ ? selected.value.map(e => e[props.valueKey])
552
612
  // 否则是单选
553
- : [ selected.value[0][props.rowKey] ]
613
+ : [ selected.value[0][props.valueKey] ]
554
614
  )
555
615
  // 否则为空
556
616
  : []
@@ -642,10 +702,43 @@ export default {
642
702
  /**
643
703
  * 移除已选数据
644
704
  */
645
- function onRemoveSelected(item, index) {
705
+ function onRemoveSelected(index) {
646
706
  selected.value.splice(index, 1)
647
707
  }
648
708
 
709
+ /**
710
+ * 字段获取焦点触发
711
+ */
712
+ function onFieldFocus(e) {
713
+
714
+ // 停止冒泡
715
+ e.stopPropagation()
716
+
717
+ // 设置输入框焦点
718
+ setInputFocus()
719
+
720
+ window.scrollTo(window.pageXOffset || window.scrollX || document.body.scrollLeft || 0, 0)
721
+ }
722
+
723
+ /**
724
+ * 字段失去焦点触发
725
+ */
726
+ function onFieldBlur(e) {
727
+
728
+ // 停止冒泡
729
+ e.stopPropagation()
730
+
731
+ if (
732
+ // 如果开启筛选
733
+ props.filter
734
+ // 如果没有显示弹出层
735
+ && ! showPopup.value
736
+ ) {
737
+ // 清空输入框值
738
+ inputValue.value = ''
739
+ }
740
+ }
741
+
649
742
  /**
650
743
  * 字段清空触发
651
744
  */
@@ -654,34 +747,47 @@ export default {
654
747
  // 清空快捷表格已选数据
655
748
  selected.value = []
656
749
 
657
- // 关闭弹出层
750
+ // 隐藏弹出层
658
751
  popupRef.value.hide()
659
752
  }
660
753
 
661
754
  /**
662
- * 弹出层显示回调
755
+ * 弹出层获取焦点触发
663
756
  */
664
- function onPopupShow() {
757
+ function onPopupFocus(e) {
665
758
 
666
- // 表格加载(只加载一次)
667
- $table.tableLoad()
759
+ // 停止冒泡
760
+ e.stopPropagation()
668
761
 
669
762
  // 设置输入框焦点
670
763
  setInputFocus()
764
+
765
+ window.scrollTo(window.pageXOffset || window.scrollX || document.body.scrollLeft || 0, 0)
671
766
  }
672
767
 
673
768
  /**
674
- * 弹出层获取焦点触发
769
+ * 弹出层显示回调
675
770
  */
676
- function onPopupFocus(e) {
771
+ function onPopupShow() {
677
772
 
678
- // 停止冒泡
679
- e.stopPropagation()
773
+ // 显示弹出层
774
+ showPopup.value = true
680
775
 
681
776
  // 设置输入框焦点
682
777
  setInputFocus()
683
778
 
684
- window.scrollTo(window.pageXOffset || window.scrollX || document.body.scrollLeft || 0, 0)
779
+ // 表格加载(只加载一次)
780
+ $table.tableLoad()
781
+ .finally()
782
+ }
783
+
784
+ /**
785
+ * 弹出层隐藏前显示回调
786
+ */
787
+ function onPopupBeforeHide() {
788
+
789
+ // 隐藏弹出层
790
+ showPopup.value = false
685
791
  }
686
792
 
687
793
  /**
@@ -692,6 +798,7 @@ export default {
692
798
  // 设置当前已选数据
693
799
  $table.tableSelected.value = [...selected.value]
694
800
 
801
+ // 隐藏弹出层
695
802
  popupRef.value.hide()
696
803
  }
697
804
 
@@ -699,7 +806,10 @@ export default {
699
806
  * 对话框显示回调
700
807
  */
701
808
  function onDialogShow() {
809
+
810
+ // 表格加载(只加载一次)
702
811
  $table.tableLoad()
812
+ .finally()
703
813
  }
704
814
 
705
815
  /**
@@ -710,7 +820,12 @@ export default {
710
820
  let isReload = true
711
821
 
712
822
  // 清空输入框值
713
- if (inputValue.value) {
823
+ if (
824
+ // 如果开启筛选
825
+ props.filter
826
+ // 如果有输入框值
827
+ && inputValue.value
828
+ ) {
714
829
  // 此时清空输入框后, 会自动刷新表格
715
830
  inputValue.value = ''
716
831
 
@@ -741,7 +856,7 @@ export default {
741
856
  if (props.multiple) {
742
857
 
743
858
  const opt = {}
744
- opt[props.rowKey] = row[props.rowKey]
859
+ opt[props.valueKey] = row[props.valueKey]
745
860
 
746
861
  // 获取当前数据索引
747
862
  const itemIndex = _.findIndex(selected.value, opt)
@@ -760,15 +875,40 @@ export default {
760
875
  // 否则为单选
761
876
  } else {
762
877
  selected.value = [ row ]
878
+
879
+ // 隐藏弹出层
763
880
  popupRef.value.hide()
764
881
  }
765
882
  }
766
883
 
884
+ /**
885
+ * 设置输入框文字选中
886
+ */
887
+ function setInputSelection() {
888
+ if (
889
+ // 如果开启筛选
890
+ props.filter
891
+ // 如果有输入框节点
892
+ && inputRef.value
893
+ // 如果输入框有值
894
+ && inputValue.value.length
895
+ ) {
896
+ // 全选文字
897
+ inputRef.value.select()
898
+ // inputRef.value.setSelectionRange(0, inputValue.value.length)
899
+ }
900
+ }
901
+
767
902
  /**
768
903
  * 设置输入框焦点
769
904
  */
770
905
  function setInputFocus() {
771
- if (inputRef.value) {
906
+ if (
907
+ // 如果开启筛选
908
+ props.filter
909
+ // 如果有输入框节点
910
+ && inputRef.value
911
+ ) {
772
912
  inputRef.value.focus()
773
913
  }
774
914
  }
@@ -784,6 +924,15 @@ export default {
784
924
  await onLoadSelected()
785
925
  })
786
926
 
927
+ /**
928
+ * 在组件因为响应式状态变更而更新其 DOM 树之后调用
929
+ */
930
+ onUpdated(function () {
931
+ if (_.has(popupRef.value, 'currentComponent.ref.updatePosition')) {
932
+ popupRef.value.currentComponent.ref.updatePosition()
933
+ }
934
+ })
935
+
787
936
  // ==========【返回】=============================================================================================
788
937
 
789
938
  return {
@@ -792,6 +941,8 @@ export default {
792
941
 
793
942
  // 插槽标识
794
943
  slotNames,
944
+ // 当前标签字段
945
+ currentlabelKey,
795
946
  // 显示值
796
947
  showValue,
797
948
 
@@ -808,15 +959,24 @@ export default {
808
959
  // 当前表格列数据
809
960
  columns,
810
961
 
962
+ // 当前格式化显示标签
963
+ currentFormatLabel,
811
964
  // 移除已选数据
812
965
  onRemoveSelected,
966
+
967
+ // 字段获取焦点触发
968
+ onFieldFocus,
969
+ // 字段失去焦点触发
970
+ onFieldBlur,
813
971
  // 字段清空触发
814
972
  onFieldClear,
815
973
 
816
- // 弹出层显示回调
817
- onPopupShow,
818
974
  // 弹出层获取焦点触发
819
975
  onPopupFocus,
976
+ // 弹出层显示回调
977
+ onPopupShow,
978
+ // 弹出层隐藏前显示回调
979
+ onPopupBeforeHide,
820
980
 
821
981
  // 对话框显示前回调
822
982
  onDialogBeforeShow,