EasyTier+RDP开关按钮 + G规范MD展示
- EasyTier: Turn On/Turn Off按钮 (onclick通过JS赋值,无引号问题) - RDP: Enable/Disable按钮 (按钮状态与tunnel/rdp状态联动) - G规范: 用<pre>展示dev-spec.md完整内容 - 使用document.createElement+onclick避免HTML引号转义地狱 - Playwright验证: 0 errors, 所有功能正常
This commit is contained in:
@@ -103,12 +103,15 @@ async function fT(){try{var r=await fetch('/api/todos'),d=await r.json();fill('t
|
|||||||
async function fE(){try{var r=await fetch('/api/metagrowth'),d=await r.json();fill('meta','fixes: '+(d.total_fixes||0)+' commits: '+(d.commit_count||0))}catch(e){}}
|
async function fE(){try{var r=await fetch('/api/metagrowth'),d=await r.json();fill('meta','fixes: '+(d.total_fixes||0)+' commits: '+(d.commit_count||0))}catch(e){}}
|
||||||
async function fF(){try{var r=await fetch('/api/expected'),d=await r.json();var ok=0;for(var i=0;i<d.expected.length;i++){var e=d.expected[i],a=d.actual[e.name]||'',cmp=(e.expected.indexOf('running')===0&&a==='running')||(e.expected.indexOf('scheduled')===0&&(a==='scheduled'||a==='running'));if(cmp)ok++}fill('exp',ok+'/'+d.expected.length+' compliant')}catch(e){}}
|
async function fF(){try{var r=await fetch('/api/expected'),d=await r.json();var ok=0;for(var i=0;i<d.expected.length;i++){var e=d.expected[i],a=d.actual[e.name]||'',cmp=(e.expected.indexOf('running')===0&&a==='running')||(e.expected.indexOf('scheduled')===0&&(a==='scheduled'||a==='running'));if(cmp)ok++}fill('exp',ok+'/'+d.expected.length+' compliant')}catch(e){}}
|
||||||
async function fK(){try{var r=await fetch('/api/kanban'),d=await r.json(),n=(d.tasks||[]).length;fill('kanban',n?'<span>'+n+' tasks</span>':'<span class="dim">No tasks</span>')}catch(e){}}
|
async function fK(){try{var r=await fetch('/api/kanban'),d=await r.json(),n=(d.tasks||[]).length;fill('kanban',n?'<span>'+n+' tasks</span>':'<span class="dim">No tasks</span>')}catch(e){}}
|
||||||
async function fI(){try{var r=await fetch('/api/platform'),d=await r.json();var h='<div class="ps"><h2>Platform</h2><div class="psv">';for(var i=0;i<d.length;i++){h+='<div class="i"><span class="d '+(d[i].status==='running'?'ok':'stopped')+'"></span>'+esc(d[i].name)+'</div>';}h+='</div></div>';try{var r2=await fetch('/api/ejabberd'),e=await r2.json();var ea=e.alive||e.xmpp_bot_connected;h+='<div class="ps"><h2>EasyTier VPN</h2><div class="psv"><div class="i"><span class="d stopped" id="et-w"></span>Windows <span id="et-w-ip"></span></div><div class="i"><span class="d stopped" id="et-246"></span>246 <span id="et-246-ip"></span></div></div></div><div class="ps"><h2>RDP Remote Desktop</h2><div class="psv"><div class="i"><span class="d stopped" id="rdp-st"></span>RDP <span id="rdp-info"></span></div><div class="i"><span class="d stopped" id="rdp-tun"></span>Tunnel</div></div></div><div class="ps"><h2>Ejabberd</h2><div class="psv"><div class="i"><span class="d '+(ea?'ok':'stopped')+'"></span>'+(ea?'ALIVE':'DOWN')+'</div></div></div>';}catch(e2){}fill('infra',h)}catch(e){}}
|
async function fI(){try{var r=await fetch('/api/platform'),d=await r.json();var h='<div class="ps"><h2>Platform</h2><div class="psv">';for(var i=0;i<d.length;i++){h+='<div class="i"><span class="d '+(d[i].status==='running'?'ok':'stopped')+'"></span>'+esc(d[i].name)+'</div>';}h+='</div></div>';try{var r2=await fetch('/api/ejabberd'),e=await r2.json();var ea=e.alive||e.xmpp_bot_connected;h+='<div class="ps"><h2>Ejabberd</h2><div class="psv"><div class="i"><span class="d '+(ea?'ok':'stopped')+'"></span>'+(ea?'ALIVE':'DOWN')+'</div></div></div>';}catch(e2){}fill('infra',h)}catch(e){}}
|
||||||
var FETCHES={agents:fa,git:fG,svc:fS,mon:fM,todos:fT,meta:fE,exp:fF,spec:fS2,kanban:fK,infra:fI,easytier:fE2,rdp:fR,principles:function(){return(FETCHES[as]||function(){})()}};
|
var FETCHES={agents:fa,git:fG,svc:fS,mon:fM,todos:fT,meta:fE,exp:fF,spec:fS2,kanban:fK,infra:fI,easytier:fE2,rdp:fR,principles:function(){return(FETCHES[as]||function(){})()}};
|
||||||
async function loadAll(){var d=new Date();qs('subtitle').textContent=d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate()+' '+d.getHours()+':'+d.getMinutes();await Promise.all(Object.keys(FETCHES).map(function(k){return FETCHES[k]()}))}
|
async function loadAll(){var d=new Date();qs('subtitle').textContent=d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate()+' '+d.getHours()+':'+d.getMinutes();await Promise.all(Object.keys(FETCHES).map(function(k){return FETCHES[k]()}));setTimeout(fetchEasyTierStatus,500);setTimeout(fetchRdpStatus,500)}
|
||||||
|
|
||||||
async function fE2(){try{var r=await fetch('/api/easytier'),d=await r.json(),s=d.status||{};var e1=document.getElementById('et-w');if(e1){e1.className='d '+(s.windows==='running'?'ok':'stopped')}var e2=document.getElementById('et-246');if(e2){e2.className='d '+(s['246']==='running'?'ok':'stopped')}if(d.virtual_ips){var w=document.getElementById('et-w-ip');if(w)w.textContent=d.virtual_ips.windows||'';var t=document.getElementById('et-246-ip');if(t)t.textContent=d.virtual_ips['246']||''}}catch(e){}}
|
async function fE2(){try{var r=await fetch('/api/easytier'),d=await r.json(),s=d.status||{};var e1=document.getElementById('et-w');if(e1){e1.className='d '+(s.windows==='running'?'ok':'stopped')}var e2=document.getElementById('et-246');if(e2){e2.className='d '+(s['246']==='running'?'ok':'stopped')}if(d.virtual_ips){var w=document.getElementById('et-w-ip');if(w)w.textContent=d.virtual_ips.windows||'';var t=document.getElementById('et-246-ip');if(t)t.textContent=d.virtual_ips['246']||''}}catch(e){}}
|
||||||
async function fR(){try{var r=await fetch('/api/rdp'),d=await r.json();var e1=document.getElementById('rdp-st');if(e1){e1.className='d '+(d.rdp_enabled?'ok':'stopped')}var e2=document.getElementById('rdp-tun');if(e2){e2.className='d '+(d.tunnel_running?'ok':'stopped')}var info=document.getElementById('rdp-info');if(info)info.textContent=d.public_endpoint||''}catch(e){}}
|
async function fR(){try{var r=await fetch('/api/rdp'),d=await r.json();var e1=document.getElementById('rdp-st');if(e1){e1.className='d '+(d.rdp_enabled?'ok':'stopped')}var e2=document.getElementById('rdp-tun');if(e2){e2.className='d '+(d.tunnel_running?'ok':'stopped')}var info=document.getElementById('rdp-info');if(info)info.textContent=d.public_endpoint||''}catch(e){}}
|
||||||
async function fS2(){try{var r=await fetch('/api/spec'),d=await r.json();if(!d.ok||!d.content){fill('spec','Failed');return}fill('spec','<div class=mono style=font-size:11px;color:var(--dim);white-space:pre-wrap;max-height:500px;overflow-y:auto;background:var(--bg);padding:12px;border-radius:6px>'+esc(d.content)+'</div>')}catch(e){fill('spec','Error')}}
|
async function fS2(){try{var r=await fetch('/api/spec'),d=await r.json();if(!d.ok||!d.content){fill('spec','Failed');return}fill('spec','<div class=mono style=font-size:11px;color:var(--dim);white-space:pre-wrap;max-height:500px;overflow-y:auto;background:var(--bg);padding:12px;border-radius:6px>'+esc(d.content)+'</div>')}catch(e){fill('spec','Error')}}
|
||||||
init();loadAll();setInterval(loadAll,10000);setInterval(fK,15000);setInterval(fE,10000);setInterval(fR,10000);
|
init();loadAll();setInterval(loadAll,10000);setInterval(fK,15000);
|
||||||
|
async function fetchEasyTierStatus(){try{var r=await fetch('/api/easytier'),d=await r.json(),s=d.status||{};var c=document.getElementById('ct-infra');if(!c)return;var el=document.getElementById('easytier-section');if(!el){el=document.createElement('div');el.id='easytier-section';el.innerHTML='<div class=ps style=margin-top:16px><h2>EasyTier VPN</h2><div class=psv><div class=i><span class=d id=et-w></span>Windows <span id=et-w-ip></span></div><div class=i><span class=d id=et-246></span>246 <span id=et-246-ip></span></div></div><div style=margin-top:8px;display:flex;gap:8px;align-items:center><button class="btn s" id=btn-et-on>Turn On</button><button class="btn x" id=btn-et-off disabled>Turn Off</button><span id=et-status style=font-size:12px;color:var(--dim)>-</span></div></div>';c.appendChild(el);var ob=document.getElementById('btn-et-on');var ofb=document.getElementById('btn-et-off');if(ob)ob.onclick=function(){fetch('/api/easytier/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'start'})}).then(function(){setTimeout(fetchEasyTierStatus,2000);toast('EasyTier On OK')}).catch(function(e){toast('EasyTier On FAIL','err')})};if(ofb)ofb.onclick=function(){fetch('/api/easytier/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'stop'})}).then(function(){setTimeout(fetchEasyTierStatus,2000);toast('EasyTier Off OK')}).catch(function(e){toast('EasyTier Off FAIL','err')})};}var e1=document.getElementById('et-w');if(e1)e1.className='d '+(s.windows==='running'?'ok':'stopped');var e2=document.getElementById('et-246');if(e2)e2.className='d '+(s['246']==='running'?'ok':'stopped');if(d.virtual_ips){var w=document.getElementById('et-w-ip');if(w)w.textContent=d.virtual_ips.windows||'';var t=document.getElementById('et-246-ip');if(t)t.textContent=d.virtual_ips['246']||''}var allRunning=Object.values(s).every(function(v){return v==='running'||v==='pending'});var onBtn=document.getElementById('btn-et-on');var offBtn=document.getElementById('btn-et-off');var stxt=document.getElementById('et-status');if(onBtn)onBtn.disabled=allRunning;if(offBtn)offBtn.disabled=!allRunning;if(stxt)stxt.textContent=allRunning?'Connected':'Off'}catch(e){}}
|
||||||
|
async function fetchRdpStatus(){try{var r=await fetch('/api/rdp'),d=await r.json();var c=document.getElementById('ct-infra');if(!c)return;var el=document.getElementById('rdp-section');if(!el){el=document.createElement('div');el.id='rdp-section';el.innerHTML='<div class=ps style=margin-top:16px><h2>RDP Remote Desktop</h2><div class=psv><div class=i><span class=d id=rdp-st></span>RDP <span id=rdp-info></span></div><div class=i><span class=d id=rdp-tun></span>Tunnel</div></div><div style=margin-top:8px;display:flex;gap:8px;align-items:center><button class="btn s" id=btn-rdp-on>Enable</button><button class="btn x" id=btn-rdp-off disabled>Disable</button><span id=rdp-status-txt style=font-size:12px;color:var(--dim)>-</span></div></div>';c.appendChild(el);var ob=document.getElementById('btn-rdp-on');var ofb=document.getElementById('btn-rdp-off');if(ob)ob.onclick=function(){fetch('/api/rdp/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'start'})}).then(function(){setTimeout(fetchRdpStatus,2000);toast('RDP On OK')}).catch(function(e){toast('RDP On FAIL','err')})};if(ofb)ofb.onclick=function(){fetch('/api/rdp/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'stop'})}).then(function(){setTimeout(fetchRdpStatus,2000);toast('RDP Off OK')}).catch(function(e){toast('RDP Off FAIL','err')})};}var e1=document.getElementById('rdp-st');if(e1)e1.className='d '+(d.rdp_enabled?'ok':'stopped');var e2=document.getElementById('rdp-tun');if(e2)e2.className='d '+(d.tunnel_running?'ok':'stopped');var info=document.getElementById('rdp-info');if(info)info.textContent=d.public_endpoint||'';var fullyOn=d.rdp_enabled&&d.tunnel_running;var onBtn=document.getElementById('btn-rdp-on');var offBtn=document.getElementById('btn-rdp-off');var stxt=document.getElementById('rdp-status-txt');if(onBtn)onBtn.disabled=fullyOn;if(offBtn)offBtn.disabled=!fullyOn;if(stxt)stxt.textContent=fullyOn?'Connected':d.rdp_enabled?'Tunnel pending':'Disconnected'}catch(e){}}
|
||||||
|
fetchEasyTierStatus();fetchRdpStatus();setInterval(fetchEasyTierStatus,10000);setInterval(fetchRdpStatus,10000);setInterval(fE,10000);setInterval(fR,10000);
|
||||||
</script></body></html>
|
</script></body></html>
|
||||||
Reference in New Issue
Block a user