功能:
(1)文件上传时可以预览内容。
(2)对文件名进行判断,不满足条件时提示错误。
(3)对文件表头进行检测,如有错误,将错误内容显示在预览区域中(同时可对错误的单元格进行标红显示)。
(4)错误内容没有修复前,点击上传会提示“請先處理文件錯誤后,再進行上傳!”
目前问题:无法有效处理单元格合并时的显示问题
1、FlieUpload.vue
<template>
<div class="iwpp-file-manage">
<div class='iwpp-file-container'>
<h3>文件上傳</h3>
<el-upload ref="uploadRef" class="iwpp-file-upload" accept=".xlsx, .xls" max='1' :show-file-list="false"
:before-upload="beforeUpload" :http-request="handleUpload">
<el-button type="primary">點擊選擇 Excel 文件</el-button>
<p>注意:只支持 Excel 文件格式,且第一行必須爲表頭</p>
</el-upload>
<!-- 数据预览表格 -->
<div class="iwpp-file-table-box">
<h3>{{ fileName }}</h3>
<p>{{ tabelErrorMsg }}</p>
<div class="iwpp-file-table-preview">
<table id="iwpp-file-table" style="border-collapse: collapse; "></table>
</div>
<div class="iwpp-file-table-btn">
<button id="clearButton">取消</button>
<button id="confirmButton">確定上傳</button>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessage, UploadInstance, ElLoading} from 'element-plus'
import * as XLSX from 'xlsx'
import { axios_post } from '@/utils/axiosinstance';
const fileName = ref('')
const uploadRef = ref<UploadInstance | null>(null);
const currentFile = ref(null);
const isClickDisabled = ref(false);
const tabelErrorMsg = ref('');
// 上传前的类型验证
const beforeUpload = (file) => {
const isExcel = /\.(xlsx|xls)$/.test(file.name)
clearUpload();
if (!isExcel) {
ElMessage.error('仅支持上传 Excel 文件!')
return false
}
return true
}
// 处理文件上传
const handleUpload = async ({ file }) => {
currentFile.value = file
const reader = new FileReader()
fileName.value = file.name
// 验证文件名格式
if(fileName.value.length > 0){
// 你的文件名判断逻辑
}
reader.onload = (e) => {
const data = new Uint8Array(e.target.result)
const workbook = XLSX.read(data, { type: 'array' })
// 取第一个工作表
const firstSheetName = workbook.SheetNames[0]
const worksheet = workbook.Sheets[firstSheetName]
if(!worksheet['!ref']){
return ElMessage.error('文件内容为空!');
}
// 生成表格 HTML
const tableHtml = generateTableHtml(worksheet);
const iwppFileTable = document.getElementById('iwpp-file-table') as HTMLTableElement;
iwppFileTable.innerHTML = tableHtml;
const iwppFileTableHeader = iwppFileTable.querySelector('tr') as HTMLTableRowElement;
// 验证表头格式
const iwppFileTableHeaderCells = iwppFileTableHeader.querySelectorAll('td') as NodeListOf<HTMLTableCellElement>;
let tableHeaderErr = '';
if (iwppFileTableHeaderCells.length == 0) {
tableHeaderErr = '表格中沒有表頭;';
tabelErrorMsg.value += '';
return ElMessage.error(tableHeaderErr)
}
for (let i = 0; i < iwppFileTableHeaderCells.length; i++) {
const cell = iwppFileTableHeaderCells[i];
if(!cell.innerText){
tableHeaderErr += '第' + (i+1) + '列沒有標題;';
cell.style.border = '3px solid #cc0000';
cell.style.color = '#cc0000';
continue;
}
// 你的其他表头判断逻辑
}
if(tableHeaderErr.length > 0){
tabelErrorMsg.value += '表格標題格式錯誤:' + tableHeaderErr;
}else{
tabelErrorMsg.value = '';
}
iwppFileTableHeader.style.fontWeight = 'bold';
iwppFileTableHeader.style.height = '30px';
// 显示表名和上傳
var tableTitle = document.querySelector('.iwpp-file-table-box > h3') as HTMLElement;
var tableErrorP = document.querySelector('.iwpp-file-table-box > p') as HTMLElement;
var previewDiv = document.querySelector('.iwpp-file-table-preview') as HTMLElement;
var tableDiv = document.querySelector('.iwpp-file-table-btn') as HTMLElement;
if (tableTitle) {
tableTitle.style.display = 'block';
tableErrorP.style.display = 'block';
previewDiv.style.display = 'block';
tableDiv.style.display = 'block';
// 绑定取消和上傳的按钮事件
var clearButton = document.getElementById('clearButton') as HTMLElement;
var confirmButton = document.getElementById('confirmButton') as HTMLElement;
clearButton.removeEventListener('click', clearButtonClickListener)
clearButton.addEventListener('click', clearButtonClickListener)
confirmButton.removeEventListener('click', confirmButtonClickListener);
confirmButton.addEventListener('click', confirmButtonClickListener);
}
}
reader.readAsArrayBuffer(file)
}
// 生成表格HTML(预览的重点在于此处)
function generateTableHtml(worksheet) {
const range = XLSX.utils.decode_range(worksheet['!ref']);
let tableHtml = '';
for (let row = range.s.r; row <= range.e.r; row++) {
tableHtml += '<tr style="">';
for (let col = range.s.c; col <= range.e.c; col++) {
const cellAddress = XLSX.utils.encode_cell({ r: row, c: col });
const cell = worksheet[cellAddress];
const cellValue = cell ? XLSX.utils.format_cell(cell) : '';
tableHtml += `<td style="border: 1px solid #ccc; min-width:80px; text-align:center; font-size:16px; padding:3px 8px; color: #4e4f4f;">${cellValue}</td>`;
}
tableHtml += '</tr>';
}
return tableHtml;
}
// 绑定点击事件
const clearButtonClickListener = () => {
clearUpload();
};
const confirmButtonClickListener = () => {
if (isClickDisabled.value) {
return;
}
isClickDisabled.value = true;
handleConfirm()
isClickDisabled.value = false;
};
// 清除上传文件以及预览框
const clearUpload = () => {
var tableTitle = document.querySelector('.iwpp-file-table-box > h3') as HTMLElement;
var tableErrorP = document.querySelector('.iwpp-file-table-box > p') as HTMLElement;
var previewDiv = document.querySelector('.iwpp-file-table-preview') as HTMLElement;
var tableDiv = document.querySelector('.iwpp-file-table-btn') as HTMLElement;
tableTitle.style.display = 'none';
tableErrorP.style.display = 'none';
tableDiv.style.display = 'none';
previewDiv.style.display = 'none';
document.getElementById('iwpp-file-table').innerHTML = '';
tabelErrorMsg.value = '';
fileName.value = '';
if (uploadRef.value) {
uploadRef.value.clearFiles();
}
};
// 上传文件逻辑
const handleConfirm = () => {
if(tabelErrorMsg.value.length > 0){
return ElMessage.error('請先處理文件錯誤后,再進行上傳!');
}
var file = currentFile.value;
var fileData = new FormData();
fileData.append('file', file);
let loadingInstance : any;
axios_post({
url: '你的地址',
data: fileData,
headers: {
'Content-Type': 'multipart/form-data'
},
onUploadProgress: progressEvent => {
if (!loadingInstance) {
loadingInstance = ElLoading.service({
lock: true,
text: '正在上傳文件...',
background: 'rgba(0, 0, 0, 0.7)',
});
}
}
}).then(res => {
if (loadingInstance) {
loadingInstance.close();
}
// 你的res处理逻辑
}).catch(err => {
if (loadingInstance) {
loadingInstance.close();
}
// 你的err处理逻辑
});
};
</script>
<style lang="scss" scoped>
.iwpp-file-manage {
width: 100%;
height: 100%;
background-color: $bg;
}
.iwpp-file-container {
padding: 30px;
>h3:nth-of-type(1) {
font-size: 32px;
color: #eee;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
user-select: none;
}
.iwpp-file-upload {
button {
width: 200px;
height: 40px;
font-size: 16px;
}
p {
font-size: 14px;
color: #eee;
margin-left: 15px;
user-select: none;
}
}
.iwpp-file-table-box {
>h3 {
font-size: 22px;
color: #4e4f4f;
padding: 20px 10px 10px;
background-color: #fff;
text-align: center;
margin-top: 20px;
display: none;
}
>p{
background-color: #fff;
font-size: 14px;
color:#cc0000;
text-align: center;
padding: 0 10px 10px;
display: none;
}
.iwpp-file-table-preview {
height: 500px;
background-color: #fff;
overflow: auto;
display: none;
padding:0 20px;
}
.iwpp-file-table-btn {
display: none;
text-align: right;
margin-top: 20px;
#clearButton {
margin-right: 20px;
width: 100px;
height: 36px;
font-size: 16px;
background-color: #dbdbdb;
color: #333;
border: none;
border-radius: 4px;
cursor: pointer;
}
#confirmButton {
width: 100px;
height: 36px;
font-size: 16px;
background-color: #409eff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}
}
}
}
</style>