using System.Configuration;
using System.Data;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SparkClient.Model.Common;
using SparkClient.Model.Entity.ApiEntity;
using SparkClient.Model.Helper;
using SparkClient.Model.Services;
using SparkClient.ViewModel.BaseWindow;
using SparkClient.ViewModel.Configuration;
using SparkClient.Views.Dialog;
using SparkDotNetCore.DiamondScanner;
using SparkDotNetCore.DiamondScanner.Entity;
using MessageBox = SparkClient.Views.Dialog.MessageBox;
namespace SparkClient.ViewModel.Grading;
public class GradingLoadingVM : BaseViewModel,IDisposable
{
private double _progress;
private SOCClientService _socClientService;
public AlgorithmResultEntity Parameter;
///
/// 进度
///
public double Progress
{
get => _progress;
set
{
_progress = value;
OnPropertyChanged(nameof(Progress));
}
}
public ICommand StopCommand { get; }
private string _diamondCode;
private string _diamnondType;
private bool _disposed;
private CancellationTokenSource _progressCts;
private CancellationTokenSource? _playbackCts;
private Diamond _diamond;
private Scanner _scanner;
private CancellationTokenSource _completionCts;
#region 图片播放控制
private PlayStatus _currentStatus = PlayStatus.Stopped;
public PlayStatus CurrentStatus
{
get => _currentStatus;
set
{
_currentStatus = value;
OnPropertyChanged(nameof(CurrentStatus));
OnPropertyChanged(nameof(ButtonText)); // 状态变更时更新按钮文本
}
}
public string ButtonText => CurrentStatus switch
{
PlayStatus.Playing => MultilingualHelper.getString("GradingLoadingPaused"),
PlayStatus.Paused => MultilingualHelper.getString("GradingLoadingContinue"),
_ => MultilingualHelper.getString("GradingLoadingReplay") // Stopped 状态
};
private CancellationTokenSource _cts;
private int _playDelay = 100; // 默认播放速度
public ICommand PlayControlCommand { get; }
public ICommand PreviousCommand { get; }
public ICommand NextCommand { get; }
private int _currentIndex;
public int CurrentIndex
{
get => _currentIndex;
set
{
_currentIndex = value;
OnPropertyChanged(nameof(CurrentIndex));
UpdateCurrentImage();
}
}
public string[] ImagePaths { get; set; }
private ImageSource _currentImage;
public ImageSource CurrentImage
{
get => _currentImage;
private set
{
_currentImage = value;
OnPropertyChanged(nameof(CurrentImage));
}
}
private bool _imageIsEnable;
public bool ImageIsEnable
{
get => _imageIsEnable;
private set
{
_imageIsEnable = value;
OnPropertyChanged(nameof(ImageIsEnable)); // 触发通知
}
}
#endregion
public GradingLoadingVM(string diamnondType, string diamondCode)
{
_diamondCode = diamondCode;
_diamnondType = diamnondType;
StopCommand = new RelayCommand(Stop);
PlayControlCommand = new RelayCommand(async _ => await HandlePlayControl());
PreviousCommand = new RelayCommand(_ => MovePrevious());
NextCommand = new RelayCommand(_ => MoveNext());
ImageIsEnable = false;
_progressCts = new CancellationTokenSource();
_playbackCts = new CancellationTokenSource();
_completionCts = new CancellationTokenSource();
}
///
/// 开始检测
///
public async Task Start(int type = 0)
{
try
{
var progress = RunProgressAsync(_progressCts.Token);
if (type == 11)
{
JsonImport jsonImport = new JsonImport();
bool? a = jsonImport.ShowDialog();
if (a ?? false)
{
string fileName = jsonImport.FilePath.Text;
string[] lines = File.ReadAllLines(fileName);
StringBuilder stringBuilder = new StringBuilder();
foreach (var line in lines)
{
stringBuilder.Append(line);
}
Parameter = JsonConvert.DeserializeObject(stringBuilder.ToString());
await CompleteProgressQuicklyAsync();
return 0;
}
else
{
return -1;
}
}
if(type == 0){
_socClientService = new SOCClientService();
var processImage = _socClientService.ProcessImageCollectionAsync();
//通知页面可以播放图片
await processImage;
if (!("ok".Equals(processImage.Result.Status) || "S000".Equals(processImage.Result.Status)))
{
_progressCts.Cancel();
new MessageBox().Show(
MultilingualHelper.getString(StatusCodes.GetConstantNameByValue(processImage.Result.Status)));
return -1;
}
LoadImages(processImage.Result.Images);
}
if (type == 1)
{
List mnFiles = new List();
for (int i = 0; i < 100; i++)
{
mnFiles.Add($"{i}.bmp");
}
LoadImages(mnFiles);
}
ImageIsEnable = true;
StartPlayback();
Diamond diamond = new Diamond();
string circleSql = $"SELECT VALUE FROM CUTTER_CONFIG WHERE KEY = 'half_circle'";
DataTable circleTable = DataBaseHelper.ExecuteQuery(circleSql);
object halfCircleValue = circleTable.Rows[0][0];
bool.TryParse(halfCircleValue.ToString(), out bool boolResult);
bool half_circle = boolResult;
//算法配置参数,初始化算法配置数据并获取 AlgorithmConfigJson
var _algorithmConfigVM = new AlgorithmConfigVM();
_algorithmConfigVM.InitAlgorithmData(null);
string algo_config = _algorithmConfigVM.AlgorithmConfigJson;
//图片根目录
string? image_file_base_path = ConfigurationManager.AppSettings["ImageFileBasePath"];
if (string.IsNullOrEmpty(image_file_base_path))
{
throw new InvalidOperationException("ImageFileBasePath is not configured in AppSettings.");
}
// 获取 log4net 日志文件所在的目录
string? log4NetLogDirectory =
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
// 构建C++ DLL 日志文件路径
string algorithm_log_path = Path.Combine(log4NetLogDirectory, "logs");
// 将所有变量拼接成一个 JSON 对象
JObject jsonData = new JObject(
new JProperty("shape", _diamnondType.Split(" ")[0]),
new JProperty("shape_mode", _diamnondType.Split(" ")[1]),
new JProperty("image_file_base_path", image_file_base_path),
new JProperty("image_files", ImagePaths),
new JProperty("half_circle", half_circle),
new JProperty("algorithm_log_path", algorithm_log_path),
new JProperty("algo_config", JObject.Parse(algo_config))
);
_scanner = new Scanner(diamond);
var detectTask = _scanner.DetectAsyncByJsonStr(jsonData.ToString());
await detectTask;
if (detectTask.Status == TaskStatus.RanToCompletion)
{
return ReslutGen(detectTask);
}
await progress;
return ReslutGen(detectTask);
}
catch(Exception ex)
{
return -100;
}
}
private int ReslutGen(Task detectTask)
{
CompleteProgressQuicklyAsync();
switch (detectTask.Result.Status)
{
case StatusCodes.AlgorithmFailed:
new MessageBox().Show(MultilingualHelper.getString("AlgorithmFailed"));
return -1;
case StatusCodes.ImageFileReadFailure:
new MessageBox().Show(MultilingualHelper.getString("ImageFileReadFailure"));
return -1;
case StatusCodes.JsonParseFailure:
new MessageBox().Show(MultilingualHelper.getString("JsonParseFailure"));
return -1;
case StatusCodes.NoDiamond:
new MessageBox().Show(MultilingualHelper.getString("NoDiamond"));
return -1;
}
Progress = 100;
string strParam = JsonConvert.SerializeObject(detectTask.Result);
AlgorithmResultEntity parameter = JsonConvert.DeserializeObject(strParam);
if (parameter == null)
{
new MessageBox().Show(MultilingualHelper.getString("JsonParseFailure"));
return -1;
}
try
{
string parameterJson = JsonConvert.SerializeObject(parameter);
parameterJson = JToken.Parse(parameterJson).ToString();
string outputPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", "result");
if (!Directory.Exists(outputPath))
Directory.CreateDirectory(outputPath);
string outputFilePath = $"{outputPath}/{_diamondCode}-{DateTime.Now:yyyyMMdd_HHmmss}.json";
using (var file = File.Create(outputFilePath))
using (StreamWriter stream = new StreamWriter(file))
{
stream.Write(parameterJson);
}
}
catch (Exception ex)
{
Logger.Error("output输出失败:" + ex.Message);
}
Parameter = parameter;
return 0;
}
private async Task CompleteProgressSlowlyAsync()
{
// 缓慢完成剩余3%(总耗时保持原速度的3倍)
const int remainingSteps = 3;
int stepTime = 500; // 自定义慢速步长
int current = (int)Progress;
for (int i = 1; i <= remainingSteps; i++)
{
if (_progressCts.IsCancellationRequested) break;
UpdateProgress(current + i);
await Task.Delay(stepTime);
}
}
private async Task CompleteProgressQuicklyAsync()
{
// 取消原进度任务
_progressCts.Cancel();
// 快速完成剩余进度(0.5秒内完成)
int current = (int)Progress;
int remaining = 100 - current;
if (remaining <= 0) return;
int stepTime = Math.Max(50, 500 / remaining); // 动态计算步长
while (current < 100)
{
current = Math.Min(current + 1, 100);
UpdateProgress(current);
await Task.Delay(stepTime);
}
}
private void UpdateProgress(int value)
{
// UI线程安全更新
Application.Current.Dispatcher.Invoke(() =>
{
Progress = value;
});
}
private void Stop(object param)
{
//询问?停止:忽略
try
{
MessageBox messageBox = new MessageBox();
MessageBoxResult showAsk = messageBox.ShowAsk(MultilingualHelper.getString("GradingLoadingStopAsk"));
if (showAsk == MessageBoxResult.OK)
{
WindowManager.mainViewModel.Content = WindowManager.PreviousVM();
_scanner?.Cancel();
_progressCts.Cancel();
this.Dispose();
}
}
catch (Exception ex)
{
}
}
private async Task RunProgressAsync(CancellationToken token)
{
var configValue = ConfigurationHelper.ReadConfigValue("ProgressTime");
int totalDuration = int.TryParse(configValue, out var result) ? result : 50000;
int stepTime = totalDuration / 97;
// 使用 IProgress 实现线程安全的进度报告
var progress = new Progress(value =>
{
if (!token.IsCancellationRequested)
Progress = value;
});
await Task.Run(async () =>
{
for (int i = 0; i <= 97; i++)
{
token.ThrowIfCancellationRequested();
// 报告进度
((IProgress)progress).Report(i);
// 使用可取消的延迟
await Task.Delay(stepTime, token);
}
}, token);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing)
{
// 取消所有操作
_progressCts?.Cancel();
_playbackCts?.Cancel();
// 释放托管资源
_progressCts?.Dispose();
_playbackCts?.Dispose();
}
_disposed = true;
}
#region 图片播放处理
public void LoadImages(string folderPath)
{
ImagePaths = Directory.GetFiles(folderPath, "*.bmp");
CurrentIndex = 0;
CurrentStatus = PlayStatus.Stopped;
}
public void LoadImages(List folderPath)
{
ImagePaths = folderPath.ToArray();
CurrentIndex = 0;
CurrentStatus = PlayStatus.Stopped;
}
private async Task HandlePlayControl()
{
switch (CurrentStatus)
{
case PlayStatus.Stopped:
await StartPlayback(); // 开始或重播
break;
case PlayStatus.Playing:
PausePlayback(); // 暂停
break;
case PlayStatus.Paused:
await ResumePlayback();// 继续
break;
}
}
private async Task StartPlayback()
{
CurrentStatus = PlayStatus.Playing;
_cts = new CancellationTokenSource();
try
{
for (CurrentIndex = 0; CurrentIndex < ImagePaths.Length; CurrentIndex++)
{
if (_cts.Token.IsCancellationRequested) break;
await Task.Delay(_playDelay);
}
// 播放完成处理
if (CurrentIndex >= ImagePaths.Length)
{
CurrentStatus = PlayStatus.Stopped;
CurrentIndex = 0; // 重置为初始位置
}
}
catch (TaskCanceledException) { /* 正常取消处理 */ }
}
private void PausePlayback()
{
_cts?.Cancel();
CurrentStatus = PlayStatus.Paused;
}
private async Task ResumePlayback()
{
CurrentStatus = PlayStatus.Playing;
_cts = new CancellationTokenSource();
await StartPlayback();
}
private void UpdateCurrentImage()
{
if (ImagePaths == null || CurrentIndex < 0 || CurrentIndex >= ImagePaths.Length)
return;
string? savePath = ConfigurationManager.AppSettings["ImageFileBasePath"];
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.UriSource = new Uri(savePath + @"\" + ImagePaths[CurrentIndex]);
bitmap.EndInit();
bitmap.Freeze(); // 确保跨线程安全#
CurrentImage = bitmap;
OnPropertyChanged(nameof(CurrentImage));
}
private void MovePrevious()
{
if (CurrentStatus == PlayStatus.Playing)
PausePlayback();
CurrentIndex = (CurrentIndex - 1 + ImagePaths.Length) % ImagePaths.Length;
}
private void MoveNext()
{
if (CurrentStatus == PlayStatus.Playing)
PausePlayback();
CurrentIndex = (CurrentIndex + 1) % ImagePaths.Length;
}
#endregion
}
public enum PlayStatus
{
Stopped, // 初始/停止状态
Playing, // 播放中
Paused // 暂停中
}