123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- 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<string,FormulaItem> _formula; // 公式
- public CalculateFormula()
- {
- _formula = new Dictionary<string, FormulaItem>();
- }
- 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];
- }
- /// <summary>
- /// 主计算入口
- /// </summary>
- 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);
- }
- }
- /// <summary>
- /// 解析依赖
- /// </summary>
- private Dictionary<string, List<string>> BuildDependencyGraph(Dictionary<string, FormulaItem> dict)
- {
- var graph = new Dictionary<string, List<string>>();
- foreach (var kv in dict)
- {
- var deps = new List<string>();
- 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;
- }
- /// <summary>
- /// 拓扑排序
- /// </summary>
- private List<string> TopologicalSort(Dictionary<string, List<string>> graph)
- {
- var result = new List<string>();
- var visited = new Dictionary<string, int>(); // 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<string, List<string>> graph,Dictionary<string, int> visited, List<string> 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);
- }
- /// <summary>
- /// 展开公式,把变量替换为已计算的值
- /// </summary>
- private string ExpandFormula(string formula, Dictionary<string, FormulaItem> 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;
- }
- /// <summary>
- /// 公式计算
- /// </summary>
- /// <param name="expression"></param>
- /// <param name="name"></param>
- /// <returns></returns>
- 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}");
- }
- }
- /// <summary>
- /// Sql公式计算
- /// </summary>
- /// <param name="expression"></param>
- /// <param name="name"></param>
- /// <returns></returns>
- 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}");
- }
- }
- }
- }
|