功能:
(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>

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注