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 | <template> | 1 | <template> |
| 2 | <div class="user-info-head" @click="editCropper()"> | 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 | </div> | 4 | </div> |
| 5 | <el-dialog | 5 | <el-dialog |
| 6 | v-model="dialogVisible" | 6 | v-model="dialogVisible" |
| 7 | title="编辑头像" | 7 | title="编辑头像" |
| 8 | + :mask-closable="false" | ||
| 8 | width="800px" | 9 | width="800px" |
| 9 | append-to-body | 10 | append-to-body |
| 10 | - style="padding: 30px 20px" | ||
| 11 | - @opened="modalOpened" | 11 | + @opened="cropperVisible = true" |
| 12 | > | 12 | > |
| 13 | <el-row> | 13 | <el-row> |
| 14 | - <el-col :xs="24" :md="12" style="height: 350px"> | 14 | + <el-col :xs="24" :md="12" :style="{ height: '350px' }"> |
| 15 | <VueCropper | 15 | <VueCropper |
| 16 | ref="cropper" | 16 | ref="cropper" |
| 17 | v-if="cropperVisible" | 17 | v-if="cropperVisible" |
| 18 | - :img="options.options.img" | 18 | + :img="options.img" |
| 19 | :info="true" | 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 | </el-col> | 29 | </el-col> |
| 27 | - <el-col :xs="24" :md="12" style="height: 350px"> | 30 | + <el-col :xs="24" :md="12" :style="{ height: '350px' }"> |
| 28 | <div | 31 | <div |
| 29 | class="avatar-upload-preview" | 32 | class="avatar-upload-preview" |
| 30 | :style="{ | 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 | overflow: 'hidden', | 36 | overflow: 'hidden', |
| 34 | margin: '5px' | 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 | </div> | 42 | </div> |
| 45 | </div> | 43 | </div> |
| 46 | </el-col> | 44 | </el-col> |
| @@ -88,9 +86,9 @@ | @@ -88,9 +86,9 @@ | ||
| 88 | </el-dialog> | 86 | </el-dialog> |
| 89 | </template> | 87 | </template> |
| 90 | <script setup lang="ts"> | 88 | <script setup lang="ts"> |
| 91 | -import { ref, reactive, watch } from 'vue' | 89 | +import { ref, reactive, watch, Ref, UnwrapNestedRefs } from 'vue' |
| 92 | import 'vue-cropper/dist/index.css' | 90 | import 'vue-cropper/dist/index.css' |
| 93 | -import { VueCropper } from 'vue-cropper' | 91 | +import VueCropper from 'vue-cropper/lib/vue-cropper.vue' |
| 94 | import { ElRow, ElCol, ElUpload, ElMessage, ElDialog } from 'element-plus' | 92 | import { ElRow, ElCol, ElUpload, ElMessage, ElDialog } from 'element-plus' |
| 95 | import { propTypes } from '@/utils/propTypes' | 93 | import { propTypes } from '@/utils/propTypes' |
| 96 | import { uploadAvatarApi } from '@/api/system/user/profile' | 94 | import { uploadAvatarApi } from '@/api/system/user/profile' |
| @@ -101,30 +99,47 @@ const cropperVisible = ref(false) | @@ -101,30 +99,47 @@ const cropperVisible = ref(false) | ||
| 101 | const props = defineProps({ | 99 | const props = defineProps({ |
| 102 | img: propTypes.string.def('') | 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 | const editCropper = () => { | 140 | const editCropper = () => { |
| 122 | dialogVisible.value = true | 141 | dialogVisible.value = true |
| 123 | } | 142 | } |
| 124 | -// 打开弹出层结束时的回调 | ||
| 125 | -const modalOpened = () => { | ||
| 126 | - cropperVisible.value = true | ||
| 127 | -} | ||
| 128 | /** 向左旋转 */ | 143 | /** 向左旋转 */ |
| 129 | const rotateLeft = () => { | 144 | const rotateLeft = () => { |
| 130 | cropper.value.rotateLeft() | 145 | cropper.value.rotateLeft() |
| @@ -146,11 +161,14 @@ const beforeUpload = (file: Blob) => { | @@ -146,11 +161,14 @@ const beforeUpload = (file: Blob) => { | ||
| 146 | ElMessage('文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。') | 161 | ElMessage('文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。') |
| 147 | } else { | 162 | } else { |
| 148 | const reader = new FileReader() | 163 | const reader = new FileReader() |
| 164 | + // 转化为base64 | ||
| 149 | reader.readAsDataURL(file) | 165 | reader.readAsDataURL(file) |
| 150 | reader.onload = () => { | 166 | reader.onload = () => { |
| 151 | if (reader.result) { | 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,7 +178,8 @@ const uploadImg = () => { | ||
| 160 | let formData = new FormData() | 178 | let formData = new FormData() |
| 161 | formData.append('avatarFile', data) | 179 | formData.append('avatarFile', data) |
| 162 | uploadAvatarApi(formData).then((res) => { | 180 | uploadAvatarApi(formData).then((res) => { |
| 163 | - options.options.img = res | 181 | + options.img = res |
| 182 | + window.location.reload() | ||
| 164 | }) | 183 | }) |
| 165 | dialogVisible.value = false | 184 | dialogVisible.value = false |
| 166 | cropperVisible.value = false | 185 | cropperVisible.value = false |
| @@ -168,15 +187,15 @@ const uploadImg = () => { | @@ -168,15 +187,15 @@ const uploadImg = () => { | ||
| 168 | } | 187 | } |
| 169 | /** 实时预览 */ | 188 | /** 实时预览 */ |
| 170 | const realTime = (data: any) => { | 189 | const realTime = (data: any) => { |
| 171 | - options.previews = data | 190 | + previews.value = data |
| 172 | } | 191 | } |
| 173 | watch( | 192 | watch( |
| 174 | () => props.img, | 193 | () => props.img, |
| 175 | () => { | 194 | () => { |
| 176 | if (props.img) { | 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,19 +3,19 @@ | ||
| 3 | <el-table-column type="seq" title="序号" width="60" fixed="left" /> | 3 | <el-table-column type="seq" title="序号" width="60" fixed="left" /> |
| 4 | <el-table-column label="社交平台" align="left" width="120"> | 4 | <el-table-column label="社交平台" align="left" width="120"> |
| 5 | <template #default="{ row }"> | 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 | </template> | 8 | </template> |
| 9 | </el-table-column> | 9 | </el-table-column> |
| 10 | <el-table-column label="操作" align="center"> | 10 | <el-table-column label="操作" align="center"> |
| 11 | <template #default="{ row }"> | 11 | <template #default="{ row }"> |
| 12 | <template v-if="row.openid"> | 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 | </template> | 15 | </template> |
| 16 | <template v-else> | 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 | </template> | 19 | </template> |
| 20 | </template> | 20 | </template> |
| 21 | </el-table-column> | 21 | </el-table-column> |