141 lines
3.6 KiB
Vue
141 lines
3.6 KiB
Vue
<template>
|
|
<div style="overflow: hidden">
|
|
<a-upload
|
|
class="relative fix-capture"
|
|
name="file"
|
|
:show-upload-list="false"
|
|
list-type="picture-card"
|
|
:action="url"
|
|
:headers="fileHeader"
|
|
accept="image/*"
|
|
:before-upload="beforeUpload"
|
|
:custom-request="customRequest"
|
|
@change="handelChange"
|
|
>
|
|
<div
|
|
@click="deleteAvatar"
|
|
style="position: absolute; bottom: 10px; left: 0; z-index: 10"
|
|
>
|
|
<BaseIcon icon="vuesax-linear:trash" class="text-red-600 cursor-pointer" />
|
|
</div>
|
|
<div class="relative" v-if="imageUrl">
|
|
<img
|
|
:src="imageUrl"
|
|
alt="avatar"
|
|
style="min-width: 104px; max-height: 104px; object-fit: cover; display: inline"
|
|
/>
|
|
</div>
|
|
<div v-if="!imageUrl" class="flex flex-col items-center">
|
|
<span>
|
|
<slot name="TitlePic">افزودن عکس</slot>
|
|
</span>
|
|
<div v-if="loading" class="flex gap-4 items-center mt-2">
|
|
<loading-outlined></loading-outlined>
|
|
<span>{{ percent }} %</span>
|
|
</div>
|
|
</div>
|
|
</a-upload>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { uploadURL } from '@root/config'
|
|
import { onMounted, ref, watch, computed } from 'vue'
|
|
import { LoadingOutlined } from '@ant-design/icons-vue'
|
|
import { message } from 'ant-design-vue'
|
|
import type { UploadProps } from 'ant-design-vue'
|
|
import { getToken } from '@/utils'
|
|
import { fixFileCapture } from '@/utils/fixFileCapture'
|
|
import {
|
|
createImageBeforeUpload,
|
|
createImageCustomRequest
|
|
} from '@/utils/prepareImageForUpload'
|
|
import { normalizeUploadFileResponse, toAbsoluteFileUrl } from '@/utils/file'
|
|
|
|
const loading = ref<boolean>(false)
|
|
const percent = ref<number>(0)
|
|
const url = ref<string | undefined>(`${uploadURL}`)
|
|
const fileHeader = computed(() => ({
|
|
Authorization: `Bearer ${getToken()}`
|
|
}))
|
|
|
|
interface Props {
|
|
imageUrl?: string
|
|
compressed?: boolean
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
compressed: false
|
|
})
|
|
const imageUrl = ref('')
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'remove'): void
|
|
(e: 'upload', file: any): void
|
|
(e: 'startUpload'): void
|
|
(e: 'errorUpload'): void
|
|
}>()
|
|
|
|
const beforeUpload: UploadProps['beforeUpload'] = createImageBeforeUpload((msg) =>
|
|
message.error(msg)
|
|
)
|
|
|
|
const customRequest: UploadProps['customRequest'] = createImageCustomRequest({
|
|
action: () => url.value || uploadURL,
|
|
getHeaders: () => fileHeader.value,
|
|
messageError: (msg) => message.error(msg),
|
|
onStarted: () => {
|
|
loading.value = true
|
|
percent.value = 0
|
|
emit('startUpload')
|
|
},
|
|
onUploaded: (body) => {
|
|
const fileResource = normalizeUploadFileResponse(body)
|
|
const record = body && typeof body === 'object' ? (body as Record<string, any>) : undefined
|
|
imageUrl.value =
|
|
fileResource?.full_src ||
|
|
toAbsoluteFileUrl(record?.full_src || record?.src) ||
|
|
''
|
|
loading.value = false
|
|
percent.value = 100
|
|
emit('upload', body)
|
|
message.success('فایل با موفقیت آپلود شد')
|
|
},
|
|
onFailed: () => {
|
|
loading.value = false
|
|
emit('errorUpload')
|
|
}
|
|
})
|
|
|
|
function handelChange({ file }) {
|
|
if (Object.hasOwn(file, 'percent') && file.percent != null) {
|
|
percent.value = Math.floor(file.percent)
|
|
}
|
|
fixFileCapture()
|
|
|
|
if (file.status === 'uploading') {
|
|
loading.value = true
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
fixFileCapture()
|
|
})
|
|
|
|
function deleteAvatar(e) {
|
|
imageUrl.value = null
|
|
emit('remove')
|
|
e.stopPropagation()
|
|
}
|
|
|
|
watch(
|
|
() => props.imageUrl,
|
|
() => {
|
|
imageUrl.value = props.imageUrl
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
</script>
|
|
|
|
<style></style>
|
|
|