using System.Text.RegularExpressions;
using Admin.NET.Plugin.AiDOP.Entity;
using SqlSugar;
namespace Admin.NET.Plugin.AiDOP.Infrastructure.FormulaExpr;
///
/// 把结构化公式替换为人读预览:
/// $F_S1_001 → 统计期订单总数
/// @S1_L1_001 → 订单评审周期(天)
/// / → ÷, * → ×
///
public static class FormulaPreviewBuilder
{
private static readonly Regex RefRe = new(@"([@$])([A-Za-z][A-Za-z0-9_]*)", RegexOptions.Compiled);
public static async Task BuildAsync(
ISqlSugarClient db,
long tenantId,
string? expr,
FormulaParser.ParseResult? parsed = null)
{
if (string.IsNullOrWhiteSpace(expr)) return string.Empty;
parsed ??= FormulaParser.Parse(expr);
var metricMap = parsed.MetricRefs.Count == 0
? new Dictionary()
: (await db.Queryable()
.Where(x => x.TenantId == tenantId && parsed.MetricRefs.Contains(x.MetricCode))
.Select(x => new { x.MetricCode, x.MetricName })
.ToListAsync())
.ToDictionary(x => x.MetricCode, x => x.MetricName, StringComparer.OrdinalIgnoreCase);
var factMap = parsed.FactRefs.Count == 0
? new Dictionary()
: (await db.Queryable()
.Where(x => x.TenantId == tenantId && parsed.FactRefs.Contains(x.FactCode))
.Select(x => new { x.FactCode, x.FactName })
.ToListAsync())
.ToDictionary(x => x.FactCode, x => x.FactName, StringComparer.OrdinalIgnoreCase);
var preview = RefRe.Replace(expr, m =>
{
var sym = m.Groups[1].Value;
var code = m.Groups[2].Value;
if (sym == "@" && metricMap.TryGetValue(code, out var mn)) return mn ?? $"@{code}";
if (sym == "$" && factMap.TryGetValue(code, out var fn)) return fn ?? $"${code}";
return m.Value;
});
preview = preview.Replace('/', '÷').Replace('*', '×');
// 连续空白压缩
preview = Regex.Replace(preview, @"\s+", " ").Trim();
return preview;
}
}