You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
195 lines
4.4 KiB
195 lines
4.4 KiB
<!--
|
|
@ 作者: 袁纪菲
|
|
@ 时间: 2024.3.18
|
|
@ 备注: 添加卡片
|
|
-->
|
|
<script setup>
|
|
import { ref,computed,reactive,watch,toRef} from 'vue';
|
|
|
|
const props = defineProps({
|
|
visible:Boolean
|
|
});
|
|
const emits = defineEmits(["update:visible", "data"]);
|
|
|
|
const formLabelWidth = '80px'
|
|
let timer
|
|
const dialog = ref(false)
|
|
const loading = ref(false)
|
|
|
|
const form = reactive({
|
|
data:{
|
|
id: '',
|
|
name: '',
|
|
imageUrl: '',
|
|
},
|
|
visible: computed({
|
|
get(){
|
|
return props.visible
|
|
},
|
|
set(val) {
|
|
emits('update:visible', val)
|
|
}
|
|
})
|
|
})
|
|
const drawerRefadd = ref();
|
|
|
|
// 图片预览地址
|
|
const previewImageUrl = ref('');
|
|
// 图片上传前的钩子函数
|
|
const beforeUpload = (file) => {
|
|
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
|
|
if (!isJPG) {
|
|
ElMessage.error('只能上传 JPG 或 PNG 格式的图片');
|
|
return false;
|
|
}
|
|
const isLt2M = file.size / 1024 / 1024 < 2;
|
|
if (!isLt2M) {
|
|
ElMessage.error('图片大小不能超过 2MB');
|
|
return false;
|
|
}
|
|
// 如果验证通过,则可以将本地图片转为 URL 显示预览
|
|
const reader = new FileReader();
|
|
reader.readAsDataURL(file);
|
|
reader.onload = () => {
|
|
previewImageUrl.value = reader.result;
|
|
form.data.imageUrl = reader.result; // 更新到表单数据
|
|
};
|
|
return isJPG && isLt2M;
|
|
};
|
|
// 表单提交
|
|
const onSubmit = async () => {
|
|
// 验证表单数据...
|
|
if (!form.data.name) {
|
|
ElMessage.error("标题不能为空");
|
|
return;
|
|
}
|
|
// 模拟向本地数据添加新的卡片数据
|
|
const newCard = { ...form.data };
|
|
// 关闭添加卡片的抽屉
|
|
drawerRefadd.value.close();
|
|
// 将新卡片数据发送回父组件
|
|
emits('data', newCard);
|
|
// 清空表单以便下次使用
|
|
form.data.name = '';
|
|
// 提交成功后,关闭loading状态
|
|
loading.value = false;
|
|
emits('update:visible', false)
|
|
};
|
|
|
|
// };
|
|
// 关闭
|
|
const handleClose = () => {
|
|
if (loading.value) {
|
|
return
|
|
}
|
|
ElMessageBox.confirm(
|
|
'你是否要提交数据?',
|
|
"温馨提示",
|
|
{
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning',
|
|
}
|
|
)
|
|
.then(() => {
|
|
loading.value = true
|
|
timer = setTimeout(() => {
|
|
// done() 不能用done
|
|
// 动画关闭需要一定的时间
|
|
setTimeout(() => {
|
|
loading.value = false
|
|
emits('update:visible', false)
|
|
}, 400)
|
|
}, 2000)
|
|
})
|
|
|
|
.catch(() => {
|
|
// catch error
|
|
cancelForm();
|
|
})
|
|
}
|
|
// 取消
|
|
const cancelForm = () => {
|
|
loading.value = false
|
|
dialog.value = false
|
|
emits('update:visible', false)
|
|
clearTimeout(timer)
|
|
form.data.name = ''
|
|
}
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<el-drawer
|
|
ref="drawerRefadd"
|
|
:model-value="visible"
|
|
title="添加"
|
|
:before-close="handleClose"
|
|
direction="ltr"
|
|
class="demo-drawer"
|
|
size="400px"
|
|
>
|
|
<div class="demo-drawer__content">
|
|
<el-form :model="form">
|
|
<el-form-item label="标题" :label-width="formLabelWidth">
|
|
<el-input v-model="form.data.name" autocomplete="off" />
|
|
</el-form-item>
|
|
<el-form-item label="图片" :label-width=formLabelWidth>
|
|
<el-upload
|
|
class="picture-uploader"
|
|
action=""
|
|
:auto-upload="false"
|
|
:before-upload="beforeUpload"
|
|
:on-change="handleChange"
|
|
list-type="picture-card">
|
|
<i class="el-icon-plus"></i>
|
|
</el-upload>
|
|
<!-- 预览区域 -->
|
|
<div v-if="form.data.imageUrl" class="preview-image">
|
|
<img :src="form.data.imageUrl" alt="预览图片" />
|
|
</div>
|
|
</el-form-item>
|
|
</el-form>
|
|
<div class="demo-drawer__footer">
|
|
<el-button @click="cancelForm">取消</el-button>
|
|
<el-button type="primary" :loading="loading" @click="onSubmit">
|
|
{{loading ? '正在提交 ...' : '提交'}}
|
|
</el-button>
|
|
</div>
|
|
</div>
|
|
</el-drawer>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.el-form {
|
|
margin: 30px 15px 10px 0;
|
|
.el-image {
|
|
width: 120px;
|
|
height: 120px;
|
|
border: 1px solid #ccc;
|
|
margin-right: 10px;
|
|
}
|
|
}
|
|
.picture {
|
|
display: flex;
|
|
justify-content: space-around;
|
|
.uppicture {
|
|
flex: 1;
|
|
position: relative;
|
|
border: 1px solid #ccc;
|
|
input {
|
|
width: 100%;
|
|
height: 100%;
|
|
vertical-align: middle;
|
|
opacity: 0;
|
|
}
|
|
i {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
font-size: 30px;
|
|
}
|
|
}
|
|
}
|
|
</style>
|