😎实体调整及代码优化

This commit is contained in:
zuohuaijun 2025-09-05 14:35:50 +08:00
parent d6acf55255
commit d08a642514
7 changed files with 262 additions and 251 deletions

View File

@ -91,24 +91,24 @@ public abstract class EntityBase : EntityBaseId, IDeletedFilter
public abstract class EntityBaseData : EntityBase, IOrgIdFilter
{
/// <summary>
/// 创建者部门Id
/// 创建者机构Id
/// </summary>
[OwnerOrg]
[SugarColumn(ColumnDescription = "创建者部门Id")]
[SugarColumn(ColumnDescription = "创建者机构Id")]
public virtual long? CreateOrgId { get; set; }
/// <summary>
/// 创建者部门
/// 创建者机构
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
[Navigate(NavigateType.OneToOne, nameof(CreateOrgId))]
public virtual SysOrg CreateOrg { get; set; }
public virtual SysOrg SysOrg { get; set; }
/// <summary>
/// 创建者部门名称
/// 创建者机构名称
/// </summary>
[SugarColumn(ColumnDescription = "创建者部门名称", Length = 64)]
[SugarColumn(ColumnDescription = "创建者机构名称", Length = 64)]
public virtual string? CreateOrgName { get; set; }
}
@ -122,6 +122,14 @@ public abstract class EntityTenant : EntityBase, ITenantIdFilter
/// </summary>
[SugarColumn(ColumnDescription = "租户Id", IsOnlyIgnoreUpdate = true)]
public virtual long? TenantId { get; set; }
/// <summary>
/// 租户
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
[Navigate(NavigateType.OneToOne, nameof(TenantId))]
public SysTenant SysTenant { get; set; }
}
/// <summary>
@ -134,6 +142,14 @@ public abstract class EntityTenantId : EntityBaseId, ITenantIdFilter
/// </summary>
[SugarColumn(ColumnDescription = "租户Id", IsOnlyIgnoreUpdate = true)]
public virtual long? TenantId { get; set; }
/// <summary>
/// 租户
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
[Navigate(NavigateType.OneToOne, nameof(TenantId))]
public SysTenant SysTenant { get; set; }
}
/// <summary>
@ -146,4 +162,12 @@ public abstract class EntityTenantBaseData : EntityBaseData, ITenantIdFilter
/// </summary>
[SugarColumn(ColumnDescription = "租户Id", IsOnlyIgnoreUpdate = true)]
public virtual long? TenantId { get; set; }
/// <summary>
/// 租户
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
[Navigate(NavigateType.OneToOne, nameof(TenantId))]
public SysTenant SysTenant { get; set; }
}

View File

@ -19,12 +19,28 @@ public partial class SysTenant : EntityBase
[SugarColumn(ColumnDescription = "租管用户Id")]
public long UserId { get; set; }
/// <summary>
/// 租管用户
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
[Navigate(NavigateType.OneToOne, nameof(UserId))]
public SysUser SysUser { get; set; }
/// <summary>
/// 机构Id
/// </summary>
[SugarColumn(ColumnDescription = "机构Id")]
public long OrgId { get; set; }
/// <summary>
/// 机构
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
[Navigate(NavigateType.OneToOne, nameof(OrgId))]
public SysOrg SysOrg { get; set; }
/// <summary>
/// 域名
/// </summary>

View File

