Compare commits

..

2 Commits

Author SHA1 Message Date
2248356998 qq.com
a4aa000cf0 10.9.66 2025-07-23 19:11:39 +08:00
Diego
01aa6ca066 10.9.65 2025-07-23 16:34:02 +08:00
21 changed files with 325 additions and 148 deletions

View File

@@ -62,7 +62,7 @@ public class SugarAopService : ISugarAopService
if (ex.Parameters == null) return;
Console.ForegroundColor = ConsoleColor.Red;
DbContext.WriteLog($"{config.ConfigId}库操作异常");
DbContext.WriteErrorLogWithSql(UtilMethods.GetNativeSql(ex.Sql, (SugarParameter[])ex.Parameters));
DbContext.WriteErrorLogWithSql(UtilMethods.GetNativeSql(ex.Sql, (IReadOnlyList<SugarParameter>)ex.Parameters));
NewLife.Log.XTrace.WriteException(ex);
Console.ForegroundColor = ConsoleColor.White;
};

View File

@@ -1,9 +1,9 @@
<Project>
<PropertyGroup>
<PluginVersion>10.9.64</PluginVersion>
<ProPluginVersion>10.9.64</ProPluginVersion>
<DefaultVersion>10.9.64</DefaultVersion>
<PluginVersion>10.9.66</PluginVersion>
<ProPluginVersion>10.9.66</ProPluginVersion>
<DefaultVersion>10.9.66</DefaultVersion>
<AuthenticationVersion>2.9.24</AuthenticationVersion>
<SourceGeneratorVersion>10.9.24</SourceGeneratorVersion>
<NET8Version>8.0.18</NET8Version>

View File

