Browse Source

工位MES上传与本地记录优化,支持多工位压力

本次提交主要优化了工位数据上传MES和本地CSV记录功能,提升系统健壮性和数据一致性。主要变更包括:
- 压力值变量由单一变量改为数组,支持多工位压力独立记录。
- MES上传时间采用服务器时间,保证数据准确。
- 新增RecordStationResult方法,支持按工位和日期自动保存产品记录到CSV,异常时自动生成临时文件防止数据丢失。
- MES上传结果动态判断PASS/FAIL。
- 日志与消息提示更详细,便于追踪。
- 清理冗余代码,增强异常处理。
徐孝锋 6 months ago
parent
commit
b308887134
2 changed files with 136 additions and 46 deletions
  1. 135 44
      TeamAAS-VM/Core/Management.cs
  2. 1 2
      TeamAAS-VM/Services/MesService.cs

+ 135 - 44
TeamAAS-VM/Core/Management.cs

@@ -1262,7 +1262,11 @@ namespace TeamAAS_VP.Core
         Int16[] _LastMesCheck = new Int16[10];
         DateTime[] _LastMesCheckTime = new DateTime[10];
         Dictionary<string, string> mes_cc = new Dictionary<string, string>();
-        double currentPressure = 0;//当前的压力
+        /// <summary>
+        /// 当前压力值
+        /// </summary>
+        double[] currentPressure = new double[10];
+
         /// <summary>
         /// PLC命令触发时
         /// </summary>
