Răsfoiți Sursa

新增图片保存路径模式及拍照记录功能完善

本次提交新增了“年月/日/配方名/产品SN/产品SN+时间”图片保存路径模式,并在相关界面和服务层实现了该功能。扩展了枚举和多语言资源,完善了图片保存路径的生成逻辑,支持按配方名和产品SN分类存储。接口层增加了参数,服务层新增拍照数据记录方法,提升了系统数据的可追溯性和管理便捷性。同时优化了依赖注入和部分代码风格。
孝锋 徐 7 luni în urmă
părinte
comite
e53bf309fa

+ 5 - 0
TeamAAS-VM/Enums/ProcedureSaveImagePathModel.cs

@@ -43,5 +43,10 @@ namespace TeamAAS_VP.Enums
         [Description("..//yyyy-MM//MM-dd//NG//yyyy-MM-dd HH_mm_ss.png")]
         [Localization(ResourceName = "ProcedureSaveImagePathModel_Month_Day_Ng_Time", ResourceType = typeof(Lang))]
         Month_Day_Ng_Time = 3,
+
+        //年月/日/配方名/产品SN/产品SN+时间
+        [Description("..//yyyy-MM//MM-dd//产品配方名//产品SN//产品SN-yyyy-MM-dd HH_mm_ss.png")]
+        [Localization(ResourceName = "ProcedureSaveImagePathModel_Month_Day_Formula_ProductSN_Time", ResourceType = typeof(Lang))]
+        Month_Day_Formula_ProductSN_Time = 4
     }
 }

+ 1 - 1
TeamAAS-VM/Interfaces/IRemoteCommandService.cs

@@ -249,7 +249,7 @@ namespace TeamAAS_VP.Interfaces
         /// <param name="robotCoord"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        Task<(bool IsSucceed, double X, double Y, double U)> ExecutePhotoGetSinglePoint(ProcedureModel procedure, Dictionary<string, string> InputTerminal, double[] robotCoord, CancellationToken cancellationToken);
+        Task<(bool IsSucceed, double X, double Y, double U)> ExecutePhotoGetSinglePoint(ProcedureModel procedure, Dictionary<string, string> InputTerminal, double[] robotCoord, CancellationToken cancellationToken,int? index,string remark);
 
         /// <summary>
         /// 执行相机拍照获取单个点位结果,并且返回图像和图形

+ 9 - 0
TeamAAS-VM/Resources/Languages/Lang.Designer.cs

@@ -915,6 +915,15 @@ namespace TeamAAS_VP.Resources.Languages {
             }
         }
         
+        /// <summary>
+        ///   查找类似 年月/日/配方名/产品SN/产品SN+时间 的本地化字符串。
+        /// </summary>
+        public static string ProcedureSaveImagePathModel_Month_Day_Formula_ProductSN_Time {
+            get {
+                return ResourceManager.GetString("ProcedureSaveImagePathModel_Month_Day_Formula_ProductSN_Time", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   查找类似 /年月/日/NG/时间 的本地化字符串。
         /// </summary>

+ 3 - 0
TeamAAS-VM/Resources/Languages/Lang.resx

@@ -4061,4 +4061,7 @@
   <data name="视觉静态精度分析" xml:space="preserve">
     <value>视觉静态精度分析</value>
   </data>
+  <data name="ProcedureSaveImagePathModel_Month_Day_Formula_ProductSN_Time" xml:space="preserve">
+    <value>年月/日/配方名/产品SN/产品SN+时间</value>
+  </data>
 </root>

+ 80 - 8
TeamAAS-VM/Services/RemoteCommandService.cs

@@ -1571,13 +1571,13 @@ namespace TeamAAS_VP.Services
         /// <param name="outImage"></param>
         /// <param name="outGraphicCollection"></param>
         /// <returns></returns>
-        public bool ExecutePhotoEx(ProcedureModel procedure, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection,out ICogImage outImage,out CogGraphicCollection outGraphicCollection)
+        public bool ExecutePhotoEx(ProcedureModel procedure, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection, out ICogImage outImage, out CogGraphicCollection outGraphicCollection)
         {
             outImage = null;
             outGraphicCollection = null;
             try
             {
-                
+
                 // 1. 采集图像
                 var camera = _cameraService.GetCamera(procedure.CameraId);
                 bool succed = camera.SetExposureTime(procedure.ExposureTime);
@@ -1600,7 +1600,7 @@ namespace TeamAAS_VP.Services
                     outputCollection = null;
                     return false;
                 }
-                outImage= image;
+                outImage = image;
                 procedure.ToolBlock.Inputs["InputImage"].Value = image;
                 LogHelper.WriteLogInfo(string.Format(Lang.采集图像完成用时0ms, (DateTime.Now - nowtime).Milliseconds));
 
@@ -1638,7 +1638,7 @@ namespace TeamAAS_VP.Services
                         if (item.Value is ICogRecord)
                             record = item.Value as ICogRecord;
                     }
-                    outGraphicCollection= outputCollection["Graphic"].Value as CogGraphicCollection;
+                    outGraphicCollection = outputCollection["Graphic"].Value as CogGraphicCollection;
                     return true;
                 }
                 else
@@ -1667,7 +1667,7 @@ namespace TeamAAS_VP.Services
         /// <param name="robotCoord"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public async Task<(bool IsSucceed, double X, double Y, double U)> ExecutePhotoGetSinglePoint(ProcedureModel procedure, Dictionary<string, string> InputTerminal, double[] robotCoord, CancellationToken cancellationToken)
+        public async Task<(bool IsSucceed, double X, double Y, double U)> ExecutePhotoGetSinglePoint(ProcedureModel procedure, Dictionary<string, string> InputTerminal, double[] robotCoord, CancellationToken cancellationToken, int? index, string remark)
         {
             DateTime nowtime = DateTime.Now;
             await SetLightBeforePhoto(procedure);
@@ -1719,6 +1719,7 @@ namespace TeamAAS_VP.Services
                     {
                         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, string.Empty);
                     return (true, calibResult.X, calibResult.Y, calibResult.U);
                 }
                 SendTaskMessage(Lang.多次拍照失败, MessageLevel.Alarm);
@@ -1736,6 +1737,77 @@ namespace TeamAAS_VP.Services
             }
         }
 
