管理页面代码重构

This commit is contained in:
snltty
2025-11-17 16:52:54 +08:00
parent 222bfb9fd0
commit 16d6892ff4
30 changed files with 460 additions and 124 deletions

View File

@@ -1,5 +1,5 @@
v1.9.6
2025-11-16 20:01:56
2025-11-17 16:52:54
1. 一些累计更新一些BUG修复
2. 优化客户端数据同步,减少服务器流量
3. 去除cdkey改为发电解锁中继速度

View File

@@ -1,4 +1,5 @@
using linker.messenger.tunnel;
using linker.libs;
using linker.messenger.tunnel;
using linker.tunnel.transport;
namespace linker.messenger.store.file.tunnel
@@ -21,11 +22,9 @@ namespace linker.messenger.store.file.tunnel
{
this.runningConfig = runningConfig;
var list = config.Data.Client.Tunnel.Transports;
if (list != null && list.Count > 0)
if (config.Data.Client.Tunnel.Transports != null && config.Data.Client.Tunnel.Transports.Count > 0)
{
runningConfig.Data.Tunnel.Transports.AddOrUpdate("default", list, (a, b) => list);
runningConfig.Data.Tunnel.Transports.AddOrUpdate(Helper.GlobalString, config.Data.Client.Tunnel.Transports, (a, b) => config.Data.Client.Tunnel.Transports);
runningConfig.Data.Update();
config.Data.Client.Tunnel.Transports = [];
@@ -43,20 +42,121 @@ namespace linker.messenger.store.file.tunnel
return true;
}
public async Task<bool> SetTunnelTransports(string machineId, List<ITunnelTransport> list)
{
if (string.IsNullOrWhiteSpace(machineId)) return false;
if (runningConfig.Data.Tunnel.Transports.TryGetValue(machineId, out List<TunnelTransportItemInfo> transportItems) == false)
{
transportItems = new List<TunnelTransportItemInfo>();
}
Rebuild(transportItems, list);
ForceUpdate(transportItems, list);
runningConfig.Data.Tunnel.Transports.AddOrUpdate(machineId, transportItems, (a, b) => transportItems);
runningConfig.Data.Update();
OnChanged();
return true;
}
public async Task<List<TunnelTransportItemInfo>> GetTunnelTransports(string machineId)
{
if (runningConfig.Data.Tunnel.Transports.TryGetValue(machineId, out List<TunnelTransportItemInfo> list))
{
if (runningConfig.Data.Tunnel.Transports.TryGetValue(Helper.GlobalString, out List<TunnelTransportItemInfo> defaults))
{
if(Rebuild(list, defaults))
{
runningConfig.Data.Tunnel.Transports.AddOrUpdate(machineId, list, (a, b) => list);
runningConfig.Data.Update();
}
}
return list;
}
if (runningConfig.Data.Tunnel.Transports.TryGetValue("default", out list))
if (runningConfig.Data.Tunnel.Transports.TryGetValue(Helper.GlobalString, out list))
{
return list;
}
return [];
}
private void ForceUpdate(List<TunnelTransportItemInfo> currents, List<ITunnelTransport> news)
{
//强制更新一些信息
foreach (var item in currents)
{
var transport = news.FirstOrDefault(c => c.Name == item.Name);
if (transport != null)
{
item.DisableReverse = transport.DisableReverse;
item.DisableSSL = transport.DisableSSL;
item.Name = transport.Name;
item.Label = transport.Label;
if (transport.DisableReverse)
{
item.Reverse = transport.Reverse;
}
if (transport.DisableSSL)
{
item.SSL = transport.SSL;
}
if (item.Order == 0)
{
item.Order = transport.Order;
}
}
}
}
private bool Rebuild(List<TunnelTransportItemInfo> currents, List<ITunnelTransport> news)
{
return Rebuild(currents, news.Select(c => new TunnelTransportItemInfo
{
Label = c.Label,
Name = c.Name,
ProtocolType = c.ProtocolType.ToString(),
Reverse = c.Reverse,
DisableReverse = c.DisableReverse,
SSL = c.SSL,
DisableSSL = c.DisableSSL,
Order = c.Order
}).ToList());
}
private bool Rebuild(List<TunnelTransportItemInfo> currents,List<TunnelTransportItemInfo> news)
{
//有新的协议
var newTransportNames = news.Select(c => c.Name).Except(currents.Select(c => c.Name));
if (newTransportNames.Any())
{
currents.AddRange(news.Where(c => newTransportNames.Contains(c.Name)).Select(c => new TunnelTransportItemInfo
{
Label = c.Label,
Name = c.Name,
ProtocolType = c.ProtocolType.ToString(),
Reverse = c.Reverse,
DisableReverse = c.DisableReverse,
SSL = c.SSL,
DisableSSL = c.DisableSSL,
Order = c.Order
}));
}
//有已移除的协议
var oldTransportNames = currents.Select(c => c.Name).Except(news.Select(c => c.Name));
if (oldTransportNames.Any())
{
foreach (var item in currents.Where(c => oldTransportNames.Contains(c.Name)).ToList())
{
currents.Remove(item);
}
}
return newTransportNames.Any() || oldTransportNames.Any();
}
public async Task<bool> SetRouteLevelPlus(int level)
{
runningConfig.Data.Tunnel.RouteLevelPlus = level;
@@ -64,7 +164,6 @@ namespace linker.messenger.store.file.tunnel
OnChanged();
return await Task.FromResult(true).ConfigureAwait(false);
}
public async Task<bool> SetPortMap(int privatePort, int publicPort)
{
runningConfig.Data.Tunnel.PortMapLan = privatePort;
@@ -73,7 +172,6 @@ namespace linker.messenger.store.file.tunnel
OnChanged();
return await Task.FromResult(true).ConfigureAwait(false);
}
public async Task<bool> SetNetwork(TunnelPublicNetworkInfo network)
{
runningConfig.Data.Update();

View File

@@ -124,6 +124,7 @@ namespace linker.messenger.tunnel
return true;
}
/// <summary>
/// 获取打洞协议
/// </summary>
@@ -133,7 +134,7 @@ namespace linker.messenger.tunnel
{
if (param.Content == signInClientStore.Id || string.IsNullOrWhiteSpace(param.Content))
{
return await tunnelMessengerAdapter.GetTunnelTransports("default").ConfigureAwait(false);
return await tunnelMessengerAdapter.GetTunnelTransports(Helper.GlobalString).ConfigureAwait(false);
}
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
@@ -161,7 +162,7 @@ namespace linker.messenger.tunnel
TunnelTransportItemSetInfo info = param.Content.DeJson<TunnelTransportItemSetInfo>();
if (info.MachineId == signInClientStore.Id || string.IsNullOrWhiteSpace(info.MachineId))
{
await tunnelMessengerAdapter.SetTunnelTransports("default", info.Data).ConfigureAwait(false);
await tunnelMessengerAdapter.SetTunnelTransports(Helper.GlobalString, info.Data).ConfigureAwait(false);
return true;
}
await tunnelMessengerAdapter.SetTunnelTransports(info.MachineId, info.Data).ConfigureAwait(false);
@@ -174,6 +175,7 @@ namespace linker.messenger.tunnel
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
public async Task<TunnelLocalNetworkInfo> GetNetwork(ApiControllerParamsInfo param)
{
if (param.Content == signInClientStore.Id)

View File

@@ -51,7 +51,13 @@ namespace linker.messenger.tunnel
/// </summary>
/// <param name="list"></param>
public Task<bool> SetTunnelTransports(string machineId, List<TunnelTransportItemInfo> list);
/// <summary>
/// 保存打洞协议列表
/// </summary>
/// <param name="machineId"></param>
/// <param name="list"></param>
/// <returns></returns>
public Task<bool> SetTunnelTransports(string machineId, List<ITunnelTransport> list);
public Action OnChanged { get; set; }
@@ -112,13 +118,18 @@ namespace linker.messenger.tunnel
{
return await tunnelClientStore.GetTunnelTransports(machineid).ConfigureAwait(false);
}
public async Task<bool> SetTunnelTransports(string machineid, List<TunnelTransportItemInfo> list)
{
bool res = await tunnelClientStore.SetTunnelTransports(machineid, list).ConfigureAwait(false);
SetCounter();
return res;
}
public async Task<bool> SetTunnelTransports(string machineid, List<ITunnelTransport> list)
{
bool res = await tunnelClientStore.SetTunnelTransports(machineid, list).ConfigureAwait(false);
SetCounter();
return res;
}
private void SetCounter()
{
counterDecenter.SetValue($"transport", tunnelClientStore.TransportMachineIdCount);

View File

@@ -20,12 +20,12 @@ namespace linker.messenger.tunnel
}
public Memory<byte> GetData()
{
return serializer.Serialize(tunnelMessengerAdapter.GetTunnelTransports("default").Result);
return serializer.Serialize(tunnelMessengerAdapter.GetTunnelTransports(Helper.GlobalString).Result);
}
public void SetData(Memory<byte> data)
{
tunnelMessengerAdapter.SetTunnelTransports("default", serializer.Deserialize<List<TunnelTransportItemInfo>>(data.Span));
tunnelMessengerAdapter.SetTunnelTransports(Helper.GlobalString, serializer.Deserialize<List<TunnelTransportItemInfo>>(data.Span));
}
}
}

View File

@@ -123,7 +123,7 @@ namespace linker.messenger.wlist
return string.Empty;
}
public async Task<Dictionary<string, double>> List(ApiControllerParamsInfo param)
public async Task<Dictionary<string, Dictionary<int, double>>> List(ApiControllerParamsInfo param)
{
KeyValueInfo info = param.Content.DeJson<KeyValueInfo>();
@@ -135,10 +135,10 @@ namespace linker.messenger.wlist
}).ConfigureAwait(false);
if (resp.Code == MessageResponeCodes.OK)
{
return serializer.Deserialize<Dictionary<string, double>>(resp.Data.Span);
return serializer.Deserialize<Dictionary<string, Dictionary<int, double>>>(resp.Data.Span);
}
return new Dictionary<string, double>();
return [];
}
sealed class KeyValueInfo
{

View File

@@ -1,4 +1,5 @@
using linker.libs;
using linker.libs.extends;
using linker.libs.winapis;
using linker.messenger.relay.server;
using linker.messenger.signin;
@@ -38,6 +39,7 @@ namespace linker.messenger.wlist
connection.Write(Helper.FalseArray);
return;
}
Console.WriteLine(info.Data.ToJson());
await whiteListServerStore.Add(info.Data).ConfigureAwait(false);
connection.Write(Helper.TrueArray);
}
@@ -144,13 +146,11 @@ namespace linker.messenger.wlist
List<WhiteListInfo> whites = await whiteListServerStore.Get(info.Key, userids, info.Value).ConfigureAwait(false);
var result = whites.Where(c => string.IsNullOrWhiteSpace(c.UserId) == false).GroupBy(c => c.UserId).ToDictionary(c => $"u_{c.Key}", v =>
{
return v.Any(x => x.Bandwidth == 0) ? v.First(x => x.Bandwidth == 0).Bandwidth : v.OrderByDescending(x => x.Bandwidth).First().Bandwidth;
}).Concat(whites.Where(c => string.IsNullOrWhiteSpace(c.MachineId) == false).GroupBy(c => c.MachineId).ToDictionary(c => $"m_{c.Key}", v =>
{
return v.Any(x => x.Bandwidth == 0) ? v.First(x => x.Bandwidth == 0).Bandwidth : v.OrderByDescending(x => x.Bandwidth).First().Bandwidth;
})).ToDictionary();
var result = whites.Where(c => string.IsNullOrWhiteSpace(c.UserId) == false).GroupBy(c => c.UserId)
.ToDictionary(c => $"u_{c.Key}", v => v.Select(c => c).ToDictionary(x => x.Id, x => x.Bandwidth))
.Concat(whites.Where(c => string.IsNullOrWhiteSpace(c.MachineId) == false).GroupBy(c => c.MachineId)
.ToDictionary(c => $"m_{c.Key}", v => v.Select(c => c).ToDictionary(x => x.Id, x => x.Bandwidth)))
.ToDictionary();
connection.Write(serializer.Serialize(result));
}
}

