phase-b: add node uuid/alias/ip metadata APIs and node list enrichment

This commit is contained in:
2026-03-03 20:29:44 +08:00
parent 3b555df56c
commit 065f9ba5b6
5 changed files with 270 additions and 12 deletions

View File

@@ -86,25 +86,32 @@
<div class="overflow-auto">
<table class="w-full text-sm min-w-[900px]">
<thead class="text-slate-400"><tr>
<th class="p-3 text-left">节点</th><th class="p-3 text-left">公网</th><th class="p-3 text-left">NAT</th><th class="p-3 text-left">租户</th><th class="p-3 text-left">版本</th><th class="p-3 text-left">在线时长</th><th class="p-3 text-left">动作</th>
<th class="p-3 text-left">节点</th><th class="p-3 text-left">唯一ID</th><th class="p-3 text-left">虚拟IP</th><th class="p-3 text-left">公网</th><th class="p-3 text-left">NAT</th><th class="p-3 text-left">租户</th><th class="p-3 text-left">版本</th><th class="p-3 text-left">在线时长</th><th class="p-3 text-left">动作</th>
</tr></thead>
<tbody>
<tr v-for="n in filteredNodes" :key="n.name" class="border-t border-white/5">
<td class="p-3">{{ n.name }}</td>
<tr v-for="n in filteredNodes" :key="n.nodeUUID || n.name" class="border-t border-white/5">
<td class="p-3">
<div class="font-semibold">{{ n.alias || n.name }}</div>
<div class="text-xs text-slate-500">hostname: {{ n.name }}</div>
</td>
<td class="p-3 text-xs text-slate-400">{{ n.nodeUUID || '-' }}</td>
<td class="p-3">{{ n.virtualIP || '-' }}</td>
<td class="p-3">{{ n.publicIP }}:{{ n.publicPort }}</td>
<td class="p-3">{{ natText(n.natType) }}</td>
<td class="p-3">{{ n.tenantId || 0 }}</td>
<td class="p-3">{{ n.version || '-' }}</td>
<td class="p-3">{{ uptime(n.loginTime) }}</td>
<td class="p-3">
<div class="flex gap-2">
<div class="flex gap-2 flex-wrap">
<button class="btn2" @click="renameNode(n)">改昵称</button>
<button class="btn2" @click="changeNodeIP(n)">改IP</button>
<button class="btn2" @click="openConnect(n.name)">发起连接</button>
<button class="btn2" @click="openAppManager(n.name)">推配置</button>
<button class="btn2" @click="kickNode(n.name)">踢下线</button>
</div>
</td>
</tr>
<tr v-if="!filteredNodes.length"><td class="p-6 text-center text-slate-500" colspan="7">暂无节点</td></tr>
<tr v-if="!filteredNodes.length"><td class="p-6 text-center text-slate-500" colspan="9">暂无节点</td></tr>
</tbody>
</table>
</div>
@@ -407,6 +414,28 @@ createApp({
catch(e){ toast(e.message, 'error'); }
};
const renameNode = async (node) => {
if (!node.nodeUUID) return toast('该节点尚无UUID稍后重连后再试', 'error');
const nextAlias = prompt('输入新昵称(留空则清除)', node.alias || '');
if (nextAlias === null) return;
try {
await api('/api/v1/nodes/alias', { method:'POST', body: JSON.stringify({ node_uuid: node.nodeUUID, alias: nextAlias }) });
toast('昵称已更新');
refreshAll();
} catch(e){ toast(e.message, 'error'); }
};
const changeNodeIP = async (node) => {
if (!node.nodeUUID) return toast('该节点尚无UUID稍后重连后再试', 'error');
const nextIP = prompt('输入新的虚拟IP必须在本网络CIDR内', node.virtualIP || '');
if (!nextIP) return;
try {
await api('/api/v1/nodes/ip', { method:'POST', body: JSON.stringify({ node_uuid: node.nodeUUID, virtual_ip: nextIP }) });
toast('IP已更新节点将按新IP重连');
refreshAll();
} catch(e){ toast(e.message, 'error'); }
};
const appPushNode = ref('');
const appPushRaw = ref('[{"appName":"demo","protocol":"tcp","srcPort":8080,"peerNode":"","dstHost":"127.0.0.1","dstPort":80,"enabled":1}]');
const openAppManager = (node) => { appPushNode.value = node; toast(`已选中 ${node},请在控制台执行推配置`); tab.value = 'p2p'; };
@@ -546,7 +575,7 @@ createApp({
tenants, activeTenant, keys, users, enrolls, tenantForm, keyForm, userForm,
natText, uptime, fmtTime,
login, logout, refreshAll, saveSDWAN, addSDWANNode, removeSDWANNode, autoAssignIPs,
kickNode, openAppManager, pushAppConfigs, openConnect, doConnect,
kickNode, renameNode, changeNodeIP, openAppManager, pushAppConfigs, openConnect, doConnect,
createTenant, loadTenants, setTenantStatus,
createKey, loadKeys, setKeyStatus,
createUser, loadUsers, setUserStatus, resetUserPassword, deleteUser,