@@ -18,46 +18,71 @@
<EditTemplate Context="value">
<div class="col-12 col-sm-6 col-md-4">
<Select SkipValidate="true" @bind-Value="@value.ChannelType" OnSelectedItemChanged=@((a)=>
{
return InvokeAsync(StateHasChanged);
}) />
{
return InvokeAsync(StateHasChanged);
}) />
</div>
</EditTemplate>
</EditorItem>
</EditorItem>
<EditorItem @bind-Field="@context.RemoteUrl" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpClient&&context.ChannelType!=ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.BindUrl" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpClient&&context.ChannelType!=ChannelTypeEnum.UdpSession&&context.ChannelType!=ChannelTypeEnum.TcpService) />
<EditorItem @bind-Field="@context.RemoteUrl" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpClient && context.ChannelType != ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.BindUrl" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpClient && context.ChannelType != ChannelTypeEnum.UdpSession && context.ChannelType != ChannelTypeEnum.TcpService) />
<EditorItem @bind-Field="@context.PortName" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.BaudRate" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.DataBits" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.Parity" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.StopBits" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.DtrEnable" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.RtsEnable" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.StreamAsync" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.PortName" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.BaudRate" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.DataBits" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.Parity" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.StopBits" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.DtrEnable" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.RtsEnable" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.StreamAsync" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.CacheTimeout" Ignore=@(context.ChannelType==ChannelTypeEnum.UdpSession||context.ChannelType==ChannelTypeEnum.Other) />
<EditorItem @bind-Field="@context.ConnectTimeout" Ignore=@(context.ChannelType==ChannelTypeEnum.UdpSession||context.ChannelType==ChannelTypeEnum.TcpService||context.ChannelType==ChannelTypeEnum.Other) />
<EditorItem @bind-Field="@context.MaxConcurrentCount" Ignore=@(context.ChannelType==ChannelTypeEnum.Other) />
<EditorItem @bind-Field="@context.CacheTimeout" Ignore=@(context.ChannelType == ChannelTypeEnum.UdpSession || context.ChannelType == ChannelTypeEnum.Other) />
<EditorItem @bind-Field="@context.ConnectTimeout" Ignore=@(context.ChannelType == ChannelTypeEnum.UdpSession || context.ChannelType == ChannelTypeEnum.TcpService || context.ChannelType == ChannelTypeEnum.Other) />
<EditorItem @bind-Field="@context.MaxConcurrentCount" Ignore=@(context.ChannelType == ChannelTypeEnum.Other) />
<EditorItem @bind-Field="@context.MaxClientCount" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpService) />
<EditorItem @bind-Field="@context.CheckClearTime" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpService) />
<EditorItem @bind-Field="@context.Heartbeat" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpService&&context.ChannelType!=ChannelTypeEnum.TcpClient&&context.ChannelType!=ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.HeartbeatTime" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpClient&&context.ChannelType!=ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.DtuId" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpClient&&context.ChannelType!=ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.DtuSeviceType" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpService&&context.ChannelType!=ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.MaxClientCount" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpService) />
<EditorItem @bind-Field="@context.CheckClearTime" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpService) />
</FieldItems>
<Buttons>
<Button IsAsync class="mx-2" Color=Color.Primary OnClick="ConnectClick">@Localizer["Connect"]</Button>
<Button IsAsync class="mx-2" Color=Color.Warning OnClick="DisconnectClick">@Localizer["Disconnect"]</Button>
</Buttons>
</EditorFormObject>
</ValidateForm>
<EditorItem @bind-Field="@context.Heartbeat" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpService && context.ChannelType != ChannelTypeEnum.TcpClient && context.ChannelType != ChannelTypeEnum.UdpSession)>
<EditTemplate Context="value">
<div class="col-12 col-sm-6 col-md-4">
<BootstrapInput @bind-Value=value.Heartbeat ShowLabel="true" class="me-2"></BootstrapInput>
<Checkbox @bind-Value=value.HeartbeatHex ShowAfterLabel DisplayText="hex"></Checkbox>
</div>
</EditTemplate>
</EditorItem>
</BodyTemplate>
</Card>
<EditorItem @bind-Field="@context.HeartbeatTime" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpClient && context.ChannelType != ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.DtuId" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpClient && context.ChannelType != ChannelTypeEnum.UdpSession)>
<EditTemplate Context="value">
<div class="col-12 col-sm-6 col-md-4">
<BootstrapInput @bind-Value=value.DtuId ShowLabel="true" class="me-2"></BootstrapInput>
<Checkbox @bind-Value=value.DtuIdHex ShowAfterLabel DisplayText="hex"></Checkbox>
</div>
</EditTemplate>
</EditorItem>
<EditorItem @bind-Field="@context.DtuIdHex" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpService) />
<EditorItem @bind-Field="@context.DtuSeviceType" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpService && context.ChannelType != ChannelTypeEnum.UdpSession) />
</FieldItems>
<Buttons>
<Button IsAsync class="mx-2" Color=Color.Primary OnClick="ConnectClick">@Localizer["Connect"]</Button>
<Button IsAsync class="mx-2" Color=Color.Warning OnClick="DisconnectClick">@Localizer["Disconnect"]</Button>
</Buttons>
</EditorFormObject>
</ValidateForm>
</BodyTemplate>
</Card>

View File

@@ -72,6 +72,8 @@
"DtuId": "DtuId",
"DtuSeviceType": "DtuSeviceType",
"Heartbeat": "Heartbeat",
"DtuIdHex": "DtuIdHex",
"HeartbeatHex": "HeartbeatHex",
"HeartbeatTime": "HeartbeatTime",
"MaxClientCount": "MaxClientCount",
"MaxConcurrentCount": "MaxConcurrentCount",

View File

@@ -69,9 +69,11 @@
"ConnectTimeout": "连接超时",
"DataBits": "数据位",
"DtrEnable": "Dtr",
"DtuId": "Dtu终端注册包(utf-8)",
"DtuId": "Dtu终端注册包",
"DtuSeviceType": "DTU服务类型",
"Heartbeat": "心跳内容(utf8)",
"Heartbeat": "心跳内容",
"DtuIdHex": "Dtu终端注册包是否Hex",
"HeartbeatHex": "心跳内容是否Hex",
"HeartbeatTime": "心跳间隔",
"MaxClientCount": "最大连接数",
"MaxConcurrentCount": "最大并发数",

