index.vue 1.92 KB
<template>
  <Upload :accept="accept" :custom-request="onUpload" :on-before-upload="onBeforeUpload" :file-list="[]" :show-file-list="false">
    <template #upload-button>
      <Avatar :shape="shape" :size="size" trigger-type="mask">
        <template #trigger-icon>
          <icon-camera />
        </template>
        <img v-if="modelValue" :src="modelValue" alt="avatar" style="width: 100%; height: 100%" />
        <div v-else class="no-avatar">
          <icon-plus />
        </div>
      </Avatar>
    </template>
  </Upload>
</template>

<script lang="ts" setup>
import { IconCamera, IconPlus } from '@arco-design/web-vue/es/icon';
import useOss from '@/hooks/oss';
import { Avatar, Message, Upload, UploadRequest, useFormItem } from '@arco-design/web-vue';

const props = withDefaults(
  defineProps<{
    modelValue: string;
    size: number;
    shape: 'circle' | 'square';
    accept: string;
    limit: number;
  }>(),
  {
    modelValue: '',
    size: 80,
    shape: 'circle',
    accept: 'image/*',
    limit: 5,
  }
);

const { eventHandlers } = useFormItem();

const emits = defineEmits(['update:modelValue']);

const { upload } = useOss();

const onBeforeUpload = (file: File) => {
  if (file.size > props.limit * 1024 * 1024) {
    Message.warning(`${file.name} 文件超过${props.limit}MB,无法上传`);
    return Promise.resolve(false);
  }

  return Promise.resolve(file);
};

const onUpload = (option: any): UploadRequest => {
  const { fileItem } = option;

  if (fileItem.file) {
    upload(fileItem.file, 'image').then((res) => {
      emits('update:modelValue', res.url);
      eventHandlers.value?.onChange?.();
    });
  }

  return {};
};
</script>

<style lang="less" scoped>
:deep(.arco-avatar-text) {
  width: 100%;
  height: 100%;
}

.no-avatar {
  position: absolute;
  display: flex;
  align-content: center;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
}
</style>