zhizhi/server/sites/yaoming/index.html

776 lines
35 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>