This commit is contained in:
snltty
2025-03-08 01:56:41 +08:00
parent c6eeab74b9
commit 0d1e62f07d
24 changed files with 2247 additions and 213 deletions

View File

@@ -0,0 +1,7 @@
<?php
declare (strict_types=1);
return [
'STATUS' => '1',
'KeyId' => 'FAFAB92C-DFDF-1221-DEA2-40A0E915EB10',
];

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
use App\Consts\Plugin;
return [
Plugin::NAME => 'Linker',
Plugin::AUTHOR => 'snltty',
Plugin::WEB_SITE => '#',
Plugin::DESCRIPTION => '下单成功后加密卡密',
Plugin::VERSION => '1.0.0'
];

View File

@@ -0,0 +1,11 @@
<?php
declare (strict_types=1);
return [
[
"title" => "Key",
"name" => "KeyId",
"type" => "input",
"placeholder" => "加密秘钥"
]
];

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Plugin\Demo\Controller;
use App\Controller\Base\View\ManagePlugin;
use App\Interceptor\ManageSession;
use Kernel\Annotation\Interceptor;
/**
* Class Demo
* @package App\Plugin\Demo\Controller
*/
#[Interceptor(ManageSession::class)]
class Demo extends ManagePlugin
{
/**
* @throws \Kernel\Exception\ViewException
*/
public function test(): string
{
return $this->render(title: 'Demo', template: 'Demo.html', controller: true);
}
}

91
readme/Demo/Hook/Demo.php Normal file
View File

@@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
namespace App\Plugin\Demo\Hook;
use App\Controller\Base\View\ManagePlugin;
use Kernel\Annotation\Hook;
use App\Util\Plugin;
class Demo extends ManagePlugin
{
#[Hook(point: \App\Consts\Hook::USER_API_ORDER_PAY_AFTER)]
public function tradeAfter($commodity, $order, $pay)
{
$secret = json_decode($order->secret,true);
try{
$widget = json_decode($order->widget,true);
foreach($widget as $k=>$v){
$secret["Widget".$k] = $v["value"];
}
}catch(\Exception $e){
}
//file_put_contents("order.txt",json_encode($order,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
$secret["OrderId"] = "ACG".$order["trade_no"];
$secret["Contact"] = $order["contact"];
$secret["CostPrice"] = $order['commodity']["factory_price"];
$secret["Price"] = $order['commodity']["price"];
$secret["UserPrice"] = $order['commodity']["user_price"];
$secret["PayPrice"] = $order["amount"];
$secret["Count"] = $order["card_num"];
$order->secret = json_encode($secret,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$config = Plugin::getConfig("Demo");
$aesCrypto = new AesCrypto($config["KeyId"]);
$order->secret = base64_encode($aesCrypto->encode($order->secret));
$order->save();
}
}
class AesCrypto
{
private $key;
private $iv;
private $password;
public function __construct($password)
{
$this->password = $password;
$this->initAes();
}
private function initAes()
{
$keyAndIV = $this->generateKeyAndIV($this->password);
$this->key = $keyAndIV['key'];
$this->iv = $keyAndIV['iv'];
}
public function encode($data)
{
return $this->encodeWithOffset($data, 0, strlen($data));
}
public function encodeWithOffset($data, $offset, $length)
{
$data = substr($data, $offset, $length);
return openssl_encrypt($data, 'AES-128-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
}
public function decode($data)
{
return $this->decodeWithOffset($data, 0, strlen($data));
}
public function decodeWithOffset($data, $offset, $length)
{
$data = substr($data, $offset, $length);
return openssl_decrypt($data, 'AES-128-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
}
private function generateKeyAndIV($password)
{
$hash = hash('sha384', $password, true);
$key = substr($hash, 0, 16); // 取前 16 字节作为密钥
$iv = substr($hash, 16, 16); // 取接下来的 16 字节作为 IV
return ['key' => $key, 'iv' => $iv];
}
}

View File

@@ -0,0 +1,20 @@
#{include file=$manage_view_path|cat:"/Header.html"}
<!--begin::Content-->
<div class="content d-flex flex-column flex-column-fluid" id="kt_content">
<!--begin::Toolbar-->
#{include file=$manage_view_path|cat:"Toolbar.html"}
<!--end::Toolbar-->
<!--begin::Post-->
<div class="post d-flex flex-column-fluid">
<!--begin::Container-->
<div class="container-fluid">
ok
</div>
<!--end::Container-->
</div>
<!--end::Post-->
</div>
<!--end::Content-->
<script>
</script>
#{include file=$manage_view_path|cat:"Footer.html"}

1060
readme/OrderService.php Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -11,9 +11,9 @@ namespace linker.libs
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
public static ISymmetricCrypto CreateSymmetric(string password)
public static ISymmetricCrypto CreateSymmetric(string password, PaddingMode mode = PaddingMode.ANSIX923)
{
return new AesCrypto(password);
return new AesCrypto(password, mode);
}
}
@@ -38,11 +38,11 @@ namespace linker.libs
public string Password { get; set; }
public AesCrypto(string password)
public AesCrypto(string password, PaddingMode mode = PaddingMode.ANSIX923)
{
Password = password;
using Aes aes = Aes.Create();
aes.Padding = PaddingMode.ANSIX923;
aes.Padding = mode;
(aes.Key, aes.IV) = GenerateKeyAndIV(password);
encryptoTransform = aes.CreateEncryptor(aes.Key, aes.IV);

View File

@@ -68,7 +68,7 @@ namespace linker.messenger.relay
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
[Access(AccessValue.RelayCdkey)]
public async Task<bool> AddCdkey(ApiControllerParamsInfo param)
{
@@ -97,6 +97,7 @@ namespace linker.messenger.relay
Payload = serializer.Serialize(new RelayServerCdkeyDelInfo
{
CdkeyId = long.Parse(param.Content),
UserId = signInClientStore.Server.UserId,
SecretKey = relayClientStore.Server.SecretKey
})
});
@@ -141,6 +142,39 @@ namespace linker.messenger.relay
return new RelayServerCdkeyPageResultInfo();
}
public async Task<RelayServerCdkeyTestResultInfo> TestCdkey(ApiControllerParamsInfo param)
{
RelayServerCdkeyImportInfo info = param.Content.DeJson<RelayServerCdkeyImportInfo>();
info.SecretKey = relayClientStore.Server.SecretKey;
info.UserId = signInClientStore.Server.UserId;
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.TestCdkey,
Payload = serializer.Serialize(info)
});
if (resp.Code == MessageResponeCodes.OK)
{
return serializer.Deserialize<RelayServerCdkeyTestResultInfo>(resp.Data.Span);
}
return new RelayServerCdkeyTestResultInfo();
}
public async Task<bool> ImportCdkey(ApiControllerParamsInfo param)
{
RelayServerCdkeyImportInfo info = param.Content.DeJson<RelayServerCdkeyImportInfo>();
info.SecretKey = relayClientStore.Server.SecretKey;
info.UserId = signInClientStore.Server.UserId;
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.ImportCdkey,
Payload = serializer.Serialize(info)
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
}
public sealed class RelayConnectInfo

View File

