|
|
@@ -46,9 +46,30 @@ namespace TeamAAS_VP.Views.Home
|
|
|
private readonly Prism.Services.Dialogs.IDialogService _dialogService;
|
|
|
|
|
|
private CancellationTokenSource _saveImageCts = new CancellationTokenSource();
|
|
|
+ private readonly object _saveImageCtsLock = new object();
|
|
|
private readonly SemaphoreSlim _saveSemaphore = new SemaphoreSlim(5, 5);
|
|
|
private List<Models.DelaySaveImage> delaySaveImages = new List<Models.DelaySaveImage>();
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 安全获取有效的 CancellationToken。如果当前 CTS 已释放则自动创建新的。
|
|
|
+ /// </summary>
|
|
|
+ private CancellationToken GetSafeSaveToken()
|
|
|
+ {
|
|
|
+ lock (_saveImageCtsLock)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var token = _saveImageCts.Token;
|
|
|
+ return token;
|
|
|
+ }
|
|
|
+ catch (ObjectDisposedException)
|
|
|
+ {
|
|
|
+ _saveImageCts = new CancellationTokenSource();
|
|
|
+ return _saveImageCts.Token;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public ShowVisionRender()
|
|
|
{
|
|
|
InitializeComponent();
|
|
|
@@ -648,13 +669,19 @@ namespace TeamAAS_VP.Views.Home
|
|
|
{
|
|
|
if (render == null) return;
|
|
|
if (disp == null) return;
|
|
|
- if (!render.IsSaveImage) return;
|
|
|
+ if (!render.IsSaveImage)
|
|
|
+ {
|
|
|
+ LogHelper.WriteLogInfo($"[SAVE-IMAGE] 跳过保存: IsSaveImage=false, Id={render.Id}, DisplayName={render.DisplayName}");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ LogHelper.WriteLogInfo($"[SAVE-IMAGE] 开始保存流程: Id={render.Id}, SaveModel={render.SaveImageModel}, SavePath={render.SavePath}, IsDelay={render.IsDelaySaveImage}, ProductCode={_productService.CurrentProductCode}");
|
|
|
|
|
|
bool needRecordedBitmap =
|
|
|
render.SaveImageModel == ProcedureSaveImageModel.Recorded ||
|
|
|
render.SaveImageModel == ProcedureSaveImageModel.OriginalAndRecorded;
|
|
|
|
|
|
- var token = _saveImageCts.Token;
|
|
|
+ var token = GetSafeSaveToken();
|
|
|
|
|
|
disp.BeginInvoke(new Action(() =>
|
|
|
{
|
|
|
@@ -773,11 +800,14 @@ namespace TeamAAS_VP.Views.Home
|
|
|
{
|
|
|
if (string.IsNullOrEmpty(path) || string.IsNullOrWhiteSpace(path) || !Path.IsPathRooted(path))
|
|
|
{
|
|
|
+ LogHelper.WriteLogInfo($"[SAVE-IMAGE] 保存失败:路径无效 path=\"{path}\"");
|
|
|
_eventAggregator.GetEvent<TaskMessageNotification>()
|
|
|
.Publish(new Models.MessageStruct() { Message = "保存图像路径为无效的路径!", level = MessageLevel.Alarm });
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ LogHelper.WriteLogInfo($"[SAVE-IMAGE] SaveImageAsync 开始: path={path}, model={saveImageModel}, pathModel={saveImagePathModel}, result={result}, is3D={is3Dmodel}, fileName={imageFileName}");
|
|
|
+
|
|
|
try
|
|
|
{
|
|
|
await Task.CompletedTask; // 消除 CS1998:调用者已在后台线程,下方所有 I/O 为同步执行
|
|
|
@@ -1000,7 +1030,7 @@ namespace TeamAAS_VP.Views.Home
|
|
|
catch (OperationCanceledException) { }
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
- LogHelper.WriteLogError("保存流程运行结果的图片时出错!", ex);
|
|
|
+ LogHelper.WriteLogError($"[SAVE-IMAGE] 保存流程运行结果的图片时出错!path={path}", ex);
|
|
|
}
|
|
|
finally
|
|
|
{
|
|
|
@@ -1034,7 +1064,7 @@ namespace TeamAAS_VP.Views.Home
|
|
|
delaySaveImages.Clear();
|
|
|
}
|
|
|
|
|
|
- var token = _saveImageCts.Token;
|
|
|
+ var token = GetSafeSaveToken();
|
|
|
foreach (var item in itemsToSave)
|
|
|
{
|
|
|
try
|