Преглед изворни кода

自定义图片文件名格式与CTQ配置优化

新增图片文件名模板功能,支持变量与格式化;视觉流程图片保存支持自定义命名并界面实时预览。CTQ参数调整为每工位独立配置,界面与保存逻辑合并。接口适配多次拍照命名,提升灵活性和可维护性。版本号升级至1.2.2.1。
徐孝锋 пре 7 месеци
родитељ
комит
930ce1b3fb

+ 98 - 0
TeamAAS-VM/Core/FileNameTemplate.cs

@@ -0,0 +1,98 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace TeamAAS_VP.Core
+{
+    public class FileNameTemplate
+    {
+        private readonly string _template;
+        private readonly Dictionary<string, Func<object>> _variables;
+
+        public FileNameTemplate(string template)
+        {
+            _template = template ?? throw new ArgumentNullException(nameof(template));
+            _variables = new Dictionary<string, Func<object>>(StringComparer.OrdinalIgnoreCase);
+
+            // 注册内置变量
+            RegisterDefaultVariables();
+        }
+
+        // 注册自定义变量
+        public void RegisterVariable(string name, Func<object> valueProvider)
+        {
+            _variables[name] = valueProvider ?? throw new ArgumentNullException(nameof(valueProvider));
+        }
+
+        // 生成文件名
+        public string Generate()
+        {
+            string result = _template;
+
+            // 查找所有 {变量名[:格式化字符串]} 格式的占位符
+            var matches = Regex.Matches(_template, @"\{([^}:]+)(?::([^}]+))?\}");
+
+            foreach (Match match in matches)
+            {
+                string fullPlaceholder = match.Value;
+                string varName = match.Groups[1].Value;
+                string format = match.Groups[2].Success ? match.Groups[2].Value : null;
+
+                if (_variables.TryGetValue(varName, out var valueProvider))
+                {
+                    object value = valueProvider();
+                    string replacement = FormatValue(value, format);
+                    result = result.Replace(fullPlaceholder, replacement);
+                }
+            }
+
+            // 移除文件名中不允许的字符
+            result = SanitizeFileName(result);
+
+            return result;
+        }
+
+        private string FormatValue(object value, string format)
+        {
+            if (value == null) return "";
+
+            // 如果是日期时间类型,应用格式
+            if (value is DateTime dateTime && !string.IsNullOrEmpty(format))
+            {
+                return dateTime.ToString(format);
+            }
+
+            // 如果是数值类型,应用格式
+            if (value is IFormattable formattable && !string.IsNullOrEmpty(format))
+            {
+                return formattable.ToString(format, null);
+            }
+
+            return value.ToString();
+        }
+
+        private string SanitizeFileName(string fileName)
+        {
+            // 移除文件名中不允许的字符
+            char[] invalidChars = System.IO.Path.GetInvalidFileNameChars();
+            foreach (char c in invalidChars)
+            {
+                fileName = fileName.Replace(c.ToString(), "");
+            }
+            return fileName;
+        }
+
+        private void RegisterDefaultVariables()
+        {
+            // 日期时间变量
+            RegisterVariable("Now", () => DateTime.Now);
+            RegisterVariable("Today", () => DateTime.Today);
+            RegisterVariable("UtcNow", () => DateTime.UtcNow);
+
+            // 可以在这里添加更多内置变量
+        }
+    }
+}

+ 208 - 112
TeamAAS-VM/Core/Management.cs

@@ -1293,12 +1293,12 @@ namespace TeamAAS_VP.Core
                 }
 
                 //获取产品编码
-                _productService.CurrentProductCode = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, 0));
-                //如果产品编码为空,则以当前的时间戳作为编码
-                if (string.IsNullOrEmpty(_productService.CurrentProductCode))
-                {
-                    _productService.CurrentProductCode = DateTime.Now.ToString("yyyyMMddHHmmssfff");
-                }
+                //_productService.CurrentProductCode = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, 0));
+                ////如果产品编码为空,则以当前的时间戳作为编码
+                //if (string.IsNullOrEmpty(_productService.CurrentProductCode))
+                //{
+                //    _productService.CurrentProductCode = DateTime.Now.ToString("yyyyMMddHHmmssfff");
+                //}
 
                 // 触发下相机拍照
                 if (addressConfig.In_DowmCameraExe.Address.Contains(tuple.nodeId))
@@ -1781,7 +1781,6 @@ namespace TeamAAS_VP.Core
                             var headRecord = await _systemDatabaseService.GetLatestHeadChangeRecordAsync();
                             //最后一次的披头编号
                             string headNumber = headRecord != null ? headRecord.HeadBatchNumber : "N/A";
-                            var cdata = _configService.GetCTQDataInfo();//获取ctq数据参数
 
                             await Task.Delay(60);
                             //获取电批结果
@@ -1862,100 +1861,6 @@ namespace TeamAAS_VP.Core
                             await plc.WriteNodeAsync(addressConfig.In_WorkDone.Address, (Int16)0);
                             // 停止采集压力并保存
                             await StopAndSavePressureCollectionAsync(currentProduct.Name, _productService.CurrentProductCode, positionIndex);
