| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- <script lang="ts" setup>
- import { useUserStore } from '@/stores/user'
- import { ACCESS_TOKEN } from '@/utils/constants'
- import { ElMessage } from 'element-plus'
- import { isAbsolutePath, ossUpload } from '@/utils/utils'
- import config from '@/config/defaultSetting'
- import type { UploadProps, UploadFile } from 'element-plus'
- import type { BasicFormItem } from '@/types/form'
- interface Props {
- item: BasicFormItem
- modelValue: any
- size?: number | string
- iconSize?: number | string
- fileSize?: number | string
- uploadApi?: string
- oss?: boolean
- limit?: number
- }
- const props = withDefaults(defineProps<Props>(), {
- size: '148px',
- iconSize: '28px',
- uploadApi: config.uploadApi,
- fileSize: 10,
- oss: config.oss,
- limit: 1
- })
- const emits = defineEmits(['update:modelValue'])
- const baseApi = import.meta.env.VITE_BASE_API
- const modelValue = computed({
- get: () => props.modelValue,
- set: value => emits('update:modelValue', value)
- })
- const user = useUserStore()
- const headers = reactive({
- [ACCESS_TOKEN]: user.token
- })
- const limit = Number(props.limit) || 1
- // 生成图片地址
- const prefix = props.oss ? config.ossHost : baseApi
- const genImageUrl = (url: string) => {
- if (url.startsWith('blob:') || isAbsolutePath(url)) {
- return url
- } else {
- return prefix + url
- }
- }
- const uploadRef = ref()
- // 在上传之前对文件进行验证
- const fileSize = Number(props.fileSize) || 10
- const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
- if (rawFile.size / 1024 / 1024 > fileSize) {
- ElMessage.error(`图片大小不能超过${fileSize}MB!`)
- return false
- }
- return true
- }
- // 图片上传成功
- const uploadList = ref([...props.modelValue])
- const handleUploadSuccess: UploadProps['onSuccess'] = (response, uploadFile: UploadFile, uploadFiles: UploadFile[]) => {
- if (response.success || response.code === 200) {
- // 附加oss路径
- uploadList.value = uploadFiles
- } else {
- ElMessage.error(response.msg)
- }
- }
- // 删除图片
- const handleRemove = (file: UploadFile) => {
- uploadRef.value.handleRemove(file)
- uploadList.value = modelValue.value
- }
- // 图片预览
- const showViewer = ref(false)
- const previewIndex = ref(0)
- const previewList = computed(() => modelValue.value.map((item: any) => genImageUrl(item.url)))
- const handlePreview = (file: UploadFile) => {
- previewIndex.value = modelValue.value.findIndex((item: any) => item.url === file.url)
- showViewer.value = true
- }
- const closeViewer = () => {
- showViewer.value = false
- }
- // 接口需要的属性
- props.item.extra = computed(() => uploadList.value.map((item: any) => item.response?.url || item.url))
- // 动态属性
- const attrs: any = props.oss ? { 'http-request': ossUpload } : {}
- if (!props.item.props?.onSuccess) {
- attrs['on-success'] = handleUploadSuccess
- }
- </script>
- <template>
- <el-upload
- ref="uploadRef"
- v-model:file-list="modelValue"
- :class="{ 'is-disabled': modelValue.length >= limit }"
- :action="isAbsolutePath(props.uploadApi) ? props.uploadApi : baseApi + props.uploadApi"
- :headers="headers"
- :before-upload="beforeUpload"
- :limit="limit"
- list-type="picture-card"
- accept="image/*"
- v-bind="{ ...attrs, ...$attrs }"
- >
- <el-icon class="avatar-uploader-icon" :style="{ fontSize: iconSize }"><Plus /></el-icon>
- <template #file="{ file }">
- <el-image class="el-upload-list__item-thumbnail" :src="genImageUrl(file.url)" fit="cover" />
- <span class="el-upload-list__item-actions">
- <span class="el-upload-list__item-preview" @click="handlePreview(file)">
- <el-icon><zoom-in /></el-icon>
- </span>
- <span class="el-upload-list__item-delete" @click="handleRemove(file)">
- <el-icon><Delete /></el-icon>
- </span>
- </span>
- </template>
- </el-upload>
- <el-image-viewer v-if="showViewer" :url-list="previewList" :initial-index="previewIndex" @close="closeViewer" />
- </template>
- <style lang="scss" scoped>
- :deep(.el-upload) {
- width: v-bind(size);
- height: v-bind(size);
- border: 1px dashed var(--el-border-color);
- border-radius: 6px;
- cursor: pointer;
- position: relative;
- overflow: hidden;
- transition: var(--el-transition-duration-fast);
- &:hover {
- border-color: var(--el-color-primary);
- }
- }
- :deep(.el-upload-list--picture-card .el-upload-list__item) {
- width: v-bind(size);
- height: v-bind(size);
- }
- .is-disabled :deep(.el-upload--picture-card) {
- display: none;
- }
- </style>
|