图片裁剪组件

This commit is contained in:
陈红丽 2024-09-02 15:09:25 +08:00
parent c01a5a4fd0
commit f34a697cc9
5 changed files with 66 additions and 14 deletions

View File

@ -3,7 +3,12 @@
<slot name="default"></slot>
<template v-if="!$slots.default">
<div class="img-cropper-img" @click="openCropper">
<img :src="src" :class="{ circled: circled }" />
<img :src="src" :class="{ circled: circled }" v-if="src"/>
<div class="addImg" v-else>
<el-icon>
<plus />
</el-icon>
</div>
<div class="mask" :class="{ circled: circled }">
<el-icon class="el-input__icon">
<UploadOutlined />
@ -17,6 +22,7 @@
confirmButText="确认上传"
:uploadApi="uploadApi"
:circled="circled"
@uploadSuccess="handleSuccess"
/>
</div>
</template>
@ -43,8 +49,10 @@
const iconSize = cssUnit(Math.ceil(parseInt(getWidth) / 4));
// const emit = defineEmits(['change']);
const emit = defineEmits(['uploadSuccess']);
function handleSuccess(value){
emit('uploadSuccess',value)
}
function openCropper() {
cropperRef.value.showModal();
}
@ -67,12 +75,24 @@
width: 100%;
height: 100%;
border-radius: 50%;
.addImg {
width: v-bind(getWidth);
height: v-bind(getWidth);
border:1px dashed #999999;
display: flex;
justify-content: center;
align-items: center;
.el-icon {
color: #999999;
font-size: v-bind(iconSize);
}
}
.mask {
position: absolute;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;

View File

@ -160,7 +160,7 @@
import { ElMessage } from 'element-plus';
import { basicModal, useModal } from '@/components/Modal';
import CropperImage from './CropperImage.vue';
import { dataURLtoBlob } from '@/utils/file/base64Conver';
import { dataURLtoBlob ,base64ToFile} from '@/utils/file/base64Conver';
import { isFunction } from '@/utils/is';
import {
UploadOutlined,
@ -251,11 +251,14 @@
}
const uploadApi = props.uploadApi;
if (uploadApi && isFunction(uploadApi)) {
const blob = dataURLtoBlob(previewSource.value);
const file = base64ToFile(previewSource.value,filename);
try {
setSubLoading(true);
const result = await uploadApi({ name: 'file', file: blob, filename });
emit('uploadSuccess', { source: previewSource.value, data: result.data });
const formData = new FormData()
formData.append('file',file)
formData.append('name',filename)
const result = await uploadApi(formData);
emit('uploadSuccess', result);
closeModal();
} finally {
setSubLoading(false);

View File

@ -39,3 +39,19 @@ export function urlToBase64(url: string, mineType?: string): Promise<string> {
img.src = url;
});
}
/**
* base64 to file
* @param dataURL
*/
export function base64ToFile(dataurl:any, filename:any) {
let arr = dataurl.split(",");
let mime = arr[0].match(/:(.*?);/)[1];
let bstr = atob(arr[1]);
let len = bstr.length;
let u8arr = new Uint8Array(len);
while (len--) {
u8arr[len] = bstr.charCodeAt(len);
}
return new File([u8arr], filename, {type: mime});
}

View File

@ -243,7 +243,6 @@ const getMenu = async () => {
const data: any = await getMenuList();
const menu: any = {id: 0, name: "顶级", children: []};
const lists = buildTree(data)
console.log(lists)
menu.children = arrayToTree(
treeToArray(lists).filter((item) => item.type ==0)
);

View File

@ -97,14 +97,19 @@
</el-form-item>
</div>
<el-form-item label="头像" prop="avatar" :rules="{ required: true, message: '请输上传头像', trigger: 'blur' }">
<UploadImg @changeFileName="(name)=>formData.avatarName=name"
<!-- <UploadImg @changeFileName="(name)=>formData.avatarName=name"
:fileType=" ['image/jpeg', 'image/png', 'image/jpg', 'image/gif']"
name="user"
:fileSize="200"
:cropper="true"
v-model:image-url="formData.avatar">
<template v-slot:tip>支持扩展名: jpg png jpeg;文件大小不超过200M</template>
</UploadImg>
</UploadImg> -->
<Cropper ref="cropperCircled" :src="formData.avatar" :uploadApi="upload" title="矩形头像上传" @uploadSuccess="uploadSuccess">
<template #avatar>
</template>
</Cropper>
</el-form-item>
</el-form>
<template #footer>
@ -121,8 +126,10 @@
<script lang="ts" setup>
import { getUserDetail, userAdd, userUpdate } from '@/api/system/user';
import UploadImg from '@/components/Upload/Image.vue';
import {upload} from '@/api/common'
import { Cropper } from '@/components/Cropper';
import chinaArea from '@/components/ChinaArea/index.vue';
import { onMounted, reactive, shallowRef } from "vue";
import { ref,onMounted, reactive, shallowRef } from "vue";
import { getRoleAllList } from '@/api/system/role';
import { getDeptList } from '@/api/system/dept';
import { getLevelAllList } from '@/api/system/level';
@ -148,7 +155,7 @@ const props = defineProps({
default: 0
}
});
const cropperCircled = ref();
const emit = defineEmits(["success", "update:visible"]);
const formData = reactive({
id: 0,
@ -184,6 +191,9 @@ const passwordConfirmValidator = (
callback();
};
const uploadSuccess =(data)=>{
formData.avatar = data.fileUrl
}
const dialogClose = () => {
emit("update:visible", false);
};
@ -240,6 +250,10 @@ const getAllDict = async () => {
list = await getPositionAllList();
optionData.positionList = list ? list : [];
};
function cropperCircledImg() {
cropperCircled.value.openCropper();
}
onMounted(() => {
getAllDict()
if (props.userId) {