数据同步bug修改

This commit is contained in:
冯少康 2026-08-10 16:26:33 +08:00
parent 38e2a1868a
commit 0235db5279
2 changed files with 249 additions and 144 deletions

View File

@ -634,6 +634,7 @@ export class X6Graph {
addChildNode( addChildNode(
parentId: string, parentId: string,
config: ChildNodeConfig, config: ChildNodeConfig,
skipRearrange = false,
): { node: Node; edge: Edge } { ): { node: Node; edge: Edge } {
const graph = this.getGraph(); const graph = this.getGraph();
@ -682,12 +683,24 @@ export class X6Graph {
throw new Error(`创建连线(${parentId}${childNode.id})失败`); throw new Error(`创建连线(${parentId}${childNode.id})失败`);
} }
// 重排同层级节点 // // 重排同层级节点
// this.rearrangeLevelNodes(config.level);
// // 新增:如果添加的是第三层级,同步重排第二层级
// if (config.level === "level3") {
// this.rearrangeLevelNodes("level2");
// }
if (!skipRearrange) {
this.rearrangeLevelNodes(config.level); this.rearrangeLevelNodes(config.level);
// 新增:如果添加的是第三层级,同步重排第二层级 // 新增:如果添加的是第三层级,同步重排第二层级
if (config.level === "level3") { if (config.level === "level3") {
this.rearrangeLevelNodes("level2"); this.rearrangeLevelNodes("level2");
} }
// 如果新增level4要重排level3父层级父节点位置可能变化
if (config.level === "level4") {
this.rearrangeLevelNodes("level3");
}
}
return { node: childNode, edge: edge as Edge }; return { node: childNode, edge: edge as Edge };
} }
@ -697,9 +710,8 @@ export class X6Graph {
private rearrangeLevelNodes(level: NodeLevel): void { private rearrangeLevelNodes(level: NodeLevel): void {
const graph = this.getGraph(); const graph = this.getGraph();
const containerHeight = graph.container.clientHeight; const containerHeight = graph.container.clientHeight;
const centerY = (containerHeight - this.nodeStyle.height) / 2; // 画布中心点 const centerY = (containerHeight - this.nodeStyle.height) / 2;
// 获取当前层级的所有节点(按标签排序)
const levelNodes = graph const levelNodes = graph
.getNodes() .getNodes()
.filter((node) => node.getData().level === level) .filter((node) => node.getData().level === level)
@ -709,16 +721,12 @@ export class X6Graph {
return labelA.localeCompare(labelB, undefined, { numeric: true }); return labelA.localeCompare(labelB, undefined, { numeric: true });
}); });
const totalNodes = levelNodes.length; const totalNodes = levelNodes.length;
if (totalNodes === 0) return; if (totalNodes === 0) return;
// ======================== 第二层级:间距根据自身第三层级子节点数量动态调整 ========================
if (level === "level2") { if (level === "level2") {
// 1. 统计每个第二层级节点的第三层级子节点数量
const level2ChildCount = new Map<string, number>(); const level2ChildCount = new Map<string, number>();
levelNodes.forEach((node) => { levelNodes.forEach((node) => {
const childIds = this.getChildNodeIds(node.id); const childIds = this.getChildNodeIds(node.id);
// 筛选出属于第三层级的子节点
const level3ChildCount = childIds.filter((childId) => { const level3ChildCount = childIds.filter((childId) => {
const childNode = graph.getCellById(childId) as Node; const childNode = graph.getCellById(childId) as Node;
return childNode?.getData().level === "level3"; return childNode?.getData().level === "level3";
@ -726,45 +734,34 @@ export class X6Graph {
level2ChildCount.set(node.id, level3ChildCount); level2ChildCount.set(node.id, level3ChildCount);
}); });
// 2. 计算每个第二层级节点的动态间距(自身子节点越多,间距越大) const baseGap = 100;
const baseGap = 100; // 基础间距 const factor = 30;
const factor = 30; // 比例因子每个子节点增加30px间距 let currentY = centerY;
let currentY = centerY; // 起始Y坐标后续会调整为整体居中 const nodePositions = new Map<string, number>();
const nodePositions = new Map<string, number>(); // 记录每个节点的Y坐标
// 先计算第一个节点的位置(以画布中心为基准)
const firstNode = levelNodes[0]; const firstNode = levelNodes[0];
nodePositions.set(firstNode.id, currentY); nodePositions.set(firstNode.id, currentY);
// 计算后续节点的位置(根据前一个节点的子节点数量动态调整间距)
for (let i = 1; i < totalNodes; i++) { for (let i = 1; i < totalNodes; i++) {
const prevNode = levelNodes[i - 1]; const prevNode = levelNodes[i - 1];
const prevChildCount = level2ChildCount.get(prevNode.id) || 0; const prevChildCount = level2ChildCount.get(prevNode.id) || 0;
// 间距 = 基础间距 + 前一个节点的子节点数 × 因子
const dynamicGap = baseGap + prevChildCount * factor; const dynamicGap = baseGap + prevChildCount * factor;
// 下一个节点Y坐标 = 当前Y + 节点高度 + 动态间距
currentY += this.nodeStyle.height + dynamicGap; currentY += this.nodeStyle.height + dynamicGap;
nodePositions.set(levelNodes[i].id, currentY); nodePositions.set(levelNodes[i].id, currentY);
} }
// 3. 计算整体偏移量,让第二层级节点整体垂直居中 // ✅修复括号优先级
const lastNodeY = nodePositions.get(levelNodes[totalNodes - 1].id) || 0; const firstY = nodePositions.get(levelNodes[0].id) ?? 0;
const totalHeight = const lastNodeY = nodePositions.get(levelNodes[totalNodes - 1].id) ?? 0;
lastNodeY - nodePositions.get(levelNodes[0].id) || const totalHeight = lastNodeY - firstY + this.nodeStyle.height;
0 + this.nodeStyle.height; const offset = centerY - firstY - totalHeight / 2;
const offset =
centerY - (nodePositions.get(levelNodes[0].id) || 0) - totalHeight / 2;
// 4. 应用最终位置(加上偏移量,确保整体居中)
levelNodes.forEach((node) => { levelNodes.forEach((node) => {
const nodeY = (nodePositions.get(node.id) || 0) + offset; const nodeY = (nodePositions.get(node.id) || 0) + offset;
const nodeX = this.levelXMap.get("level2") || 300; const nodeX = this.levelXMap.get("level2") || 300;
node.setPosition(nodeX, nodeY); node.setPosition(nodeX, nodeY);
}); });
} } else if (level === "level3") {
// ======================== 第三层级:跟随父节点垂直分布 ========================
else if (level === "level3") {
const parentGroups = new Map<string, Node[]>(); const parentGroups = new Map<string, Node[]>();
levelNodes.forEach((node) => { levelNodes.forEach((node) => {
const parentEdge = graph const parentEdge = graph
@ -785,7 +782,7 @@ export class X6Graph {
const parentY = parentNode.getPosition().y; const parentY = parentNode.getPosition().y;
const childCount = children.length; const childCount = children.length;
const verticalGap = 20; // 第三层级内部固定间距 const verticalGap = 20;
const totalChildHeight = const totalChildHeight =
this.nodeStyle.height * childCount + verticalGap * (childCount - 1); this.nodeStyle.height * childCount + verticalGap * (childCount - 1);
@ -801,46 +798,53 @@ export class X6Graph {
}); });
}); });
} else if (level === "level4") { } else if (level === "level4") {
// 1. 按父节点level3分组每个level3只对应1个level4 const levelNodes = this.graph.getCells().filter((cell) => {
const parentGroups = new Map<string, Node[]>(); return cell.isNode() && cell.getData()?.level === level;
levelNodes.forEach((node) => { }) as Node[];
const parentEdge = graph if (!levelNodes.length) return;
.getEdges()
.find((edge) => edge.getTargetCellId() === node.id); const allEdges = this.graph.getEdges();
if (parentEdge) { //按照父节点Y排序保证顺序和左侧level3从上到下保持一致
const parentId = parentEdge.getSourceCellId(); levelNodes.sort((a, b) => {
// 只保留level3的父节点确保父节点层级正确 let ay = 0,
const parentNode = graph.getCellById(parentId) as Node; by = 0;
if (parentNode?.getData().level === "level3") { for (const e of allEdges) {
parentGroups.set(parentId, [ if (e.getTargetCellId() === a.id) {
...(parentGroups.get(parentId) || []), const p = this.graph.getCellById(e.getSourceCellId()) as Node;
node, ay = p.getPosition().y;
]); }
if (e.getTargetCellId() === b.id) {
const p = this.graph.getCellById(e.getSourceCellId()) as Node;
by = p.getPosition().y;
} }
} }
return ay - by;
}); });
// 2. 每个level3父节点的level4子节点放在父节点右侧固定间距 const nodeH = this.nodeStyle.height;
parentGroups.forEach((children, parentId) => { const verticalGap = 20;
const parentNode = graph.getCellById(parentId) as Node; const totalHeight =
if (!parentNode) return; levelNodes.length * nodeH + (levelNodes.length - 1) * verticalGap;
// level4固定在level3父节点右侧X坐标=level3X + 节点宽度 + 间距20px //参考level3整体的中心点
const parentPos = parentNode.getPosition(); const level3Nodes = this.graph
.getCells()
.filter((c) => c.isNode() && c.getData()?.level === "level3") as Node[];
let refCenterY = 300;
if (level3Nodes.length > 0) {
const topY = Math.min(...level3Nodes.map((n) => n.getPosition().y));
const botY =
Math.max(...level3Nodes.map((n) => n.getPosition().y)) + nodeH;
refCenterY = (topY + botY) / 2;
}
const startY = refCenterY - totalHeight / 2;
const level4X = this.levelXMap.get("level4") || 800; const level4X = this.levelXMap.get("level4") || 800;
// Y坐标与父节点完全对齐上下居中
const level4Y = parentPos.y;
// 只保留第一个level4节点确保仅一个子节点 let currentY = startY;
const targetChild = children[0]; levelNodes.forEach((node) => {
if (targetChild) { node.setPosition(level4X, currentY);
targetChild.setPosition(level4X, level4Y); currentY += nodeH + verticalGap;
// 多余节点直接删除避免多个level4
if (children.length > 1) {
children.slice(1).forEach((excessNode) => excessNode.remove());
this.resetLevelCount("level4"); // 重置数量统计
}
}
}); });
} }
} }
@ -853,6 +857,37 @@ export class X6Graph {
const cell = graph.getCellById(nodeId); const cell = graph.getCellById(nodeId);
if (!cell || !graph.isNode(cell)) return; if (!cell || !graph.isNode(cell)) return;
// if (targetNode.getData().tbslFlag) {
// // 1、拿到被删节点的直接父节点
// const inEdges = graph.getIncomingEdges(graph.getCellById(nodeId));
// inEdges[0].setData({ ...inEdges[0].getData(), syncCount: null });
// inEdges[0].setAttrs({
// label: {
// text: 22222,
// },
// });
// }
if (cell.data.tbslFlag) {
graph.getEdges().forEach((edge) => {
const sourceNode = edge.getSourceNode();
const targetNode = edge.getTargetNode();
if (targetNode.id == cell.id) {
sourceNode.setData({ syncCount: null });
}
});
const inEdges = graph.getIncomingEdges(cell);
inEdges[0].setData({ ...inEdges[0].getData(), syncCount: null });
inEdges[0].setAttrs({
label: {
text: 22222,
},
});
}
const node = cell as Node; const node = cell as Node;
const nodeLevel = node.getData().level as NodeLevel; const nodeLevel = node.getData().level as NodeLevel;
@ -880,28 +915,61 @@ export class X6Graph {
// 3. 遍历灌库数据,创建 level2→level3→level4 层级 // 3. 遍历灌库数据,创建 level2→level3→level4 层级
importData.forEach((item) => { importData.forEach((item) => {
// 3.1 创建 level2 节点userName 作为 label父节点是根节点 // 3.1 创建 level2 节点userName 作为 label父节点是根节点
const { node: level2Node } = this.addChildNode(rootId, { const { node: level2Node } = this.addChildNode(
rootId,
{
id: uuidv4(), id: uuidv4(),
label: item.userName, label: item.userName,
level: "level2", level: "level2",
}); },
true,
);
// 3.2 遍历当前 level2 的 tables创建 level3 和 level4 节点 // 3.2 遍历当前 level2 的 tables创建 level3 和 level4 节点
item.tables.forEach((table) => { item.tables.forEach((table) => {
// 3.2.1 创建 level3 节点tableName 作为 label父节点是当前 level2 // 3.2.1 创建 level3 节点tableName 作为 label父节点是当前 level2
const { node: level3Node } = this.addChildNode(level2Node.id, { const { node: level3Node } = this.addChildNode(
level2Node.id,
{
id: uuidv4(), id: uuidv4(),
label: table.tableName, label: table.tableName,
level: "level3", level: "level3",
}); },
true,
);
// 3.2.2 创建 level4 节点columnName 作为 label父节点是当前 level3 // 3.2.2 创建 level4 节点columnName 作为 label父节点是当前 level3
this.addChildNode(level3Node.id, { this.addChildNode(
level3Node.id,
{
id: uuidv4(), id: uuidv4(),
label: table.columnName, label: table.columnName,
level: "level4", level: "level4",
},
true,
);
if (table.syncCount) {
level3Node.data.syncCount = table.syncCount;
console.log(level3Node, "3333");
this.addChildNode(level3Node.id, {
id: uuidv4(),
label: table.syncCount.toString(),
level: "level4",
}); });
}
}, true);
}); });
// // 全部节点循环创建完成后,统一执行全套重排
this.rearrangeLevelNodes("level2");
this.rearrangeLevelNodes("level3");
this.rearrangeLevelNodes("level4");
this.graph.zoomToFit({
padding: 40, // 四周留白,节点不会贴边框
maxZoom: 1, // 最大缩放比例,不要放太大;数据多时会缩小
minZoom: 0.3,
}); });
} }
@ -986,7 +1054,7 @@ export class X6Graph {
targetOwner: name, // 传入的name字段作为targetOwner targetOwner: name, // 传入的name字段作为targetOwner
tableName, tableName,
columnName, columnName,
syncCount syncCount,
}); });
} }
} }