View File

@@ -94,10 +94,12 @@ namespace ThingsGateway.Foundation
public virtual int MaxClientCount { get; set; }
public virtual int CheckClearTime { get; set; }
public virtual string Heartbeat { get; set; }
public virtual bool HeartbeatHex { get; set; }
#region dtu终端
public virtual int HeartbeatTime { get; set; }
public virtual string DtuId { get; set; }
public virtual bool DtuIdHex { get; set; }
#endregion
public virtual DtuSeviceType DtuSeviceType { get; set; }

View File

@@ -54,20 +54,29 @@ public static class ChannelOptionsExtensions
/// <returns></returns>
internal static async Task OnChannelEvent(this IClientChannel clientChannel, ChannelEventHandler funcs)
{
clientChannel.ThrowIfNull(nameof(IClientChannel));
funcs.ThrowIfNull(nameof(ChannelEventHandler));
if (funcs.Count > 0)
try
{
for (int i = 0; i < funcs.Count; i++)
clientChannel.ThrowIfNull(nameof(IClientChannel));
funcs.ThrowIfNull(nameof(ChannelEventHandler));
if (funcs.Count > 0)
{
var func = funcs[i];
var handled = await func.Invoke(clientChannel, i == funcs.Count - 1).ConfigureAwait(false);
if (handled)
for (int i = 0; i < funcs.Count; i++)
{
break;
var func = funcs[i];
var handled = await func.Invoke(clientChannel, i == funcs.Count - 1).ConfigureAwait(false);
if (handled)
{
break;
}
}
}
}
catch (Exception ex)
{
clientChannel.Logger?.LogWarning(ex, "fail ChannelEvent");
}
}

View File

@@ -111,10 +111,13 @@ public interface IChannelOptions
int CheckClearTime { get; set; }
/// <summary>
/// 心跳检测(utf8)
/// 心跳检测
/// </summary>
string Heartbeat { get; set; }
/// <summary>
/// 心跳检测是否hex
/// </summary>
bool HeartbeatHex { get; set; }
#region dtu终端
/// <summary>
/// 心跳时间
@@ -122,10 +125,13 @@ public interface IChannelOptions
public int HeartbeatTime { get; set; }
/// <summary>
/// 默认Dtu注册包(utf-8)
/// 默认Dtu注册包
/// </summary>
public string DtuId { get; set; }
/// <summary>
/// 默认Dtu注册包是否hex
/// </summary>
bool DtuIdHex { get; set; }
#endregion
public DtuSeviceType DtuSeviceType { get; set; }

View File