View File

@@ -66,5 +66,12 @@ namespace linker.tunnel
/// </summary>
/// <param name="transports"></param>
public Task<bool> SetTunnelTransports(string machineid,List<TunnelTransportItemInfo> list);
/// <summary>
/// 保存打洞协议列表
/// </summary>
/// <param name="machineid"></param>
/// <param name="list"></param>
/// <returns></returns>
public Task<bool> SetTunnelTransports(string machineid, List<ITunnelTransport> list);
}
}

View File

@@ -53,59 +53,7 @@ namespace linker.tunnel
}
private async Task RebuildTransports()
{
var transportItems = (await tunnelMessengerAdapter.GetTunnelTransports("default").ConfigureAwait(false)).ToList();
//有新的协议
var newTransportNames = transports.Select(c => c.Name).Except(transportItems.Select(c => c.Name));
if (newTransportNames.Any())
{
transportItems.AddRange(transports.Where(c => newTransportNames.Contains(c.Name)).Select(c => new TunnelTransportItemInfo
{
Label = c.Label,
Name = c.Name,
ProtocolType = c.ProtocolType.ToString(),
Reverse = c.Reverse,
DisableReverse = c.DisableReverse,
SSL = c.SSL,
DisableSSL = c.DisableSSL,
Order = c.Order
}));
}
//有已移除的协议
var oldTransportNames = transportItems.Select(c => c.Name).Except(transports.Select(c => c.Name));
if (oldTransportNames.Any())
{
foreach (var item in transportItems.Where(c => oldTransportNames.Contains(c.Name)))
{
transportItems.Remove(item);
}
}
//强制更新一些信息
foreach (var item in transportItems)
{
var transport = transports.FirstOrDefault(c => c.Name == item.Name);
if (transport != null)
{
item.DisableReverse = transport.DisableReverse;
item.DisableSSL = transport.DisableSSL;
item.Name = transport.Name;
item.Label = transport.Label;
if (transport.DisableReverse)
{
item.Reverse = transport.Reverse;
}
if (transport.DisableSSL)
{
item.SSL = transport.SSL;
}
if (item.Order == 0)
{
item.Order = transport.Order;
}
}
}
await tunnelMessengerAdapter.SetTunnelTransports("default",transportItems).ConfigureAwait(false);
await tunnelMessengerAdapter.SetTunnelTransports(Helper.GlobalString, transports).ConfigureAwait(false);
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Info($"load tunnel transport:{string.Join(",", transports.Select(c => c.GetType().Name))}");
}

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1763363882257" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10530" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000" height="1000"><path d="M512 512m-512 0a512 512 0 1 0 1024 0 512 512 0 1 0-1024 0Z" fill="#FF090B" p-id="10531"></path><path d="M512 512m-426.666667 0a426.666667 426.666667 0 1 0 853.333334 0 426.666667 426.666667 0 1 0-853.333334 0Z" fill="#FFFFFF" p-id="10532"></path><path d="M624.64 469.333333v104.106667l95.573333 220.16s29.013333 46.08-17.066666 59.733333c0 0-30.72 5.12-46.08-23.893333l-85.333334-160.426667s-18.773333-47.786667-34.133333-30.72L477.866667 703.146667s-17.066667 34.133333-17.066667 128c0 0 6.826667 22.186667-37.546667 22.186666 0 0-30.72 1.706667-30.72-20.48v-87.04s5.12-98.986667 92.16-197.973333v-29.013333l-15.36-81.92s-17.066667-20.48-29.013333-3.413334c0 0 3.413333 23.893333-47.786667 51.2l-58.026666 20.48s-32.426667 11.946667-37.546667-6.826666c0 0-11.946667-25.6 6.826667-32.426667l52.906666-29.013333s61.44-40.96 58.026667-92.16c0 0 10.24-58.026667 63.146667-75.093334 0 0 25.6-20.48 58.026666-8.533333l138.24 63.146667s18.773333 11.946667 18.773334 25.6v136.533333s3.413333 25.6-15.36 25.6c0 0-30.72-10.24-30.72-18.773333l1.706666-102.4s-3.413333-8.533333-25.6-22.186667l-22.186666-17.066667s-25.6-17.066667-20.48 6.826667c-1.706667 0 44.373333 68.266667 44.373333 110.933333zM445.44 256c-32.426667 0-59.733333-25.6-59.733333-59.733333 0-32.426667 25.6-59.733333 59.733333-59.733334s59.733333 25.6 59.733333 59.733334-25.6 59.733333-59.733333 59.733333z" fill="#1E1C1A" p-id="10533"></path><path d="M200.6528 152.3712l670.976 670.976-48.2816 48.264533L152.3712 200.635733z" fill="#FF090B" p-id="10534"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1763014920950" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11190" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000" height="1000"><path d="M0 0m78.769231 0l866.461538 0q78.769231 0 78.769231 78.769231l0 866.461538q0 78.769231-78.769231 78.769231l-866.461538 0q-78.769231 0-78.769231-78.769231l0-866.461538q0-78.769231 78.769231-78.769231Z" fill="#FFFFFF" fill-opacity="0" p-id="11191"></path><path d="M555.204923 445.518769h232.763077l-299.244308 432.206769v-299.244307H256l299.204923-432.206769v299.244307z" fill="#FF0000" p-id="11192"></path></svg>

