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

feat: 添加 Helpers 模块及相关接口/服务更新

zly пре 2 месеци
родитељ
комит
5e71140851

+ 20 - 3
TeamAAS-VM/Core/Management.cs

@@ -2612,6 +2612,8 @@ namespace TeamAAS_VP.Core
                                     var ImageTaskResults = await Task.WhenAll(_ImageTaskList);
                                     imageBatchWatch.Stop();
                                     LogHelper.WriteLogInfo($"[PLC-TRACE] {fixedCameraTraceId} image task batch done, taskCount={ImageTaskResults.Length}, elapsedMs={imageBatchWatch.ElapsedMilliseconds}");
+                                    // 并发执行所有 ToolBlock(每个 ToolBlock 在独立 STA 线程中运行)
+                                    var procedureTasks = new List<Task>();
                                     foreach (var item in ImageTaskResults)
                                     {
                                         if (item.IsSucceed)
@@ -2620,9 +2622,9 @@ namespace TeamAAS_VP.Core
                                             if (targetPoint.AiVision == 1)
                                             {
                                                 var targetPoint2 = currentProduct.AoiPoints?.FirstOrDefault(p => p.Number == cameraIndex);
-                                                await ExecuteProcedureAsync(targetPoint.AiVision, targetPoint2.CameraProcedureId2, item.Images, Is3d, currentProduct);
+                                                procedureTasks.Add(ExecuteProcedureAsync(targetPoint.AiVision, targetPoint2.CameraProcedureId2, item.Images, Is3d, currentProduct));
                                             }
-                                            await ExecuteProcedureAsync(item.cameraIndex, item.procedureId, item.Images, Is3d, currentProduct);
+                                            procedureTasks.Add(ExecuteProcedureAsync(item.cameraIndex, item.procedureId, item.Images, Is3d, currentProduct));
                                         }
                                         else
                                         {
@@ -2631,6 +2633,8 @@ namespace TeamAAS_VP.Core
                                             ClearCountdown();
                                         }
                                     }
+                                    // 等待所有并发 ToolBlock 执行完成
+                                    await Task.WhenAll(procedureTasks);
                                 });
                             }
 
@@ -2641,7 +2645,20 @@ namespace TeamAAS_VP.Core
                                 bool resultFlog = true;
                                 //等待所有的图像处理流程处理完成
                                 //之前版本使用的是lock机制无法进行并发操作,目前能完美进行并发且能等待所有任务完成
-                                bool countdownCompleted = countdown.Wait(TimeSpan.FromSeconds(5));
+                                // 异步等待 countdown,避免同步阻塞线程池线程
+                                bool countdownCompleted;
+                                using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
+                                {
+                                    try
+                                    {
+                                        await Task.Run(() => countdown.Wait(cts.Token), cts.Token);
+                                        countdownCompleted = true;
+                                    }
+                                    catch (OperationCanceledException)
+                                    {
+                                        countdownCompleted = false;
+                                    }
+                                }
                                 if (!countdownCompleted)
                                 {
                                     SendTaskMessage($"检测流程超时!预期{countdown.InitialCount}个模板完成,实际仅完成{countdown.InitialCount - countdown.CurrentCount}个,按NG处理", MessageLevel.Alarm);

+ 115 - 0
TeamAAS-VM/Helpers/VisionProHelper.cs

@@ -0,0 +1,115 @@
+using Cognex.VisionPro;
+using Cognex.VisionPro.ToolBlock;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace TeamAAS_VP.Helpers
+{
+    /// <summary>
+    /// VisionPro 工具辅助类。
+    /// 提供在独立 STA 线程中异步执行 CogToolBlock 的能力,
+    /// 避免 COM 封送到主 UI 线程导致界面假死。
+    /// </summary>
+    public static class VisionProHelper
+    {
+        /// <summary>
+        /// 在专用 STA 后台线程中异步运行 ToolBlock。
+        /// 每次调用创建一个新的 STA 线程,ToolBlock 执行完毕后线程自动退出。
+        /// </summary>
+        /// <param name="toolBlock">要执行的 CogToolBlock 实例</param>
+        /// <returns>异步任务,完成时表示 ToolBlock 执行完毕</returns>
+        public static Task RunToolBlockAsync(CogToolBlock toolBlock)
+        {
+            if (toolBlock == null)
+                throw new ArgumentNullException(nameof(toolBlock));
+
+            var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            var thread = new Thread(() =>
+            {
+                try
+                {
+                    toolBlock.Run();
+                    tcs.TrySetResult(true);
+                }
+                catch (Exception ex)
+                {
+                    tcs.TrySetException(ex);
+                }
+            })
+            {
+                IsBackground = true,
+                Name = $"VP-Run-{Guid.NewGuid():N}"
+            };
+            thread.SetApartmentState(ApartmentState.STA);
+            thread.Start();
+            return tcs.Task;
+        }
+
+        /// <summary>
+        /// 在专用 STA 后台线程中异步加载 VisionPro 序列化对象(.vpp 文件等)。
+        /// </summary>
+        /// <typeparam name="T">反序列化的目标类型</typeparam>
+        /// <param name="filePath">.vpp 文件完整路径</param>
+        /// <returns>包含反序列化对象的异步任务</returns>
+        public static Task<T> LoadVisionProObjectAsync<T>(string filePath) where T : class
+        {
+            if (string.IsNullOrEmpty(filePath))
+                throw new ArgumentNullException(nameof(filePath));
+
+            var tcs = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);
+            var thread = new Thread(() =>
+            {
+                try
+                {
+                    var obj = CogSerializer.LoadObjectFromFile(filePath) as T;
+                    tcs.TrySetResult(obj);
+                }
+                catch (Exception ex)
+                {
+                    tcs.TrySetException(ex);
+                }
+            })
+            {
+                IsBackground = true,
+                Name = $"VP-Load-{Guid.NewGuid():N}"
+            };
+            thread.SetApartmentState(ApartmentState.STA);
+            thread.Start();
+            return tcs.Task;
+        }
+
+        /// <summary>
+        /// 在专用 STA 后台线程中异步保存 VisionPro 对象到文件。
+        /// </summary>
+        /// <param name="obj">要保存的对象</param>
+        /// <param name="filePath">目标文件路径</param>
+        /// <returns>异步任务</returns>
+        public static Task SaveVisionProObjectAsync(object obj, string filePath)
+        {
+            if (obj == null) throw new ArgumentNullException(nameof(obj));
+            if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException(nameof(filePath));
+
+            var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            var thread = new Thread(() =>
+            {
+                try
+                {
+                    CogSerializer.SaveObjectToFile(obj, filePath);
+                    tcs.TrySetResult(true);
+                }
+                catch (Exception ex)
+                {
+                    tcs.TrySetException(ex);
+                }
+            })
+            {
+                IsBackground = true,
+                Name = $"VP-Save-{Guid.NewGuid():N}"
+            };
+            thread.SetApartmentState(ApartmentState.STA);
+            thread.Start();
+            return tcs.Task;
+        }
+    }
+}

+ 57 - 57
TeamAAS-VM/Interfaces/IMesService.cs

