feat: 维护 Tab(STF 容器一键重启 + adb 远程终端,含设备快捷选择/卸载 agent/重连)
This commit is contained in:
+85
-1
@@ -258,7 +258,7 @@ function showTab(name){
|
||||
document.querySelectorAll('.tab-panel').forEach(p=>p.classList.remove('active'));
|
||||
document.querySelectorAll('.navbar .tab').forEach(t=>t.classList.remove('active'));
|
||||
document.getElementById('tab-'+name).classList.add('active');
|
||||
document.querySelectorAll('.navbar .tab')[['monitor','tasks','apps','groups','logs','users'].indexOf(name)].classList.add('active');
|
||||
document.querySelectorAll('.navbar .tab')[['monitor','tasks','apps','groups','logs','users','maintenance'].indexOf(name)].classList.add('active');
|
||||
// 停止所有定时器
|
||||
if(_monitorTimer){clearInterval(_monitorTimer);_monitorTimer=null;}
|
||||
if(_logTimer){clearInterval(_logTimer);_logTimer=null;}
|
||||
@@ -266,6 +266,7 @@ function showTab(name){
|
||||
if(name==='monitor'){loadMonitor();_monitorTimer=setInterval(loadMonitor,5000);}
|
||||
if(name==='tasks'){loadTasks();loadCustomActions();}
|
||||
if(name==='apps')loadApks();
|
||||
if(name==='maintenance')loadAdbDevices();
|
||||
if(name==='groups')loadGroups();
|
||||
if(name==='logs'){loadLogs();if(document.getElementById('log-auto').checked)_logTimer=setInterval(loadLogs,3000);}
|
||||
if(name==='users')loadUsers();
|
||||
@@ -1927,6 +1928,89 @@ async function deleteUser(uid){
|
||||
handleResult(r,()=>loadUsers());
|
||||
}
|
||||
|
||||
// ================== Tab: 维护(仅管理员) ==================
|
||||
// 服务器类命令(不需要 -s 目标设备)
|
||||
const _NO_DEVICE_CMDS=['devices','version','help','start-server','connect','kill-server','disconnect'];
|
||||
function _selectedSerial(){
|
||||
const sel=document.getElementById('adb-device');
|
||||
return sel?sel.value:'';
|
||||
}
|
||||
// 选中目标设备时自动附加 -s <serial>;服务器类命令保持原样
|
||||
function _attachDevice(cmd){
|
||||
const serial=_selectedSerial();
|
||||
if(!serial)return cmd;
|
||||
if(/^-s\s/.test(cmd))return cmd; // 已手写 -s 不再重复附加
|
||||
const first=(cmd.split(/\s+/)[0]||'').toLowerCase();
|
||||
if(_NO_DEVICE_CMDS.indexOf(first)>=0)return cmd;
|
||||
return '-s '+serial+' '+cmd;
|
||||
}
|
||||
async function loadAdbDevices(){
|
||||
const sel=document.getElementById('adb-device');
|
||||
if(!sel)return;
|
||||
const r=await apiGet('/api/adb/devices');
|
||||
if(!r||!r.ok)return;
|
||||
const cur=sel.value;
|
||||
const stateTxt={device:'在线',offline:'离线',stf:'STF池(未连接)'};
|
||||
const opts=['<option value="">(不指定设备)</option>'].concat(
|
||||
(r.devices||[]).map(d=>
|
||||
'<option value="'+esc(d.serial)+'">'+esc(d.serial)+' ('+(stateTxt[d.state]||d.state)+')</option>'
|
||||
)
|
||||
);
|
||||
sel.innerHTML=opts.join('');
|
||||
if(cur)sel.value=cur;
|
||||
}
|
||||
function fillAdbCmd(cmd){
|
||||
document.getElementById('adb-cmd-input').value=cmd;
|
||||
}
|
||||
async function _runAdbFull(full){
|
||||
const out=document.getElementById('adb-output');
|
||||
out.textContent='$ '+full+'\n执行中...';
|
||||
const r=await apiPost('/api/adb/cmd',{cmd:full});
|
||||
if(!r)return;
|
||||
if(!r.ok){out.textContent='$ '+full+'\n⚠ '+r.error;return;}
|
||||
out.textContent='$ '+full+'\n\n'+(r.stdout||'')+(r.stderr?'\n[stderr] '+r.stderr:'')+'\n\n[exit '+r.code+']';
|
||||
out.scrollTop=out.scrollHeight;
|
||||
}
|
||||
async function runAdbCmd(){
|
||||
const input=document.getElementById('adb-cmd-input');
|
||||
let cmd=(input.value||'').trim();
|
||||
if(!cmd){showToast('请输入 adb 命令','error');return;}
|
||||
cmd=cmd.replace(/^adb\s+/i,''); // 兼容手输/快捷按钮带的 "adb " 前缀,避免拼成 "adb adb devices"
|
||||
cmd=_attachDevice(cmd);
|
||||
await _runAdbFull('adb '+cmd);
|
||||
}
|
||||
function uninstallStfAgent(){
|
||||
const serial=_selectedSerial();
|
||||
if(!serial){showToast('请先选择目标设备','error');return;}
|
||||
if(!confirm('确定卸载 '+serial+' 上的 STF agent(jp.co.cyberagent.stf)?\n\n卸载后 STF 会在设备重连时自动重新推送安装。'))return;
|
||||
_runAdbFull('adb -s '+serial+' uninstall jp.co.cyberagent.stf');
|
||||
}
|
||||
function reconnectAdbDevice(){
|
||||
const serial=_selectedSerial();
|
||||
if(!serial){showToast('请先选择目标设备','error');return;}
|
||||
_runAdbFull('adb connect '+serial);
|
||||
}
|
||||
function checkStfAgent(){
|
||||
const serial=_selectedSerial();
|
||||
if(!serial){showToast('请先选择目标设备','error');return;}
|
||||
_runAdbFull('adb -s '+serial+' shell pm list packages | grep cyberagent');
|
||||
}
|
||||
async function restartStf(){
|
||||
if(!confirm('确定重启 STF 容器?\n\n影响:STF 约 30 秒不可用,期间所有设备占用状态重置,正在执行的任务会受影响。\n\n确认继续吗?'))return;
|
||||
const st=document.getElementById('stf-restart-status');
|
||||
st.textContent='正在重启 STF 容器(SSH 执行中,最长 60s)...';
|
||||
const r=await apiPost('/api/stf/restart',{});
|
||||
if(!r)return;
|
||||
if(r.ok){st.textContent='✅ '+r.msg+(r.detail?' ['+r.detail+']':'');showToast(r.msg,'success');}
|
||||
else{st.textContent='❌ '+r.error;showToast(r.error,'error');}
|
||||
}
|
||||
|
||||
// 测试此步骤弹窗关闭
|
||||
function closeTestModal(){
|
||||
const ov=document.getElementById('test-overlay');
|
||||
if(ov)ov.classList.remove('show');
|
||||
}
|
||||
|
||||
// ================== Tab: 应用 ==================
|
||||
let _apksCache=[];
|
||||
let _installTimer=null;
|
||||
|
||||
Reference in New Issue
Block a user