Commit 974361041a024011915ce56c2363b3fc0042fbf3
1 parent
0e6c1870
refactor
Showing
2 changed files
with
70 additions
and
51 deletions
yudao-ui-admin-vue3/src/views/Profile/components/UserAvatar.vue
| 1 | 1 | <template> |
| 2 | 2 | <div class="user-info-head" @click="editCropper()"> |
| 3 | - <img :src="options.options.img" title="点击上传头像" class="img-circle img-lg" alt="" /> | |
| 3 | + <img :src="props.img" title="点击上传头像" class="img-circle img-lg" alt="" /> | |
| 4 | 4 | </div> |
| 5 | 5 | <el-dialog |
| 6 | 6 | v-model="dialogVisible" |
| 7 | 7 | title="编辑头像" |
| 8 | + :mask-closable="false" | |
| 8 | 9 | width="800px" |
| 9 | 10 | append-to-body |
| 10 | - style="padding: 30px 20px" | |
| 11 | - @opened="modalOpened" | |
| 11 | + @opened="cropperVisible = true" | |
| 12 | 12 | > |
| 13 | 13 | <el-row> |
| 14 | - <el-col :xs="24" :md="12" style="height: 350px"> | |
| 14 | + <el-col :xs="24" :md="12" :style="{ height: '350px' }"> | |
| 15 | 15 | <VueCropper |
| 16 | 16 | ref="cropper" |
| 17 | 17 | v-if="cropperVisible" |
| 18 | - :img="options.options.img" | |
| 18 | + :img="options.img" | |
| 19 | 19 | :info="true" |
| 20 | - :autoCrop="options.options.autoCrop" | |
| 21 | - :autoCropWidth="options.options.autoCropWidth" | |
| 22 | - :autoCropHeight="options.options.autoCropHeight" | |
| 23 | - :fixedBox="options.options.fixedBox" | |
| 24 | - @real-time="realTime" | |
| 20 | + :infoTrue="options.infoTrue" | |
| 21 | + :autoCrop="options.autoCrop" | |
| 22 | + :autoCropWidth="options.autoCropWidth" | |
| 23 | + :autoCropHeight="options.autoCropHeight" | |
| 24 | + :fixedNumber="options.fixedNumber" | |
| 25 | + :fixedBox="options.fixedBox" | |
| 26 | + :centerBox="options.centerBox" | |
| 27 | + @realTime="realTime" | |
| 25 | 28 | /> |
| 26 | 29 | </el-col> |
| 27 | - <el-col :xs="24" :md="12" style="height: 350px"> | |
| 30 | + <el-col :xs="24" :md="12" :style="{ height: '350px' }"> | |
| 28 | 31 | <div |
| 29 | 32 | class="avatar-upload-preview" |
| 30 | 33 | :style="{ |
| 31 | - width: options.previews.w + 'px', | |
| 32 | - height: options.previews.h + 'px', | |
| 34 | + width: previews.w + 'px', | |
| 35 | + height: previews.h + 'px', | |
| 33 | 36 | overflow: 'hidden', |
| 34 | 37 | margin: '5px' |
| 35 | 38 | }" |
| 36 | 39 | > |
| 37 | - <div :style="options.previews.div"> | |
| 38 | - <img | |
| 39 | - :src="options.previews.url" | |
| 40 | - :style="options.previews.img" | |
| 41 | - style="!max-width: 100%" | |
| 42 | - alt="" | |
| 43 | - /> | |
| 40 | + <div :style="previews.div"> | |
| 41 | + <img :src="previews.url" :style="previews.img" style="!max-width: 100%" alt="" /> | |
| 44 | 42 | </div> |
| 45 | 43 | </div> |
| 46 | 44 | </el-col> |
| ... | ... | @@ -88,9 +86,9 @@ |
| 88 | 86 | </el-dialog> |
| 89 | 87 | </template> |
| 90 | 88 | <script setup lang="ts"> |
| 91 | -import { ref, reactive, watch } from 'vue' | |
| 89 | +import { ref, reactive, watch, Ref, UnwrapNestedRefs } from 'vue' | |
| 92 | 90 | import 'vue-cropper/dist/index.css' |
| 93 | -import { VueCropper } from 'vue-cropper' | |
| 91 | +import VueCropper from 'vue-cropper/lib/vue-cropper.vue' | |
| 94 | 92 | import { ElRow, ElCol, ElUpload, ElMessage, ElDialog } from 'element-plus' |
| 95 | 93 | import { propTypes } from '@/utils/propTypes' |
| 96 | 94 | import { uploadAvatarApi } from '@/api/system/user/profile' |
| ... | ... | @@ -101,30 +99,47 @@ const cropperVisible = ref(false) |
| 101 | 99 | const props = defineProps({ |
| 102 | 100 | img: propTypes.string.def('') |
| 103 | 101 | }) |
| 104 | -const options = reactive({ | |
| 105 | - options: { | |
| 106 | - img: props.img, //裁剪图片的地址 | |
| 107 | - autoCrop: true, // 是否默认生成截图框 | |
| 108 | - autoCropWidth: 200, // 默认生成截图框宽度 | |
| 109 | - autoCropHeight: 200, // 默认生成截图框高度 | |
| 110 | - fixedBox: true // 固定截图框大小 不允许改变 | |
| 111 | - }, | |
| 112 | - previews: { | |
| 113 | - img: '', | |
| 114 | - url: '', | |
| 115 | - w: 0, | |
| 116 | - h: 0, | |
| 117 | - div: '' | |
| 118 | - } | |
| 102 | +interface Options { | |
| 103 | + img: string | ArrayBuffer | null // 裁剪图片的地址 | |
| 104 | + info: true // 裁剪框的大小信息 | |
| 105 | + outputSize: number // 裁剪生成图片的质量 [1至0.1] | |
| 106 | + outputType: 'jpeg' // 裁剪生成图片的格式 | |
| 107 | + canScale: boolean // 图片是否允许滚轮缩放 | |
| 108 | + autoCrop: boolean // 是否默认生成截图框 | |
| 109 | + autoCropWidth: number // 默认生成截图框宽度 | |
| 110 | + autoCropHeight: number // 默认生成截图框高度 | |
| 111 | + fixedBox: boolean // 固定截图框大小 不允许改变 | |
| 112 | + fixed: boolean // 是否开启截图框宽高固定比例 | |
| 113 | + fixedNumber: Array<number> // 截图框的宽高比例 需要配合centerBox一起使用才能生效 | |
| 114 | + full: boolean // 是否输出原图比例的截图 | |
| 115 | + canMoveBox: boolean // 截图框能否拖动 | |
| 116 | + original: boolean // 上传图片按照原始比例渲染 | |
| 117 | + centerBox: boolean // 截图框是否被限制在图片里面 | |
| 118 | + infoTrue: boolean // true 为展示真实输出图片宽高 false 展示看到的截图框宽高 | |
| 119 | +} | |
| 120 | +const options: UnwrapNestedRefs<Options> = reactive({ | |
| 121 | + img: '', // 需要剪裁的图片 | |
| 122 | + autoCrop: true, // 是否默认生成截图框 | |
| 123 | + autoCropWidth: 200, // 默认生成截图框的宽度 | |
| 124 | + autoCropHeight: 200, // 默认生成截图框的长度 | |
| 125 | + fixedBox: false, // 是否固定截图框的大小 不允许改变 | |
| 126 | + info: true, // 裁剪框的大小信息 | |
| 127 | + outputSize: 1, // 裁剪生成图片的质量 [1至0.1] | |
| 128 | + outputType: 'jpeg', // 裁剪生成图片的格式 | |
| 129 | + canScale: false, // 图片是否允许滚轮缩放 | |
| 130 | + fixed: true, // 是否开启截图框宽高固定比例 | |
| 131 | + fixedNumber: [1, 1], // 截图框的宽高比例 需要配合centerBox一起使用才能生效 | |
| 132 | + full: true, // 是否输出原图比例的截图 | |
| 133 | + canMoveBox: false, // 截图框能否拖动 | |
| 134 | + original: false, // 上传图片按照原始比例渲染 | |
| 135 | + centerBox: true, // 截图框是否被限制在图片里面 | |
| 136 | + infoTrue: true // true 为展示真实输出图片宽高 false 展示看到的截图框宽高 | |
| 119 | 137 | }) |
| 138 | +const previews: Ref<any> = ref({}) | |
| 120 | 139 | /** 编辑头像 */ |
| 121 | 140 | const editCropper = () => { |
| 122 | 141 | dialogVisible.value = true |
| 123 | 142 | } |
| 124 | -// 打开弹出层结束时的回调 | |
| 125 | -const modalOpened = () => { | |
| 126 | - cropperVisible.value = true | |
| 127 | -} | |
| 128 | 143 | /** 向左旋转 */ |
| 129 | 144 | const rotateLeft = () => { |
| 130 | 145 | cropper.value.rotateLeft() |
| ... | ... | @@ -146,11 +161,14 @@ const beforeUpload = (file: Blob) => { |
| 146 | 161 | ElMessage('文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。') |
| 147 | 162 | } else { |
| 148 | 163 | const reader = new FileReader() |
| 164 | + // 转化为base64 | |
| 149 | 165 | reader.readAsDataURL(file) |
| 150 | 166 | reader.onload = () => { |
| 151 | 167 | if (reader.result) { |
| 152 | - options.options.img = reader.result as string | |
| 168 | + // 获取到需要剪裁的图片 展示到剪裁框中 | |
| 169 | + options.img = reader.result as string | |
| 153 | 170 | } |
| 171 | + return false | |
| 154 | 172 | } |
| 155 | 173 | } |
| 156 | 174 | } |
| ... | ... | @@ -160,7 +178,8 @@ const uploadImg = () => { |
| 160 | 178 | let formData = new FormData() |
| 161 | 179 | formData.append('avatarFile', data) |
| 162 | 180 | uploadAvatarApi(formData).then((res) => { |
| 163 | - options.options.img = res | |
| 181 | + options.img = res | |
| 182 | + window.location.reload() | |
| 164 | 183 | }) |
| 165 | 184 | dialogVisible.value = false |
| 166 | 185 | cropperVisible.value = false |
| ... | ... | @@ -168,15 +187,15 @@ const uploadImg = () => { |
| 168 | 187 | } |
| 169 | 188 | /** 实时预览 */ |
| 170 | 189 | const realTime = (data: any) => { |
| 171 | - options.previews = data | |
| 190 | + previews.value = data | |
| 172 | 191 | } |
| 173 | 192 | watch( |
| 174 | 193 | () => props.img, |
| 175 | 194 | () => { |
| 176 | 195 | if (props.img) { |
| 177 | - options.options.img = props.img | |
| 178 | - options.previews.img = props.img | |
| 179 | - options.previews.url = props.img | |
| 196 | + options.img = props.img | |
| 197 | + previews.value.img = props.img | |
| 198 | + previews.value.url = props.img | |
| 180 | 199 | } |
| 181 | 200 | } |
| 182 | 201 | ) | ... | ... |
yudao-ui-admin-vue3/src/views/Profile/components/UserSocial.vue
| ... | ... | @@ -3,19 +3,19 @@ |
| 3 | 3 | <el-table-column type="seq" title="序号" width="60" fixed="left" /> |
| 4 | 4 | <el-table-column label="社交平台" align="left" width="120"> |
| 5 | 5 | <template #default="{ row }"> |
| 6 | - <img style="height: 20px; vertical-align: middle" :src="row.img" alt="" /> | |
| 7 | - {{ row.title }} | |
| 6 | + <img class="h-5 align-middle" :src="row.img" alt="" /> | |
| 7 | + <p class="mr-5">{{ row.title }}</p> | |
| 8 | 8 | </template> |
| 9 | 9 | </el-table-column> |
| 10 | 10 | <el-table-column label="操作" align="center"> |
| 11 | 11 | <template #default="{ row }"> |
| 12 | 12 | <template v-if="row.openid"> |
| 13 | 13 | 已绑定 |
| 14 | - <XTextButton type="primary" @click="unbind(row)" title="(解绑)" /> | |
| 14 | + <XTextButton type="primary" class="mr-5" @click="unbind(row)" title="(解绑)" /> | |
| 15 | 15 | </template> |
| 16 | 16 | <template v-else> |
| 17 | 17 | 未绑定 |
| 18 | - <XTextButton type="primary" @click="bind(row)" title="(绑定)" /> | |
| 18 | + <XTextButton type="primary" class="mr-5" @click="bind(row)" title="(绑定)" /> | |
| 19 | 19 | </template> |
| 20 | 20 | </template> |
| 21 | 21 | </el-table-column> | ... | ... |