fix: Tailscale 设备表接入统一分页/搜索逻辑(setListPager),修正 IP 可修改的过时提示文案

This commit is contained in:
2026-08-11 09:19:41 +08:00
parent de66c6194b
commit 6051c5c2fd
2 changed files with 34 additions and 22 deletions
+31 -21
View File
@@ -2268,6 +2268,8 @@ function closeTestModal(){
} }
// ================== Tab: 维护 - Tailscale 管理 ================== // ================== Tab: 维护 - Tailscale 管理 ==================
// 与其他表格共用 setListPager/applyListPager 统一逻辑(搜索 + 分页)
let _tsDevices=[];
async function loadTailscaleDevices(){ async function loadTailscaleDevices(){
const tb=document.getElementById('tb-tailscale'); const tb=document.getElementById('tb-tailscale');
const st=document.getElementById('ts-status'); const st=document.getElementById('ts-status');
@@ -2284,27 +2286,35 @@ async function loadTailscaleDevices(){
return; return;
} }
if(hint)hint.textContent=''; if(hint)hint.textContent='';
const devs=r.devices||[]; _tsDevices=r.devices||[];
if(!devs.length){tb.innerHTML='<tr><td colspan="8" class="empty">tailnet 暂无设备</td></tr>';if(st)st.textContent='';return;} setListPager('tailscale',{
tb.innerHTML=devs.map(d=>{ data:()=>_tsDevices,
const ip=(d.addresses||[])[0]||'-'; filter:(d,kw)=>((d.hostname||'').toLowerCase().includes(kw)||(d.name||'').toLowerCase().includes(kw)||(d.addresses||[]).join(',').includes(kw)),
return '<tr>'+ render:renderTsRow,
'<td><code>'+esc(d.hostname||'-')+'</code></td>'+ tbody:'tb-tailscale',pager:'pager-tailscale',pageSize:10,
'<td>'+esc(d.name||'-')+'</td>'+ empty:'<tr><td colspan="8" class="empty">tailnet 暂无设备</td></tr>'
'<td style="font-family:monospace">'+esc(ip)+'</td>'+ });
'<td>'+esc(d.os||'-')+'</td>'+ applyListPager('tailscale');
'<td>'+((d.online===true)?'<span class="label label-success">在线</span>':(d.online===false?'<span class="label label-default">离线</span>':'<span class="label label-warning" title="12 小时内见过但当前未上报">最近在线</span>'))+'</td>'+ initListSearch('tailscale','search-tailscale');
'<td>'+(d.authorized?'<span class="label label-success">已授权</span>':'<span class="label label-danger">未授权</span>')+'</td>'+ if(st)st.textContent='共 '+_tsDevices.length+' 台设备';
'<td>'+(d.key_expiry_disabled?'<span class="label label-warning">永不过期</span>':'<span class="label label-default">会过期</span>')+'</td>'+ }
'<td style="white-space:nowrap">'+ function renderTsRow(d){
'<button class="btn btn-xs" onclick="renameTailscaleDevice(\''+esc(d.id)+'\',\''+esc(d.name||'')+'\')">改名</button> '+ const ip=(d.addresses||[])[0]||'-';
'<button class="btn btn-xs" onclick="setTsIp(\''+esc(d.id)+'\',\''+esc((d.addresses||[])[0]||'')+'\')" title="修改设备的 Tailscale IPv4(会断开当前连接,平台 serial 随之变化)">设置IP</button> '+ return '<tr>'+
'<button class="btn btn-xs" onclick="toggleTsAuth(\''+esc(d.id)+'\','+(!d.authorized)+')">'+(d.authorized?'取消授权':'授权')+'</button> '+ '<td><code>'+esc(d.hostname||'-')+'</code></td>'+
'<button class="btn btn-xs" onclick="toggleTsKeyExpiry(\''+esc(d.id)+'\','+(!d.key_expiry_disabled)+')">'+(d.key_expiry_disabled?'恢复过期':'密钥不过期')+'</button> '+ '<td>'+esc(d.name||'-')+'</td>'+
'<button class="btn btn-danger btn-xs" onclick="deleteTailscaleDevice(\''+esc(d.id)+'\')">移除</button>'+ '<td style="font-family:monospace">'+esc(ip)+'</td>'+
'</td></tr>'; '<td>'+esc(d.os||'-')+'</td>'+
}).join(''); '<td>'+((d.online===true)?'<span class="label label-success">在线</span>':(d.online===false?'<span class="label label-default">离线</span>':'<span class="label label-warning" title="12 小时内见过但当前未上报">最近在线</span>'))+'</td>'+
if(st)st.textContent='共 '+devs.length+' 台设备'; '<td>'+(d.authorized?'<span class="label label-success">已授权</span>':'<span class="label label-danger">未授权</span>')+'</td>'+
'<td>'+(d.key_expiry_disabled?'<span class="label label-warning">永不过期</span>':'<span class="label label-default">会过期</span>')+'</td>'+
'<td style="white-space:nowrap">'+
'<button class="btn btn-xs" onclick="renameTailscaleDevice(\''+esc(d.id)+'\',\''+esc(d.name||'')+'\')">改名</button> '+
'<button class="btn btn-xs" onclick="setTsIp(\''+esc(d.id)+'\',\''+esc((d.addresses||[])[0]||'')+'\')" title="修改设备的 Tailscale IPv4(会断开当前连接,平台 serial 随之变化)">设置IP</button> '+
'<button class="btn btn-xs" onclick="toggleTsAuth(\''+esc(d.id)+'\','+(!d.authorized)+')">'+(d.authorized?'取消授权':'授权')+'</button> '+
'<button class="btn btn-xs" onclick="toggleTsKeyExpiry(\''+esc(d.id)+'\','+(!d.key_expiry_disabled)+')">'+(d.key_expiry_disabled?'恢复过期':'密钥不过期')+'</button> '+
'<button class="btn btn-danger btn-xs" onclick="deleteTailscaleDevice(\''+esc(d.id)+'\')">移除</button>'+
'</td></tr>';
} }
function renameTailscaleDevice(id, current){ function renameTailscaleDevice(id, current){
const name=prompt('修改显示名(只改名称,不影响主机名):', current||''); const name=prompt('修改显示名(只改名称,不影响主机名):', current||'');
+3 -1
View File
@@ -523,6 +523,7 @@ select.form-control{cursor:pointer}
<div class="toolbar" style="margin:8px 0"> <div class="toolbar" style="margin:8px 0">
<button class="btn btn-primary" onclick="loadTailscaleDevices()">刷新设备</button> <button class="btn btn-primary" onclick="loadTailscaleDevices()">刷新设备</button>
<button class="btn" onclick="openTailscaleAuthKey()">生成接入 Auth Key</button> <button class="btn" onclick="openTailscaleAuthKey()">生成接入 Auth Key</button>
<input class="form-control list-search" id="search-tailscale" placeholder="搜索主机名/名称/IP...">
<span id="ts-status" class="text-muted" style="margin-left:10px"></span> <span id="ts-status" class="text-muted" style="margin-left:10px"></span>
</div> </div>
<table class="table"> <table class="table">
@@ -531,7 +532,8 @@ select.form-control{cursor:pointer}
</tr></thead> </tr></thead>
<tbody id="tb-tailscale"><tr><td colspan="8" class="empty">点击"刷新设备"加载</td></tr></tbody> <tbody id="tb-tailscale"><tr><td colspan="8" class="empty">点击"刷新设备"加载</td></tr></tbody>
</table> </table>
<div class="help">设备 IP 由 tailnet 自动分配,不可修改(只读展示);"密钥不过期"= 关闭设备密钥验证,设备不会被定期踢下线;auth key 生成后只显示一次,请立即复制。</div> <div class="list-pager" id="pager-tailscale"></div>
<div class="help">"设置IP"可修改设备 IPv4(会断开当前连接,平台 serial 随之变化,需同步 STF 设备池);"密钥不过期"= 关闭设备密钥验证,设备不会被定期踢下线;auth key 生成后只显示一次,请立即复制。</div>
</div> </div>
</div><!-- /.content --> </div><!-- /.content -->