当前位置: 首页 > news >正文

vue3.2 + vxe-table4.x 实现多层级结构的 合并、 展开、收起 功能

<template>
  <div style="padding: 20px">
    <vxe-table border :data="list" :height="800" :span-method="rowspanMethod">
      <vxe-column title="一级类目" field="category1">
        <template #default="{ row }">
          <a-space>
            <span>{{ row.category1 }}</span>
            <a-button @click="toggleCategoryExpand(row, '1')">
              {{ showText(row, '1') ? '收起' : '展开' }}
            </a-button>
          </a-space>
        </template>
      </vxe-column>
      <vxe-column title="二级类目" field="category2">
        <template #default="{ row }">
          <a-space>
            <span>{{ row.category2 }}</span>
            <a-button
              v-if="showText(row, '1')"
              @click="toggleCategoryExpand(row, '2')"
            >
              {{ showText(row, '2') ? '收起' : '展开' }}
            </a-button>
          </a-space>
        </template>
      </vxe-column>
      <vxe-column title="三级类目" field="category3"></vxe-column>
      <vxe-column title="报告金额" field="amount"></vxe-column>
      <vxe-column title="合计" field="total"></vxe-column>
    </vxe-table>
  </div>
</template>

<script>
import { defineComponent, ref } from 'vue'
import XEUtils from 'xe-utils'

export default defineComponent({
  setup() {
    const flattenedData = [
      {
        id: '0',
        category: '人工成本',
        parentId: null
      },
      {
        id: '0-0',
        parentId: '0',
        category: '人工成本0-0'
      },
      {
        id: '0-0-0',
        parentId: '0-0',
        category: '人工成本0-0-0'
      },
      {
        id: '0-0-1',
        parentId: '0-0',
        category: '人工成本0-0-1'
      },
      {
        id: '0-1',
        parentId: '0',
        category: '人工成本0-1'
      },
      {
        id: '0-1-0',
        parentId: '0-1',
        category: '人工成本0-1-0'
      },
      {
        id: '0-1-1',
        parentId: '0-1',
        category: '人工成本0-1-1'
      }
    ]
    const treeData = XEUtils.toArrayTree(flattenedData)
    const treeDataTemp = JSON.parse(JSON.stringify(treeData))
    const renderTreeData = ref(treeDataTemp)
    const list = ref([])

    // 工具方法
    const toColTreeData = (treeData) => {
      const options = { children: 'children' }
      const list = []
      const keyMap = {}
      XEUtils.eachTree(
        treeData,
        (item, index, result, paths, parent) => {
          keyMap[item.id] = item
          item.keys = parent ? parent.keys.concat([item.id]) : [item.id]
          if (!item.children || !item.children.length) {
            const row = {}
            item.keys.forEach((key, index) => {
              const level = index + 1
              const obj = keyMap[key]
              row[`category${level}`] = obj.category
              row[`id${level}`] = obj.id
            })
            list.push(row)
          }
        },
        options
      )
      return list
    }

    const rowspanMethod = ({ row, _rowIndex, column, visibleData }) => {
      const fields = ['category1', 'category2']
      const cellValue = row[column.field]
      if (cellValue && fields.includes(column.field)) {
        const prevRow = visibleData[_rowIndex - 1]
        let nextRow = visibleData[_rowIndex + 1]
        if (prevRow && prevRow[column.field] === cellValue) {
          return { rowspan: 0, colspan: 0 }
        } else {
          let countRowspan = 1
          while (nextRow && nextRow[column.field] === cellValue) {
            nextRow = visibleData[++countRowspan + _rowIndex]
          }
          if (countRowspan > 1) {
            return { rowspan: countRowspan, colspan: 1 }
          }
        }
      }
    }

    renderTreeData.value.forEach((item) => {
      if (item.children.length) {
        item.children = []
      }
    })

    list.value = toColTreeData(renderTreeData.value)

    const toggleCategoryExpand = (row, level) => {
      if (level === '1') {
        toggleLevelOne(row)
      }
      if (level === '2') {
        toggleLevelTwo(row)
      }
    }
    const toggleLevelOne = (row) => {
      const { id1 } = row
      const item = renderTreeData.value.find((item) => item.id === id1)
      if (item.children.length) {
        item.children = []
      } else {
        const a = treeData.find((item) => item.id === id1)
        item.children = JSON.parse(JSON.stringify(a.children))
        item.children.forEach((child) => {
          child.children = []
        })
      }
      list.value = toColTreeData(renderTreeData.value)
    }

    const toggleLevelTwo = (row) => {
      const { id1, id2 } = row
      const item1 = renderTreeData.value.find((item) => item.id === id1)
      const item2 = item1.children.find((item) => item.id === id2)
      if (item2.children.length) {
        item2.children = []
      } else {
        const a1 = treeData.find((item) => item.id === id1)
        const a2 = a1.children.find((item) => item.id === id2)
        item2.children = a2.children
      }
      list.value = toColTreeData(renderTreeData.value)
    }

    const showText = (row, level) => {
      const { id1, id2 } = row
      if (level === '1') {
        const item = renderTreeData.value.find((item) => item.id === id1)
        if (item) {
          return item.children.length
        }
        return false
      }
      if (level === '2') {
        const item1 = renderTreeData.value.find((item) => item.id === id1)
        const item2 = item1.children.find((item) => item.id === id2)
        if (item2) {
          return item2.children.length
        }
        return false
      }
    }

    return {
      rowspanMethod,
      toggleCategoryExpand,
      list,
      showText
    }
  }
})
</script>

在这里插入图片描述

相关文章:

  • Three.js 与 Cesium.js 的开源:three-cesium-examples
  • 协议-CoAP
  • DeepSeek-OpenSourceWeek-第三天-Release of DeepGEMM
  • 《deepseek FlashMLA :高效的 MLA 解码内核》:此文为AI自动翻译
  • Mac本地部署Deep Seek R1
  • Mybatis面试总结(下):xml文件和mybatis内部结构的映射关系是?为什么说MyBatis是半自动ORM?它与全自动的区别是?
  • JVM线程分析详解
  • C高级——shell(3)
  • Professional Pycharm教程
  • Jmeter基础知识总结
  • [笔记.AI]AI知识科普提纲
  • 《昇思25天学习打卡营第14天|计算机视觉-ShuffleNet图像分类》
  • Flutter 学习之旅 之 flutter 在 Android 端读取相册图片显示
  • 浅谈对目前 Deep Seek 的看法
  • HOW POWERFUL ARE GRAPH NEURAL NETWORKS?(GIN)
  • DAV_postgresql_2-user_role
  • unity 红点树
  • 网络安全应急响应中主机历史命令被删除 网络安全事件应急响应
  • JAVA面试常见题_基础部分_mybatis面试题
  • Spark RDD持久化机制深度解析
  • 比特币价格重返10万美元,哪些因素使然?
  • 古埃及展进入百天倒计时,闭幕前168小时不闭馆
  • 雇来的“妈妈”:为入狱雇主无偿带娃4年,没做好准备说再见
  • 上海交大:关注到对教师邵某的网络举报,已成立专班开展调查
  • 西南大学教授、重庆健美运动奠基人之一李启圣逝世
  • 欧盟委员会计划对950亿欧元美国进口产品采取反制措施