Files
CheckDevice/Check.Main/Dispatch/ProductManager.cs
2025-10-20 14:47:17 +08:00

245 lines
9.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
}