using Dlhis.Basic.Device.Dtos; using Dlhis.Basic.Device.Request; using Dlhis.Basic.Device.Response; using Dlhis.Basic.Organization.Dto; using Dlhis.Basic.Organization.Services; using Dlhis.Basic.Utils; 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 Dlhis.Entity.Visitor.Entity; using Dlhis.Entity.Visitor.Enums; using Dlhis.Sys.Api; using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.DataAccess.Dto; 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 ITenantApi _tenantApi; private readonly INamedResolver _namedResolver; private readonly IFactorySettingService _factorySettingService; private readonly IDevicePermissionAnalyzeService _devicePermissionAnalyzeService; private readonly ICurrentUser _currentUser; public DevicePermissionService(IDbContext dbContext, ITenantApi tenantApi, INamedResolver namedResolver, IFactorySettingService factorySettingService, IDevicePermissionAnalyzeService devicePermissionAnalyzeService, ICurrentUser currentUser) { _dbContext = dbContext; _tenantApi = tenantApi; _namedResolver = namedResolver; _factorySettingService = factorySettingService; _devicePermissionAnalyzeService = devicePermissionAnalyzeService; _currentUser = currentUser; } public async Task AssignAsync(DevicePermissionSaveRequest request) { return await _namedResolver .GetService(PermissionAnalyzeConstants.GetTypeName(request.AssignType)) .AnalyzeAsync(request); } public async Task AssignToUniqueAsync(DevicePermissionsAssignToDeviceRequest request) { var currentTenantId = _currentUser.GetStringTenantId(); var device = await _dbContext.Queryable().Where(x => x.Code == request.UniqueValue).SingleAsync(); device.ThrowIfNull("设备不存在"); var deviceGroupCodes = await _dbContext.Queryable().Where(x => x.DeviceCode == device.Code).Select(x => x.GroupCode).ToListAsync(); var existsTenantAssigned = await _dbContext.Queryable() .Where(x => (x.UniqueType == DeviceAssignmentTypeEnumType.Device && x.UniqueValue == request.UniqueValue) || (x.UniqueType == DeviceAssignmentTypeEnumType.Group && deviceGroupCodes.Contains(x.UniqueValue))) .Where(x => x.AssignType == AssignTypeEnumType.Tenant) .AnyAsync(); existsTenantAssigned.ThrowIfTrue("当前设备或者所在分组已分配到厂区,无法操作"); //当前匹配的基地权限 var dps = await _dbContext.Queryable() .Where(x => x.UniqueType == DeviceAssignmentTypeEnumType.Device) .Where(x => x.UniqueValue == request.UniqueValue) .Where(x => x.AssignType == AssignTypeEnumType.User) .Where(x => x.Type == device.Type) .Where(x => x.TenantId == currentTenantId) .ToListAsync(); var beforeUserNos = dps.Select(x => x.AssignValue).Distinct().ToList(); var presentUserNos = new List(); if (request.Values.IsPresent()) { var today = DateTime.Today; var factories = _currentUser.GetUserClaim("tenants").Split(",").ToList(); presentUserNos = await _dbContext.Client.Queryable() .Where(gainfo => factories.Contains(gainfo.Factory) || SqlFunc.Subqueryable() .Where(x => factories.Contains(x.Destination) && SqlFunc.DateIsSame(x.BeginDate, today)) .Any() ) .Where(gainfo => request.Values.Contains(gainfo.Code) || request.Values.Contains(gainfo.No) || request.Values.Contains(gainfo.IdNo)) .Select(gainfo => gainfo.No) .ToListAsync(); } var tasksToAdd = new List(); var tasksToDelete = new List(); try { var usersToAdd = presentUserNos.Except(beforeUserNos); var usersToDelete = beforeUserNos.Except(presentUserNos).ToList(); var userTenantDeviceCodes = usersToDelete.IsPresent() ? await _devicePermissionAnalyzeService.GetUserAssignDeviceCodesWithTypeInTenantAsync(beforeUserNos.Concat(presentUserNos).Distinct().ToList()) : new Dictionary>(); tasksToAdd.AddRange(usersToAdd.Select(userNo => new DeviceTaskEntity { Type = DeviceTaskEnumType.Add, DeviceType = device.Type, UserId = null, UserNo = userNo, DeviceUniqueNo = device.UniqueNo, Status = DeviceTaskStatusEnumType.Wait, Version = 0, ResultMessage = null, Source = "人员分配到设备unique", Priority = 0, TenantId = currentTenantId, })); foreach (var userNo in usersToDelete) { if (userTenantDeviceCodes.TryGetValue(userNo, out var permissions)) { foreach (var permission in permissions) { permission.AssignTypes.RemoveAll(x => x.UniqueType == DeviceAssignmentTypeEnumType.Device && x.AssignType == AssignTypeEnumType.User); } var myDeviceCodes = permissions.SelectMany(x => x.AssignTypes.SelectMany(p => p.Codes)).Distinct().ToList(); if (myDeviceCodes.All(x => x != device.Code)) { tasksToDelete.Add(new DeviceTaskEntity { Type = DeviceTaskEnumType.Delete, DeviceType = device.Type, UserId = null, UserNo = userNo, DeviceUniqueNo = device.UniqueNo, Status = DeviceTaskStatusEnumType.Wait, Version = 0, ResultMessage = null, Source = "人员分配到设备unique", Priority = 0, TenantId = currentTenantId }); } } } } finally { await _dbContext.InsertAsync(tasksToAdd); await _dbContext.InsertAsync(tasksToDelete); await _dbContext.DeleteAsync(dps); await _dbContext.InsertAsync(presentUserNos.Select(v => new DevicePermissionEntity { UniqueType = DeviceAssignmentTypeEnumType.Device, UniqueValue = request.UniqueValue, AssignType = AssignTypeEnumType.User, AssignValue = v, TenantId = currentTenantId, Type = device.Type }).ToList()); } return new DevicePermissionAssignResponse(tasksToAdd.Count, tasksToDelete.Count); } // /// // public async Task AssignToUniqueImportAsync(IFormFile file) // { // var deviceNo = Path.GetFileNameWithoutExtension(file.FileName); // // var device = await _dbContext.Queryable().Where(x => x.UniqueNo == deviceNo).SingleAsync(); // device.ThrowIfNull("设备不存在"); // // ExcelPackage.LicenseContext = LicenseContext.NonCommercial; // using (var package = new ExcelPackage(file.OpenReadStream())) // { // ExcelWorksheet worksheet = package.Workbook.Worksheets[0]; // int rowCount = worksheet.Dimension.Rows; // 获取行数 // int colCount = worksheet.Dimension.Columns; // 获取列数 // // var list = new List(); // for (int i = 1; i < rowCount; i++) // { // var userCode = worksheet.Cells[i + 1, 2].GetCellValue(); // list.Add(userCode); // } // // foreach (var items in list.Chunk(500)) // { // var gainfoNos = await _dbContext.Queryable().Where(x => items.Contains(x.Code)).Select(x => x.No).ToListAsync(); // // var permissions = gainfoNos.Select(x => new DevicePermissionEntity // { // AssignType = AssignTypeEnumType.User, // AssignValue = x, // UniqueType = DeviceAssignmentTypeEnumType.Device, // UniqueValue = device.Code, // Type = device.Type, // TenantId = device.TenantId, // IsDeleted = false // }).ToList(); // // await _dbContext.InsertAsync(permissions); // // var tasks = permissions.Select(x => new DeviceTaskEntity // { // Type = DeviceTaskEnumType.Add, // DeviceType = x.Type, // UserId = null, // UserNo = x.AssignValue, // DeviceUniqueNo = device.UniqueNo, // Status = DeviceTaskStatusEnumType.Wait, // Version = 0, // ResultMessage = null, // Source = "人员分配到设备import", // Priority = 0, // TenantId = device.TenantId, // }).ToList(); // // await _dbContext.InsertAsync(tasks); // } // } // } public async Task> GetGainfoPageByDeviceAsync(DeviceWithGainfoRequest request) { var query = await GetDeviceUsersQueryAsync(request.DeviceUniqueNo, request.Search, request.UserType); var page = await query.ToPageListAsync(request); var userNos = page.Data.Select(x => x.No).ToList(); var downStatus = await _dbContext.Queryable() .Where(x => userNos.Contains(x.UserNo)) .Where(x => x.DeviceUniqueNo == request.DeviceUniqueNo) .Where(x => x.Status == DeviceTaskStatusEnumType.Success) .Select(x => new { num = SqlFunc.RowNumber(SqlFunc.Desc(x.ModifiedTime), x.UserNo), x.UserNo, x.Status, x.ResultMessage, x.ModifiedTime }).MergeTable() .Where(x => x.num == 1) .ToListAsync(); var tenants = await _tenantApi.GetTenantsInternalAsync(); page.Data.ForEach(x => { x.Workplace = tenants.FirstOrDefault(item => item.Code == x.Workplace)?.Name; x.Factory = tenants.FirstOrDefault(item => item.Code == x.Factory)?.Name; var d = downStatus.FirstOrDefault(item => item.UserNo == x.No); if (d == null) { return; } x.Status = d.Status; x.ResultMessage = d.ResultMessage; x.ModifiedTime = d.ModifiedTime; }); return page; } /// public async Task ResetGainfoPageByDeviceAsync(Guid code, string search, GainfoUserTypeEnumType? userType) { var device = await _dbContext.Queryable().Where(x => x.Code == code).SingleAsync(); device.ThrowIfNull("设备不存在"); var query = await GetDeviceUsersQueryAsync(device.UniqueNo, string.Empty, userType); var all = await query.ToListAsync(); var gainfoNos = all.Select(x => x.No).Distinct().ToList(); await _dbContext.InsertAsync(gainfoNos.Select(x => new DeviceTaskEntity { DeviceUniqueNo = device.UniqueNo, Status = DeviceTaskStatusEnumType.Wait, Type = DeviceTaskEnumType.Add, DeviceType = device.Type, UserNo = x, Version = 0, TenantId = device.TenantId, Source = "重新生成设备下的人员" }).ToList()); } public async Task GenerateDeviceTasksAsync(string userNo, DeviceTaskEnumType taskType, string source) { var deviceCodes = await GetUserDeviceCodesByNoAsync(userNo); if (deviceCodes.IsEmpty()) return; var devices = await _dbContext.Queryable() .Where(x => x.Enable) .Where(x => deviceCodes.Contains(x.Code)) .ToListAsync(); await _dbContext.InsertAsync(devices.Select(x => new DeviceTaskEntity { DeviceUniqueNo = x.UniqueNo, Status = DeviceTaskStatusEnumType.Wait, Type = taskType, DeviceType = x.Type, UserNo = userNo, Priority = 0, Version = 0, TenantId = x.TenantId, Source = source }).ToList()); } /// /// 获取用户所有设备权限 /// /// /// public async Task> GetUserDeviceCodesByNoAsync(string userNo) { var no = await _dbContext.Queryable().Where(x => x.No == userNo || x.Code == userNo).Select(x => x.No).SingleAsync(); var result = await _devicePermissionAnalyzeService.GetUserAssignDeviceCodesWithTypeInTenantAsync(new List { no }); var deviceCodes = result.First().Value.SelectMany(x => x.AssignTypes.SelectMany(p => p.Codes)).Distinct().ToList(); //例外处理: 特殊手动分配的设备权限 var manuallyDeviceCodes = await _dbContext.Queryable().Where(x => x.UserNo == no) .Select(x => x.DeviceCode) .ToListAsync(); return deviceCodes.Concat(manuallyDeviceCodes).Distinct().ToList(); } public async Task ResetVisitorsByDeviceAsync(string deviceUniqueNo) { var device = await _dbContext.Queryable().SingleAsync(x => x.UniqueNo == deviceUniqueNo); device.ThrowIfNull("设备不存在"); var userNos = await GetDeviceUserNosFromVisitorAsync(device.Code); var deviceTaskEntities = userNos.Select(x => new DeviceTaskEntity { Type = DeviceTaskEnumType.Add, DeviceType = device.Type, UserId = null, UserNo = x, DeviceUniqueNo = device.UniqueNo, Status = DeviceTaskStatusEnumType.Wait, Version = 0, ResultMessage = null, Source = "手动下发设备中的访客人员", Priority = 0, TenantId = device.TenantId }).ToList(); return await _dbContext.InsertAsync(deviceTaskEntities); } //********************************************************************help methods******************************************************************************************** /// /// 获取设备下的人员 /// /// /// /// /// /// private async Task> GetDeviceUsersQueryAsync(string deviceUniqueNo, string search, GainfoUserTypeEnumType? userType) { var device = await _dbContext.Queryable().SingleAsync(x => x.UniqueNo == deviceUniqueNo); device.ThrowIfNull("设备不存在"); var ids = await GetDeviceUserIdsAsync(deviceUniqueNo); var factorySetting = await _factorySettingService.GetFactorySettingAsync(device.TenantId, false); var userTypes = new List(); if (userType.HasValue) { if (userType == GainfoUserTypeEnumType.Normal) { userTypes.Add(GainfoUserTypeEnumType.Normal); userTypes.Add(GainfoUserTypeEnumType.SecurityWhite); } else { userTypes.Add(userType.Value); } } var query = _dbContext.Queryable() .Where(x => ids.Contains(x.Id)) .WhereIF(userTypes.Any(), x => userTypes.Contains(x.Type)) .Where(x => x.Type != GainfoUserTypeEnumType.External) .WhereIF(factorySetting.EnableOutsourceDown == false, x => x.Type != GainfoUserTypeEnumType.Outsource) .WhereIF(device.Type == DeviceTypeEnumType.Meal, x => x.Type != GainfoUserTypeEnumType.External && x.Type != GainfoUserTypeEnumType.Outsource) .WhereIF(search.IsPresent(), x => x.Code == search || x.Name.Contains(search)) .Select(); return query; } private async Task> GetDeviceUserIdsAsync(string deviceUniqueNo) { var device = await _dbContext.Queryable().SingleAsync(x => x.UniqueNo == deviceUniqueNo); device.ThrowIfNull("设备不存在"); var departments = await _dbContext.Queryable().Select().ToListAsync(); //当前设备的分组 var groups = await _dbContext.Queryable() .Where(x => x.DeviceCode == device.Code) .Where(x => x.IsDeleted == false) .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))) .Where(x => x.IsDeleted == false) .ToListAsync(); var ids = new List(); foreach (var permissionGroup in permissions.GroupBy(x => x.AssignType)) { var assignType = permissionGroup.Key; var assignValues = permissionGroup.Select(x => x.AssignValue).ToList(); switch (assignType) { case AssignTypeEnumType.User: ids.AddRange(await _dbContext.Queryable() .Where(x => assignValues.Contains(x.No)) .Select(x => x.Id) .ToListAsync() ); break; case AssignTypeEnumType.Group: { var codes = assignValues.Select(Guid.Parse); ids.AddRange(await _dbContext.Queryable() .LeftJoin((a, b) => a.Code == b.GroupCode) .LeftJoin((a, b, c) => b.UserNo == c.No) .Where(a => codes.Contains(a.Code)) .Select((a, b, c) => c.Id) .ToListAsync() ); } break; case AssignTypeEnumType.Department: { //递归向上获取 assignValue = tenant:department var tenantDepartments = assignValues.Select(x => { var arr = x.Split(":"); var currentDepartmentNo = arr.Last(); var departmentNos = RecursionHelper.HandlerDepartmentNextCodes(currentDepartmentNo, departments); return new { tenantId = arr.First(), departmentNos }; }); var where = LinqExpressionExtensions.False(); foreach (var tenantDepartment in tenantDepartments) { where = where.Or(x => x.Factory == tenantDepartment.tenantId && tenantDepartment.departmentNos.Contains(x.DepartmentNo)); } ids.AddRange(await _dbContext.Queryable() .Where(where) .Select(x => x.Id) .ToListAsync() ); } break; case AssignTypeEnumType.Tenant: { ids.AddRange(await _dbContext.Queryable() .Where(x => assignValues.Contains(x.Factory)) .Select(x => x.Id) .ToListAsync() ); } break; default: throw new ArgumentOutOfRangeException($"不支持的权限类型:{assignType}"); } } return ids.Distinct().ToList(); } public async Task ExternalAndManuallyUserNoAsync(string deviceUniqueNo) { var device = await _dbContext.Queryable().SingleAsync(x => x.UniqueNo == deviceUniqueNo); device.ThrowIfNull("设备不存在"); var devicePermissionManuallyUserNos = await GetManuallyDeviceUserNoAsync(device.Code); var visitorUserNos = await GetDeviceUserNosFromVisitorAsync(device.Code); return new DeviceOtherUserCountResponse { ManuallyUserCount = devicePermissionManuallyUserNos.Count, VisitorCount = visitorUserNos.Count }; } public async Task> GetDeviceExceptUsersAsync(string deviceUniqueNo) { var device = await _dbContext.Queryable().SingleAsync(x => x.UniqueNo == deviceUniqueNo); device.ThrowIfNull("设备不存在"); var usersQuery = await GetDeviceUsersQueryAsync(deviceUniqueNo, string.Empty, null); var userCodes = (await usersQuery.ToListAsync()).Select(x => x.Code); var devicePermissionManuallyUserNos = await GetManuallyDeviceUserNoAsync(device.Code); var visitorUserNos = await GetDeviceUserNosFromVisitorAsync(device.Code); var otherUserCodes = await _dbContext.Queryable() .Where(x => devicePermissionManuallyUserNos.Contains(x.No) || visitorUserNos.Contains(x.No)) .Select(x => x.Code) .ToListAsync(); var existsUserCodes = userCodes.Concat(otherUserCodes).Distinct().ToList(); var deviceExistsUserCodes = await _dbContext.Queryable() .Where(x => x.DeviceUniqueNo == deviceUniqueNo) .Select(x => x.UserCode) .ToListAsync(); //获取deviceExistsUserCodes不存在existsUserCodes的工号 var toDeleteUserCodes = deviceExistsUserCodes.Except(existsUserCodes).ToList(); return toDeleteUserCodes; } public async Task GenerateDeleteDeviceTasksAsync(string deviceUniqueNo) { var device = await _dbContext.Queryable().SingleAsync(x => x.UniqueNo == deviceUniqueNo); device.ThrowIfNull("设备不存在"); var userCodes = await GetDeviceExceptUsersAsync(deviceUniqueNo); var gainfoMap = await _dbContext.Queryable() .Where(x => userCodes.Contains(x.Code)) .Select(x => new { x.Code, x.No }) .ToListAsync(); var leaveMap = await _dbContext.Queryable() .Where(x => userCodes.Contains(x.Code)) .Select(x => new { x.Code, x.No }) .ToListAsync(); var userNos = gainfoMap.Select(x => x.No).ToList(); var userNoLeaves = leaveMap.Select(x => x.No).ToList(); // 找出没有在两个表中映射到 No 的 code,原样作为 No 加入 var mappedCodes = gainfoMap.Select(x => x.Code).Concat(leaveMap.Select(x => x.Code)).Distinct().ToList(); var notMappedCodes = userCodes.Except(mappedCodes).ToList(); userNos.AddRange(userNoLeaves); userNos.AddRange(notMappedCodes); await _dbContext.Updateable() .SetColumns(x => x.IsDeleted == true) .SetColumns(x => x.ModifiedTime == DateTime.Now) .Where(x => x.DeviceUniqueNo == deviceUniqueNo) .ExecuteCommandAsync(); var distinctUserNos = userNos.Distinct().ToList(); return await _dbContext.InsertAsync(distinctUserNos.Select(x => new DeviceTaskEntity { DeviceUniqueNo = device.UniqueNo, Status = DeviceTaskStatusEnumType.Wait, Type = DeviceTaskEnumType.Delete, DeviceType = device.Type, UserNo = x, Priority = 0, Version = 0, TenantId = device.TenantId, Source = "设备删除,清除设备中非法人员" }).ToList()); } public async Task> GetDeviceUserCodesAsync(string deviceUniqueNo) { var device = await _dbContext.Queryable().SingleAsync(x => x.UniqueNo == deviceUniqueNo); device.ThrowIfNull("设备不存在"); var userIds = await GetDeviceUserIdsAsync(deviceUniqueNo); var devicePermissionManuallyUserNos = await _dbContext.Queryable() .Where(x => SqlFunc.Subqueryable() .Where(p => p.DeviceCode == device.Code) .Where(p => p.UserNo == x.No).Any()) .Select(x => x.No) .ToListAsync(); var userNos = await GetDeviceUserNosFromVisitorAsync(device.Code); userNos = userNos.Concat(devicePermissionManuallyUserNos).Distinct().ToList(); var gainfoUserCodes = await _dbContext.Queryable() .Where(x => userIds.Contains(x.Id) || userNos.Contains(x.No)) .Select(x => x.Code) .ToListAsync(); return gainfoUserCodes; } private async Task> GetDeviceUserNosFromVisitorAsync(Guid deviceCode) { var now = DateTime.Now; // 获取与指定设备关联的分组编码 var groupCodes = await _dbContext.Queryable() .Where(x => SqlFunc.Subqueryable() .Where(p => p.GroupCode == x.Code) .Where(p => p.DeviceCode == deviceCode) .Any()) .Select(x => x.Code) .ToListAsync(); // 获取与分组相关联的区域编码及类型 var areaCodes = await _dbContext.Queryable() .LeftJoin((x, y) => x.CustomCode == y.CustomCode) .Where(x => groupCodes.Contains(x.DeviceGroupCode)) .Select((x, y) => new { x.CustomCode, y.Type }) .ToListAsync(); // 根据区域类型筛选出门区和厂区的区域编码 var doorAreaCodes = areaCodes.Where(p => p.Type == AppointmentAreaEnumType.Door).Select(p => p.CustomCode).ToList(); var workplaceAreaCodes = areaCodes.Where(p => p.Type == AppointmentAreaEnumType.Workplace).Select(p => p.CustomCode).ToList(); // 查询当前时间段内已到访的访客预约明细 var details = await _dbContext.Queryable() .Where(x => (x.IsEnterDoorArea && now >= x.DoorStart && now <= x.DoorEnd && x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Arrived) || x.IsEnterWorkplace && now >= x.WorkplaceStart && now <= x.WorkplaceEnd && x.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Arrived) .ToListAsync(); //到访门区或厂区的访客编号列表 return details.Where(x => (x.IsEnterDoorArea && doorAreaCodes.Contains(x.ApplyDoorArea)) || (x.IsEnterWorkplace && workplaceAreaCodes.Any(p => x.ApplyWorkplaceAreas.Contains(p))) ) .Select(x => x.UserNo) .Distinct() .ToList(); } private async Task> GetManuallyDeviceUserNoAsync(Guid deviceCode) { return await _dbContext.Queryable() .Where(x => SqlFunc.Subqueryable() .Where(p => p.DeviceCode == deviceCode) .Where(p => p.UserNo == x.No).Any()) .Select(x => x.No) .ToListAsync(); } }