using Microsoft.Extensions.Logging; using OrpaonVision.Core.Results; using OrpaonVision.Core.Security; using OrpaonVision.Model.Configuration; using OrpaonVision.Model.Security; using System.Collections.Concurrent; namespace OrpaonVision.ConfigApp.Infrastructure.Services; /// /// 机种权限服务实现。 /// public sealed class ProductPermissionService : IProductPermissionService { private readonly ILogger _logger; private readonly ConcurrentDictionary> _userPermissions; private readonly ConcurrentDictionary> _productLocks; private readonly ConcurrentDictionary> _switchHistory; private readonly object _lockObject = new(); /// /// 构造函数。 /// public ProductPermissionService(ILogger logger) { _logger = logger; _userPermissions = new ConcurrentDictionary>(); _productLocks = new ConcurrentDictionary>(); _switchHistory = new ConcurrentDictionary>(); // 初始化默认权限数据 InitializeDefaultPermissions(); } /// public async Task> CheckPermissionAsync(Guid userId, Guid productTypeId, ProductPermissionType permissionType, CancellationToken cancellationToken = default) { try { _logger.LogDebug("检查用户权限: {UserId}, {ProductTypeId}, {PermissionType}", userId, productTypeId, permissionType); var userKey = userId.ToString(); if (!_userPermissions.TryGetValue(userKey, out var permissions)) { _logger.LogWarning("用户 {UserId} 没有任何机种权限", userId); return Result.Success(false); } var hasPermission = permissions.Any(p => p.ProductTypeId == productTypeId && p.PermissionType == permissionType && p.IsEnabled && (!p.ExpiresAtUtc.HasValue || p.ExpiresAtUtc.Value > DateTime.UtcNow)); _logger.LogDebug("用户 {UserId} 对机种 {ProductTypeId} 的权限 {PermissionType}: {HasPermission}", userId, productTypeId, permissionType, hasPermission); return Result.Success(hasPermission); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "检查用户权限失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "CHECK_PERMISSION_FAILED", "检查用户权限失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> CheckPermissionByCodeAsync(Guid userId, string productTypeCode, ProductPermissionType permissionType, CancellationToken cancellationToken = default) { try { // 这里需要根据机种编码查找机种ID,暂时使用模拟数据 var productTypeId = await GetProductTypeIdByCodeAsync(productTypeCode, cancellationToken); if (productTypeId == Guid.Empty) { _logger.LogWarning("机种编码 {ProductTypeCode} 不存在", productTypeCode); return Result.Success(false); } return await CheckPermissionAsync(userId, productTypeId, permissionType, cancellationToken); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "根据机种编码检查权限失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "CHECK_PERMISSION_BY_CODE_FAILED", "根据机种编码检查权限失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task>> GetUserPermissionsAsync(Guid userId, Guid productTypeId, CancellationToken cancellationToken = default) { try { var userKey = userId.ToString(); if (!_userPermissions.TryGetValue(userKey, out var permissions)) { return Result>.Success(new List()); } var userProductPermissions = permissions .Where(p => p.ProductTypeId == productTypeId && p.IsEnabled) .ToList(); return Result>.Success(userProductPermissions); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取用户机种权限失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "GET_USER_PERMISSIONS_FAILED", "获取用户机种权限失败。", traceId); return Result>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> GrantPermissionAsync(Guid userId, Guid productTypeId, ProductPermissionType permissionType, DateTime? expiresAtUtc = null, string? remark = null, CancellationToken cancellationToken = default) { try { _logger.LogInformation("授予用户机种权限: {UserId}, {ProductTypeId}, {PermissionType}", userId, productTypeId, permissionType); lock (_lockObject) { var userKey = userId.ToString(); var permissions = _userPermissions.GetOrAdd(userKey, _ => new List()); // 检查是否已存在相同权限 var existingPermission = permissions.FirstOrDefault(p => p.ProductTypeId == productTypeId && p.PermissionType == permissionType); if (existingPermission != null) { // 更新现有权限 existingPermission.IsEnabled = true; existingPermission.ExpiresAtUtc = expiresAtUtc; existingPermission.Remark = remark; existingPermission.UpdatedAtUtc = DateTime.UtcNow; existingPermission.UpdatedBy = Environment.UserName; _logger.LogInformation("更新现有权限: {PermissionId}", existingPermission.Id); return Result.Success(existingPermission); } // 创建新权限 var newPermission = new ProductPermissionModel { Id = Guid.NewGuid(), ProductTypeId = productTypeId, UserId = userId, RoleId = Guid.NewGuid(), // 模拟角色ID PermissionType = permissionType, IsEnabled = true, GrantedAtUtc = DateTime.UtcNow, GrantedBy = Environment.UserName, ExpiresAtUtc = expiresAtUtc, Remark = remark, CreatedAtUtc = DateTime.UtcNow, CreatedBy = Environment.UserName, UpdatedAtUtc = DateTime.UtcNow, UpdatedBy = Environment.UserName }; permissions.Add(newPermission); _logger.LogInformation("成功授予权限: {PermissionId}", newPermission.Id); return Result.Success(newPermission); } } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "授予用户机种权限失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "GRANT_PERMISSION_FAILED", "授予用户机种权限失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task RevokePermissionAsync(Guid permissionId, string reason, CancellationToken cancellationToken = default) { try { _logger.LogInformation("撤销用户机种权限: {PermissionId}, 原因: {Reason}", permissionId, reason); lock (_lockObject) { foreach (var permissions in _userPermissions.Values) { var permission = permissions.FirstOrDefault(p => p.Id == permissionId); if (permission != null) { permission.IsEnabled = false; permission.UpdatedAtUtc = DateTime.UtcNow; permission.UpdatedBy = Environment.UserName; permission.Remark = $"权限已撤销: {reason}"; _logger.LogInformation("成功撤销权限: {PermissionId}", permissionId); return Result.Success(); } } return Result.Fail("PERMISSION_NOT_FOUND", "指定的权限不存在"); } } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "撤销用户机种权限失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "REVOKE_PERMISSION_FAILED", "撤销用户机种权限失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> IsProductLockedAsync(Guid productTypeId, ProductLockType lockType, CancellationToken cancellationToken = default) { try { if (!_productLocks.TryGetValue(productTypeId, out var locks)) { return Result.Success(false); } var activeLocks = locks.Where(l => !l.IsUnlocked && (!l.ExpectedUnlockAtUtc.HasValue || l.ExpectedUnlockAtUtc.Value > DateTime.UtcNow)); var isLocked = lockType == ProductLockType.Permission ? activeLocks.Any(l => l.LockType == ProductLockType.Permission || l.LockType == ProductLockType.Maintenance) : activeLocks.Any(l => l.LockType == lockType); return Result.Success(isLocked); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "检查机种锁定状态失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "CHECK_LOCK_FAILED", "检查机种锁定状态失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> LockProductAsync(Guid productTypeId, ProductLockType lockType, string lockReason, DateTime? expectedUnlockAtUtc = null, CancellationToken cancellationToken = default) { try { _logger.LogInformation("锁定机种: {ProductTypeId}, {LockType}, 原因: {LockReason}", productTypeId, lockType, lockReason); lock (_lockObject) { var locks = _productLocks.GetOrAdd(productTypeId, _ => new List()); // 检查是否已存在相同类型的活跃锁定 var existingLock = locks.FirstOrDefault(l => !l.IsUnlocked && l.LockType == lockType); if (existingLock != null) { return Result.Fail("ALREADY_LOCKED", $"机种已被相同类型的锁定锁定: {existingLock.LockReason}"); } var lockRecord = new ProductLockRecordModel { Id = Guid.NewGuid(), ProductTypeId = productTypeId, LockType = lockType, LockReason = lockReason, LockedByUserId = Guid.NewGuid(), // 模拟用户ID LockedByName = Environment.UserName, LockedAtUtc = DateTime.UtcNow, ExpectedUnlockAtUtc = expectedUnlockAtUtc, IsUnlocked = false, CreatedAtUtc = DateTime.UtcNow, CreatedBy = Environment.UserName }; locks.Add(lockRecord); _logger.LogInformation("成功锁定机种: {LockId}", lockRecord.Id); return Result.Success(lockRecord); } } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "锁定机种失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "LOCK_PRODUCT_FAILED", "锁定机种失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task UnlockProductAsync(Guid lockRecordId, string unlockReason, CancellationToken cancellationToken = default) { try { _logger.LogInformation("解锁机种: {LockRecordId}, 原因: {UnlockReason}", lockRecordId, unlockReason); lock (_lockObject) { foreach (var locks in _productLocks.Values) { var lockRecord = locks.FirstOrDefault(l => l.Id == lockRecordId); if (lockRecord != null && !lockRecord.IsUnlocked) { lockRecord.IsUnlocked = true; lockRecord.UnlockedAtUtc = DateTime.UtcNow; lockRecord.UnlockedByUserId = Guid.NewGuid(); // 模拟用户ID lockRecord.UnlockedByName = Environment.UserName; lockRecord.UnlockReason = unlockReason; _logger.LogInformation("成功解锁机种: {LockId}", lockRecordId); return Result.Success(); } } return Result.Fail("LOCK_NOT_FOUND", "指定的锁定记录不存在或已解锁"); } } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "解锁机种失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "UNLOCK_PRODUCT_FAILED", "解锁机种失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> ValidateSwitchPermissionAsync(Guid userId, Guid? sourceProductTypeId, Guid targetProductTypeId, bool isForced = false, CancellationToken cancellationToken = default) { try { _logger.LogInformation("验证机种切换权限: {UserId}, {SourceProductTypeId} -> {TargetProductTypeId}, 强制: {IsForced}", userId, sourceProductTypeId, targetProductTypeId, isForced); var sourceProduct = sourceProductTypeId.HasValue ? await GetProductTypeAsync(sourceProductTypeId.Value) : null; var targetProduct = await GetProductTypeAsync(targetProductTypeId); // 检查目标机种是否存在 if (targetProduct == null) { var validationResult1 = new ProductSwitchValidationResult { SourceProduct = sourceProduct, TargetProduct = targetProduct, CanSwitch = false, Message = "目标机种不存在" }; return Result.Success(validationResult1); } // 检查目标机种状态 if (targetProduct.Status != ProductTypeStatus.Published) { var validationResult2 = new ProductSwitchValidationResult { SourceProduct = sourceProduct, TargetProduct = targetProduct, CanSwitch = false, Message = "目标机种未发布,无法切换" }; return Result.Success(validationResult2); } // 检查目标机种是否被锁定 var isLocked = await IsProductLockedAsync(targetProductTypeId, ProductLockType.Runtime, cancellationToken); if (isLocked.Succeeded && isLocked.Data) { var validationResult3 = new ProductSwitchValidationResult { SourceProduct = sourceProduct, TargetProduct = targetProduct, CanSwitch = false, Message = "目标机种已被锁定,无法切换" }; return Result.Success(validationResult3); } // 获取用户权限 var userPermissions = await GetUserPermissionsAsync(userId, targetProductTypeId, cancellationToken); var currentPermissions = userPermissions.Succeeded ? userPermissions.Data.Select(p => p.PermissionType).ToList() : new List(); // 确定所需权限 var requiredPermissions = new List { ProductPermissionType.Switch }; if (isForced) { requiredPermissions.Add(ProductPermissionType.ForceSwitch); } // 收集错误和警告 var errors = new List(); var warnings = new List(); var approvers = new List(); var requiresApproval = false; // 检查权限 if (!userPermissions.Succeeded) { errors.Add($"获取用户权限失败: {userPermissions.Message}"); } else if (!userPermissions.Data.Any(p => requiredPermissions.Contains(p.PermissionType))) { errors.Add("用户没有足够的权限进行机种切换"); } // 强制切换需要审批 if (isForced) { requiresApproval = true; approvers.Add("班组长"); warnings.Add("强制切换需要班组长审批"); } // 检查源机种(如果有) if (sourceProductTypeId.HasValue) { var sourcePermissions = await GetUserPermissionsAsync(userId, sourceProductTypeId.Value, cancellationToken); if (sourcePermissions.Succeeded && !sourcePermissions.Data.Any(p => p.PermissionType == ProductPermissionType.Switch)) { warnings.Add("当前用户在源机种没有切换权限"); } } var canSwitch = !errors.Any(); var message = canSwitch ? "验证通过,可以切换机种" : "验证失败,无法切换机种"; var validationResult = new ProductSwitchValidationResult { SourceProduct = sourceProduct, TargetProduct = targetProduct, CurrentPermissions = currentPermissions, RequiredPermissions = requiredPermissions, Errors = errors, Warnings = warnings, Approvers = approvers, RequiresApproval = requiresApproval, CanSwitch = canSwitch, Message = message }; return Result.Success(validationResult); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "验证机种切换权限失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "VALIDATE_SWITCH_FAILED", "验证机种切换权限失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> RecordSwitchAsync(Guid userId, string userName, string userRole, Guid? sourceProductTypeId, Guid targetProductTypeId, ProductSwitchType switchType, string switchReason, bool isForced = false, string? forcedReason = null, CancellationToken cancellationToken = default) { try { _logger.LogInformation("记录机种切换: {UserId}, {SourceProductTypeId} -> {TargetProductTypeId}, {SwitchType}", userId, sourceProductTypeId, targetProductTypeId, switchType); lock (_lockObject) { var switchHistory = _switchHistory.GetOrAdd(targetProductTypeId, _ => new List()); var switchRecord = new ProductSwitchRecordModel { Id = Guid.NewGuid(), SourceProductTypeId = sourceProductTypeId, SourceProductTypeCode = sourceProductTypeId.HasValue ? GetProductTypeCodeAsync(sourceProductTypeId.Value).Result : null, TargetProductTypeId = targetProductTypeId, TargetProductTypeCode = GetProductTypeCodeAsync(targetProductTypeId).Result ?? string.Empty, SwitchType = switchType, SwitchReason = switchReason, SwitchedByUserId = userId, SwitchedByName = userName, SwitchedByRole = userRole, SwitchedAtUtc = DateTime.UtcNow, IsForced = isForced, ForcedReason = forcedReason, CreatedAtUtc = DateTime.UtcNow, CreatedBy = Environment.UserName }; switchHistory.Add(switchRecord); _logger.LogInformation("成功记录机种切换: {SwitchId}", switchRecord.Id); return Result.Success(switchRecord); } } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "记录机种切换失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "RECORD_SWITCH_FAILED", "记录机种切换失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task>> GetSwitchHistoryAsync(Guid? productTypeId = null, Guid? userId = null, DateTime? startTime = null, DateTime? endTime = null, CancellationToken cancellationToken = default) { try { var allRecords = new List(); if (productTypeId.HasValue) { if (_switchHistory.TryGetValue(productTypeId.Value, out var records)) { allRecords.AddRange(records); } } else { foreach (var records in _switchHistory.Values) { allRecords.AddRange(records); } } // 过滤条件 if (userId.HasValue) { allRecords = allRecords.Where(r => r.SwitchedByUserId == userId.Value).ToList(); } if (startTime.HasValue) { allRecords = allRecords.Where(r => r.SwitchedAtUtc >= startTime.Value).ToList(); } if (endTime.HasValue) { allRecords = allRecords.Where(r => r.SwitchedAtUtc <= endTime.Value).ToList(); } // 按时间倒序排列 allRecords = allRecords.OrderByDescending(r => r.SwitchedAtUtc).ToList(); return Result>.Success(allRecords); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取机种切换历史失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "GET_SWITCH_HISTORY_FAILED", "获取机种切换历史失败。", traceId); return Result>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task>> GetLockRecordsAsync(Guid productTypeId, bool includeUnlocked = false, CancellationToken cancellationToken = default) { try { if (!_productLocks.TryGetValue(productTypeId, out var locks)) { return Result>.Success(new List()); } var filteredLocks = includeUnlocked ? locks.ToList() : locks.Where(l => !l.IsUnlocked).ToList(); // 按时间倒序排列 filteredLocks = filteredLocks.OrderByDescending(l => l.LockedAtUtc).ToList(); return Result>.Success(filteredLocks); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取机种锁定记录失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "GET_LOCK_RECORDS_FAILED", "获取机种锁定记录失败。", traceId); return Result>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } #region 私有辅助方法 /// /// 初始化默认权限数据。 /// private void InitializeDefaultPermissions() { // 这里可以初始化一些默认的权限数据用于测试 _logger.LogInformation("初始化默认机种权限数据"); } /// /// 根据机种编码获取机种ID。 /// private async Task GetProductTypeIdByCodeAsync(string productTypeCode, CancellationToken cancellationToken = default) { // 模拟实现,实际应该从数据库查询 await Task.Delay(10, cancellationToken); return productTypeCode switch { "VF-A100" => Guid.Parse("11111111-1111-1111-1111-111111111111"), "VF-B200" => Guid.Parse("22222222-2222-2222-2222-222222222222"), "VF-C300" => Guid.Parse("33333333-3333-3333-3333-333333333333"), _ => Guid.Empty }; } /// /// 获取机种信息。 /// private async Task GetProductTypeAsync(Guid productTypeId, CancellationToken cancellationToken = default) { // 模拟实现,实际应该从数据库查询 await Task.Delay(10, cancellationToken); return new ProductTypeModel { Id = productTypeId, Code = "VF-A100", Name = "变频器A100", Status = ProductTypeStatus.Published, TotalLayers = 3, IsPublished = true, CreatedAtUtc = DateTime.UtcNow.AddDays(-30), CreatedBy = "System" }; } /// /// 获取机种编码。 /// private async Task GetProductTypeCodeAsync(Guid productTypeId, CancellationToken cancellationToken = default) { var productType = await GetProductTypeAsync(productTypeId, cancellationToken); return productType?.Code; } #endregion }