添加项目文件。

This commit is contained in:
fuenmao
2025-09-29 13:48:36 +08:00
parent f61e922f0c
commit 5dc1780ef1
407 changed files with 63703 additions and 0 deletions
@@ -0,0 +1,14 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
@@ -0,0 +1,15 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System.Services.System.Relation.Dto;
public class RelationOutput
{
}
@@ -0,0 +1,103 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 关系服务
/// </summary>
public interface IRelationService : ITransient
{
/// <summary>
/// 根据分类获取关系表信息
/// </summary>
/// <param name="category">分类名称</param>
/// <returns>关系表</returns>
Task<List<SysRelation>> GetRelationByCategory(string category);
/// <summary>
/// 通过对象ID和分类获取关系列表
/// </summary>
/// <param name="objectId">对象ID</param>
/// <param name="category">分类</param>
/// <returns></returns>
Task<List<SysRelation>> GetRelationListByObjectIdAndCategory(long objectId, string category);
/// <summary>
/// 通过对象ID列表和分类获取关系列表
/// </summary>
/// <param name="objectIds">对象ID</param>
/// <param name="category">分类</param>
/// <returns></returns>
Task<List<SysRelation>> GetRelationListByObjectIdListAndCategory(List<long> objectIds, string category);
/// <summary>
/// 通过目标ID和分类获取关系列表
/// </summary>
/// <param name="targetId">目标ID</param>
/// <param name="category">分类</param>
/// <returns></returns>
Task<List<SysRelation>> GetRelationListByTargetIdAndCategory(string targetId, string category);
/// <summary>
/// 通过目标ID列表和分类获取关系列表
/// </summary>
/// <param name="targetIds"></param>
/// <param name="category"></param>
/// <returns></returns>
Task<List<SysRelation>> GetRelationListByTargetIdListAndCategory(List<string> targetIds, string category);
/// <summary>
/// 获取关系表用户工作台
/// </summary>
/// <param name="userId">用户ID</param>
/// <returns>关系表数据</returns>
Task<SysRelation> GetWorkbench(long userId);
/// <summary>
/// 更新缓存
/// </summary>
/// <param name="category">分类</param>
/// <returns></returns>
Task RefreshCache(string category);
/// <summary>
/// 保存关系
/// </summary>
/// <param name="category">分类</param>
/// <param name="objectId">对象ID</param>
/// <param name="targetId">目标ID</param>
/// <param name="extJson">拓展信息</param>
/// <param name="clear">是否清除老的数据</param>
/// <param name="refreshCache">是否刷新缓存</param>
/// <returns></returns>
Task SaveRelation(string category, long objectId, string targetId,
string extJson, bool clear, bool refreshCache = true);
/// <summary>
/// 批量保存关系
/// </summary>
/// <param name="category">分类</param>
/// <param name="objectId">对象ID</param>
/// <param name="targetIds">目标ID列表</param>
/// <param name="extJsons">拓展信息列表</param>
/// <param name="clear">是否清除老的数据</param>
/// <returns></returns>
Task SaveRelationBatch(string category, long objectId, List<string> targetIds,
List<string> extJsons, bool clear);
/// <summary>
/// 获取用户模块ID
/// </summary>
/// <param name="roleIdList"></param>
/// <param name="userId"></param>
/// <returns></returns>
Task<List<long>> GetUserModuleId(List<long> roleIdList, long userId);
}
@@ -0,0 +1,174 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <inheritdoc cref="IRelationService"/>
public class RelationService : DbRepository<SysRelation>, IRelationService
{
private readonly ILogger<RelationService> _logger;
private readonly ISimpleCacheService _simpleCacheService;
public RelationService(ILogger<RelationService> logger, ISimpleCacheService simpleCacheService)
{
_logger = logger;
_simpleCacheService = simpleCacheService;
}
/// <inheritdoc/>
public async Task<List<SysRelation>> GetRelationByCategory(string category)
{
var key = SystemConst.CACHE_SYS_RELATION + category;
//先从Redis拿
var sysRelations = _simpleCacheService.Get<List<SysRelation>>(key);
if (sysRelations == null)
{
//redis没有就去数据库拿
sysRelations = await base.GetListAsync(it => it.Category == category);
if (sysRelations.Count > 0)
{
//插入Redis
_simpleCacheService.Set(key, sysRelations);
}
}
return sysRelations;
}
/// <inheritdoc/>
public async Task<List<SysRelation>> GetRelationListByObjectIdAndCategory(long objectId, string category)
{
var sysRelations = await GetRelationByCategory(category);
var result = sysRelations.Where(it => it.ObjectId == objectId).ToList();//获取关系集合
return result;
}
/// <inheritdoc/>
public async Task<SysRelation> GetWorkbench(long userId)
{
var sysRelations = await GetRelationByCategory(CateGoryConst.RELATION_SYS_USER_WORKBENCH_DATA);
var result = sysRelations.Where(it => it.ObjectId == userId).FirstOrDefault();//获取个人工作台
return result;
}
/// <inheritdoc/>
public async Task<List<SysRelation>> GetRelationListByObjectIdListAndCategory(List<long> objectIds, string category)
{
var sysRelations = await GetRelationByCategory(category);
var result = sysRelations.Where(it => objectIds.Contains(it.ObjectId)).ToList();//获取关系集合
return result;
}
/// <inheritdoc/>
public async Task<List<SysRelation>> GetRelationListByTargetIdAndCategory(string targetId, string category)
{
var sysRelations = await GetRelationByCategory(category);
var result = sysRelations.Where(it => it.TargetId == targetId).ToList();//获取关系集合
return result;
}
/// <inheritdoc/>
public async Task<List<SysRelation>> GetRelationListByTargetIdListAndCategory(List<string> targetIds, string category)
{
var sysRelations = await GetRelationByCategory(category);
var result = sysRelations.Where(it => targetIds.Contains(it.TargetId)).ToList();//获取关系集合
return result;
}
/// <inheritdoc/>
public async Task RefreshCache(string category)
{
var key = SystemConst.CACHE_SYS_RELATION + category;//key
_simpleCacheService.Remove(key);//删除redis
await GetRelationByCategory(category);//更新缓存
}
/// <inheritdoc/>
public async Task SaveRelationBatch(string category, long objectId, List<string> targetIds,
List<string> extJsons, bool clear)
{
var sysRelations = new List<SysRelation>();//要添加的列表
for (var i = 0; i < targetIds.Count; i++)
{
sysRelations.Add(new SysRelation
{
ObjectId = objectId,
TargetId = targetIds[i],
Category = category,
ExtJson = extJsons == null ? null : extJsons[i]
});
}
//事务
var result = await Tenant.UseTranAsync(async () =>
{
if (clear)
await DeleteAsync(it => it.ObjectId == objectId && it.Category == category);//删除老的
await InsertRangeAsync(sysRelations);//添加新的
});
if (result.IsSuccess)//如果成功了
{
await RefreshCache(category);
}
else
{
//写日志
_logger.LogError(result.ErrorMessage, result.ErrorException);
throw Oops.Oh(ErrorCodeEnum.A0003);
}
}
/// <inheritdoc/>
public async Task SaveRelation(string category, long objectId, string targetId,
string extJson, bool clear, bool refreshCache = true)
{
var sysRelation = new SysRelation
{
ObjectId = objectId,
TargetId = targetId,
Category = category,
ExtJson = extJson
};
//事务
var result = await Tenant.UseTranAsync(async () =>
{
if (clear)
await DeleteAsync(it => it.ObjectId == objectId && it.Category == category);//删除老的
await InsertAsync(sysRelation);//添加新的
});
if (result.IsSuccess)//如果成功了
{
if (refreshCache)
await RefreshCache(category);
}
else
{
//写日志
_logger.LogError(result.ErrorMessage, result.ErrorException);
throw Oops.Oh(ErrorCodeEnum.A0003);
}
}
/// <inheritdoc/>
public async Task<List<long>> GetUserModuleId(List<long> roleIdList, long userId)
{
var moduleIds = new List<long>();
var roleRelation = await GetRelationByCategory(CateGoryConst.RELATION_SYS_ROLE_HAS_MODULE);//获取角色模块关系集合
if (roleRelation != null && roleRelation.Count > 0)
{
moduleIds = roleRelation.Where(it => roleIdList.Contains(it.ObjectId)).Select(it => it.TargetId.ToLong()).ToList();
}
var userRelation = await GetRelationByCategory(CateGoryConst.RELATION_SYS_USER_HAS_MODULE);//获取用户模块关系集合
if (userRelation != null && userRelation.Count > 0)
{
var userModuleIds = userRelation.Where(it => it.ObjectId == userId).Select(it => it.TargetId.ToLong()).ToList();
moduleIds.AddRange(userModuleIds);
}
return moduleIds;
}
}
@@ -0,0 +1,27 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 资源输入
/// </summary>
public class ResTreeSelectorInput
{
/// <summary>
/// 资源分类
/// </summary>
public string ShowSystem { get; set; }
/// <summary>
/// 是否包含按钮
/// </summary>
public bool IsContainButton { get; set; }
}
@@ -0,0 +1,110 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 角色授权资源树输出
/// </summary>
public class ResTreeSelector
{
/// <summary>
/// 模块id
/// </summary>
public long Id { get; set; }
/// <summary>
/// 模块名称
/// </summary>
public string Title { get; set; }
/// <summary>
/// 模块图标
/// </summary>
public string Icon { get; set; }
/// <summary>
/// 模块下菜单集合
/// </summary>
public List<RoleGrantResourceMenu> Menu { get; set; }
/// <summary>
/// 授权菜单类
/// </summary>
public class RoleGrantResourceMenu
{
/// <summary>
/// 菜单id
/// </summary>
public long Id { get; set; }
/// <summary>
/// 父id
/// </summary>
public long ParentId { get; set; }
/// <summary>
/// 父名称
/// </summary>
public string ParentName { get; set; }
/// <summary>
/// 模块名称
/// </summary>
public string Title { get; set; }
/// <summary>
/// 模块id
/// </summary>
public long Module { get; set; }
/// <summary>
/// 菜单下按钮集合
/// </summary>
public List<RoleGrantResourceButton> Button { get; set; } = new List<RoleGrantResourceButton>();
}
/// <summary>
/// 角色授权资源按钮信息
/// </summary>
public class RoleGrantResourceButton
{
/// <summary>
/// 按钮id
/// </summary>
public long Id { get; set; }
/// <summary>
/// 标题
/// </summary>
public string Title { get; set; }
}
}
/// <summary>
/// 权限树选择器输出
/// </summary>
public class PermissionTreeSelector
{
/// <summary>
/// 接口描述
/// </summary>
public string ApiName { get; set; }
/// <summary>
/// 路由名称
/// </summary>
public string ApiRoute { get; set; }
/// <summary>
/// 权限名称
/// </summary>
public string PermissionName { get; set; }
}
@@ -0,0 +1,113 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 资源服务
/// </summary>
public interface IResourceService : ITransient
{
/// <summary>
/// 获取所有的菜单和模块以及单页面列表,并按分类和排序码排序
/// </summary>
/// <returns>所有的菜单和模块以及单页面列表</returns>
Task<List<SysResource>> GetAllModuleAndMenuAndSpaList();
/// <summary>
/// 根据模块ID获取菜单和单页面列表
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task<List<SysResource>> GetMenuAndSpaListByModuleId(long id);
/// <summary>
/// 根据资源ID获取所有下级资源
/// </summary>
/// <param name="resId">资源ID</param>
/// <param name="isContainOneself">是否包含自己</param>
/// <returns>资源列表</returns>
Task<List<SysResource>> GetChildListById(long resId, bool isContainOneself = true);
/// <summary>
/// 根据资源ID获取所有下级资源
/// </summary>
/// <param name="sysResources">资源列表</param>
/// <param name="resId">资源ID</param>
/// <param name="isContainOneself">是否包含自己</param>
/// <returns>资源列表</returns>
List<SysResource> GetChildListById(List<SysResource> sysResources, long resId, bool isContainOneself = true);
/// <summary>
/// 获取ID获取Code列表
/// </summary>
/// <param name="ids">id列表</param>
/// <param name="category">分类</param>
/// <returns>Code列表</returns>
Task<List<string>> GetCodeByIds(List<long> ids, string category);
/// <summary>
/// 获取资源列表
/// </summary>
/// <param name="categoryList">资源分类列表</param>
/// <returns></returns>
Task<List<SysResource>> GetListAsync(List<string>? categoryList = null);
/// <summary>
/// 根据分类获取资源列表
/// </summary>
/// <param name="category">分类名称</param>
/// <returns>资源列表</returns>
Task<List<SysResource>> GetListByCategory(string category);
/// <summary>
/// 根据菜单ID获取菜单
/// </summary>
/// <param name="ids">id列表</param>
/// <param name="category">分类</param>
/// <returns></returns>
Task<List<SysResource>> GetResourcesByIds(List<long> ids, string category);
/// <summary>
/// 获取权限授权树
/// </summary>
/// <param name="routes">路由列表</param>
/// <returns></returns>
List<PermissionTreeSelector> PermissionTreeSelector(List<string> routes);
/// <summary>
/// 刷新缓存
/// </summary>
/// <param name="category">分类名称</param>
/// <returns></returns>
Task RefreshCache(string category = null);
/// <summary>
/// 角色授权资源树
/// </summary>
/// <returns></returns>
Task<List<ResTreeSelector>> ResourceTreeSelector();
/// <summary>
/// 获取上级
/// </summary>
/// <param name="resourceList"></param>
/// <param name="parentId"></param>
/// <returns></returns>
List<SysResource> GetResourceParent(List<SysResource> resourceList, long parentId);
/// <summary>
/// 获取授权菜单类菜单名称
/// </summary>
/// <param name="menuList">菜单列表</param>
/// <param name="menu">当前菜单</param>
/// <returns></returns>
string GetRoleGrantResourceMenuTitle(List<SysResource> menuList, SysResource menu);
}
@@ -0,0 +1,427 @@
// 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 System.ComponentModel;
using StringHelper = SimpleTool.StringHelper;
namespace SimpleAdmin.System;
/// <inheritdoc cref="IResourceService"/>
public class ResourceService : DbRepository<SysResource>, IResourceService
{
private readonly ISimpleCacheService _simpleCacheService;
private readonly IRelationService _relationService;
public ResourceService(ISimpleCacheService simpleCacheService, IRelationService relationService)
{
_simpleCacheService = simpleCacheService;
_relationService = relationService;
}
/// <inheritdoc />
public async Task<List<string>> GetCodeByIds(List<long> ids, string category)
{
//根据分类获取所有
var sysResources = await GetListByCategory(category);
//条件查询
var result = sysResources.Where(it => ids.Contains(it.Id)).Select(it => it.Code).ToList();
return result;
}
/// <inheritdoc/>
public async Task<List<SysResource>> GetListAsync(List<string>? categoryList = null)
{
//定义结果
var sysResources = new List<SysResource>();
//定义资源分类列表,如果是空的则获取全部资源
categoryList = categoryList != null
? categoryList
: new List<string>
{
CateGoryConst.RESOURCE_MENU, CateGoryConst.RESOURCE_BUTTON,
CateGoryConst.RESOURCE_SPA, CateGoryConst.RESOURCE_MODULE
};
//遍历列表
foreach (var category in categoryList)
{
//根据分类获取到资源列表
var data = await GetListByCategory(category);
//添加到结果集
sysResources.AddRange(data);
}
return sysResources;
}
/// <inheritdoc/>
public async Task<List<SysResource>> GetAllModuleAndMenuAndSpaList()
{
//获取所有的菜单和模块以及单页面列表,
var sysResources = await GetListAsync(new List<string>
{
CateGoryConst.RESOURCE_MODULE, CateGoryConst.RESOURCE_MENU, CateGoryConst.RESOURCE_SPA
});
if (sysResources != null)
{
//并按分类和排序码排序
sysResources = sysResources.OrderBy(it => it.Category).ThenBy(it => it.SortCode).ToList();
}
return sysResources;
}
/// <inheritdoc/>
public async Task<List<SysResource>> GetMenuAndSpaListByModuleId(long id)
{
//获取所有的菜单和模块以及单页面列表,
var sysResources = await GetListAsync(new List<string> { CateGoryConst.RESOURCE_MENU, CateGoryConst.RESOURCE_SPA });
if (sysResources != null)
{
//并按分类和排序码排序
sysResources = sysResources.Where(it => it.Category == CateGoryConst.RESOURCE_SPA || it.Module == id)//根据模块ID获取菜单
.OrderBy(it => it.Category).ThenBy(it => it.SortCode).ToList();//排序
}
return sysResources;
}
/// <inheritdoc/>
public async Task RefreshCache(string category = null)
{
//如果分类是空的
if (category == null)
{
//删除全部key
_simpleCacheService.DelByPattern(SystemConst.CACHE_SYS_RESOURCE);
await GetListAsync();
}
else
{
//否则只删除一个Key
_simpleCacheService.Remove(SystemConst.CACHE_SYS_RESOURCE + category);
await GetListByCategory(category);
}
}
/// <inheritdoc />
public async Task<List<SysResource>> GetChildListById(long resId, bool isContainOneself = true)
{
//获取所有机构
var sysResources = await GetListAsync();
//查找下级
var childList = GetResourceChildren(sysResources, resId);
if (isContainOneself)//如果包含自己
{
//获取自己的机构信息
var self = sysResources.Where(it => it.Id == resId).FirstOrDefault();
if (self != null) childList.Insert(0, self);//如果机构不为空就插到第一个
}
return childList;
}
/// <inheritdoc />
public List<SysResource> GetChildListById(List<SysResource> sysResources, long resId, bool isContainOneself = true)
{
//查找下级
var childList = GetResourceChildren(sysResources, resId);
if (isContainOneself)//如果包含自己
{
//获取自己的机构信息
var self = sysResources.Where(it => it.Id == resId).FirstOrDefault();
if (self != null) childList.Insert(0, self);//如果机构不为空就插到第一个
}
return childList;
}
/// <inheritdoc />
public async Task<List<SysResource>> GetListByCategory(string category)
{
//先从Redis拿
var sysResources = _simpleCacheService.Get<List<SysResource>>(SystemConst.CACHE_SYS_RESOURCE + category);
if (sysResources == null)
{
//redis没有就去数据库拿
sysResources = await base.GetListAsync(it => it.Category == category);
if (sysResources.Count > 0)
{
//插入Redis
_simpleCacheService.Set(SystemConst.CACHE_SYS_RESOURCE + category, sysResources);
}
}
return sysResources;
}
/// <inheritdoc />
public async Task<List<ResTreeSelector>> ResourceTreeSelector()
{
var resourceTreeSelectors = new List<ResTreeSelector>();//定义结果
//获取模块列表
var moduleList = await GetListByCategory(CateGoryConst.RESOURCE_MODULE);
//遍历模块
foreach (var module in moduleList)
{
//将实体转换为ResourceTreeSelectorOutPut获取基本信息
var resourceTreeSelector = module.Adapt<ResTreeSelector>();
resourceTreeSelector.Menu = await GetRoleGrantResourceMenus(module.Id);
resourceTreeSelectors.Add(resourceTreeSelector);
}
return resourceTreeSelectors;
}
/// <inheritdoc />
public List<PermissionTreeSelector> PermissionTreeSelector(List<string> routes)
{
var permissions = new List<PermissionTreeSelector>();//权限列表
var controllerTypes =
App.EffectiveTypes.Where(u =>
!u.IsInterface && !u.IsAbstract && u.IsDefined(typeof(RolePermissionAttribute), false));
foreach (var controller in controllerTypes)
{
var apiAttribute = controller.GetCustomAttribute<ApiDescriptionSettingsAttribute>();//获取接口描述特性
var tag = apiAttribute.Tag;//获取标签
//获取数据权限特性
var routeAttributes = controller.GetCustomAttributes<RouteAttribute>().ToList();
if (routeAttributes == null)
continue;
var route = routeAttributes[0];//取第一个值
var routeName = GetRouteName(controller.Name, route.Template);//赋值路由名称
//如果路由包含在路由列表中
if (routes.Contains(routeName))
{
//获取所有方法
var methods = controller.GetMethods();
//遍历方法
foreach (var method in methods)
{
//获取忽略数据权限特性
var ignoreRolePermission = method.GetCustomAttribute<IgnoreRolePermissionAttribute>();
if (ignoreRolePermission == null)//如果是空的代表需要数据权限
{
//获取接口描述
var displayName = method.GetCustomAttribute<DisplayNameAttribute>();
if (displayName != null)
{
//默认路由名称
var apiRoute = StringHelper.FirstCharToLower(method.Name);
//获取get特性
var requestGet = method.GetCustomAttribute<HttpGetAttribute>();
if (requestGet != null)//如果是get方法
apiRoute = requestGet.Template;
else
{
//获取post特性
var requestPost = method.GetCustomAttribute<HttpPostAttribute>();
if (requestPost != null)//如果是post方法
apiRoute = requestPost.Template;
}
apiRoute = route.Template + $"/{apiRoute}";
if (!apiRoute.StartsWith("/"))
apiRoute = "/" + apiRoute;//如果路由地址不是/开头则加上/防止控制器没写
var apiName = displayName.DisplayName;//如果描述不为空则接口名称用描述的名称
//合并
var permissionName = apiRoute + $"[{tag}-{apiName}]";
//添加到权限列表
permissions.Add(new PermissionTreeSelector
{
ApiName = apiName,
ApiRoute = apiRoute,
PermissionName = permissionName
});
}
}
}
}
}
return permissions;
}
/// <inheritdoc />
public async Task<List<SysResource>> GetResourcesByIds(List<long> ids, string category)
{
//获取所有菜单
var menus = await GetListByCategory(category);
if (!UserManager.SuperAdmin)//超级管理员获取所有
{
//获取菜单信息
menus = menus.Where(it => ids.Contains(it.Id)).ToList();
}
return menus;
}
/// <inheritdoc />
public List<SysResource> GetResourceParent(List<SysResource> resourceList, long parentId)
{
//找上级资源ID列表
var resources = resourceList.Where(it => it.Id == parentId).FirstOrDefault();
if (resources != null)//如果数量大于0
{
var data = new List<SysResource>();
var parents = GetResourceParent(resourceList, resources.ParentId.Value);
data.AddRange(parents);//添加子节点;
data.Add(resources);//添加到列表
return data;//返回结果
}
return new List<SysResource>();
}
#region 方法
/// <summary>
/// 获取路由地址名称
/// </summary>
/// <param name="controllerName">控制器地址</param>
/// <param name="template">路由名称</param>
/// <returns></returns>
private string GetRouteName(string controllerName, string template)
{
if (!template.StartsWith("/"))
template = "/" + template;//如果路由名称不是/开头则加上/防止控制器没写
if (template.Contains("[controller]"))
{
controllerName = controllerName.Replace("Controller", "");//去掉Controller
controllerName = StringHelper.FirstCharToLower(controllerName);//转首字母小写写
template = template.Replace("[controller]", controllerName);//替换[controller]
}
return template;
}
/// <summary>
/// 获取资源所有下级
/// </summary>
/// <param name="resourceList">资源列表</param>
/// <param name="parentId">父ID</param>
/// <returns></returns>
public List<SysResource> GetResourceChildren(List<SysResource> resourceList, long parentId)
{
//找下级资源ID列表
var resources = resourceList.Where(it => it.ParentId == parentId).ToList();
if (resources.Count > 0)//如果数量大于0
{
var data = new List<SysResource>();
foreach (var item in resources)//遍历资源
{
var res = GetResourceChildren(resourceList, item.Id);
data.AddRange(res);//添加子节点;
data.Add(item);//添加到列表
}
return data;//返回结果
}
return new List<SysResource>();
}
/// <summary>
/// 获取授权菜单
/// </summary>
/// <param name="moduleId">模块ID</param>
/// <returns></returns>
public async Task<List<ResTreeSelector.RoleGrantResourceMenu>> GetRoleGrantResourceMenus(long moduleId)
{
var roleGrantResourceMenus = new List<ResTreeSelector.RoleGrantResourceMenu>();//定义结果
var allMenuList = (await GetListByCategory(CateGoryConst.RESOURCE_MENU)).Where(it => it.Module == moduleId).ToList();//获取所有菜单列表
var allButtonList = await GetListByCategory(CateGoryConst.RESOURCE_BUTTON);//获取所有按钮列表
var parentMenuList = allMenuList.Where(it => it.ParentId == SimpleAdminConst.ZERO).ToList();//获取一级目录
//遍历一级目录
foreach (var parent in parentMenuList)
{
//如果是目录则去遍历下级
if (parent.MenuType == SysResourceConst.CATALOG)
{
//获取所有下级菜单
var menuList = GetChildListById(allMenuList, parent.Id, false);
if (menuList.Count > 0)//如果有菜单
{
//遍历下级菜单
foreach (var menu in menuList)
{
//如果菜单类型是菜单
if (menu.MenuType is SysResourceConst.MENU or SysResourceConst.SUBSET)
{
//获取菜单下按钮集合并转换成对应实体
var buttonList = allButtonList.Where(it => it.ParentId == menu.Id).ToList();
var buttons = buttonList.Adapt<List<ResTreeSelector.RoleGrantResourceButton>>();
roleGrantResourceMenus.Add(new ResTreeSelector.RoleGrantResourceMenu
{
Id = menu.Id,
ParentId = parent.Id,
ParentName = parent.Title,
Module = moduleId,
Title = GetRoleGrantResourceMenuTitle(menuList, menu),//菜单名称需要特殊处理因为有二级菜单
Button = buttons
});
}
else if (menu.MenuType == SysResourceConst.LINK || menu.MenuType == SysResourceConst.IFRAME)//如果是内链或者外链
{
//直接加到资源列表
roleGrantResourceMenus.Add(new ResTreeSelector.RoleGrantResourceMenu
{
Id = menu.Id,
ParentId = parent.Id,
ParentName = parent.Title,
Module = moduleId,
Title = menu.Title
});
}
}
}
else
{
//否则就将自己加到一级目录里面
roleGrantResourceMenus.Add(new ResTreeSelector.RoleGrantResourceMenu
{
Id = parent.Id,
ParentId = parent.Id,
ParentName = parent.Title,
Module = moduleId
});
}
}
else
{
//就将自己加到一级目录里面
var roleGrantResourcesButtons = new ResTreeSelector.RoleGrantResourceMenu
{
Id = parent.Id,
ParentId = parent.Id,
ParentName = parent.Title,
Module = moduleId,
Title = parent.Title
};
//如果菜单类型是菜单
if (parent.MenuType == SysResourceConst.MENU)
{
//获取菜单下按钮集合并转换成对应实体
var buttonList = allButtonList.Where(it => it.ParentId == parent.Id).ToList();
roleGrantResourcesButtons.Button = buttonList.Adapt<List<ResTreeSelector.RoleGrantResourceButton>>();
}
roleGrantResourceMenus.Add(roleGrantResourcesButtons);
}
}
return roleGrantResourceMenus;
}
/// <inheritdoc />
public string GetRoleGrantResourceMenuTitle(List<SysResource> menuList, SysResource menu)
{
//查找菜单上级
var parentList = GetResourceParent(menuList, menu.ParentId.Value);
//如果有父级菜单
if (parentList.Count > 0)
{
var titles = parentList.Select(it => it.Title).ToList();//提取出父级的name
var title = string.Join("- ", titles) + $"-{menu.Title}";//根据-分割,转换成字符串并在最后加上菜单的title
return title;
}
return menu.Title;//原路返回
}
#endregion 方法
}
@@ -0,0 +1,80 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 编辑个人信息参数
/// </summary>
public class UpdateInfoInput : SysUser
{
/// <summary>
/// 姓名
/// </summary>
[Required(ErrorMessage = "Name不能为空")]
public override string Name { get; set; }
}
public class UpdateSignatureInput
{
/// <summary>
/// 签名图片
/// </summary>
[Required(ErrorMessage = "Signature签名图片不能为空")]
public string Signature { get; set; }
}
/// <summary>
/// 更新个人工作台
/// </summary>
public class UpdateWorkbenchInput
{
/// <summary>
/// 工作台数据
/// </summary>
[Required(ErrorMessage = "WorkbenchData不能为空")]
public string WorkbenchData { get; set; }
}
/// <summary>
/// 更新个人密码
/// </summary>
public class UpdatePasswordInput
{
/// <summary>
/// 密码
/// </summary>
[Required(ErrorMessage = "Password不能为空")]
public string Password { get; set; }
/// <summary>
/// 新密码
/// </summary>
[Required(ErrorMessage = "NewPassword不能为空")]
public string NewPassword { get; set; }
}
/// <summary>
/// 设置默认模块输入
/// </summary>
public class SetDefaultModuleInput
{
/// <summary>
/// 模块Id
/// </summary>
[Required(ErrorMessage = "Id不能为空")]
public long Id { get; set; }
/// <summary>
/// 是否默认
/// </summary>
[Required(ErrorMessage = "IfDefault不能为空")]
public bool IfDefault { get; set; }
}
@@ -0,0 +1,58 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 我的机构数样式
/// </summary>
public class LoginOrgTreeOutput
{
/// <summary>
/// Id
/// </summary>
public long Id { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Label { get; set; }
/// <summary>
/// 父ID
/// </summary>
public long Pid { get; set; }
/// <summary>
/// 子节点
/// </summary>
public List<LoginOrgTreeOutput> Children { get; set; }
/// <summary>
/// 样式
/// </summary>
public MyStyle? Style { get; set; }
/// <summary>
/// 我的机构样式
/// </summary>
public class MyStyle
{
/// <summary>
/// 背景色
/// </summary>
public string Background { get; set; } = "var(--primary-color)";
/// <summary>
/// 字体颜色
/// </summary>
public string Color { get; set; } = "#FFF";
}
}
@@ -0,0 +1,157 @@
// Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
//
// SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
// 1.请不要删除和修改根目录下的LICENSE文件。
// 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
// 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
// 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
// 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
// 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关。
namespace SimpleAdmin.System;
/// <summary>
/// 个人信息中心服务
/// </summary>
public interface IUserCenterService : ITransient
{
#region 查询
/// <summary>
/// 获取登录用户菜单
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<List<SysResource>> GetLoginMenu(BaseIdInput input);
/// <summary>
/// 获取个人工作台
/// </summary>
/// <returns></returns>
Task<string> GetLoginWorkbench();
/// <summary>
/// 获取组织架构
/// </summary>
/// <returns>组织架构</returns>
Task<List<LoginOrgTreeOutput>> LoginOrgTree();
/// <summary>
/// 获取快捷菜单树
/// </summary>
/// <returns></returns>
Task<List<SysResource>> ShortcutTree();
/// <summary>
/// 读取登录用户站内信详情
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<SysMessage> LoginMessageDetail(MessageDetailInput input);
/// <summary>
/// 获取登录用户的站内信分页
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<SqlSugarPagedList<SysMessage>> LoginMessagePage(MessagePageInput input);
#endregion 查询
#region 编辑
/// <summary>
/// 更新个人信息
/// </summary>
/// <param name="input">信息参数</param>
/// <returns></returns>
Task UpdateUserInfo(UpdateInfoInput input);
/// <summary>
/// 更新签名
/// </summary>
/// <param name="input">签名图片</param>
/// <returns></returns>
Task UpdateSignature(UpdateSignatureInput input);
/// <summary>
/// 编辑个人工作台
/// </summary>
/// <param name="input">工作台字符串</param>
/// <returns></returns>
Task UpdateWorkbench(UpdateWorkbenchInput input);
/// <summary>
/// 删除我的消息
/// </summary>
/// <param name="input">消息Id</param>
/// <returns></returns>
Task DeleteMyMessage(BaseIdInput input);
/// <summary>
/// 修改个人密码
/// </summary>
/// <param name="input">密码信息</param>
/// <returns></returns>
Task UpdatePassword(UpdatePasswordInput input);
/// <summary>
/// 修改头像
/// </summary>
/// <param name="input">头像文件</param>
/// <returns></returns>
Task<string> UpdateAvatar(BaseFileInput input);
/// <summary>
/// 修改默认模块
/// </summary>
/// <param name="input">默认模块输入参数</param>
/// <returns></returns>
Task SetDefaultModule(SetDefaultModuleInput input);
#endregion 编辑
#region 我的消息
/// <summary>
/// 获取登录用户的站内信分页
/// </summary>
/// <param name="input">查询参数</param>
/// <returns>站内信列表</returns>
Task<SqlSugarPagedList<SysMessage>> MyMessagePage(MessagePageInput input);
/// <summary>
/// 读取登录用户站内信详情
/// </summary>
/// <param name="input">消息ID</param>
/// <returns>消息详情</returns>
Task<SysMessage> MyMessageDetail(BaseIdInput input);
/// <summary>
/// 获取未读消息数量
/// </summary>
/// <returns>未读消息数量</returns>
Task<List<MessageUnReadOutPut>> UnReadCount();
/// <summary>
/// 最新未读消息
/// </summary>
/// <returns></returns>
Task<List<SysMessage>> NewUnRead();
/// <summary>
/// 设置已读
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<int> SetRead(MessageReadInput input);
/// <summary>
/// 删除我的消息
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<int> SetDelete(MessageReadInput input);
#endregion
}
@@ -0,0 +1,461 @@
// 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 NewLife;
using System.Text.RegularExpressions;
namespace SimpleAdmin.System;
/// <inheritdoc cref="IUserCenterService"/>
public class UserCenterService : DbRepository<SysUser>, IUserCenterService
{
private readonly ISysUserService _userService;
private readonly IRelationService _relationService;
private readonly IResourceService _resourceService;
private readonly IMenuService _menuService;
private readonly IConfigService _configService;
private readonly ISysOrgService _sysOrgService;
private readonly IMessageService _messageService;
public UserCenterService(ISysUserService userService, IRelationService relationService, IResourceService resourceService,
IMenuService menuService, IConfigService configService, ISysOrgService sysOrgService,
IMessageService messageService)
{
_userService = userService;
_relationService = relationService;
_resourceService = resourceService;
_menuService = menuService;
_configService = configService;
_sysOrgService = sysOrgService;
_messageService = messageService;
}
#region 查询
/// <inheritdoc />
public async Task<List<SysResource>> GetLoginMenu(BaseIdInput input)
{
var result = new List<SysResource>();
//获取用户信息
var userInfo = await _userService.GetUserByAccount(UserManager.UserAccount, UserManager.TenantId);
if (userInfo != null)
{
//定义菜单ID列表
var menuIdList = new HashSet<long>();//获取所有的菜单和模块以及单页面列表,并按分类和排序码排序
var allModuleAndMenuAndSpaList = await _resourceService.GetMenuAndSpaListByModuleId(input.Id);
//通过 App.GetOptions<TOptions> 获取选项
var settings = App.GetOptions<SystemSettingsOptions>();
//如果设置了超级管理员可以看到全部
if (settings.SuperAdminViewAllData && UserManager.SuperAdmin)
{
menuIdList = allModuleAndMenuAndSpaList.Select(it => it.Id).ToHashSet();
}
else
{
//获取用户所拥有的资源集合
var resourceList =
await _relationService.GetRelationListByObjectIdAndCategory(userInfo.Id, CateGoryConst.RELATION_SYS_USER_HAS_RESOURCE);
if (resourceList.Count == 0)//如果没有就获取角色的
//获取角色所拥有的资源集合
resourceList = await _relationService.GetRelationListByObjectIdListAndCategory(userInfo.RoleIdList,
CateGoryConst.RELATION_SYS_ROLE_HAS_RESOURCE);
//获取菜单Id集合
menuIdList.AddRange(resourceList.Select(r => r.TargetId.ToLong()).ToList());
}
var allMenuList = new List<SysResource>();//菜单列表
var allSpaList = new List<SysResource>();//单页列表
//遍历菜单集合
allModuleAndMenuAndSpaList.ForEach(it =>
{
switch (it.Category)
{
case CateGoryConst.RESOURCE_MENU://菜单
allMenuList.Add(it);//添加到菜单列表
break;
case CateGoryConst.RESOURCE_SPA://单页
allSpaList.Add(it);//添加到单页列表
break;
}
});
//获取我的菜单列表,只显示启用的
var myMenus = allMenuList.Where(it => menuIdList.Contains(it.Id) && it.Status == CommonStatusConst.ENABLE).ToList();
// 对获取到的角色对应的菜单列表进行处理,获取父列表
var parentList = GetMyParentMenus(allMenuList, myMenus);
myMenus.AddRange(parentList);//合并列表
// 遍历单页列表
allSpaList.ForEach(it =>
{
it.ParentId = SimpleAdminConst.ZERO;
});
myMenus.AddRange(allSpaList);//单页添加到菜单
//构建meta
ConstructMeta(myMenus);
//构建菜单树
result = _menuService.ConstructMenuTrees(myMenus);
}
return result;
}
/// <inheritdoc />
public async Task<string> GetLoginWorkbench()
{
//获取个人工作台信息
var sysRelation = await _relationService.GetWorkbench(UserManager.UserId);
if (sysRelation != null)
{
//如果有数据直接返回个人工作台
return sysRelation.ExtJson.ToLower();
}
//如果没数据去系统配置里取默认的工作台
var devConfig = await _configService.GetByConfigKey(CateGoryConst.CONFIG_SYS_BASE, SysConfigConst.SYS_DEFAULT_WORKBENCH_DATA);
if (devConfig != null)
{
return devConfig.ConfigValue.ToLower();//返回工作台信息
}
return "";
}
/// <inheritdoc />
public async Task<List<LoginOrgTreeOutput>> LoginOrgTree()
{
var orgList = await _sysOrgService.GetListAsync();//获取全部机构
var parentOrgList = _sysOrgService.GetOrgParents(orgList, UserManager.OrgId);//获取父节点列表
var topOrg = parentOrgList.Where(it => it.ParentId == SimpleAdminConst.ZERO).FirstOrDefault();//获取顶级节点
if (topOrg != null)
{
var orgChildList = await _sysOrgService.GetChildListById(topOrg.Id);//获取下级
var orgTree = ConstrucOrgTrees(orgChildList, 0, UserManager.OrgId);//获取组织架构
return orgTree;
}
return new List<LoginOrgTreeOutput>();
}
/// <inheritdoc />
public async Task<List<SysResource>> ShortcutTree()
{
var sysResourceList = await _resourceService.GetAllModuleAndMenuAndSpaList();//获取模块和菜单和单页列表
var userInfo = await _userService.GetUserById(UserManager.UserId);
var hasResourcesList = new HashSet<long>();//拥有的资源列表
var hasModuleList = new HashSet<long>();//拥有的资源列表
var userResourceList =
(await _relationService.GetRelationListByObjectIdAndCategory(UserManager.UserId, CateGoryConst.RELATION_SYS_USER_HAS_RESOURCE))
.Select(it => it.TargetId.ToLong()).ToList();//获取用户资源id列表
var userModuleList =
(await _relationService.GetRelationListByObjectIdAndCategory(UserManager.UserId, CateGoryConst.RELATION_SYS_USER_HAS_MODULE))
.Select(it => it.TargetId.ToLong()).ToList();//获取用户模块id列表
if (userResourceList.Count > 0)//如果用户资源列表大于0就以用户为主
{
hasResourcesList.AddRange(userResourceList);
hasResourcesList.AddRange(userModuleList);
}
else
{
var roleIds = userInfo.RoleIdList;//获取角色ID列表
var roleResourceList =
(await _relationService.GetRelationListByObjectIdListAndCategory(roleIds, CateGoryConst.RELATION_SYS_ROLE_HAS_RESOURCE))
.Select(it => it.TargetId.ToLong()).ToList();//获取角色资源id列表
var roleModuleList =
(await _relationService.GetRelationListByObjectIdListAndCategory(roleIds, CateGoryConst.RELATION_SYS_ROLE_HAS_MODULE))
.Select(it => it.TargetId.ToLong()).ToList();//获取角色模块id列表
hasResourcesList.AddRange(roleResourceList);
hasResourcesList.AddRange(roleModuleList);
}
// 获取目录
var catalogList = sysResourceList.Where(it => it.MenuType == SysResourceConst.CATALOG).ToList();
//过滤出拥有的资源列表
sysResourceList =
sysResourceList.Where(it =>
hasResourcesList.Contains(it.Id) || it.Category == CateGoryConst.RESOURCE_SPA)
.ToList();//获取拥有的资源列表
var parentIds = sysResourceList.Select(it => it.ParentId).Distinct().ToList();//获取父ID列表
var parentList = catalogList.Where(it => parentIds.Contains(it.Id)).ToList();//获取所拥有的父级目录
sysResourceList.AddRange(parentList);//添加到列表
return await _menuService.ShortcutTree(sysResourceList);
}
/// <inheritdoc />
public async Task<SqlSugarPagedList<SysMessage>> LoginMessagePage(MessagePageInput input)
{
var messages = await _messageService.MyMessagePage(input, UserManager.UserId);//分页查询
return messages;
}
/// <inheritdoc />
public async Task<SysMessage> LoginMessageDetail(MessageDetailInput input)
{
return await _messageService.Detail(input);//返回详情,不带用户列表
}
#endregion 查询
#region 编辑
/// <inheritdoc />
public async Task UpdateUserInfo(UpdateInfoInput input)
{
//如果手机号不是空
if (!string.IsNullOrEmpty(input.Phone))
{
if (!input.Phone.MatchPhoneNumber())//判断是否是手机号格式
throw Oops.Bah("手机号码格式错误");
input.Phone = CryptogramUtil.Sm4Encrypt(input.Phone);
var any = await IsAnyAsync(it => it.Phone == input.Phone && it.Id != UserManager.UserId);//判断是否有重复的
if (any)
throw Oops.Bah("系统已存在该手机号");
}
if (!string.IsNullOrEmpty(input.Email))
{
var match = input.Email.MatchEmail();
if (!match.isMatch)
throw Oops.Bah("邮箱格式错误");
}
//更新指定字段
var result = await UpdateSetColumnsTrueAsync(it => new SysUser
{
Name = input.Name,
Email = input.Email,
Phone = input.Phone,
Nickname = input.Nickname,
Gender = input.Gender,
Birthday = input.Birthday
}, it => it.Id == UserManager.UserId);
if (result)
_userService.DeleteUserFromRedis(UserManager.UserId);//redis删除用户数据
}
/// <inheritdoc />
public async Task UpdateSignature(UpdateSignatureInput input)
{
var signatureArray = input.Signature.Split(",");//分割
// var base64String = signatureArray[1];//根据逗号分割取到base64字符串
// var image = base64String.GetSkBitmapFromBase64();//转成图片
// var resizeImage = image.ResizeImage(100, 50);//重新裁剪
// var newBase64String = resizeImage.ImgToBase64String();//重新转为base64
// var newSignature = signatureArray[0] + "," + newBase64String;//赋值新的签名
//更新签名
var result = await UpdateSetColumnsTrueAsync(it => new SysUser
{
Signature = input.Signature
}, it => it.Id == UserManager.UserId);
if (result)
_userService.DeleteUserFromRedis(UserManager.UserId);//redis删除用户数据
}
/// <inheritdoc />
public async Task UpdateWorkbench(UpdateWorkbenchInput input)
{
//关系表保存个人工作台
await _relationService.SaveRelation(CateGoryConst.RELATION_SYS_USER_WORKBENCH_DATA, UserManager.UserId, null, input.WorkbenchData,
true);
}
/// <inheritdoc />
public async Task DeleteMyMessage(BaseIdInput input)
{
await _messageService.DeleteMyMessage(input, UserManager.UserId);
}
/// <inheritdoc />
public async Task UpdatePassword(UpdatePasswordInput input)
{
//获取用户信息
var userInfo = await _userService.GetUserById(UserManager.UserId);
var password = CryptogramUtil.Sm2Decrypt(input.Password);//SM2解密
if (userInfo.Password != password) throw Oops.Bah("原密码错误");
var newPassword = CryptogramUtil.Sm2Decrypt(input.NewPassword);//sm2解密
var loginPolicy = await _configService.GetConfigsByCategory(CateGoryConst.CONFIG_PWD_POLICY);//获取密码策略
var containNumber = loginPolicy.First(it => it.ConfigKey == SysConfigConst.PWD_CONTAIN_NUM).ConfigValue.ToBoolean();//是否包含数字
var containLower = loginPolicy.First(it => it.ConfigKey == SysConfigConst.PWD_CONTAIN_LOWER).ConfigValue.ToBoolean();//是否包含小写
var containUpper = loginPolicy.First(it => it.ConfigKey == SysConfigConst.PWD_CONTAIN_UPPER).ConfigValue.ToBoolean();//是否包含大写
var containChar = loginPolicy.First(it => it.ConfigKey == SysConfigConst.PWD_CONTAIN_CHARACTER).ConfigValue.ToBoolean();//是否包含特殊字符
var minLength = loginPolicy.First(it => it.ConfigKey == SysConfigConst.PWD_MIN_LENGTH).ConfigValue.ToInt();//最小长度
if (minLength > newPassword.Length)
throw Oops.Bah($"密码长度不能小于{minLength}");
if (containNumber && !Regex.IsMatch(newPassword, "[0-9]"))
throw Oops.Bah("密码必须包含数字");
if (containLower && !Regex.IsMatch(newPassword, "[a-z]"))
throw Oops.Bah("密码必须包含小写字母");
if (containUpper && !Regex.IsMatch(newPassword, "[A-Z]"))
throw Oops.Bah("密码必须包含大写字母");
if (containChar && !Regex.IsMatch(newPassword, "[~!@#$%^&*()_+`\\-={}|\\[\\]:\";'<>?,./]"))
throw Oops.Bah("密码必须包含特殊字符");
// var similarity = PwdUtil.Similarity(password, newPassword);
// if (similarity > 80)
// throw Oops.Bah($"新密码请勿与旧密码过于相似");
newPassword = CryptogramUtil.Sm4Encrypt(newPassword);//SM4加密
userInfo.Password = newPassword;
await UpdateSetColumnsTrueAsync(it => new SysUser { Password = newPassword }, it => it.Id == userInfo.Id);//更新密码
_userService.DeleteUserFromRedis(UserManager.UserId);//redis删除用户数据
}
/// <inheritdoc />
public async Task<string> UpdateAvatar(BaseFileInput input)
{
var userInfo = await _userService.GetUserById(UserManager.UserId);
var file = input.File;
using var fileStream = file.OpenReadStream();//获取文件流
var bytes = new byte[fileStream.Length];
fileStream.Read(bytes, 0, bytes.Length);
fileStream.Close();
var base64String = Convert.ToBase64String(bytes);//转base64
var avatar = base64String.ToImageBase64();//转图片
await UpdateSetColumnsTrueAsync(it => new SysUser { Avatar = avatar }, it => it.Id == userInfo.Id);// 更新头像
_userService.DeleteUserFromRedis(UserManager.UserId);//redis删除用户数据
return avatar;
}
/// <inheritdoc />
public async Task SetDefaultModule(SetDefaultModuleInput input)
{
//获取用户信息
var userInfo = await _userService.GetUserById(UserManager.UserId);
//如果是默认模块
if (input.IfDefault)
userInfo.DefaultModule = input.Id;
else
userInfo.DefaultModule = null;
await Context.Updateable(userInfo).UpdateColumns(it => new { it.DefaultModule }).ExecuteCommandAsync();//修改默认模块
_userService.DeleteUserFromRedis(UserManager.UserId);//redis删除用户数据
}
#endregion 编辑
#region 我的消息
/// <inheritdoc />
public async Task<SqlSugarPagedList<SysMessage>> MyMessagePage(MessagePageInput input)
{
var messages = await _messageService.MyMessagePage(input, UserManager.UserId);//分页查询
return messages;
}
/// <inheritdoc />
public async Task<SysMessage> MyMessageDetail(BaseIdInput input)
{
return await _messageService.Detail(new MessageDetailInput { Id = input.Id, Read = true });//返回详情,不带用户列表
}
/// <inheritdoc />
public async Task<List<MessageUnReadOutPut>> UnReadCount()
{
return await _messageService.UnReadCount(UserManager.UserId);
}
/// <inheritdoc />
public async Task<List<SysMessage>> NewUnRead()
{
return await _messageService.NewUnRead(UserManager.UserId);
}
/// <inheritdoc />
public async Task<int> SetRead(MessageReadInput input)
{
return await _messageService.SetRead(input);
}
/// <inheritdoc />
public async Task<int> SetDelete(MessageReadInput input)
{
return await _messageService.SetDelete(input);
}
#endregion
#region 方法
/// <summary>
/// 获取父菜单集合
/// </summary>
/// <param name="allMenuList">所有菜单列表</param>
/// <param name="myMenus">我的菜单列表</param>
/// <returns></returns>
private List<SysResource> GetMyParentMenus(List<SysResource> allMenuList, List<SysResource> myMenus)
{
var parentList = new List<SysResource>();
myMenus.ForEach(it =>
{
var parents = _resourceService.GetResourceParent(allMenuList, it.ParentId.Value);//获取父级
parents.ForEach(parent =>
{
// 如果父级菜单存在,并且父级菜单状态为启用,并不在父级列表中,则添加到父级列表
if (parent != null && parent.Status == CommonStatusConst.ENABLE && !parentList.Contains(parent)
&& !myMenus.Contains(parent))
{
parentList.Add(parent);//添加到父列表
}
});
});
return parentList;
}
/// <summary>
/// 构建Meta
/// </summary>
/// <param name="myMenus">我的菜单集合</param>
private void ConstructMeta(List<SysResource> myMenus)
{
myMenus.ForEach(it =>
{
//定义meta
var meta = new Meta
{
Icon = it.Icon,
Title = it.Title,
IsAffix = it.IsAffix,
IsHide = it.IsHide,
IsKeepAlive = it.IsKeepAlive,
IsFull = it.IsFull,
ActiveMenu = it.ActiveMenu,
IsLink = it.IsLink
};
it.Meta = meta;
});
}
/// <summary>
/// 构建机构树
/// </summary>
/// <param name="orgList">机构列表</param>
/// <param name="parentId">父ID</param>
/// <param name="orgId">用户ID</param>
/// <returns></returns>
public List<LoginOrgTreeOutput> ConstrucOrgTrees(List<SysOrg> orgList, long parentId, long orgId)
{
//找下级字典ID列表
var orgParents = orgList.Where(it => it.ParentId == parentId).OrderBy(it => it.SortCode).ToList();
if (orgParents.Count > 0)//如果数量大于0
{
var data = new List<LoginOrgTreeOutput>();
foreach (var item in orgParents)//遍历字典
{
var loginOrg = new LoginOrgTreeOutput
{
Children = ConstrucOrgTrees(orgList, item.Id, orgId),//添加子节点
Id = item.Id,
Label = item.Name,
Pid = item.ParentId,
Style = orgId != item.Id ? null : new LoginOrgTreeOutput.MyStyle()
};
data.Add(loginOrg);//添加到列表
}
return data;//返回结果
}
return new List<LoginOrgTreeOutput>();
}
#endregion 方法
}