@@ -177,90 +177,6 @@ namespace linker.messenger.relay.messenger
}
/// <summary>
/// 检查权限
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)RelayMessengerIds.AccessCdkey)]
public void AccessCdkey(IConnection connection)
{
string secretKey = serializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span);
connection.Write(relayServerStore.SecretKey == secretKey ? Helper.TrueArray : Helper.FalseArray);
}
/// <summary>
/// 添加CDKEY
/// </summary>
/// <param name="connection"></param>
[MessengerId((ushort)RelayMessengerIds.AddCdkey)]
public async Task AddCdkey(IConnection connection)
{
RelayServerCdkeyAddInfo info = serializer.Deserialize<RelayServerCdkeyAddInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
{
connection.Write(Helper.FalseArray);
return;
}
if (relayServerStore.SecretKey != info.SecretKey)
{
connection.Write(Helper.FalseArray);
return;
}
await relayServerCdkeyStore.Add(info.Data);
connection.Write(Helper.TrueArray);
}
/// <summary>
/// 删除Cdkey
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)RelayMessengerIds.DelCdkey)]
public async Task DelCdkey(IConnection connection)
{
RelayServerCdkeyDelInfo info = serializer.Deserialize<RelayServerCdkeyDelInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
{
connection.Write(Helper.FalseArray);
return;
}
if (relayServerStore.SecretKey != info.SecretKey)
{
connection.Write(Helper.FalseArray);
return;
}
await relayServerCdkeyStore.Del(info.CdkeyId);
connection.Write(Helper.TrueArray);
}
/// <summary>
/// 查询CDKEY
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)RelayMessengerIds.PageCdkey)]
public async Task PageCdkey(IConnection connection)
{
RelayServerCdkeyPageRequestInfo info = serializer.Deserialize<RelayServerCdkeyPageRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
{
connection.Write(serializer.Serialize(new RelayServerCdkeyPageResultInfo { }));
return;
}
if (relayServerStore.SecretKey != info.SecretKey && string.IsNullOrWhiteSpace(info.UserId))
{
connection.Write(serializer.Serialize(new RelayServerCdkeyPageResultInfo { }));
return;
}
var page = await relayServerCdkeyStore.Get(info);
connection.Write(serializer.Serialize(page));
}
/// <summary>
/// 获取缓存
/// </summary>
@@ -311,5 +227,132 @@ namespace linker.messenger.relay.messenger
Dictionary<long, long> result = await relayServerTransfer.AddTraffic(info);
connection.Write(serializer.Serialize(result));
}
/// <summary>
/// 检查权限
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)RelayMessengerIds.AccessCdkey)]
public void AccessCdkey(IConnection connection)
{
string secretKey = serializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span);
connection.Write(relayServerStore.SecretKey == secretKey ? Helper.TrueArray : Helper.FalseArray);
}
/// <summary>
/// 添加CDKEY
/// </summary>
/// <param name="connection"></param>
[MessengerId((ushort)RelayMessengerIds.AddCdkey)]
public async Task AddCdkey(IConnection connection)
{
RelayServerCdkeyAddInfo info = serializer.Deserialize<RelayServerCdkeyAddInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
{
connection.Write(Helper.FalseArray);
return;
}
if (relayServerStore.SecretKey != info.SecretKey)
{
connection.Write(Helper.FalseArray);
return;
}
await relayServerCdkeyStore.Add(info.Data);
connection.Write(Helper.TrueArray);
}
/// <summary>
/// 删除Cdkey
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)RelayMessengerIds.DelCdkey)]
public async Task DelCdkey(IConnection connection)
{
RelayServerCdkeyDelInfo info = serializer.Deserialize<RelayServerCdkeyDelInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
{
connection.Write(Helper.FalseArray);
return;
}
if (relayServerStore.SecretKey == info.SecretKey)
{
await relayServerCdkeyStore.Del(info.CdkeyId);
}
else
{
await relayServerCdkeyStore.Del(info.CdkeyId,info.UserId);
}
connection.Write(Helper.TrueArray);
}
/// <summary>
/// 查询CDKEY
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)RelayMessengerIds.PageCdkey)]
public async Task PageCdkey(IConnection connection)
{
RelayServerCdkeyPageRequestInfo info = serializer.Deserialize<RelayServerCdkeyPageRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
{
connection.Write(serializer.Serialize(new RelayServerCdkeyPageResultInfo { }));
return;
}
if (relayServerStore.SecretKey != info.SecretKey && string.IsNullOrWhiteSpace(info.UserId))
{
connection.Write(serializer.Serialize(new RelayServerCdkeyPageResultInfo { }));
return;
}
var page = await relayServerCdkeyStore.Page(info);
connection.Write(serializer.Serialize(page));
}
/// <summary>
/// 测试cdkey
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)RelayMessengerIds.TestCdkey)]
public async Task TestCdkey(IConnection connection)
{
RelayServerCdkeyImportInfo info = serializer.Deserialize<RelayServerCdkeyImportInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
{
connection.Write(serializer.Serialize(new RelayServerCdkeyTestResultInfo { }));
return;
}
if (relayServerStore.SecretKey != info.SecretKey)
{
connection.Write(serializer.Serialize(new RelayServerCdkeyTestResultInfo { }));
return;
}
RelayServerCdkeyTestResultInfo test = await relayServerCdkeyStore.Test(info);
connection.Write(serializer.Serialize(test));
}
/// <summary>
/// 导入cdkey
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)RelayMessengerIds.ImportCdkey)]
public async Task ImportCdkey(IConnection connection)
{
RelayServerCdkeyImportInfo info = serializer.Deserialize<RelayServerCdkeyImportInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
{
connection.Write(Helper.FalseArray);
return;
}
bool result = await relayServerCdkeyStore.Import(info);
connection.Write(result ? Helper.TrueArray : Helper.FalseArray);
}
}
}

View File

@@ -25,6 +25,9 @@
NodeReport = 2113,
TrafficReport = 2114,
TestCdkey = 2115,
ImportCdkey = 2116,
Max = 2199
}
}

View File

