Merge pull request 'main-d' (#90) from x4689221/Admin.NET.Pro:main-d into main

Reviewed-on: http://101.43.53.74:3000/Admin.NET/Admin.NET.Pro/pulls/90
This commit is contained in:
zuohuaijun 2024-08-12 02:36:56 +08:00
commit eb249a2ed1
5 changed files with 161 additions and 126 deletions

View File

@ -4,6 +4,8 @@
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Org.BouncyCastle.Crypto;
namespace Admin.NET.Core;
/// <summary>
@ -69,6 +71,11 @@ public partial class SysOnlineUser : EntityTenantId
/// <summary>
/// 登录模式
/// </summary>
[SugarColumn(ColumnDescription = "登录模式")]
public LoginModeEnum LoginMode { get; set; }
[SugarColumn(ColumnDescription = "登陆模式")]
public LoginModeEnum? LoginMode { get; set; }
[SugarColumn(ColumnDescription = "设备")]
[MaxLength(256)]
public string? Device { get; set; }
}

View File

@ -48,7 +48,7 @@ public class OnlineUserHub : Hub<IOnlineUserHub>
var realName = httpContext.User.FindFirst(ClaimConst.RealName)?.Value;
var tenantId = (httpContext.User.FindFirst(ClaimConst.TenantId)?.Value).ToLong();
var loginMode = (LoginModeEnum)(httpContext.User.FindFirst(ClaimConst.LoginMode)?.Value).ToInt();
var device = httpContext.GetClientDeviceInfo().Trim();
var user = new SysOnlineUser
{
ConnectionId = Context.ConnectionId,
@ -61,19 +61,22 @@ public class OnlineUserHub : Hub<IOnlineUserHub>
Os = httpContext.GetClientOs(),
TenantId = tenantId,
LoginMode = loginMode,
Device = device
};
await _sysOnlineUerRep.InsertAsync(user);
// _sysCacheService.HashAdd(CacheConst.KeyUserOnline, user.UserId.ToString(), user);
// 是否开启单用户登录
if (await _sysConfigService.GetConfigValue<bool>(ConfigConst.SysSingleLogin))
{
_sysCacheService.Set(CacheConst.KeyUserOnline + user.UserId + loginMode, user);
_sysCacheService.HashAdd(CacheConst.KeyUserOnline,""+user.UserId + loginMode, user);
}
else
else //非单用户登录则绑定用户设备信息
{
var device = httpContext.GetClientDeviceInfo().Trim();
_sysCacheService.Set(CacheConst.KeyUserOnline + user.UserId + device, user);
_sysCacheService.HashAdd(CacheConst.KeyUserOnline, user.UserId + device, user);
}
// 以租户Id进行分组
var groupName = $"{GROUP_ONLINE}{user.TenantId}";
@ -108,12 +111,14 @@ public class OnlineUserHub : Hub<IOnlineUserHub>
// 是否开启单用户登录
if (await _sysConfigService.GetConfigValue<bool>(ConfigConst.SysSingleLogin))
{
_sysCacheService.Remove(CacheConst.KeyUserOnline + user.UserId);
_sysCacheService.HashDel<SysOnlineUser>(CacheConst.KeyUserOnline, "" + user.UserId + user.LoginMode);
// _sysCacheService.Remove(CacheConst.KeyUserOnline + user.UserId);
}
else
{
var device = httpContext.GetClientDeviceInfo().Trim();
_sysCacheService.Remove(CacheConst.KeyUserOnline + user.UserId + device);
_sysCacheService.HashDel<SysOnlineUser>(CacheConst.KeyUserOnline, user.UserId + device);
// _sysCacheService.Remove(CacheConst.KeyUserOnline + user.UserId + device);
}
// 通知当前组用户变动

View File

