245 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| 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
 | ||
|     }
 | ||
| }
 |