图片裁剪组件
This commit is contained in:
parent
c01a5a4fd0
commit
f34a697cc9
@ -3,7 +3,12 @@
|
|||||||
<slot name="default"></slot>
|
<slot name="default"></slot>
|
||||||
<template v-if="!$slots.default">
|
<template v-if="!$slots.default">
|
||||||
<div class="img-cropper-img" @click="openCropper">
|
<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 }">
|
<div class="mask" :class="{ circled: circled }">
|
||||||
<el-icon class="el-input__icon">
|
<el-icon class="el-input__icon">
|
||||||
<UploadOutlined />
|
<UploadOutlined />
|
||||||
@ -17,6 +22,7 @@
|
|||||||
confirmButText="确认上传"
|
confirmButText="确认上传"
|
||||||
:uploadApi="uploadApi"
|
:uploadApi="uploadApi"
|
||||||
:circled="circled"
|
:circled="circled"
|
||||||
|
@uploadSuccess="handleSuccess"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -43,8 +49,10 @@
|
|||||||
|
|
||||||
const iconSize = cssUnit(Math.ceil(parseInt(getWidth) / 4));
|
const iconSize = cssUnit(Math.ceil(parseInt(getWidth) / 4));
|
||||||
|
|
||||||
// const emit = defineEmits(['change']);
|
const emit = defineEmits(['uploadSuccess']);
|
||||||
|
function handleSuccess(value){
|
||||||
|
emit('uploadSuccess',value)
|
||||||
|
}
|
||||||
function openCropper() {
|
function openCropper() {
|
||||||
cropperRef.value.showModal();
|
cropperRef.value.showModal();
|
||||||
}
|
}
|
||||||
@ -61,18 +69,30 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&-img {
|
&-img {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 50%;
|
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 {
|
.mask {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: rgba(0, 0, 0, 0.6);
|
background: rgba(0, 0, 0, 0.5);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -160,7 +160,7 @@
|
|||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { basicModal, useModal } from '@/components/Modal';
|
import { basicModal, useModal } from '@/components/Modal';
|
||||||
import CropperImage from './CropperImage.vue';
|
import CropperImage from './CropperImage.vue';
|
||||||
import { dataURLtoBlob } from '@/utils/file/base64Conver';
|
import { dataURLtoBlob ,base64ToFile} from '@/utils/file/base64Conver';
|
||||||
import { isFunction } from '@/utils/is';
|
import { isFunction } from '@/utils/is';
|
||||||
import {
|
import {
|
||||||
UploadOutlined,
|
UploadOutlined,
|
||||||
@ -251,11 +251,14 @@
|
|||||||
}
|
}
|
||||||
const uploadApi = props.uploadApi;
|
const uploadApi = props.uploadApi;
|
||||||
if (uploadApi && isFunction(uploadApi)) {
|
if (uploadApi && isFunction(uploadApi)) {
|
||||||
const blob = dataURLtoBlob(previewSource.value);
|
const file = base64ToFile(previewSource.value,filename);
|
||||||
try {
|
try {
|
||||||
setSubLoading(true);
|
setSubLoading(true);
|
||||||
const result = await uploadApi({ name: 'file', file: blob, filename });
|
const formData = new FormData()
|
||||||
emit('uploadSuccess', { source: previewSource.value, data: result.data });
|
formData.append('file',file)
|
||||||
|
formData.append('name',filename)
|
||||||
|
const result = await uploadApi(formData);
|
||||||
|
emit('uploadSuccess', result);
|
||||||
closeModal();
|
closeModal();
|
||||||
} finally {
|
} finally {
|
||||||
setSubLoading(false);
|
setSubLoading(false);
|
||||||
|
@ -39,3 +39,19 @@ export function urlToBase64(url: string, mineType?: string): Promise<string> {
|
|||||||
img.src = url;
|
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});
|
||||||
|
}
|
||||||
|
@ -243,7 +243,6 @@ const getMenu = async () => {
|
|||||||
const data: any = await getMenuList();
|
const data: any = await getMenuList();
|
||||||
const menu: any = {id: 0, name: "顶级", children: []};
|
const menu: any = {id: 0, name: "顶级", children: []};
|
||||||
const lists = buildTree(data)
|
const lists = buildTree(data)
|
||||||
console.log(lists)
|
|
||||||
menu.children = arrayToTree(
|
menu.children = arrayToTree(
|
||||||
treeToArray(lists).filter((item) => item.type ==0)
|
treeToArray(lists).filter((item) => item.type ==0)
|
||||||
);
|
);
|
||||||
|
@ -97,14 +97,19 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
<el-form-item label="头像" prop="avatar" :rules="{ required: true, message: '请输上传头像', trigger: 'blur' }">
|
<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']"
|
:fileType=" ['image/jpeg', 'image/png', 'image/jpg', 'image/gif']"
|
||||||
name="user"
|
name="user"
|
||||||
:fileSize="200"
|
:fileSize="200"
|
||||||
:cropper="true"
|
:cropper="true"
|
||||||
v-model:image-url="formData.avatar">
|
v-model:image-url="formData.avatar">
|
||||||
<template v-slot:tip>支持扩展名: jpg png jpeg;文件大小不超过200M</template>
|
<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-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -121,8 +126,10 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getUserDetail, userAdd, userUpdate } from '@/api/system/user';
|
import { getUserDetail, userAdd, userUpdate } from '@/api/system/user';
|
||||||
import UploadImg from '@/components/Upload/Image.vue';
|
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 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 { getRoleAllList } from '@/api/system/role';
|
||||||
import { getDeptList } from '@/api/system/dept';
|
import { getDeptList } from '@/api/system/dept';
|
||||||
import { getLevelAllList } from '@/api/system/level';
|
import { getLevelAllList } from '@/api/system/level';
|
||||||
@ -148,7 +155,7 @@ const props = defineProps({
|
|||||||
default: 0
|
default: 0
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const cropperCircled = ref();
|
||||||
const emit = defineEmits(["success", "update:visible"]);
|
const emit = defineEmits(["success", "update:visible"]);
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
id: 0,
|
id: 0,
|
||||||
@ -184,6 +191,9 @@ const passwordConfirmValidator = (
|
|||||||
callback();
|
callback();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const uploadSuccess =(data)=>{
|
||||||
|
formData.avatar = data.fileUrl
|
||||||
|
}
|
||||||
const dialogClose = () => {
|
const dialogClose = () => {
|
||||||
emit("update:visible", false);
|
emit("update:visible", false);
|
||||||
};
|
};
|
||||||
@ -240,6 +250,10 @@ const getAllDict = async () => {
|
|||||||
list = await getPositionAllList();
|
list = await getPositionAllList();
|
||||||
optionData.positionList = list ? list : [];
|
optionData.positionList = list ? list : [];
|
||||||
};
|
};
|
||||||
|
function cropperCircledImg() {
|
||||||
|
cropperCircled.value.openCropper();
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getAllDict()
|
getAllDict()
|
||||||
if (props.userId) {
|
if (props.userId) {
|
||||||
|
Loading…
Reference in New Issue
Block a user