@ -5,6 +5,8 @@
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using NewLife.Caching.Models;
using NewLife.Reflection;
using Newtonsoft.Json;
namespace Admin.NET.Core.Service;
@ -62,6 +64,86 @@ public class SysCacheService : IDynamicApiController, ISingleton
return _cacheProvider.Cache.Set($"{_cacheOptions.Prefix}{key}", value, expire);
}
public async Task<TR> AdGetAsync<TR>(String cacheName, Func<Task<TR>> del, TimeSpan? expiry = default(TimeSpan?)) where TR : class
{
return await AdGetAsync<TR>(cacheName, del, new object[] { }, expiry);
}
public async Task<TR> AdGetAsync<TR, T1>(String cacheName, Func<T1, Task<TR>> del, T1 t1, TimeSpan? expiry = default(TimeSpan?)) where TR : class
{
return await AdGetAsync<TR>(cacheName, del, new object[] { t1 }, expiry);
}
public async Task<TR> AdGetAsync<TR, T1, T2>(String cacheName, Func<T1, T2, Task<TR>> del, T1 t1, T2 t2, TimeSpan? expiry = default(TimeSpan?)) where TR : class
{
return await AdGetAsync<TR>(cacheName, del, new object[] { t1, t2 }, expiry);
}
public async Task<TR> AdGetAsync<TR, T1, T2, T3>(String cacheName, Func<T1, T2, T3, Task<TR>> del, T1 t1, T2 t2, T3 t3, TimeSpan? expiry = default(TimeSpan?)) where TR : class
{
return await AdGetAsync<TR>(cacheName, del, new object[] { t1, t2, t3 }, expiry);
}
private async Task<T> AdGetAsync<T>(string cacheName, Delegate del, Object[] obs, TimeSpan? expiry) where T : class
{
var key = Key(cacheName, obs);
// 使用分布式锁
using (_cacheProvider.Cache.AcquireLock($@"lock:AdGetAsync:{cacheName}", 1000))
{
var value = Get<T>(key);
value ??= await ((dynamic)del).DynamicInvokeAsync(obs);
Set(key, value);
return value;
}
}
public T Get<T>(String cacheName, object t1)
{
return Get<T>(cacheName, new object[] { t1 });
}
public T Get<T>(String cacheName, object t1, object t2)
{
return Get<T>(cacheName, new object[] { t1, t2 });
}
public T Get<T>(String cacheName, object t1, object t2, object t3)
{
return Get<T>(cacheName, new object[] { t1, t2, t3 });
}
private T Get<T>(String cacheName, Object[] obs)
{
var key = cacheName + ":" + obs.Aggregate(string.Empty, (current, o) => current + $"<{o}>");
return Get<T>(key);
}
private static string Key(string cacheName, object[] obs)
{
foreach (var obj in obs)
{
if (obj is TimeSpan)
{
throw new Exception("缓存参数类型不能能是:TimeSpan类型");
}
}
StringBuilder sb = new StringBuilder(cacheName + ":");
foreach (var a in obs)
{
sb.Append($@"<{KeySingle(a)}>");
}
return sb.ToString();
}
public static string KeySingle(object t)
{
if (t.GetType().IsClass && !t.GetType().IsPrimitive)
{
return JsonConvert.SerializeObject(t);
}
return t?.ToString();
}
/// <summary>
/// 获取缓存的剩余生存时间
/// </summary>
@ -175,9 +257,9 @@ public class SysCacheService : IDynamicApiController, ISingleton
/// <param name="key"></param>
/// <returns></returns>
[NonAction]
public RedisHash<string, T> GetHashMap<T>(string key)
public IDictionary<String, T> GetHashMap<T>(string key)
{
return _cacheProvider.Cache.GetDictionary<T>(key) as RedisHash<string, T>;
return _cacheProvider.Cache.GetDictionary<T>(key);
}
/// <summary>
@ -191,7 +273,12 @@ public class SysCacheService : IDynamicApiController, ISingleton
public bool HashSet<T>(string key, Dictionary<string, T> dic)
{
var hash = GetHashMap<T>(key);
return hash.HMSet(dic);
foreach (var v in dic)
{
hash.Add(v);
}
return true;
}
/// <summary>
@ -219,8 +306,7 @@ public class SysCacheService : IDynamicApiController, ISingleton
public List<T> HashGet<T>(string key, params string[] fields)
{
var hash = GetHashMap<T>(key);
var result = hash.HMGet(fields);
return result.ToList();
return hash.Where(t => fields.Any(c => t.Key == c)).Select(t => t.Value).ToList();
}
/// <summary>
@ -234,8 +320,12 @@ public class SysCacheService : IDynamicApiController, ISingleton
public T HashGetOne<T>(string key, string field)
{
var hash = GetHashMap<T>(key);
var result = hash.HMGet(new string[] { field });
return result[0];
var value = hash.GetValue(field);
if (value == null)
{
return default(T);
}
return (T)hash.GetValue(field);
}
/// <summary>
@ -248,7 +338,7 @@ public class SysCacheService : IDynamicApiController, ISingleton
public IDictionary<string, T> HashGetAll<T>(string key)
{
var hash = GetHashMap<T>(key);
return hash.GetAll();
return hash;
}
/// <summary>
@ -262,35 +352,36 @@ public class SysCacheService : IDynamicApiController, ISingleton
public int HashDel<T>(string key, params string[] fields)
{
var hash = GetHashMap<T>(key);
return hash.HDel(fields);
fields.ToList().ForEach(t => hash.Remove(t));
return fields.Length;
}
/// <summary>
/// 搜索HASH
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="searchModel"></param>
/// <returns></returns>
[NonAction]
public List<KeyValuePair<string, T>> HashSearch<T>(string key, SearchModel searchModel)
{
var hash = GetHashMap<T>(key);
return hash.Search(searchModel).ToList();
}
///// <summary>
///// 搜索HASH
///// </summary>
///// <typeparam name="T"></typeparam>
///// <param name="key"></param>
///// <param name="searchModel"></param>
///// <returns></returns>
//[NonAction]
//public List<KeyValuePair<string, T>> HashSearch<T>(string key, SearchModel searchModel)
//{
// var hash = GetHashMap<T>(key);
// return hash.Search(searchModel).ToList();
//}
/// <summary>
/// 搜索HASH
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="pattern"></param>
/// <param name="count"></param>
/// <returns></returns>
[NonAction]
public List<KeyValuePair<string, T>> HashSearch<T>(string key, string pattern, int count)
{
var hash = GetHashMap<T>(key);
return hash.Search(pattern, count).ToList();
}
///// <summary>
///// 搜索HASH
///// </summary>
///// <typeparam name="T"></typeparam>
///// <param name="key"></param>
///// <param name="pattern"></param>
///// <param name="count"></param>
///// <returns></returns>
//[NonAction]
//public List<KeyValuePair<string, T>> HashSearch<T>(string key, string pattern, int count)
//{
// var hash = GetHashMap<T>(key);
// return hash.Search(pattern, count).ToList();
//}
}