Before

Width:  |  Height:  |  Size: 747 B

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1763364230445" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12699" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000" height="1000"><path d="M0 512c0 282.4 229.6 512 512 512s512-229.6 512-512S794.4 0 512 0 0 229.6 0 512z" fill="#515151" p-id="12700" data-spm-anchor-id="a313x.search_index.0.i2.53a83a81qrVrBK" class="selected"></path><path d="M85.6 512c0 236 191.2 426.4 426.4 426.4 236 0 426.4-191.2 426.4-426.4 0-236-191.2-426.4-426.4-426.4S85.6 276 85.6 512z" fill="#FFFFFF" p-id="12701"></path><path d="M624.8 469.6v104L720 793.6s28.8 46.4-16.8 60c0 0-30.4 4.8-46.4-24L572 668.8s-18.4-48-34.4-30.4l-60 64.8s-16.8 34.4-16.8 128c0 0 7.2 22.4-37.6 22.4 0 0-30.4 1.6-30.4-20.8V745.6s4.8-99.2 92-197.6v-28.8l-15.2-81.6s-16.8-20.8-28.8-3.2c0 0 3.2 24-48 51.2l-58.4 20.8s-32.8 12-37.6-7.2c0 0-12-25.6 7.2-32.8l52.8-28.8s61.6-40.8 58.4-92c0 0 10.4-58.4 63.2-75.2 0 0 25.6-20.8 58.4-8.8l138.4 63.2s18.4 12 18.4 25.6v136.8s3.2 25.6-15.2 25.6c0 0-30.4-10.4-30.4-18.4l1.6-102.4s-3.2-8.8-25.6-22.4l-22.4-16.8S576 336 580.8 360c-2.4-1.6 44 66.4 44 109.6zM445.6 256c-32.8 0-60-25.6-60-60 0-32.8 25.6-60 60-60s60 25.6 60 60-26.4 60-60 60z" fill="#515151" p-id="12702" data-spm-anchor-id="a313x.search_index.0.i3.53a83a81qrVrBK" class="selected"></path></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1763363855111" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8440" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000" height="1000"><path d="M0 512c0 282.4 229.6 512 512 512s512-229.6 512-512S794.4 0 512 0 0 229.6 0 512z" fill="#009944" p-id="8441"></path><path d="M85.6 512c0 236 191.2 426.4 426.4 426.4 236 0 426.4-191.2 426.4-426.4 0-236-191.2-426.4-426.4-426.4S85.6 276 85.6 512z" fill="#FFFFFF" p-id="8442"></path><path d="M624.8 469.6v104L720 793.6s28.8 46.4-16.8 60c0 0-30.4 4.8-46.4-24L572 668.8s-18.4-48-34.4-30.4l-60 64.8s-16.8 34.4-16.8 128c0 0 7.2 22.4-37.6 22.4 0 0-30.4 1.6-30.4-20.8V745.6s4.8-99.2 92-197.6v-28.8l-15.2-81.6s-16.8-20.8-28.8-3.2c0 0 3.2 24-48 51.2l-58.4 20.8s-32.8 12-37.6-7.2c0 0-12-25.6 7.2-32.8l52.8-28.8s61.6-40.8 58.4-92c0 0 10.4-58.4 63.2-75.2 0 0 25.6-20.8 58.4-8.8l138.4 63.2s18.4 12 18.4 25.6v136.8s3.2 25.6-15.2 25.6c0 0-30.4-10.4-30.4-18.4l1.6-102.4s-3.2-8.8-25.6-22.4l-22.4-16.8S576 336 580.8 360c-2.4-1.6 44 66.4 44 109.6zM445.6 256c-32.8 0-60-25.6-60-60 0-32.8 25.6-60 60-60s60 25.6 60 60-26.4 60-60 60z" fill="#009944" p-id="8443"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -13,4 +13,7 @@ export const wlistStatus = (type) => {
}
export const wlistAddOrder = (data) => {
return sendWebsocketMsg('whitelist/addorder', data);
}
export const wlistList = (data) => {
return sendWebsocketMsg('whitelist/list', data);
}