@ -186,7 +186,7 @@ public class SysAuthService : IDynamicApiController, ITransient
{
VerifyPassword(password, keyPasswordErrorTimes, passwordErrorTimes, user);
}
else if (!await App.GetRequiredService<SysLdapService>().AuthAccount(user.TenantId.Value, userLdap.Account, CryptogramHelper.Decrypt(password)))
else if (!await App.GetRequiredService<SysLdapService>().AuthAccount(user.TenantId!.Value, userLdap.Account, CryptogramHelper.Decrypt(password)))
{
_sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
throw Oops.Oh(ErrorCodeEnum.D1000);
@ -256,9 +256,9 @@ public class SysAuthService : IDynamicApiController, ITransient
// 更新用户登录信息
user.LastLoginIp = _httpContextAccessor.HttpContext.GetRemoteIpAddressToIPv4(true);
(user.LastLoginAddress, double? longitude, double? latitude) = CommonHelper.GetIpAddress(user.LastLoginIp);
(user.LastLoginAddress, double? _, double? _) = CommonHelper.GetIpAddress(user.LastLoginIp);
user.LastLoginTime = DateTime.Now;
user.LastLoginDevice = CommonHelper.GetClientDeviceInfo(_httpContextAccessor.HttpContext?.Request?.Headers?.UserAgent);
user.LastLoginDevice = CommonHelper.GetClientDeviceInfo(_httpContextAccessor.HttpContext?.Request.Headers.UserAgent);
await _sysUserRep.AsUpdateable(user).UpdateColumns(u => new
{
u.LastLoginIp,
@ -387,7 +387,7 @@ public class SysAuthService : IDynamicApiController, ITransient
[AllowAnonymous]
public int SwaggerCheckUrl()
{
return _httpContextAccessor.HttpContext.User.Identity.IsAuthenticated ? 200 : 401;
return _httpContextAccessor.HttpContext!.User.Identity!.IsAuthenticated ? 200 : 401;
}
/// <summary>
@ -405,7 +405,7 @@ public class SysAuthService : IDynamicApiController, ITransient
// 关闭默认租户验证码验证
var tenantList = _sysCacheService.Get<List<SysTenant>>(CacheConst.KeyTenant);
var tenant = tenantList.FirstOrDefault(u => u.Id == SqlSugarConst.DefaultTenantId);
var tmpCaptcha = tenant.Captcha;
var tmpCaptcha = tenant!.Captcha;
tenant.Captcha = false;
_sysCacheService.Set(CacheConst.KeyTenant, tenantList);

View File

@ -436,6 +436,7 @@ public static class SqlSugarExtension
// 执行前处理种子数据
if (handleBefore != null) foreach (var sd in seedData) handleBefore(sd);
dbProvider.QueryFilter.ClearAndBackup();
int total, insertCount = 0, updateCount = 0;
if (entityType.GetCustomAttribute<SplitTableAttribute>(true) != null)
{
@ -475,6 +476,7 @@ public static class SqlSugarExtension
}
}
}
dbProvider.QueryFilter.Restore();
return (total, insertCount, updateCount);
}
@ -515,16 +517,16 @@ public static class SqlSugarExtension
#region
/// <summary>
/// 延迟初始化流水号服务实例
/// </summary>
private static readonly Lazy<SysCommonService> SysCommon = new(() => App.GetService<SysCommonService>());
/// <summary>
/// 包含缩写特性的类型属性缓存表
/// </summary>
private static readonly ConcurrentDictionary<Type, Dictionary<string, (PropertyInfo Prop, BindTextAbbrAttribute Attr)>?> _textAbbrPropCache = new();
/// <summary>
/// 系统通用服务
/// </summary>
private static readonly Lazy<SysCommonService> _lazySysCommonService = new(() => App.GetService<SysCommonService>());
/// <summary>
/// 初始化文本简称数据
/// </summary>
@ -586,8 +588,9 @@ public static class SqlSugarExtension
if (string.IsNullOrWhiteSpace(value)) return;
// 使用线程安全的延迟初始化服务实例获取文本缩写
var abbrValue = _lazySysCommonService.Value
var abbrValue = SysCommon.Value
.GetNameAbbr(new() { Text = value, All = attribute.SaveFullAbbr })
.ConfigureAwait(false)
.GetAwaiter()
.GetResult();
entityInfo.SetValue(abbrValue);
@ -597,16 +600,16 @@ public static class SqlSugarExtension
#region
/// <summary>
/// 延迟初始化流水号服务实例
/// </summary>
private static readonly Lazy<SysSerialService> SerialService = new(() => App.GetService<SysSerialService>());
/// <summary>
/// 包含流水号特性的类型属性缓存表
/// </summary>
private static readonly ConcurrentDictionary<Type, Dictionary<string, (PropertyInfo Prop, BindSerialAttribute Attr)>?> _serialPropCache = new();
/// <summary>
/// 系统通用服务
/// </summary>
private static readonly Lazy<SysSerialService> _lazySysSerialService = new(() => App.GetService<SysSerialService>());
/// <summary>
/// 自动生成流水号到绑定字段
/// </summary>
@ -641,8 +644,9 @@ public static class SqlSugarExtension
var (_, attribute) = propData;
// 使用线程安全的延迟初始化服务实例获取流水号
var serial = _lazySysSerialService.Value
var serial = SerialService.Value
.NextSeqNo(attribute.Type, attribute.IsGlobal)
.ConfigureAwait(false)
.GetAwaiter()
.GetResult();
entityInfo.SetValue(serial);

