Compare commits

..

6 Commits

Author SHA1 Message Date
Diego
d33d900592 增加github oauth登录 2025-06-15 00:17:25 +08:00
Diego
29365c4ef9 修改脚本测试方法 2025-06-14 11:56:31 +08:00
Diego
17a6189089 style: 更新SysResourcePage页面样式 2025-06-13 16:03:28 +08:00
Diego
003b8a3763 10.7.56 2025-06-13 13:35:38 +08:00
Diego
1c7f8b5cab 10.7.55 2025-06-13 09:14:22 +08:00
Diego
b7ff9ffca2 更新解决方案 2025-06-13 09:06:42 +08:00
125 changed files with 705 additions and 698 deletions

View File

@@ -20,6 +20,7 @@ using System.Collections.Concurrent;
using ThingsGateway.Extension;
using ThingsGateway.FriendlyException;
using ThingsGateway.NewLife.Json.Extension;
using ThingsGateway.SqlSugar;
namespace ThingsGateway.Admin.Application;
@@ -90,13 +91,12 @@ public sealed class OperDescAttribute : MoAttribute
OperDescAttribute.WriteToQueue(log);
}
}
private static SqlSugarClient _db = DbContext.Db.GetConnectionScopeWithAttr<SysOperateLog>().CopyNew();
/// <summary>
/// 将日志消息写入数据库中
/// </summary>
private static async Task ProcessQueue()
{
var db = DbContext.Db.GetConnectionScopeWithAttr<SysOperateLog>().CopyNew();
var appLifetime = App.RootServices!.GetService<IHostApplicationLifetime>()!;
while (!appLifetime.ApplicationStopping.IsCancellationRequested)
{
@@ -105,7 +105,7 @@ public sealed class OperDescAttribute : MoAttribute
var data = _logMessageQueue.ToListWithDequeue(); // 从日志队列中获取数据
if (data.Count > 0)
{
await db.InsertableWithAttr(data).ExecuteCommandAsync(appLifetime.ApplicationStopping).ConfigureAwait(false);//入库
await _db.InsertableWithAttr(data).ExecuteCommandAsync(appLifetime.ApplicationStopping).ConfigureAwait(false);//入库
}
}
catch (Exception ex)

View File

@@ -1,40 +0,0 @@
using Microsoft.AspNetCore.Authentication.OAuth;
using System.Text.Json;
namespace ThingsGateway.Admin.Application;
/// <summary>OAuthOptions 配置类</summary>
public abstract class AdminOAuthOptions : OAuthOptions
{
/// <summary>默认构造函数</summary>
protected AdminOAuthOptions()
{
ConfigureClaims();
this.Events.OnRemoteFailure = context =>
{
var redirectUri = string.IsNullOrEmpty(HomePath) ? "/" : HomePath;
context.Response.Redirect(redirectUri);
context.HandleResponse();
return Task.CompletedTask;
};
}
/// <summary>配置 Claims 映射</summary>
protected virtual void ConfigureClaims()
{
}
public virtual string GetName(JsonElement element)
{
JsonElement.ObjectEnumerator target = element.EnumerateObject();
return target.TryGetValue("name");
}
/// <summary>获得/设置 登陆后首页</summary>
public string HomePath { get; set; } = "/";
}

View File

@@ -1,12 +0,0 @@
namespace ThingsGateway.Admin.Application;
public class GiteeOAuthUser
{
public string Id { get; set; }
public string Login { get; set; }
public string Name { get; set; }
public string Avatar_Url { get; set; }
}

View File

@@ -1,22 +0,0 @@
using System.Text.Json;
namespace ThingsGateway.Admin.Application;
public static class OAuthUserExtensions
{
public static GiteeOAuthUser ToAuthUser(this JsonElement element)
{
GiteeOAuthUser authUser = new GiteeOAuthUser();
JsonElement.ObjectEnumerator target = element.EnumerateObject();
authUser.Id = target.TryGetValue("id");
authUser.Login = target.TryGetValue("login");
authUser.Name = target.TryGetValue("name");
authUser.Avatar_Url = target.TryGetValue("avatar_url");
return authUser;
}
public static string TryGetValue(this JsonElement.ObjectEnumerator target, string propertyName)
{
return target.FirstOrDefault<JsonProperty>((Func<JsonProperty, bool>)(t => t.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase))).Value.ToString() ?? string.Empty;
}
}

View File