-
-                            try
-                            {
-                                #region 数据
-                                DFC.Clear();
-                                bool torqueRes, turnRes, pressureRes;
-                                if (lockResult.LockTorque >= lockResult.TargetTorqueLowerLimit && lockResult.LockTorque <= lockResult.TargetTorqueUpperLimit)
-                                {
-                                    torqueRes = true;
-                                }
-                                else torqueRes = false;
-                                if (lockResult.Pressure >= cdata.CTQ_LSL_Pressure && lockResult.Pressure <= cdata.CTQ_USL_Pressure)
-                                {
-                                    pressureRes = true;
-                                }
-                                else pressureRes = false;
-                                if (lockResult.LockTurns >= lockResult.TargetTurnsLowerLimit && lockResult.LockTurns <= lockResult.TargetTurnsUpperLimit)
-                                {
-                                    turnRes = true;
-                                }
-                                else turnRes = false;
-                                DFC.Add(new DataFormCtq
-                                {
-                                    PPID = productSn,
-                                    PROCESS_NAME = cdata.PROCESS_NAME,
-                                    PROCESS_START_TIME = StartScrewTime.ToString(),
-                                    CTQ_NAME = "Torque",
-                                    CTQ_VALUE = lockResult.LockTorque,
-                                    CTQ_LSL = lockResult.TargetTorqueLowerLimit,
-                                    CTQ_USL = lockResult.TargetTorqueUpperLimit,
-                                    PROCESS_END_TIME = DateTime.Now.ToString(),
-                                    SUPPLIER_NAME = cdata.SUPPLIER_NAME,
-                                    COMMODITY_TYPE = cdata.COMMODITY_TYPE,
-                                    REVISION = cdata.REVISION,
-                                    WO = wo,
-                                    MFG_LOT = cdata.MFG_LOT,
-                                    MFG_ASSY_LINE = cdata.MFG_ASSY_LINE,
-                                    PROCESS_OUTCOME = torqueRes ? "PASS" : "FAIL",
-                                    PROCESS_MACHINE_ID = cdata.PROCESS_MACHINE_ID,
-                                    CTQ_UNIT_OF_MEASURE = "kgf.cm",
-                                    ERROR_MESSAGE = torqueRes ? "" : "Torque_Spec OOS"
-                                });
-                                DFC.Add(new DataFormCtq
-                                {
-                                    PPID = productSn,
-                                    PROCESS_NAME = cdata.PROCESS_NAME,
-                                    PROCESS_START_TIME = StartScrewTime.ToString(),
-                                    CTQ_NAME = "Turn",
-                                    CTQ_VALUE = lockResult.LockTurns,
-                                    CTQ_LSL = lockResult.TargetTurnsLowerLimit,
-                                    CTQ_USL = lockResult.TargetTurnsUpperLimit,
-                                    PROCESS_END_TIME = DateTime.Now.ToString(),
-                                    SUPPLIER_NAME = cdata.SUPPLIER_NAME,
-                                    COMMODITY_TYPE = cdata.COMMODITY_TYPE,
-                                    REVISION = cdata.REVISION,
-                                    WO = wo,
-                                    MFG_LOT = cdata.MFG_LOT,
-                                    MFG_ASSY_LINE = cdata.MFG_ASSY_LINE,
-                                    PROCESS_OUTCOME = turnRes ? "PASS" : "FAIL",
-                                    PROCESS_MACHINE_ID = cdata.PROCESS_MACHINE_ID,
-                                    CTQ_UNIT_OF_MEASURE = "圈",
-                                    ERROR_MESSAGE = turnRes ? "" : "Turn_Spec OOS"
-                                });
-                                DFC.Add(new DataFormCtq
-                                {
-                                    PPID = productSn,
-                                    PROCESS_NAME = cdata.PROCESS_NAME,
-                                    PROCESS_START_TIME = StartScrewTime.ToString(),
-                                    CTQ_NAME = "Pressure",
-                                    CTQ_VALUE = lockResult.Pressure,
-                                    CTQ_LSL = cdata.CTQ_LSL_Pressure,
-                                    CTQ_USL = cdata.CTQ_USL_Pressure,
-                                    PROCESS_END_TIME = DateTime.Now.ToString(),
-                                    SUPPLIER_NAME = cdata.SUPPLIER_NAME,
-                                    COMMODITY_TYPE = cdata.COMMODITY_TYPE,
-                                    REVISION = cdata.REVISION,
-                                    WO = wo,
-                                    MFG_LOT = cdata.MFG_LOT,
-                                    MFG_ASSY_LINE = cdata.MFG_ASSY_LINE,
-                                    PROCESS_OUTCOME = pressureRes ? "PASS" : "FAIL",
-                                    PROCESS_MACHINE_ID = cdata.PROCESS_MACHINE_ID,
-                                    CTQ_UNIT_OF_MEASURE = "N",
-                                    ERROR_MESSAGE = pressureRes ? "" : "Pressure_Spec OOS"
-                                });
-                                foreach (var item in DFC)
-                                {
-                                    FileHelper.WriteDataToCSV(item);
-                                }
-                                #endregion
-                            }
-                            catch (Exception ex)
-                            {
-                                SendTaskMessage("CTQ数据存储时出错" + ex.Message, MessageLevel.Error);
-                            }
                         }
                         else
                         {
@@ -2162,7 +2067,7 @@ namespace TeamAAS_VP.Core
                                     var _cts = new CancellationTokenSource();
 
                                     await _remoteCommandService.SetLightBeforePhoto(qrCodeProcess);
-                                    var qrCodeResult = _remoteCommandService.ExecutePhoto(qrCodeProcess, out CogToolBlockTerminalCollection outputCollection);
+                                    var qrCodeResult = _remoteCommandService.ExecutePhoto(i + 1, qrCodeProcess, out CogToolBlockTerminalCollection outputCollection);
 
                                     if (qrCodeResult && outputCollection.Contains("QR"))
                                     {
@@ -2243,6 +2148,10 @@ namespace TeamAAS_VP.Core
                                                     if (snItem != null)
                                                     {
                                                         ProductMainSN[i] = snItem.Replace("sn=", "").Trim();
+                                                        if (i == 0)
+                                                        {
+                                                            _productService.CurrentProductCode = ProductMainSN[i];
+                                                        }
                                                         SendTaskMessage($"产品主sn:{ProductMainSN[i]}", MessageLevel.Info);
                                                     }
                                                     if (woItem != null)
@@ -2300,6 +2209,10 @@ namespace TeamAAS_VP.Core
                                                 if (snItem != null)
                                                 {
                                                     ProductMainSN[i] = snItem.Replace("sn=", "").Trim();
+                                                    if (i == 0)
+                                                    {
+                                                        _productService.CurrentProductCode = ProductMainSN[i];
+                                                    }
                                                     SendTaskMessage($"产品主sn:{ProductMainSN[i]}", MessageLevel.Info);
                                                 }
                                                 if (woItem != null)
@@ -2330,6 +2243,8 @@ namespace TeamAAS_VP.Core
                                 // 上传本站数据
                                 else if (state == 2)
                                 {
+                                    DFC.Clear();
+
                                     //获取当前工位的配置
                                     var stationConfig = _configService.GetDeviceInfo(i);
                                     SendTaskMessage($"收到{i}:{stationConfig.DeviceName}上传本站数据请求...", MessageLevel.Debug);
@@ -2388,17 +2303,117 @@ namespace TeamAAS_VP.Core
                                             bool recordResult = false;
                                             if (i == 0)
                                             {
-                                                recordResult = RecordLockResult(i, lockResultsAll, ProductMainSN[i], serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath);
-                                            }
-                                            else
-                                            {
-                                                Dictionary<string,string> dataItems = new Dictionary<string, string>();
-                                                //结果
-                                                dataItems.Add("Result", resultIndex == 1 ? "OK" : "NG");
-                                                //压力值
-                                                //dataItems.Add("Pressure", pressure);
-                                                recordResult = RecordOtherStationResult(i, dataItems, ProductMainSN[i], serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath);
+                                                foreach (var lockResult in lockResultsAll)
+                                                {
+                                                    bool torqueRes, turnRes, pressureRes;
+                                                    if (lockResult.LockTorque >= lockResult.TargetTorqueLowerLimit && lockResult.LockTorque <= lockResult.TargetTorqueUpperLimit)
+                                                    {
+                                                        torqueRes = true;
+                                                    }
+                                                    else torqueRes = false;
+                                                    if (lockResult.Pressure >= stationConfig.DataInfo.CTQ_LSL_Pressure && lockResult.Pressure <= stationConfig.DataInfo.CTQ_USL_Pressure)
+                                                    {
+                                                        pressureRes = true;
+                                                    }
+                                                    else pressureRes = false;
+                                                    if (lockResult.LockTurns >= lockResult.TargetTurnsLowerLimit && lockResult.LockTurns <= lockResult.TargetTurnsUpperLimit)
+                                                    {
+                                                        turnRes = true;
+                                                    }
+                                                    else turnRes = false;
+                                                    DFC.Add(new DataFormCtq
+                                                    {
+                                                        PPID = ProductMainSN[i],
+                                                        PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
+                                                        PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
+                                                        CTQ_NAME = "Torque",
+                                                        CTQ_VALUE = lockResult.LockTorque,
+                                                        CTQ_LSL = lockResult.TargetTorqueLowerLimit,
+                                                        CTQ_USL = lockResult.TargetTorqueUpperLimit,
+                                                        PROCESS_END_TIME = serverTimeResult.Now.ToString(),
+                                                        SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
+                                                        COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
+                                                        REVISION = stationConfig.DataInfo.REVISION,
+                                                        WO = wo,
+                                                        MFG_LOT = stationConfig.DataInfo.MFG_LOT,
+                                                        MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
+                                                        PROCESS_OUTCOME = torqueRes ? "PASS" : "FAIL",
+                                                        PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
+                                                        CTQ_UNIT_OF_MEASURE = "kgf.cm",
+                                                        ERROR_MESSAGE = torqueRes ? "" : "Torque_Spec OOS"
+                                                    });
+                                                    DFC.Add(new DataFormCtq
+                                                    {
+                                                        PPID = ProductMainSN[i],
+                                                        PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
+                                                        PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
+                                                        CTQ_NAME = "Turn",
+                                                        CTQ_VALUE = lockResult.LockTurns,
+                                                        CTQ_LSL = lockResult.TargetTurnsLowerLimit,
+                                                        CTQ_USL = lockResult.TargetTurnsUpperLimit,
+                                                        PROCESS_END_TIME = serverTimeResult.Now.ToString(),
+                                                        SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
+                                                        COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
+                                                        REVISION = stationConfig.DataInfo.REVISION,
+                                                        WO = wo,
+                                                        MFG_LOT = stationConfig.DataInfo.MFG_LOT,
+                                                        MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
+                                                        PROCESS_OUTCOME = turnRes ? "PASS" : "FAIL",
+                                                        PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
+                                                        CTQ_UNIT_OF_MEASURE = "圈",
+                                                        ERROR_MESSAGE = turnRes ? "" : "Turn_Spec OOS"
+                                                    });
+                                                    DFC.Add(new DataFormCtq
+                                                    {
+                                                        PPID = ProductMainSN[i],
+                                                        PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
+                                                        PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
+                                                        CTQ_NAME = "Pressure",
+                                                        CTQ_VALUE = lockResult.Pressure,
+                                                        CTQ_LSL = stationConfig.DataInfo.CTQ_LSL_Pressure,
+                                                        CTQ_USL = stationConfig.DataInfo.CTQ_USL_Pressure,
+                                                        PROCESS_END_TIME = serverTimeResult.Now.ToString(),
+                                                        SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
+                                                        COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
+                                                        REVISION = stationConfig.DataInfo.REVISION,
+                                                        WO = wo,
+                                                        MFG_LOT = stationConfig.DataInfo.MFG_LOT,
+                                                        MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
+                                                        PROCESS_OUTCOME = pressureRes ? "PASS" : "FAIL",
+                                                        PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
+                                                        CTQ_UNIT_OF_MEASURE = "N",
+                                                        ERROR_MESSAGE = pressureRes ? "" : "Pressure_Spec OOS"
+                                                    });
+                                                }
                                             }
+                                            //else
+                                            //{
+                                            //    DFC.Add(new DataFormCtq
+                                            //    {
+                                            //        PPID = ProductMainSN[i],
+                                            //        PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
+                                            //        PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
+                                            //        CTQ_NAME = "Pressure",
+                                            //        CTQ_VALUE = lockResult.Pressure,
+                                            //        CTQ_LSL = stationConfig.DataInfo.CTQ_LSL_Pressure,
+                                            //        CTQ_USL = stationConfig.DataInfo.CTQ_USL_Pressure,
+                                            //        PROCESS_END_TIME = serverTimeResult.Now.ToString(),
+                                            //        SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
+                                            //        COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
+                                            //        REVISION = stationConfig.DataInfo.REVISION,
+                                            //        WO = wo,
+                                            //        MFG_LOT = stationConfig.DataInfo.MFG_LOT,
+                                            //        MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
+                                            //        PROCESS_OUTCOME = pressureRes ? "PASS" : "FAIL",
+                                            //        PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
+                                            //        CTQ_UNIT_OF_MEASURE = "N",
+                                            //        ERROR_MESSAGE = pressureRes ? "" : "Pressure_Spec OOS"
+                                            //    });
+                                            //    //压力值
+                                            //    //dataItems.Add("Pressure", pressure);
+                                            //    recordResult = RecordOtherStationResult(i, dataItems, ProductMainSN[i], serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath);
+                                            //}
+                                            recordResult = RecordStationResult(i, DFC, ProductMainSN[i], serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath);
                                             if (recordResult)
                                             {
                                                 SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存成功", MessageLevel.Debug);
@@ -2927,6 +2942,87 @@ namespace TeamAAS_VP.Core
             }
         }
 
+        /// <summary>
+        /// 记录工位的结果,其他工位要存储的数据项按照键值对集合的形式传入,键为数据项名称,值为数据项的值
+        /// </summary>
+        /// <param name="stationIndex"></param>
+        /// <param name="dfcs"></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, IEnumerable<DataFormCtq> dfcs, 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();
+                }
+                if (dfcs == null || dfcs.Count() == 0)
+                {
+                    return false;
+                }
+                foreach (var dfc in dfcs)
+                {
+                    sb.Append($"{dfc.PPID},{dfc.PROCESS_NAME},{dfc.PROCESS_START_TIME},{dfc.CTQ_NAME},{dfc.CTQ_VALUE:F3},{dfc.CTQ_LSL:F3},{dfc.CTQ_USL:F3},{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, dfcs, productMainSN, ct, timestamp, tempFileName, false);
+                return false;
+            }
+        }
         #endregion
 
         #endregion

+ 0 - 3
TeamAAS-VM/Interfaces/IConfigService.cs

@@ -538,8 +538,5 @@ namespace TeamAAS_VP.Interfaces
         void SaveTorqueReaderConfig(TorqueSerialPortConfig config);
 
         TorqueSerialPortConfig GetTorqueReaderConfig();
-
-        CTQ_Data GetCTQDataInfo();
-        void SaveCTQDataInfo(CTQ_Data cd);
     }
 }

+ 3 - 2
TeamAAS-VM/Interfaces/IRemoteCommandService.cs

@@ -235,18 +235,19 @@ namespace TeamAAS_VP.Interfaces
         /// <summary>
         /// 执行相机拍照
         /// </summary>
+        /// <param name="index"></param>
         /// <param name="procedure"></param>
         /// <param name="InputTerminal"></param>
         /// <param name="outputCollection"></param>
         /// <returns></returns>
