<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{TITLE}}</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: {{FONT_FAMILY}};
background: {{BACKGROUND_GRADIENT}};
min-height: 100vh;
color: {{TEXT_COLOR}};
padding: 20px;
}
.dashboard-container {
max-width: 1600px;
margin: 0 auto;
}
/* Dashboard头部 */
.dashboard-header {
background: {{HEADER_GRADIENT}};
color: {{HEADER_TEXT_COLOR}};
padding: 30px;
border-radius: 15px;
margin-bottom: 20px;
text-align: center;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}
.dashboard-header h1 {
font-size: 2.5em;
font-weight: 300;
margin: 0;
}
.dashboard-header .meta {
margin-top: 10px;
opacity: 0.9;
font-size: 0.95em;
}
/* 栅格布局 */
.dashboard-grid {
display: grid;
grid-template-columns: repeat({{GRID_COLS}}, 1fr);
gap: 20px;
grid-auto-rows: minmax({{ROW_HEIGHT}}px, auto);
}
/* Panel卡片 */
.panel-card {
background: {{CONTAINER_BACKGROUND}};
border-radius: 12px;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
overflow: hidden;
transition: transform 0.2s, box-shadow 0.2s;
display: flex;
flex-direction: column;
}
.panel-card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0,0,0,0.15);
}
.panel-card-header {
padding: 15px 20px;
border-bottom: 2px solid {{HEADER_GRADIENT}};
background: {{HEADER_GRADIENT}};
color: {{HEADER_TEXT_COLOR}};
}
.panel-card-header h3 {
margin: 0;
font-size: 1.2em;
font-weight: 500;
}
.panel-card-body {
flex: 1;
position: relative;
min-height: 400px;
}
.panel-card-body iframe {
width: 100%;
height: 100%;
border: none;
position: absolute;
top: 0;
left: 0;
}
.panel-link {
padding: 10px 20px;
border-top: 1px solid {{FOOTER_BORDER}};
text-align: center;
}
.panel-link a {
color: {{HEADER_GRADIENT}};
text-decoration: none;
font-size: 0.9em;
transition: opacity 0.2s;
}
.panel-link a:hover {
opacity: 0.7;
}
/* 页脚 */
.dashboard-footer {
text-align: center;
padding: 30px 20px;
color: {{FOOTER_TEXT_COLOR}};
font-size: 0.9em;
margin-top: 30px;
border-top: 1px solid {{FOOTER_BORDER}};
}
/* 加载动画 */
.loading {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: {{FOOTER_TEXT_COLOR}};
}
.loading::after {
content: "加载中...";
}
/* 响应式设计 */
@media (max-width: 1200px) {
.dashboard-grid {
grid-template-columns: repeat(6, 1fr);
}
}
@media (max-width: 768px) {
body {
padding: 10px;
}
.dashboard-header {
padding: 20px;
}
.dashboard-header h1 {
font-size: 1.8em;
}
.dashboard-grid {
grid-template-columns: 1fr !important;
gap: 15px;
}
.panel-card {
grid-column: 1 / -1 !important;
}
.panel-card-body {
min-height: 300px;
}
}
/* 打印样式 */
@media print {
body {
background: white;
padding: 0;
}
.dashboard-header {
background: #f5f5f5;
color: #333;
}
.panel-card {
break-inside: avoid;
box-shadow: none;
border: 1px solid #ddd;
}
.panel-link {
display: none;
}
.dashboard-footer {
page-break-before: always;
}
}
</style>
</head>
<body>
<div class="dashboard-container">
<!-- Dashboard头部 -->
<div class="dashboard-header">
<h1>{{TITLE}}</h1>
<div class="meta">
<span>生成时间: {{GENERATION_TIME}}</span>
<span style="margin: 0 10px;">•</span>
<span>图表数量: {{CHART_COUNT}}</span>
</div>
</div>
<!-- Panel网格 -->
<div class="dashboard-grid" id="dashboardGrid">
{{PANEL_CARDS}}
</div>
<!-- 页脚 -->
<div class="dashboard-footer">
<p>由专业数据可视化MCP服务器生成 | Dashboard聚合模式</p>
<p style="margin-top: 10px; font-size: 0.85em;">
所有图表均为独立Panel,支持独立访问和分享
</p>
</div>
</div>
<script>
// Panel配置
const panelsConfig = {{PANELS_CONFIG}};
console.log(`Dashboard loaded with ${panelsConfig.length} panels`);
// 监听iframe加载
document.querySelectorAll('iframe').forEach((iframe, index) => {
iframe.addEventListener('load', () => {
console.log(`Panel ${index + 1} loaded successfully`);
});
iframe.addEventListener('error', () => {
console.error(`Panel ${index + 1} failed to load`);
const container = iframe.parentElement;
if (container) {
container.innerHTML = '<div class="loading">加载失败</div>';
}
});
});
// 响应式高度调整
function adjustIframeHeights() {
document.querySelectorAll('.panel-card-body').forEach(body => {
const card = body.closest('.panel-card');
if (card) {
const gridRowSpan = window.getComputedStyle(card).gridRowEnd;
// 自适应高度
}
});
}
window.addEventListener('resize', adjustIframeHeights);
window.addEventListener('load', adjustIframeHeights);
// 暴露全局API
window.DashboardAPI = {
getPanels: () => panelsConfig,
reloadPanel: (index) => {
const iframe = document.querySelectorAll('iframe')[index];
if (iframe) {
iframe.src = iframe.src;
}
},
reloadAll: () => {
document.querySelectorAll('iframe').forEach(iframe => {
iframe.src = iframe.src;
});
}
};
</script>
</body>
</html>