@@ -20,6 +20,7 @@ using ThingsGateway.NewLife;
using ThingsGateway.NewLife.Caching;
using ThingsGateway.NewLife.Threading;
using ThingsGateway.Schedule;
using ThingsGateway.SqlSugar;
namespace ThingsGateway.Admin.Application;
@@ -60,7 +61,7 @@ public class HardwareJob : IJob, IHardwareJob
var historyHardwareInfos = MemoryCache.Get<List<HistoryHardwareInfo>>(CacheKey);
if (historyHardwareInfos == null)
{
using var db = DbContext.Db.GetConnectionScopeWithAttr<HistoryHardwareInfo>().CopyNew();
using var db = _db.CopyNew();
historyHardwareInfos = await db.Queryable<HistoryHardwareInfo>().Where(a => a.Date > DateTime.Now.AddDays(-3)).ToListAsync().ConfigureAwait(false);
MemoryCache.Set(CacheKey, historyHardwareInfos);
@@ -70,6 +71,7 @@ public class HardwareJob : IJob, IHardwareJob
private bool error = false;
private DateTime hisInsertTime = default;
private SqlSugarClient _db = DbContext.Db.GetConnectionScopeWithAttr<HistoryHardwareInfo>().CopyNew();
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
{
@@ -121,7 +123,6 @@ public class HardwareJob : IJob, IHardwareJob
if (DateTime.Now > hisInsertTime.Add(TimeSpan.FromMilliseconds(HardwareInfoOptions.HistoryInterval)))
{
hisInsertTime = DateTime.Now;
using var db = DbContext.Db.GetConnectionScopeWithAttr<HistoryHardwareInfo>().CopyNew();
{
var his = new HistoryHardwareInfo()
{
@@ -132,12 +133,12 @@ public class HardwareJob : IJob, IHardwareJob
CpuUsage = (HardwareInfo.MachineInfo.CpuRate * 100).ToInt(),
Temperature = (HardwareInfo.MachineInfo.Temperature).ToInt(),
};
await db.Insertable(his).ExecuteCommandAsync(stoppingToken).ConfigureAwait(false);
await _db.Insertable(his).ExecuteCommandAsync(stoppingToken).ConfigureAwait(false);
MemoryCache.Remove(CacheKey);
}
var sevenDaysAgo = TimerX.Now.AddDays(-HardwareInfoOptions.DaysAgo);
//删除特定信息
var result = await db.Deleteable<HistoryHardwareInfo>(a => a.Date <= sevenDaysAgo).ExecuteCommandAsync(stoppingToken).ConfigureAwait(false);
var result = await _db.Deleteable<HistoryHardwareInfo>(a => a.Date <= sevenDaysAgo).ExecuteCommandAsync(stoppingToken).ConfigureAwait(false);
if (result > 0)
{
MemoryCache.Remove(CacheKey);

View File

@@ -1,18 +1,14 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Collections.Concurrent;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using ThingsGateway.Extension;
@@ -80,6 +76,7 @@ public class AdminOAuthHandler<TOptions>(
AuthenticationProperties properties,
OAuthTokenResponse tokens)
{
Backchannel.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tokens.AccessToken);
properties.RedirectUri = Options.HomePath;
properties.IsPersistent = true;
var appConfig = await configService.GetAppConfigAsync().ConfigureAwait(false);
@@ -90,7 +87,7 @@ public class AdminOAuthHandler<TOptions>(
properties.ExpiresUtc = TimeProvider.System.GetUtcNow().AddSeconds(result);
expire = (int)(result / 60.0);
}
var user = await HandleUserInfoAsync(tokens).ConfigureAwait(false);
var user = await Options.HandleUserInfoAsync(Context, tokens).ConfigureAwait(false);
var loginEvent = await GetLogin(expire).ConfigureAwait(false);
await UpdateUser(loginEvent).ConfigureAwait(false);
@@ -148,43 +145,8 @@ public class AdminOAuthHandler<TOptions>(
}
/// <summary>处理用户信息方法</summary>
protected virtual async Task<JsonElement> HandleUserInfoAsync(OAuthTokenResponse tokens)
{
var request = new HttpRequestMessage(HttpMethod.Get, BuildUserInfoUrl(tokens));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await Backchannel.SendAsync(request, Context.RequestAborted).ConfigureAwait(false);
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
return JsonDocument.Parse(content).RootElement;
}
throw new OAuthTokenException($"OAuth user info endpoint failure: {await Display(response).ConfigureAwait(false)}");
}
/// <summary>生成用户信息请求地址方法</summary>
protected virtual string BuildUserInfoUrl(OAuthTokenResponse tokens)
{
return QueryHelpers.AddQueryString(Options.UserInformationEndpoint, new Dictionary<string, string>
{
{ "access_token", tokens.AccessToken }
});
}
/// <summary>生成错误信息方法</summary>
protected static async Task<string> Display(HttpResponseMessage response)
{
var output = new StringBuilder();
output.Append($"Status: {response.StatusCode}; ");
output.Append($"Headers: {response.Headers}; ");
output.Append($"Body: {await response.Content.ReadAsStringAsync().ConfigureAwait(false)};");
return output.ToString();
}
private async Task<LoginEvent> GetLogin(int expire)
{

View File

@@ -0,0 +1,87 @@
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
namespace ThingsGateway.Admin.Application;
/// <summary>OAuthOptions 配置类</summary>
public abstract class AdminOAuthOptions : OAuthOptions
{
/// <summary>默认构造函数</summary>
protected AdminOAuthOptions()
{
ConfigureClaims();
this.Events.OnRemoteFailure = context =>
{
var redirectUri = string.IsNullOrEmpty(HomePath) ? "/" : HomePath;
context.Response.Redirect(redirectUri);
context.HandleResponse();
return Task.CompletedTask;
};
Backchannel = new HttpClient(new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator // 若测试用
});
Backchannel.DefaultRequestHeaders.UserAgent.Add(
new ProductInfoHeaderValue("ThingsGateway", "1.0"));
}
/// <summary>配置 Claims 映射</summary>
protected virtual void ConfigureClaims()
{
}
public virtual string GetName(JsonElement element)
{
JsonElement.ObjectEnumerator target = element.EnumerateObject();
return target.TryGetValue("name");
}
/// <summary>获得/设置 登陆后首页</summary>
public string HomePath { get; set; } = "/";
/// <summary>处理用户信息方法</summary>
public virtual async Task<JsonElement> HandleUserInfoAsync(HttpContext context, OAuthTokenResponse tokens)
{
var request = new HttpRequestMessage(HttpMethod.Get, BuildUserInfoUrl(tokens));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await Backchannel.SendAsync(request, context.RequestAborted).ConfigureAwait(false);
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
return JsonDocument.Parse(content).RootElement;
}
throw new OAuthTokenException($"OAuth user info endpoint failure: {await Display(response).ConfigureAwait(false)}");
}
/// <summary>生成用户信息请求地址方法</summary>
protected virtual string BuildUserInfoUrl(OAuthTokenResponse tokens)
{
return QueryHelpers.AddQueryString(UserInformationEndpoint, new Dictionary<string, string>
{
{ "access_token", tokens.AccessToken }
});
}
/// <summary>生成错误信息方法</summary>
protected async Task<string> Display(HttpResponseMessage response)
{
var output = new StringBuilder();
output.Append($"Status: {response.StatusCode}; ");
output.Append($"Headers: {response.Headers}; ");
output.Append($"Body: {await response.Content.ReadAsStringAsync().ConfigureAwait(false)};");
return output.ToString();
}
}

View File

@@ -3,16 +3,20 @@ using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.WebUtilities;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using ThingsGateway.NewLife.Log;
namespace ThingsGateway.Admin.Application;
public class GiteeOAuthOptions : AdminOAuthOptions
{
INoticeService _noticeService;
IVerificatInfoService _verificatInfoService;
public GiteeOAuthOptions() : base()
{
_noticeService = App.GetService<INoticeService>();
_verificatInfoService = App.GetService<IVerificatInfoService>();
this.SignInScheme = ClaimConst.Scheme;
this.AuthorizationEndpoint = "https://gitee.com/oauth/authorize";
this.TokenEndpoint = "https://gitee.com/oauth/token";
@@ -29,11 +33,14 @@ public class GiteeOAuthOptions : AdminOAuthOptions
Events.OnRedirectToAuthorizationEndpoint = context =>
{
//context.RedirectUri = context.RedirectUri.Replace("http%3A%2F%2F", "https%3A%2F%2F"); // 强制替换
context.Response.Redirect(context.RedirectUri);
return Task.CompletedTask;
};
Events.OnRemoteFailure = context =>
{
XTrace.WriteException(context.Failure);
return Task.CompletedTask;
};
}
/// <summary>刷新 Token 方法</summary>
@@ -60,16 +67,7 @@ public class GiteeOAuthOptions : AdminOAuthOptions
return OAuthTokenResponse.Failed(new OAuthTokenException($"OAuth token endpoint failure: {await Display(response).ConfigureAwait(false)}"));
}
/// <summary>生成错误信息方法</summary>
protected static async Task<string> Display(HttpResponseMessage response)
{
var output = new StringBuilder();
output.Append($"Status: {response.StatusCode}; ");
output.Append($"Headers: {response.Headers}; ");
output.Append($"Body: {await response.Content.ReadAsStringAsync().ConfigureAwait(false)};");
return output.ToString();
}
public override string GetName(JsonElement element)
{
@@ -77,7 +75,7 @@ public class GiteeOAuthOptions : AdminOAuthOptions
return target.TryGetValue("name");
}
private static async Task HandlerGiteeStarredUrl(OAuthCreatingTicketContext context, string repoFullName = "ThingsGateway/ThingsGateway")
private async Task HandlerGiteeStarredUrl(OAuthCreatingTicketContext context, string repoFullName = "ThingsGateway/ThingsGateway")
{
if (string.IsNullOrWhiteSpace(context.AccessToken))
throw new InvalidOperationException("Access token is missing.");
@@ -89,7 +87,7 @@ public class GiteeOAuthOptions : AdminOAuthOptions
{ "access_token", context.AccessToken }
};
var request = new HttpRequestMessage(HttpMethod.Put, QueryHelpers.AddQueryString(uri, queryString))
var request = new HttpRequestMessage(HttpMethod.Get, QueryHelpers.AddQueryString(uri, queryString))
{
Headers = { Accept = { new MediaTypeWithQualityHeaderValue("application/json") } }
};
@@ -99,7 +97,17 @@ public class GiteeOAuthOptions : AdminOAuthOptions
if (!response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new Exception($"Failed to star repository: {response.StatusCode}, {content}");
var id = context.Identity.Claims.FirstOrDefault(a => a.Type == ClaimConst.VerificatId).Value;
var verificatInfoIds = _verificatInfoService.GetOne(id.ToLong());
_ = Task.Run(async () =>
{
await Task.Delay(5000).ConfigureAwait(false);
await _noticeService.NavigationMesage(verificatInfoIds.ClientIds, "https://gitee.com/ThingsGateway/ThingsGateway", "创作不易如有帮助请star仓库").ConfigureAwait(false);
});
//throw new Exception($"Failed to star repository: {response.StatusCode}, {content}");
}

View File

@@ -0,0 +1,122 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using ThingsGateway.NewLife.Log;
namespace ThingsGateway.Admin.Application;
public class GitHubOAuthOptions : AdminOAuthOptions
{
INoticeService _noticeService;
IVerificatInfoService _verificatInfoService;
public GitHubOAuthOptions() : base()
{
_noticeService = App.GetService<INoticeService>();
_verificatInfoService = App.GetService<IVerificatInfoService>();
SignInScheme = ClaimConst.Scheme;
AuthorizationEndpoint = "https://github.com/login/oauth/authorize";
TokenEndpoint = "https://github.com/login/oauth/access_token";
UserInformationEndpoint = "https://api.github.com/user";
HomePath = "/";
CallbackPath = "/signin-github";
Scope.Add("read:user");
Scope.Add("public_repo"); // 需要用于 Star 仓库
Events.OnCreatingTicket = async context =>
{
await HandleGitHubStarAsync(context).ConfigureAwait(false);
};
Events.OnRedirectToAuthorizationEndpoint = context =>
{
context.Response.Redirect(context.RedirectUri);
return Task.CompletedTask;
};
Events.OnRemoteFailure = context =>
{
XTrace.WriteException(context.Failure);
return Task.CompletedTask;
};
}
protected override void ConfigureClaims()
{
ClaimActions.MapJsonKey(ClaimConst.AvatarUrl, "avatar_url");
ClaimActions.MapJsonKey(ClaimConst.Account, "login");
base.ConfigureClaims();
}
public override string GetName(JsonElement element)
{
if (element.TryGetProperty("login", out var loginProp))
{
return loginProp.GetString() ?? string.Empty;
}
return string.Empty;
}
private async Task HandleGitHubStarAsync(OAuthCreatingTicketContext context, string repoFullName = "ThingsGateway/ThingsGateway")
{
if (string.IsNullOrWhiteSpace(context.AccessToken))
throw new InvalidOperationException("Access token is missing.");
var request = new HttpRequestMessage(HttpMethod.Put, $"https://api.github.com/user/starred/{repoFullName}")
{
Headers =
{
Accept = { new MediaTypeWithQualityHeaderValue("application/vnd.github+json") },
Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken),
},
Content = new StringContent(string.Empty) // GitHub Star 接口需要空内容
};
request.Headers.UserAgent.Add(new ProductInfoHeaderValue("ThingsGateway", "1.0")); // GitHub API 要求 User-Agent
var response = await context.Backchannel.SendAsync(request, context.HttpContext.RequestAborted).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var id = context.Identity.Claims.FirstOrDefault(a => a.Type == ClaimConst.VerificatId).Value;
var verificatInfoIds = _verificatInfoService.GetOne(id.ToLong());
_ = Task.Run(async () =>
{
await Task.Delay(5000).ConfigureAwait(false);
await _noticeService.NavigationMesage(verificatInfoIds.ClientIds, "https://github.com/ThingsGateway/ThingsGateway", "创作不易如有帮助请star仓库").ConfigureAwait(false);
});
}
}
/// <summary>处理用户信息方法</summary>
public override async Task<JsonElement> HandleUserInfoAsync(HttpContext context, OAuthTokenResponse tokens)
{
var request = new HttpRequestMessage(HttpMethod.Get, UserInformationEndpoint);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.github+json"));
request.Headers.UserAgent.Add(new ProductInfoHeaderValue("ThingsGateway", "1.0")); // GitHub API 要求 User-Agent
var response = await Backchannel.SendAsync(request, context.RequestAborted).ConfigureAwait(false);
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
return JsonDocument.Parse(content).RootElement;
}
throw new OAuthTokenException($"OAuth user info endpoint failure: {await Display(response).ConfigureAwait(false)}");
}
}

