using JLHHJSvr.Com.Model; using JLHHJSvr.LJException; using JLHHJSvr.LJFramework.Tools; using NPOI.SS.Formula; using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text.RegularExpressions; namespace JLHHJSvr.Tools { public class CalculateFormula { private Dictionary _formula; // 公式 public CalculateFormula() { _formula = new Dictionary(); } public void AddFormulaItem(FormulaItem item) { if(_formula.ContainsKey(item.formula_name)) { _formula.Remove(item.formula_name); } _formula.Add(item.formula_name, item); } public void AddFormulaItem(string name,decimal value) { AddFormulaItem(new FormulaItem() { formula_name = name, value = value,isConst = true }); } public void AddFormulaItem(string name, string formula) { AddFormulaItem(new FormulaItem() { formula_name = name, formula = formula, isConst = false }); } public FormulaItem GetFormulaItem(string name,bool isConst = false) { return _formula[name]; } /// /// 主计算入口 /// public void CalculateAll() { var graph = BuildDependencyGraph(_formula); var sorted = TopologicalSort(graph); foreach (var name in sorted) { var item = _formula[name]; // 常量直接赋值 if (item.isConst) { //item.formula_transform = item.formula; //item.value = Convert.ToDecimal(item.formula); continue; } // 变量公式 item.formula = ConvertToEnglishSymbols(item.formula); string expanded = ExpandFormula(item.formula, _formula); item.formula_transform = expanded; // 计算 if (item.isSql) SqlCalculate(item); else Calculate(item); } } /// /// 解析依赖 /// private Dictionary> BuildDependencyGraph(Dictionary dict) { var graph = new Dictionary>(); foreach (var kv in dict) { var deps = new List(); foreach (var name in dict.Keys) { if (name == kv.Key || kv.Value.isConst) continue; if (Regex.IsMatch(kv.Value.formula, name)) { deps.Add(name); } } graph[kv.Key] = deps; } return graph; } /// /// 拓扑排序 /// private List TopologicalSort(Dictionary> graph) { var result = new List(); var visited = new Dictionary(); // 0=未访问,1=正在访问,2=已完成 foreach (var node in graph.Keys) { if (!visited.ContainsKey(node)) { Dfs(node, graph, visited, result); } } return result; } private void Dfs(string node, Dictionary> graph,Dictionary visited, List result) { if (visited.ContainsKey(node) && visited[node] == 1) throw new InvalidOperationException($"检测到循环依赖: {node}"); if (visited.ContainsKey(node) && visited[node] == 2) return; visited[node] = 1; foreach (var dep in graph[node]) { Dfs(dep, graph, visited, result); } visited[node] = 2; result.Add(node); } /// /// 展开公式,把变量替换为已计算的值 /// private string ExpandFormula(string formula, Dictionary dict) { foreach (var kv in dict) { formula = Regex.Replace(formula, kv.Key, kv.Value.value.ToString()); } return formula; } private string ConvertToEnglishSymbols(string input) { input = input.Replace("(", "(") .Replace(")", ")") .Replace(",", ",") .Replace("。", ".") .Replace(":", ":") .Replace(";", ";") .Replace("“", "\"") .Replace("”", "\"") .Replace("‘", "'") .Replace("’", "'"); return input; } /// /// 公式计算 /// /// /// /// private void Calculate(FormulaItem formula) { try { formula.value = LJExprParser.Parse(formula.formula_transform).Result.DecimalValue; formula.isConst = true; } catch (Exception ex) { throw new LJCommonException($"计算{formula.formula_name}公式错误: {ex.Message}"); } } /// /// Sql公式计算 /// /// /// /// private void SqlCalculate(FormulaItem formula) { try { //cmd.CommandText = $@"{formula.formula}"; //cmd.Parameters.Clear(); //return cmd.ExecuteScalar(); } catch (Exception ex) { throw new LJCommonException($"计算{formula.formula_name}公式错误: {ex.Message}"); } } } }