feat: 头像上传组件
This commit is contained in:
@ -1,57 +1,34 @@
|
||||
<template>
|
||||
<div class="upload-avatar">
|
||||
<div class="el-upload el-upload--picture-card" @click="showDialog = true">
|
||||
<image-avatar
|
||||
v-if="avatarUrl"
|
||||
:file-id="avatarUrl"
|
||||
:size="146"
|
||||
/>
|
||||
<div class="el-upload el-upload--picture-card" @click="showDialog = !disabled">
|
||||
<el-avatar v-if="avatarUrl" :src="avatarUrl" :size="146" alt="头像" />
|
||||
<el-icon v-else class="avatar-uploader-icon">
|
||||
<plus />
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</div>
|
||||
<slot name="text">
|
||||
<div class="el-upload__tip w-400px">
|
||||
<div v-show="!disabled" class="el-upload__tip w-400px">
|
||||
<slot name="tip">
|
||||
单张图片不大于{{ fileSize }}MB,且格式为jpeg、jpg、png或bmp,只可上传1张
|
||||
</slot>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
<el-dialog
|
||||
v-model="showDialog"
|
||||
title="上传头像"
|
||||
width="800px"
|
||||
append-to-body
|
||||
@opened="modalOpened"
|
||||
@closed="closeDialog"
|
||||
>
|
||||
<el-dialog v-model="showDialog" title="上传头像" width="800px" append-to-body @opened="modalOpened" @closed="closeDialog">
|
||||
<el-row>
|
||||
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
|
||||
<VueCropper
|
||||
v-if="visible"
|
||||
ref="cropperRef"
|
||||
:img="cropperURL"
|
||||
:info="true"
|
||||
:auto-crop="options.autoCrop"
|
||||
:auto-crop-width="autoCropWidth"
|
||||
:auto-crop-height="autoCropHeight"
|
||||
:fixed-box="options.fixedBox"
|
||||
:output-type="options.outputType"
|
||||
@real-time="realTime"
|
||||
v-if="visible" ref="cropperRef" :img="cropperURL" :info="true" :auto-crop="options.autoCrop"
|
||||
:auto-crop-width="autoCropWidth" :auto-crop-height="autoCropHeight" :fixed-box="options.fixedBox"
|
||||
:output-type="options.outputType" @real-time="realTime"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
|
||||
<div
|
||||
class="avatar-upload-preview"
|
||||
:style="imageStyle"
|
||||
absolute h-200px w-200px rd="1/2" top="1/2" overflow-hidden
|
||||
class="translate-x-1/2 -translate-y-1/2" :style="imageStyle"
|
||||
>
|
||||
<img
|
||||
v-show="options.previews.url"
|
||||
:src="options.previews.url"
|
||||
:style="options.previews.img"
|
||||
alt="实时预览图片"
|
||||
>
|
||||
<img v-show="options.previews.url" :src="options.previews.url" :style="options.previews.img" alt="实时预览图片">
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -66,16 +43,16 @@
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 1, offset: 2 }" :md="2">
|
||||
<el-button icon="Plus" @click="changeScale(1)" />
|
||||
<el-button :icon="Plus" @click="changeScale(1)" />
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
|
||||
<el-button icon="Minus" @click="changeScale(-1)" />
|
||||
<el-button :icon="Minus" @click="changeScale(-1)" />
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
|
||||
<el-button icon="RefreshLeft" @click="rotateLeft()" />
|
||||
<el-button :icon="RefreshLeft" @click="rotateLeft()" />
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
|
||||
<el-button icon="RefreshRight" @click="rotateRight()" />
|
||||
<el-button :icon="RefreshRight" @click="rotateRight()" />
|
||||
</el-col>
|
||||
<el-col :lg="{ span: 2, offset: 6 }" :md="2">
|
||||
<el-button type="primary" :loading="loading" @click="confirmUpload">
|
||||
@ -90,6 +67,7 @@
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { CSSProperties } from 'vue'
|
||||
import { VueCropper } from 'vue-cropper'
|
||||
import { Minus, Plus, RefreshLeft, RefreshRight, Upload } from '@element-plus/icons-vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
accpet?: string
|
||||
@ -104,7 +82,8 @@ const props = withDefaults(defineProps<{
|
||||
autoCropHeight?: number
|
||||
/** 默认生成截图框高度 */
|
||||
autoCropWidth?: number
|
||||
uploadFunction?: (...args: any) => Promise<FileVO>
|
||||
uploadFunction?: (formData: FormData) => Promise<FileVO>
|
||||
disabled?: boolean
|
||||
}>(), {
|
||||
accpet: '.jpeg,.jpg,.png,.bmp',
|
||||
fileSize: 2,
|
||||
@ -124,6 +103,7 @@ const avatarUrl = useVModel(props, 'modelValue', emit)
|
||||
const imageStyle = computed(() => ({
|
||||
height: `${props.autoCropHeight}px`,
|
||||
width: `${props.autoCropWidth}px`,
|
||||
boxShadow: '0 0 4px #ccc',
|
||||
}))
|
||||
|
||||
let loading = $ref(false)
|
||||
@ -138,7 +118,7 @@ interface PreviewData {
|
||||
}
|
||||
|
||||
interface Option {
|
||||
/** 裁剪图片的地址 */
|
||||
/** 裁剪图片的地址 */
|
||||
img: any
|
||||
/** 是否默认生成截图框 */
|
||||
autoCrop: boolean
|
||||
@ -236,4 +216,5 @@ function closeDialog() {
|
||||
|
||||
<style>
|
||||
@import url('vue-cropper/dist/index.css');
|
||||
@import url('element-plus/theme-chalk/el-upload.css');
|
||||
</style>
|
||||
|
@ -1,13 +1,49 @@
|
||||
/*
|
||||
* @Author: zhaojinfeng 121016171@qq.com
|
||||
* @Date: 2023-07-18 12:28:36
|
||||
* @LastEditors: zhaojinfeng 121016171@qq.com
|
||||
* @LastEditTime: 2023-07-20 17:13:00
|
||||
* @FilePath: \vue3\stories\UploadAvatar.stories.ts
|
||||
* @Description:
|
||||
*
|
||||
*/
|
||||
import type { Meta, StoryObj } from '@storybook/vue3'
|
||||
import ThUploadAvatar from '../packages/upload-avatar/index.vue'
|
||||
import avatar from './assets/avatar.jpeg'
|
||||
|
||||
const meta = {
|
||||
title: '表单组件/UploadAvatar',
|
||||
component: ThUploadAvatar,
|
||||
tags: ['autodocs'],
|
||||
args: {
|
||||
modelValue: '',
|
||||
accpet: '.jpeg,.jpg,.png,.bmp',
|
||||
disabled: false,
|
||||
fileSize: 2,
|
||||
autoCropHeight: 200,
|
||||
autoCropWidth: 200,
|
||||
uploadFunction() {
|
||||
return Promise.resolve({
|
||||
id: 0,
|
||||
url: avatar,
|
||||
})
|
||||
},
|
||||
onOnSuccess() {
|
||||
ElMessage.success('模拟上传成功')
|
||||
},
|
||||
},
|
||||
} satisfies Meta<typeof ThUploadAvatar>
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Base: Story = {}
|
||||
export const Base: Story = {
|
||||
storyName: '基本使用',
|
||||
}
|
||||
export const Preview: Story = {
|
||||
storyName: '启用disabled,当做预览组件',
|
||||
args: {
|
||||
modelValue: avatar,
|
||||
disabled: false,
|
||||
},
|
||||
}
|
||||
|
BIN
stories/assets/avatar.jpeg
Normal file
BIN
stories/assets/avatar.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 84 KiB |
3
types/auto-imports.d.ts
vendored
3
types/auto-imports.d.ts
vendored
@ -12,6 +12,7 @@ declare global {
|
||||
const $shallowRef: typeof import('vue/macros')['$shallowRef']
|
||||
const $toRef: typeof import('vue/macros')['$toRef']
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
||||
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
||||
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
|
||||
const computed: typeof import('vue')['computed']
|
||||
@ -306,6 +307,7 @@ declare module 'vue' {
|
||||
readonly $shallowRef: UnwrapRef<typeof import('vue/macros')['$shallowRef']>
|
||||
readonly $toRef: UnwrapRef<typeof import('vue/macros')['$toRef']>
|
||||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||
readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']>
|
||||
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
|
||||
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
|
||||
readonly computed: UnwrapRef<typeof import('vue')['computed']>
|
||||
@ -594,6 +596,7 @@ declare module '@vue/runtime-core' {
|
||||
readonly $shallowRef: UnwrapRef<typeof import('vue/macros')['$shallowRef']>
|
||||
readonly $toRef: UnwrapRef<typeof import('vue/macros')['$toRef']>
|
||||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||
readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']>
|
||||
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
|
||||
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
|
||||
readonly computed: UnwrapRef<typeof import('vue')['computed']>
|
||||
|
Reference in New Issue
Block a user