feat: 设备池管理面板(新增/停用/删除/一键重连,调度数据源规范化入口)+ STF 设备管理增删桥接同步设备池(迁移期)
This commit is contained in:
@@ -111,6 +111,7 @@ function showSubTab(tabId, name){
|
||||
tab.querySelectorAll('.sub-tab').forEach(b=>b.classList.toggle('active', b.dataset.sub===name));
|
||||
tab.querySelectorAll('.sub-panel').forEach(p=>p.classList.toggle('active', p.id===tabId+'-sub-'+name));
|
||||
if(name==='screen' && typeof loadScreenDevices==='function') loadScreenDevices();
|
||||
if(name==='devpool' && typeof loadDevPool==='function') loadDevPool();
|
||||
}
|
||||
|
||||
// ================== 模态框 ==================
|
||||
|
||||
@@ -546,3 +546,71 @@ function screenSendText(){
|
||||
onUp({clientX:t.clientX,clientY:t.clientY,preventDefault(){}});
|
||||
},{passive:false});
|
||||
})();
|
||||
|
||||
// ================== Tab: 工具 - 设备池管理(本地 SQLite 清单) ==================
|
||||
async function loadDevPool(){
|
||||
const tb=document.getElementById('tb-devpool');
|
||||
const status=document.getElementById('devpool-status');
|
||||
if(!tb)return;
|
||||
tb.innerHTML='<tr><td colspan="6" class="empty">加载中...</td></tr>';
|
||||
const r=await apiGet('/api/devices/pool');
|
||||
if(!r||!r.ok){tb.innerHTML='<tr><td colspan="6" class="empty">加载失败</td></tr>';return;}
|
||||
const rows=r.devices||[];
|
||||
const onlineCnt=rows.filter(x=>x.online).length;
|
||||
status.textContent='共 '+rows.length+' 台,在线 '+onlineCnt+' 台';
|
||||
tb.innerHTML=rows.map(d=>{
|
||||
const st= d.enabled
|
||||
? '<span class="label label-success">启用</span>'
|
||||
: '<span class="label label-default">停用</span>';
|
||||
const online= d.online
|
||||
? '<span class="label label-success">在线</span>'
|
||||
: '<span class="label label-warning">离线</span>';
|
||||
return '<tr>'+
|
||||
'<td style="font-family:monospace">'+esc(d.serial)+'</td>'+
|
||||
'<td>'+esc(d.name||'')+'</td>'+
|
||||
'<td>'+online+'</td>'+
|
||||
'<td>'+st+'</td>'+
|
||||
'<td style="color:var(--text-light)">'+esc(d.created_at||'')+'</td>'+
|
||||
'<td style="white-space:nowrap">'+
|
||||
'<button class="btn btn-xs" onclick="togglePoolDev(\''+esc(d.serial)+'\','+(!d.enabled)+')">'+(d.enabled?'停用':'启用')+'</button> '+
|
||||
'<button class="btn btn-xs btn-danger" onclick="removePoolDev(\''+esc(d.serial)+'\')">删除</button>'+
|
||||
'</td></tr>';
|
||||
}).join('')||'<tr><td colspan="6" class="empty">设备池为空,添加第一台设备开始</td></tr>';
|
||||
}
|
||||
|
||||
async function addPoolDev(){
|
||||
const serial=document.getElementById('devpool-serial').value.trim();
|
||||
const name=document.getElementById('devpool-name').value.trim();
|
||||
if(!serial){showToast('请输入 serial','error');return;}
|
||||
const r=await apiPost('/api/devices/pool/add',{serial,name});
|
||||
if(!r)return;
|
||||
if(r.ok){
|
||||
showToast(r.msg+(serial.includes(':')?'(已尝试连接)':''),'success');
|
||||
document.getElementById('devpool-serial').value='';
|
||||
document.getElementById('devpool-name').value='';
|
||||
loadDevPool();
|
||||
}else showToast(r.error,'error');
|
||||
}
|
||||
|
||||
async function removePoolDev(serial){
|
||||
if(!confirm('从设备池删除 '+serial+'?\n\n删除后不再参与任务调度(不影响设备本身与其他功能)。'))return;
|
||||
const r=await apiPost('/api/devices/pool/remove',{serial});
|
||||
if(!r)return;
|
||||
if(r.ok){showToast(r.msg,'success');loadDevPool();}
|
||||
else showToast(r.error,'error');
|
||||
}
|
||||
|
||||
async function togglePoolDev(serial,enabled){
|
||||
const r=await apiPost('/api/devices/pool/toggle',{serial,enabled});
|
||||
if(!r)return;
|
||||
if(r.ok){showToast(r.msg,'success');loadDevPool();}
|
||||
else showToast(r.error,'error');
|
||||
}
|
||||
|
||||
async function reconnectPoolDevices(){
|
||||
if(!confirm('并发 adb connect 设备池内全部设备?\n\n已连接的自动跳过。'))return;
|
||||
const r=await apiPost('/api/devices/pool/reconnect',{});
|
||||
if(!r)return;
|
||||
if(r.ok){showToast(r.msg,'success');setTimeout(loadDevPool,12000);}
|
||||
else showToast(r.error,'error');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user