表格选择和子选择测试

Posted by Shallow Dreameron March 9, 2025
<template>
  <input type="file" webkitdirectory directory multiple @change="handleFolderUpload" />
  <el-table :data="tableData" border style="width: 100%" row-key="id" ref="mainTable">
    <el-table-column
        type="selection"
        width="55"
        :reserve-selection="true"
        @select="handleParentSelect"
        @select-all="handleParentSelectAll"
    />
    <el-table-column prop="group" label="组" />

    <el-table-column label="thru">
      <template #default="{ row }">
        <el-popover
            placement="right"
            title="thru 详情"
            width="400"
            trigger="click"
        >
          <template #reference>
            <el-button type="primary">查看</el-button>
          </template>
          <el-table
              :data="row.thru"
              border
              row-key="id"
              ref="getThruRef(row.id)"
              @selection-change="(val) => handleInnerSelectionChange(val, row, 'thru')"
          >
            <el-table-column type="selection" width="50" />
            <el-table-column prop="name" label="文件名" />
          </el-table>
        </el-popover>
      </template>
    </el-table-column>

    <el-table-column label="xtalk">
      <template #default="{ row }">
        <el-popover
            placement="right"
            title="xtalk 详情"
            width="400"
            trigger="click"
        >
          <template #reference>
            <el-button type="primary">查看</el-button>
          </template>
          <el-table
              :data="row.xtalk"
              border
              row-key="id"
              ref="getXtalkRef(row.id)"
              @selection-change="(val) => handleInnerSelectionChange(val, row, 'xtalk')"
          >
            <el-table-column type="selection" width="50" />
            <el-table-column prop="name" label="文件名" />
          </el-table>
        </el-popover>
      </template>
    </el-table-column>
  </el-table>

  <pre></pre>
</template>

<script setup>
import {ref, nextTick} from "vue";

const mainTable = ref(null);
const tableData = ref([]);

const selectedItems = ref([]);

const tableRefs = ref({});

const getThruRef = (id) => (el) => tableRefs.value[`thru-${id}`] = el;
const getXtalkRef = (id) => (el) => tableRefs.value[`xtalk-${id}`] = el;

const parseFolderStructure = (folderFiles) => {
  const data = [];

  folderFiles.forEach(filePath => {
    const parts = filePath.split('/');
    const groupName = parts[1]; // 修改为从第二层开始作为组
    const subFolder = parts[2];
    const fileName = parts.slice(3).join('/');

    let group = data.find(group => group.group === groupName);
    if (!group) {
      group = {
        id: data.length + 1,
        group: groupName,
        thru: [],
        xtalk: [],
        selected: false
      };
      data.push(group);
    }

    const fileData = {
      id: `${group.id}-${fileName}`,
      name: fileName,
      extraInfo: `来自 ${subFolder}`,
      selected: false
    };

    if (subFolder === 'thru') {
      group.thru.push(fileData);
    } else if (subFolder === 'xtalk') {
      group.xtalk.push(fileData);
    }
  });

  return data;
};

const handleFolderUpload = (event) => {
  const folderFiles = Array.from(event.target.files).map(file => file.webkitRelativePath);
  tableData.value = parseFolderStructure(folderFiles);
};

const updateSelectedData = () => {
  selectedItems.value = tableData.value.map(row => ({
    id: row.id,
    group: row.group,
    thru: row.thru.map(file => ({...file})),
    xtalk: row.xtalk.map(file => ({...file}))
  }));
};

const handleParentSelectAll = async (isSelected) => {
  tableData.value.forEach(row => {
    row.selected = isSelected;
    row.thru.forEach(file => (file.selected = isSelected));
    row.xtalk.forEach(file => (file.selected = isSelected));
  });

  await nextTick();
  Object.values(tableRefs.value).forEach(ref => ref?.toggleAllSelection?.());
  mainTable.value.toggleAllSelection();

  updateSelectedData();
};

const handleParentSelect = (selection, row) => {
  const isSelected = selection.some(item => item.id === row.id);
  row.selected = isSelected;
  row.thru.forEach(file => (file.selected = isSelected));
  row.xtalk.forEach(file => (file.selected = isSelected));
  updateSelectedData();
};

const handleInnerSelectionChange = (selectedRows, row, type) => {
  row[type].forEach(file => {
    file.selected = selectedRows.some(selected => selected.id === file.id);
  });

  const allSelected = [...row.thru, ...row.xtalk].every(file => file.selected);
  const anySelected = [...row.thru, ...row.xtalk].some(file => file.selected);

  row.selected = allSelected;

  const elTable = document.querySelector(".el-table__body-wrapper table");
  const rowIndex = tableData.value.findIndex(item => item.id === row.id);
  const checkbox = elTable.querySelectorAll(".el-checkbox__input")[rowIndex];

  checkbox.classList.toggle("is-indeterminate", !allSelected && anySelected);
  checkbox.classList.toggle("is-checked", allSelected);

  updateSelectedData();
};
</script>