2025-10-10 11:44:56 +08:00

286 lines
6.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<!-- 绑定本地visible变量 -->
<a-modal
v-model="localVisible"
title="批量导入"
:maskClosable="false"
@cancel="handleCancel"
:footer="null"
width="500px"
>
<!-- 原有内容不变 -->
<div class="import-container">
<div class="import-section" :class="{ 'section-top': true }">
<h3 class="section-title">
<span class="required-mark">*</span>下载模板填写表格信息
</h3>
<p class="section-desc">
请按照数据模板格式准备数据模板中的表头名称不可更改表头行不能删除单次导入的数据不超过1000条
</p>
<div class="file-info">
<a-icon type="file-excel-o" class="file-icon" theme="outlined" />
<div class="file-detail">
<p class="file-format">支持格式.xlsx .xls</p>
<a-button
type="primary"
class="action-btn"
@click="handleDownloadTemplate"
>
下载模板
</a-button>
</div>
</div>
</div>
<div class="import-section upload-section" :class="{ 'section-bottom': true }">
<h3 class="section-title">
<span class="required-mark">*</span>上传填好的表格信息
</h3>
<p class="section-desc">
文件后缀名必须为xls或xlsx即Excel格式文件大小不得超过10M
</p>
<div class="file-info">
<a-icon type="file-excel-o" class="file-icon" theme="filled" />
<div class="file-detail">
<p class="file-format">支持格式.xlsx .xls</p>
<a-upload
:showUploadList="false"
:beforeUpload="beforeUpload"
:customRequest="handleFileUpload"
>
<a-button
type="primary"
class="action-btn"
>
选择表格
</a-button>
</a-upload>
<div v-if="selectedFile" class="selected-file">
<span class="file-name">{{ selectedFile.name }}</span>
<a-icon
type="close-circle"
class="remove-icon"
@click="clearSelectedFile"
/>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<a-button @click="handleCancel">取消</a-button>
<a-button
type="primary"
@click="handleConfirmUpload"
:disabled="!selectedFile"
>
上传
</a-button>
</div>
</a-modal>
</template>
<script setup>
import { ref, defineProps, defineEmits, watch } from 'vue';
import { message } from 'ant-design-vue';
// 1. 定义接收父组件的prop遵循v-model默认命名规范
const props = defineProps({
modelValue: { // 注意这里改名为modelValue这是v-model的默认绑定名
type: Boolean,
default: false
}
});
// 2. 定义事件(通知父组件更新值)
const emit = defineEmits(['update:modelValue', 'upload', 'download']);
// 3. 创建本地变量用于模态框的v-model绑定
const localVisible = ref(props.modelValue);
const selectedFile = ref(null);
// 4. 监听父组件传入的modelValue变化同步到本地变量
watch(
() => props.modelValue,
(newVal) => {
localVisible.value = newVal;
}
);
// 5. 监听本地变量变化,通知父组件(实现双向绑定)
watch(
() => localVisible.value,
(newVal) => {
emit('update:modelValue', newVal);
}
);
// 处理取消
const handleCancel = () => {
localVisible.value = false; // 修改本地变量
selectedFile.value = null;
};
// 处理下载模板
const handleDownloadTemplate = () => {
emit('download');
};
// 上传前的校验
const beforeUpload = (file) => {
const isExcel = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|| file.type === 'application/vnd.ms-excel';
if (!isExcel) {
message.error('请上传Excel格式的文件.xls或.xlsx');
return false;
}
const isLt10M = file.size / 1024 / 1024 < 10;
if (!isLt10M) {
message.error('文件大小不能超过10M');
return false;
}
selectedFile.value = file;
return false;
};
// 处理文件上传
const handleFileUpload = () => {
// 自定义上传逻辑
};
// 清除选中的文件
const clearSelectedFile = () => {
selectedFile.value = null;
};
// 确认上传
const handleConfirmUpload = () => {
if (selectedFile.value) {
emit('upload', selectedFile.value);
localVisible.value = false; // 上传后关闭模态框
}
};
</script>
<style scoped>
.import-container {
background-color: #ffffff;
border-radius: 4px;
overflow: hidden;
}
.import-section {
padding: 16px 16px;
background-color: #fafafa;
transition: all 0.3s ease;
}
.import-section.section-top {
/* border-bottom: 1px solid #e8e8e8; */
margin-bottom: 8px;
border-radius: 4px 4px 0 0;
}
.import-section.section-bottom {
border-radius: 0 0 4px 4px;
}
.section-title {
margin: 0 0 8px 0;
font-size: 14px;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
}
.required-mark {
color: #ff4d4f;
margin-right: 4px;
}
.section-desc {
margin: 0 0 16px 0;
font-size: 12px;
color: rgba(0, 0, 0, 0.65);
line-height: 1.5;
}
.file-info {
display: flex;
align-items: center;
padding: 12px;
/* background-color: #f5f5f5; */
border-radius: 4px;
}
.file-icon {
font-size: 48px;
color: #00b42a;
margin-right: 16px;
}
.file-detail {
flex: 1;
}
.file-format {
margin: 0 0 8px 0;
font-size: 12px;
color: rgba(0, 0, 0, 0.75);
}
.action-btn {
margin-bottom: 8px;
}
.selected-file {
display: flex;
align-items: center;
font-size: 12px;
color: rgba(0, 0, 0, 0.9);
max-width: 300px;
padding: 4px 0;
}
.file-name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 8px;
background-color: #fff;
padding: 2px 6px;
border-radius: 2px;
border: 1px solid #e8e8e8;
}
.remove-icon {
color: rgba(0, 0, 0, 0.45);
cursor: pointer;
transition: color 0.3s;
}
.remove-icon:hover {
color: #ff4d4f;
}
.modal-footer {
display: flex;
justify-content: flex-end;
padding: 16px;
border-top: 1px solid #f0f0f0;
margin-top: 8px;
}
.modal-footer > button:not(:last-child) {
margin-right: 8px;
}
</style>