Files
ipms-sjy/yudao-ui-admin-vue3/src/views/Profile/components/UserAvatar.vue

209 lines
5.6 KiB
Vue
Raw Normal View History

2022-07-18 19:06:37 +08:00
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import 'vue-cropper/dist/index.css'
import { VueCropper } from 'vue-cropper'
import { ElRow, ElCol, ElUpload, ElMessage, ElDialog } from 'element-plus'
2022-07-18 19:06:37 +08:00
import { propTypes } from '@/utils/propTypes'
import { uploadAvatarApi } from '@/api/system/user/profile'
const cropper = ref()
2022-08-03 00:41:59 +08:00
const dialogVisible = ref(false)
const cropperVisible = ref(false)
2022-07-18 19:06:37 +08:00
const props = defineProps({
img: propTypes.string.def('')
})
2022-08-03 00:41:59 +08:00
const options = reactive({
2022-07-18 19:06:37 +08:00
dialogTitle: '编辑头像',
options: {
img: props.img, //裁剪图片的地址
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 200, // 默认生成截图框宽度
autoCropHeight: 200, // 默认生成截图框高度
fixedBox: true // 固定截图框大小 不允许改变
},
previews: {
img: '',
url: ''
}
})
/** 编辑头像 */
const editCropper = () => {
2022-08-03 00:41:59 +08:00
dialogVisible.value = true
}
// 打开弹出层结束时的回调
const modalOpened = () => {
cropperVisible.value = true
2022-07-18 19:06:37 +08:00
}
/** 向左旋转 */
const rotateLeft = () => {
cropper.value.rotateLeft()
}
/** 向右旋转 */
const rotateRight = () => {
cropper.value.rotateRight()
}
/** 图片缩放 */
const changeScale = (num: number) => {
num = num || 1
cropper.value.changeScale(num)
}
// 覆盖默认的上传行为
2022-08-03 00:41:59 +08:00
const requestUpload: any = () => {}
2022-07-18 19:06:37 +08:00
/** 上传预处理 */
const beforeUpload = (file: Blob) => {
if (file.type.indexOf('image/') == -1) {
ElMessage('文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。')
} else {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => {
2022-07-19 22:33:54 +08:00
if (reader.result) {
2022-08-03 00:41:59 +08:00
options.options.img = reader.result as string
2022-07-19 22:33:54 +08:00
}
2022-07-18 19:06:37 +08:00
}
}
}
/** 上传图片 */
const uploadImg = () => {
2022-08-03 00:41:59 +08:00
cropper.value.getCropBlob((data: any) => {
2022-07-18 19:06:37 +08:00
let formData = new FormData()
formData.append('avatarfile', data)
uploadAvatarApi(formData)
})
}
/** 实时预览 */
2022-08-03 00:41:59 +08:00
const realTime = (data: any) => {
options.previews = data
2022-07-18 19:06:37 +08:00
}
watch(
() => props.img,
() => {
if (props.img) {
2022-08-03 00:41:59 +08:00
options.options.img = props.img
options.previews.img = props.img
options.previews.url = props.img
2022-07-18 19:06:37 +08:00
}
}
)
</script>
<template>
<div class="user-info-head" @click="editCropper()">
2022-08-03 00:41:59 +08:00
<img :src="options.options.img" title="点击上传头像" class="img-circle img-lg" alt="" />
2022-07-18 19:06:37 +08:00
</div>
<el-dialog
2022-08-03 00:41:59 +08:00
v-model="dialogVisible"
:title="options.dialogTitle"
width="800px"
append-to-body
2022-07-18 19:06:37 +08:00
style="padding: 30px 20px"
2022-08-03 00:41:59 +08:00
@opened="modalOpened"
2022-07-18 19:06:37 +08:00
>
<el-row>
<el-col :xs="24" :md="12" style="height: 350px">
2022-07-18 19:06:37 +08:00
<VueCropper
ref="cropper"
2022-08-03 00:41:59 +08:00
:img="options.options.img"
2022-07-18 19:06:37 +08:00
:info="true"
2022-08-03 00:41:59 +08:00
:autoCrop="options.options.autoCrop"
:autoCropWidth="options.options.autoCropWidth"
:autoCropHeight="options.options.autoCropHeight"
:fixedBox="options.options.fixedBox"
2022-07-18 19:06:37 +08:00
@real-time="realTime"
2022-08-03 00:41:59 +08:00
v-if="cropperVisible"
2022-07-18 19:06:37 +08:00
/>
</el-col>
<el-col :xs="24" :md="12" style="height: 350px">
2022-07-18 19:06:37 +08:00
<div class="avatar-upload-preview">
<img
2022-08-03 00:41:59 +08:00
:src="options.previews.url"
:style="options.previews.img"
2022-07-18 19:06:37 +08:00
style="!max-width: 100%"
alt=""
/>
</div>
</el-col>
</el-row>
<template #footer>
<el-row>
<el-col :lg="2" :md="2">
<el-upload
action="#"
:http-request="requestUpload"
:show-file-list="false"
:before-upload="beforeUpload"
>
2022-07-18 19:06:37 +08:00
<el-button size="small">
<Icon icon="ep:upload-filled" class="mr-5px" />
选择
</el-button>
</el-upload>
</el-col>
<el-col :lg="{ span: 1, offset: 2 }" :md="2">
<el-button size="small" @click="changeScale(1)">
<Icon icon="ep:zoom-in" class="mr-5px" />
</el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button size="small" @click="changeScale(-1)">
<Icon icon="ep:zoom-out" class="mr-5px" />
</el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button size="small" @click="rotateLeft()">
<Icon icon="ep:arrow-left-bold" class="mr-5px" />
</el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button size="small" @click="rotateRight()">
<Icon icon="ep:arrow-right-bold" class="mr-5px" />
</el-button>
</el-col>
<el-col :lg="{ span: 2, offset: 6 }" :md="2">
<el-button size="small" type="primary" @click="uploadImg()"> </el-button>
</el-col>
</el-row>
</template>
</el-dialog>
2022-07-18 19:06:37 +08:00
</template>
<style scoped>
.user-info-head {
position: relative;
display: inline-block;
}
.img-circle {
border-radius: 50%;
}
.img-lg {
width: 120px;
height: 120px;
}
.avatar-upload-preview {
position: absolute;
top: 50%;
-webkit-transform: translate(50%, -50%);
transform: translate(50%, -50%);
width: 200px;
height: 200px;
border-radius: 50%;
-webkit-box-shadow: 0 0 4px #ccc;
box-shadow: 0 0 4px #ccc;
overflow: hidden;
}
.user-info-head:hover:after {
content: '+';
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
color: #eee;
background: rgba(0, 0, 0, 0.5);
font-size: 24px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
cursor: pointer;
line-height: 110px;
border-radius: 50%;
}
</style>