版本260406
This commit is contained in:
@@ -0,0 +1,643 @@
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// 机种权限服务实现。
|
||||
/// </summary>
|
||||
public sealed class ProductPermissionService : IProductPermissionService
|
||||
{
|
||||
private readonly ILogger<ProductPermissionService> _logger;
|
||||
private readonly ConcurrentDictionary<string, List<ProductPermissionModel>> _userPermissions;
|
||||
private readonly ConcurrentDictionary<Guid, List<ProductLockRecordModel>> _productLocks;
|
||||
private readonly ConcurrentDictionary<Guid, List<ProductSwitchRecordModel>> _switchHistory;
|
||||
private readonly object _lockObject = new();
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数。
|
||||
/// </summary>
|
||||
public ProductPermissionService(ILogger<ProductPermissionService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_userPermissions = new ConcurrentDictionary<string, List<ProductPermissionModel>>();
|
||||
_productLocks = new ConcurrentDictionary<Guid, List<ProductLockRecordModel>>();
|
||||
_switchHistory = new ConcurrentDictionary<Guid, List<ProductSwitchRecordModel>>();
|
||||
|
||||
// 初始化默认权限数据
|
||||
InitializeDefaultPermissions();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Result<bool>> 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<bool>.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<bool>.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<bool>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Result<bool>> 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<bool>.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<bool>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Result<IReadOnlyList<ProductPermissionModel>>> GetUserPermissionsAsync(Guid userId, Guid productTypeId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userKey = userId.ToString();
|
||||
if (!_userPermissions.TryGetValue(userKey, out var permissions))
|
||||
{
|
||||
return Result<IReadOnlyList<ProductPermissionModel>>.Success(new List<ProductPermissionModel>());
|
||||
}
|
||||
|
||||
var userProductPermissions = permissions
|
||||
.Where(p => p.ProductTypeId == productTypeId && p.IsEnabled)
|
||||
.ToList();
|
||||
|
||||
return Result<IReadOnlyList<ProductPermissionModel>>.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<IReadOnlyList<ProductPermissionModel>>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Result<ProductPermissionModel>> 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<ProductPermissionModel>());
|
||||
|
||||
// 检查是否已存在相同权限
|
||||
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<ProductPermissionModel>.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<ProductPermissionModel>.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<ProductPermissionModel>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Result> 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());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Result<bool>> IsProductLockedAsync(Guid productTypeId, ProductLockType lockType, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_productLocks.TryGetValue(productTypeId, out var locks))
|
||||
{
|
||||
return Result<bool>.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<bool>.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<bool>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Result<ProductLockRecordModel>> 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<ProductLockRecordModel>());
|
||||
|
||||
// 检查是否已存在相同类型的活跃锁定
|
||||
var existingLock = locks.FirstOrDefault(l => !l.IsUnlocked && l.LockType == lockType);
|
||||
if (existingLock != null)
|
||||
{
|
||||
return Result<ProductLockRecordModel>.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<ProductLockRecordModel>.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<ProductLockRecordModel>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Result> 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());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Result<ProductSwitchValidationResult>> 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<ProductSwitchValidationResult>.Success(validationResult1);
|
||||
}
|
||||
|
||||
// 检查目标机种状态
|
||||
if (targetProduct.Status != ProductTypeStatus.Published)
|
||||
{
|
||||
var validationResult2 = new ProductSwitchValidationResult
|
||||
{
|
||||
SourceProduct = sourceProduct,
|
||||
TargetProduct = targetProduct,
|
||||
CanSwitch = false,
|
||||
Message = "目标机种未发布,无法切换"
|
||||
};
|
||||
return Result<ProductSwitchValidationResult>.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<ProductSwitchValidationResult>.Success(validationResult3);
|
||||
}
|
||||
|
||||
// 获取用户权限
|
||||
var userPermissions = await GetUserPermissionsAsync(userId, targetProductTypeId, cancellationToken);
|
||||
var currentPermissions = userPermissions.Succeeded ? userPermissions.Data.Select(p => p.PermissionType).ToList() : new List<ProductPermissionType>();
|
||||
|
||||
// 确定所需权限
|
||||
var requiredPermissions = new List<ProductPermissionType> { ProductPermissionType.Switch };
|
||||
if (isForced)
|
||||
{
|
||||
requiredPermissions.Add(ProductPermissionType.ForceSwitch);
|
||||
}
|
||||
|
||||
// 收集错误和警告
|
||||
var errors = new List<string>();
|
||||
var warnings = new List<string>();
|
||||
var approvers = new List<string>();
|
||||
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<ProductSwitchValidationResult>.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<ProductSwitchValidationResult>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Result<ProductSwitchRecordModel>> 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<ProductSwitchRecordModel>());
|
||||
|
||||
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<ProductSwitchRecordModel>.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<ProductSwitchRecordModel>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Result<IReadOnlyList<ProductSwitchRecordModel>>> GetSwitchHistoryAsync(Guid? productTypeId = null, Guid? userId = null, DateTime? startTime = null, DateTime? endTime = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var allRecords = new List<ProductSwitchRecordModel>();
|
||||
|
||||
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<IReadOnlyList<ProductSwitchRecordModel>>.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<IReadOnlyList<ProductSwitchRecordModel>>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Result<IReadOnlyList<ProductLockRecordModel>>> GetLockRecordsAsync(Guid productTypeId, bool includeUnlocked = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_productLocks.TryGetValue(productTypeId, out var locks))
|
||||
{
|
||||
return Result<IReadOnlyList<ProductLockRecordModel>>.Success(new List<ProductLockRecordModel>());
|
||||
}
|
||||
|
||||
var filteredLocks = includeUnlocked
|
||||
? locks.ToList()
|
||||
: locks.Where(l => !l.IsUnlocked).ToList();
|
||||
|
||||
// 按时间倒序排列
|
||||
filteredLocks = filteredLocks.OrderByDescending(l => l.LockedAtUtc).ToList();
|
||||
|
||||
return Result<IReadOnlyList<ProductLockRecordModel>>.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<IReadOnlyList<ProductLockRecordModel>>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
#region 私有辅助方法
|
||||
|
||||
/// <summary>
|
||||
/// 初始化默认权限数据。
|
||||
/// </summary>
|
||||
private void InitializeDefaultPermissions()
|
||||
{
|
||||
// 这里可以初始化一些默认的权限数据用于测试
|
||||
_logger.LogInformation("初始化默认机种权限数据");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据机种编码获取机种ID。
|
||||
/// </summary>
|
||||
private async Task<Guid> 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
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取机种信息。
|
||||
/// </summary>
|
||||
private async Task<ProductTypeModel?> 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"
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取机种编码。
|
||||
/// </summary>
|
||||
private async Task<string?> GetProductTypeCodeAsync(Guid productTypeId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var productType = await GetProductTypeAsync(productTypeId, cancellationToken);
|
||||
return productType?.Code;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user