using Admin.NET.Plugin.AiDOP.Entity; using Admin.NET.Plugin.AiDOP.Entity.S8; using Admin.NET.Plugin.AiDOP.Service.S8.OrderFlow; using Yitter.IdGenerator; namespace Admin.NET.Plugin.AiDOP.Infrastructure; /// /// Ai-DOP 每租户必备基线:S8 七个业务角色 + KPI calc config(从 AIDOP 模板租户复制)。 /// 形态为「每租户复制」,便于各租户独立调整 KPI 公式与角色配置。 /// public sealed class AidopTenantInitService : ITransient { /// AIDOP 运行租户:KPI calc config 模板来源。 public const long KpiTemplateTenantId = 797403760988229L; /// AIDOPDemo:S8 七模块场景模板来源,不含规则、数据源或凭据。 public const long S8SceneTemplateTenantId = 797403760988230L; // S8-CFG-NOTIFY-NONDEFAULT-ROLE-OPTIONS-FIX-1:改引用 canonical 单一来源。 // 原先此处与 S8SysRoleSeedData 各存一份逐字相同的字面量,靠人工同步; // role-options 若再复制第三份必然分叉,故统一收口到 S8CanonicalRole。内容未变。 private static (string Code, string Name, int OrderNo)[] S8BusinessRoles => Admin.NET.Plugin.AiDOP.Infrastructure.S8.S8CanonicalRole.BusinessRoles; private readonly ISqlSugarClient _db; public AidopTenantInitService(ISqlSugarClient db) => _db = db; /// 幂等种入目标租户的 S8 业务角色、KPI 主数据/布局与 calc config;允许重复调用。 public async Task InitTenantBaselineAsync(long tenantId) { if (tenantId <= 0) return; await SeedS8BusinessRolesAsync(tenantId); AidopImprovementApprovalSeed.EnsureBaselineRoles(_db, tenantId); await SeedS8ScenesFromTemplateAsync(tenantId); AidopKpiMasterSeed.EnsureSeed(_db, tenantId, includeDemoValues: false); await SeedKpiCalcConfigFromTemplateAsync(tenantId); } private async Task SeedS8ScenesFromTemplateAsync(long tenantId) { if (tenantId == S8SceneTemplateTenantId) return; var factoryId = await _db.Queryable() .ClearFilter() .Where(x => x.Id == tenantId) .Select(x => x.OrgId) .FirstAsync(); if (factoryId <= 0) return; var templates = await _db.Queryable() .ClearFilter() .Where(x => x.TenantId == S8SceneTemplateTenantId && x.Enabled) .OrderBy(x => x.SortNo) .ToListAsync(); var now = DateTime.Now; foreach (var template in templates) { var exists = await _db.Queryable() .ClearFilter() .AnyAsync(x => x.TenantId == tenantId && x.FactoryId == factoryId && x.SceneCode == template.SceneCode); if (exists) continue; await _db.Insertable(new AdoS8SceneConfig { TenantId = tenantId, FactoryId = factoryId, SceneCode = template.SceneCode, SceneName = template.SceneName, Enabled = true, SortNo = template.SortNo, CreatedAt = now, }).ExecuteCommandAsync(); } } private async Task SeedS8BusinessRolesAsync(long tenantId) { var ct = DateTime.Now; foreach (var (code, name, orderNo) in S8BusinessRoles) { var exists = await _db.Queryable() .ClearFilter() .AnyAsync(r => r.TenantId == tenantId && r.Code == code); if (exists) continue; await _db.Insertable(new SysRole { Id = YitIdHelper.NextId(), TenantId = tenantId, Name = name, Code = code, OrderNo = orderNo, DataScope = DataScopeEnum.Self, Status = StatusEnum.Enable, Remark = "S8 业务角色(异常协同承接)", CreateTime = ct, }).ExecuteCommandAsync(); } } private async Task SeedKpiCalcConfigFromTemplateAsync(long tenantId) { if (tenantId == KpiTemplateTenantId) return; var templates = await _db.Queryable() .ClearFilter() .Where(c => c.TenantId == KpiTemplateTenantId) .ToListAsync(); if (templates.Count == 0) return; var now = DateTime.Now; foreach (var tpl in templates) { var exists = await _db.Queryable() .ClearFilter() .AnyAsync(c => c.TenantId == tenantId && c.MetricCode == tpl.MetricCode && c.VersionNo == tpl.VersionNo); if (exists) continue; await _db.Insertable(new AdoSmartOpsKpiCalcConfig { TenantId = tenantId, MetricCode = tpl.MetricCode, ModuleCode = tpl.ModuleCode, VersionNo = tpl.VersionNo, CalcEngineType = tpl.CalcEngineType, DataSourceCode = tpl.DataSourceCode, SqlScript = tpl.SqlScript, SqlParametersJson = tpl.SqlParametersJson, TimeoutSeconds = tpl.TimeoutSeconds, PublishStatus = tpl.PublishStatus, IsCurrent = tpl.IsCurrent, Remark = tpl.Remark, CreatedBy = "AidopTenantInit", CreatedAt = now, }).ExecuteCommandAsync(); } } }