View File

@ -1,33 +0,0 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary>
/// 懒加载帮助类
/// </summary>
public class LazyHelper
{
private static readonly ConcurrentDictionary<Type, dynamic> Cache = new();
/// <summary>
/// 获取服务
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static Lazy<T> GetService<T>() where T : class
{
try
{
return Cache.GetOrAdd(typeof(T), _ => new Lazy<T>(() => App.GetService<T>()));
}
catch (Exception)
{
Cache.Remove(typeof(T), out _);
return null;
}
}
}

View File

@ -6,203 +6,203 @@
using Renci.SshNet;
namespace Admin.NET.Core
namespace Admin.NET.Core;
/// <summary>
/// SSH/Sftp 工具类
/// </summary>
public class SSHHelper : IDisposable
{
/// <summary>
/// SSH/Sftp 工具类
/// </summary>
public class SSHHelper : IDisposable
private readonly SftpClient _sftp;
public SSHHelper(string host, int port, string user, string password)
{
private readonly SftpClient _sftp;
_sftp = new SftpClient(host, port, user, password);
}
public SSHHelper(string host, int port, string user, string password)
/// <summary>
/// 连接
/// </summary>
private void Connect()
{
if (!_sftp.IsConnected)
_sftp.Connect();
}
/// <summary>
/// 是否存在同名文件
/// </summary>
/// <param name="ftpFileName"></param>
/// <returns></returns>
public bool Exists(string ftpFileName)
{
Connect();
return _sftp.Exists(ftpFileName);
}
/// <summary>
/// 删除文件
/// </summary>
/// <param name="ftpFileName"></param>
public void DeleteFile(string ftpFileName)
{
Connect();
_sftp.DeleteFile(ftpFileName);
}
/// <summary>
/// 下载到指定目录
/// </summary>
/// <param name="ftpFileName"></param>
/// <param name="localFileName"></param>
public void DownloadFile(string ftpFileName, string localFileName)
{
Connect();
using Stream fileStream = File.OpenWrite(localFileName);
_sftp.DownloadFile(ftpFileName, fileStream);
}
/// <summary>
/// 读取字节
/// </summary>
/// <param name="ftpFileName"></param>
/// <returns></returns>
public byte[] ReadAllBytes(string ftpFileName)
{
Connect();
return _sftp.ReadAllBytes(ftpFileName);
}
/// <summary>
/// 读取流
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public Stream OpenRead(string path)
{
return _sftp.Open(path, FileMode.Open, FileAccess.Read);
}
/// <summary>
/// 继续下载
/// </summary>
/// <param name="ftpFileName"></param>
/// <param name="localFileName"></param>
public void DownloadFileWithResume(string ftpFileName, string localFileName)
{
DownloadFile(ftpFileName, localFileName);
}
/// <summary>
/// 重命名
/// </summary>
/// <param name="oldPath"></param>
/// <param name="newPath"></param>
public void RenameFile(string oldPath, string newPath)
{
_sftp.RenameFile(oldPath, newPath);
}
/// <summary>
/// 指定目录下文件
/// </summary>
/// <param name="folder"></param>
/// <param name="filters"></param>
/// <returns></returns>
public List<string> GetFileList(string folder, IEnumerable<string> filters)
{
Connect();
var files = new List<string>();
var sftpFiles = _sftp.ListDirectory(folder);
foreach (var file in sftpFiles)
{
_sftp = new SftpClient(host, port, user, password);
if (file.IsRegularFile && filters.Any(f => file.Name.EndsWith(f)))
files.Add(file.Name);
}
/// <summary>
/// 连接
/// </summary>
private void Connect()
return files;
}
/// <summary>
/// 上传指定目录文件
/// </summary>
/// <param name="localFileName"></param>
/// <param name="ftpFileName"></param>
public void UploadFile(string localFileName, string ftpFileName)
{
Connect();
var dir = Path.GetDirectoryName(ftpFileName);
CreateDir(_sftp, dir);
using var fileStream = new FileStream(localFileName, FileMode.Open);
_sftp.UploadFile(fileStream, ftpFileName);
}
/// <summary>
/// 上传字节
/// </summary>
/// <param name="bs"></param>
/// <param name="ftpFileName"></param>
public void UploadFile(byte[] bs, string ftpFileName)
{
Connect();
var dir = Path.GetDirectoryName(ftpFileName);
CreateDir(_sftp, dir);
_sftp.WriteAllBytes(ftpFileName, bs);
}
/// <summary>
/// 上传流
/// </summary>
/// <param name="fileStream"></param>
/// <param name="ftpFileName"></param>
public void UploadFile(Stream fileStream, string ftpFileName)
{
Connect();
var dir = Path.GetDirectoryName(ftpFileName);
CreateDir(_sftp, dir);
_sftp.UploadFile(fileStream, ftpFileName);
fileStream.Dispose();
}
/// <summary>
/// 创建目录
/// </summary>
/// <param name="sftp"></param>
/// <param name="dir"></param>
/// <exception cref="ArgumentNullException"></exception>
private void CreateDir(SftpClient sftp, string dir)
{
ArgumentNullException.ThrowIfNull(dir);
if (sftp.Exists(dir)) return;
var index = dir.LastIndexOfAny(['/', '\\']);
if (index > 0)
{
if (!_sftp.IsConnected)
_sftp.Connect();
}
/// <summary>
/// 是否存在同名文件
/// </summary>
/// <param name="ftpFileName"></param>
/// <returns></returns>
public bool Exists(string ftpFileName)
{
Connect();
return _sftp.Exists(ftpFileName);
}
/// <summary>
/// 删除文件
/// </summary>
/// <param name="ftpFileName"></param>
public void DeleteFile(string ftpFileName)
{
Connect();
_sftp.DeleteFile(ftpFileName);
}
/// <summary>
/// 下载到指定目录
/// </summary>
/// <param name="ftpFileName"></param>
/// <param name="localFileName"></param>
public void DownloadFile(string ftpFileName, string localFileName)
{
Connect();
using Stream fileStream = File.OpenWrite(localFileName);
_sftp.DownloadFile(ftpFileName, fileStream);
}
/// <summary>
/// 读取字节
/// </summary>
/// <param name="ftpFileName"></param>
/// <returns></returns>
public byte[] ReadAllBytes(string ftpFileName)
{
Connect();
return _sftp.ReadAllBytes(ftpFileName);
}
/// <summary>
/// 读取流
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public Stream OpenRead(string path)
{
return _sftp.Open(path, FileMode.Open, FileAccess.Read);
}
/// <summary>
/// 继续下载
/// </summary>
/// <param name="ftpFileName"></param>
/// <param name="localFileName"></param>
public void DownloadFileWithResume(string ftpFileName, string localFileName)
{
DownloadFile(ftpFileName, localFileName);
}
/// <summary>
/// 重命名
/// </summary>
/// <param name="oldPath"></param>
/// <param name="newPath"></param>
public void RenameFile(string oldPath, string newPath)
{
_sftp.RenameFile(oldPath, newPath);
}
/// <summary>
/// 指定目录下文件
/// </summary>
/// <param name="folder"></param>
/// <param name="filters"></param>
/// <returns></returns>
public List<string> GetFileList(string folder, IEnumerable<string> filters)
{
Connect();
var files = new List<string>();
var sftpFiles = _sftp.ListDirectory(folder);
foreach (var file in sftpFiles)
{
if (file.IsRegularFile && filters.Any(f => file.Name.EndsWith(f)))
files.Add(file.Name);
}
return files;
}
/// <summary>
/// 上传指定目录文件
/// </summary>
/// <param name="localFileName"></param>
/// <param name="ftpFileName"></param>
public void UploadFile(string localFileName, string ftpFileName)
{
Connect();
var dir = Path.GetDirectoryName(ftpFileName);
CreateDir(_sftp, dir);
using var fileStream = new FileStream(localFileName, FileMode.Open);
_sftp.UploadFile(fileStream, ftpFileName);
}
/// <summary>
/// 上传字节
/// </summary>
/// <param name="bs"></param>
/// <param name="ftpFileName"></param>
public void UploadFile(byte[] bs, string ftpFileName)
{
Connect();
var dir = Path.GetDirectoryName(ftpFileName);
CreateDir(_sftp, dir);
_sftp.WriteAllBytes(ftpFileName, bs);
}
/// <summary>
/// 上传流
/// </summary>
/// <param name="fileStream"></param>
/// <param name="ftpFileName"></param>
public void UploadFile(Stream fileStream, string ftpFileName)
{
Connect();
var dir = Path.GetDirectoryName(ftpFileName);
CreateDir(_sftp, dir);
_sftp.UploadFile(fileStream, ftpFileName);
fileStream.Dispose();
}
/// <summary>
/// 创建目录
/// </summary>
/// <param name="sftp"></param>
/// <param name="dir"></param>
/// <exception cref="ArgumentNullException"></exception>
private void CreateDir(SftpClient sftp, string dir)
{
ArgumentNullException.ThrowIfNull(dir);
if (sftp.Exists(dir)) return;
var index = dir.LastIndexOfAny(['/', '\\']);
if (index > 0)
{
var p = dir[..index];
if (!sftp.Exists(p))
CreateDir(sftp, p);
sftp.CreateDirectory(dir);
}
}
/// <summary>
/// 释放对象
/// </summary>
public void Dispose()
{
if (_sftp == null) return;
if (_sftp.IsConnected)
_sftp.Disconnect();
_sftp.Dispose();
var p = dir[..index];
if (!sftp.Exists(p))
CreateDir(sftp, p);
sftp.CreateDirectory(dir);
}
}
/// <summary>
/// 释放对象
/// </summary>
public void Dispose()
{
if (_sftp == null) return;
if (_sftp.IsConnected)
_sftp.Disconnect();
_sftp.Dispose();
}
}

View File

@ -61,7 +61,7 @@ public class SuperApiAop : DefaultSuperApiAop
var paths = api?.Url?.Split('/');
var actionName = paths?[^1];
var userManager = LazyHelper.GetService<UserManager>();
var userManager = App.GetService<UserManager>();
var apiInfo = new
{
requestUrl = api?.Url,
@ -79,13 +79,13 @@ public class SuperApiAop : DefaultSuperApiAop
{
new
{
type = userManager?.Value.Account,
value = userManager?.Value.RealName
type = userManager?.Account,
value = userManager?.RealName
},
new
{
type = userManager?.Value.RealName,
value = userManager?.Value.RealName
type = userManager?.RealName,
value = userManager?.RealName
},
},
exception = aopContext.Exception == null ? null : JSON.Serialize(aopContext.Exception)