95 lines
2.8 KiB
Vue
95 lines
2.8 KiB
Vue
|
<template>
|
||
|
<div class="simpleUploadDiv">
|
||
|
<a-progress v-if="uploading" type="circle" :percent="percent" />
|
||
|
<a-image height="80%" v-else :src="minioBaseUrl + modelValue" alt="avatar" />
|
||
|
<a-button class="btn-success" @click="selectFile">{{ btnLabel }}</a-button>
|
||
|
<input id="myFileInput" type="file" style="display: none" />
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<script setup lang="ts">
|
||
|
import { message } from 'ant-design-vue'
|
||
|
import { onMounted, onUnmounted, ref } from 'vue'
|
||
|
import { generateSimpleObjectName, getResignedObjectUrl } from '@/utils/minioUtil'
|
||
|
import axios, { CancelTokenSource } from 'axios'
|
||
|
import { convertFileSizeToStr } from '@/utils/index.ts'
|
||
|
|
||
|
const minioBaseUrl = __APP_ENV.VITE_APP_MINIO_URL
|
||
|
|
||
|
const modelValue = defineModel<string>('value')
|
||
|
const props = withDefaults(
|
||
|
defineProps<{
|
||
|
parentDir?: string
|
||
|
allowedExtensions?: string[]
|
||
|
maxSize?: number
|
||
|
width?: string | number
|
||
|
height?: string | number
|
||
|
btnLabel?: string
|
||
|
}>(),
|
||
|
{
|
||
|
parentDir: '',
|
||
|
allowedExtensions: () => ['jpg', 'jpeg', 'png', 'gif'],
|
||
|
maxSize: 1024 * 1024 * 4,
|
||
|
width: '150px',
|
||
|
height: '150px',
|
||
|
btnLabel: '选择图片',
|
||
|
}
|
||
|
)
|
||
|
|
||
|
const uploading = ref(false)
|
||
|
const percent = ref(0)
|
||
|
let cancelToken: CancelTokenSource | null = null
|
||
|
|
||
|
const selectFile = () => {
|
||
|
document.getElementById('myFileInput')?.click()
|
||
|
}
|
||
|
|
||
|
async function inputFileListener(this: HTMLInputElement) {
|
||
|
const selectedFile: File = this.files?.[0] as File
|
||
|
|
||
|
const fileExtension = selectedFile?.name?.split('.')?.pop()?.toLowerCase() as string
|
||
|
if (!props.allowedExtensions.includes(fileExtension)) {
|
||
|
return message.error(`错误:不支持的文件格式,目前支持:【${props.allowedExtensions}】`)
|
||
|
}
|
||
|
|
||
|
const isMax = selectedFile.size > props.maxSize
|
||
|
if (isMax) {
|
||
|
return message.error(`文件大小超出限制,最大支持:【${convertFileSizeToStr(props.maxSize)}】`)
|
||
|
}
|
||
|
|
||
|
cancelToken?.cancel()
|
||
|
percent.value = 0
|
||
|
uploading.value = true
|
||
|
|
||
|
const objectName = generateSimpleObjectName(selectedFile.name, props.parentDir)
|
||
|
const uploadUrl = await getResignedObjectUrl(__APP_ENV.VITE_APP_MINIO_BUCKET, objectName)
|
||
|
cancelToken = axios.CancelToken.source()
|
||
|
await axios.put(uploadUrl, selectedFile, {
|
||
|
cancelToken: cancelToken.token,
|
||
|
onUploadProgress: (progressEvent) => {
|
||
|
percent.value = ((progressEvent.loaded / (progressEvent.total as number)) * 100) | 0
|
||
|
},
|
||
|
})
|
||
|
|
||
|
modelValue.value = '/' + __APP_ENV.VITE_APP_MINIO_BUCKET + objectName
|
||
|
uploading.value = false
|
||
|
}
|
||
|
|
||
|
onMounted(() => {
|
||
|
document.getElementById('myFileInput')?.addEventListener('change', inputFileListener)
|
||
|
})
|
||
|
|
||
|
onUnmounted(() => {
|
||
|
document.getElementById('myFileInput')?.removeEventListener('change', inputFileListener)
|
||
|
})
|
||
|
</script>
|
||
|
|
||
|
<style scoped lang="scss">
|
||
|
.simpleUploadDiv {
|
||
|
width: v-bind(width);
|
||
|
height: v-bind(height);
|
||
|
display: flex;
|
||
|
flex-direction: column;
|
||
|
}
|
||
|
</style>
|