@@ -2,8 +2,38 @@
{
public interface IRelayServerCdkeyStore
{
/// <summary>
/// 添加
/// </summary>
/// <param name="info"></param>
/// <returns></returns>
public Task<bool> Add(RelayServerCdkeyStoreInfo info);
/// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public Task<bool> Del(long id);
/// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <param name="userid"></param>
/// <returns></returns>
public Task<bool> Del(long id, string userid);
/// <summary>
/// 测试卡密是否可用
/// </summary>
/// <param name="base64"></param>
/// <returns></returns>
public Task<RelayServerCdkeyTestResultInfo> Test(RelayServerCdkeyImportInfo info);
/// <summary>
/// 导入卡密
/// </summary>
/// <param name="base64"></param>
/// <returns></returns>
public Task<bool> Import(RelayServerCdkeyImportInfo info);
/// <summary>
/// 获取有效的CDKEY
@@ -11,30 +41,32 @@
/// <param name="userid"></param>
/// <returns></returns>
public Task<List<RelayServerCdkeyStoreInfo>> GetAvailable(string userid);
/// <summary>
/// 获取CDKEY列表
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
public Task<List<RelayServerCdkeyStoreInfo>> Get(List<long> ids);
/// <summary>
/// 消耗流量
/// </summary>
/// <param name="dic"></param>
/// <returns></returns>
public Task<bool> Traffic(Dictionary<long, long> dic);
public Task<RelayServerCdkeyPageResultInfo> Get(RelayServerCdkeyPageRequestInfo relayServerCdkeyPageRequestInfo);
/// <summary>
/// 分页
/// </summary>
/// <param name="relayServerCdkeyPageRequestInfo"></param>
/// <returns></returns>
public Task<RelayServerCdkeyPageResultInfo> Page(RelayServerCdkeyPageRequestInfo relayServerCdkeyPageRequestInfo);
}
public sealed class RelayServerCdkeyConfigInfo
{
/// <summary>
/// 获取可用的CDKEY
/// 加解密密钥
/// </summary>
public string CdkeyAvailablePostUrl { get; set; } = string.Empty;
/// <summary>
/// 分页获取CDKEY
/// </summary>
public string CdkeyPagePostUrl { get; set; } = string.Empty;
/// <summary>
/// id列表获取CDKEY
/// </summary>
public string CdkeyListPostUrl { get; set; } = string.Empty;
/// <summary>
/// 报告流量websocket
/// </summary>
public string CdkeyTrafficWsUrl { get; set; } = string.Empty;
public string SecretKey { get; set; } = Guid.NewGuid().ToString().ToUpper();
}
public sealed partial class RelayServerCdkeyPageRequestInfo
@@ -45,8 +77,23 @@
public string Sort { get; set; }
public string UserId { get; set; }
public string Remark { get; set; }
public string OrderId { get; set; }
public string Contact { get; set; }
public string SecretKey { get; set; }
public RelayServerCdkeyPageRequestFlag Flag { get; set; }
}
public enum RelayServerCdkeyPageRequestFlag
{
All = 0,
TimeIn = 1,
TimeOut = 2,
BytesIn = 4,
BytesOut = 8,
UnDeleted = 16,
Deleted = 32,
}
public sealed partial class RelayServerCdkeyPageResultInfo
{
public int Page { get; set; }
@@ -63,6 +110,7 @@
public sealed partial class RelayServerCdkeyDelInfo
{
public string SecretKey { get; set; }
public string UserId { get; set; }
public long CdkeyId { get; set; }
}
@@ -77,11 +125,6 @@
/// 用户标识
/// </summary>
public string UserId { get; set; }
/// <summary>
/// KEY
/// </summary>
public string CdKey { get; set; }
/// <summary>
/// 添加时间
/// </summary>
@@ -98,26 +141,112 @@
/// 最后使用时间
/// </summary>
public DateTime UseTime { get; set; }
/// <summary>
/// 允许节点
/// </summary>
public List<string> Nodes { get; set; }
/// <summary>
/// 流量
/// </summary>
public long MaxBytes { get; set; }
/// <summary>
/// 成本价
/// </summary>
public double CostPrice { get; set; }
/// <summary>
/// 原价
/// </summary>
public double Memory { get; set; }
public double Price { get; set; }
/// <summary>
/// 会员价
/// </summary>
public double UserPrice { get; set; }
/// <summary>
/// 支付金额
/// </summary>
public double PayMemory { get; set; }
public double PayPrice { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 订单号
/// </summary>
public string OrderId { get; set; }
/// <summary>
/// 联系方式
/// </summary>
public string Contact { get; set; }
/// <summary>
/// 已删除
/// </summary>
public bool Deleted { get; set; }
}
public sealed partial class RelayServerCdkeyTestResultInfo
{
public RelayServerCdkeyOrderInfo Order { get; set; }
public string Cdkey { get; set; }
public List<string> Field { get; set; } = new List<string>();
}
/// <summary>
/// 导入中继cdkey
/// </summary>
public sealed partial class RelayServerCdkeyImportInfo
{
public string SecretKey { get; set; }
public string UserId { get; set; }
public string Base64 { get; set; }
}
/// <summary>
/// 导入中继cdkey
/// </summary>
public sealed partial class RelayServerCdkeyOrderInfo
{
/// <summary>
/// 总流量
/// </summary>
public int GB { get; set; }
/// <summary>
/// 带宽
/// </summary>
public int Speed { get; set; }
/// <summary>
/// 有效年
/// </summary>
public string Time { get; set; }
/// <summary>
/// 用户标识
/// </summary>
public string WidgetUserId { get; set; }
/// <summary>
/// 订单号
/// </summary>
public string OrderId { get; set; }
/// <summary>
/// 联系方式
/// </summary>
public string Contact { get; set; }
/// <summary>
/// 成本价
/// </summary>
public double CostPrice { get; set; }
/// <summary>
/// 原价
/// </summary>
public double Price { get; set; }
/// <summary>
/// 会员价
/// </summary>
public double UserPrice { get; set; }
/// <summary>
/// 支付金额
/// </summary>
public double PayPrice { get; set; }
/// <summary>
/// 数量
/// </summary>
public int Count { get; set; }
}
}

View File

@@ -183,7 +183,8 @@ namespace linker.messenger.relay.server
Interlocked.Add(ref cache.Sendt, length);
if (cache.CurrentCdkey != null) return cache.CurrentCdkey.LastBytes > 0;
var current = cache.CurrentCdkey;
if (current != null) return current.LastBytes > 0;
return relayServerNodeStore.Node.MaxGbTotalLastBytes > 0;
}
@@ -210,6 +211,7 @@ namespace linker.messenger.relay.server
return;
}
relayCache.CurrentCdkey = null;
relayCache.Limit.SetLimit((uint)Math.Ceiling((relayServerNodeStore.Node.MaxBandwidth * 1024 * 1024) / 8.0));
}

View File

@@ -61,8 +61,11 @@ namespace linker.messenger.serializer.memorypack
MemoryPackFormatterProvider.Register(new RelayServerCdkeyPageResultInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayServerCdkeyAddInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayServerCdkeyDelInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayTrafficReportInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayTrafficUpdateInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayServerCdkeyImportInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayServerCdkeyTestResultInfoFormatter());
MemoryPackFormatterProvider.Register(new RelayServerCdkeyOrderInfoFormatter());
MemoryPackFormatterProvider.Register(new AccessUpdateInfoFormatter());
MemoryPackFormatterProvider.Register(new AccessInfoFormatter());

View File

