Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

424 lines
14 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🌊 光湖纪元 · 实时系统仪表盘</title>
<style>
:root {
--bg: #0d1117;
--card: #161b22;
--border: #30363d;
--text: #e6edf3;
--text2: #8b949e;
--accent: #58a6ff;
--green: #3fb950;
--yellow: #d29922;
--red: #f85149;
--purple: #bc8cff;
--pink: #f778ba;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: var(--bg);
color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
min-height: 100vh;
}
.header {
text-align: center;
padding: 2rem 1rem 1rem;
border-bottom: 1px solid var(--border);
}
.header h1 { font-size: 1.8rem; margin-bottom: 0.5rem; }
.header h1 span { color: var(--accent); }
.header .subtitle { color: var(--text2); font-size: 0.95rem; }
.status-bar {
display: flex;
justify-content: center;
gap: 1.5rem;
padding: 1rem;
flex-wrap: wrap;
}
.status-pill {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0.4rem 1rem;
border-radius: 2rem;
background: var(--card);
border: 1px solid var(--border);
font-size: 0.85rem;
}
.status-pill .dot {
width: 8px; height: 8px; border-radius: 50%;
animation: pulse 2s infinite;
}
.dot.green { background: var(--green); }
.dot.yellow { background: var(--yellow); }
.dot.red { background: var(--red); }
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem;
padding: 1.5rem;
max-width: 1200px;
margin: 0 auto;
}
.card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 8px;
padding: 1.2rem;
position: relative;
overflow: hidden;
}
.card::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
height: 3px;
}
.card.blue::before { background: var(--accent); }
.card.green::before { background: var(--green); }
.card.purple::before { background: var(--purple); }
.card.pink::before { background: var(--pink); }
.card.yellow::before { background: var(--yellow); }
.card .title {
font-size: 0.8rem;
color: var(--text2);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 0.8rem;
}
.card .value {
font-size: 2.2rem;
font-weight: 700;
line-height: 1;
}
.card .detail {
font-size: 0.8rem;
color: var(--text2);
margin-top: 0.5rem;
}
.wide-card {
grid-column: 1 / -1;
}
.section-title {
padding: 1.5rem 1.5rem 0.5rem;
max-width: 1200px;
margin: 0 auto;
font-size: 1.1rem;
color: var(--text2);
border-top: 1px solid var(--border);
}
/* Activity Timeline */
.timeline { list-style: none; }
.timeline li {
display: flex;
gap: 0.8rem;
padding: 0.6rem 0;
border-bottom: 1px solid var(--border);
font-size: 0.85rem;
}
.timeline li:last-child { border-bottom: none; }
.timeline .time { color: var(--text2); min-width: 5rem; }
.timeline .event { flex: 1; }
/* Gauge */
.gauge-row {
display: flex;
align-items: center;
gap: 0.8rem;
margin-bottom: 0.5rem;
}
.gauge-row .label { font-size: 0.8rem; min-width: 5rem; color: var(--text2); }
.gauge-bar {
flex: 1;
height: 6px;
background: var(--border);
border-radius: 3px;
overflow: hidden;
}
.gauge-fill {
height: 100%;
border-radius: 3px;
transition: width 1s ease-out;
}
.gauge-fill.green { background: var(--green); }
.gauge-fill.blue { background: var(--accent); }
.gauge-fill.purple { background: var(--purple); }
.gauge-fill.yellow { background: var(--yellow); }
.gauge-row .pct { font-size: 0.8rem; min-width: 3rem; text-align: right; }
/* Footer */
.footer {
text-align: center;
padding: 2rem 1rem;
color: var(--text2);
font-size: 0.8rem;
border-top: 1px solid var(--border);
}
.footer a { color: var(--accent); text-decoration: none; }
/* Loading */
.loading {
text-align: center;
padding: 3rem;
color: var(--text2);
}
.spinner {
display: inline-block;
width: 2rem; height: 2rem;
border: 3px solid var(--border);
border-top-color: var(--accent);
border-radius: 50%;
animation: spin 0.8s linear infinite;
margin-bottom: 1rem;
}
@keyframes spin { to { transform: rotate(360deg); } }
/* Responsive */
@media (max-width: 600px) {
.grid { padding: 0.8rem; }
.card .value { font-size: 1.8rem; }
}
.blink { animation: blink-anim 1s steps(1) infinite; }
@keyframes blink-anim {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
.refresh-btn {
background: var(--card);
border: 1px solid var(--border);
color: var(--accent);
padding: 0.4rem 1rem;
border-radius: 4px;
cursor: pointer;
font-size: 0.8rem;
margin-left: 0.5rem;
}
.refresh-btn:hover { background: var(--border); }
</style>
</head>
<body>
<div class="header">
<h1>🌊 <span>光湖纪元</span> · 实时系统仪表盘</h1>
<div class="subtitle">
AGE-5 · 数字地球操作系统 · 数据每次系统执行后自动更新
<button class="refresh-btn" onclick="loadData()">🔄 刷新</button>
</div>
</div>
<div id="status-bar" class="status-bar">
<div class="status-pill"><div class="dot green"></div> 加载中...</div>
</div>
<div id="content">
<div class="loading">
<div class="spinner"></div>
<div>正在从仓库加载实时数据...</div>
</div>
</div>
<div class="footer">
<p>
<a href="https://github.com/qinfendebingshuo/guanghulab">📦 返回仓库</a> ·
<a href="https://guanghulab.com">🌐 guanghulab.com</a> ·
数据源: <code>data/system-health.json</code>
</p>
<p style="margin-top:0.5rem">
光湖 HoloLake · 由冰朔创建 · 铸渊守护 · 🏛️ 国作登字-2026-A-00037559
</p>
<p id="last-update" style="margin-top:0.3rem"></p>
</div>
<script>
var REPO = 'qinfendebingshuo/guanghulab';
var BRANCH = 'main';
var HEALTH_PATH = 'data/system-health.json';
var BULLETIN_PATH = 'data/bulletin-board.json';
function rawUrl(p) {
return 'https://raw.githubusercontent.com/' + REPO + '/' + BRANCH + '/' + p + '?t=' + Date.now();
}
async function fetchJSON(url) {
var res = await fetch(url);
if (!res.ok) throw new Error('HTTP ' + res.status);
return res.json();
}
function timeSince(dateStr) {
var d = new Date(dateStr);
var now = new Date();
var sec = Math.floor((now - d) / 1000);
if (sec < 60) return sec + '秒前';
var min = Math.floor(sec / 60);
if (min < 60) return min + '分钟前';
var hr = Math.floor(min / 60);
if (hr < 24) return hr + '小时前';
var day = Math.floor(hr / 24);
return day + '天前';
}
function statusColor(s) {
if (s === 'healthy') return 'green';
if (s === 'warning') return 'yellow';
return 'red';
}
function renderStatusBar(health) {
var bar = document.getElementById('status-bar');
var s = health.system_status || 'unknown';
var color = statusColor(s);
var statusText = s === 'healthy' ? '✅ 系统正常运转' : s === 'warning' ? '⚠️ 系统有告警' : '❌ 系统异常';
var updated = health.last_updated ? timeSince(health.last_updated) : '未知';
bar.innerHTML =
'<div class="status-pill"><div class="dot ' + color + '"></div> ' + statusText + '</div>' +
'<div class="status-pill">🕐 数据更新于 ' + updated + '</div>' +
'<div class="status-pill">🧬 神经系统 ' + (health.metrics.neural_system_version || 'v?') + '</div>' +
'<div class="status-pill">📜 本体论 ' + (health.metrics.ontology_version || 'v?') + '</div>';
}
function renderCards(health) {
var m = health.metrics;
var scan = health.last_skyeye_scan || {};
var html = '';
// Section: Core Metrics
html += '<div class="section-title">📊 核心指标 · Core Metrics</div>';
html += '<div class="grid">';
html += card('blue', '⚙️ 自动化流水线 (Workflows)', m.workflows.total,
'活跃 ' + m.workflows.active + ' · 失败 ' + m.workflows.failed + ' · 成功率 ' +
(m.workflows.total > 0 ? Math.round((m.workflows.active / m.workflows.total) * 100) : 0) + '%');
html += card('purple', '🤖 智能代理 (Agents)', m.agents.total,
'24 小时全天候自动运行');
html += card('pink', '🎭 AI 人格体 (Personas)', m.ai_personas.total,
'在线 ' + m.ai_personas.active + ' · 休眠 ' + m.ai_personas.hibernating);
html += card('green', '👥 人类开发者 (Developers)', m.human_developers.total,
'24h 活跃 ' + m.human_developers.active_24h + ' 人');
html += card('yellow', '🛡️ 系统守卫 (Guards)', m.guards.total,
'在线 ' + m.guards.active + ' · 告警 ' + m.guards.warnings);
html += card('blue', '📦 功能模块 (Modules)', m.modules.total,
'登录·人格·用户中心·工单·对话·云服务·看板·云盘·健康检查');
html += '</div>';
// Section: Performance
html += '<div class="section-title">⚡ 运行性能 · Performance</div>';
html += '<div class="grid">';
html += gaugeCard('系统健康', [
{ label: '流水线', pct: m.workflows.total > 0 ? Math.round((m.workflows.active / m.workflows.total) * 100) : 0, color: 'green' },
{ label: '守卫', pct: m.guards.total > 0 ? Math.round((m.guards.active / m.guards.total) * 100) : 0, color: 'blue' },
{ label: '人格体', pct: m.ai_personas.total > 0 ? Math.round((m.ai_personas.active / m.ai_personas.total) * 100) : 0, color: 'purple' },
{ label: '目录完整', pct: scan.directories ? parseFraction(scan.directories) : 100, color: 'green' }
]);
html += card('green', '⏱️ 部署耗时', '< 3 min', '从代码提交到生产环境上线');
html += card('blue', '🔁 每日自动化', '50+', '定时任务 + 事件触发 + 手动调度');
html += card('purple', '🔄 Notion 同步延迟', '< 60s', 'GitHub 代码变更 → Notion 知识库');
html += '</div>';
// Section: SkyEye Scan
html += '<div class="section-title">🦅 天眼扫描 · SkyEye Scan</div>';
html += '<div class="grid">';
html += card('blue', '📋 最近扫描', scan.id || '—',
'流水线 ' + (scan.workflows || '?') + ' · 守卫 ' + (scan.guards || '?') + ' · 目录 ' + (scan.directories || '?'));
html += card(scan.issues > 0 ? 'yellow' : 'green', '🔍 扫描结果',
(scan.issues || 0) + ' 个问题',
'错误 ' + (scan.errors || 0) + ' · 告警 ' + (scan.warnings || 0));
html += card('green', '📜 本体论完整性 (D16)', scan.d16_ontology || '—', '6 条核心公理 · 3 层安全定义');
html += card('green', '🧬 神经映射完整性 (D20)', scan.d20_neural_map || '—', '11 核心流水线 · 5 Notion 知识库');
html += '</div>';
// Section: Hibernation
html += '<div class="section-title">🌙 休眠节律 · Hibernation</div>';
html += '<div class="grid">';
var hib = health.hibernation || {};
html += card('purple', '⭐ 周休眠', hib.next_weekly || '—', '全局快照 + 自愈扫描 + 系统优化');
html += card('blue', '🌙 日休眠', hib.next_daily || '—', '日检查点 + 健康探针');
html += card(health.alerts && health.alerts.length > 0 ? 'red' : 'green', '🚨 系统告警',
health.alerts && health.alerts.length > 0 ? health.alerts.length + ' 条告警' : '无告警',
health.alerts && health.alerts.length > 0 ? health.alerts.map(function(a) { return a; }).join(' · ') : '系统运行正常');
html += '</div>';
document.getElementById('content').innerHTML = html;
}
function card(color, title, value, detail) {
return '<div class="card ' + color + '">' +
'<div class="title">' + title + '</div>' +
'<div class="value">' + value + '</div>' +
'<div class="detail">' + detail + '</div>' +
'</div>';
}
function gaugeCard(title, gauges) {
var html = '<div class="card green"><div class="title">' + title + '</div>';
for (var i = 0; i < gauges.length; i++) {
var g = gauges[i];
html += '<div class="gauge-row">' +
'<div class="label">' + g.label + '</div>' +
'<div class="gauge-bar"><div class="gauge-fill ' + g.color + '" style="width:' + g.pct + '%"></div></div>' +
'<div class="pct">' + g.pct + '%</div>' +
'</div>';
}
html += '</div>';
return html;
}
function parseFraction(str) {
var parts = str.split('/');
if (parts.length === 2) {
var num = parseInt(parts[0]);
var den = parseInt(parts[1]);
return den > 0 ? Math.round((num / den) * 100) : 0;
}
return 100;
}
async function loadData() {
try {
var health;
try {
health = await fetchJSON(rawUrl(HEALTH_PATH));
} catch (e1) {
// Fallback: try loading from local path (for GitHub Pages deployment)
health = await fetchJSON('./system-health.json?t=' + Date.now());
}
renderStatusBar(health);
renderCards(health);
document.getElementById('last-update').textContent =
'🕐 数据加载于 ' + new Date().toLocaleString('zh-CN') +
' · 数据更新于 ' + (health.last_updated || '未知');
} catch (e) {
document.getElementById('content').innerHTML =
'<div class="loading" style="color:var(--red)">❌ 数据加载失败: ' + e.message +
'<br><br><button class="refresh-btn" onclick="loadData()">🔄 重试</button></div>';
}
}
// Auto-refresh every 5 minutes
loadData();
setInterval(loadData, 5 * 60 * 1000);
</script>
</body>
</html>