提交 b96ea075 编写于 作者: 无木

feat(avatar-cropper): more props added

为头像剪裁组件添加value属性、onChange事件以及用于自定义上传按钮的属性;更新个人设置页的头像设置
上级 6cbac4b7
......@@ -7,6 +7,11 @@
- 增加`ignoreRoute`用于在`ROUTE_MAPPING``BACK`权限模式下仅生成菜单
- 增加`hidePathForChildren`配置,标识为子项目生成菜单时忽略本级`path`
- **TableAction** 新增`tooltip`配置,可以为按钮增加 tooltip 提示
- **CropperAvatar**
- 新增`value`用于设置当前头像
- 新增`onChange`用于接受头像剪裁并上传成功事件
- 新增`btnText``btnProps` 用于自定义上传按钮文案和属性
- 为剪裁`Modal`内的操作按钮添加工具提示
### 🐛 Bug Fixes
......
<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;
}
......
<template>
<PageWrapper title="图片裁剪示例" content="需要开启测试接口服务才能进行上传测试!">
<CollapseContainer title="头像裁剪">
<CropperAvatar :uploadApi="uploadApi" />
<CropperAvatar :uploadApi="uploadApi" :value="avatar" />
</CollapseContainer>
<CollapseContainer title="矩形裁剪" class="my-4">
......@@ -9,7 +9,7 @@
<div class="cropper-container mr-10">
<CropperImage ref="refCropper" :src="img" @cropend="handleCropend" style="width: 40vw" />
</div>
<img :src="cropperImg" class="croppered" v-if="cropperImg" />
<img :src="cropperImg" class="croppered" v-if="cropperImg" alt="" />
</div>
<p v-if="cropperImg">裁剪后图片信息:{{ info }}</p>
</CollapseContainer>
......@@ -34,10 +34,11 @@
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { PageWrapper } from '/@/components/Page';
import { CollapseContainer } from '/@/components/Container/index';
import { CollapseContainer } from '/@/components/Container';
import { CropperImage, CropperAvatar } from '/@/components/Cropper';
import { uploadApi } from '/@/api/sys/upload';
import img from '/@/assets/images/header.jpg';
import { useUserStore } from '/@/store/modules/user';
export default defineComponent({
components: {
......@@ -51,7 +52,8 @@
const cropperImg = ref('');
const circleInfo = ref('');
const circleImg = ref('');
const userStore = useUserStore();
const avatar = ref(userStore.getUserInfo?.avatar || '');
function handleCropend({ imgBase64, imgInfo }) {
info.value = imgInfo;
cropperImg.value = imgBase64;
......@@ -70,6 +72,7 @@
circleImg,
handleCropend,
handleCircleCropend,
avatar,
uploadApi,
};
},
......
......@@ -7,10 +7,14 @@
<a-col :span="10">
<div class="change-avatar">
<div class="mb-2"> 头像 </div>
<img width="140" :src="avatar" />
<Upload :showUploadList="false">
<Button class="ml-5"> <Icon icon="feather:upload" />更换头像 </Button>
</Upload>
<CropperAvatar
:uploadApi="uploadApi"
:value="avatar"
btnText="更换头像"
:btnProps="{ preIcon: 'ant-design:cloud-upload-outlined' }"
@change="updateAvatar"
width="150"
/>
</div>
</a-col>
</a-row>
......@@ -18,11 +22,11 @@
</CollapseContainer>
</template>
<script lang="ts">
import { Button, Upload, Row, Col } from 'ant-design-vue';
import { Button, Row, Col } from 'ant-design-vue';
import { computed, defineComponent, onMounted } from 'vue';
import { BasicForm, useForm } from '/@/components/Form/index';
import { CollapseContainer } from '/@/components/Container/index';
import Icon from '/@/components/Icon/index';
import { CollapseContainer } from '/@/components/Container';
import { CropperAvatar } from '/@/components/Cropper';
import { useMessage } from '/@/hooks/web/useMessage';
......@@ -30,16 +34,16 @@
import { accountInfoApi } from '/@/api/demo/account';
import { baseSetschemas } from './data';
import { useUserStore } from '/@/store/modules/user';
import { uploadApi } from '/@/api/sys/upload';
export default defineComponent({
components: {
BasicForm,
CollapseContainer,
Button,
Upload,
Icon,
[Row.name]: Row,
[Col.name]: Col,
ARow: Row,
ACol: Col,
CropperAvatar,
},
setup() {
const { createMessage } = useMessage();
......@@ -61,9 +65,17 @@
return avatar || headerImg;
});
function updateAvatar(src: string) {
const userinfo = userStore.getUserInfo;
userinfo.avatar = src;
userStore.setUserInfo(userinfo);
}
return {
avatar,
register,
uploadApi,
updateAvatar,
handleSubmit: () => {
createMessage.success('更新成功!');
},
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册