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;
private static readonly (string Code, string Name, int OrderNo)[] S8BusinessRoles =
{
("ROLE_ORDER_PLANNER", "订单计划员", 800),
("ROLE_PRODUCTION_PLANNER", "生产计划员", 801),
("ROLE_PURCHASER", "采购员", 802),
("ROLE_WH_INBOUND", "仓库收货员", 803),
("ROLE_WH_OUTBOUND", "仓库发货员", 804),
("ROLE_QC", "质检员", 805),
("ROLE_EQUIP_MAINT", "设备维修员", 806),
};
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();
}
}
}