fix: multi issues - TUN read loop, SDWAN routing for TenantID=0, WS keepalive 10s
This commit is contained in:
@@ -224,6 +224,42 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===== 租户管理 ===== -->
|
||||
<div v-if="tab==='tenant'" class="fade-in space-y-6">
|
||||
<div class="glass rounded-2xl p-5">
|
||||
<div class="text-slate-300 text-sm font-bold mb-3">创建租户</div>
|
||||
<div class="flex gap-3">
|
||||
<input v-model="newTenant" placeholder="租户名称" class="ipt">
|
||||
<button @click="createTenant" class="btn-blue">创建</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="glass rounded-2xl p-5">
|
||||
<div class="text-slate-300 text-sm font-bold mb-3">生成租户 API Key</div>
|
||||
<button @click="createKey" class="btn-blue">生成 Key</button>
|
||||
<div class="mt-3 text-xs text-slate-400">Key:</div>
|
||||
<textarea v-model="tenantKey" class="ipt mt-1" rows="2" placeholder="生成后显示"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="glass rounded-2xl p-5">
|
||||
<div class="text-slate-300 text-sm font-bold mb-3">生成 Enroll Code</div>
|
||||
<div class="flex gap-3">
|
||||
<button @click="createEnroll" class="btn-blue">生成</button>
|
||||
<input v-model="enrollCode" placeholder="Enroll Code" class="ipt">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="glass rounded-2xl p-5">
|
||||
<div class="text-slate-300 text-sm font-bold mb-3">兑换 Node Secret</div>
|
||||
<div class="flex gap-3">
|
||||
<input v-model="enrollNode" placeholder="节点名" class="ipt">
|
||||
<button @click="consumeEnroll" class="btn-blue">兑换</button>
|
||||
</div>
|
||||
<div class="mt-3 text-xs text-slate-400">Node Secret:</div>
|
||||
<textarea v-model="enrollSecret" class="ipt mt-1" rows="2" placeholder="兑换后显示"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -279,8 +315,13 @@ createApp({setup(){
|
||||
const na=reactive({appName:'',srcPort:0,peerNode:'',dstPort:0});
|
||||
const addNode=ref(''),addIP=ref('');
|
||||
const p2p=reactive({from:'',to:'',name:'tunnel',srcPort:18080,dstPort:22});
|
||||
const tenants=ref([]),newTenant=ref('');
|
||||
const tenantKey=ref('');
|
||||
const enrollCode=ref('');
|
||||
const enrollNode=ref('');
|
||||
const enrollSecret=ref('');
|
||||
|
||||
const tabs=[{id:'dash',label:'仪表盘'},{id:'nodes',label:'节点管理'},{id:'sdwan',label:'SDWAN 组网'},{id:'p2p',label:'P2P 连接'}];
|
||||
const tabs=[{id:'dash',label:'仪表盘'},{id:'nodes',label:'节点管理'},{id:'sdwan',label:'SDWAN 组网'},{id:'p2p',label:'P2P 连接'},{id:'tenant',label:'租户管理'}];
|
||||
|
||||
const show=(m,c='info',d=3000)=>{toast.value=m;toastType.value=c;setTimeout(()=>toast.value='',d)};
|
||||
const log=(m,c='info')=>{logs.value.unshift({t:new Date().toLocaleTimeString(),m,c});if(logs.value.length>50)logs.value.pop()};
|
||||
@@ -313,6 +354,37 @@ createApp({setup(){
|
||||
busy.value=false
|
||||
};
|
||||
|
||||
const createTenant=async()=>{
|
||||
if(!newTenant.value)return;busy.value=true;
|
||||
const r=await api('/api/v1/admin/tenants',{method:'POST',body:JSON.stringify({name:newTenant.value})});
|
||||
busy.value=false;
|
||||
if(r){show('租户已创建','ok');log('创建租户 '+newTenant.value,'ok');newTenant.value=''}
|
||||
};
|
||||
|
||||
const createKey=async()=>{
|
||||
const id=prompt('输入 tenant_id');
|
||||
if(!id)return;busy.value=true;
|
||||
const r=await api(`/api/v1/admin/tenants/${id}/keys`,{method:'POST',body:JSON.stringify({scope:'all',ttl:0})});
|
||||
busy.value=false;
|
||||
if(r){tenantKey.value=r.api_key||'';show('API Key 已生成','ok')}
|
||||
};
|
||||
|
||||
const createEnroll=async()=>{
|
||||
if(!tenantKey.value){show('先填入租户 API Key','err');return}
|
||||
busy.value=true;
|
||||
const r=await api('/api/v1/tenants/enroll',{method:'POST',headers:{'Authorization':'Bearer '+tenantKey.value}});
|
||||
busy.value=false;
|
||||
if(r){enrollCode.value=r.enroll_code||'';show('Enroll Code 已生成','ok')}
|
||||
};
|
||||
|
||||
const consumeEnroll=async()=>{
|
||||
if(!enrollCode.value||!enrollNode.value){show('需要 enroll_code 与 node 名称','err');return}
|
||||
busy.value=true;
|
||||
const r=await api('/api/v1/enroll/consume',{method:'POST',body:JSON.stringify({code:enrollCode.value,node:enrollNode.value})});
|
||||
busy.value=false;
|
||||
if(r){enrollSecret.value=r.node_secret||'';show('Node Secret 已生成','ok')}
|
||||
};
|
||||
|
||||
const saveSD=async()=>{
|
||||
busy.value=true;
|
||||
const r=await api('/api/v1/sdwan/edit',{method:'POST',body:JSON.stringify(sd.value)});
|
||||
@@ -375,8 +447,10 @@ createApp({setup(){
|
||||
|
||||
return{loggedIn,loginToken,loginErr,busy,tab,tabs,nf,toast,toastType,
|
||||
st,nodes,sd,logs,tunNode,tunApps,na,addNode,addIP,p2p,
|
||||
tenants,newTenant,tenantKey,enrollCode,enrollNode,enrollSecret,
|
||||
login,refresh,saveSD,kickNode,openTunnel,pushTun,openConnect,doConnect,
|
||||
addSDNode,autoIP,nodeOnline,uptime,fNodes,uaNodes}
|
||||
addSDNode,autoIP,nodeOnline,uptime,fNodes,uaNodes,
|
||||
createTenant,createKey,createEnroll,consumeEnroll}
|
||||
}}).mount('#app');
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user