|
|
|
|
@ -1,37 +1,27 @@ |
|
|
|
|
<template> |
|
|
|
|
<abstract-dialog :loading="loading" title="上传头像" :value="value" width="50%" @close="cancel"> |
|
|
|
|
<div class="avatar-cropper"> |
|
|
|
|
<vue-cropper |
|
|
|
|
ref="cropper" |
|
|
|
|
:img="img" |
|
|
|
|
:info="false" |
|
|
|
|
autoCrop |
|
|
|
|
autoCropHeight="200px" |
|
|
|
|
autoCropWidth="200px" |
|
|
|
|
fixedBox |
|
|
|
|
full |
|
|
|
|
outputType="png" |
|
|
|
|
@wheel.native.prevent="scale" |
|
|
|
|
/> |
|
|
|
|
<abstract-dialog :loading="loading" title="上传头像" :value="value" width="50%" @close="clear"> |
|
|
|
|
<div class="avatar-cropper cropper-bg"> |
|
|
|
|
<div v-show="!img" class="avatar-cropper-bg cropper-bg" title="选择图片" @click="handleBgClick"/> |
|
|
|
|
|
|
|
|
|
<img :src="img"> |
|
|
|
|
|
|
|
|
|
<input |
|
|
|
|
ref="input" |
|
|
|
|
accept="image/png, image/jpeg, image/gif, image/jpg" |
|
|
|
|
type="file" |
|
|
|
|
@change="chooseImage" |
|
|
|
|
@change="onInputChange" |
|
|
|
|
> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<template v-slot:footer> |
|
|
|
|
<el-button plain size="small" @click="$refs.input.click()">选择图片</el-button> |
|
|
|
|
<el-button plain size="small" @click="chooseImage">选择图片</el-button> |
|
|
|
|
<el-button plain size="small" @click="closeDialog">取 消</el-button> |
|
|
|
|
<el-button size="small" type="primary" @click="confirm">确 定</el-button> |
|
|
|
|
<el-button :loading="loading" size="small" type="primary" @click="confirm">确 定</el-button> |
|
|
|
|
</template> |
|
|
|
|
</abstract-dialog> |
|
|
|
|
</template> |
|
|
|
|
|
|
|
|
|
<script> |
|
|
|
|
import {VueCropper} from 'vue-cropper' |
|
|
|
|
import AbstractDialog from '@/component/abstract/Dialog' |
|
|
|
|
import dialogMixin from "@/mixin/dialogMixin" |
|
|
|
|
import {elError, elSuccess} from "@/util/message" |
|
|
|
|
@ -43,7 +33,7 @@ export default { |
|
|
|
|
|
|
|
|
|
mixins: [dialogMixin], |
|
|
|
|
|
|
|
|
|
components: {VueCropper, AbstractDialog}, |
|
|
|
|
components: {AbstractDialog}, |
|
|
|
|
|
|
|
|
|
props: { |
|
|
|
|
value: Boolean |
|
|
|
|
@ -53,31 +43,35 @@ export default { |
|
|
|
|
return { |
|
|
|
|
loading: false, |
|
|
|
|
img: '', |
|
|
|
|
name: '' |
|
|
|
|
name: '', |
|
|
|
|
type: '' |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
methods: { |
|
|
|
|
//在未选择图片时点击背景,则弹出文件选择框 |
|
|
|
|
handleBgClick() { |
|
|
|
|
!this.img && this.chooseImage() |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
clear() { |
|
|
|
|
this.loading = false |
|
|
|
|
this.$refs.cropper.clearCrop() |
|
|
|
|
this.cropper && this.cropper.destroy() |
|
|
|
|
this.img && window.URL.revokeObjectURL(this.img) |
|
|
|
|
this.img = '' |
|
|
|
|
this.name = '' |
|
|
|
|
this.type = '' |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
scale(e) { |
|
|
|
|
const eventDelta = e.wheelDelta || -(e.detail || 0) * 40 |
|
|
|
|
this.$refs.cropper.changeScale(eventDelta / 120) |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
chooseImage(e) { |
|
|
|
|
onInputChange(e) { |
|
|
|
|
if (this.loading) return |
|
|
|
|
|
|
|
|
|
this.clear() |
|
|
|
|
|
|
|
|
|
const file = e.target.files[0] |
|
|
|
|
|
|
|
|
|
if (!file) return |
|
|
|
|
|
|
|
|
|
if (!file.type.includes('image')) { |
|
|
|
|
return elError('请上传图片') |
|
|
|
|
} |
|
|
|
|
@ -87,34 +81,71 @@ export default { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.name = file.name |
|
|
|
|
const reader = new FileReader() |
|
|
|
|
reader.onload = e => { |
|
|
|
|
this.img = window.URL.createObjectURL(new Blob([e.target.result])) |
|
|
|
|
this.type = file.type |
|
|
|
|
this.img = window.URL.createObjectURL(file) |
|
|
|
|
|
|
|
|
|
//使用nextTick原因是img的src此时还未赋值 |
|
|
|
|
this.$nextTick(() => { |
|
|
|
|
this.cropper = new window.Cropper( |
|
|
|
|
this.$el.querySelector('.avatar-cropper > img'), |
|
|
|
|
{ |
|
|
|
|
dragMode: 'move', |
|
|
|
|
initialAspectRatio: 1, |
|
|
|
|
aspectRatio: 1, |
|
|
|
|
checkCrossOrigin: false, |
|
|
|
|
checkOrientation: false, |
|
|
|
|
guides: false, |
|
|
|
|
center: false, |
|
|
|
|
rotatable: false, |
|
|
|
|
cropBoxResizable: false, |
|
|
|
|
toggleDragModeOnDblclick: false, |
|
|
|
|
|
|
|
|
|
//图片加载完成后将裁剪框的大小设置为200x200并居中 |
|
|
|
|
ready: () => { |
|
|
|
|
const size = 200 |
|
|
|
|
const container = this.$el.querySelector('.avatar-cropper') |
|
|
|
|
const top = (500 - size) / 2 |
|
|
|
|
const left = (container.offsetWidth - size) / 2 |
|
|
|
|
|
|
|
|
|
this.cropper.setCropBoxData({width: size, height: size, top, left}) |
|
|
|
|
} |
|
|
|
|
reader.readAsArrayBuffer(file) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
}) |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
chooseImage() { |
|
|
|
|
this.$refs.input.click() |
|
|
|
|
}, |
|
|
|
|
confirm() { |
|
|
|
|
if (!this.img) return elError('请先上传图片') |
|
|
|
|
|
|
|
|
|
if (this.loading) return |
|
|
|
|
|
|
|
|
|
this.loading = true |
|
|
|
|
this.$refs.cropper.getCropBlob(data => { |
|
|
|
|
upload(new Blob([data]), this.name) |
|
|
|
|
.then(({data}) => updateAvatar.request(data.data)) |
|
|
|
|
|
|
|
|
|
this.cropper |
|
|
|
|
.getCroppedCanvas() |
|
|
|
|
.toBlob( |
|
|
|
|
data => { |
|
|
|
|
upload(data, this.name) |
|
|
|
|
.then(({key}) => updateAvatar.request(key)) |
|
|
|
|
.then(({data, msg}) => { |
|
|
|
|
this.$store.commit('user/avatar', autoCompleteUrl(data)) |
|
|
|
|
this.$store.dispatch('user/refresh') |
|
|
|
|
elSuccess(msg) |
|
|
|
|
this.closeDialog() |
|
|
|
|
}) |
|
|
|
|
.finally(() => this.cancel()) |
|
|
|
|
}) |
|
|
|
|
.finally(() => this.loading = false) |
|
|
|
|
}, |
|
|
|
|
this.type |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
cancel() { |
|
|
|
|
this.closeDialog() |
|
|
|
|
beforeDestroy() { |
|
|
|
|
this.clear() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
</script> |
|
|
|
|
|
|
|
|
|
@ -122,15 +153,32 @@ export default { |
|
|
|
|
.avatar-cropper { |
|
|
|
|
height: 500px; |
|
|
|
|
width: 100%; |
|
|
|
|
border: 1px solid #ebebeb; |
|
|
|
|
|
|
|
|
|
.cropper-crop-box { |
|
|
|
|
border-radius: 50%; |
|
|
|
|
overflow: hidden; |
|
|
|
|
&-bg { |
|
|
|
|
height: 100%; |
|
|
|
|
width: 100%; |
|
|
|
|
cursor: pointer; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
> img { |
|
|
|
|
display: none; |
|
|
|
|
height: 100%; |
|
|
|
|
width: 100%; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
> input[type=file] { |
|
|
|
|
display: none; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.cropper-view-box { |
|
|
|
|
border-radius: 50%; |
|
|
|
|
box-sizing: border-box; |
|
|
|
|
border: 1px solid rgba(51, 153, 255, .75); |
|
|
|
|
outline: unset; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.cropper-face { |
|
|
|
|
border-radius: 50%; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
</style> |
|
|
|
|
|