Ben Lin
2024-06-18 ebbd788fbb2c0b45d4473798efc57eec8ba74a25
src/components/Cropper/src/CropperAvatar.vue
@@ -1,6 +1,6 @@
<template>
  <div :class="getClass" :style="getStyle">
    <div :class="`${prefixCls}-image-wrapper`" :style="getImageWrapperStyle" @click="openModal">
    <div :class="`${prefixCls}-image-wrapper`" :style="getImageWrapperStyle" @click="openModal()">
      <div :class="`${prefixCls}-image-mask`" :style="getImageWrapperStyle">
        <Icon
          icon="ant-design:cloud-upload-outlined"
@@ -20,99 +20,78 @@
      {{ btnText ? btnText : t('component.cropper.selectImage') }}
    </a-button>
    <CopperModal
    <CropperModal
      @register="register"
      @upload-success="handleUploadSuccess"
      :uploadApi="uploadApi"
      :src="sourceValue"
      :size="size"
    />
  </div>
</template>
<script lang="ts">
  import {
    defineComponent,
    computed,
    CSSProperties,
    unref,
    ref,
    watchEffect,
    watch,
    PropType,
  } from 'vue';
  import CopperModal from './CopperModal.vue';
  import { useDesign } from '/@/hooks/web/useDesign';
  import { useModal } from '/@/components/Modal';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { useI18n } from '/@/hooks/web/useI18n';
  import type { ButtonProps } from '/@/components/Button';
<script lang="ts" setup>
  import { computed, CSSProperties, unref, ref, watchEffect, watch, PropType } from 'vue';
  import CropperModal from './CropperModal.vue';
  import { useDesign } from '@/hooks/web/useDesign';
  import { useModal } from '@/components/Modal';
  import { useMessage } from '@/hooks/web/useMessage';
  import { useI18n } from '@/hooks/web/useI18n';
  import type { ButtonProps } from '@/components/Button';
  import Icon from '@/components/Icon/Icon.vue';
  const props = {
  defineOptions({ name: 'CropperAvatar' });
  const props = defineProps({
    width: { type: [String, Number], default: '200px' },
    value: { type: String },
    showBtn: { type: Boolean, default: true },
    btnProps: { type: Object as PropType<ButtonProps> },
    btnText: { type: String, default: '' },
    uploadApi: { type: Function as PropType<({ file: Blob, name: string }) => Promise<void>> },
  };
  export default defineComponent({
    name: 'CropperAvatar',
    components: { CopperModal, Icon },
    props,
    emits: ['update:value', 'change'],
    setup(props, { emit, expose }) {
      const sourceValue = ref(props.value || '');
      const { prefixCls } = useDesign('cropper-avatar');
      const [register, { openModal, closeModal }] = useModal();
      const { createMessage } = useMessage();
      const { t } = useI18n();
      const getClass = computed(() => [prefixCls]);
      const getWidth = computed(() => `${props.width}`.replace(/px/, '') + 'px');
      const getIconWidth = computed(() => parseInt(`${props.width}`.replace(/px/, '')) / 2 + 'px');
      const getStyle = computed((): CSSProperties => ({ width: unref(getWidth) }));
      const getImageWrapperStyle = computed(
        (): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) }),
      );
      watchEffect(() => {
        sourceValue.value = props.value || '';
      });
      watch(
        () => sourceValue.value,
        (v: string) => {
          emit('update:value', v);
        },
      );
      function handleUploadSuccess({ source, data }) {
        sourceValue.value = source;
        emit('change', { source, data });
        createMessage.success(t('component.cropper.uploadSuccess'));
      }
      expose({ openModal: openModal.bind(null, true), closeModal });
      return {
        t,
        prefixCls,
        register,
        openModal: openModal as any,
        getIconWidth,
        sourceValue,
        getClass,
        getImageWrapperStyle,
        getStyle,
        handleUploadSuccess,
      };
    uploadApi: {
      type: Function as PropType<({ file, name }: { file: Blob; name: string }) => Promise<void>>,
    },
    size: { type: Number, default: 5 },
  });
  const emit = defineEmits(['update:value', 'change']);
  const sourceValue = ref(props.value || '');
  const { prefixCls } = useDesign('cropper-avatar');
  const [register, { openModal, closeModal }] = useModal();
  const { createMessage } = useMessage();
  const { t } = useI18n();
  const getClass = computed(() => [prefixCls]);
  const getWidth = computed(() => `${props.width}`.replace(/px/, '') + 'px');
  const getIconWidth = computed(() => parseInt(`${props.width}`.replace(/px/, '')) / 2 + 'px');
  const getStyle = computed((): CSSProperties => ({ width: unref(getWidth) }));
  const getImageWrapperStyle = computed(
    (): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) }),
  );
  watchEffect(() => {
    sourceValue.value = props.value || '';
  });
  watch(
    () => sourceValue.value,
    (v: string) => {
      emit('update:value', v);
    },
  );
  function handleUploadSuccess({ source, data }) {
    sourceValue.value = source;
    emit('change', { source, data });
    createMessage.success(t('component.cropper.uploadSuccess'));
  }
  defineExpose({ openModal: openModal.bind(null, true), closeModal });
</script>
<style lang="less" scoped>