数据同步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

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

View File

@ -220,45 +220,42 @@ onMounted(() => {
},
(res) => {
initGraph();
getModelList((value: any) => {
console.log(value);
if (res.result.userInfos.length) {
graph.value?.importData(res.result.userInfos, formData.sourceId);
if (res.result.userInfos.length) {
graph.value?.importData(res.result.userInfos, formData.sourceId);
res.result.userInfos.forEach((item: any) => {
const graphSl = graph.value?.getGraph();
res.result.userInfos.forEach((item: any) => {
const graphSl = graph.value?.getGraph();
//
const allNodes = graphSl.getNodes();
console.log(allNodes, "allNodes");
// label name item.name
const matchNodesData = allNodes
.map((node) => {
return {
label: node.label,
id: node.id,
};
})
.filter((item1) => {
return item1.label == item.userName;
});
const exists = modeList.value.find(
(item1: any) => item1.label === item.userName
);
if (!exists) {
const newItem = {
value: matchNodesData[0].id,
label: item.userName,
//
const allNodes = graphSl.getNodes();
console.log(allNodes, "allNodes");
// label name item.name
const matchNodesData = allNodes
.map((node) => {
return {
label: node.label,
id: node.id,
};
modeList.value.push(newItem);
formData.mode.push(newItem.value);
} else {
formData.mode.push(exists.value);
}
});
}
});
})
.filter((item1) => {
return item1.label == item.userName;
});
const exists = modeList.value.find(
(item1: any) => item1.label === item.userName
);
if (!exists) {
const newItem = {
value: matchNodesData[0].id,
label: item.userName,
};
modeList.value.push(newItem);
formData.mode.push(newItem.value);
} else {
formData.mode.push(exists.value);
}
});
}
// mindMap.value = res.result;
}
@ -306,7 +303,7 @@ onMounted(() => {
const jdItem = graphSl.getCellById(res.id);
nowPzTbslId.value = res.id;
const oldSyncCount = jdItem.getData().syncCount;
const oldSyncCount = jdItem?.getData().syncCount;
pztbslFlag.value = true;
if (oldSyncCount) {
pztbslValue.value = oldSyncCount;
@ -332,7 +329,41 @@ function paTbslMethod() {
const graphSl = graph.value?.getGraph();
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;
pztbslValue.value = "";
nowPzTbslId.value = null;
@ -351,18 +382,18 @@ function getTargetUserName(taskId: any) {
});
}
// id
function getModelList(callback?: (data: any) => void) {
getUser({ sourceId: formData.sourceId }, (res) => {
modeList.value = res.result.map((item: any) => {
return {
value: uuidv4(),
label: item,
};
});
callback?.(res);
});
}
// // id
// function getModelList(callback?: (data: any) => void) {
// getUser({ sourceId: formData.sourceId }, (res) => {
// modeList.value = res.result.map((item: any) => {
// return {
// value: uuidv4(),
// label: item,
// };
// });
// callback?.(res);
// });
// }
// id
function getDataListById(name: any) {
@ -581,12 +612,18 @@ function handleCancel() {
width="20vw"
class="config-dialog"
>
<el-input
v-model="pztbslValue"
style="width: 240px"
type="number"
placeholder="请配置同步数量"
/>
<div
style="
display: flex;
justify-content: center;
align-items: center;
width: 100%;
"
>
<span style="color: #fff">同步数量</span>
<el-input v-model="pztbslValue" style="width: 240px" type="number" />
</div>
<template #footer>
<ElButton
type="text"