-        bool ExecutePhoto(ProcedureModel procedure, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection, ImageParameters imgPara);
+        bool ExecutePhoto(int index, ProcedureModel procedure, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection, ImageParameters imgPara);
         /// <summary>
         /// 执行拍照二维码流程运行
         /// </summary>
         /// <param name="procedure"></param>
         /// <param name="outputCollection"></param>
         /// <returns></returns>
-        bool ExecutePhoto(ProcedureModel procedure, out CogToolBlockTerminalCollection outputCollection);
+        bool ExecutePhoto(int index, ProcedureModel procedure, out CogToolBlockTerminalCollection outputCollection);
 
         /// <summary>
         /// 执行相机拍照获取单个点位结果

+ 48 - 1
TeamAAS-VM/Models/CTQ_Data.cs

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 
 namespace TeamAAS_VP.Models
 {
-    public class CTQ_Data:BindableBase
+    public class CTQ_Data : BindableBase
     {
         private string _PPID;
         /// <summary>
@@ -129,5 +129,52 @@ namespace TeamAAS_VP.Models
         /// </summary>
         public string ERROR_MESSAGE { get => _ERROR_MESSAGE; set => SetProperty(ref _ERROR_MESSAGE, value); }
 
+        public CTQ_Data()
+        {
+            PPID = string.Empty;
+            PROCESS_NAME = string.Empty;
+            PROCESS_START_TIME = string.Empty;
+            CTQ_NAME = string.Empty;
+            CTQ_VALUE = 0.0;
+            CTQ_LSL_Pressure = 0.0;
+            CTQ_USL_Pressure = 0.0;
+            PROCESS_END_TIME = string.Empty;
+            SUPPLIER_NAME = string.Empty;
+            COMMODITY_TYPE = string.Empty;
+            REVISION = string.Empty;
+            WO = string.Empty;
+            MFG_LOT = string.Empty;
+            MFG_ASSY_LINE = string.Empty;
+            PROCESS_OUTCOME = string.Empty;
+            PROCESS_MACHINE_ID = string.Empty;
+            CTQ_UNIT_OF_MEASURE = string.Empty;
+            ERROR_MESSAGE = string.Empty;
+        }
+
+        public CTQ_Data Copy()
+        {
+            return new CTQ_Data
+            {
+                PPID = this.PPID,
+                PROCESS_NAME = this.PROCESS_NAME,
+                PROCESS_START_TIME = this.PROCESS_START_TIME,
+                CTQ_NAME = this.CTQ_NAME,
+                CTQ_VALUE = this.CTQ_VALUE,
+                CTQ_LSL_Pressure = this.CTQ_LSL_Pressure,
+                CTQ_USL_Pressure = this.CTQ_USL_Pressure,
+                PROCESS_END_TIME = this.PROCESS_END_TIME,
+                SUPPLIER_NAME = this.SUPPLIER_NAME,
+                COMMODITY_TYPE = this.COMMODITY_TYPE,
+                REVISION = this.REVISION,
+                WO = this.WO,
+                MFG_LOT = this.MFG_LOT,
+                MFG_ASSY_LINE = this.MFG_ASSY_LINE,
+                PROCESS_OUTCOME = this.PROCESS_OUTCOME,
+                PROCESS_MACHINE_ID = this.PROCESS_MACHINE_ID,
+                CTQ_UNIT_OF_MEASURE = this.CTQ_UNIT_OF_MEASURE,
+                ERROR_MESSAGE = this.ERROR_MESSAGE
+            };
+        }
+
     }
 }

+ 27 - 0
TeamAAS-VM/Models/DeviceInfo.cs

@@ -90,6 +90,12 @@ namespace TeamAAS_VP.Models
         /// </summary>
         public bool EnableDoubleMes { get => _enableDoubleMes; set => SetProperty(ref _enableDoubleMes, value); }
 
+        private CTQ_Data _dataInfo = new CTQ_Data();
+        public CTQ_Data DataInfo
+        {
+            get { return _dataInfo; }
+            set { SetProperty(ref _dataInfo, value); }
+        }
 
         public DeviceInfo()
         {
@@ -102,5 +108,26 @@ namespace TeamAAS_VP.Models
             MesUrl = string.Empty;
             EnableMES = false;
         }
+
+        public DeviceInfo Copy()
+        {
+            return new DeviceInfo
+            {
+                DeviceNo = this.DeviceNo,
+                DeviceName = this.DeviceName,
+                DeviceDesc = this.DeviceDesc,
+                Line = this.Line,
+                Station = this.Station,
+                FixtureId = this.FixtureId,
+                F = this.F,
+                comp = this.comp,
+                MesUrl = this.MesUrl,
+                EnableMES = this.EnableMES,
+                SaveCsv = this.SaveCsv,
+                SaveCsvPath = this.SaveCsvPath,
+                EnableDoubleMes = this.EnableDoubleMes,
+                DataInfo = this.DataInfo.Copy()
+            };
+        }
     }
 }

+ 12 - 0
TeamAAS-VM/Models/Product/ProcedureModel.cs

@@ -284,6 +284,17 @@ namespace TeamAAS_VP.Models
             set { SetProperty(ref _SavePath, value); }
         }
 
+        //用户定义的图片文件名格式,例如:{ProductSN}_Daisy_KB Screw _01 _{CameraName}-Locate_{ShotCount}_WhiteRingLight_{Result}_{DateTime:yyyy-MM-dd_HH-mm-ss}.png
+        private string _ImageFileNameFormat;
+        /// <summary>
+        /// 用户定义的图片文件名格式,例如:{ProductSN}_Daisy_KB Screw _01 _{CameraName}-Locate_{ShotCount}_WhiteRingLight_{Result}_{DateTime:yyyy-MM-dd_HH-mm-ss}.png
+        /// </summary>
+        public string ImageFileNameFormat
+        {
+            get { return _ImageFileNameFormat; }
+            set { SetProperty(ref _ImageFileNameFormat, value); }
+        }
+
         private bool _IsCompress;
         /// <summary>
         /// 是否压缩图片
@@ -408,6 +419,7 @@ namespace TeamAAS_VP.Models
                 SaveImageModel = this.SaveImageModel,
                 SaveImagePathModel = this.SaveImagePathModel,
                 SavePath = this.SavePath,
+                ImageFileNameFormat=this.ImageFileNameFormat,
                 IsCompress = this.IsCompress,
                 FeederFindFrequency = this.FeederFindFrequency?.Copy(),
                 IsExcludeNearPoint=this.IsExcludeNearPoint,

+ 11 - 0
TeamAAS-VM/Models/ShowRender.cs

@@ -101,6 +101,17 @@ namespace TeamAAS_VP.Models
             set { SetProperty(ref _SavePath, value); }
         }
 
+        //用户定义的图片文件名
+        private string _ImageFileName;
+        /// <summary>
+        /// 用户定义的图片文件名
+        /// </summary>
+        public string ImageFileName
+        {
+            get { return _ImageFileName; }
+            set { SetProperty(ref _ImageFileName, value); }
+        }
+
         private bool _IsCompress;
         /// <summary>
         /// 是否压缩图片

+ 2 - 2
TeamAAS-VM/Properties/AssemblyInfo.cs

@@ -51,5 +51,5 @@ using System.Windows;
 //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
 //通过使用 "*",如下所示:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.2.2.0")]
-[assembly: AssemblyFileVersion("1.2.2.0")]
+[assembly: AssemblyVersion("1.2.2.1")]
+[assembly: AssemblyFileVersion("1.2.2.1")]

+ 0 - 48
TeamAAS-VM/Services/ConfigService.cs

@@ -55,8 +55,6 @@ namespace TeamAAS_VP.Services
             public static readonly string CardReaderConfigurationPath = "..//Config//CardReaderConfiguration.cfg";
             // ��������·��
             public static readonly string TorqueReaderConfigurationPath = "..//Config//TorqueReaderConfiguration.cfg";
-            // ������������·��
-            public static readonly string DataConfigurationPath = "..//Config//DataConfiguration.cfg";
         }
 
         private readonly object _sync = new object();
@@ -250,14 +248,6 @@ namespace TeamAAS_VP.Services
                     _cardReaderConfig = new SerialPortConfig();
                     FileHelper.WriteJsonFile(_cardReaderConfig, ConfigPaths.CardReaderConfigurationPath);
                 }
-
-                if (File.Exists(ConfigPaths.DataConfigurationPath))
-                    CtqData = FileHelper.ReadJsonFile<CTQ_Data>(ConfigPaths.DataConfigurationPath);
-                else
-                {
-                    CtqData = new CTQ_Data();
-                    FileHelper.WriteJsonFile(CtqData, ConfigPaths.DataConfigurationPath);
-                }
             }
         }
 
@@ -300,8 +290,6 @@ namespace TeamAAS_VP.Services
                 // save card reader config
                 if (_cardReaderConfig != null)
                     FileHelper.WriteJsonFile(_cardReaderConfig, ConfigPaths.CardReaderConfigurationPath);
-                if (CtqData != null)
-                    FileHelper.WriteJsonFile(CtqData, ConfigPaths.DataConfigurationPath);
             }
         }
 
@@ -562,42 +550,6 @@ namespace TeamAAS_VP.Services
         }
         #endregion
 
-        #region CTQData
-        /// <summary>
-        /// ��ȡCTQ��Ϣ����
-        /// </summary>
-        public CTQ_Data GetCTQDataInfo()
-        {
-            lock (_sync)
-            {
-                if (CtqData == null)
-                {
-                    if (File.Exists(ConfigPaths.DataConfigurationPath))
-                        CtqData = FileHelper.ReadJsonFile<CTQ_Data>(ConfigPaths.DataConfigurationPath);
-                    else
-                    {
-                        CtqData = new CTQ_Data();
-                        FileHelper.WriteJsonFile(CtqData, ConfigPaths.DataConfigurationPath);
-                    }
-                }
-                return CtqData;
-            }
-        }
-
-        /// <summary>
-        /// ����CTQ��Ϣ
-        /// </summary>
-        public void SaveCTQDataInfo(CTQ_Data cd)
-        {
-            if (cd == null) return;
-            lock (_sync)
-            {
-                CtqData = cd;
-                FileHelper.WriteJsonFile(CtqData, ConfigPaths.DataConfigurationPath);
-            }
-        }
-        #endregion
-
         #region Robots
         /// <summary>
         /// ��ȡ���л��������õ�ֻ�����ϡ�

