@deot/vc-components 1.0.24 → 1.0.25

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.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { reactive, defineComponent, createVNode, ref, watch, getCurrentInstance, computed, TransitionGroup, Transition as Transition$1, h, inject, onMounted, provide, shallowRef, onUnmounted, withDirectives, vShow, createApp, onBeforeUnmount, Fragment as Fragment$1, Teleport, withModifiers, nextTick, isVNode, onBeforeMount, mergeProps, createTextVNode, toRaw, onUpdated, useAttrs as useAttrs$1 } from 'vue';
1
+ import { reactive, defineComponent, createVNode, ref, watch, getCurrentInstance, computed, TransitionGroup, Transition as Transition$1, h, inject, provide, shallowRef, onMounted, onUnmounted, withDirectives, vShow, createApp, onBeforeUnmount, Fragment as Fragment$1, Teleport, withModifiers, nextTick, isVNode, onBeforeMount, mergeProps, createTextVNode, toRaw, onUpdated, useAttrs as useAttrs$1 } from 'vue';
2
2
  import { debounce, isEqualWith, pick, startCase, throttle, cloneDeep, max, merge as merge$1, isEmpty as isEmpty$1, kebabCase } from 'lodash-es';
3
3
  import { Resize } from '@deot/helper-resize';
4
4
  import { Utils as Utils$1, IS_SERVER as IS_SERVER$1 } from '@deot/vc-shared';
@@ -10,6 +10,7 @@ import { useAttrs, useScrollbar, getInstance } from '@deot/vc-hooks';
10
10
  import { Wheel } from '@deot/helper-wheel';
11
11
  import { Validator } from '@deot/helper-validator';
12
12
  import { Storage } from '@deot/helper-cache';
13
+ import PhotoSwipeLightbox from 'photoswipe/lightbox';
13
14
  import * as Load from '@deot/helper-load';
14
15
  import { style } from '@deot/helper-load';
15
16
  import { Interrupter } from '@deot/helper-scheduler';
@@ -1065,7 +1066,7 @@ const Button = /* @__PURE__ */ defineComponent({
1065
1066
  slots
1066
1067
  }) {
1067
1068
  const vm = getCurrentInstance();
1068
- const hasSlot = ref(true);
1069
+ const isHover = ref(false);
1069
1070
  const isLoading = ref(false);
1070
1071
  const group = inject('vc-button-group', {
1071
1072
  size: 'medium',
@@ -1074,10 +1075,11 @@ const Button = /* @__PURE__ */ defineComponent({
1074
1075
  });
1075
1076
  const classes = computed(() => ({
1076
1077
  'is-circle': props.circle || group.circle,
1077
- 'is-alone': !hasSlot.value,
1078
+ 'is-alone': !slots?.default,
1078
1079
  'is-round': props.round,
1079
1080
  'is-long': props.long,
1080
1081
  'is-disabled': props.disabled,
1082
+ 'is-hover': isHover.value,
1081
1083
  [`is-${props.size}`]: true,
1082
1084
  [`is-${props.type}`]: true
1083
1085
  }));
@@ -1090,9 +1092,6 @@ const Button = /* @__PURE__ */ defineComponent({
1090
1092
  });
1091
1093
  }
1092
1094
  };
1093
- onMounted(() => {
1094
- hasSlot.value = slots.default !== undefined;
1095
- });
1096
1095
  return () => {
1097
1096
  return createVNode(Debounce, {
1098
1097
  "tag": props.tag,
@@ -1103,15 +1102,19 @@ const Button = /* @__PURE__ */ defineComponent({
1103
1102
  "wait": props.wait,
1104
1103
  "disabled": props.disabled,
1105
1104
  "type": props.htmlType,
1106
- "onClick": handleClick
1105
+ "onClick": handleClick,
1106
+ "onMouseenter": () => isHover.value = true,
1107
+ "onMouseleave": () => isHover.value = false
1107
1108
  }, {
1108
1109
  default: () => [props.icon && createVNode(Icon, {
1109
1110
  "type": props.icon
1110
- }, null), isLoading.value && createVNode(Spin, {
1111
+ }, null), slots.icon && slots?.icon?.({
1112
+ hover: isHover.value
1113
+ }), isLoading.value && createVNode(Spin, {
1111
1114
  "size": 12,
1112
1115
  "foreground": props.type === 'default' ? '#ccc' : '#fff',
1113
1116
  "class": "vc-button__loading"
1114
- }, null), hasSlot.value && createVNode("span", null, [slots?.default?.()])]
1117
+ }, null), slots?.default && createVNode("span", null, [slots?.default?.()])]
1115
1118
  });
1116
1119
  };
1117
1120
  }
@@ -1527,7 +1530,8 @@ const useCheckbox = () => {
1527
1530
  "is-indeterminate": props.indeterminate,
1528
1531
  "is-checked": checked.value,
1529
1532
  "is-disabled": props.disabled,
1530
- "is-focus": isFocus.value
1533
+ "is-focus": isFocus.value,
1534
+ "is-error": !!formItem?.message?.value
1531
1535
  };
1532
1536
  });