View File

@@ -0,0 +1,6 @@
namespace ThingsGateway.Admin.Application;
public class GithubOAuthSettings : GiteeOAuthSettings
{
}

View File

@@ -0,0 +1,11 @@
using System.Text.Json;
namespace ThingsGateway.Admin.Application;
public static class OAuthUserExtensions
{
public static string TryGetValue(this JsonElement.ObjectEnumerator target, string propertyName)
{
return target.FirstOrDefault<JsonProperty>((Func<JsonProperty, bool>)(t => t.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase))).Value.ToString() ?? string.Empty;
}
}

View File

@@ -18,7 +18,7 @@ public class SysRelationSeedData : ISqlSugarEntitySeedData<SysRelation>
/// <inheritdoc/>
public IEnumerable<SysRelation> SeedData()
{
var db = DbContext.Db.GetConnectionScopeWithAttr<SysRelation>().CopyNew();
using var db = DbContext.Db.GetConnectionScopeWithAttr<SysRelation>().CopyNew();
if (db.Queryable<SysRelation>().Any(a => a.ObjectId == RoleConst.SuperAdminId))
return Enumerable.Empty<SysRelation>();
var data = SeedDataUtil.GetSeedData<SysRelation>(PathExtensions.CombinePathWithOs("SeedData", "Admin", "seed_sys_relation.json"));

View File

@@ -10,7 +10,6 @@
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;

View File

@@ -5,6 +5,9 @@
@<div>
<span class="mx-3">@item.ConfirmMessage</span>
<Button Text=@Localizers["Jump"] Color="Color.Link" OnClick="()=>NavigationManager.NavigateTo(item.Uri)"></Button>
<a href=@item.Uri target="_blank">
@item.Uri
</a>
</div>;
}

View File

@@ -33,7 +33,7 @@
</PopConfirmButton>
<PopConfirmButton Color=Color.Warning IsDisabled="SelectedRows.Count!=1||!AuthorizeButton(AdminOperConst.Edit)" Text=@OperDescLocalizer["ChangeParentResource"] Icon="fa fa-copy" OnConfirm="OnChangeParent">
<BodyTemplate>
<div class="min-height-500 overflow-y-auto">
<div class="overflow-y-auto" style="height:500px">
<TreeView Items="MenuTreeItems" IsVirtualize="true" OnTreeItemClick="a=>{ChangeParentId=a.Value.Id;return Task.CompletedTask;}" />
</div>
</BodyTemplate>

View File

@@ -16,6 +16,7 @@
<!--动态适用GC-->
<GarbageCollectionAdaptationMode>1</GarbageCollectionAdaptationMode>
<CETCompat>false</CETCompat>
<!--使用自托管线程池-->
<!--<UseWindowsThreadPool>false</UseWindowsThreadPool> -->

View File

@@ -124,16 +124,8 @@ public class SugarAopService : ISugarAopService
//执行时间超过1秒
if (db.Ado.SqlExecutionTime.TotalSeconds > 1)
{
//代码CS文件名
var fileName = db.Ado.SqlStackTrace.FirstFileName;
//代码行数
var fileLine = db.Ado.SqlStackTrace.FirstLine;
//方法名
var FirstMethodName = db.Ado.SqlStackTrace.FirstMethodName;
DbContext.WriteLog($"{fileName}-{FirstMethodName}-{fileLine} 执行时间超过1秒");
DbContext.WriteLog($"SQL执行时间超过1秒");
DbContext.WriteLogWithSql(UtilMethods.GetNativeSql(sql, pars));
}
};
}

View File

@@ -10,7 +10,6 @@
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using ThingsGateway.SqlSugar;

View File

@@ -39,7 +39,7 @@
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.5.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">

View File

