Files
web_hgtv_admin/src/components/UploadImg/index.vue
T
rootandClaude Opus 5.5 fbc0302c24 Initial commit
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 16:54:42 +08:00

243 lines
5.8 KiB
Vue

<!--
* @Author: 王涛
* @Mail: no
* @Date: 2020-09-29 19:56:44
* @LastEditors: Administrator admin@example.com
* @LastEditTime: 2024-11-19 10:14:08
-->
<template>
<!-- 使用方法 <UploadImg @changeImgUrl='changeMobileAvatar' :img='form.mobileAvatar' :width='"100px"' :height='"100px"'></UploadImg>
changeMobileAvatar(data) {
this.form.mobileAvatar = data
}, -->
<el-upload
class="avatar-uploader"
:action="action"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:data="{ appId: $store.getters.appId }"
:before-upload="beforeAvatarUpload"
:disabled="displayOnly">
<div ref="uploader">
<img v-if="newImg" :src="newImg" class="avatar" />
<i v-if="imageUrl && !displayOnly" @click.stop="handleRemove" class="el-icon-delete"></i>
<i v-if="!newImg && !displayOnly" class="el-icon-plus avatar-uploader-icon"></i>
</div>
</el-upload>
</template>
<script>
import { handleVerAutoImg } from '@/utils/index.js'
export default {
data() {
return {
imageUrl: '',
newImg: ''
}
},
props: {
img: {
type: String,
default: ''
},
width: {
type: String,
default: '180px'
},
height: {
type: String,
default: '180px'
},
index: {
type: Number,
default: 0
},
showIndex: {
type: Boolean,
default: false
},
action: {
type: String,
default: '/media/web/upload/image'
},
domain: {
type: String,
default: ''
},
displayOnly: {
type: Boolean,
default: false
}
},
computed: {
currentDomain() {
return this.domain || this.$store.getters.getSystemConfig.imgWebCdn || ''
}
},
watch: {
img: function(val, oldval) {
this.imageUrl = val
},
imageUrl: async function(val, oldval) {
if (!val) {
this.newImg = ''
return
}
const a = await handleVerAutoImg(this.buildImageUrl(val))
this.newImg = a
}
},
mounted() {
this.$refs['uploader'].style.width = this.width
this.$refs['uploader'].style.height = this.height
this.$refs['uploader'].style.lineHeight = this.height
if (this.img) {
this.imageUrl = this.img
} else {
this.imageUrl = ''
}
},
methods: {
buildImageUrl(path) {
if (!path) return ''
if (/^(blob:|https?:\/\/|data:)/.test(path)) return path
const base = this.currentDomain || ''
if (!base) return path
const normalizedBase = base.endsWith('/') ? base.slice(0, -1) : base
const normalizedPath = path.startsWith('/') ? path : `/${path}`
return `${normalizedBase}${normalizedPath}`
},
async changeImg(url) {
},
handleAvatarSuccess(res, file) {
if (res.code === 200) {
this.$message({
type: 'success',
message: '上传成功!'
})
this.imageUrl = res.data.path
this.changeImgUrl()
} else {
this.$message({
type: 'error',
message: '上传失败!'
})
this.imageUrl = ''
}
},
changeImgUrl() {
if (this.showIndex) {
this.$emit('changeImgUrl', { url: this.imageUrl, index: this.index })
} else {
this.$emit('changeImgUrl', this.imageUrl)
}
},
handleRemove() {
this.imageUrl = ''
this.changeImgUrl()
if (this.showIndex) {
this.$emit('onRemove', { key: '', index: this.index })
} else {
this.$emit('onRemove')
}
},
// 上传前进行压缩
beforeAvatarUpload(file) {
const isJPG =
file.type === 'image/jpeg' ||
file.type === 'image/png' ||
file.type === 'image/gif' ||
file.type === 'image/webp'
// const isLt2M = file.size / 1024 / 1024 < 2
if (!isJPG) {
this.$message({
type: 'error',
message: '上传图片只能是 JPG 格式!!'
})
}
// if (!isLt2M) {
// this.$message({
// type: 'error',
// message: '上传图片大小不能超过 2MB!!'
// })
// }
return isJPG
},
// 图片等比压缩
handleCompressImage(file, type) {
return new Promise((resolve, reject) => {
try {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = (e) => {
const image = new Image()
image.src = e.target.result
image.onload = () => {
if (image.width > 720) {
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
const imageWidth = 720
const imageHeight = (720 / image.width) * image.height
canvas.width = imageWidth
canvas.height = imageHeight
context.drawImage(image, 0, 0, imageWidth, imageHeight)
canvas.toBlob(
(blob) => {
resolve(new Blob([blob], { type: type }))
},
'image/jpeg',
0.9
)
} else {
resolve(file)
}
}
}
} catch (e) {
reject(e)
}
})
}
}
}
</script>
<style scoped>
.avatar-uploader {
.el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.el-upload:hover {
border-color: #409eff;
}
}
.avatar-uploader-icon {
font-size: 28px;
color: #d9d9d9;
width: 100%;
height: 100%;
line-height: 100%;
text-align: center;
}
.avatar {
width: 100%;
height: 100%;
max-width: 100%;
max-height: 100%;
display: block;
object-fit: contain;
}
.el-icon-delete {
z-index: 9999999;
position: absolute;
bottom: 10px;
right: 10px;
color: red;
}
</style>