View File

@@ -13,20 +13,9 @@
</p>
<p class="flex">
<template v-if="scope.row.Connected">
<div>
<template v-if="scope.row.hook_tuntap && scope.row.hook_tuntap.systems">
<template v-for="system in scope.row.hook_tuntap.systems">
<span :title="scope.row.hook_tuntap.SystemInfo">
<img class="system" :src="`./${system}.svg`" />
</span>
</template>
</template>
</div>
<span title="20Mbps">
<a href="javascript:;"><img class="system" src="lightning.svg" /></a>
</span>
<SystemInfo :item="scope.row"></SystemInfo>
<span class="flex-1"></span>
<WlistShow type="Relay" :item="scope.row"></WlistShow>
<UpdaterBtn :config="true" :item="scope.row"></UpdaterBtn>
</template>
<template v-else>
@@ -42,10 +31,13 @@ import { ref } from 'vue';
import {Search} from '@element-plus/icons-vue'
import UpdaterBtn from '../updater/UpdaterBtn.vue';
import DeviceName from './DeviceName.vue';
import SystemInfo from '../tuntap/SystemInfo.vue';
import WlistShow from '../wlist/Device.vue'
export default {
emits:['refresh'],
components:{Search,UpdaterBtn,DeviceName},
components:{Search,UpdaterBtn,DeviceName,SystemInfo,WlistShow},
setup(props,{emit}) {
const name = ref(sessionStorage.getItem('search-name') || '');
@@ -62,16 +54,8 @@ export default {
}
</script>
<style lang="stylus" scoped>
.el-input{
width:12rem;
margin-right:.6rem
}
img.system{
height:1.4rem;
vertical-align: middle;
margin-right:.1rem
border:1px solid rgba(0,0,0,.1);
border-radius:.2rem;
}
</style>

View File

@@ -31,6 +31,7 @@ export const provideDevices = () => {
}
const deviceRefreshHook = (name) => {
if(hooks[name]) {
hooks[name].refresh = true;
hooks[name].changed = true;
}
}
@@ -41,7 +42,7 @@ export const provideDevices = () => {
const hook = hooks[name];
if(hook.refresh) {
hook.refresh = false;
hook.refreshFn();
hook.refreshFn(devices.page.List);
}
}
for(let name in hooks) {
@@ -57,7 +58,7 @@ export const provideDevices = () => {
}
for(let name in hooks) {
const hook = hooks[name];
hook.changed = await hook.dataFn();
hook.changed = await hook.dataFn(devices.page.List);
}
devices.timer1 = setTimeout(fn,1000);
}

View File

@@ -1,7 +1,7 @@
<template>
<AccessBoolean value="FirewallOther">
<AccessBoolean value="FirewallSelf,FirewallOther">
<template #default="{values}">
<template v-if="values.FirewallOther && !item.isSelf">
<template v-if="(values.FirewallSelf && item.isSelf) || (values.FirewallOther && !item.isSelf)">
<el-col :span="12">
<a href="javascript:;" :class="{green:firewallCounter>0}" @click="handleFirewall"><img src="firewall.svg" alt="firewall"> ({{firewallCounter}})</a>
</el-col>

View File

@@ -6,9 +6,11 @@
<div>
<div class="numbers">
<el-row>
<FirewallOper :item="scope.row"></FirewallOper>
<WakeupOper :item="scope.row"></WakeupOper>
<TransportOper :item="scope.row"></TransportOper>
<template v-if="scope.row.Connected">
<FirewallOper :item="scope.row"></FirewallOper>
<WakeupOper :item="scope.row"></WakeupOper>
<TransportOper :item="scope.row"></TransportOper>
</template>
<el-col :span="12">
<el-dropdown size="small" >
<div class="dropdown">

View File

@@ -1,6 +1,6 @@
<template>
<AccessShow value="Transport">
<el-col :span="12" v-if="!item.isSelf">
<el-col :span="12">
<a href="javascript:;" :class="{green:transportCounter>0}" @click="handleTransport"><img src="transport.svg" alt="transport"> ({{ transportCounter }})</a>
</el-col>
</AccessShow>

View File

@@ -1,5 +1,5 @@
<template>
<el-dialog v-model="state.show" append-to=".app-wrap" :title="`本机与[${state.machineName}]之间的打洞协议`" top="1vh" width="98%">
<el-dialog v-model="state.show" append-to=".app-wrap" :title="state.title" top="1vh" width="98%">
<div>
<Transport :machineId="state.machineId"></Transport>
</div>
@@ -9,6 +9,7 @@
import { reactive, watch } from 'vue';
import Transport from '../transport/Transport.vue'
import { useTransport } from './transport';
import { injectGlobalData } from '@/provide';
export default {
props: ['modelValue'],
emits: ['update:modelValue'],
@@ -16,12 +17,16 @@ export default {
Transport
},
setup(props, { emit }) {
const globalData = injectGlobalData();
const transport = useTransport();
const isSelf = globalData.value.config.Client.Id == transport.value.device.id || !transport.value.device.id;
const state = reactive({
show: true,
machineId: transport.value.device.id,
machineName: transport.value.device.name
title:isSelf? `[${transport.value.device.name}]上的打洞协议` : `本机与[${transport.value.device.name}]之间的打洞协议`,
});
watch(() => state.show, (val) => {
if (!val) {

View File

@@ -1,7 +1,7 @@
<template>
<el-dialog v-model="state.show" append-to=".app-wrap" :title="`与[${state.device.MachineName}]的链接`" top="1vh" width="500">
<el-dialog v-model="state.show" append-to=".app-wrap" :title="`与[${state.device.MachineName}]的链接`" top="1vh" width="350">
<div>
<el-descriptions border size="small" :column="2" column-max-width="120px" overlength-control="wrap">
<el-descriptions border size="small" :column="1" column-max-width="120px" overlength-control="wrap">
<el-descriptions-item label="目标">{{ state.connection.IPEndPoint || '0.0.0.0:0' }}</el-descriptions-item>
<el-descriptions-item label="事务">{{ state.transactions[state.connection.TransactionId] }}</el-descriptions-item>
<el-descriptions-item label="协议">
@@ -48,7 +48,7 @@
<template #reference>
<el-button type="danger" size="small"><el-icon>
<Delete />
</el-icon></el-button>
</el-icon></el-button>
</template>
</el-popconfirm>
</AccessShow>

View File

@@ -0,0 +1,30 @@
<template>
<div>
<template v-if="item.hook_tuntap && item.hook_tuntap.systems">
<template v-for="system in item.hook_tuntap.systems">
<span :title="item.hook_tuntap.SystemInfo">
<img :src="`./${system}.svg`" />
</span>
</template>
</template>
</div>
</template>
<script>
export default {
props:['item'],
setup () {
return {}
}
}
</script>
<style lang="stylus" scoped>
img{
height:1.4rem;
vertical-align: middle;
margin-right:.1rem
border:1px solid rgba(0,0,0,.1);
border-radius:.2rem;
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<AccessBoolean value="WakeupOther">
<AccessBoolean value="WakeupSelf,WakeupOther">
<template #default="{values}">
<template v-if="values.WakeupOther && !item.isSelf">
<template v-if="(values.WakeupSelf && item.isSelf) || (values.WakeupOther && !item.isSelf)">
<el-col :span="12">
<a href="javascript:;" :class="{green:wakeupCounter>0}" @click="handleWakeup"><img src="wakeup.svg" alt="wakeup"> ({{ wakeupCounter }})</a>
</el-col>

View File

@@ -105,7 +105,7 @@ export default {
UserId:editState.value.UserId || '',
Name:editState.value.Name || '',
Remark:editState.value.Remark || '',
Nodes:editState.value.Nodes || [],
Nodes:editState.value.Nodes || ['*'],
Bandwidth:editState.value.Bandwidth || 0,
UseTime:editState.value.UseTime || '',
EndTime:editState.value.EndTime || '',
@@ -138,7 +138,8 @@ export default {
state.ruleForm.Nodes = state.nodeIds.concat(ports);
}
const handleShowNodes = ()=>{
const handleShowNodes = ()=>{
return false;
state.nodeIds = state.ruleForm.Nodes.filter(c=>!!!state.prefix ||c.indexOf(state.prefix) < 0);
state.showNodes = true;
}

View File

@@ -0,0 +1,64 @@
<template>
<span>
<a href="javascript:;" :title="wlist.title" @click="handleWlist">
<img :src="wlist.img" />
</a>
</span>
</template>
<script>
import { computed } from 'vue';
import { useWlist } from './wlist';
export default {
props: ['item','type'],
setup (props) {
const wlistState = useWlist();
const text = {'Relay':'中继','SForward':'穿透'}[props.type];
const choiceOnece = (json)=>{
const arr = Object.keys(json).reduce((arr,curr)=>{
arr.push({ id:curr,value:json[curr] });
return arr;
},[]);
const denyOrAllow = arr.filter(c=>c.value <= 0);
const result = denyOrAllow.length > 0
? denyOrAllow.sort((a,b)=>a.value - b.value)[0]
: arr.sort((a,b)=>b.value - a.value)[0];
return {
id:result.id,
value:result.value,
title:result.value < 0 ? `拒绝${text}` : result.value == 0 ? `允许无限速${text}` : `允许${result.value}Mbps限速${text}`,
img:result.value < 0 ? 'blist.svg':'wlist.svg'
};
}
const wlist = computed(()=>props.item.hook_wlist === undefined || Object.keys(props.item.hook_wlist).length == 0
? {id:0,value:0,title:`${text}限制配置`,img:'wlist-none.svg'}
: choiceOnece(props.item.hook_wlist));
const handleWlist = ()=>{
wlistState.value.device.id = props.item.MachineId;
wlistState.value.device.name = props.item.MachineName;
wlistState.value.device.type = props.type;
wlistState.value.device.typeText = text;
wlistState.value.show = true;
}
return {
wlist,handleWlist
}
}
}
</script>
<style lang="stylus" scoped>
img{
height:1.4rem;
vertical-align: middle;
margin-right:.1rem
border:1px solid rgba(0,0,0,.1);
border-radius:.2rem;
}
</style>

View File

@@ -111,7 +111,7 @@ export default {
provide('edit',editState);
const handleAdd = ()=>{
editState.value = {Id:0,Name:'',Nodes:[],Remark:'',UserId:'',Type:props.type,prefix:props.prefix || ''};
editState.value = {Id:0,Name:'',Nodes:['*'],Remark:'',UserId:'',Type:props.type,prefix:props.prefix || ''};
state.showAdd = true;
}
const handleEdit = (row)=>{

View File

@@ -0,0 +1,127 @@
<template>
<el-dialog v-model="state.show" append-to=".app-wrap" :title="state.title" top="1vh" width="370">
<div>
<el-descriptions border size="small" :column="1" column-max-width="120px" overlength-control="wrap">
<el-descriptions-item label="名称">{{ state.status.Info.Name }}</el-descriptions-item>
<el-descriptions-item label="带宽">
<div>
<span v-if="state.status.Info.Bandwidth < 0">禁止</span>
<span v-if="state.status.Info.Bandwidth == 0">无限制</span>
<span v-else-if="state.status.Info.Bandwidth>0">{{state.status.Info.Bandwidth}}Mbps</span>
</div>
</el-descriptions-item>
<el-descriptions-item label="开始时间">{{ state.status.Info.UseTime }}</el-descriptions-item>
<el-descriptions-item label="结束时间">{{ state.status.Info.EndTime }}</el-descriptions-item>
<el-descriptions-item label="作用于">
<span v-if="state.status.Info.UserId">同用户id客户端</span>
<span v-else-if="state.status.Info.MachineId">本客户端</span>
</el-descriptions-item>
<el-descriptions-item label="备注">{{ state.status.Info.Remark }}</el-descriptions-item>
<el-descriptions-item label="操作">
<div v-if="state.super">
<template v-if="state.status.Info.Id > 0">
<el-popconfirm confirm-button-text="确认" cancel-button-text="取消" title="确定删除?" @confirm="handleDel">
<template #reference>
<el-button type="danger" size="small" :loading="state.loading"><el-icon> <Delete /></el-icon></el-button>
</template>
</el-popconfirm>
</template>
<template v-else>
<el-button type="success" size="small" :loading="state.loading" @click="handleAdd"><el-icon> <Plus /></el-icon></el-button>
</template>
</div>
</el-descriptions-item>
</el-descriptions>
</div>
</el-dialog>
<Add v-if="state.showAdd" v-model="state.showAdd" @success="handleAddSuccess"></Add>
</template>
<script>
import { computed, onMounted, provide, reactive, ref, watch } from 'vue';
import { useWlist } from './wlist';
import { wlistDel, wlistStatus } from '@/apis/wlist';
import { Delete, Plus } from '@element-plus/icons-vue';
import { injectGlobalData } from '@/provide';
import Add from './Add.vue';
export default {
props: ['modelValue'],
emits: ['update:modelValue'],
components: {Delete, Plus,Add },
setup(props, { emit }) {
const wlist = useWlist();
const globalData = injectGlobalData();
const state = reactive({
show: true,
machineId: wlist.value.device.id,
title: `[${wlist.value.device.name}]上的${wlist.value.device.typeText}白名单`,
status: {
Enabled:false,
Type:'',
Info:{}
},
super:computed(()=>globalData.value.signin.Super),
loading:false,
showAdd:false
});
watch(() => state.show, (val) => {
if (!val) {
setTimeout(() => {
emit('update:modelValue', val);
}, 300);
}
});
const handleRefreshData = ()=>{
wlistStatus(wlist.value.device.type).then(res=>{
state.status = res;
state.status.Info = res.Info || {}
});
}
const handleDel = ()=>{
state.loading = true;
wlistDel(state.status.Info.Id).then(()=>{
state.loading = false;
handleRefreshData();
emit('change');
}).catch(()=>{
state.loading = false;
})
}
const editState = ref({});
const nodes = ref([]);
provide('edit',editState);
provide('nodes',nodes);
const handleAdd = ()=>{
editState.value = {
Id:0
,Name:wlist.value.device.name
,Nodes:['*']
,Remark:''
,MachineId:wlist.value.device.id
,Type:wlist.value.device.type
,prefix:''
};
state.showAdd = true;
}
const handleAddSuccess = ()=>{
handleRefreshData();
emit('change');
}
onMounted(()=>{
handleRefreshData();
});
return {
state,handleRefreshData,handleDel,handleAdd,handleAddSuccess
}
}
}
</script>
<style lang="stylus" scoped>
</style>

View File

@@ -41,10 +41,8 @@ export default {
}
onMounted(()=>{
wlistStatus(props.type).then(res=>{
state.status = res;
console.log(res);
});
});

View File

@@ -0,0 +1,47 @@
import { wlistList } from "@/apis/wlist";
import { inject, provide, ref } from "vue"
const wlistSymbol = Symbol();
export const provideWlist = () => {
const wlist = ref({
device: {id:'',name:'',type:'',typeText:''},
show:false,
list: null,
});
provide(wlistSymbol, wlist);
const wlistDataFn = (devices) => {
return new Promise((resolve, reject) => {
if(wlist.value.list !== null){
resolve(false);
return;
}
wlistList({Key:'Relay',Value:devices.map(c=>c.MachineId)}).then((res) => {
wlist.value.list = res;
resolve(true);
}).catch(() => {
resolve(false);
});
})
}
const wlistRefreshFn = () => {
wlist.value.list = null;
}
const wlistProcessFn = (device,json) => {
if(wlist.value.list){
Object.assign(json,{
hook_wlist: wlist.value.list[`m_${device.MachineId}`] || wlist.value.list[`u_${device.Args.userid}`] || {}
});
}
}
return {
wlist,wlistDataFn,wlistProcessFn,wlistRefreshFn
}
}
export const useWlist = () => {
return inject(wlistSymbol);
}

View File

@@ -36,6 +36,7 @@
<OperAction v-if="action.show" v-model="action.show" ></OperAction>
<Stopwatch v-if="flow.showStopwatch" v-model="flow.showStopwatch" ></Stopwatch>
<OperFlow v-if="flow.show" v-model="flow.show" ></OperFlow>
<OperWlist v-if="wlist.show" v-model="wlist.show" @change="deviceRefreshHook('wlist')" ></OperWlist>
</div>
</template>
<script>
@@ -95,6 +96,8 @@ import { provideFirewall } from '@/views/components/firewall/firewall'
import { provideWakeup } from '@/views/components/wakeup/wakeup'
import { provideTransport } from '@/views/components/transport/transport'
import { provideAction } from '@/views/components/action/action'
import { provideWlist } from '@/views/components/wlist/wlist'
import OperWlist from '../../../components/wlist/OperDialog.vue'
export default {
@@ -108,7 +111,7 @@ export default {
Forward,ForwardEdit,
SForwardEdit ,UpdaterConfirm,
Stopwatch,
Oper,OperFirewall,OperWakeup ,OperTransport,OperAction,OperFlow
Oper,OperFirewall,OperWakeup ,OperTransport,OperAction,OperFlow,OperWlist
},
setup(props) {
@@ -144,6 +147,9 @@ export default {
deviceAddHook('tuntap',tuntapDataFn,tuntapProcessFn,tuntapRefreshFn);
const {connections,connectionDataFn,connectionProcessFn,connectionRefreshFn } = provideConnections();
deviceAddHook('connection',connectionDataFn,connectionProcessFn,connectionRefreshFn);
const {wlist,wlistDataFn,wlistProcessFn,wlistRefreshFn} = provideWlist();
deviceAddHook('wlist',wlistDataFn,wlistProcessFn,wlistRefreshFn);
const handleSortChange = (row)=>{
@@ -212,7 +218,7 @@ export default {
tunnel,connections,
forward,
sforward,
updater,flow,oper,firewall,wakeup,transport,action
updater,flow,oper,firewall,wakeup,transport,action,wlist
}
}
}