@@ -10,6 +10,8 @@
using System.Text;
using ThingsGateway.Foundation.Extension.String;
namespace ThingsGateway.Foundation;
/// <inheritdoc/>
@@ -28,13 +30,34 @@ public class DtuPlugin : PluginBase, ITcpReceivingPlugin
set
{
_heartbeat = value;
if (!_heartbeat.IsNullOrEmpty())
HeartbeatByte = new ArraySegment<byte>(Encoding.UTF8.GetBytes(value));
if (!heartbeatHex)
HeartbeatByte = new ArraySegment<byte>(Encoding.UTF8.GetBytes(_heartbeat ?? string.Empty));
else
HeartbeatByte = new ArraySegment<byte>(_heartbeat?.HexStringToBytes() ?? Array.Empty<byte>());
}
}
private string _heartbeat;
private ArraySegment<byte> HeartbeatByte = new();
private bool heartbeatHex;
public bool HeartbeatHex
{
get
{
return heartbeatHex;
}
set
{
heartbeatHex = value;
if (!heartbeatHex)
HeartbeatByte = new ArraySegment<byte>(Encoding.UTF8.GetBytes(_heartbeat ?? string.Empty));
else
HeartbeatByte = new ArraySegment<byte>(_heartbeat?.HexStringToBytes() ?? Array.Empty<byte>());
}
}
public bool DtuIdHex { get; set; }
/// <inheritdoc/>
public async Task OnTcpReceiving(ITcpSession client, ByteBlockEventArgs e)
{
@@ -43,7 +66,7 @@ public class DtuPlugin : PluginBase, ITcpReceivingPlugin
{
if (!socket.Id.StartsWith("ID="))
{
var id = $"ID={e.ByteBlock}";
var id = DtuIdHex ? $"ID={e.ByteBlock.Span.ToHexString()}" : $"ID={e.ByteBlock.ToString(0, e.ByteBlock.Length)}";
if (tcpServiceChannel.TryGetClient(id, out var oldClient))
{
try

View File

@@ -10,6 +10,8 @@
using System.Text;
using ThingsGateway.Foundation.Extension.String;
namespace ThingsGateway.Foundation;
[PluginOption(Singleton = true)]
@@ -24,7 +26,10 @@ internal sealed class HeartbeatAndReceivePlugin : PluginBase, ITcpConnectedPlugi
set
{
_dtuId = value;
DtuIdByte = new ArraySegment<byte>(Encoding.UTF8.GetBytes(value));
if (!dtuIdHex)
DtuIdByte = new ArraySegment<byte>(Encoding.UTF8.GetBytes(_dtuId ?? string.Empty));
else
DtuIdByte = new ArraySegment<byte>(_dtuId?.HexStringToBytes() ?? Array.Empty<byte>());
}
}
private string _dtuId;
@@ -42,15 +47,64 @@ internal sealed class HeartbeatAndReceivePlugin : PluginBase, ITcpConnectedPlugi
set
{
_heartbeat = value;
if (!_heartbeat.IsNullOrEmpty())
{
HeartbeatByte = new ArraySegment<byte>(Encoding.UTF8.GetBytes(value));
}
if (!heartbeatHex)
HeartbeatByte = new ArraySegment<byte>(Encoding.UTF8.GetBytes(_heartbeat ?? string.Empty));
else
HeartbeatByte = new ArraySegment<byte>(_heartbeat?.HexStringToBytes() ?? Array.Empty<byte>());
}
}
private string _heartbeat;
private ArraySegment<byte> HeartbeatByte;
private bool heartbeatHex;
public bool HeartbeatHex
{
get
{
return heartbeatHex;
}
set
{
heartbeatHex = value;
if (!heartbeatHex)
{
HeartbeatByte = new ArraySegment<byte>(Encoding.UTF8.GetBytes(_heartbeat ?? string.Empty));
}
else
{
HeartbeatByte = new ArraySegment<byte>(_heartbeat?.HexStringToBytes() ?? Array.Empty<byte>());
}
}
}
private bool dtuIdHex;
public bool DtuIdHex
{
get
{
return dtuIdHex;
}
set
{
dtuIdHex = value;
if (!dtuIdHex)
{
DtuIdByte = new ArraySegment<byte>(Encoding.UTF8.GetBytes(_dtuId ?? string.Empty));
}
else
{
DtuIdByte = new ArraySegment<byte>(_dtuId?.HexStringToBytes() ?? Array.Empty<byte>());
}
}
}
private Task Task;
private bool SendHeartbeat;
public int HeartbeatTime { get; set; } = 3000;

View File

@@ -25,6 +25,8 @@ public static class PluginUtil
action += a =>
{
var plugin = a.Add<HeartbeatAndReceivePlugin>();
plugin.HeartbeatHex = channelOptions.HeartbeatHex;
plugin.DtuIdHex = channelOptions.DtuIdHex;
plugin.Heartbeat = channelOptions.Heartbeat;
plugin.DtuId = channelOptions.DtuId;
plugin.HeartbeatTime = channelOptions.HeartbeatTime;
@@ -52,7 +54,9 @@ public static class PluginUtil
action += a =>
{
var plugin = a.Add<DtuPlugin>();
plugin.HeartbeatHex = channelOptions.HeartbeatHex;
plugin.Heartbeat = channelOptions.Heartbeat;
plugin.DtuIdHex = channelOptions.DtuIdHex;
};
}
return action;

View File

@@ -142,7 +142,20 @@ public static partial class DeviceExtension
return new();
case WaitDataStatus.Canceled: return new(new OperationCanceledException());
case WaitDataStatus.Overtime: return waitDataAsync.WaitResult == null ? new(new TimeoutException()) : new(waitDataAsync.WaitResult);
case WaitDataStatus.Overtime:
{
if (waitDataAsync.WaitResult != null)
{
waitDataAsync.WaitResult.Exception = new TimeoutException();
if (waitDataAsync.WaitResult.IsSuccess) waitDataAsync.WaitResult.OperCode = 999;
if (waitDataAsync.WaitResult.ErrorMessage.IsNullOrEmpty()) waitDataAsync.WaitResult.ErrorMessage = "Timeout";
return new(waitDataAsync.WaitResult);
}
else
{
return new(new TimeoutException());
}
}
case WaitDataStatus.Disposed:
case WaitDataStatus.Default:
default:

View File

@@ -12,6 +12,8 @@
"DtuSeviceType": "DtuSeviceType",
"Heartbeat": "Heartbeat",
"HeartbeatTime": "HeartbeatTime",
"DtuIdHex": "DtuIdHex",
"HeartbeatHex": "HeartbeatHex",
"MaxClientCount": "MaxClientCount",
"MaxConcurrentCount": "MaxConcurrentCount",
"Name": "Name",
@@ -73,7 +75,7 @@
"Timeout": "Timeout"
},
"ThingsGateway.Foundation.DtuServiceDeviceBase": {
"DtuId": "DtuId(UTF8)"
"DtuId": "DtuId"
},
"ThingsGateway.Foundation.VariableClass": {
"RegisterAddress": "RegisterAddress"

View File

@@ -8,9 +8,11 @@
"ConnectTimeout": "连接超时",
"DataBits": "数据位",
"DtrEnable": "Dtr",
"DtuId": "Dtu终端注册包(utf-8)",
"DtuId": "Dtu终端注册包",
"DtuSeviceType": "DTU服务类型",
"Heartbeat": "心跳内容(utf8)",
"Heartbeat": "心跳内容",
"DtuIdHex": "Dtu终端注册包是否Hex",
"HeartbeatHex": "心跳内容是否Hex",
"HeartbeatTime": "心跳间隔",
"MaxClientCount": "最大连接数",
"MaxConcurrentCount": "最大并发数",
@@ -73,7 +75,7 @@
"Timeout": "读写超时"
},
"ThingsGateway.Foundation.DtuServiceDeviceBase": {
"DtuId": "Dtu注册包(UTF8)"
"DtuId": "Dtu注册包"
},
"ThingsGateway.Foundation.VariableClass": {
"RegisterAddress": "寄存器地址"

View File

@@ -177,6 +177,10 @@ public class Channel : ChannelOptionsBase, IPrimaryIdEntity, IBaseDataEntity, IB
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
public override string Heartbeat { get; set; }
[SugarColumn(ColumnDescription = "心跳内容是否Hex", IsNullable = true)]
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
public override bool HeartbeatHex { get; set; }
#region dtu终端
[SugarColumn(ColumnDescription = "心跳间隔", IsNullable = true)]
@@ -187,6 +191,9 @@ public class Channel : ChannelOptionsBase, IPrimaryIdEntity, IBaseDataEntity, IB
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
public override string DtuId { get; set; }
[SugarColumn(ColumnDescription = "DtuId是否Hex", IsNullable = true)]
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
public override bool DtuIdHex { get; set; }
#endregion
[SugarColumn(ColumnDescription = "Dtu类型", IsNullable = true)]

View File

@@ -242,6 +242,8 @@
"ExportChannel": "Export Channel",
"Heartbeat": "Heartbeat",
"HeartbeatTime": "HeartbeatTime",
"DtuIdHex": "DtuIdHex",
"HeartbeatHex": "HeartbeatHex",
"ImportChannel": "Import Channel",
"ImportNullError": "Unable to recognize",
"LogEnable": "LogEnable",
@@ -274,10 +276,10 @@
},
"ThingsGateway.Gateway.Application.CollectFoundationDtuPackPropertyBase": {
"DtuId": "DtuId(UTF8)"
"DtuId": "DtuId"
},
"ThingsGateway.Gateway.Application.CollectFoundationDtuPropertyBase": {
"DtuId": "DtuId(UTF8)"
"DtuId": "DtuId"
},
"ThingsGateway.Gateway.Application.CollectFoundationPackPropertyBase": {
"MaxPack": "MaxPack"

View File

@@ -235,11 +235,13 @@
"DeleteChannel": "删除通道",
"Disconnect": "断开",
"DtrEnable": "Dtr",
"DtuId": "Dtu终端注册包(utf-8)",
"DtuId": "Dtu终端注册包",
"DtuSeviceType": "DTU服务类型",
"Enable": "启用",
"ExportChannel": "导出通道",
"Heartbeat": "心跳内容(utf8)",
"Heartbeat": "心跳内容",
"DtuIdHex": "Dtu终端注册包是否Hex",
"HeartbeatHex": "心跳内容是否Hex",
"HeartbeatTime": "心跳间隔",
"ImportChannel": "导入通道",
"ImportNullError": "无法识别",
@@ -273,10 +275,10 @@
},
"ThingsGateway.Gateway.Application.CollectFoundationDtuPackPropertyBase": {
"DtuId": "Dtu注册包(UTF8)"
"DtuId": "Dtu注册包"
},
"ThingsGateway.Gateway.Application.CollectFoundationDtuPropertyBase": {
"DtuId": "Dtu注册包(UTF8)"
"DtuId": "Dtu注册包"
},
"ThingsGateway.Gateway.Application.CollectFoundationPackPropertyBase": {
"MaxPack": "最大打包长度"

View File

@@ -33,102 +33,125 @@
RenderFragment renderFragment =>
@<EditorForm class="p-2" AutoGenerateAllItem="false" RowType=RowType.Inline ItemsPerRow=2 LabelWidth=200 Model="Model">
<FieldItems>
<EditorItem TValue="string" TModel="Channel" @bind-Field="@context.Name">
<EditTemplate Context="value">
<div class="col-12">
<h6>@GatewayLocalizer["BasicInformation"]</h6>
</div>
</EditTemplate>
</EditorItem>
<FieldItems>
<EditorItem TValue="string" TModel="Channel" @bind-Field="@context.Name">
<EditTemplate Context="value">
<div class="col-12">
<h6>@GatewayLocalizer["BasicInformation"]</h6>
</div>
</EditTemplate>
</EditorItem>
<EditorItem @bind-Field="@context.Name" Readonly=BatchEditEnable />
<EditorItem @bind-Field="@context.Name" Readonly=BatchEditEnable />
<EditorItem @bind-Field="@context.PluginName">
<EditTemplate Context="value">
<div class="col-12 col-md-6">
<Select @bind-Value="@value.PluginName"
Items="@PluginNames" IsDisabled=BatchEditEnable
ShowSearch="true">
<ItemTemplate Context="name">
@if (PluginDcit.TryGetValue(name.Value, out var pluginOutput))
{
if (pluginOutput.EducationPlugin)
{
<div class="d-flex">
<span>@name.Text</span>
<div style="flex-grow: 1;"></div>
<Tag Color="Color.Primary">PRO</Tag>
</div>
}
else
<EditorItem @bind-Field="@context.PluginName">
<EditTemplate Context="value">
<div class="col-12 col-md-6">
<Select @bind-Value="@value.PluginName"
Items="@PluginNames" IsDisabled=BatchEditEnable
ShowSearch="true">
<ItemTemplate Context="name">
@if (PluginDcit.TryGetValue(name.Value, out var pluginOutput))
{
if (pluginOutput.EducationPlugin)
{
<div class="d-flex">
<span>@name.Text</span>
<div style="flex-grow: 1;"></div>
<Tag Color="Color.Primary">PRO</Tag>
</div>
}
else
{
<span>@name.Text</span>
}
}
else
}
else
{
<span>@name.Value</span>
}
</ItemTemplate>
</Select>
</div>
</EditTemplate>
</EditorItem>
</ItemTemplate>
</Select>
</div>
</EditTemplate>
</EditorItem>
<EditorItem @bind-Field="@context.Enable" />
<EditorItem @bind-Field="@context.LogLevel" />
<EditorItem @bind-Field="@context.Enable" />
<EditorItem @bind-Field="@context.LogLevel" />
<EditorItem TValue="string" TModel="Channel" @bind-Field="@context.Name">
<EditTemplate Context="value">
<div class="col-12">
<h6>@GatewayLocalizer["Connection"]</h6>
</div>
</EditTemplate>
</EditorItem>
<EditorItem TValue="string" TModel="Channel" @bind-Field="@context.Name">
<EditTemplate Context="value">
<div class="col-12">
<h6>@GatewayLocalizer["Connection"]</h6>
</div>
</EditTemplate>
</EditorItem>
<EditorItem @bind-Field="@context.ChannelType">
<EditorItem @bind-Field="@context.ChannelType">
<EditTemplate Context="value">
<div class="col-12 col-sm-6 col-md-6">
<Select SkipValidate="true" @bind-Value="@value.ChannelType" OnSelectedItemChanged=@((a)=>
{
return InvokeAsync(StateHasChanged);
}) />
</div>
</EditTemplate>
<EditTemplate Context="value">
<div class="col-12 col-sm-6 col-md-6">
<Select SkipValidate="true" @bind-Value="@value.ChannelType" OnSelectedItemChanged=@((a)=>
{
return InvokeAsync(StateHasChanged);
}) />
</div>
</EditTemplate>
</EditorItem>
</EditorItem>
<EditorItem @bind-Field="@context.RemoteUrl" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpClient&&context.ChannelType!=ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.BindUrl" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpClient&&context.ChannelType!=ChannelTypeEnum.UdpSession&&context.ChannelType!=ChannelTypeEnum.TcpService) />
<EditorItem @bind-Field="@context.RemoteUrl" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpClient && context.ChannelType != ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.BindUrl" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpClient && context.ChannelType != ChannelTypeEnum.UdpSession && context.ChannelType != ChannelTypeEnum.TcpService) />
<EditorItem @bind-Field="@context.PortName" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.BaudRate" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.DataBits" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.Parity" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.StopBits" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.DtrEnable" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.RtsEnable" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.StreamAsync" Ignore=@(context.ChannelType!=ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.PortName" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.BaudRate" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.DataBits" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.Parity" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.StopBits" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.DtrEnable" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.RtsEnable" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.StreamAsync" Ignore=@(context.ChannelType != ChannelTypeEnum.SerialPort) />
<EditorItem @bind-Field="@context.CacheTimeout" Ignore=@(context.ChannelType==ChannelTypeEnum.UdpSession||context.ChannelType==ChannelTypeEnum.Other) />
<EditorItem @bind-Field="@context.ConnectTimeout" Ignore=@(context.ChannelType==ChannelTypeEnum.UdpSession||context.ChannelType==ChannelTypeEnum.TcpService||context.ChannelType==ChannelTypeEnum.Other) />
<EditorItem @bind-Field="@context.MaxConcurrentCount" Ignore=@(context.ChannelType==ChannelTypeEnum.Other) />
<EditorItem @bind-Field="@context.CacheTimeout" Ignore=@(context.ChannelType == ChannelTypeEnum.UdpSession || context.ChannelType == ChannelTypeEnum.Other) />
<EditorItem @bind-Field="@context.ConnectTimeout" Ignore=@(context.ChannelType == ChannelTypeEnum.UdpSession || context.ChannelType == ChannelTypeEnum.TcpService || context.ChannelType == ChannelTypeEnum.Other) />
<EditorItem @bind-Field="@context.MaxConcurrentCount" Ignore=@(context.ChannelType == ChannelTypeEnum.Other) />
<EditorItem @bind-Field="@context.MaxClientCount" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpService) />
<EditorItem @bind-Field="@context.CheckClearTime" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpService) />
<EditorItem @bind-Field="@context.Heartbeat" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpService&&context.ChannelType!=ChannelTypeEnum.TcpClient&&context.ChannelType!=ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.HeartbeatTime" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpClient&&context.ChannelType!=ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.DtuId" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpClient&&context.ChannelType!=ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.DtuSeviceType" Ignore=@(context.ChannelType!=ChannelTypeEnum.TcpService&&context.ChannelType!=ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.MaxClientCount" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpService) />
<EditorItem @bind-Field="@context.CheckClearTime" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpService) />
</FieldItems>
<EditorItem @bind-Field="@context.Heartbeat" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpService && context.ChannelType != ChannelTypeEnum.TcpClient && context.ChannelType != ChannelTypeEnum.UdpSession)>
<EditTemplate Context="value">
<div class="col-12 col-md-6">
<BootstrapInput @bind-Value=value.Heartbeat ShowLabel="true" class="me-2"></BootstrapInput>
<Checkbox @bind-Value=value.HeartbeatHex ShowAfterLabel DisplayText="hex"></Checkbox>
</div>
</EditTemplate>
</EditorItem>
</EditorForm>;
<EditorItem @bind-Field="@context.HeartbeatTime" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpClient && context.ChannelType != ChannelTypeEnum.UdpSession) />
<EditorItem @bind-Field="@context.DtuId" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpClient && context.ChannelType != ChannelTypeEnum.UdpSession)>
<EditTemplate Context="value">
<div class="col-12 col-md-6">
<BootstrapInput @bind-Value=value.DtuId ShowLabel="true" class="me-2"></BootstrapInput>
<Checkbox @bind-Value=value.DtuIdHex ShowAfterLabel DisplayText="hex"></Checkbox>
</div>
</EditTemplate>
</EditorItem>
<EditorItem @bind-Field="@context.DtuIdHex" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpService) />
<EditorItem @bind-Field="@context.DtuSeviceType" Ignore=@(context.ChannelType != ChannelTypeEnum.TcpService && context.ChannelType != ChannelTypeEnum.UdpSession) />
</FieldItems>
</EditorForm>;
}

