using System.Collections.Concurrent; using Dlhis.Basic.DataPermissions; using Dlhis.Basic.Device.Dtos; using Dlhis.Basic.Device.Request; using Dlhis.Basic.Organization.Dto; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Device.Entities; using Dlhis.Entity.Device.Enums; using Dlhis.Entity.Sys.Entities; using Dlhis.Entity.Sys.Enums; using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.Utils.Extensions; namespace Dlhis.Basic.Device.Services.Implements; public class DevicePermissionAnalyzeService : IDevicePermissionAnalyzeService { private readonly IDbContext _dbContext; private readonly ICurrentUser _currentUser; private readonly IDataPermissionService _myDataPermissionService; public DevicePermissionAnalyzeService(IDbContext dbContext, ICurrentUser currentUser, IDataPermissionService myDataPermissionService) { _dbContext = dbContext; _currentUser = currentUser; _myDataPermissionService = myDataPermissionService; } public async Task> GetDevicePermissionsAsync(DevicePermissionSaveRequest request) { var currentTenantId = await GetCurrentFactoryAsync(request.UniqueType, request.Codes); //获取当前查询的配置 var setting = _dbContext.GetQueryableSetting(); var query = _dbContext.Queryable().Where(x => x.AssignType == request.AssignType && x.AssignValue == request.GetActualAssignValue() && x.UniqueType == request.UniqueType && x.Type == request.Type && x.TenantId == currentTenantId); //根据数据权限进行过滤 if (setting.GetEnableDataPermission()) { (bool enableDeviceFilter, List deviceCodes) = _myDataPermissionService.GetMyDeviceCodes(); (bool enableDeviceGroupFilter, List deviceGroupCodes) = _myDataPermissionService.GetMyDeviceGroupCodes(); query = query .WhereIF(enableDeviceFilter && request.UniqueType == DeviceAssignmentTypeEnumType.Device, x => deviceCodes.Contains(x.UniqueValue)) .WhereIF(enableDeviceGroupFilter && request.UniqueType == DeviceAssignmentTypeEnumType.Group, x => deviceGroupCodes.Contains(x.UniqueValue)); } return await query.ToListAsync(); //获取当前的操作人的基地 async Task GetCurrentFactoryAsync(DeviceAssignmentTypeEnumType uniqueType, List codes) { var internalCurrentTenantId = _currentUser.GetStringTenantId(); var r = uniqueType switch { DeviceAssignmentTypeEnumType.Device => await _dbContext.Queryable().Where(x => codes.Contains(x.Code)).Where(x => x.TenantId != internalCurrentTenantId).AnyAsync(), DeviceAssignmentTypeEnumType.Group => await _dbContext.Queryable().Where(x => codes.Contains(x.Code)).Where(x => x.TenantId != internalCurrentTenantId).AnyAsync(), _ => false }; r.ThrowIfTrue("存在设备或者设备组不属于当前厂区,操作失败!"); return internalCurrentTenantId; } } public async Task> GetUserPermissionDeviceCodesAsync(string userNo) { var result = await GetUserAssignDeviceCodesWithTypeInTenantAsync(new List { userNo }); return result.Count == 0 ? new List() : result[userNo].SelectMany(x => x.AssignTypes.SelectMany(p => p.Codes)).Distinct().ToList(); } public async Task>> GetUserAssignDeviceCodesWithTypeInTenantAsync( List userNos, DeviceAssignmentTypeEnumType? ignoreUniqueType = null, string ignoreAssignValue = null, AssignTypeEnumType? ignoreAssignType = null) { var gainfos = await _dbContext.Queryable().WhereIF(userNos.IsPresent(), x => userNos.Contains(x.No)).ToListAsync(); if (!gainfos.Any()) return new Dictionary>(); var devices = await _dbContext.Queryable().ToListAsync(); var enableFactoryPermissions = await _dbContext.Queryable().ToListAsync(); var gainfoGroupRelationships = await _dbContext.Queryable() .Where(x => x.IsDeleted == false) .Where(x => userNos.Contains(x.UserNo)) .ToListAsync(); var gainfoGroups = await _dbContext.Queryable().ToListAsync(); var devicePermissions = await _dbContext.Queryable() .Where(x => x.IsDeleted == false) .Select() .ToListAsync(); var deviceGroups = await _dbContext.Queryable() .Where(x => x.IsDeleted == false) .ToListAsync(); var deviceRelationships = await _dbContext.Queryable() .Where(x => x.IsDeleted == false) .ToListAsync(); var departments = await _dbContext.Queryable().Select().ToListAsync(); var result = new ConcurrentDictionary>(); gainfos.ParallelForEach(gainfo => { var internalIgnoreAssignTypes = new List(); if (ignoreAssignType.HasValue) internalIgnoreAssignTypes.Add(ignoreAssignType.Value); if (gainfo.Type == GainfoUserTypeEnumType.External || (gainfo.Type == GainfoUserTypeEnumType.Outsource && (enableFactoryPermissions.FirstOrDefault(x => x.TenantId == gainfo.Factory)?.EnableOutsourceDown ?? true) == false)) { internalIgnoreAssignTypes.Add(AssignTypeEnumType.Tenant); } var excludes = new[] { GainfoUserTypeEnumType.Outsource, GainfoUserTypeEnumType.External }; var analyzePack = new AnalyzePackDto { UserNo = gainfo.No, UserDepartment = gainfo.DepartmentNo, UserFactory = gainfo.Factory, UserGainfoGroupCodes = gainfoGroupRelationships.Where(x => x.UserNo == gainfo.No).Select(x => x.GroupCode), DeviceCodes = devices.WhereIf(excludes.Contains(gainfo.Type), x => x.Type == DeviceTypeEnumType.Door).Select(x => x.Code), //只允许门禁 IgnoreAssignValue = ignoreAssignValue, IgnoreAssignTypes = internalIgnoreAssignTypes, IgnoreUniqueType = ignoreUniqueType }; var codes = GetAssignDeviceCodesPermissions(analyzePack, gainfoGroups, devicePermissions, deviceGroups, deviceRelationships, departments); result.TryAdd(gainfo.No, codes); }); return result.ToDictionary(x => x.Key, x => x.Value); } private static List GetAssignDeviceCodesPermissions( AnalyzePackDto analyzePack, List gainfoGroups, List devicePermissions, List deviceGroups, List deviceGroupRelationships, List departments) { var deviceDtos = new List(); var uniqueTypes = new[] { DeviceAssignmentTypeEnumType.Device, DeviceAssignmentTypeEnumType.Group }; //根据权限分配类型 foreach (var assignType in new[] { AssignTypeEnumType.User, AssignTypeEnumType.Group, AssignTypeEnumType.Department, AssignTypeEnumType.Tenant }) { //二选一移除当前类型的权限,差异分析使用 //eg: 按人分配,移除A设备,只需要查看其他3个类型是否存在A设备而进行删除任务生成 // 按部门分配,移除A设备,需要查看部门上顶级部门是否存在A设备,则通过IgnoreAssignValue移除当前部门其他权限(分组同理) if (analyzePack.IgnoreAssignTypes.Contains(assignType) && analyzePack.IgnoreAssignValue.IsEmpty()) { continue; } if (assignType == AssignTypeEnumType.Group) { var tempUserGroupCodes = analyzePack.UserGainfoGroupCodes.ToList(); foreach (Guid analyzePackUserGainfoGroupCode in analyzePack.UserGainfoGroupCodes) { tempUserGroupCodes.AddRange(RecursionHelper.HandlerGainfoGroupPreviousCodes(analyzePackUserGainfoGroupCode, gainfoGroups)); } analyzePack.UserGainfoGroupCodes = tempUserGroupCodes.Distinct().ToList(); } var assignValues = assignType switch { AssignTypeEnumType.User => new List { analyzePack.UserNo }, AssignTypeEnumType.Group => analyzePack.UserGainfoGroupCodes.Select(x => x.ToString()), AssignTypeEnumType.Department => RecursionHelper.HandlerDepartmentPreviousCodes(analyzePack.UserDepartment, departments).Select(x => analyzePack.UserFactory + ":" + x).ToList(), AssignTypeEnumType.Tenant => new List { analyzePack.UserFactory }, AssignTypeEnumType.Role => throw new NotSupportedException("不支持角色分配"), _ => throw new ArgumentOutOfRangeException() }; var data = assignValues.SelectMany(x => uniqueTypes.Select(p => new { assignValue = x, uniqueType = p })).ToList(); //移除IgnoreAssignValue的数据,对应以上说明 var needRemove = data.Where(x => x.assignValue == analyzePack.IgnoreAssignValue && x.uniqueType == analyzePack.IgnoreUniqueType); data = data.ExceptBy(needRemove, x => new { x.assignValue, x.uniqueType }).ToList(); foreach (var dataPack in data.GroupBy(x => x.uniqueType)) { var currentUniqueType = dataPack.Key; var currentAssignValues = dataPack.Select(x => x.assignValue).ToList(); deviceDtos.AddRange( SearchActualAssignPermissions( devicePermissions, deviceGroups, deviceGroupRelationships, currentUniqueType, assignType, currentAssignValues ) ); } } return deviceDtos.GroupBy(x => x.Tenant).Select(x => { var dto = new TenantAssignTypeDeviceCode { Tenant = x.Key, AssignTypes = x.SelectMany(p => p.AssignTypes) .GroupBy(p => new { p.AssignType, p.AssignValue, p.UniqueType }) .Select(p => new AssignTypeDeviceCode { AssignType = p.Key.AssignType, AssignValue = p.Key.AssignValue, UniqueType = p.Key.UniqueType, Codes = p.SelectMany(xx => xx.Codes.Where(xxx => analyzePack.DeviceCodes.Contains(xxx))).ToList(), OriginalCodes = p.Where(xx => xx.OriginalCodes.IsPresent()).SelectMany(xx => xx.OriginalCodes).ToList() }).ToList() }; return dto; }).ToList(); } private static List SearchActualAssignPermissions( List devicePermissions, List deviceGroups, List deviceGroupRelationships, DeviceAssignmentTypeEnumType uniqueType, AssignTypeEnumType assignType, List assignValues) { var r = devicePermissions .Where(x => x.UniqueType == uniqueType) .Where(x => x.AssignType == assignType) .Where(x => assignValues.Contains(x.AssignValue)) .GroupBy(x => x.TenantId) .Select(x => new TenantAssignTypeDeviceCode { Tenant = x.Key, AssignTypes = x.GroupBy(xx => new { xx.AssignType, xx.AssignValue }).Select(xx => new AssignTypeDeviceCode { AssignType = xx.Key.AssignType, AssignValue = xx.Key.AssignValue, UniqueType = uniqueType, Codes = xx.Select(xxx => xxx.UniqueValue).ToList() }).ToList() }) .ToList(); if (uniqueType == DeviceAssignmentTypeEnumType.Group) { foreach (var groupItem in r) { foreach (var assignTypeDeviceCodeItem in groupItem.AssignTypes) { var nextItems = new List(); foreach (var code in assignTypeDeviceCodeItem.Codes) { nextItems.AddRange(RecursionHelper.HandlerDeviceGroupNextCodes(code, deviceGroups)); } nextItems = nextItems.Distinct().ToList(); assignTypeDeviceCodeItem.OriginalCodes = nextItems; assignTypeDeviceCodeItem.Codes = deviceGroupRelationships.Where(x => nextItems.Contains(x.GroupCode)).Select(x => x.DeviceCode).ToList(); } } } return r; } public async Task> GetAssignmentsAsync(DeviceGetAssignmentsRequest request) { var r = await GetDevicePermissionsAsync(new DevicePermissionSaveRequest { AssignType = request.AssignType, AssignValue = request.AssignValue, UniqueType = request.UniqueType, Codes = null, TenantId = request.TenantId, Type = request.Type }); return r.Select(x => x.UniqueValue).ToList(); } public async Task> GetAssignmentUniqueAsync(DeviceGetAssignmentUniquesRequest request) { var nos = await _dbContext.Queryable() .Where(x => x.UniqueType == request.UniqueType) .Where(x => x.UniqueValue == request.UniqueValue) .Where(x => x.AssignType == AssignTypeEnumType.User) .Where(x => x.Type == request.Type) .Select(x => x.AssignValue) .ToListAsync(); return await _dbContext.Queryable().Where(x => nos.Contains(x.No)).Select(x => new GainfoDto { Id = x.Id, Code = x.Code, Name = x.Name, Workplace = x.Workplace, Factory = x.Factory }).ToListAsync(); } }