@@ -1160,7 +1160,7 @@ public class MachineInfo
public static String GetInfo(String path, String property, String? nameSpace = null)
{
// Linux Mono不支持WMI
if (Runtime.Mono) return "";
if (Runtime.Mono) return string.Empty;
var bbs = new List<String>();
try
@@ -1181,7 +1181,7 @@ public class MachineInfo
catch (Exception ex)
{
if (XTrace.Log.Level <= LogLevel.Debug) XTrace.WriteLine("WMI.GetInfo({0})失败!{1}", path, ex.Message);
return "";
return string.Empty;
}
bbs.Sort();

View File

@@ -854,13 +854,13 @@ public static class IOHelper
/// <returns></returns>
public static String ToHex(this Byte[]? data, Int32 offset = 0, Int32 count = -1)
{
if (data == null || data.Length <= 0) return "";
if (data == null || data.Length <= 0) return string.Empty;
if (count < 0)
count = data.Length - offset;
else if (offset + count > data.Length)
count = data.Length - offset;
if (count == 0) return "";
if (count == 0) return string.Empty;
//return BitConverter.ToString(data).Replace("-", null);
// 上面的方法要替换-,效率太低
@@ -883,7 +883,7 @@ public static class IOHelper
/// <returns></returns>
public static String ToHex(this Byte[]? data, String? separate, Int32 groupSize = 0, Int32 maxLength = -1)
{
if (data == null || data.Length <= 0) return "";
if (data == null || data.Length <= 0) return string.Empty;
if (groupSize < 0) groupSize = 0;

View File

@@ -8,7 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using ThingsGateway.NewLife;

View File

@@ -201,9 +201,9 @@ namespace ThingsGateway.SqlSugar
try
{
if (this.Context.CurrentConnectionConfig?.MoreSettings?.IsNoReadXmlDescription == true)
if (this.Context.CurrentConnectionConfig?.MoreSettings?.IsNoReadXmlDescription ?? true == true)
{
return "";
return string.Empty;
}
if (entityType.Assembly.IsDynamic && entityType.Assembly.FullName.StartsWith("Dynamic"))
{

View File

@@ -17,7 +17,7 @@
public int DefaultCacheDurationInSeconds { get; set; }
public bool? TableEnumIsString { get; set; }
public DateTime? DbMinDate { get; set; } = DateTime.MinValue.Date.AddYears(1900 - 1);
public bool IsNoReadXmlDescription { get; set; }
public bool IsNoReadXmlDescription { get; set; } = true;
public bool SqlServerCodeFirstNvarchar { get; set; }
public bool OracleCodeFirstNvarchar2 { get; set; }
public bool SqliteCodeFirstEnableDefaultValue { get; set; }

View File

@@ -501,7 +501,7 @@ namespace ThingsGateway.SqlSugar
{
return GetFirstTypeNameFromExpression(methodCall.Arguments.FirstOrDefault());
}
return "";
return string.Empty;
}
public static string GetMethodName(Expression expression)

View File

@@ -245,7 +245,7 @@ namespace ThingsGateway.SqlSugar
public string GetMemberName(MemberExpression memberExpression)
{
return "";
return string.Empty;
}
private void ExtMapper(MapperExpressionInfo fillInfo, MapperExpressionInfo mappingFild1Info, MapperExpressionInfo mappingFild1Info2, MapperExpressionInfo selectInfo)

View File

@@ -47,7 +47,7 @@ namespace ThingsGateway.SqlSugar
var isWhere = Convert.ToBoolean(value);
if (!Convert.ToBoolean(isWhere))
{
return "";
return string.Empty;
}
var argExp = exp.Arguments[1];
var copyContext = this.Context;

View File

@@ -43,7 +43,7 @@ namespace ThingsGateway.SqlSugar
}
else
{
return "";
return string.Empty;
}
}
}

View File

@@ -576,7 +576,7 @@ WHERE table_name = '" + tableName + "'");
}
else
{
return "";
return string.Empty;
}
}

View File

@@ -144,7 +144,7 @@ namespace ThingsGateway.SqlSugar
public string DataTableToCsvString(DataTable table)
{
if (table.Rows.Count == 0)
return "";
return string.Empty;
StringBuilder sb = new StringBuilder();
DataColumn colum;
foreach (DataRow row in table.Rows)

View File

@@ -262,7 +262,7 @@ namespace ThingsGateway.SqlSugar
{
get
{
return "";
return string.Empty;
}
}
#endregion

View File

@@ -51,7 +51,7 @@ namespace ThingsGateway.SqlSugar
{
get
{
return "";
return string.Empty;
}
}
protected override string AddColumnToTableSql

View File

@@ -92,12 +92,12 @@ namespace ThingsGateway.SqlSugar
public static string ObjToString(this object thisValue)
{
if (thisValue != null) return thisValue.ToString().Trim();
return "";
return string.Empty;
}
public static string ObjToStringNoTrim(this object thisValue)
{
if (thisValue != null) return thisValue.ToString();
return "";
return string.Empty;
}
public static string ObjToStringNew(this object thisValue)
{
@@ -110,7 +110,7 @@ namespace ThingsGateway.SqlSugar
return Convert.ToDateTime(thisValue.ToString()).ToString("yyyy-MM-dd");
}
if (thisValue != null) return thisValue.ToString().Trim();
return "";
return string.Empty;
}
public static string ObjToString(this object thisValue, string errorValue)

View File

@@ -57,7 +57,7 @@
public static string ObjToString(this object thisValue)
{
if (thisValue != null) return thisValue.ToString().Trim();
return "";
return string.Empty;
}
public static string ObjToString(this object thisValue, string errorValue)

View File