+        /// <summary>
+        /// 记录拍照结果数据至数据库
+        /// </summary>
+        /// <param name="procedure"></param>
+        /// <param name="robotCoord"></param>
+        /// <param name="isSuccess"></param>
+        /// <param name="pixelPosition"></param>
+        /// <param name="absolutePosition"></param>
+        /// <param name="imagePath"></param>
+        /// <param name="emarks"></param>
+        /// <returns></returns>
+        private async Task RecordPhotoCaptureAsync(ProcedureModel procedure, double[] robotCoord, bool isSuccess, double[] pixelPosition, double[] absolutePosition, string imagePath, string emarks)
+        {
+            try
+            {
+                //当前的产品配方名
+                string formulaName = _productService.GetCurrentProduct().Name;
+                //如果当前产品名称存在非法字符,则替换为下划线
+                foreach (char c in System.IO.Path.GetInvalidFileNameChars())
+                {
+                    formulaName = formulaName.Replace(c, '_');
+                }
+                //获取当前的产品SN
+                string productSN = _productService.CurrentProductCode;
+                //如果产品SN存在非法字符,则替换为下划线
+                foreach (char c in System.IO.Path.GetInvalidFileNameChars())
+                {
+                    productSN = productSN.Replace(c, '_');
+                }
+                //当前用户
+                string currentUser = _systemDatabaseService.GetCurrentUser()?.UserName;
+
+                //相机名称
+                string cameraName = procedure.CameraName;
+                //视觉流程名称
+                string procedureName = procedure.Name;
+                //如果机器人坐标为空,则获取当前机器人坐标
+                if (robotCoord == null)
+                {
+                    var robot = _robotService.GetAllRobots().FirstOrDefault();
+                    if (robot != null)
+                    {
+                        var pos = await robot.GetRobotPosAsync();
+                        robotCoord = new double[] { pos.X, pos.Y, pos.Z };
+                    }
+                    else
+                    {
+                        robotCoord = new double[] { 0, 0, 0 };
+                    }
+                }
+                PhotoCaptureRecord photoCaptureRecord = new PhotoCaptureRecord();
+                photoCaptureRecord.RecipeName = formulaName;
+                photoCaptureRecord.ProductSN = productSN;
+                photoCaptureRecord.CameraName = cameraName;
+                photoCaptureRecord.ProcessName = procedureName;
+                photoCaptureRecord.RobotPosition=string.Join(",", robotCoord);
+                photoCaptureRecord.IsSuccess = isSuccess;
+                photoCaptureRecord.PixelPosition = string.Join(",", pixelPosition);
+                photoCaptureRecord.AbsolutePosition = string.Join(",", absolutePosition);
+                photoCaptureRecord.ImagePath = imagePath;
+                photoCaptureRecord.Remarks = emarks;
+                photoCaptureRecord.OperatorName = currentUser;
+
+                await _systemDatabaseService.RecordPhotoCaptureAsync(photoCaptureRecord);
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("记录拍照结果数据至数据库时出错", ex);
+            }
+        }
+
         /// <summary>
         /// 执行相机拍照获取单个点位结果,并且返回图像和图形
         /// </summary>
