File: /var/www/html/private/Mermaid代码转成图.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mermaid 流程图生成器</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }
.container { max-width: 1200px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
h1 { text-align: center; color: #333; }
textarea { width: 100%; height: 200px; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-family: monospace; font-size: 14px; resize: vertical; box-sizing: border-box; }
button { display: block; width: 100%; padding: 10px; background-color: #007bff; color: white; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; margin: 10px 0; }
button:hover:not(:disabled) { background-color: #0056b3; }
button:disabled { background-color: #6c757d; cursor: not-allowed; opacity: 0.6; }
#download-btn { width: 100%; padding: 10px; display: none; background-color: #28a745; font-size: 16px; margin-top: 10px; }
#download-btn:hover:not(:disabled) { background-color: #218838; }
#download-btn:disabled { opacity: 0.6; }
#mermaid-chart { margin-top: 20px; text-align: center; border: 1px solid #ddd; border-radius: 4px; padding: 10px; background: #fafafa; min-height: 400px; }
.instructions { background: #e9ecef; padding: 10px; border-radius: 4px; margin-bottom: 10px; }
.error { color: red; background: #ffe6e6; padding: 10px; border-radius: 4px; margin: 10px 0; }
.loading { color: blue; background: #e7f3ff; padding: 10px; border-radius: 4px; margin: 10px 0; }
.success { color: green; background: #d4edda; padding: 10px; border-radius: 4px; margin: 10px 0; }
#loading-msg { display: none; }
.debug-note { background: #f8f9fa; padding: 10px; border-radius: 4px; margin: 10px 0; font-size: 12px; }
.button-group { display: flex; flex-direction: column; align-items: center; gap: 10px; width: 100%; }
</style>
</head>
<body>
<div class="container">
<h1>Mermaid 流程图生成器</h1>
<div class="debug-note">
<p><strong>调试提示:</strong> 按 F12 打开控制台(Console 标签),查看加载日志和渲染日志。如果看到 "渲染回调执行" 和 "按钮恢复" 则正常;否则报告错误消息。</p>
</div>
<div class="instructions">
<p>输入 Mermaid 代码,点击按钮生成图。预填充 PPO 示例。生成后“下载 SVG”按钮会立即启用(绿色可按)。</p>
<p><strong>更新:</strong> 修复按钮状态:渲染后生成按钮立即恢复;下载按钮在回调执行后启用。即使 SVG 延迟,按钮也可用。</p>
</div>
<textarea id="mermaid-code">flowchart LR
A[初始化] --> B[策略网络 动作输出]
B --> C[Simulink 仿真]
C --> D[计算奖励 存储]
D --> E{缓冲区满?}
E -- 否 --> B
E -- 是 --> F[PPO更新 采样与计算]
F --> G[裁剪目标 函数更新]
G --> H{训练 完成?}
H -- 否 --> B
H -- 是 --> I[完成]
%% 样式定义
classDef init fill:#4e79a7,color:#fff
classDef interaction fill:#59a14f,color:#fff
classDef simulation fill:#76b7b2,color:#fff
classDef learning fill:#f28e2b,color:#fff
classDef decision fill:#e15759,color:#fff
classDef success fill:#59a14f,color:#fff
class A init
class B interaction
class C,D simulation
class F,G learning
class E,H decision
class I success</textarea>
<div class="button-group">
<button id="render-btn" onclick="renderMermaid()">生成流程图</button>
<button id="download-btn" onclick="downloadSVG()" disabled>下载 SVG</button>
</div>
<div id="loading-msg" class="loading">正在检测 Mermaid 库加载(最多10秒)...</div>
<div id="status-msg"></div>
<div id="error-msg" class="error" style="display: none;"></div>
<div id="mermaid-chart"></div>
</div>
<!-- 尝试加载本地 JS -->
<script src="mermaid.min.js"></script>
<script>
let mermaidReady = false;
let loadAttempts = 0;
const maxAttempts = 50; // 10s / 200ms = 50
function pollMermaid() {
loadAttempts++;
if (typeof mermaid !== 'undefined' && mermaidReady === false) {
mermaidReady = true;
document.getElementById('loading-msg').style.display = 'none';
document.getElementById('render-btn').disabled = false;
const status = document.getElementById('status-msg');
status.innerHTML = '<div class="success">Mermaid 库加载成功!现在您可以点击“生成流程图”按钮。</div>';
console.log('Mermaid detected via polling!');
return;
}
if (loadAttempts < maxAttempts) {
setTimeout(pollMermaid, 200);
} else {
console.log('Local load timeout, falling back to CDN');
loadCDN();
}
}
function loadCDN() {
const status = document.getElementById('loading-msg');
status.innerHTML = '本地加载超时,切换到在线 CDN...';
const script = document.createElement('script');
script.src = 'https://unpkg.com/mermaid@11/dist/mermaid.min.js';
script.async = true;
script.onload = function() {
mermaidReady = true;
status.style.display = 'none';
document.getElementById('render-btn').disabled = false;
const statusMsg = document.getElementById('status-msg');
statusMsg.innerHTML = '<div class="success">Mermaid 从 CDN 加载成功!现在您可以点击“生成流程图”按钮。</div>';
console.log('Mermaid loaded from CDN');
};
script.onerror = function() {
const error = document.getElementById('error-msg');
error.textContent = '本地和 CDN 均加载失败。请检查网络/CSP,或手动下载 JS 文件。控制台有详情。';
error.style.display = 'block';
status.style.display = 'none';
document.getElementById('render-btn').disabled = true;
console.error('CDN load failed');
};
document.head.appendChild(script);
}
function renderMermaid() {
if (!mermaidReady) {
alert('Mermaid 未就绪,请等待加载完成。');
return;
}
const code = document.getElementById('mermaid-code').value.trim();
const chartDiv = document.getElementById('mermaid-chart');
const errorDiv = document.getElementById('error-msg');
const btn = document.getElementById('render-btn');
const downloadBtn = document.getElementById('download-btn');
if (!code) {
errorDiv.textContent = '请输入 Mermaid 代码!';
errorDiv.style.display = 'block';
return;
}
errorDiv.style.display = 'none';
downloadBtn.disabled = true;
downloadBtn.style.display = 'block';
btn.disabled = true;
btn.textContent = '渲染中...';
chartDiv.innerHTML = ''; // 清空旧图
try {
const mermaidDiv = document.createElement('div');
mermaidDiv.className = 'mermaid';
mermaidDiv.textContent = code;
chartDiv.appendChild(mermaidDiv);
// 使用 Promise 包装 mermaid.run 以确保恢复状态
const renderPromise = mermaid.run({
nodes: [mermaidDiv],
suppressErrors: false
});
renderPromise.then((results) => {
console.log('渲染回调执行');
btn.disabled = false;
btn.textContent = '生成流程图';
downloadBtn.disabled = false; // 立即启用下载按钮
console.log('按钮恢复:生成按钮和下载按钮均启用');
// 检查 SVG(可选)
setTimeout(() => {
const svg = chartDiv.querySelector('svg');
if (svg) {
console.log('SVG 准备就绪,可下载');
} else {
console.warn('SVG 未立即找到,但按钮已启用');
}
}, 500);
}).catch((err) => {
console.error('Mermaid run error:', err);
errorDiv.textContent = '渲染失败:' + err.message + '。检查代码语法。';
errorDiv.style.display = 'block';
chartDiv.innerHTML = '<p>渲染出错,请检查代码。</p>';
btn.disabled = false;
btn.textContent = '生成流程图';
downloadBtn.disabled = true;
});
} catch (error) {
console.error('Render error:', error);
errorDiv.textContent = '渲染失败:' + error.message + '。检查代码语法。';
errorDiv.style.display = 'block';
chartDiv.innerHTML = '<p>渲染出错,请检查代码。</p>';
btn.disabled = false;
btn.textContent = '生成流程图';
downloadBtn.disabled = true;
}
}
function downloadSVG() {
const chartDiv = document.getElementById('mermaid-chart');
const svg = chartDiv.querySelector('svg');
if (!svg) {
alert('当前无 SVG 图可下载。请确保流程图已渲染成功(检查图是否显示)。如果图显示但下载失败,刷新页面重试。');
return;
}
const svgData = new XMLSerializer().serializeToString(svg);
const fullSvg = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n' + svgData;
const blob = new Blob([fullSvg], { type: 'image/svg+xml;charset=utf-8' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'flowchart.svg';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
console.log('SVG 下载启动');
}
// 启动加载检测
window.addEventListener('load', function() {
document.getElementById('loading-msg').style.display = 'block';
document.getElementById('render-btn').disabled = true;
document.getElementById('download-btn').style.display = 'none';
document.getElementById('download-btn').disabled = true;
console.log('Starting Mermaid poll...');
setTimeout(pollMermaid, 500);
});
</script>
</body>
</html>