273 lines
8.0 KiB
HTML
273 lines
8.0 KiB
HTML
<!doctype html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>System Simulation App</title>
|
|
<style>
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
height: 100vh;
|
|
color: #18202a;
|
|
font-family:
|
|
system-ui,
|
|
-apple-system,
|
|
BlinkMacSystemFont,
|
|
"Segoe UI",
|
|
sans-serif;
|
|
background: #f6f8fb;
|
|
}
|
|
|
|
.app {
|
|
display: grid;
|
|
grid-template-rows: 48px minmax(0, 1fr);
|
|
height: 100vh;
|
|
}
|
|
|
|
.toolbar {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
padding: 0 14px;
|
|
border-bottom: 1px solid #d8dee8;
|
|
background: #ffffff;
|
|
}
|
|
|
|
.title {
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
font-size: 15px;
|
|
font-weight: 650;
|
|
line-height: 1.2;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.status {
|
|
max-width: 220px;
|
|
overflow: hidden;
|
|
color: #5d6877;
|
|
font-size: 13px;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
button {
|
|
height: 32px;
|
|
padding: 0 12px;
|
|
border: 1px solid #1b6fb8;
|
|
border-radius: 6px;
|
|
color: #ffffff;
|
|
font: inherit;
|
|
font-size: 14px;
|
|
background: #1b6fb8;
|
|
cursor: pointer;
|
|
}
|
|
|
|
button:disabled {
|
|
border-color: #98a2af;
|
|
background: #98a2af;
|
|
cursor: wait;
|
|
}
|
|
|
|
iframe {
|
|
display: block;
|
|
width: 100%;
|
|
height: 100%;
|
|
border: 0;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<main class="app">
|
|
<header class="toolbar">
|
|
<div class="title">System Simulation App</div>
|
|
<div class="actions">
|
|
<span class="status" id="status">加载中</span>
|
|
<button id="export-button" type="button" disabled>生成 XML</button>
|
|
</div>
|
|
</header>
|
|
<iframe id="drawio-frame" title="draw.io"></iframe>
|
|
</main>
|
|
|
|
<script>
|
|
const DRAWIO_BASE_URL = __DRAWIO_BASE_URL__;
|
|
const frame = document.getElementById("drawio-frame");
|
|
const exportButton = document.getElementById("export-button");
|
|
const statusNode = document.getElementById("status");
|
|
const drawioUrl = new URL(DRAWIO_BASE_URL, window.location.href);
|
|
drawioUrl.searchParams.set("embed", "1");
|
|
drawioUrl.searchParams.set("proto", "json");
|
|
drawioUrl.searchParams.set("configure", "1");
|
|
drawioUrl.searchParams.set("libraries", "1");
|
|
drawioUrl.searchParams.set("spin", "1");
|
|
drawioUrl.searchParams.set("noSaveBtn", "1");
|
|
drawioUrl.searchParams.set("noExitBtn", "1");
|
|
drawioUrl.searchParams.set("saveAndExit", "0");
|
|
frame.src = drawioUrl.toString();
|
|
|
|
let pendingExport = false;
|
|
|
|
const initialXml =
|
|
'<mxGraphModel dx="1200" dy="800" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0"><root><mxCell id="0"/><mxCell id="1" parent="0"/></root></mxGraphModel>';
|
|
|
|
const componentLibrary = [
|
|
{
|
|
title: "贮箱",
|
|
w: 80,
|
|
h: 80,
|
|
xml:
|
|
'<mxGraphModel><root><mxCell id="0"/><mxCell id="1" parent="0"/><object id="tank" label="贮箱" componentType="tank" medium="N2" volume="1.0"><mxCell style="shape=cylinder;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1"><mxGeometry width="80" height="80" as="geometry"/></mxCell></object></root></mxGraphModel>',
|
|
},
|
|
{
|
|
title: "阀门",
|
|
w: 72,
|
|
h: 56,
|
|
xml:
|
|
'<mxGraphModel><root><mxCell id="0"/><mxCell id="1" parent="0"/><object id="valve" label="阀门" componentType="valve" valveType="manual" nominalDiameter="10"><mxCell style="rhombus;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1"><mxGeometry width="72" height="56" as="geometry"/></mxCell></object></root></mxGraphModel>',
|
|
},
|
|
{
|
|
title: "管段",
|
|
w: 96,
|
|
h: 36,
|
|
xml:
|
|
'<mxGraphModel><root><mxCell id="0"/><mxCell id="1" parent="0"/><object id="pipe" label="管段" componentType="pipe" length="1.0" diameter="0.01"><mxCell style="rounded=1;whiteSpace=wrap;html=1;arcSize=12;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1"><mxGeometry width="96" height="36" as="geometry"/></mxCell></object></root></mxGraphModel>',
|
|
},
|
|
];
|
|
|
|
function setStatus(text) {
|
|
statusNode.textContent = text;
|
|
}
|
|
|
|
function sendToDrawio(message) {
|
|
frame.contentWindow.postMessage(JSON.stringify(message), drawioUrl.origin);
|
|
}
|
|
|
|
function parseMessage(data) {
|
|
if (typeof data !== "string") {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return JSON.parse(data);
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
window.addEventListener("message", async (event) => {
|
|
if (event.origin !== drawioUrl.origin) {
|
|
return;
|
|
}
|
|
|
|
const message = parseMessage(event.data);
|
|
if (!message) {
|
|
return;
|
|
}
|
|
|
|
if (message.event === "configure") {
|
|
sendToDrawio({
|
|
action: "configure",
|
|
config: {
|
|
defaultLibraries: "system-components",
|
|
enabledLibraries: [],
|
|
enableCustomLibraries: false,
|
|
libraries: [
|
|
{
|
|
title: { main: "System" },
|
|
entries: [
|
|
{
|
|
id: "system-components",
|
|
title: { main: "Components" },
|
|
libs: [
|
|
{
|
|
title: { main: "Components" },
|
|
data: componentLibrary,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (message.event === "init") {
|
|
sendToDrawio({
|
|
action: "load",
|
|
xml: initialXml,
|
|
title: "system.drawio",
|
|
autosave: 1,
|
|
});
|
|
exportButton.disabled = false;
|
|
setStatus("已就绪");
|
|
return;
|
|
}
|
|
|
|
if (message.event === "autosave") {
|
|
setStatus("已更新");
|
|
return;
|
|
}
|
|
|
|
if (message.event === "save" && pendingExport) {
|
|
pendingExport = false;
|
|
await exportSystemXml(message.xml);
|
|
}
|
|
});
|
|
|
|
exportButton.addEventListener("click", () => {
|
|
pendingExport = true;
|
|
exportButton.disabled = true;
|
|
setStatus("生成中");
|
|
sendToDrawio({ action: "save" });
|
|
});
|
|
|
|
async function exportSystemXml(diagramXml) {
|
|
try {
|
|
const response = await fetch("/api/system-xml", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ xml: diagramXml }),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(await response.text());
|
|
}
|
|
|
|
const systemXml = await response.text();
|
|
downloadText(systemXml, "system.xml", "application/xml");
|
|
setStatus("已生成");
|
|
} catch (error) {
|
|
console.error(error);
|
|
setStatus("生成失败");
|
|
} finally {
|
|
exportButton.disabled = false;
|
|
}
|
|
}
|
|
|
|
function downloadText(text, filename, mimeType) {
|
|
const blob = new Blob([text], { type: mimeType });
|
|
const url = URL.createObjectURL(blob);
|
|
const link = document.createElement("a");
|
|
link.href = url;
|
|
link.download = filename;
|
|
link.click();
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|