feat: WeChat QR get button — trigger container /api/bot/login (DISABLE_AUTO_LOGIN) via POST /api/wechat/trigger-login; show QR block when logged_out even without qr_url
This commit is contained in:
@@ -1997,6 +1997,28 @@ def api_wechat_status():
|
|||||||
|
|
||||||
return jsonify(result)
|
return jsonify(result)
|
||||||
|
|
||||||
|
@app.route("/api/wechat/trigger-login", methods=["POST"])
|
||||||
|
def api_wechat_trigger_login():
|
||||||
|
"""触发微信 bot 登录(获取二维码)——容器 DISABLE_AUTO_LOGIN=true 时需主动 POST /api/bot/login。
|
||||||
|
|
||||||
|
返回 {ok, login_url} 或 {ok: false, error}。前端拿到 login_url 后轮询 /api/wechat/status 拿 qr_url。
|
||||||
|
"""
|
||||||
|
import urllib.request as _ur
|
||||||
|
try:
|
||||||
|
req = _ur.Request(
|
||||||
|
"http://127.0.0.1:3001/api/bot/login",
|
||||||
|
data=b"",
|
||||||
|
headers={"Content-Type": "application/json"},
|
||||||
|
method="POST",
|
||||||
|
)
|
||||||
|
with _ur.urlopen(req, timeout=10) as resp:
|
||||||
|
data = json.loads(resp.read().decode("utf-8", errors="replace"))
|
||||||
|
if data.get("success"):
|
||||||
|
return jsonify({"ok": True, "login_url": data.get("loginUrl", "/login")})
|
||||||
|
return jsonify({"ok": False, "error": data.get("error", "unknown")})
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"ok": False, "error": str(e)})
|
||||||
|
|
||||||
@app.route("/api/platform")
|
@app.route("/api/platform")
|
||||||
@app.route("/api/health")
|
@app.route("/api/health")
|
||||||
def api_health():
|
def api_health():
|
||||||
|
|||||||
@@ -323,24 +323,35 @@ async function fI(){
|
|||||||
if(s.status==='running'){dc='ok';dt=s.message?' <span style=color:var(--green)>'+esc(s.message)+'</span>':'';}
|
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>';}
|
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>';
|
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){
|
if(s.id==='wechat_bridge'&&s.status==='logged_out'){
|
||||||
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="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>';
|
if(s.qr_url){
|
||||||
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 style=text-align:center;flex-shrink:0>';
|
||||||
h+='<div id=wechat-qr-status style="margin-top:6px;font-size:14px;color:var(--dim)">';
|
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+='<span id=wechat-qr-age>\u4e8c\u7ef4\u7801\u7ea65\u5206\u949f\u6709\u6548</span></div>';
|
h+='<div id=wechat-qr-status style="margin-top:6px;font-size:14px;color:var(--dim)">';
|
||||||
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+='<span id=wechat-qr-age>\u4e8c\u7ef4\u7801\u7ea65\u5206\u949f\u6709\u6548</span></div>';
|
||||||
h+='<div style=flex:1;min-width:160px;font-size:14px;color:var(--dim)>';
|
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+='<p style="margin:0 0 4px;color:var(--yellow);font-weight:600">\u83ab\u8377\u5fae\u4fe1\u9700\u8981\u626b\u7801\u767b\u5f55</p>';
|
h+='<div style=flex:1;min-width:160px;font-size:14px;color:var(--dim)>';
|
||||||
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:0 0 4px;color:var(--yellow);font-weight:600">\u83ab\u8377\u5fae\u4fe1\u9700\u8981\u626b\u7801\u767b\u5f55</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+='<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+='</div></div>';
|
h+='<p style=margin-top:4px>\u94fe\u63a5: <code style=word-break:break-all;font-size:13px>'+esc(s.qr_url||'')+'</code></p>';
|
||||||
setTimeout(function(){
|
h+='</div>';
|
||||||
var el=document.getElementById('wechat-qr-age');
|
setTimeout(function(){
|
||||||
if(el)el.innerHTML='<span style=color:var(--red)>\u4e8c\u7ef4\u7801\u5df2\u8fc7\u671f</span>';
|
var el=document.getElementById('wechat-qr-age');
|
||||||
var btn=document.getElementById('wechat-qr-refresh');
|
if(el)el.innerHTML='<span style=color:var(--red)>\u4e8c\u7ef4\u7801\u5df2\u8fc7\u671f</span>';
|
||||||
if(btn)btn.textContent='\u5df2\u8fc7\u671f\uff0c\u70b9\u51fb\u5237\u65b0';
|
var btn=document.getElementById('wechat-qr-refresh');
|
||||||
},300000);
|
if(btn)btn.textContent='\u5df2\u8fc7\u671f\uff0c\u70b9\u51fb\u5237\u65b0';
|
||||||
|
},300000);
|
||||||
|
}else{
|
||||||
|
h+='<div style=text-align:center;flex-shrink:0>';
|
||||||
|
h+='<button id=wechat-qr-get class="btn s" style="font-size:14px;padding:8px 18px" onclick="getWechatQR()">\u83b7\u53d6\u767b\u5f55\u4e8c\u7ef4\u7801</button>';
|
||||||
|
h+='<div id=wechat-qr-get-status style="margin-top:6px;font-size:13px;color:var(--dim)">\u70b9\u51fb\u83b7\u53d6\u65b0\u7684\u767b\u5f55\u4e8c\u7ef4\u7801</div></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\u5df2\u6389\u7ebf</p>';
|
||||||
|
h+='<p style=margin:0;line-height:1.5>'+esc(s.message||'')+'\u3002\u70b9\u51fb\u5de6\u4fa7\u6309\u94ae\u89e6\u53d1\u767b\u5f55\uff0c\u751f\u6210\u4e8c\u7ef4\u7801\u540e\u7528\u5fae\u4fe1\u626b\u7801\u3002</p>';
|
||||||
|
h+='</div>';
|
||||||
|
}
|
||||||
|
h+='</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try{var r2=await fetch('/api/ejabberd'),ej=await r2.json();var ejA=ej.alive||ej.xmpp_bot_connected;
|
try{var r2=await fetch('/api/ejabberd'),ej=await r2.json();var ejA=ej.alive||ej.xmpp_bot_connected;
|
||||||
@@ -632,4 +643,42 @@ h+='<p style="line-height:1.7;margin:6px 0">'+inMd(block)+'</p>';}
|
|||||||
return h;
|
return h;
|
||||||
function inMd(t){return t.replace(/\*\*([^*]+)\*\*/g,'<strong>$1</strong>').replace(/\*([^*]+)\*/g,'<em>$1</em>').replace(/`([^`]+)`/g,'<code style="background:var(--bg);padding:1px 4px;border-radius:3px;font-size:0.9em">$1</code>').replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2" style="color:var(--accent)" target=_blank>$1</a>')}}
|
function inMd(t){return t.replace(/\*\*([^*]+)\*\*/g,'<strong>$1</strong>').replace(/\*([^*]+)\*/g,'<em>$1</em>').replace(/`([^`]+)`/g,'<code style="background:var(--bg);padding:1px 4px;border-radius:3px;font-size:0.9em">$1</code>').replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2" style="color:var(--accent)" target=_blank>$1</a>')}}
|
||||||
init();loadAll();setInterval(loadAll,10000);setInterval(fK,15000);
|
init();loadAll();setInterval(loadAll,10000);setInterval(fK,15000);
|
||||||
|
|
||||||
|
/* --- WeChat QR: 获取二维码(触发容器 /api/bot/login) + 刷新 --- */
|
||||||
|
async function getWechatQR(){
|
||||||
|
var st=document.getElementById('wechat-qr-get-status');
|
||||||
|
var btn=document.getElementById('wechat-qr-get');
|
||||||
|
if(st)st.innerHTML='<span style=color:var(--yellow)>\u6b63\u5728\u83b7\u53d6\u4e8c\u7ef4\u7801...</span>';
|
||||||
|
if(btn)btn.disabled=true;
|
||||||
|
try{
|
||||||
|
var r=await fetch('/api/wechat/trigger-login',{method:'POST'});
|
||||||
|
var d=await r.json();
|
||||||
|
if(d.ok){
|
||||||
|
if(st)st.innerHTML='<span style=color:var(--green)>\u5df2\u89e6\u53d1\uff0c\u6b63\u5728\u751f\u6210\u4e8c\u7ef4\u7801...</span>';
|
||||||
|
// 触发后轮询 status 拿 qr_url(容器生成二维码需要几秒)
|
||||||
|
for(var i=0;i<10;i++){
|
||||||
|
await new Promise(res=>setTimeout(res,2000));
|
||||||
|
try{
|
||||||
|
var rs=await fetch('/api/wechat/status'),sd=await rs.json();
|
||||||
|
if(sd.qr_url){location.reload();return;}
|
||||||
|
}catch(e){}
|
||||||
|
}
|
||||||
|
if(st)st.innerHTML='<span style=color:var(--red)>\u4e8c\u7ef4\u7801\u672a\u751f\u6210\uff0c\u8bf7\u91cd\u8bd5</span>';
|
||||||
|
if(btn)btn.disabled=false;
|
||||||
|
}else{
|
||||||
|
if(st)st.innerHTML='<span style=color:var(--red)>\u83b7\u53d6\u5931\u8d25: '+esc(d.error||'')+'</span>';
|
||||||
|
if(btn)btn.disabled=false;
|
||||||
|
}
|
||||||
|
}catch(e){
|
||||||
|
if(st)st.innerHTML='<span style=color:var(--red)>\u83b7\u53d6\u5931\u8d25: '+esc(e.message||'')+'</span>';
|
||||||
|
if(btn)btn.disabled=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function refreshWechatQR(){
|
||||||
|
try{
|
||||||
|
await fetch('/api/wechat/trigger-login',{method:'POST'});
|
||||||
|
// 刷新后等几秒重新拉状态
|
||||||
|
setTimeout(function(){location.reload();},3000);
|
||||||
|
}catch(e){}
|
||||||
|
}
|
||||||
</script></body></html>
|
</script></body></html>
|
||||||
Reference in New Issue
Block a user