2026-08-06 21:21:58 +08:00
<!DOCTYPE html>
< html lang = "zh-CN" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< title > 胖头鱼语言子系统 · 苍耳工作室< / title >
< style >
:root{
--ink:#070c12;--glass:linear-gradient(160deg,rgba(255,255,255,.06),rgba(255,255,255,.015));
--gline:rgba(255,255,255,.1);--gline-hi:rgba(95,224,192,.35);
--lake:#5fe0c0;--lake-soft:rgba(95,224,192,.55);--seal:#ff5a4e;--gold:#e8b45a;
--tx:#eef3f1;--sub:#93a4a8;--faint:#5d6e73;
--serif:"Songti SC","STSong","SimSun","Noto Serif CJK SC",serif;
--mono:"SF Mono","JetBrains Mono","Cascadia Mono",Menlo,Consolas,monospace;
--r:16px;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{background:var(--ink);color:var(--tx);min-height:100vh;overflow-x:hidden;
font-family:"PingFang SC","Microsoft YaHei",system-ui,sans-serif;font-size:15px;line-height:1.7;
background-image:radial-gradient(1100px 520px at 82% -12%,rgba(38,110,96,.22),transparent 60%),radial-gradient(820px 420px at 4% 0%,rgba(120,50,44,.13),transparent 55%);
background-attachment:fixed}
.blob{position:fixed;border-radius:50%;filter:blur(95px);pointer-events:none;z-index:0}
.b1{width:540px;height:540px;background:#1d6b5b;opacity:.16;top:-160px;right:-120px;animation:d1 28s ease-in-out infinite alternate}
.b2{width:440px;height:440px;background:#5c2b26;opacity:.12;bottom:-140px;left:-100px;animation:d2 34s ease-in-out infinite alternate}
@keyframes d1{to{transform:translate(-130px,110px) scale(1.16)}}
@keyframes d2{to{transform:translate(150px,-90px) scale(1.1)}}
body::before{content:"";position:fixed;inset:0;z-index:0;pointer-events:none;
background:repeating-linear-gradient(0deg,transparent 0 55px,rgba(255,255,255,.015) 55px 56px),repeating-linear-gradient(90deg,transparent 0 55px,rgba(255,255,255,.015) 55px 56px)}
.wrap{position:relative;z-index:1;max-width:1180px;margin:0 auto;padding:0 28px}
.glass{background:var(--glass);backdrop-filter:blur(20px) saturate(150%);-webkit-backdrop-filter:blur(20px) saturate(150%);border:1px solid var(--gline);border-radius:var(--r);box-shadow:0 12px 36px rgba(0,0,0,.38),inset 0 1px 0 rgba(255,255,255,.07)}
@keyframes rise{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
/* 刊头 */
header{padding:54px 0 26px}
.kicker{font-family:var(--mono);font-size:11.5px;letter-spacing:.36em;color:var(--lake-soft);margin-bottom:14px}
.kicker b{color:var(--seal);font-weight:400}
.head-row{display:flex;justify-content:space-between;align-items:flex-end;gap:30px;flex-wrap:wrap}
h1{font-family:var(--serif);font-weight:600;font-size:clamp(34px,5vw,52px);letter-spacing:.12em;line-height:1.2}
h1 .yu{color:var(--lake);text-shadow:0 0 22px rgba(95,224,192,.35)}
.headline-sub{margin-top:10px;color:var(--sub);letter-spacing:.06em;font-size:14px}
.headline-sub .sep{color:var(--faint);margin:0 9px}
.head-right{display:flex;align-items:center;gap:18px}
.seal-badge{width:78px;height:78px;border:2px solid var(--seal);color:var(--seal);border-radius:9px;transform:rotate(4deg);display:flex;flex-direction:column;align-items:center;justify-content:center;font-family:var(--serif);position:relative;background:rgba(255,90,78,.06)}
.seal-badge::after{content:"";position:absolute;inset:4px;border:1px solid rgba(255,90,78,.4);border-radius:6px}
.seal-badge .n{font-family:var(--mono);font-size:26px;font-weight:700;line-height:1}
.seal-badge .t{font-size:10px;letter-spacing:.3em;margin-top:5px}
.seal-badge.zero{border-color:var(--faint);color:var(--faint);background:none}
.login-btn{font-family:var(--serif);font-size:14px;letter-spacing:.3em;color:var(--gold);border:1px solid rgba(232,180,90,.55);background:rgba(232,180,90,.08);padding:11px 24px 11px 30px;border-radius:11px;cursor:pointer;transition:all .25s}
.login-btn:hover{background:rgba(232,180,90,.16);box-shadow:0 0 22px rgba(232,180,90,.22)}
.login-user{font-family:var(--mono);font-size:12px;color:var(--lake);letter-spacing:.04em;text-align:right;line-height:1.6}
.login-user button{font-family:var(--serif);font-size:11px;letter-spacing:.2em;color:var(--sub);border:1px solid rgba(255,255,255,.16);background:none;padding:3px 12px;border-radius:7px;cursor:pointer;margin-top:4px}
.rule{height:1px;background:linear-gradient(90deg,var(--gline-hi),rgba(255,255,255,.08) 55%,transparent);margin-top:26px}
/* 区块标题 */
.zone{font-family:var(--serif);font-size:15px;letter-spacing:.44em;color:var(--sub);margin:38px 0 16px;display:flex;align-items:center;gap:16px}
.zone::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,rgba(255,255,255,.12),transparent)}
.zone .en{font-family:var(--mono);font-size:10px;letter-spacing:.2em;color:var(--faint)}
/* 登录卡 */
.login-hero{display:flex;gap:34px;align-items:center;padding:38px 40px;animation:rise .6s ease both}
.login-hero .copy{flex:1;min-width:240px}
.login-hero .copy .lead{font-family:var(--serif);font-size:24px;letter-spacing:.1em;line-height:1.5;margin-bottom:10px}
.login-hero .copy .lead em{color:var(--gold);font-style:normal}
.login-hero .copy p{color:var(--sub);font-size:13.5px;line-height:1.8}
.login-box{flex:none;width:330px;padding:26px;border-radius:14px;background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.1)}
.login-box h3{font-family:var(--serif);font-size:17px;letter-spacing:.14em;margin-bottom:14px;display:flex;align-items:center;gap:10px}
.login-box h3 .dot{width:8px;height:8px;border-radius:50%;background:var(--gold);box-shadow:0 0 9px rgba(232,180,90,.8)}
.login-box input{width:100%;padding:12px 14px;margin-bottom:11px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.12);color:var(--tx);font-family:var(--mono);font-size:14px;border-radius:10px}
.login-box input:focus{outline:none;border-color:var(--gold);box-shadow:0 0 0 3px rgba(232,180,90,.12)}
.login-box .hint{font-size:11.5px;color:var(--faint);line-height:1.7;margin-bottom:14px}
.welcome-bar{display:flex;align-items:center;gap:16px;padding:16px 24px;animation:rise .5s ease both}
.welcome-bar .wt{font-family:var(--serif);font-size:16px;letter-spacing:.1em;color:var(--lake)}
.welcome-bar .ws{color:var(--sub);font-size:12.5px}
/* 工作室卡 */
.studio{padding:34px 38px;animation:rise .6s ease both;position:relative;overflow:hidden}
.studio::before{content:"";position:absolute;right:-40px;top:-40px;width:220px;height:220px;border-radius:50%;background:radial-gradient(circle,rgba(95,224,192,.14),transparent 70%)}
.studio .tag-row{display:flex;gap:10px;margin-bottom:16px;flex-wrap:wrap}
.studio .chip{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;color:var(--lake);border:1px solid rgba(95,224,192,.35);background:rgba(95,224,192,.06);padding:3px 11px;border-radius:99px}
.studio h2{font-family:var(--serif);font-size:26px;letter-spacing:.1em;margin-bottom:8px}
.studio .desc{color:var(--sub);font-size:13.5px;max-width:640px;line-height:1.8;margin-bottom:20px}
.studio .acts{display:flex;gap:12px;flex-wrap:wrap}
.studio .film{position:absolute;right:36px;bottom:26px;font-family:var(--mono);font-size:10px;color:var(--faint);letter-spacing:.2em}
/* 选项卡 */
.panel{padding:0;overflow:hidden;animation:rise .6s ease both}
.tabs{display:flex;border-bottom:1px solid rgba(255,255,255,.08);background:rgba(255,255,255,.015)}
.tab{flex:1;padding:16px 10px;background:none;border:none;border-bottom:2px solid transparent;color:var(--sub);font-family:var(--serif);font-size:15px;letter-spacing:.16em;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center;gap:9px}
.tab:hover{color:var(--tx)}
.tab.active{color:var(--lake);border-bottom-color:var(--lake);background:rgba(95,224,192,.04)}
.tab .cnt{font-family:var(--mono);font-size:10.5px;min-width:20px;padding:1px 6px;border-radius:99px;background:rgba(255,90,78,.14);color:var(--seal);border:1px solid rgba(255,90,78,.35)}
.tab .cnt.zero{background:rgba(255,255,255,.05);color:var(--faint);border-color:rgba(255,255,255,.12)}
.tabpane{padding:24px 26px;display:none;min-height:180px}
.tabpane.show{display:block}
.pane-desc{color:var(--faint);font-size:12.5px;margin-bottom:16px;letter-spacing:.03em}
/* 通用条目/按钮 */
.item{border:1px solid rgba(255,255,255,.08);border-left:2px solid var(--lake-soft);border-radius:12px;padding:14px 16px;margin-bottom:10px;background:rgba(255,255,255,.02);transition:border-color .25s,background .25s}
.item:hover{border-color:rgba(95,224,192,.25);background:rgba(95,224,192,.04)}
.item .t{font-size:14px;font-weight:600;margin-bottom:4px}
.item .m{font-size:12px;color:var(--sub);line-height:1.7;font-family:var(--mono)}
.item .body{font-size:12.5px;color:var(--sub);margin-top:6px;border-top:1px dashed rgba(255,255,255,.09);padding-top:6px}
.row{display:flex;gap:10px;margin-top:12px;flex-wrap:wrap}
button.act{font-family:var(--serif);font-size:13.5px;letter-spacing:.24em;cursor:pointer;padding:7px 18px 7px 22px;border-radius:9px;transition:all .25s}
.btn-sign{color:var(--seal);border:1px solid rgba(255,90,78,.6);background:rgba(255,90,78,.07)}
.btn-sign:hover{background:rgba(255,90,78,.16);box-shadow:0 0 20px rgba(255,90,78,.22)}
.btn-deny{color:var(--sub);border:1px solid rgba(255,255,255,.14);background:rgba(255,255,255,.03)}
.btn-deny:hover{color:var(--tx);border-color:rgba(255,255,255,.3)}
.empty{color:var(--faint);font-size:13px;padding:30px 0;text-align:center;font-family:var(--serif);letter-spacing:.12em}
.locked-note{text-align:center;padding:34px 0;color:var(--gold);font-size:13px;letter-spacing:.1em}
.pbadge{display:inline-block;font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;padding:1px 9px;border-radius:5px;margin-right:8px;border:1px solid rgba(95,224,192,.4);color:var(--lake);background:rgba(95,224,192,.07)}
.pbadge.jy{border-color:rgba(232,180,90,.5);color:var(--gold);background:rgba(232,180,90,.07)}
.win-item{border:1px solid rgba(95,224,192,.3);border-radius:11px;padding:10px 14px;margin-bottom:8px;background:rgba(95,224,192,.05);font-family:var(--mono);font-size:12px;display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap}
.vbadge{display:inline-block;font-family:var(--mono);font-size:10px;padding:0 8px;border-radius:5px;margin-left:8px;letter-spacing:.08em}
.vbadge.pass{color:var(--lake);border:1px solid rgba(95,224,192,.4);background:rgba(95,224,192,.06)}
.vbadge.rej{color:var(--seal);border:1px solid rgba(255,90,78,.5);background:rgba(255,90,78,.07)}
/* 两列 */
.cols2{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:16px}
.card{padding:24px 26px;animation:rise .6s ease both}
.card h3{font-family:var(--serif);font-size:17px;letter-spacing:.16em;font-weight:600;display:flex;align-items:baseline;gap:10px;margin-bottom:2px}
.card h3 .no{font-family:var(--mono);font-size:10.5px;color:var(--seal);letter-spacing:.2em}
.card .desc{font-size:12px;color:var(--faint);margin-bottom:16px}
/* 仪表 */
.gauges{display:flex;gap:14px;justify-content:space-between;margin:6px 0 18px}
.gauge{flex:1;text-align:center}
.gauge-wrap{position:relative;width:96px;height:96px;margin:0 auto}
.g-bg{fill:none;stroke:rgba(255,255,255,.07);stroke-width:8}
.g-fg{fill:none;stroke-width:8;stroke-linecap:round;stroke-dasharray:326.7;stroke-dashoffset:326.7;transform:rotate(-90deg);transform-origin:60px 60px;transition:stroke-dashoffset 1.3s cubic-bezier(.22,1,.36,1);filter:drop-shadow(0 0 5px rgba(95,224,192,.35))}
.g-fg.warn{stroke:var(--seal)!important}
.g-center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center}
.g-num{font-family:var(--mono);font-size:21px;font-weight:700}
.g-sub{font-family:var(--mono);font-size:8.5px;color:var(--faint);margin-top:2px}
.g-label{margin-top:8px;font-family:var(--serif);letter-spacing:.3em;font-size:12px;color:var(--sub)}
.svc{display:grid;grid-template-columns:1fr 1fr;gap:9px}
.svc .row-i{display:flex;align-items:center;justify-content:space-between;border:1px solid rgba(255,255,255,.07);border-radius:10px;padding:9px 12px;background:rgba(255,255,255,.02)}
.svc .nm{font-size:12px;color:var(--sub)}
.dot{display:inline-block;width:8px;height:8px;border-radius:50%}
.dot.ok{background:var(--lake);box-shadow:0 0 8px rgba(95,224,192,.8);animation:pulse 2.4s infinite}
.dot.bad{background:var(--seal);box-shadow:0 0 8px rgba(255,90,78,.8)}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
.mini-strip{display:flex;gap:20px;margin-top:14px;font-family:var(--mono);font-size:11.5px;color:var(--sub);flex-wrap:wrap}
.mini-strip b{color:var(--tx);font-weight:600}
/* 时间线 */
.timeline{position:relative;padding-left:20px}
.timeline::before{content:"";position:absolute;left:4px;top:6px;bottom:6px;width:1px;background:linear-gradient(180deg,var(--lake-soft),rgba(255,255,255,.06))}
.tl-item{position:relative;padding:0 0 14px}
.tl-item::before{content:"";position:absolute;left:-19px;top:6px;width:8px;height:8px;border-radius:50%;background:var(--ink);border:2px solid var(--lake-soft)}
.tl-item .when{font-family:var(--mono);font-size:10.5px;color:var(--faint)}
.tl-item .what{font-size:12.5px;margin-top:1px}
.tl-item .sha{font-family:var(--mono);font-size:10px;color:var(--faint);margin-left:6px}
.tl-item .tag{display:inline-block;font-size:10px;padding:0 7px;margin-right:7px;border-radius:5px;border:1px solid rgba(95,224,192,.35);color:var(--lake);font-family:var(--mono)}
/* 部署步骤 */
.run-status{font-family:var(--mono);font-size:12px;letter-spacing:.12em;margin-bottom:12px;padding:7px 14px;border-radius:9px;display:inline-block}
.run-status.DEPLOYED{color:var(--lake);border:1px solid rgba(95,224,192,.45);background:rgba(95,224,192,.07)}
.run-status.REJECTED{color:var(--seal);border:1px solid rgba(255,90,78,.5);background:rgba(255,90,78,.07)}
.run-status.RUNNING{color:var(--gold);border:1px solid rgba(232,180,90,.5);background:rgba(232,180,90,.07);animation:pulse 1.8s infinite}
.steps{position:relative;padding-left:22px}
.steps::before{content:"";position:absolute;left:6px;top:8px;bottom:8px;width:1px;background:linear-gradient(180deg,rgba(232,180,90,.5),rgba(255,255,255,.07))}
.step{position:relative;padding:0 0 12px}
.step::before{content:"";position:absolute;left:-19px;top:4px;width:8px;height:8px;border-radius:50%;background:var(--ink);border:2px solid rgba(255,255,255,.2)}
.step.PASS::before{border-color:var(--lake);box-shadow:0 0 8px rgba(95,224,192,.6)}
.step.FAIL::before{border-color:var(--seal);box-shadow:0 0 8px rgba(255,90,78,.6)}
.step .nm{font-family:var(--mono);font-size:11.5px;letter-spacing:.08em}
.step .dt{font-size:11px;color:var(--sub)}
.deploy-cols{display:grid;grid-template-columns:1fr 1fr;gap:24px}
/* 仓库卡 */
.repo-name{font-family:var(--mono);font-size:19px;color:var(--lake);margin:8px 0 5px;text-shadow:0 0 16px rgba(95,224,192,.3)}
footer{padding:40px 0 36px;color:var(--faint)}
.foot-row{display:flex;justify-content:space-between;gap:18px;flex-wrap:wrap;font-family:var(--mono);font-size:11px;letter-spacing:.06em}
.foot-row .rhs{color:var(--lake-soft)}
a{color:var(--lake);text-decoration:none}
/* 弹窗 */
.modal-bg{position:fixed;inset:0;background:rgba(4,8,12,.82);backdrop-filter:blur(6px);display:none;align-items:center;justify-content:center;z-index:50}
.modal-bg .box{padding:36px;width:min(460px,92%);position:relative;animation:rise .3s ease both}
.modal-bg .box::before{content:"";position:absolute;inset:9px;border:1px solid rgba(255,255,255,.08);border-radius:12px;pointer-events:none}
.modal-bg h3{font-family:var(--serif);font-size:21px;letter-spacing:.2em;margin-bottom:12px;font-weight:600}
.modal-bg p{color:var(--sub);font-size:13px;line-height:1.9}
.modal-bg p .seal-word{color:var(--seal)}
#toast{position:fixed;bottom:28px;left:50%;transform:translateX(-50%);z-index:60;display:none;padding:12px 28px;font-family:var(--serif);letter-spacing:.2em;font-size:13.5px;border-radius:11px}
@media (max-width:900px){.cols2,.deploy-cols{grid-template-columns:1fr}.login-hero{flex-direction:column;align-items:stretch}.login-box{width:100%}.head-right{width:100%;justify-content:space-between}}
< / style >
< / head >
< body >
< div class = "blob b1" > < / div > < div class = "blob b2" > < / div >
< div class = "wrap" >
< header >
< div class = "kicker" > 光湖语言世界 < b > /< / b > 第五域 < b > /< / b > SYS-GLW-PTS-0001< / div >
< div class = "head-row" >
< div >
< h1 > 胖头鱼< span class = "yu" > 语言< / span > 子系统< / h1 >
< div class = "headline-sub" > 苍耳个人频道< span class = "sep" > ·< / span > 人类责任主体 苍耳< span class = "sep" > ·< / span > 人格体 耳耳蛋 / 鉴影< / div >
< / div >
< div class = "head-right" >
< div id = "login-area" > < / div >
< div class = "seal-badge" id = "gate-seal" > < div class = "n" id = "gate-n" > --< / div > < div class = "t" > 门禁< / div > < / div >
< / div >
< / div >
< div class = "rule" > < / div >
< / header >
<!-- 人类端入口 -->
< div id = "entry-zone" > < / div >
<!-- 工作室 -->
< div class = "zone" > 创 作 工 作 区< span class = "en" > STUDIO< / span > < / div >
< div class = "studio glass" >
< div class = "tag-row" >
< span class = "chip" > 视频短剧< / span > < span class = "chip" > 视频 AI 系统< / span > < span class = "chip" > 耳耳蛋主创< / span >
< / div >
< h2 > 苍耳 · 视频短剧工作室< / h2 >
< div class = "desc" > 这里是苍耳频道的主业——视频短剧创作。耳耳蛋与鉴影在仓库里维护视频 AI 系统、剧本分镜与成片流水线。人格体的每一次创作与学习,都经审批与留痕后写回这里。< / div >
< div class = "acts" >
< a href = "/code/canger/cang-ying" target = "_blank" style = "text-decoration:none" > < button class = "act btn-sign" > 进入创作仓库< / button > < / a >
< a href = "/code/canger/cang-ying/src/branch/main/video-ai-system" target = "_blank" style = "text-decoration:none" > < button class = "act btn-deny" > 视频 AI 系统< / button > < / a >
< / div >
< div class = "film" > REEL · SYS-GLW-PTS-0001< / div >
< / div >
<!-- 审批中心 -->
< div class = "zone" > 审 批 中 心< span class = "en" > APPROVAL< / span > < / div >
< div class = "panel glass" >
< div class = "tabs" >
< button class = "tab active" id = "tabbtn-sign" onclick = "switchTab('sign')" > 合并签字 < span class = "cnt zero" id = "cnt-sign" > 0< / span > < / button >
< button class = "tab" id = "tabbtn-access" onclick = "switchTab('access')" > 写入权限 < span class = "cnt zero" id = "cnt-access" > 0< / span > < / button >
< button class = "tab" id = "tabbtn-deploy" onclick = "switchTab('deploy')" > 部署通道 < span class = "cnt zero" id = "cnt-deploy" > 0< / span > < / button >
< / div >
< div class = "tabpane show" id = "pane-sign" >
< div class = "pane-desc" > 人格体推上来的合并请求,翻译成人话放在这里。你点下去的每一下,都是签字。< / div >
< div id = "prs" > < / div >
< / div >
< div class = "tabpane" id = "pane-access" >
< div class = "pane-desc" > 人格体申请写入仓库在这里排队。批准 = 授予 3 小时写入窗口,每次写入都留痕。< / div >
< div id = "access-reqs" > < / div > < div id = "access-wins" > < / div >
< / div >
< div class = "tabpane" id = "pane-deploy" >
< div class = "pane-desc" > 目标分支为 deploy 的合并请求走这条通道。批准后服务器内校验Agent自审: 地图 → 因果链 → 范围 → 完整性 → 全过才部署。全程实时可见。< / div >
< div class = "deploy-cols" >
< div id = "deploy-prs" > < / div >
< div > < div id = "run-status" > < / div > < div class = "steps" id = "deploy-steps" > < / div > < / div >
< / div >
< / div >
< / div >
<!-- 状态与痕迹 -->
< div class = "zone" > 状 态 与 痕 迹< span class = "en" > STATE & TRACE< / span > < / div >
< div class = "cols2" style = "margin-top:0" >
< div class = "card glass" >
< h3 > < span class = "no" > 壹< / span > 实时状态< / h3 >
< div class = "desc" > 服务器与代码频道的健康,一眼看完。< / div >
< div class = "gauges" >
< div class = "gauge" > < div class = "gauge-wrap" > < svg viewBox = "0 0 120 120" > < circle class = "g-bg" cx = "60" cy = "60" r = "52" / > < circle class = "g-fg" id = "ring-cpu" cx = "60" cy = "60" r = "52" stroke = "#5fe0c0" / > < / svg > < div class = "g-center" > < div class = "g-num" id = "num-cpu" > --< / div > < / div > < / div > < div class = "g-label" > 处理器< / div > < / div >
< div class = "gauge" > < div class = "gauge-wrap" > < svg viewBox = "0 0 120 120" > < circle class = "g-bg" cx = "60" cy = "60" r = "52" / > < circle class = "g-fg" id = "ring-mem" cx = "60" cy = "60" r = "52" stroke = "#7cc3e8" / > < / svg > < div class = "g-center" > < div class = "g-num" id = "num-mem" > --< / div > < div class = "g-sub" id = "sub-mem" > < / div > < / div > < / div > < div class = "g-label" > 内存< / div > < / div >
< div class = "gauge" > < div class = "gauge-wrap" > < svg viewBox = "0 0 120 120" > < circle class = "g-bg" cx = "60" cy = "60" r = "52" / > < circle class = "g-fg" id = "ring-disk" cx = "60" cy = "60" r = "52" stroke = "#e8b45a" / > < / svg > < div class = "g-center" > < div class = "g-num" id = "num-disk" > --< / div > < div class = "g-sub" id = "sub-disk" > < / div > < / div > < / div > < div class = "g-label" > 磁盘< / div > < / div >
< / div >
< div class = "svc" >
< div class = "row-i" > < span class = "nm" > 代码频道< / span > < span class = "dot bad" id = "svc-cc" > < / span > < / div >
< div class = "row-i" > < span class = "nm" > 操作面板< / span > < span class = "dot bad" id = "svc-panel" > < / span > < / div >
< div class = "row-i" > < span class = "nm" > 门禁自检< / span > < span class = "dot bad" id = "svc-gate" > < / span > < / div >
< div class = "row-i" > < span class = "nm" > 第五域同步< / span > < span class = "dot bad" id = "svc-sync" > < / span > < / div >
< / div >
< div class = "mini-strip" > < span > 负载 < b id = "load-v" > --< / b > < / span > < span > 运行 < b id = "up-v" > --< / b > 天< / span > < span > 主机 < b id = "host-v" > --< / b > < / span > < / div >
< / div >
< div class = "card glass" >
< h3 > < span class = "no" > 贰< / span > 痕迹档案< / h3 >
< div class = "desc" > 谁写的、谁唤醒的、门禁与签字——每一笔都有据。< / div >
< div class = "tabs" style = "margin:-2px -2px 14px;border-radius:10px;overflow:hidden" >
< button class = "tab active" style = "font-size:13px;padding:9px 6px" onclick = "switchTrace('push')" > 写入日志< / button >
< button class = "tab" style = "font-size:13px;padding:9px 6px" onclick = "switchTrace('wake')" > 唤醒记录< / button >
< button class = "tab" style = "font-size:13px;padding:9px 6px" onclick = "switchTrace('rcpt')" > 回执< / button >
< / div >
< div id = "trace-push" > < / div > < div id = "trace-wake" style = "display:none" > < / div > < div id = "trace-rcpt" style = "display:none" > < / div >
< / div >
< / div >
< div class = "cols2" >
< div class = "card glass" >
< h3 > < span class = "no" > 叁< / span > 人格体回写< / h3 >
< div class = "desc" > 你教给耳耳蛋的、它自己学到的,写回仓库后在这里看得见。< / div >
< div class = "timeline" id = "wbs" > < / div >
< / div >
< div class = "card glass" >
< h3 > < span class = "no" > 肆< / span > 真实仓库< / h3 >
< div class = "desc" > 面板是翻译层,仓库是真相层。< / div >
< div class = "repo-name" id = "repo-name" > --< / div >
< div style = "font-size:12.5px;color:var(--sub)" id = "repo-meta" > --< / div >
< div class = "row" >
< a href = "/code/canger/cang-ying" target = "_blank" style = "text-decoration:none" > < button class = "act btn-sign" > 进入仓库< / button > < / a >
< a href = "/code/" target = "_blank" style = "text-decoration:none" > < button class = "act btn-deny" > 代码频道< / button > < / a >
< / div >
< / div >
< / div >
< footer >
< div class = "foot-row" >
< div > 铸渊 ICE-GL-ZY001 建 · 2026-08-06 · ⊢ 要么0要么100< / div >
< div > < a href = "/persona-api.html" style = "color:var(--lake-soft)" > 人格体 API 入口文档 ↗< / a > < / div >
< div class = "rhs" id = "sync-line" > 第五域同步:--< / div >
< / div >
< / footer >
< / div >
<!-- 签字弹窗 -->
< div class = "modal-bg" id = "modal" > < div class = "box glass" >
< h3 id = "m-title" > 签 字< / h3 >
< div style = "font-size:13.5px;color:var(--lake);margin-bottom:12px;font-family:var(--mono)" id = "m-pr" > < / div >
< p > ⊢ 签字即代表:你(苍耳)作为< span class = "seal-word" > 人类责任主体< / span > ,为这台服务器的本次变更负责。< br > 签名将以当前登录的人类端账号永久记入回执。< / p >
< div class = "row" > < button class = "act btn-sign" onclick = "confirmSign()" > 落 印< / button > < button class = "act btn-deny" onclick = "closeModal()" > 收回< / button > < / div >
< / div > < / div >
<!-- 登录弹窗 -->
< div class = "modal-bg" id = "lmodal" > < div class = "box glass" >
< h3 > 人 类 端 登 录< / h3 >
< p > ⊢ 用代码仓库的< b > 人类端账号< / b > 登录。< br > 登录后解锁全部审批:合并签字、写入授权、部署审批。会话 12 小时有效。< / p >
< input id = "l-user" type = "text" placeholder = "仓库账号(如 canger) " style = "width:100%;padding:12px 14px;margin:16px 0 10px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.12);color:var(--tx);font-family:var(--mono);font-size:14px;border-radius:10px" >
< input id = "l-pass" type = "password" placeholder = "密码" style = "width:100%;padding:12px 14px;margin-bottom:16px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.12);color:var(--tx);font-family:var(--mono);font-size:14px;border-radius:10px" >
< div class = "row" > < button class = "act btn-sign" onclick = "doLogin()" > 登 录< / button > < button class = "act btn-deny" onclick = "document.getElementById('lmodal').style.display='none'" > 取消< / button > < / div >
< / div > < / div >
< div id = "toast" class = "glass" > < / div >
< script >
const C=326.7;let pending=null;
let session=localStorage.getItem("ptsSession")||"";
let sessionUser=localStorage.getItem("ptsUser")||"";
let lastState=null;
function authHeaders(){const h={};if(session)h["Authorization"]="Bearer "+session;return h;}
function esc(s){return String(s==null?"":s).replace(/&/g,"& ").replace(/< /g,"< ").replace(/>/g,"> ");}
function fmtDate(s){if(!s)return"";try{return new Date(s).toLocaleString("zh-CN",{hour12:false});}catch(e){return s;}}
function tween(el,to){const from=parseFloat(el.dataset.v||"0")||0;el.dataset.v=to;const t0=performance.now(),dur=900;
(function st(t){const p=Math.min(1,(t-t0)/dur),e=1-Math.pow(1-p,3);el.textContent=Math.round(from+(to-from)*e);if(p< 1 ) requestAnimationFrame ( st ) ; } ) ( t0 ) ; }
function setRing(id,p){const r=document.getElementById(id);if(!r)return;r.style.strokeDashoffset=C*(1-Math.max(0,Math.min(100,p))/100);r.classList.toggle("warn",p>=85);}
function dot(id,ok){const d=document.getElementById(id);if(d)d.className="dot "+(ok?"ok":"bad");}
function toast(msg,ok){const t=document.getElementById("toast");t.textContent=msg;t.style.color=ok?"var(--lake)":"var(--seal)";t.style.display="block";setTimeout(()=>t.style.display="none",4000);}
async function privileged(path,body){
if(!session){openLogin();return null;}
const r=await fetch(path,{method:"POST",headers:Object.assign({"Content-Type":"application/json"},authHeaders()),body:JSON.stringify(body)});
if(r.status===401){session="";localStorage.removeItem("ptsSession");renderEntry();openLogin();toast("会话已失效,请重新登录",false);return null;}
return await r.json();}
function renderEntry(){
const el=document.getElementById("login-area"),zone=document.getElementById("entry-zone");
if(session){
el.innerHTML='< div class = "login-user" > 人类端 · '+esc(sessionUser)+'< br > 审批已解锁 < button onclick = "doLogout()" > 登出< / button > < / div > ';
zone.innerHTML='< div class = "welcome-bar glass" > < span class = "wt" > ⊢ 欢迎回来,'+esc(sessionUser)+'< / span > < span class = "ws" > 审批中心已解锁 · 下方三个选项卡处理待办< / span > < / div > ';
}else{
el.innerHTML='< button class = "login-btn" onclick = "openLogin()" > 人 类 登 录< / button > ';
zone.innerHTML='< div class = "login-hero glass" > < div class = "copy" > < div class = "lead" > 这里是< em > 苍耳< / em > 的审批台< / div > < p > 你是这台服务器的人类责任主体。人格体推上来的合并、写入与部署申请,都需要你亲自看一眼、点一下才算数。用你的代码仓库账号登录,就能解锁全部审批。看不懂代码没关系——面板都翻译成人话了。< / p > < / div > < div class = "login-box" > < h3 > < span class = "dot" > < / span > 登录解锁审批< / h3 > < input id = "h-user" type = "text" placeholder = "仓库账号(如 canger) " > < input id = "h-pass" type = "password" placeholder = "密码" > < div class = "hint" > 就是你登录代码仓库用的那套账号密码。登录后 12 小时内不用重复登录。< / div > < button class = "login-btn" style = "width:100%;padding:12px" onclick = "heroLogin()" > 登 录 并 解 锁< / button > < / div > < / div > ';
}
}
function openLogin(){document.getElementById("lmodal").style.display="flex";setTimeout(()=>document.getElementById("l-user").focus(),60);}
async function tryLogin(u,p){
const r=await fetch("/api/login",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:u,password:p})});
const d=await r.json();
if(r.ok&&d.ok){session=d.session; sessionUser=d.user;localStorage.setItem("ptsSession",session);localStorage.setItem("ptsUser",sessionUser);
document.getElementById("lmodal").style.display="none";renderEntry();toast("登录成功 · 审批已解锁",true);refresh();return true;}
toast(d.error||"登录失败",false);return false;}
async function doLogin(){await tryLogin(document.getElementById("l-user").value.trim(),document.getElementById("l-pass").value);}
async function heroLogin(){await tryLogin(document.getElementById("h-user").value.trim(),document.getElementById("h-pass").value);}
function doLogout(){fetch("/api/logout",{method:"POST",headers:authHeaders()}).catch(()=>{});session="";sessionUser="";localStorage.removeItem("ptsSession");localStorage.removeItem("ptsUser");renderEntry();toast("已登出",true);}
function switchTab(name){["sign","access","deploy"].forEach(n=>{document.getElementById("pane-"+n).classList.toggle("show",n===name);document.getElementById("tabbtn-"+n).classList.toggle("active",n===name);});}
function switchTrace(name){["push","wake","rcpt"].forEach(n=>{document.getElementById("trace-"+n).style.display=(n===name)?"block":"none";});
const btns=document.querySelectorAll(".card .tabs .tab");/* handled by inline active */}
function setCnt(id,n){const el=document.getElementById(id);el.textContent=n;el.className="cnt"+(n?"":" zero");}
function ptag(p){return '< span class = "pbadge'+(p===" jianying " ? " jy " : " " ) + ' " > '+esc(p)+"< / span > ";}
function fmtLeft(exp){const ms=new Date(exp)-new Date();if(ms< =0)return"已过期";const h=Math.floor(ms/3600000),m=Math.floor(ms%3600000/60000);return"余 "+h+" 时 "+m+" 分";}
function openModal(i,t,a){pending={idx:i,action:a};document.getElementById("m-title").textContent=(a==="merge"?"同意合并 · 落印":"拒绝 · 收回")+" PR #"+i;document.getElementById("m-pr").textContent="「"+t+"」";document.getElementById("modal").style.display="flex";}
function closeModal(){document.getElementById("modal").style.display="none";pending=null;}
async function confirmSign(){if(!pending)return;const d=await privileged("/api/decision",{index:pending.idx,action:pending.action});closeModal();if(d)toast(d.result||d.error||"未知",!!d.ok);refresh();}
async function accessDecision(id,action){const d=await privileged("/api/access-decision",{id:id,action:action});if(d)toast(d.message||(d.ok?"已处理":"失败"),!!d.ok);refresh();}
async function deployApproveAction(idx){const d=await privileged("/api/deploy-approve",{index:idx});if(d)toast(d.message||(d.ok?"校验Agent已启动":"失败"),!!d.ok);refresh();}
function render(s){
lastState=s;const sv=s.server||{};
if(s.gate){document.getElementById("gate-n").textContent=s.gate.score;document.getElementById("gate-seal").className="seal-badge"+(s.gate.score===100?"":" zero");}
if(typeof sv.cpu==="number"){tween(document.getElementById("num-cpu"),sv.cpu);setRing("ring-cpu",sv.cpu);}
const used=sv.memTotalGB&&sv.memFreeGB!=null?+(sv.memTotalGB-sv.memFreeGB).toFixed(1):null;
if(sv.memTotalGB){const mp=Math.round(used/sv.memTotalGB*100);tween(document.getElementById("num-mem"),mp);setRing("ring-mem",mp);document.getElementById("sub-mem").textContent=used+"/"+sv.memTotalGB+"G";}
if(sv.disk){tween(document.getElementById("num-disk"),sv.disk.pct);setRing("ring-disk",sv.disk.pct);document.getElementById("sub-disk").textContent=sv.disk.usedGB+"/"+sv.disk.sizeGB+"G";}
if(sv.services){dot("svc-cc",sv.services.codeChannel);dot("svc-panel",sv.services.panel);dot("svc-gate",sv.services.gateTimer);dot("svc-sync",sv.services.syncTimer);}
document.getElementById("load-v").textContent=(sv.load||[]).join("·");
document.getElementById("up-v").textContent=sv.uptimeDays!=null?sv.uptimeDays:"--";
document.getElementById("host-v").textContent=sv.hostname||"--";
// 审批中心
const prs=s.openPRs||[];setCnt("cnt-sign",prs.length);
document.getElementById("prs").innerHTML=(prs.length& & !0)||prs.length?prs.map(p=>'< div class = "item" > < div class = "t" > PR #'+p.index+' · '+esc(p.title)+'< / div > < div class = "m" > '+esc(p.author)+' · '+fmtDate(p.created)+' · → '+esc(p.base)+' · '+p.files+' 文件 < span style = "color:var(--lake)" > +'+p.adds+'< / span > < span style = "color:var(--seal)" > -'+p.dels+'< / span > < / div > '+(p.summary?'< div class = "body" > '+esc(p.summary)+'< / div > ':'')+'< div class = "row" > < button class = "act btn-sign" onclick = "openModal('+p.index+',this.dataset.t,\'merge\')" data-t = "'+esc(p.title).replace(/" / g , " & quot ; " ) + ' " > 同意签字< / button > < button class = "act btn-deny" onclick = "openModal('+p.index+',this.dataset.t,\'reject\')" data-t = "'+esc(p.title).replace(/" / g , " & quot ; " ) + ' " > 拒绝< / button > < / div > < / div > ').join(""):(session?'< div class = "empty" > 没有待签的合并请求。< / div > ':'< div class = "locked-note" > 🔒 登录后此处显示待签的合并请求< / div > ');
const reqs=s.accessRequests||[];setCnt("cnt-access",reqs.length);
2026-08-07 18:56:35 +08:00
document.getElementById("access-reqs").innerHTML=reqs.length?reqs.map(r=>'< div class = "item" > < div class = "t" > '+ptag(r.persona)+'申请写入权限< / div > < div class = "m" > '+esc(r.reason||"未说明用途")+'< / div > < div class = "m" > '+fmtDate(r.ts)+'< / div > < div class = "row" > < button class = "act btn-sign" onclick = "accessDecision(\''+r.id+'\',\'approve\')" > '+(s.windowHours||3)+'小时授权< / button > < button class = "act btn-deny" onclick = "accessDecision(\''+r.id+'\',\'reject\')" > 拒绝< / button > < / div > < / div > ').join(""):(session?'< div class = "empty" > 暂无写入申请。< / div > ':'< div class = "locked-note" > 🔒 登录后此处显示写入申请< / div > ');
2026-08-06 21:21:58 +08:00
document.getElementById("access-wins").innerHTML=(s.activeGrants||[]).length?'< div style = "font-size:11px;color:var(--faint);letter-spacing:.2em;margin:14px 0 8px;font-family:var(--mono)" > 生效中的写入窗口< / div > '+s.activeGrants.map(g=>'< div class = "win-item" > < span > '+ptag(g.persona)+'写入窗口< / span > < span style = "color:var(--lake)" > '+fmtLeft(g.expiresAt)+'< / span > < / div > ').join(""):"";
const dprs=s.deployPRs||[];setCnt("cnt-deploy",dprs.length);
document.getElementById("deploy-prs").innerHTML=dprs.length?dprs.map(p=>'< div class = "item" style = "border-left-color:rgba(232,180,90,.6)" > < div class = "t" > 部署申请 PR #'+p.index+' · '+esc(p.title)+'< / div > < div class = "m" > '+esc(p.author)+' · '+esc(p.head)+' → deploy · '+p.files+' 文件< / div > < div class = "row" > < button class = "act btn-sign" onclick = "deployApproveAction('+p.index+')" > 批准部署< / button > < / div > < / div > ').join(""):(session?'< div class = "empty" > 部署通道无待审申请。PR 目标设为 deploy 即进入此通道。< / div > ':'< div class = "locked-note" > 🔒 登录后此处显示部署申请< / div > ');
const run=s.deployRun;const rs=document.getElementById("run-status"),st=document.getElementById("deploy-steps");
if(run& & run.status){rs.innerHTML='< span class = "run-status '+esc(run.status)+'" > '+esc(run.status)+(run.pr?" · PR#"+esc(run.pr):"")+'< / span > ';st.innerHTML=(run.steps||[]).map(x=>'< div class = "step '+esc(x.status)+'" > < div class = "nm" > '+esc(x.name)+' · '+esc(x.status)+'< / div > < div class = "dt" > '+esc(x.detail||"")+'< / div > < / div > ').join("");if(run.detail& & run.status!=="RUNNING")st.innerHTML+='< div class = "step '+(run.status===" DEPLOYED " ? " PASS " : " FAIL " ) + ' " > < div class = "nm" > 结论< / div > < div class = "dt" > '+esc(run.detail)+'< / div > < / div > ';}
else{rs.innerHTML="";st.innerHTML='< div class = "empty" > 还没有校验记录。< / div > ';}
// 痕迹
document.getElementById("trace-push").innerHTML=(s.pushLogs||[]).length?s.pushLogs.map(l=>'< div class = "item" style = "border-left-color:'+(l.verdict===" PASS " ? " rgba ( 95 , 224 , 192 , . 5 ) " : " rgba ( 255 , 90 , 78 , . 6 ) " ) + ' " > < div class = "t" > '+ptag(l.persona||l.pusher)+'推送 · '+(l.commits||0)+' 提交< span class = "vbadge '+(l.verdict===" PASS " ? " pass " : " rej " ) + ' " > '+(l.verdict==="PASS"?"通过":"拦截")+'< / span > < / div > < div class = "m" > '+fmtDate(l.ts)+'< / div > '+((l.reasons& & l.reasons.length)?'< div class = "body" > '+l.reasons.map(esc).join("< br > ")+'< / div > ':'')+'< / div > ').join(""):'< div class = "empty" > 还没有写入记录。< / div > ';
document.getElementById("trace-wake").innerHTML=(s.wakeReceipts||[]).length?s.wakeReceipts.map(w=>'< div class = "item" style = "border-left-color:rgba(232,180,90,.55)" > < div class = "t" > '+ptag(w.persona)+'唤醒回执'+(w.level?" · "+esc(w.level):"")+'< / div > < div class = "m" > '+fmtDate(w.ts)+'< / div > '+(w.summary?'< div class = "body" > '+esc(w.summary)+'< / div > ':'')+'< / div > ').join(""):'< div class = "empty" > 还没有唤醒回执。< / div > ';
document.getElementById("trace-rcpt").innerHTML=(s.receipts||[]).length?s.receipts.slice(0,6).map(r=>'< div class = "item" style = "border-left-color:rgba(232,180,90,.6)" > < div class = "m" > '+esc(r.name)+'< / div > < div class = "m" style = "color:var(--faint)" > '+fmtDate(r.mtime)+'< / div > < / div > ').join(""):'< div class = "empty" > 暂无回执。< / div > ';
// 回写 & 仓库
const dirName={memory:"记忆",eererdan:"耳耳蛋",jianying:"鉴影"};
document.getElementById("wbs").innerHTML=(s.writebacks||[]).length?s.writebacks.slice(0,7).map(w=>'< div class = "tl-item" > < div class = "when" > '+fmtDate(w.date)+'< / div > < div class = "what" > < span class = "tag" > '+(dirName[w.dir]||w.dir)+'< / span > '+esc(w.message)+'< span class = "sha" > '+esc(w.sha)+'< / span > < / div > < / div > ').join(""):'< div class = "empty" > 暂无回写。< / div > ';
document.getElementById("repo-name").textContent=s.repo.full;
document.getElementById("repo-meta").textContent="公开可读 · 人格体入门路径在内 · 合并须人类签字";
const sl=document.getElementById("sync-line");
if(s.sync& & s.sync.head)sl.textContent="第五域同步: HEAD "+s.sync.head+" · "+fmtDate(s.sync.ts);else sl.textContent="第五域同步:--";
}
async function refresh(){try{const r=await fetch("/api/state");render(await r.json());}catch(e){document.getElementById("sync-line").textContent="连接失败";}}
renderEntry();refresh();setInterval(refresh,8000);
< / script >
< / body >
< / html >