@@ -2354,10 +2358,13 @@ namespace TeamAAS_VP.Core
                                 // 上传本站数据
                                 else if (state == 2)
                                 {
-                                    SendTaskMessage($"收到{i}上传本站数据请求...", MessageLevel.Debug);
+                                    //获取当前工位的配置
+                                    var stationConfig = _configService.GetDeviceInfo(i);
+                                    SendTaskMessage($"收到{i}:{stationConfig.DeviceName}上传本站数据请求...", MessageLevel.Debug);
+                                    //从服务器中获取当前时间
+                                    var serverTimeResult = await _mesService.GetServerTimeAsync(i, code, 2);
 
-                                    //这里缺少上传MES的本站数据结果及开始和结束时间,需要补充
-                                    double ct = DateTime.UtcNow.Subtract(_LastMesCheckTime[i]).TotalSeconds;
+                                    double ct = serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds;
                                     if (i == 0)
                                     {
                                         CTtime = ct;
@@ -2417,14 +2424,14 @@ namespace TeamAAS_VP.Core
                                     SendTaskMessage($"mes开始ADD", MessageLevel.Info);
                                     string assypress = ""; string cc = "";
                                     cc = string.Join(",", mes_cc.OrderBy(kv => kv.Key, StringComparer.Ordinal).Select(kv => kv.Value));
-                                    assypress = currentPressure.ToString("F2");
+                                    assypress = currentPressure[i].ToString("F2");
                                     var res = FileHelper.ReadJsonFile<PressureModel>(FilePath.PressureParamterConfigPath);
                                     if (res.PressureUpLimit > 0)
                                     {
 
                                     }
                                     //cc-复检cc,assypress-组装站压力
-                                    (bool isSuccess, string response) = await _mesService.SubmitGetAsync(i, ProductMainSN[i], comp, cc, assypress, resultIndex == 1 ? true : false, _LastMesCheckTime[i], DateTime.UtcNow);
+                                    (bool isSuccess, string response) = await _mesService.SubmitGetAsync(i, ProductMainSN[i], comp, cc, assypress, resultIndex == 1 ? true : false, _LastMesCheckTime[i], serverTimeResult.Now);
                                     if (isSuccess)
                                     {
                                         LogHelper.WriteLogMes($"上传mes成功");
@@ -2440,44 +2447,57 @@ namespace TeamAAS_VP.Core
                                     LogHelper.WriteLogMes($"【mes结束ADD】");
                                     SendTaskMessage($"mes结束ADD", MessageLevel.Info);
                                     mes_cc.Clear();
-                                    try
+
+                                    //是否保存当前的产品记录至CSV?
+                                    if (stationConfig.SaveCsv)
                                     {
-                                        #region 数据
-                                        var cdata = _configService.GetCTQDataInfo();//获取ctq数据参数
-                                        bool assyPress = true;
-                                        DFC.Clear();
-                                        DFC.Add(new DataFormCtq
+                                        //判断锁付路径字符串是否为空,如果不为空则保存,否则不保存
+                                        if (!string.IsNullOrEmpty(stationConfig.SaveCsvPath))
                                         {
-                                            PPID = ProductMainSN[i],
-                                            PROCESS_NAME = cdata.PROCESS_NAME,
-                                            PROCESS_START_TIME = StartCtqTime.ToString(),
-                                            CTQ_NAME = "CC",
-                                            CTQ_VALUE = cc.Replace(",", ";"),
-                                            //CTQ_VALUE = 0,
-                                            CTQ_LSL = 0,
-                                            CTQ_USL = 10,
-                                            PROCESS_END_TIME = DateTime.Now.ToString(),
-                                            SUPPLIER_NAME = cdata.SUPPLIER_NAME,
-                                            COMMODITY_TYPE = cdata.COMMODITY_TYPE,
-                                            REVISION = cdata.REVISION,
-                                            WO = wo[i],
-                                            MFG_LOT = cdata.MFG_LOT,
-                                            MFG_ASSY_LINE = cdata.MFG_ASSY_LINE,
-                                            PROCESS_OUTCOME = assyPress ? "PASS" : "FAIL",
-                                            PROCESS_MACHINE_ID = cdata.PROCESS_MACHINE_ID,
-                                            CTQ_UNIT_OF_MEASURE = "mm",
-                                            ERROR_MESSAGE = assyPress ? "" : "CC OOS"
-                                        });
-                                        foreach (var item in DFC)
+                                            var cdata = _configService.GetCTQDataInfo();//获取ctq数据参数
+                                            bool assyPress = resultIndex == 1 ? true : false;
+                                            DFC.Clear();
+                                            DFC.Add(new DataFormCtq
+                                            {
+                                                PPID = ProductMainSN[i],
+                                                PROCESS_NAME = cdata.PROCESS_NAME,
+                                                PROCESS_START_TIME = StartCtqTime.ToString(),
+                                                CTQ_NAME = "CC",
+                                                CTQ_VALUE = cc.Replace(",", ";"),
+                                                //CTQ_VALUE = 0,
+                                                CTQ_LSL = 0,
+                                                CTQ_USL = 10,
+                                                PROCESS_END_TIME = DateTime.Now.ToString(),
+                                                SUPPLIER_NAME = cdata.SUPPLIER_NAME,
+                                                COMMODITY_TYPE = cdata.COMMODITY_TYPE,
+                                                REVISION = cdata.REVISION,
+                                                WO = wo[i],
+                                                MFG_LOT = cdata.MFG_LOT,
+                                                MFG_ASSY_LINE = cdata.MFG_ASSY_LINE,
+                                                PROCESS_OUTCOME = assyPress ? "PASS" : "FAIL",
+                                                PROCESS_MACHINE_ID = cdata.PROCESS_MACHINE_ID,
+                                                CTQ_UNIT_OF_MEASURE = "mm",
+                                                ERROR_MESSAGE = assyPress ? "" : "CC OOS"
+                                            });
+
+                                            bool recordResult = RecordStationResult(i, DFC[0], ProductMainSN[i], serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath);
+                                            if (recordResult)
+                                            {
+                                                SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存成功", MessageLevel.Debug);
+                                            }
+                                            else
+                                            {
+                                                SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存失败", MessageLevel.Error);
+                                            }
+                                        }
+                                        else
                                         {
-                                            FileHelper.WriteDataToCSV(item);
+                                            SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存路径,无法保存产品记录", MessageLevel.Error);
                                         }
-                                        SendTaskMessage("CTQ数据存储完成", MessageLevel.Info);
-                                        #endregion
                                     }
-                                    catch (Exception ex)
+                                    else
                                     {
-                                        SendTaskMessage("CTQ数据存储时出错" + ex.Message, MessageLevel.Error);
+                                        SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存产品记录", MessageLevel.Debug);
                                     }
                                     return;
                                 }
@@ -2520,11 +2540,8 @@ namespace TeamAAS_VP.Core
                                 }
                             }
                         }