+ 91 - 11
TeamAAS-VM/Services/RemoteCommandService.cs

@@ -3,6 +3,8 @@ using Cognex.VisionPro.ToolBlock;
 using MathNet.Numerics.LinearAlgebra;
 using Microsoft.CodeAnalysis.Scripting;
 using NPOI.SS.Formula.Functions;
+using NPOI.SS.UserModel;
+using NPOI.XSSF.Streaming.Values;
 using Org.BouncyCastle.Tls;
 using Prism.Events;
 using Prism.Ioc;
@@ -1187,7 +1189,7 @@ namespace TeamAAS_VP.Services
                 SendTaskMessage(Lang.开始执行视觉流程.Replace("{0}", $"{i + 1}").Replace("{1}", procedure.Name), MessageLevel.Info);
 
                 // 1. 执行相机拍照并运行视觉工具
-                bool visionSucceed = ExecutePhoto(procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection, imgPara);
+                bool visionSucceed = ExecutePhoto(i + 1,procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection, imgPara);
                 if (!visionSucceed)
                 {
                     SendTaskMessage(Lang.视觉任务执行失败, MessageLevel.Error);
@@ -1376,7 +1378,7 @@ namespace TeamAAS_VP.Services
                     }
                     // 1. 执行相机拍照并运行视觉工具
                     LogHelper.WriteLogInfo(Lang.开始执行相机拍照并运行视觉工具);
-                    bool visionSucceed = ExecutePhoto(procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection, imgPara);
+                    bool visionSucceed = ExecutePhoto(i + 1, procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection, imgPara);
                     if (!visionSucceed)
                     {
                         SendTaskMessage(Lang.视觉任务执行失败, MessageLevel.Error);
@@ -1454,7 +1456,7 @@ namespace TeamAAS_VP.Services
         /// 执行相机拍照并运行 ToolBlock,返回是否成功并通过 out 参数返回 Outputs。
         /// 该方法会发布 RenderUpdateNotification 以更新 UI。
         /// </summary>
-        public bool ExecutePhoto(ProcedureModel procedure, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection, ImageParameters imgPara)
+        public bool ExecutePhoto(int index,ProcedureModel procedure, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection, ImageParameters imgPara)
         {
             try
             {
@@ -1517,13 +1519,32 @@ namespace TeamAAS_VP.Services
                         if (item.Value is ICogRecord)
                             record = item.Value as ICogRecord;
                     }
+                    bool Found = (bool)(outputCollection["Found"].Value);
+                    //获取图片存储的图片文件名
+                    string imgName = string.Empty;
+                    if (procedure.IsSaveImage && !string.IsNullOrEmpty(procedure.ImageFileNameFormat))
+                    {
+                        // 创建模板,使用 {变量名:格式} 语法
+                        var template = new FileNameTemplate(procedure.ImageFileNameFormat);
+
+                        // 注册变量
+                        template.RegisterVariable("ProductSN", () => _productService.CurrentProductCode);
+                        template.RegisterVariable("CameraName", () => procedure.CameraName);
+                        template.RegisterVariable("ShotCount", () => index);
+                        template.RegisterVariable("Result", () => Found ? "OK":"NG");
+                        template.RegisterVariable("DateTime", () => DateTime.Now);
+
+                        // 生成文件名
+                        imgName = template.Generate();
+                    }
+
                     _eventAggregator.GetEvent<RenderUpdateNotification>().Publish(new ShowRender()
                     {
                         Id = procedure.Id,
                         Image = (ICogImage)procedure.ToolBlock.Inputs["InputImage"].Value,
                         Graphic = outputCollection["Graphic"].Value as CogGraphicCollection,
                         Record = record,
-                        Result = (bool)(outputCollection["Found"].Value),
+                        Result = Found,
                         IsShow = true,
                         IsSaveImage = procedure.IsSaveImage,
                         SaveImageModel = procedure.SaveImageModel,
@@ -1531,6 +1552,7 @@ namespace TeamAAS_VP.Services
                         SavePath = procedure.SavePath,
                         IsCompress = procedure.IsCompress,
                         ImgPara = imgPara,
+                        ImageFileName = imgName
                     });
                     SendTaskMessage($"{procedure.CameraName},{procedure.CameraId}", MessageLevel.Info);
                     return true;
@@ -1540,6 +1562,24 @@ namespace TeamAAS_VP.Services
                     SendTaskMessage(Lang.视觉流程执行出错耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Error);
                     SendTaskMessage(procedure.ToolBlock.RunStatus.Message, MessageLevel.Error);
                     outputCollection = null;
+
+                    //获取图片存储的图片文件名
+                    string imgName = string.Empty;
+                    if (procedure.IsSaveImage && !string.IsNullOrEmpty(procedure.ImageFileNameFormat))
+                    {
+                        // 创建模板,使用 {变量名:格式} 语法
+                        var template = new FileNameTemplate(procedure.ImageFileNameFormat);
+
+                        // 注册变量
+                        template.RegisterVariable("ProductSN", () => _productService.CurrentProductCode);
+                        template.RegisterVariable("CameraName", () => procedure.CameraName);
+                        template.RegisterVariable("ShotCount", () => index);
+                        template.RegisterVariable("Result", () => "NG");
+                        template.RegisterVariable("DateTime", () => DateTime.Now);
+
+                        // 生成文件名
+                        imgName = template.Generate();
+                    }
                     _eventAggregator.GetEvent<RenderUpdateNotification>().Publish(new ShowRender()
                     {
                         Id = procedure.Id,
@@ -1552,6 +1592,7 @@ namespace TeamAAS_VP.Services
                         SaveImagePathModel = procedure.SaveImagePathModel,
                         SavePath = procedure.SavePath,
                         ProceductName = procedure.Name,
+                        ImageFileName = imgName
                     });
                     return false;
                 }
@@ -1570,7 +1611,7 @@ namespace TeamAAS_VP.Services
         /// <param name="procedure"></param>
         /// <param name="outputCollection"></param>
         /// <returns></returns>
-        public bool ExecutePhoto(ProcedureModel procedure, out CogToolBlockTerminalCollection outputCollection)
+        public bool ExecutePhoto(int index, ProcedureModel procedure, out CogToolBlockTerminalCollection outputCollection)
         {
             try
             {
@@ -1615,20 +1656,40 @@ namespace TeamAAS_VP.Services
                         if (item.Value is ICogRecord)
                             record = item.Value as ICogRecord;
                     }
+
+                    bool Found = (bool)(outputCollection["Found"].Value);
+                    //获取图片存储的图片文件名
+                    string imgName = string.Empty;
+                    if (procedure.IsSaveImage && !string.IsNullOrEmpty(procedure.ImageFileNameFormat))
+                    {
+                        // 创建模板,使用 {变量名:格式} 语法
+                        var template = new FileNameTemplate(procedure.ImageFileNameFormat);
+
+                        // 注册变量
+                        template.RegisterVariable("ProductSN", () => _productService.CurrentProductCode);
+                        template.RegisterVariable("CameraName", () => procedure.CameraName);
+                        template.RegisterVariable("ShotCount", () => index);
+                        template.RegisterVariable("Result", () => Found ? "OK" : "NG");
+                        template.RegisterVariable("DateTime", () => DateTime.Now);
+
+                        // 生成文件名
+                        imgName = template.Generate();
+                    }
                     _eventAggregator.GetEvent<RenderUpdateNotification>().Publish(new ShowRender()
                     {
                         Id = procedure.Id,
                         Image = (ICogImage)procedure.ToolBlock.Inputs["InputImage"].Value,
                         Graphic = outputCollection["Graphic"].Value as CogGraphicCollection,
                         Record = record,
-                        Result = (bool)(outputCollection["Found"].Value),
+                        Result = Found,
                         IsShow = true,
                         IsSaveImage = procedure.IsSaveImage,
                         SaveImageModel = procedure.SaveImageModel,
                         SaveImagePathModel = procedure.SaveImagePathModel,
                         SavePath = procedure.SavePath,
                         IsCompress = procedure.IsCompress,
-                        ProceductName = procedure.Name
+                        ProceductName = procedure.Name,
+                        ImageFileName = imgName
                     });
                     SendTaskMessage($"{procedure.CameraName},{procedure.CameraId}", MessageLevel.Info);
                     return true;
@@ -1638,6 +1699,24 @@ namespace TeamAAS_VP.Services
                     SendTaskMessage(Lang.视觉流程执行出错耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Error);
                     SendTaskMessage(procedure.ToolBlock.RunStatus.Message, MessageLevel.Error);
                     outputCollection = null;
+
+                    //获取图片存储的图片文件名
+                    string imgName = string.Empty;
+                    if (procedure.IsSaveImage && !string.IsNullOrEmpty(procedure.ImageFileNameFormat))
+                    {
+                        // 创建模板,使用 {变量名:格式} 语法
+                        var template = new FileNameTemplate(procedure.ImageFileNameFormat);
+
+                        // 注册变量
+                        template.RegisterVariable("ProductSN", () => _productService.CurrentProductCode);
+                        template.RegisterVariable("CameraName", () => procedure.CameraName);
+                        template.RegisterVariable("ShotCount", () => index);
+                        template.RegisterVariable("Result", () => "NG");
+                        template.RegisterVariable("DateTime", () => DateTime.Now);
+
+                        // 生成文件名
+                        imgName = template.Generate();
+                    }
                     _eventAggregator.GetEvent<RenderUpdateNotification>().Publish(new ShowRender()
                     {
                         Id = procedure.Id,
@@ -1650,6 +1729,7 @@ namespace TeamAAS_VP.Services
                         SaveImagePathModel = procedure.SaveImagePathModel,
                         SavePath = procedure.SavePath,
                         ProceductName = procedure.Name,
+                        ImageFileName = imgName
                     });
                     return false;
                 }
@@ -1782,7 +1862,7 @@ namespace TeamAAS_VP.Services
                     SendTaskMessage(Lang.开始执行视觉流程.Replace("{0}", $"{i + 1}").Replace("{1}", procedure.Name), MessageLevel.Info);
 
                     // 1. 执行相机拍照并运行视觉工具
-                    bool visionSucceed = ExecutePhoto(procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection, imgPara);
+                    bool visionSucceed = ExecutePhoto(i + 1, procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection, imgPara);
                     if (!visionSucceed)
                     {
                         SendTaskMessage(Lang.视觉任务执行失败, MessageLevel.Error);
@@ -1806,7 +1886,7 @@ namespace TeamAAS_VP.Services
 
                     SendTaskMessage(Lang.拍照OK, MessageLevel.Debug);
 
-                    if (procedure.CalibrationId== Guid.Empty)
+                    if (procedure.CalibrationId == Guid.Empty)
                     {
                         //没有关联校准时,则执行检测任务
                         await RecordPhotoCaptureAsync(procedure, robotCoord, true, new double[] { 0, 0, 0 }, new double[] { 0, 0, 0 }, string.Empty, positionIndex, remark);
@@ -1831,7 +1911,7 @@ namespace TeamAAS_VP.Services
                         await RecordPhotoCaptureAsync(procedure, robotCoord, false, new double[] { _pixel_x, _pixel_y, _pixel_u }, new double[] { 0, 0, 0 }, string.Empty, positionIndex, remark);
                         return (false, 0, 0, 0);
                     }
-                    await RecordPhotoCaptureAsync(procedure, robotCoord,true, new double[] { _pixel_x, _pixel_y, _pixel_u }, new double[] { calibResult.X, calibResult.Y, calibResult.U }, string.Empty, positionIndex, remark);
+                    await RecordPhotoCaptureAsync(procedure, robotCoord, true, new double[] { _pixel_x, _pixel_y, _pixel_u }, new double[] { calibResult.X, calibResult.Y, calibResult.U }, string.Empty, positionIndex, remark);
                     return (true, calibResult.X, calibResult.Y, calibResult.U);
                 }
                 SendTaskMessage(Lang.多次拍照失败, MessageLevel.Alarm);
@@ -1907,7 +1987,7 @@ namespace TeamAAS_VP.Services
                 photoCaptureRecord.ProductSN = productSN;
                 photoCaptureRecord.CameraName = cameraName;
                 photoCaptureRecord.ProcessName = procedureName;
-                photoCaptureRecord.RobotPosition=string.Join(",", robotCoord);
+                photoCaptureRecord.RobotPosition = string.Join(",", robotCoord);
                 photoCaptureRecord.IsSuccess = isSuccess;
                 photoCaptureRecord.PixelPosition = string.Join(",", pixelPosition);
                 photoCaptureRecord.AbsolutePosition = string.Join(",", absolutePosition);

+ 2 - 0
TeamAAS-VM/TeamAAS-VP.csproj

@@ -529,6 +529,7 @@
     <Compile Include="Controls\FeederSystemParam.xaml.cs">
       <DependentUpon>FeederSystemParam.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Core\FileNameTemplate.cs" />
     <Compile Include="Core\StabilityAnalyzer.cs" />
     <Compile Include="Core\VisionProFileHelper.cs" />
     <Compile Include="Events\MainTabSwitchNotification.cs" />
@@ -559,6 +560,7 @@
     </Compile>
     <Compile Include="Services\MesService.cs" />
     <Compile Include="Services\ShiftWatcherService.cs" />
+    <Compile Include="ValueConverter\ImageFileNameFormatConverter.cs" />
     <Compile Include="ViewModels\Home\PickScrewAccuracyAnalyzerViewModel.cs" />
     <Compile Include="ViewModels\Product\PlcPointOffserParamsViewModel.cs" />
     <Compile Include="ViewModels\Statistics\HeadChangeRecordQueryViewModel.cs" />

+ 43 - 0
TeamAAS-VM/ValueConverter/ImageFileNameFormatConverter.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+using TeamAAS_VP.Core;
+
+namespace TeamAAS_VP.ValueConverter
+{
+    public class ImageFileNameFormatConverter : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            try
+            {
+                if (value == null) return string.Empty;
+                // 创建模板,使用 {变量名:格式} 语法
+                var template = new FileNameTemplate(value.ToString());
+
+                // 注册变量
+                template.RegisterVariable("ProductSN", () => "SN12345");
+                template.RegisterVariable("CameraName", () => "MainCamera");
+                template.RegisterVariable("ShotCount", () => 3);
+                template.RegisterVariable("Result", () => "OK");
+                template.RegisterVariable("DateTime", () => DateTime.Now);
+
+                // 生成文件名
+                string fileName = template.Generate();
+                return fileName;
+            }
+            catch (Exception)
+            {
+                return value.ToString();
+            }
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}

+ 1 - 31
TeamAAS-VM/ViewModels/SettingViewModel.cs

@@ -480,9 +480,6 @@ namespace TeamAAS_VP.ViewModels
         private DelegateCommand _RemoveDeviceInfoCommand;
         public DelegateCommand RemoveDeviceInfoCommand => _RemoveDeviceInfoCommand ?? (_RemoveDeviceInfoCommand = new DelegateCommand(ExecuteRemoveDeviceInfoCommand));
 
-        private DelegateCommand _SaveDataInfoCommand;
-        public DelegateCommand SaveDataInfoCommand => _SaveDataInfoCommand ?? (_SaveDataInfoCommand = new DelegateCommand(ExecuteSaveDataInfoCommand));
-
         private DelegateCommand _BrowseScrewCurvePathCommand;
         public DelegateCommand BrowseScrewCurvePathCommand => _BrowseScrewCurvePathCommand ?? (_BrowseScrewCurvePathCommand = new DelegateCommand(ExecuteBrowseScrewCurvePathCommand));
 
@@ -1432,12 +1429,6 @@ namespace TeamAAS_VP.ViewModels
                 }
             }
 
