SmartOpsTrustedScopeResolver.cs 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. using Admin.NET.Core;
  2. namespace Admin.NET.Plugin.AiDOP.Infrastructure;
  3. public sealed record SmartOpsTrustedScope(long TenantId, long FactoryId, long UserId);
  4. /// <summary>
  5. /// 智慧诊断与改善闭环的可信作用域:只信登录上下文,工厂由租户关系解析。
  6. /// </summary>
  7. public sealed class SmartOpsTrustedScopeResolver : ITransient
  8. {
  9. public const long PlatformTenantId = SqlSugarConst.DefaultTenantId;
  10. private readonly ISqlSugarClient _db;
  11. private readonly UserManager _userManager;
  12. public SmartOpsTrustedScopeResolver(ISqlSugarClient db, UserManager userManager)
  13. {
  14. _db = db;
  15. _userManager = userManager;
  16. }
  17. public async Task<SmartOpsTrustedScope> ResolveAsync(long? candidateFactoryId = null)
  18. {
  19. var tenantId = AidopTenantScope.ResolveOrThrow(_userManager);
  20. SmartOpsTrustedScopeRules.EnsureBusinessTenant(tenantId);
  21. var orgId = await _db.Queryable<SysTenant>()
  22. .ClearFilter<ITenantIdFilter>()
  23. .Where(x => x.Id == tenantId)
  24. .Select(x => x.OrgId)
  25. .FirstAsync();
  26. var factoryId = SmartOpsTrustedScopeRules.ResolveFactory(tenantId, orgId, candidateFactoryId);
  27. var userId = _userManager.UserId;
  28. if (userId <= 0)
  29. throw Oops.Oh("无法确定当前用户,请重新登录");
  30. return new SmartOpsTrustedScope(tenantId, factoryId, userId);
  31. }
  32. }
  33. public static class SmartOpsTrustedScopeRules
  34. {
  35. public const long PlatformTenantId = SqlSugarConst.DefaultTenantId;
  36. public static void EnsureBusinessTenant(long tenantId)
  37. {
  38. if (tenantId <= 0 || tenantId == 1 || tenantId == PlatformTenantId)
  39. throw new InvalidOperationException("平台租户不得作为业务事实作用域");
  40. }
  41. /// <summary>
  42. /// 客户端工厂只是筛选建议。未授权或不存在时回落到租户 OrgId,不得使用外租户工厂。
  43. /// </summary>
  44. public static long ResolveFactory(long tenantId, long orgId, long? candidateFactoryId)
  45. {
  46. if (orgId <= 0 || orgId == tenantId)
  47. throw new InvalidOperationException("当前租户未配置有效工厂");
  48. if (candidateFactoryId is > 0
  49. && candidateFactoryId.Value != tenantId
  50. && candidateFactoryId.Value == orgId)
  51. return candidateFactoryId.Value;
  52. return orgId;
  53. }
  54. public static bool IsAuthorizedFactory(long tenantId, long orgId, long factoryId) =>
  55. factoryId > 0 && factoryId != tenantId && factoryId == orgId;
  56. }
  57. public static class SmartOpsImprovementPlanNo
  58. {
  59. public static string BuildPrefix(DateTime now) => $"SOP-{now:yyyyMMdd}-";
  60. public static string Next(string prefix, IEnumerable<string> existing)
  61. {
  62. var max = 0;
  63. foreach (var planNo in existing)
  64. {
  65. if (string.IsNullOrWhiteSpace(planNo) || !planNo.StartsWith(prefix, StringComparison.Ordinal))
  66. continue;
  67. if (int.TryParse(planNo.AsSpan(prefix.Length), out var n))
  68. max = Math.Max(max, n);
  69. }
  70. return $"{prefix}{max + 1:000}";
  71. }
  72. }