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