Files
WeiBingJuInterface/SimpleAdmin.System/Services/Organization/User/SysUserService.cs
T
2025-09-29 13:48:36 +08:00

1166 lines
50 KiB
C#

// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
using SimpleAdmin.Core.Extension;
namespace SimpleAdmin.System;
/// <summary>
/// <inheritdoc cref="ISysUserService"/>
/// </summary>
public class SysUserService : DbRepository<SysUser>, ISysUserService
{
private readonly ILogger<ILogger> _logger;
private readonly ISimpleCacheService _simpleCacheService;
private readonly IRelationService _relationService;
private readonly IResourceService _resourceService;
private readonly ISysOrgService _sysOrgService;
private readonly ISysRoleService _sysRoleService;
private readonly IImportExportService _importExportService;
private readonly ISysPositionService _sysPositionService;
private readonly IDictService _dictService;
private readonly IConfigService _configService;
private readonly IBatchEditService _batchEditService;
public SysUserService(ILogger<ILogger> logger, ISimpleCacheService simpleCacheService, IRelationService relationService,
IResourceService resourceService, ISysOrgService orgService, ISysRoleService sysRoleService,
IImportExportService importExportService, ISysPositionService sysPositionService, IDictService dictService,
IConfigService configService, IBatchEditService updateBatchService)
{
_logger = logger;
_simpleCacheService = simpleCacheService;
_relationService = relationService;
_resourceService = resourceService;
_sysOrgService = orgService;
_sysRoleService = sysRoleService;
_importExportService = importExportService;
_sysPositionService = sysPositionService;
_dictService = dictService;
_configService = configService;
_batchEditService = updateBatchService;
}
#region 查询
/// <inheritdoc/>
public async Task<string> GetUserAvatar(long userId)
{
//先从缓存拿
var avatar = _simpleCacheService.HashGetOne<string>(SystemConst.CACHE_SYS_USER_AVATAR, userId.ToString());
if (string.IsNullOrEmpty(avatar))
{
//单查获取用户头像
avatar = await GetFirstAsync(it => it.Id == userId, it => it.Avatar);
if (!string.IsNullOrEmpty(avatar))
{
//插入缓存
_simpleCacheService.HashAdd(SystemConst.CACHE_SYS_USER_AVATAR, userId.ToString(), avatar);
}
}
return avatar;
}
/// <inheritdoc/>
public async Task<SysUser> GetUserByAccount(string account, long? tenantId = null)
{
var userId = await GetIdByAccount(account, tenantId);//获取用户ID
if (userId != SimpleAdminConst.ZERO)
{
var sysUser = await GetUserById(userId);//获取用户信息
if (sysUser.Account == account)//这里做了比较用来限制大小写
return sysUser;
return null;
}
return null;
}
/// <inheritdoc/>
public async Task<SysUser> GetUserByPhone(string phone, long? tenantId = null)
{
var userId = await GetIdByPhone(phone, tenantId);//获取用户ID
if (userId > 0)
{
return await GetUserById(userId);//获取用户信息
}
return null;
}
/// <inheritdoc/>
public async Task<long> GetIdByPhone(string phone, long? tenantId = null)
{
var orgIds = new List<long>();
var key = SystemConst.CACHE_SYS_USER_PHONE;
if (tenantId != null)
{
key += $":{tenantId}";
orgIds = await _sysOrgService.GetOrgChildIds(tenantId.Value);//获取下级机构
}
//先从缓存拿
var userId = _simpleCacheService.HashGetOne<long>(key, phone);
if (userId == 0)
{
var sm4Phone = CryptogramUtil.Sm4Encrypt(phone);//SM4加密一下
//单查获取用户手机号对应的账号
userId = await Context.Queryable<SysUser>()
.Where(it => it.Phone == sm4Phone)
.WhereIF(orgIds.Count > 0, it => orgIds.Contains(it.OrgId))
.Select(it => it.Id)
.FirstAsync();
if (userId > 0)
{
//插入缓存
_simpleCacheService.HashAdd(key, phone, userId);
}
}
return userId;
}
/// <inheritdoc/>
public async Task<SysUser> GetUserById(long userId)
{
//先从缓存拿
//var sysUser = _simpleCacheService.HashGetOne<SysUser>(SystemConst.CACHE_SYS_USER, userId.ToString());
//if (sysUser == null)
//{
// sysUser = await GetUserFromDb(userId);//从数据库拿用户信息
//}
var sysUser = await GetUserFromDb(userId);//从数据库拿用户信息
return sysUser;
}
/// <inheritdoc/>
public async Task<T> GetUserById<T>(long userId)
{
var user = await GetUserById(userId);
return user.Adapt<T>();
}
/// <inheritdoc/>
public async Task<long> GetIdByAccount(string account, long? tenantId = null)
{
var orgIds = new List<long>();
var key = SystemConst.CACHE_SYS_USER_ACCOUNT;
if (tenantId != null)
{
key += $":{tenantId}";
orgIds = await _sysOrgService.GetOrgChildIds(tenantId.Value);//获取下级机构
}
//先从缓存拿
var userId = _simpleCacheService.HashGetOne<long>(key, account);
if (userId == 0)
{
//单查获取用户账号对应ID
userId = await Context.Queryable<SysUser>()
.Where(it => it.Account == account)
.WhereIF(orgIds.Count > 0, it => orgIds.Contains(it.OrgId))
.Select(it => it.Id)
.FirstAsync();
if (userId != 0)
{
//插入缓存
_simpleCacheService.HashAdd(key, account, userId);
}
}
return userId;
}
/// <inheritdoc/>
public async Task<List<string>> GetButtonCodeList(long userId)
{
var buttonCodeList = new List<string>();//按钮ID集合
//获取用户资源集合
var resourceList = await _relationService.GetRelationListByObjectIdAndCategory(userId, CateGoryConst.RELATION_SYS_USER_HAS_RESOURCE);
var buttonIdList = new List<long>();//按钮ID集合
if (resourceList.Count == 0)//如果有表示用户单独授权了不走用户角色
{
//获取用户角色关系集合
var roleList = await _relationService.GetRelationListByObjectIdAndCategory(userId, CateGoryConst.RELATION_SYS_USER_HAS_ROLE);
var roleIdList = roleList.Select(x => x.TargetId.ToLong()).ToList();//角色ID列表
if (roleIdList.Count > 0)//如果该用户有角色
{
resourceList = await _relationService.GetRelationListByObjectIdListAndCategory(roleIdList,
CateGoryConst.RELATION_SYS_ROLE_HAS_RESOURCE);//获取资源集合
}
}
resourceList.ForEach(it =>
{
if (!string.IsNullOrEmpty(it.ExtJson))
buttonIdList.AddRange(it.ExtJson.ToJsonEntity<RelationRoleResource>().ButtonInfo);//如果有按钮权限,将按钮ID放到buttonIdList
});
if (buttonIdList.Count > 0)
{
buttonCodeList = await _resourceService.GetCodeByIds(buttonIdList, CateGoryConst.RESOURCE_BUTTON);
}
return buttonCodeList;
}
/// <inheritdoc/>
public async Task<List<DataScope>> GetPermissionListByUserId(long userId, long orgId)
{
var permissions = new List<DataScope>();//权限集合
var sysRelations =
await _relationService.GetRelationListByObjectIdAndCategory(userId, CateGoryConst.RELATION_SYS_USER_HAS_PERMISSION);//根据用户ID获取用户权限
if (sysRelations.Count == 0)//如果有表示用户单独授权了不走用户角色
{
var roleIdList =
await _relationService.GetRelationListByObjectIdAndCategory(userId, CateGoryConst.RELATION_SYS_USER_HAS_ROLE);//根据用户ID获取角色ID
if (roleIdList.Count > 0)//如果角色ID不为空
{
//获取角色权限信息
sysRelations = await _relationService.GetRelationListByObjectIdListAndCategory(roleIdList.Select(it => it.TargetId.ToLong()).ToList(),
CateGoryConst.RELATION_SYS_ROLE_HAS_PERMISSION);
}
}
var relationGroup = sysRelations.GroupBy(it => it.TargetId).ToList();//根据目标ID,也就是接口名分组,因为存在一个用户多个角色
//遍历分组
foreach (var it in relationGroup)
{
var scopeSet = new HashSet<long>();//定义不可重复列表
var relationList = it.ToList();//关系列表
var scopeCategory = CateGoryConst.SCOPE_SELF;//数据权限分类,默认为仅自己
//获取角色权限信息列表
var rolePermissions = relationList.Select(it => it.ExtJson.ToJsonEntity<RelationRolePermission>()).ToList();
if (rolePermissions.Any(role => role.ScopeCategory == CateGoryConst.SCOPE_ALL))//如果有全部
scopeCategory = CateGoryConst.SCOPE_ALL;//标记为全部
else if (rolePermissions.Any(role => role.ScopeCategory == CateGoryConst.SCOPE_ORG_CHILD))//如果有机构及以下机构
scopeCategory = CateGoryConst.SCOPE_ORG_CHILD;//标记为机构及以下机构
else if (rolePermissions.Any(role => role.ScopeCategory == CateGoryConst.SCOPE_ORG))//如果有仅自己机构
scopeCategory = CateGoryConst.SCOPE_ORG;//标记为仅自己机构
else if (rolePermissions.Any(role => role.ScopeCategory == CateGoryConst.SCOPE_ORG_DEFINE))//如果有自定义机构
{
scopeCategory = CateGoryConst.SCOPE_ORG_DEFINE;//标记为仅自己
rolePermissions.ForEach(s =>
{
scopeSet.AddRange(s.ScopeDefineOrgIdList);//添加自定义范围的机构ID
});
}
var dataScopes = scopeSet.ToList();//获取范围列表转列表
permissions.Add(new DataScope
{
ApiUrl = it.Key,
ScopeCategory = scopeCategory,
DataScopes = dataScopes
});//将改URL的权限集合加入权限集合列表
}
return permissions;
}
/// <inheritdoc/>
public async Task<SqlSugarPagedList<UserSelectorOutPut>> Selector(UserSelectorInput input)
{
var orgIds = await _sysOrgService.GetOrgChildIds(input.OrgId);//获取下级机构
var result = await Context.Queryable<SysUser>()
.WhereIF(input.OrgId > 0, u => orgIds.Contains(u.OrgId))//指定机构
.WhereIF(input.OrgIds != null, u => input.OrgIds.Contains(u.OrgId))//在指定机构列表查询
.WhereIF(input.PositionId > 0, u => u.PositionId == input.PositionId)//指定职位
.WhereIF(input.RoleId > 0,
u => SqlFunc.Subqueryable<SysRelation>()
.Where(r => r.TargetId == input.RoleId.ToString() && r.ObjectId == u.Id && r.Category == CateGoryConst.RELATION_SYS_USER_HAS_ROLE)
.Any())//指定角色
.WhereIF(!string.IsNullOrEmpty(input.Account), u => u.Account.Contains(input.Account))//根据关键字查询
.Select<UserSelectorOutPut>().ToPagedListAsync(input.PageNum, input.PageSize);
return result;
}
/// <inheritdoc/>
public async Task<SqlSugarPagedList<SysUser>> Page(UserPageInput input)
{
var query = await GetQuery(input);//获取查询条件
var pageInfo = await query.ToPagedListAsync(input.PageNum, input.PageSize);//分页
return pageInfo;
}
/// <inheritdoc/>
public async Task<List<SysUser>> List(UserPageInput input)
{
var query = await GetQuery(input);//获取查询条件
var list = await query.ToListAsync();
return list;
}
/// <inheritdoc/>
public async Task<List<RoleSelectorOutPut>> OwnRole(BaseIdInput input)
{
var relations = await _relationService.GetRelationListByObjectIdAndCategory(input.Id, CateGoryConst.RELATION_SYS_USER_HAS_ROLE);
var roleIds = relations.Select(it => it.TargetId.ToLong()).ToList();
var roleList = await Context.Queryable<SysRole>().Where(it => roleIds.Contains(it.Id)).Select<RoleSelectorOutPut>().ToListAsync();
return roleList;
}
/// <inheritdoc />
public async Task<RoleOwnResourceOutput> OwnResource(BaseIdInput input)
{
return await _sysRoleService.OwnResource(input, CateGoryConst.RELATION_SYS_USER_HAS_RESOURCE);
}
/// <inheritdoc />
public async Task<RoleOwnPermissionOutput> OwnPermission(BaseIdInput input)
{
var roleOwnPermission = new RoleOwnPermissionOutput
{
Id = input.Id
};//定义结果集
var grantInfoList = new List<RelationRolePermission>();//已授权信息集合
//获取关系列表
var relations = await _relationService.GetRelationListByObjectIdAndCategory(input.Id, CateGoryConst.RELATION_SYS_USER_HAS_PERMISSION);
//遍历关系表
relations.ForEach(it =>
{
//将扩展信息转为实体
var relationPermission = it.ExtJson.ToJsonEntity<RelationRolePermission>();
grantInfoList.Add(relationPermission);//添加到已授权信息
});
roleOwnPermission.GrantInfoList = grantInfoList;//赋值已授权信息
return roleOwnPermission;
}
/// <inheritdoc />
public async Task<List<string>> UserPermissionTreeSelector(BaseIdInput input)
{
var permissionTreeSelectors = new List<string>();//授权树结果集
//获取用户资源关系
var relationsRes = await _relationService.GetRelationByCategory(CateGoryConst.RELATION_SYS_USER_HAS_RESOURCE);
var menuIds = relationsRes.Where(it => it.ObjectId == input.Id).Select(it => it.TargetId.ToLong()).ToList();
if (menuIds.Any())
{
//获取菜单信息
var menus = await _resourceService.GetResourcesByIds(menuIds, CateGoryConst.RESOURCE_MENU);
//获取权限授权树
var permissions = _resourceService.PermissionTreeSelector(menus.Select(it => it.Path).ToList());
if (permissions.Count > 0)
{
permissionTreeSelectors = permissions.Select(it => it.PermissionName).ToList();//返回授权树权限名称列表
}
}
return permissionTreeSelectors;
}
/// <inheritdoc />
public async Task<List<UserSelectorOutPut>> GetUserListByIdList(IdListInput input)
{
var userList = await Context.Queryable<SysUser>().Where(it => input.IdList.Contains(it.Id)).Select<UserSelectorOutPut>().ToListAsync();
return userList;
}
/// <inheritdoc />
public async Task<SysUser> Detail(BaseIdInput input)
{
var user = await GetUserById(input.Id);
if (user != null)
{
user.Password = null;//清空密码
}
return user;
}
#endregion 查询
#region 数据范围相关
/// <inheritdoc/>
public async Task<List<long>?> GetLoginUserApiDataScope()
{
var userInfo = await GetUserById(UserManager.UserId);//获取用户信息
// 路由名称
var routeName = App.HttpContext.Request.Path.Value;
//获取当前url的数据范围
var dataScope = userInfo.DataScopeList.Where(it => it.ApiUrl == routeName).FirstOrDefault();
if (dataScope != null)
{
//根据数据范围分类获取数据范围
//null:代表拥有全部数据权限
//[xx,xx]:代表拥有部分机构的权限
//[]:代表仅自己权限
switch (dataScope.ScopeCategory)
{
case CateGoryConst.SCOPE_ALL:
return null;
case CateGoryConst.SCOPE_ORG_CHILD:
return userInfo.ScopeOrgChildList;
case CateGoryConst.SCOPE_ORG:
return new List<long> { userInfo.OrgId };
case CateGoryConst.SCOPE_ORG_DEFINE:
return dataScope.DataScopes;
case CateGoryConst.SCOPE_SELF:
return new List<long>();
}
}
return new List<long>();
}
/// <inheritdoc/>
public async Task<bool> CheckApiDataScope(long? orgId, long? createUerId, string errMsg = "")
{
var hasPermission = true;
//判断数据范围
var dataScope = await GetLoginUserApiDataScope();
if (dataScope is { Count: > 0 })//如果有机构
{
if (orgId == null || !dataScope.Contains(orgId.Value))//判断机构id是否在数据范围
hasPermission = false;
}
else if (dataScope is { Count: 0 })// 表示仅自己
{
if (createUerId != UserManager.UserId)
hasPermission = false;//机构的创建人不是自己则报错
}
//如果传了错误信息,直接抛出异常
if (!hasPermission && !string.IsNullOrEmpty(errMsg))
throw Oops.Bah(errMsg);
return hasPermission;
}
public async Task<bool> CheckApiDataScope(List<long> orgIds, List<long> createUerIds, string errMsg = "")
{
var hasPermission = true;
//判断数据范围
var dataScope = await GetLoginUserApiDataScope();
if (dataScope is { Count: > 0 })//如果有机构
{
if (orgIds == null || !dataScope.ContainsAll(orgIds))//判断机构id列表是否全在数据范围
hasPermission = false;
}
else if (dataScope is { Count: 0 })// 表示仅自己
{
if (createUerIds.Any(it => it != UserManager.UserId))//如果创建者id里有任何不是自己创建的机构
hasPermission = false;
}
//如果传了错误信息,直接抛出异常
if (!hasPermission && !string.IsNullOrEmpty(errMsg))
throw Oops.Bah(errMsg);
return hasPermission;
}
#endregion
#region 新增
/// <inheritdoc/>
public async Task Add(UserAddInput input)
{
await CheckInput(input);//检查参数
var sysUser = input.Adapt<SysUser>();//实体转换
//默认头像
sysUser.Avatar = AvatarUtil.GetNameImageBase64(sysUser.Name);
//获取默认密码
sysUser.Password = await GetDefaultPassWord(true);//设置密码
sysUser.Status = CommonStatusConst.ENABLE;//默认状态
await InsertAsync(sysUser);//添加数据
}
#endregion 新增
#region 编辑
/// <inheritdoc/>
public async Task Edit(UserEditInput input)
{
await CheckInput(input);//检查参数
var exist = await GetUserById(input.Id);//获取用户信息
if (exist != null)
{
var isSuperAdmin = exist.Account == SysRoleConst.SUPER_ADMIN;//判断是否有超管
if (isSuperAdmin && !UserManager.SuperAdmin)
throw Oops.Bah("不可修改系统内置超管用户账号");
var name = exist.Name;//姓名
var sysUser = input.Adapt<SysUser>();//实体转换
if (name != input.Name)
sysUser.Avatar = AvatarUtil.GetNameImageBase64(input.Name);//如果姓名改变了,重新生成头像
if (await Context.Updateable(sysUser).IgnoreColumns(it => new
{
//忽略更新字段
it.Password,
it.LastLoginAddress,
it.LastLoginDevice,
it.LastLoginIp,
it.LastLoginTime,
it.LatestLoginAddress,
it.LatestLoginDevice,
it.LatestLoginIp,
it.LatestLoginTime
}).IgnoreColumnsIF(name == input.Name, it => it.Avatar).ExecuteCommandAsync() > 0
)//修改数据
{
DeleteUserFromRedis(sysUser.Id);//删除用户缓存
//删除用户token缓存
_simpleCacheService.HashDel<List<TokenInfo>>(CacheConst.CACHE_USER_TOKEN, sysUser.Id.ToString());
}
}
}
/// <inheritdoc/>
public async Task Edits(BatchEditInput input)
{
//获取参数字典
var data = await _batchEditService.GetUpdateBatchConfigDict(input.Code, input.Columns);
if (data.Count > 0)
{
await Context.Updateable<SysUser>(data).Where(it => input.Ids.Contains(it.Id)).ExecuteCommandAsync();
}
}
/// <inheritdoc/>
public async Task DisableUser(BaseIdInput input)
{
var sysUser = await GetUserById(input.Id);//获取用户信息
if (sysUser != null)
{
var isSuperAdmin = sysUser.Account == SysRoleConst.SUPER_ADMIN;//判断是否有超管
if (isSuperAdmin)
throw Oops.Bah("不可禁用系统内置超管用户账号");
CheckSelf(input.Id, SystemConst.DISABLE);//判断是不是自己
//设置状态为禁用
if (await UpdateSetColumnsTrueAsync(it => new SysUser
{
Status = CommonStatusConst.DISABLED
}, it => it.Id == input.Id))
DeleteUserFromRedis(input.Id);//从缓存删除用户信息
}
}
/// <inheritdoc/>
public async Task EnableUser(BaseIdInput input)
{
CheckSelf(input.Id, SystemConst.ENABLE);//判断是不是自己
//设置状态为启用
if (await UpdateSetColumnsTrueAsync(it => new SysUser
{
Status = CommonStatusConst.ENABLE
}, it => it.Id == input.Id))
DeleteUserFromRedis(input.Id);//从缓存删除用户信息
}
/// <inheritdoc/>
public async Task ResetPassword(BaseIdInput input)
{
var password = await GetDefaultPassWord(true);//获取默认密码,这里不走Aop所以需要加密一下
//重置密码
if (await UpdateSetColumnsTrueAsync(it => new SysUser
{
Password = password
}, it => it.Id == input.Id))
DeleteUserFromRedis(input.Id);//从缓存删除用户信息
}
/// <inheritdoc />
public async Task GrantRole(UserGrantRoleInput input)
{
var sysUser = await GetUserById(input.Id);//获取用户信息
if (sysUser != null)
{
var isSuperAdmin = sysUser.Account == SysRoleConst.SUPER_ADMIN;//判断是否有超管
if (isSuperAdmin)
throw Oops.Bah("不能给超管分配角色");
CheckSelf(input.Id, SystemConst.GRANT_ROLE);//判断是不是自己
//给用户赋角色
await _relationService.SaveRelationBatch(CateGoryConst.RELATION_SYS_USER_HAS_ROLE, input.Id,
input.RoleIdList.Select(it => it.ToString()).ToList(), null, true);
DeleteUserFromRedis(input.Id);//从缓存删除用户信息
}
}
/// <inheritdoc />
public async Task GrantResource(UserGrantResourceInput input)
{
var menuIds = input.GrantInfoList.Select(it => it.MenuId).ToList();//菜单ID
var extJsons = input.GrantInfoList.Select(it => it.ToJson()).ToList();//拓展信息
var relationRoles = new List<SysRelation>();//要添加的用户资源和授权关系表
var sysUser = await GetUserById(input.Id);//获取用户
if (sysUser != null)
{
#region 用户资源处理
//遍历角色列表
for (var i = 0; i < menuIds.Count; i++)
{
//将用户资源添加到列表
relationRoles.Add(new SysRelation
{
ObjectId = sysUser.Id,
TargetId = menuIds[i].ToString(),
Category = CateGoryConst.RELATION_SYS_USER_HAS_RESOURCE,
ExtJson = extJsons == null ? null : extJsons[i]
});
}
#endregion 用户资源处理
#region 用户权限处理.
var relationRolePer = new List<SysRelation>();//要添加的用户有哪些权限列表
var defaultDataScope = input.DefaultDataScope;//获取默认数据范围
//获取菜单信息
var menus = await _resourceService.GetResourcesByIds(menuIds, CateGoryConst.RESOURCE_MENU);
if (menus.Count > 0)
{
#region 用户模块关系
//获取我的模块信息Id列表
var moduleIds = menus.Select(it => it.Module.Value).Distinct().ToList();
moduleIds.ForEach(it =>
{
//将角色资源添加到列表
relationRoles.Add(new SysRelation
{
ObjectId = sysUser.Id,
TargetId = it.ToString(),
Category = CateGoryConst.RELATION_SYS_USER_HAS_MODULE
});
});
#endregion
//获取权限授权树
var permissions = _resourceService.PermissionTreeSelector(menus.Select(it => it.Path).ToList());
permissions.ForEach(it =>
{
//新建角色权限关系
relationRolePer.Add(new SysRelation
{
ObjectId = sysUser.Id,
TargetId = it.ApiRoute,
Category = CateGoryConst.RELATION_SYS_USER_HAS_PERMISSION,
ExtJson = new RelationRolePermission
{
ApiUrl = it.ApiRoute,
ScopeCategory = defaultDataScope.ScopeCategory,
ScopeDefineOrgIdList = defaultDataScope.ScopeDefineOrgIdList
}.ToJson()
});
});
}
relationRoles.AddRange(relationRolePer);//合并列表
#endregion 用户权限处理.
#region 保存数据库
//事务
var result = await Tenant.UseTranAsync(async () =>
{
var relationRep = ChangeRepository<DbRepository<SysRelation>>();//切换仓储
await relationRep.DeleteAsync(it => it.ObjectId == sysUser.Id && (it.Category == CateGoryConst.RELATION_SYS_USER_HAS_PERMISSION
|| it.Category == CateGoryConst.RELATION_SYS_USER_HAS_RESOURCE) || it.Category == CateGoryConst.RELATION_SYS_USER_HAS_MODULE);
await relationRep.InsertRangeAsync(relationRoles);//添加新的
});
if (result.IsSuccess)//如果成功了
{
await _relationService.RefreshCache(CateGoryConst.RELATION_SYS_USER_HAS_PERMISSION);//刷新关系缓存
await _relationService.RefreshCache(CateGoryConst.RELATION_SYS_USER_HAS_RESOURCE);//刷新关系缓存
await _relationService.RefreshCache(CateGoryConst.RELATION_SYS_USER_HAS_MODULE);//刷新关系缓存
DeleteUserFromRedis(input.Id);//删除该用户缓存
}
else
{
//写日志
_logger.LogError(result.ErrorMessage, result.ErrorException);
throw Oops.Oh(ErrorCodeEnum.A0003);
}
#endregion 保存数据库
}
}
/// <inheritdoc />
public async Task GrantPermission(GrantPermissionInput input)
{
var sysUser = await GetUserById(input.Id);//获取用户
if (sysUser != null)
{
var apiUrls = input.GrantInfoList.Select(it => it.ApiUrl).ToList();//apiurl列表
var extJsons = input.GrantInfoList.Select(it => it.ToJson()).ToList();//拓展信息
await _relationService.SaveRelationBatch(CateGoryConst.RELATION_SYS_USER_HAS_PERMISSION, input.Id, apiUrls, extJsons,
true);//添加到数据库
DeleteUserFromRedis(input.Id);
}
}
#endregion 编辑
#region 删除
/// <inheritdoc/>
public async Task Delete(BaseIdListInput input)
{
//获取所有ID
var ids = input.Ids;
if (ids.Count > 0)
{
var containsSuperAdmin = await IsAnyAsync(it => it.Account == SysRoleConst.SUPER_ADMIN && ids.Contains(it.Id));//判断是否有超管
if (containsSuperAdmin)
throw Oops.Bah("不可删除系统内置超管用户");
if (ids.Contains(UserManager.UserId))
throw Oops.Bah("不可删除自己");
//定义删除的关系
var delRelations = new List<string>
{
CateGoryConst.RELATION_SYS_USER_HAS_RESOURCE,
CateGoryConst.RELATION_SYS_USER_HAS_PERMISSION,
CateGoryConst.RELATION_SYS_USER_HAS_ROLE,
CateGoryConst.RELATION_SYS_USER_HAS_MODULE,
CateGoryConst.RELATION_SYS_USER_SCHEDULE_DATA,
CateGoryConst.RELATION_SYS_USER_WORKBENCH_DATA
};
//事务
var result = await Tenant.UseTranAsync(async () =>
{
//清除该用户作为主管信息
await UpdateAsync(it => new SysUser
{
DirectorId = null
}, it => ids.Contains(it.DirectorId.Value));
//删除用户
await DeleteByIdsAsync(ids.Cast<object>().ToArray());
var relationRep = ChangeRepository<DbRepository<SysRelation>>();//切换仓储
//删除关系表用户与资源关系,用户与权限关系,用户与角色关系
await relationRep.DeleteAsync(it => ids.Contains(it.ObjectId) && delRelations.Contains(it.Category));
var orgRep = ChangeRepository<DbRepository<SysOrg>>();//切换仓储
//删除组织表主管信息
await orgRep.DeleteAsync(it => ids.Contains(it.DirectorId.Value));
});
if (result.IsSuccess)//如果成功了
{
DeleteUserFromRedis(ids);//缓存删除用户
await _relationService.RefreshCache(CateGoryConst.RELATION_SYS_USER_HAS_ROLE);//关系表刷新SYS_USER_HAS_ROLE缓存
await _relationService.RefreshCache(CateGoryConst.RELATION_SYS_USER_HAS_RESOURCE);//关系表刷新SYS_USER_HAS_ROLE缓存
await _relationService.RefreshCache(CateGoryConst.RELATION_SYS_USER_HAS_PERMISSION);//关系表刷新SYS_USER_HAS_ROLE缓存
await _relationService.RefreshCache(CateGoryConst.RELATION_SYS_USER_HAS_MODULE);//关系表刷新RELATION_SYS_USER_HAS_MODULE缓存
await _relationService.RefreshCache(CateGoryConst.RELATION_SYS_USER_SCHEDULE_DATA);//关系表刷新RELATION_SYS_USER_SCHEDULE_DATA缓存
await _relationService.RefreshCache(CateGoryConst.RELATION_SYS_USER_WORKBENCH_DATA);//关系表刷新RELATION_SYS_USER_WORKBENCH_DATA缓存
// TODO 此处需要将这些用户踢下线,并永久注销这些用户
var idArray = ids.Select(it => it.ToString()).ToArray();
//从列表中删除
_simpleCacheService.HashDel<List<TokenInfo>>(CacheConst.CACHE_USER_TOKEN, idArray);
}
else
{
//写日志
_logger.LogError(result.ErrorMessage, result.ErrorException);
throw Oops.Oh(ErrorCodeEnum.A0002);
}
}
}
/// <inheritdoc />
public void DeleteUserFromRedis(long userId)
{
DeleteUserFromRedis(new List<long>
{
userId
});
}
/// <inheritdoc />
public void DeleteUserFromRedis(List<long> ids)
{
var userIds = ids.Select(it => it.ToString()).ToArray();//id转string列表
var sysUsers = _simpleCacheService.HashGet<SysUser>(SystemConst.CACHE_SYS_USER, userIds);//获取用户列表
sysUsers = sysUsers.Where(it => it != null).ToList();//过滤掉不存在的
if (sysUsers.Count > 0)
{
var accounts = sysUsers.Select(it => it.Account).ToArray();//账号集合
var phones = sysUsers.Select(it => it.Phone).ToArray();//手机号集合
//删除用户信息
_simpleCacheService.HashDel<SysUser>(SystemConst.CACHE_SYS_USER, userIds);
//删除用户头像信息
_simpleCacheService.HashDel<string>(SystemConst.CACHE_SYS_USER_AVATAR, userIds);
var userAccountKey = SystemConst.CACHE_SYS_USER_ACCOUNT;
var userPhoneKey = SystemConst.CACHE_SYS_USER_PHONE;
if (sysUsers.Any(it => it.TenantId != null))//如果有租户id不是空的表示是多租户模式
{
var tenantIds = sysUsers.Where(it => it.TenantId != null).Select(it => it.TenantId.Value).Distinct().ToArray();//租户id列表
foreach (var tenantId in tenantIds)
{
userAccountKey = $"{userAccountKey}:{tenantId}";
userPhoneKey = $"{userPhoneKey}:{tenantId}";
//删除账号
_simpleCacheService.HashDel<long>(userAccountKey, accounts);
//删除手机
if (phones != null)
_simpleCacheService.HashDel<long>(userPhoneKey, phones);
}
}
else
{
//删除账号
_simpleCacheService.HashDel<long>(userAccountKey, accounts);
//删除手机
if (phones != null)
_simpleCacheService.HashDel<long>(userPhoneKey, phones);
}
}
}
#endregion 删除
#region 导入导出
/// <inheritdoc/>
public async Task<FileStreamResult> Template()
{
var templateName = "用户信息";
//var result = _importExportService.GenerateLocalTemplate(templateName);
var result = await _importExportService.GenerateTemplate<SysUserImportInput>(templateName);
return result;
}
/// <inheritdoc/>
public async Task<ImportPreviewOutput<SysUserImportInput>> Preview(ImportPreviewInput input)
{
var importPreview = await _importExportService.GetImportPreview<SysUserImportInput>(input.File);
importPreview.Data = await CheckImport(importPreview.Data);//检查导入数据
return importPreview;
}
/// <inheritdoc/>
public async Task<ImportResultOutPut<SysUserImportInput>> Import(ImportResultInput<SysUserImportInput> input)
{
var data = await CheckImport(input.Data, true);//检查数据格式
var result = _importExportService.GetImportResultPreview(data, out var importData);
var sysUsers = importData.Adapt<List<SysUser>>();//转实体
await SetUserDefault(sysUsers);//设置默认值
await InsertOrBulkCopy(sysUsers);// 数据导入
return result;
}
/// <inheritdoc/>
public async Task<FileStreamResult> Export(UserPageInput input)
{
var genTests = await List(input);
var data = genTests.Adapt<List<SysUserExportOutput>>();//转为Dto
var result = await _importExportService.Export(data, "用户信息");
return result;
}
/// <inheritdoc/>
public async Task<List<T>> CheckImport<T>(List<T> data, bool clearError = false) where T : SysUserImportInput
{
#region 校验要用到的数据
var accounts = data.Select(it => it.Account).ToList();//当前导入数据账号列表
var phones = data.Where(it => !string.IsNullOrEmpty(it.Phone)).Select(it => it.Phone).ToList();//当前导入数据手机号列表
var emails = data.Where(it => !string.IsNullOrEmpty(it.Email)).Select(it => it.Email).ToList();//当前导入数据邮箱列表
var sysUsers = await GetListAsync(it => true, it => new SysUser
{
Account = it.Account,
Phone = it.Phone,
Email = it.Email
});//获取数据用户信息
var dbAccounts = sysUsers.Select(it => it.Account).ToList();//数据库账号列表
var dbPhones = sysUsers.Where(it => !string.IsNullOrEmpty(it.Phone)).Select(it => it.Phone).ToList();//数据库手机号列表
var dbEmails = sysUsers.Where(it => !string.IsNullOrEmpty(it.Email)).Select(it => it.Email).ToList();//邮箱账号列表
var sysOrgList = await _sysOrgService.GetListAsync();
var sysPositions = await _sysPositionService.GetListAsync();
var dictList = await _dictService.GetListAsync();
#endregion 校验要用到的数据
foreach (var item in data)
{
if (clearError)//如果需要清除错误
{
item.ErrorInfo = new Dictionary<string, string>();
item.HasError = false;
}
#region 校验账号
if (dbAccounts.Contains(item.Account))
item.ErrorInfo.Add(nameof(item.Account), $"系统已存在账号{item.Account}");
if (accounts.Where(u => u == item.Account).Count() > 1)
item.ErrorInfo.Add(nameof(item.Account), "账号重复");
#endregion 校验账号
#region 校验手机号
if (!string.IsNullOrEmpty(item.Phone))
{
if (dbPhones.Contains(item.Phone))
item.ErrorInfo.Add(nameof(item.Phone), $"系统已存在手机号{item.Phone}的用户");
if (phones.Where(u => u == item.Phone).Count() > 1)
item.ErrorInfo.Add(nameof(item.Phone), "手机号重复");
}
#endregion 校验手机号
#region 校验邮箱
if (!string.IsNullOrEmpty(item.Email))
{
if (dbEmails.Contains(item.Email))
item.ErrorInfo.Add(nameof(item.Email), $"系统已存在邮箱{item.Email}");
if (emails.Where(u => u == item.Email).Count() > 1)
item.ErrorInfo.Add(nameof(item.Email), "邮箱重复");
}
#endregion 校验邮箱
#region 校验部门和职位
if (!string.IsNullOrEmpty(item.OrgName))
{
var org = sysOrgList.Where(u => u.Names == item.OrgName).FirstOrDefault();
if (org != null) item.OrgId = org.Id;//赋值组织Id
else item.ErrorInfo.Add(nameof(item.OrgName), $"部门{org}不存在");
}
//校验职位
if (!string.IsNullOrEmpty(item.PositionName))
{
if (string.IsNullOrEmpty(item.OrgName))
item.ErrorInfo.Add(nameof(item.PositionName), "请填写部门");
else
{
//根据部门ID和职位名判断是否有职位
var position = sysPositions.FirstOrDefault(u => u.OrgId == item.OrgId && u.Name == item.PositionName);
if (position != null) item.PositionId = position.Id;
else item.ErrorInfo.Add(nameof(item.PositionName), $"职位{item.PositionName}不存在");
}
}
#endregion 校验部门和职位
#region 校验性别等字典
var genders = await _dictService.GetValuesByDictValue(SysDictConst.GENDER, dictList);
if (!genders.Contains(item.Gender))
item.ErrorInfo.Add(nameof(item.Gender), "性别只能是男和女");
if (!string.IsNullOrEmpty(item.Nation))
{
var nations = await _dictService.GetValuesByDictValue(SysDictConst.NATION, dictList);
if (!nations.Contains(item.Nation))
item.ErrorInfo.Add(nameof(item.Nation), "不存在的民族");
}
if (!string.IsNullOrEmpty(item.IdCardType))
{
var idCarTypes = await _dictService.GetValuesByDictValue(SysDictConst.ID_CARD_TYPE, dictList);
if (!idCarTypes.Contains(item.IdCardType))
item.ErrorInfo.Add(nameof(item.IdCardType), "证件类型错误");
}
if (!string.IsNullOrEmpty(item.CultureLevel))
{
var cultureLevels = await _dictService.GetValuesByDictValue(SysDictConst.CULTURE_LEVEL, dictList);
if (!cultureLevels.Contains(item.CultureLevel))
item.ErrorInfo.Add(nameof(item.CultureLevel), "文化程度有误");
}
#endregion 校验性别等字典
if (item.ErrorInfo.Count > 0) item.HasError = true;//如果错误信息数量大于0则表示有错误
}
data = data.OrderByDescending(it => it.HasError).ToList();//排序
return data;
}
/// <inheritdoc/>
public async Task SetUserDefault(List<SysUser> sysUsers)
{
var defaultPassword = await GetDefaultPassWord(true);//默认密码
//默认值赋值
sysUsers.ForEach(user =>
{
user.Status = CommonStatusConst.ENABLE;//状态
user.Phone = CryptogramUtil.Sm4Encrypt(user.Phone);//手机号
user.Password = defaultPassword;//默认密码
user.Avatar = AvatarUtil.GetNameImageBase64(user.Name);//默认头像
});
}
#endregion 导入导出
#region 方法
/// <summary>
/// 获取默认密码
/// </summary>
/// <returns></returns>
private async Task<string> GetDefaultPassWord(bool isSm4 = false)
{
//获取默认密码
var defaultPassword = (await _configService.GetByConfigKey(CateGoryConst.CONFIG_PWD_POLICY, SysConfigConst.PWD_DEFAULT_PASSWORD)).ConfigValue;
return isSm4 ? CryptogramUtil.Sm4Encrypt(defaultPassword) : defaultPassword;//判断是否需要加密
}
/// <summary>
/// 检查输入参数
/// </summary>
/// <param name="sysUser"></param>
private async Task CheckInput(SysUser sysUser)
{
var sysOrgList = await _sysOrgService.GetListAsync();//获取组织列表
var userOrg = sysOrgList.FirstOrDefault(it => it.Id == sysUser.OrgId);
if (userOrg == null)
throw Oops.Bah($"组织机构不存在");
//获取多租户配置
var isTenant = await _configService.IsTenant();
long? tenantId = null;
if (isTenant)
tenantId = await _sysOrgService.GetTenantIdByOrgId(sysUser.OrgId, sysOrgList);
//判断账号重复,直接从缓存拿
var accountId = await GetIdByAccount(sysUser.Account, tenantId);
if (accountId > 0 && accountId != sysUser.Id)
throw Oops.Bah($"存在重复的账号:{sysUser.Account}");
//如果手机号不是空
if (!string.IsNullOrEmpty(sysUser.Phone))
{
if (!sysUser.Phone.MatchPhoneNumber())//验证手机格式
throw Oops.Bah($"手机号码:{sysUser.Phone} 格式错误");
var phoneId = await GetIdByPhone(sysUser.Phone, tenantId);
if (phoneId > 0 && sysUser.Id != phoneId)//判断重复
throw Oops.Bah($"存在重复的手机号:{sysUser.Phone}");
sysUser.Phone = CryptogramUtil.Sm4Encrypt(sysUser.Phone);
}
//如果邮箱不是空
if (!string.IsNullOrEmpty(sysUser.Email))
{
var (isMatch, match) = sysUser.Email.MatchEmail();//验证邮箱格式
if (!isMatch)
throw Oops.Bah($"邮箱:{sysUser.Email} 格式错误");
if (await IsAnyAsync(it => it.Email == sysUser.Email && it.Id != sysUser.Id))
throw Oops.Bah($"存在重复的邮箱:{sysUser.Email}");
}
if (sysUser.DirectorId != null)
{
if (sysUser.DirectorId.Value == UserManager.UserId) throw Oops.Bah($"不能设置自己为主管");
}
}
/// <summary>
/// 检查是否为自己
/// </summary>
/// <param name="id"></param>
/// <param name="operate">操作名称</param>
private void CheckSelf(long id, string operate)
{
if (id == UserManager.UserId)//如果是自己
{
throw Oops.Bah($"禁止{operate}自己");
}
}
/// <summary>
/// 根据日期计算年龄
/// </summary>
/// <param name="birthdate"></param>
/// <returns></returns>
public int GetAgeByBirthdate(DateTime birthdate)
{
var now = DateTime.Now;
var age = now.Year - birthdate.Year;
if (now.Month < birthdate.Month || now.Month == birthdate.Month && now.Day < birthdate.Day)
{
age--;
}
return age < 0 ? 0 : age;
}
/// <summary>
/// 获取SqlSugar的ISugarQueryable
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private async Task<ISugarQueryable<SysUser>> GetQuery(UserPageInput input)
{
var orgIds = await _sysOrgService.GetOrgChildIds(input.OrgId);//获取下级机构
var query = Context.Queryable<SysUser>().LeftJoin<SysOrg>((u, o) => u.OrgId == o.Id).LeftJoin<SysPosition>((u, o, p) => u.PositionId == p.Id)
.WhereIF(input.OrgId > 0, u => orgIds.Contains(u.OrgId))//根据组织
.WhereIF(input.Expression != null, input.Expression?.ToExpression())//动态查询
.WhereIF(!string.IsNullOrEmpty(input.Status), u => u.Status == input.Status)//根据状态查询
.WhereIF(!string.IsNullOrEmpty(input.SearchKey), u => u.Name.Contains(input.SearchKey) || u.Account.Contains(input.SearchKey))//根据关键字查询
.OrderByIF(!string.IsNullOrEmpty(input.SortField), $"u.{input.SortField} {input.SortOrder}").OrderBy(u => u.Id)//排序
.OrderBy((u, o) => u.CreateTime)//排序
.Select((u, o, p) => new SysUser
{
Id = u.Id.SelectAll(),
OrgName = o.Name,
PositionName = p.Name,
OrgNames = o.Names
}).Mapper(u =>
{
u.Password = null;//密码清空
u.Phone = CryptogramUtil.Sm4Decrypt(u.Phone);//手机号解密
});
return query;
}
/// <summary>
/// 数据库获取用户信息
/// </summary>
/// <param name="userId">用户ID</param>
/// <returns></returns>
private async Task<SysUser> GetUserFromDb(long userId)
{
var sysUser = await Context.Queryable<SysUser>().LeftJoin<SysOrg>((u, o) => u.OrgId == o.Id)//连表
.LeftJoin<SysPosition>((u, o, p) => u.PositionId == p.Id)//连表
.Where(u => u.Id == userId)
.Select((u, o, p) => new SysUser
{
Id = u.Id.SelectAll(),
OrgName = o.Name,
OrgNames = o.Names,
PositionName = p.Name,
OrgAndPosIdList = o.ParentIdList
}).FirstAsync();
if (sysUser != null)
{
sysUser.Password = CryptogramUtil.Sm4Decrypt(sysUser.Password);//解密密码
sysUser.Phone = CryptogramUtil.Sm4Decrypt(sysUser.Phone);//解密手机号
sysUser.OrgAndPosIdList.AddRange(sysUser.OrgId, sysUser.PositionId);//添加组织和职位Id
if (sysUser.DirectorId != null)
{
sysUser.DirectorInfo = await GetUserById<UserSelectorOutPut>(sysUser.DirectorId.Value);//获取主管信息
}
//获取按钮码
var buttonCodeList = await GetButtonCodeList(sysUser.Id);
//获取数据权限
var dataScopeList = await GetPermissionListByUserId(sysUser.Id, sysUser.OrgId);
//获取权限码
var permissionCodeList = dataScopeList.Select(it => it.ApiUrl).ToList();
//获取角色码
var roleCodeList = await _sysRoleService.GetRoleListByUserId(sysUser.Id);
//权限码赋值
sysUser.ButtonCodeList = buttonCodeList;
sysUser.RoleCodeList = roleCodeList.Select(it => it.Code).ToList();
sysUser.RoleIdList = roleCodeList.Select(it => it.Id).ToList();
sysUser.PermissionCodeList = permissionCodeList;
sysUser.DataScopeList = dataScopeList;
var sysOrgList = await _sysOrgService.GetListAsync();
var scopeOrgChildList =
(await _sysOrgService.GetChildListById(sysUser.OrgId, true, sysOrgList)).Select(it => it.Id).ToList();//获取所属机构的下级机构Id列表
sysUser.ScopeOrgChildList = scopeOrgChildList;
if (await _configService.IsTenant())//如果是多租户就获取用户的租户Id
{
var tenantId = await _sysOrgService.GetTenantIdByOrgId(sysUser.OrgId, sysOrgList);
sysUser.TenantId = tenantId;
}
var moduleIds = await _relationService.GetUserModuleId(sysUser.RoleIdList, sysUser.Id);//获取模块ID列表
var modules = await _resourceService.GetResourcesByIds(moduleIds, CateGoryConst.RESOURCE_MODULE);//获取模块列表
sysUser.ModuleList = modules;//模块列表赋值给用户
//插入缓存
_simpleCacheService.HashAdd(SystemConst.CACHE_SYS_USER_AVATAR, sysUser.Id.ToString(), sysUser.Avatar);
sysUser.Avatar = null;//头像清空,减少CACHE_SYS_USER的大小
_simpleCacheService.HashAdd(SystemConst.CACHE_SYS_USER, sysUser.Id.ToString(), sysUser);
return sysUser;
}
return null;
}
#endregion 方法
}