Laservall_solidworks_inject/Server/Handlers/ExportHandler.cs

119 lines
4.6 KiB
C#
Raw Normal View History

using Laservall.Solidworks.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Laservall.Solidworks.Server.Handlers
{
internal sealed class ExportHandler
{
private readonly Func<BomLoadResult> _getLastResult;
private readonly IBomDataProvider _dataProvider;
public ExportHandler(Func<BomLoadResult> getLastResult, IBomDataProvider dataProvider)
{
_getLastResult = getLastResult;
_dataProvider = dataProvider;
}
public async Task HandleExport(HttpListenerContext context, CancellationToken ct)
{
var result = _getLastResult();
if (result == null || result.Items == null || result.Items.Count == 0)
{
context.Response.StatusCode = 404;
byte[] err = Encoding.UTF8.GetBytes("{\"error\":\"No BOM data loaded\"}");
context.Response.ContentType = "application/json; charset=utf-8";
context.Response.ContentLength64 = err.Length;
await context.Response.OutputStream.WriteAsync(err, 0, err.Length, ct);
context.Response.Close();
return;
}
bool isFlatView = context.Request.QueryString["flat"] == "true";
var items = isFlatView ? _dataProvider.GetFlatBomItems(result.Items) : result.Items;
var settings = result.Settings;
var csv = BuildCsv(items, result.DynamicKeys, settings, isFlatView);
// UTF-8 BOM for Excel compatibility
byte[] bom = new byte[] { 0xEF, 0xBB, 0xBF };
byte[] csvBytes = Encoding.UTF8.GetBytes(csv);
byte[] body = new byte[bom.Length + csvBytes.Length];
Buffer.BlockCopy(bom, 0, body, 0, bom.Length);
Buffer.BlockCopy(csvBytes, 0, body, bom.Length, csvBytes.Length);
context.Response.StatusCode = 200;
context.Response.ContentType = "text/csv; charset=utf-8";
context.Response.Headers.Set("Content-Disposition", "attachment; filename=\"BOM_Export.csv\"");
context.Response.ContentLength64 = body.Length;
await context.Response.OutputStream.WriteAsync(body, 0, body.Length, ct);
context.Response.Close();
}
private static string BuildCsv(
List<BomItemModel> items,
List<string> dynamicKeys,
BomSettings settings,
bool isFlatView)
{
var builtInDefs = new List<(string Name, Func<BomItemModel, string> Getter)>
{
("层级", item => item.LevelDisplay ?? ""),
("图号", item => item.DrawingNo ?? ""),
("零件名称", item => item.ConfigName ?? ""),
("属性", item => item.Classification ?? ""),
("材料", item => item.MaterialProp ?? ""),
("材质", item => item.Material ?? ""),
("数量", item => item.Quantity.ToString()),
("装配体", item => item.IsAssembly ? "是" : "否"),
("外购件", item => item.IsOutSourcing ? "是" : "否")
};
var exportBuiltIns = builtInDefs
.Where(d => settings.IsColumnExport(d.Name))
.Where(d => !isFlatView || (d.Name != "层级" && d.Name != "装配体"))
.ToList();
var exportDynamicKeys = (dynamicKeys ?? new List<string>())
.Where(k => settings.IsColumnExport(k))
.ToList();
var sb = new StringBuilder();
var headers = exportBuiltIns.Select(d => d.Name).Concat(exportDynamicKeys).ToList();
sb.AppendLine(string.Join(",", headers.Select(EscapeCsvField)));
foreach (var item in items)
{
var fields = new List<string>();
foreach (var def in exportBuiltIns)
{
fields.Add(def.Getter(item));
}
foreach (var key in exportDynamicKeys)
{
fields.Add(item.GetProp(key));
}
sb.AppendLine(string.Join(",", fields.Select(EscapeCsvField)));
}
return sb.ToString();
}
private static string EscapeCsvField(string field)
{
if (string.IsNullOrEmpty(field)) return "";
if (field.Contains(",") || field.Contains("\"") || field.Contains("\n"))
{
return "\"" + field.Replace("\"", "\"\"") + "\"";
}
return field;
}
}
}