using CsvHelper;
using CsvHelper.Configuration;
using FATrace.Com;
using FATrace.OEMApp.Model;
using NLog;
using System.Globalization;
using System.Text;
namespace FATrace.OEMApp.Services
{
public class CsvService
{
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
public CsvService()
{
RawUseCsvPath = ConfigHelper.GetValue("RawUseCsvPath");
}
///
/// 原料使用信息CSV文件路径
///
public string RawUseCsvPath { get; set; }
///
/// 将一条原料使用记录导出为单独CSV文件(包含表头)
/// 文件保存目录来自 RawUseCsvPath;文件名包含时间戳与内袋二维码(若有)
///
/// 原料使用记录
/// 生成的CSV完整路径
/// 当 data 为空时抛出
/// 当 RawUseCsvPath 未配置时抛出
/// 当写入文件失败时抛出
public string ExportSingle(RawUseCsvDto data)
{
if (data == null) throw new ArgumentNullException(nameof(data));
if (string.IsNullOrWhiteSpace(RawUseCsvPath))
{
const string msg = "RawUseCsvPath 未配置,无法导出CSV。";
_logger.Error(msg);
throw new InvalidOperationException(msg);
}
try
{
// 确保目录存在
Directory.CreateDirectory(RawUseCsvPath);
// 构建安全文件名:时间戳_内袋二维码.csv(若二维码为空则用RawUse代替)
var safeCode = SanitizeFileName(string.IsNullOrWhiteSpace(data.InBagCode) ? "RawUse" : data.InBagCode!.Trim());
var fileName = $"{safeCode}.csv";
var fullPath = Path.Combine(RawUseCsvPath, fileName);
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = true,
};
using (var writer = new StreamWriter(fullPath, false, new UTF8Encoding(encoderShouldEmitUTF8Identifier: true)))
using (var csv = new CsvWriter(writer, config))
{
csv.Context.RegisterClassMap();
csv.WriteHeader();
csv.NextRecord();
csv.WriteRecord(data);
csv.NextRecord();
}
_logger.Info($"CSV 导出成功: {fullPath}");
return fullPath;
}
catch (Exception ex)
{
_logger.Error(ex, "导出原料使用CSV失败。");
throw new IOException("导出原料使用CSV失败。", ex);
}
}
private static string SanitizeFileName(string name)
{
var invalid = Path.GetInvalidFileNameChars();
var sb = new StringBuilder(name.Length);
foreach (var ch in name)
{
sb.Append(invalid.Contains(ch) ? '_' : ch);
}
var result = sb.ToString();
return string.IsNullOrWhiteSpace(result) ? "RawUse" : result;
}
}
}