优化仿真求解性能并修复流量闭合问题(初版)
This commit is contained in:
1 parent
57b459bc72
commit
5332a788f3
55 files changed
+8973
-549
No files matched your search
@@ -2902,6 +2902,8 @@ test("恢复工程时采用当前目录端口并明确丢弃已删除端口的
|
||||
test("AMESim canvas nodes use icon anchors and highlight only compatible free ports", async ({
|
||||
page,
|
||||
}) => {
|
||||
const pageErrors: string[] = [];
|
||||
page.on("pageerror", (error) => pageErrors.push(error.message));
|
||||
await page.goto("/");
|
||||
|
||||
const firstOrifice = await dragSymbolToCanvas(page, "amesim_pnor001", {
|
||||
@@ -3214,6 +3216,39 @@ test("AMESim canvas nodes use icon anchors and highlight only compatible free po
|
||||
await expect(signalInput).toHaveCSS("opacity", "0");
|
||||
await expect(signalOutput).toHaveCSS("pointer-events", "none");
|
||||
await expect(signalInput).toHaveCSS("pointer-events", "none");
|
||||
|
||||
const renderedEdges = page.locator(".flow-canvas .react-flow__edge");
|
||||
const clickEdgeMiddle = async (edgeIndex: number) => {
|
||||
const point = await renderedEdges
|
||||
.nth(edgeIndex)
|
||||
.locator(".react-flow__edge-interaction")
|
||||
.evaluate((path: SVGPathElement) => {
|
||||
const localPoint = path.getPointAtLength(path.getTotalLength() / 2);
|
||||
const matrix = path.getScreenCTM();
|
||||
if (!matrix) {
|
||||
throw new Error("Unable to resolve the edge screen position");
|
||||
}
|
||||
const screenPoint = new DOMPoint(
|
||||
localPoint.x,
|
||||
localPoint.y,
|
||||
).matrixTransform(matrix);
|
||||
return { x: screenPoint.x, y: screenPoint.y };
|
||||
});
|
||||
await page.mouse.click(point.x, point.y);
|
||||
};
|
||||
|
||||
await clickEdgeMiddle(0);
|
||||
await expect(renderedEdges).toHaveCount(2);
|
||||
await expect(renderedEdges.nth(0)).toHaveClass(
|
||||
/selected|editor-edge-selected/,
|
||||
);
|
||||
await clickEdgeMiddle(1);
|
||||
await expect(renderedEdges).toHaveCount(2);
|
||||
await expect(renderedEdges.nth(1)).toHaveClass(
|
||||
/selected|editor-edge-selected/,
|
||||
);
|
||||
await expect(page.getByText("System Simulation Flow", { exact: true })).toBeVisible();
|
||||
expect(pageErrors).toEqual([]);
|
||||
});
|
||||
|
||||
test("端口图标随画布缩小且物理端口始终保持标准圆形", async ({ page }) => {
|
||||
|
||||
@@ -6,9 +6,9 @@ import {
|
||||
wideProject,
|
||||
} from "./fixtures";
|
||||
|
||||
async function readModelingViewport(page: Page) {
|
||||
async function readViewport(page: Page, canvasSelector: string) {
|
||||
return page
|
||||
.locator(".flow-canvas .react-flow__viewport")
|
||||
.locator(`${canvasSelector} .react-flow__viewport`)
|
||||
.evaluate((viewport) => {
|
||||
const values =
|
||||
getComputedStyle(viewport)
|
||||
@@ -22,6 +22,10 @@ async function readModelingViewport(page: Page) {
|
||||
});
|
||||
}
|
||||
|
||||
async function readModelingViewport(page: Page) {
|
||||
return readViewport(page, ".flow-canvas");
|
||||
}
|
||||
|
||||
test("拖入组件不自动适配画布,手动适配按钮仍然生效", async ({ page }) => {
|
||||
await prepareApp(page);
|
||||
await page.goto("/");
|
||||
@@ -257,10 +261,24 @@ test("切换到结果页时自动适配只读系统图", async ({ page }) => {
|
||||
"system-simulation-flow:project:demo-system",
|
||||
JSON.stringify(project),
|
||||
);
|
||||
window.localStorage.setItem(
|
||||
"system-simulation-flow:canvas-grid-visibility",
|
||||
JSON.stringify({ lines: true, dots: false }),
|
||||
);
|
||||
}, { project: wideProject, snapshot: resultSnapshot });
|
||||
|
||||
await page.goto("/");
|
||||
await page.getByRole("button", { name: "加载工程" }).click();
|
||||
await expect(
|
||||
page.locator(
|
||||
'.flow-canvas .react-flow__background pattern[id$="major-grid-lines"]',
|
||||
),
|
||||
).toHaveCount(1);
|
||||
await expect(
|
||||
page.locator(
|
||||
'.flow-canvas .react-flow__background pattern[id$="minor-grid-dots"]',
|
||||
),
|
||||
).toHaveCount(0);
|
||||
const freeModelingHandle = page.locator(
|
||||
'.flow-canvas .react-flow__node[data-id="generic_sensor_1"] .port-handle[data-port-name="port_a"]',
|
||||
);
|
||||
@@ -271,6 +289,24 @@ test("切换到结果页时自动适配只读系统图", async ({ page }) => {
|
||||
);
|
||||
await page.getByRole("tab", { name: /^结果/ }).click();
|
||||
await expectAllNodesInsideCanvas(page, ".results-system-canvas");
|
||||
await expect(
|
||||
page.locator(
|
||||
'.results-system-canvas .react-flow__background pattern[id$="major-grid-lines"]',
|
||||
),
|
||||
).toHaveCount(1);
|
||||
await expect(
|
||||
page.locator(
|
||||
'.results-system-canvas .react-flow__background pattern[id$="minor-grid-dots"]',
|
||||
),
|
||||
).toHaveCount(0);
|
||||
await expect(
|
||||
page.locator(".results-system-canvas .react-flow__controls"),
|
||||
).toHaveCount(0);
|
||||
const fitSystemViewButton = page.getByRole("button", {
|
||||
name: "适应系统图窗口",
|
||||
exact: true,
|
||||
});
|
||||
await expect(fitSystemViewButton).toBeVisible();
|
||||
await expect(
|
||||
page.locator(".results-system-canvas .react-flow__attribution"),
|
||||
).toHaveCount(0);
|
||||
@@ -278,6 +314,49 @@ test("切换到结果页时自动适配只读系统图", async ({ page }) => {
|
||||
page.getByRole("complementary", { name: "仿真控制台", exact: true }),
|
||||
).toHaveCount(0);
|
||||
|
||||
const resultPane = page.locator(".results-system-canvas .react-flow__pane");
|
||||
const resultPaneBox = await resultPane.boundingBox();
|
||||
expect(resultPaneBox).not.toBeNull();
|
||||
const fittedResultViewport = await readViewport(
|
||||
page,
|
||||
".results-system-canvas",
|
||||
);
|
||||
await page.mouse.move(
|
||||
resultPaneBox!.x + resultPaneBox!.width / 2,
|
||||
resultPaneBox!.y + resultPaneBox!.height / 2,
|
||||
);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(
|
||||
resultPaneBox!.x + resultPaneBox!.width / 2 + 180,
|
||||
resultPaneBox!.y + resultPaneBox!.height / 2 + 90,
|
||||
{ steps: 5 },
|
||||
);
|
||||
await page.mouse.up();
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const viewport = await readViewport(page, ".results-system-canvas");
|
||||
return Math.hypot(
|
||||
viewport.x - fittedResultViewport.x,
|
||||
viewport.y - fittedResultViewport.y,
|
||||
);
|
||||
})
|
||||
.toBeGreaterThan(100);
|
||||
const pannedResultViewport = await readViewport(
|
||||
page,
|
||||
".results-system-canvas",
|
||||
);
|
||||
await fitSystemViewButton.click();
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const viewport = await readViewport(page, ".results-system-canvas");
|
||||
return Math.hypot(
|
||||
viewport.x - pannedResultViewport.x,
|
||||
viewport.y - pannedResultViewport.y,
|
||||
);
|
||||
})
|
||||
.toBeGreaterThan(100);
|
||||
await expectAllNodesInsideCanvas(page, ".results-system-canvas");
|
||||
|
||||
await page.getByRole("tab", { name: "建模" }).click();
|
||||
await expectAllNodesInsideCanvas(page, ".flow-canvas");
|
||||
await expect(freeModelingHandle).toHaveAttribute(
|
||||
@@ -354,3 +433,153 @@ test("切换到结果页时自动适配只读系统图", async ({ page }) => {
|
||||
expect(shape.circle).toEqual({ cx: 3, cy: 3, r: 2.5 });
|
||||
}
|
||||
});
|
||||
|
||||
test("结果页专用图标只按实际包络命中被相邻节点包围的元件", async ({
|
||||
page,
|
||||
}) => {
|
||||
await prepareApp(page);
|
||||
const pneumaticPort = (name: string, side: "left" | "right") => ({
|
||||
name,
|
||||
kind: "physical",
|
||||
domain: "pneumatic",
|
||||
nominalRole: "bidirectional",
|
||||
positiveFlowDirection: "intoComponent",
|
||||
side,
|
||||
});
|
||||
const pnplNode = (
|
||||
id: string,
|
||||
position: { x: number; y: number },
|
||||
rotation: 0 | 90 | 180 | 270,
|
||||
) => ({
|
||||
id,
|
||||
type: "simulationComponent",
|
||||
position,
|
||||
data: {
|
||||
label: id,
|
||||
componentType: "amesim_pnpl01",
|
||||
modelType: "amesim_pnpl01",
|
||||
modelVersion: "0.1.0",
|
||||
ports: [pneumaticPort("port_1", "left")],
|
||||
parameters: {},
|
||||
parameterUnits: {},
|
||||
parameterScientificNotation: {},
|
||||
rotation,
|
||||
mirrored: false,
|
||||
},
|
||||
});
|
||||
const targetNodeId = "amesim_pnch012_2";
|
||||
const overlapProject = {
|
||||
...wideProject,
|
||||
name: "overlapped-symbols",
|
||||
nodes: [
|
||||
{
|
||||
id: "generic_sensor_0",
|
||||
type: "simulationComponent",
|
||||
position: { x: 360, y: 390 },
|
||||
data: {
|
||||
label: "generic_sensor_0",
|
||||
componentType: "generic_sensor",
|
||||
modelType: "generic_sensor",
|
||||
modelVersion: "1.0.0",
|
||||
symbol: "symbol-not-registered",
|
||||
ports: [],
|
||||
parameters: {},
|
||||
parameterUnits: {},
|
||||
parameterScientificNotation: {},
|
||||
rotation: 0,
|
||||
mirrored: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: targetNodeId,
|
||||
type: "simulationComponent",
|
||||
position: { x: 569.2129060235693, y: 515.6448805401301 },
|
||||
data: {
|
||||
label: targetNodeId,
|
||||
componentType: "amesim_pnch012",
|
||||
modelType: "amesim_pnch012",
|
||||
modelVersion: "0.1.0",
|
||||
ports: [
|
||||
pneumaticPort("port_1", "left"),
|
||||
pneumaticPort("port_2", "right"),
|
||||
pneumaticPort("port_3", "left"),
|
||||
pneumaticPort("port_4", "right"),
|
||||
],
|
||||
parameters: {},
|
||||
parameterUnits: {},
|
||||
parameterScientificNotation: {},
|
||||
rotation: 0,
|
||||
mirrored: false,
|
||||
},
|
||||
},
|
||||
pnplNode(
|
||||
"amesim_pnpl01_7",
|
||||
{ x: 535.6129060235693, y: 523.6448805401301 },
|
||||
180,
|
||||
),
|
||||
pnplNode(
|
||||
"amesim_pnpl01_8",
|
||||
{ x: 587.2129060235693, y: 555.2448805401301 },
|
||||
90,
|
||||
),
|
||||
pnplNode(
|
||||
"amesim_pnpl01_9",
|
||||
{ x: 618.8129060235693, y: 523.6448805401301 },
|
||||
0,
|
||||
),
|
||||
],
|
||||
edges: [],
|
||||
};
|
||||
const overlapSnapshot = {
|
||||
...resultSnapshot,
|
||||
id: "overlapped-symbols-result",
|
||||
project: overlapProject,
|
||||
};
|
||||
await page.addInitScript((snapshot) => {
|
||||
window.sessionStorage.setItem(
|
||||
"system-simulation-flow:latest-result",
|
||||
JSON.stringify(snapshot),
|
||||
);
|
||||
}, overlapSnapshot);
|
||||
|
||||
await page.goto("/");
|
||||
await page.getByRole("tab", { name: /^结果/ }).click();
|
||||
await expectAllNodesInsideCanvas(
|
||||
page,
|
||||
".results-system-canvas",
|
||||
overlapProject.nodes.length,
|
||||
);
|
||||
|
||||
const targetNode = page.locator(
|
||||
`.results-system-canvas .react-flow__node[data-id="${targetNodeId}"]`,
|
||||
);
|
||||
const targetEnvelope = targetNode.locator('[data-symbol-envelope="true"]');
|
||||
await expect(targetNode).toHaveClass(/component-icon-node/);
|
||||
await expect(targetNode).toHaveCSS("pointer-events", "none");
|
||||
await expect(targetEnvelope).toHaveCSS("pointer-events", "auto");
|
||||
|
||||
const pane = page.locator(".results-system-canvas .react-flow__pane");
|
||||
const paneBox = await pane.boundingBox();
|
||||
expect(paneBox).not.toBeNull();
|
||||
await page.mouse.click(paneBox!.x + 6, paneBox!.y + 6);
|
||||
await expect(targetNode).not.toHaveClass(/selected/);
|
||||
|
||||
const envelopeBox = await targetEnvelope.boundingBox();
|
||||
expect(envelopeBox).not.toBeNull();
|
||||
const targetPoint = {
|
||||
x: envelopeBox!.x + envelopeBox!.width / 2,
|
||||
y: envelopeBox!.y + envelopeBox!.height / 2,
|
||||
};
|
||||
const hitNodeId = await page.evaluate(({ x, y }) => {
|
||||
const element = document.elementFromPoint(x, y);
|
||||
return element?.closest<HTMLElement>(".react-flow__node")?.dataset.id ?? null;
|
||||
}, targetPoint);
|
||||
expect(hitNodeId).toBe(targetNodeId);
|
||||
await page.mouse.click(targetPoint.x, targetPoint.y);
|
||||
await expect(targetNode).toHaveClass(/selected/);
|
||||
await expect(
|
||||
page.locator(
|
||||
'.results-system-canvas .react-flow__node[data-id^="amesim_pnpl01_"].selected',
|
||||
),
|
||||
).toHaveCount(0);
|
||||
});
|
||||
Reference in new issue
Block a user