-                    }
-                    //开始/停止 组装/锁附
-                    for (int i = 0; i < 7; i++)
-                    {
-                        if (string.Format(addressConfig.In_WorkStart.Address, i).Contains(tuple.nodeId))
+                        //停止组装
+                        else if (string.Format(addressConfig.In_WorkStart.Address, i).Contains(tuple.nodeId))
                         {
                             if (tuple.value is Int16 state)
                             {
@@ -2548,7 +2565,7 @@ namespace TeamAAS_VP.Core
                                     //float pressure = plc.ReadNode<float>(addressConfig.In_PressureValue.Address);
                                     //读取压力值
                                     float pressure = plc.ReadNode<float>(string.Format(addressConfig.In_PressureValue.Address, i));
-                                    currentPressure = pressure;
+                                    currentPressure[i] = pressure;
                                     SendTaskMessage($"[{i}]压力:{pressure}", MessageLevel.Info);
 
                                     //await Task.Delay(60);
@@ -2859,6 +2876,80 @@ namespace TeamAAS_VP.Core
         }
         #endregion
 
+        /// <summary>
+        /// 记录工位的结果,其他工位要存储的数据项按照键值对集合的形式传入,键为数据项名称,值为数据项的值
+        /// </summary>
+        /// <param name="stationIndex"></param>
+        /// <param name="dfc"></param>
+        /// <param name="productMainSN"></param>
+        /// <param name="ct"></param>
+        /// <param name="timestamp"></param>
+        /// <param name="savePath"></param>
+        /// <param name="isFirstEnter"></param>
+        /// <returns></returns>
+        private bool RecordStationResult(int stationIndex, DataFormCtq dfc, string productMainSN, double ct, DateTime timestamp, string savePath, bool isFirstEnter = true)
+        {
+            try
+            {
+                //获取当前工位的配置
+                var stationConfig = _configService.GetDeviceInfo(stationIndex);
+                if (stationConfig == null) return false;
+                //如果保存路径为空,则不保存
+                if (string.IsNullOrEmpty(savePath)) return false;
+                string fullPath = savePath;
+                //如果保存路径是一个文件路径,则直接保存,否则按照工位和日期进行保存
+                if (File.Exists(savePath) || Path.HasExtension(savePath))
+                {
+                    fullPath = savePath;
+                    //如果路径不存在,则创建
+                    // 创建目录
+                    string directory = Path.GetDirectoryName(fullPath);
+                    if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
+                    {
+                        Directory.CreateDirectory(directory);
+                    }
+                }
+                else
+                {
+                    //结果保存至CSV文件,文件名格式:savePath\yyyy-MM\工位编号_工位名称_yyyy-MM-dd.csv
+                    string datePath = timestamp.ToString("yyyy-MM") + "\\";
+                    string dirPath = Path.Combine(savePath, datePath);
+                    if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
+                    string fileName = $"{stationIndex}_{stationConfig.DeviceName}_{timestamp.ToString("yyyy-MM-dd")}.csv";
+                    fullPath = Path.Combine(dirPath, fileName);
+                }
+                StringBuilder sb = new StringBuilder();
+                if (!File.Exists(fullPath))
+                {
+                    sb.Append("PPID,PROCESS_NAME,PROCESS_START_TIME,CTQ_NAME,CTQ_VALUE,CTQ_LSL,CTQ_USL,PROCESS_END_TIME,SUPPLIER_NAME,COMMODITY_TYPE,REVISION,WO#,MFG_LOT#," +
+                        "MFG_ASSY_LINE,PROCESS_OUTCOME,PROCESS_MACHINE_ID,CTQ_UNIT_OF_MEASURE,ERROR_MESSAGE");
+                    sb.AppendLine();
+                }
+                sb.Append($"{dfc.PPID},{dfc.PROCESS_NAME},{dfc.PROCESS_START_TIME},{dfc.CTQ_NAME},{dfc.CTQ_VALUE},{dfc.CTQ_LSL},{dfc.CTQ_USL},{dfc.PROCESS_END_TIME},{dfc.SUPPLIER_NAME},{dfc.COMMODITY_TYPE},{dfc.REVISION},{dfc.WO},{dfc.MFG_LOT},{dfc.MFG_ASSY_LINE},{dfc.PROCESS_OUTCOME},{dfc.PROCESS_MACHINE_ID},{dfc.CTQ_UNIT_OF_MEASURE},{dfc.ERROR_MESSAGE}");
+                sb.AppendLine();
+                // 使用 StreamWriter 以追加模式打开文件
+                StreamWriter sw = new StreamWriter(fullPath, true, Encoding.UTF8);
+                sw.Write(sb.ToString());
+                sw.Close();
+                sw.Dispose();
+                return true;
+            }
+            catch (Exception ex)
+            {
+                if (!isFirstEnter)
+                {
+                    return false;
+                }
+                LogHelper.WriteLogError("记录其他工位结果时出错!", ex);
+                //我希望在这里生成一个临时文件来保存这次的记录,因为如果本地文件被打开时可能会导致无法写入,如果不保存的话可能会丢失这次的记录,所以我想在这里生成一个临时文件来保存这次的记录
+                //生成临时文件的路径,格式为savePath\yyyy-MM\工位编号_yyyy-MM-dd_temp\工位编号_yyyy-MM-dd_HH-mm-ss-fff_temp.csv
+                string datePath = timestamp.ToString("yyyy-MM") + "\\";
+                string tempDirPath = Path.Combine(savePath, datePath, $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd")}_temp");
+                string tempFileName = $"{stationIndex}_{timestamp.ToString("yyyy-MM-dd_HH-mm-ss-fff")}_temp.csv";
+                RecordStationResult(stationIndex, dfc, productMainSN, ct, timestamp, tempFileName, false);
+                return false;
+            }
+        }
         #endregion
     }
 }

+ 1 - 2
TeamAAS-VM/Services/MesService.cs

@@ -286,8 +286,7 @@ namespace TeamAAS_VP.Services
                 }
             }
 
-            //string res = isSuccess ? "PASS" : "FAIL";
-            string res = "PASS";
+            string res = isSuccess ? "PASS" : "FAIL";
             string url = "";
             if (device.F == "PTL")
             {