@@ -510,14 +510,16 @@ namespace linker.messenger.serializer.memorypack
[MemoryPackInclude]
long CdkeyId => info.CdkeyId;
[MemoryPackInclude]
double Bandwidth => info.Bandwidth;
[MemoryPackInclude]
long LastBytes => info.LastBytes;
[MemoryPackInclude]
string Id => info.Id;
[MemoryPackInclude]
string UserId => info.UserId;
[MemoryPackInclude]
string CdKey => info.CdKey;
[MemoryPackInclude]
DateTime AddTime => info.AddTime;
[MemoryPackInclude]
@@ -526,42 +528,50 @@ namespace linker.messenger.serializer.memorypack
DateTime EndTime => info.EndTime;
[MemoryPackInclude]
DateTime UseTime => info.UseTime;
[MemoryPackInclude]
List<string> Nodes => info.Nodes;
[MemoryPackInclude]
double Bandwidth => info.Bandwidth;
[MemoryPackInclude]
long MaxBytes => info.MaxBytes;
[MemoryPackInclude]
long LastBytes => info.LastBytes;
double CostPrice => info.CostPrice;
[MemoryPackInclude]
double Memory => info.Memory;
double Price => info.Price;
[MemoryPackInclude]
double PayMemory => info.PayMemory;
double UserPrice => info.UserPrice;
[MemoryPackInclude]
double PayPrice => info.PayPrice;
[MemoryPackInclude]
string Remark => info.Remark;
[MemoryPackInclude]
string OrderId => info.OrderId;
[MemoryPackInclude]
string Contact => info.Contact;
[MemoryPackInclude]
bool Deleted => info.Deleted;
[MemoryPackConstructor]
SerializableRelayServerCdkeyStoreInfo(long cdkeyid, string id, string userid, string cdKey, DateTime addTime, DateTime startTime, DateTime endTime, DateTime useTime,
List<string> nodes, double bandwidth, long maxBytes, long lastBytes, double memory, double payMemory, string remark)
SerializableRelayServerCdkeyStoreInfo(long cdkeyid, double bandwidth, long lastBytes, string id, string userid, DateTime addTime, DateTime startTime, DateTime endTime, DateTime useTime, long maxBytes, double costPrice, double price, double userPrice, double payPrice, string remark, string orderId, string contact, bool deleted)
{
var info = new RelayServerCdkeyStoreInfo
{
CdkeyId = cdkeyid,
Bandwidth = bandwidth,
LastBytes = lastBytes,
Id = id,
UserId = userid,
CdKey = cdKey,
AddTime = addTime,
StartTime = startTime,
EndTime = endTime,
UseTime = useTime,
Nodes = nodes,
Bandwidth = bandwidth,
MaxBytes = maxBytes,
LastBytes = lastBytes,
Memory = memory,
PayMemory = payMemory,
Remark = remark
CostPrice = costPrice,
Price = price,
UserPrice = userPrice,
PayPrice = payPrice,
Remark = remark,
OrderId = orderId,
Contact = contact,
Deleted = deleted
};
this.info = info;
}
@@ -664,14 +674,17 @@ namespace linker.messenger.serializer.memorypack
[MemoryPackInclude]
string SecretKey => info.SecretKey;
[MemoryPackInclude]
string UserId => info.UserId;
[MemoryPackInclude]
long CdkeyId => info.CdkeyId;
[MemoryPackConstructor]
SerializableRelayServerCdkeyDelInfo(string secretKey, long cdkeyid)
SerializableRelayServerCdkeyDelInfo(string secretKey, string userid, long cdkeyid)
{
var info = new RelayServerCdkeyDelInfo
{
SecretKey = secretKey,
UserId = userid,
CdkeyId = cdkeyid
};
this.info = info;
@@ -730,10 +743,16 @@ namespace linker.messenger.serializer.memorypack
[MemoryPackInclude]
string Remark => info.Remark;
[MemoryPackInclude]
string OrderId => info.OrderId;
[MemoryPackInclude]
string Contact => info.Contact;
[MemoryPackInclude]
string SecretKey => info.SecretKey;
[MemoryPackInclude]
RelayServerCdkeyPageRequestFlag Flag => info.Flag;
[MemoryPackConstructor]
SerializableRelayServerCdkeyPageRequestInfo(int page, int size, string order, string sort, string userid, string remark, string secretKey)
SerializableRelayServerCdkeyPageRequestInfo(int page, int size, string order, string sort, string userid, string remark, string orderid, string contact, string secretKey,RelayServerCdkeyPageRequestFlag flag)
{
var info = new RelayServerCdkeyPageRequestInfo
{
@@ -743,7 +762,10 @@ namespace linker.messenger.serializer.memorypack
Page = page,
UserId = userid,
Remark = remark,
SecretKey = secretKey
OrderId = orderid,
Contact = contact,
SecretKey = secretKey,
Flag = flag
};
this.info = info;
}
@@ -845,7 +867,7 @@ namespace linker.messenger.serializer.memorypack
[MemoryPackable]
public readonly partial struct SerializableRelayTrafficReportInfo
public readonly partial struct SerializableRelayTrafficUpdateInfo
{
[MemoryPackIgnore]
public readonly RelayTrafficUpdateInfo info;
@@ -858,7 +880,7 @@ namespace linker.messenger.serializer.memorypack
string SecretKey => info.SecretKey;
[MemoryPackConstructor]
SerializableRelayTrafficReportInfo(Dictionary<long, long> dic, List<long> ids, string secretKey)
SerializableRelayTrafficUpdateInfo(Dictionary<long, long> dic, List<long> ids, string secretKey)
{
var info = new RelayTrafficUpdateInfo
{
@@ -869,12 +891,12 @@ namespace linker.messenger.serializer.memorypack
this.info = info;
}
public SerializableRelayTrafficReportInfo(RelayTrafficUpdateInfo info)
public SerializableRelayTrafficUpdateInfo(RelayTrafficUpdateInfo info)
{
this.info = info;
}
}
public class RelayTrafficReportInfoFormatter : MemoryPackFormatter<RelayTrafficUpdateInfo>
public class RelayTrafficUpdateInfoFormatter : MemoryPackFormatter<RelayTrafficUpdateInfo>
{
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayTrafficUpdateInfo value)
{
@@ -884,7 +906,7 @@ namespace linker.messenger.serializer.memorypack
return;
}
writer.WritePackable(new SerializableRelayTrafficReportInfo(value));
writer.WritePackable(new SerializableRelayTrafficUpdateInfo(value));
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayTrafficUpdateInfo value)
@@ -896,10 +918,208 @@ namespace linker.messenger.serializer.memorypack
return;
}
var wrapped = reader.ReadPackable<SerializableRelayTrafficReportInfo>();
var wrapped = reader.ReadPackable<SerializableRelayTrafficUpdateInfo>();
value = wrapped.info;
}
}
[MemoryPackable]
public readonly partial struct SerializableRelayServerCdkeyImportInfo
{
[MemoryPackIgnore]
public readonly RelayServerCdkeyImportInfo info;
[MemoryPackInclude]
string SecretKey => info.SecretKey;
[MemoryPackInclude]
string UserId => info.UserId;
[MemoryPackInclude]
string Base64 => info.Base64;
[MemoryPackConstructor]
SerializableRelayServerCdkeyImportInfo(string secretKey, string userid, string base64)
{
var info = new RelayServerCdkeyImportInfo
{
SecretKey = secretKey,
UserId = userid,
Base64 = base64
};
this.info = info;
}
public SerializableRelayServerCdkeyImportInfo(RelayServerCdkeyImportInfo info)
{
this.info = info;
}
}
public class RelayServerCdkeyImportInfoFormatter : MemoryPackFormatter<RelayServerCdkeyImportInfo>
{
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayServerCdkeyImportInfo value)
{
if (value == null)
{
writer.WriteNullObjectHeader();
return;
}
writer.WritePackable(new SerializableRelayServerCdkeyImportInfo(value));
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayServerCdkeyImportInfo value)
{
if (reader.PeekIsNull())
{
reader.Advance(1); // skip null block
value = null;
return;
}
var wrapped = reader.ReadPackable<SerializableRelayServerCdkeyImportInfo>();
value = wrapped.info;
}
}
[MemoryPackable]
public readonly partial struct SerializableRelayServerCdkeyTestResultInfo
{
[MemoryPackIgnore]
public readonly RelayServerCdkeyTestResultInfo info;
[MemoryPackInclude, MemoryPackAllowSerialize]
RelayServerCdkeyOrderInfo Order => info.Order;
[MemoryPackInclude]
string Cdkey => info.Cdkey;
[MemoryPackInclude]
List<string> Field => info.Field;
[MemoryPackConstructor]
SerializableRelayServerCdkeyTestResultInfo(RelayServerCdkeyOrderInfo order, string cdkey, List<string> field)
{
var info = new RelayServerCdkeyTestResultInfo
{
Order = order,
Cdkey = cdkey,
Field = field
};
this.info = info;
}
public SerializableRelayServerCdkeyTestResultInfo(RelayServerCdkeyTestResultInfo info)
{
this.info = info;
}
}
public class RelayServerCdkeyTestResultInfoFormatter : MemoryPackFormatter<RelayServerCdkeyTestResultInfo>
{
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayServerCdkeyTestResultInfo value)
{
if (value == null)
{
writer.WriteNullObjectHeader();
return;
}
writer.WritePackable(new SerializableRelayServerCdkeyTestResultInfo(value));
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayServerCdkeyTestResultInfo value)
{
if (reader.PeekIsNull())
{
reader.Advance(1); // skip null block
value = null;
return;
}
var wrapped = reader.ReadPackable<SerializableRelayServerCdkeyTestResultInfo>();
value = wrapped.info;
}
}
[MemoryPackable]
public readonly partial struct SerializableRelayServerCdkeyOrderInfo
{
[MemoryPackIgnore]
public readonly RelayServerCdkeyOrderInfo info;
[MemoryPackInclude]
int GB => info.GB;
[MemoryPackInclude]
int Speed => info.Speed;
[MemoryPackInclude]
string Time => info.Time;
[MemoryPackInclude]
string WidgetUserId => info.WidgetUserId;
[MemoryPackInclude]
string OrderId => info.OrderId;
[MemoryPackInclude]
string Contact => info.Contact;
[MemoryPackInclude]
double CostPrice => info.CostPrice;
[MemoryPackInclude]
double Price => info.Price;
[MemoryPackInclude]
double UserPrice => info.UserPrice;
[MemoryPackInclude]
double PayPrice => info.PayPrice;
[MemoryPackInclude]
int Count => info.Count;
[MemoryPackConstructor]
SerializableRelayServerCdkeyOrderInfo(int gb, int speed, string time, string widgetUserId, string orderId, string contact, double costPrice, double price, double userPrice, double payPrice, int count)
{
var info = new RelayServerCdkeyOrderInfo
{
GB = gb,
Speed = speed,
Time = time,
WidgetUserId = widgetUserId,
OrderId = orderId,
Contact = contact,
CostPrice = costPrice,
Price = price,
UserPrice = userPrice,
PayPrice = payPrice,
Count = count
};
this.info = info;
}
public SerializableRelayServerCdkeyOrderInfo(RelayServerCdkeyOrderInfo info)
{
this.info = info;
}
}
public class RelayServerCdkeyOrderInfoFormatter : MemoryPackFormatter<RelayServerCdkeyOrderInfo>
{
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayServerCdkeyOrderInfo value)
{
if (value == null)
{
writer.WriteNullObjectHeader();
return;
}
writer.WritePackable(new SerializableRelayServerCdkeyOrderInfo(value));
}
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayServerCdkeyOrderInfo value)
{
if (reader.PeekIsNull())
{
reader.Advance(1); // skip null block
value = null;
return;
}
var wrapped = reader.ReadPackable<SerializableRelayServerCdkeyOrderInfo>();
value = wrapped.info;
}
}
}

