10.20PLC+相机2.3视觉修改

This commit is contained in:
17860779768
2025-08-25 16:33:58 +08:00
committed by Maikouce China
commit dca4b2afac
52 changed files with 11698 additions and 0 deletions

View File

@@ -0,0 +1,244 @@
using Check.Main.Common;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
namespace Check.Main.Dispatch
{
public static class ProductManager
{
private static readonly string _productRootPath = Path.Combine(Application.StartupPath, "Product");
private static readonly string _productListFilePath = Path.Combine(Application.StartupPath, "products.json");
// --- 公共属性和事件 ---
public static List<string> ProductList { get; private set; } = new List<string>();
public static string CurrentProductName { get; private set; }
public static ProcessConfig CurrentConfig { get; private set; }
/// <summary>
/// 当产品切换或配置加载后触发。
/// </summary>
public static event Action OnProductChanged;
/// <summary>
/// 静态构造函数,在程序启动时自动执行。
/// </summary>
static ProductManager()
{
Directory.CreateDirectory(_productRootPath); // 确保Product文件夹存在
LoadProductList();
// 默认加载列表中的第一个产品,或者创建一个默认的
SwitchToProduct(ProductList.FirstOrDefault() ?? "DefaultProduct");
}
/// <summary>
/// 切换到指定的产品,并加载其配置。
/// </summary>
public static bool SwitchToProduct(string productName)
{
if (string.IsNullOrWhiteSpace(productName)) return false;
ThreadSafeLogger.Log($"正在切换到产品: {productName}");
var config = LoadConfigForProduct(productName);
if (config == null)
{
// 如果加载失败(例如新创建的产品还没有配置文件),则创建一个新的
config = new ProcessConfig();
}
CurrentProductName = productName;
CurrentConfig = config;
// 广播产品已变更的通知
OnProductChanged?.Invoke();
return true;
}
/// <summary>
/// 添加一个新产品。
/// </summary>
public static bool AddNewProduct(string newProductName)
{
if (string.IsNullOrWhiteSpace(newProductName) || ProductList.Contains(newProductName))
{
return false; // 名称无效或已存在
}
// 创建一个全新的、空的配置
var newConfig = new ProcessConfig();
// 保存这个新产品的空配置,这也会创建文件夹
if (SaveConfigForProduct(newProductName, newConfig))
{
ProductList.Add(newProductName);
SaveProductList(); // 更新产品列表文件
SwitchToProduct(newProductName); // 创建后立即切换到新产品
return true;
}
return false;
}
/// <summary>
/// 删除指定的产品及其所有相关配置。
/// </summary>
/// <param name="productNameToDelete">要删除的产品名称。</param>
/// <returns>成功删除返回 true否则返回 false。</returns>
public static bool DeleteProduct(string productNameToDelete)
{
if (string.IsNullOrWhiteSpace(productNameToDelete) || !ProductList.Contains(productNameToDelete))
{
ThreadSafeLogger.Log($"[警告] 尝试删除一个不存在的产品: {productNameToDelete}");
return false; // 产品不存在
}
ThreadSafeLogger.Log($"正在删除产品: {productNameToDelete}...");
try
{
// 1. 从产品列表中移除
ProductList.Remove(productNameToDelete);
SaveProductList(); // 更新列表文件
// 2. 删除对应的配置文件夹
var safeFolderName = GetSafeFolderName(productNameToDelete);
var productDir = Path.Combine(_productRootPath, safeFolderName);
if (Directory.Exists(productDir))
{
Directory.Delete(productDir, true); // true 表示递归删除所有子文件和子文件夹
}
ThreadSafeLogger.Log($"产品 '{productNameToDelete}' 已成功删除。");
// 3. 如果被删除的是当前活动产品,则需要切换到一个新的有效产品
if (CurrentProductName == productNameToDelete)
{
// 切换到列表中的第一个产品,或者如果列表为空,则创建一个默认产品
string nextProduct = ProductList.FirstOrDefault() ?? "DefaultProduct";
SwitchToProduct(nextProduct);
}
else
{
// 如果删除的不是当前产品,我们仍然需要触发一次事件,
// 以便UI主要是下拉列表能够刷新它的数据源。
OnProductChanged?.Invoke();
}
return true;
}
catch (Exception ex)
{
ThreadSafeLogger.Log($"[错误] 删除产品 '{productNameToDelete}' 失败: {ex.Message}");
// 如果出错,最好把刚删除的项加回来,保持状态一致性
if (!ProductList.Contains(productNameToDelete))
{
ProductList.Add(productNameToDelete);
}
return false;
}
}
/// <summary>
/// 为当前产品保存更改。
/// </summary>
public static void SaveCurrentProductConfig()
{
if (CurrentConfig != null && !string.IsNullOrWhiteSpace(CurrentProductName))
{
SaveConfigForProduct(CurrentProductName, CurrentConfig);
}
}
#region
private static void LoadProductList()
{
try
{
if (File.Exists(_productListFilePath))
{
var json = File.ReadAllText(_productListFilePath);
ProductList = JsonConvert.DeserializeObject<List<string>>(json) ?? new List<string>();
}
}
catch (Exception ex)
{
ThreadSafeLogger.Log($"[错误] 加载产品列表失败: {ex.Message}");
ProductList = new List<string>();
}
}
private static void SaveProductList()
{
try
{
var json = JsonConvert.SerializeObject(ProductList, Newtonsoft.Json.Formatting.Indented);
File.WriteAllText(_productListFilePath, json);
}
catch (Exception ex)
{
ThreadSafeLogger.Log($"[错误] 保存产品列表失败: {ex.Message}");
}
}
private static ProcessConfig LoadConfigForProduct(string productName)
{
var safeFolderName = GetSafeFolderName(productName);
var configPath = Path.Combine(_productRootPath, safeFolderName, "config.xml");
if (!File.Exists(configPath)) return null;
try
{
XmlSerializer serializer = new XmlSerializer(typeof(ProcessConfig));
using (var fs = new FileStream(configPath, FileMode.Open, FileAccess.Read))
{
return (ProcessConfig)serializer.Deserialize(fs);
}
}
catch (Exception ex)
{
ThreadSafeLogger.Log($"[错误] 加载产品 '{productName}' 的配置失败: {ex.Message}");
return null;
}
}
private static bool SaveConfigForProduct(string productName, ProcessConfig config)
{
try
{
var safeFolderName = GetSafeFolderName(productName);
var productDir = Path.Combine(_productRootPath, safeFolderName);
Directory.CreateDirectory(productDir); // 确保文件夹存在
var configPath = Path.Combine(productDir, "config.xml");
XmlSerializer serializer = new XmlSerializer(typeof(ProcessConfig));
using (var fs = new FileStream(configPath, FileMode.Create, FileAccess.Write))
{
serializer.Serialize(fs, config);
}
return true;
}
catch (Exception ex)
{
ThreadSafeLogger.Log($"[错误] 保存产品 '{productName}' 的配置失败: {ex.Message}");
return false;
}
}
private static string GetSafeFolderName(string productName)
{
// 移除所有不适合做文件夹名称的字符
string invalidChars = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
Regex r = new Regex(string.Format("[{0}]", Regex.Escape(invalidChars)));
return r.Replace(productName, "");
}
#endregion
}
}