2025-08-14 14:59:34 +08:00

326 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<!-- 调试信息 -->
<div style="margin-bottom: 20px; padding: 15px; background: #f5f7fa; border-radius: 8px;">
<el-button size="small" @click="showDebugInfo">查看调试信息</el-button>
<el-button size="small" @click="showRawData">查看原始数据</el-button>
<el-button size="small" type="primary" @click="testTreeStructure">测试树形结构</el-button>
<el-button size="small" type="success" @click="getCategories">重新加载数据</el-button>
<span style="margin-left: 20px; color: #666;">
数据总数: {{ tableData.length }} |
树形层级: {{ getMaxLevel() }}
</span>
</div>
<el-table :data="tableData" style="width: 100%;margin-bottom: 20px;" row-key="id" border v-loading="loading"
element-loading-text="加载中..." element-loading-spinner="el-icon-loading"
:tree-props="{ children: 'children' }" :default-expand-all="false" :expand-on-click-node="false">
<el-table-column prop="name" label="名称" min-width="120">
</el-table-column>
<el-table-column prop="id" label="id" min-width="200">
</el-table-column>
<el-table-column prop="level" label="层级" min-width="120">
</el-table-column>
<el-table-column label="操作" width="280" fixed="right">
<template slot-scope="scope">
<el-button type="text" size="small" @click="addNode(scope.row, 'sibling')">新增同级</el-button>
<el-button type="text" size="small" @click="addNode(scope.row, 'child')">新增子级</el-button>
<el-button type="text" size="small" @click="editNode(scope.row)">编辑</el-button>
<el-button type="text" size="small" @click="deleteNode(scope.row)"
style="color: #F56C6C;">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-drawer title="菜单管理" :visible.sync="drawer" :direction="direction">
<div style="margin: 20px;"></div>
<el-form :label-position="labelPosition" label-width="80px" :model="formLabelAlign">
<el-form-item label="菜单名称">
<el-input v-model="formLabelAlign.name"></el-input>
</el-form-item>
</el-form>
</el-drawer>
</div>
</template>
<script>
import { reqNcMatchMenu } from '@/api/ncmatch';
export default {
name: 'menuMangement',
data() {
return {
loading: false,
categories: [],
tableData: [], // 移除硬编码的测试数据
drawer: false,
direction: 'rtl',
labelPosition: 'right',
formLabelAlign: {
name: '',
region: '',
type: ''
}
}
},
created() {
this.getCategories();
},
methods: {
addNode(row, type) {
this.drawer = true;
console.log('新增节点:', row, '类型:', type);
},
getCategories() {
this.loading = true;
reqNcMatchMenu({ url_link: window.location.href }).then(res => {
this.loading = false;
if (res.status) {
this.categories = this.buildSimpleTree(res.data);
this.tableData = this.categories; // 使用精简的树形结构
console.log("构建的精简树结构:", this.categories);
}
}).catch(error => {
this.loading = false;
console.error('获取菜单数据失败:', error);
});
},
editNode(row) {
this.drawer = true;
console.log('编辑节点:', row);
},
deleteNode(row) {
this.drawer = true;
console.log('删除节点:', row);
},
buildTree(data, parentId = null) {
if (!Array.isArray(data)) {
console.log('数据不是数组:', data);
return [];
}
console.log('构建树结构当前parentId:', parentId, '数据长度:', data.length);
// 找出当前层级的节点
const currentNodes = data.filter(item => {
// 处理顶级节点parentid 为 null 或空字符串)
if (parentId === null) {
return !item.parentid || item.parentid === '' || item.parentid === '0';
}
return item.parentid === parentId;
});
console.log('当前层级节点数量:', currentNodes.length, '节点:', currentNodes);
if (currentNodes.length === 0) return [];
// 处理每个节点
return currentNodes.map(node => {
const resultNode = {
id: node.id,
name: node.name || '未命名',
parentid: node.parentid
};
// 递归处理子节点
const children = this.buildSimpleTree(data, node.id);
// 只有当有子节点时才添加 children 字段
if (children && children.length > 0) {
resultNode.children = children;
}
return resultNode;
});
},
// 精简的树形结构构建方法
buildSimpleTree(data, parentId = null) {
if (!Array.isArray(data)) {
return [];
}
// 找出当前层级的节点
const currentNodes = data.filter(item => {
if (parentId === null) {
return !item.parentid || item.parentid === '' || item.parentid === '0';
}
return item.parentid === parentId;
});
if (currentNodes.length === 0) return [];
// 处理每个节点,只保留必要字段
return currentNodes.map(node => {
const resultNode = {
id: node.id,
name: node.name || '未命名',
parentid: node.parentid
};
// 递归处理子节点
const children = this.buildSimpleTree(data, node.id);
// 只有当有子节点时才添加 children 字段
if (children && children.length > 0) {
resultNode.children = children;
}
return resultNode;
});
},
// 计算节点层级
calculateLevel(data, nodeId) {
let level = 1;
let currentId = nodeId;
while (true) {
const parent = data.find(item => item.id === currentId);
if (!parent || !parent.parentid || parent.parentid === '' || parent.parentid === '0') {
break;
}
level++;
currentId = parent.parentid;
}
return level;
},
showDebugInfo() {
console.log("当前 tableData 的结构:", this.tableData);
console.log("当前 tableData 的层级分布:", this.getLevelDistribution());
console.log("当前 tableData 的最大层级:", this.getMaxLevel());
// 检查树形结构
this.checkTreeStructure(this.tableData);
},
// 检查树形结构
checkTreeStructure(nodes, level = 0) {
if (!Array.isArray(nodes)) return;
nodes.forEach(node => {
const indent = ' '.repeat(level);
console.log(`${indent}📁 ${node.name} (ID: ${node.id})`);
console.log(`${indent} - hasChildren: ${node.hasChildren}`);
console.log(`${indent} - children.length: ${node.children ? node.children.length : 'undefined'}`);
console.log(`${indent} - level: ${node.level}`);
if (node.children && node.children.length > 0) {
this.checkTreeStructure(node.children, level + 1);
}
});
},
showRawData() {
console.log("原始数据:", this.categories);
},
// 测试树形结构
testTreeStructure() {
const testData = [
{
id: 1,
name: '一级菜单1',
parentid: null
},
{
id: 2,
name: '一级菜单2',
parentid: null
},
{
id: 3,
name: '一级菜单3',
parentid: null,
children: [
{
id: 31,
name: '二级菜单3-1',
parentid: 3
},
{
id: 32,
name: '二级菜单3-2',
parentid: 3,
children: [
{
id: 321,
name: '三级菜单3-2-1',
parentid: 32
}
]
}
]
}
];
console.log("精简测试数据:", testData);
this.tableData = testData;
},
getLevelDistribution() {
const levels = {};
this.tableData.forEach(node => {
const level = node.level;
if (levels[level]) {
levels[level]++;
} else {
levels[level] = 1;
}
});
return levels;
},
getMaxLevel() {
let maxLevel = 0;
this.tableData.forEach(node => {
if (node.level > maxLevel) {
maxLevel = node.level;
}
});
return maxLevel;
}
}
}
</script>
<style scoped>
.el-table {
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.el-table th {
background-color: #f5f7fa;
color: #606266;
font-weight: 600;
}
.el-table td {
padding: 12px 0;
}
.el-button--text {
padding: 4px 8px;
margin: 0 2px;
}
.el-button--text:hover {
background-color: #f5f7fa;
border-radius: 4px;
}
.el-tag {
border-radius: 4px;
}
/* 树形表格的缩进样式 */
.el-table__expand-icon {
margin-right: 8px;
}
/* 加载状态样式 */
.el-loading-mask {
background-color: rgba(255, 255, 255, 0.8);
}
</style>