<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>