@@ -8,108 +8,108 @@ using TeamAAS_VP.Models;
 namespace TeamAAS_VP.Interfaces
 {
     /// <summary>
-    /// MES 通信服务接口。
-    /// 提供通过配置的 URL 发起 GET 请求的抽象,用于执行过站(Station)与提交结果(Submit)操作。
-    /// 实现者应负责管理内部 HTTP 客户端或通信资源,并在 Dispose 中释放这些资源。
+    /// MES 閫氫俊鏈嶅姟鎺ュ彛銆�
+    /// 鎻愪緵閫氳繃閰嶇疆鐨� URL 鍙戣捣 GET 璇锋眰鐨勬娊璞★紝鐢ㄤ簬鎵ц�杩囩珯锛圫tation锛変笌鎻愪氦缁撴灉锛圫ubmit锛夋搷浣溿€�
+    /// 瀹炵幇鑰呭簲璐熻矗绠$悊鍐呴儴 HTTP 瀹㈡埛绔�垨閫氫俊璧勬簮锛屽苟鍦� Dispose 涓�噴鏀捐繖浜涜祫婧愩€�
     /// </summary>
     public interface IMesService : IDisposable
     {
         /// <summary>
-        /// 使用配置的过站(Station)URL 发起 GET 请求,携带序列号(sn)作为查询参数进行过站。
+        /// 浣跨敤閰嶇疆鐨勮繃绔欙紙Station锛塙RL 鍙戣捣 GET 璇锋眰锛屾惡甯﹀簭鍒楀彿锛坰n锛変綔涓烘煡璇㈠弬鏁拌繘琛岃繃绔欍€�
         /// </summary>
-        /// <param name="sn">要过站的产品序列号,不能为空或空白。</param>
-        /// <param name="cancellationToken">用于在外部请求取消时中止异步请求的 <see cref="CancellationToken"/>。默认值为 <see cref="CancellationToken.None"/>。</param>
+        /// <param name="sn">瑕佽繃绔欑殑浜у搧搴忓垪鍙凤紝涓嶈兘涓虹┖鎴栫┖鐧姐€�</param>
+        /// <param name="cancellationToken">鐢ㄤ簬鍦ㄥ�閮ㄨ�姹傚彇娑堟椂涓��寮傛�璇锋眰鐨� <see cref="CancellationToken"/>銆傞粯璁ゅ€间负 <see cref="CancellationToken.None"/>銆�</param>
         /// <returns>
-        /// 一个包含请求结果的元组:
-        /// IsSuccess 表示请求并解析 MES 响应是否被认为成功(由实现定义,例如 HTTP 200 且业务状态正常)。
-        /// Response 为 MES 返回的原始响应字符串或描述错误的信息(不为 null,可为空字符串)。
+        /// 涓€涓�寘鍚��姹傜粨鏋滅殑鍏冪粍锛�
+        /// IsSuccess 琛ㄧず璇锋眰骞惰В鏋� MES 鍝嶅簲鏄�惁琚��涓烘垚鍔燂紙鐢卞疄鐜板畾涔夛紝渚嬪� HTTP 200 涓斾笟鍔$姸鎬佹�甯革級銆�
+        /// Response 涓� MES 杩斿洖鐨勫師濮嬪搷搴斿瓧绗︿覆鎴栨弿杩伴敊璇�殑淇℃伅锛堜笉涓� null锛屽彲涓虹┖瀛楃�涓诧級銆�
         /// </returns>
         /// <remarks>
-        /// - 实现应从配置中读取过站 URL 并将 sn 作为查询参数附加到 URL。
-        /// - 实现应尊重 <paramref name="cancellationToken"/>,在取消时尽早抛出 <see cref="OperationCanceledException"/> 或返回失败结果。
-        /// - 若 <paramref name="sn"/> 无效,应抛出 <see cref="ArgumentNullException"/> 或 <see cref="ArgumentException"/>。
+        /// - 瀹炵幇搴斾粠閰嶇疆涓��鍙栬繃绔� URL 骞跺皢 sn 浣滀负鏌ヨ�鍙傛暟闄勫姞鍒� URL銆�
+        /// - 瀹炵幇搴斿皧閲� <paramref name="cancellationToken"/>锛屽湪鍙栨秷鏃跺敖鏃╂姏鍑� <see cref="OperationCanceledException"/> 鎴栬繑鍥炲け璐ョ粨鏋溿€�
+        /// - 鑻� <paramref name="sn"/> 鏃犳晥锛屽簲鎶涘嚭 <see cref="ArgumentNullException"/> 鎴� <see cref="ArgumentException"/>銆�
         /// </remarks>
         Task<(bool IsSuccess, string Response)> StationGetAsync(string sn, string comp, CancellationToken cancellationToken = default);
 
         /// <summary>
-        /// 使用配置的过站(Station)URL 发起 GET 请求,携带序列号(sn)作为查询参数进行过站,并使用指定的超时时间(秒)。
+        /// 浣跨敤閰嶇疆鐨勮繃绔欙紙Station锛塙RL 鍙戣捣 GET 璇锋眰锛屾惡甯﹀簭鍒楀彿锛坰n锛変綔涓烘煡璇㈠弬鏁拌繘琛岃繃绔欙紝骞朵娇鐢ㄦ寚瀹氱殑瓒呮椂鏃堕棿锛堢�锛夈€�
         /// </summary>
-        /// <param name="sn">要过站的产品序列号,不能为空或空白。</param>
-        /// <param name="timeoutInSeconds">请求超时时间,单位为秒。应为正数;实现可以将其应用到 HTTP 客户端或请求级别超时。</param>
+        /// <param name="sn">瑕佽繃绔欑殑浜у搧搴忓垪鍙凤紝涓嶈兘涓虹┖鎴栫┖鐧姐€�</param>
+        /// <param name="timeoutInSeconds">璇锋眰瓒呮椂鏃堕棿锛屽崟浣嶄负绉掋€傚簲涓烘�鏁帮紱瀹炵幇鍙�互灏嗗叾搴旂敤鍒� HTTP 瀹㈡埛绔�垨璇锋眰绾у埆瓒呮椂銆�</param>
         /// <returns>
-        /// 一个包含请求结果的元组:
-        /// IsSuccess 表示请求并解析 MES 响应是否被认为成功。
-        /// Response 为 MES 返回的原始响应字符串或描述错误的信息。
+        /// 涓€涓�寘鍚��姹傜粨鏋滅殑鍏冪粍锛�
+        /// IsSuccess 琛ㄧず璇锋眰骞惰В鏋� MES 鍝嶅簲鏄�惁琚��涓烘垚鍔熴€�
+        /// Response 涓� MES 杩斿洖鐨勫師濮嬪搷搴斿瓧绗︿覆鎴栨弿杩伴敊璇�殑淇℃伅銆�
         /// </returns>
         /// <remarks>
-        /// - 此重载方便在不使用 <see cref="CancellationToken"/> 的场景中指定超时时间。
-        /// - 实现应验证 <paramref name="timeoutInSeconds"/> 为合理值(例如 > 0),否则可抛出 <see cref="ArgumentOutOfRangeException"/>。
+        /// - 姝ら噸杞芥柟渚垮湪涓嶄娇鐢� <see cref="CancellationToken"/> 鐨勫満鏅�腑鎸囧畾瓒呮椂鏃堕棿銆�
+        /// - 瀹炵幇搴旈獙璇� <paramref name="timeoutInSeconds"/> 涓哄悎鐞嗗€硷紙渚嬪� > 0锛夛紝鍚﹀垯鍙�姏鍑� <see cref="ArgumentOutOfRangeException"/>銆�
         /// </remarks>
         Task<(bool IsSuccess, string Response)> StationGetAsync(string sn, string comp, double timeoutInSeconds);
 
         Task<(bool IsSuccess, string Response)> StationGetExAsync(string sn, string comp, double timeoutInSeconds);
 
         /// <summary>
-        /// 使用配置的提交(Submit)URL 发起 GET 请求,提交过站结果及时间信息。
+        /// 浣跨敤閰嶇疆鐨勬彁浜わ紙Submit锛塙RL 鍙戣捣 GET 璇锋眰锛屾彁浜よ繃绔欑粨鏋滃強鏃堕棿淇℃伅銆�
         /// </summary>
-        /// <param name="sn">待提交的产品序列号,不能为空或空白。</param>
-        /// <param name="isSuccess">表示该序列号对应的过站是否成功(业务层面的成功标志)。</param>
-        /// <param name="start_time">过程开始时间(本地时间或 UTC,取决于与 MES 的约定)。实现方应按与 MES 约定的时区/格式发送。</param>
-        /// <param name="stop_time">过程结束时间,语义同 <paramref name="start_time"/>。</param>
-        /// <param name="cancellationToken">用于在外部请求取消时中止异步请求的 <see cref="CancellationToken"/>。默认值为 <see cref="CancellationToken.None"/>。</param>
+        /// <param name="sn">寰呮彁浜ょ殑浜у搧搴忓垪鍙凤紝涓嶈兘涓虹┖鎴栫┖鐧姐€�</param>
+        /// <param name="isSuccess">琛ㄧず璇ュ簭鍒楀彿瀵瑰簲鐨勮繃绔欐槸鍚︽垚鍔燂紙涓氬姟灞傞潰鐨勬垚鍔熸爣蹇楋級銆�</param>
+        /// <param name="start_time">杩囩▼寮€濮嬫椂闂达紙鏈�湴鏃堕棿鎴� UTC锛屽彇鍐充簬涓� MES 鐨勭害瀹氾級銆傚疄鐜版柟搴旀寜涓� MES 绾﹀畾鐨勬椂鍖�/鏍煎紡鍙戦€併€�</param>
+        /// <param name="stop_time">杩囩▼缁撴潫鏃堕棿锛岃�涔夊悓 <paramref name="start_time"/>銆�</param>
+        /// <param name="cancellationToken">鐢ㄤ簬鍦ㄥ�閮ㄨ�姹傚彇娑堟椂涓��寮傛�璇锋眰鐨� <see cref="CancellationToken"/>銆傞粯璁ゅ€间负 <see cref="CancellationToken.None"/>銆�</param>
         /// <returns>
-        /// 一个包含请求结果的元组:
-        /// IsSuccess 表示提交请求及解析 MES 响应是否被认为成功。
-        /// Response 为 MES 返回的原始响应字符串或描述错误的信息。
+        /// 涓€涓�寘鍚��姹傜粨鏋滅殑鍏冪粍锛�
+        /// IsSuccess 琛ㄧず鎻愪氦璇锋眰鍙婅В鏋� MES 鍝嶅簲鏄�惁琚��涓烘垚鍔熴€�
+        /// Response 涓� MES 杩斿洖鐨勫師濮嬪搷搴斿瓧绗︿覆鎴栨弿杩伴敊璇�殑淇℃伅銆�
         /// </returns>
         /// <remarks>
-        /// - 实现应将时间参数按 MES 要求格式化为查询字符串或适当的请求参数。
-        /// - 若 <paramref name="start_time"/> 晚于 <paramref name="stop_time"/>,实现应记录并视情况返回失败或抛出异常。
-        /// - 实现应尊重 <paramref name="cancellationToken"/>,并在取消时尽早中止请求。
+        /// - 瀹炵幇搴斿皢鏃堕棿鍙傛暟鎸� MES 瑕佹眰鏍煎紡鍖栦负鏌ヨ�瀛楃�涓叉垨閫傚綋鐨勮�姹傚弬鏁般€�
+        /// - 鑻� <paramref name="start_time"/> 鏅氫簬 <paramref name="stop_time"/>锛屽疄鐜板簲璁板綍骞惰�鎯呭喌杩斿洖澶辫触鎴栨姏鍑哄紓甯搞€�
+        /// - 瀹炵幇搴斿皧閲� <paramref name="cancellationToken"/>锛屽苟鍦ㄥ彇娑堟椂灏芥棭涓��璇锋眰銆�
         /// </remarks>
         Task<(bool IsSuccess, string Response)> SubmitGetAsync(string sn, string comp, string assypress, string cc,string height, bool isSuccess, DateTime start_time, DateTime stop_time, CancellationToken cancellationToken = default);
 
         /// <summary>
-        /// 使用配置的提交(Submit)URL 发起 GET 请求,提交过站结果及时间信息,并使用指定的超时时间(秒)。
+        /// 浣跨敤閰嶇疆鐨勬彁浜わ紙Submit锛塙RL 鍙戣捣 GET 璇锋眰锛屾彁浜よ繃绔欑粨鏋滃強鏃堕棿淇℃伅锛屽苟浣跨敤鎸囧畾鐨勮秴鏃舵椂闂达紙绉掞級銆�
         /// </summary>
-        /// <param name="sn">待提交的产品序列号,不能为空或空白。</param>
-        /// <param name="isSuccess">表示该序列号对应的过站是否成功。</param>
-        /// <param name="start_time">过程开始时间。</param>
-        /// <param name="stop_time">过程结束时间。</param>
-        /// <param name="timeoutInSeconds">请求超时时间,单位为秒。应为正数。</param>
+        /// <param name="sn">寰呮彁浜ょ殑浜у搧搴忓垪鍙凤紝涓嶈兘涓虹┖鎴栫┖鐧姐€�</param>
+        /// <param name="isSuccess">琛ㄧず璇ュ簭鍒楀彿瀵瑰簲鐨勮繃绔欐槸鍚︽垚鍔熴€�</param>
+        /// <param name="start_time">杩囩▼寮€濮嬫椂闂淬€�</param>
+        /// <param name="stop_time">杩囩▼缁撴潫鏃堕棿銆�</param>
+        /// <param name="timeoutInSeconds">璇锋眰瓒呮椂鏃堕棿锛屽崟浣嶄负绉掋€傚簲涓烘�鏁般€�</param>
         /// <returns>
-        /// 一个包含请求结果的元组:
-        /// IsSuccess 指示提交是否被认为成功。
-        /// Response 包含 MES 的原始响应或错误信息。
+        /// 涓€涓�寘鍚��姹傜粨鏋滅殑鍏冪粍锛�
+        /// IsSuccess 鎸囩ず鎻愪氦鏄�惁琚��涓烘垚鍔熴€�
+        /// Response 鍖呭惈 MES 鐨勫師濮嬪搷搴旀垨閿欒�淇℃伅銆�
         /// </returns>
         /// <remarks>
-        /// - 此重载用于在不传入 <see cref="CancellationToken"/> 的场景中指定超时时间。
-        /// - 实现应确保对时间参数与布尔参数进行适当的 URL 编码或格式化。
+        /// - 姝ら噸杞界敤浜庡湪涓嶄紶鍏� <see cref="CancellationToken"/> 鐨勫満鏅�腑鎸囧畾瓒呮椂鏃堕棿銆�
+        /// - 瀹炵幇搴旂‘淇濆�鏃堕棿鍙傛暟涓庡竷灏斿弬鏁拌繘琛岄€傚綋鐨� URL 缂栫爜鎴栨牸寮忓寲銆�
         /// </remarks>
         Task<(bool IsSuccess, string Response)> SubmitGetAsync(string sn, string comp, string assypress, string cc, string height, bool isSuccess, DateTime start_time, DateTime stop_time, double timeoutInSeconds);
 
         /// <summary>
-        /// 使用配置的提交(Submit)URL 发起 GET 请求,提交过站结果及时间信息。
+        /// 浣跨敤閰嶇疆鐨勬彁浜わ紙Submit锛塙RL 鍙戣捣 GET 璇锋眰锛屾彁浜よ繃绔欑粨鏋滃強鏃堕棿淇℃伅銆�
         /// </summary>
-        /// <param name="sn">待提交的产品序列号,不能为空或空白。</param>
-        /// <param name="isSuccess">表示该序列号对应的过站是否成功(业务层面的成功标志)。</param>
-        /// <param name="start_time">过程开始时间(本地时间或 UTC,取决于与 MES 的约定)。实现方应按与 MES 约定的时区/格式发送。</param>
-        /// <param name="stop_time">过程结束时间,语义同 <paramref name="start_time"/>。</param>
-        /// <param name="cancellationToken">用于在外部请求取消时中止异步请求的 <see cref="CancellationToken"/>。默认值为 <see cref="CancellationToken.None"/>。</param>
+        /// <param name="sn">寰呮彁浜ょ殑浜у搧搴忓垪鍙凤紝涓嶈兘涓虹┖鎴栫┖鐧姐€�</param>
+        /// <param name="isSuccess">琛ㄧず璇ュ簭鍒楀彿瀵瑰簲鐨勮繃绔欐槸鍚︽垚鍔燂紙涓氬姟灞傞潰鐨勬垚鍔熸爣蹇楋級銆�</param>
+        /// <param name="start_time">杩囩▼寮€濮嬫椂闂达紙鏈�湴鏃堕棿鎴� UTC锛屽彇鍐充簬涓� MES 鐨勭害瀹氾級銆傚疄鐜版柟搴旀寜涓� MES 绾﹀畾鐨勬椂鍖�/鏍煎紡鍙戦€併€�</param>
+        /// <param name="stop_time">杩囩▼缁撴潫鏃堕棿锛岃�涔夊悓 <paramref name="start_time"/>銆�</param>
+        /// <param name="cancellationToken">鐢ㄤ簬鍦ㄥ�閮ㄨ�姹傚彇娑堟椂涓��寮傛�璇锋眰鐨� <see cref="CancellationToken"/>銆傞粯璁ゅ€间负 <see cref="CancellationToken.None"/>銆�</param>
         /// <returns>
-        /// 一个包含请求结果的元组:
-        /// IsSuccess 表示提交请求及解析 MES 响应是否被认为成功。
-        /// Response 为 MES 返回的原始响应字符串或描述错误的信息。
+        /// 涓€涓�寘鍚��姹傜粨鏋滅殑鍏冪粍锛�
+        /// IsSuccess 琛ㄧず鎻愪氦璇锋眰鍙婅В鏋� MES 鍝嶅簲鏄�惁琚��涓烘垚鍔熴€�
+        /// Response 涓� MES 杩斿洖鐨勫師濮嬪搷搴斿瓧绗︿覆鎴栨弿杩伴敊璇�殑淇℃伅銆�
         /// </returns>
         /// <remarks>
-        /// - 实现应将时间参数按 MES 要求格式化为查询字符串或适当的请求参数。
-        /// - 若 <paramref name="start_time"/> 晚于 <paramref name="stop_time"/>,实现应记录并视情况返回失败或抛出异常。
-        /// - 实现应尊重 <paramref name="cancellationToken"/>,并在取消时尽早中止请求。
+        /// - 瀹炵幇搴斿皢鏃堕棿鍙傛暟鎸� MES 瑕佹眰鏍煎紡鍖栦负鏌ヨ�瀛楃�涓叉垨閫傚綋鐨勮�姹傚弬鏁般€�
+        /// - 鑻� <paramref name="start_time"/> 鏅氫簬 <paramref name="stop_time"/>锛屽疄鐜板簲璁板綍骞惰�鎯呭喌杩斿洖澶辫触鎴栨姏鍑哄紓甯搞€�
+        /// - 瀹炵幇搴斿皧閲� <paramref name="cancellationToken"/>锛屽苟鍦ㄥ彇娑堟椂灏芥棭涓��璇锋眰銆�
         /// </remarks>
         Task<(bool IsSuccess, string Response)> SubmitGetAsync(int deviceNo,string sn, string comp, string mesdata, bool isSuccess, string submitDataError, DateTime start_time, DateTime stop_time, CancellationToken cancellationToken = default);
 
         /// <summary>
-        /// 获取服务器当前时间
+        /// 鑾峰彇鏈嶅姟鍣ㄥ綋鍓嶆椂闂�
         /// </summary>
         /// <param name="sn"></param>
         /// <param name="timeoutInSeconds"></param>
@@ -117,7 +117,7 @@ namespace TeamAAS_VP.Interfaces
         Task<(bool IsSuccess, DateTime Now)> GetServerTimeAsync(string sn, double timeoutInSeconds);
 
         /// <summary>
-        /// 上传log
+        /// 涓婁紶log
         /// </summary>
         /// <param name="sn"></param>
         /// <param name="name"></param>

+ 61 - 61
TeamAAS-VM/Interfaces/IPlcService.cs

@@ -6,163 +6,163 @@ using TeamAAS_VP.Models;
 namespace TeamAAS_VP.Interfaces
 {
     /// <summary>
-    /// 提供 PLC 生命周期管理的接口,包括创建、获取、初始化及注销 PLC 实例。
+    /// 鎻愪緵 PLC 鐢熷懡鍛ㄦ湡绠$悊鐨勬帴鍙o紝鍖呮嫭鍒涘缓銆佽幏鍙栥€佸垵濮嬪寲鍙婃敞閿€ PLC 瀹炰緥銆�
     /// </summary>
     public interface IPlcService : IDisposable
     {
         /// <summary>
-        /// 异步创建并注册一个新的 PLC 实例。
+        /// 寮傛�鍒涘缓骞舵敞鍐屼竴涓�柊鐨� PLC 瀹炰緥銆�
         /// </summary>
-        /// <param name="id">PLC 唯一标识。</param>
-        /// <param name="plcInfo">PLC 的配置信息。</param>
-        /// <returns>创建是否成功。</returns>
+        /// <param name="id">PLC 鍞�竴鏍囪瘑銆�</param>
+        /// <param name="plcInfo">PLC 鐨勯厤缃�俊鎭�€�</param>
+        /// <returns>鍒涘缓鏄�惁鎴愬姛銆�</returns>
         Task<bool> CreatePlcAsync(Guid id, PlcInfo plcInfo);
 
         /// <summary>
-        /// 同步创建并注册一个新的 PLC 实例。
+        /// 鍚屾�鍒涘缓骞舵敞鍐屼竴涓�柊鐨� PLC 瀹炰緥銆�
         /// </summary>
-        /// <param name="id">PLC 唯一标识。</param>
-        /// <param name="plcInfo">PLC 的配置信息。</param>
-        /// <returns>创建是否成功。</returns>
+        /// <param name="id">PLC 鍞�竴鏍囪瘑銆�</param>
+        /// <param name="plcInfo">PLC 鐨勯厤缃�俊鎭�€�</param>
+        /// <returns>鍒涘缓鏄�惁鎴愬姛銆�</returns>
         bool CreatePlc(Guid id, PlcInfo plcInfo);
 
         /// <summary>
-        /// 初始化所有PLC实例(同步)。
+        /// 鍒濆�鍖栨墍鏈塒LC瀹炰緥锛堝悓姝ワ級銆�
         /// </summary>
         /// <param name="plcs"></param>
         /// <returns></returns>
         (bool IsSucceed, string Message) InitializePlc(PlcInfo[] plcs);
 
         /// <summary>
-        /// 初始化所有PLC实例(异步)。
+        /// 鍒濆�鍖栨墍鏈塒LC瀹炰緥锛堝紓姝ワ級銆�
         /// </summary>
         /// <param name="plcs"></param>
         /// <returns></returns>
         Task<(bool IsSucceed, string Message)> InitializePlcAsync(PlcInfo[] plcs);
 
         /// <summary>
-        /// 获取指定 ID 的 PLC 实例(同步),如果不存在可返回 null 或抛出异常,视实现而定。
+        /// 鑾峰彇鎸囧畾 ID 鐨� PLC 瀹炰緥锛堝悓姝ワ級锛屽�鏋滀笉瀛樺湪鍙�繑鍥� null 鎴栨姏鍑哄紓甯革紝瑙嗗疄鐜拌€屽畾銆�
         /// </summary>
-        /// <param name="id">PLC 唯一标识。</param>
-        /// <returns>对应的 <see cref="IPlc"/> 实例。</returns>
+        /// <param name="id">PLC 鍞�竴鏍囪瘑銆�</param>
+        /// <returns>瀵瑰簲鐨� <see cref="IPlc"/> 瀹炰緥銆�</returns>
         IPlc GetPlc(Guid id);
 
         /// <summary>
-        /// 异步获取指定 ID 的 PLC 实例。
+        /// 寮傛�鑾峰彇鎸囧畾 ID 鐨� PLC 瀹炰緥銆�
         /// </summary>
-        /// <param name="id">PLC 唯一标识。</param>
-        /// <returns>对应的 <see cref="IPlc"/> 实例的任务。</returns>
+        /// <param name="id">PLC 鍞�竴鏍囪瘑銆�</param>
+        /// <returns>瀵瑰簲鐨� <see cref="IPlc"/> 瀹炰緥鐨勪换鍔°€�</returns>
         Task<IPlc> GetPlcAsync(Guid id);
 
         /// <summary>
-        /// 获取当前所有已注册的 PLC(只读集合,同步)。
+        /// 鑾峰彇褰撳墠鎵€鏈夊凡娉ㄥ唽鐨� PLC锛堝彧璇婚泦鍚堬紝鍚屾�锛夈€�
         /// </summary>
-        /// <returns>只读的 PLC 实例集合。</returns>
+        /// <returns>鍙��鐨� PLC 瀹炰緥闆嗗悎銆�</returns>
         IReadOnlyCollection<IPlc> GetAllPlcs();
 
         /// <summary>
-        /// 异步获取当前所有已注册的 PLC(只读集合)。
+        /// 寮傛�鑾峰彇褰撳墠鎵€鏈夊凡娉ㄥ唽鐨� PLC锛堝彧璇婚泦鍚堬級銆�
         /// </summary>
-        /// <returns>只读的 PLC 实例集合的任务。</returns>
+        /// <returns>鍙��鐨� PLC 瀹炰緥闆嗗悎鐨勪换鍔°€�</returns>
         Task<IReadOnlyCollection<IPlc>> GetAllPlcsAsync();
 
         /// <summary>
-        /// 尝试根据 ID 获取 PLC(同步),若存在则返回 true 并通过 out 参数返回实例。
+        /// 灏濊瘯鏍规嵁 ID 鑾峰彇 PLC锛堝悓姝ワ級锛岃嫢瀛樺湪鍒欒繑鍥� true 骞堕€氳繃 out 鍙傛暟杩斿洖瀹炰緥銆�
         /// </summary>
-        /// <param name="id">PLC 唯一标识。</param>
-        /// <param name="plc">输出的 PLC 实例(若找到)。</param>
-        /// <returns>是否找到。</returns>
+        /// <param name="id">PLC 鍞�竴鏍囪瘑銆�</param>
+        /// <param name="plc">杈撳嚭鐨� PLC 瀹炰緥锛堣嫢鎵惧埌锛夈€�</param>
+        /// <returns>鏄�惁鎵惧埌銆�</returns>
         bool TryGetPlc(Guid id, out IPlc plc);
 
         /// <summary>
-        /// 尝试根据 ID 异步获取 PLC,返回是否找到及实例的元组。
+        /// 灏濊瘯鏍规嵁 ID 寮傛�鑾峰彇 PLC锛岃繑鍥炴槸鍚︽壘鍒板強瀹炰緥鐨勫厓缁勩€�
         /// </summary>
-        /// <param name="id">PLC 唯一标识。</param>
-        /// <returns>包含是否找到与实例的元组。</returns>
+        /// <param name="id">PLC 鍞�竴鏍囪瘑銆�</param>
+        /// <returns>鍖呭惈鏄�惁鎵惧埌涓庡疄渚嬬殑鍏冪粍銆�</returns>
         Task<(bool found, IPlc plc)> TryGetPlcAsync(Guid id);
 
         /// <summary>
-        /// 判断是否包含指定 ID 的 PLC(同步)。
+        /// 鍒ゆ柇鏄�惁鍖呭惈鎸囧畾 ID 鐨� PLC锛堝悓姝ワ級銆�
         /// </summary>
-        /// <param name="id">PLC 唯一标识。</param>
-        /// <returns>是否包含。</returns>
+        /// <param name="id">PLC 鍞�竴鏍囪瘑銆�</param>
+        /// <returns>鏄�惁鍖呭惈銆�</returns>
         bool ContainsPlc(Guid id);
 
         /// <summary>
-        /// 判断是否包含指定 ID 的 PLC(异步)。
+        /// 鍒ゆ柇鏄�惁鍖呭惈鎸囧畾 ID 鐨� PLC锛堝紓姝ワ級銆�
         /// </summary>
-        /// <param name="id">PLC 唯一标识。</param>
-        /// <returns>是否包含的任务。</returns>
+        /// <param name="id">PLC 鍞�竴鏍囪瘑銆�</param>
+        /// <returns>鏄�惁鍖呭惈鐨勪换鍔°€�</returns>
         Task<bool> ContainsPlcAsync(Guid id);
 
         /// <summary>
-        /// 移除指定 ID 的 PLC(同步),并释放其资源。
+        /// 绉婚櫎鎸囧畾 ID 鐨� PLC锛堝悓姝ワ級锛屽苟閲婃斁鍏惰祫婧愩€�
         /// </summary>
-        /// <param name="id">PLC 唯一标识。</param>
-        /// <returns>移除是否成功。</returns>
+        /// <param name="id">PLC 鍞�竴鏍囪瘑銆�</param>
+        /// <returns>绉婚櫎鏄�惁鎴愬姛銆�</returns>
         bool RemovePlc(Guid id);
 
         /// <summary>
-        /// 异步移除指定 ID 的 PLC,并释放其资源。
+        /// 寮傛�绉婚櫎鎸囧畾 ID 鐨� PLC锛屽苟閲婃斁鍏惰祫婧愩€�
         /// </summary>
-        /// <param name="id">PLC 唯一标识。</param>
-        /// <returns>移除是否成功的任务。</returns>
+        /// <param name="id">PLC 鍞�竴鏍囪瘑銆�</param>
+        /// <returns>绉婚櫎鏄�惁鎴愬姛鐨勪换鍔°€�</returns>
         Task<bool> RemovePlcAsync(Guid id);
 
         /// <summary>
-        /// 移除所有已注册的 PLC(同步),并释放相关资源。
+        /// 绉婚櫎鎵€鏈夊凡娉ㄥ唽鐨� PLC锛堝悓姝ワ級锛屽苟閲婃斁鐩稿叧璧勬簮銆�
         /// </summary>
-        /// <returns>是否全部成功移除;若部分失败则返回 false。</returns>
+        /// <returns>鏄�惁鍏ㄩ儴鎴愬姛绉婚櫎锛涜嫢閮ㄥ垎澶辫触鍒欒繑鍥� false銆�</returns>
         bool RemoveAllPlcs();
 
         /// <summary>
-        /// 异步移除所有已注册的 PLC,并释放相关资源。
+        /// 寮傛�绉婚櫎鎵€鏈夊凡娉ㄥ唽鐨� PLC锛屽苟閲婃斁鐩稿叧璧勬簮銆�
         /// </summary>
-        /// <returns>是否全部成功移除的任务;若部分失败则返回 false。</returns>
+        /// <returns>鏄�惁鍏ㄩ儴鎴愬姛绉婚櫎鐨勪换鍔★紱鑻ラ儴鍒嗗け璐ュ垯杩斿洖 false銆�</returns>
         Task<bool> RemoveAllPlcsAsync();
 
         /// <summary>
-        /// 异步注销指定的 PLC(例如注销事件、断开连接等),不一定会立即从集合中移除,具体行为由实现决定。
+        /// 寮傛�娉ㄩ攢鎸囧畾鐨� PLC锛堜緥濡傛敞閿€浜嬩欢銆佹柇寮€杩炴帴绛夛級锛屼笉涓€瀹氫細绔嬪嵆浠庨泦鍚堜腑绉婚櫎锛屽叿浣撹�涓虹敱瀹炵幇鍐冲畾銆�
         /// </summary>
-        /// <param name="id">PLC 唯一标识。</param>
-        /// <returns>任务。</returns>
+        /// <param name="id">PLC 鍞�竴鏍囪瘑銆�</param>
+        /// <returns>浠诲姟銆�</returns>
         Task UnRegisterPlcAsync(Guid id);
 
         /// <summary>
-        /// 同步注销指定的 PLC(例如注销事件、断开连接等),不一定会立即从集合中移除,具体行为由实现决定。
+        /// 鍚屾�娉ㄩ攢鎸囧畾鐨� PLC锛堜緥濡傛敞閿€浜嬩欢銆佹柇寮€杩炴帴绛夛級锛屼笉涓€瀹氫細绔嬪嵆浠庨泦鍚堜腑绉婚櫎锛屽叿浣撹�涓虹敱瀹炵幇鍐冲畾銆�
         /// </summary>
-        /// <param name="id">PLC 唯一标识。</param>
+        /// <param name="id">PLC 鍞�竴鏍囪瘑銆�</param>
         void UnRegisterPlc(Guid id);
 
         /// <summary>
-        /// 根据 PLC 编号获取 PLC 实例(同步)。
+        /// 鏍规嵁 PLC 缂栧彿鑾峰彇 PLC 瀹炰緥锛堝悓姝ワ級銆�
         /// </summary>
-        /// <param name="number">PLC 编号。</param>
-        /// <returns>对应的 <see cref="IPlc"/> 实例。</returns>
+        /// <param name="number">PLC 缂栧彿銆�</param>
+        /// <returns>瀵瑰簲鐨� <see cref="IPlc"/> 瀹炰緥銆�</returns>
         IPlc GetPlcByNumber(int number);
 
         /// <summary>
-        /// 根据 PLC 编号异步获取 PLC 实例。
+        /// 鏍规嵁 PLC 缂栧彿寮傛�鑾峰彇 PLC 瀹炰緥銆�
         /// </summary>
-        /// <param name="number">PLC 编号。</param>
-        /// <returns>对应的 <see cref="IPlc"/> 实例的任务。</returns>
+        /// <param name="number">PLC 缂栧彿銆�</param>
+        /// <returns>瀵瑰簲鐨� <see cref="IPlc"/> 瀹炰緥鐨勪换鍔°€�</returns>
         Task<IPlc> GetPlcByNumberAsync(int number);
 
         /// <summary>
-        /// 根据 PLC 编号异步注销 PLC(例如注销事件、断开连接等)。
+        /// 鏍规嵁 PLC 缂栧彿寮傛�娉ㄩ攢 PLC锛堜緥濡傛敞閿€浜嬩欢銆佹柇寮€杩炴帴绛夛級銆�
         /// </summary>
-        /// <param name="number">PLC 编号。</param>
-        /// <returns>任务。</returns>
+        /// <param name="number">PLC 缂栧彿銆�</param>
+        /// <returns>浠诲姟銆�</returns>
         Task UnRegisterPlcByNumberAsync(int number);
 
         /// <summary>
-        /// 根据 PLC 编号同步注销 PLC(例如注销事件、断开连接等)。
+        /// 鏍规嵁 PLC 缂栧彿鍚屾�娉ㄩ攢 PLC锛堜緥濡傛敞閿€浜嬩欢銆佹柇寮€杩炴帴绛夛級銆�
         /// </summary>
-        /// <param name="number">PLC 编号。</param>
+        /// <param name="number">PLC 缂栧彿銆�</param>
         void UnRegisterPlcByNumber(int number);
 
         /// <summary>
-        /// 更新PLC编号
+        /// 鏇存柊PLC缂栧彿
         /// </summary>
         /// <param name="id"></param>
         /// <param name="newNumber"></param>

+ 113 - 113
TeamAAS-VM/Interfaces/IProductService.cs

@@ -6,262 +6,262 @@ using TeamAAS_VP.Models;
 namespace TeamAAS_VP.Interfaces
 {
     /// <summary>
-    /// 产品管理服务:用于创建、存储、复制、移除、修改、加载与获取产品,以及管理当前产品状态。
-    /// 实现应负责线程安全地管理内存中的产品集合,并提供同步与异步两种操作方式以便 UI 与后台任务使用。
+    /// 浜у搧绠$悊鏈嶅姟锛氱敤浜庡垱寤恒€佸瓨鍌ㄣ€佸�鍒躲€佺Щ闄ゃ€佷慨鏀广€佸姞杞戒笌鑾峰彇浜у搧锛屼互鍙婄�鐞嗗綋鍓嶄骇鍝佺姸鎬併€�
+    /// 瀹炵幇搴旇礋璐g嚎绋嬪畨鍏ㄥ湴绠$悊鍐呭瓨涓�殑浜у搧闆嗗悎锛屽苟鎻愪緵鍚屾�涓庡紓姝ヤ袱绉嶆搷浣滄柟寮忎互渚� UI 涓庡悗鍙颁换鍔′娇鐢ㄣ€�
     /// </summary>
     public interface IProductService : IDisposable
     {
 
         void Clear();
         /// <summary>
-        /// 当前产品编号
+        /// 褰撳墠浜у搧缂栧彿
         /// </summary>
         string CurrentProductCode { get; set; }
 
         /// <summary>
-        /// 产品切换事件
+        /// 浜у搧鍒囨崲浜嬩欢
         /// </summary>
         event Action<ProductModel> OnProductChanged;
 
         /// <summary>
-        /// 使用指定的本地产品清单文件初始化服务(同步)。
-        /// 实现应负责从清单文件读取产品信息并将其加载到服务的内部集合中。
-        /// 返回 true 表示初始化并加载成功;false 表示失败(或按实现约定抛出异常)。
+        /// 浣跨敤鎸囧畾鐨勬湰鍦颁骇鍝佹竻鍗曟枃浠跺垵濮嬪寲鏈嶅姟锛堝悓姝ワ級銆�
+        /// 瀹炵幇搴旇礋璐d粠娓呭崟鏂囦欢璇诲彇浜у搧淇℃伅骞跺皢鍏跺姞杞藉埌鏈嶅姟鐨勫唴閮ㄩ泦鍚堜腑銆�
+        /// 杩斿洖 true 琛ㄧず鍒濆�鍖栧苟鍔犺浇鎴愬姛锛沠alse 琛ㄧず澶辫触锛堟垨鎸夊疄鐜扮害瀹氭姏鍑哄紓甯革級銆�
         /// </summary>
-        /// <returns>初始化是否成功。</returns>
+        /// <returns>鍒濆�鍖栨槸鍚︽垚鍔熴€�</returns>
         bool Initialize();
 
         /// <summary>
-        /// 使用指定的本地产品清单文件初始化服务(异步)。
-        /// 实现应负责从清单文件读取产品信息并将其加载到服务的内部集合中。
-        /// 返回 true 表示初始化并加载成功;false 表示失败(或按实现约定抛出异常)。
+        /// 浣跨敤鎸囧畾鐨勬湰鍦颁骇鍝佹竻鍗曟枃浠跺垵濮嬪寲鏈嶅姟锛堝紓姝ワ級銆�
+        /// 瀹炵幇搴旇礋璐d粠娓呭崟鏂囦欢璇诲彇浜у搧淇℃伅骞跺皢鍏跺姞杞藉埌鏈嶅姟鐨勫唴閮ㄩ泦鍚堜腑銆�
+        /// 杩斿洖 true 琛ㄧず鍒濆�鍖栧苟鍔犺浇鎴愬姛锛沠alse 琛ㄧず澶辫触锛堟垨鎸夊疄鐜扮害瀹氭姏鍑哄紓甯革級銆�
         /// </summary>
-        /// <returns>初始化是否成功的任务。</returns>
+        /// <returns>鍒濆�鍖栨槸鍚︽垚鍔熺殑浠诲姟銆�</returns>
         Task<bool> InitializeAsync();
 
         /// <summary>
-        /// 获取所有产品的简要信息列表(同步)。
+        /// 鑾峰彇鎵€鏈変骇鍝佺殑绠€瑕佷俊鎭�垪琛�紙鍚屾�锛夈€�
         /// </summary>
         /// <returns></returns>
         IEnumerable<(Guid id, string name, string filePath)> GetAllProductList();
 
         /// <summary>
-        /// 异步创建产品并将其添加到服务管理的集合中。
+        /// 寮傛�鍒涘缓浜у搧骞跺皢鍏舵坊鍔犲埌鏈嶅姟绠$悊鐨勯泦鍚堜腑銆�
         /// </summary>
-        /// <param name="product">要创建并添加的产品模型。</param>
-        /// <returns>如果创建并添加成功则返回 true;否则返回 false。</returns>
+        /// <param name="product">瑕佸垱寤哄苟娣诲姞鐨勪骇鍝佹ā鍨嬨€�</param>
+        /// <returns>濡傛灉鍒涘缓骞舵坊鍔犳垚鍔熷垯杩斿洖 true锛涘惁鍒欒繑鍥� false銆�</returns>
         Task<bool> CreateProductAsync(ProductModel product);
 
         /// <summary>
-        /// 同步创建产品并将其添加到服务管理的集合中。
+        /// 鍚屾�鍒涘缓浜у搧骞跺皢鍏舵坊鍔犲埌鏈嶅姟绠$悊鐨勯泦鍚堜腑銆�
         /// </summary>
-        /// <param name="product">要创建并添加的产品模型。</param>
-        /// <returns>如果创建并添加成功则返回 true;否则返回 false。</returns>
+        /// <param name="product">瑕佸垱寤哄苟娣诲姞鐨勪骇鍝佹ā鍨嬨€�</param>
+        /// <returns>濡傛灉鍒涘缓骞舵坊鍔犳垚鍔熷垯杩斿洖 true锛涘惁鍒欒繑鍥� false銆�</returns>
         bool CreateProduct(ProductModel product);
 
         /// <summary>
-        /// 根据指定 ID 获取产品(同步)。
+        /// 鏍规嵁鎸囧畾 ID 鑾峰彇浜у搧锛堝悓姝ワ級銆�
         /// </summary>
-        /// <param name="id">产品的唯一标识符。</param>
-        /// <returns>如果存在则返回对应的 <see cref="ProductModel"/>;不存在时返回 null(或实现自定义的空表示)。</returns>
+        /// <param name="id">浜у搧鐨勫敮涓€鏍囪瘑绗︺€�</param>
+        /// <returns>濡傛灉瀛樺湪鍒欒繑鍥炲�搴旂殑 <see cref="ProductModel"/>锛涗笉瀛樺湪鏃惰繑鍥� null锛堟垨瀹炵幇鑷�畾涔夌殑绌鸿〃绀猴級銆�</returns>
         ProductModel GetProduct(Guid id);
 
         /// <summary>
-        /// 根据指定 ID 异步获取产品。
+        /// 鏍规嵁鎸囧畾 ID 寮傛�鑾峰彇浜у搧銆�
         /// </summary>
-        /// <param name="id">产品的唯一标识符。</param>
-        /// <returns>返回可能为 null 的 <see cref="ProductModel"/>,表示未找到时为 null。</returns>
+        /// <param name="id">浜у搧鐨勫敮涓€鏍囪瘑绗︺€�</param>
+        /// <returns>杩斿洖鍙�兘涓� null 鐨� <see cref="ProductModel"/>锛岃〃绀烘湭鎵惧埌鏃朵负 null銆�</returns>
         Task<ProductModel> GetProductAsync(Guid id);
 
         /// <summary>
-        /// 获取所有已加载的产品(只读集合,同步)。
+        /// 鑾峰彇鎵€鏈夊凡鍔犺浇鐨勪骇鍝侊紙鍙��闆嗗悎锛屽悓姝ワ級銆�
         /// </summary>
-        /// <returns>返回包含当前所有产品的只读集合。</returns>
+        /// <returns>杩斿洖鍖呭惈褰撳墠鎵€鏈変骇鍝佺殑鍙��闆嗗悎銆�</returns>
         IReadOnlyCollection<ProductModel> GetAllProducts();
 
         /// <summary>
-        /// 异步获取所有已加载的产品(只读集合)。
+        /// 寮傛�鑾峰彇鎵€鏈夊凡鍔犺浇鐨勪骇鍝侊紙鍙��闆嗗悎锛夈€�
         /// </summary>
-        /// <returns>返回包含当前所有产品的只读集合。</returns>
+        /// <returns>杩斿洖鍖呭惈褰撳墠鎵€鏈変骇鍝佺殑鍙��闆嗗悎銆�</returns>
         Task<IReadOnlyCollection<ProductModel>> GetAllProductsAsync();
 
         /// <summary>
-        /// 尝试根据指定 ID 获取产品(同步),不会抛出异常用于查找失败的情况。
+        /// 灏濊瘯鏍规嵁鎸囧畾 ID 鑾峰彇浜у搧锛堝悓姝ワ級锛屼笉浼氭姏鍑哄紓甯哥敤浜庢煡鎵惧け璐ョ殑鎯呭喌銆�
         /// </summary>
-        /// <param name="id">要查找的产品 ID。</param>
-        /// <param name="product">当返回 true 时为找到的产品;否则应设置为 null 或默认值。</param>
-        /// <returns>如果找到产品则返回 true;否则返回 false。</returns>
+        /// <param name="id">瑕佹煡鎵剧殑浜у搧 ID銆�</param>
+        /// <param name="product">褰撹繑鍥� true 鏃朵负鎵惧埌鐨勪骇鍝侊紱鍚﹀垯搴旇�缃�负 null 鎴栭粯璁ゅ€笺€�</param>
+        /// <returns>濡傛灉鎵惧埌浜у搧鍒欒繑鍥� true锛涘惁鍒欒繑鍥� false銆�</returns>
         bool TryGetProduct(Guid id, out ProductModel product);
 
         /// <summary>
-        /// 异步尝试根据指定 ID 获取产品。返回一个元组,包含查找是否成功以及对应的产品(若未找到则为 null)。
+        /// 寮傛�灏濊瘯鏍规嵁鎸囧畾 ID 鑾峰彇浜у搧銆傝繑鍥炰竴涓�厓缁勶紝鍖呭惈鏌ユ壘鏄�惁鎴愬姛浠ュ強瀵瑰簲鐨勪骇鍝侊紙鑻ユ湭鎵惧埌鍒欎负 null锛夈€�
         /// </summary>
-        /// <param name="id">要查找的产品 ID。</param>
-        /// <returns>返回元组:(found: 是否找到, product: 找到的产品或 null)。</returns>
+        /// <param name="id">瑕佹煡鎵剧殑浜у搧 ID銆�</param>
+        /// <returns>杩斿洖鍏冪粍锛�(found: 鏄�惁鎵惧埌, product: 鎵惧埌鐨勪骇鍝佹垨 null)銆�</returns>
         Task<(bool found, ProductModel product)> TryGetProductAsync(Guid id);
 
         /// <summary>
-        /// 判断服务中是否包含指定 ID 的产品(同步)。
+        /// 鍒ゆ柇鏈嶅姟涓�槸鍚﹀寘鍚�寚瀹� ID 鐨勪骇鍝侊紙鍚屾�锛夈€�
         /// </summary>
-        /// <param name="id">产品的唯一标识符。</param>
-        /// <returns>若包含则返回 true;否则返回 false。</returns>
+        /// <param name="id">浜у搧鐨勫敮涓€鏍囪瘑绗︺€�</param>
+        /// <returns>鑻ュ寘鍚�垯杩斿洖 true锛涘惁鍒欒繑鍥� false銆�</returns>
         bool ContainsProduct(Guid id);
 
         /// <summary>
-        /// 异步判断服务中是否包含指定 ID 的产品。
+        /// 寮傛�鍒ゆ柇鏈嶅姟涓�槸鍚﹀寘鍚�寚瀹� ID 鐨勪骇鍝併€�
         /// </summary>
-        /// <param name="id">产品的唯一标识符。</param>
-        /// <returns>若包含则返回 true;否则返回 false。</returns>
+        /// <param name="id">浜у搧鐨勫敮涓€鏍囪瘑绗︺€�</param>
+        /// <returns>鑻ュ寘鍚�垯杩斿洖 true锛涘惁鍒欒繑鍥� false銆�</returns>
         Task<bool> ContainsProductAsync(Guid id);
 
         /// <summary>
-        /// 判断服务中是否包含指定名称的产品(同步)。
+        /// 鍒ゆ柇鏈嶅姟涓�槸鍚﹀寘鍚�寚瀹氬悕绉扮殑浜у搧锛堝悓姝ワ級銆�
         /// </summary>
-        /// <param name="name">产品的名称</param>
-        /// <returns>若包含则返回 true;否则返回 false。</returns>
+        /// <param name="name">浜у搧鐨勫悕绉�</param>
+        /// <returns>鑻ュ寘鍚�垯杩斿洖 true锛涘惁鍒欒繑鍥� false銆�</returns>
         bool ContainsProductByName(string name);
 
         /// <summary>
-        /// 判断服务中是否包含指定名称的产品(异步)。
+        /// 鍒ゆ柇鏈嶅姟涓�槸鍚﹀寘鍚�寚瀹氬悕绉扮殑浜у搧锛堝紓姝ワ級銆�
         /// </summary>
-        /// <param name="name">产品的名称</param>
-        /// <returns>若包含则返回 true;否则返回 false。</returns>
+        /// <param name="name">浜у搧鐨勫悕绉�</param>
+        /// <returns>鑻ュ寘鍚�垯杩斿洖 true锛涘惁鍒欒繑鍥� false銆�</returns>
         Task<bool> ContainsProductByNameAsync(string name);
 
         /// <summary>
-        /// 从服务中移除指定 ID 的产品(同步)。
+        /// 浠庢湇鍔′腑绉婚櫎鎸囧畾 ID 鐨勪骇鍝侊紙鍚屾�锛夈€�
         /// </summary>
-        /// <param name="id">要移除的产品 ID。</param>
-        /// <returns>如果移除成功(存在并被移除)返回 true,否则返回 false。</returns>
+        /// <param name="id">瑕佺Щ闄ょ殑浜у搧 ID銆�</param>
+        /// <returns>濡傛灉绉婚櫎鎴愬姛锛堝瓨鍦ㄥ苟琚�Щ闄わ級杩斿洖 true锛屽惁鍒欒繑鍥� false銆�</returns>
         bool RemoveProduct(Guid id);
 
         /// <summary>
-        /// 异步从服务中移除指定 ID 的产品。
+        /// 寮傛�浠庢湇鍔′腑绉婚櫎鎸囧畾 ID 鐨勪骇鍝併€�
         /// </summary>
-        /// <param name="id">要移除的产品 ID。</param>
-        /// <returns>如果移除成功(存在并被移除)返回 true,否则返回 false。</returns>
+        /// <param name="id">瑕佺Щ闄ょ殑浜у搧 ID銆�</param>
+        /// <returns>濡傛灉绉婚櫎鎴愬姛锛堝瓨鍦ㄥ苟琚�Щ闄わ級杩斿洖 true锛屽惁鍒欒繑鍥� false銆�</returns>
         Task<bool> RemoveProductAsync(Guid id);
 
         /// <summary>
-        /// 从服务中移除所有产品(同步),清空内部集合并释放相关资源(若有)。
+        /// 浠庢湇鍔′腑绉婚櫎鎵€鏈変骇鍝侊紙鍚屾�锛夛紝娓呯┖鍐呴儴闆嗗悎骞堕噴鏀剧浉鍏宠祫婧愶紙鑻ユ湁锛夈€�
         /// </summary>
         void RemoveAllProducts();
 
         /// <summary>
-        /// 将指定产品保存到给定文件路径(同步)。
-        /// 若产品不存在,应抛出相应异常或以返回值/日志方式处理(实现约定)。
+        /// 灏嗘寚瀹氫骇鍝佷繚瀛樺埌缁欏畾鏂囦欢璺�緞锛堝悓姝ワ級銆�
+        /// 鑻ヤ骇鍝佷笉瀛樺湪锛屽簲鎶涘嚭鐩稿簲寮傚父鎴栦互杩斿洖鍊�/鏃ュ織鏂瑰紡澶勭悊锛堝疄鐜扮害瀹氾級銆�
         /// </summary>
-        /// <param name="id">要保存的产品 ID。</param>
-        /// <param name="filePath">目标文件的完整路径。</param>
+        /// <param name="id">瑕佷繚瀛樼殑浜у搧 ID銆�</param>
+        /// <param name="filePath">鐩�爣鏂囦欢鐨勫畬鏁磋矾寰勩€�</param>
         void SaveProduct(Guid id, string filePath);
 
         /// <summary>
-        /// 异步将指定产品保存到给定文件路径。
+        /// 寮傛�灏嗘寚瀹氫骇鍝佷繚瀛樺埌缁欏畾鏂囦欢璺�緞銆�
         /// </summary>
-        /// <param name="id">要保存的产品 ID。</param>
-        /// <param name="filePath">目标文件的完整路径。</param>
+        /// <param name="id">瑕佷繚瀛樼殑浜у搧 ID銆�</param>
+        /// <param name="filePath">鐩�爣鏂囦欢鐨勫畬鏁磋矾寰勩€�</param>
         Task SaveProductAsync(Guid id, string filePath);
 
         /// <summary>
-        /// 保存产品
+        /// 淇濆瓨浜у搧
         /// </summary>
         /// <param name="id"></param>
         void SaveProduct(Guid id);
 
         /// <summary>
-        /// 保存产品
+        /// 淇濆瓨浜у搧
         /// </summary>
         /// <param name="id"></param>
         /// <returns></returns>
         Task SaveProductAsync(Guid id);
 
         /// <summary>
-        /// 保存产品清单
+        /// 淇濆瓨浜у搧娓呭崟
         /// </summary>
         void SaveProductList();
 
         /// <summary>
-        /// 异步保存产品清单
+        /// 寮傛�淇濆瓨浜у搧娓呭崟
         /// </summary>
         /// <returns></returns>
         Task SaveProductListAsync();
 
         /// <summary>
-        /// 从指定文件加载产品(同步)。实现应负责反序列化并将产品添加到服务管理的集合(或仅返回实例,取决于实现约定)。
+        /// 浠庢寚瀹氭枃浠跺姞杞戒骇鍝侊紙鍚屾�锛夈€傚疄鐜板簲璐熻矗鍙嶅簭鍒楀寲骞跺皢浜у搧娣诲姞鍒版湇鍔$�鐞嗙殑闆嗗悎锛堟垨浠呰繑鍥炲疄渚嬶紝鍙栧喅浜庡疄鐜扮害瀹氾級銆�
         /// </summary>
-        /// <param name="id">要加载的产品唯一标识符。</param>
-        /// <returns>加载并返回的 <see cref="ProductModel"/> 实例。</returns>
+        /// <param name="id">瑕佸姞杞界殑浜у搧鍞�竴鏍囪瘑绗︺€�</param>
+        /// <returns>鍔犺浇骞惰繑鍥炵殑 <see cref="ProductModel"/> 瀹炰緥銆�</returns>
         ProductModel LoadProduct(Guid id);
 
         /// <summary>
-        /// 异步从指定文件加载产品并返回加载的模型。
+        /// 寮傛�浠庢寚瀹氭枃浠跺姞杞戒骇鍝佸苟杩斿洖鍔犺浇鐨勬ā鍨嬨€�
         /// </summary>
-        /// <param name="id">要加载的产品唯一标识符。</param>
-        /// <returns>加载并返回的 <see cref="ProductModel"/> 实例。</returns>
+        /// <param name="id">瑕佸姞杞界殑浜у搧鍞�竴鏍囪瘑绗︺€�</param>
+        /// <returns>鍔犺浇骞惰繑鍥炵殑 <see cref="ProductModel"/> 瀹炰緥銆�</returns>
         Task<ProductModel> LoadProductAsync(Guid id);
 
         /// <summary>
-        /// 根据产品加载记录,获取最近一次加载的产品信息(同步)。
+        /// 鏍规嵁浜у搧鍔犺浇璁板綍锛岃幏鍙栨渶杩戜竴娆″姞杞界殑浜у搧淇℃伅锛堝悓姝ワ級銆�
         /// </summary>
-        /// <returns>返回一个元组:<c>(id, name)</c>,分别表示最后加载的产品 ID 与名称;若无记录,ID 可为 <see cref="Guid"/>.Empty,名称可为空字符串。</returns>
+        /// <returns>杩斿洖涓€涓�厓缁勶細<c>(id, name)</c>锛屽垎鍒�〃绀烘渶鍚庡姞杞界殑浜у搧 ID 涓庡悕绉帮紱鑻ユ棤璁板綍锛孖D 鍙�负 <see cref="Guid"/>.Empty锛屽悕绉板彲涓虹┖瀛楃�涓层€�</returns>
         (Guid id, string name) LoadLastProduct();
 
         /// <summary>
-        /// 异步根据产品加载记录,获取最近一次加载的产品信息。
+        /// 寮傛�鏍规嵁浜у搧鍔犺浇璁板綍锛岃幏鍙栨渶杩戜竴娆″姞杞界殑浜у搧淇℃伅銆�
         /// </summary>
-        /// <returns>返回一个元组:<c>(id, name)</c>,分别表示最后加载的产品 ID 与名称;若无记录,ID 可为 <see cref="Guid"/>.Empty,名称可为空字符串。</returns>
+        /// <returns>杩斿洖涓€涓�厓缁勶細<c>(id, name)</c>锛屽垎鍒�〃绀烘渶鍚庡姞杞界殑浜у搧 ID 涓庡悕绉帮紱鑻ユ棤璁板綍锛孖D 鍙�负 <see cref="Guid"/>.Empty锛屽悕绉板彲涓虹┖瀛楃�涓层€�</returns>
         Task<(Guid id, string name)> LoadLastProductAsync();
 
         /// <summary>
-        /// 设置为当前选中的或正在编辑的产品(同步)。
+        /// 璁剧疆涓哄綋鍓嶉€変腑鐨勬垨姝e湪缂栬緫鐨勪骇鍝侊紙鍚屾�锛夈€�
         /// </summary>
         /// <param name="id"></param>
         void SetCurrentProduct(Guid id);
 
         /// <summary>
-        /// 获取当前选中的或正在编辑的产品实例(同步)。
+        /// 鑾峰彇褰撳墠閫変腑鐨勬垨姝e湪缂栬緫鐨勪骇鍝佸疄渚嬶紙鍚屾�锛夈€�
         /// </summary>
-        /// <returns>当前产品的 <see cref="ProductModel"/> 实例;若无当前产品可返回 null。</returns>
+        /// <returns>褰撳墠浜у搧鐨� <see cref="ProductModel"/> 瀹炰緥锛涜嫢鏃犲綋鍓嶄骇鍝佸彲杩斿洖 null銆�</returns>
         ProductModel GetCurrentProduct();
 
         /// <summary>
-        /// 复制指定产品为一个新对象并返回新对象的 ID(同步)。
-        /// 实现应复制所有必要的数据并为新产品生成新的唯一 ID,同时支持为新产品指定名称。
+        /// 澶嶅埗鎸囧畾浜у搧涓轰竴涓�柊瀵硅薄骞惰繑鍥炴柊瀵硅薄鐨� ID锛堝悓姝ワ級銆�
+        /// 瀹炵幇搴斿�鍒舵墍鏈夊繀瑕佺殑鏁版嵁骞朵负鏂颁骇鍝佺敓鎴愭柊鐨勫敮涓€ ID锛屽悓鏃舵敮鎸佷负鏂颁骇鍝佹寚瀹氬悕绉般€�
         /// </summary>
-        /// <param name="id">要复制的源产品 ID。</param>
-        /// <param name="newName">新复制产品的名称。</param>
-        /// <returns>新复制产品的 ID。</returns>
+        /// <param name="id">瑕佸�鍒剁殑婧愪骇鍝� ID銆�</param>
+        /// <param name="newName">鏂板�鍒朵骇鍝佺殑鍚嶇О銆�</param>
+        /// <returns>鏂板�鍒朵骇鍝佺殑 ID銆�</returns>
         Guid CopyProduct(Guid id, string newName);
 
         /// <summary>
-        /// 异步复制指定产品为一个新对象并返回新对象的 ID。
+        /// 寮傛�澶嶅埗鎸囧畾浜у搧涓轰竴涓�柊瀵硅薄骞惰繑鍥炴柊瀵硅薄鐨� ID銆�
         /// </summary>
-        /// <param name="id">要复制的源产品 ID。</param>
-        /// <param name="newName">新复制产品的名称。</param>
-        /// <returns>新复制产品的 ID。</returns>
+        /// <param name="id">瑕佸�鍒剁殑婧愪骇鍝� ID銆�</param>
+        /// <param name="newName">鏂板�鍒朵骇鍝佺殑鍚嶇О銆�</param>
+        /// <returns>鏂板�鍒朵骇鍝佺殑 ID銆�</returns>
         Task<Guid> CopyProductAsync(Guid id, string newName);
 
         /// <summary>
-        /// 永久删除产品
+        /// 姘镐箙鍒犻櫎浜у搧
         /// </summary>
         /// <param name="id"></param>
         void DeleteProduct(Guid id);
 
         /// <summary>
-        /// 永久删除产品
+        /// 姘镐箙鍒犻櫎浜у搧
         /// </summary>
         /// <param name="id"></param>
         Task DeleteProductAsync(Guid id);
 
         /// <summary>
-        /// 对指定产品进行重命名
+        /// 瀵规寚瀹氫骇鍝佽繘琛岄噸鍛藉悕
         /// </summary>
         /// <param name="id"></param>
         /// <param name="newName"></param>
         void RenameProduct(Guid id, string newName);
 
         /// <summary>
-        /// 对指定产品进行重命名
+        /// 瀵规寚瀹氫骇鍝佽繘琛岄噸鍛藉悕
         /// </summary>
         /// <param name="id"></param>
         /// <param name="newName"></param>
@@ -269,20 +269,20 @@ namespace TeamAAS_VP.Interfaces
         Task RenameProductAsync(Guid id, string newName);
 
         /// <summary>
-        /// 更新产品
+        /// 鏇存柊浜у搧
         /// </summary>
         /// <param name="product"></param>
         void UpdateProduct(ProductModel product);
 
         /// <summary>
-        /// 更新产品
+        /// 鏇存柊浜у搧
         /// </summary>
         /// <param name="product"></param>
         /// <returns></returns>
         Task UpdateProductAsync(ProductModel product);
 
         /// <summary>
-        /// 根据指定的模板名称创建产品
+        /// 鏍规嵁鎸囧畾鐨勬ā鏉垮悕绉板垱寤轰骇鍝�
         /// </summary>
         /// <param name="templateName"></param>
         /// <param name="productName"></param>
@@ -290,7 +290,7 @@ namespace TeamAAS_VP.Interfaces
         ProductModel CreateProductByTemplateName(string templateName, string productName);
 
         /// <summary>
-        /// 根据指定的模板名称异步创建产品
+        /// 鏍规嵁鎸囧畾鐨勬ā鏉垮悕绉板紓姝ュ垱寤轰骇鍝�
         /// </summary>
         /// <param name="templateName"></param>
         /// <param name="productName"></param>
@@ -298,14 +298,14 @@ namespace TeamAAS_VP.Interfaces
         Task<ProductModel> CreateProductByTemplateNameAsync(string templateName, string productName);
 
         /// <summary>
-        /// 增加相机时,需要对产品的相机流程进行增加
+        /// 澧炲姞鐩告満鏃讹紝闇€瑕佸�浜у搧鐨勭浉鏈烘祦绋嬭繘琛屽�鍔�
         /// </summary>
         /// <param name="cameraId"></param>
         /// <param name="cameraName"></param>
         void AddCameraToProduct(Guid cameraId, string cameraName);
 
         /// <summary>
-        /// 增加相机时,需要对产品的相机流程进行增加
+        /// 澧炲姞鐩告満鏃讹紝闇€瑕佸�浜у搧鐨勭浉鏈烘祦绋嬭繘琛屽�鍔�
         /// </summary>
         /// <param name="cameraId"></param>
         /// <param name="cameraName"></param>
@@ -313,27 +313,27 @@ namespace TeamAAS_VP.Interfaces
         Task AddCameraToProductAsync(Guid cameraId, string cameraName);
 
         /// <summary>
-        /// 删除相机时,需要对产品的相机流程进行删除
+        /// 鍒犻櫎鐩告満鏃讹紝闇€瑕佸�浜у搧鐨勭浉鏈烘祦绋嬭繘琛屽垹闄�
         /// </summary>
         /// <param name="cameraId"></param>
         void RemoveCameraFromProduct(Guid cameraId);
 
         /// <summary>
-        /// 删除相机时,需要对产品的相机流程进行删除
+        /// 鍒犻櫎鐩告満鏃讹紝闇€瑕佸�浜у搧鐨勭浉鏈烘祦绋嬭繘琛屽垹闄�
         /// </summary>
         /// <param name="cameraId"></param>
         /// <returns></returns>
         Task RemoveCameraFromProductAsync(Guid cameraId);
 
         /// <summary>
-        /// 修改相机名称时,需要对产品的相机流程进行修改
+        /// 淇�敼鐩告満鍚嶇О鏃讹紝闇€瑕佸�浜у搧鐨勭浉鏈烘祦绋嬭繘琛屼慨鏀�
         /// </summary>
         /// <param name="cameraId"></param>
         /// <param name="newCameraName"></param>
         void UpdateCameraNameInProduct(Guid cameraId, string newCameraName);
 
         /// <summary>
-        /// 修改相机名称时,需要对产品的相机流程进行修改
+        /// 淇�敼鐩告満鍚嶇О鏃讹紝闇€瑕佸�浜у搧鐨勭浉鏈烘祦绋嬭繘琛屼慨鏀�
         /// </summary>
         /// <param name="cameraId"></param>
         /// <param name="newCameraName"></param>
@@ -341,7 +341,7 @@ namespace TeamAAS_VP.Interfaces
         Task UpdateCameraNameInProductAsync(Guid cameraId, string newCameraName);
 
         /// <summary>
-        /// 增加机器人时,需要对产品的机器人点位进行增加
+        /// 澧炲姞鏈哄櫒浜烘椂锛岄渶瑕佸�浜у搧鐨勬満鍣ㄤ汉鐐逛綅杩涜�澧炲姞
         /// </summary>
         /// <param name="robotId"></param>
         /// <param name="robotPointName"></param>
@@ -349,13 +349,13 @@ namespace TeamAAS_VP.Interfaces
 
 
         /// <summary>
-        /// 增加扫码枪时,需要对产品的扫码枪点位进行增加
+        /// 澧炲姞鎵�爜鏋�椂锛岄渶瑕佸�浜у搧鐨勬壂鐮佹灙鐐逛綅杩涜�澧炲姞
         /// </summary>
         /// <param name="scannerId"></param>
         /// <param name="scannerPointName"></param>
         void AddScannerPointToProduct(Guid scannerId, string scannerPointName);
         /// <summary>
-        /// 增加机器人时,需要对产品的机器人点位进行增加
+        /// 澧炲姞鏈哄櫒浜烘椂锛岄渶瑕佸�浜у搧鐨勬満鍣ㄤ汉鐐逛綅杩涜�澧炲姞
         /// </summary>
         /// <param name="robotId"></param>
         /// <param name="robotPointName"></param>
@@ -363,33 +363,33 @@ namespace TeamAAS_VP.Interfaces
         Task AddRobotPointToProductAsync(Guid robotId, string robotPointName);
 
         /// <summary>
-        /// 删除机器人时,需要对产品的机器人点位进行删除
+        /// 鍒犻櫎鏈哄櫒浜烘椂锛岄渶瑕佸�浜у搧鐨勬満鍣ㄤ汉鐐逛綅杩涜�鍒犻櫎
         /// </summary>
         /// <param name="robotId"></param>
         void RemoveRobotPointFromProduct(Guid robotId);
 
         /// <summary>
-        /// 删除扫码枪时,需要对产品的扫码枪点位进行删除
+        /// 鍒犻櫎鎵�爜鏋�椂锛岄渶瑕佸�浜у搧鐨勬壂鐮佹灙鐐逛綅杩涜�鍒犻櫎
         /// </summary>
         /// <param name="scannerId"></param>
         void RemoveScannerPointFromProduct(Guid scannerId);
 
         /// <summary>
-        /// 删除机器人时,需要对产品的机器人点位进行删除
+        /// 鍒犻櫎鏈哄櫒浜烘椂锛岄渶瑕佸�浜у搧鐨勬満鍣ㄤ汉鐐逛綅杩涜�鍒犻櫎
         /// </summary>
         /// <param name="robotId"></param>
         /// <returns></returns>
         Task RemoveRobotPointFromProductAsync(Guid robotId);
 
         /// <summary>
-        /// 修改机器人名称时,需要对产品的机器人点位进行修改
+        /// 淇�敼鏈哄櫒浜哄悕绉版椂锛岄渶瑕佸�浜у搧鐨勬満鍣ㄤ汉鐐逛綅杩涜�淇�敼
         /// </summary>
         /// <param name="robotId"></param>
         /// <param name="newRobotPointName"></param>
         void UpdateRobotPointNameInProduct(Guid robotId, string newRobotPointName);
 
         /// <summary>
-        /// 修改机器人名称时,需要对产品的机器人点位进行修改
+        /// 淇�敼鏈哄櫒浜哄悕绉版椂锛岄渶瑕佸�浜у搧鐨勬満鍣ㄤ汉鐐逛綅杩涜�淇�敼
         /// </summary>
         /// <param name="robotId"></param>
         /// <param name="newRobotPointName"></param>
@@ -397,7 +397,7 @@ namespace TeamAAS_VP.Interfaces
         Task UpdateRobotPointNameInProductAsync(Guid robotId, string newRobotPointName);
 
         /// <summary>
-        /// 加载指定产品流程的视觉工具
+        /// 鍔犺浇鎸囧畾浜у搧娴佺▼鐨勮�瑙夊伐鍏�
         /// </summary>
         /// <param name="productid"></param>
         /// <param name="cameraid"></param>
@@ -405,7 +405,7 @@ namespace TeamAAS_VP.Interfaces
         void LoadProcedureVisionTools(Guid productid, Guid cameraid, string prcname);
 
         /// <summary>
-        /// 加载指定产品流程的视觉工具
+        /// 鍔犺浇鎸囧畾浜у搧娴佺▼鐨勮�瑙夊伐鍏�
         /// </summary>
         /// <param name="productid"></param>
         /// <param name="cameraid"></param>
@@ -414,7 +414,7 @@ namespace TeamAAS_VP.Interfaces
         Task<bool> LoadProcedureVisionToolsAsync(Guid productid, Guid cameraid, string prcname);
 
         /// <summary>
-        /// 获取当前产品的指定视觉流程ID的视觉流程对象
+        /// 鑾峰彇褰撳墠浜у搧鐨勬寚瀹氳�瑙夋祦绋婭D鐨勮�瑙夋祦绋嬪�璞�
         /// </summary>
         /// <param name="procedureId"></param>
         /// <returns></returns>

+ 55 - 57
TeamAAS-VM/Interfaces/IRemoteCommandService.cs

@@ -13,17 +13,17 @@ namespace TeamAAS_VP.Interfaces
     public interface IRemoteCommandService : IDisposable
     {
         /// <summary>
-        /// 是否正在执行命令
+        /// 鏄�惁姝e湪鎵ц�鍛戒护
         /// </summary>
         bool IsExecuting { get; }
 
         /// <summary>
-        /// 是否正在执行视觉命令
+        /// 鏄�惁姝e湪鎵ц�瑙嗚�鍛戒护
         /// </summary>
         bool IsExecutingVisionCommand { get; }
 
         /// <summary>
-        /// 计时器计时通知事件
+        /// 鑺傛媿璁℃椂閫氱煡浜嬩欢
         /// </summary>
         event EventHandler<TimeSpan> CycleTimingTicked;
 
@@ -37,7 +37,7 @@ namespace TeamAAS_VP.Interfaces
         Task ExecuteAsync(string command, CancellationToken cancellationToken, Action<string> callback);
 
         /// <summary>
-        /// 加载产品
+        /// 鍔犺浇浜у搧
         /// </summary>
         /// <param name="productName"></param>
         /// <param name="cancellationToken"></param>
@@ -45,7 +45,7 @@ namespace TeamAAS_VP.Interfaces
         Task<bool> LoadProductAsync(string productName, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 通过产品编号获取产品名称
+        /// 閫氳繃浜у搧缂栧彿鑾峰彇浜у搧鍚嶇О
         /// </summary>
         /// <param name="productNumber"></param>
         /// <param name="cancellationToken"></param>
@@ -53,7 +53,7 @@ namespace TeamAAS_VP.Interfaces
         Task<string> GetProductNameByNumberAsync(int productNumber, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 通过产品名称获取产品编号
+        /// 閫氳繃浜у搧鍚嶇О鑾峰彇浜у搧缂栧彿
         /// </summary>
         /// <param name="productName"></param>
         /// <param name="cancellationToken"></param>
@@ -61,21 +61,21 @@ namespace TeamAAS_VP.Interfaces
         Task<int> GetProductNumberByNameAsync(string productName, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 获取当前产品名称
+        /// 鑾峰彇褰撳墠浜у搧鍚嶇О
         /// </summary>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         Task<string> GetCurrentProductNameAsync(CancellationToken cancellationToken);
 
         /// <summary>
-        /// 获取当前产品编号
+        /// 鑾峰彇褰撳墠浜у搧缂栧彿
         /// </summary>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         Task<int> GetCurrentProductNumberAsync(CancellationToken cancellationToken);
 
         /// <summary>
-        /// 通过机器人编号和点位编号获取机器人点位信息
+        /// 閫氳繃鏈哄櫒浜虹紪鍙峰拰鐐逛綅缂栧彿鑾峰彇鏈哄櫒浜虹偣浣嶄俊鎭�
         /// </summary>
         /// <param name="robotNumber"></param>
         /// <param name="pointNumber"></param>
@@ -84,31 +84,31 @@ namespace TeamAAS_VP.Interfaces
         Task<string> GetRobotPointInfoAsync(int robotNumber, int pointNumber, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 通过机器人编号和托盘编号、点编号获取机器人托盘点位信息
+        /// 閫氳繃鏈哄櫒浜虹紪鍙峰拰鎵樼洏缂栧彿銆佺偣缂栧彿鑾峰彇鏈哄櫒浜烘墭鐩樼偣浣嶄俊鎭�
         /// </summary>
-        /// <param name="robotNumber">机器人编号</param>
-        /// <param name="palletNumber">托盘编号</param>
-        /// <param name="pointNumber">点编号</param>
+        /// <param name="robotNumber">鏈哄櫒浜虹紪鍙�</param>
+        /// <param name="palletNumber">鎵樼洏缂栧彿</param>
+        /// <param name="pointNumber">鐐圭紪鍙�</param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         Task<string> GetRobotPalletPointInfoAsync(int robotNumber, int palletNumber, int pointNumber, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 开始节拍计时
+        /// 寮€濮嬭妭鎷嶈�鏃�
         /// </summary>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         Task<bool> StartCycleTimingAsync(CancellationToken cancellationToken);
 
         /// <summary>
-        /// 停止节拍计时
+        /// 鍋滄�鑺傛媿璁℃椂
         /// </summary>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         Task<bool> StopCycleTimingAsync(CancellationToken cancellationToken);
 
         /// <summary>
-        /// 创建一条生产计数,传入计数项
+        /// 鏂板�涓€鏉$敓浜ц�鏁拌�褰�
         /// </summary>
         /// <param name="countItem"></param>
         /// <param name="cancellationToken"></param>
@@ -116,7 +116,7 @@ namespace TeamAAS_VP.Interfaces
         Task<bool> CreateProductionCountAsync(string countItem, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 获取当前生产计数
+        /// 鑾峰彇褰撳墠鐢熶骇璁℃暟
         /// </summary>
         /// <param name="countItem"></param>
         /// <param name="cancellationToken"></param>
@@ -124,7 +124,7 @@ namespace TeamAAS_VP.Interfaces
         Task<int> GetCurrentProductionCountAsync(string countItem, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 重置生产计数
+        /// 閲嶇疆鐢熶骇璁℃暟
         /// </summary>
         /// <param name="countItem"></param>
         /// <param name="cancellationToken"></param>
@@ -132,7 +132,7 @@ namespace TeamAAS_VP.Interfaces
         Task<bool> ResetProductionCountAsync(string countItem, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 创建一条报警记录
+        /// 璁板綍涓€鏉℃姤璀︿俊鎭�
         /// </summary>
         /// <param name="alarmCode"></param>
         /// <param name="alarmDescription"></param>
@@ -141,7 +141,7 @@ namespace TeamAAS_VP.Interfaces
         Task<bool> CreateAlarmRecordAsync(string alarmCode, string alarmDescription, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 创建一条运行信息记录
+        /// 璁板綍涓€鏉℃搷浣滀俊鎭�棩蹇�
         /// </summary>
         /// <param name="logMessage"></param>
         /// <param name="cancellationToken"></param>
@@ -149,7 +149,7 @@ namespace TeamAAS_VP.Interfaces
         Task<bool> CreateOperationLogAsync(string logMessage, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 获取当前产品指定编号的全局参数
+        /// 鑾峰彇褰撳墠浜у搧鎸囧畾缂栧彿鐨勫叏灞€鍙傛暟
         /// </summary>
         /// <param name="parameterNumber"></param>
         /// <param name="itemIndex"></param>
@@ -158,14 +158,14 @@ namespace TeamAAS_VP.Interfaces
         Task<string> GetGlobalParameterAsync(int parameterNumber, int itemIndex, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 获取当前产品的运行速度
+        /// 鑾峰彇褰撳墠浜у搧杩愯�閫熷害鍙傛暟
         /// </summary>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         Task<string> GetOperationSpeedAsync(CancellationToken cancellationToken);
 
         /// <summary>
-        /// 获取末端工具信息,传入流程触发命令和工具编号
+        /// 鑾峰彇鏈��宸ュ叿鍙傛暟淇℃伅,鍖呮嫭娴佺▼瑙﹀彂鍛戒护鍜屽伐鍏风紪鍙�
         /// </summary>
         /// <param name="triggerCommand"></param>
         /// <param name="toolNumber"></param>
@@ -174,7 +174,7 @@ namespace TeamAAS_VP.Interfaces
         Task<string> GetToolParamAsync(string triggerCommand, int toolNumber, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 获取流程参数信息,传入流程触发命令
+        /// 鑾峰彇娴佺▼鍙傛暟淇℃伅,鍖呮嫭娴佺▼瑙﹀彂鍛戒护
         /// </summary>
         /// <param name="triggerCommand"></param>
         /// <param name="cancellationToken"></param>
@@ -182,7 +182,7 @@ namespace TeamAAS_VP.Interfaces
         Task<string> GetProcessParamAsync(string triggerCommand, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 执行清料任务
+        /// 鎵ц�娓呮枡浠诲姟
         /// </summary>
         /// <param name="taskNumber"></param>
         /// <param name="cancellationToken"></param>
@@ -190,7 +190,7 @@ namespace TeamAAS_VP.Interfaces
         Task<bool> ExecuteClearMaterialTaskAsync(int taskNumber, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 终止清料任务
+        /// 鍋滄�娓呮枡浠诲姟
         /// </summary>
         /// <param name="taskNumber"></param>
         /// <param name="cancellationToken"></param>
@@ -198,23 +198,23 @@ namespace TeamAAS_VP.Interfaces
         Task<bool> StopClearMaterialTaskAsync(int taskNumber, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 获取机器人是否进入调试模式
+        /// 鑾峰彇鏈哄櫒浜烘槸鍚﹀�浜庤皟璇曟ā寮�
         /// </summary>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         Task<bool> IsRobotInDebugModeAsync(int robotNumber, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 执行视觉任务
+        /// 鎵ц�瑙嗚�浠诲姟
         /// </summary>
-        /// <param name="procedure">流程</param>
-        /// <param name="items">是否先振动</param>
+        /// <param name="procedure">娴佺▼</param>
+        /// <param name="items">鍛戒护鍙傛暟</param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         Task<(bool IsSucceed, string[] Response)> ExecuteVisionTaskAsync(ProcedureModel procedure, string[] items, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 执行Feeder视觉引导任务
+        /// 鎵ц�Feeder瑙嗚�寮曞�浠诲姟
         /// </summary>
         /// <param name="feeder"></param>
         /// <param name="procedure"></param>
@@ -224,7 +224,7 @@ namespace TeamAAS_VP.Interfaces
         Task<(bool IsSucceed, string[] Response)> ExecuteFeederVisionTaskAsync(IVoiceCoilMotorFeeder feeder, ProcedureModel procedure, string[] items, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 执行普通视觉任务
+        /// 鎵ц�鏅�€氳�瑙変换鍔�
         /// </summary>
         /// <param name="procedure"></param>
         /// <param name="items"></param>
@@ -233,33 +233,31 @@ namespace TeamAAS_VP.Interfaces
         Task<(bool IsSucceed, string Response)> ExecuteNormalVisionTaskAsync(ProcedureModel procedure, string[] items, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 执行相机拍照
+        /// 鎵ц�鐩告満鎷嶇収
         /// </summary>
         /// <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);
+        Task<(bool Success, CogToolBlockTerminalCollection OutputCollection)> ExecutePhotoAsync(ProcedureModel procedure, Dictionary<string, string> InputTerminal);
 
         /// <summary>
-        /// 执行翻转相机拍照流程运行
+        /// 鎵ц�鐩告満鎷嶇収娴佺▼杩愯�
         /// </summary>
         /// <param name="procedure"></param>
-        /// <param name="outputCollection"></param>
         /// <returns></returns>
-        bool ExecutePhoto(ProcedureModel procedure, out CogToolBlockTerminalCollection outputCollection);
+        Task<(bool Success, CogToolBlockTerminalCollection OutputCollection)> ExecutePhotoAsync(ProcedureModel procedure);
 
         /// <summary>
-        /// 执行相机拍照
+        /// 鎵ц�鐩告満鎷嶇収骞惰繍琛� ToolBlock
         /// </summary>
         /// <param name="procedure"></param>
         /// <param name="InputTerminal"></param>
-        /// <param name="outputCollection"></param>
         /// <returns></returns>
-        bool ExecutePhoto2(ProcedureModel procedure, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection);
+        Task<(bool Success, CogToolBlockTerminalCollection OutputCollection)> ExecutePhoto2Async(ProcedureModel procedure, Dictionary<string, string> InputTerminal);
 
         /// <summary>
-        /// 执行相机拍照获取单个点位结果
+        /// 鎵ц�鐩告満鎷嶇収鑾峰彇鍗曚釜鐐逛綅缁撴灉
         /// </summary>
         /// <param name="procedure"></param>
         /// <param name="InputTerminal"></param>
@@ -269,14 +267,14 @@ namespace TeamAAS_VP.Interfaces
         Task<(bool IsSucceed, double X, double Y, double U)> ExecutePhotoGetSinglePoint(ProcedureModel procedure, Dictionary<string, string> InputTerminal, double[] robotCoord, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 相机采集图像
+        /// 閲囬泦鍥惧儚
         /// </summary>
         /// <param name="procedure"></param>
         /// <returns></returns>
         Task<(bool IsSucceed, ICogImage[] Image, string Msg)> ExecuteGrabImageAsync(ProcedureModel procedure,bool Is3dPhoto, SystemConfiguration sysConfig);
 
         /// <summary>
-        /// 执行相机拍照获取单个点位结果
+        /// 鎵ц�鐩告満鎷嶇収鑾峰彇澶氫釜鐐逛綅缁撴灉
         /// </summary>
         /// <param name="procedure"></param>
         /// <param name="InputTerminal"></param>
@@ -286,7 +284,7 @@ namespace TeamAAS_VP.Interfaces
         Task<(bool IsSucceed, string[] Items, double Count)> ExecutePhotoGetSinglePoint1(ProcedureModel procedure, ICogImage[] imges, Dictionary<string, string> InputTerminal, double[] robotCoord, CancellationToken cancellationToken,bool is3dmodel, float confThreshold = 0.25f, float iouThreshold = 0.45f);
 
         /// <summary>
-        /// 执行相机拍照获取单个点位结果
+        /// 鎵ц�鐩告満鎷嶇収鑾峰彇澶氫釜鐐逛綅缁撴灉
         /// </summary>
         /// <param name="procedure"></param>
         /// <param name="InputTerminal"></param>
@@ -297,7 +295,7 @@ namespace TeamAAS_VP.Interfaces
 
 
         /// <summary>
-        /// 执行相机拍照获取单个点位结果
+        /// 鎵ц�鐩告満鎷嶇収鑾峰彇鍗曚釜鐐逛綅缁撴灉
         /// </summary>
         /// <param name="procedure"></param>
         /// <param name="InputTerminal"></param>
@@ -306,7 +304,7 @@ namespace TeamAAS_VP.Interfaces
         /// <returns></returns>
         Task<(bool IsSucceed, string X, double Y, double U)> ExecutePhotoGetSinglePoint2(ProcedureModel procedure, Dictionary<string, string> InputTerminal, double[] robotCoord, CancellationToken cancellationToken);
         /// <summary>
-        /// 执行相机拍照获取单个点位结果,并且返回图像和图形
+        /// 鎵ц�鐩告満鎷嶇収鑾峰彇鍗曚釜鐐逛綅缁撴灉,骞朵笖杩斿洖鍥惧儚鍜屽浘褰�
         /// </summary>
         /// <param name="procedure"></param>
         /// <param name="InputTerminal"></param>
@@ -316,7 +314,7 @@ namespace TeamAAS_VP.Interfaces
         Task<(bool IsSucceed, double X, double Y, double U, ICogImage Image, CogGraphicCollection Graphic)> ExecutePhotoGetSinglePointWithImage(ProcedureModel procedure, Dictionary<string, string> InputTerminal, double[] robotCoord, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 获取需要输出项
+        /// 鑾峰彇瑙嗚�杈撳嚭
         /// </summary>
         /// <param name="procedure"></param>
         /// <param name="outputCollection"></param>
@@ -325,7 +323,7 @@ namespace TeamAAS_VP.Interfaces
         (bool IsSucceed, string ErrMsg, Dictionary<string, (bool IsPoint, object Value)> Output) GetVisionOutput(ProcedureModel procedure, CogToolBlockTerminalCollection outputCollection, double[] robotPos);
 
         /// <summary>
-        /// Feeder拍照前,执行Feeder
+        /// Feeder鎷嶇収鍓嶇殑鍑嗗�鍔ㄤ綔
         /// </summary>
         /// <param name="Feeder"></param>
         /// <param name="procedure"></param>
@@ -336,7 +334,7 @@ namespace TeamAAS_VP.Interfaces
         Task ExecuteFeederForPhotoBefore(IVoiceCoilMotorFeeder Feeder, ProcedureModel procedure, bool doVibrateFirst, bool doCaptureFirst, CancellationToken cancellationToken);
 
         /// <summary>
-        /// Feeder拍照后,拍照失败时,执行Feeder
+        /// Feeder鎷嶇収鍚庝笖澶辫触鏃�,鎵ц�Feeder
         /// </summary>
         /// <param name="Feeder"></param>
         /// <param name="procedure"></param>
@@ -345,7 +343,7 @@ namespace TeamAAS_VP.Interfaces
         Task ExecuteFeederForPhotoLater(IVoiceCoilMotorFeeder Feeder, ProcedureModel procedure, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 执行Feeder料仓供料及振动集合
+        /// 鎵ц�Feeder鏂欎粨渚涙枡鍙婃尟鍔ㄤ换鍔�
         /// </summary>
         /// <param name="feeder"></param>
         /// <param name="works"></param>
@@ -355,7 +353,7 @@ namespace TeamAAS_VP.Interfaces
         Task ExecuteFeederStockWorks(IVoiceCoilMotorFeeder feeder, FeederStockWorks works, CancellationToken cancellationToken, bool isUpdateParame = true);
 
         /// <summary>
-        /// 执行料仓振动任务
+        /// 鎵ц�鏂欎粨鎸�姩浠诲姟
         /// </summary>
         /// <param name="feeder"></param>
         /// <param name="works"></param>
@@ -364,7 +362,7 @@ namespace TeamAAS_VP.Interfaces
         Task ExecuteFeederStockWorksOnly(IVoiceCoilMotorFeeder feeder, FeederStockWork[] works, CancellationToken cancellationToken);
 
         /// <summary>
-        /// 执行Feeder振动任务
+        /// 鎵ц�Feeder鎸�姩鍔ㄤ綔
         /// </summary>
         /// <param name="feeder"></param>
         /// <param name="works"></param>
@@ -374,7 +372,7 @@ namespace TeamAAS_VP.Interfaces
         Task ExecuteFeederWorkOnly(IVoiceCoilMotorFeeder feeder, FeederWork[] works, CancellationToken cancellationToken, bool isUpdateParame = true);
 
         /// <summary>
-        /// 执行Feeder振动集合
+        /// 鎵ц�Feeder鎸�姩闆嗗悎
         /// </summary>
         /// <param name="feeder"></param>
         /// <param name="works"></param>
@@ -384,16 +382,16 @@ namespace TeamAAS_VP.Interfaces
         Task ExecuteFeederWorks(IVoiceCoilMotorFeeder feeder, FeederWorks works, CancellationToken cancellationToken, bool isUpdateParame = true);
 
         /// <summary>
-        /// 在拍照前设置光源亮度和打开光源
+        /// 鎷嶇収鍓嶈�缃�厜婧愪寒搴﹀拰鎵撳紑鍏夋簮
         /// </summary>
-        /// <param name="procedure">流程模型</param>
+        /// <param name="procedure">娴佺▼妯″瀷</param>
         /// <returns></returns>
         Task SetLightBeforePhoto(ProcedureModel procedure);
 
         /// <summary>
-        /// 在拍照后关闭光源
+        /// 鎷嶇収鍚庡叧闂�厜婧�
         /// </summary>
-        /// <param name="procedure">流程模型</param>
+        /// <param name="procedure">娴佺▼妯″瀷</param>
         /// <returns></returns>
         Task TurnOffLightAfterPhoto(ProcedureModel procedure);
     }

+ 123 - 123
TeamAAS-VM/Interfaces/ISystemDatabaseService.cs

@@ -1,13 +1,13 @@
-/* 伪代码计划(详细步骤):
-   1. 在文件顶部以注释形式写明生成注释的目的与范围(中文说明)。
-   2. 为接口 ISystemDatabaseService 添加完整的 XML 文档注释:
-      - 在接口声明上添加总体描述(接口职责、线程/异步约定、与数据库交互的总体行为描述)。
-      - 为每个方法添加 <summary>,<param>,<returns>(如适用)和 <remarks>(必要时)。
-      - 对于带有可为空参数的方法(如 ResetProductionAsync、GetTotalProductionAsync),在 <param> 中说明 null 的语义。
-      - 对于返回集合的方法,说明集合可能为空或包含元素。
-      - 对于认证方法,说明失败时返回 null 或抛出异常的约定(与现有签名保持一致)。
-   3. 保持原有 using 和 namespace 不变,确保注释符合 C# XML 注释格式并使用中文表述。
-   4. 保证代码风格和缩进与项目一致(4 空格缩进),使用 C# 注释约定 (///)。
+/* 浼�唬鐮佽�鍒掞紙璇︾粏姝ラ�锛夛細
+   1. 鍦ㄦ枃浠堕《閮ㄤ互娉ㄩ噴褰㈠紡鍐欐槑鐢熸垚娉ㄩ噴鐨勭洰鐨勪笌鑼冨洿锛堜腑鏂囪�鏄庯級銆�
+   2. 涓烘帴鍙� ISystemDatabaseService 娣诲姞瀹屾暣鐨� XML 鏂囨。娉ㄩ噴锛�
+      - 鍦ㄦ帴鍙e0鏄庝笂娣诲姞鎬讳綋鎻忚堪锛堟帴鍙h亴璐c€佺嚎绋�/寮傛�绾﹀畾銆佷笌鏁版嵁搴撲氦浜掔殑鎬讳綋琛屼负鎻忚堪锛夈€�
+      - 涓烘瘡涓�柟娉曟坊鍔� <summary>锛�<param>锛�<returns>锛堝�閫傜敤锛夊拰 <remarks>锛堝繀瑕佹椂锛夈€�
+      - 瀵逛簬甯︽湁鍙�负绌哄弬鏁扮殑鏂规硶锛堝� ResetProductionAsync銆丟etTotalProductionAsync锛夛紝鍦� <param> 涓��鏄� null 鐨勮�涔夈€�
+      - 瀵逛簬杩斿洖闆嗗悎鐨勬柟娉曪紝璇存槑闆嗗悎鍙�兘涓虹┖鎴栧寘鍚�厓绱犮€�
+      - 瀵逛簬璁よ瘉鏂规硶锛岃�鏄庡け璐ユ椂杩斿洖 null 鎴栨姏鍑哄紓甯哥殑绾﹀畾锛堜笌鐜版湁绛惧悕淇濇寔涓€鑷达級銆�
+   3. 淇濇寔鍘熸湁 using 鍜� namespace 涓嶅彉锛岀‘淇濇敞閲婄�鍚� C# XML 娉ㄩ噴鏍煎紡骞朵娇鐢ㄤ腑鏂囪〃杩般€�
+   4. 淇濊瘉浠g爜椋庢牸鍜岀缉杩涗笌椤圭洰涓€鑷达紙4 绌烘牸缂╄繘锛夛紝浣跨敤 C# 娉ㄩ噴绾﹀畾 (///)銆�
 */
 
 using System;
@@ -18,190 +18,190 @@ using TeamAAS_VP.Models;
 namespace TeamAAS_VP.Interfaces
 {
     /// <summary>
-    /// 提供与系统数据库交互的抽象服务接口。
-    /// 包含用户管理、用户认证与产能(生产)记录的增删改查与统计方法。
-    /// 所有方法均为异步方法以支持非阻塞 IO 操作。
+    /// 鎻愪緵涓庣郴缁熸暟鎹�簱浜や簰鐨勬娊璞℃湇鍔℃帴鍙c€�
+    /// 鍖呭惈鐢ㄦ埛绠$悊銆佺敤鎴疯�璇佷笌浜ц兘锛堢敓浜э級璁板綍鐨勫�鍒犳敼鏌ヤ笌缁熻�鏂规硶銆�
+    /// 鎵€鏈夋柟娉曞潎涓哄紓姝ユ柟娉曚互鏀�寔闈為樆濉� IO 鎿嶄綔銆�
     /// </summary>
     public interface ISystemDatabaseService
     {
         // User CRUD
 
         /// <summary>
-        /// 将新的用户记录添加到数据库中。
+        /// 灏嗘柊鐨勭敤鎴疯�褰曟坊鍔犲埌鏁版嵁搴撲腑銆�
         /// </summary>
-        /// <param name="user">要添加的用户对象。应包含必要的字段(例如用户名、密码摘要等)。</param>
+        /// <param name="user">瑕佹坊鍔犵殑鐢ㄦ埛瀵硅薄銆傚簲鍖呭惈蹇呰�鐨勫瓧娈碉紙渚嬪�鐢ㄦ埛鍚嶃€佸瘑鐮佹憳瑕佺瓑锛夈€�</param>
         /// <returns>
-        /// 一个包含已保存用户信息的 <see cref="User"/> 实例(通常带有数据库生成的 Id)。
+        /// 涓€涓�寘鍚�凡淇濆瓨鐢ㄦ埛淇℃伅鐨� <see cref="User"/> 瀹炰緥锛堥€氬父甯︽湁鏁版嵁搴撶敓鎴愮殑 Id锛夈€�
         /// </returns>
         /// <remarks>
-        /// 实现者应负责对重复用户名或验证失败的情况进行处理(例如抛出异常或按项目约定返回特定结果)。
+        /// 瀹炵幇鑰呭簲璐熻矗瀵归噸澶嶇敤鎴峰悕鎴栭獙璇佸け璐ョ殑鎯呭喌杩涜�澶勭悊锛堜緥濡傛姏鍑哄紓甯告垨鎸夐」鐩�害瀹氳繑鍥炵壒瀹氱粨鏋滐級銆�
         /// </remarks>
         Task<User> AddUserAsync(User user);
 
         /// <summary>
-        /// 更新现有用户的数据库记录。
+        /// 鏇存柊鐜版湁鐢ㄦ埛鐨勬暟鎹�簱璁板綍銆�
         /// </summary>
-        /// <param name="user">包含更新后信息的用户对象,必须包含有效的用户 Id。</param>
-        /// <returns>更新后的 <see cref="User"/> 对象。</returns>
-        /// <remarks>如果指定用户不存在,实现可以抛出异常或按约定返回 null。</remarks>
+        /// <param name="user">鍖呭惈鏇存柊鍚庝俊鎭�殑鐢ㄦ埛瀵硅薄锛屽繀椤诲寘鍚�湁鏁堢殑鐢ㄦ埛 Id銆�</param>
+        /// <returns>鏇存柊鍚庣殑 <see cref="User"/> 瀵硅薄銆�</returns>
+        /// <remarks>濡傛灉鎸囧畾鐢ㄦ埛涓嶅瓨鍦�紝瀹炵幇鍙�互鎶涘嚭寮傚父鎴栨寜绾﹀畾杩斿洖 null銆�</remarks>
         Task<User> UpdateUserAsync(User user);
 
         /// <summary>
-        /// 删除指定 Id 的用户记录。
+        /// 鍒犻櫎鎸囧畾 Id 鐨勭敤鎴疯�褰曘€�
         /// </summary>
-        /// <param name="userId">要删除的用户的数据库 Id。</param>
-        /// <returns>若删除成功返回 true;如果用户不存在或删除失败返回 false。</returns>
+        /// <param name="userId">瑕佸垹闄ょ殑鐢ㄦ埛鐨勬暟鎹�簱 Id銆�</param>
+        /// <returns>鑻ュ垹闄ゆ垚鍔熻繑鍥� true锛涘�鏋滅敤鎴蜂笉瀛樺湪鎴栧垹闄ゅけ璐ヨ繑鍥� false銆�</returns>
         Task<bool> DeleteUserAsync(int userId);
 
         /// <summary>
-        /// 根据用户 Id 获取用户信息。
+        /// 鏍规嵁鐢ㄦ埛 Id 鑾峰彇鐢ㄦ埛淇℃伅銆�
         /// </summary>
-        /// <param name="userId">要查询的用户 Id。</param>
-        /// <returns>找到则返回对应的 <see cref="User"/> 对象;不存在时返回 null。</returns>
+        /// <param name="userId">瑕佹煡璇㈢殑鐢ㄦ埛 Id銆�</param>
+        /// <returns>鎵惧埌鍒欒繑鍥炲�搴旂殑 <see cref="User"/> 瀵硅薄锛涗笉瀛樺湪鏃惰繑鍥� null銆�</returns>
         Task<User> GetUserByIdAsync(int userId);
 
         /// <summary>
-        /// 获取系统中所有用户的集合。
+        /// 鑾峰彇绯荤粺涓�墍鏈夌敤鎴风殑闆嗗悎銆�
         /// </summary>
         /// <returns>
-        /// 一个用户集合;如果没有用户,返回的集合可为空或为空集合,具体由实现决定(建议返回空集合而非 null)。
+        /// 涓€涓�敤鎴烽泦鍚堬紱濡傛灉娌℃湁鐢ㄦ埛锛岃繑鍥炵殑闆嗗悎鍙�负绌烘垨涓虹┖闆嗗悎锛屽叿浣撶敱瀹炵幇鍐冲畾锛堝缓璁�繑鍥炵┖闆嗗悎鑰岄潪 null锛夈€�
         /// </returns>
         Task<IEnumerable<User>> GetAllUsersAsync();
 
         // User authentication
 
         /// <summary>
-        /// 使用用户名和密码(或密码摘要)对用户进行认证。
+        /// 浣跨敤鐢ㄦ埛鍚嶅拰瀵嗙爜锛堟垨瀵嗙爜鎽樿�锛夊�鐢ㄦ埛杩涜�璁よ瘉銆�
         /// </summary>
-        /// <param name="username">要认证的用户名。</param>
-        /// <param name="password">用于认证的密码或密码摘要。</param>
+        /// <param name="username">瑕佽�璇佺殑鐢ㄦ埛鍚嶃€�</param>
+        /// <param name="password">鐢ㄤ簬璁よ瘉鐨勫瘑鐮佹垨瀵嗙爜鎽樿�銆�</param>
         /// <returns>
-        /// 认证成功时返回对应的 <see cref="User"/> 对象(可包含用户的身份信息或权限);认证失败时返回 null。
+        /// 璁よ瘉鎴愬姛鏃惰繑鍥炲�搴旂殑 <see cref="User"/> 瀵硅薄锛堝彲鍖呭惈鐢ㄦ埛鐨勮韩浠戒俊鎭�垨鏉冮檺锛夛紱璁よ瘉澶辫触鏃惰繑鍥� null銆�
         /// </returns>
-        /// <remarks>实现者应确保密码比较使用安全方式(例如散列和抗时序攻击的比较)。</remarks>
+        /// <remarks>瀹炵幇鑰呭簲纭�繚瀵嗙爜姣旇緝浣跨敤瀹夊叏鏂瑰紡锛堜緥濡傛暎鍒楀拰鎶楁椂搴忔敾鍑荤殑姣旇緝锛夈€�</remarks>
         Task<User> AuthenticateUserAsync(string username, string password);
 
         // Remember user helpers
 
         /// <summary>
-        /// 将指定用户名标记为“记住”,并取消其他用户的记住标志。
+        /// 灏嗘寚瀹氱敤鎴峰悕鏍囪�涓衡€滆�浣忊€濓紝骞跺彇娑堝叾浠栫敤鎴风殑璁颁綇鏍囧織銆�
         /// </summary>
-        /// <param name="username">要记住的用户名。</param>
-        /// <returns>完成记住用户操作的任务。</returns>
+        /// <param name="username">瑕佽�浣忕殑鐢ㄦ埛鍚嶃€�</param>
+        /// <returns>瀹屾垚璁颁綇鐢ㄦ埛鎿嶄綔鐨勪换鍔°€�</returns>
         /// <remarks>
-        /// 实现者应负责确保此操作的原子性与一致性。
+        /// 瀹炵幇鑰呭簲璐熻矗纭�繚姝ゆ搷浣滅殑鍘熷瓙鎬т笌涓€鑷存€с€�
         /// </remarks>
         Task SetRememberUserAsync(string username);
 
         /// <summary>
-        /// 清除所有用户的“记住”标志。
+        /// 娓呴櫎鎵€鏈夌敤鎴风殑鈥滆�浣忊€濇爣蹇椼€�
         /// </summary>
-        /// <returns>完成清除操作的任务。</returns>
+        /// <returns>瀹屾垚娓呴櫎鎿嶄綔鐨勪换鍔°€�</returns>
         /// <remarks>
-        /// 实现者应负责确保此操作不会影响当前在线用户的会话。
+        /// 瀹炵幇鑰呭簲璐熻矗纭�繚姝ゆ搷浣滀笉浼氬奖鍝嶅綋鍓嶅湪绾跨敤鎴风殑浼氳瘽銆�
         /// </remarks>
         Task ClearRememberUserAsync();
 
         /// <summary>
-        /// 获取当前被标记为记住的用户(如果存在)。
+        /// 鑾峰彇褰撳墠琚�爣璁颁负璁颁綇鐨勭敤鎴凤紙濡傛灉瀛樺湪锛夈€�
         /// </summary>
-        /// <returns>被记住的用户或 null。</returns>
+        /// <returns>琚��浣忕殑鐢ㄦ埛鎴� null銆�</returns>
         /// <remarks>
-        /// 实现者应确保此方法高效执行并尽量减少资源消耗。
+        /// 瀹炵幇鑰呭簲纭�繚姝ゆ柟娉曢珮鏁堟墽琛屽苟灏介噺鍑忓皯璧勬簮娑堣€椼€�
         /// </remarks>
         Task<User> GetRememberedUserAsync();
 
         // Current user / session helpers
 
         /// <summary>
-        /// 将指定用户设为当前用户(会写入一条登录记录,标记为成功)
+        /// 灏嗘寚瀹氱敤鎴疯�涓哄綋鍓嶇敤鎴凤紙浼氬啓鍏ヤ竴鏉$櫥褰曡�褰曪紝鏍囪�涓烘垚鍔燂級
         /// </summary>
-        /// <param name="userId">要设为当前用户的用户 Id。</param>
-        /// <returns>完成设为当前用户操作的任务。</returns>
+        /// <param name="userId">瑕佽�涓哄綋鍓嶇敤鎴风殑鐢ㄦ埛 Id銆�</param>
+        /// <returns>瀹屾垚璁句负褰撳墠鐢ㄦ埛鎿嶄綔鐨勪换鍔°€�</returns>
         /// <remarks>
-        /// 实现者应确保此操作为线程安全,并正确处理可能的并发访问。
+        /// 瀹炵幇鑰呭簲纭�繚姝ゆ搷浣滀负绾跨▼瀹夊叏锛屽苟姝g‘澶勭悊鍙�兘鐨勫苟鍙戣�闂�€�
         /// </remarks>
         Task SetCurrentUserAsync(int userId);
 
         /// <summary>
-        /// 获取当前(最近一次成功登录的)用户。
+        /// 鑾峰彇褰撳墠锛堟渶杩戜竴娆℃垚鍔熺櫥褰曠殑锛夌敤鎴枫€�
         /// </summary>
-        /// <returns>返回最近一次成功登录的 <see cref="User"/>,找不到则返回 null。</returns>
+        /// <returns>杩斿洖鏈€杩戜竴娆℃垚鍔熺櫥褰曠殑 <see cref="User"/>锛屾壘涓嶅埌鍒欒繑鍥� null銆�</returns>
         Task<User> GetCurrentUserAsync();
 
         /// <summary>
-        /// 获取当前用户
+        /// 鑾峰彇褰撳墠鐢ㄦ埛
         /// </summary>
         /// <returns></returns>
         User GetCurrentUser();
 
         /// <summary>
-        /// 记录一条用户登录记录(成功或失败)。
+        /// 璁板綍涓€鏉$敤鎴风櫥褰曡�褰曪紙鎴愬姛鎴栧け璐ワ級銆�
         /// </summary>
-        /// <param name="record">登录记录对象,不能为空。</param>
-        /// <returns>完成记录登录操作的任务。</returns>
+        /// <param name="record">鐧诲綍璁板綍瀵硅薄锛屼笉鑳戒负绌恒€�</param>
+        /// <returns>瀹屾垚璁板綍鐧诲綍鎿嶄綔鐨勪换鍔°€�</returns>
         /// <remarks>
-        /// 实现者应负责确保记录的持久化,并处理可能的异常情况。
+        /// 瀹炵幇鑰呭簲璐熻矗纭�繚璁板綍鐨勬寔涔呭寲锛屽苟澶勭悊鍙�兘鐨勫紓甯告儏鍐点€�
         /// </remarks>
         Task RecordUserLoginAsync(UserLoginRecord record);
 
         /// <summary>
-        /// 获取指定用户最近的一条登录记录(如果有)。
+        /// 鑾峰彇鎸囧畾鐢ㄦ埛鏈€杩戠殑涓€鏉$櫥褰曡�褰曪紙濡傛灉鏈夛級銆�
         /// </summary>
-        /// <param name="userId">用户 Id。</param>
-        /// <returns>最近的一条 <see cref="UserLoginRecord"/> 或 null。</returns>
+        /// <param name="userId">鐢ㄦ埛 Id銆�</param>
+        /// <returns>鏈€杩戠殑涓€鏉� <see cref="UserLoginRecord"/> 鎴� null銆�</returns>
         /// <remarks>
-        /// 如果用户没有登录记录,返回 null 而非抛出异常。
+        /// 濡傛灉鐢ㄦ埛娌℃湁鐧诲綍璁板綍锛岃繑鍥� null 鑰岄潪鎶涘嚭寮傚父銆�
         /// </remarks>
         Task<UserLoginRecord> GetLastUserLoginRecordAsync(int userId);
 
         // Production records
 
         /// <summary>
-        /// 将一条生产记录写入数据库。
+        /// 灏嗕竴鏉$敓浜ц�褰曞啓鍏ユ暟鎹�簱銆�
         /// </summary>
-        /// <param name="record">要记录的 <see cref="ProductionRecord"/> 实例,包含产品名、分类、数量和时间等信息。</param>
-        /// <returns>完成写入操作的任务。</returns>
+        /// <param name="record">瑕佽�褰曠殑 <see cref="ProductionRecord"/> 瀹炰緥锛屽寘鍚�骇鍝佸悕銆佸垎绫汇€佹暟閲忓拰鏃堕棿绛変俊鎭�€�</param>
+        /// <returns>瀹屾垚鍐欏叆鎿嶄綔鐨勪换鍔°€�</returns>
         Task RecordProductionAsync(ProductionRecord record);
 
         /// <summary>
-        /// 清除产能计数。
+        /// 娓呴櫎浜ц兘璁℃暟銆�
         /// </summary>
         /// <param name="productName">
-        /// 要清除计数的产品名称。传入 null 表示清除所有产品的计数。
+        /// 瑕佹竻闄よ�鏁扮殑浜у搧鍚嶇О銆備紶鍏� null 琛ㄧず娓呴櫎鎵€鏈変骇鍝佺殑璁℃暟銆�
         /// </param>
-        /// <returns>完成清除操作的任务。</returns>
+        /// <returns>瀹屾垚娓呴櫎鎿嶄綔鐨勪换鍔°€�</returns>
         Task ResetProductionAsync(string productName = null);
 
         /// <summary>
-        /// 获取指定产品在可选分类集合下的总产能(对 Quantity 求和)。
+        /// 鑾峰彇鎸囧畾浜у搧鍦ㄥ彲閫夊垎绫婚泦鍚堜笅鐨勬€讳骇鑳斤紙瀵� Quantity 姹傚拰锛夈€�
         /// </summary>
-        /// <param name="productName">要统计的产品名称,不能为空或空字符串。</param>
+        /// <param name="productName">瑕佺粺璁$殑浜у搧鍚嶇О锛屼笉鑳戒负绌烘垨绌哄瓧绗︿覆銆�</param>
         /// <param name="categories">
-        /// 可选的分类集合;如果传入 null 或为空集合,则统计所有分类。
+        /// 鍙�€夌殑鍒嗙被闆嗗悎锛涘�鏋滀紶鍏� null 鎴栦负绌洪泦鍚堬紝鍒欑粺璁℃墍鏈夊垎绫汇€�
         /// </param>
-        /// <returns>指定条件下的总产能数量(int)。</returns>
+        /// <returns>鎸囧畾鏉′欢涓嬬殑鎬讳骇鑳芥暟閲忥紙int锛夈€�</returns>
         Task<int> GetTotalProductionAsync(string productName, IEnumerable<string> categories = null);
 
         /// <summary>
-        /// 按指定粒度获取产能统计结果。
+        /// 鎸夋寚瀹氱矑搴﹁幏鍙栦骇鑳界粺璁$粨鏋溿€�
         /// </summary>
-        /// <param name="query">包含时间范围、分组粒度(例如按天/按周/按月)、产品名称和分类过滤等条件的查询对象。</param>
+        /// <param name="query">鍖呭惈鏃堕棿鑼冨洿銆佸垎缁勭矑搴︼紙渚嬪�鎸夊ぉ/鎸夊懆/鎸夋湀锛夈€佷骇鍝佸悕绉板拰鍒嗙被杩囨护绛夋潯浠剁殑鏌ヨ�瀵硅薄銆�</param>
         /// <returns>
-        /// 满足查询条件的分组统计结果集合,每项为 <see cref="ProductionStatResult"/>。
-        /// 如果没有匹配项,可以返回空集合(建议不返回 null)。
+        /// 婊¤冻鏌ヨ�鏉′欢鐨勫垎缁勭粺璁$粨鏋滈泦鍚堬紝姣忛」涓� <see cref="ProductionStatResult"/>銆�
+        /// 濡傛灉娌℃湁鍖归厤椤癸紝鍙�互杩斿洖绌洪泦鍚堬紙寤鸿�涓嶈繑鍥� null锛夈€�
         /// </returns>
         Task<IEnumerable<ProductionStatResult>> GetProductionStatsAsync(ProductionStatQuery query);
 
         /// <summary>
-        /// 获取所有已知分类相加起来的今天的产能
+        /// 鑾峰彇鎵€鏈夊凡鐭ュ垎绫荤浉鍔犺捣鏉ョ殑浠婂ぉ鐨勪骇鑳�
         /// </summary>
         /// <param name="productName"></param>
         /// <returns></returns>
         Task<int> GetTodayProductionAsync(string productName);
 
         /// <summary>
-        /// 获取所有已知分类相加起来的当前时间往前的一个小时的产能
+        /// 鑾峰彇鎵€鏈夊凡鐭ュ垎绫荤浉鍔犺捣鏉ョ殑褰撳墠鏃堕棿寰€鍓嶇殑涓€涓�皬鏃剁殑浜ц兘
         /// </summary>
         /// <param name="productName"></param>
         /// <returns></returns>
@@ -209,65 +209,65 @@ namespace TeamAAS_VP.Interfaces
 
 
         /// <summary>
-        /// 获取今天的Nguyen数量
+        /// 鑾峰彇浠婂ぉ鐨凬guyen鏁伴噺
         /// </summary>
         /// <param name="productName"></param>
         /// <returns></returns>
         Task<int> GetNGProductionAsync(string productName);
 
         /// <summary>
-        /// 获取当前月的产能
+        /// 鑾峰彇褰撳墠鏈堢殑浜ц兘
         /// </summary>
         /// <param name="productName"></param>
         /// <returns></returns>
         Task<int> GetCurrentMonthProductionAsync(string productName);
 
         /// <summary>
-        /// 获取当前周的产能
+        /// 鑾峰彇褰撳墠鍛ㄧ殑浜ц兘
         /// </summary>
         /// <param name="productName"></param>
         /// <returns></returns>
         Task<int> GetCurrentWeekProductionAsync(string productName);
 
         /// <summary>
-        /// 获取指定产品名称的总产能
+        /// 鑾峰彇鎸囧畾浜у搧鍚嶇О鐨勬€讳骇鑳�
         /// </summary>
         /// <param name="productName"></param>
         /// <returns></returns>
         Task<int> GetOverallProductionAsync(string productName);
 
         /// <summary>
-        /// 获取指定产品的所有已知分类。
+        /// 鑾峰彇鎸囧畾浜у搧鐨勬墍鏈夊凡鐭ュ垎绫汇€�
         /// </summary>
-        /// <param name="productName">要查询分类的产品名称。</param>
+        /// <param name="productName">瑕佹煡璇㈠垎绫荤殑浜у搧鍚嶇О銆�</param>
         /// <returns>
-        /// 一个字符串集合,包含该产品的所有分类名称;如果没有分类,返回空集合或 null(建议返回空集合)。
+        /// 涓€涓�瓧绗︿覆闆嗗悎锛屽寘鍚��浜у搧鐨勬墍鏈夊垎绫诲悕绉帮紱濡傛灉娌℃湁鍒嗙被锛岃繑鍥炵┖闆嗗悎鎴� null锛堝缓璁�繑鍥炵┖闆嗗悎锛夈€�
         /// </returns>
         Task<IEnumerable<string>> GetProductCategoriesAsync(string productName);
 
         /// <summary>
-        /// 获取指定产品名称的所有记录按照分类的产能统计
+        /// 鑾峰彇鎸囧畾浜у搧鍚嶇О鐨勬墍鏈夎�褰曟寜鐓у垎绫荤殑浜ц兘缁熻�
         /// </summary>
         /// <param name="productName"></param>
         /// <returns></returns>
         Task<Dictionary<string, int>> GetProductionByCategoriesAsync(string productName);
 
         /// <summary>
-        /// 获取指定产品名称的一个月内按照每天统计对应的类别和数量
+        /// 鑾峰彇鎸囧畾浜у搧鍚嶇О鐨勪竴涓�湀鍐呮寜鐓ф瘡澶╃粺璁″�搴旂殑绫诲埆鍜屾暟閲�
         /// </summary>
         /// <param name="productName"></param>
         /// <returns></returns>
         Task<Dictionary<DateTime, Dictionary<string, int>>> GetMonthlyProductionByDayAndCategoryAsync(string productName);
 
         /// <summary>
-        /// 获取指定产品名称的一个星期内按照每天统计对应的类别和数量
+        /// 鑾峰彇鎸囧畾浜у搧鍚嶇О鐨勪竴涓�槦鏈熷唴鎸夌収姣忓ぉ缁熻�瀵瑰簲鐨勭被鍒�拰鏁伴噺
         /// </summary>
         /// <param name="productName"></param>
         /// <returns></returns>
         Task<Dictionary<int, Dictionary<string, int>>> GetWeeklyProductionByDayAndCategoryAsync(string productName);
 
         /// <summary>
-        /// 获取指定产品名称的当天内按照每小时统计对应的类别和数量
+        /// 鑾峰彇鎸囧畾浜у搧鍚嶇О鐨勫綋澶╁唴鎸夌収姣忓皬鏃剁粺璁″�搴旂殑绫诲埆鍜屾暟閲�
         /// </summary>
         /// <param name="productName"></param>
         /// <returns></returns>
@@ -277,70 +277,70 @@ namespace TeamAAS_VP.Interfaces
         // Alarm records
 
         /// <summary>
-        /// 将一条报警记录写入数据库。
+        /// 灏嗕竴鏉℃姤璀﹁�褰曞啓鍏ユ暟鎹�簱銆�
         /// </summary>
-        /// <param name="alarm">要记录的 <see cref="AlarmRecord"/> 对象。</param>
-        /// <returns>完成写入操作的任务。</returns>
+        /// <param name="alarm">瑕佽�褰曠殑 <see cref="AlarmRecord"/> 瀵硅薄銆�</param>
+        /// <returns>瀹屾垚鍐欏叆鎿嶄綔鐨勪换鍔°€�</returns>
         Task RecordAlarmAsync(Models.AlarmRecord alarm);
 
         /// <summary>
-        /// 查询报警记录,按时间范围和可选的编号或来源过滤。
+        /// 鏌ヨ�鎶ヨ�璁板綍锛屾寜鏃堕棿鑼冨洿鍜屽彲閫夌殑缂栧彿鎴栨潵婧愯繃婊ゃ€�
         /// </summary>
-        /// <param name="start">起始时间(含)。</param>
-        /// <param name="end">结束时间(不含)。</param>
-        /// <param name="code">可选的报警编号过滤,传入 null 表示不过滤。</param>
-        /// <param name="source">可选的报警来源过滤,传入 null 表示不过滤。</param>
-        /// <returns>满足条件的报警记录集合。</returns>
+        /// <param name="start">璧峰�鏃堕棿锛堝惈锛夈€�</param>
+        /// <param name="end">缁撴潫鏃堕棿锛堜笉鍚�級銆�</param>
+        /// <param name="code">鍙�€夌殑鎶ヨ�缂栧彿杩囨护锛屼紶鍏� null 琛ㄧず涓嶈繃婊ゃ€�</param>
+        /// <param name="source">鍙�€夌殑鎶ヨ�鏉ユ簮杩囨护锛屼紶鍏� null 琛ㄧず涓嶈繃婊ゃ€�</param>
+        /// <returns>婊¤冻鏉′欢鐨勬姤璀﹁�褰曢泦鍚堛€�</returns>
         Task<IEnumerable<Models.AlarmRecord>> QueryAlarmsAsync(DateTime start, DateTime end, string code = null, string source = null);
 
         // Lock results
 
         /// <summary>
-        /// 记录单次锁付结果(波形数据 WaveDatas 不存入数据库)
+        /// 璁板綍鍗曟�閿佷粯缁撴灉锛堟尝褰㈡暟鎹� WaveDatas 涓嶅瓨鍏ユ暟鎹�簱锛�
         /// </summary>
-        /// <param name="result">要存储的 LockResult 对象</param>
+        /// <param name="result">瑕佸瓨鍌ㄧ殑 LockResult 瀵硅薄</param>
         Task RecordLockResultAsync(LockResult result);
 
         /// <summary>
-        /// 分页查询锁付结果。
-        /// 返回符合时间范围及可选过滤条件的记录集合和总记录数。
+        /// 鍒嗛〉鏌ヨ�閿佷粯缁撴灉銆�
+        /// 杩斿洖绗﹀悎鏃堕棿鑼冨洿鍙婂彲閫夎繃婊ゆ潯浠剁殑璁板綍闆嗗悎鍜屾€昏�褰曟暟銆�
         /// </summary>
-        /// <param name="start">起始时间(含)</param>
-        /// <param name="end">结束时间(不含)</param>
-        /// <param name="pageIndex">页号(从 1 开始)</param>
-        /// <param name="pageSize">每页大小</param>
-        /// <param name="productNumber">可选的产品编号过滤</param>
-        /// <param name="screwNumber">可选的螺丝编号(Number)过滤</param>
-        /// <param name="lockPassed">可选的是否通过过滤</param>
-        /// <returns>返回一个元组,包含记录集合和总记录数</returns>
+        /// <param name="start">璧峰�鏃堕棿锛堝惈锛�</param>
+        /// <param name="end">缁撴潫鏃堕棿锛堜笉鍚�級</param>
+        /// <param name="pageIndex">椤靛彿锛堜粠 1 寮€濮嬶級</param>
+        /// <param name="pageSize">姣忛〉澶у皬</param>
+        /// <param name="productNumber">鍙�€夌殑浜у搧缂栧彿杩囨护</param>
+        /// <param name="screwNumber">鍙�€夌殑铻轰笣缂栧彿锛圢umber锛夎繃婊�</param>
+        /// <param name="lockPassed">鍙�€夌殑鏄�惁閫氳繃杩囨护</param>
+        /// <returns>杩斿洖涓€涓�厓缁勶紝鍖呭惈璁板綍闆嗗悎鍜屾€昏�褰曟暟</returns>
         Task<(IEnumerable<LockResult> Items, int TotalCount)> QueryLockResultsAsync(DateTime start, DateTime end, int pageIndex, int pageSize, string productNumber = null, int? screwNumber = null, bool? lockPassed = null);
 
         /// <summary>
-        /// 查询所有符合条件的锁付结果(不分页)。
+        /// 鏌ヨ�鎵€鏈夌�鍚堟潯浠剁殑閿佷粯缁撴灉锛堜笉鍒嗛〉锛夈€�
         /// </summary>
-        /// <param name="start">起始时间(含)</param>
-        /// <param name="end">结束时间(不含)</param>
-        /// <param name="productNumber">可选的产品编号过滤</param>
-        /// <param name="screwNumber">可选的螺丝编号过滤</param>
-        /// <param name="lockPassed">可选的是否通过过滤</param>
-        /// <returns>符合条件的锁付结果集合。</returns>
+        /// <param name="start">璧峰�鏃堕棿锛堝惈锛�</param>
+        /// <param name="end">缁撴潫鏃堕棿锛堜笉鍚�級</param>
+        /// <param name="productNumber">鍙�€夌殑浜у搧缂栧彿杩囨护</param>
+        /// <param name="screwNumber">鍙�€夌殑铻轰笣缂栧彿杩囨护</param>
+        /// <param name="lockPassed">鍙�€夌殑鏄�惁閫氳繃杩囨护</param>
+        /// <returns>绗﹀悎鏉′欢鐨勯攣浠樼粨鏋滈泦鍚堛€�</returns>
         Task<IEnumerable<LockResult>> QueryAllLockResultsAsync(DateTime start, DateTime end, string productNumber = null, int? screwNumber = null, bool? lockPassed = null);
 
         /// <summary>
-        /// 记录一次螺丝供料器批次更换记录
+        /// 璁板綍涓€娆¤灪涓濅緵鏂欏櫒鎵规�鏇存崲璁板綍
         /// </summary>
         Task RecordScrewFeederBatchAsync(ScrewFeederBatchRecord record);
 
         /// <summary>
-        /// 将指定用户设为当前用户(会写入一条登录记录,标记为成功)
+        /// 灏嗘寚瀹氱敤鎴疯�涓哄綋鍓嶇敤鎴凤紙浼氬啓鍏ヤ竴鏉$櫥褰曡�褰曪紝鏍囪�涓烘垚鍔燂級
         /// </summary>
         /// <param name="user"></param>
         /// <returns></returns>
         Task SetCurrentUserAsync(User user);
 
-        #region 产品和mes的绑定,自动切换产品
+        #region 浜у搧鍜宮es鐨勭粦瀹�,鑷�姩鍒囨崲浜у搧
         /// <summary>
-        /// 添加绑定信息
+        /// 娣诲姞缁戝畾淇℃伅
         /// </summary>
         /// <param name="record"></param>
         /// <param name="product"></param>
@@ -349,7 +349,7 @@ namespace TeamAAS_VP.Interfaces
         Task InsertProWithMesAsync(ProductWithMes record, ProductModel product);
 
         /// <summary>
-        /// 删除绑定信息
+        /// 鍒犻櫎缁戝畾淇℃伅
         /// </summary>
         /// <param name="record"></param>
         /// <param name="product"></param>
@@ -357,7 +357,7 @@ namespace TeamAAS_VP.Interfaces
         Task<int> DeleteProWithMesAsync(ProductModel product);
 
         /// <summary>
-        /// 更新绑定信息
+        /// 鏇存柊缁戝畾淇℃伅
         /// </summary>
         /// <param name="record"></param>
         /// <param name="product"></param>
@@ -366,21 +366,21 @@ namespace TeamAAS_VP.Interfaces
         Task<int> UpdateProductWithMesAsync(ProductWithMes record, ProductModel product);
 
         /// <summary>
-        /// 查询绑定信息
+        /// 鏌ヨ�缁戝畾淇℃伅
         /// </summary>
         /// <param name="product"></param>
         /// <returns></returns>
         Task<ProductWithMes> QueryProductWithMesAsync(ProductModel product);
 
         /// <summary>
-        /// 查询所有绑定信息
+        /// 鏌ヨ�鎵€鏈夌粦瀹氫俊鎭�
         /// </summary>
         /// <param name="product"></param>
         /// <returns></returns>
         Task<List<ProductWithMes>> QueryProductWithMesALLAsync();
 
         /// <summary>
-        /// 通过产品的编码和颜色查询产品的id
+        /// 閫氳繃浜у搧鐨勭紪鐮佸拰棰滆壊鏌ヨ�浜у搧鐨刬d
         /// </summary>
         /// <param name="code"></param>
         /// <returns></returns>

+ 20 - 13
TeamAAS-VM/Services/ProductService.cs

@@ -13,6 +13,7 @@ using System.Windows.Interop;
 using Team.FFFeederService.Interfaces;
 using TeamAAS_VP.Core;
 using TeamAAS_VP.Events;
+using TeamAAS_VP.Helpers;
 using TeamAAS_VP.Interfaces;
 using TeamAAS_VP.Models;
 using TeamAAS_VP.Models.Product;
@@ -473,19 +474,19 @@ namespace TeamAAS_VP.Services
                     {
                         if (item1.ToolBlock == null)
                         {
-                            item1.ToolBlock = CogSerializer.LoadObjectFromFile(prcPath) as CogToolBlock;
+                            item1.ToolBlock = VisionProHelper.LoadVisionProObjectAsync<CogToolBlock>(prcPath).GetAwaiter().GetResult();
                         }
                         //continue;
                     }
 
                     if (item1.ToolBlock != null)
                     {
-                        CogSerializer.SaveObjectToFile(item1.ToolBlock, prcPath);
+                        VisionProHelper.SaveVisionProObjectAsync(item1.ToolBlock, prcPath).GetAwaiter().GetResult();
                     }
                     else if (File.Exists(TemplateToolBlock))
                     {
-                        item1.ToolBlock = CogSerializer.LoadObjectFromFile(TemplateToolBlock) as CogToolBlock;
-                        CogSerializer.SaveObjectToFile(item1.ToolBlock, prcPath);
+                        item1.ToolBlock = VisionProHelper.LoadVisionProObjectAsync<CogToolBlock>(TemplateToolBlock).GetAwaiter().GetResult();
+                        VisionProHelper.SaveVisionProObjectAsync(item1.ToolBlock, prcPath).GetAwaiter().GetResult();
                     }
                 }
             }
@@ -545,10 +546,13 @@ namespace TeamAAS_VP.Services
 
                     string prcPath = Path.Combine(dir, camera.Camera, prc.Name + ".vpp");
 
-                    prc.ToolBlock = _vppCache.GetOrAdd(prcPath, path =>
+                    // 在独立 STA 线程中加载 VPP,避免 COM 封送到 UI 线程
+                    if (!_vppCache.TryGetValue(prcPath, out var cached))
                     {
-                        return CogSerializer.LoadObjectFromFile(path) as CogToolBlock;
-                    });
+                        cached = VisionProHelper.LoadVisionProObjectAsync<CogToolBlock>(prcPath).GetAwaiter().GetResult();
+                        _vppCache.TryAdd(prcPath, cached);
+                    }
+                    prc.ToolBlock = cached;
                 }
             }
             return p;
@@ -582,10 +586,13 @@ namespace TeamAAS_VP.Services
 
                         string prcPath = Path.Combine(dir, camera.Camera, prc.Name + ".vpp");
                         temp = prcPath;
-                        prc.ToolBlock = _vppCache.GetOrAdd(prcPath, path =>
+                        // 异步加载 VPP,避免同步 I/O 阻塞调用线程(在独立 STA 线程中执行)
+                        if (!_vppCache.TryGetValue(prcPath, out var cached))
                         {
-                            return CogSerializer.LoadObjectFromFile(path) as CogToolBlock;
-                        });
+                            cached = await VisionProHelper.LoadVisionProObjectAsync<CogToolBlock>(prcPath);
+                            _vppCache.TryAdd(prcPath, cached);
+                        }
+                        prc.ToolBlock = cached;
                     }
                 }
             }
@@ -1151,13 +1158,13 @@ namespace TeamAAS_VP.Services
             string vpppath = Path.Combine(root, product.Name, cameraProcedure.Camera, prcname + ".vpp");
             if (File.Exists(vpppath))
             {
-                procedure.ToolBlock = CogSerializer.LoadObjectFromFile(vpppath) as CogToolBlock;
+                procedure.ToolBlock = VisionProHelper.LoadVisionProObjectAsync<CogToolBlock>(vpppath).GetAwaiter().GetResult();
             }
             else if (File.Exists(TemplateToolBlock))
             {
-                procedure.ToolBlock = CogSerializer.LoadObjectFromFile(TemplateToolBlock) as CogToolBlock;
+                procedure.ToolBlock = VisionProHelper.LoadVisionProObjectAsync<CogToolBlock>(TemplateToolBlock).GetAwaiter().GetResult();
                 //保存到指定路径
-                CogSerializer.SaveObjectToFile(procedure.ToolBlock, vpppath);
+                VisionProHelper.SaveVisionProObjectAsync(procedure.ToolBlock, vpppath).GetAwaiter().GetResult();
             }
             else
             {

+ 57 - 69
TeamAAS-VM/Services/RemoteCommandService.cs

@@ -33,6 +33,7 @@ using TeamAAS_VP.Core.Cameras;
 using TeamAAS_VP.Data;
 using TeamAAS_VP.Enums;
 using TeamAAS_VP.Events;
+using TeamAAS_VP.Helpers;
 using TeamAAS_VP.Interfaces;
 using TeamAAS_VP.Models;
 using TeamAAS_VP.Models.Calibration;
@@ -1222,7 +1223,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);
+                var (visionSucceed, outputCollection) = await ExecutePhotoAsync(procedure, InputTerminal);
                 if (!visionSucceed)
                 {
                     SendTaskMessage(Lang.视觉任务执行失败, MessageLevel.Error);
@@ -1411,7 +1412,7 @@ namespace TeamAAS_VP.Services
                     }
                     // 1. 执行相机拍照并运行视觉工具
                     LogHelper.WriteLogInfo("开始执行相机拍照并运行视觉工具");
-                    bool visionSucceed = ExecutePhoto(procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection);
+                    var (visionSucceed, outputCollection) = await ExecutePhotoAsync(procedure, InputTerminal);
                     if (!visionSucceed)
                     {
                         SendTaskMessage(Lang.视觉任务执行失败, MessageLevel.Error);
@@ -1489,9 +1490,8 @@ namespace TeamAAS_VP.Services
         /// 执行翻转相机拍照流程运行
         /// </summary>
         /// <param name="procedure"></param>
-        /// <param name="outputCollection"></param>
         /// <returns></returns>
-        public bool ExecutePhoto(ProcedureModel procedure, out CogToolBlockTerminalCollection outputCollection)
+        public async Task<(bool Success, CogToolBlockTerminalCollection OutputCollection)> ExecutePhotoAsync(ProcedureModel procedure)
         {
             try
             {
@@ -1515,20 +1515,19 @@ namespace TeamAAS_VP.Services
                 {
 
                     SendTaskMessage(Lang.图像采集失败, MessageLevel.Error);
-                    outputCollection = null;
-                    return false;
+                    return (false, null);
                 }
                 procedure.ToolBlock.Inputs["InputImage"].Value = image;
                 LogHelper.WriteLogInfo(string.Format("采集图像完成用时0ms", (DateTime.Now - nowtime).Milliseconds));
 
-                // 3. 运行视觉工具
+                // 3. 运行视觉工具(在独立 STA 线程中异步执行,避免阻塞 UI 线程)
                 LogHelper.WriteLogInfo("开始运行视觉工具");
-                procedure.ToolBlock.Run();      //运行ToolBlock
+                await VisionProHelper.RunToolBlockAsync(procedure.ToolBlock);
 
                 if (procedure.ToolBlock.RunStatus.Result == CogToolResultConstants.Accept)
                 {
                     SendTaskMessage(Lang.视觉流程执行耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Info);
-                    outputCollection = procedure.ToolBlock.Outputs;     //获取输出终端集合
+                    var outputCollection = procedure.ToolBlock.Outputs;     //获取输出终端集合
                     DatabaseHelper.AddCameraRecords(_productService.GetCurrentProduct().Name, procedure.Name, outputCollection);
                     ICogRecord record = null;
                     foreach (CogToolBlockTerminal item in outputCollection)
@@ -1576,13 +1575,12 @@ namespace TeamAAS_VP.Services
                         ImageFileName = imgName,
                         Is3DModel = true
                     });
-                    return true;
+                    return (true, outputCollection);
                 }
                 else
                 {
                     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;
@@ -1619,15 +1617,14 @@ namespace TeamAAS_VP.Services
                         ImageFileName = imgName,
                         Is3DModel = true
                     });
-                    return false;
+                    return (false, null);
                 }
             }
             catch (Exception ex)
             {
                 SendTaskMessage(ex.Message, MessageLevel.Error);
                 LogHelper.WriteLogError("执行相机取图并执行视觉工具组时出错", ex);
-                outputCollection = null;
-                return false;
+                return (false, null);
             }
         }
 
@@ -1635,7 +1632,7 @@ namespace TeamAAS_VP.Services
         /// 执行相机拍照并运行 ToolBlock,返回是否成功并通过 out 参数返回 Outputs。
         /// 该方法会发布 RenderUpdateNotification 以更新 UI。
         /// </summary>
-        public bool ExecutePhoto(ProcedureModel procedure, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection)
+        public async Task<(bool Success, CogToolBlockTerminalCollection OutputCollection)> ExecutePhotoAsync(ProcedureModel procedure, Dictionary<string, string> InputTerminal)
         {
             try
             {
@@ -1660,8 +1657,7 @@ namespace TeamAAS_VP.Services
                 {
 
                     SendTaskMessage(Lang.图像采集失败, MessageLevel.Error);
-                    outputCollection = null;
-                    return false;
+                    return (false, null);
                 }
                 procedure.ToolBlock.Inputs["InputImage"].Value = image;
                 LogHelper.WriteLogInfo($"采集图像完成;用时:{(DateTime.Now - nowtime).Milliseconds}ms");
@@ -1685,14 +1681,14 @@ namespace TeamAAS_VP.Services
                     }
                 }
 
-                // 3. 运行视觉工具
+                // 3. 运行视觉工具(在独立 STA 线程中异步执行,避免阻塞 UI 线程)
                 LogHelper.WriteLogInfo("开始运行视觉工具");
-                procedure.ToolBlock.Run();      //运行ToolBlock
+                await VisionProHelper.RunToolBlockAsync(procedure.ToolBlock);
 
                 if (procedure.ToolBlock.RunStatus.Result == CogToolResultConstants.Accept)
                 {
                     SendTaskMessage(Lang.视觉流程执行耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Info);
-                    outputCollection = procedure.ToolBlock.Outputs;     //获取输出终端集合
+                    var outputCollection = procedure.ToolBlock.Outputs;     //获取输出终端集合
                     DatabaseHelper.AddCameraRecords(_productService.GetCurrentProduct().Name, procedure.Name, outputCollection);
                     ICogRecord record = null;
                     foreach (CogToolBlockTerminal item in outputCollection)
@@ -1740,13 +1736,12 @@ namespace TeamAAS_VP.Services
                         ImageFileName = imgName,
                         Is3DModel = true
                     });
-                    return true;
+                    return (true, outputCollection);
                 }
                 else
                 {
                     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;
@@ -1783,15 +1778,14 @@ namespace TeamAAS_VP.Services
                         ImageFileName = imgName,
                         Is3DModel = true
                     });
-                    return false;
+                    return (false, null);
                 }
             }
             catch (Exception ex)
             {
                 SendTaskMessage(ex.Message, MessageLevel.Error);
                 LogHelper.WriteLogError("执行相机取图并执行视觉工具组时出错!", ex);
-                outputCollection = null;
-                return false;
+                return (false, null);
             }
         }
 
@@ -1800,7 +1794,7 @@ namespace TeamAAS_VP.Services
         /// 执行相机拍照并运行 ToolBlock,返回是否成功并通过 out 参数返回 Outputs。
         /// 该方法会发布 RenderUpdateNotification 以更新 UI。
         /// </summary>
-        public bool ExecutePhoto2(ProcedureModel procedure, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection)
+        public async Task<(bool Success, CogToolBlockTerminalCollection OutputCollection)> ExecutePhoto2Async(ProcedureModel procedure, Dictionary<string, string> InputTerminal)
         {
             try
             {
@@ -1825,8 +1819,7 @@ namespace TeamAAS_VP.Services
                 {
 
                     SendTaskMessage(Lang.图像采集失败, MessageLevel.Error);
-                    outputCollection = null;
-                    return false;
+                    return (false, null);
                 }
                 procedure.ToolBlock.Inputs["InputImage"].Value = image;
                 LogHelper.WriteLogInfo($"采集图像完成;用时:{(DateTime.Now - nowtime).Milliseconds}ms");
@@ -1851,14 +1844,14 @@ namespace TeamAAS_VP.Services
                     }
                 }
 
-                // 3. 运行视觉工具
+                // 3. 运行视觉工具(在独立 STA 线程中异步执行,避免阻塞 UI 线程)
                 LogHelper.WriteLogInfo("开始运行视觉工具");
-                procedure.ToolBlock.Run();      //运行ToolBlock
+                await VisionProHelper.RunToolBlockAsync(procedure.ToolBlock);
 
                 if (procedure.ToolBlock.RunStatus.Result == CogToolResultConstants.Accept)
                 {
                     SendTaskMessage(Lang.视觉流程执行耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Info);
-                    outputCollection = procedure.ToolBlock.Outputs;     //获取输出终端集合
+                    var outputCollection = procedure.ToolBlock.Outputs;     //获取输出终端集合
                     DatabaseHelper.AddCameraRecords(_productService.GetCurrentProduct().Name, procedure.Name, outputCollection);
                     ICogRecord record = null;
                     foreach (CogToolBlockTerminal item in outputCollection)
@@ -1905,13 +1898,12 @@ namespace TeamAAS_VP.Services
                         ImageFileName = imgName,
                         Is3DModel = false
                     });
-                    return true;
+                    return (true, outputCollection);
                 }
                 else
                 {
                     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;
@@ -1947,22 +1939,21 @@ namespace TeamAAS_VP.Services
                         ImageFileName = imgName,
                         Is3DModel = false
                     });
-                    return false;
+                    return (false, null);
                 }
             }
             catch (Exception ex)
             {
                 SendTaskMessage(ex.Message, MessageLevel.Error);
                 LogHelper.WriteLogError("执行相机取图并执行视觉工具组时出错!", ex);
-                outputCollection = null;
-                return false;
+                return (false, null);
             }
         }
         /// <summary>
         /// 执行相机拍照并运行 ToolBlock,返回是否成功并通过 out 参数返回 Outputs。
         /// 该方法会发布 RenderUpdateNotification 以更新 UI。
         /// </summary>
-        public bool ExecutePhoto(ProcedureModel procedure, ICogImage[] imges, Dictionary<string, string> InputTerminal, out CogToolBlockTerminalCollection outputCollection, bool is3dmodel, float confThreshold = 0.25f, float iouThreshold = 0.45f)
+        public async Task<(bool Success, CogToolBlockTerminalCollection OutputCollection)> ExecutePhotoAsync(ProcedureModel procedure, ICogImage[] imges, Dictionary<string, string> InputTerminal, bool is3dmodel, float confThreshold = 0.25f, float iouThreshold = 0.45f)
         {
             try
             {
@@ -2117,9 +2108,10 @@ namespace TeamAAS_VP.Services
                                 // 如果你希望模板也拿 YOLO 画框图,就用 yoloColorCogImage
                                 procedure.ToolBlock.Inputs["InputImage"].Value = yoloColorCogImage;
 
-                                procedure.ToolBlock.Run();
+                                // 在独立 STA 线程中异步执行 ToolBlock(AI 推理路径)
+                                await VisionProHelper.RunToolBlockAsync(procedure.ToolBlock);
 
-                                outputCollection = procedure.ToolBlock.Outputs;
+                                var outputCollection = procedure.ToolBlock.Outputs;
 
                                 ICogRecord record = null;
                                 foreach (CogToolBlockTerminal item in outputCollection)
@@ -2197,18 +2189,18 @@ namespace TeamAAS_VP.Services
                         }
                     }
 
-                    return true;
+                    return (true, null);
                 }
                 else
                 {
-                    // 3. 运行视觉工具
+                    // 3. 运行视觉工具(在独立 STA 线程中异步执行,避免阻塞 UI 线程)
                     LogHelper.WriteLogInfo("开始运行视觉工具");
-                    procedure.ToolBlock.Run();      //运行ToolBlock
+                    await VisionProHelper.RunToolBlockAsync(procedure.ToolBlock);
 
                     if (procedure.ToolBlock.RunStatus.Result == CogToolResultConstants.Accept)
                     {
                         SendTaskMessage(Lang.视觉流程执行耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Info);
-                        outputCollection = procedure.ToolBlock.Outputs;     //获取输出终端集合
+                        var outputCollection = procedure.ToolBlock.Outputs;     //获取输出终端集合
                         DatabaseHelper.AddCameraRecords(_productService.GetCurrentProduct().Name, procedure.Name, outputCollection);
                         ICogRecord record = null;
                         foreach (CogToolBlockTerminal item in outputCollection)
@@ -2375,13 +2367,13 @@ namespace TeamAAS_VP.Services
 
                             });
                         }
-                        return true;
+                        return (true, outputCollection);
                     }
                     else
                     {
                         SendTaskMessage(Lang.视觉流程执行出错耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Error);
                         SendTaskMessage(procedure.ToolBlock.RunStatus.Message, MessageLevel.Error);
-                        outputCollection = null;
+                        var outputCollection = procedure.ToolBlock.Outputs;
 
                         //获取图片存储的图片文件名
                         string imgName = string.Empty;
@@ -2484,7 +2476,7 @@ namespace TeamAAS_VP.Services
                                 Is3DModel = is3dmodel
                             });
                         }
