feat: WeChat QR code + status inline in Platform tab

wechat_bridge entry now shows:
- status text (已登录Xh / 已掉线Xh) via s.message
- inline QR code with 5min expiry + refresh button when logged out
- refreshWechatQR() fetches latest QR on demand (no polling)
This commit is contained in:
2026-08-02 04:43:16 +08:00
parent b0ad75b88e
commit be2b194b71
+25 -1
View File
@@ -318,7 +318,31 @@ async function fI(){
var h='';
try{var r=await fetch('/api/platform'),d=await r.json();
h+='<div class="ps"><h2>Platform<span class="help-btn" onclick="showModuleHelp(\'infra\',\'human\')" title="使用说明">?</span><span class="help-btn ai" onclick="showModuleHelp(\'infra\',\'ai\')" title="AI Spec">§</span></h2><div class="psv">';
for(var i=0;i<d.length;i++){var s=d[i];h+='<div class="i"><span class="d '+(s.status==='running'?'ok':'stopped')+'"></span><span class="sn">'+esc(s.name)+'</span><span class="help-btn" onclick="showModuleHelp(\''+s.id+'\',\'human\')" title="使用说明">?</span><span class="help-btn ai" onclick="showModuleHelp(\''+s.id+'\',\'ai\')" title="AI Spec">§</span></div>';}
for(var i=0;i<d.length;i++){var s=d[i];
var dc='stopped',ds='',dt='';
if(s.status==='running'){dc='ok';dt=s.message?' <span style=color:var(--green)>'+esc(s.message)+'</span>':'';}
else if(s.status==='logged_out'){dc='ok';ds='background:var(--yellow)';dt=' <span style=color:var(--yellow)>'+esc(s.message||'\u9700\u626b\u7801')+'</span>';}
h+='<div class="i"><span class="d '+dc+'"'+(ds?' style='+ds:'')+'></span><span class="sn">'+esc(s.name)+dt+'</span><span class="help-btn" onclick="showModuleHelp(\''+s.id+'\',\'human\')" title="\u4f7f\u7528\u8bf4\u660e">?</span><span class="help-btn ai" onclick="showModuleHelp(\''+s.id+'\',\'ai\')" title="AI Spec">\u00a7</span></div>';
if(s.id==='wechat_bridge'&&s.status==='logged_out'&&s.qr_url){
h+='<div style="margin:0 0 10px 18px;padding:12px 16px;background:#1a1400;border:1px solid var(--yellow);border-radius:8px;display:flex;gap:14px;align-items:flex-start;flex-wrap:wrap">';
h+='<div style=text-align:center;flex-shrink:0>';
h+='<img id=wechat-qr-img src="https://api.qrserver.com/v1/create-qr-code/?size=200x200&data='+encodeURIComponent(s.qr_url||'')+'" style="border:2px solid var(--yellow);border-radius:6px">';
h+='<div id=wechat-qr-status style="margin-top:6px;font-size:14px;color:var(--dim)">';
h+='<span id=wechat-qr-age>\u4e8c\u7ef4\u7801\u7ea65\u5206\u949f\u6709\u6548</span></div>';
h+='<button id=wechat-qr-refresh class="btn r" style="margin-top:4px;font-size:14px;padding:3px 10px" onclick="refreshWechatQR()">\u5237\u65b0\u4e8c\u7ef4\u7801</button></div>';
h+='<div style=flex:1;min-width:160px;font-size:14px;color:var(--dim)>';
h+='<p style="margin:0 0 4px;color:var(--yellow);font-weight:600">\u83ab\u8377\u5fae\u4fe1\u9700\u8981\u626b\u7801\u767b\u5f55</p>';
h+='<p style=margin:0;line-height:1.5>'+esc(s.message||'')+'\u3002\u7528\u5fae\u4fe1\u626b\u63cf\u5de6\u4fa7\u4e8c\u7ef4\u7801\u91cd\u65b0\u767b\u5f55\u3002</p>';
h+='<p style=margin-top:4px>\u94fe\u63a5: <code style=word-break:break-all;font-size:13px>'+esc(s.qr_url||'')+'</code></p>';
h+='</div></div>';
setTimeout(function(){
var el=document.getElementById('wechat-qr-age');
if(el)el.innerHTML='<span style=color:var(--red)>\u4e8c\u7ef4\u7801\u5df2\u8fc7\u671f</span>';
var btn=document.getElementById('wechat-qr-refresh');
if(btn)btn.textContent='\u5df2\u8fc7\u671f\uff0c\u70b9\u51fb\u5237\u65b0';
},300000);
}
}
try{var r2=await fetch('/api/ejabberd'),ej=await r2.json();var ejA=ej.alive||ej.xmpp_bot_connected;
h+='<div class="i"><span class="d '+(ejA?'ok':'stopped')+'"></span><span class="sn">Ejabberd XMPP</span><span class="help-btn" onclick="showModuleHelp(\'ejabberd\',\'human\')" title="使用说明">?</span><span class="help-btn ai" onclick="showModuleHelp(\'ejabberd\',\'ai\')" title="AI Spec">§</span></div>';
}catch(ejErr){}