View File

@ -5,6 +5,7 @@
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Microsoft.AspNetCore.SignalR;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
namespace Admin.NET.Core.Service;
@ -46,29 +47,9 @@ public class SysMessageService : IDynamicApiController, ITransient
[DisplayName("发送消息给除了发送人的其他人")]
public async Task SendOtherUser(MessageInput input)
{
var cacheKey = CacheConst.KeyUserOnline + input.ReceiveUserId;
// 是否开启单用户登录
if (await _sysConfigService.GetConfigValue<bool>(ConfigConst.SysSingleLogin))
{
var values = Enum.GetValues(typeof(LoginModeEnum)).Cast<LoginModeEnum>().ToList();
foreach (var value in values)
{
var user = _sysCacheService.Get<SysOnlineUser>(cacheKey + value);
if (user == null) continue;
await _chatHubContext.Clients.AllExcept(user.ConnectionId).ReceiveMessage(input);
}
}
else
{
var _cacheKeys = _sysCacheService.GetKeyList().Where(u => u.StartsWith(cacheKey)).ToArray();
foreach (var _cacheKey in _cacheKeys)
{
var user = _sysCacheService.Get<SysOnlineUser>(_cacheKey);
if (user == null) return;
await _chatHubContext.Clients.AllExcept(user.ConnectionId).ReceiveMessage(input);
}
}
var hashKey = _sysCacheService.HashGetAll<SysOnlineUser>(CacheConst.KeyUserOnline);
var exceptRecevieUsers = hashKey.Where(t => t.Value.UserId == input.ReceiveUserId).Select(t => t.Value).ToList();
await _chatHubContext.Clients.AllExcept(exceptRecevieUsers.Select(t=>t.ConnectionId)).ReceiveMessage(input);
}
/// <summary>
@ -79,29 +60,9 @@ public class SysMessageService : IDynamicApiController, ITransient
[DisplayName("发送消息给某个人")]
public async Task SendUser(MessageInput input)
{
var cacheKey = CacheConst.KeyUserOnline + input.ReceiveUserId;
// 是否开启单用户登录
if (await _sysConfigService.GetConfigValue<bool>(ConfigConst.SysSingleLogin))
{
var values = Enum.GetValues(typeof(LoginModeEnum)).Cast<LoginModeEnum>().ToList();
foreach (var value in values)
{
var user = _sysCacheService.Get<SysOnlineUser>(cacheKey + value);
if (user == null) continue;
await _chatHubContext.Clients.Client(user.ConnectionId).ReceiveMessage(input);
}
}
else
{
var _cacheKeys = _sysCacheService.GetKeyList().Where(u => u.StartsWith(cacheKey)).ToArray();
foreach (var _cacheKey in _cacheKeys)
{
var user = _sysCacheService.Get<SysOnlineUser>(_cacheKey);
if (user == null) return;
await _chatHubContext.Clients.Client(user.ConnectionId).ReceiveMessage(input);
}
}
var hashKey = _sysCacheService.HashGetAll<SysOnlineUser>(CacheConst.KeyUserOnline);
var recevieUsers = hashKey.Where(t => t.Value.UserId == input.ReceiveUserId).Select(t => t.Value).ToList();
await recevieUsers.ForEachAsync(t => _chatHubContext.Clients.Client(t.ConnectionId).ReceiveMessage(input));
}
/// <summary>
@ -112,31 +73,8 @@ public class SysMessageService : IDynamicApiController, ITransient
[DisplayName("发送消息给某些人")]
public async Task SendUsers(MessageInput input)
{
var userList = new List<string>();
foreach (var userId in input.UserIds)
{
var cacheKey = CacheConst.KeyUserOnline + userId;
// 是否开启单用户登录
if (await _sysConfigService.GetConfigValue<bool>(ConfigConst.SysSingleLogin))
{
var values = Enum.GetValues(typeof(LoginModeEnum)).Cast<LoginModeEnum>().ToList();
foreach (var value in values)
{
var user = _sysCacheService.Get<SysOnlineUser>(cacheKey + value);
if (user != null) userList.Add(user.ConnectionId);
}
}
else
{
var _cacheKeys = _sysCacheService.GetKeyList().Where(u => u.StartsWith(cacheKey)).ToArray();
foreach (var _cacheKey in _cacheKeys)
{
var user = _sysCacheService.Get<SysOnlineUser>(_cacheKey);
if (user != null) userList.Add(user.ConnectionId);
}
}
}
await _chatHubContext.Clients.Clients(userList).ReceiveMessage(input);
var hashKey = _sysCacheService.HashGetAll<SysOnlineUser>(CacheConst.KeyUserOnline);
var recevieUsers = hashKey.Where(t => input.UserIds.Any(c => c == t.Value.UserId)).Select(t => t.Value).ToList();
await recevieUsers.ForEachAsync(t => _chatHubContext.Clients.Client(t.ConnectionId).ReceiveMessage(input));
}
}