@@ -1748,8 +1820,8 @@ namespace TeamAAS_VP.Services
         {
             DateTime nowtime = DateTime.Now;
             await SetLightBeforePhoto(procedure);
-            ICogImage outImage=null;
-            CogGraphicCollection outGraphicCollection=null;
+            ICogImage outImage = null;
+            CogGraphicCollection outGraphicCollection = null;
             try
             {
                 //拍照失败时,需要多次拍照
@@ -2243,7 +2315,7 @@ namespace TeamAAS_VP.Services
                     if (!isSucceed)
                     {
                         LogHelper.WriteLogInfo(string.Format(Lang.设置光源通道0打开失败, lightChannel.GlobalIndex));
-                            //"设置光源通道{lightChannel.GlobalIndex}打开失败!");
+                        //"设置光源通道{lightChannel.GlobalIndex}打开失败!");
                     }
                     isSucceed = await _lightManagerService.SetGlobalChannelBrightnessAsync(lightChannel.GlobalIndex, lightChannel.DefaultBrightness);
                     if (!isSucceed)

+ 1 - 1
TeamAAS-VM/ViewModels/Product/PlcPointParamsViewModel.cs

@@ -1782,7 +1782,7 @@ namespace TeamAAS_VP.ViewModels.Product
 
                 var _cts = new CancellationTokenSource();
                 // 2. 执行拍照并获取识别结果
-                var recognitionResult = await _remoteCommandService.ExecutePhotoGetSinglePoint(SelectProcedure, null, new double[] { rpoint.X, rpoint.Y, 0 }, _cts.Token);
+                var recognitionResult = await _remoteCommandService.ExecutePhotoGetSinglePointWithImage(SelectProcedure, null, new double[] { rpoint.X, rpoint.Y, 0 }, _cts.Token);
                 if (!recognitionResult.IsSucceed)
                 {
                     if (DialogHost.IsDialogOpen("RootDialog"))

+ 65 - 0
TeamAAS-VM/Views/Home/ShowVisionRender.xaml.cs

@@ -21,6 +21,7 @@ using TeamAAS_VP.Events;
 using TeamAAS_VP.Interfaces;
 using TeamAAS_VP.Models;
 using TeamAAS_VP.Resources.Languages;
+using TeamAAS_VP.Services;
 using TeamAAS_VP.ViewModels;
 using TeamAAS_VP.ViewModels.Home;
 using static MaterialDesignThemes.Wpf.Theme.ToolBar;
@@ -37,6 +38,8 @@ namespace TeamAAS_VP.Views.Home
         Dictionary<Guid, TextBlock> Titles;
         IEventAggregator _eventAggregator;
         ISystemDatabaseService _systemDatabaseService;
+        IProductService _productService;
+
         public ShowVisionRender()
         {
             InitializeComponent();
@@ -45,6 +48,7 @@ namespace TeamAAS_VP.Views.Home
             viewModel = DataContext as ShowVisionRenderViewModel;
             _eventAggregator = viewModel._eventAggregator;
             _systemDatabaseService= ((Prism.PrismApplicationBase)App.Current).Container.Resolve<ISystemDatabaseService>();
+            _productService = ((Prism.PrismApplicationBase)App.Current).Container.Resolve<IProductService>();
             viewModel.UpdateLayout += ViewModel_UpdateLayout;
             _eventAggregator.GetEvent<RenderUpdateNotification>().Subscribe(UpdateRenderModuleSource);
             _eventAggregator.GetEvent<ProductChangedNotification>().Subscribe(ProductChanged);
@@ -889,6 +893,26 @@ namespace TeamAAS_VP.Views.Home
                                 return;
                             }
                         }
+                        else if (saveImagePathModel== ProcedureSaveImagePathModel.Month_Day_Formula_ProductSN_Time)
+                        {
+                            //当前的产品配方名
+                            string formulaName = _productService.GetCurrentProduct().Name;
+                            //如果当前产品名称存在非法字符,则替换为下划线
+                            foreach (char c in Path.GetInvalidFileNameChars())
+                            {
+                                formulaName = formulaName.Replace(c, '_');
+                            }
+                            //获取当前的产品SN
+                            string productSN = _productService.CurrentProductCode;
+                            //如果产品SN存在非法字符,则替换为下划线
+                            foreach (char c in Path.GetInvalidFileNameChars())
+                            {
+                                productSN = productSN.Replace(c, '_');
+                            }
+                            //拍照结果
+                            string resultStr = result ? "OK" : "NG";
+                            Originalpath = $"{path}\\{now.ToString("yyyy-MM")}\\{now.ToString("MM-dd")}\\{formulaName}\\{productSN}\\{productSN}-{now.ToString("yyyy-MM-dd HH_mm_ss")}-{resultStr}.bmp";
+                        }
                         if (!Directory.Exists(Path.GetDirectoryName(Originalpath)))   //判断文件夹是否存在
                         {
                             Directory.CreateDirectory(Path.GetDirectoryName(Originalpath));    //创建文件夹
@@ -936,6 +960,26 @@ namespace TeamAAS_VP.Views.Home
                                 return;
                             }
                         }
+                        else if (saveImagePathModel == ProcedureSaveImagePathModel.Month_Day_Formula_ProductSN_Time)
+                        {
+                            //当前的产品配方名
+                            string formulaName = _productService.GetCurrentProduct().Name;
+                            //如果当前产品名称存在非法字符,则替换为下划线
+                            foreach (char c in Path.GetInvalidFileNameChars())
+                            {
+                                formulaName = formulaName.Replace(c, '_');
+                            }
+                            //获取当前的产品SN
+                            string productSN = _productService.CurrentProductCode;
+                            //如果产品SN存在非法字符,则替换为下划线
+                            foreach (char c in Path.GetInvalidFileNameChars())
+                            {
+                                productSN = productSN.Replace(c, '_');
+                            }
+                            //拍照结果
+                            string resultStr = result ? "OK" : "NG";
+                            Recordedpath = $"{path}\\{now.ToString("yyyy-MM")}\\{now.ToString("MM-dd")}\\{formulaName}\\{productSN}\\{productSN}-{now.ToString("yyyy-MM-dd HH_mm_ss")}-{resultStr}.bmp";
+                        }
                         if (!Directory.Exists(Path.GetDirectoryName(Recordedpath)))   //判断文件夹是否存在
                         {
                             Directory.CreateDirectory(Path.GetDirectoryName(Recordedpath));    //创建文件夹
@@ -992,6 +1036,27 @@ namespace TeamAAS_VP.Views.Home
                                 return;
                             }
                         }