View File

@@ -138,9 +138,8 @@ public partial class VariableEditComponent
AddressDynamicComponent = new BootstrapDynamicComponent(AddressUIType, new Dictionary<string, object?>
{
[nameof(IAddressUIBase.Model)] = Model.RegisterAddress,
[nameof(IAddressUIBase.ModelChanged)] =
(string address) => Model.RegisterAddress = address
(Action<string>)(address => Model.RegisterAddress = address)
});
}
else

View File

@@ -59,7 +59,7 @@ public partial class ModbusMaster : ComponentBase, IDisposable
op.Component = BootstrapDynamicComponent.CreateComponent<ModbusAddressComponent>(new Dictionary<string, object?>
{
{nameof(ModbusAddressComponent.ModelChanged), (string a) => DeviceComponent?.SetRegisterAddress(a)},
{nameof(ModbusAddressComponent.ModelChanged), (Action<string>)(a => DeviceComponent?.SetRegisterAddress(a))},
{nameof(ModbusAddressComponent.Model),address },
});

View File

@@ -52,7 +52,7 @@ public partial class ModbusSlave : ComponentBase, IDisposable
op.Component = BootstrapDynamicComponent.CreateComponent<ModbusAddressComponent>(new Dictionary<string, object?>
{
{nameof(ModbusAddressComponent.ModelChanged), (string a) => DeviceComponent?.SetRegisterAddress(a)},
{nameof(ModbusAddressComponent.ModelChanged), (Action<string>)(a => DeviceComponent?.SetRegisterAddress(a))},
{nameof(ModbusAddressComponent.Model),address },
});