-            if (DataInfo == null)
-            {
-                // load device info
-                DataInfo = _configService.GetCTQDataInfo();
-            }
-
             if (ScrewFeederList == null)
             {
                 var screwFeeders = _configService.GetAllScrewFeeders();
@@ -1756,12 +1747,7 @@ namespace TeamAAS_VP.ViewModels
         {
             try
             {
-                if (SelectDeviceInfo != null)
-                {
-                    _configService.SaveDeviceInfo(SelectDeviceInfo);
-                    _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.完成, Duration = 1 });
-                }
-                else if (DeviceInfoList != null && DeviceInfoList.Count > 0)
+                if (DeviceInfoList != null && DeviceInfoList.Count > 0)
                 {
                     // 保存所有设备信息
                     _configService.SaveAllDeviceInfos(DeviceInfoList);
@@ -1824,22 +1810,6 @@ namespace TeamAAS_VP.ViewModels
             }
         }
 
-        private void ExecuteSaveDataInfoCommand()
-        {
-            try
-            {
-                if (DataInfo != null)
-                {
-                    _configService.SaveCTQDataInfo(DataInfo);
-                    _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.完成, Duration = 1 });
-                }
-            }
-            catch (Exception ex)
-            {
-                _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
-            }
-        }
-
         /// <summary>
         /// 选择CSV存储路径
         /// </summary>

+ 35 - 28
TeamAAS-VM/Views/Home/ShowVisionRender.xaml.cs

@@ -85,14 +85,14 @@ namespace TeamAAS_VP.Views.Home
                         ((Cognex.VisionPro.CogRecordDisplay)item.Value.Child).Record = null;
                         ((Cognex.VisionPro.CogRecordDisplay)item.Value.Child).Image = render.Image;
                         ((Cognex.VisionPro.CogRecordDisplay)item.Value.Child).StaticGraphics.Clear();
-                        if (render.Graphic!=null)
+                        if (render.Graphic != null)
                             ((Cognex.VisionPro.CogRecordDisplay)item.Value.Child).StaticGraphics.AddList(render.Graphic, "");
 
                         if (render.Record != null)
                             ((Cognex.VisionPro.CogRecordDisplay)item.Value.Child).Record = render.Record;
                         if (render.IsSaveImage)
                         {
-                            SaveImage(render.SaveImageModel, render.SaveImagePathModel, render.SavePath, render.Image, (Bitmap)((Cognex.VisionPro.CogRecordDisplay)item.Value.Child).CreateContentBitmap(Cognex.VisionPro.Display.CogDisplayContentBitmapConstants.Custom), render.Result, render.IsCompress, render.ImgPara);
+                            SaveImage(render.SaveImageModel, render.SaveImagePathModel, render.SavePath, render.Image, (Bitmap)((Cognex.VisionPro.CogRecordDisplay)item.Value.Child).CreateContentBitmap(Cognex.VisionPro.Display.CogDisplayContentBitmapConstants.Custom), render.Result, render.IsCompress, render.ImgPara, render.ImageFileName);
                         }
                         break;
                     }
@@ -354,7 +354,8 @@ namespace TeamAAS_VP.Views.Home
                                 clonedBitmap,
                                 render.Result,
                                 render.IsCompress,
-                                render.ImgPara
+                                render.ImgPara,
+                                render.ImageFileName
                             );
                         }
                         catch (OperationCanceledException)
@@ -395,7 +396,7 @@ namespace TeamAAS_VP.Views.Home
         /// <param name="reimage">渲染图像</param>
         /// <param name="result">拍照结果</param>
         /// <param name="isCompress">是否压缩</param>
