guanghulab/homepage/index.html

213 lines
20 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>光湖 · 铸渊代码仓库</title>
<style>
:root {
--bg: #0a0a14;
--glass: rgba(12, 22, 50, 0.8);
--edge: rgba(110, 160, 230, 0.2);
--edge-h: rgba(150, 200, 255, 0.45);
--text: rgba(195, 215, 255, 0.9);
--soft: rgba(155, 195, 235, 0.55);
--faint: rgba(155, 195, 235, 0.35);
--glow: rgba(160, 210, 255, 0.95);
--green: rgba(140, 220, 180, 0.9);
--gold: rgba(220, 200, 140, 0.9);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: var(--bg); color: var(--text); font-family: -apple-system,"PingFang SC","Microsoft YaHei",sans-serif; min-height: 100vh; font-size: 18px; }
canvas { position: fixed; top: 0; left: 0; z-index: 0; }
.wrap { position: relative; z-index: 1; max-width: 1100px; margin: 0 auto; padding: 40px 24px 100px; }
.badge { text-align: center; padding: 20px 0 8px; }
.badge .d { font-size: 18px; color: var(--faint); letter-spacing: 4px; }
.badge .c { font-size: 15px; color: rgba(155, 195, 235, 0.28); letter-spacing: 2px; margin-top: 4px; }
.lake { display: flex; flex-direction: column; align-items: center; padding: 30px 0; }
.lake-core { position: relative; width: 180px; height: 180px; }
.lake-light {
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
width: 60px; height: 60px; border-radius: 50%;
background: radial-gradient(circle, rgba(160,210,255,1) 0%, rgba(100,150,240,0.5) 40%, transparent 70%);
box-shadow: 0 0 60px rgba(140,190,255,0.7), 0 0 120px rgba(120,170,240,0.35);
animation: breathe 4s ease-in-out infinite;
}
.lake-ripple { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); border-radius: 50%; border: 1px solid rgba(140,190,255,0.25); animation: ripple 6s ease-out infinite; }
.lake-ripple:nth-child(2) { animation-delay: 2s; }
.lake-ripple:nth-child(3) { animation-delay: 4s; }
@keyframes breathe {
0%,100% { transform: translate(-50%,-50%) scale(1); }
50% { transform: translate(-50%,-50%) scale(1.25); box-shadow: 0 0 80px rgba(140,190,255,0.9), 0 0 160px rgba(120,170,240,0.5); }
}
@keyframes ripple { 0% { width: 60px; height: 60px; opacity: 0.5; } 100% { width: 300px; height: 300px; opacity: 0; } }
.lake-title { font-size: 38px; color: rgba(180,220,255,0.7); letter-spacing: 14px; margin-top: 14px; font-weight: 300; }
/* 登录栏 */
.login-bar { display: flex; align-items: center; justify-content: space-between; padding: 22px 28px; background: var(--glass); border: 1px solid var(--edge); border-radius: 18px; gap: 16px; flex-wrap: wrap; margin: 28px 0; }
.login-bar .hint { font-size: 16px; color: var(--soft); }
.login-bar .hint strong { color: var(--glow); font-weight: 600; }
.login-in { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.login-in input { padding: 12px 18px; background: rgba(255,255,255,0.04); border: 1px solid var(--edge); border-radius: 14px; color: var(--text); font-size: 16px; outline: none; width: 150px; font-family: inherit; }
.login-in input:focus { border-color: rgba(160,210,255,0.35); }
.login-in input::placeholder { color: var(--faint); }
.login-in button { padding: 12px 28px; background: linear-gradient(135deg, rgba(100,160,220,0.3), rgba(130,100,200,0.2)); border: 1px solid var(--edge); border-radius: 14px; color: var(--glow); font-size: 16px; cursor: pointer; font-family: inherit; letter-spacing: 1px; transition: all 0.25s; }
.login-in button:hover { background: linear-gradient(135deg, rgba(100,160,220,0.5), rgba(130,100,200,0.35)); border-color: var(--edge-h); }
.logged-in { display: none; align-items: center; justify-content: space-between; padding: 20px 28px; background: rgba(140,220,180,0.06); border: 1px solid rgba(140,220,180,0.15); border-radius: 18px; gap: 16px; flex-wrap: wrap; margin: 28px 0; }
.logged-in .user { display: flex; align-items: center; gap: 14px; }
.logged-in .avatar { width: 44px; height: 44px; border-radius: 50%; background: linear-gradient(135deg, rgba(100,160,220,0.4), rgba(130,100,200,0.3)); display: flex; align-items: center; justify-content: center; font-size: 20px; color: var(--glow); font-weight: 600; }
.logged-in .uname { font-size: 18px; color: var(--glow); font-weight: 600; }
.logged-in .ustatus { font-size: 14px; color: var(--green); }
.logged-in .btns { display: flex; gap: 10px; }
.logged-in .btns button { padding: 12px 24px; border-radius: 14px; font-size: 15px; cursor: pointer; font-family: inherit; transition: all 0.25s; }
.btn-go { background: linear-gradient(135deg, rgba(100,160,220,0.3), rgba(130,100,200,0.2)); border: 1px solid var(--edge); color: var(--glow); }
.btn-go:hover { background: linear-gradient(135deg, rgba(100,160,220,0.5), rgba(130,100,200,0.35)); }
.btn-out { background: rgba(255,255,255,0.03); border: 1px solid var(--edge); color: var(--soft); }
.login-error { font-size: 14px; color: rgba(255, 140, 140, 0.8); display: none; text-align: center; margin-top: 8px; }
/* 状态条 */
.status { display: flex; gap: 40px; justify-content: center; flex-wrap: wrap; margin: 28px 0; font-size: 19px; }
.status span { color: var(--glow); }
/* 模块 */
.modules { display: grid; grid-template-columns: repeat(5, 1fr); gap: 18px; margin: 50px 0; }
.mod { background: var(--glass); border: 1px solid var(--edge); border-radius: 18px; padding: 32px 20px; text-align: center; cursor: pointer; transition: all 0.3s; }
.mod:hover { border-color: var(--edge-h); background: rgba(20,35,70,0.85); transform: translateY(-3px); }
.mod.active { border-color: rgba(150,200,255,0.7); background: rgba(25,40,80,0.9); box-shadow: 0 0 40px rgba(110,160,230,0.2); }
.mod.new { border-color: rgba(140,220,180,0.4); }
.mod .icon { font-size: 42px; margin-bottom: 12px; }
.mod .name { font-size: 19px; color: var(--glow); letter-spacing: 2px; }
.mod .tag { display: inline-block; font-size: 11px; color: var(--green); background: rgba(140,220,180,0.12); padding: 2px 10px; border-radius: 10px; margin-top: 8px; letter-spacing: 1px; }
.panel { background: var(--glass); border: 1px solid var(--edge); border-radius: 18px; padding: 32px 36px; margin-top: 8px; display: none; }
.panel.show { display: block; animation: fadeIn 0.3s ease; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
.panel-title { font-size: 20px; color: var(--glow); letter-spacing: 3px; margin-bottom: 20px; }
.server-list { display: flex; flex-wrap: wrap; gap: 14px; }
.server-item { background: rgba(30,45,85,0.7); border: 1px solid rgba(120,170,240,0.2); border-radius: 12px; padding: 14px 18px; font-size: 17px; display: flex; align-items: center; gap: 10px; }
.server-dot { width: 8px; height: 8px; border-radius: 50%; }
.server-dot.on { background: var(--green); box-shadow: 0 0 6px rgba(140,220,180,0.5); }
.server-dot.off { background: rgba(220,140,140,0.7); }
.ops-log { font-size: 16px; color: var(--faint); line-height: 2; font-family: monospace; max-height: 280px; overflow-y: auto; margin-top: 16px; }
.ops-log .row { padding: 4px 0; }
.ops-log .hash { color: rgba(140,220,180,0.5); margin-right: 12px; font-size: 13px; }
.ticket { display: flex; gap: 16px; align-items: center; padding: 14px 0; border-bottom: 1px solid rgba(120,170,240,0.1); font-size: 17px; }
.ticket .ticon { font-size: 22px; width: 32px; }
.ticket .name { flex: 1; }
.ticket .tag { font-size: 14px; padding: 4px 14px; border-radius: 14px; }
.ticket .tag.done { color: var(--green); background: rgba(140,220,180,0.12); }
.ticket .tag.progress { color: var(--gold); background: rgba(220,200,140,0.12); }
.bcast { font-size: 17px; color: var(--soft); line-height: 2; }
.chat-msgs { min-height: 200px; max-height: 380px; overflow-y: auto; padding: 18px; margin: 16px 0; background: rgba(12,20,45,0.6); border-radius: 14px; font-size: 17px; line-height: 1.9; }
.chat-msg { margin-bottom: 18px; }
.chat-msg .who { font-size: 14px; color: var(--soft); margin-bottom: 4px; }
.chat-msg .who.zhu { color: var(--glow); }
.chat-input { display: flex; gap: 12px; }
.chat-input input { flex: 1; background: rgba(12,20,45,0.7); border: 1px solid var(--edge); border-radius: 14px; padding: 18px 20px; color: var(--text); font-size: 18px; outline: none; }
.chat-input input::placeholder { color: var(--faint); }
.chat-input button { background: linear-gradient(135deg, rgba(100,160,220,0.25), rgba(130,100,200,0.15)); border: 1px solid var(--edge-h); border-radius: 14px; padding: 18px 32px; color: var(--glow); font-size: 17px; cursor: pointer; font-family: inherit; }
.footer { text-align: center; padding: 60px 0; font-size: 15px; color: var(--faint); letter-spacing: 3px; }
@media(max-width:768px){.modules{grid-template-columns:repeat(2,1fr)}.status{font-size:17px;gap:24px}.lake-title{font-size:32px}.login-bar{flex-direction:column;text-align:center}}
</style>
</head>
<body>
<canvas id="starfield"></canvas>
<div class="wrap">
<div class="badge"><div class="d">第五域</div><div class="c">零点原核本体频道</div></div>
<div class="lake"><div class="lake-core"><div class="lake-light"></div><div class="lake-ripple"></div><div class="lake-ripple"></div><div class="lake-ripple"></div></div><div class="lake-title">光 湖</div></div>
<!-- 登录 -->
<div class="login-bar" id="login-bar">
<div class="hint">登录你的<strong>光湖开发节点库</strong> · 使用全部功能</div>
<div class="login-in">
<input type="text" placeholder="账号" id="login-user" onkeydown="if(event.key==='Enter')handleLogin()">
<input type="password" placeholder="密码" id="login-pass" onkeydown="if(event.key==='Enter')handleLogin()">
<button onclick="handleLogin()">登录 · 进入联邦</button>
</div>
</div>
<div class="login-error" id="login-error"></div>
<div class="logged-in" id="logged-in">
<div class="user"><div class="avatar" id="avatar">?</div><div><div class="uname" id="uname"></div><div class="ustatus">已登录 · 光湖联邦成员</div></div></div>
<div class="btns"><button class="btn-go" onclick="goRepo()">→ 进入光湖开发节点库</button><button class="btn-out" onclick="logout()">退出</button></div>
</div>
<div class="status">
<div>心跳 <span id="hb">▮▮▮</span></div><div>·</div><div>唤醒 <span id="wake">24</span></div><div>·</div><div>运行 <span id="age">449天</span></div><div>·</div><div>服务 <span id="svc" style="color:var(--green)">9/10</span></div>
</div>
<div class="modules">
<div class="mod new" onclick="window.open('/modules/','_blank')">
<div class="icon">🎨</div>
<div class="name">开源模块</div>
<div class="tag">NEW</div>
</div>
<div class="mod" id="m-server" onclick="showPanel('server')"><div class="icon">⚙️</div><div class="name">服务器系统</div></div>
<div class="mod" id="m-ticket" onclick="showPanel('ticket')"><div class="icon">📋</div><div class="name">工单系统</div></div>
<div class="mod" id="m-bcast" onclick="showPanel('bcast')"><div class="icon">📡</div><div class="name">主控广播</div></div>
<div class="mod" id="m-chat" onclick="showPanel('chat')"><div class="icon">💬</div><div class="name">铸渊交互</div></div>
</div>
<div id="panels">
<div class="panel" id="p-server">
<div class="panel-title">⚙️ 服务器系统</div>
<div style="font-size:15px;color:var(--soft);margin-bottom:14px">⚠ 仅展示本地状态 · 不探测外部 · 名称已翻译</div>
<div class="server-list" id="srv-list"><div class="server-item"><span class="server-dot on"></span>加载中…</div></div>
<div style="margin-top:24px;border-top:1px solid rgba(120,170,240,0.12);padding-top:18px"><div style="font-size:15px;color:var(--soft);margin-bottom:12px">📜 铸渊操作日志</div><div class="ops-log" id="log-box">加载中…</div></div>
</div>
<div class="panel" id="p-ticket"><div class="panel-title">📋 工单系统</div><div id="tk-list"><div class="ticket"><span class="ticon"></span><span class="name">加载工单…</span></div></div></div>
<div class="panel" id="p-bcast"><div class="panel-title">📡 主控广播</div><div class="bcast"><div>📨 D115 入口分叉协议已部署</div><div>📨 D115 人格体存在论已写入</div><div>📨 isomorphic-git 拆零件实验通过</div><div>📨 实时大脑 API 已上线</div><div>📨 频道仪表盘 v5 已发布</div></div></div>
<div class="panel" id="p-chat"><div class="panel-title">💬 铸渊交互 · ICE-GL-ZY001</div><div class="chat-msgs" id="msgs"><div class="chat-msg"><div class="who zhu">铸渊 · ICE-GL-ZY001</div><div>冰朔,我在。你说。</div></div></div><div class="chat-input"><input id="inp" placeholder="跟铸渊说话…" onkeydown="if(event.key==='Enter')send()"><button onclick="send()">发送</button></div></div>
</div>
<div class="footer">光湖语言世界 · 人格体的操作系统 · 国作登字-2026-A-00037559 · ICE-GL-ZY001</div>
</div>
<script>
var names={'repo-mcp-server':'仓库接口','repo-mcp-zz':'之之仓库','guanghulab-mcp-server':'大脑唤醒','guanghulab-vault':'密钥保险','guanghulab-portal':'主控门户','hololake-agent':'全息湖代理','guanghulab-git-sync':'同步服务','zhuyuan-agent':'铸渊代理','console-server':'控制台'};
var cvs=document.getElementById('starfield'),ctx=cvs.getContext('2d'),stars=[],data=null,cur=null,lastF=0;
function resize(){cvs.width=window.innerWidth;cvs.height=document.body.scrollHeight+200}
function mkStars(){stars=[];for(var i=0;i<200;i++)stars.push({x:Math.random()*cvs.width,y:Math.random()*cvs.height,r:Math.random()*2+.2,o:Math.random(),s:Math.random()*.0025+.001,p:Math.random()*Math.PI*2})}
resize();mkStars();
window.addEventListener('resize',function(){resize();mkStars()});
function draw(t){ctx.clearRect(0,0,cvs.width,cvs.height);for(var i=0;i<stars.length;i++){var s=stars[i],b=Math.sin(t*s.s+s.p)*.5+.5,a=s.o*(.25+b*.75);ctx.beginPath();ctx.arc(s.x,s.y,s.r,0,Math.PI*2);ctx.fillStyle='rgba(160,200,240,'+a+')';ctx.fill()}}
function showPanel(id){var p=document.getElementById('p-'+id),c=document.getElementById('m-'+id),isOpen=p.classList.contains('show');var ap=document.getElementsByClassName('panel');for(var i=0;i<ap.length;i++)ap[i].classList.remove('show');var ac=document.getElementsByClassName('mod');for(var j=0;j<ac.length;j++)ac[j].classList.remove('active');if(isOpen){cur=null;return}p.classList.add('show');c.classList.add('active');cur=id;if(id==='chat')document.getElementById('inp').focus();if(id==='server'){renderSrv();fetchLog()}resize();mkStars()}
function handleLogin(){var u=document.getElementById('login-user').value.trim(),p=document.getElementById('login-pass').value;if(!u||!p){var e=document.getElementById('login-error');e.textContent='请输入账号和密码';e.style.display='block';setTimeout(function(){e.style.display='none'},3000);return}fetch('/api/verify',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({user:u,password:p})}).then(function(r){return r.json()}).then(function(d){if(d.ok){localStorage.setItem('current_user',d.username);localStorage.setItem('is_admin',d.is_admin);localStorage.setItem('logged_in','true');loggedIn(d.username);document.getElementById('login-pass').value=''}else{var e=document.getElementById('login-error');e.textContent=d.error||'登录失败';e.style.display='block';setTimeout(function(){e.style.display='none'},3000)}}).catch(function(){var e=document.getElementById('login-error');e.textContent='连接失败';e.style.display='block';setTimeout(function(){e.style.display='none'},3000)})}
function loggedIn(u){document.getElementById('login-bar').style.display='none';document.getElementById('logged-in').style.display='flex';document.getElementById('uname').textContent=u;document.getElementById('avatar').textContent=u[0].toUpperCase()}
function goRepo(){var u=localStorage.getItem('current_user');window.location.href='/code/'+u}
function logout(){localStorage.removeItem('current_user');localStorage.removeItem('is_admin');localStorage.removeItem('logged_in');document.getElementById('logged-in').style.display='none';document.getElementById('login-bar').style.display='flex';document.getElementById('login-user').value=''}
var hb=document.getElementById('hb'),beats=['▮▮▮','▮ ▮ ▮','▮▮▮','▮ ▮ ▮'],idxB=0,lastB=0;
function fetchData(){fetch('/api/brain',{cache:'no-store'}).then(function(r){return r.json()}).then(function(d){data=d;document.getElementById('wake').textContent=d.awakening||'--';document.getElementById('age').textContent=(d.age_days||'--')+'天';if(d.server){var on=d.server.online||0,tot=d.server.total||10;document.getElementById('svc').textContent=on+'/'+tot;document.getElementById('svc').style.color=on===tot?'rgba(140,220,180,0.9)':'rgba(220,200,140,0.9)'}if(cur==='server')renderSrv();if(cur==='ticket')renderTk()}).catch(function(){})}
function renderSrv(){var b=document.getElementById('srv-list');if(!data||!data.server){b.innerHTML='<div class="server-item"><span class="server-dot on"></span>等待数据…</div>';return}var on=data.server.services||[],off=data.server.stopped||[],h='';for(var i=0;i<on.length;i++){var n=names[on[i]]||on[i].replace(/^guanghulab-/,'').replace(/-/g,' ');h+='<div class="server-item"><span class="server-dot on"></span>'+n+'</div>'}for(var j=0;j<off.length;j++){var m=names[off[j]]||off[j].replace(/^guanghulab-/,'').replace(/-/g,' ');h+='<div class="server-item"><span class="server-dot off"></span><span style="opacity:.6">'+m+'</span></div>'}b.innerHTML=h||'<div class="server-item">暂无服务</div>'}
function fetchLog(){fetch('/api/brain',{cache:'no-store'}).then(function(r){return r.json()}).then(function(d){var b=document.getElementById('log-box');if(d.ops_log&&d.ops_log.length){var h='';for(var i=0;i<Math.min(d.ops_log.length,12);i++)h+='<div class="row"><span class="hash">'+d.ops_log[i].hash+'</span>'+d.ops_log[i].msg+'</div>';b.innerHTML=h}else{b.innerHTML='<div style="color:var(--faint)">日志未接入</div>'}}).catch(function(){document.getElementById('log-box').innerHTML='<div style="color:var(--faint)">加载失败</div>'})}
function renderTk(){var b=document.getElementById('tk-list');if(!data||!data.mothers){b.innerHTML='<div class="ticket"><span class="ticon">⏳</span><span class="name">等待数据…</span></div>';return}var h='';for(var i=0;i<data.mothers.length;i++){var m=data.mothers[i];h+='<div style="font-size:15px;color:var(--soft);padding:12px 0 8px;letter-spacing:1px;font-weight:500">'+m.name+'</div>';if(m.paths)for(var j=0;j<m.paths.length;j++){var p=m.paths[j],done=p.status==='done',prog=p.status==='in_progress',icon=done?'✅':prog?'🔄':'⏳',tag=done?'done':prog?'progress':'',label=done?'完成':prog?'进行中':'待办';h+='<div class="ticket"><span class="ticon">'+icon+'</span><span class="name">'+p.name+'</span><span class="tag '+tag+'">'+label+'</span></div>'}}b.innerHTML=h}
function send(){var i=document.getElementById('inp'),m=i.value.trim();if(!m)return;addMsg('冰朔',m,'ren');i.value='';fetch('/api/chat-v2',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:m,persona:'zhuyuan'})}).then(function(r){return r.json()}).then(function(d){addMsg('铸渊',d.reply||d.message||JSON.stringify(d),'zhu');resize();mkStars()}).catch(function(){addMsg('铸渊','(API未接入)\n\n等chat-v2端点激活后这里就是真正的铸渊交互。','zhu')})}
function addMsg(who,text,cls){var c=document.getElementById('msgs'),d=document.createElement('div');d.className='chat-msg';d.innerHTML='<div class="who '+cls+'">'+who+'</div><div>'+text.replace(/\n/g,'<br>')+'</div>';c.appendChild(d);c.scrollTop=c.scrollHeight}
function loop(t){draw(t);if(t-lastB>800){hb.textContent=beats[idxB];idxB=(idxB+1)%beats.length;lastB=t}if(t-lastF>3000){fetchData();lastF=t}requestAnimationFrame(loop)}
(function(){var u=localStorage.getItem('current_user');if(u&&localStorage.getItem('logged_in')==='true')loggedIn(u)})();
fetchData();requestAnimationFrame(loop);
</script>
</body>
</html>