feat: 工具Tab新增STF设备管理(读写220脚本DEVICES列表+docker adb connect/disconnect,220侧timeout兜底防卡死)+ 修复设备列表:5555重复显示
This commit is contained in:
+55
-1
@@ -288,7 +288,7 @@ function showTab(name){
|
||||
// 按需加载数据
|
||||
if(name==='monitor'){loadMonitor();_monitorTimer=setInterval(loadMonitor,5000);}
|
||||
if(name==='tasks'){showSubTab('tasks',_activeSubs.tasks);loadTasks();loadCustomActions();}
|
||||
if(name==='tools'){showSubTab('tools',_activeSubs.tools);loadToolsDevices();loadAdbDevices();loadTailscaleDevices();loadApks();}
|
||||
if(name==='tools'){showSubTab('tools',_activeSubs.tools);loadToolsDevices();loadAdbDevices();loadTailscaleDevices();loadApks();loadStfDevMgmt();}
|
||||
if(name==='groups')loadGroups();
|
||||
if(name==='logs'){loadLogs();if(document.getElementById('log-auto').checked)_logTimer=setInterval(loadLogs,3000);}
|
||||
if(name==='users')loadUsers();
|
||||
@@ -350,6 +350,60 @@ function toggleClipDevice(cb){
|
||||
else _clipSelected.delete(cb.value);
|
||||
}
|
||||
|
||||
// ================== 工具:STF 设备管理 ==================
|
||||
async function loadStfDevMgmt(){
|
||||
const status = document.getElementById('stfdev-status');
|
||||
const r = await apiGet('/api/stf/devmgmt/status');
|
||||
if(!r || !r.ok){status.textContent='加载失败';showToast('加载失败: '+(r&&r.error||''),'error');return;}
|
||||
const configured = r.configured || []; // 脚本 DEVICES 里的 IP(裸 IP)
|
||||
const connected = {}; // 裸 IP -> state(220 adb devices 的 serial 带 :5555,归一化)
|
||||
(r.connected || []).forEach(d=>{
|
||||
const s = d.serial;
|
||||
connected[s.endsWith(':5555') ? s.slice(0,-5) : s] = d.state;
|
||||
});
|
||||
const ips = Array.from(new Set(configured.concat(Object.keys(connected))));
|
||||
const tbody = document.getElementById('tb-stfdev');
|
||||
if(!ips.length){
|
||||
tbody.innerHTML='<tr><td colspan="4" class="empty">无设备(脚本未配置、220 adb 也无连接)</td></tr>';
|
||||
status.textContent='';
|
||||
return;
|
||||
}
|
||||
tbody.innerHTML = ips.map(ip=>{
|
||||
const inCfg = configured.includes(ip);
|
||||
const st = connected[ip];
|
||||
const stHtml = st==='device'
|
||||
? '<span class="label label-success">已连接</span>'
|
||||
: (st ? '<span class="label label-warning">'+esc(st)+'</span>' : '<span class="label label-default">未连接</span>');
|
||||
return '<tr><td style="font-family:monospace">'+esc(ip)+'</td>'+
|
||||
'<td>'+(inCfg?'<span class="label label-info">脚本中</span>':'<span class="label label-default">未配置</span>')+'</td>'+
|
||||
'<td>'+stHtml+'</td>'+
|
||||
'<td><button class="btn btn-xs btn-danger" onclick="removeStfDev(\''+esc(ip)+'\')">移除(断开+删脚本)</button></td></tr>';
|
||||
}).join('');
|
||||
status.textContent = '脚本配置 '+configured.length+' 台,已连接 '+Object.keys(connected).length+' 台';
|
||||
}
|
||||
|
||||
async function addStfDev(){
|
||||
const ip = document.getElementById('stfdev-ip').value.trim();
|
||||
if(!ip){showToast('请输入设备 IP','error');return;}
|
||||
const r = await apiPost('/api/stf/devmgmt/add', {ip:ip});
|
||||
if(!r)return;
|
||||
if(r.ok){
|
||||
showToast((r.msgs||[]).join(';'),'success');
|
||||
document.getElementById('stfdev-ip').value='';
|
||||
loadStfDevMgmt();
|
||||
}else showToast('添加失败: '+(r.error||''),'error');
|
||||
}
|
||||
|
||||
async function removeStfDev(ip){
|
||||
if(!confirm('确定移除 '+ip+'?\n\n将从 connect_devices.sh 删除并断开 220 的 adb 连接,\n设备会从 OpenSTF 设备池下线(任务不再分配到它)。'))return;
|
||||
const r = await apiPost('/api/stf/devmgmt/remove', {ip:ip});
|
||||
if(!r)return;
|
||||
if(r.ok){
|
||||
showToast((r.msgs||[]).join(';'),'success');
|
||||
loadStfDevMgmt();
|
||||
}else showToast('移除失败: '+(r.error||''),'error');
|
||||
}
|
||||
|
||||
async function injectClipboard(){
|
||||
const text = document.getElementById('clip-text').value.trim();
|
||||
if(!text){showToast('请输入要注入的文字','error');return;}
|
||||
|
||||
Reference in New Issue
Block a user