<template>
|
<el-dialog :title="`导入${importLabel}`" :visible.sync="visible" width="600px">
|
<div class="batch-import-container">
|
<!-- 导入类型选择 -->
|
<el-form label-width="100px" v-if="showTypeSelector">
|
<el-form-item label="样本类型">
|
<el-radio-group v-model="importType">
|
<el-radio :label="1">正样本</el-radio>
|
<el-radio :label="2">负样本</el-radio>
|
<el-radio :label="3">待标记样本</el-radio>
|
</el-radio-group>
|
</el-form-item>
|
</el-form>
|
|
<!-- 上传区域 -->
|
<div class="upload-area" @dragover.prevent @drop="onDrop">
|
<div class="upload-content">
|
<i class="el-icon-upload"></i>
|
<div class="upload-text">
|
<p>将图片拖放到此处,或</p>
|
<el-button type="primary">选择图片</el-button>
|
</div>
|
<p class="upload-hint">支持JPG/PNG格式,最多100张图片,单张最大5MB</p>
|
</div>
|
<input
|
type="file"
|
ref="fileInput"
|
class="file-input"
|
multiple
|
accept="image/*"
|
@change="handleFileChange"
|
>
|
</div>
|
|
<!-- 图片预览区 -->
|
<div class="image-preview">
|
<div class="preview-header">
|
<span>已选择图片 ({{ fileList.length }})</span>
|
<el-button
|
type="text"
|
:disabled="fileList.length === 0"
|
@click="fileList = []"
|
>
|
清空
|
</el-button>
|
</div>
|
|
<div class="preview-content">
|
<div
|
class="preview-item"
|
v-for="(file, index) in fileList"
|
:key="index"
|
>
|
<img :src="getPreviewUrl(file)" alt="预览图">
|
<div class="image-info">
|
<span class="file-name">{{ file.name }}</span>
|
<span class="file-size">{{ formatSize(file.size) }}</span>
|
</div>
|
<i
|
class="el-icon-delete"
|
title="删除"
|
@click="removeFile(index)"
|
></i>
|
</div>
|
|
<div class="empty-hint" v-if="fileList.length === 0">
|
暂未选择图片
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<div slot="footer" class="dialog-footer">
|
<el-button @click="visible = false">取 消</el-button>
|
<el-button
|
type="primary"
|
:disabled="fileList.length === 0"
|
@click="submitImport"
|
>
|
导 入
|
</el-button>
|
</div>
|
</el-dialog>
|
</template>
|
|
<script>
|
export default {
|
name: 'BatchImport',
|
props: {
|
// 是否显示类型选择器(用于区分导入按钮和下拉导入)
|
showTypeSelector: {
|
type: Boolean,
|
default: true
|
},
|
// 预设的导入类型(1-正样本、2-负样本、3-待标记)
|
presetType: {
|
type: Number,
|
default: 0
|
}
|
},
|
data() {
|
return {
|
visible: false,
|
importType: this.presetType || 1,
|
fileList: []
|
};
|
},
|
computed: {
|
importLabel() {
|
const labels = {1: '正样本', 2: '负样本', 3: '待标记样本'};
|
return this.presetType ? labels[this.presetType] : labels[this.importType];
|
}
|
},
|
methods: {
|
open() {
|
this.visible = true;
|
this.fileList = [];
|
if (!this.presetType) this.importType = 1;
|
},
|
|
close() {
|
this.visible = false;
|
},
|
|
onDrop(e) {
|
e.preventDefault();
|
this.addFiles(e.dataTransfer.files);
|
},
|
|
handleFileChange(e) {
|
this.addFiles(e.target.files);
|
// 重置input以便可以再次选择相同文件
|
e.target.value = null;
|
},
|
|
addFiles(fileList) {
|
const files = Array.from(fileList);
|
// 过滤非图片文件
|
const validFiles = files.filter(file => file.type.startsWith('image/'));
|
|
// 限制文件数量 (最多100张)
|
if (this.fileList.length + validFiles.length > 100) {
|
this.$message.warning('最多支持100张图片导入');
|
return;
|
}
|
|
validFiles.forEach(file => {
|
// 检查文件大小 (5MB以内)
|
if (file.size > 5 * 1024 * 1024) {
|
this.$message.warning(`文件 ${file.name} 超过5MB限制`);
|
return;
|
}
|
this.fileList.push(file);
|
});
|
},
|
|
getPreviewUrl(file) {
|
return URL.createObjectURL(file);
|
},
|
|
formatSize(size) {
|
if (size < 1024) return size + ' B';
|
if (size < 1024 * 1024) return (size / 1024).toFixed(1) + ' KB';
|
return (size / (1024 * 1024)).toFixed(1) + ' MB';
|
},
|
|
removeFile(index) {
|
this.fileList.splice(index, 1);
|
},
|
|
submitImport() {
|
const finalImportType = this.presetType || this.importType;
|
const fileNames = this.fileList.map(f => f.name);
|
|
this.$emit('import', {
|
type: finalImportType,
|
files: this.fileList
|
});
|
|
// this.$message.success(`成功导入 ${fileNames.length} 张图片`);
|
this.close();
|
}
|
}
|
};
|
</script>
|
|
<style scoped>
|
.batch-import-container {
|
padding: 10px;
|
}
|
|
.upload-area {
|
position: relative;
|
border: 2px dashed #dcdfe6;
|
border-radius: 6px;
|
padding: 20px;
|
text-align: center;
|
margin-bottom: 20px;
|
cursor: pointer;
|
transition: border-color 0.3s;
|
}
|
|
.upload-area:hover {
|
border-color: #409EFF;
|
}
|
|
.upload-content {
|
pointer-events: none;
|
}
|
|
.upload-content i {
|
font-size: 48px;
|
color: #c0c4cc;
|
margin-bottom: 15px;
|
}
|
|
.upload-text {
|
margin-bottom: 10px;
|
}
|
|
.upload-hint {
|
color: #909399;
|
font-size: 12px;
|
margin-top: 10px;
|
}
|
|
.file-input {
|
position: absolute;
|
top: 0;
|
left: 0;
|
width: 100%;
|
height: 100%;
|
opacity: 0;
|
cursor: pointer;
|
}
|
|
.image-preview {
|
border: 1px solid #ebeef5;
|
border-radius: 4px;
|
max-height: 300px;
|
overflow-y: auto;
|
}
|
|
.preview-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 10px 15px;
|
background-color: #f5f7fa;
|
border-bottom: 1px solid #ebeef5;
|
}
|
|
.preview-content {
|
padding: 10px;
|
}
|
|
.preview-item {
|
position: relative;
|
display: flex;
|
align-items: center;
|
padding: 10px;
|
border-bottom: 1px solid #f1f1f1;
|
}
|
|
.preview-item:hover {
|
background-color: #f8f8f8;
|
}
|
|
.preview-item img {
|
width: 50px;
|
height: 50px;
|
object-fit: cover;
|
border-radius: 4px;
|
margin-right: 10px;
|
}
|
|
.image-info {
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
}
|
|
.file-name {
|
font-size: 14px;
|
margin-bottom: 5px;
|
white-space: nowrap;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
max-width: 380px;
|
}
|
|
.file-size {
|
color: #909399;
|
font-size: 12px;
|
}
|
|
.preview-item .el-icon-delete {
|
color: #f56c6c;
|
font-size: 16px;
|
cursor: pointer;
|
}
|
|
.empty-hint {
|
text-align: center;
|
padding: 30px;
|
color: #909399;
|
}
|
</style>
|