Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
243 lines
5.8 KiB
Vue
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>
|