C内核流量计算方法优化,前端文件名称读取优化

This commit is contained in:
lujingze committed 2026-09-11 08:48:56 +00:00
1 parent 5d5a2e1843
commit 808c484f5b
94 files changed
+20163 -4418

No files matched your search

+123 -209
View File
@@ -272,7 +272,7 @@ test("复制块保留内部连接,同时未连接端口仍参与待放置吸
await expect(targetPort).toHaveAttribute("data-connected", "true");
});
test("正交连接线可拖动内部线段,且无连接交叉点显示跨线桥", async ({
test("选中正交连接线不显示拐点,仍可拖动线段、撤销并保存跨线桥路由", async ({
page,
}) => {
const project = {
@@ -342,6 +342,7 @@ test("正交连接线可拖动内部线段,且无连接交叉点显示跨线
.locator(".react-flow__edge-interaction")
.dispatchEvent("click");
await expect(horizontalEdge).toHaveClass(/selected|editor-edge-selected/);
await expect(horizontalEdge.locator("circle")).toHaveCount(0);
const horizontalSegment = horizontalEdge
.locator(".manual-edge-segment-handle.horizontal")
.first();
@@ -404,125 +405,21 @@ test("正交连接线可拖动内部线段,且无连接交叉点显示跨线
pathBeforeVerticalDrag ?? "",
);
const cornerHandle = horizontalEdge.locator(
'.manual-edge-corner-handle[data-corner-index="2"]',
);
await expect(cornerHandle).toHaveCount(1);
const cornerBefore = await cornerHandle.evaluate(
(circle: SVGCircleElement) => ({
flowX: circle.cx.baseVal.value,
flowY: circle.cy.baseVal.value,
screen: (() => {
const matrix = circle.getScreenCTM();
if (!matrix) {
throw new Error("无法获取连接线拐点坐标");
}
const point = new DOMPoint(
circle.cx.baseVal.value,
circle.cy.baseVal.value,
).matrixTransform(matrix);
return { x: point.x, y: point.y };
})(),
}),
);
const pathBeforeCornerDrag = await horizontalPath.getAttribute("d");
await page.mouse.move(cornerBefore.screen.x, cornerBefore.screen.y);
await page.mouse.down();
await page.mouse.move(
cornerBefore.screen.x + 32,
cornerBefore.screen.y + 24,
{ steps: 6 },
);
await page.mouse.up();
await expect(horizontalPath).not.toHaveAttribute(
"d",
pathBeforeCornerDrag ?? "",
);
const cornerAfter = await cornerHandle.evaluate(
(circle: SVGCircleElement) => ({
flowX: circle.cx.baseVal.value,
flowY: circle.cy.baseVal.value,
}),
);
expect(Math.abs(cornerAfter.flowX - cornerBefore.flowX)).toBeGreaterThan(1);
expect(Math.abs(cornerAfter.flowY - cornerBefore.flowY)).toBeGreaterThan(1);
const pathAfterSegmentDrags = await horizontalPath.getAttribute("d");
await expect(horizontalEdge.locator("circle")).toHaveCount(0);
await page.keyboard.press("Control+z");
await expect(horizontalPath).toHaveAttribute(
"d",
pathBeforeCornerDrag ?? "",
pathBeforeVerticalDrag ?? "",
);
await horizontalEdge
.locator(".react-flow__edge-interaction")
.dispatchEvent("click");
await expect(horizontalEdge).toHaveClass(/selected|editor-edge-selected/);
const boundaryCorner = horizontalEdge.locator(
'.manual-edge-corner-handle[data-corner-index="1"]',
);
await expect(boundaryCorner).toHaveCount(1);
const boundaryStart = await boundaryCorner.evaluate(
(circle: SVGCircleElement) => {
const matrix = circle.getScreenCTM();
if (!matrix) {
throw new Error("无法获取端点相邻拐点坐标");
}
const point = new DOMPoint(
circle.cx.baseVal.value,
circle.cy.baseVal.value,
).matrixTransform(matrix);
return { x: point.x, y: point.y };
},
);
const boundaryPathLocator = horizontalEdge.locator(".react-flow__edge-path");
const boundaryPathBefore = await boundaryPathLocator.getAttribute("d");
const boundaryTarget = {
x: boundaryStart.x + 38,
y: boundaryStart.y + 30,
};
await page.mouse.move(boundaryStart.x, boundaryStart.y);
await page.mouse.down();
await page.mouse.move(
(boundaryStart.x + boundaryTarget.x) / 2,
(boundaryStart.y + boundaryTarget.y) / 2,
{ steps: 4 },
);
await page.mouse.move(boundaryTarget.x, boundaryTarget.y, { steps: 4 });
await page.mouse.up();
await expect(boundaryPathLocator).not.toHaveAttribute(
await page.keyboard.press("Control+y");
await expect(horizontalPath).toHaveAttribute(
"d",
boundaryPathBefore ?? "",
pathAfterSegmentDrags ?? "",
);
await expect(boundaryPathLocator).toHaveAttribute("d", / Q /);
const cornerScreenPoints = await horizontalEdge
.locator(".manual-edge-corner-handle")
.evaluateAll((circles: SVGCircleElement[]) =>
circles.map((circle) => {
const matrix = circle.getScreenCTM();
if (!matrix) {
throw new Error("无法获取调整后的拐点坐标");
}
const point = new DOMPoint(
circle.cx.baseVal.value,
circle.cy.baseVal.value,
).matrixTransform(matrix);
return { x: point.x, y: point.y };
}),
);
const closestCornerDistance = Math.min(
...cornerScreenPoints.map((point) =>
Math.hypot(point.x - boundaryTarget.x, point.y - boundaryTarget.y),
),
);
expect(
closestCornerDistance,
JSON.stringify({ boundaryStart, boundaryTarget, cornerScreenPoints }),
).toBeLessThan(3);
const boundaryPathAfter = await boundaryPathLocator.getAttribute("d");
const linePoints = [
...(boundaryPathAfter ?? "").matchAll(
...(pathAfterSegmentDrags ?? "").matchAll(
/[ML]\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)/g,
),
].map((match) => ({ x: Number(match[1]), y: Number(match[2]) }));
@@ -623,110 +520,127 @@ test("缩小画布后连接线端点仍与端口图标边缘对齐", async ({ pa
expect(alignment!.targetGapY).toBeLessThan(0.75);
});
test("直线首次折弯后即使原手柄卸载,拖动仍连续且保持正交", async ({
page,
}) => {
const project = {
...structuredClone(wideProject),
nodes: [
projectNode("straight-source", 0, 260),
projectNode("straight-target", 700, 260),
],
edges: [
{
id: "straight-edge",
source: "straight-source",
target: "straight-target",
sourceHandle: "port_b",
targetHandle: "port_a",
data: { isContactEdge: false },
},
],
};
await page.addInitScript((storedProject) => {
window.localStorage.setItem(
"system-simulation-flow:project:demo-system",
JSON.stringify(storedProject),
for (const route of [
{ label: "直线", targetY: 260, targetRotation: 0, pointCount: 2 },
{ label: "L 型连接线", targetY: 480, targetRotation: 90, pointCount: 3 },
]) {
test(`${route.label}可直接拖动线条,首次折弯后仍连续且保持正交`, async ({
page,
}) => {
const project = {
...structuredClone(wideProject),
nodes: [
projectNode("straight-source", 0, 260),
{
...projectNode("straight-target", 700, route.targetY),
data: {
...projectNode("straight-target", 700, route.targetY).data,
rotation: route.targetRotation,
},
},
],
edges: [
{
id: "straight-edge",
source: "straight-source",
target: "straight-target",
sourceHandle: "port_b",
targetHandle: "port_a",
data: { isContactEdge: false },
},
],
};
await page.addInitScript((storedProject) => {
window.localStorage.setItem(
"system-simulation-flow:project:demo-system",
JSON.stringify(storedProject),
);
}, project);
await page.goto("/");
await page.getByRole("button", { name: "加载工程", exact: true }).click();
const edge = page.locator(
'.flow-canvas .react-flow__edge[data-id="straight-edge"]',
);
}, project);
await page.goto("/");
await page.getByRole("button", { name: "加载工程", exact: true }).click();
const edge = page.locator(
'.flow-canvas .react-flow__edge[data-id="straight-edge"]',
);
const edgePath = edge.locator(".react-flow__edge-path");
await edge.locator(".react-flow__edge-interaction").dispatchEvent("click");
const routeHandle = edge.locator(".manual-edge-route-handle");
await expect(routeHandle).toHaveCount(1);
const dragStart = await routeHandle.evaluate((circle: SVGCircleElement) => {
const matrix = circle.getScreenCTM();
if (!matrix) {
throw new Error("无法获取直线路由手柄坐标");
}
const point = new DOMPoint(
circle.cx.baseVal.value,
circle.cy.baseVal.value,
).matrixTransform(matrix);
return { x: point.x, y: point.y };
});
const pathBefore = await edgePath.getAttribute("d");
await page.mouse.move(dragStart.x, dragStart.y);
await page.mouse.down();
await page.mouse.move(dragStart.x + 18, dragStart.y + 21, { steps: 4 });
await expect(routeHandle).toHaveCount(0);
const verticalSegment = edge
.locator(".manual-edge-segment-handle.vertical")
.first();
await expect(verticalSegment).toHaveCount(1);
const segmentXAtHalfMove = await verticalSegment.evaluate(
(line: SVGLineElement) => {
const edgePath = edge.locator(".react-flow__edge-path");
await edge.locator(".react-flow__edge-interaction").dispatchEvent("click");
await expect(edge.locator("circle")).toHaveCount(0);
const routeHandle = edge.locator(
'.manual-edge-segment-handle[data-segment-index="0"]',
);
await expect(routeHandle).toHaveCount(1);
await expect(routeHandle).toHaveCSS("pointer-events", "stroke");
const dragStart = await routeHandle.evaluate((line: SVGLineElement) => {
const matrix = line.getScreenCTM();
if (!matrix) {
throw new Error("无法获取首次折弯后的竖直线段坐标");
throw new Error("无法获取待拖动连接线段坐标");
}
return new DOMPoint(
line.x1.baseVal.value,
line.y1.baseVal.value,
).matrixTransform(matrix).x;
},
);
const point = new DOMPoint(
line.x1.baseVal.value * 0.75 + line.x2.baseVal.value * 0.25,
line.y1.baseVal.value * 0.75 + line.y2.baseVal.value * 0.25,
).matrixTransform(matrix);
return { x: point.x, y: point.y };
});
const pathBefore = await edgePath.getAttribute("d");
expect([...(pathBefore ?? "").matchAll(/[ML]\s/g)]).toHaveLength(route.pointCount);
await page.mouse.move(dragStart.x, dragStart.y);
await page.mouse.down();
await page.mouse.move(dragStart.x + 18, dragStart.y + 21, { steps: 4 });
await page.mouse.move(dragStart.x + 36, dragStart.y + 42, { steps: 4 });
const segmentXAtFullMove = await verticalSegment.evaluate(
(line: SVGLineElement) => {
const matrix = line.getScreenCTM();
if (!matrix) {
throw new Error("无法获取连续拖动后的竖直线段坐标");
}
return new DOMPoint(
line.x1.baseVal.value,
line.y1.baseVal.value,
).matrixTransform(matrix).x;
},
);
await page.mouse.up();
expect(Math.abs(segmentXAtFullMove - segmentXAtHalfMove)).toBeGreaterThan(10);
await expect(edgePath).not.toHaveAttribute("d", pathBefore ?? "");
await expect(
edge.locator(".manual-edge-segment-handle.horizontal").first(),
).toHaveCount(1);
await expect(routeHandle).toHaveCount(0);
const verticalSegment = edge
.locator(".manual-edge-segment-handle.vertical")
.first();
await expect(verticalSegment).toHaveCount(1);
const segmentXAtHalfMove = await verticalSegment.evaluate(
(line: SVGLineElement) => {
const matrix = line.getScreenCTM();
if (!matrix) {
throw new Error("无法获取首次折弯后的竖直线段坐标");
}
return new DOMPoint(
line.x1.baseVal.value,
line.y1.baseVal.value,
).matrixTransform(matrix).x;
},
);
const routeAfter = await edgePath.getAttribute("d");
const routePoints = [
...(routeAfter ?? "").matchAll(
/[ML]\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)/g,
),
].map((match) => ({ x: Number(match[1]), y: Number(match[2]) }));
routePoints.slice(1).forEach((point, index) => {
const previous = routePoints[index];
expect(
Math.abs(point.x - previous.x) < 0.01 ||
Math.abs(point.y - previous.y) < 0.01,
).toBe(true);
await page.mouse.move(dragStart.x + 36, dragStart.y + 42, { steps: 4 });
const segmentXAtFullMove = await verticalSegment.evaluate(
(line: SVGLineElement) => {
const matrix = line.getScreenCTM();
if (!matrix) {
throw new Error("无法获取连续拖动后的竖直线段坐标");
}
return new DOMPoint(
line.x1.baseVal.value,
line.y1.baseVal.value,
).matrixTransform(matrix).x;
},
);
await page.mouse.up();
expect(Math.abs(segmentXAtFullMove - segmentXAtHalfMove)).toBeGreaterThan(10);
await expect(edgePath).not.toHaveAttribute("d", pathBefore ?? "");
await expect(edge.locator("circle")).toHaveCount(0);
await expect(
edge.locator(".manual-edge-segment-handle.horizontal").first(),
).toHaveCount(1);
const routeAfter = await edgePath.getAttribute("d");
const routePoints = [
...(routeAfter ?? "").matchAll(
/[ML]\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)/g,
),
].map((match) => ({ x: Number(match[1]), y: Number(match[2]) }));
routePoints.slice(1).forEach((point, index) => {
const previous = routePoints[index];
expect(
Math.abs(point.x - previous.x) < 0.01 ||
Math.abs(point.y - previous.y) < 0.01,
).toBe(true);
});
});
});
}
test("同一组件不同端口发出的线路在远端交叉时仍显示跨线桥", async ({
page,