+                        else if (saveImagePathModel == ProcedureSaveImagePathModel.Month_Day_Formula_ProductSN_Time)
+                        {
+                            //当前的产品配方名
+                            string formulaName = _productService.GetCurrentProduct().Name;
+                            //如果当前产品名称存在非法字符,则替换为下划线
+                            foreach (char c in Path.GetInvalidFileNameChars())
+                            {
+                                formulaName = formulaName.Replace(c, '_');
+                            }
+                            //获取当前的产品SN
+                            string productSN = _productService.CurrentProductCode;
+                            //如果产品SN存在非法字符,则替换为下划线
+                            foreach (char c in Path.GetInvalidFileNameChars())
+                            {
+                                productSN = productSN.Replace(c, '_');
+                            }
+                            //拍照结果
+                            string resultStr = result ? "OK" : "NG";
+                            Originalpath = $"{path}\\Original\\{now.ToString("yyyy-MM")}\\{now.ToString("MM-dd")}\\{formulaName}\\{productSN}\\{productSN}-{now.ToString("yyyy-MM-dd HH_mm_ss")}-{resultStr}.bmp";
+                            Recordedpath = $"{path}\\Recored\\{now.ToString("yyyy-MM")}\\{now.ToString("MM-dd")}\\{formulaName}\\{productSN}\\{productSN}-{now.ToString("yyyy-MM-dd HH_mm_ss")}-{resultStr}.bmp";
+                        }
                         if (!Directory.Exists(Path.GetDirectoryName(Originalpath)))   //判断文件夹是否存在
                         {
                             Directory.CreateDirectory(Path.GetDirectoryName(Originalpath));    //创建文件夹