@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.cjs CHANGED
@@ -12,6 +12,7 @@ const vcHooks = require('@deot/vc-hooks');
12
12
  const helperWheel = require('@deot/helper-wheel');
13
13
  const helperValidator = require('@deot/helper-validator');
14
14
  const helperCache = require('@deot/helper-cache');
15
+ const PhotoSwipeLightbox = require('photoswipe/lightbox');
15
16
  const Load = require('@deot/helper-load');
16
17
  const helperScheduler = require('@deot/helper-scheduler');
17
18
  const lodash = require('lodash');
@@ -1087,7 +1088,7 @@ const Button = /* @__PURE__ */ vue.defineComponent({
1087
1088
  slots
1088
1089
  }) {
1089
1090
  const vm = vue.getCurrentInstance();
1090
- const hasSlot = vue.ref(true);
1091
+ const isHover = vue.ref(false);
1091
1092
  const isLoading = vue.ref(false);
1092
1093
  const group = vue.inject('vc-button-group', {
1093
1094
  size: 'medium',
@@ -1096,10 +1097,11 @@ const Button = /* @__PURE__ */ vue.defineComponent({
1096
1097
  });
1097
1098
  const classes = vue.computed(() => ({
1098
1099
  'is-circle': props.circle || group.circle,
1099
- 'is-alone': !hasSlot.value,
1100
+ 'is-alone': !slots?.default,
1100
1101
  'is-round': props.round,
1101
1102
  'is-long': props.long,
1102
1103
  'is-disabled': props.disabled,
1104
+ 'is-hover': isHover.value,
1103
1105
  [`is-${props.size}`]: true,
1104
1106
  [`is-${props.type}`]: true
1105
1107
  }));
@@ -1112,9 +1114,6 @@ const Button = /* @__PURE__ */ vue.defineComponent({
1112
1114
  });
1113
1115
  }
1114
1116
  };
1115
- vue.onMounted(() => {
1116
- hasSlot.value = slots.default !== undefined;
1117
- });
1118
1117
  return () => {
1119
1118
  return vue.createVNode(Debounce, {
1120
1119
  "tag": props.tag,
@@ -1125,15 +1124,19 @@ const Button = /* @__PURE__ */ vue.defineComponent({
1125
1124
  "wait": props.wait,
1126
1125
  "disabled": props.disabled,
1127
1126
  "type": props.htmlType,
1128
- "onClick": handleClick
1127
+ "onClick": handleClick,
1128
+ "onMouseenter": () => isHover.value = true,
1129
+ "onMouseleave": () => isHover.value = false
1129
1130
  }, {
1130
1131
  default: () => [props.icon && vue.createVNode(Icon, {
1131
1132
  "type": props.icon
1132
- }, null), isLoading.value && vue.createVNode(Spin, {
1133
+ }, null), slots.icon && slots?.icon?.({
1134
+ hover: isHover.value
1135
+ }), isLoading.value && vue.createVNode(Spin, {
1133
1136
  "size": 12,
1134
1137
  "foreground": props.type === 'default' ? '#ccc' : '#fff',
1135
1138
  "class": "vc-button__loading"
1136
- }, null), hasSlot.value && vue.createVNode("span", null, [slots?.default?.()])]
1139
+ }, null), slots?.default && vue.createVNode("span", null, [slots?.default?.()])]
1137
1140
  });
1138
1141
  };
1139
1142
  }
@@ -1549,7 +1552,8 @@ const useCheckbox = () => {
1549
1552
  "is-indeterminate": props.indeterminate,
1550
1553
  "is-checked": checked.value,
1551
1554
  "is-disabled": props.disabled,
1552
- "is-focus": isFocus.value
1555
+ "is-focus": isFocus.value,
1556
+ "is-error": !!formItem?.message?.value
1553
1557
  };
1554
1558
  });
