Parcourir la source

1、增加公式计算类

iggy il y a 1 mois
Parent
commit
328a8678e9

+ 3 - 9
JLHHJSvr/Com/Model/CalCulationFormula.cs

@@ -8,10 +8,6 @@ namespace JLHHJSvr.Com.Model
 {
     public sealed class FormulaItem
     {
-        /// <summary>
-        /// 公式id
-        /// </summary>
-        public int formula_id { get; set; }
         /// <summary>
         /// 公式名
         /// </summary>
@@ -29,9 +25,9 @@ namespace JLHHJSvr.Com.Model
         /// </summary>
         public object value { get; set; }
         /// <summary>
-        /// 拓扑
+        /// 是否使用sql进行计算
         /// </summary>
-        public List<string> graph { get; set; }
+        public bool isSql { get; set; }
 
         public override bool Equals(object o)
         {
@@ -43,8 +39,7 @@ namespace JLHHJSvr.Com.Model
             if (o is FormulaItem)
             {
                 FormulaItem item = (FormulaItem)o;
-                return formula_id == item.formula_id &&
-                formula_name.Equals(item.formula_name);
+                return formula_name.Equals(item.formula_name);
             }
             return false;
         }
@@ -52,7 +47,6 @@ namespace JLHHJSvr.Com.Model
         public override int GetHashCode()
         {
             int hash = 17;
-            hash = hash * 23 + formula_id.GetHashCode();
             hash = hash * 23 + formula_name.GetHashCode();
             return hash;
         }

+ 22 - 22
JLHHJSvr/Helper/SoftBedHelper.cs

@@ -564,35 +564,35 @@ namespace JLHHJSvr.Helper
 		private void InitReplaceMents(u_softbed softbed)
 		{
 			// 公式变量
-			formula.AddFormulaItem("不含税出厂价", "【车间成本】*(【工厂利润率】+【外销加点】)");
-			formula.AddFormulaItem("部门不含税价", "【不含税出厂价】/【部门利润率】/( 1 - (【佣金点数】- 1))*【额外点数】+【FOB】");
-			formula.AddFormulaItem("部门含税价", "【部门不含税价】*【税率】");
-			formula.AddFormulaItem("税金", "【部门不含税价】* (【税率】-1)");
-			formula.AddFormulaItem("外币价", "【部门含税价】/【汇率】");
+			formula.AddFormulaItem("不含税出厂价", "【车间成本】*(【工厂利润率】+【外销加点】)");
+			formula.AddFormulaItem("部门不含税价", "【不含税出厂价】/【部门利润率】/( 1 - (【佣金点数】- 1))*【额外点数】+【FOB】");
+			formula.AddFormulaItem("部门含税价", "【部门不含税价】*【税率】");
+			formula.AddFormulaItem("税金", "【部门不含税价】* (【税率】-1)");
+			formula.AddFormulaItem("外币价", "【部门含税价】/【汇率】");
 
 			// 常量变量
-			formula.AddFormulaItem("部门利润率", softbed.dept_profitrate);
-			formula.AddFormulaItem("佣金点数", softbed.commission);
-			formula.AddFormulaItem("额外点数", softbed.other_rate);
-			formula.AddFormulaItem("额外费用", softbed.extras_cost);
-			formula.AddFormulaItem("FOB", 0);
-			formula.AddFormulaItem("汇率", softbed.moneyrate);
-			formula.AddFormulaItem("税率", softbed.taxrate);
+			formula.AddFormulaItem("部门利润率", softbed.dept_profitrate);
+			formula.AddFormulaItem("佣金点数", softbed.commission);
+			formula.AddFormulaItem("额外点数", softbed.other_rate);
+			formula.AddFormulaItem("额外费用", softbed.extras_cost);
+			formula.AddFormulaItem("FOB", 0);
+			formula.AddFormulaItem("汇率", softbed.moneyrate);
+			formula.AddFormulaItem("税率", softbed.taxrate);
         }
 
         private void InitMxReplaceMents(u_softbed softbed,u_softbed_mx mx)
         {
             // 默认公式变量
-            formula.AddFormulaItem("实际用量", "【用料量】*【1 + 损耗率】");
-            formula.AddFormulaItem("成本金额", "【实际用量】 * 【成本单价】");
+            formula.AddFormulaItem("实际用量", "【用料量】*【1 + 损耗率】");
+            formula.AddFormulaItem("成本金额", "【实际用量】 * 【成本单价】");
 
             // 常量变量
-            formula.AddFormulaItem("下料长", mx.cutting_length);
-            formula.AddFormulaItem("下料宽", mx.cutting_width);
-            formula.AddFormulaItem("下料数量", mx.cutting_qty);
-            formula.AddFormulaItem("用料量", mx.useqty);
-            formula.AddFormulaItem("损耗率", mx.loss_rate);
-            formula.AddFormulaItem("材料单价", mx.price);
+            formula.AddFormulaItem("下料长", mx.cutting_length);
+            formula.AddFormulaItem("下料宽", mx.cutting_width);
+            formula.AddFormulaItem("下料数量", mx.cutting_qty);
+            formula.AddFormulaItem("用料量", mx.useqty);
+            formula.AddFormulaItem("损耗率", mx.loss_rate);
+            formula.AddFormulaItem("材料单价", mx.price);
 
 			if(mx.formulaid > 0)
 			{
@@ -608,8 +608,8 @@ namespace JLHHJSvr.Helper
 				{
 					if(reader.Read())
 					{
-                        formula.AddFormulaItem("实际用量", Convert.ToString(reader["use_formula"]));
-                        formula.AddFormulaItem("成本单价", Convert.ToString(reader["price_formula"]));
+                        formula.AddFormulaItem("实际用量", Convert.ToString(reader["use_formula"]));
+                        formula.AddFormulaItem("成本单价", Convert.ToString(reader["price_formula"]));
                     }
 				}
 			}

+ 101 - 24
JLHHJSvr/Tools/CalculateFormula.cs

@@ -1,8 +1,10 @@
 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;
 
@@ -10,8 +12,8 @@ namespace JLHHJSvr.Tools
 {
     public class CalculateFormula
     {
-        private HashSet<FormulaItem> _formula;
-        private HashSet<FormulaItem> _const;
+        private HashSet<FormulaItem> _formula; // 公式
+        private HashSet<FormulaItem> _const; // 常量
 
         public CalculateFormula() 
         {
@@ -43,27 +45,110 @@ namespace JLHHJSvr.Tools
 
         public void AddFormulaItem(string name, string formula)
         {
-            var formulaItem = new FormulaItem() { formula_name = name, formula = formula }
+            var formulaItem = new FormulaItem() { formula_name = name, formula = formula };
             AddFormulaItem(formulaItem);
+        }
 
-            BuildFormulaGraph(formulaItem);
+        /// <summary>
+        /// 主计算入口
+        /// </summary>
+        public void CalculateAll()
+        {
+            var dict = _formula.ToDictionary(f => f.formula_name, f => f);
+            foreach (var c in _const)
+            {
+                dict[c.formula_name] = c;
+            }
+
+            var graph = BuildDependencyGraph(dict);
+            var sorted = TopologicalSort(graph);
+            foreach (var name in sorted)
+            {
+                var item = dict[name];
+                item.formula = ConvertToEnglishSymbols(item.formula);
+                // 展开
+                string expanded = ExpandFormula(item.formula, dict);
+                item.formula_transform = expanded;
+                // 计算
+                if (item.isSql) SqlCalculate(item);
+                else Calculate(item);
+            }
         }
 
-        // 构建拓扑图
-        private void BuildFormulaGraph(FormulaItem formula)
+        /// <summary>
+        /// 解析依赖
+        /// </summary>
+        private Dictionary<string, List<string>> BuildDependencyGraph(Dictionary<string, FormulaItem> dict)
         {
-            formula.graph = new List<string>();
-            // 定义正则表达式模式,匹配包含【】的内容
-            string pattern = @"【(.*?)】";
-            // 创建正则表达式对象
-            Regex regex = new Regex(pattern);
-            // 使用正则表达式匹配输入字符串
-            MatchCollection matches = regex.Matches(formula.formula);
-
-            foreach (Match match in matches)
+            var graph = new Dictionary<string, List<string>>();
+
+            foreach (var kv in dict)
             {
-                formula.graph.Add(match.Value);
+                var deps = new List<string>();
+
+                foreach (var name in dict.Keys)
+                {
+                    if (name == kv.Key) 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)
+            {
+                if (kv.Value.value != null) // 已经算过
+                {
+                    formula = Regex.Replace(formula, $"【{kv.Key}】", kv.Value.value.ToString());
+                }
+            }
+            return formula;
         }
 
         private string ConvertToEnglishSymbols(string input)
@@ -81,10 +166,6 @@ namespace JLHHJSvr.Tools
 
             return input;
         }
-        private void FormatExpression(FormulaItem formula)
-        {
-            formula.formula = ConvertToEnglishSymbols(formula.formula);
-        }
         /// <summary>
         /// 公式计算
         /// </summary>
@@ -93,8 +174,6 @@ namespace JLHHJSvr.Tools
         /// <returns></returns>
         private void Calculate(FormulaItem formula)
         {
-            FormatExpression(formula);
-
             try
             {
                 formula.value = LJExprParser.Parse(formula.formula).Result;
@@ -112,8 +191,6 @@ namespace JLHHJSvr.Tools
         /// <returns></returns>
         private void SqlCalculate(FormulaItem formula)
         {
-            FormatExpression(formula);
-
             try
             {
                 //cmd.CommandText = $@"{formula.formula}";