using Dlhis.Basic.Device.Dtos; using Dlhis.Basic.Device.Request; using Dlhis.Basic.Organization.Dto; using Dlhis.Entity.Basic.Entity; 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.Dto; using Kurisu.AspNetCore.DataAccess.Entity; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.Utils.Extensions; using SqlSugar; namespace Dlhis.Basic.Device.Services.Implements; public class DevicePermissionService : IDevicePermissionService { private readonly IDbContext _dbContext; private readonly ICurrentUser _currentUser; private readonly ILogger _logger; public DevicePermissionService(IDbContext dbContext, ICurrentUser currentUser, ILogger logger) { _dbContext = dbContext; _currentUser = currentUser; _logger = logger; } public async Task AssignAsync(DevicePermissionSaveRequest request) { throw new Exception("系统维护中,暂不可操作"); var tenantId = request.AssignType == AssignTypeEnumType.Department ? request.TenantId : _currentUser.GetStringTenantId(); await GenerateDeviceTasksAsync(async () => { //删除当前匹配的基地权限 var p = await _dbContext.Queryable() .Where(x => x.AssignType == request.AssignType) .Where(x => x.AssignValue == request.AssignValue) .Where(x => x.UniqueType == request.UniqueType) .Where(x => x.TenantId == tenantId) .ToListAsync(); await _dbContext.DeleteReallyAsync(p); //保存配置的权限 if (request.Codes.IsPresent()) { var devicePermissions = request.Codes.Select(code => new DevicePermissionEntity { AssignType = request.AssignType, AssignValue = request.AssignValue, UniqueType = request.UniqueType, UniqueValue = code, TenantId = tenantId }).ToList(); await _dbContext.InsertAsync(devicePermissions); } }, null); } public async Task AssignToUniqueAsync(DevicePermissionsAssignToDeviceRequest request) { var tenantId = request.AssignType == AssignTypeEnumType.Department ? request.TenantId : _currentUser.GetStringTenantId(); await GenerateDeviceTasksAsync(async () => { //删除当前匹配的基地权限 var p = await _dbContext.Queryable() .Where(x => x.UniqueType == request.UniqueType) .Where(x => x.UniqueValue == request.UniqueValue) .Where(x => x.AssignType == request.AssignType) .Where(x => request.Values.Contains(x.AssignValue)) .Where(x => x.TenantId == tenantId) .ToListAsync(); await _dbContext.DeleteReallyAsync(p); if (!request.IsDelete) { //保存配置的权限 if (request.Values.IsPresent()) { var devicePermissions = request.Values.Select(v => new DevicePermissionEntity { AssignType = request.AssignType, AssignValue = v, UniqueType = request.UniqueType, UniqueValue = request.UniqueValue, TenantId = tenantId }).ToList(); await _dbContext.InsertAsync(devicePermissions); } } }, null); } public async Task GeneratePermissionsAsync(long id) { var assignment = await _dbContext.Queryable().SingleAsync(x => x.Id == id); if (assignment == null) return; if (assignment.IsHandler) return; try { var request = assignment.Assignment.ToObject(); await GenerateDeviceTasksAsync(async () => { //删除当前匹配的基地权限 var p = await _dbContext.Queryable() .Where(x => x.AssignType == request.AssignType) .Where(x => x.AssignValue == request.AssignValue) .Where(x => x.UniqueType == request.UniqueType) .Where(x => x.TenantId == request.TenantId) .ToListAsync(); await _dbContext.DeleteReallyAsync(p); //保存配置的权限 if (request.Codes.IsPresent()) { var devicePermissions = request.Codes.Select(code => new DevicePermissionEntity { AssignType = request.AssignType, AssignValue = request.AssignValue, UniqueType = request.UniqueType, UniqueValue = code, TenantId = request.TenantId }).ToList(); await _dbContext.InsertAsync(devicePermissions); } }, null); } finally { assignment.IsHandler = true; await _dbContext.UpdateAsync(assignment); } } public async Task> GetAssignmentsAsync(DeviceAssignmentTypeEnumType uniqueType, AssignTypeEnumType assignType, string assignValue) { var devicePermissions = await _dbContext.Queryable().ToListAsync(); var deviceGroups = await _dbContext.Queryable().ToListAsync(); var result = GetAssignCodesInternal(devicePermissions, deviceGroups, uniqueType, assignType, assignValue); return result.FirstOrDefault(x => x.Tenant == _currentUser.GetStringTenantId())?.Codes; } public async Task GenerateDeviceTasksAsync(Func func, List userNos) { //获取所有人的权限 if (userNos.IsEmpty()) userNos = await GetPermissionUserNosAsync(); var before = await GetAssignDeviceCodesInternalAsync(userNos); _logger.LogInformation("任务前置人数{count}", userNos.Count); //业务处理 _dbContext.Client.QueryFilter.Restore(); await func(); _dbContext.Client.QueryFilter.ClearAndBackup(); //获取业务处理后所有人的权限 var nextUserNos = await GetPermissionUserNosAsync(); if (nextUserNos.Any()) userNos = userNos.Concat(nextUserNos).Distinct().ToList(); var current = await GetAssignDeviceCodesInternalAsync(userNos); _logger.LogInformation("任务后置人数{count}", userNos.Count); var devices = await _dbContext.Queryable().Where(x => x.Enable).ToListAsync(); var waitTasks = new List(); foreach (var userNo in userNos) { before.TryGetValue(userNo, out var beforeTenantDeviceCodes); beforeTenantDeviceCodes ??= new(); current.TryGetValue(userNo, out var currentTenantDeviceCodes); currentTenantDeviceCodes ??= new(); 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 ?? new(); var beforeCodes = beforeTenantDeviceCodes.FirstOrDefault(x => x.Tenant == tenant)?.Codes ?? new(); //被删除 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(); //下发任务创建 var toDeleted = deletedItems.Select(x => 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, }).ToList(); var toAdd = addItems.Select(x => 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, }).ToList(); waitTasks.AddRange(toDeleted.Concat(toAdd).ToList()); } } _logger.LogInformation("任务产生数量{count}", waitTasks.Count); if (waitTasks.Any()) { await _dbContext.InsertAsync(waitTasks); } } public async Task GetPermissionUsersInfoAsync(List userNos) { if (userNos.IsEmpty()) userNos = await GetPermissionUserNosAsync(); var permissions = await GetAssignDeviceCodesInternalAsync(userNos); return new PermissionUsersInfoDto { UserNos = userNos, PermissionInfos = permissions }; } public async Task ReGeneratePermissionUsersInfoAsync(PermissionUsersInfoDto beforeDto) { var userNos = beforeDto.UserNos; var before = beforeDto.PermissionInfos.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase); var current = await GetAssignDeviceCodesInternalAsync(userNos); var deivces = await _dbContext.Queryable().Where(x => x.Enable).ToListAsync(); var waitTasks = new List(); foreach (var userNo in userNos) { before.TryGetValue(userNo, out var beforeTenantDeviceCodes); beforeTenantDeviceCodes ??= new(); current.TryGetValue(userNo, out var currentTenantDeviceCodes); currentTenantDeviceCodes ??= new(); var tenants = beforeTenantDeviceCodes.Select(x => x.Tenant).Concat(currentTenantDeviceCodes.Select(x => x.Tenant)).Distinct().ToList(); foreach (var tenant in tenants) { var currentCodes = currentTenantDeviceCodes.FirstOrDefault(x => x.Tenant == tenant)?.Codes ?? new(); var beforeCodes = beforeTenantDeviceCodes.FirstOrDefault(x => x.Tenant == tenant)?.Codes ?? new(); //被删除 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 = deivces.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(); //下发任务创建 var toDeleted = deletedItems.Select(x => new DeviceTaskEntity { DeviceUniqueNo = deivces.First(item => item.Code == x).UniqueNo, Status = DeviceTaskStatusEnumType.Wait, Type = DeviceTaskEnumType.Delete, DeviceType = deivces.First(item => item.Code == x).Type, UserNo = userNo, Version = 0, TenantId = tenant, }).ToList(); var toAdd = addItems.Select(x => new DeviceTaskEntity { DeviceUniqueNo = deivces.First(item => item.Code == x).UniqueNo, Status = DeviceTaskStatusEnumType.Wait, Type = DeviceTaskEnumType.Add, DeviceType = deivces.First(item => item.Code == x).Type, UserNo = userNo, Version = 0, TenantId = tenant, }).ToList(); waitTasks.AddRange(toDeleted.Concat(toAdd).ToList()); } } if (waitTasks.Any()) { await _dbContext.InsertAsync(waitTasks); } return waitTasks.Count; } public async Task> GetGainfoPageByDeviceAsync(DeviceWithGainfoRequest request) { var device = await _dbContext.Queryable().Where(x => x.UniqueNo == request.DeviceUniqueNo).SingleAsync(); //当前设备的分组 var groups = await _dbContext.Queryable() .Where(x => x.DeviceCode == device.Code) .Select(x => x.GroupCode) .ToListAsync(); var permissions = await _dbContext.Queryable() .Where(x => (x.UniqueType == DeviceAssignmentTypeEnumType.Device && x.UniqueValue == device.Code) || (x.UniqueType == DeviceAssignmentTypeEnumType.Group && groups.Contains(x.UniqueValue))) .ToListAsync(); var ids = new List(); foreach (var permission in permissions) { switch (permission.AssignType) { case AssignTypeEnumType.User: ids.Add(await _dbContext.Queryable().Where(x => x.No == permission.AssignValue).Select(x => x.Id).SingleAsync()); break; case AssignTypeEnumType.Group: { var code = Guid.Parse(permission.AssignValue); ids.AddRange(await _dbContext.Queryable().Where(x => x.Code == code) .LeftJoin((a, b) => a.Code == b.GroupCode) .LeftJoin((a, b, c) => b.UserNo == c.No) .Select((a, b, c) => c.Id).ToListAsync()); } break; case AssignTypeEnumType.Department: { ids.AddRange(await _dbContext.Queryable().Where(x => x.DepartmentNo == permission.AssignValue).Select(x => x.Id).ToListAsync()); } break; case AssignTypeEnumType.Tenant: { ids.AddRange(await _dbContext.Queryable().Where(x => x.Factory == permission.AssignValue).Select(x => x.Id).ToListAsync()); } break; default: throw new ArgumentOutOfRangeException(); } } return await _dbContext.Queryable() .Where(x => ids.Contains(x.Id)) .WhereIF(request.Search.IsPresent(), x => x.Code == request.Search || x.Name.Contains(request.Search)) .Select() .ToPageListAsync(request); } public async Task GenerateDeviceTasksAsync(string userNo, DeviceTaskEnumType taskType) { var deviceCodes = await GetAssignDeviceCodesAsync(userNo); if (!deviceCodes.Any()) { return; } var deivces = await _dbContext.Queryable() .Where(x => x.Enable) .Where(x => deviceCodes.Contains(x.Code)) .ToListAsync(); var tasks = deivces.Select(x => new DeviceTaskEntity { DeviceUniqueNo = x.UniqueNo, Status = DeviceTaskStatusEnumType.Wait, Type = taskType, DeviceType = x.Type, UserNo = userNo, CancellationId = 0, Version = 0, TenantId = x.TenantId }).ToList(); await _dbContext.InsertAsync(tasks); } public async Task> GetCanteenDeviceUniqueNosByUserNoAsync(string userNo) { var all = await GetAssignDeviceCodesAsync(userNo); return await _dbContext.Queryable() .Where(x => x.Enable) .Where(x => x.Type == DeviceTypeEnumType.Meal) .Where(x => all.Contains(x.Code)) .Select(x => x.UniqueNo) .ToListAsync(); } /// /// 获取用户所有设备权限 /// /// /// public async Task> GetAssignDeviceCodesAsync(string userNo) { var devices = await _dbContext.Queryable().Where(x => x.Enable).ToListAsync(); var deviceRegistries = await _dbContext.Queryable().Where(x => !SqlFunc.IsNullOrEmpty(x.BusinessPlaceCode)).ToListAsync(); var gainfo = await _dbContext.Queryable().Where(x => x.No == userNo).SingleAsync() ?? await _dbContext.Queryable().AS("GainfoLeave").Where(x => x.No == userNo).SingleAsync(); var gainfoGroups = await _dbContext.Queryable().ToListAsync(); var devicePermissions = await _dbContext.Queryable().ToListAsync(); var deviceGroups = await _dbContext.Queryable().ToListAsync(); var deviceRelationships = await _dbContext.Queryable().ToListAsync(); var result = GetAssignDeviceCodesInternal(gainfo, gainfoGroups, devicePermissions, deviceGroups, deviceRelationships, deviceRegistries, devices); return result.SelectMany(x => x.Codes).ToList(); } //************************************************ help methods ******************************************************* /// /// 获取当前基地有权限的用户 /// /// private async Task> GetPermissionUserNosAsync() { var permissions = await _dbContext.Queryable().ToListAsync(); //User var userNos = permissions.Where(x => x.AssignType == AssignTypeEnumType.User).Select(x => x.AssignValue).ToList(); //Group var groupCode = permissions.Where(x => x.AssignType == AssignTypeEnumType.Group).Select(x => Guid.Parse(x.AssignValue)).ToList(); var userNosByGroup = await _dbContext.Queryable() .Where(x => groupCode.Contains(x.GroupCode)) .Select(x => x.UserNo) .ToListAsync(); //Department var departmentNos = permissions.Where(x => x.AssignType == AssignTypeEnumType.Department).Select(x => x.AssignValue).ToList(); var userNosByDepartment = await _dbContext.Queryable().Where(x => departmentNos.Contains(x.DepartmentNo)).Select(x => x.No).ToListAsync(); //Tenant var tenants = permissions.Where(x => x.AssignType == AssignTypeEnumType.Tenant).Select(x => x.AssignValue).Distinct().ToList(); var userNosByWerk = await _dbContext.Queryable().Where(x => tenants.Contains(x.Factory)).Select(x => x.No).ToListAsync(); return userNos.Concat(userNosByGroup).Concat(userNosByDepartment).Concat(userNosByWerk).Distinct().ToList(); } private static List GetAssignCodesInternal( List devicePermissions, List deviceGroups, DeviceAssignmentTypeEnumType uniqueType, AssignTypeEnumType assignType, string assignValue) { var tenantDevicePermissions = devicePermissions .Where(x => x.UniqueType == uniqueType) .Where(x => x.AssignType == assignType) .Where(x => x.AssignValue == assignValue) .GroupBy(x => x.TenantId) .Select(x => new UserTenantDeviceCodeDto { Tenant = x.Key, Codes = x.Select(p => p.UniqueValue).ToList() }) .ToList(); //处理获取设备分组的情况 if (uniqueType == DeviceAssignmentTypeEnumType.Group) { //开始递归处理 var tops = deviceGroups.Where(x => !x.PCode.HasValue).ToList(); tops.ForEach(x => { RecursionGetNext(x, deviceGroups, tenantDevicePermissions, tenantDevicePermissions.SelectMany(item => item.Codes).Contains(x.Code)); }); } return tenantDevicePermissions.GroupBy(x => x.Tenant).Select(x => { var tenant = x.Key; return new UserTenantDeviceCodeDto { Tenant = tenant, Codes = x.SelectMany(item => item.Codes).ToList() }; }).ToList(); void RecursionGetNext(DeviceGroupEntity current, List deviceGroups, List result, bool add) { var next = deviceGroups.Where(x => x.PCode == current.Code).ToList(); foreach (var item in next) { if (add) { result.Add(new UserTenantDeviceCodeDto { Tenant = item.TenantId, Codes = new List { item.Code } }); } RecursionGetNext(item, deviceGroups, result, result.SelectMany(x => x.Codes).Contains(item.Code)); } } } private async Task>> GetAssignDeviceCodesInternalAsync(List userNos) { var devices = await _dbContext.Queryable().Where(x => x.Enable).ToListAsync(); var deviceUniqueNos = devices.Select(x => x.UniqueNo).ToList(); var registries = await _dbContext.Queryable() .Where(x => deviceUniqueNos.Contains(x.DeviceUniqueNo)) .Where(x => !SqlFunc.IsNullOrEmpty(x.BusinessPlaceCode)) .ToListAsync(); var gainfos = await _dbContext.Queryable().Where(x => userNos.Contains(x.No)).ToListAsync(); if (!gainfos.Any()) { return new Dictionary>(); } var gainfoGroupRelationships = await _dbContext.Queryable().Where(x => userNos.Contains(x.UserNo)).ToListAsync(); var devicePermissions = await _dbContext.Queryable().ToListAsync(); var deviceGroups = await _dbContext.Queryable().ToListAsync(); var deviceRelationships = await _dbContext.Queryable().ToListAsync(); var result = new Dictionary>(gainfos.Count, StringComparer.OrdinalIgnoreCase); foreach (var gainfo in gainfos) { var codes = GetAssignDeviceCodesInternal(gainfo, gainfoGroupRelationships, devicePermissions, deviceGroups, deviceRelationships, registries, devices); result.Add(gainfo.No, codes); } return result; } private static List GetAssignDeviceCodesInternal( GainfoEntity gainfo, List gainfoGroupRelationships, List devicePermissions, List deviceGroups, List deviceGroupRelationships, List deviceRegistries, List devices ) { var userNo = gainfo.No; var deviceDtos = new List(); var deviceGroupDtos = new List(); var businessPlaceDtos = new List(); //获取人员的分组,跨基地 var gainfoGroups = gainfoGroupRelationships.Where(x => x.UserNo == userNo).Select(x => x.GroupCode).ToList(); //按用户 var du = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.User, userNo); var gu = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.User, userNo); var pu = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.BusinessPlace, AssignTypeEnumType.User, userNo); deviceDtos.AddRange(du); deviceGroupDtos.AddRange(gu); businessPlaceDtos.AddRange(pu); //按用户组 foreach (var groupCode in gainfoGroups) { var dg = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.Group, groupCode.ToString()); var gg = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.Group, groupCode.ToString()); var pg = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.BusinessPlace, AssignTypeEnumType.Group, groupCode.ToString()); deviceDtos.AddRange(dg); deviceGroupDtos.AddRange(gg); businessPlaceDtos.AddRange(pg); } //按部门 var gainfoFactoryDevicePermissions = devicePermissions.Where(x => x.TenantId == gainfo.Factory).ToList(); var dd = GetAssignCodesInternal(gainfoFactoryDevicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.Department, gainfo.DepartmentNo); var gd = GetAssignCodesInternal(gainfoFactoryDevicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.Department, gainfo.DepartmentNo); var pd = GetAssignCodesInternal(gainfoFactoryDevicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.BusinessPlace, AssignTypeEnumType.Department, gainfo.DepartmentNo); deviceDtos.AddRange(dd); deviceGroupDtos.AddRange(gd); businessPlaceDtos.AddRange(pd); //按厂区 var dt = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Device, AssignTypeEnumType.Tenant, gainfo.Factory); var gt = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.Group, AssignTypeEnumType.Tenant, gainfo.Factory); var pt = GetAssignCodesInternal(devicePermissions, deviceGroups, DeviceAssignmentTypeEnumType.BusinessPlace, AssignTypeEnumType.Tenant, gainfo.Factory); deviceDtos.AddRange(dt); deviceGroupDtos.AddRange(gt); businessPlaceDtos.AddRange(pt); var deviceGroupCodes = deviceGroupDtos.SelectMany(x => x.Codes).Distinct().ToList(); var businessPlaceCodes = businessPlaceDtos.SelectMany(x => x.Codes).Distinct().ToList(); var deviceCodesByGroup = deviceGroupRelationships.Where(x => deviceGroupCodes.Contains(x.GroupCode)).GroupBy(x => x.TenantId) .Select(x => new UserTenantDeviceCodeDto { Tenant = x.Key, Codes = x.Select(item => item.DeviceCode).Distinct().ToList() }); var placeGroup = deviceRegistries.Where(x => businessPlaceCodes.Contains(x.BusinessPlaceCode!.Value)) .GroupBy(x => x.TenantId) .Select(x => { var currentDeviceUniqueNos = x.Select(item => item.DeviceUniqueNo).ToList(); return new UserTenantDeviceCodeDto { Tenant = x.Key, Codes = devices.Where(d => currentDeviceUniqueNos.Contains(d.UniqueNo)).Select(d => d.Code).Distinct().ToList() }; }).ToList(); deviceDtos.AddRange(deviceCodesByGroup); deviceDtos.AddRange(placeGroup); return deviceDtos.GroupBy(x => x.Tenant).Select(x => new UserTenantDeviceCodeDto { Tenant = x.Key, Codes = x.SelectMany(item => item.Codes).Distinct().ToList() }).ToList(); } }