mirror of
https://github.com/snltty/linker.git
synced 2025-09-27 05:25:57 +08:00
cdkey
This commit is contained in:
@@ -14,7 +14,10 @@ class Demo extends ManagePlugin
|
|||||||
#[Hook(point: \App\Consts\Hook::USER_API_ORDER_PAY_AFTER)]
|
#[Hook(point: \App\Consts\Hook::USER_API_ORDER_PAY_AFTER)]
|
||||||
public function tradeAfter($commodity, $order, $pay)
|
public function tradeAfter($commodity, $order, $pay)
|
||||||
{
|
{
|
||||||
$secret = json_decode($order->secret,true);
|
$lines = array_map(function($line) {
|
||||||
|
return rtrim($line, "\r");
|
||||||
|
}, explode("\n", $order->secret));
|
||||||
|
$secret = json_decode($lines[0],true);
|
||||||
|
|
||||||
try{
|
try{
|
||||||
$widget = json_decode($order->widget,true);
|
$widget = json_decode($order->widget,true);
|
||||||
@@ -32,13 +35,12 @@ class Demo extends ManagePlugin
|
|||||||
$secret["PayPrice"] = $order["amount"];
|
$secret["PayPrice"] = $order["amount"];
|
||||||
$secret["Count"] = $order["card_num"];
|
$secret["Count"] = $order["card_num"];
|
||||||
$order->secret = json_encode($secret,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
$order->secret = json_encode($secret,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
|
//file_put_contents("secret.txt",$order->secret);
|
||||||
$config = Plugin::getConfig("Demo");
|
$config = Plugin::getConfig("Demo");
|
||||||
$aesCrypto = new AesCrypto($config["KeyId"]);
|
$aesCrypto = new AesCrypto($config["KeyId"]);
|
||||||
$order->secret = base64_encode($aesCrypto->encode($order->secret));
|
$order->secret = base64_encode($aesCrypto->encode($order->secret));
|
||||||
$order->save();
|
$order->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
class AesCrypto
|
class AesCrypto
|
||||||
{
|
{
|
||||||
|
Binary file not shown.
@@ -28,6 +28,8 @@
|
|||||||
TestCdkey = 2115,
|
TestCdkey = 2115,
|
||||||
ImportCdkey = 2116,
|
ImportCdkey = 2116,
|
||||||
|
|
||||||
|
UpdateNode = 2117,
|
||||||
|
|
||||||
Max = 2199
|
Max = 2199
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -82,6 +82,7 @@
|
|||||||
public string SecretKey { get; set; }
|
public string SecretKey { get; set; }
|
||||||
public RelayServerCdkeyPageRequestFlag Flag { get; set; }
|
public RelayServerCdkeyPageRequestFlag Flag { get; set; }
|
||||||
}
|
}
|
||||||
|
[Flags]
|
||||||
public enum RelayServerCdkeyPageRequestFlag
|
public enum RelayServerCdkeyPageRequestFlag
|
||||||
{
|
{
|
||||||
All = 0,
|
All = 0,
|
||||||
|
@@ -23,6 +23,7 @@ namespace linker.messenger.relay.server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="node"></param>
|
/// <param name="node"></param>
|
||||||
public void SetInfo(RelayServerNodeInfo node);
|
public void SetInfo(RelayServerNodeInfo node);
|
||||||
|
public void UpdateInfo(RelayServerNodeUpdateInfo update);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置月份
|
/// 设置月份
|
||||||
@@ -81,6 +82,17 @@ namespace linker.messenger.relay.server
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed partial class RelayServerNodeUpdateInfo
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public int MaxConnection { get; set; }
|
||||||
|
public double MaxBandwidth { get; set; }
|
||||||
|
public double MaxBandwidthTotal { get; set; }
|
||||||
|
public double MaxGbTotal { get; set; }
|
||||||
|
public long MaxGbTotalLastBytes { get; set; }
|
||||||
|
public bool Public { get; set; }
|
||||||
|
}
|
||||||
public sealed partial class RelayServerNodeReportInfo
|
public sealed partial class RelayServerNodeReportInfo
|
||||||
{
|
{
|
||||||
public string Id { get; set; } = string.Empty;
|
public string Id { get; set; } = string.Empty;
|
||||||
@@ -104,7 +116,6 @@ namespace linker.messenger.relay.server
|
|||||||
public long LastTicks { get; set; }
|
public long LastTicks { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public sealed partial class RelayAskResultInfo
|
public sealed partial class RelayAskResultInfo
|
||||||
{
|
{
|
||||||
public ulong FlowingId { get; set; }
|
public ulong FlowingId { get; set; }
|
||||||
|
@@ -376,12 +376,12 @@ namespace linker.messenger.relay.server
|
|||||||
Name = node.Name,
|
Name = node.Name,
|
||||||
Public = node.Public,
|
Public = node.Public,
|
||||||
MaxBandwidth = node.MaxBandwidth,
|
MaxBandwidth = node.MaxBandwidth,
|
||||||
BandwidthRatio = Math.Round(node.MaxBandwidthTotal == 0 ? 0 : diff / 5 / node.MaxBandwidthTotal, 2),
|
BandwidthRatio = Math.Round(diff / 5, 2),
|
||||||
MaxBandwidthTotal = node.MaxBandwidthTotal,
|
MaxBandwidthTotal = node.MaxBandwidthTotal,
|
||||||
MaxGbTotal = node.MaxGbTotal,
|
MaxGbTotal = node.MaxGbTotal,
|
||||||
MaxGbTotalLastBytes = node.MaxGbTotalLastBytes,
|
MaxGbTotalLastBytes = node.MaxGbTotalLastBytes,
|
||||||
MaxConnection = node.MaxConnection,
|
MaxConnection = node.MaxConnection,
|
||||||
ConnectionRatio = Math.Round(node.MaxConnection == 0 ? 0 : connectionNum / 2.0 / node.MaxConnection, 2),
|
ConnectionRatio = Math.Round(connectionNum / 2.0),
|
||||||
EndPoint = endPoint
|
EndPoint = endPoint
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -51,6 +51,7 @@ namespace linker.messenger.serializer.memorypack
|
|||||||
|
|
||||||
MemoryPackFormatterProvider.Register(new RelayTestInfoFormatter());
|
MemoryPackFormatterProvider.Register(new RelayTestInfoFormatter());
|
||||||
MemoryPackFormatterProvider.Register(new RelayInfoFormatter());
|
MemoryPackFormatterProvider.Register(new RelayInfoFormatter());
|
||||||
|
MemoryPackFormatterProvider.Register(new RelayServerNodeUpdateInfoFormatter());
|
||||||
MemoryPackFormatterProvider.Register(new RelayServerNodeReportInfoFormatter());
|
MemoryPackFormatterProvider.Register(new RelayServerNodeReportInfoFormatter());
|
||||||
MemoryPackFormatterProvider.Register(new RelayAskResultInfoFormatter());
|
MemoryPackFormatterProvider.Register(new RelayAskResultInfoFormatter());
|
||||||
MemoryPackFormatterProvider.Register(new RelayCacheInfoFormatter());
|
MemoryPackFormatterProvider.Register(new RelayCacheInfoFormatter());
|
||||||
|
@@ -150,6 +150,78 @@ namespace linker.messenger.serializer.memorypack
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MemoryPackable]
|
||||||
|
public readonly partial struct SerializableRelayServerNodeUpdateInfo
|
||||||
|
{
|
||||||
|
[MemoryPackIgnore]
|
||||||
|
public readonly RelayServerNodeUpdateInfo info;
|
||||||
|
|
||||||
|
[MemoryPackInclude]
|
||||||
|
string Name => info.Name;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
int MaxConnection => info.MaxConnection;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
double MaxBandwidth => info.MaxBandwidth;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
double MaxBandwidthTotal => info.MaxBandwidthTotal;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
double MaxGbTotal => info.MaxGbTotal;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
long MaxGbTotalLastBytes => info.MaxGbTotalLastBytes;
|
||||||
|
[MemoryPackInclude]
|
||||||
|
bool Public => info.Public;
|
||||||
|
|
||||||
|
[MemoryPackConstructor]
|
||||||
|
SerializableRelayServerNodeUpdateInfo(
|
||||||
|
string name,
|
||||||
|
int maxConnection, double maxBandwidth, double maxBandwidthTotal,
|
||||||
|
double maxGbTotal, long maxGbTotalLastBytes,
|
||||||
|
bool Public)
|
||||||
|
{
|
||||||
|
var info = new RelayServerNodeUpdateInfo
|
||||||
|
{
|
||||||
|
MaxBandwidth = maxBandwidth,
|
||||||
|
MaxBandwidthTotal = maxBandwidthTotal,
|
||||||
|
MaxConnection = maxConnection,
|
||||||
|
MaxGbTotal = maxGbTotal,
|
||||||
|
MaxGbTotalLastBytes = maxGbTotalLastBytes,
|
||||||
|
Name = name,
|
||||||
|
Public = Public
|
||||||
|
};
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SerializableRelayServerNodeUpdateInfo(RelayServerNodeUpdateInfo info)
|
||||||
|
{
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class RelayServerNodeUpdateInfoFormatter : MemoryPackFormatter<RelayServerNodeUpdateInfo>
|
||||||
|
{
|
||||||
|
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayServerNodeUpdateInfo value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
writer.WriteNullObjectHeader();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WritePackable(new SerializableRelayServerNodeUpdateInfo(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayServerNodeUpdateInfo value)
|
||||||
|
{
|
||||||
|
if (reader.PeekIsNull())
|
||||||
|
{
|
||||||
|
reader.Advance(1); // skip null block
|
||||||
|
value = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var wrapped = reader.ReadPackable<SerializableRelayServerNodeUpdateInfo>();
|
||||||
|
value = wrapped.info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[MemoryPackable]
|
[MemoryPackable]
|
||||||
|
@@ -29,6 +29,7 @@ namespace linker.messenger.store.file.relay
|
|||||||
info.Id = ObjectId.NewObjectId().ToString();
|
info.Id = ObjectId.NewObjectId().ToString();
|
||||||
info.AddTime = DateTime.Now;
|
info.AddTime = DateTime.Now;
|
||||||
info.UseTime = DateTime.Now;
|
info.UseTime = DateTime.Now;
|
||||||
|
info.StartTime = DateTime.Now;
|
||||||
info.LastBytes = info.MaxBytes;
|
info.LastBytes = info.MaxBytes;
|
||||||
info.CdkeyId = YitIdHelper.NextId();
|
info.CdkeyId = YitIdHelper.NextId();
|
||||||
info.OrderId = $"Linker{YitIdHelper.NextId()}";
|
info.OrderId = $"Linker{YitIdHelper.NextId()}";
|
||||||
@@ -60,7 +61,7 @@ namespace linker.messenger.store.file.relay
|
|||||||
RelayServerCdkeyOrderInfo order = result.Cdkey.DeJson<RelayServerCdkeyOrderInfo>();
|
RelayServerCdkeyOrderInfo order = result.Cdkey.DeJson<RelayServerCdkeyOrderInfo>();
|
||||||
result.Order = order;
|
result.Order = order;
|
||||||
|
|
||||||
if (order.WidgetUserId != info.UserId)
|
if (order.WidgetUserId != info.UserId || string.IsNullOrWhiteSpace(order.WidgetUserId))
|
||||||
{
|
{
|
||||||
error.Add("UserId");
|
error.Add("UserId");
|
||||||
}
|
}
|
||||||
@@ -106,36 +107,33 @@ namespace linker.messenger.store.file.relay
|
|||||||
}
|
}
|
||||||
RelayServerCdkeyOrderInfo order = test.Order;
|
RelayServerCdkeyOrderInfo order = test.Order;
|
||||||
var time = Regex.Match(order.Time, regex).Groups;
|
var time = Regex.Match(order.Time, regex).Groups;
|
||||||
for (int i = 0; i < order.Count; i++)
|
RelayServerCdkeyStoreInfo store = new RelayServerCdkeyStoreInfo
|
||||||
{
|
{
|
||||||
RelayServerCdkeyStoreInfo store = new RelayServerCdkeyStoreInfo
|
UseTime = DateTime.Now,
|
||||||
{
|
AddTime = DateTime.Now,
|
||||||
UseTime = DateTime.Now,
|
Bandwidth = order.Speed,
|
||||||
AddTime = DateTime.Now,
|
CostPrice = order.CostPrice,
|
||||||
Bandwidth = order.Speed,
|
EndTime = DateTime.Now
|
||||||
CostPrice = order.CostPrice,
|
.AddYears(int.Parse(time[1].Value))
|
||||||
EndTime = DateTime.Now
|
.AddMonths(int.Parse(time[2].Value))
|
||||||
.AddYears(int.Parse(time[1].Value))
|
.AddDays(int.Parse(time[3].Value))
|
||||||
.AddMonths(int.Parse(time[2].Value))
|
.AddHours(int.Parse(time[4].Value))
|
||||||
.AddDays(int.Parse(time[3].Value))
|
.AddMinutes(int.Parse(time[5].Value))
|
||||||
.AddHours(int.Parse(time[4].Value))
|
.AddSeconds(int.Parse(time[6].Value)),
|
||||||
.AddMinutes(int.Parse(time[5].Value))
|
LastBytes = order.Speed * 1024 * 1024 * 1024 * order.Count,
|
||||||
.AddSeconds(int.Parse(time[6].Value)),
|
MaxBytes = order.Speed * 1024 * 1024 * 1024 * order.Count,
|
||||||
LastBytes = order.Speed * 1024 * 1024 * 1024,
|
Price = order.Price,
|
||||||
MaxBytes = order.Speed * 1024 * 1024 * 1024,
|
Remark = "order",
|
||||||
Price = order.Price,
|
StartTime = DateTime.Now,
|
||||||
Remark = "order",
|
UserId = order.WidgetUserId,
|
||||||
StartTime = DateTime.Now,
|
CdkeyId = YitIdHelper.NextId(),
|
||||||
UserId = order.WidgetUserId,
|
Contact = order.Contact,
|
||||||
CdkeyId = YitIdHelper.NextId(),
|
OrderId = order.OrderId,
|
||||||
Contact = order.Contact,
|
PayPrice = order.PayPrice,
|
||||||
OrderId = order.OrderId,
|
UserPrice = order.UserPrice,
|
||||||
PayPrice = order.PayPrice,
|
Id = ObjectId.NewObjectId().ToString()
|
||||||
UserPrice = order.UserPrice,
|
};
|
||||||
Id = ObjectId.NewObjectId().ToString()
|
liteCollection.Insert(store);
|
||||||
};
|
|
||||||
liteCollection.Insert(store);
|
|
||||||
}
|
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,6 +22,17 @@ namespace linker.messenger.store.file.relay
|
|||||||
{
|
{
|
||||||
config.Data.Server.Relay.Distributed.Node = node;
|
config.Data.Server.Relay.Distributed.Node = node;
|
||||||
}
|
}
|
||||||
|
public void UpdateInfo(RelayServerNodeUpdateInfo update)
|
||||||
|
{
|
||||||
|
config.Data.Server.Relay.Distributed.Node.Name = update.Name;
|
||||||
|
config.Data.Server.Relay.Distributed.Node.MaxConnection = update.MaxConnection;
|
||||||
|
config.Data.Server.Relay.Distributed.Node.MaxBandwidth = update.MaxBandwidth;
|
||||||
|
config.Data.Server.Relay.Distributed.Node.MaxBandwidthTotal = update.MaxBandwidthTotal;
|
||||||
|
config.Data.Server.Relay.Distributed.Node.MaxGbTotal = update.MaxGbTotal;
|
||||||
|
config.Data.Server.Relay.Distributed.Node.MaxGbTotalLastBytes = update.MaxGbTotalLastBytes;
|
||||||
|
config.Data.Server.Relay.Distributed.Node.Public = update.Public;
|
||||||
|
|
||||||
|
}
|
||||||
public void SetMaxGbTotalLastBytes(long value)
|
public void SetMaxGbTotalLastBytes(long value)
|
||||||
{
|
{
|
||||||
config.Data.Server.Relay.Distributed.Node.MaxGbTotalLastBytes=value;
|
config.Data.Server.Relay.Distributed.Node.MaxGbTotalLastBytes=value;
|
||||||
|
@@ -23,4 +23,7 @@ export const relayCdkeyDel = (data) => {
|
|||||||
}
|
}
|
||||||
export const relayCdkeyMy = (data) => {
|
export const relayCdkeyMy = (data) => {
|
||||||
return sendWebsocketMsg('relay/MyCdkey', data);
|
return sendWebsocketMsg('relay/MyCdkey', data);
|
||||||
|
}
|
||||||
|
export const relayCdkeyTest = (data) => {
|
||||||
|
return sendWebsocketMsg('relay/TestCdkey', data);
|
||||||
}
|
}
|
@@ -141,7 +141,7 @@ export default {
|
|||||||
'server.relayCdkeyPayPrice': 'Pay price',
|
'server.relayCdkeyPayPrice': 'Pay price',
|
||||||
'server.relayCdkeyCostPrice': 'Cost price',
|
'server.relayCdkeyCostPrice': 'Cost price',
|
||||||
'server.relayCdkeyUserPrice': 'User price',
|
'server.relayCdkeyUserPrice': 'User price',
|
||||||
'server.relayCdkeyOrderId': 'Order No',
|
'server.relayCdkeyOrderId': 'OrderNo',
|
||||||
'server.relayCdkeyContact': 'Email',
|
'server.relayCdkeyContact': 'Email',
|
||||||
'server.relayCdkeyRemark': 'Remark',
|
'server.relayCdkeyRemark': 'Remark',
|
||||||
|
|
||||||
@@ -161,6 +161,14 @@ export default {
|
|||||||
'server.relayCdkeyOper': 'Oper',
|
'server.relayCdkeyOper': 'Oper',
|
||||||
'server.relayCdkeyDelConfirm': 'Are you sure to delete?',
|
'server.relayCdkeyDelConfirm': 'Are you sure to delete?',
|
||||||
|
|
||||||
|
'server.relayCdkeyFlagAll': 'All',
|
||||||
|
'server.relayCdkeyFlagTimein': 'In end time',
|
||||||
|
'server.relayCdkeyFlagTimeout': 'Out end time',
|
||||||
|
'server.relayCdkeyFlagBytesin': 'Has bytes',
|
||||||
|
'server.relayCdkeyFlagBytesout': 'Not have bytes',
|
||||||
|
'server.relayCdkeyFlagDeleted': 'Deleted',
|
||||||
|
'server.relayCdkeyFlagUnDeleted': 'Not deleted',
|
||||||
|
|
||||||
|
|
||||||
'server.sforwardSecretKey': 'Server forward secretKey',
|
'server.sforwardSecretKey': 'Server forward secretKey',
|
||||||
'server.sforwardText': 'The server forward can be used when the key is correct',
|
'server.sforwardText': 'The server forward can be used when the key is correct',
|
||||||
|
@@ -164,6 +164,35 @@ export default {
|
|||||||
'server.relayCdkeyOper': '操作',
|
'server.relayCdkeyOper': '操作',
|
||||||
'server.relayCdkeyDelConfirm': '确认删除吗?',
|
'server.relayCdkeyDelConfirm': '确认删除吗?',
|
||||||
|
|
||||||
|
'server.relayCdkeyFlagAll': '全部',
|
||||||
|
'server.relayCdkeyFlagTimein': '有效期内',
|
||||||
|
'server.relayCdkeyFlagTimeout': '有效期外',
|
||||||
|
'server.relayCdkeyFlagBytesin': '剩余',
|
||||||
|
'server.relayCdkeyFlagBytesout': '已用完',
|
||||||
|
'server.relayCdkeyFlagDeleted': '已删除',
|
||||||
|
'server.relayCdkeyFlagUnDeleted': '未删除',
|
||||||
|
|
||||||
|
'server.relayCdkeyTestTitle': '测试解密CDKEY',
|
||||||
|
'server.relayCdkeyTestKey': 'CDKEY',
|
||||||
|
'server.relayCdkeyTestGB': '流量',
|
||||||
|
'server.relayCdkeyTestGBError': '流量要大于0',
|
||||||
|
'server.relayCdkeyTestSpeed': '带宽Mbps',
|
||||||
|
'server.relayCdkeyTestSpeedError': '带宽要大于0',
|
||||||
|
'server.relayCdkeyTestTime': '持续时间',
|
||||||
|
'server.relayCdkeyTestTimeError': '格式错误',
|
||||||
|
'server.relayCdkeyTestUserId': '用户标识',
|
||||||
|
'server.relayCdkeyTestUserIdError': '用户标识不正确',
|
||||||
|
'server.relayCdkeyTestOrderId': '订单',
|
||||||
|
'server.relayCdkeyTestOrderIdError': '订单号不能为空',
|
||||||
|
'server.relayCdkeyTestContact': '联系方式',
|
||||||
|
'server.relayCdkeyTestCostPrice': '成本',
|
||||||
|
'server.relayCdkeyTestPrice': '原价',
|
||||||
|
'server.relayCdkeyTestUserPrice': '会员价',
|
||||||
|
'server.relayCdkeyTestPayPrice': '支付',
|
||||||
|
'server.relayCdkeyTestCount': '数量',
|
||||||
|
'server.relayCdkeyTestCountError': '数量要大于0',
|
||||||
|
'server.relayCdkeyTestParseError': '解密失败',
|
||||||
|
|
||||||
'server.sforwardSecretKey': '服务器穿透密钥',
|
'server.sforwardSecretKey': '服务器穿透密钥',
|
||||||
'server.sforwardText': '当密钥正确是可用',
|
'server.sforwardText': '当密钥正确是可用',
|
||||||
|
|
||||||
|
@@ -31,20 +31,19 @@
|
|||||||
<span v-else>{{ scope.row.MaxBandwidth }}Mbps</span>
|
<span v-else>{{ scope.row.MaxBandwidth }}Mbps</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column property="MaxBandwidthTotal" :label="$t('server.relaySpeed1')" width="80">
|
<el-table-column property="MaxBandwidthTotal" :label="`${$t('server.relaySpeed2')}/${$t('server.relaySpeed1')}`" width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span v-if="scope.row.MaxBandwidthTotal == 0">--</span>
|
<span>
|
||||||
<span v-else>{{ scope.row.MaxBandwidthTotal }}Mbps</span>
|
<span>{{scope.row.BandwidthRatio}}Mbps</span>
|
||||||
|
<span>/</span>
|
||||||
|
<span v-if="scope.row.MaxBandwidthTotal == 0">--</span>
|
||||||
|
<span v-else>{{ scope.row.MaxBandwidthTotal }}Mbps</span>
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column property="BandwidthRatio" :label="$t('server.relaySpeed2')" width="66">
|
<el-table-column property="ConnectionRatio" :label="$t('server.relayConnection')" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span>{{ (scope.row.BandwidthRatio*100).toFixed(2) }}%</span>
|
<span><strong>{{scope.row.ConnectionRatio}}</strong>/{{scope.row.MaxConnection}}</span>
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column property="ConnectionRatio" :label="$t('server.relayConnection')" width="60">
|
|
||||||
<template #default="scope">
|
|
||||||
<span>{{ (scope.row.ConnectionRatio*100).toFixed(2) }}%</span>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column property="Delay" :label="$t('server.relayDelay')" width="60">
|
<el-table-column property="Delay" :label="$t('server.relayDelay')" width="60">
|
||||||
|
139
src/linker.web/src/views/full/server/relayCdkey/Add.vue
Normal file
139
src/linker.web/src/views/full/server/relayCdkey/Add.vue
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog class="options-center" :title="$t('server.relayAddCdkey')" destroy-on-close v-model="state.show" width="60rem" top="2vh">
|
||||||
|
<div>
|
||||||
|
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-width="auto">
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyUserId')" prop="UserId">
|
||||||
|
<el-input maxlength="32" show-word-limit v-model="state.ruleForm.UserId" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyBandwidth')" prop="Bandwidth">
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.Bandwidth" :min="1" :max="102400" />Mbps
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyBytes')" prop="MaxBytes">
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.G" :min="0" :max="102400" />GB
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.M" :min="0" :max="1024" />MB
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.K" :min="0" :max="1024" />KB
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.B" :min="0" :max="1024" />B
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item></el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyDuration')" prop="EndTime">
|
||||||
|
<p>
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.Year" :min="0" />{{$t('server.relayCdkeyYear')}}
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.Month" :min="0" />{{$t('server.relayCdkeyMonth')}}
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.Day" :min="0" />{{$t('server.relayCdkeyDay')}}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.Hour" :min="0" />{{$t('server.relayCdkeyHour')}}
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.Min" :min="0" />{{$t('server.relayCdkeyMin')}}
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.Sec" :min="0" />{{$t('server.relayCdkeySec')}}
|
||||||
|
</p>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item></el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyCostPrice')" prop="CostPrice">
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.CostPrice" :min="0" />
|
||||||
|
{{ $t('server.relayCdkeyPrice') }}
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.Price" :min="0" />
|
||||||
|
{{ $t('server.relayCdkeyUserPrice') }}
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.UserPrice" :min="0" />
|
||||||
|
{{ $t('server.relayCdkeyPayPrice') }}
|
||||||
|
<el-input-number size="small" v-model="state.ruleForm.PayPrice" :min="0" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyRemark')" prop="Remark">
|
||||||
|
<el-input v-model="state.ruleForm.Remark" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyContact')" prop="Contact">
|
||||||
|
<el-input v-model="state.ruleForm.Contact" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item></el-form-item>
|
||||||
|
<el-form-item label="" prop="Btns">
|
||||||
|
<div class="t-c w-100">
|
||||||
|
<el-button @click="state.show = false">{{$t('common.cancel')}}</el-button>
|
||||||
|
<el-button type="primary" @click="handleSave">{{$t('common.confirm')}}</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { reactive, ref, watch } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import moment from "moment";
|
||||||
|
import { relayCdkeyAdd } from '@/apis/relay';
|
||||||
|
export default {
|
||||||
|
props: ['modelValue'],
|
||||||
|
emits: ['update:modelValue','success'],
|
||||||
|
setup(props,{emit}) {
|
||||||
|
const {t} = useI18n();
|
||||||
|
const state = reactive({
|
||||||
|
show:true,
|
||||||
|
ruleForm:{
|
||||||
|
UserId:'',
|
||||||
|
Bandwidth:1,
|
||||||
|
G:1,
|
||||||
|
M:0,
|
||||||
|
K:0,
|
||||||
|
B:0,
|
||||||
|
Year:1,
|
||||||
|
Month:0,
|
||||||
|
Day:0,
|
||||||
|
Hour:0,
|
||||||
|
Min:0,
|
||||||
|
Sec:0,
|
||||||
|
CostPrice:0,
|
||||||
|
Price:0,
|
||||||
|
UserPrice:0,
|
||||||
|
PayPrice:0,
|
||||||
|
Remark:'hand',
|
||||||
|
Contact:'',
|
||||||
|
},
|
||||||
|
rules:{
|
||||||
|
UserId: [{ required: true, message: "required", trigger: "blur" }],
|
||||||
|
Remark: [{ required: true, message: "required", trigger: "blur" }],
|
||||||
|
}
|
||||||
|
});
|
||||||
|
watch(() => state.show, (val) => {
|
||||||
|
if (!val) {
|
||||||
|
setTimeout(() => {
|
||||||
|
emit('update:modelValue', val);
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const ruleFormRef = ref(null);
|
||||||
|
const handleSave = ()=>{
|
||||||
|
ruleFormRef.value.validate((valid) => {
|
||||||
|
if (!valid) return;
|
||||||
|
|
||||||
|
const json = JSON.parse(JSON.stringify(state.ruleForm));
|
||||||
|
|
||||||
|
const date = new Date();
|
||||||
|
const end = new Date(date.getFullYear()+json.Year,date.getMonth()+json.Month,date.getDate()+json.Day,date.getHours()+json.Hour,date.getMinutes()+json.Min,date.getSeconds()+json.Sec);
|
||||||
|
json.EndTime = moment(end).format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
json.MaxBytes = json.G*1024*1024*1024 + json.M*1024*1024 + json.K*1024 + json.B;
|
||||||
|
|
||||||
|
relayCdkeyAdd(json).then(()=>{
|
||||||
|
ElMessage.success(t('common.oper'));
|
||||||
|
state.show = false;
|
||||||
|
emit('success');
|
||||||
|
}).catch(()=>{
|
||||||
|
ElMessage.error(t('common.operFail'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {state,ruleFormRef,handleSave}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.el-form-item{margin-bottom:1rem}
|
||||||
|
.el-input-number--small{width:10rem !important}
|
||||||
|
</style>
|
50
src/linker.web/src/views/full/server/relayCdkey/Flags.vue
Normal file
50
src/linker.web/src/views/full/server/relayCdkey/Flags.vue
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<div class="wrap">
|
||||||
|
<el-radio-group v-model="state.time" size="small" @change="handleChange">
|
||||||
|
<el-radio-button :label="$t('server.relayCdkeyFlagAll')" :value="0" />
|
||||||
|
<el-radio-button :label="$t('server.relayCdkeyFlagTimein')" :value="1" />
|
||||||
|
<el-radio-button :label="$t('server.relayCdkeyFlagTimeout')" :value="2"/>
|
||||||
|
</el-radio-group>
|
||||||
|
<el-radio-group v-model="state.bytes" size="small" @change="handleChange">
|
||||||
|
<el-radio-button :label="$t('server.relayCdkeyFlagAll')" :value="0" />
|
||||||
|
<el-radio-button :label="$t('server.relayCdkeyFlagBytesin')" :value="4" />
|
||||||
|
<el-radio-button :label="$t('server.relayCdkeyFlagBytesout')" :value="8"/>
|
||||||
|
</el-radio-group>
|
||||||
|
<el-radio-group v-model="state.deleted" size="small" @change="handleChange">
|
||||||
|
<el-radio-button :label="$t('server.relayCdkeyFlagAll')" :value="0" />
|
||||||
|
<el-radio-button :label="$t('server.relayCdkeyFlagUnDeleted')" :value="16" />
|
||||||
|
<el-radio-button :label="$t('server.relayCdkeyFlagDeleted')" :value="32"/>
|
||||||
|
</el-radio-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { onMounted, reactive } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
emits:['change'],
|
||||||
|
setup (props,{emit}) {
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
time: 1,
|
||||||
|
bytes: 4,
|
||||||
|
deleted: 16,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleChange = () => {
|
||||||
|
emit('change',state.time | state.bytes | state.deleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
handleChange();
|
||||||
|
})
|
||||||
|
|
||||||
|
return {state,handleChange}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.el-radio-group{margin-right:.6rem}
|
||||||
|
.wrap{padding-bottom:1rem}
|
||||||
|
</style>
|
@@ -20,7 +20,7 @@ export default {
|
|||||||
const state = reactive({
|
const state = reactive({
|
||||||
hasRelayCdkey:false,
|
hasRelayCdkey:false,
|
||||||
showManager:false,
|
showManager:false,
|
||||||
showMy:false
|
showMy:true
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
|
@@ -1,21 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog class="options-center" :title="$t('server.relayCdkey')" destroy-on-close v-model="state.show" width="77rem" top="2vh">
|
<el-dialog class="options-center" :title="$t('server.relayCdkey')" destroy-on-close v-model="state.show" width="77rem" top="2vh">
|
||||||
<div class="group-wrap">
|
<div class="group-wrap">
|
||||||
<div class="head flex">
|
<div class="head">
|
||||||
<div><span>{{$t('server.relayCdkeyUserId')}}</span> <el-input v-model="state.page.UserId" style="width:10rem" size="small" clearable @change="handleSearch" /></div>
|
<div class="search flex">
|
||||||
<div><span>{{$t('server.relayCdkeyOrderId')}}</span> <el-input v-model="state.page.OrderId" style="width:10rem" size="small" clearable @change="handleSearch" /></div>
|
<div><span>{{$t('server.relayCdkeyUserId')}}</span> <el-input v-model="state.page.UserId" style="width:8rem" size="small" clearable @change="handleSearch" /></div>
|
||||||
<div><span>{{$t('server.relayCdkeyContact')}}</span> <el-input v-model="state.page.Contact" style="width:10rem" size="small" clearable @change="handleSearch" /></div>
|
<div><span>{{$t('server.relayCdkeyOrderId')}}</span> <el-input v-model="state.page.OrderId" style="width:8rem" size="small" clearable @change="handleSearch" /></div>
|
||||||
<div><span>{{$t('server.relayCdkeyRemark')}}</span> <el-input v-model="state.page.Remark" style="width:10rem" size="small" clearable @change="handleSearch" /></div>
|
<div><span>{{$t('server.relayCdkeyContact')}}</span> <el-input v-model="state.page.Contact" style="width:8rem" size="small" clearable @change="handleSearch" /></div>
|
||||||
<div>
|
<div><span>{{$t('server.relayCdkeyRemark')}}</span> <el-input v-model="state.page.Remark" style="width:8rem" size="small" clearable @change="handleSearch" /></div>
|
||||||
<el-button size="small" @click="handleSearch()">
|
<div>
|
||||||
<el-icon><Search /></el-icon>
|
<el-button size="small" @click="handleSearch()">
|
||||||
</el-button>
|
<el-icon><Search /></el-icon>
|
||||||
</div>
|
</el-button>
|
||||||
<div>
|
</div>
|
||||||
<el-button size="small" type="success" @click="handleAdd()">
|
<div>
|
||||||
<el-icon><Plus /></el-icon>
|
<el-button size="small" @click="state.showTest = true">
|
||||||
</el-button>
|
<el-icon><Warning /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-button size="small" type="success" @click="state.showAdd = true">
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Flags @change="handleFlagsChange"></Flags>
|
||||||
</div>
|
</div>
|
||||||
<el-table stripe :data="state.list.List" border size="small" width="100%" @sort-change="handleSort">
|
<el-table stripe :data="state.list.List" border size="small" width="100%" @sort-change="handleSort">
|
||||||
<el-table-column prop="Bandwidth" :label="$t('server.relayCdkeyBandwidth')" width="110" sortable="custom">
|
<el-table-column prop="Bandwidth" :label="$t('server.relayCdkeyBandwidth')" width="110" sortable="custom">
|
||||||
@@ -39,8 +47,7 @@
|
|||||||
<p>{{ scope.row.Contact }}</p>
|
<p>{{ scope.row.Contact }}</p>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="Remark" :label="$t('server.relayCdkeyRemark')">
|
<el-table-column prop="Remark" :label="$t('server.relayCdkeyRemark')"></el-table-column>
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="EndTime" :label="`${$t('server.relayCdkeyEndTime')}`" width="140" sortable="custom">
|
<el-table-column prop="EndTime" :label="`${$t('server.relayCdkeyEndTime')}`" width="140" sortable="custom">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="UseTime" :label="`${$t('server.relayCdkeyUseTime')}`" width="140" sortable="custom">
|
<el-table-column prop="UseTime" :label="`${$t('server.relayCdkeyUseTime')}`" width="140" sortable="custom">
|
||||||
@@ -72,105 +79,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog class="options-center" :title="$t('server.relayAddCdkey')" destroy-on-close v-model="state.showAdd" width="60rem" top="2vh">
|
<Add v-if="state.showAdd" v-model="state.showAdd" @success="handleSearch"></Add>
|
||||||
<div>
|
<Test v-if="state.showTest" v-model="state.showTest"></Test>
|
||||||
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-width="auto">
|
|
||||||
<el-form-item :label="$t('server.relayCdkeyUserId')" prop="UserId">
|
|
||||||
<el-input maxlength="32" show-word-limit v-model="state.ruleForm.UserId" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="$t('server.relayCdkeyBandwidth')" prop="Bandwidth">
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.Bandwidth" :min="1" :max="102400" />Mbps
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="$t('server.relayCdkeyBytes')" prop="MaxBytes">
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.G" :min="0" :max="102400" />GB
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.M" :min="0" :max="1024" />MB
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.K" :min="0" :max="1024" />KB
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.B" :min="0" :max="1024" />B
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item></el-form-item>
|
|
||||||
<el-form-item :label="$t('server.relayCdkeyDuration')" prop="EndTime">
|
|
||||||
<p>
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.Year" :min="0" />{{$t('server.relayCdkeyYear')}}
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.Month" :min="0" />{{$t('server.relayCdkeyMonth')}}
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.Day" :min="0" />{{$t('server.relayCdkeyDay')}}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.Hour" :min="0" />{{$t('server.relayCdkeyHour')}}
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.Min" :min="0" />{{$t('server.relayCdkeyMin')}}
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.Sec" :min="0" />{{$t('server.relayCdkeySec')}}
|
|
||||||
</p>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item></el-form-item>
|
|
||||||
<el-form-item :label="$t('server.relayCdkeyCostPrice')" prop="CostPrice">
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.CostPrice" :min="0" />
|
|
||||||
{{ $t('server.relayCdkeyPrice') }}
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.Price" :min="0" />
|
|
||||||
{{ $t('server.relayCdkeyUserPrice') }}
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.UserPrice" :min="0" />
|
|
||||||
{{ $t('server.relayCdkeyPayPrice') }}
|
|
||||||
<el-input-number size="small" v-model="state.ruleForm.PayPrice" :min="0" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="">
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item :label="$t('server.relayCdkeyRemark')" prop="Remark">
|
|
||||||
<el-input v-model="state.ruleForm.Remark" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item :label="$t('server.relayCdkeyContact')" prop="Contact">
|
|
||||||
<el-input v-model="state.ruleForm.Contact" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item></el-form-item>
|
|
||||||
<el-form-item label="" prop="Btns">
|
|
||||||
<div class="t-c w-100">
|
|
||||||
<el-button @click="state.showAdd = false">取消</el-button>
|
|
||||||
<el-button type="primary" @click="handleSave">确认</el-button>
|
|
||||||
</div>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { injectGlobalData } from '@/provide';
|
import { injectGlobalData } from '@/provide';
|
||||||
import { ElMessage } from 'element-plus';
|
import { onMounted, reactive, watch } from 'vue'
|
||||||
import { onMounted, reactive, ref, watch } from 'vue'
|
import { Delete,Plus,Search,Warning } from '@element-plus/icons-vue';
|
||||||
import { Delete,Plus,Search } from '@element-plus/icons-vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import moment from "moment";
|
import { relayCdkeyDel,relayCdkeyPage } from '@/apis/relay';
|
||||||
import { relayCdkeyAdd,relayCdkeyDel,relayCdkeyPage } from '@/apis/relay';
|
import Flags from './Flags.vue';
|
||||||
|
import Add from './Add.vue';
|
||||||
|
import Test from './Test.vue';
|
||||||
export default {
|
export default {
|
||||||
props: ['modelValue'],
|
props: ['modelValue'],
|
||||||
emits: ['update:modelValue'],
|
emits: ['update:modelValue'],
|
||||||
components:{Delete,Plus,Search },
|
components:{Delete,Plus,Search ,Flags,Add,Test,Warning},
|
||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
const {t} = useI18n();
|
const {t} = useI18n();
|
||||||
const globalData = injectGlobalData();
|
const globalData = injectGlobalData();
|
||||||
const defaultJson = {
|
|
||||||
UserId:'',
|
|
||||||
Bandwidth:1,
|
|
||||||
G:1,
|
|
||||||
M:0,
|
|
||||||
K:0,
|
|
||||||
B:0,
|
|
||||||
Year:1,
|
|
||||||
Month:0,
|
|
||||||
Day:0,
|
|
||||||
Hour:0,
|
|
||||||
Min:0,
|
|
||||||
Sec:0,
|
|
||||||
CostPrice:0,
|
|
||||||
Price:0,
|
|
||||||
UserPrice:0,
|
|
||||||
PayPrice:0,
|
|
||||||
Remark:'hand',
|
|
||||||
Contact:'',
|
|
||||||
};
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
page:{
|
page:{
|
||||||
Page:1,
|
Page:1,
|
||||||
@@ -181,6 +109,7 @@ export default {
|
|||||||
OrderId:'',
|
OrderId:'',
|
||||||
Contact:'',
|
Contact:'',
|
||||||
Remark:'',
|
Remark:'',
|
||||||
|
Flag:0
|
||||||
},
|
},
|
||||||
list:{
|
list:{
|
||||||
Page:1,
|
Page:1,
|
||||||
@@ -190,11 +119,7 @@ export default {
|
|||||||
},
|
},
|
||||||
show:true,
|
show:true,
|
||||||
showAdd:false,
|
showAdd:false,
|
||||||
ruleForm:JSON.parse(JSON.stringify(defaultJson)),
|
showTest:false
|
||||||
rules:{
|
|
||||||
UserId: [{ required: true, message: "required", trigger: "blur" }],
|
|
||||||
Remark: [{ required: true, message: "required", trigger: "blur" }],
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
watch(() => state.show, (val) => {
|
watch(() => state.show, (val) => {
|
||||||
if (!val) {
|
if (!val) {
|
||||||
@@ -212,6 +137,10 @@ export default {
|
|||||||
return `${(num*1.0).toFixed(2)}${['B', 'KB', 'MB', 'GB', 'TB'][index]}`;
|
return `${(num*1.0).toFixed(2)}${['B', 'KB', 'MB', 'GB', 'TB'][index]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleFlagsChange = (flag)=>{
|
||||||
|
state.page.Flag = flag;
|
||||||
|
handleSearch();
|
||||||
|
}
|
||||||
const handleSearch = ()=>{
|
const handleSearch = ()=>{
|
||||||
relayCdkeyPage(state.page).then((res)=>{
|
relayCdkeyPage(state.page).then((res)=>{
|
||||||
state.list = res;
|
state.list = res;
|
||||||
@@ -227,50 +156,26 @@ export default {
|
|||||||
handleSearch();
|
handleSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAdd = (row)=>{
|
|
||||||
state.ruleForm = JSON.parse(JSON.stringify(defaultJson));
|
|
||||||
state.showAdd = true;
|
|
||||||
}
|
|
||||||
const handleDel = (row)=>{
|
const handleDel = (row)=>{
|
||||||
relayCdkeyDel(row.CdkeyId).then((res)=>{
|
relayCdkeyDel(row.CdkeyId).then((res)=>{
|
||||||
handleSearch();
|
handleSearch();
|
||||||
}).catch(()=>{})
|
}).catch(()=>{})
|
||||||
}
|
}
|
||||||
const ruleFormRef = ref(null);
|
|
||||||
const handleSave = ()=>{
|
|
||||||
ruleFormRef.value.validate((valid) => {
|
|
||||||
if (!valid) return;
|
|
||||||
|
|
||||||
const json = JSON.parse(JSON.stringify(state.ruleForm));
|
|
||||||
|
|
||||||
const date = new Date();
|
|
||||||
const end = new Date(date.getFullYear()+json.Year,date.getMonth()+json.Month,date.getDate()+json.Day,date.getHours()+json.Hour,date.getMinutes()+json.Min,date.getSeconds()+json.Sec);
|
|
||||||
json.EndTime = moment(end).format("YYYY-MM-DD HH:mm:ss");
|
|
||||||
json.MaxBytes = json.G*1024*1024*1024 + json.M*1024*1024 + json.K*1024 + json.B;
|
|
||||||
|
|
||||||
relayCdkeyAdd(json).then(()=>{
|
|
||||||
ElMessage.success(t('common.oper'));
|
|
||||||
state.showAdd = false;
|
|
||||||
handleSearch();
|
|
||||||
}).catch(()=>{
|
|
||||||
ElMessage.error(t('common.operFail'));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
handleSearch();
|
handleSearch();
|
||||||
})
|
})
|
||||||
|
|
||||||
return {state,ruleFormRef,parseSpeed,handleSort,handleSearch,handlePageChange,handleAdd,handleDel,handleSave}
|
return {state,parseSpeed,handleSort,handleFlagsChange,handleSearch,handlePageChange,handleDel}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.head{
|
.head{
|
||||||
&>div{
|
.search{
|
||||||
margin-right:1rem;
|
&>div{
|
||||||
|
margin-right:1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.page{
|
.page{
|
||||||
|
@@ -1,15 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog class="options-center" :title="$t('server.relayMyCdkey')" destroy-on-close v-model="state.show" width="77rem" top="2vh">
|
<el-dialog class="options-center" :title="$t('server.relayMyCdkey')" destroy-on-close v-model="state.show" width="77rem" top="2vh">
|
||||||
<div class="group-wrap">
|
<div class="group-wrap">
|
||||||
<div class="head flex">
|
<div class="head">
|
||||||
<div><span>{{$t('server.relayCdkeyOrderId')}}</span> <el-input v-model="state.page.OrderId" style="width:10rem" size="small" clearable @change="handleSearch" /></div>
|
<div class="search flex">
|
||||||
<div><span>{{$t('server.relayCdkeyContact')}}</span> <el-input v-model="state.page.Contact" style="width:10rem" size="small" clearable @change="handleSearch" /></div>
|
<div><span>{{$t('server.relayCdkeyOrderId')}}</span> <el-input v-model="state.page.OrderId" style="width:10rem" size="small" clearable @change="handleSearch" /></div>
|
||||||
<div><span>{{$t('server.relayCdkeyRemark')}}</span> <el-input v-model="state.page.Remark" style="width:10rem" size="small" clearable @change="handleSearch" /></div>
|
<div><span>{{$t('server.relayCdkeyContact')}}</span> <el-input v-model="state.page.Contact" style="width:10rem" size="small" clearable @change="handleSearch" /></div>
|
||||||
<div>
|
<div><span>{{$t('server.relayCdkeyRemark')}}</span> <el-input v-model="state.page.Remark" style="width:10rem" size="small" clearable @change="handleSearch" /></div>
|
||||||
<el-button size="small" @click="handleSearch()">
|
<div>
|
||||||
<el-icon><Search /></el-icon>
|
<el-button size="small" @click="handleSearch()">
|
||||||
</el-button>
|
<el-icon><Search /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Flags @change="handleFlagsChange"></Flags>
|
||||||
</div>
|
</div>
|
||||||
<el-table stripe :data="state.list.List" border size="small" width="100%" @sort-change="handleSort">
|
<el-table stripe :data="state.list.List" border size="small" width="100%" @sort-change="handleSort">
|
||||||
<el-table-column prop="Bandwidth" :label="$t('server.relayCdkeyBandwidth')" width="110" sortable="custom">
|
<el-table-column prop="Bandwidth" :label="$t('server.relayCdkeyBandwidth')" width="110" sortable="custom">
|
||||||
@@ -75,10 +78,11 @@ import { onMounted, reactive, watch } from 'vue'
|
|||||||
import { Delete,Plus,Search } from '@element-plus/icons-vue';
|
import { Delete,Plus,Search } from '@element-plus/icons-vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import {relayCdkeyMy,relayCdkeyDel } from '@/apis/relay';
|
import {relayCdkeyMy,relayCdkeyDel } from '@/apis/relay';
|
||||||
|
import Flags from './Flags.vue';
|
||||||
export default {
|
export default {
|
||||||
props: ['modelValue'],
|
props: ['modelValue'],
|
||||||
emits: ['update:modelValue'],
|
emits: ['update:modelValue'],
|
||||||
components:{Delete,Plus,Search },
|
components:{Delete,Plus,Search,Flags },
|
||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
const {t} = useI18n();
|
const {t} = useI18n();
|
||||||
const globalData = injectGlobalData();
|
const globalData = injectGlobalData();
|
||||||
@@ -91,6 +95,7 @@ export default {
|
|||||||
OrderId:'',
|
OrderId:'',
|
||||||
Contact:'',
|
Contact:'',
|
||||||
Remark:'',
|
Remark:'',
|
||||||
|
Flag:0
|
||||||
},
|
},
|
||||||
list:{
|
list:{
|
||||||
Page:1,
|
Page:1,
|
||||||
@@ -116,6 +121,10 @@ export default {
|
|||||||
return `${(num*1.0).toFixed(2)}${['B', 'KB', 'MB', 'GB', 'TB'][index]}`;
|
return `${(num*1.0).toFixed(2)}${['B', 'KB', 'MB', 'GB', 'TB'][index]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleFlagsChange = (flag)=>{
|
||||||
|
state.page.Flag = flag;
|
||||||
|
handleSearch();
|
||||||
|
}
|
||||||
const handleSearch = ()=>{
|
const handleSearch = ()=>{
|
||||||
relayCdkeyMy(state.page).then((res)=>{
|
relayCdkeyMy(state.page).then((res)=>{
|
||||||
state.list = res;
|
state.list = res;
|
||||||
@@ -139,14 +148,16 @@ export default {
|
|||||||
handleSearch();
|
handleSearch();
|
||||||
})
|
})
|
||||||
|
|
||||||
return {state,parseSpeed,handleSort,handleSearch,handlePageChange,handleDel}
|
return {state,parseSpeed,handleSort,handleFlagsChange,handleSearch,handlePageChange,handleDel}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.head{
|
.head{
|
||||||
&>div{
|
.search{
|
||||||
margin-right:1rem;
|
&>div{
|
||||||
|
margin-right:1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.page{
|
.page{
|
||||||
|
189
src/linker.web/src/views/full/server/relayCdkey/Test.vue
Normal file
189
src/linker.web/src/views/full/server/relayCdkey/Test.vue
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog class="options-center" :title="$t('server.relayCdkeyTestTitle')" destroy-on-close v-model="state.show" width="40rem" top="2vh">
|
||||||
|
<div>
|
||||||
|
<el-form ref="ruleFormRef" :model="state.ruleForm" :rules="state.rules" label-width="auto">
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyTestKey')" prop="Base64">
|
||||||
|
<el-input v-model="state.Base64" @change="handleChange" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="" v-if="state.ruleForm.Field.indexOf('Parse')>=0">
|
||||||
|
<div class="t-c w-100">
|
||||||
|
<span class="red">{{$t('server.relayCdkeyTestParseError')}}</span>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyTestGB')" prop="GB">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18">
|
||||||
|
<el-input v-model="state.ruleForm.Order.GB" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<span class="red" v-if="state.ruleForm.Field.indexOf('GB')>=0">{{$t('server.relayCdkeyTestGBError')}}</span>
|
||||||
|
<span v-else class="green">success</span>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyTestSpeed')" prop="Speed">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18">
|
||||||
|
<el-input v-model="state.ruleForm.Order.Speed" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<span class="red" v-if="state.ruleForm.Field.indexOf('Speed')>=0">{{$t('server.relayCdkeyTestSpeedError')}}</span>
|
||||||
|
<span v-else class="green">success</span>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyTestTime')" prop="Time">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18">
|
||||||
|
<el-input v-model="state.ruleForm.Order.Time" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<span class="red" v-if="state.ruleForm.Field.indexOf('Time')>=0">{{$t('server.relayCdkeyTestTimeError')}}</span>
|
||||||
|
<span v-else class="green">success</span>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyTestUserId')" prop="WidgetUserId">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18">
|
||||||
|
<el-input v-model="state.ruleForm.Order.WidgetUserId" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<span class="red" v-if="state.ruleForm.Field.indexOf('UserId')>=0">{{$t('server.relayCdkeyTestUserIdError')}}</span>
|
||||||
|
<span v-else class="green">success</span>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyTestOrderId')" prop="OrderId">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18">
|
||||||
|
<el-input v-model="state.ruleForm.Order.OrderId" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<span class="red" v-if="state.ruleForm.Field.indexOf('OrderId')>=0">{{$t('server.relayCdkeyTestOrderIdError')}}</span>
|
||||||
|
<span v-else class="green">success</span>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyTestContact')" prop="Contact">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18">
|
||||||
|
<el-input v-model="state.ruleForm.Order.Contact" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<span class="red" v-if="state.ruleForm.Field.indexOf('Contact')>=0">{{$t('server.relayCdkeyTestContactError')}}</span>
|
||||||
|
<span v-else class="green">success</span>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyTestCostPrice')" prop="CostPrice">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18">
|
||||||
|
<el-input v-model="state.ruleForm.Order.CostPrice" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<span class="red" v-if="state.ruleForm.Field.indexOf('CostPrice')>=0">{{$t('server.relayCdkeyTestCostPriceError')}}</span>
|
||||||
|
<span v-else class="green">success</span>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyTestPrice')" prop="Price">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18">
|
||||||
|
<el-input v-model="state.ruleForm.Order.Price" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<span class="red" v-if="state.ruleForm.Field.indexOf('Price')>=0">{{$t('server.relayCdkeyTestPriceError')}}</span>
|
||||||
|
<span v-else class="green">success</span>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyTestUserPrice')" prop="UserPrice">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18">
|
||||||
|
<el-input v-model="state.ruleForm.Order.UserPrice" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<span class="red" v-if="state.ruleForm.Field.indexOf('UserPrice')>=0">{{$t('server.relayCdkeyTestUserPriceError')}}</span>
|
||||||
|
<span v-else class="green">success</span>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyTestPayPrice')" prop="PayPrice">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18">
|
||||||
|
<el-input v-model="state.ruleForm.Order.PayPrice" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<span class="red" v-if="state.ruleForm.Field.indexOf('PayPrice')>=0">{{$t('server.relayCdkeyTestPayPriceError')}}</span>
|
||||||
|
<span v-else class="green">success</span>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('server.relayCdkeyTestCount')" prop="Count">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18">
|
||||||
|
<el-input v-model="state.ruleForm.Order.Count" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<span class="red" v-if="state.ruleForm.Field.indexOf('Count')>=0">{{$t('server.relayCdkeyTestCountError')}}</span>
|
||||||
|
<span v-else class="green">success</span>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="" prop="Btns">
|
||||||
|
<div class="t-c w-100">
|
||||||
|
<el-button @click="state.show = false">{{$t('common.cancel')}}</el-button>
|
||||||
|
<el-button type="primary" @click="handleChange">{{$t('common.confirm')}}</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, watch } from 'vue'
|
||||||
|
import { Search } from '@element-plus/icons-vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { relayCdkeyTest } from '@/apis/relay';
|
||||||
|
export default {
|
||||||
|
props: ['modelValue'],
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
components:{Search},
|
||||||
|
setup(props,{emit}) {
|
||||||
|
const {t} = useI18n();
|
||||||
|
const state = reactive({
|
||||||
|
show:true,
|
||||||
|
Base64:'qn1vYOBtu81DkBI10nTTw7h/Vzi1Do3X1HI2+P5fflINL2wNPxrUYQPeOxUqgT+RcZSKLGF3dCMOyYBB+1VKmuI6ZaN86Whr1Xux2dY25tI5/3i/x/K1S78E6+E70ruh61phQZT3QLLVAHnIa2HpFhtPLKZaWc++ReSzixBqkW/sTT/l2iDqG2rl/zKynRM6srXWJkJr+2Msme1u5/Qu/0o6VaJ3ylv71HlB4zubNybQX5WMsOWrjN4/ruRSVF0LcayshqEfwlpeGR44nn5jMxpgQhxxpk/1flVImF00cC4=',
|
||||||
|
ruleForm:{
|
||||||
|
Order:{},
|
||||||
|
Cdkey:'',
|
||||||
|
Field:[],
|
||||||
|
},
|
||||||
|
rules:{}
|
||||||
|
});
|
||||||
|
watch(() => state.show, (val) => {
|
||||||
|
if (!val) {
|
||||||
|
setTimeout(() => {
|
||||||
|
emit('update:modelValue', val);
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleChange = ()=>{
|
||||||
|
relayCdkeyTest({Base64:state.Base64}).then(res=>{
|
||||||
|
if(res.Cdkey) state.ruleForm.Cdkey = res.Cdkey;
|
||||||
|
if(res.Field) state.ruleForm.Field = res.Field;
|
||||||
|
if(res.Order) state.ruleForm.Order = res.Order;
|
||||||
|
}).catch(()=>{})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {state,handleChange}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.el-form-item{margin-bottom:1rem}
|
||||||
|
.el-input-number--small{width:10rem !important}
|
||||||
|
</style>
|
@@ -2,6 +2,8 @@
|
|||||||
using System.ServiceProcess;
|
using System.ServiceProcess;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using linker.messenger.entry;
|
using linker.messenger.entry;
|
||||||
|
using linker.tunnel;
|
||||||
|
using linker.messenger.relay.client;
|
||||||
|
|
||||||
namespace linker
|
namespace linker
|
||||||
{
|
{
|
||||||
@@ -56,6 +58,7 @@ namespace linker
|
|||||||
LinkerMessengerEntry.Build();
|
LinkerMessengerEntry.Build();
|
||||||
LinkerMessengerEntry.Setup(ExcludeModule.None);
|
LinkerMessengerEntry.Setup(ExcludeModule.None);
|
||||||
|
|
||||||
|
|
||||||
LoggerHelper.Instance.Warning($"current version : {VersionHelper.version}");
|
LoggerHelper.Instance.Warning($"current version : {VersionHelper.version}");
|
||||||
LoggerHelper.Instance.Warning($"linker env is docker : {Environment.GetEnvironmentVariable("SNLTTY_LINKER_IS_DOCKER")}");
|
LoggerHelper.Instance.Warning($"linker env is docker : {Environment.GetEnvironmentVariable("SNLTTY_LINKER_IS_DOCKER")}");
|
||||||
LoggerHelper.Instance.Warning($"linker env os : {System.Runtime.InteropServices.RuntimeInformation.OSDescription}");
|
LoggerHelper.Instance.Warning($"linker env os : {System.Runtime.InteropServices.RuntimeInformation.OSDescription}");
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
v1.6.9
|
v1.6.9
|
||||||
2025-03-08 01:56:41
|
2025-03-08 19:25:04
|
||||||
1. 优化linux下路由跟踪问题
|
1. 优化linux下路由跟踪问题
|
||||||
2. 优化linux下获取本机IP问题
|
2. 优化linux下获取本机IP问题
|
||||||
3. 增加ICS,让win7+、win server2008+支持NAT
|
3. 增加ICS,让win7+、win server2008+支持NAT
|
||||||
|
Reference in New Issue
Block a user