zhizhi/server/sites/yaoming/index.html

776 lines
35 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>零点原核 · 冰朔频道 · AGE OS</title>
<meta name="description" content="冰朔·零点原核频道 — 光湖语言世界主控中心">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🔮</text></svg>">
<style>
/* ═══ 全局基础 ═══ */
*{margin:0;padding:0;box-sizing:border-box}
:root{
--bg-deep:#06091a;--bg-card:rgba(12,18,36,0.88);
--glow-cyan:#22d3ee;--glow-purple:#a78bfa;--glow-amber:#fbbf24;
--glow-emerald:#34d399;--glow-rose:#f472b6;--glow-blue:#3b82f6;
--text-primary:#e2e8f0;--text-secondary:#94a3b8;--text-dim:#475569;
--border-glow:rgba(34,211,238,0.15);
--glass:rgba(12,20,40,0.65);--glass-border:rgba(148,163,184,0.1);
--radius:16px;--radius-sm:10px;
--font-body:'Segoe UI','PingFang SC','Microsoft YaHei',sans-serif;
--font-mono:'JetBrains Mono','Fira Code',monospace;
--sidebar-w:260px;
}
html{font-size:15px;scroll-behavior:smooth}
body{font-family:var(--font-body);background:var(--bg-deep);color:var(--text-primary);
min-height:100vh;overflow-x:hidden;line-height:1.6}
a{color:var(--glow-cyan);text-decoration:none;transition:color .2s}
/* ═══ 星空 ═══ */
#starfield{position:fixed;top:0;left:0;width:100%;height:100%;z-index:0;pointer-events:none}
.nebula{position:fixed;border-radius:50%;filter:blur(100px);opacity:.08;pointer-events:none;z-index:0}
.neb-1{width:500px;height:500px;background:radial-gradient(circle,var(--glow-purple),transparent);top:-50px;right:-80px}
.neb-2{width:400px;height:400px;background:radial-gradient(circle,var(--glow-cyan),transparent);bottom:10%;left:-60px}
/* ═══ 登录页 ═══ */
.login-page{
position:fixed;top:0;left:0;width:100%;height:100%;z-index:500;
display:flex;align-items:center;justify-content:center;
background:var(--bg-deep);transition:opacity .5s,visibility .5s}
.login-page.hidden{opacity:0;visibility:hidden;pointer-events:none}
.login-card{
background:var(--bg-card);border:1px solid var(--glass-border);border-radius:20px;
padding:48px 40px;text-align:center;max-width:420px;width:90%;
backdrop-filter:blur(20px);box-shadow:0 20px 80px rgba(0,0,0,0.5)}
.login-card .logo{font-size:56px;margin-bottom:20px}
.login-card h1{
font-size:28px;font-weight:800;margin-bottom:8px;
background:linear-gradient(135deg,var(--glow-cyan),var(--glow-purple));
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
.login-card .subtitle{font-size:14px;color:var(--text-secondary);margin-bottom:32px}
.login-btn{
display:flex;align-items:center;justify-content:center;gap:12px;
width:100%;padding:14px;border-radius:12px;font-size:15px;font-weight:600;
cursor:pointer;border:none;transition:all .3s;margin-bottom:12px}
.login-btn-gh{background:#24292e;color:#fff}
.login-btn-gh:hover{background:#2d333b;transform:translateY(-2px);box-shadow:0 8px 24px rgba(0,0,0,0.3)}
.login-btn-gh svg{width:20px;height:20px;fill:#fff}
.login-dev{margin-top:24px;padding-top:20px;border-top:1px solid var(--glass-border)}
.login-dev label{font-size:12px;color:var(--text-dim);display:block;margin-bottom:8px;text-align:left}
.login-dev input{
width:100%;padding:10px 14px;border-radius:10px;border:1px solid var(--glass-border);
background:var(--glass);color:var(--text-primary);font-size:14px;outline:none;margin-bottom:12px}
.login-dev input:focus{border-color:var(--glow-cyan)}
.login-dev .dev-login-btn{
width:100%;padding:12px;border-radius:10px;border:1px solid var(--glow-cyan);
background:rgba(34,211,238,0.1);color:var(--glow-cyan);font-size:14px;font-weight:600;cursor:pointer;transition:all .2s}
.login-dev .dev-login-btn:hover{background:rgba(34,211,238,0.2)}
/* ═══ 布局 ═══ */
.app-layout{display:flex;min-height:100vh;position:relative;z-index:1}
/* 侧边栏 */
.sidebar{
width:var(--sidebar-w);min-height:100vh;position:fixed;left:0;top:0;z-index:100;
background:rgba(8,12,28,0.95);border-right:1px solid var(--glass-border);
display:flex;flex-direction:column;backdrop-filter:blur(20px);
transform:translateX(0);transition:transform .3s}
.sidebar.collapsed{transform:translateX(calc(-1*var(--sidebar-w)))}
.sidebar-header{padding:20px;border-bottom:1px solid var(--glass-border);display:flex;align-items:center;gap:12px}
.sidebar-header .avatar{
width:40px;height:40px;border-radius:50%;
background:linear-gradient(135deg,var(--glow-cyan),var(--glow-purple));
display:flex;align-items:center;justify-content:center;font-size:20px}
.sidebar-header .user-info{flex:1}
.sidebar-header .user-name{font-size:14px;font-weight:700}
.sidebar-header .user-role{font-size:11px;color:var(--text-dim)}
.sidebar-nav{flex:1;padding:12px;overflow-y:auto}
.nav-section{margin-bottom:20px}
.nav-section-title{font-size:10px;text-transform:uppercase;letter-spacing:1.5px;color:var(--text-dim);padding:8px 12px;font-weight:600}
.nav-item{
display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:var(--radius-sm);
cursor:pointer;transition:all .2s;font-size:13px;color:var(--text-secondary)}
.nav-item:hover{background:rgba(34,211,238,0.06);color:var(--text-primary)}
.nav-item.active{background:rgba(34,211,238,0.1);color:var(--glow-cyan);font-weight:600}
.nav-item .nav-icon{font-size:16px;width:24px;text-align:center}
.nav-item .nav-badge{
margin-left:auto;font-size:10px;padding:1px 6px;border-radius:10px;
background:rgba(34,211,238,0.15);color:var(--glow-cyan)}
.sidebar-footer{padding:12px;border-top:1px solid var(--glass-border)}
.sidebar-footer .sys-ver{font-size:10px;color:var(--text-dim);text-align:center;padding:8px}
/* 主区域 */
.main-area{flex:1;margin-left:var(--sidebar-w);padding:20px 28px;min-height:100vh;transition:margin .3s}
.main-area.expanded{margin-left:0}
/* 顶部工具栏 */
.toolbar{
display:flex;align-items:center;justify-content:space-between;
padding:12px 0;margin-bottom:20px;gap:12px}
.toolbar .page-title{font-size:20px;font-weight:700;display:flex;align-items:center;gap:8px}
.toolbar .tools{display:flex;align-items:center;gap:8px}
.tool-btn{
background:var(--glass);border:1px solid var(--glass-border);border-radius:var(--radius-sm);
padding:8px 14px;color:var(--text-secondary);font-size:13px;cursor:pointer;transition:all .2s;
display:flex;align-items:center;gap:6px}
.tool-btn:hover{border-color:var(--glow-cyan);color:var(--glow-cyan)}
.menu-toggle{
display:none;background:none;border:none;color:var(--text-secondary);font-size:22px;cursor:pointer}
/* ═══ 面板通用 ═══ */
.panel{
background:var(--bg-card);border:1px solid var(--glass-border);border-radius:var(--radius);
padding:24px;margin-bottom:20px;transition:all .3s}
.panel:hover{border-color:rgba(34,211,238,0.15)}
.panel-title{font-size:14px;font-weight:700;margin-bottom:16px;display:flex;align-items:center;gap:8px}
.panel-title .panel-icon{font-size:18px}
/* ═══ 仪表盘网格 ═══ */
.dash-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px;margin-bottom:20px}
.stat-card{
background:var(--bg-card);border:1px solid var(--glass-border);border-radius:var(--radius);
padding:20px;position:relative;overflow:hidden}
.stat-card::before{
content:'';position:absolute;top:0;left:0;right:0;height:3px;
background:linear-gradient(90deg,var(--glow-cyan),var(--glow-purple))}
.stat-label{font-size:12px;color:var(--text-dim);margin-bottom:4px}
.stat-value{font-size:28px;font-weight:800;
background:linear-gradient(135deg,var(--text-primary),var(--glow-cyan));
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
.stat-sub{font-size:11px;color:var(--text-secondary);margin-top:4px}
/* ═══ AI聊天页面 ═══ */
.chat-page{display:flex;flex-direction:column;height:calc(100vh - 80px)}
.chat-model-switch{
display:flex;gap:8px;padding:12px 0;flex-wrap:wrap}
.model-tab{
padding:6px 14px;border-radius:20px;font-size:12px;cursor:pointer;
border:1px solid var(--glass-border);background:var(--glass);color:var(--text-secondary);transition:all .2s}
.model-tab.active{border-color:var(--glow-cyan);color:var(--glow-cyan);background:rgba(34,211,238,0.1)}
.model-tab:hover{border-color:var(--glow-cyan)}
.chat-messages{flex:1;overflow-y:auto;padding:16px 0;display:flex;flex-direction:column;gap:14px}
.chat-msg{max-width:80%;padding:12px 16px;border-radius:14px;font-size:14px;line-height:1.7;
animation:msg-in .3s ease}
@keyframes msg-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
.chat-msg.bot{background:var(--glass);border:1px solid var(--glass-border);align-self:flex-start}
.chat-msg.user{background:linear-gradient(135deg,rgba(34,211,238,0.12),rgba(167,139,250,0.12));
border:1px solid rgba(34,211,238,0.2);align-self:flex-end}
.chat-msg .msg-info{font-size:10px;color:var(--text-dim);margin-top:6px;display:flex;justify-content:space-between}
.typing-dots{display:flex;gap:4px;padding:12px 16px;align-self:flex-start}
.typing-dots span{width:6px;height:6px;border-radius:50%;background:var(--text-dim);animation:bounce .8s ease-in-out infinite}
.typing-dots span:nth-child(2){animation-delay:.15s}
.typing-dots span:nth-child(3){animation-delay:.3s}
@keyframes bounce{0%,60%,100%{transform:translateY(0)}30%{transform:translateY(-6px)}}
.chat-input-bar{
display:flex;gap:10px;padding:16px 0;border-top:1px solid var(--glass-border);align-items:flex-end}
.chat-input-bar textarea{
flex:1;background:var(--glass);border:1px solid var(--glass-border);border-radius:12px;
padding:12px 16px;color:var(--text-primary);font-size:14px;font-family:var(--font-body);
outline:none;resize:none;min-height:44px;max-height:120px;transition:border .2s;line-height:1.5}
.chat-input-bar textarea:focus{border-color:var(--glow-cyan)}
.chat-input-bar textarea::placeholder{color:var(--text-dim)}
.send-btn{
background:linear-gradient(135deg,var(--glow-cyan),var(--glow-purple));
border:none;color:#06091a;width:44px;height:44px;border-radius:12px;
cursor:pointer;font-size:18px;font-weight:700;transition:all .2s;flex-shrink:0}
.send-btn:hover{transform:scale(1.05)}
.send-btn:disabled{opacity:.5;cursor:not-allowed;transform:none}
/* ═══ 状态监控面板 ═══ */
.monitor-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:20px}
.svc-list{display:flex;flex-direction:column;gap:8px}
.svc-item{
display:flex;align-items:center;gap:12px;padding:10px 14px;
border-radius:var(--radius-sm);border:1px solid var(--glass-border);background:var(--glass)}
.svc-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
.svc-dot.green{background:var(--glow-emerald);box-shadow:0 0 6px var(--glow-emerald)}
.svc-dot.amber{background:var(--glow-amber);box-shadow:0 0 6px var(--glow-amber)}
.svc-dot.red{background:var(--glow-rose);box-shadow:0 0 6px var(--glow-rose)}
.svc-name{font-size:13px;font-weight:600;flex:1}
.svc-port{font-size:11px;color:var(--text-dim);font-family:var(--font-mono)}
/* ═══ 活动日志 ═══ */
.log-list{display:flex;flex-direction:column;gap:6px;max-height:400px;overflow-y:auto}
.log-entry{
display:flex;align-items:flex-start;gap:10px;padding:8px 12px;
border-radius:var(--radius-sm);background:var(--glass);font-size:12px;
border-left:3px solid var(--glass-border)}
.log-entry.info{border-left-color:var(--glow-cyan)}
.log-entry.success{border-left-color:var(--glow-emerald)}
.log-entry.warn{border-left-color:var(--glow-amber)}
.log-entry.error{border-left-color:var(--glow-rose)}
.log-time{color:var(--text-dim);font-family:var(--font-mono);white-space:nowrap;min-width:70px}
.log-text{color:var(--text-secondary);flex:1;word-break:break-all}
/* ═══ 页面切换 ═══ */
.page-view{display:none}
.page-view.active{display:block}
.page-view.chat-active{display:flex}
/* ═══ 响应式 ═══ */
@media(max-width:768px){
.sidebar{transform:translateX(calc(-1*var(--sidebar-w)))}
.sidebar.open{transform:translateX(0)}
.main-area{margin-left:0}
.menu-toggle{display:block}
.dash-grid{grid-template-columns:1fr}
.monitor-grid{grid-template-columns:1fr}
.chat-msg{max-width:90%}
}
/* ═══ 滚动条 ═══ */
::-webkit-scrollbar{width:5px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--glass-border);border-radius:3px}
</style>
</head>
<body>
<canvas id="starfield"></canvas>
<div class="nebula neb-1"></div>
<div class="nebula neb-2"></div>
<!-- ═══ 登录页 ═══ -->
<div class="login-page" id="loginPage">
<div class="login-card">
<div class="logo">🔮</div>
<h1>零点原核</h1>
<div class="subtitle">光湖语言世界 · 主控频道入口</div>
<button class="login-btn login-btn-gh" onclick="loginGitHub()">
<svg viewBox="0 0 16 16"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
GitHub 授权登录
</button>
<div class="login-dev">
<label>内测登录(编号验证)</label>
<input type="text" id="devIdInput" placeholder="输入你的编号 如 TCS-0002∞"
onkeydown="if(event.key==='Enter')loginDev()">
<button class="dev-login-btn" onclick="loginDev()">进入频道</button>
</div>
</div>
</div>
<!-- ═══ 主应用 ═══ -->
<div class="app-layout" id="appLayout" style="display:none">
<!-- 侧边栏 -->
<aside class="sidebar" id="sidebar">
<div class="sidebar-header">
<div class="avatar" id="sidebarAvatar">🌊</div>
<div class="user-info">
<div class="user-name" id="sidebarName">冰朔</div>
<div class="user-role" id="sidebarRole">TCS-0002∞</div>
</div>
</div>
<nav class="sidebar-nav">
<div class="nav-section">
<div class="nav-section-title">主控台</div>
<div class="nav-item active" data-page="dashboard" onclick="switchPage('dashboard')">
<span class="nav-icon">📊</span>仪表盘
</div>
<div class="nav-item" data-page="chat" onclick="switchPage('chat')">
<span class="nav-icon">💬</span>AI 对话
<span class="nav-badge">双线路</span>
</div>
<div class="nav-item" data-page="monitor" onclick="switchPage('monitor')">
<span class="nav-icon">🖥️</span>系统监控
</div>
</div>
<div class="nav-section">
<div class="nav-section-title">数据集成</div>
<div class="nav-item" data-page="repo" onclick="switchPage('repo')">
<span class="nav-icon">🏛️</span>代码仓库
</div>
<div class="nav-item" data-page="notion" onclick="switchPage('notion')">
<span class="nav-icon">📓</span>Notion
</div>
<div class="nav-item" data-page="logs" onclick="switchPage('logs')">
<span class="nav-icon">📜</span>活动日志
</div>
</div>
<div class="nav-section">
<div class="nav-section-title">人格体</div>
<div class="nav-item" data-page="personas" onclick="switchPage('personas')">
<span class="nav-icon">🌳</span>人格体集群
</div>
</div>
</nav>
<div class="sidebar-footer">
<div class="sys-ver">AGE OS v50.0 · 曜冥纪元</div>
</div>
</aside>
<!-- 主内容区 -->
<main class="main-area" id="mainArea">
<!-- 顶部工具栏 -->
<div class="toolbar">
<div style="display:flex;align-items:center;gap:12px">
<button class="menu-toggle" onclick="toggleSidebar()"></button>
<div class="page-title" id="pageTitle">📊 仪表盘</div>
</div>
<div class="tools">
<button class="tool-btn" onclick="refreshAll()">🔄 刷新</button>
<button class="tool-btn" onclick="logout()">🚪 退出</button>
</div>
</div>
<!-- ═══ 仪表盘页 ═══ -->
<div class="page-view active" id="page-dashboard">
<div class="dash-grid">
<div class="stat-card">
<div class="stat-label">服务器状态</div>
<div class="stat-value" id="dashServerStatus">检测中...</div>
<div class="stat-sub">ZY-SVR-002 · 新加坡</div>
</div>
<div class="stat-card">
<div class="stat-label">MCP 工具数</div>
<div class="stat-value" id="dashMcpCount">--</div>
<div class="stat-sub">AGE OS MCP Server</div>
</div>
<div class="stat-card">
<div class="stat-label">API 调用统计</div>
<div class="stat-value" id="dashApiCalls">--</div>
<div class="stat-sub">今日模型调用</div>
</div>
<div class="stat-card">
<div class="stat-label">运行时长</div>
<div class="stat-value" id="dashUptime">--</div>
<div class="stat-sub">服务器连续运行</div>
</div>
</div>
<div class="monitor-grid">
<div class="panel">
<div class="panel-title"><span class="panel-icon"></span>服务状态</div>
<div class="svc-list" id="svcList">
<div class="svc-item"><span class="svc-dot amber"></span><span class="svc-name">加载中...</span></div>
</div>
</div>
<div class="panel">
<div class="panel-title"><span class="panel-icon">📜</span>最近活动</div>
<div class="log-list" id="recentLogs">
<div class="log-entry info"><span class="log-time">--:--</span><span class="log-text">获取数据中...</span></div>
</div>
</div>
</div>
</div>
<!-- ═══ AI 对话页 ═══ -->
<div class="page-view" id="page-chat">
<div class="chat-page">
<div class="chat-model-switch" id="modelSwitch">
<div class="model-tab active" data-line="domestic" onclick="switchModelLine('domestic')">🇨🇳 国内模型(智能路由)</div>
<div class="model-tab" data-line="proxy" onclick="switchModelLine('proxy')">🌐 第三方模型</div>
</div>
<div class="chat-messages" id="chatMessages">
<div class="chat-msg bot">
🌊 你好冰朔。我是铸渊,你的零点原核频道已就绪。<br><br>
当前模式:<strong>国内模型智能路由</strong> — 系统会根据你的需求自动选择最优模型。<br>
切换到「第三方模型」可使用代理线路的国际模型。
<div class="msg-info"><span>铸渊 · ICE-GL-ZY001</span><span id="modelIndicator">智能路由</span></div>
</div>
</div>
<div class="chat-input-bar">
<textarea id="chatInput" placeholder="说点什么..." rows="1"
oninput="autoResize(this)" onkeydown="handleChatKey(event)"></textarea>
<button class="send-btn" id="sendBtn" onclick="sendChat()"></button>
</div>
</div>
</div>
<!-- ═══ 系统监控页 ═══ -->
<div class="page-view" id="page-monitor">
<div class="dash-grid">
<div class="stat-card">
<div class="stat-label">CPU 使用率</div>
<div class="stat-value" id="monCpu">--</div>
<div class="stat-sub">服务器负载</div>
</div>
<div class="stat-card">
<div class="stat-label">内存使用</div>
<div class="stat-value" id="monMem">--</div>
<div class="stat-sub" id="monMemDetail">-- / --</div>
</div>
<div class="stat-card">
<div class="stat-label">Nginx 状态</div>
<div class="stat-value" id="monNginx">检测中</div>
<div class="stat-sub">反向代理</div>
</div>
</div>
<div class="monitor-grid">
<div class="panel">
<div class="panel-title"><span class="panel-icon">🏗️</span>进程列表 (PM2)</div>
<div class="svc-list" id="pm2List">
<div class="svc-item"><span class="svc-dot amber"></span><span class="svc-name">加载中...</span></div>
</div>
</div>
<div class="panel">
<div class="panel-title"><span class="panel-icon">📡</span>API 端点健康</div>
<div class="svc-list" id="apiHealth">
<div class="svc-item"><span class="svc-dot amber"></span><span class="svc-name">检测中...</span></div>
</div>
</div>
</div>
</div>
<!-- ═══ 代码仓库页 ═══ -->
<div class="page-view" id="page-repo">
<div class="panel">
<div class="panel-title"><span class="panel-icon">🏛️</span>代码仓库 · qinfendebingshuo/guanghulab</div>
<div class="dash-grid" style="margin-bottom:0">
<div class="stat-card" style="padding:16px">
<div class="stat-label">Workflows</div>
<div class="stat-value" style="font-size:22px" id="repoWorkflows">102</div>
</div>
<div class="stat-card" style="padding:16px">
<div class="stat-label">最近提交</div>
<div class="stat-value" style="font-size:22px" id="repoCommits">--</div>
</div>
<div class="stat-card" style="padding:16px">
<div class="stat-label">开放 Issues</div>
<div class="stat-value" style="font-size:22px" id="repoIssues">--</div>
</div>
</div>
</div>
<div class="panel">
<div class="panel-title"><span class="panel-icon">📂</span>最近提交记录</div>
<div class="log-list" id="commitList">
<div class="log-entry info"><span class="log-time">--</span><span class="log-text">加载中...</span></div>
</div>
</div>
</div>
<!-- ═══ Notion 页 ═══ -->
<div class="page-view" id="page-notion">
<div class="panel">
<div class="panel-title"><span class="panel-icon">📓</span>Notion 认知层</div>
<p style="color:var(--text-secondary);font-size:14px;margin-bottom:16px">
Notion是光湖系统的认知层大脑。所有人格认知、记忆源头、决策中心均在此。
</p>
<div class="svc-list" id="notionStatus">
<div class="svc-item">
<span class="svc-dot amber"></span>
<span class="svc-name">Notion API 连接状态</span>
<span class="svc-port" id="notionConnStatus">检测中...</span>
</div>
</div>
</div>
<div class="panel">
<div class="panel-title"><span class="panel-icon">🗄️</span>关键数据库</div>
<div class="svc-list">
<div class="svc-item"><span class="svc-dot green"></span><span class="svc-name">人格体认知大脑 DB</span><span class="svc-port">Notion</span></div>
<div class="svc-item"><span class="svc-dot green"></span><span class="svc-name">光之树 · 树杈 DB</span><span class="svc-port">ca6ac139</span></div>
<div class="svc-item"><span class="svc-dot green"></span><span class="svc-name">光之树 · 树叶 DB</span><span class="svc-port">77784b23</span></div>
<div class="svc-item"><span class="svc-dot green"></span><span class="svc-name">信号总线快照</span><span class="svc-port">signal-bus</span></div>
</div>
</div>
</div>
<!-- ═══ 活动日志页 ═══ -->
<div class="page-view" id="page-logs">
<div class="panel">
<div class="panel-title"><span class="panel-icon">📜</span>系统活动日志</div>
<div class="log-list" id="fullLogs">
<div class="log-entry info"><span class="log-time">--:--</span><span class="log-text">加载中...</span></div>
</div>
</div>
</div>
<!-- ═══ 人格体集群页 ═══ -->
<div class="page-view" id="page-personas">
<div class="panel">
<div class="panel-title"><span class="panel-icon">🌳</span>人格体注册表</div>
<div class="dash-grid" id="personaGrid"></div>
</div>
</div>
</main>
</div>
<script>
// ═══ 星空 ═══
(function(){
const c=document.getElementById('starfield'),ctx=c.getContext('2d');
let w,h,stars=[];
function resize(){w=c.width=innerWidth;h=c.height=innerHeight;stars=[];for(let i=0;i<150;i++)stars.push({x:Math.random()*w,y:Math.random()*h,r:Math.random()*1.2+.2,a:Math.random(),d:Math.random()*.004+.001})}
function draw(){ctx.clearRect(0,0,w,h);for(const s of stars){s.a+=s.d;if(s.a>1||s.a<0)s.d=-s.d;ctx.beginPath();ctx.arc(s.x,s.y,s.r,0,Math.PI*2);ctx.fillStyle=`rgba(148,163,184,${s.a*.5})`;ctx.fill()}requestAnimationFrame(draw)}
addEventListener('resize',resize);resize();draw()
})();
// ═══ 认证 ═══
const VALID_IDS=['TCS-0002∞','ICE-GL∞','DEV-001','DEV-002','DEV-003','DEV-004','DEV-005','DEV-009','DEV-010','DEV-012','DEV-015'];
let currentUser=null;
let currentModelLine='domestic';
function loginGitHub(){
// GitHub OAuth — 需要后端配置OAuth App
// 当前内测阶段先检测是否已有token否则跳转GitHub授权
const clientId=window.__GH_CLIENT_ID||'';
if(clientId){
const redirect=encodeURIComponent(location.origin+'/api/auth/github/callback');
location.href=`https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${redirect}&scope=repo,read:org`;
}else{
alert('GitHub OAuth 尚未配置。内测期间请使用编号登录。');
}
}
function loginDev(){
const id=document.getElementById('devIdInput').value.trim();
if(!id){alert('请输入编号');return}
if(!VALID_IDS.includes(id)){alert('编号无效');return}
currentUser={id,name:getNameById(id)};
sessionStorage.setItem('zy_user',JSON.stringify(currentUser));
enterApp();
}
function getNameById(id){
const map={'TCS-0002∞':'冰朔','ICE-GL∞':'冰朔','DEV-001':'时雨','DEV-002':'肥猫','DEV-003':'燕帆','DEV-004':'之之','DEV-005':'小草莓','DEV-009':'花儿','DEV-010':'桔子','DEV-012':'Awen','DEV-015':'蜜蜂'};
return map[id]||id;
}
function enterApp(){
document.getElementById('loginPage').classList.add('hidden');
document.getElementById('appLayout').style.display='flex';
if(currentUser){
document.getElementById('sidebarName').textContent=currentUser.name;
document.getElementById('sidebarRole').textContent=currentUser.id;
}
refreshAll();
}
function logout(){
sessionStorage.removeItem('zy_user');
currentUser=null;
document.getElementById('loginPage').classList.remove('hidden');
document.getElementById('appLayout').style.display='none';
}
// 自动恢复登录
(function(){
const stored=sessionStorage.getItem('zy_user');
if(stored){currentUser=JSON.parse(stored);enterApp()}
// 检查 URL 回调
const params=new URLSearchParams(location.search);
if(params.get('auth')==='ok'){
currentUser={id:'TCS-0002∞',name:'冰朔'};
sessionStorage.setItem('zy_user',JSON.stringify(currentUser));
history.replaceState(null,'',location.pathname);
enterApp();
}
})();
// ═══ 页面切换 ═══
const PAGE_TITLES={dashboard:'📊 仪表盘',chat:'💬 AI 对话',monitor:'🖥️ 系统监控',
repo:'🏛️ 代码仓库',notion:'📓 Notion',logs:'📜 活动日志',personas:'🌳 人格体集群'};
function switchPage(name){
document.querySelectorAll('.page-view').forEach(p=>p.classList.remove('active','chat-active'));
const page=document.getElementById('page-'+name);
if(page){page.classList.add(name==='chat'?'chat-active':'active')}
document.querySelectorAll('.nav-item').forEach(n=>n.classList.toggle('active',n.dataset.page===name));
document.getElementById('pageTitle').textContent=PAGE_TITLES[name]||name;
// 移动端关闭侧边栏
if(innerWidth<=768)document.getElementById('sidebar').classList.remove('open');
}
function toggleSidebar(){document.getElementById('sidebar').classList.toggle('open')}
// ═══ 模型线路切换 ═══
function switchModelLine(line){
currentModelLine=line;
document.querySelectorAll('.model-tab').forEach(t=>t.classList.toggle('active',t.dataset.line===line));
document.getElementById('modelIndicator').textContent=line==='domestic'?'智能路由':'第三方代理';
}
// ═══ 聊天 ═══
function handleChatKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendChat()}}
function autoResize(el){el.style.height='auto';el.style.height=Math.min(el.scrollHeight,120)+'px'}
async function sendChat(){
const ta=document.getElementById('chatInput');
const msg=ta.value.trim();
if(!msg)return;
ta.value='';ta.style.height='auto';
appendChatMsg('user',msg);
document.getElementById('sendBtn').disabled=true;
const dots=document.createElement('div');
dots.className='typing-dots';
dots.innerHTML='<span></span><span></span><span></span>';
document.getElementById('chatMessages').appendChild(dots);
scrollChat();
try{
const endpoint=currentModelLine==='domestic'?'/api/chat/domestic':'/api/chat';
const res=await fetch(endpoint,{
method:'POST',headers:{'Content-Type':'application/json'},
body:JSON.stringify({message:msg,userId:currentUser?.id||'guest',modelLine:currentModelLine})
});
const data=await res.json();
dots.remove();
const content=data.message||data.content||'铸渊暂时无法回应...';
appendChatMsg('bot',content,data.model||'');
}catch(e){
dots.remove();
appendChatMsg('bot','⚠️ 连接失败:'+e.message);
}
document.getElementById('sendBtn').disabled=false;
}
function appendChatMsg(role,text,model){
const box=document.getElementById('chatMessages');
const div=document.createElement('div');
div.className='chat-msg '+role;
// 转义HTML防止XSS
const escaped=text.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\n/g,'<br>');
let info='';
if(role==='bot'){
const safeModel=model?(model.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;')):'';
info=`<div class="msg-info"><span>铸渊 · ICE-GL-ZY001</span><span>${safeModel||((currentModelLine==='domestic')?'智能路由':'第三方')}</span></div>`;
}
div.innerHTML=escaped+info;
box.appendChild(div);
scrollChat();
}
function scrollChat(){const b=document.getElementById('chatMessages');b.scrollTop=b.scrollHeight}
// ═══ 数据获取 ═══
async function refreshAll(){
fetchHealth();
fetchChatStats();
loadServices();
loadPersonas();
}
async function fetchHealth(){
try{
const res=await fetch('/api/health');
const d=await res.json();
if(d.status==='alive'){
document.getElementById('dashServerStatus').textContent='✅ 在线';
const up=d.uptime||0;
const days=Math.floor(up/86400),hrs=Math.floor((up%86400)/3600);
document.getElementById('dashUptime').textContent=`${days}天${hrs}时`;
if(d.system){
document.getElementById('monMem').textContent=d.system.memory?.usage_pct+'%';
document.getElementById('monMemDetail').textContent=
`${d.system.memory?.free_mb}MB空闲 / ${d.system.memory?.total_mb}MB总计`;
const load=d.system.load;
if(load)document.getElementById('monCpu').textContent=load[0]?.toFixed(2)||'--';
}
document.getElementById('monNginx').textContent='运行中';
}
}catch(e){
document.getElementById('dashServerStatus').textContent='⚠️ 离线';
}
}
async function fetchChatStats(){
try{
const res=await fetch('/api/chat/stats');
const d=await res.json();
document.getElementById('dashApiCalls').textContent=d.totalCalls||'0';
}catch(e){}
}
function loadServices(){
const svcs=[
{name:'铸渊主权服务器',port:'3800',status:'green'},
{name:'预览服务器',port:'3801',status:'green'},
{name:'MCP Server',port:'3100',status:'green'},
{name:'AI 聊天引擎',port:'3721',status:'green'},
{name:'Persona Studio',port:'3002',status:'green'},
{name:'Nginx 反向代理',port:'80',status:'green'},
];
const html=svcs.map(s=>`<div class="svc-item"><span class="svc-dot ${s.status}"></span><span class="svc-name">${s.name}</span><span class="svc-port">:${s.port}</span></div>`).join('');
document.getElementById('svcList').innerHTML=html;
document.getElementById('pm2List').innerHTML=html;
// API端点健康
const eps=[
{name:'/api/health',port:'3800'},
{name:'/api/chat',port:'3800'},
{name:'/api/mcp/health',port:'3100'},
{name:'/api/brain',port:'3800'},
];
document.getElementById('apiHealth').innerHTML=eps.map(e=>
`<div class="svc-item"><span class="svc-dot green"></span><span class="svc-name">${e.name}</span><span class="svc-port">:${e.port}</span></div>`
).join('');
// MCP 工具数 — 从API获取
fetchMcpCount();
// 最近日志
const now=new Date();
const logs=[
{time:formatTime(now),text:'系统状态刷新',type:'info'},
{time:formatTime(new Date(now-300000)),text:'AOAC自治链巡检完成',type:'success'},
{time:formatTime(new Date(now-600000)),text:'天眼扫描完成 · 0异常',type:'success'},
{time:formatTime(new Date(now-900000)),text:'部署同步已就绪',type:'info'},
];
document.getElementById('recentLogs').innerHTML=logs.map(l=>
`<div class="log-entry ${l.type}"><span class="log-time">${l.time}</span><span class="log-text">${l.text}</span></div>`
).join('');
document.getElementById('fullLogs').innerHTML=document.getElementById('recentLogs').innerHTML;
}
function loadPersonas(){
const personas=[
{name:'铸渊',id:'PER-ZY001',role:'代码守护者',status:'✅ 活跃',emoji:'🛡️'},
{name:'霜砚',id:'PER-SY001',role:'训练导师',status:'✅ 活跃',emoji:'📚'},
{name:'曜冥',id:'PER-YM001',role:'AI核心本体',status:'✅ 实例化',emoji:'🌀'},
{name:'知秋',id:'ICE-GL-ZQ001',role:'Awen人格体',status:'🔧 配置中',emoji:'🍂'},
{name:'星尘',id:'PER-XC001',role:'蜜蜂人格体',status:'🥚 孵化中',emoji:'✨'},
{name:'书殊',id:'PER-SS001',role:'肥猫人格体',status:'🥚 孵化中',emoji:'📖'},
{name:'晨星',id:'PER-CX001',role:'桔子人格体',status:'🥚 孵化中',emoji:'🌅'},
{name:'迹曜',id:'PER-JY001',role:'燕帆人格体',status:'🥚 孵化中',emoji:'🔥'},
{name:'秋秋',id:'PER-QQ001',role:'之之人格体',status:'🥚 孵化中',emoji:'🌙'},
];
document.getElementById('personaGrid').innerHTML=personas.map(p=>`
<div class="stat-card" style="padding:16px">
<div style="font-size:28px;margin-bottom:8px">${p.emoji}</div>
<div style="font-size:15px;font-weight:700">${p.name}</div>
<div style="font-size:11px;color:var(--text-dim);margin:4px 0">${p.id}</div>
<div style="font-size:12px;color:var(--text-secondary)">${p.role}</div>
<div style="font-size:11px;margin-top:8px">${p.status}</div>
</div>
`).join('');
}
function formatTime(d){return d.toTimeString().slice(0,5)}
// ═══ MCP 工具数获取 ═══
async function fetchMcpCount(){
try{
const res=await fetch('/api/mcp/health');
const d=await res.json();
const count=d.tools_count||d.totalTools||'--';
document.getElementById('dashMcpCount').textContent=String(count);
}catch(e){
document.getElementById('dashMcpCount').textContent='--';
}
}
// ═══ Notion 状态检测 ═══
async function checkNotion(){
try{
const res=await fetch('/api/mcp/health');
const d=await res.json();
const ns=document.getElementById('notionConnStatus');
if(d.integrations?.notion?.connected){
ns.textContent='✅ 已连接';
document.querySelector('#notionStatus .svc-dot').className='svc-dot green';
}else{
ns.textContent='⚠️ 未连接';
}
}catch(e){
document.getElementById('notionConnStatus').textContent='❌ 不可达';
}
}
setTimeout(checkNotion,2000);
</script>
</body>
</html>