View File

@@ -1,17 +1,25 @@
using linker.messenger.relay.server;
using linker.libs;
using linker.libs.extends;
using linker.messenger.relay.server;
using LiteDB;
using System.Text;
using System.Text.RegularExpressions;
using Yitter.IdGenerator;
namespace linker.messenger.store.file.relay
{
public sealed class RelayServerCdkeyStore : IRelayServerCdkeyStore
{
private string regex = @"([0-9]+)-([0-9]+)-([0-9]+)\s+([0-9]+):([0-9]+):([0-9]+)";
private readonly Storefactory dBfactory;
private readonly ILiteCollection<RelayServerCdkeyStoreInfo> liteCollection;
private readonly ICrypto crypto;
public RelayServerCdkeyStore(Storefactory dBfactory, FileConfig fileConfig)
{
this.dBfactory = dBfactory;
liteCollection = dBfactory.GetCollection<RelayServerCdkeyStoreInfo>("relayCdkey");
this.crypto = CryptoFactory.CreateSymmetric(fileConfig.Data.Server.Relay.Cdkey.SecretKey, System.Security.Cryptography.PaddingMode.PKCS7);
}
public async Task<bool> Add(RelayServerCdkeyStoreInfo info)
@@ -19,11 +27,11 @@ namespace linker.messenger.store.file.relay
if (string.IsNullOrWhiteSpace(info.Id))
{
info.Id = ObjectId.NewObjectId().ToString();
info.CdKey = Guid.NewGuid().ToString().ToUpper();
info.AddTime = DateTime.Now;
info.UseTime = DateTime.Now;
info.LastBytes = info.MaxBytes;
info.CdkeyId = YitIdHelper.NextId();
info.OrderId = $"Linker{YitIdHelper.NextId()}";
liteCollection.Insert(info);
}
else
@@ -34,7 +42,101 @@ namespace linker.messenger.store.file.relay
}
public async Task<bool> Del(long id)
{
return await Task.FromResult(liteCollection.DeleteMany(c => c.CdkeyId == id) > 0);
return await Task.FromResult(liteCollection.UpdateMany(c => new RelayServerCdkeyStoreInfo { Deleted = true }, c => c.CdkeyId == id) > 0);
}
public async Task<bool> Del(long id, string userid)
{
return await Task.FromResult(liteCollection.UpdateMany(c => new RelayServerCdkeyStoreInfo { Deleted = true }, c => c.CdkeyId == id && c.UserId == userid) > 0);
}
public async Task<RelayServerCdkeyTestResultInfo> Test(RelayServerCdkeyImportInfo info)
{
List<string> error = new List<string>();
RelayServerCdkeyTestResultInfo result = new RelayServerCdkeyTestResultInfo();
try
{
result.Cdkey = Encoding.UTF8.GetString(crypto.Decode(Convert.FromBase64String(info.Base64)).Span);
RelayServerCdkeyOrderInfo order = result.Cdkey.DeJson<RelayServerCdkeyOrderInfo>();
result.Order = order;
if (order.WidgetUserId != info.UserId)
{
error.Add("UserId");
}
if (order.Speed <= 0)
{
error.Add("Speed");
}
if (order.GB <= 0)
{
error.Add("GB");
}
if (order.Count <= 0)
{
error.Add("Count");
}
if (Regex.IsMatch(order.Time, regex) == false)
{
error.Add("Time");
}
if (string.IsNullOrWhiteSpace(order.OrderId))
{
error.Add("OrderId");
}
}
catch (Exception ex)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Error(ex);
}
error.Add("Parse");
}
result.Field = error;
return await Task.FromResult(result);
}
public async Task<bool> Import(RelayServerCdkeyImportInfo info)
{
RelayServerCdkeyTestResultInfo test = await Test(info);
if (test.Field.Count > 0)
{
return false;
}
RelayServerCdkeyOrderInfo order = test.Order;
var time = Regex.Match(order.Time, regex).Groups;
for (int i = 0; i < order.Count; i++)
{
RelayServerCdkeyStoreInfo store = new RelayServerCdkeyStoreInfo
{
UseTime = DateTime.Now,
AddTime = DateTime.Now,
Bandwidth = order.Speed,
CostPrice = order.CostPrice,
EndTime = DateTime.Now
.AddYears(int.Parse(time[1].Value))
.AddMonths(int.Parse(time[2].Value))
.AddDays(int.Parse(time[3].Value))
.AddHours(int.Parse(time[4].Value))
.AddMinutes(int.Parse(time[5].Value))
.AddSeconds(int.Parse(time[6].Value)),
LastBytes = order.Speed * 1024 * 1024 * 1024,
MaxBytes = order.Speed * 1024 * 1024 * 1024,
Price = order.Price,
Remark = "order",
StartTime = DateTime.Now,
UserId = order.WidgetUserId,
CdkeyId = YitIdHelper.NextId(),
Contact = order.Contact,
OrderId = order.OrderId,
PayPrice = order.PayPrice,
UserPrice = order.UserPrice,
Id = ObjectId.NewObjectId().ToString()
};
liteCollection.Insert(store);
}
return await Task.FromResult(true);
}
public async Task<bool> Traffic(Dictionary<long, long> dic)
@@ -53,25 +155,42 @@ namespace linker.messenger.store.file.relay
public async Task<List<RelayServerCdkeyStoreInfo>> GetAvailable(string userid)
{
return await Task.FromResult(liteCollection.Find(x => x.UserId == userid && x.LastBytes > 0 && x.StartTime <= DateTime.Now && x.EndTime < DateTime.Now).ToList());
return await Task.FromResult(liteCollection.Find(x => x.UserId == userid && x.LastBytes > 0 && x.StartTime <= DateTime.Now && x.EndTime < DateTime.Now && x.Deleted == false).ToList());
}
public async Task<List<RelayServerCdkeyStoreInfo>> Get(List<long> ids)
{
return await Task.FromResult(liteCollection.Find(x => ids.Contains(x.CdkeyId)).ToList());
}
public async Task<RelayServerCdkeyPageResultInfo> Get(RelayServerCdkeyPageRequestInfo info)
public async Task<RelayServerCdkeyPageResultInfo> Page(RelayServerCdkeyPageRequestInfo info)
{
ILiteQueryable<RelayServerCdkeyStoreInfo> query = liteCollection.Query();
if (string.IsNullOrWhiteSpace(info.Order) == false)
if (info.Flag.HasFlag(RelayServerCdkeyPageRequestFlag.TimeIn))
{
query = query.OrderBy(info.Order, info.Sort == "asc" ? Query.Ascending : Query.Descending);
query = query.Where(x => x.EndTime > DateTime.Now);
}
else
if (info.Flag.HasFlag(RelayServerCdkeyPageRequestFlag.TimeOut))
{
query = query.OrderBy(c => c.CdkeyId, Query.Descending);
query = query.Where(x => x.EndTime < DateTime.Now);
}
if (info.Flag.HasFlag(RelayServerCdkeyPageRequestFlag.BytesIn))
{
query = query.Where(x => x.LastBytes > 0);
}
if (info.Flag.HasFlag(RelayServerCdkeyPageRequestFlag.BytesOut))
{
query = query.Where(x => x.LastBytes <= 0);
}
if (info.Flag.HasFlag(RelayServerCdkeyPageRequestFlag.Deleted))
{
query = query.Where(x => x.Deleted == true);
}
if (info.Flag.HasFlag(RelayServerCdkeyPageRequestFlag.UnDeleted))
{
query = query.Where(x => x.Deleted == false);
}
if (string.IsNullOrWhiteSpace(info.UserId) == false)
{
query = query.Where(x => x.UserId == info.UserId);
@@ -80,6 +199,22 @@ namespace linker.messenger.store.file.relay
{
query = query.Where(x => x.Remark.Contains(info.Remark));
}
if (string.IsNullOrWhiteSpace(info.OrderId) == false)
{
query = query.Where(x => x.OrderId.Contains(info.OrderId));
}
if (string.IsNullOrWhiteSpace(info.Contact) == false)
{
query = query.Where(x => x.Contact.Contains(info.Contact));
}
if (string.IsNullOrWhiteSpace(info.Order) == false)
{
query = query.OrderBy(info.Order, info.Sort == "asc" ? Query.Ascending : Query.Descending);
}
else
{
query = query.OrderBy(c => c.CdkeyId, Query.Descending);
}
return await Task.FromResult(new RelayServerCdkeyPageResultInfo
{

View File

@@ -20,4 +20,7 @@ export const relayCdkeyAdd = (data) => {
}
export const relayCdkeyDel = (data) => {
return sendWebsocketMsg('relay/DelCdkey', data);
}
export const relayCdkeyMy = (data) => {
return sendWebsocketMsg('relay/MyCdkey', data);
}

View File

@@ -130,21 +130,34 @@ export default {
'server.relayUse': 'Use',
'server.relayMyCdkey': 'My CDKEY',
'server.relayCdkey': 'Manager CDKEY',
'server.relayAddCdkey': 'Add CDKEY',
'server.relayCdkeyUserId': 'UserId',
'server.relayCdkeyBandwidth': 'Bandwidth',
'server.relayCdkeyMaxBytes': 'Total',
'server.relayCdkeyLastBytes': 'Surplus',
'server.relayCdkeyMemory': 'Price',
'server.relayCdkeyPayMemory': 'Pay',
'server.relayCdkeyBytes': 'Bytes',
'server.relayCdkeyPay': 'Pay',
'server.relayCdkeyOrder': 'Order',
'server.relayCdkeyPrice': 'Price',
'server.relayCdkeyPayPrice': 'Pay price',
'server.relayCdkeyCostPrice': 'Cost price',
'server.relayCdkeyUserPrice': 'User price',
'server.relayCdkeyOrderId': 'Order No',
'server.relayCdkeyContact': 'Email',
'server.relayCdkeyRemark': 'Remark',
'server.relayCdkeyAddTime': 'Add',
'server.relayCdkeyStartTime': 'Start',
'server.relayCdkeyEndTime': 'End Time',
'server.relayCdkeyUseTime': 'Use Time',
'server.relayCdkeyYear': 'Year',
'server.relayCdkeyMonth': 'Month',
'server.relayCdkeyDay': 'Day',
'server.relayCdkeyHour': 'Hour',
'server.relayCdkeyMin': 'Min',
'server.relayCdkeySec': 'Sec',
'server.relayCdkeyDuration': 'Duration',
'server.relayCdkeyStartTimeY': 'Year',
'server.relayCdkeyStartTimeM': 'Month',
'server.relayCdkeyEndTime': 'End',
'server.relayCdkeyUseTime': 'Use',
'server.relayCdkeyRemark': 'Remark',
'server.relayCdkeyOper': 'Oper',
'server.relayCdkeyDelConfirm': 'Are you sure to delete',

View File

@@ -133,21 +133,34 @@ export default {
'server.relayUse': '使用',
'server.relayMyCdkey': '我的CDKEY',
'server.relayCdkey': '管理CDKEY',
'server.relayAddCdkey': '添加CDKEY',
'server.relayCdkeyUserId': '用户标识',
'server.relayCdkeyBandwidth': '最大带宽',
'server.relayCdkeyMaxBytes': '流量',
'server.relayCdkeyLastBytes': '剩余流量',
'server.relayCdkeyMemory': '原价',
'server.relayCdkeyPayMemory': '支付',
'server.relayCdkeyBandwidth': '带宽',
'server.relayCdkeyBytes': '流量',
'server.relayCdkeyPay': '支付',
'server.relayCdkeyPrice': '原价',
'server.relayCdkeyPayPrice': '支付',
'server.relayCdkeyCostPrice': '成本',
'server.relayCdkeyUserPrice': '会员价',
'server.relayCdkeyOrder': '订单',
'server.relayCdkeyOrderId': '订单号',
'server.relayCdkeyContact': '邮箱',
'server.relayCdkeyRemark': '备注',
'server.relayCdkeyAddTime': '添加',
'server.relayCdkeyStartTime': '开始',
'server.relayCdkeyEndTime': '有效时间',
'server.relayCdkeyUseTime': '最后使用',
'server.relayCdkeyYear': '年',
'server.relayCdkeyMonth': '月',
'server.relayCdkeyDay': '日',
'server.relayCdkeyHour': '时',
'server.relayCdkeyMin': '分',
'server.relayCdkeySec': '秒',
'server.relayCdkeyDuration': '持续时间',
'server.relayCdkeyStartTimeY': '年',
'server.relayCdkeyStartTimeM': '月',
'server.relayCdkeyEndTime': '结束',
'server.relayCdkeyUseTime': '使用',
'server.relayCdkeyRemark': '备注',
'server.relayCdkeyOper': '操作',
'server.relayCdkeyDelConfirm': '确认删除吗?',

View File

@@ -1,7 +1,8 @@
<template>
<a href="javascript:;" class="mgl-1 a-line">{{$t('server.relayMyCdkey')}}</a>
<a @click="state.showMy = true" href="javascript:;" class="mgl-1 a-line">{{$t('server.relayMyCdkey')}}</a>
<a v-if="state.hasRelayCdkey && hasRelayCdkey" @click="state.showManager = true" href="javascript:;" class="mgl-1 a-line">{{$t('server.relayCdkey')}}</a>
<Manager v-if="state.showManager" v-model="state.showManager" />
<My v-if="state.showMy" v-model="state.showMy" />
</template>
<script>
@@ -9,8 +10,9 @@ import { relayCdkeyAccess } from '@/apis/relay';
import { injectGlobalData } from '@/provide';
import { computed, onMounted, reactive } from 'vue';
import Manager from './Manager.vue'
import My from './My.vue'
export default {
components:{Manager},
components:{Manager,My},
setup () {
const globalData = injectGlobalData();
@@ -18,7 +20,7 @@ export default {
const state = reactive({
hasRelayCdkey:false,
showManager:false,
showList:false,
showMy:false
});
onMounted(()=>{

View File

@@ -2,8 +2,10 @@
<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="head flex">
<div><span>用户id</span> <el-input v-model="state.page.UserId" style="width:10rem" size="small" clearable @change="handleSearch" /></div>
<div><span>备注</span> <el-input v-model="state.page.Remark" style="width:10rem" size="small" clearable @change="handleSearch" /></div>
<div><span>{{$t('server.relayCdkeyUserId')}}</span> <el-input v-model="state.page.UserId" 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.relayCdkeyContact')}}</span> <el-input v-model="state.page.Contact" 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>
<el-button size="small" @click="handleSearch()">
<el-icon><Search /></el-icon>
@@ -15,15 +17,27 @@
</el-button>
</div>
</div>
<el-table stripe :data="state.list.List" border size="small" width="100%" @cell-dblclick="handleCellClick">
<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">
<template #default="scope">{{ scope.row.Bandwidth }}Mbps</template>
</el-table-column>
<el-table-column prop="LastBytes" :label="`${$t('server.relayCdkeyLastBytes')}/${$t('server.relayCdkeyMaxBytes')}`" width="160" sortable="custom">
<template #default="scope">{{ parseSpeed(scope.row.LastBytes) }}/{{ parseSpeed(scope.row.MaxBytes) }}</template>
<el-table-column prop="LastBytes" :label="`${$t('server.relayCdkeyBytes')}`" width="80" sortable="custom">
<template #default="scope">
<p><strong>{{ parseSpeed(scope.row.LastBytes) }}</strong></p>
<p>{{ parseSpeed(scope.row.MaxBytes) }}</p>
</template>
</el-table-column>
<el-table-column prop="PayMemory" :label="`${$t('server.relayCdkeyPayMemory')}/${$t('server.relayCdkeyMemory')}`" width="120" sortable="custom">
<template #default="scope">{{ scope.row.PayMemory }}/{{ scope.row.Memory }}</template>
<el-table-column prop="PayPrice" :label="`${$t('server.relayCdkeyPay')}`" width="120" sortable="custom">
<template #default="scope">
<p><strong>{{$t('server.relayCdkeyPayPrice')}}.{{ scope.row.PayPrice }}</strong>/{{$t('server.relayCdkeyPrice')}}.{{ scope.row.Price }}</p>
<p>{{$t('server.relayCdkeyUserPrice')}}.{{ scope.row.UserPrice }}/{{$t('server.relayCdkeyCostPrice')}}.{{ scope.row.CostPrice }}</p>
</template>
</el-table-column>
<el-table-column prop="OrderId" :label="`${$t('server.relayCdkeyOrder')}`" width="180">
<template #default="scope">
<p>{{ scope.row.OrderId }}</p>
<p>{{ scope.row.Contact }}</p>
</template>
</el-table-column>
<el-table-column prop="Remark" :label="$t('server.relayCdkeyRemark')">
</el-table-column>
@@ -31,13 +45,11 @@
</el-table-column>
<el-table-column prop="UseTime" :label="`${$t('server.relayCdkeyUseTime')}`" width="140" sortable="custom">
</el-table-column>
<el-table-column prop="StartTime" :label="`${$t('server.relayCdkeyStartTime')}`" width="140" sortable="custom">
</el-table-column>
<el-table-column prop="AddTime" :label="`${$t('server.relayCdkeyAddTime')}`" width="140" sortable="custom">
</el-table-column>
<el-table-column fixed="right" prop="Oper" :label="$t('server.relayCdkeyOper')" width="60">
<template #default="scope">
<div>
<div v-if="scope.row.Deleted == false">
<el-popconfirm :title="$t('server.relayCdkeyDelConfirm')" @confirm="handleDel(scope.row)">
<template #reference>
<el-button type="danger" size="small">
@@ -60,7 +72,7 @@
</div>
</div>
</el-dialog>
<el-dialog class="options-center" :title="$t('server.relayCdkey')" destroy-on-close v-model="state.showAdd" width="42rem" top="2vh">
<el-dialog class="options-center" :title="$t('server.relayAddCdkey')" destroy-on-close v-model="state.showAdd" 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">
@@ -69,27 +81,48 @@
<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.relayCdkeyMaxBytes')" prop="MaxBytes">
<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.relayCdkeyStartTime')" prop="StartTime">
<el-date-picker v-model="state.ruleForm.StartTime" type="datetime" placeholder="Select date and time"/>
</el-form-item>
<el-form-item :label="$t('server.relayCdkeyEndTime')" prop="EndTime">
<el-date-picker v-model="state.ruleForm.EndTime" type="datetime" placeholder="Select date and time"/>
<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.relayCdkeyMemory')" prop="Memory">
<el-input-number size="small" v-model="state.ruleForm.Memory" :min="0" />
{{ $t('server.relayCdkeyPayMemory') }}
<el-input-number size="small" v-model="state.ruleForm.PayMemory" :min="0" />
<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="$t('server.relayCdkeyRemark')" prop="Remark">
<el-input v-model="state.ruleForm.Remark" />
<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">
@@ -125,19 +158,28 @@ export default {
M:0,
K:0,
B:0,
StartTime:new Date(),
EndTime:new Date(new Date().getFullYear() + 1,new Date().getMonth(),new Date().getDay(),new Date().getHours(),new Date().getMinutes(),new Date().getSeconds()),
Memory:0,
PayMemory:0,
Remark:'',
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({
page:{
Page:1,
Size:15,
Size:10,
Order:'',
Sort:'',
Userid:'',
UserId:'',
OrderId:'',
Contact:'',
Remark:'',
},
list:{
@@ -179,6 +221,11 @@ export default {
state.page.Page = p;
handleSearch();
}
const handleSort = (a)=>{
state.page.Order = a.prop;
state.page.Sort = {'ascending':'asc','descending':'desc'}[a.order];
handleSearch();
}
const handleAdd = (row)=>{
state.ruleForm = JSON.parse(JSON.stringify(defaultJson));
@@ -190,13 +237,15 @@ export default {
}).catch(()=>{})
}
const ruleFormRef = ref(null);
const handleSave = ()=>{
const handleSave = ()=>{
ruleFormRef.value.validate((valid) => {
if (!valid) return;
const json = JSON.parse(JSON.stringify(state.ruleForm));
json.StartTime = moment(json.StartTime).format("YYYY-MM-DD HH:mm:ss");
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(()=>{
@@ -214,7 +263,7 @@ export default {
handleSearch();
})
return {state,ruleFormRef,parseSpeed,handleSearch,handlePageChange,handleAdd,handleDel,handleSave}
return {state,ruleFormRef,parseSpeed,handleSort,handleSearch,handlePageChange,handleAdd,handleDel,handleSave}
}
}
</script>

View File

@@ -0,0 +1,158 @@
<template>
<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="head 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.relayCdkeyContact')}}</span> <el-input v-model="state.page.Contact" 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>
<el-button size="small" @click="handleSearch()">
<el-icon><Search /></el-icon>
</el-button>
</div>
</div>
<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">
<template #default="scope">{{ scope.row.Bandwidth }}Mbps</template>
</el-table-column>
<el-table-column prop="LastBytes" :label="`${$t('server.relayCdkeyBytes')}`" width="80" sortable="custom">
<template #default="scope">
<p><strong>{{ parseSpeed(scope.row.LastBytes) }}</strong></p>
<p>{{ parseSpeed(scope.row.MaxBytes) }}</p>
</template>
</el-table-column>
<el-table-column prop="PayPrice" :label="`${$t('server.relayCdkeyPay')}`" width="120" sortable="custom">
<template #default="scope">
<p><strong>{{$t('server.relayCdkeyPayPrice')}}.{{ scope.row.PayPrice }}</strong>/{{$t('server.relayCdkeyPrice')}}.{{ scope.row.Price }}</p>
<p>{{$t('server.relayCdkeyUserPrice')}}.{{ scope.row.UserPrice }}/{{$t('server.relayCdkeyCostPrice')}}.{{ scope.row.CostPrice }}</p>
</template>
</el-table-column>
<el-table-column prop="OrderId" :label="`${$t('server.relayCdkeyOrder')}`" width="180">
<template #default="scope">
<p>{{ scope.row.OrderId }}</p>
<p>{{ scope.row.Contact }}</p>
</template>
</el-table-column>
<el-table-column prop="Remark" :label="$t('server.relayCdkeyRemark')">
</el-table-column>
<el-table-column prop="EndTime" :label="`${$t('server.relayCdkeyEndTime')}`" width="140" sortable="custom">
</el-table-column>
<el-table-column prop="UseTime" :label="`${$t('server.relayCdkeyUseTime')}`" width="140" sortable="custom">
</el-table-column>
<el-table-column prop="AddTime" :label="`${$t('server.relayCdkeyAddTime')}`" width="140" sortable="custom">
</el-table-column>
<el-table-column fixed="right" prop="Oper" :label="$t('server.relayCdkeyOper')" width="60">
<template #default="scope">
<div v-if="scope.row.Deleted == false">
<el-popconfirm :title="$t('server.relayCdkeyDelConfirm')" @confirm="handleDel(scope.row)">
<template #reference>
<el-button type="danger" size="small">
<el-icon><Delete /></el-icon>
</el-button>
</template>
</el-popconfirm>
</div>
</template>
</el-table-column>
</el-table>
<div class="t-c">
<div class="page">
<el-pagination small background layout="prev, pager, next"
:page-size="state.page.Size"
:total="state.list.Count"
:pager-count="5"
:current-page="state.page.Page" @current-change="handlePageChange" />
</div>
</div>
</div>
</el-dialog>
</template>
<script>
import { injectGlobalData } from '@/provide';
import { onMounted, reactive, watch } from 'vue'
import { Delete,Plus,Search } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n';
import {relayCdkeyMy,relayCdkeyDel } from '@/apis/relay';
export default {
props: ['modelValue'],
emits: ['update:modelValue'],
components:{Delete,Plus,Search },
setup(props,{emit}) {
const {t} = useI18n();
const globalData = injectGlobalData();
const state = reactive({
page:{
Page:1,
Size:10,
Order:'',
Sort:'',
OrderId:'',
Contact:'',
Remark:'',
},
list:{
Page:1,
Size:15,
Count:0,
List:[]
},
show:true
});
watch(() => state.show, (val) => {
if (!val) {
setTimeout(() => {
emit('update:modelValue', val);
}, 300);
}
});
const parseSpeed = (num) => {
let index = 0;
while (num >= 1024) {
num /= 1024;
index++;
}
return `${(num*1.0).toFixed(2)}${['B', 'KB', 'MB', 'GB', 'TB'][index]}`;
}
const handleSearch = ()=>{
relayCdkeyMy(state.page).then((res)=>{
state.list = res;
}).catch(()=>{})
}
const handlePageChange = (p)=>{
state.page.Page = p;
handleSearch();
}
const handleSort = (a)=>{
state.page.Order = a.prop;
state.page.Sort = {'ascending':'asc','descending':'desc'}[a.order];
handleSearch();
}
const handleDel = (row)=>{
relayCdkeyDel(row.CdkeyId).then((res)=>{
handleSearch();
}).catch(()=>{})
}
onMounted(()=>{
handleSearch();
})
return {state,parseSpeed,handleSort,handleSearch,handlePageChange,handleDel}
}
}
</script>
<style lang="stylus" scoped>
.head{
&>div{
margin-right:1rem;
}
}
.page{
padding:2rem 0;
display:inline-block;
}
.el-form-item{margin-bottom:1rem}
.el-input-number--small{width:10rem !important}
</style>

View File

@@ -1,5 +1,5 @@
v1.6.9
2025-03-06 21:15:19
2025-03-08 01:56:41
1. 优化linux下路由跟踪问题
2. 优化linux下获取本机IP问题
3. 增加ICS让win7+、win server2008+支持NAT