-                        return false;
+                        return (false, outputCollection);
                     }
                 }
 
@@ -2493,8 +2485,7 @@ namespace TeamAAS_VP.Services
             {
                 SendTaskMessage(ex.Message, MessageLevel.Error);
                 LogHelper.WriteLogError("执行相机取图并执行视觉工具组时出错!", ex);
-                outputCollection = null;
-                return false;
+                return (false, null);
             }
         }
 
@@ -2776,7 +2767,7 @@ namespace TeamAAS_VP.Services
                     SendTaskMessage(Lang.开始执行视觉流程.Replace("{0}", $"{i + 1}").Replace("{1}", procedure.Name), MessageLevel.Info);
 
                     // 1. 执行相机拍照并运行视觉工具
-                    bool visionSucceed = ExecutePhoto(procedure, imges, InputTerminal, out CogToolBlockTerminalCollection outputCollection, is3dmodel, confThreshold, iouThreshold);
+                    var (visionSucceed, outputCollection) = await ExecutePhotoAsync(procedure, imges, InputTerminal, is3dmodel, confThreshold, iouThreshold);
                     if (!visionSucceed)
                     {
                         SendTaskMessage(Lang.视觉任务执行失败, MessageLevel.Error);
@@ -2856,7 +2847,7 @@ namespace TeamAAS_VP.Services
                     SendTaskMessage(Lang.开始执行视觉流程.Replace("{0}", $"{i + 1}").Replace("{1}", procedure.Name), MessageLevel.Info);
 
                     // 1. 执行相机拍照并运行视觉工具
-                    bool visionSucceed = ExecutePhoto2(procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection);
+                    var (visionSucceed, outputCollection) = await ExecutePhoto2Async(procedure, InputTerminal);
                     if (!visionSucceed)
                     {
                         SendTaskMessage(Lang.视觉任务执行失败, MessageLevel.Error);
@@ -2928,10 +2919,8 @@ 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 async Task<(bool Success, CogToolBlockTerminalCollection OutputCollection, ICogImage OutImage, CogGraphicCollection OutGraphicCollection)> ExecutePhotoExAsync(ProcedureModel procedure, Dictionary<string, string> InputTerminal)
         {
-            outImage = null;
-            outGraphicCollection = null;
             try
             {
 
@@ -2954,10 +2943,8 @@ namespace TeamAAS_VP.Services
                 {
 
                     SendTaskMessage(Lang.图像采集失败, MessageLevel.Error);
-                    outputCollection = null;
-                    return false;
+                    return (false, null, null, null);
                 }
-                outImage = image;
                 procedure.ToolBlock.Inputs["InputImage"].Value = image;
                 LogHelper.WriteLogInfo($"采集图像完成;用时:{(DateTime.Now - nowtime).Milliseconds}ms");
 
@@ -2980,14 +2967,14 @@ namespace TeamAAS_VP.Services
                     }
                 }
 
-                // 3. 运行视觉工具
+                // 3. 运行视觉工具(在独立 STA 线程中异步执行,避免阻塞 UI 线程)
                 LogHelper.WriteLogInfo("开始运行视觉工具");
-                procedure.ToolBlock.Run();      //运行ToolBlock
+                await VisionProHelper.RunToolBlockAsync(procedure.ToolBlock);
 
                 if (procedure.ToolBlock.RunStatus.Result == CogToolResultConstants.Accept)
                 {
                     SendTaskMessage(Lang.视觉流程执行耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Info);
-                    outputCollection = procedure.ToolBlock.Outputs;     //获取输出终端集合
+                    var outputCollection = procedure.ToolBlock.Outputs;     //获取输出终端集合
                     DatabaseHelper.AddCameraRecords(_productService.GetCurrentProduct().Name, procedure.Name, outputCollection);
                     ICogRecord record = null;
                     foreach (CogToolBlockTerminal item in outputCollection)
@@ -2995,24 +2982,23 @@ namespace TeamAAS_VP.Services
                         if (item.Value is ICogRecord)
                             record = item.Value as ICogRecord;
                     }
-                    outGraphicCollection = outputCollection["Graphic"].Value as CogGraphicCollection;
-                    return true;
+                    var outGraphicCollection = outputCollection["Graphic"].Value as CogGraphicCollection;
+                    return (true, outputCollection, image, outGraphicCollection);
                 }
                 else
                 {
                     SendTaskMessage(Lang.视觉流程执行出错耗时.Replace("{0}", procedure.Name).Replace("{1}", $"{procedure.ToolBlock.RunStatus.ProcessingTime:F1}"), MessageLevel.Error);
                     SendTaskMessage(procedure.ToolBlock.RunStatus.Message, MessageLevel.Error);
-                    outputCollection = null;
-                    outGraphicCollection = outputCollection["Graphic"].Value as CogGraphicCollection;
-                    return false;
+                    var outputCollection = procedure.ToolBlock.Outputs;
+                    var outGraphicCollection = outputCollection["Graphic"].Value as CogGraphicCollection;
+                    return (false, outputCollection, image, outGraphicCollection);
                 }
             }
             catch (Exception ex)
             {
                 SendTaskMessage(ex.Message, MessageLevel.Error);
                 LogHelper.WriteLogError("执行相机取图并执行视觉工具组时出错!", ex);
-                outputCollection = null;
-                return false;
+                return (false, null, null, null);
             }
         }
 
