build: 10.11.23
feat: 增加部分demo feat: 增加管理软件桌面端
This commit is contained in:
@@ -27,6 +27,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" PrivateAssets="all" Private="false" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" PrivateAssets="all" Private="false" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@@ -89,8 +89,8 @@
|
||||
</div>
|
||||
</Side>
|
||||
<Main>
|
||||
<Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowContextMenuFullScreen="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
|
||||
AdditionalAssemblies="@App.RazorAssemblies" Menus="@MenuService.AllOwnMenuItems"
|
||||
<Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
|
||||
ShowFullscreenToolbarButton=false ShowContextMenuFullScreen=false ShowFullScreen=false AdditionalAssemblies="@App.RazorAssemblies" Menus="@MenuService.AllOwnMenuItems"
|
||||
DefaultUrl=@("/") Body=@(Body!) OnCloseTabItemAsync=@((a)=>
|
||||
{
|
||||
return Task.FromResult(!(a.Url=="/"||a.Url.IsNullOrEmpty()));
|
||||
|
@@ -254,8 +254,6 @@ public static class SpecificationDocumentBuilder
|
||||
/// <param name="configure">自定义配置</param>
|
||||
internal static void BuildGen(SwaggerGenOptions swaggerGenOptions, Action<SwaggerGenOptions> configure = null)
|
||||
{
|
||||
|
||||
|
||||
// 创建分组文档
|
||||
CreateSwaggerDocs(swaggerGenOptions);
|
||||
|
||||
|
@@ -6,7 +6,7 @@
|
||||
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.1.0" />
|
||||
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -1,15 +1,17 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<PluginVersion>10.11.22</PluginVersion>
|
||||
<ProPluginVersion>10.11.22</ProPluginVersion>
|
||||
<DefaultVersion>10.11.22</DefaultVersion>
|
||||
<AuthenticationVersion>10.11.2</AuthenticationVersion>
|
||||
<SourceGeneratorVersion>10.11.2</SourceGeneratorVersion>
|
||||
<PluginVersion>10.11.23</PluginVersion>
|
||||
<ProPluginVersion>10.11.23</ProPluginVersion>
|
||||
<DefaultVersion>10.11.23</DefaultVersion>
|
||||
<AuthenticationVersion>10.11.3</AuthenticationVersion>
|
||||
<SourceGeneratorVersion>10.11.3</SourceGeneratorVersion>
|
||||
<NET8Version>8.0.19</NET8Version>
|
||||
<NET9Version>9.0.8</NET9Version>
|
||||
<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages>
|
||||
<IsTrimmable>false</IsTrimmable>
|
||||
<ManagementProPluginVersion>10.11.22</ManagementProPluginVersion>
|
||||
<ManagementPluginVersion>10.11.22</ManagementPluginVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
@@ -0,0 +1,9 @@
|
||||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("Reliability", "CA2007:考虑对等待的任务调用 ConfigureAwait", Justification = "<挂起>", Scope = "member", Target = "~M:ThingsGateway.Foundation.Demo.Program.Main(System.String[])~System.Threading.Tasks.Task")]
|
||||
[assembly: SuppressMessage("Reliability", "CA2007:考虑对等待的任务调用 ConfigureAwait", Justification = "<挂起>", Scope = "member", Target = "~M:ThingsGateway.Foundation.Demo.ModbusMasterDemo.TestRead~System.Threading.Tasks.Task")]
|
11
src/Foundation/ThingsGateway.Foundation.Demo/GlobalUsings.cs
Normal file
11
src/Foundation/ThingsGateway.Foundation.Demo/GlobalUsings.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
global using TouchSocket.Core;
|
221
src/Foundation/ThingsGateway.Foundation.Demo/ModbusMasterDemo.cs
Normal file
221
src/Foundation/ThingsGateway.Foundation.Demo/ModbusMasterDemo.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using ThingsGateway.Foundation.Modbus;
|
||||
using ThingsGateway.NewLife.Json.Extension;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo;
|
||||
|
||||
#pragma warning disable CA2007 // 考虑对等待的任务调用 ConfigureAwait
|
||||
#pragma warning disable CA1861 // 不要将常量数组作为参数
|
||||
|
||||
/// <summary>
|
||||
/// ModbusMaster
|
||||
/// </summary>
|
||||
public class ModbusMasterDemo
|
||||
{
|
||||
/// <summary>
|
||||
/// 新建链路
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IChannel GetChannel(ChannelOptions channelOptions)
|
||||
{
|
||||
TouchSocketConfig touchSocketConfig = new TouchSocketConfig();
|
||||
return touchSocketConfig.GetChannel(channelOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新建协议对象
|
||||
/// </summary>
|
||||
/// <param name="channel"></param>
|
||||
/// <returns></returns>
|
||||
public ModbusMaster GetDevice(IChannel channel)
|
||||
{
|
||||
var client = new ModbusMaster();
|
||||
client.InitChannel(channel);
|
||||
return client;
|
||||
}
|
||||
public async Task TestReadWrite()
|
||||
{
|
||||
|
||||
//获取链路对象
|
||||
using var channel = GetChannel(new ChannelOptions()
|
||||
{
|
||||
ChannelType = ChannelTypeEnum.TcpClient,
|
||||
RemoteUrl = "127.0.0.1:502",
|
||||
});
|
||||
//配置其他属性,如日志等
|
||||
channel.Config.ConfigureContainer(a => a.AddConsoleLogger());
|
||||
|
||||
//获取协议对象
|
||||
using var device = GetDevice(channel);
|
||||
|
||||
//读取具体类型数据
|
||||
var data = await device.ReadDoubleAsync("400001"); //通过字符串转化地址,读取保持寄存器地址0
|
||||
device.Logger?.Info($"读取到的数据:{data.ToJsonNetString()}");
|
||||
|
||||
|
||||
//读取原始字节数组
|
||||
|
||||
var bytes = await device.ReadAsync("400001", 10); //通过字符串转化地址,读取保持寄存器地址0,10个寄存器
|
||||
device.Logger?.Info($"读取到的数据:{data.ToJsonNetString()}");
|
||||
|
||||
bytes = await device.ModbusReadAsync(new ModbusAddress()
|
||||
{
|
||||
StartAddress = 0,
|
||||
FunctionCode = 3,
|
||||
Length = 10,
|
||||
}); //配置地址对象,读取保持寄存器地址0,10个寄存器
|
||||
|
||||
if (bytes.IsSuccess)
|
||||
{
|
||||
//解析bytes字节数组
|
||||
var byteData = bytes.Content.Span;
|
||||
var data1 = device.ThingsGatewayBitConverter.ToDouble(byteData, 0);
|
||||
var data2 = device.ThingsGatewayBitConverter.ToDouble(byteData, 8);
|
||||
var data3 = device.ThingsGatewayBitConverter.ToUInt16(byteData, 16);
|
||||
device.Logger?.Info($"读取到的数据:{data1},{data2},{data3}");
|
||||
}
|
||||
|
||||
|
||||
//写入数据
|
||||
var write = await device.WriteAsync("400001", (double)123.456); //通过字符串转化地址,写入保持寄存器地址0
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
write = await device.WriteAsync("400001", new double[] { 123.456, 123.456 }); //通过字符串转化地址,写入保持寄存器地址2,2个double寄存器
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
|
||||
write = await device.ModbusRequestAsync(new ModbusAddress()
|
||||
{
|
||||
StartAddress = 0,
|
||||
FunctionCode = 3,
|
||||
MasterWriteDatas = device.ThingsGatewayBitConverter.GetBytes(new double[] { 123.456, 123.456 })
|
||||
}, false); //通过字符串转化地址,写入保持寄存器地址2,2个double寄存器
|
||||
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
|
||||
}
|
||||
public async Task TestMulRead()
|
||||
{
|
||||
|
||||
//获取链路对象
|
||||
using var channel = GetChannel(new ChannelOptions()
|
||||
{
|
||||
ChannelType = ChannelTypeEnum.TcpClient,
|
||||
RemoteUrl = "127.0.0.1:502",
|
||||
});
|
||||
//配置其他属性,如日志等
|
||||
channel.Config.ConfigureContainer(a => a.AddConsoleLogger());
|
||||
|
||||
//获取协议对象
|
||||
using var device = GetDevice(channel);
|
||||
|
||||
|
||||
//批量打包
|
||||
var variableRuntimes = new List<VariableClass>()
|
||||
{
|
||||
new VariableClass()
|
||||
{
|
||||
DataType=DataTypeEnum.Double,
|
||||
RegisterAddress="40001",
|
||||
IntervalTime="1000",
|
||||
},
|
||||
new VariableClass()
|
||||
{
|
||||
DataType=DataTypeEnum.UInt16,
|
||||
RegisterAddress="40009",
|
||||
IntervalTime="1000",
|
||||
},
|
||||
new VariableClass()
|
||||
{
|
||||
DataType=DataTypeEnum.Double,
|
||||
RegisterAddress="40005",
|
||||
IntervalTime="1000",
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
var deviceVariableSourceReads = device.LoadSourceRead<VariableSourceClass>(variableRuntimes, 125, "1000");
|
||||
foreach (var item in deviceVariableSourceReads)
|
||||
{
|
||||
var result = await device.ReadAsync(item.AddressObject);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result1 = item.VariableRuntimes.PraseStructContent(device, result.Content.Span, exWhenAny: true);
|
||||
if (!result1.IsSuccess)
|
||||
{
|
||||
item.LastErrorMessage = result1.ErrorMessage;
|
||||
var time = DateTime.Now;
|
||||
item.VariableRuntimes.ForEach(a => a.SetValue(null, time, isOnline: false));
|
||||
device.Logger?.Warning(result1.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
device.Logger?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item.LastErrorMessage = result.ErrorMessage;
|
||||
var time = DateTime.Now;
|
||||
item.VariableRuntimes.ForEach(a => a.SetValue(null, time, isOnline: false));
|
||||
device.Logger?.Warning(result.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
device.Logger?.Info($"批量读取到的数据:{variableRuntimes.Select(a => new { a.RegisterAddress, a.Value }).ToJsonNetString()}");
|
||||
|
||||
}
|
||||
|
||||
public async Task TestVariableObject()
|
||||
{
|
||||
|
||||
//获取链路对象
|
||||
using var channel = GetChannel(new ChannelOptions()
|
||||
{
|
||||
ChannelType = ChannelTypeEnum.TcpClient,
|
||||
RemoteUrl = "127.0.0.1:502",
|
||||
});
|
||||
//配置其他属性,如日志等
|
||||
channel.Config.ConfigureContainer(a => a.AddConsoleLogger());
|
||||
|
||||
//获取协议对象
|
||||
using var device = GetDevice(channel);
|
||||
|
||||
|
||||
//使用变量对象读取
|
||||
var testModbusObject = new TestModbusObject(device, 125);
|
||||
await testModbusObject.MultiReadAsync();
|
||||
device.Logger?.Info($"批量读取到的数据:{testModbusObject.ToJsonNetString()}");
|
||||
|
||||
//源生成的写入方法
|
||||
var write = await testModbusObject.WriteDouble1Async(123.456);
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
}
|
||||
}
|
||||
[GeneratorVariable]
|
||||
public partial class TestModbusObject : VariableObject
|
||||
{
|
||||
public TestModbusObject(IDevice device, int maxPack) : base(device, maxPack)
|
||||
{
|
||||
}
|
||||
|
||||
[VariableRuntime(RegisterAddress = "400001")]
|
||||
public double Double1 { get; set; }
|
||||
[VariableRuntime(RegisterAddress = "400005")]
|
||||
public double Double2 { get; set; }
|
||||
|
||||
[VariableRuntime(RegisterAddress = "400009")]
|
||||
public ushort UShort3 { get; set; }
|
||||
[VariableRuntime(RegisterAddress = "4000010")]
|
||||
public ushort UShort4 { get; set; }
|
||||
}
|
34
src/Foundation/ThingsGateway.Foundation.Demo/Program.cs
Normal file
34
src/Foundation/ThingsGateway.Foundation.Demo/Program.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo;
|
||||
#pragma warning disable CA2007 // 考虑对等待的任务调用 ConfigureAwait
|
||||
|
||||
public class Program
|
||||
{
|
||||
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
ModbusMasterDemo modbusMasterDemo = new();
|
||||
await modbusMasterDemo.TestReadWrite();
|
||||
await modbusMasterDemo.TestMulRead();
|
||||
await modbusMasterDemo.TestVariableObject();
|
||||
|
||||
Console.ReadKey();
|
||||
|
||||
SiemensS7MasterDemo siemensS7MasterDemo = new();
|
||||
await siemensS7MasterDemo.TestReadWrite();
|
||||
await siemensS7MasterDemo.TestMulRead();
|
||||
await siemensS7MasterDemo.TestVariableObject();
|
||||
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,214 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using ThingsGateway.Foundation.SiemensS7;
|
||||
using ThingsGateway.NewLife.Json.Extension;
|
||||
|
||||
namespace ThingsGateway.Foundation.Demo;
|
||||
|
||||
#pragma warning disable CA2007 // 考虑对等待的任务调用 ConfigureAwait
|
||||
#pragma warning disable CA1861 // 不要将常量数组作为参数
|
||||
|
||||
/// <summary>
|
||||
/// SiemensS7Master
|
||||
/// </summary>
|
||||
public class SiemensS7MasterDemo
|
||||
{
|
||||
/// <summary>
|
||||
/// 新建链路
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IChannel GetChannel(ChannelOptions channelOptions)
|
||||
{
|
||||
TouchSocketConfig touchSocketConfig = new TouchSocketConfig();
|
||||
return touchSocketConfig.GetChannel(channelOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新建协议对象
|
||||
/// </summary>
|
||||
/// <param name="channel"></param>
|
||||
/// <returns></returns>
|
||||
public SiemensS7Master GetDevice(IChannel channel)
|
||||
{
|
||||
var client = new SiemensS7Master();
|
||||
client.InitChannel(channel);
|
||||
return client;
|
||||
}
|
||||
public async Task TestReadWrite()
|
||||
{
|
||||
|
||||
//获取链路对象
|
||||
using var channel = GetChannel(new ChannelOptions()
|
||||
{
|
||||
ChannelType = ChannelTypeEnum.TcpClient,
|
||||
RemoteUrl = "127.0.0.1:102",
|
||||
});
|
||||
//配置其他属性,如日志等
|
||||
channel.Config.ConfigureContainer(a => a.AddConsoleLogger());
|
||||
|
||||
//获取协议对象
|
||||
using var device = GetDevice(channel);
|
||||
|
||||
//读取具体类型数据
|
||||
var data = await device.ReadDoubleAsync("V1"); //通过字符串转化地址,读取v1
|
||||
device.Logger?.Info($"读取到的数据:{data.ToJsonNetString()}");
|
||||
|
||||
|
||||
//读取原始字节数组
|
||||
|
||||
var bytes = await device.ReadAsync("V1", 20); //通过字符串转化地址,读取v1,10个寄存器
|
||||
device.Logger?.Info($"读取到的数据:{data.ToJsonNetString()}");
|
||||
|
||||
|
||||
if (bytes.IsSuccess)
|
||||
{
|
||||
//解析bytes字节数组
|
||||
var byteData = bytes.Content.Span;
|
||||
var data1 = device.ThingsGatewayBitConverter.ToDouble(byteData, 0);
|
||||
var data2 = device.ThingsGatewayBitConverter.ToDouble(byteData, 8);
|
||||
var data3 = device.ThingsGatewayBitConverter.ToUInt16(byteData, 16);
|
||||
device.Logger?.Info($"读取到的数据:{data1},{data2},{data3}");
|
||||
}
|
||||
|
||||
|
||||
//写入数据
|
||||
var write = await device.WriteAsync("v1", (double)123.456); //通过字符串转化地址,写入保持寄存器地址0
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
write = await device.WriteAsync("v1", new double[] { 123.456, 123.456 }); //通过字符串转化地址,写入保持寄存器地址2,2个double寄存器
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
|
||||
}
|
||||
public async Task TestMulRead()
|
||||
{
|
||||
|
||||
//获取链路对象
|
||||
using var channel = GetChannel(new ChannelOptions()
|
||||
{
|
||||
ChannelType = ChannelTypeEnum.TcpClient,
|
||||
RemoteUrl = "127.0.0.1:102",
|
||||
});
|
||||
//配置其他属性,如日志等
|
||||
channel.Config.ConfigureContainer(a => a.AddConsoleLogger());
|
||||
|
||||
//获取协议对象
|
||||
using var device = GetDevice(channel);
|
||||
|
||||
|
||||
//批量打包
|
||||
var variableRuntimes = new List<VariableClass>()
|
||||
{
|
||||
new VariableClass()
|
||||
{
|
||||
DataType=DataTypeEnum.Double,
|
||||
RegisterAddress="v1",
|
||||
IntervalTime="1000",
|
||||
},
|
||||
new VariableClass()
|
||||
{
|
||||
DataType=DataTypeEnum.UInt16,
|
||||
RegisterAddress="v9",
|
||||
IntervalTime="1000",
|
||||
},
|
||||
new VariableClass()
|
||||
{
|
||||
DataType=DataTypeEnum.Double,
|
||||
RegisterAddress="v11",
|
||||
IntervalTime="1000",
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
var deviceVariableSourceReads = device.LoadSourceRead<VariableSourceClass>(variableRuntimes, 125, "1000");
|
||||
foreach (var item in deviceVariableSourceReads)
|
||||
{
|
||||
var result = await device.ReadAsync(item.AddressObject);
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result1 = item.VariableRuntimes.PraseStructContent(device, result.Content.Span, exWhenAny: true);
|
||||
if (!result1.IsSuccess)
|
||||
{
|
||||
item.LastErrorMessage = result1.ErrorMessage;
|
||||
var time = DateTime.Now;
|
||||
item.VariableRuntimes.ForEach(a => a.SetValue(null, time, isOnline: false));
|
||||
device.Logger?.Warning(result1.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
device.Logger?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item.LastErrorMessage = result.ErrorMessage;
|
||||
var time = DateTime.Now;
|
||||
item.VariableRuntimes.ForEach(a => a.SetValue(null, time, isOnline: false));
|
||||
device.Logger?.Warning(result.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
device.Logger?.Info($"批量读取到的数据:{variableRuntimes.Select(a => new { a.RegisterAddress, a.Value }).ToJsonNetString()}");
|
||||
|
||||
}
|
||||
|
||||
public async Task TestVariableObject()
|
||||
{
|
||||
|
||||
//获取链路对象
|
||||
using var channel = GetChannel(new ChannelOptions()
|
||||
{
|
||||
ChannelType = ChannelTypeEnum.TcpClient,
|
||||
RemoteUrl = "127.0.0.1:102",
|
||||
});
|
||||
//配置其他属性,如日志等
|
||||
channel.Config.ConfigureContainer(a => a.AddConsoleLogger());
|
||||
|
||||
//获取协议对象
|
||||
using var device = GetDevice(channel);
|
||||
|
||||
|
||||
//使用变量对象读取
|
||||
var testS7Object = new TestS7Object(device, 125);
|
||||
await testS7Object.MultiReadAsync();
|
||||
device.Logger?.Info($"批量读取到的数据:{testS7Object.ToJsonNetString()}");
|
||||
|
||||
//源生成的写入方法
|
||||
var write = await testS7Object.WriteDouble1Async(123.456);
|
||||
device.Logger?.Info($"写入结果:{write.ToJsonNetString()}");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 实体类操作PLC数据
|
||||
/// </summary>
|
||||
[GeneratorVariable]
|
||||
public partial class TestS7Object : VariableObject
|
||||
{
|
||||
[VariableRuntime(RegisterAddress = "v1")]
|
||||
public double Double1 { get; set; }
|
||||
[VariableRuntime(RegisterAddress = "v9")]
|
||||
public double Double2 { get; set; }
|
||||
|
||||
[VariableRuntime(RegisterAddress = "v17")]
|
||||
public ushort UShort3 { get; set; }
|
||||
[VariableRuntime(RegisterAddress = "v19")]
|
||||
public ushort UShort4 { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public TestS7Object(IDevice device, int maxPack) : base(device, maxPack)
|
||||
{
|
||||
}
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
@using Microsoft.AspNetCore.Components.Web;
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop;
|
||||
@using ThingsGateway.Foundation
|
||||
@using ThingsGateway.NewLife.Threading
|
||||
@using ThingsGateway.Extension;
|
||||
@using BootstrapBlazor.Components
|
||||
@namespace ThingsGateway.Debug
|
||||
|
||||
<div class="w-100" style=@($"height:{HeightString}")>
|
||||
|
||||
<Card HeaderText=@HeaderText class=@("w-100 h-100")>
|
||||
<HeaderTemplate>
|
||||
<div class="flex-fill">
|
||||
</div>
|
||||
|
||||
@if (LogLevelChanged.HasDelegate)
|
||||
{
|
||||
<Select Value="@LogLevel" ValueChanged="LogLevelChanged" IsPopover></Select>
|
||||
}
|
||||
<Tooltip class=" col-auto" Title="@RazorLocalizer[Pause?"Play":"Pause"]" Placement="Placement.Bottom">
|
||||
|
||||
<Button Color="Color.None" style="color: var(--bs-card-title-color);" Icon=@(Pause?"fa fa-play":"fa fa-pause") OnClick="OnPause" />
|
||||
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip class=" col-auto" Title="@RazorLocalizer["Export"]" Placement="Placement.Bottom">
|
||||
|
||||
<Button IsAsync Color="Color.None" style="color: var(--bs-card-title-color);" Icon=@("fa fa-sign-out") OnClick="HandleOnExportClick" />
|
||||
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip class=" col-auto" Title="@RazorLocalizer["Delete"]" Placement="Placement.Bottom">
|
||||
|
||||
<Button IsAsync Color="Color.None" style="color: var(--bs-card-title-color);" Icon=@("far fa-trash-alt") OnClick="Delete" />
|
||||
|
||||
</Tooltip>
|
||||
|
||||
|
||||
</HeaderTemplate>
|
||||
<BodyTemplate>
|
||||
<div style=@($"height:calc(100% - 50px);overflow-y:scroll;flex-fill;")>
|
||||
<Virtualize Items="CurrentMessages??new List<LogMessage>()" Context="itemMessage" ItemSize="60" OverscanCount=2>
|
||||
<ItemContent>
|
||||
@* <Tooltip Placement="Placement.Bottom" Title=@itemMessage.Message.Substring(0, Math.Min(itemMessage.Message.Length, 500))> *@
|
||||
<div class=@(itemMessage.Level<(byte)Microsoft.Extensions.Logging.LogLevel.Information?"":
|
||||
itemMessage.Level>=(byte)Microsoft.Extensions.Logging.LogLevel.Warning? " red--text text-truncate":"green--text text-truncate")
|
||||
title=@itemMessage.Message.Substring(0, Math.Min(itemMessage.Message.Length, 500))>
|
||||
|
||||
@itemMessage.Message.Substring(0, Math.Min(itemMessage.Message.Length, 150))
|
||||
|
||||
</div>
|
||||
@* </Tooltip> *@
|
||||
</ItemContent>
|
||||
</Virtualize>
|
||||
</div>
|
||||
|
||||
</BodyTemplate>
|
||||
</Card>
|
||||
|
||||
|
||||
</div>
|
@@ -0,0 +1,203 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using ThingsGateway.Extension;
|
||||
using ThingsGateway.Foundation;
|
||||
using ThingsGateway.NewLife;
|
||||
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Debug;
|
||||
|
||||
public partial class LocalLogConsole : IDisposable
|
||||
{
|
||||
private bool Pause;
|
||||
|
||||
public bool Disposed { get; set; }
|
||||
|
||||
[Parameter, EditorRequired]
|
||||
public LogLevel LogLevel { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<LogLevel> LogLevelChanged { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string HeaderText { get; set; } = "Log";
|
||||
|
||||
[Parameter]
|
||||
public string HeightString { get; set; } = "calc(100% - 300px)";
|
||||
|
||||
[Parameter, EditorRequired]
|
||||
public string LogPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志
|
||||
/// </summary>
|
||||
public ICollection<LogMessage> Messages { get; set; } = new List<LogMessage>();
|
||||
|
||||
private ICollection<LogMessage> CurrentMessages => Pause ? PauseMessagesText : Messages;
|
||||
|
||||
[Inject]
|
||||
private DownloadService DownloadService { get; set; }
|
||||
[Inject]
|
||||
private IStringLocalizer<ThingsGateway.Razor._Imports> RazorLocalizer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 暂停缓存
|
||||
/// </summary>
|
||||
private ICollection<LogMessage> PauseMessagesText { get; set; } = new List<LogMessage>();
|
||||
|
||||
[Inject]
|
||||
private IPlatformService PlatformService { get; set; }
|
||||
|
||||
private string logPath;
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (LogPath != logPath)
|
||||
{
|
||||
logPath = LogPath;
|
||||
Messages = new List<LogMessage>();
|
||||
await ExecuteAsync();
|
||||
}
|
||||
|
||||
await base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
[Inject]
|
||||
private ToastService ToastService { get; set; }
|
||||
[Inject]
|
||||
TextFileReadService TextFileReadService { get; set; }
|
||||
public void Dispose()
|
||||
{
|
||||
Disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
private WaitLock WaitLock = new(nameof(LogConsole));
|
||||
protected async Task ExecuteAsync()
|
||||
{
|
||||
if (WaitLock.Waited) return;
|
||||
try
|
||||
{
|
||||
await WaitLock.WaitAsync();
|
||||
await Task.Delay(1000);
|
||||
|
||||
if (LogPath != null)
|
||||
{
|
||||
var files = await TextFileReadService.GetLogFilesAsync(LogPath);
|
||||
if (!files.IsSuccess)
|
||||
{
|
||||
Messages = new List<LogMessage>();
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
Stopwatch sw = Stopwatch.StartNew();
|
||||
var result = await TextFileReadService.LastLogDataAsync(files.Content.FirstOrDefault());
|
||||
if (result.IsSuccess)
|
||||
{
|
||||
Messages = result.Content.Where(a => a.LogLevel >= LogLevel).Select(a => new LogMessage((int)a.LogLevel, $"{a.LogTime} - {a.Message}{(a.ExceptionString.IsNullOrWhiteSpace() ? null : $"{Environment.NewLine}{a.ExceptionString}")}")).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
Messages = new List<LogMessage>();
|
||||
}
|
||||
sw.Stop();
|
||||
if (sw.ElapsedMilliseconds > 500)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NewLife.Log.XTrace.WriteException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
WaitLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_ = RunTimerAsync();
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
private async Task Delete()
|
||||
{
|
||||
await TextFileReadService.DeleteLogDataAsync(LogPath);
|
||||
}
|
||||
|
||||
private async Task HandleOnExportClick(MouseEventArgs args)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Pause)
|
||||
{
|
||||
using var memoryStream = new MemoryStream();
|
||||
using StreamWriter writer = new(memoryStream);
|
||||
foreach (var item in PauseMessagesText)
|
||||
{
|
||||
await writer.WriteLineAsync(item.Message);
|
||||
}
|
||||
await writer.FlushAsync();
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// 定义文件名称规则的正则表达式模式
|
||||
string pattern = @"[\\/:*?""<>|]";
|
||||
// 使用正则表达式将不符合规则的部分替换为下划线
|
||||
string sanitizedFileName = Regex.Replace(HeaderText, pattern, "_");
|
||||
await DownloadService.DownloadFromStreamAsync($"{sanitizedFileName}{DateTime.Now.ToFileDateTimeFormat()}.txt", memoryStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PlatformService != null)
|
||||
await PlatformService.OnLogExport(LogPath);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ToastService.Warn(ex);
|
||||
}
|
||||
}
|
||||
private Task OnPause()
|
||||
{
|
||||
Pause = !Pause;
|
||||
if (Pause)
|
||||
PauseMessagesText = Messages.ToList();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task RunTimerAsync()
|
||||
{
|
||||
while (!Disposed)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ExecuteAsync();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NewLife.Log.XTrace.WriteException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -142,33 +142,7 @@ public partial class LogConsole : IDisposable
|
||||
|
||||
private async Task Delete()
|
||||
{
|
||||
if (LogPath != null)
|
||||
{
|
||||
var files = await TextFileReadService.GetLogFilesAsync(LogPath);
|
||||
if (files.IsSuccess)
|
||||
{
|
||||
foreach (var item in files.Content)
|
||||
{
|
||||
if (File.Exists(item))
|
||||
{
|
||||
int error = 0;
|
||||
while (error < 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileUtil.DeleteFile(item);
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Task.Delay(3000);
|
||||
error++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await TextFileReadService.DeleteLogDataAsync(LogPath);
|
||||
}
|
||||
|
||||
private async Task HandleOnExportClick(MouseEventArgs args)
|
||||
|
@@ -34,5 +34,6 @@ public class Startup : AppStartup
|
||||
|
||||
services.AddScoped<IPlatformService, PlatformService>();
|
||||
services.AddSingleton<ITextFileReadService, TextFileReadService>();
|
||||
services.AddSingleton<TextFileReadService, TextFileReadService>();
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@@ -13,6 +13,8 @@ namespace ThingsGateway.Foundation;
|
||||
|
||||
public interface ITextFileReadService
|
||||
{
|
||||
Task DeleteLogDataAsync(string path);
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定目录下所有文件信息
|
||||
/// </summary>
|
||||
|
@@ -10,6 +10,8 @@
|
||||
|
||||
|
||||
|
||||
using ThingsGateway.NewLife;
|
||||
|
||||
namespace ThingsGateway.Foundation;
|
||||
|
||||
public class TextFileReadService : ITextFileReadService
|
||||
@@ -17,4 +19,37 @@ public class TextFileReadService : ITextFileReadService
|
||||
public Task<OperResult<List<string>>> GetLogFilesAsync(string directoryPath) => Task.FromResult(TextFileReader.GetLogFiles(directoryPath));
|
||||
|
||||
public Task<OperResult<List<LogData>>> LastLogDataAsync(string file, int lineCount = 200) => Task.FromResult(TextFileReader.LastLogData(file, lineCount));
|
||||
|
||||
|
||||
public async Task DeleteLogDataAsync(string path)
|
||||
{
|
||||
if (path != null)
|
||||
{
|
||||
var files = TextFileReader.GetLogFiles(path);
|
||||
if (files.IsSuccess)
|
||||
{
|
||||
foreach (var item in files.Content)
|
||||
{
|
||||
if (File.Exists(item))
|
||||
{
|
||||
int error = 0;
|
||||
while (error < 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileUtil.DeleteFile(item);
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Task.Delay(3000).ConfigureAwait(false);
|
||||
error++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace ThingsGateway.Foundation;
|
||||
|
||||
/// <summary>
|
||||
@@ -60,6 +61,8 @@ public class VariableClass : IVariable
|
||||
/// <summary>
|
||||
/// IVariableSource
|
||||
/// </summary>
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public IVariableSource? VariableSource { get; set; }
|
||||
public object? RawValue { get; private set; }
|
||||
|
||||
|
@@ -75,6 +75,8 @@ public interface IManagementRpcServer : IRpcServer
|
||||
|
||||
[DmtpRpc]
|
||||
Task<bool> DeleteDeviceAsync(List<long> ids, bool restart);
|
||||
[DmtpRpc]
|
||||
Task DeleteLogDataAsync(string path);
|
||||
|
||||
/// <summary>
|
||||
/// 删除 RpcLog 表中的所有记录
|
||||
|
@@ -185,7 +185,7 @@ public partial class ManagementRpcServer : IRpcServer, IManagementRpcServer, IBa
|
||||
App.GetService<IDevicePageService>().IsRedundantDeviceAsync(id);
|
||||
|
||||
public Task<OperResult<List<LogData>>> LastLogDataAsync(string file, int lineCount = 200) => App.GetService<ITextFileReadService>().LastLogDataAsync(file, lineCount);
|
||||
|
||||
public Task DeleteLogDataAsync(string path) => App.GetService<ITextFileReadService>().DeleteLogDataAsync(path);
|
||||
public Task<QueryData<ChannelRuntime>> OnChannelQueryAsync(QueryPageOptions options) =>
|
||||
App.GetService<IChannelPageService>().OnChannelQueryAsync(options);
|
||||
|
||||
|
@@ -34,7 +34,8 @@
|
||||
<TableColumn Field="@context.DeviceName" FieldExpression=@(() => context.DeviceName) ShowTips=true Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.Name" ShowTips=true Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.Description" ShowTips=true Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.BusinessGroup" ShowTips=true Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.CollectGroup" ShowTips=true Filterable=true Sortable=true Visible=false />
|
||||
<TableColumn @bind-Field="@context.BusinessGroup" ShowTips=true Filterable=true Sortable=true Visible=false />
|
||||
<TableColumn @bind-Field="@context.BusinessGroupUpdateTrigger" ShowTips=true Filterable=true Sortable=true Visible=false />
|
||||
<TableColumn @bind-Field="@context.RpcWriteCheck" ShowTips=true Filterable=true Sortable=true Visible=false />
|
||||
|
||||
@@ -51,7 +52,7 @@
|
||||
|
||||
<TableColumn @bind-Field="@context.SaveValue" Filterable=true Sortable=true Visible=false />
|
||||
<TableColumn @bind-Field="@context.DataType" Filterable=true Sortable=true Visible=false />
|
||||
<TableColumn Field="@context.RuntimeType" ShowTips=true FieldExpression=@(() => context.RuntimeType) Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn Field="@context.RuntimeType" ShowTips=true FieldExpression=@(() => context.RuntimeType) Filterable=true Sortable=true Visible=false />
|
||||
|
||||
<TableColumn @bind-Field="@context.RegisterAddress" Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.ArrayLength" Filterable=true Sortable=true Visible=false />
|
||||
@@ -60,7 +61,7 @@
|
||||
<TableColumn @bind-Field="@context.IntervalTime" Filterable=true Sortable=true Visible="false" />
|
||||
<TableColumn @bind-Field="@context.OtherMethod" Filterable=true Sortable=true Visible="false" />
|
||||
<TableColumn @bind-Field="@context.RpcWriteEnable" Filterable=true Sortable=true Visible="false" />
|
||||
<TableColumn @bind-Field="@context.ReadExpressions" Filterable=true Sortable=true Visible="false" />
|
||||
<TableColumn @bind-Field="@context.ReadExpressions" Filterable=true Sortable=true Visible="true" />
|
||||
<TableColumn @bind-Field="@context.WriteExpressions" Filterable=true Sortable=true Visible="false" />
|
||||
<TableColumn @bind-Field="@context.Unit" Filterable=true Sortable=true Visible="false" />
|
||||
|
||||
|
@@ -56,8 +56,8 @@
|
||||
</Side>
|
||||
<Main>
|
||||
|
||||
<Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowContextMenuFullScreen="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
|
||||
AdditionalAssemblies="@App.RazorAssemblies" Menus="@MenuService.AllOwnMenuItems"
|
||||
<Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
|
||||
ShowFullscreenToolbarButton=false ShowContextMenuFullScreen=false ShowFullScreen=false AdditionalAssemblies="@App.RazorAssemblies" Menus="@MenuService.AllOwnMenuItems"
|
||||
DefaultUrl=@("/") Body=@(Body!) OnCloseTabItemAsync=@((a)=>
|
||||
{
|
||||
return Task.FromResult(!(a.Url=="/"||a.Url.IsNullOrEmpty()));
|
||||
|
@@ -102,7 +102,7 @@ internal sealed class Program
|
||||
hybridApp.MainWindow.SetUseOsDefaultLocation(false);
|
||||
hybridApp.MainWindow.SetUseOsDefaultSize(false);
|
||||
hybridApp.MainWindow.SetSize(new System.Drawing.Size(1920, 1080));
|
||||
hybridApp.MainWindow.SetTitle("ThingsGateway.Photino");
|
||||
hybridApp.MainWindow.SetTitle("ThingsGateway边缘网关");
|
||||
hybridApp.MainWindow.SetIconFile("favicon.ico");
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, error) =>
|
||||
|
@@ -88,8 +88,8 @@
|
||||
</div>
|
||||
</Side>
|
||||
<Main>
|
||||
<Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowContextMenuFullScreen="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
|
||||
AdditionalAssemblies="@App.RazorAssemblies" Menus="@MenuService.AllOwnMenuItems"
|
||||
<Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
|
||||
ShowFullscreenToolbarButton=false ShowContextMenuFullScreen=false ShowFullScreen=false AdditionalAssemblies="@App.RazorAssemblies" Menus="@MenuService.AllOwnMenuItems"
|
||||
DefaultUrl=@("/") Body=@(Body!) OnCloseTabItemAsync=@((a)=>
|
||||
{
|
||||
return Task.FromResult(!(a.Url=="/"||a.Url.IsNullOrEmpty()));
|
||||
|
@@ -111,6 +111,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "foundation", "foundation",
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "debug", "debug", "{053AB5FA-9742-96EC-76A1-2AEC739860C6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThingsGateway.Foundation.Demo", "Foundation\ThingsGateway.Foundation.Demo\ThingsGateway.Foundation.Demo.csproj", "{520DEEAA-1CBD-C0CB-2363-EB190D7DE4EA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -281,6 +283,10 @@ Global
|
||||
{EAEE6A03-D2E7-7283-0F7A-F15B6261EE96}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EAEE6A03-D2E7-7283-0F7A-F15B6261EE96}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EAEE6A03-D2E7-7283-0F7A-F15B6261EE96}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{520DEEAA-1CBD-C0CB-2363-EB190D7DE4EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{520DEEAA-1CBD-C0CB-2363-EB190D7DE4EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{520DEEAA-1CBD-C0CB-2363-EB190D7DE4EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{520DEEAA-1CBD-C0CB-2363-EB190D7DE4EA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -327,10 +333,11 @@ Global
|
||||
{1D9CD7A3-9700-A851-0ABD-183347D9CC33} = {36510D70-161F-4241-B8D0-781E21032816}
|
||||
{E6EF2033-F02A-CDAD-5A72-EE397A89742E} = {36510D70-161F-4241-B8D0-781E21032816}
|
||||
{053AB5FA-9742-96EC-76A1-2AEC739860C6} = {36510D70-161F-4241-B8D0-781E21032816}
|
||||
{520DEEAA-1CBD-C0CB-2363-EB190D7DE4EA} = {2AC600BB-4325-4E0A-93A7-B1F53C8E2CA7}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {199B1B96-4F56-4828-9531-813BA02DB282}
|
||||
RESX_NeutralResourcesLanguage = zh-Hans
|
||||
RESX_Rules = {"EnabledRules":[]}
|
||||
RESX_NeutralResourcesLanguage = zh-Hans
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
Reference in New Issue
Block a user