-        private void SaveImage(ProcedureSaveImageModel saveImageModel, ProcedureSaveImagePathModel saveImagePathModel, string path, ICogImage image, Bitmap reimage, bool result, bool isCompress, ImageParameters imgPara)
+        private void SaveImage(ProcedureSaveImageModel saveImageModel, ProcedureSaveImagePathModel saveImagePathModel, string path, ICogImage image, Bitmap reimage, bool result, bool isCompress, ImageParameters imgPara, string imageFileName)
         {
             if (string.IsNullOrEmpty(path) || string.IsNullOrWhiteSpace(path) || !Path.IsPathRooted(path))
             {
@@ -409,28 +410,34 @@ namespace TeamAAS_VP.Views.Home
                 try
                 {
                     DateTime now = DateTime.Now;
+                    //图片名
+                    string imgName = now.ToString("yyyy-MM-dd HH_mm_ss");
+                    if (!string.IsNullOrEmpty(imageFileName))
+                    {
+                        imgName = imageFileName;
+                    }
 
                     if (saveImageModel == ProcedureSaveImageModel.Original)
                     {
-                        string Originalpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
+                        string Originalpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\{imgName}.bmp";
 
                         if (saveImagePathModel == ProcedureSaveImagePathModel.Month_Day_OkNG_Time)
                         {
                             Originalpath = result
-                                ? $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{now:yyyy-MM-dd HH_mm_ss}.bmp"
-                                : $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
+                                ? $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{imgName}.bmp"
+                                : $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{imgName}.bmp";
                         }
                         else if (saveImagePathModel == ProcedureSaveImagePathModel.Month_Day_Ok_Time)
                         {
                             if (result)
-                                Originalpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
+                                Originalpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{imgName}.bmp";
                             else
                                 return;
                         }
                         else if (saveImagePathModel == ProcedureSaveImagePathModel.Month_Day_Ng_Time)
                         {
                             if (!result)
-                                Originalpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
+                                Originalpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{imgName}.bmp";
                             else
                                 return;
                         }
@@ -447,7 +454,7 @@ namespace TeamAAS_VP.Views.Home
                                 productSN = productSN.Replace(c, '_');
 
                             string resultStr = result ? "OK" : "NG";
-                            Originalpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{resultStr}\\{productSN}\\{productSN}-{now:yyyy-MM-dd HH_mm_ss}-{resultStr}.bmp";
+                            Originalpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{resultStr}\\{productSN}\\{imgName}.bmp";
                         }
 
                         if (!Directory.Exists(Path.GetDirectoryName(Originalpath)))
@@ -462,25 +469,25 @@ namespace TeamAAS_VP.Views.Home
                     }
                     else if (saveImageModel == ProcedureSaveImageModel.Recorded)
                     {
-                        string Recordedpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
+                        string Recordedpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\{imgName}.bmp";
 
                         if (saveImagePathModel == ProcedureSaveImagePathModel.Month_Day_OkNG_Time)
                         {
                             Recordedpath = result
-                                ? $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{now:yyyy-MM-dd HH_mm_ss}.bmp"
-                                : $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
+                                ? $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{imgName}.bmp"
+                                : $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{imgName}.bmp";
                         }
                         else if (saveImagePathModel == ProcedureSaveImagePathModel.Month_Day_Ok_Time)
                         {
                             if (result)
-                                Recordedpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
+                                Recordedpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{imgName}.bmp";
                             else
                                 return;
                         }
                         else if (saveImagePathModel == ProcedureSaveImagePathModel.Month_Day_Ng_Time)
                         {
                             if (!result)
-                                Recordedpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
+                                Recordedpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{imgName}.bmp";
                             else
                                 return;
                         }
@@ -495,7 +502,7 @@ namespace TeamAAS_VP.Views.Home
                                 productSN = productSN.Replace(c, '_');
 
                             string resultStr = result ? "OK" : "NG";
-                            Recordedpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{resultStr}\\{productSN}\\{productSN}-{now:yyyy-MM-dd HH_mm_ss}-{resultStr}.bmp";
+                            Recordedpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{resultStr}\\{productSN}\\{imgName}.bmp";
                         }
 
                         if (!Directory.Exists(Path.GetDirectoryName(Recordedpath)))
@@ -512,28 +519,28 @@ namespace TeamAAS_VP.Views.Home
                     }
                     else if (saveImageModel == ProcedureSaveImageModel.OriginalAndRecorded)
                     {
-                        string Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
-                        string Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
+                        string Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\{imgName}.bmp";
+                        string Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\{imgName}.bmp";
 
                         if (saveImagePathModel == ProcedureSaveImagePathModel.Month_Day_OkNG_Time)
                         {
                             if (result)
                             {
-                                Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
-                                Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
+                                Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{imgName}.bmp";
+                                Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{imgName}.bmp";
                             }
                             else
                             {
-                                Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
-                                Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
+                                Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{imgName}.bmp";
+                                Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{imgName}.bmp";
                             }
                         }
                         else if (saveImagePathModel == ProcedureSaveImagePathModel.Month_Day_Ok_Time)
                         {
                             if (result)
                             {
-                                Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
-                                Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
+                                Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{imgName}.bmp";
+                                Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\OK\\{imgName}.bmp";
                             }
                             else
                             {
@@ -544,8 +551,8 @@ namespace TeamAAS_VP.Views.Home
                         {
                             if (!result)
                             {
-                                Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
-                                Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{now:yyyy-MM-dd HH_mm_ss}.bmp";
+                                Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{imgName}.bmp";
+                                Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\NG\\{imgName}.bmp";
                             }
                             else
                             {
@@ -563,8 +570,8 @@ namespace TeamAAS_VP.Views.Home
                                 productSN = productSN.Replace(c, '_');
 
                             string resultStr = result ? "OK" : "NG";
-                            Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{resultStr}\\{productSN}\\{productSN}-{now:yyyy-MM-dd HH_mm_ss}-{resultStr}.bmp";
-                            Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{resultStr}\\{productSN}\\{productSN}-{now:yyyy-MM-dd HH_mm_ss}-{resultStr}.bmp";
+                            Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{resultStr}\\{productSN}\\{imgName}.bmp";
+                            Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{resultStr}\\{productSN}\\{imgName}.bmp";
                         }
 
                         if (!Directory.Exists(Path.GetDirectoryName(Originalpath)))

+ 47 - 10
TeamAAS-VM/Views/Product/ProcedureParams.xaml

@@ -20,7 +20,7 @@
              prism:ViewModelLocator.AutoWireViewModel="True"
              mc:Ignorable="d"
              d:DataContext="{d:DesignInstance Type=vm:ProcedureParamsViewModel}"
-             d:Height="600"
+             d:Height="1080"
              d:Width="1024"
              d:Background="White"
              FontFamily="{DynamicResource DefaultFont}">
@@ -30,7 +30,7 @@
         </b:EventTrigger>
     </b:Interaction.Triggers>
     <UserControl.Resources>
-
+        <valueConverter:ImageFileNameFormatConverter x:Key="ImageFileNameFormatConverter" />
     </UserControl.Resources>
     <Grid>
         <Grid.RowDefinitions>
@@ -107,7 +107,8 @@
             </Expander>
             <ScrollViewer Grid.Column="1"
                           IsEnabled="{Binding IsAllowEdit}">
-                <Grid Grid.Column="1"
+                <Grid x:Name="grid"
+                      Grid.Column="1"
                       Margin="10"
                       IsEnabled="{Binding IsAllowEdit}"
                       HorizontalAlignment="Center"
@@ -132,6 +133,8 @@
                         <RowDefinition Height="auto" />
                         <RowDefinition Height="auto" />
                         <RowDefinition Height="auto" />
+                        <RowDefinition Height="auto" />
+                        <RowDefinition Height="auto" />
                     </Grid.RowDefinitions>
                     <Grid.ColumnDefinitions>
                         <ColumnDefinition Width="auto" />
@@ -428,8 +431,42 @@
                               Visibility="{Binding ElementName=chbSaveImage,Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}}"
                               IsChecked="{Binding SelectProcedure.IsCompress,Mode=TwoWay}"
                               Style="{StaticResource MaterialDesignLightCheckBox}" />
+                    <!--图片名称格式-->
+                    <TextBlock Grid.Row="14"
+                               Grid.Column="0"
+                               Visibility="{Binding ElementName=chbSaveImage,Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}}"
+                               Text="图片名称格式:" />
+                    <TextBox Grid.Row="14"
+                             Grid.Column="1"
+                             HorizontalAlignment="Stretch"
+                             Visibility="{Binding ElementName=chbSaveImage,Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}}"
+                             Text="{Binding SelectProcedure.ImageFileNameFormat,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
+                    </TextBox>
+                    <!--示例-->
+                    <StackPanel Grid.Row="15"
+                                Grid.Column="0"
+                                Grid.ColumnSpan="2"
+                                Orientation="Vertical"
+                                Visibility="{Binding ElementName=chbSaveImage,Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}}">
+                        <TextBlock Text="示例:{ProductSN}_Daisy_KB Screw _01 _{CameraName}-Locate_{ShotCount}_WhiteRingLight_{Result}_{DateTime:yyyy-MM-dd_HH-mm-ss}"
+                                   Foreground="LightGray"
+                                   FontSize="10"
+                                   TextTrimming="CharacterEllipsis"
+                                   TextWrapping="Wrap"
+                                   Width="{Binding Width, ElementName=grid}" />
+                        <TextBlock Text="转换后的名称:"
+                                   Foreground="Gray"
+                                   FontSize="10" />
+                        <TextBlock Text="{Binding SelectProcedure.ImageFileNameFormat,Converter={StaticResource ImageFileNameFormatConverter},Mode=TwoWay}"
+                                   Foreground="Gray"
+                                   FontSize="10"
+                                   TextTrimming="CharacterEllipsis"
+                                   TextWrapping="Wrap"
+                                   Width="{Binding Width, ElementName=grid}"  />
+                    </StackPanel>
+
                     <!--自定义参数-->
-                    <GroupBox Grid.Row="14"
+                    <GroupBox Grid.Row="16"
                               Grid.Column="0"
                               Grid.ColumnSpan="2"
                               HorizontalAlignment="Stretch"
@@ -440,12 +477,12 @@
                             <StackPanel DockPanel.Dock="Top"
                                         Orientation="Horizontal">
                                 <Button Content="{materialDesign:PackIcon Kind=AddCircle}"
-                                        Style="{StaticResource MahApps.Styles.Button.Flat}" 
-                                        Command="{Binding AddUserDefineParameterCommand}"/>
+                                        Style="{StaticResource MahApps.Styles.Button.Flat}"
+                                        Command="{Binding AddUserDefineParameterCommand}" />
                                 <Button Content="{materialDesign:PackIcon Kind=RemoveCircle}"
                                         Style="{StaticResource MahApps.Styles.Button.Flat}"
-                                        Margin="5,0" 
-                                        Command="{Binding RemoveUserDefineParameterCommand}"/>
+                                        Margin="5,0"
+                                        Command="{Binding RemoveUserDefineParameterCommand}" />
                             </StackPanel>
                             <DataGrid HorizontalAlignment="Stretch"
                                       VerticalAlignment="Stretch"
@@ -499,10 +536,10 @@
                             </DataGrid>
                         </DockPanel>
                     </GroupBox>
-                    <TextBlock Grid.Row="15"
+                    <TextBlock Grid.Row="17"
                                Grid.Column="0"
                                Text="{lex:Loc 重写视觉处理逻辑}" />
-                    <Button Grid.Row="15"
+                    <Button Grid.Row="17"
                             Grid.Column="1"
                             Margin="0,2,0,0"
                             Command="{Binding OverrideVisionTaskCommand}">

+ 158 - 176
TeamAAS-VM/Views/SettingView.xaml

@@ -237,7 +237,7 @@
                         <ColumnDefinition Width="auto" />
                         <ColumnDefinition Width="*" />
                     </Grid.ColumnDefinitions>
-                    
+
                     <!--增删改查按钮-->
                     <StackPanel Grid.ColumnSpan="2"
                                 IsEnabled="{Binding IsAllowEdit}"
@@ -259,7 +259,7 @@
                             <materialDesign:PackIcon Kind="ContentSaveCheck" />
                         </Button>
                     </StackPanel>
-                    
+
                     <!--设备列表-->
                     <TreeView Grid.Row="1"
                               Grid.Column="0"
@@ -304,7 +304,7 @@
                             </TreeViewItem.ItemTemplate>
                         </TreeViewItem>
                     </TreeView>
-                    
+
                     <!--参数详情-->
                     <ScrollViewer Grid.Row="1"
                                   Grid.Column="1"
@@ -313,10 +313,10 @@
                                   Visibility="{Binding SelectDeviceInfo,Converter={StaticResource ObjectToVisibilityConverter}}">
                         <Grid>
                             <Grid.RowDefinitions>
-                                <RowDefinition Height="auto"/>
-                                <RowDefinition Height="auto"/>
+                                <RowDefinition Height="auto" />
+                                <RowDefinition Height="auto" />
                             </Grid.RowDefinitions>
-                            
+
                             <!--设备信息表单-->
                             <Grid>
                                 <Grid.RowDefinitions>
@@ -334,6 +334,17 @@
                                     <RowDefinition Height="Auto" />
                                     <RowDefinition Height="Auto" />
                                     <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
                                 </Grid.RowDefinitions>
                                 <Grid.ColumnDefinitions>
                                     <ColumnDefinition Width="auto" />
@@ -380,7 +391,7 @@
                                          Grid.Column="1"
                                          Text="{Binding SelectDeviceInfo.MesUrl, Mode=TwoWay}"
                                          Margin="6,2" />
-                                
+
                                 <TextBlock Grid.Row="4"
                                            Grid.Column="0"
                                            Text="Line:"
@@ -467,132 +478,99 @@
                                             <materialDesign:PackIcon Kind="FolderOpenOutline" />
                                         </Button.Content>
                                     </Button>
-                                    <TextBox  Text="{Binding SelectDeviceInfo.SaveCsvPath, Mode=TwoWay}"
-                                               />
-                                    
-                                </DockPanel>
-
-                            </Grid>
-
-                            <!--CTQ 数据信息-->
-                            <Grid Margin="0,16,0,0"
-                                  Grid.Row="1">
-                                <Grid.RowDefinitions>
-                                    <RowDefinition Height="Auto" />
-                                    <RowDefinition Height="Auto" />
-                                    <RowDefinition Height="Auto" />
-                                    <RowDefinition Height="Auto" />
-                                    <RowDefinition Height="Auto" />
-                                    <RowDefinition Height="Auto" />
-                                    <RowDefinition Height="Auto" />
-                                    <RowDefinition Height="Auto" />
-                                    <RowDefinition Height="Auto" />
-                                    <RowDefinition Height="Auto" />
-                                    <RowDefinition Height="Auto" />
-                                </Grid.RowDefinitions>
-                                <Grid.ColumnDefinitions>
-                                    <ColumnDefinition Width="auto" />
-                                    <ColumnDefinition Width="*" />
-                                </Grid.ColumnDefinitions>
+                                    <TextBox  Text="{Binding SelectDeviceInfo.SaveCsvPath, Mode=TwoWay}" />
 
-                                <TextBlock Grid.Row="0"
+                                </DockPanel>
+                                <!--CTQ 数据信息-->
+                                <TextBlock Grid.Row="13"
                                            Grid.Column="0"
                                            Text="PROCESS_NAME:"
                                            HorizontalAlignment="Right"
                                            VerticalAlignment="Center" />
-                                <TextBox Grid.Row="0"
+                                <TextBox Grid.Row="13"
                                          Grid.Column="1"
-                                         Text="{Binding DataInfo.PROCESS_NAME, Mode=TwoWay}"
-                                         Margin="6" />
+                                         Text="{Binding SelectDeviceInfo.DataInfo.PROCESS_NAME, Mode=TwoWay}"
+                                         Margin="6,2" />
 
-                                <TextBlock Grid.Row="1"
+                                <TextBlock Grid.Row="14"
                                            Grid.Column="0"
                                            Text="CTQ_LSL(压力下限):"
                                            HorizontalAlignment="Right"
                                            VerticalAlignment="Center" />
-                                <TextBox Grid.Row="1"
+                                <TextBox Grid.Row="14"
                                          Grid.Column="1"
-                                         Text="{Binding DataInfo.CTQ_LSL_Pressure, Mode=TwoWay}"
-                                         Margin="6" />
+                                         Text="{Binding SelectDeviceInfo.DataInfo.CTQ_LSL_Pressure, Mode=TwoWay}"
+                                         Margin="6,2" />
 
-                                <TextBlock Grid.Row="2"
+                                <TextBlock Grid.Row="15"
                                            Grid.Column="0"
                                            Text="CTQ_USL(压力上限):"
                                            HorizontalAlignment="Right"
                                            VerticalAlignment="Center" />
-                                <TextBox Grid.Row="2"
+                                <TextBox Grid.Row="15"
                                          Grid.Column="1"
-                                         Text="{Binding DataInfo.CTQ_USL_Pressure, Mode=TwoWay}"
-                                         Margin="6" />
+                                         Text="{Binding SelectDeviceInfo.DataInfo.CTQ_USL_Pressure, Mode=TwoWay}"
+                                         Margin="6,2" />
 
-                                <TextBlock Grid.Row="3"
+                                <TextBlock Grid.Row="16"
                                            Grid.Column="0"
                                            Text="SUPPLIER_NAME:"
                                            HorizontalAlignment="Right"
                                            VerticalAlignment="Center" />
-                                <TextBox Grid.Row="3"
+                                <TextBox Grid.Row="16"
                                          Grid.Column="1"
-                                         Text="{Binding DataInfo.SUPPLIER_NAME, Mode=TwoWay}"
-                                         Margin="6" />
+                                         Text="{Binding SelectDeviceInfo.DataInfo.SUPPLIER_NAME, Mode=TwoWay}"
+                                         Margin="6,2" />
 
-                                <TextBlock Grid.Row="4"
+                                <TextBlock Grid.Row="17"
                                            Grid.Column="0"
                                            Text="COMMODITY_TYPE:"
                                            HorizontalAlignment="Right"
                                            VerticalAlignment="Center" />
-                                <TextBox Grid.Row="4"
+                                <TextBox Grid.Row="17"
                                          Grid.Column="1"
-                                         Text="{Binding DataInfo.COMMODITY_TYPE, Mode=TwoWay}"
-                                         Margin="6" />
+                                         Text="{Binding SelectDeviceInfo.DataInfo.COMMODITY_TYPE, Mode=TwoWay}"
+                                         Margin="6,2" />
 
-                                <TextBlock Grid.Row="5"
+                                <TextBlock Grid.Row="18"
                                            Grid.Column="0"
                                            Text="REVISION:"
                                            HorizontalAlignment="Right"
                                            VerticalAlignment="Center" />
-                                <TextBox Grid.Row="5"
+                                <TextBox Grid.Row="18"
                                          Grid.Column="1"
-                                         Text="{Binding DataInfo.REVISION, Mode=TwoWay}"
-                                         Margin="6" />
+                                         Text="{Binding SelectDeviceInfo.DataInfo.REVISION, Mode=TwoWay}"
+                                         Margin="6,2" />
 
-                                <TextBlock Grid.Row="6"
+                                <TextBlock Grid.Row="19"
                                            Grid.Column="0"
                                            Text="MFG_LOT#:"
                                            HorizontalAlignment="Right"
                                            VerticalAlignment="Center" />
-                                <TextBox Grid.Row="6"
+                                <TextBox Grid.Row="19"
                                          Grid.Column="1"
-                                         Text="{Binding DataInfo.MFG_LOT, Mode=TwoWay}"
-                                         Margin="6" />
+                                         Text="{Binding SelectDeviceInfo.DataInfo.MFG_LOT, Mode=TwoWay}"
+                                         Margin="6,2" />
 
-                                <TextBlock Grid.Row="7"
+                                <TextBlock Grid.Row="20"
                                            Grid.Column="0"
                                            Text="MFG_ASSY_LINE:"
                                            HorizontalAlignment="Right"
                                            VerticalAlignment="Center" />
-                                <TextBox Grid.Row="7"
+                                <TextBox Grid.Row="20"
                                          Grid.Column="1"
-                                         Text="{Binding DataInfo.MFG_ASSY_LINE, Mode=TwoWay}"
-                                         Margin="6" />
+                                         Text="{Binding SelectDeviceInfo.DataInfo.MFG_ASSY_LINE, Mode=TwoWay}"
+                                         Margin="6,2" />
 
-                                <TextBlock Grid.Row="8"
+                                <TextBlock Grid.Row="21"
                                            Grid.Column="0"
                                            Text="PROCESS_MACHINE_ID:"
                                            HorizontalAlignment="Right"
                                            VerticalAlignment="Center" />
-                                <TextBox Grid.Row="8"
+                                <TextBox Grid.Row="21"
                                          Grid.Column="1"
-                                         Text="{Binding DataInfo.PROCESS_MACHINE_ID, Mode=TwoWay}"
-                                         Margin="6" />
-
-                                <StackPanel Orientation="Horizontal"
-                                            HorizontalAlignment="Right"
-                                            Grid.Row="9"
-                                            Grid.ColumnSpan="2"
-                                            Margin="6">
-                                    <Button Style="{StaticResource MaterialDesignRaisedButton}"
-                                            Command="{Binding SaveDataInfoCommand}">保存CTQ数据</Button>
-                                </StackPanel>
+                                         Text="{Binding SelectDeviceInfo.DataInfo.PROCESS_MACHINE_ID, Mode=TwoWay}"
+                                         Margin="6,2" />
                             </Grid>
                         </Grid>
                     </ScrollViewer>
@@ -2698,14 +2676,14 @@
                             </StackPanel>
                         </Button>
                     </Grid>
-                    <StackPanel Grid.Row="5"  Margin="0,12,0,0" Orientation="Horizontal" >
+                    <StackPanel Grid.Row="5"
+                                Margin="0,12,0,0"
+                                Orientation="Horizontal">
                         <!--刷卡参数配置-->
-                        <GroupBox 
-                              Header="刷卡器配置"
-                              Width="300"
-                            Margin="0,0,50,0"
-                            HorizontalAlignment="Left"
-                             >
+                        <GroupBox Header="刷卡器配置"
+                                  Width="300"
+                                  Margin="0,0,50,0"
+                                  HorizontalAlignment="Left">
                             <Grid Margin="10">
                                 <Grid.ColumnDefinitions>
                                     <ColumnDefinition Width="auto" />
@@ -2720,65 +2698,66 @@
                                     <RowDefinition Height="Auto" />
                                 </Grid.RowDefinitions>
                                 <TextBlock Text="PortName:"
-                                       Grid.Row="0"
-                                       Grid.Column="0"
-                                       HorizontalAlignment="Right" />
+                                           Grid.Row="0"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
                                 <TextBox Text="{Binding CardReaderConfig.PortName,Mode=TwoWay}"
-                                     Grid.Row="0"
-                                     Grid.Column="1"
-                                     Margin="6,0" />
+                                         Grid.Row="0"
+                                         Grid.Column="1"
+                                         Margin="6,0" />
                                 <TextBlock Text="BaudRate:"
-                                       Grid.Row="1"
-                                       Grid.Column="0"
-                                       HorizontalAlignment="Right" />
+                                           Grid.Row="1"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
                                 <TextBox Text="{Binding CardReaderConfig.BaudRate,Mode=TwoWay}"
-                                     Grid.Row="1"
-                                     Grid.Column="1"
-                                     Margin="6,0" />
+                                         Grid.Row="1"
+                                         Grid.Column="1"
+                                         Margin="6,0" />
                                 <TextBlock Text="Parity:"
-                                       Grid.Row="2"
-                                       Grid.Column="0"
-                                       HorizontalAlignment="Right" />
+                                           Grid.Row="2"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
                                 <ComboBox Grid.Row="2"
-                                      Grid.Column="1"
-                                      SelectedItem="{Binding CardReaderConfig.Parity,Mode=TwoWay}"
-                                      ItemsSource="{Binding Source={StaticResource Parity}}" />
+                                          Grid.Column="1"
+                                          SelectedItem="{Binding CardReaderConfig.Parity,Mode=TwoWay}"
+                                          ItemsSource="{Binding Source={StaticResource Parity}}" />
                                 <TextBlock Text="StopBits:"
-                                       Grid.Row="3"
-                                       Grid.Column="0"
-                                       HorizontalAlignment="Right" />
+                                           Grid.Row="3"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
                                 <ComboBox Grid.Row="3"
-                                      Grid.Column="1"
-                                      SelectedItem="{Binding CardReaderConfig.StopBits,Mode=TwoWay}"
-                                      ItemsSource="{Binding Source={StaticResource StopBits}}" />
+                                          Grid.Column="1"
+                                          SelectedItem="{Binding CardReaderConfig.StopBits,Mode=TwoWay}"
+                                          ItemsSource="{Binding Source={StaticResource StopBits}}" />
                                 <TextBlock Text="DataBits:"
-                                       Grid.Row="4"
-                                       Grid.Column="0"
-                                       HorizontalAlignment="Right" />
+                                           Grid.Row="4"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
                                 <TextBox Text="{Binding CardReaderConfig.DataBits,Mode=TwoWay}"
-                                     Grid.Row="4"
-                                     Grid.Column="1"
-                                     Margin="6,0" />
+                                         Grid.Row="4"
+                                         Grid.Column="1"
+                                         Margin="6,0" />
 
                                 <Button Grid.Row="5"
-                                    Grid.Column="1"
-                                    Margin="0,6"
-                                    Style="{StaticResource MaterialDesignRaisedButton}"
-                                    materialDesign:ButtonAssist.CornerRadius="10"
-                                    MinWidth="120"
-                                    Command="{Binding SaveCardReaderConfigCommand}">
+                                        Grid.Column="1"
+                                        Margin="0,6"
+                                        Style="{StaticResource MaterialDesignRaisedButton}"
+                                        materialDesign:ButtonAssist.CornerRadius="10"
+                                        MinWidth="120"
+                                        Command="{Binding SaveCardReaderConfigCommand}">
                                     <StackPanel Orientation="Horizontal"
-                                            HorizontalAlignment="Center">
+                                                HorizontalAlignment="Center">
                                         <materialDesign:PackIcon Kind="ContentSaveCheck"
-                                                             Margin="0,0,6,0" />
+                                                                 Margin="0,0,6,0" />
                                         <TextBlock VerticalAlignment="Center"
-                                               Text="保存刷卡器配置" />
+                                                   Text="保存刷卡器配置" />
                                     </StackPanel>
                                 </Button>
                             </Grid>
                         </GroupBox>
 
-                        <GroupBox Header="扭力测量仪配置"  Width="300">
+                        <GroupBox Header="扭力测量仪配置"
+                                  Width="300">
                             <Grid Margin="10">
                                 <Grid.ColumnDefinitions>
                                     <ColumnDefinition Width="auto" />
@@ -2793,59 +2772,59 @@
                                     <RowDefinition Height="Auto" />
                                 </Grid.RowDefinitions>
                                 <TextBlock Text="PortName:"
-                                     Grid.Row="0"
-                                     Grid.Column="0"
-                                     HorizontalAlignment="Right" />
+                                           Grid.Row="0"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
                                 <TextBox Text="{Binding TorqueReadConfig.PortName,Mode=TwoWay}"
-                                     Grid.Row="0"
-                                     Grid.Column="1"
-                                     Margin="6,0" />
+                                         Grid.Row="0"
+                                         Grid.Column="1"
+                                         Margin="6,0" />
                                 <TextBlock Text="BaudRate:"
-                                    Grid.Row="1"
-                                    Grid.Column="0"
-                                    HorizontalAlignment="Right" />
+                                           Grid.Row="1"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
                                 <TextBox Text="{Binding TorqueReadConfig.BaudRate,Mode=TwoWay}"
-                                    Grid.Row="1"
-                                    Grid.Column="1"
-                                    Margin="6,0" />
+                                         Grid.Row="1"
+                                         Grid.Column="1"
+                                         Margin="6,0" />
                                 <TextBlock Text="Parity:"
-                                    Grid.Row="2"
-                                    Grid.Column="0"
-                                    HorizontalAlignment="Right" />
+                                           Grid.Row="2"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
                                 <ComboBox Grid.Row="2"
-                                    Grid.Column="1"
-                                    SelectedItem="{Binding TorqueReadConfig.Parity,Mode=TwoWay}"
-                                    ItemsSource="{Binding Source={StaticResource Parity}}" />
+                                          Grid.Column="1"
+                                          SelectedItem="{Binding TorqueReadConfig.Parity,Mode=TwoWay}"
+                                          ItemsSource="{Binding Source={StaticResource Parity}}" />
                                 <TextBlock Text="StopBits:"
-                                    Grid.Row="3"
-                                    Grid.Column="0"
-                                    HorizontalAlignment="Right" />
+                                           Grid.Row="3"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
                                 <ComboBox Grid.Row="3"
-                                    Grid.Column="1"
-                                    SelectedItem="{Binding TorqueReadConfig.StopBits,Mode=TwoWay}"
-                                    ItemsSource="{Binding Source={StaticResource StopBits}}" />
+                                          Grid.Column="1"
+                                          SelectedItem="{Binding TorqueReadConfig.StopBits,Mode=TwoWay}"
+                                          ItemsSource="{Binding Source={StaticResource StopBits}}" />
                                 <TextBlock Text="DataBits:"
-                                    Grid.Row="4"
-                                    Grid.Column="0"
-                                    HorizontalAlignment="Right" />
+                                           Grid.Row="4"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
                                 <TextBox Text="{Binding TorqueReadConfig.DataBits,Mode=TwoWay}"
-                                     Grid.Row="4"
-                                     Grid.Column="1"
-                                     Margin="6,0" />
+                                         Grid.Row="4"
+                                         Grid.Column="1"
+                                         Margin="6,0" />
 
                                 <Button Grid.Row="5"
-                                    Grid.Column="1"
-                                    Margin="0,6"
-                                    Style="{StaticResource MaterialDesignRaisedButton}"
-                                    materialDesign:ButtonAssist.CornerRadius="10"
-                                    MinWidth="120"
-                                    Command="{Binding SaveTorqueReaderConfigCommand}">
+                                        Grid.Column="1"
+                                        Margin="0,6"
+                                        Style="{StaticResource MaterialDesignRaisedButton}"
+                                        materialDesign:ButtonAssist.CornerRadius="10"
+                                        MinWidth="120"
+                                        Command="{Binding SaveTorqueReaderConfigCommand}">
                                     <StackPanel Orientation="Horizontal"
-                        HorizontalAlignment="Center">
+                                                HorizontalAlignment="Center">
                                         <materialDesign:PackIcon Kind="ContentSaveCheck"
-                                         Margin="0,0,6,0" />
+                                                                 Margin="0,0,6,0" />
                                         <TextBlock VerticalAlignment="Center"
-                           Text="保存扭力测量仪配置" />
+                                                   Text="保存扭力测量仪配置" />
                                     </StackPanel>
                                 </Button>
                             </Grid>
@@ -2937,11 +2916,13 @@
                                     </Binding>
                                 </TextBox.Text>
                             </TextBox>
-                            <StackPanel Grid.Column="2" Grid.RowSpan="2" HorizontalAlignment="Center" Margin="10,5" >
-                                <ToggleButton 
-                                           Margin="0,10"
-                                          Height="40" 
-                                          Width="60"/>
+                            <StackPanel Grid.Column="2"
+                                        Grid.RowSpan="2"
+                                        HorizontalAlignment="Center"
+                                        Margin="10,5">
+                                <ToggleButton Margin="0,10"
+                                              Height="40"
+                                              Width="60" />
                             </StackPanel>
 
                             <!--结束符-->
@@ -2985,12 +2966,13 @@
                                     </Binding>
                                 </TextBox.Text>
                             </TextBox>
-                            <ToggleButton Grid.Row="2" Grid.Column="2" 
-                                          Grid.RowSpan="2" 
-                                          HorizontalAlignment="Center" 
-                                          Margin="10,5" 
-                                          Height="40" 
-                                          Width="60"/>
+                            <ToggleButton Grid.Row="2"
+                                          Grid.Column="2"
+                                          Grid.RowSpan="2"
+                                          HorizontalAlignment="Center"
+                                          Margin="10,5"
+                                          Height="40"
+                                          Width="60" />
                         </Grid>
                     </GroupBox>
                 </StackPanel>