This commit is contained in:
xingyu
2022-11-22 23:34:31 +08:00
parent 0e6c187008
commit 974361041a
2 changed files with 70 additions and 51 deletions

View File

@@ -1,46 +1,44 @@
<template> <template>
<div class="user-info-head" @click="editCropper()"> <div class="user-info-head" @click="editCropper()">
<img :src="options.options.img" title="点击上传头像" class="img-circle img-lg" alt="" /> <img :src="props.img" title="点击上传头像" class="img-circle img-lg" alt="" />
</div> </div>
<el-dialog <el-dialog
v-model="dialogVisible" v-model="dialogVisible"
title="编辑头像" title="编辑头像"
:mask-closable="false"
width="800px" width="800px"
append-to-body append-to-body
style="padding: 30px 20px" @opened="cropperVisible = true"
@opened="modalOpened"
> >
<el-row> <el-row>
<el-col :xs="24" :md="12" style="height: 350px"> <el-col :xs="24" :md="12" :style="{ height: '350px' }">
<VueCropper <VueCropper
ref="cropper" ref="cropper"
v-if="cropperVisible" v-if="cropperVisible"
:img="options.options.img" :img="options.img"
:info="true" :info="true"
:autoCrop="options.options.autoCrop" :infoTrue="options.infoTrue"
:autoCropWidth="options.options.autoCropWidth" :autoCrop="options.autoCrop"
:autoCropHeight="options.options.autoCropHeight" :autoCropWidth="options.autoCropWidth"
:fixedBox="options.options.fixedBox" :autoCropHeight="options.autoCropHeight"
@real-time="realTime" :fixedNumber="options.fixedNumber"
:fixedBox="options.fixedBox"
:centerBox="options.centerBox"
@realTime="realTime"
/> />
</el-col> </el-col>
<el-col :xs="24" :md="12" style="height: 350px"> <el-col :xs="24" :md="12" :style="{ height: '350px' }">
<div <div
class="avatar-upload-preview" class="avatar-upload-preview"
:style="{ :style="{
width: options.previews.w + 'px', width: previews.w + 'px',
height: options.previews.h + 'px', height: previews.h + 'px',
overflow: 'hidden', overflow: 'hidden',
margin: '5px' margin: '5px'
}" }"
> >
<div :style="options.previews.div"> <div :style="previews.div">
<img <img :src="previews.url" :style="previews.img" style="!max-width: 100%" alt="" />
:src="options.previews.url"
:style="options.previews.img"
style="!max-width: 100%"
alt=""
/>
</div> </div>
</div> </div>
</el-col> </el-col>
@@ -88,9 +86,9 @@
</el-dialog> </el-dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, watch } from 'vue' import { ref, reactive, watch, Ref, UnwrapNestedRefs } from 'vue'
import 'vue-cropper/dist/index.css' import 'vue-cropper/dist/index.css'
import { VueCropper } from 'vue-cropper' import VueCropper from 'vue-cropper/lib/vue-cropper.vue'
import { ElRow, ElCol, ElUpload, ElMessage, ElDialog } from 'element-plus' import { ElRow, ElCol, ElUpload, ElMessage, ElDialog } from 'element-plus'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { uploadAvatarApi } from '@/api/system/user/profile' import { uploadAvatarApi } from '@/api/system/user/profile'
@@ -101,30 +99,47 @@ const cropperVisible = ref(false)
const props = defineProps({ const props = defineProps({
img: propTypes.string.def('') img: propTypes.string.def('')
}) })
const options = reactive({ interface Options {
options: { img: string | ArrayBuffer | null // 裁剪图片的地址
img: props.img, //裁剪图片的地址 info: true // 裁剪框的大小信息
autoCrop: true, // 是否默认生成截图框 outputSize: number // 裁剪生成图片的质量 [1至0.1]
autoCropWidth: 200, // 默认生成截图框宽度 outputType: 'jpeg' // 裁剪生成图片的格式
autoCropHeight: 200, // 默认生成截图框高度 canScale: boolean // 图片是否允许滚轮缩放
fixedBox: true // 固定截图框大小 不允许改变 autoCrop: boolean // 是否默认生成截图框
}, autoCropWidth: number // 默认生成截图框宽度
previews: { autoCropHeight: number // 默认生成截图框高度
img: '', fixedBox: boolean // 固定截图框大小 不允许改变
url: '', fixed: boolean // 是否开启截图框宽高固定比例
w: 0, fixedNumber: Array<number> // 截图框的宽高比例 需要配合centerBox一起使用才能生效
h: 0, full: boolean // 是否输出原图比例的截图
div: '' canMoveBox: boolean // 截图框能否拖动
} original: boolean // 上传图片按照原始比例渲染
centerBox: boolean // 截图框是否被限制在图片里面
infoTrue: boolean // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
}
const options: UnwrapNestedRefs<Options> = reactive({
img: '', // 需要剪裁的图片
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 200, // 默认生成截图框的宽度
autoCropHeight: 200, // 默认生成截图框的长度
fixedBox: false, // 是否固定截图框的大小 不允许改变
info: true, // 裁剪框的大小信息
outputSize: 1, // 裁剪生成图片的质量 [1至0.1]
outputType: 'jpeg', // 裁剪生成图片的格式
canScale: false, // 图片是否允许滚轮缩放
fixed: true, // 是否开启截图框宽高固定比例
fixedNumber: [1, 1], // 截图框的宽高比例 需要配合centerBox一起使用才能生效
full: true, // 是否输出原图比例的截图
canMoveBox: false, // 截图框能否拖动
original: false, // 上传图片按照原始比例渲染
centerBox: true, // 截图框是否被限制在图片里面
infoTrue: true // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
}) })
const previews: Ref<any> = ref({})
/** 编辑头像 */ /** 编辑头像 */
const editCropper = () => { const editCropper = () => {
dialogVisible.value = true dialogVisible.value = true
} }
// 打开弹出层结束时的回调
const modalOpened = () => {
cropperVisible.value = true
}
/** 向左旋转 */ /** 向左旋转 */
const rotateLeft = () => { const rotateLeft = () => {
cropper.value.rotateLeft() cropper.value.rotateLeft()
@@ -146,11 +161,14 @@ const beforeUpload = (file: Blob) => {
ElMessage('文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。') ElMessage('文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。')
} else { } else {
const reader = new FileReader() const reader = new FileReader()
// 转化为base64
reader.readAsDataURL(file) reader.readAsDataURL(file)
reader.onload = () => { reader.onload = () => {
if (reader.result) { if (reader.result) {
options.options.img = reader.result as string // 获取到需要剪裁的图片 展示到剪裁框中
options.img = reader.result as string
} }
return false
} }
} }
} }
@@ -160,7 +178,8 @@ const uploadImg = () => {
let formData = new FormData() let formData = new FormData()
formData.append('avatarFile', data) formData.append('avatarFile', data)
uploadAvatarApi(formData).then((res) => { uploadAvatarApi(formData).then((res) => {
options.options.img = res options.img = res
window.location.reload()
}) })
dialogVisible.value = false dialogVisible.value = false
cropperVisible.value = false cropperVisible.value = false
@@ -168,15 +187,15 @@ const uploadImg = () => {
} }
/** 实时预览 */ /** 实时预览 */
const realTime = (data: any) => { const realTime = (data: any) => {
options.previews = data previews.value = data
} }
watch( watch(
() => props.img, () => props.img,
() => { () => {
if (props.img) { if (props.img) {
options.options.img = props.img options.img = props.img
options.previews.img = props.img previews.value.img = props.img
options.previews.url = props.img previews.value.url = props.img
} }
} }
) )

View File

@@ -3,19 +3,19 @@
<el-table-column type="seq" title="序号" width="60" fixed="left" /> <el-table-column type="seq" title="序号" width="60" fixed="left" />
<el-table-column label="社交平台" align="left" width="120"> <el-table-column label="社交平台" align="left" width="120">
<template #default="{ row }"> <template #default="{ row }">
<img style="height: 20px; vertical-align: middle" :src="row.img" alt="" /> <img class="h-5 align-middle" :src="row.img" alt="" />
{{ row.title }} <p class="mr-5">{{ row.title }}</p>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center"> <el-table-column label="操作" align="center">
<template #default="{ row }"> <template #default="{ row }">
<template v-if="row.openid"> <template v-if="row.openid">
已绑定 已绑定
<XTextButton type="primary" @click="unbind(row)" title="(解绑)" /> <XTextButton type="primary" class="mr-5" @click="unbind(row)" title="(解绑)" />
</template> </template>
<template v-else> <template v-else>
未绑定 未绑定
<XTextButton type="primary" @click="bind(row)" title="(绑定)" /> <XTextButton type="primary" class="mr-5" @click="bind(row)" title="(绑定)" />
</template> </template>
</template> </template>
</el-table-column> </el-table-column>