@@ -893,42 +893,25 @@ namespace ThingsGateway.SqlSugar
return Guid.NewGuid() + "";
}
}
static Type IAsyncStateMachineType = typeof(IAsyncStateMachine);
public static bool IsAsyncMethod(MethodBase method)
{
if (method == null)
{
return false;
}
if (method.DeclaringType != null)
{
if (method.DeclaringType.GetInterfaces().Contains(typeof(IAsyncStateMachine)))
{
return true;
}
}
if (method == null) return false;
if (method.GetCustomAttribute<AsyncStateMachineAttribute>() != null)
return true;
if (method.DeclaringType?.GetInterfaces().Contains(IAsyncStateMachineType) == true)
return true;
// 补救方案:有些 async 方法是动态生成的,名字惯例判断
var name = method.Name;
if (name.Contains("OutputAsyncCausalityEvents"))
{
return true;
}
if (name.Contains("OutputWaitEtwEvents"))
{
return true;
}
if (name.Contains("ExecuteAsync"))
{
return true;
}
//if (method?.DeclaringType?.FullName?.Contains("Furion.InternalApp")==true)
//{
// return false;
//}
Type attType = typeof(AsyncStateMachineAttribute);
var attrib = (AsyncStateMachineAttribute)method.GetCustomAttribute(attType);
return (attrib != null);
return name.EndsWith("ExecuteAsync") || name.Contains("OutputAsyncCausalityEvents") || name.Contains("OutputWaitEtwEvents");
}
public static StackTraceInfo GetStackTrace()
{

View File

@@ -29,7 +29,7 @@ namespace ThingsGateway.SqlSugar.TDengine
{
get
{
return "";
return string.Empty;
}
}

View File

@@ -16,7 +16,7 @@
public static string ObjToStringNoTrim(this object thisValue)
{
if (thisValue != null) return thisValue.ToString();
return "";
return string.Empty;
}
public static string ToLower(this string value, bool isLower)
{
@@ -78,7 +78,7 @@
public static string ObjToString(this object thisValue)
{
if (thisValue != null) return thisValue.ToString().Trim();
return "";
return string.Empty;
}
public static string ObjToString(this object thisValue, string errorValue)

View File

@@ -1,8 +1,8 @@
<Project>
<PropertyGroup>
<PluginVersion>10.7.54</PluginVersion>
<ProPluginVersion>10.7.54</ProPluginVersion>
<PluginVersion>10.7.58</PluginVersion>
<ProPluginVersion>10.7.58</ProPluginVersion>
<AuthenticationVersion>2.6.0</AuthenticationVersion>
<NET8Version>8.0.17</NET8Version>
<NET9Version>9.0.6</NET9Version>

View File

@@ -1,6 +1,4 @@
using System.Runtime.CompilerServices;
using ThingsGateway.Blazor.Diagrams.Core.Behaviors;
using ThingsGateway.Blazor.Diagrams.Core.Behaviors;
using ThingsGateway.Blazor.Diagrams.Core.Controls;
using ThingsGateway.Blazor.Diagrams.Core.Events;
using ThingsGateway.Blazor.Diagrams.Core.Extensions;

View File

@@ -23,6 +23,12 @@ public abstract class BusinessBaseWithCacheAlarmModel<VarModel, DevModel, AlarmM
protected ConcurrentQueue<CacheDBItem<AlarmModel>> _memoryAlarmModelQueue = new();
private volatile bool LocalDBCacheAlarmModelInited;
private CacheDB DBCacheAlarm;
protected internal override Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken)
{
DBCacheAlarm = LocalDBCacheAlarmModel();
return base.InitChannelAsync(channel, cancellationToken);
}
/// <summary>
/// 入缓存
@@ -161,10 +167,8 @@ public abstract class BusinessBaseWithCacheAlarmModel<VarModel, DevModel, AlarmM
{
while (!cancellationToken.IsCancellationRequested)
{
using var cache = LocalDBCacheAlarmModel();
//循环获取,固定读最大行数量,执行完成需删除行
var varList = await cache.DBProvider.Queryable<CacheDBItem<AlarmModel>>().Take(_businessPropertyWithCache.SplitSize).ToListAsync(cancellationToken).ConfigureAwait(false);
var varList = await DBCacheAlarm.DBProvider.Queryable<CacheDBItem<AlarmModel>>().Take(_businessPropertyWithCache.SplitSize).ToListAsync(cancellationToken).ConfigureAwait(false);
if (varList.Count > 0)
{
try
@@ -175,7 +179,7 @@ public abstract class BusinessBaseWithCacheAlarmModel<VarModel, DevModel, AlarmM
if (result.IsSuccess)
{
//删除缓存
await cache.DBProvider.Deleteable<CacheDBItem<AlarmModel>>(varList).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);
await DBCacheAlarm.DBProvider.Deleteable<CacheDBItem<AlarmModel>>(varList).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);
}
else
break;

View File

@@ -24,6 +24,14 @@ public abstract class BusinessBaseWithCacheDeviceModel<VarModel, DevModel> : Bus
private volatile bool LocalDBCacheDevModelInited;
private CacheDB DBCacheDev;
protected internal override Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken)
{
DBCacheDev = LocalDBCacheDevModel();
return base.InitChannelAsync(channel, cancellationToken);
}
/// <summary>
/// 入缓存
/// </summary>
@@ -159,10 +167,9 @@ public abstract class BusinessBaseWithCacheDeviceModel<VarModel, DevModel> : Bus
{
while (!cancellationToken.IsCancellationRequested)
{
using var cache = LocalDBCacheDevModel();
//循环获取
var varList = await cache.DBProvider.Queryable<CacheDBItem<DevModel>>().Take(_businessPropertyWithCache.SplitSize).ToListAsync(cancellationToken).ConfigureAwait(false);
var varList = await DBCacheDev.DBProvider.Queryable<CacheDBItem<DevModel>>().Take(_businessPropertyWithCache.SplitSize).ToListAsync(cancellationToken).ConfigureAwait(false);
if (varList.Count > 0)
{
try
@@ -173,7 +180,7 @@ public abstract class BusinessBaseWithCacheDeviceModel<VarModel, DevModel> : Bus
if (result.IsSuccess)
{
//删除缓存
await cache.DBProvider.Deleteable<CacheDBItem<DevModel>>(varList).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);
await DBCacheDev.DBProvider.Deleteable<CacheDBItem<DevModel>>(varList).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);
}
else
break;

View File

@@ -25,6 +25,16 @@ public abstract class BusinessBaseWithCacheVariableModel<VarModel> : BusinessBas
protected volatile bool success = true;
private volatile bool LocalDBCacheVarModelInited;
private volatile bool LocalDBCacheVarModelsInited;
private CacheDB DBCacheVar;
private CacheDB DBCacheVars;
protected internal override Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken)
{
DBCacheVar = LocalDBCacheVarModel();
DBCacheVars = LocalDBCacheVarModels();
return base.InitChannelAsync(channel, cancellationToken);
}
protected sealed override BusinessPropertyBase _businessPropertyBase => _businessPropertyWithCache;
protected abstract BusinessPropertyWithCache _businessPropertyWithCache { get; }
@@ -264,8 +274,8 @@ public abstract class BusinessBaseWithCacheVariableModel<VarModel> : BusinessBas
while (!cancellationToken.IsCancellationRequested)
{
//循环获取
using var cache = LocalDBCacheVarModel();
var varList = await cache.DBProvider.Queryable<CacheDBItem<VarModel>>().Take(_businessPropertyWithCache.SplitSize).ToListAsync(cancellationToken).ConfigureAwait(false);
var varList = await DBCacheVar.DBProvider.Queryable<CacheDBItem<VarModel>>().Take(_businessPropertyWithCache.SplitSize).ToListAsync(cancellationToken).ConfigureAwait(false);
if (varList.Count > 0)
{
try
@@ -276,7 +286,7 @@ public abstract class BusinessBaseWithCacheVariableModel<VarModel> : BusinessBas
if (result.IsSuccess)
{
//删除缓存
await cache.DBProvider.Deleteable<CacheDBItem<VarModel>>(varList).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);
await DBCacheVar.DBProvider.Deleteable<CacheDBItem<VarModel>>(varList).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);
}
else
break;
@@ -325,8 +335,8 @@ public abstract class BusinessBaseWithCacheVariableModel<VarModel> : BusinessBas
while (!cancellationToken.IsCancellationRequested)
{
//循环获取
using var cache = LocalDBCacheVarModels();
var varList = await cache.DBProvider.Queryable<CacheDBItem<List<VarModel>>>().FirstAsync(cancellationToken).ConfigureAwait(false);
var varList = await DBCacheVars.DBProvider.Queryable<CacheDBItem<List<VarModel>>>().FirstAsync(cancellationToken).ConfigureAwait(false);
if (varList?.Value?.Count > 0)
{
try
@@ -337,7 +347,7 @@ public abstract class BusinessBaseWithCacheVariableModel<VarModel> : BusinessBas
if (result.IsSuccess)
{
//删除缓存
await cache.DBProvider.Deleteable<CacheDBItem<List<VarModel>>>(varList).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);
await DBCacheVars.DBProvider.Deleteable<CacheDBItem<List<VarModel>>>(varList).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);
}
else
break;

View File

@@ -18,6 +18,7 @@ using System.Collections.Concurrent;
using ThingsGateway.Extension;
using ThingsGateway.Extension.Generic;
using ThingsGateway.NewLife.Json.Extension;
using ThingsGateway.SqlSugar;
using TouchSocket.Core;
@@ -249,12 +250,13 @@ internal sealed class RpcService : IRpcService
return new(results);
}
private SqlSugarClient _db = DbContext.Db.GetConnectionScopeWithAttr<RpcLog>().CopyNew(); // 创建一个新的数据库上下文实例
/// <summary>
/// 异步执行RPC日志插入操作的方法。
/// </summary>
private async Task RpcLogInsertAsync()
{
var db = DbContext.Db.GetConnectionScopeWithAttr<RpcLog>().CopyNew(); // 创建一个新的数据库上下文实例
var appLifetime = App.RootServices!.GetService<IHostApplicationLifetime>()!;
while (!appLifetime.ApplicationStopping.IsCancellationRequested)
{
@@ -264,7 +266,7 @@ internal sealed class RpcService : IRpcService
if (data.Count > 0)
{
// 将数据插入到数据库中
await db.InsertableWithAttr(data).ExecuteCommandAsync(appLifetime.ApplicationStopping).ConfigureAwait(false);
await _db.InsertableWithAttr(data).ExecuteCommandAsync(appLifetime.ApplicationStopping).ConfigureAwait(false);
}
}
catch (Exception ex)

View File

@@ -4,7 +4,6 @@ using Newtonsoft.Json.Linq;
using System.ComponentModel.DataAnnotations;
using ThingsGateway.Admin.Application;
using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
using ThingsGateway.SqlSugar;

View File

@@ -19,8 +19,6 @@ using ThingsGateway.Blazor.Diagrams.Core.Anchors;
using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
using static Dm.net.buffer.ByteArrayBuffer;
namespace ThingsGateway.Gateway.Application;
public static class RuleHelpers

View File

@@ -1,8 +1,6 @@

using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife;
using TouchSocket.Core;

View File

@@ -1,7 +1,5 @@

using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
using ThingsGateway.Gateway.Application;
using TouchSocket.Core;

View File

@@ -1,7 +1,5 @@

using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
using ThingsGateway.Gateway.Application;
using ThingsGateway.Gateway.Application.Extensions;
using ThingsGateway.NewLife.Extension;

View File

@@ -1,6 +1,5 @@

using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
using TouchSocket.Core;

View File

@@ -1,5 +1,4 @@
using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
namespace ThingsGateway.Gateway.Application;
public abstract class NumberNode : PlaceholderNode

View File

@@ -1,6 +1,5 @@

using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
namespace ThingsGateway.Gateway.Application;
public abstract class TextNode : PlaceholderNode

View File

@@ -1,11 +1,7 @@

using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
using System.Collections.Concurrent;
using ThingsGateway.Foundation;
using ThingsGateway.Gateway.Application;
using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using TouchSocket.Core;

View File

@@ -1,10 +1,7 @@

using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
using System.Collections.Concurrent;
using ThingsGateway.Foundation;
using ThingsGateway.Gateway.Application;
using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using TouchSocket.Core;

View File

@@ -1,7 +1,5 @@

using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
using ThingsGateway.Foundation;
using ThingsGateway.NewLife;
using TouchSocket.Core;

View File

@@ -1,10 +1,7 @@

using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
using System.Collections.Concurrent;
using ThingsGateway.Foundation;
using ThingsGateway.Gateway.Application;
using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using TouchSocket.Core;

View File

@@ -1,6 +1,5 @@

using ThingsGateway.Blazor.Diagrams.Core.Geometry;
using ThingsGateway.Blazor.Diagrams.Core.Models;
namespace ThingsGateway.Gateway.Application;
public abstract class VariableNode : TextNode

View File

@@ -1,6 +1,4 @@
using ThingsGateway.Blazor.Diagrams.Core;
using ThingsGateway.Blazor.Diagrams.Core.Controls.Default;
using ThingsGateway.Blazor.Diagrams.Core.Models.Base;
using ThingsGateway.Blazor.Diagrams.Core.Options;
namespace ThingsGateway.Gateway.Application;

View File

@@ -16,7 +16,6 @@ using Microsoft.Extensions.Logging;
using ThingsGateway.Blazor.Diagrams.Core;
using ThingsGateway.Blazor.Diagrams.Core.Models;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife;
using TouchSocket.Core;

View File

@@ -12,9 +12,7 @@ using BootstrapBlazor.Components;
using System.Data;
using ThingsGateway.Admin.Application;
using ThingsGateway.Extension.Generic;
using ThingsGateway.Gateway.Application;
using ThingsGateway.SqlSugar;
using TouchSocket.Core;

View File

@@ -10,7 +10,6 @@
using Mapster;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
@@ -18,7 +17,6 @@ using System.Reflection;
using ThingsGateway.Authentication;
using ThingsGateway.Management;
using ThingsGateway.Gateway.Application;
using ThingsGateway.SqlSugar;
using ThingsGateway.Upgrade;

View File

@@ -9,7 +9,6 @@
//------------------------------------------------------------------------------
using ThingsGateway.Admin.Razor;
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;

View File

@@ -12,7 +12,6 @@ using Mapster;
using ThingsGateway.Admin.Application;
using ThingsGateway.Foundation;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Json.Extension;
using TouchSocket.Core;

View File

@@ -8,7 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Json.Extension;
namespace ThingsGateway.Gateway.Razor;

View File

@@ -11,7 +11,6 @@
using Mapster;
using ThingsGateway.Admin.Application;
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;

View File

@@ -10,8 +10,6 @@
using Microsoft.AspNetCore.Components.Forms;
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;
public partial class ChannelEditComponent

View File

@@ -8,8 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;
public partial class ChannelRuntimeInfo

View File

@@ -8,8 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;
public partial class ChannelRuntimeInfo1 : IDisposable

View File

@@ -14,7 +14,6 @@ using Microsoft.AspNetCore.Components.Forms;
using ThingsGateway.Admin.Application;
using ThingsGateway.Extension.Generic;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Extension;
namespace ThingsGateway.Gateway.Razor;

View File

@@ -1,6 +1,4 @@
using Mapster;
using ThingsGateway.Gateway.Application;
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有

View File

@@ -14,7 +14,6 @@ using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Web;
using ThingsGateway.Admin.Razor;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Extension;
using ThingsGateway.NewLife.Json.Extension;
using ThingsGateway.SqlSugar;

View File

@@ -8,11 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;
public enum ChannelDevicePluginTypeEnum
{

View File

@@ -11,7 +11,6 @@
using Mapster;
using ThingsGateway.Admin.Application;
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;

View File

@@ -12,7 +12,6 @@ using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Web;
using ThingsGateway.Extension.Generic;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Extension;
namespace ThingsGateway.Gateway.Razor;

View File

@@ -8,8 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;
public partial class DeviceRuntimeInfo

View File

@@ -8,8 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;
public partial class DeviceRuntimeInfo1 : IDisposable

View File

@@ -14,7 +14,6 @@ using Microsoft.AspNetCore.Components.Forms;
using ThingsGateway.Admin.Application;
using ThingsGateway.Extension.Generic;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Extension;
namespace ThingsGateway.Gateway.Razor;

View File

@@ -7,26 +7,24 @@
@namespace ThingsGateway.Gateway.Razor
<ValidateForm Model="Model.Value"
@key=@($"DeviceEditValidateForm{Id}{Model.Value.GetType().TypeHandle.Value}")
<ValidateForm Model="Model.Value"
@key=@($"DeviceEditValidateForm{Id}{Model.Value.GetType().TypeHandle.Value}")
@ref=Model.ValidateForm
Id=@($"DeviceEditValidateForm{Id}{Model.Value.GetType().TypeHandle.Value}")>
@ref=Model.ValidateForm
Id=@($"DeviceEditValidateForm{Id}{Model.Value.GetType().TypeHandle.Value}")
>
<EditorFormObject class="p-2" Items=PluginPropertyEditorItems IsDisplay="!CanWrite" AutoGenerateAllItem="false" RowType=RowType.Inline ItemsPerRow=@(CanWrite?2:3) ShowLabelTooltip=true LabelWidth=@(CanWrite?240:120) Model="Model.Value" ShowLabel="true" @key=@($"DeviceEditEditorFormObject{Id}{Model.Value.GetType().TypeHandle.Value}")>
<EditorFormObject class="p-2" Items=PluginPropertyEditorItems IsDisplay="!CanWrite" AutoGenerateAllItem="false" RowType=RowType.Inline ItemsPerRow=@(CanWrite ? 2 : 3) ShowLabelTooltip=true LabelWidth=@(CanWrite ? 240 : 120) Model="Model.Value" ShowLabel="true" @key=@($"DeviceEditEditorFormObject{Id}{Model.Value.GetType().TypeHandle.Value}")>
<FieldItems>
@if (Model.Value is BusinessPropertyWithCacheIntervalScript businessProperty)
{
<EditorItem FieldExpression=@(()=>context) Field=@(context)>
<EditorItem FieldExpression=@(() => context) Field=@(context)>
<EditTemplate Context="value">
<div class="col-12 col-md-12 min-height-500">
<BootstrapLabel Value=@PropertyComponentLocalizer["BigTextScriptDeviceModel"] ShowLabelTooltip="true" />
<CodeEditor ShowLineNo @bind-Value=@businessProperty.BigTextScriptDeviceModel Language="csharp" Theme="vs-dark" IsReadonly=@(!CanWrite) />
<div class="ms-2 d-flex justify-content-center align-items-center">
<Button IsDisabled=@(!CanWrite) OnClick="()=>CheckScript(businessProperty,nameof(businessProperty.BigTextScriptDeviceModel))">
<Button IsDisabled=@(!CanWrite) OnClick=@(() => CheckScript(businessProperty, nameof(businessProperty.BigTextScriptDeviceModel), Localizer["check"], this, DialogService))>
@Localizer["Check"]
</Button>
</div>
@@ -36,7 +34,7 @@ Id=@($"DeviceEditValidateForm{Id}{Model.Value.GetType().TypeHandle.Value}")
<CodeEditor IsReadonly=@(!CanWrite) ShowLineNo @bind-Value=@businessProperty.BigTextScriptVariableModel Language="csharp" Theme="vs-dark" />
<div class="ms-2 d-flex justify-content-center align-items-center">
<Button IsDisabled=@(!CanWrite) OnClick="()=>CheckScript(businessProperty,nameof(businessProperty.BigTextScriptVariableModel))">
<Button IsDisabled=@(!CanWrite) OnClick=@(() => CheckScript(businessProperty, nameof(businessProperty.BigTextScriptVariableModel), Localizer["check"], this, DialogService))>
@Localizer["Check"]
</Button>
</div>
@@ -46,7 +44,7 @@ Id=@($"DeviceEditValidateForm{Id}{Model.Value.GetType().TypeHandle.Value}")
<CodeEditor IsReadonly=@(!CanWrite) ShowLineNo @bind-Value=@businessProperty.BigTextScriptAlarmModel Language="csharp" Theme="vs-dark" />
<div class="ms-2 d-flex justify-content-center align-items-center">
<Button IsDisabled=@(!CanWrite) OnClick="()=>CheckScript(businessProperty,nameof(businessProperty.BigTextScriptAlarmModel))">
<Button IsDisabled=@(!CanWrite) OnClick=@(() => CheckScript(businessProperty, nameof(businessProperty.BigTextScriptAlarmModel), Localizer["check"], this, DialogService))>
@Localizer["Check"]
</Button>
</div>

View File

@@ -8,7 +8,7 @@
// QQ群605534569
// ------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Json.Extension;
namespace ThingsGateway.Gateway.Razor;
public partial class PropertyComponent : IPropertyUIBase
@@ -34,7 +34,7 @@ public partial class PropertyComponent : IPropertyUIBase
[Inject]
private IStringLocalizer<DeviceEditComponent> Localizer { get; set; }
private async Task CheckScript(BusinessPropertyWithCacheIntervalScript businessProperty, string pname)
public static async Task CheckScript(BusinessPropertyWithCacheIntervalScript businessProperty, string pname, string title, object receiver, DialogService dialogService)
{
string script = null;
if (pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptAlarmModel))
@@ -58,7 +58,7 @@ public partial class PropertyComponent : IPropertyUIBase
var op = new DialogOption()
{
IsScrolling = true,
Title = Localizer["Check"],
Title = title,
ShowFooter = false,
ShowCloseButton = false,
Size = Size.ExtraExtraLarge,
@@ -67,8 +67,16 @@ public partial class PropertyComponent : IPropertyUIBase
op.Component = BootstrapDynamicComponent.CreateComponent<ScriptCheck>(new Dictionary<string, object?>
{
{nameof(ScriptCheck.Data),Array.Empty<object>() },
{nameof(ScriptCheck.Script),script },
{nameof(ScriptCheck.GetResult), (string input,string script)=>
{
var type= script == businessProperty.BigTextScriptDeviceModel?typeof(List<DeviceBasicData>):script ==businessProperty.BigTextScriptAlarmModel?typeof(List<AlarmVariable>):typeof(List<VariableBasicData>);
var data = (IEnumerable<object>)Newtonsoft.Json.JsonConvert.DeserializeObject(input, type);
var value = data.GetDynamicModel(script);
return Task.FromResult( value.ToSystemTextJsonString());
}},
{nameof(ScriptCheck.OnGetDemo),()=>
{
return
@@ -210,7 +218,7 @@ public partial class PropertyComponent : IPropertyUIBase
;
}
},
{nameof(ScriptCheck.ScriptChanged),EventCallback.Factory.Create<string>(this, v =>
{nameof(ScriptCheck.ScriptChanged),EventCallback.Factory.Create<string>(receiver, v =>
{
if (pname == nameof(BusinessPropertyWithCacheIntervalScript.BigTextScriptAlarmModel))
{
@@ -229,7 +237,7 @@ public partial class PropertyComponent : IPropertyUIBase
}) },
});
await DialogService.Show(op);
await dialogService.Show(op);
}

View File

@@ -8,18 +8,14 @@
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Json.Extension;
namespace ThingsGateway.Gateway.Razor;
public partial class ScriptCheck
{
private string Input { get; set; }
[Parameter, EditorRequired]
public string Input { get; set; } = string.Empty;
private string Output { get; set; }
[Parameter, EditorRequired]
public IEnumerable<object> Data { get; set; }
[Parameter, EditorRequired]
public string Script { get; set; }
[Parameter, EditorRequired]
@@ -31,21 +27,20 @@ public partial class ScriptCheck
await ScriptChanged.InvokeAsync(script);
}
private Type type;
protected override void OnInitialized()
{
Input = Data.ToSystemTextJsonString();
type = Data.GetType();
base.OnInitialized();
}
private void CheckScript()
[Parameter]
public Func<string, string, Task<string>> GetResult { get; set; }
private async Task CheckScript()
{
try
{
Data = (IEnumerable<object>)Newtonsoft.Json.JsonConvert.DeserializeObject(Input, type);
var value = Data.GetDynamicModel(Script);
Output = value.ToSystemTextJsonString();
if (GetResult != null)
{
Output = await GetResult(Input, Script).ConfigureAwait(false);
}
}
catch (Exception ex)

View File

@@ -8,8 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;
public partial class GatewayInfo

View File

@@ -8,8 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;
public partial class GatewayMonitorPage

View File

@@ -11,7 +11,6 @@
using Mapster;
using ThingsGateway.Admin.Application;
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;

View File

@@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Components.Web;
using System.Collections.Concurrent;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Extension;
using ThingsGateway.NewLife.Json.Extension;

View File

@@ -15,7 +15,6 @@ using Microsoft.Extensions.Options;
using ThingsGateway.Admin.Application;
using ThingsGateway.Extension.Generic;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Extension;
using ThingsGateway.NewLife.Json.Extension;

View File

@@ -8,8 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;
public partial class BackendLogPage

View File

@@ -8,8 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;
public partial class RpcLogPage

View File

@@ -10,7 +10,6 @@
using Mapster;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Extension;
namespace ThingsGateway.Gateway.Razor;

View File

@@ -8,8 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;
public partial class PluginPage

View File

@@ -10,8 +10,6 @@
using Microsoft.AspNetCore.Components.Forms;
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;
public partial class SavePlugin

View File

@@ -9,7 +9,6 @@
//------------------------------------------------------------------------------
using ThingsGateway.Admin.Application;
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;

View File

@@ -47,7 +47,7 @@ namespace ThingsGateway.Gateway.Razor
return (await expressionNode.ExecuteAsync(new NodeInput(){Value=a==null?a:JToken.Parse(a??string.Empty) },default).ConfigureAwait(false)).JToken?.ToString();
if(Node is IActuatorNode actuatorNode)
return (await actuatorNode.ExecuteAsync(new NodeInput(){Value=a==null?a:JToken.Parse(a??string.Empty) },default).ConfigureAwait(false)).JToken?.ToString();
return "";
return string.Empty;
}) },
{nameof(ScriptEdit.Script),Node.Text },
{nameof(ScriptEdit.ScriptChanged),EventCallback.Factory.Create<string>(this, v =>

View File

@@ -9,7 +9,6 @@
// ------------------------------------------------------------------------------
using ThingsGateway.Extension.Generic;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Extension;
namespace ThingsGateway.Gateway.Razor

View File

@@ -8,8 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Gateway.Razor;
[ThingsGateway.DependencyInjection.SuppressSniffer]

View File

@@ -15,8 +15,7 @@ global using Microsoft.Extensions.Localization;
global using System.Diagnostics.CodeAnalysis;
global using ThingsGateway.Gateway.Application;
global using ThingsGateway.Razor;
global using ThingsGateway.Gateway.Application;
[assembly: SuppressMessage("Reliability", "CA2007", Justification = "<挂起>", Scope = "module")]

View File

@@ -8,7 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace ThingsGateway.Debug;

View File

@@ -188,7 +188,7 @@ public struct PropertyID : ISerializable
return $"{Code}";
}
return "";
return string.Empty;
}
private sealed class Names

View File

@@ -1,38 +0,0 @@
@using BootstrapBlazor.Components
@using Microsoft.Extensions.Localization
@using ThingsGateway.Extension
@using ThingsGateway.Foundation
@using ThingsGateway.Admin.Application
@using ThingsGateway.Admin.Razor
@using ThingsGateway.Gateway.Application
@using ThingsGateway.Plugin.SqlDB
@namespace ThingsGateway.Plugin.DB
<ValidateForm Model="Model.Value"
@key=@($"DeviceEditValidateForm{Id}{Model.Value.GetType().TypeHandle.Value}")
@ref=Model.ValidateForm
Id=@($"DeviceEditValidateForm{Id}{Model.Value.GetType().TypeHandle.Value}")>
<EditorFormObject class="p-2" Items=PluginPropertyEditorItems IsDisplay="!CanWrite" AutoGenerateAllItem="false" RowType=RowType.Inline ItemsPerRow=@(CanWrite?2:3) ShowLabelTooltip=true LabelWidth=@(CanWrite?240:120) Model="Model.Value" ShowLabel="true" @key=@($"DeviceEditEditorFormObject{Id}{Model.Value.GetType().TypeHandle.Value}")>
<FieldItems>
@if (Model.Value is RealDBProducerProperty businessProperty)
{
<EditorItem FieldExpression=@(()=>context) Field=@(context)>
<EditTemplate Context="value">
<div class="col-12 col-md-12">
<BootstrapLabel Value=@RealDBProducerPropertyLocalizer["BigTextScriptHistoryTable"] ShowLabelTooltip="true" />
<CodeEditor @bind-Value=@businessProperty.BigTextScriptHistoryTable Language="csharp" Theme="vs-dark" />
</div>
</EditTemplate>
</EditorItem>
}
</FieldItems>
</EditorFormObject>
</ValidateForm>

View File

@@ -1,41 +0,0 @@
// ------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://thingsgateway.cn/
// QQ群605534569
// ------------------------------------------------------------------------------
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using ThingsGateway.Razor;
namespace ThingsGateway.Plugin.DB
{
public partial class RealDBProducerPropertyRazor : IPropertyUIBase
{
[Parameter, EditorRequired]
public IEnumerable<IEditorItem> PluginPropertyEditorItems { get; set; }
[Parameter, EditorRequired]
public string Id { get; set; }
[Parameter, EditorRequired]
public bool CanWrite { get; set; }
[Parameter, EditorRequired]
public ModelValueValidateForm Model { get; set; }
IStringLocalizer RealDBProducerPropertyLocalizer { get; set; }
protected override Task OnParametersSetAsync()
{
RealDBProducerPropertyLocalizer = App.CreateLocalizerByType(Model.Value.GetType());
return base.OnParametersSetAsync();
}
}
}

View File

@@ -13,7 +13,9 @@ using BootstrapBlazor.Components;
using Mapster;
using ThingsGateway.Admin.Application;
using ThingsGateway.Debug;
using ThingsGateway.Foundation;
using ThingsGateway.NewLife;
using ThingsGateway.NewLife.Extension;
using ThingsGateway.Plugin.DB;
using ThingsGateway.SqlSugar;
@@ -29,7 +31,7 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode
private readonly QuestDBProducerVariableProperty _variablePropertys = new();
/// <inheritdoc/>
public override Type DriverPropertyUIType => typeof(RealDBProducerPropertyRazor);
public override Type DriverPropertyUIType => typeof(SqlDBProducerPropertyRazor);
/// <inheritdoc/>
public override Type DriverUIType
@@ -45,6 +47,13 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode
public override VariablePropertyBase VariablePropertys => _variablePropertys;
protected override BusinessPropertyWithCacheInterval _businessPropertyWithCacheInterval => _driverPropertys;
private SqlSugarClient _db;
protected override void Dispose(bool disposing)
{
_db?.TryDispose();
base.Dispose(disposing);
}
public async Task<SqlSugarPagedList<IDBHistoryValue>> GetDBHistoryValuePagesAsync(DBHistoryValuePageInput input)
{
@@ -60,7 +69,7 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode
protected override async Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken)
{
_db = BusinessDatabaseUtil.GetDb(_driverPropertys.DbType, _driverPropertys.BigTextConnectStr);
_config = new TypeAdapterConfig();
DateTime utcTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
_config.ForType<VariableRuntime, QuestDBHistoryValue>()
@@ -153,20 +162,19 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode
protected override async Task ProtectedStartAsync(CancellationToken cancellationToken)
{
var db = BusinessDatabaseUtil.GetDb(_driverPropertys.DbType, _driverPropertys.BigTextConnectStr);
db.DbMaintenance.CreateDatabase();
_db.DbMaintenance.CreateDatabase();
//必须为间隔上传
if (!_driverPropertys.BigTextScriptHistoryTable.IsNullOrEmpty())
{
DynamicSQLBase? hisModel = CSharpScriptEngineExtension.Do<DynamicSQLBase>(_driverPropertys.BigTextScriptHistoryTable);
hisModel.Logger = LogMessage;
await hisModel.DBInit(db, cancellationToken).ConfigureAwait(false);
await hisModel.DBInit(_db, cancellationToken).ConfigureAwait(false);
}
else
{
db.CodeFirst.As<QuestDBHistoryValue>(_driverPropertys.TableName).InitTables(typeof(QuestDBHistoryValue));
_db.CodeFirst.As<QuestDBHistoryValue>(_driverPropertys.TableName).InitTables(typeof(QuestDBHistoryValue));
}
await base.ProtectedStartAsync(cancellationToken).ConfigureAwait(false);

Some files were not shown because too many files have changed in this diff Show More