|
|
|
@ -1,33 +1,59 @@ |
|
|
|
<template> |
|
|
|
<div :class="getClass" :style="getStyle"> |
|
|
|
<div :class="`${prefixCls}-image-wrapper`" :style="getImageWrapperStyle" @click="openModal"> |
|
|
|
<div :class="`${prefixCls}-image-mask`" :style="getImageWrapperStyle"> |
|
|
|
<Icon |
|
|
|
icon="ant-design:cloud-upload-outlined" |
|
|
|
:size="getIconWidth" |
|
|
|
:style="getImageWrapperStyle" |
|
|
|
color="#d6d6d6" |
|
|
|
/> |
|
|
|
</div> |
|
|
|
<img :src="sourceValue" v-if="sourceValue" alt="avatar" /> |
|
|
|
</div> |
|
|
|
<a-button :class="`${prefixCls}-upload-btn`" @click="openModal"> |
|
|
|
{{ t('component.cropper.selectImage') }} |
|
|
|
<a-button |
|
|
|
:class="`${prefixCls}-upload-btn`" |
|
|
|
@click="openModal" |
|
|
|
v-if="showBtn" |
|
|
|
v-bind="btnProps" |
|
|
|
> |
|
|
|
{{ btnText ? btnText : t('component.cropper.selectImage') }} |
|
|
|
</a-button> |
|
|
|
<CopperModal @register="register" @uploadSuccess="handleUploadSuccess" :uploadApi="uploadApi" /> |
|
|
|
|
|
|
|
<CopperModal |
|
|
|
@register="register" |
|
|
|
@uploadSuccess="handleUploadSuccess" |
|
|
|
:uploadApi="uploadApi" |
|
|
|
:src="sourceValue" |
|
|
|
/> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
<script lang="ts"> |
|
|
|
import { defineComponent, computed, CSSProperties, unref, ref } from 'vue'; |
|
|
|
import { defineComponent, computed, CSSProperties, unref, ref, watchEffect, watch } from 'vue'; |
|
|
|
import CopperModal from './CopperModal.vue'; |
|
|
|
import { useDesign } from '/@/hooks/web/useDesign'; |
|
|
|
import { useModal } from '/@/components/Modal'; |
|
|
|
import { useMessage } from '/@/hooks/web/useMessage'; |
|
|
|
import { useI18n } from '/@/hooks/web/useI18n'; |
|
|
|
import type { ButtonProps } from '/@/components/Button'; |
|
|
|
import Icon from '/@/components/Icon'; |
|
|
|
|
|
|
|
const props = { |
|
|
|
width: { type: [String, Number], default: '200px' }, |
|
|
|
value: { type: String }, |
|
|
|
showBtn: { type: Boolean, default: true }, |
|
|
|
btnProps: { type: Object as ButtonProps }, |
|
|
|
btnText: { type: String, default: '' }, |
|
|
|
uploadApi: { type: Function as PropType<({ file: Blob, name: string }) => Promise<void>> }, |
|
|
|
}; |
|
|
|
|
|
|
|
export default defineComponent({ |
|
|
|
name: 'CropperAvatar', |
|
|
|
components: { CopperModal }, |
|
|
|
components: { CopperModal, Icon }, |
|
|
|
props, |
|
|
|
setup(props) { |
|
|
|
const sourceValue = ref(''); |
|
|
|
emits: ['update:value', 'change'], |
|
|
|
setup(props, { emit }) { |
|
|
|
const sourceValue = ref(props.value || ''); |
|
|
|
const { prefixCls } = useDesign('cropper-avatar'); |
|
|
|
const [register, { openModal }] = useModal(); |
|
|
|
const { createMessage } = useMessage(); |
|
|
|
@ -37,14 +63,28 @@ |
|
|
|
|
|
|
|
const getWidth = computed(() => `${props.width}`.replace(/px/, '') + 'px'); |
|
|
|
|
|
|
|
const getIconWidth = computed(() => parseInt(`${props.width}`.replace(/px/, '')) / 2 + 'px'); |
|
|
|
|
|
|
|
const getStyle = computed((): CSSProperties => ({ width: unref(getWidth) })); |
|
|
|
|
|
|
|
const getImageWrapperStyle = computed( |
|
|
|
(): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) }) |
|
|
|
); |
|
|
|
|
|
|
|
watchEffect(() => { |
|
|
|
sourceValue.value = props.value; |
|
|
|
}); |
|
|
|
|
|
|
|
watch( |
|
|
|
() => sourceValue.value, |
|
|
|
(v: string) => { |
|
|
|
emit('update:value', v); |
|
|
|
} |
|
|
|
); |
|
|
|
|
|
|
|
function handleUploadSuccess({ source }) { |
|
|
|
sourceValue.value = source; |
|
|
|
emit('change', source); |
|
|
|
createMessage.success(t('component.cropper.uploadSuccess')); |
|
|
|
} |
|
|
|
|
|
|
|
@ -53,6 +93,7 @@ |
|
|
|
prefixCls, |
|
|
|
register, |
|
|
|
openModal, |
|
|
|
getIconWidth, |
|
|
|
sourceValue, |
|
|
|
getClass, |
|
|
|
getImageWrapperStyle, |
|
|
|
@ -82,6 +123,27 @@ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&-image-mask { |
|
|
|
opacity: 0; |
|
|
|
position: absolute; |
|
|
|
width: inherit; |
|
|
|
height: inherit; |
|
|
|
border-radius: inherit; |
|
|
|
border: inherit; |
|
|
|
background: rgba(0, 0, 0, 0.4); |
|
|
|
cursor: pointer; |
|
|
|
-webkit-transition: opacity 0.4s; |
|
|
|
transition: opacity 0.4s; |
|
|
|
|
|
|
|
::v-deep(svg) { |
|
|
|
margin: auto; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&-image-mask:hover { |
|
|
|
opacity: 40; |
|
|
|
} |
|
|
|
|
|
|
|
&-upload-btn { |
|
|
|
margin: 10px auto; |
|
|
|
} |
|
|
|
|