testFlow/ui/page/testG6.html
Wyle.Gong-巩文昕 7a1aae1e2f ui
2025-04-23 11:21:08 +08:00

314 lines
7.9 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>G6 Tree View</title>
<script src="/ui/assets/g6.js"></script>
<style>
#tree_container {
width: 1100px;
height: 800px;
margin: 0 auto;
border: 1px solid #ddd;
}
.g6-tooltip {
border: 1px solid #e2e2e2;
border-radius: 4px;
font-size: 12px;
color: #545454;
background-color: rgba(255, 255, 255, 0.9);
padding: 10px 8px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
}
.control-panel {
padding: 10px;
margin-bottom: 10px;
}
button {
margin: 5px;
padding: 5px 10px;
}
</style>
</head>
<body>
<div class="control-panel">
<button id="add-btn">添加节点</button>
<button id="edit-btn">编辑选中节点</button>
<button id="delete-btn">删除选中节点</button>
<button id="refresh-btn">刷新树</button>
</div>
<div id="tree_container"></div>
<script>
// 全局变量
let graph = null;
let selectedNode = null;
// 将后端数据转换为G6可用的格式
function convertToG6Format(data) {
const map = {};
const roots = [];
// 创建所有节点
data.forEach(item => {
map[item.id] = {
id: item.id,
label: item.name,
style: {
fill: '#91d5ff',
stroke: '#40a9ff'
},
children: []
};
});
// 构建树结构
data.forEach(item => {
const node = map[item.id];
if (!item.parent_id || item.parent_id === '' || item.parent_id === '-1') {
roots.push(node);
} else {
const parent = map[item.parent_id];
if (parent) {
if (!parent.children) parent.children = [];
parent.children.push(node);
}
}
});
// 返回根节点数组的第一个作为主树
return roots.length > 0 ? { id: 'root', label: 'Root', children: roots } : {};
}
// 初始化G6图形
function initGraph() {
// 注册自定义节点,美化显示效果
window.G6.registerNode('tree-node', {
draw(cfg, group) {
const keyShape = group.addShape('rect', {
attrs: {
x: 0,
y: -15,
width: 120,
height: 30,
radius: 4,
fill: cfg.style ? cfg.style.fill : '#91d5ff',
stroke: cfg.style ? cfg.style.stroke : '#40a9ff',
cursor: 'pointer'
},
name: 'node-keyshape',
});
group.addShape('text', {
attrs: {
text: cfg.label,
x: 10,
y: 0,
fontSize: 14,
fill: '#333',
textAlign: 'left',
textBaseline: 'middle',
cursor: 'pointer'
},
name: 'node-label'
});
return keyShape;
}
});
// 创建G6实例
graph = new window.G6.Graph({
container: 'tree_container',
width: 1100,
height: 800,
fitView: true,
animate: true,
modes: {
default: ['drag-canvas', 'zoom-canvas', {
type: 'drag-node',
enableDelegate: true
}]
},
layout: {
type: 'compactBox',
direction: 'LR',
getId: function getId(d) {
return d.id;
},
getHeight: function getHeight() {
return 16;
},
getWidth: function getWidth() {
return 16;
},
getVGap: function getVGap() {
return 40;
},
getHGap: function getHGap() {
return 100;
}
},
defaultNode: {
type: 'tree-node'
},
nodeStateStyles: {
selected: {
fill: '#d9f7be',
stroke: '#73d13d'
}
}
});
// 节点点击事件
graph.on('node:click', evt => {
const { item } = evt;
const nodeId = item._cfg.id;
// 取消之前选中状态
if (selectedNode) {
graph.setItemState(selectedNode, 'selected', false);
}
// 设置新选中状态
graph.setItemState(item, 'selected', true);
selectedNode = item;
console.log('选中节点:', nodeId);
});
// 注册按钮事件
document.getElementById('add-btn').addEventListener('click', addNode);
document.getElementById('edit-btn').addEventListener('click', editNode);
document.getElementById('delete-btn').addEventListener('click', deleteNode);
document.getElementById('refresh-btn').addEventListener('click', fetchAndRenderTree);
return graph;
}
// 获取数据并渲染树
async function fetchAndRenderTree() {
try {
const response = await fetch('http://127.0.0.1:5002/api/tree/');
const result = await response.json();
if (result.code === 0) {
const treeData = convertToG6Format(result.data);
graph.data(treeData);
graph.render();
// 自动适应画布
setTimeout(() => {
graph.fitView();
}, 500);
} else {
console.error('获取数据失败:', result.message);
}
} catch (error) {
console.error('获取数据错误:', error);
}
}
// 添加节点
function addNode() {
const parentId = selectedNode ? selectedNode._cfg.id : '-1';
const newNodeName = prompt('请输入新节点名称:');
if (newNodeName) {
fetch('http://127.0.0.1:5002/api/tree/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: newNodeName,
parent_id: parentId
})
})
.then(response => response.json())
.then(data => {
alert('节点添加成功');
fetchAndRenderTree();
})
.catch(error => {
console.error('添加节点失败:', error);
});
}
}
// 编辑节点
function editNode() {
if (!selectedNode) {
alert('请先选择一个节点');
return;
}
const nodeId = selectedNode._cfg.id;
const newName = prompt('请输入新的节点名称:', selectedNode._cfg.model.label);
if (newName) {
fetch(`http://127.0.0.1:5002/api/tree/${nodeId}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: newName
})
})
.then(response => response.json())
.then(data => {
alert('节点更新成功');
fetchAndRenderTree();
})
.catch(error => {
console.error('更新节点失败:', error);
});
}
}
// 删除节点
function deleteNode() {
if (!selectedNode) {
alert('请先选择一个节点');
return;
}
const nodeId = selectedNode._cfg.id;
const confirmDelete = confirm('确定删除此节点吗?');
if (confirmDelete) {
fetch(`http://127.0.0.1:5002/api/tree/${nodeId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
cascade: false
})
})
.then(response => response.json())
.then(data => {
alert('节点删除成功');
selectedNode = null;
fetchAndRenderTree();
})
.catch(error => {
console.error('删除节点失败:', error);
});
}
}
// 页面加载完成后初始化图形并加载数据
$node.addEventListener('DOMContentLoaded', () => {
graph = initGraph();
fetchAndRenderTree();
});
</script>
</body>
</html>