1533
1537
  watch(
@@ -3178,7 +3182,8 @@ const useInput = (input) => {
3178
3182
  const classes = computed(() => {
3179
3183
  return {
3180
3184
  "is-focus": isFocus.value,
3181
- "is-disabled": props.disabled
3185
+ "is-disabled": props.disabled,
3186
+ "is-error": !!formItem?.message?.value
3182
3187
  };
3183
3188
  });
3184
3189
  const currentMaxlength = computed(() => {
@@ -8699,7 +8704,7 @@ const Drawer$ = new Portal(DrawerView, {
8699
8704
  multiple: true
8700
8705
  });
8701
8706
  const destroy$3 = () => Drawer$.destroy();
8702
- const open$1 = (options) => {
8707
+ const open$2 = (options) => {
8703
8708
  const leaf = Drawer$.popup({
8704
8709
  ...options,
8705
8710
  onFulfilled: options.onClose,
@@ -8709,7 +8714,7 @@ const open$1 = (options) => {
8709
8714
  leaf.wrapper.toggle?.(true);
8710
8715
  return leaf;
8711
8716
  };
8712
- const Drawer = Object.assign(DrawerView, { open: open$1, destroy: destroy$3 });
8717
+ const Drawer = Object.assign(DrawerView, { open: open$2, destroy: destroy$3 });
8713
8718
 
8714
8719
  const MDrawer = Drawer;
8715
8720
  const MDrawerView = DrawerView;
@@ -8808,7 +8813,7 @@ const useForm = (expose, options = {}) => {
8808
8813
  const instance = getCurrentInstance();
8809
8814
  const props = instance.props;
8810
8815
  const fields = [];
8811
- provide("form", {
8816
+ provide("vc-form", {
8812
8817
  props,
8813
8818
  add: (field) => {
8814
8819
  field && fields.push(field);
@@ -8956,8 +8961,7 @@ const props$L = {
8956
8961
  default: false
8957
8962
  },
8958
8963
  labelPosition: {
8959
- type: String,
8960
- default: "right"
8964
+ type: String
8961
8965
  },
8962
8966
  contentStyle: [Object, String],
8963
8967
  contentClass: [Object, String],
@@ -8975,7 +8979,7 @@ const toRules = (rules) => {
8975
8979
  return rules instanceof Array ? rules : rules ? [rules] : [];
8976
8980
  };
8977
8981
  const useFormItem = (expose) => {
8978
- const form = inject("form");
8982
+ const form = inject("vc-form");
8979
8983
  const instance = getCurrentInstance();
8980
8984
  const props = instance.props;
8981
8985
  const { slots } = instance;
@@ -9488,7 +9492,7 @@ const ObjectFit = {
9488
9492
  FILL: 'fill',
9489
9493
  SCALE_DOWN: 'scale-down'
9490
9494
  };
9491
- const Image = /* @__PURE__ */ defineComponent({
9495
+ const Image$1 = /* @__PURE__ */ defineComponent({
9492
9496
  name: COMPONENT_NAME$W,
9493
9497
  inheritAttrs: false,
9494
9498
  props: props$H,
@@ -9683,7 +9687,7 @@ const Image = /* @__PURE__ */ defineComponent({
9683
9687
  }
9684
9688
  });
9685
9689
 
9686
- const MImage = Image;
9690
+ const MImage = Image$1;
9687
9691
 
9688
9692
  const props$G = {
9689
9693
  tag: {
@@ -9721,7 +9725,7 @@ const props$F = {
9721
9725
  /** @jsxImportSource vue */
9722
9726
 
9723
9727
  const COMPONENT_NAME$U = 'vc-image-preview';
9724
- const ImagePreview = /* @__PURE__ */ defineComponent({
9728
+ const ImagePreview$1 = /* @__PURE__ */ defineComponent({
9725
9729
  name: COMPONENT_NAME$U,
9726
9730
  props: props$F,
9727
9731
  setup(props, {
@@ -9735,6 +9739,81 @@ const ImagePreview = /* @__PURE__ */ defineComponent({
9735
9739
  }
9736
9740
  });
9737
9741
 
9742
+ const MAX_WIDTH = window.innerWidth;
9743
+ const MAX_HEIGHT = window.innerHeight;
9744
+ const getFitSize = (src) => {
9745
+ return new Promise((resolve) => {
9746
+ const img = new Image();
9747
+ let width;
9748
+ let height;
9749
+ img.onload = () => {
9750
+ const owidth = img.naturalWidth || img.width;
9751
+ const oheight = img.naturalHeight || img.height;
9752
+ if (owidth > oheight) {
9753
+ width = Math.min(MAX_WIDTH, owidth);
9754
+ height = width / owidth * oheight;
9755
+ resolve({
9756
+ width,
9757
+ height
9758
+ });
9759
+ } else {
9760
+ height = Math.min(MAX_HEIGHT, oheight);
9761
+ width = height / oheight * owidth;
9762
+ resolve({
9763
+ width,
9764
+ height
9765
+ });
9766
+ }
9767
+ };
9768
+ img.onerror = () => resolve({});
9769
+ img.src = src;
9770
+ });
9771
+ };
9772
+ const open$1 = async (options) => {
9773
+ const e = VcInstance.globalEvent;
9774
+ const data = options.data.map((i) => {
9775
+ if (typeof i === "string") {
9776
+ return {
9777
+ src: i
9778
+ };
9779
+ }
9780
+ return {
9781
+ ...i,
9782
+ src: i.source || i.src
9783
+ };
9784
+ });
9785
+ for (let i = 0; i < data.length; i++) {
9786
+ if (!data[i].width) {
9787
+ data[i] = {
9788
+ ...data[i],
9789
+ ...await getFitSize(data[i].src)
9790
+ };
9791
+ }
9792
+ }
9793
+ const lightbox = new PhotoSwipeLightbox({
9794
+ pswpModule: () => import('photoswipe'),
9795
+ closeTitle: "关闭(Esc)",
9796
+ zoomTitle: "缩放",
9797
+ arrowPrevTitle: "上一张",
9798
+ arrowNextTitle: "下一张",
9799
+ errorMsg: "网络异常 图片加载失败",
9800
+ indexIndicatorSep: " / ",
9801
+ initialZoomLevel: "fit"
9802
+ });
9803
+ lightbox.init();
9804
+ lightbox.loadAndOpen(
9805
+ options.current || 0,
9806
+ data,
9807
+ // 下面无效,需要给官方支持
9808
+ {
9809
+ x: e?.clientX,
9810
+ y: e?.clientY
9811
+ }
9812
+ );
9813
+ };
9814
+
9815
+ const ImagePreview = Object.assign(ImagePreview$1, { open: open$1 });
9816
+
9738
9817
  const MImagePreview = ImagePreview;
9739
9818
 
9740
9819
  const props$E = {
@@ -10341,9 +10420,8 @@ const props$z = {
10341
10420
  type: [String, Boolean],
10342
10421
  default: "取消"
10343
10422
  },
10344
- wrapperStyle: {
10345
- type: [String, Object]
10346
- },
10423
+ wrapperStyle: [String, Object],
10424
+ wrapperClass: [String, Object],
10347
10425
  footer: {
10348
10426
  type: Boolean,
10349
10427
  default: true
@@ -10397,6 +10475,7 @@ const ModalView = /* @__PURE__ */ defineComponent({
10397
10475
 
10398
10476
  // 注: 服务端渲染为0, 在客服端激活前,展示端存在问题【高度不定】
10399
10477
  const MAX_HEIGHT = IS_SERVER$1 ? 0 : window.innerHeight - 20;
10478
+ const MAX_WIDTH = IS_SERVER$1 ? 0 : window.innerWidth - 20;
10400
10479
  const defaultSize = computed(() => {
10401
10480
  let width = 0;
10402
10481
  let height = 0;
@@ -10415,7 +10494,7 @@ const ModalView = /* @__PURE__ */ defineComponent({
10415
10494
  break;
10416
10495
  }
10417
10496
  return {
10418
- width: props.width || width,
10497
+ width: Math.min(props.width || width, MAX_WIDTH),
10419
10498
  height: Math.min(props.height || height, MAX_HEIGHT)
10420
10499
  };
10421
10500
  });
@@ -10651,7 +10730,7 @@ const ModalView = /* @__PURE__ */ defineComponent({
10651
10730
  "style": [props.wrapperStyle || {}, props.draggable ? {
10652
10731
  top: 0
10653
10732
  } : {}],
10654
- "class": "vc-modal__wrapper",
10733
+ "class": [props.wrapperClass, 'vc-modal__wrapper'],
10655
10734
  "onClick": e => handleClose(e, false)
10656
10735
  }, [createVNode(TransitionScale, {
10657
10736
  "mode": "part",
@@ -12318,8 +12397,12 @@ const Progress = /* @__PURE__ */ defineComponent({
12318
12397
  setup(props, {
12319
12398
  slots
12320
12399
  }) {
12400
+ const currentPercent = computed(() => {
12401
+ const v = Number(props.percent);
12402
+ return v >= 100 ? 100 : v;
12403
+ });
12321
12404
  const currentStatus = computed(() => {
12322
- if (Number(props.percent) >= 100) {
12405
+ if (currentPercent.value === 100) {
12323
12406
  return 'success';
12324
12407
  }
12325
12408
  return props.status;
@@ -12331,6 +12414,7 @@ const Progress = /* @__PURE__ */ defineComponent({
12331
12414
  const binds = computed(() => {
12332
12415
  return {
12333
12416
  ...props,
12417
+ percent: currentPercent.value,
12334
12418
  status: currentStatus.value,
12335
12419
  color: currentColor.value
12336
12420
  };
@@ -12408,7 +12492,8 @@ const useRadio = () => {
12408
12492
  return {
12409
12493
  "is-checked": checked.value,
12410
12494
  "is-disabled": isDisabled.value,
12411
- "is-focus": isFocus.value
12495
+ "is-focus": isFocus.value,
12496
+ "is-error": !!formItem?.message?.value
12412
12497
  };
12413
12498
  });
12414
12499
  watch(
@@ -12592,8 +12677,7 @@ const RadioGroup = /* @__PURE__ */ defineComponent({
12592
12677
  return () => {
12593
12678
  if (props.fragment) return slots.default?.();
12594
12679
  return createVNode("div", {
12595
- "class": "vc-radio-group",
12596
- "style": classes.value,
12680
+ "class": [classes.value, 'vc-radio-group'],
12597
12681
  "name": props.name
12598
12682
  }, [slots?.default?.()]);
12599
12683
  };
@@ -16913,7 +16997,11 @@ const props$a = {
16913
16997
  closable: {
16914
16998
  type: Boolean,
16915
16999
  default: false
16916
- }
17000
+ },
17001
+ barStyle: [Object, String],
17002
+ contentStyle: [Object, String],
17003
+ barClass: [Object, String],
17004
+ contentClass: [Object, String]
16917
17005
  };
16918
17006
 
16919
17007
  const useTabs = (options = {}) => {
@@ -17166,10 +17254,10 @@ const Tabs = /* @__PURE__ */ defineComponent({
17166
17254
  "class": "vc-tabs__extra"
17167
17255
  }, [slots.extra?.()]), createVNode("div", {
17168
17256
  "ref": wrapper,
17169
- "style": {
17257
+ "style": [props.barStyle, {
17170
17258
  padding: tabs.scrollable.value ? '0 24px' : 0
17171
- },
17172
- "class": "vc-tabs__bar"
17259
+ }],
17260
+ "class": [props.barClass, 'vc-tabs__bar']
17173
17261
  }, [tabs.scrollable.value && createVNode(Icon, {
17174
17262
  "class": "vc-tabs__icon is-left",
17175
17263
  "type": "left",
@@ -17209,8 +17297,8 @@ const Tabs = /* @__PURE__ */ defineComponent({
17209
17297
  }, null)]);
17210
17298
  })])])]), createVNode("div", {
17211
17299
  "ref": content,
17212
- "style": tabs.contentStyle.value,
17213
- "class": "vc-tabs__content"
17300
+ "style": [props.contentStyle, tabs.contentStyle.value],
17301
+ "class": [props.contentClass, 'vc-tabs__content']
17214
17302
  }, [slots.default?.()])]);
17215
17303
  };
17216
17304
  }
@@ -17825,7 +17913,8 @@ const useTextarea = (textarea, expose) => {
17825
17913
  const classes = computed(() => {
17826
17914
  return {
17827
17915
  "is-focus": isFocus.value,
17828
- "is-disabled": props.disabled
17916
+ "is-disabled": props.disabled,
17917
+ "is-error": !!formItem?.message?.value
17829
17918
  };
17830
17919
  });
17831
17920
  const listeners = computed(() => {
@@ -18743,10 +18832,342 @@ const Upload = defineComponent({
18743
18832
  const MUpload = Upload;
18744
18833
 
18745
18834
  const props = {
18746
- tag: {
18747
- type: String,
18748
- default: "div"
18749
- }
18835
+ picker: {
18836
+ type: Array,
18837
+ default: () => ["image"]
18838
+ },
18839
+ sortable: {
18840
+ type: Boolean,
18841
+ default: false
18842
+ },
18843
+ mask: {
18844
+ type: Boolean,
18845
+ default: false
18846
+ },
18847
+ /**
18848
+ * vc-upload组件的属性
18849
+ */
18850
+ uploadOptions: {
18851
+ type: Object,
18852
+ default() {
18853
+ return {};
18854
+ }
18855
+ },
18856
+ /**
18857
+ * 数据源['xxx.jpg', ....]
18858
+ */
18859
+ modelValue: {
18860
+ type: [String, Array, Object],
18861
+ // { value: '', label: '' }
18862
+ default: () => []
18863
+ },
18864
+ // 数据字典
18865
+ keyValue: {
18866
+ type: Object,
18867
+ default: () => {
18868
+ return {
18869
+ label: "label",
18870
+ value: "value"
18871
+ };
18872
+ }
18873
+ },
18874
+ output: {
18875
+ type: [String, Function],
18876
+ default: "object",
18877
+ validator: (v) => /(string|object)/.test(v)
18878
+ },
18879
+ /**
18880
+ * 可上传的最大值,跟upload内的Max不同,有可能是对象类型,对应的Upload做限制
18881
+ */
18882
+ max: {
18883
+ type: [Number, Object],
18884
+ default: Number.MAX_SAFE_INTEGER
18885
+ },
18886
+ disabled: {
18887
+ type: Boolean,
18888
+ default: false
18889
+ },
18890
+ /**
18891
+ * 上传成功后对数据的格式化
18892
+ */
18893
+ formatter: Function,
18894
+ // TODO 下面两个重复了,需删除
18895
+ /**
18896
+ * 盒子className
18897
+ */
18898
+ boxClass: String,
18899
+ imagePreviewOptions: {
18900
+ type: Object,
18901
+ default: () => ({})
18902
+ },
18903
+ imageClass: String,
18904
+ videoClass: String,
18905
+ audioClass: String,
18906
+ fileClass: String,
18907
+ compressOptions: {
18908
+ type: Object,
18909
+ default: () => {
18910
+ return {
18911
+ compress: false,
18912
+ // 是否开启图片压缩
18913
+ width: 0,
18914
+ // 图片缩放最大宽度,为0默认源图片宽度
18915
+ height: 0,
18916
+ // 图片缩放最大高度,为0默认源图片高度
18917
+ filetype: "image/jpeg",
18918
+ // 文件类型
18919
+ encoderOptions: 0.92
18920
+ // 在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,使用默认值 0.92
18921
+ };
18922
+ }
18923
+ },
18924
+ showMessage: Boolean,
18925
+ gallery: Boolean
18926
+ };
18927
+
18928
+ const recognizer = (url) => {
18929
+ const reg = /\.(jpe?g|png|gif|bmp|webp|image|heic|mp4|mov|avi|mpg|mpeg|rmvb)/ig;
18930
+ const result = url.match(reg);
18931
+ return result && result.length ? /.(jpe?g|png|gif|bmp|webp|image|heic)/ig.test(result[result.length - 1]) ? "image" : "video" : "file";
18932
+ };
18933
+ const FILE_ACCEPT_MAP = {
18934
+ DOC_ACCEPTS: ".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document",
18935
+ EXCEL_ACCEPTS: ".csv,.xls,.xlsx,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
18936
+ PPT_ACCEPTS: ".ppt,.pptx,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation",
18937
+ PDF_ACCEPTS: ".pdf,application/pdf",
18938
+ TXT_ACCEPTS: "text/plain",
18939
+ HTML_ACCEPTS: "text/html"
18940
+ };
18941
+
18942
+ const {
18943
+ DOC_ACCEPTS,
18944
+ EXCEL_ACCEPTS,
18945
+ PPT_ACCEPTS,
18946
+ PDF_ACCEPTS,
18947
+ TXT_ACCEPTS,
18948
+ HTML_ACCEPTS
18949
+ } = FILE_ACCEPT_MAP;
18950
+ const usePicker = (expose) => {
18951
+ const instance = getCurrentInstance();
18952
+ const props = instance.props;
18953
+ const { emit } = instance;
18954
+ const formItem = inject("vc-form-item", {});
18955
+ const allowKeepString = computed(() => {
18956
+ return typeof props.modelValue === "string";
18957
+ });
18958
+ const allowKeepObject = computed(() => {
18959
+ const v = props.modelValue;
18960
+ return props.output === "object" && props.max === 1 && !Array.isArray(v) && typeof v === "object";
18961
+ });
18962
+ const currentValue = ref({
18963
+ image: [],
18964
+ video: [],
18965
+ audio: [],
18966
+ file: []
18967
+ });
18968
+ const currentUploadOptions = ref({
18969
+ image: {
18970
+ accept: "image/gif,image/jpeg,image/jpg,image/png",
18971
+ ...props.uploadOptions.image || {}
18972
+ },
18973
+ video: {
18974
+ accept: "video/*",
18975
+ ...props.uploadOptions.video || {}
18976
+ },
18977
+ audio: {
18978
+ accept: "audio/*",
18979
+ ...props.uploadOptions.audio || {}
18980
+ },
18981
+ file: {
18982
+ accept: `${DOC_ACCEPTS},${EXCEL_ACCEPTS},${PPT_ACCEPTS},${PDF_ACCEPTS},${TXT_ACCEPTS},${HTML_ACCEPTS}`,
18983
+ ...props.uploadOptions.file || {}
18984
+ }
18985
+ });
18986
+ const dynamicMax = computed(() => {
18987
+ const image = currentValue.value.image || [];
18988
+ const video = currentValue.value.video || [];
18989
+ const audio = currentValue.value.audio || [];
18990
+ const file = currentValue.value.file || [];
18991
+ const imageCount = image.length || 0;
18992
+ const videoCount = video.length || 0;
18993
+ const audioCount = audio.length || 0;
18994
+ const fileCount = file.length || 0;
18995
+ if (typeof props.max === "number") {
18996
+ const curNum = imageCount + videoCount + audioCount + fileCount;
18997
+ const leftNum = props.max - curNum;
18998
+ return {
18999
+ image: leftNum,
19000
+ video: leftNum,
19001
+ audio: leftNum,
19002
+ file: leftNum
19003
+ };
19004
+ } else if (typeof props.max === "object") {
19005
+ const {
19006
+ image: $image,
19007
+ video: $video,
19008
+ audio: $audio,
19009
+ file: $file
19010
+ } = props.max;
19011
+ const max = {};
19012
+ $image && (max.image = $image - imageCount);
19013
+ $video && (max.video = $video - videoCount);
19014
+ $audio && (max.audio = $audio - audioCount);
19015
+ $file && (max.file = $file - fileCount);
19016
+ return max;
19017
+ }
19018
+ return {};
19019
+ });
19020
+ const sync = () => {
19021
+ let v = props.picker.reduce((pre, cur) => pre.concat(currentValue.value[cur] || []), []).filter((i) => !i.errorFlag).map((i) => {
19022
+ if (props.output === "string") return i[props.keyValue.value];
19023
+ if (typeof props.output === "function") return props.output(i) || i;
19024
+ return i;
19025
+ });
19026
+ if (allowKeepString.value) {
19027
+ v = v.map((i) => i[props.keyValue.value] || i).join(",");
19028
+ } else if (allowKeepObject.value) {
19029
+ v = v[0] || null;
19030
+ }
19031
+ emit("update:modelValue", v);
19032
+ emit("change", v);
19033
+ formItem.change?.(v);
19034
+ };
19035
+ const handleFileBefore = async (vFile, fileList, type) => {
19036
+ if (props?.compressOptions?.compress && type === "image") ;
19037
+ const onFileBefore = instance.vnode.props?.onFileBefore || (() => {
19038
+ });
19039
+ return await onFileBefore(vFile, fileList, type) || vFile;
19040
+ };
19041
+ const handleFileStart = (vFile, type) => {
19042
+ currentValue.value[type].push(vFile);
19043
+ emit("file-start", vFile, type);
19044
+ };
19045
+ const handleFileProgress = (e, vFile, type) => {
19046
+ if (parseInt(e.percent, 10) <= 100) {
19047
+ currentValue.value[type] = currentValue.value[type].map((item) => {
19048
+ if (vFile.uploadId === item.uploadId) {
19049
+ return {
19050
+ ...item,
19051
+ percent: e.percent
19052
+ };
19053
+ }
19054
+ return item;
19055
+ });
19056
+ }
19057
+ };
19058
+ const handleFileSuccess = (response, vFile, cycle, type) => {
19059
+ currentValue.value[type] = currentValue.value[type].map((item) => {
19060
+ if (item.uploadId === vFile.uploadId) {
19061
+ return {
19062
+ type,
19063
+ [props.keyValue.label]: vFile.name,
19064
+ // 外部需要满足response中带source
19065
+ [props.keyValue.value]: response.source
19066
+ };
19067
+ }
19068
+ return item;
19069
+ });
19070
+ emit("file-success", response, vFile, cycle, type);
19071
+ };
19072
+ const handleError = (err, type) => {
19073
+ props.showMessage && err.message && Message.error(err.message);
19074
+ emit("error", err, type);
19075
+ };
19076
+ const handleFileError = (response, vFile, cycle, type) => {
19077
+ currentValue.value[type] = currentValue.value[type].map((item) => {
19078
+ if (item.uploadId === vFile.uploadId) {
19079
+ return {
19080
+ ...item,
19081
+ ...response,
19082
+ // 文件基础信息
19083
+ type,
19084
+ [props.keyValue.label]: vFile.name,
19085
+ errorFlag: (/* @__PURE__ */ new Date()).getTime()
19086
+ };
19087
+ }
19088
+ return item;
19089
+ });
19090
+ emit("file-error", response, vFile, cycle, type);
19091
+ };
19092
+ const handleFileComplete = (response, type) => {
19093
+ sync();
19094
+ emit("complete", response, type);
19095
+ };
19096
+ const handleDelete = async (index, type) => {
19097
+ const onRemoveBefore = instance.vnode.props?.onRemoveBefore || (() => {
19098
+ });
19099
+ await onRemoveBefore(index, type);
19100
+ const target = currentValue.value[type];
19101
+ const item = target[index];
19102
+ if (!item) {
19103
+ console.error("【vc-upload-picker】: 没有找到要删除的元素");
19104
+ return;
19105
+ }
19106
+ if (item.errorFlag) {
19107
+ currentValue.value[type] = target.filter(
19108
+ (it) => it.uploadId != item.uploadId
19109
+ );
19110
+ return;
19111
+ }
19112
+ target.splice(index, 1);
19113
+ sync();
19114
+ };
19115
+ const parseModelValue = (v) => {
19116
+ const initialData = { image: [], video: [], audio: [], file: [] };
19117
+ if (allowKeepString.value) {
19118
+ v = (props.max === 1 ? [v] : v.split(",")).filter((i) => !!i);
19119
+ } else if (allowKeepObject.value) {
19120
+ v = [v].filter((i) => i && !!i[props.keyValue.value]);
19121
+ }
19122
+ if (!Array.isArray(v) || !v.length) return initialData;
19123
+ return v.reduce((pre, cur) => {
19124
+ const value = cur[props.keyValue.value] || (typeof cur === "object" ? "" : cur);
19125
+ const label = cur[props.keyValue.label] || value.replace(/^.*\/([^/]+)$/, "$1");
19126
+ const type = cur.type || (props.picker.length === 1 ? props.picker[0] : recognizer(value));
19127
+ switch (type) {
19128
+ case "image":
19129
+ case "video":
19130
+ case "audio":
19131
+ case "file":
19132
+ pre[type].push({
19133
+ // 文件类型
19134
+ type,
19135
+ // 文件名
19136
+ [props.keyValue.label]: label,
19137
+ // 源文件地址
19138
+ [props.keyValue.value]: value,
19139
+ // 上传进度
19140
+ percent: null,
19141
+ // 错误标记
19142
+ errorFlag: false
19143
+ });
19144
+ return pre;
19145
+ default:
19146
+ return pre;
19147
+ }
19148
+ }, initialData);
19149
+ };
19150
+ watch(
19151
+ () => props.modelValue,
19152
+ (v) => {
19153
+ currentValue.value = parseModelValue(v);
19154
+ },
19155
+ { immediate: true }
19156
+ );
19157
+ expose();
19158
+ return {
19159
+ currentValue,
19160
+ currentUploadOptions,
19161
+ dynamicMax,
19162
+ handleDelete,
19163
+ handleFileBefore,
19164
+ handleFileStart,
19165
+ handleFileProgress,
19166
+ handleFileSuccess,
19167
+ handleFileError,
19168
+ handleError,
19169
+ handleFileComplete
19170
+ };
18750
19171
  };
18751
19172
 
18752
19173
  /** @jsxImportSource vue */
@@ -18755,17 +19176,115 @@ const COMPONENT_NAME = 'vc-upload-picker';
18755
19176
  const UploadPicker = /* @__PURE__ */ defineComponent({
18756
19177
  name: COMPONENT_NAME,
18757
19178
  props: props,
19179
+ emits: ['update:modelValue', 'file-success', 'file-start', 'success', 'error', 'complete', 'change', 'remove-before'],
18758
19180
  setup(props, {
18759
- slots
19181
+ slots,
19182
+ expose
18760
19183
  }) {
19184
+ const instance = getCurrentInstance();
19185
+ const currentPicker = computed(() => {
19186
+ return props.picker.reduce((pre, cur) => {
19187
+ switch (cur) {
19188
+ case 'image':
19189
+ pre.push({
19190
+ type: cur,
19191
+ item: 'div'
19192
+ // item: ImageItem
19193
+ });
19194
+ return pre;
19195
+ case 'video':
19196
+ pre.push({
19197
+ type: cur,
19198
+ item: 'div'
19199
+ // item: VideoItem
19200
+ });
19201
+ return pre;
19202
+ case 'audio':
19203
+ pre.push({
19204
+ type: cur,
19205
+ item: 'div'
19206
+ // item: AudioItem
19207
+ });
19208
+ return pre;
19209
+ case 'file':
19210
+ pre.push({
19211
+ type: cur,
19212
+ item: 'div'
19213
+ // item: FileItem
19214
+ });
19215
+ return pre;
19216
+ default:
19217
+ return pre;
19218
+ }
19219
+ }, []);
19220
+ });
19221
+ const handleClick = (e, type) => {
19222
+ const options = VcInstance.options.UploadPicker || {};
19223
+ if (typeof props.gallery === 'function' || props.gallery && options.gallery) {
19224
+ const fn = typeof props.gallery === 'function' ? props.gallery : options.gallery;
19225
+
19226
+ // 阻止原生事件,如video, file不走gallery, 可以跳过;
19227
+ fn(instance, type) && e.stopPropagation();
19228
+ }
19229
+ };
19230
+ const base = usePicker(expose);
18761
19231
  return () => {
18762
19232
  return createVNode("div", {
18763
19233
  "class": "vc-upload-picker"
18764
- }, [slots?.default?.()]);
19234
+ }, [currentPicker.value.map((picker, $index) => {
19235
+ return createVNode(Fragment$1, {
19236
+ "key": `${picker}-${$index}`
19237
+ }, [base.currentValue.value[picker.type].map((item, index) => {
19238
+ const Item = picker.item;
19239
+ return createVNode(Item, {
19240
+ "key": typeof item === 'object' ? item.uid : item,
19241
+ "it": item,
19242
+ "disabled": props.disabled,
19243
+ "image-preview-options": props.imagePreviewOptions,
19244
+ "imageClass": props.imageClass,
19245
+ "videoClass": props.videoClass,
19246
+ "audioClass": props.audioClass,
19247
+ "fileClass": props.fileClass,
19248
+ "index": index,
19249
+ "data": item,
19250
+ "class": "vc-upload-picker__item",
19251
+ "onDelete": () => base.handleDelete(index, picker.type)
19252
+ }, {
19253
+ default: scopeData => {
19254
+ return slots.default ? slots.default({
19255
+ it: scopeData?.it,
19256
+ current: scopeData?.current,
19257
+ index,
19258
+ name: picker.type
19259
+ }) : scopeData;
19260
+ }
19261
+ });
19262
+ }), withDirectives(createVNode(Upload, mergeProps(base.currentUploadOptions.value[picker.type], {
19263
+ "max": base.dynamicMax[picker.type],
19264
+ "class": "vc-upload-picker__upload",
19265
+ "onFileBefore": (vFile, fileList) => base.handleFileBefore(vFile, fileList, picker.type),
19266
+ "onFileStart": vFile => base.handleFileStart(vFile, picker.type),
19267
+ "onFileProgress": (e, vFile) => base.handleFileProgress(e, vFile, picker.type),
19268
+ "onFileSuccess": (response, vFile, cycle) => base.handleFileSuccess(response, vFile, cycle, picker.type),
19269
+ "onFileError": (response, vFile, cycle) => base.handleFileError(response, vFile, cycle, picker.type),
19270
+ "onError": e => base.handleError(e, picker.type),
19271
+ "onComplete": response => base.handleFileComplete(response, picker.type)
19272
+ }), {
19273
+ default: () => [slots?.[`${picker.type}-upload`] ? slots[`${picker.type}-upload`]?.() : createVNode("div", {
19274
+ "class": [props.boxClass, 'vc-upload-picker__box'],
19275
+ "onClick": e => handleClick(e, picker.type)
19276
+ }, [createVNode(Icon, {
19277
+ "type": "mini-plus",
19278
+ "class": "vc-upload-picker__plus-icon"
19279
+ }, null), createVNode("span", {
19280
+ "style": "margin-top: 8px"
19281
+ }, [createTextVNode("\u4E0A\u4F20")])])]
19282
+ }), [[vShow, !props.disabled && base.dynamicMax.value[picker.type] >= 1]])]);
19283
+ })]);
18765
19284
  };
18766
19285
  }
18767
19286
  });
18768
19287
 
18769
19288
  const MUploadPicker = UploadPicker;
18770
19289
 
18771
- export { ActionSheet, Alert, Artboard, Button, ButtonGroup, Calendar, Card, Carousel, Cascader, Chart, Checkbox, CheckboxGroup, Clipboard, Collapse, CollapseItem, ColorPicker, Countdown, Customer, DatePicker, Debounce, Divider, Drawer, DrawerView, Dropdown, Editor, Expand$1 as Expand, Form, FormItem, Fragment, HTMLToImage, Icon, IconManager, Image, ImageCrop, ImagePreview, ImageProcessing, Input, InputNumber, InputSearch, MList as List, MListItem as ListItem, MActionSheet, MAlert, MArtboard, MButton, MButtonGroup, MCalendar, MCard, MCarousel, MCascader, MChart, MCheckbox, MCheckboxGroup, MClipboard, MCollapse, MCollapseItem, MColorPicker, MCountdown, MCustomer, MDatePicker, Debounce as MDebounce, MDivider, MDrawer, MDrawerView, MDropdown, MEditor, MExpand, MForm, MFormItem, MFragment, MHTMLToImage, MIcon, MImage, MImageCrop, MImagePreview, MImageProcessing, MInput, MInputNumber, MInputSearch, MList, MListItem, MMarquee, MMessage, modal as MModal, MModalView, MNotice, MOption, MPagination, MPicker, MPopconfirm, MPopover, MPopup, MPortal, MPrint, MProgress, MRadio, MRadioGroup, MRate, MRecycleList, MResizer, MScroller, MSelect, MSlider, MSortList, MSpin, MSteps, MSwitch, MTable, MTableColumn, MTabs, MTabsPane, MTag, MText, MTextarea, MTimePicker, MTimeline, MToast, MToastView, MTouch, MTransition, MTransitionCollapse, MTransitionFade, MTransitionScale, MTransitionSlide, MTransitionZoom, MTree, MUpload, MUploadPicker, Marquee, Message, MessageView, Modal, ModalView, Notice, NoticeView, Option$1 as Option, Pagination, Picker, Popconfirm, Popover, Popup, Portal, PortalView, Print, Progress, Radio, RadioGroup, Rate, RecycleList, Resizer, Scroller, ScrollerWheel, Select, Slider, SortList, Spin, Steps, Switch, Table, TableColumn, Tabs, TabsPane, Tag, Text, Textarea, Theme, ThemeImage, ThemeText, ThemeView, TimePicker, Timeline, Toast, ToastView, Touch, Transition, TransitionCollapse, TransitionFade, TransitionScale, TransitionSlide, TransitionZoom, Tree, Upload, UploadPicker, VcError, VcInstance };
19290
+ export { ActionSheet, Alert, Artboard, Button, ButtonGroup, Calendar, Card, Carousel, Cascader, Chart, Checkbox, CheckboxGroup, Clipboard, Collapse, CollapseItem, ColorPicker, Countdown, Customer, DatePicker, Debounce, Divider, Drawer, DrawerView, Dropdown, Editor, Expand$1 as Expand, Form, FormItem, Fragment, HTMLToImage, Icon, IconManager, Image$1 as Image, ImageCrop, ImagePreview, ImageProcessing, Input, InputNumber, InputSearch, MList as List, MListItem as ListItem, MActionSheet, MAlert, MArtboard, MButton, MButtonGroup, MCalendar, MCard, MCarousel, MCascader, MChart, MCheckbox, MCheckboxGroup, MClipboard, MCollapse, MCollapseItem, MColorPicker, MCountdown, MCustomer, MDatePicker, Debounce as MDebounce, MDivider, MDrawer, MDrawerView, MDropdown, MEditor, MExpand, MForm, MFormItem, MFragment, MHTMLToImage, MIcon, MImage, MImageCrop, MImagePreview, MImageProcessing, MInput, MInputNumber, MInputSearch, MList, MListItem, MMarquee, MMessage, modal as MModal, MModalView, MNotice, MOption, MPagination, MPicker, MPopconfirm, MPopover, MPopup, MPortal, MPrint, MProgress, MRadio, MRadioGroup, MRate, MRecycleList, MResizer, MScroller, MSelect, MSlider, MSortList, MSpin, MSteps, MSwitch, MTable, MTableColumn, MTabs, MTabsPane, MTag, MText, MTextarea, MTimePicker, MTimeline, MToast, MToastView, MTouch, MTransition, MTransitionCollapse, MTransitionFade, MTransitionScale, MTransitionSlide, MTransitionZoom, MTree, MUpload, MUploadPicker, Marquee, Message, MessageView, Modal, ModalView, Notice, NoticeView, Option$1 as Option, Pagination, Picker, Popconfirm, Popover, Popup, Portal, PortalView, Print, Progress, Radio, RadioGroup, Rate, RecycleList, Resizer, Scroller, ScrollerWheel, Select, Slider, SortList, Spin, Steps, Switch, Table, TableColumn, Tabs, TabsPane, Tag, Text, Textarea, Theme, ThemeImage, ThemeText, ThemeView, TimePicker, Timeline, Toast, ToastView, Touch, Transition, TransitionCollapse, TransitionFade, TransitionScale, TransitionSlide, TransitionZoom, Tree, Upload, UploadPicker, VcError, VcInstance };