@@ -3037,7 +3023,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);
+                    var (visionSucceed, outputCollection) = await ExecutePhotoAsync(procedure, InputTerminal);
                     if (!visionSucceed)
                     {
                         SendTaskMessage(Lang.视觉任务执行失败, MessageLevel.Error);
@@ -3120,7 +3106,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);
+                    var (visionSucceed, outputCollection) = await ExecutePhotoAsync(procedure, InputTerminal);
                     if (!visionSucceed)
                     {
                         SendTaskMessage(Lang.视觉任务执行失败, MessageLevel.Error);
@@ -3213,7 +3199,9 @@ namespace TeamAAS_VP.Services
 
 
                     // 1. 执行相机拍照并运行视觉工具
-                    bool visionSucceed = ExecutePhotoEx(procedure, InputTerminal, out CogToolBlockTerminalCollection outputCollection, out outImage, out outGraphicCollection);
+                    bool visionSucceed;
+                    CogToolBlockTerminalCollection outputCollection;
+                    (visionSucceed, outputCollection, outImage, outGraphicCollection) = await ExecutePhotoExAsync(procedure, InputTerminal);
                     if (!visionSucceed)
                     {
                         SendTaskMessage(Lang.视觉任务执行失败, MessageLevel.Error);

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

@@ -595,6 +595,7 @@
     <Compile Include="Interfaces\IMesService.cs" />
     <Compile Include="Interfaces\IScanner.cs" />
     <Compile Include="Interfaces\IScannerService.cs" />
+    <Compile Include="Helpers\VisionProHelper.cs" />
     <Compile Include="Models\CTQ_Data.cs" />
     <Compile Include="Models\DataFormCtq.cs" />
     <Compile Include="Models\DeviceInfo.cs" />