<div id="app">
<el-table :data="tableData" border size="mini" :span-method="tableSpanMethod">
<el-table-column align="center" prop="index1" label="一级指标">
<template slot-scope="scope">
<el-checkbox
v-model="scope.row.index1.check"
:indeterminate="scope.row.index1.isIndeterminate"
@change="checkboxChange($event, scope.row.index1)">
{{ scope.row.index1.label }}
</el-checkbox>
</template>
</el-table-column>
<el-table-column align="center" prop="index2" label="二级指标">
<template slot-scope="scope">
<el-checkbox
v-model="scope.row.index2.check"
:indeterminate="scope.row.index2.isIndeterminate"
@change="checkboxChange($event, scope.row.index2)">
{{ scope.row.index2.label }}
</el-checkbox>
</template>
</el-table-column>
<el-table-column align="center" prop="index3" label="三级指标">
<template slot-scope="scope">
<el-checkbox
v-model="scope.row.index3.check"
:indeterminate="scope.row.index3.isIndeterminate"
@change="checkboxChange($event, scope.row.index3)">
{{ scope.row.index3.label }}
</el-checkbox>
</template>
</el-table-column>
<el-table-column align="center" prop="index4" label="四级指标">
<template slot-scope="scope">
<el-checkbox
v-model="scope.row.index4.check"
:indeterminate="scope.row.index4.isIndeterminate"
@change="checkboxChange($event, scope.row.index4)">
{{ scope.row.index4.label }}
</el-checkbox>
</template>
</el-table-column>
<el-table-column align="center" prop="index5.label" label="五级指标"></el-table-column>
</el-table>
</div>
<script>
export default {
data(){
return {
tableData: [],
testData: [
{
id: '1',
pId: '0',
label: '基础功能',
check: false,
isIndeterminate: false,
children: [
{
id: '1-1',
pId: '1',
label: '需求池',
check: false,
isIndeterminate: false,
children: [
{
id: '1-1-1',
pId: '1-1',
label: '排序',
check: false,
isIndeterminate: false,
children: [
{
id: '1-1-1-1',
pId: '1-1-1',
label: '日期排序',
check: false,
isIndeterminate: false,
children: [
{
id: '1-1-1-1-1',
pId: '1-1-1-1',
label: 'platform',
children: []
}
]
},{
id: '1-1-1-2',
pId: '1-1-1',
label: '名称排序',
check: false,
isIndeterminate: false,
children: [
{
id: '1-1-1-2-1',
pId: '1-1-1-2',
label: 'gisquest',
children: []
}
]
}
]
},{
id: '1-1-2',
pId: '1-1',
label: '排期',
check: false,
isIndeterminate: false,
children: [
{
id: '1-1-2-1',
pId: '1-1-2',
label: '季度排期',
check: false,
isIndeterminate: false,
children: [
{
id: '1-1-2-1-1',
pId: '1-1-2-1',
label: 'platform',
children: []
}
]
}
]
}
]
},{
id: '1-2',
pId: '1',
label: '专项工作',
check: false,
isIndeterminate: false,
children: [
{
id: '1-2-1',
pId: '1-2',
label: '任务工单',
check: false,
isIndeterminate: false,
children: [
{
id: '1-2-1-1',
pId: '1-2-1',
label: '知识沉淀',
check: false,
isIndeterminate: false,
children: [
{
id: '1-2-1-1-1',
pId: '1-2-1-1',
label: 'gisquest',
children: []
}
]
}
]
}
]
}
]
}
],
}
}
},
mounted() {
this.treeToTableData();
},
methods: {
treeToTableData(){
let ewArr = this.parseTreeToRow(this.testData);
let tableData = [];
ewArr.map(item => {
let obj = {};
item.map((itemc, indexb) => {
obj['index' + (indexb + 1)] = {
id: itemc.id,
pId: itemc.pId,
label: itemc.label,
check: itemc.check,
isIndeterminate: itemc.isIndeterminate,
};
})
tableData.push(obj)
})
this.tableData = tableData;
},
/**
* 递归-----将树结构数据格式,转化为,二维数组 表格形式
* @param node 树的源数据
* @param data 树转化为二维数组的数据
* @param row 临时存储数据
* @returns {*[]}
*/
parseTreeToRow(node, data = [], row = []) {
node.map(item => {
let obj = {
id: item.id,
pId: item.pId,
label: item.label,
check: item.check,
isIndeterminate: item.isIndeterminate,
}
if(item.children && item.children.length != 0){
this.parseTreeToRow(item.children, data, [...row, obj]);
}else{
data.push([...row, obj])
}
})
return data;
},
/**
* 合并行或列的计算方法
*/
tableSpanMethod({row, column, rowIndex, columnIndex}){
return {
rowspan: columnIndex < 4 ? this.mergeRows(row[column.property], this.tableData, rowIndex, column.property) : 1,
colspan: 1
};
},
/**
* 表格单元格合并-----行
* @param {Object} value 当前单元格的值
* @param {Object} data 当前表格所有数据
* @param {Object} index 当前单元格的值所在 行 索引
* @param {Object} property 当前列的property
* @returns {number} 待合并单元格数量
*/
mergeRows(value, data, index, property) {
// 判断 当前行的该列数据 与 上一行的该列数据 是否相等
if (index !== 0 && value.label === data[index - 1][property].label) {
// 返回 0 使表格被跨 行 的那个单元格不会渲染
return 0;
};
// 判断 当前行的该列数据 与 下一行的该列数据 是否相等
let rowSpan = 1;
for (let i = index + 1; i < data.length; i++) {
if (value.label !== data[i][property].label) {
break;
};
rowSpan++;
};
return rowSpan;
},
/**
* checkbox 切换事件
* @param val 切换后的值
* @param cell 当前单元格的值
*/
checkboxChange(val, cell){
// 根据 id pid 获取到的节点
let getNode = this.queryNodeById(this.testData, cell.id, cell.pId);
// 当前节点 和 当前节点的所有父级节点集合
let currentNode = getNode.cNode, parentNode = getNode.pNodes;
// 递归当前节点以及所有子节点 设置全部选中与否
this.setTreeRecursion(currentNode, val);
// 递归每个父节点的全部子节点个数,以及每个父节点的全部选中的子节点个数
parentNode.map(item => {
let num = this.queryNodesTotal(item.children);
let childrenNum = num.total;
let childrenCheckNum = num.checkTotal;
// 设置 父节点的选中 与 isIndeterminate
item.check = childrenNum == childrenCheckNum;
item.isIndeterminate = childrenCheckNum > 0 && childrenCheckNum < childrenNum;
})
// 重新构造表格数据
this.treeToTableData();
},
/**
* 递归-----根据 id 查询当前节点 和 根据 pId 查询 当前节点的所有父级节点集合
* @param node 树的源数据
* @param nodeId 节点的 id
* @param nodePid 节点的 pId
* @param temp 返回的匹配的节点数据集合
* @returns {{pNodes: *[], cNode: {}}} pNodes: 父级节点集合,cNode:当前节点
*/
queryNodeById(node, nodeId, nodePid, temp = { cNode: {}, pNodes: [] }){
let forFn = (arr, id, pId) => {
for (let i = 0; i < arr.length; i++) {
if (arr[i].id === id) {
temp.cNode = arr[i];
break;
}else if (arr[i].id === pId) {
temp.pNodes.push(arr[i]);
forFn(node, id, arr[i].pId);
break;
} else {
if (arr[i].children) {
forFn(arr[i].children, id, pId)
}
}
}
}
forFn(node, nodeId, nodePid);
return temp;
},
/**
* 递归-----树组件节点属性修改
* @param data 树的源数据
* @param val 修改属性的值
* @returns {*} 属性修改后的树的数据
*/
setTreeRecursion(data, val) {
if(data.check != undefined && data.check != null){
data.check = val; // 切换当前 checkbox 选中状态
data.isIndeterminate = false; // 切换当前 checkbox 时,要取消 isIndeterminate
}
if(data.children){
data.children.map((item, index) => {
this.setTreeRecursion(item, val);
});
}
return data;
},
/**
* 递归-----查询 树组件 共有多少节点
* @param data data树的源数据
* @param num num 总节点数
* @returns {{checkTotal: number, total: number}} checkTotal: 选中的节点总数,total: 所有节点总数
*/
queryNodesTotal(data, num = { total: 0, checkTotal: 0 }){
let forFn = nodes => {
for(let i = 0; i < nodes.length; i++){
if(nodes[i].check != undefined && nodes[i].check != null){
num.total++;
if(nodes[i].check) num.checkTotal++;
}
if(nodes[i].children && nodes[i].children.length != 0){
forFn(nodes[i].children);
}
}
}
forFn(data);
return num;
}
}
</script>
网友评论