using System.Collections.Concurrent; using Dlhis.Basic.DataPermissions; using Dlhis.Basic.Device.Dtos; using Dlhis.Basic.Device.Request; using Dlhis.Basic.Device.Response; 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.Entity; 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 IMyDataPermissionService _myDataPermissionService; public DevicePermissionAnalyzeService(IDbContext dbContext, ICurrentUser currentUser, IMyDataPermissionService myDataPermissionService) { _dbContext = dbContext; _currentUser = currentUser; _myDataPermissionService = myDataPermissionService; } public async Task> GetDevicePermissions(DevicePermissionSaveRequest request) { var currentTenantId = _currentUser.GetStringTenantId(); (bool enableDeviceFilter, List deviceCodes) = _myDataPermissionService.GetMyDeviceCodes(); (bool enableDeviceGroupFilter, List deviceGroupCodes) = _myDataPermissionService.GetMyDeviceGroupCodes(); return await _dbContext.Queryable().Where(x => x.AssignType == request.AssignType && x.AssignValue == request.GetActualAssignValue() && x.UniqueType == request.UniqueType && x.Type == request.Type && x.TenantId == currentTenantId) .WhereIF(enableDeviceFilter && request.UniqueType == DeviceAssignmentTypeEnumType.Device, x => deviceCodes.Contains(x.UniqueValue)) .WhereIF(enableDeviceGroupFilter && request.UniqueType == DeviceAssignmentTypeEnumType.Group, x => deviceGroupCodes.Contains(x.UniqueValue)) .ToListAsync(); } public async Task GenerateDeviceTasksAsync(Func func, List userNos) { var before = await GetUserAssignDeviceCodesInTenantAsync(userNos); //业务处理 _dbContext.Client.QueryFilter.Restore(); await func(); _dbContext.Client.QueryFilter.ClearAndBackup(); var current = await GetUserAssignDeviceCodesInTenantAsync(userNos); var devices = await _dbContext.Queryable().Where(x => x.Enable).ToListAsync(); var waitAddTasks = new List(); var waitDeleteTasks = new List(); foreach (var userNo in userNos) { var beforeTenantDeviceCodes = before[userNo].ToList(); var currentTenantDeviceCodes = current[userNo].ToList(); var tenants = new HashSet(); foreach (var item in beforeTenantDeviceCodes) tenants.Add(item.Tenant); foreach (var item in currentTenantDeviceCodes) tenants.Add(item.Tenant); foreach (var tenant in tenants) { var currentCodes = currentTenantDeviceCodes.FirstOrDefault(x => x.Tenant == tenant)?.Codes?.ToList() ?? new List(); var beforeCodes = beforeTenantDeviceCodes.FirstOrDefault(x => x.Tenant == tenant)?.Codes?.ToList() ?? new List(); //被删除 var deletedItems = beforeCodes.Where(x => !currentCodes.Contains(x)).ToList(); //新增 var addItems = currentCodes.Where(x => !beforeCodes.Contains(x)).ToList(); if (!deletedItems.Any() && !addItems.Any()) { continue; } var deviceCodes = devices.Where(x => deletedItems.Contains(x.Code) || addItems.Contains(x.Code)).Select(x => x.Code).ToList(); deletedItems = deletedItems.Where(x => deviceCodes.Contains(x)).ToList(); addItems = addItems.Where(x => deviceCodes.Contains(x)).ToList(); //下发任务创建 deletedItems.ForEach(x => waitDeleteTasks.Add(new DeviceTaskEntity { DeviceUniqueNo = devices.First(item => item.Code == x).UniqueNo, Status = DeviceTaskStatusEnumType.Wait, Type = DeviceTaskEnumType.Delete, CancellationId = 0, DeviceType = devices.First(item => item.Code == x).Type, UserNo = userNo, Version = 0, TenantId = tenant, Source = DeviceTaskSourceEnumType.Manually })); addItems.ForEach(x => waitAddTasks.Add(new DeviceTaskEntity { DeviceUniqueNo = devices.First(item => item.Code == x).UniqueNo, Status = DeviceTaskStatusEnumType.Wait, Type = DeviceTaskEnumType.Add, DeviceType = devices.First(item => item.Code == x).Type, UserNo = userNo, Version = 0, TenantId = tenant, Source = DeviceTaskSourceEnumType.Manually })); } } await ChunkInsertAsync(waitAddTasks); await ChunkInsertAsync(waitDeleteTasks); return new DevicePermissionAssignResponse(waitAddTasks.Count, waitDeleteTasks.Count); } public async Task>> GetUserAssignDeviceCodesWithTypeInTenantAsync(List userNos, params AssignTypeEnumType[] ignoreAssignTypes) { var gainfos = await _dbContext.Queryable().Where(x => userNos.Contains(x.No)).ToListAsync(); if (!gainfos.Any()) return new Dictionary>(); var devices = await _dbContext.Queryable().Where(x => x.Enable).ToListAsync(); var enableFactoryPermissions = await _dbContext.Queryable().ToListAsync(); var gainfoGroupRelationships = await _dbContext.Queryable().Where(x => userNos.Contains(x.UserNo)).ToListAsync(); var gainfoGroups = await _dbContext.Queryable().ToListAsync(); var devicePermissions = await _dbContext.Queryable().WhereIF(ignoreAssignTypes.IsPresent(), x => !ignoreAssignTypes.Contains(x.AssignType)).ToListAsync(); var deviceGroups = await _dbContext.Queryable().ToListAsync(); var deviceRelationships = await _dbContext.Queryable().ToListAsync(); var departments = await _dbContext.Queryable().ToListAsync(); var result = new ConcurrentDictionary>(); gainfos.ParallelForEach(gainfo => { var internalIgnoreAssignTypes = new List(); internalIgnoreAssignTypes.AddRange(ignoreAssignTypes); if (gainfo.Type == GainfoUserTypeEnumType.Outsource && (enableFactoryPermissions.FirstOrDefault(x => x.TenantId == gainfo.Factory)?.EnableOutsourceDown ?? true) == false) { internalIgnoreAssignTypes.Add(AssignTypeEnumType.Tenant); } var analyzePack = new AnalyzePackDto { UserNo = gainfo.No, UserDepartment = gainfo.Factory + ":" + gainfo.DepartmentNo, UserFactory = gainfo.Factory, UserGainfoGroupCodes = gainfoGroupRelationships.Where(x => x.UserNo == gainfo.No).Select(x => x.GroupCode), DeviceCodes = devices.WhereIf(gainfo.Type == GainfoUserTypeEnumType.Outsource, x => x.Type != DeviceTypeEnumType.Meal).Select(x => x.Code), //外包人员不允许餐饮 IgnoreAssignTypeTypes = internalIgnoreAssignTypes }; var codes = GetAssignDeviceCodesInternal(analyzePack, gainfoGroups, devicePermissions, deviceGroups, deviceRelationships, departments); result.TryAdd(gainfo.No, codes); }); return result.ToDictionary(x => x.Key, x => x.Value); } private static IEnumerable GetAssignDeviceCodesInternal( AnalyzePackDto analyzePack, List gainfoGroups, List devicePermissions, List deviceGroups, List deviceGroupRelationships, List departments) { var deviceDtos = new List(); var deviceGroupDtos = new List(); foreach (var assignType in new[] { AssignTypeEnumType.User, AssignTypeEnumType.Group, AssignTypeEnumType.Department, AssignTypeEnumType.Tenant }) { var assignValues = assignType switch { AssignTypeEnumType.User => new[] { analyzePack.UserNo }, AssignTypeEnumType.Group => analyzePack.UserGainfoGroupCodes.Select(x => x.ToString()).ToArray(), AssignTypeEnumType.Department => new[] { analyzePack.UserDepartment }, AssignTypeEnumType.Tenant => new[] { analyzePack.UserFactory }, AssignTypeEnumType.Role => throw new ArgumentOutOfRangeException(), _ => throw new ArgumentOutOfRangeException() }; if (analyzePack.IgnoreAssignTypeTypes.Contains(assignType)) { continue; } foreach (var assignValue in assignValues) { deviceDtos.AddRange(GetMyTypeDevicePermissionAsync(devicePermissions, gainfoGroups, deviceGroups, departments, DeviceAssignmentTypeEnumType.Device, assignType, assignValue)); deviceGroupDtos.AddRange(GetMyTypeDevicePermissionAsync(devicePermissions, gainfoGroups, deviceGroups, departments, DeviceAssignmentTypeEnumType.Group, assignType, assignValue)); } } //设备组转设备 deviceDtos.AddRange(deviceGroupDtos.Select(x => { var tenant = x.Tenant; var deviceGroupCodes = x.AssignTypes.SelectMany(item => item.Codes); var type = x.AssignTypes.ElementAt(0).AssignType; return new TenantAssignTypeDeviceCode { Tenant = tenant, AssignTypes = new[] { new AssignTypeDeviceCode { AssignType = type, Codes = deviceGroupRelationships.Where(item => deviceGroupCodes.Contains(item.GroupCode)).Select(item => item.DeviceCode) } } }; })); return deviceDtos.GroupBy(x => x.Tenant).Select(x => { var dto = new TenantAssignTypeDeviceCode { Tenant = x.Key, AssignTypes = x.SelectMany(p => p.AssignTypes) .GroupBy(p => p.AssignType) .Select(p => new AssignTypeDeviceCode { AssignType = p.Key, Codes = p.SelectMany(item => analyzePack.DeviceCodes.Where(it => item.Codes.Contains(it))) }) }; return dto; }); } private static List GetCurrentAssignTypePermissions( List devicePermissions, List gainfoGroups, List departments, DeviceAssignmentTypeEnumType uniqueType, AssignTypeEnumType assignType, string assignValue) { if (assignType == AssignTypeEnumType.Department) { // 2401:00001 //递归向上获取 assignValue = department.No var arr = assignValue.Split(":"); var tenantId = arr[0]; var currentDepartmentNo = arr[1]; var departmentNos = RecursionHelper.HandlerDepartmentPreviousCodes(currentDepartmentNo, departments).Select(x => tenantId + ":" + x).ToList(); return devicePermissions .Where(x => x.UniqueType == uniqueType) .Where(x => x.AssignType == assignType) .Where(x => departmentNos.Contains(x.AssignValue)) .GroupBy(x => x.TenantId) .Select(x => new UserTenantDeviceCodeDto { Tenant = x.Key, Codes = x.Select(p => p.UniqueValue) }) .ToList(); } if (assignType == AssignTypeEnumType.Group) { var gainfoGroupCodes = RecursionHelper.HandlerGainfoGroupPreviousCodes(Guid.Parse(assignValue), gainfoGroups).Select(x => x.ToString()); return devicePermissions .Where(x => x.UniqueType == uniqueType) .Where(x => x.AssignType == assignType) .Where(x => gainfoGroupCodes.Contains(x.AssignValue)) .GroupBy(x => x.TenantId) .Select(x => new UserTenantDeviceCodeDto { Tenant = x.Key, Codes = x.Select(p => p.UniqueValue) }) .ToList(); } //user / tenant return devicePermissions .Where(x => x.UniqueType == uniqueType && x.AssignType == assignType && x.AssignValue == assignValue) .GroupBy(x => x.TenantId) .Select(x => new UserTenantDeviceCodeDto { Tenant = x.Key, Codes = x.Select(p => p.UniqueValue) }) .ToList(); } private static IEnumerable GetMyTypeDevicePermissionAsync( List devicePermissions, List gainfoGroups, List deviceGroups, List departments, DeviceAssignmentTypeEnumType uniqueType, AssignTypeEnumType assignType, string assignValue) { var tenantDevicePermissions = GetCurrentAssignTypePermissions(devicePermissions, gainfoGroups, departments, uniqueType, assignType, assignValue); //处理获取设备分组的情况,递归向下查询子分组 if (uniqueType == DeviceAssignmentTypeEnumType.Group) { foreach (var tenantDevicePermission in tenantDevicePermissions) { var deviceGroupCodes = tenantDevicePermission.Codes; var r = tenantDevicePermission.Codes.ToList(); foreach (var deviceGroupCode in deviceGroupCodes) { r.AddRange(RecursionHelper.HandlerDeviceGroupNextCodes(deviceGroupCode, deviceGroups)); } tenantDevicePermission.Codes = r.Distinct().ToList(); } } return tenantDevicePermissions.GroupBy(x => x.Tenant).Select(x => { var tenant = x.Key; return new TenantAssignTypeDeviceCode { Tenant = tenant, AssignTypes = new[] { new AssignTypeDeviceCode { AssignType = assignType, Codes = x.SelectMany(item => item.Codes) } } }; }); } private async Task ChunkInsertAsync(List batch) where T : class, new() { foreach (var tasks in batch.Chunk(500)) { await _dbContext.InsertAsync(tasks.ToList()); } } public async Task>> GetUserAssignDeviceCodesInTenantAsync(List userNos, params AssignTypeEnumType[] ignoreAssignTypes) { var result = await GetUserAssignDeviceCodesWithTypeInTenantAsync(userNos, ignoreAssignTypes); return result.ToDictionary(x => x.Key, x => x.Value.GroupBy(p => p.Tenant).Select(item => { return new UserTenantDeviceCodeDto { Tenant = item.Key, Codes = item.SelectMany(p => p.AssignTypes).SelectMany(p => p.Codes).Distinct().ToList(), }; })); } public async Task> GetAssignmentsAsync(DeviceGetAssignmentsRequest request) { var currentAssignValue = request.AssignType == AssignTypeEnumType.Department ? request.TenantId + ":" + request.AssignValue : request.AssignValue; (bool enableFilter, List deviceCodes) = _myDataPermissionService.GetMyDeviceCodes(); return await _dbContext.Queryable() .Where(x => x.AssignType == request.AssignType) .Where(x => x.AssignValue == currentAssignValue) .Where(x => x.UniqueType == request.UniqueType) .WhereIF(enableFilter && request.UniqueType == DeviceAssignmentTypeEnumType.Device, x => deviceCodes.Contains(x.UniqueValue)) .Where(x => x.Type == request.Type) .Select(x => x.UniqueValue) .ToListAsync(); } 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(); } public async Task> GetAssignDeviceCodesAsync(string userCode) { var userNo = await _dbContext.Queryable().Where(x => x.Code == userCode || x.No == userCode).Select(x => x.No).SingleAsync(); var result = await GetUserAssignDeviceCodesInTenantAsync(new List { userNo }); return result.First().Value.SelectMany(x => x.Codes).ToList(); } }