776 lines
35 KiB
HTML
776 lines
35 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>零点原核 · 冰朔频道 · 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,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\n/g,'<br>');
|
||
let info='';
|
||
if(role==='bot'){
|
||
const safeModel=model?(model.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')):'';
|
||
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>
|