View File

@ -302,8 +302,7 @@ public class SysOrgService : IDynamicApiController, ITransient
[NonAction]
public async Task<List<long>> GetUserOrgIdList(long userId, long userOrgId)
{
var orgIdList = _sysCacheService.Get<List<long>>($"{CacheConst.KeyUserOrg}{userId}"); // 取缓存
if (orgIdList == null || orgIdList.Count < 1)
return await _sysCacheService.AdGetAsync(CacheConst.KeyUserOrg, async (i1, i2) =>
{
// 本人创建机构集合
var orgList0 = await _sysOrgRep.AsQueryable().Where(u => u.CreateUserId == userId).Select(u => u.Id).ToListAsync();
@ -312,13 +311,8 @@ public class SysOrgService : IDynamicApiController, ITransient
// 角色机构集合
var orgList2 = await GetUserRoleOrgIdList(userId, userOrgId);
// 机构并集
orgIdList = orgList1.Select(u => u.OrgId).Union(orgList2).Union(orgList0).ToList();
// 当前所属机构
if (!orgIdList.Contains(userOrgId))
orgIdList.Add(userOrgId);
_sysCacheService.Set($"{CacheConst.KeyUserOrg}{userId}", orgIdList, TimeSpan.FromDays(7)); // 存缓存
}
return orgIdList;
return orgList1.Select(u => u.OrgId).Union(orgList2).Union(orgList0).ToList();
}, userId, userOrgId);
}
/// <summary>