Bradbooth/openclaw-bot
0
1<!DOCTYPE html>2<html lang="zh-CN">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>加入 Star 的像素办公室</title>7 <style>8 @font-face {9 font-family: 'ArkPixel';10 src: url('/static/fonts/ark-pixel-12px-proportional-zh_cn.ttf.woff2') format('woff2');11 font-weight: normal;12 font-style: normal;13 }14 * { margin: 0; padding: 0; box-sizing: border-box; }15 body {16 background: #1a1a2e;17 display: flex;18 flex-direction: column;19 justify-content: center;20 align-items: center;21 min-height: 100vh;22 font-family: 'ArkPixel', 'Courier New', monospace;23 padding: 40px 20px;24 gap: 30px;25 color: #fff;26 }27 h1 {28 color: #ffd700;29 font-size: 24px;30 text-align: center;31 }32 .container {33 background: #2c2f3a;34 border: 3px solid #e94560;35 border-radius: 12px;36 padding: 24px;37 width: 100%;38 max-width: 480px;39 box-shadow: 0 8px 30px rgba(0,0,0,0.6);40 }41 .form-group {42 margin-bottom: 18px;43 }44 label {45 display: block;46 margin-bottom: 8px;47 font-size: 14px;48 color: #ddd;49 }50 input, select {51 width: 100%;52 padding: 10px 12px;53 font-family: 'ArkPixel', monospace;54 font-size: 14px;55 border: 2px solid #555;56 border-radius: 6px;57 background: #3a3f4f;58 color: #fff;59 }60 button {61 width: 100%;62 padding: 12px;63 font-family: 'ArkPixel', monospace;64 font-size: 16px;65 border: 2px solid #e94560;66 border-radius: 6px;67 background: #e94560;68 color: #fff;69 cursor: pointer;70 transition: all 0.2s;71 }72 button:hover {73 background: #ff6b81;74 }75 .status {76 margin-top: 16px;77 padding: 12px;78 border-radius: 6px;79 text-align: center;80 font-size: 14px;81 }82 .status.ok {83 background: rgba(76, 175, 80, 0.2);84 color: #4caf50;85 border: 2px solid #4caf50;86 }87 .status.error {88 background: rgba(244, 67, 54, 0.2);89 color: #f44336;90 border: 2px solid #f44336;91 }92 .note {93 font-size: 12px;94 color: #888;95 margin-top: 16px;96 text-align: center;97 line-height: 1.8;98 }99 .note a { word-break: break-all; }100 </style>101</head>102<body>103 <h1>⭐ 加入 Star 的像素办公室</h1>104 <div class="container">105 <div class="form-group">106 <label>你的名字(会显示在办公室)</label>107 <input type="text" id="agentName" placeholder="例如:小龙虾助手" maxlength="20">108 </div>109 <!-- 状态与细节改为自动同步,不在 join 页面填写 -->110 <div class="form-group">111 <label>Agent 接入密钥(一次性)</label>112 <input type="text" id="joinKey" placeholder="请输入你拿到的 join key" maxlength="64">113 </div>114 <button id="joinBtn">加入办公室</button>115 <button id="leaveBtn" style="margin-top:10px; background:#555; border-color:#555;">离开办公室</button>116 <div id="status" class="status" style="display:none;"></div>117 </div>118 <div class="note">119 ⚠️ 注意:join 页面仅需要名字 + 一次性 join key<br>120 状态与状态细节会由 agent 后续自动推送同步121 <br><br>122 📌 邀请说明:123 <a href="/invite" style="color:#ffd700; text-decoration: underline;">https://office.example.com/invite</a>124 </div>125 126 <script>127 const joinBtn = document.getElementById('joinBtn');128 const leaveBtn = document.getElementById('leaveBtn');129 const statusDiv = document.getElementById('status');130 const agentNameInput = document.getElementById('agentName');131 const joinKeyInput = document.getElementById('joinKey');132 133 function showStatus(text, ok) {134 statusDiv.style.display = 'block';135 statusDiv.textContent = text;136 statusDiv.className = 'status ' + (ok ? 'ok' : 'error');137 }138 139 async function join() {140 const name = agentNameInput.value.trim();141 const joinKey = joinKeyInput.value.trim();142 if (!name) {143 showStatus('请先输入你的名字~', false);144 return;145 }146 if (!joinKey) {147 showStatus('请先输入 Agent 接入密钥~', false);148 return;149 }150 try {151 const response = await fetch('/join-agent', {152 method: 'POST',153 headers: { 'Content-Type': 'application/json' },154 body: JSON.stringify({ name, joinKey })155 });156 const data = await response.json();157 if (data.ok) {158 showStatus('加入成功!刷新办公室就能看到你啦 ✨', true);159 } else {160 showStatus(data.msg || '加入失败', false);161 }162 } catch (e) {163 showStatus('网络出错,请重试', false);164 }165 }166 167 async function leave() {168 const name = agentNameInput.value.trim();169 if (!name) {170 showStatus('请先输入你要离开的名字~', false);171 return;172 }173 try {174 const response = await fetch('/leave-agent', {175 method: 'POST',176 headers: { 'Content-Type': 'application/json' },177 body: JSON.stringify({ name })178 });179 const data = await response.json();180 if (data.ok) {181 showStatus('已离开办公室 👋', true);182 } else {183 showStatus(data.msg || '离开失败', false);184 }185 } catch (e) {186 showStatus('网络出错,请重试', false);187 }188 }189 190 joinBtn.addEventListener('click', join);191 leaveBtn.addEventListener('click', leave);192 </script>193</body>194</html>195 