View File

@ -220,8 +220,6 @@ onMounted(() => {
}, },
(res) => { (res) => {
initGraph(); initGraph();
getModelList((value: any) => {
console.log(value);
if (res.result.userInfos.length) { if (res.result.userInfos.length) {
graph.value?.importData(res.result.userInfos, formData.sourceId); graph.value?.importData(res.result.userInfos, formData.sourceId);
@ -258,7 +256,6 @@ onMounted(() => {
} }
}); });
} }
});
// mindMap.value = res.result; // mindMap.value = res.result;
} }
@ -306,7 +303,7 @@ onMounted(() => {
const jdItem = graphSl.getCellById(res.id); const jdItem = graphSl.getCellById(res.id);
nowPzTbslId.value = res.id; nowPzTbslId.value = res.id;
const oldSyncCount = jdItem.getData().syncCount; const oldSyncCount = jdItem?.getData().syncCount;
pztbslFlag.value = true; pztbslFlag.value = true;
if (oldSyncCount) { if (oldSyncCount) {
pztbslValue.value = oldSyncCount; pztbslValue.value = oldSyncCount;
@ -332,7 +329,41 @@ function paTbslMethod() {
const graphSl = graph.value?.getGraph(); const graphSl = graph.value?.getGraph();
const jdItem = graphSl.getCellById(nowPzTbslId.value); const jdItem = graphSl.getCellById(nowPzTbslId.value);
jdItem.setData({ ...jdItem.getData(), syncCount:pztbslValue.value })
if (jdItem.data.syncCount) {
jdItem.setData({ syncCount: pztbslValue.value });
const outEdges = graphSl.getOutgoingEdges(jdItem);
const children = outEdges
.map((edge) => edge.getTargetNode())
.filter((n): n is Node => !!n);
const fhtjNode = children.find((node) => {
const d = node.getData();
//
return d?.tbslFlag;
});
if (fhtjNode) {
fhtjNode.setLabel(pztbslValue.value);
fhtjNode.setAttrs({
label: {
text: pztbslValue.value,
},
});
}
} else {
jdItem.setData({ ...jdItem.getData(), syncCount: pztbslValue.value });
let id = uuidv4();
graph.value?.addChildNode(nowPzTbslId.value, {
id,
label: pztbslValue.value,
level: "level4", // level4
});
let node = graphSl.getCellById(id);
node.setData({
...node.getData(),
tbslFlag: true,
});
}
pztbslFlag.value = false; pztbslFlag.value = false;
pztbslValue.value = ""; pztbslValue.value = "";
nowPzTbslId.value = null; nowPzTbslId.value = null;
@ -351,18 +382,18 @@ function getTargetUserName(taskId: any) {
}); });
} }
// id // // id
function getModelList(callback?: (data: any) => void) { // function getModelList(callback?: (data: any) => void) {
getUser({ sourceId: formData.sourceId }, (res) => { // getUser({ sourceId: formData.sourceId }, (res) => {
modeList.value = res.result.map((item: any) => { // modeList.value = res.result.map((item: any) => {
return { // return {
value: uuidv4(), // value: uuidv4(),
label: item, // label: item,
}; // };
}); // });
callback?.(res); // callback?.(res);
}); // });
} // }
// id // id
function getDataListById(name: any) { function getDataListById(name: any) {
@ -581,12 +612,18 @@ function handleCancel() {
width="20vw" width="20vw"
class="config-dialog" class="config-dialog"
> >
<el-input <div
v-model="pztbslValue" style="
style="width: 240px" display: flex;
type="number" justify-content: center;
placeholder="请配置同步数量" align-items: center;
/> width: 100%;
"
>
<span style="color: #fff">同步数量</span>
<el-input v-model="pztbslValue" style="width: 240px" type="number" />
</div>
<template #footer> <template #footer>
<ElButton <ElButton
type="text" type="text"