1555
1559
  vue.watch(
@@ -3200,7 +3204,8 @@ const useInput = (input) => {
3200
3204
  const classes = vue.computed(() => {
3201
3205
  return {
3202
3206
  "is-focus": isFocus.value,
3203
- "is-disabled": props.disabled
3207
+ "is-disabled": props.disabled,
3208
+ "is-error": !!formItem?.message?.value
3204
3209
  };
3205
3210
  });
3206
3211
  const currentMaxlength = vue.computed(() => {
@@ -8721,7 +8726,7 @@ const Drawer$ = new Portal(DrawerView, {
8721
8726
  multiple: true
8722
8727
  });
8723
8728
  const destroy$3 = () => Drawer$.destroy();
8724
- const open$1 = (options) => {
8729
+ const open$2 = (options) => {
8725
8730
  const leaf = Drawer$.popup({
8726
8731
  ...options,
8727
8732
  onFulfilled: options.onClose,
@@ -8731,7 +8736,7 @@ const open$1 = (options) => {
8731
8736
  leaf.wrapper.toggle?.(true);
8732
8737
  return leaf;
8733
8738
  };
8734
- const Drawer = Object.assign(DrawerView, { open: open$1, destroy: destroy$3 });
8739
+ const Drawer = Object.assign(DrawerView, { open: open$2, destroy: destroy$3 });
8735
8740
 
8736
8741
  const MDrawer = Drawer;
8737
8742
  const MDrawerView = DrawerView;
@@ -8830,7 +8835,7 @@ const useForm = (expose, options = {}) => {
8830
8835
  const instance = vue.getCurrentInstance();
8831
8836
  const props = instance.props;
8832
8837
  const fields = [];
8833
- vue.provide("form", {
8838
+ vue.provide("vc-form", {
8834
8839
  props,
8835
8840
  add: (field) => {
8836
8841
  field && fields.push(field);
@@ -8978,8 +8983,7 @@ const props$L = {
8978
8983
  default: false
8979
8984
  },
8980
8985
  labelPosition: {
8981
- type: String,
8982
- default: "right"
8986
+ type: String
8983
8987
  },
8984
8988
  contentStyle: [Object, String],
8985
8989
  contentClass: [Object, String],
@@ -8997,7 +9001,7 @@ const toRules = (rules) => {
8997
9001
  return rules instanceof Array ? rules : rules ? [rules] : [];
8998
9002
  };
8999
9003
  const useFormItem = (expose) => {
9000
- const form = vue.inject("form");
9004
+ const form = vue.inject("vc-form");
9001
9005
  const instance = vue.getCurrentInstance();
9002
9006
  const props = instance.props;
9003
9007
  const { slots } = instance;
@@ -9510,7 +9514,7 @@ const ObjectFit = {
9510
9514
  FILL: 'fill',
9511
9515
  SCALE_DOWN: 'scale-down'
9512
9516
  };
9513
- const Image = /* @__PURE__ */ vue.defineComponent({
9517
+ const Image$1 = /* @__PURE__ */ vue.defineComponent({
9514
9518
  name: COMPONENT_NAME$W,
9515
9519
  inheritAttrs: false,
9516
9520
  props: props$H,
@@ -9705,7 +9709,7 @@ const Image = /* @__PURE__ */ vue.defineComponent({
9705
9709
  }
9706
9710
  });
9707
9711
 
9708
- const MImage = Image;
9712
+ const MImage = Image$1;
9709
9713
 
9710
9714
  const props$G = {
9711
9715
  tag: {
@@ -9743,7 +9747,7 @@ const props$F = {
9743
9747
  /** @jsxImportSource vue */
9744
9748
 
9745
9749
  const COMPONENT_NAME$U = 'vc-image-preview';
9746
- const ImagePreview = /* @__PURE__ */ vue.defineComponent({
9750
+ const ImagePreview$1 = /* @__PURE__ */ vue.defineComponent({
9747
9751
  name: COMPONENT_NAME$U,
9748
9752
  props: props$F,
9749
9753
  setup(props, {
@@ -9757,6 +9761,81 @@ const ImagePreview = /* @__PURE__ */ vue.defineComponent({
9757
9761
  }
9758
9762
  });
9759
9763
 
9764
+ const MAX_WIDTH = window.innerWidth;
9765
+ const MAX_HEIGHT = window.innerHeight;
9766
+ const getFitSize = (src) => {
9767
+ return new Promise((resolve) => {
9768
+ const img = new Image();
9769
+ let width;
9770
+ let height;
9771
+ img.onload = () => {
9772
+ const owidth = img.naturalWidth || img.width;
9773
+ const oheight = img.naturalHeight || img.height;
9774
+ if (owidth > oheight) {
9775
+ width = Math.min(MAX_WIDTH, owidth);
9776
+ height = width / owidth * oheight;
9777
+ resolve({
9778
+ width,
9779
+ height
9780
+ });
9781
+ } else {
9782
+ height = Math.min(MAX_HEIGHT, oheight);
9783
+ width = height / oheight * owidth;
9784
+ resolve({
9785
+ width,
9786
+ height
9787
+ });
9788
+ }
9789
+ };
9790
+ img.onerror = () => resolve({});
9791
+ img.src = src;
9792
+ });
9793
+ };
9794
+ const open$1 = async (options) => {
9795
+ const e = VcInstance.globalEvent;
9796
+ const data = options.data.map((i) => {
9797
+ if (typeof i === "string") {
9798
+ return {
9799
+ src: i
9800
+ };
9801
+ }
9802
+ return {
9803
+ ...i,
9804
+ src: i.source || i.src
9805
+ };
9806
+ });
9807
+ for (let i = 0; i < data.length; i++) {
9808
+ if (!data[i].width) {
9809
+ data[i] = {
9810
+ ...data[i],
9811
+ ...await getFitSize(data[i].src)
9812
+ };
9813
+ }
9814
+ }
9815
+ const lightbox = new PhotoSwipeLightbox({
9816
+ pswpModule: () => import('photoswipe'),
9817
+ closeTitle: "关闭(Esc)",
9818
+ zoomTitle: "缩放",
9819
+ arrowPrevTitle: "上一张",
9820
+ arrowNextTitle: "下一张",
9821
+ errorMsg: "网络异常 图片加载失败",
9822
+ indexIndicatorSep: " / ",
9823
+ initialZoomLevel: "fit"
9824
+ });
9825
+ lightbox.init();
9826
+ lightbox.loadAndOpen(
9827
+ options.current || 0,
9828
+ data,
9829
+ // 下面无效,需要给官方支持
9830
+ {
9831
+ x: e?.clientX,
9832
+ y: e?.clientY
9833
+ }
9834
+ );
9835
+ };
9836
+
9837
+ const ImagePreview = Object.assign(ImagePreview$1, { open: open$1 });
9838
+
9760
9839
  const MImagePreview = ImagePreview;
9761
9840
 
9762
9841
  const props$E = {
@@ -10363,9 +10442,8 @@ const props$z = {
10363
10442
  type: [String, Boolean],
10364
10443
  default: "取消"
10365
10444
  },
10366
- wrapperStyle: {
10367
- type: [String, Object]
10368
- },
10445
+ wrapperStyle: [String, Object],
10446
+ wrapperClass: [String, Object],
10369
10447
  footer: {
10370
10448
  type: Boolean,
10371
10449
  default: true
@@ -10419,6 +10497,7 @@ const ModalView = /* @__PURE__ */ vue.defineComponent({
10419
10497
 
10420
10498
  // 注: 服务端渲染为0, 在客服端激活前,展示端存在问题【高度不定】
10421
10499
  const MAX_HEIGHT = vcShared.IS_SERVER ? 0 : window.innerHeight - 20;
10500
+ const MAX_WIDTH = vcShared.IS_SERVER ? 0 : window.innerWidth - 20;
10422
10501
  const defaultSize = vue.computed(() => {
10423
10502
  let width = 0;
10424
10503
  let height = 0;
@@ -10437,7 +10516,7 @@ const ModalView = /* @__PURE__ */ vue.defineComponent({
10437
10516
  break;
10438
10517
  }
10439
10518
  return {
10440
- width: props.width || width,
10519
+ width: Math.min(props.width || width, MAX_WIDTH),
10441
10520
  height: Math.min(props.height || height, MAX_HEIGHT)
10442
10521
  };
10443
10522
  });
@@ -10673,7 +10752,7 @@ const ModalView = /* @__PURE__ */ vue.defineComponent({
10673
10752
  "style": [props.wrapperStyle || {}, props.draggable ? {
10674
10753
  top: 0
10675
10754
  } : {}],
10676
- "class": "vc-modal__wrapper",
10755
+ "class": [props.wrapperClass, 'vc-modal__wrapper'],
10677
10756
  "onClick": e => handleClose(e, false)
10678
10757
  }, [vue.createVNode(TransitionScale, {
10679
10758
  "mode": "part",
@@ -12340,8 +12419,12 @@ const Progress = /* @__PURE__ */ vue.defineComponent({
12340
12419
  setup(props, {
12341
12420
  slots
12342
12421
  }) {
12422
+ const currentPercent = vue.computed(() => {
12423
+ const v = Number(props.percent);
12424
+ return v >= 100 ? 100 : v;
12425
+ });
12343
12426
  const currentStatus = vue.computed(() => {
12344
- if (Number(props.percent) >= 100) {
12427
+ if (currentPercent.value === 100) {
12345
12428
  return 'success';
12346
12429
  }
12347
12430
  return props.status;
@@ -12353,6 +12436,7 @@ const Progress = /* @__PURE__ */ vue.defineComponent({
12353
12436
  const binds = vue.computed(() => {
12354
12437
  return {
12355
12438
  ...props,
12439
+ percent: currentPercent.value,
12356
12440
  status: currentStatus.value,
12357
12441
  color: currentColor.value
12358
12442
  };
@@ -12430,7 +12514,8 @@ const useRadio = () => {
12430
12514
  return {
12431
12515
  "is-checked": checked.value,
12432
12516
  "is-disabled": isDisabled.value,
12433
- "is-focus": isFocus.value
12517
+ "is-focus": isFocus.value,
12518
+ "is-error": !!formItem?.message?.value
12434
12519
  };
12435
12520
  });
12436
12521
  vue.watch(
@@ -12614,8 +12699,7 @@ const RadioGroup = /* @__PURE__ */ vue.defineComponent({
12614
12699
  return () => {
12615
12700
  if (props.fragment) return slots.default?.();
12616
12701
  return vue.createVNode("div", {
12617
- "class": "vc-radio-group",
12618
- "style": classes.value,
12702
+ "class": [classes.value, 'vc-radio-group'],
12619
12703
  "name": props.name
12620
12704
  }, [slots?.default?.()]);
12621
12705
  };
@@ -16935,7 +17019,11 @@ const props$a = {
16935
17019
  closable: {
16936
17020
  type: Boolean,
16937
17021
  default: false
16938
- }
17022
+ },
17023
+ barStyle: [Object, String],
17024
+ contentStyle: [Object, String],
17025
+ barClass: [Object, String],
17026
+ contentClass: [Object, String]
16939
17027
  };
16940
17028
 
16941
17029
  const useTabs = (options = {}) => {
@@ -17188,10 +17276,10 @@ const Tabs = /* @__PURE__ */ vue.defineComponent({
17188
17276
  "class": "vc-tabs__extra"
17189
17277
  }, [slots.extra?.()]), vue.createVNode("div", {
17190
17278
  "ref": wrapper,
17191
- "style": {
17279
+ "style": [props.barStyle, {
17192
17280
  padding: tabs.scrollable.value ? '0 24px' : 0
17193
- },
17194
- "class": "vc-tabs__bar"
17281
+ }],
17282
+ "class": [props.barClass, 'vc-tabs__bar']
17195
17283
  }, [tabs.scrollable.value && vue.createVNode(Icon, {
17196
17284
  "class": "vc-tabs__icon is-left",
17197
17285
  "type": "left",
@@ -17231,8 +17319,8 @@ const Tabs = /* @__PURE__ */ vue.defineComponent({
17231
17319
  }, null)]);
17232
17320
  })])])]), vue.createVNode("div", {
17233
17321
  "ref": content,
17234
- "style": tabs.contentStyle.value,
17235
- "class": "vc-tabs__content"
17322
+ "style": [props.contentStyle, tabs.contentStyle.value],
17323
+ "class": [props.contentClass, 'vc-tabs__content']
17236
17324
  }, [slots.default?.()])]);
17237
17325
  };
17238
17326
  }
@@ -17847,7 +17935,8 @@ const useTextarea = (textarea, expose) => {
17847
17935
  const classes = vue.computed(() => {
17848
17936
  return {
17849
17937
  "is-focus": isFocus.value,
17850
- "is-disabled": props.disabled
17938
+ "is-disabled": props.disabled,
17939
+ "is-error": !!formItem?.message?.value
17851
17940
  };
17852
17941
  });
17853
17942
  const listeners = vue.computed(() => {
@@ -18765,10 +18854,342 @@ const Upload = vue.defineComponent({
18765
18854
  const MUpload = Upload;
18766
18855
 
18767
18856
  const props = {
18768
- tag: {
18769
- type: String,
18770
- default: "div"
18771
- }
18857
+ picker: {
18858
+ type: Array,
18859
+ default: () => ["image"]
18860
+ },
18861
+ sortable: {
18862
+ type: Boolean,
18863
+ default: false
18864
+ },
18865
+ mask: {
18866
+ type: Boolean,
18867
+ default: false
18868
+ },
18869
+ /**
18870
+ * vc-upload组件的属性
18871
+ */
18872
+ uploadOptions: {
18873
+ type: Object,
18874
+ default() {
18875
+ return {};
18876
+ }
18877
+ },
18878
+ /**
18879
+ * 数据源['xxx.jpg', ....]
18880
+ */
18881
+ modelValue: {
18882
+ type: [String, Array, Object],
18883
+ // { value: '', label: '' }
18884
+ default: () => []
18885
+ },
18886
+ // 数据字典
18887
+ keyValue: {
18888
+ type: Object,
18889
+ default: () => {
18890
+ return {
18891
+ label: "label",
18892
+ value: "value"
18893
+ };
18894
+ }
18895
+ },
18896
+ output: {
18897
+ type: [String, Function],
18898
+ default: "object",
18899
+ validator: (v) => /(string|object)/.test(v)
18900
+ },
18901
+ /**
18902
+ * 可上传的最大值,跟upload内的Max不同,有可能是对象类型,对应的Upload做限制
18903
+ */
18904
+ max: {
18905
+ type: [Number, Object],
18906
+ default: Number.MAX_SAFE_INTEGER
18907
+ },
18908
+ disabled: {
18909
+ type: Boolean,
18910
+ default: false
18911
+ },
18912
+ /**
18913
+ * 上传成功后对数据的格式化
18914
+ */
18915
+ formatter: Function,
18916
+ // TODO 下面两个重复了,需删除
18917
+ /**
18918
+ * 盒子className
18919
+ */
18920
+ boxClass: String,
18921
+ imagePreviewOptions: {
18922
+ type: Object,
18923
+ default: () => ({})
18924
+ },
18925
+ imageClass: String,
18926
+ videoClass: String,
18927
+ audioClass: String,
18928
+ fileClass: String,
18929
+ compressOptions: {
18930
+ type: Object,
18931
+ default: () => {
18932
+ return {
18933
+ compress: false,
18934
+ // 是否开启图片压缩
18935
+ width: 0,
18936
+ // 图片缩放最大宽度,为0默认源图片宽度
18937
+ height: 0,
18938
+ // 图片缩放最大高度,为0默认源图片高度
18939
+ filetype: "image/jpeg",
18940
+ // 文件类型
18941
+ encoderOptions: 0.92
18942
+ // 在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,使用默认值 0.92
18943
+ };
18944
+ }
18945
+ },
18946
+ showMessage: Boolean,
18947
+ gallery: Boolean
18948
+ };
18949
+
18950
+ const recognizer = (url) => {
18951
+ const reg = /\.(jpe?g|png|gif|bmp|webp|image|heic|mp4|mov|avi|mpg|mpeg|rmvb)/ig;
18952
+ const result = url.match(reg);
18953
+ return result && result.length ? /.(jpe?g|png|gif|bmp|webp|image|heic)/ig.test(result[result.length - 1]) ? "image" : "video" : "file";
18954
+ };
18955
+ const FILE_ACCEPT_MAP = {
18956
+ DOC_ACCEPTS: ".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document",
18957
+ EXCEL_ACCEPTS: ".csv,.xls,.xlsx,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
18958
+ PPT_ACCEPTS: ".ppt,.pptx,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation",
18959
+ PDF_ACCEPTS: ".pdf,application/pdf",
18960
+ TXT_ACCEPTS: "text/plain",
18961
+ HTML_ACCEPTS: "text/html"
18962
+ };
18963
+
18964
+ const {
18965
+ DOC_ACCEPTS,
18966
+ EXCEL_ACCEPTS,
18967
+ PPT_ACCEPTS,
18968
+ PDF_ACCEPTS,
18969
+ TXT_ACCEPTS,
18970
+ HTML_ACCEPTS
18971
+ } = FILE_ACCEPT_MAP;
18972
+ const usePicker = (expose) => {
18973
+ const instance = vue.getCurrentInstance();
18974
+ const props = instance.props;
18975
+ const { emit } = instance;
18976
+ const formItem = vue.inject("vc-form-item", {});
18977
+ const allowKeepString = vue.computed(() => {
18978
+ return typeof props.modelValue === "string";
18979
+ });
18980
+ const allowKeepObject = vue.computed(() => {
18981
+ const v = props.modelValue;
18982
+ return props.output === "object" && props.max === 1 && !Array.isArray(v) && typeof v === "object";
18983
+ });
18984
+ const currentValue = vue.ref({
18985
+ image: [],
18986
+ video: [],
18987
+ audio: [],
18988
+ file: []
18989
+ });
18990
+ const currentUploadOptions = vue.ref({
18991
+ image: {
18992
+ accept: "image/gif,image/jpeg,image/jpg,image/png",
18993
+ ...props.uploadOptions.image || {}
18994
+ },
18995
+ video: {
18996
+ accept: "video/*",
18997
+ ...props.uploadOptions.video || {}
18998
+ },
18999
+ audio: {
19000
+ accept: "audio/*",
19001
+ ...props.uploadOptions.audio || {}
19002
+ },
19003
+ file: {
19004
+ accept: `${DOC_ACCEPTS},${EXCEL_ACCEPTS},${PPT_ACCEPTS},${PDF_ACCEPTS},${TXT_ACCEPTS},${HTML_ACCEPTS}`,
19005
+ ...props.uploadOptions.file || {}
19006
+ }
19007
+ });
19008
+ const dynamicMax = vue.computed(() => {
19009
+ const image = currentValue.value.image || [];
19010
+ const video = currentValue.value.video || [];
19011
+ const audio = currentValue.value.audio || [];
19012
+ const file = currentValue.value.file || [];
19013
+ const imageCount = image.length || 0;
19014
+ const videoCount = video.length || 0;
19015
+ const audioCount = audio.length || 0;
19016
+ const fileCount = file.length || 0;
19017
+ if (typeof props.max === "number") {
19018
+ const curNum = imageCount + videoCount + audioCount + fileCount;
19019
+ const leftNum = props.max - curNum;
19020
+ return {
19021
+ image: leftNum,
19022
+ video: leftNum,
19023
+ audio: leftNum,
19024
+ file: leftNum
19025
+ };
19026
+ } else if (typeof props.max === "object") {
19027
+ const {
19028
+ image: $image,
19029
+ video: $video,
19030
+ audio: $audio,
19031
+ file: $file
19032
+ } = props.max;
19033
+ const max = {};
19034
+ $image && (max.image = $image - imageCount);
19035
+ $video && (max.video = $video - videoCount);
19036
+ $audio && (max.audio = $audio - audioCount);
19037
+ $file && (max.file = $file - fileCount);
19038
+ return max;
19039
+ }
19040
+ return {};
19041
+ });
19042
+ const sync = () => {
19043
+ let v = props.picker.reduce((pre, cur) => pre.concat(currentValue.value[cur] || []), []).filter((i) => !i.errorFlag).map((i) => {
19044
+ if (props.output === "string") return i[props.keyValue.value];
19045
+ if (typeof props.output === "function") return props.output(i) || i;
19046
+ return i;
19047
+ });
19048
+ if (allowKeepString.value) {
19049
+ v = v.map((i) => i[props.keyValue.value] || i).join(",");
19050
+ } else if (allowKeepObject.value) {
19051
+ v = v[0] || null;
19052
+ }
19053
+ emit("update:modelValue", v);
19054
+ emit("change", v);
19055
+ formItem.change?.(v);
19056
+ };
19057
+ const handleFileBefore = async (vFile, fileList, type) => {
19058
+ if (props?.compressOptions?.compress && type === "image") ;
19059
+ const onFileBefore = instance.vnode.props?.onFileBefore || (() => {
19060
+ });
19061
+ return await onFileBefore(vFile, fileList, type) || vFile;
19062
+ };
19063
+ const handleFileStart = (vFile, type) => {
19064
+ currentValue.value[type].push(vFile);
19065
+ emit("file-start", vFile, type);
19066
+ };
19067
+ const handleFileProgress = (e, vFile, type) => {
19068
+ if (parseInt(e.percent, 10) <= 100) {
19069
+ currentValue.value[type] = currentValue.value[type].map((item) => {
19070
+ if (vFile.uploadId === item.uploadId) {
19071
+ return {
19072
+ ...item,
19073
+ percent: e.percent
19074
+ };
19075
+ }
19076
+ return item;
19077
+ });
19078
+ }
19079
+ };
19080
+ const handleFileSuccess = (response, vFile, cycle, type) => {
19081
+ currentValue.value[type] = currentValue.value[type].map((item) => {
19082
+ if (item.uploadId === vFile.uploadId) {
19083
+ return {
19084
+ type,
19085
+ [props.keyValue.label]: vFile.name,
19086
+ // 外部需要满足response中带source
19087
+ [props.keyValue.value]: response.source
19088
+ };
19089
+ }
19090
+ return item;
19091
+ });
19092
+ emit("file-success", response, vFile, cycle, type);
19093
+ };
19094
+ const handleError = (err, type) => {
19095
+ props.showMessage && err.message && Message.error(err.message);
19096
+ emit("error", err, type);
19097
+ };
19098
+ const handleFileError = (response, vFile, cycle, type) => {
19099
+ currentValue.value[type] = currentValue.value[type].map((item) => {
19100
+ if (item.uploadId === vFile.uploadId) {
19101
+ return {
19102
+ ...item,
19103
+ ...response,
19104
+ // 文件基础信息
19105
+ type,
19106
+ [props.keyValue.label]: vFile.name,
19107
+ errorFlag: (/* @__PURE__ */ new Date()).getTime()
19108
+ };
19109
+ }
19110
+ return item;
19111
+ });
19112
+ emit("file-error", response, vFile, cycle, type);
19113
+ };
19114
+ const handleFileComplete = (response, type) => {
19115
+ sync();
19116
+ emit("complete", response, type);
19117
+ };
19118
+ const handleDelete = async (index, type) => {
19119
+ const onRemoveBefore = instance.vnode.props?.onRemoveBefore || (() => {
19120
+ });
19121
+ await onRemoveBefore(index, type);
19122
+ const target = currentValue.value[type];
19123
+ const item = target[index];
19124
+ if (!item) {
19125
+ console.error("【vc-upload-picker】: 没有找到要删除的元素");
19126
+ return;
19127
+ }
19128
+ if (item.errorFlag) {
19129
+ currentValue.value[type] = target.filter(
19130
+ (it) => it.uploadId != item.uploadId
19131
+ );
19132
+ return;
19133
+ }
19134
+ target.splice(index, 1);
19135
+ sync();
19136
+ };
19137
+ const parseModelValue = (v) => {
19138
+ const initialData = { image: [], video: [], audio: [], file: [] };
19139
+ if (allowKeepString.value) {
19140
+ v = (props.max === 1 ? [v] : v.split(",")).filter((i) => !!i);
19141
+ } else if (allowKeepObject.value) {
19142
+ v = [v].filter((i) => i && !!i[props.keyValue.value]);
19143
+ }
19144
+ if (!Array.isArray(v) || !v.length) return initialData;
19145
+ return v.reduce((pre, cur) => {
19146
+ const value = cur[props.keyValue.value] || (typeof cur === "object" ? "" : cur);
19147
+ const label = cur[props.keyValue.label] || value.replace(/^.*\/([^/]+)$/, "$1");
19148
+ const type = cur.type || (props.picker.length === 1 ? props.picker[0] : recognizer(value));
19149
+ switch (type) {
19150
+ case "image":
19151
+ case "video":
19152
+ case "audio":
19153
+ case "file":
19154
+ pre[type].push({
19155
+ // 文件类型
19156
+ type,
19157
+ // 文件名
19158
+ [props.keyValue.label]: label,
19159
+ // 源文件地址
19160
+ [props.keyValue.value]: value,
19161
+ // 上传进度
19162
+ percent: null,
19163
+ // 错误标记
19164
+ errorFlag: false
19165
+ });
19166
+ return pre;
19167
+ default:
19168
+ return pre;
19169
+ }
19170
+ }, initialData);
19171
+ };
19172
+ vue.watch(
19173
+ () => props.modelValue,
19174
+ (v) => {
19175
+ currentValue.value = parseModelValue(v);
19176
+ },
19177
+ { immediate: true }
19178
+ );
19179
+ expose();
19180
+ return {
19181
+ currentValue,
19182
+ currentUploadOptions,
19183
+ dynamicMax,
19184
+ handleDelete,
19185
+ handleFileBefore,
19186
+ handleFileStart,
19187
+ handleFileProgress,
19188
+ handleFileSuccess,
19189
+ handleFileError,
19190
+ handleError,
19191
+ handleFileComplete
19192
+ };
18772
19193
  };
18773
19194
 
18774
19195
  /** @jsxImportSource vue */
@@ -18777,13 +19198,111 @@ const COMPONENT_NAME = 'vc-upload-picker';
18777
19198
  const UploadPicker = /* @__PURE__ */ vue.defineComponent({
18778
19199
  name: COMPONENT_NAME,
18779
19200
  props: props,
19201
+ emits: ['update:modelValue', 'file-success', 'file-start', 'success', 'error', 'complete', 'change', 'remove-before'],
18780
19202
  setup(props, {
18781
- slots
19203
+ slots,
19204
+ expose
18782
19205
  }) {
19206
+ const instance = vue.getCurrentInstance();
19207
+ const currentPicker = vue.computed(() => {
19208
+ return props.picker.reduce((pre, cur) => {
19209
+ switch (cur) {
19210
+ case 'image':
19211
+ pre.push({
19212
+ type: cur,
19213
+ item: 'div'
19214
+ // item: ImageItem
19215
+ });
19216
+ return pre;
19217
+ case 'video':
19218
+ pre.push({
19219
+ type: cur,
19220
+ item: 'div'
19221
+ // item: VideoItem
19222
+ });
19223
+ return pre;
19224
+ case 'audio':
19225
+ pre.push({
19226
+ type: cur,
19227
+ item: 'div'
19228
+ // item: AudioItem
19229
+ });
19230
+ return pre;
19231
+ case 'file':
19232
+ pre.push({
19233
+ type: cur,
19234
+ item: 'div'
19235
+ // item: FileItem
19236
+ });
19237
+ return pre;
19238
+ default:
19239
+ return pre;
19240
+ }
19241
+ }, []);
19242
+ });
19243
+ const handleClick = (e, type) => {
19244
+ const options = VcInstance.options.UploadPicker || {};
19245
+ if (typeof props.gallery === 'function' || props.gallery && options.gallery) {
19246
+ const fn = typeof props.gallery === 'function' ? props.gallery : options.gallery;
19247
+
19248
+ // 阻止原生事件,如video, file不走gallery, 可以跳过;
19249
+ fn(instance, type) && e.stopPropagation();
19250
+ }
19251
+ };
19252
+ const base = usePicker(expose);
18783
19253
  return () => {
18784
19254
  return vue.createVNode("div", {
18785
19255
  "class": "vc-upload-picker"
18786
- }, [slots?.default?.()]);
19256
+ }, [currentPicker.value.map((picker, $index) => {
19257
+ return vue.createVNode(vue.Fragment, {
19258
+ "key": `${picker}-${$index}`
19259
+ }, [base.currentValue.value[picker.type].map((item, index) => {
19260
+ const Item = picker.item;
19261
+ return vue.createVNode(Item, {
19262
+ "key": typeof item === 'object' ? item.uid : item,
19263
+ "it": item,
19264
+ "disabled": props.disabled,
19265
+ "image-preview-options": props.imagePreviewOptions,
19266
+ "imageClass": props.imageClass,
19267
+ "videoClass": props.videoClass,
19268
+ "audioClass": props.audioClass,
19269
+ "fileClass": props.fileClass,
19270
+ "index": index,
19271
+ "data": item,
19272
+ "class": "vc-upload-picker__item",
19273
+ "onDelete": () => base.handleDelete(index, picker.type)
19274
+ }, {
19275
+ default: scopeData => {
19276
+ return slots.default ? slots.default({
19277
+ it: scopeData?.it,
19278
+ current: scopeData?.current,
19279
+ index,
19280
+ name: picker.type
19281
+ }) : scopeData;
19282
+ }
19283
+ });
19284
+ }), vue.withDirectives(vue.createVNode(Upload, vue.mergeProps(base.currentUploadOptions.value[picker.type], {
19285
+ "max": base.dynamicMax[picker.type],
19286
+ "class": "vc-upload-picker__upload",
19287
+ "onFileBefore": (vFile, fileList) => base.handleFileBefore(vFile, fileList, picker.type),
19288
+ "onFileStart": vFile => base.handleFileStart(vFile, picker.type),
19289
+ "onFileProgress": (e, vFile) => base.handleFileProgress(e, vFile, picker.type),
19290
+ "onFileSuccess": (response, vFile, cycle) => base.handleFileSuccess(response, vFile, cycle, picker.type),
19291
+ "onFileError": (response, vFile, cycle) => base.handleFileError(response, vFile, cycle, picker.type),
19292
+ "onError": e => base.handleError(e, picker.type),
19293
+ "onComplete": response => base.handleFileComplete(response, picker.type)
19294
+ }), {
19295
+ default: () => [slots?.[`${picker.type}-upload`] ? slots[`${picker.type}-upload`]?.() : vue.createVNode("div", {
19296
+ "class": [props.boxClass, 'vc-upload-picker__box'],
19297
+ "onClick": e => handleClick(e, picker.type)
19298
+ }, [vue.createVNode(Icon, {
19299
+ "type": "mini-plus",
19300
+ "class": "vc-upload-picker__plus-icon"
19301
+ }, null), vue.createVNode("span", {
19302
+ "style": "margin-top: 8px"
19303
+ }, [vue.createTextVNode("\u4E0A\u4F20")])])]
19304
+ }), [[vue.vShow, !props.disabled && base.dynamicMax.value[picker.type] >= 1]])]);
19305
+ })]);
18787
19306
  };
18788
19307
  }
18789
19308
  });
@@ -18822,7 +19341,7 @@ exports.Fragment = Fragment;
18822
19341
  exports.HTMLToImage = HTMLToImage;
18823
19342
  exports.Icon = Icon;
18824
19343
  exports.IconManager = IconManager;
18825
- exports.Image = Image;
19344
+ exports.Image = Image$1;
18826
19345
  exports.ImageCrop = ImageCrop;
18827
19346
  exports.ImagePreview = ImagePreview;
18828
19347
  exports.ImageProcessing = ImageProcessing;