feat: 移除RedLocker,更改为自实现 (#169)

用户表增加最后登录时间字段
列表查询多字段模糊查询改为单字段精确查询
WebSocket版本更新检查
前端自定义字段筛选
暗黑模式样式调整
[skip ci]

Co-authored-by: tk <fiyne1a@dingtalk.com>
This commit is contained in:
2024-08-12 11:44:14 +08:00
committed by GitHub
parent 4733adede5
commit cd8ed674e0
58 changed files with 585 additions and 320 deletions

View File

@ -8,11 +8,10 @@ namespace NetAdmin.SysComponent.Application.Services.Sys;
/// <inheritdoc cref="IApiService" />
public sealed class ApiService(
BasicRepository<Sys_Api, string> rpo //
, XmlCommentReader xmlCommentReader //
, IActionDescriptorCollectionProvider actionDescriptorCollectionProvider
, RedLocker redLocker) //
: RedLockerService<Sys_Api, string, IApiService>(rpo, redLocker), IApiService
BasicRepository<Sys_Api, string> rpo //
, XmlCommentReader xmlCommentReader //
, IActionDescriptorCollectionProvider actionDescriptorCollectionProvider) //
: RedisService<Sys_Api, string, IApiService>(rpo), IApiService
{
/// <inheritdoc />
public Task<int> BulkDeleteAsync(BulkReq<DelReq> req)

View File

@ -18,19 +18,23 @@ public sealed class UserService(
, IEventPublisher eventPublisher) //
: RepositoryService<Sys_User, long, IUserService>(rpo), IUserService
{
private readonly Expression<Func<Sys_User, Sys_User>> _selectUserFields = a => new Sys_User {
Id = a.Id
, Avatar = a.Avatar
, Email = a.Email
, Mobile = a.Mobile
, Enabled = a.Enabled
, UserName = a.UserName
, Summary = a.Summary
, Version = a.Version
, CreatedTime = a.CreatedTime
, Dept = new Sys_Dept { Id = a.Dept.Id, Name = a.Dept.Name }
, Roles = a.Roles
};
private readonly Expression<Func<Sys_User, Sys_User>> _listUserExp = a => new Sys_User {
Id = a.Id
, Avatar = a.Avatar
, Email = a.Email
, Mobile = a.Mobile
, Enabled = a.Enabled
, UserName = a.UserName
, Summary = a.Summary
, Version = a.Version
, CreatedTime = a.CreatedTime
, LastLoginTime = a.LastLoginTime
, Dept = new Sys_Dept {
Id = a.Dept.Id
, Name = a.Dept.Name
}
, Roles = a.Roles
};
/// <inheritdoc />
public async Task<int> BulkDeleteAsync(BulkReq<DelReq> req)
@ -232,14 +236,15 @@ public sealed class UserService(
public async Task<PagedQueryRsp<QueryUserRsp>> PagedQueryAsync(PagedQueryReq<QueryUserReq> req)
{
req.ThrowIfInvalid();
var list = await (await QueryInternalAsync(req).ConfigureAwait(false)).Page(req.Page, req.PageSize)
#if DBTYPE_SQLSERVER
.WithLock(SqlServerLock.NoLock |
SqlServerLock.NoWait)
#endif
.Count(out var total)
.ToListAsync(_selectUserFields)
.ConfigureAwait(false);
var listUserExp = req.GetToListExp<Sys_User>() ?? _listUserExp;
var select = await QueryInternalAsync(req, listUserExp == _listUserExp).ConfigureAwait(false);
var list = await select.Page(req.Page, req.PageSize)
#if DBTYPE_SQLSERVER
.WithLock(SqlServerLock.NoLock | SqlServerLock.NoWait)
#endif
.Count(out var total)
.ToListAsync(listUserExp)
.ConfigureAwait(false);
return new PagedQueryRsp<QueryUserRsp>(req.Page, req.PageSize, total, list.Adapt<IEnumerable<QueryUserRsp>>());
}
@ -248,7 +253,7 @@ public sealed class UserService(
{
req.ThrowIfInvalid();
var list = await (await QueryInternalAsync(req).ConfigureAwait(false)).Take(req.Count)
.ToListAsync(_selectUserFields)
.ToListAsync(_listUserExp)
.ConfigureAwait(false);
return list.Adapt<IEnumerable<QueryUserRsp>>();
}
@ -437,22 +442,6 @@ public sealed class UserService(
return dbUser.Adapt<UserInfoRsp>();
}
private static LoginRsp LoginInternal(Sys_User dbUser)
{
if (!dbUser.Enabled) {
throw new NetAdminInvalidOperationException(Ln.);
}
var tokenPayload
= new Dictionary<string, object> { { nameof(ContextUserToken), dbUser.Adapt<ContextUserToken>() } };
var accessToken = JWTEncryption.Encrypt(tokenPayload);
return new LoginRsp {
AccessToken = accessToken
, RefreshToken = JWTEncryption.GenerateRefreshToken(accessToken)
};
}
private async Task<Dictionary<long, string>> CreateEditCheckAsync(CreateEditUserReq req)
{
// 检查角色是否存在
@ -475,21 +464,44 @@ public sealed class UserService(
return dept.Count != 1 ? throw new NetAdminInvalidOperationException(Ln.) : roles;
}
private ISelect<Sys_User> QueryInternal(QueryReq<QueryUserReq> req, IEnumerable<long> deptIds)
private LoginRsp LoginInternal(Sys_User dbUser)
{
var ret = Rpo.Select.Include(a => a.Dept)
.IncludeMany(a => a.Roles.Select(b => new Sys_Role { Id = b.Id, Name = b.Name }))
.WhereDynamicFilter(req.DynamicFilter)
.WhereIf(deptIds != null, a => deptIds.Contains(a.DeptId))
.WhereIf( //
req.Filter?.Id > 0, a => a.Id == req.Filter.Id)
.WhereIf( //
req.Filter?.RoleId > 0, a => a.Roles.Any(b => b.Id == req.Filter.RoleId))
.WhereIf( //
req.Keywords?.Length > 0
, a => a.Id == req.Keywords.Int64Try(0) || a.UserName == req.Keywords ||
a.Mobile == req.Keywords ||
a.Email == req.Keywords || a.Summary.Contains(req.Keywords));
if (!dbUser.Enabled) {
throw new NetAdminInvalidOperationException(Ln.);
}
_ = UpdateAsync(dbUser with { LastLoginTime = DateTime.Now }, [nameof(Sys_User.LastLoginTime)]
, ignoreVersion: true);
var tokenPayload
= new Dictionary<string, object> { { nameof(ContextUserToken), dbUser.Adapt<ContextUserToken>() } };
var accessToken = JWTEncryption.Encrypt(tokenPayload);
return new LoginRsp {
AccessToken = accessToken
, RefreshToken = JWTEncryption.GenerateRefreshToken(accessToken)
};
}
private ISelect<Sys_User> QueryInternal(QueryReq<QueryUserReq> req, IEnumerable<long> deptIds
, bool includeRoles = true)
{
var ret = Rpo.Select.Include(a => a.Dept);
if (includeRoles) {
ret = ret.IncludeMany(a => a.Roles.Select(b => new Sys_Role { Id = b.Id, Name = b.Name }));
}
ret = ret.WhereDynamicFilter(req.DynamicFilter)
.WhereIf(deptIds != null, a => deptIds.Contains(a.DeptId))
.WhereIf( //
req.Filter?.Id > 0, a => a.Id == req.Filter.Id)
.WhereIf( //
req.Filter?.RoleId > 0, a => a.Roles.Any(b => b.Id == req.Filter.RoleId))
.WhereIf( //
req.Keywords?.Length > 0
, a => a.Id == req.Keywords.Int64Try(0) || a.UserName == req.Keywords ||
a.Mobile == req.Keywords ||
a.Email == req.Keywords || a.Summary.Contains(req.Keywords));
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (req.Order) {
@ -518,7 +530,7 @@ public sealed class UserService(
return QueryInternal(req, deptIds);
}
private async Task<ISelect<Sys_User>> QueryInternalAsync(QueryReq<QueryUserReq> req)
private async Task<ISelect<Sys_User>> QueryInternalAsync(QueryReq<QueryUserReq> req, bool includeRoles = true)
{
IEnumerable<long> deptIds = null;
if (req.Filter?.DeptId > 0) {
@ -529,6 +541,6 @@ public sealed class UserService(
.ConfigureAwait(false);
}
return QueryInternal(req, deptIds);
return QueryInternal(req, deptIds, includeRoles);
}
}