houzhongjian
2024-08-08 820397e43a0b64d35c6d31d2a55475061438593b
提交 | 用户 | 时间
820397 1 <template>
H 2   <div class="user-info-head" @click="open()">
3     <el-avatar v-if="sourceValue" :src="sourceValue" alt="avatar" class="img-circle img-lg" />
4     <el-avatar v-if="!sourceValue" :src="avatar" alt="avatar" class="img-circle img-lg" />
5     <el-button v-if="showBtn" :class="`${prefixCls}-upload-btn`" @click="open()">
6       {{ btnText ? btnText : t('cropper.selectImage') }}
7     </el-button>
8     <CopperModal
9       ref="cropperModelRef"
10       :srcValue="sourceValue"
11       @upload-success="handleUploadSuccess"
12     />
13   </div>
14 </template>
15 <script lang="ts" setup>
16 import { useDesign } from '@/hooks/web/useDesign'
17
18 import { propTypes } from '@/utils/propTypes'
19 import { useI18n } from 'vue-i18n'
20 import CopperModal from './CopperModal.vue'
21 import avatar from '@/assets/imgs/avatar.gif'
22
23 defineOptions({ name: 'CropperAvatar' })
24
25 const props = defineProps({
26   width: propTypes.string.def('200px'),
27   value: propTypes.string.def(''),
28   showBtn: propTypes.bool.def(true),
29   btnText: propTypes.string.def('')
30 })
31
32 const emit = defineEmits(['update:value', 'change'])
33 const sourceValue = ref(props.value)
34 const { getPrefixCls } = useDesign()
35 const prefixCls = getPrefixCls('cropper-avatar')
36 const message = useMessage()
37 const { t } = useI18n()
38
39 const cropperModelRef = ref()
40
41 watchEffect(() => {
42   sourceValue.value = props.value
43 })
44
45 watch(
46   () => sourceValue.value,
47   (v: string) => {
48     emit('update:value', v)
49   }
50 )
51
52 function handleUploadSuccess({ source, data, filename }) {
53   sourceValue.value = source
54   emit('change', { source, data, filename })
55   message.success(t('cropper.uploadSuccess'))
56 }
57
58 function open() {
59   cropperModelRef.value.openModal()
60 }
61
62 function close() {
63   cropperModelRef.value.closeModal()
64 }
65
66 defineExpose({
67   open,
68   close
69 })
70 </script>
71 <style lang="scss" scoped>
72 $prefix-cls: #{$namespace}--cropper-avatar;
73
74 .#{$prefix-cls} {
75   display: inline-block;
76   text-align: center;
77
78   &-image-wrapper {
79     overflow: hidden;
80     cursor: pointer;
81     border: 1px solid;
82     border-radius: 50%;
83
84     img {
85       width: 100%;
86     }
87   }
88
89   &-image-mask {
90     position: absolute;
91     width: inherit;
92     height: inherit;
93     cursor: pointer;
94     background: rgb(0 0 0 / 40%);
95     border: inherit;
96     border-radius: inherit;
97     opacity: 0;
98     transition: opacity 0.4s;
99
100     ::v-deep(svg) {
101       margin: auto;
102     }
103   }
104
105   &-image-mask:hover {
106     opacity: 40;
107   }
108
109   &-upload-btn {
110     margin: 10px auto;
111   }
112 }
113
114 .user-info-head {
115   position: relative;
116   display: inline-block;
117 }
118
119 .img-circle {
120   border-radius: 50%;
121 }
122
123 .img-lg {
124   width: 120px;
125   height: 120px;
126 }
127
128 .user-info-head:hover::after {
129   position: absolute;
130   inset: 0;
131   font-size: 24px;
132   -webkit-font-smoothing: antialiased;
133   -moz-osx-font-smoothing: grayscale;
134   font-style: normal;
135   line-height: 110px;
136   color: #eee;
137   cursor: pointer;
138   background: rgb(0 0 0 / 50%);
139   border-radius: 50%;
140   content: '+';
141 }
142 </style>