Compare commits
5 Commits
c9a8442a29
...
5b996be91e
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b996be91e | |||
| 6bddbff08e | |||
| 1ec72bc98f | |||
| b122b88435 | |||
| b677ac8ec9 |
@@ -4,9 +4,9 @@ namespace ExportDXF
|
|||||||
{
|
{
|
||||||
public class DrawingInfo
|
public class DrawingInfo
|
||||||
{
|
{
|
||||||
private static Regex drawingFormatRegex = new Regex(@"(?<jobNo>[345]\d{3}(-\d+\w{1,2})?)\s?(?<dwgNo>[ABEP]\d+(-?(\d+[A-Z]?))?)", RegexOptions.IgnoreCase);
|
private static Regex drawingFormatRegex = new Regex(@"(?<equipmentNo>[345]\d{3}(-\d+\w{1,2})?)\s?(?<dwgNo>[ABEP]\d+(-?(\d+[A-Z]?))?)", RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
public string JobNo { get; set; }
|
public string EquipmentNo { get; set; }
|
||||||
|
|
||||||
public string DrawingNo { get; set; }
|
public string DrawingNo { get; set; }
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ namespace ExportDXF
|
|||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{JobNo} {DrawingNo}";
|
return $"{EquipmentNo} {DrawingNo}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
@@ -39,7 +39,7 @@ namespace ExportDXF
|
|||||||
|
|
||||||
var dwg = new DrawingInfo();
|
var dwg = new DrawingInfo();
|
||||||
|
|
||||||
dwg.JobNo = match.Groups["jobNo"].Value;
|
dwg.EquipmentNo = match.Groups["equipmentNo"].Value;
|
||||||
dwg.DrawingNo = match.Groups["dwgNo"].Value;
|
dwg.DrawingNo = match.Groups["dwgNo"].Value;
|
||||||
dwg.Source = input;
|
dwg.Source = input;
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<PublisherName>Rogers Engineering</PublisherName>
|
<PublisherName>Rogers Engineering</PublisherName>
|
||||||
<CreateWebPageOnPublish>true</CreateWebPageOnPublish>
|
<CreateWebPageOnPublish>true</CreateWebPageOnPublish>
|
||||||
<WebPage>publish.htm</WebPage>
|
<WebPage>publish.htm</WebPage>
|
||||||
<ApplicationRevision>7</ApplicationRevision>
|
<ApplicationRevision>8</ApplicationRevision>
|
||||||
<ApplicationVersion>1.6.0.%2a</ApplicationVersion>
|
<ApplicationVersion>1.6.0.%2a</ApplicationVersion>
|
||||||
<UseApplicationTrust>false</UseApplicationTrust>
|
<UseApplicationTrust>false</UseApplicationTrust>
|
||||||
<PublishWizardCompleted>true</PublishWizardCompleted>
|
<PublishWizardCompleted>true</PublishWizardCompleted>
|
||||||
@@ -70,6 +70,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="PresentationCore" />
|
<Reference Include="PresentationCore" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.IO.Compression" />
|
||||||
|
<Reference Include="System.IO.Compression.FileSystem" />
|
||||||
<Reference Include="SolidWorks.Interop.sldworks, Version=24.1.0.45, Culture=neutral, PublicKeyToken=7c4797c3e4eeac03, processorArchitecture=MSIL">
|
<Reference Include="SolidWorks.Interop.sldworks, Version=24.1.0.45, Culture=neutral, PublicKeyToken=7c4797c3e4eeac03, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||||
@@ -85,6 +88,7 @@
|
|||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.Security" />
|
<Reference Include="System.Security" />
|
||||||
|
<Reference Include="System.Web.Extensions" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -119,6 +123,7 @@
|
|||||||
<Compile Include="Services\BomExcelSettings.cs" />
|
<Compile Include="Services\BomExcelSettings.cs" />
|
||||||
<Compile Include="Services\DrawingExporter.cs" />
|
<Compile Include="Services\DrawingExporter.cs" />
|
||||||
<Compile Include="Services\DxfExportService.cs" />
|
<Compile Include="Services\DxfExportService.cs" />
|
||||||
|
<Compile Include="Services\CutFabApiClient.cs" />
|
||||||
<Compile Include="Services\PartExporter.cs" />
|
<Compile Include="Services\PartExporter.cs" />
|
||||||
<Compile Include="Services\SolidWorksService.cs" />
|
<Compile Include="Services\SolidWorksService.cs" />
|
||||||
<Compile Include="Utilities\SheetMetalProperties.cs" />
|
<Compile Include="Utilities\SheetMetalProperties.cs" />
|
||||||
|
|||||||
98
ExportDXF/Forms/MainForm.Designer.cs
generated
98
ExportDXF/Forms/MainForm.Designer.cs
generated
@@ -31,11 +31,13 @@
|
|||||||
this.activeDocTitleBox = new System.Windows.Forms.TextBox();
|
this.activeDocTitleBox = new System.Windows.Forms.TextBox();
|
||||||
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
|
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
|
||||||
this.label1 = new System.Windows.Forms.Label();
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
this.label2 = new System.Windows.Forms.Label();
|
|
||||||
this.prefixTextBox = new System.Windows.Forms.TextBox();
|
|
||||||
this.button1 = new System.Windows.Forms.Button();
|
this.button1 = new System.Windows.Forms.Button();
|
||||||
this.label3 = new System.Windows.Forms.Label();
|
this.label3 = new System.Windows.Forms.Label();
|
||||||
this.comboBox1 = new System.Windows.Forms.ComboBox();
|
this.comboBox1 = new System.Windows.Forms.ComboBox();
|
||||||
|
this.label4 = new System.Windows.Forms.Label();
|
||||||
|
this.equipmentNoBox = new System.Windows.Forms.ComboBox();
|
||||||
|
this.label5 = new System.Windows.Forms.Label();
|
||||||
|
this.comboBox2 = new System.Windows.Forms.ComboBox();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
// activeDocTitleBox
|
// activeDocTitleBox
|
||||||
@@ -46,8 +48,8 @@
|
|||||||
this.activeDocTitleBox.Location = new System.Drawing.Point(130, 13);
|
this.activeDocTitleBox.Location = new System.Drawing.Point(130, 13);
|
||||||
this.activeDocTitleBox.Name = "activeDocTitleBox";
|
this.activeDocTitleBox.Name = "activeDocTitleBox";
|
||||||
this.activeDocTitleBox.ReadOnly = true;
|
this.activeDocTitleBox.ReadOnly = true;
|
||||||
this.activeDocTitleBox.Size = new System.Drawing.Size(584, 25);
|
this.activeDocTitleBox.Size = new System.Drawing.Size(748, 25);
|
||||||
this.activeDocTitleBox.TabIndex = 2;
|
this.activeDocTitleBox.TabIndex = 1;
|
||||||
this.activeDocTitleBox.TextChanged += new System.EventHandler(this.activeDocTitleBox_TextChanged);
|
this.activeDocTitleBox.TextChanged += new System.EventHandler(this.activeDocTitleBox_TextChanged);
|
||||||
//
|
//
|
||||||
// richTextBox1
|
// richTextBox1
|
||||||
@@ -59,8 +61,8 @@
|
|||||||
this.richTextBox1.Location = new System.Drawing.Point(12, 106);
|
this.richTextBox1.Location = new System.Drawing.Point(12, 106);
|
||||||
this.richTextBox1.Name = "richTextBox1";
|
this.richTextBox1.Name = "richTextBox1";
|
||||||
this.richTextBox1.ReadOnly = true;
|
this.richTextBox1.ReadOnly = true;
|
||||||
this.richTextBox1.Size = new System.Drawing.Size(754, 342);
|
this.richTextBox1.Size = new System.Drawing.Size(866, 556);
|
||||||
this.richTextBox1.TabIndex = 3;
|
this.richTextBox1.TabIndex = 10;
|
||||||
this.richTextBox1.Text = "";
|
this.richTextBox1.Text = "";
|
||||||
//
|
//
|
||||||
// label1
|
// label1
|
||||||
@@ -69,72 +71,92 @@
|
|||||||
this.label1.Location = new System.Drawing.Point(13, 16);
|
this.label1.Location = new System.Drawing.Point(13, 16);
|
||||||
this.label1.Name = "label1";
|
this.label1.Name = "label1";
|
||||||
this.label1.Size = new System.Drawing.Size(111, 17);
|
this.label1.Size = new System.Drawing.Size(111, 17);
|
||||||
this.label1.TabIndex = 4;
|
this.label1.TabIndex = 0;
|
||||||
this.label1.Text = "Active document :";
|
this.label1.Text = "Active document :";
|
||||||
//
|
//
|
||||||
// label2
|
|
||||||
//
|
|
||||||
this.label2.AutoSize = true;
|
|
||||||
this.label2.Location = new System.Drawing.Point(23, 47);
|
|
||||||
this.label2.Name = "label2";
|
|
||||||
this.label2.Size = new System.Drawing.Size(101, 17);
|
|
||||||
this.label2.TabIndex = 4;
|
|
||||||
this.label2.Text = "Prefix files with :";
|
|
||||||
//
|
|
||||||
// prefixTextBox
|
|
||||||
//
|
|
||||||
this.prefixTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
|
||||||
| System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.prefixTextBox.Location = new System.Drawing.Point(130, 44);
|
|
||||||
this.prefixTextBox.Name = "prefixTextBox";
|
|
||||||
this.prefixTextBox.Size = new System.Drawing.Size(584, 25);
|
|
||||||
this.prefixTextBox.TabIndex = 2;
|
|
||||||
//
|
|
||||||
// button1
|
// button1
|
||||||
//
|
//
|
||||||
this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
this.button1.Image = global::ExportDXF.Properties.Resources.play;
|
this.button1.Image = global::ExportDXF.Properties.Resources.play;
|
||||||
this.button1.Location = new System.Drawing.Point(720, 13);
|
this.button1.Location = new System.Drawing.Point(884, 13);
|
||||||
this.button1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
this.button1.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
this.button1.Name = "button1";
|
this.button1.Name = "button1";
|
||||||
this.button1.Size = new System.Drawing.Size(46, 56);
|
this.button1.Size = new System.Drawing.Size(46, 56);
|
||||||
this.button1.TabIndex = 0;
|
this.button1.TabIndex = 11;
|
||||||
this.button1.UseVisualStyleBackColor = true;
|
this.button1.UseVisualStyleBackColor = true;
|
||||||
this.button1.Click += new System.EventHandler(this.button1_Click);
|
this.button1.Click += new System.EventHandler(this.button1_Click);
|
||||||
//
|
//
|
||||||
// label3
|
// label3
|
||||||
//
|
//
|
||||||
this.label3.AutoSize = true;
|
this.label3.AutoSize = true;
|
||||||
this.label3.Location = new System.Drawing.Point(12, 78);
|
this.label3.Location = new System.Drawing.Point(12, 47);
|
||||||
this.label3.Name = "label3";
|
this.label3.Name = "label3";
|
||||||
this.label3.Size = new System.Drawing.Size(112, 17);
|
this.label3.Size = new System.Drawing.Size(112, 17);
|
||||||
this.label3.TabIndex = 4;
|
this.label3.TabIndex = 2;
|
||||||
this.label3.Text = "View flip decider :";
|
this.label3.Text = "View flip decider :";
|
||||||
//
|
//
|
||||||
// comboBox1
|
// comboBox1
|
||||||
//
|
//
|
||||||
this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
this.comboBox1.FormattingEnabled = true;
|
this.comboBox1.FormattingEnabled = true;
|
||||||
this.comboBox1.Location = new System.Drawing.Point(130, 75);
|
this.comboBox1.Location = new System.Drawing.Point(130, 44);
|
||||||
this.comboBox1.Name = "comboBox1";
|
this.comboBox1.Name = "comboBox1";
|
||||||
this.comboBox1.Size = new System.Drawing.Size(353, 25);
|
this.comboBox1.Size = new System.Drawing.Size(432, 25);
|
||||||
this.comboBox1.TabIndex = 5;
|
this.comboBox1.TabIndex = 3;
|
||||||
|
//
|
||||||
|
// label4
|
||||||
|
//
|
||||||
|
this.label4.AutoSize = true;
|
||||||
|
this.label4.Location = new System.Drawing.Point(42, 78);
|
||||||
|
this.label4.Name = "label4";
|
||||||
|
this.label4.Size = new System.Drawing.Size(82, 17);
|
||||||
|
this.label4.TabIndex = 4;
|
||||||
|
this.label4.Text = "Equipment #";
|
||||||
|
//
|
||||||
|
// equipmentNoBox
|
||||||
|
//
|
||||||
|
this.equipmentNoBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
|
this.equipmentNoBox.FormattingEnabled = true;
|
||||||
|
this.equipmentNoBox.Location = new System.Drawing.Point(130, 75);
|
||||||
|
this.equipmentNoBox.Name = "equipmentNoBox";
|
||||||
|
this.equipmentNoBox.Size = new System.Drawing.Size(138, 25);
|
||||||
|
this.equipmentNoBox.TabIndex = 5;
|
||||||
|
//
|
||||||
|
// label5
|
||||||
|
//
|
||||||
|
this.label5.AutoSize = true;
|
||||||
|
this.label5.Location = new System.Drawing.Point(314, 78);
|
||||||
|
this.label5.Name = "label5";
|
||||||
|
this.label5.Size = new System.Drawing.Size(68, 17);
|
||||||
|
this.label5.TabIndex = 6;
|
||||||
|
this.label5.Text = "Drawing #";
|
||||||
|
//
|
||||||
|
// comboBox2
|
||||||
|
//
|
||||||
|
this.comboBox2.FormattingEnabled = true;
|
||||||
|
this.comboBox2.Location = new System.Drawing.Point(388, 75);
|
||||||
|
this.comboBox2.Name = "comboBox2";
|
||||||
|
this.comboBox2.Size = new System.Drawing.Size(174, 25);
|
||||||
|
this.comboBox2.TabIndex = 7;
|
||||||
//
|
//
|
||||||
// MainForm
|
// MainForm
|
||||||
//
|
//
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
|
||||||
this.ClientSize = new System.Drawing.Size(778, 460);
|
this.ClientSize = new System.Drawing.Size(942, 674);
|
||||||
|
this.Controls.Add(this.comboBox2);
|
||||||
|
this.Controls.Add(this.equipmentNoBox);
|
||||||
|
this.Controls.Add(this.label5);
|
||||||
this.Controls.Add(this.comboBox1);
|
this.Controls.Add(this.comboBox1);
|
||||||
|
this.Controls.Add(this.label4);
|
||||||
this.Controls.Add(this.label3);
|
this.Controls.Add(this.label3);
|
||||||
this.Controls.Add(this.label2);
|
|
||||||
this.Controls.Add(this.label1);
|
this.Controls.Add(this.label1);
|
||||||
this.Controls.Add(this.richTextBox1);
|
this.Controls.Add(this.richTextBox1);
|
||||||
this.Controls.Add(this.prefixTextBox);
|
|
||||||
this.Controls.Add(this.activeDocTitleBox);
|
this.Controls.Add(this.activeDocTitleBox);
|
||||||
this.Controls.Add(this.button1);
|
this.Controls.Add(this.button1);
|
||||||
this.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
this.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
this.MaximizeBox = false;
|
this.MaximizeBox = false;
|
||||||
|
this.MinimumSize = new System.Drawing.Size(643, 355);
|
||||||
this.Name = "MainForm";
|
this.Name = "MainForm";
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||||
this.Text = "ExportDXF";
|
this.Text = "ExportDXF";
|
||||||
@@ -149,10 +171,12 @@
|
|||||||
private System.Windows.Forms.TextBox activeDocTitleBox;
|
private System.Windows.Forms.TextBox activeDocTitleBox;
|
||||||
private System.Windows.Forms.RichTextBox richTextBox1;
|
private System.Windows.Forms.RichTextBox richTextBox1;
|
||||||
private System.Windows.Forms.Label label1;
|
private System.Windows.Forms.Label label1;
|
||||||
private System.Windows.Forms.Label label2;
|
|
||||||
private System.Windows.Forms.TextBox prefixTextBox;
|
|
||||||
private System.Windows.Forms.Label label3;
|
private System.Windows.Forms.Label label3;
|
||||||
private System.Windows.Forms.ComboBox comboBox1;
|
private System.Windows.Forms.ComboBox comboBox1;
|
||||||
|
private System.Windows.Forms.Label label4;
|
||||||
|
private System.Windows.Forms.ComboBox equipmentNoBox;
|
||||||
|
private System.Windows.Forms.Label label5;
|
||||||
|
private System.Windows.Forms.ComboBox comboBox2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +1,33 @@
|
|||||||
using ExportDXF.Extensions;
|
using ExportDXF.Extensions;
|
||||||
using ExportDXF.Models;
|
using ExportDXF.Models;
|
||||||
using ExportDXF.Services;
|
using ExportDXF.Services;
|
||||||
using ExportDXF.ViewFlipDeciders;
|
using ExportDXF.ViewFlipDeciders;
|
||||||
|
using OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace ExportDXF.Forms
|
namespace ExportDXF.Forms
|
||||||
{
|
{
|
||||||
public partial class MainForm : Form
|
public partial class MainForm : Form
|
||||||
{
|
{
|
||||||
private readonly ISolidWorksService _solidWorksService;
|
private readonly ISolidWorksService _solidWorksService;
|
||||||
private readonly IDxfExportService _exportService;
|
private readonly IDxfExportService _exportService;
|
||||||
|
private readonly ICutFabApiClient _apiClient;
|
||||||
private CancellationTokenSource _cancellationTokenSource;
|
private CancellationTokenSource _cancellationTokenSource;
|
||||||
|
public MainForm(ISolidWorksService solidWorksService, IDxfExportService exportService, ICutFabApiClient apiClient)
|
||||||
public MainForm(ISolidWorksService solidWorksService, IDxfExportService exportService)
|
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_solidWorksService = solidWorksService ??
|
_solidWorksService = solidWorksService ??
|
||||||
throw new ArgumentNullException(nameof(solidWorksService));
|
throw new ArgumentNullException(nameof(solidWorksService));
|
||||||
|
|
||||||
_exportService = exportService ??
|
_exportService = exportService ??
|
||||||
throw new ArgumentNullException(nameof(exportService));
|
throw new ArgumentNullException(nameof(exportService));
|
||||||
|
_apiClient = apiClient ??
|
||||||
|
throw new ArgumentNullException(nameof(apiClient));
|
||||||
InitializeViewFlipDeciders();
|
InitializeViewFlipDeciders();
|
||||||
}
|
}
|
||||||
|
|
||||||
~MainForm()
|
~MainForm()
|
||||||
{
|
{
|
||||||
_cancellationTokenSource?.Dispose();
|
_cancellationTokenSource?.Dispose();
|
||||||
@@ -37,29 +35,24 @@ namespace ExportDXF.Forms
|
|||||||
components?.Dispose();
|
components?.Dispose();
|
||||||
Dispose(false);
|
Dispose(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async void OnLoad(EventArgs e)
|
protected override async void OnLoad(EventArgs e)
|
||||||
{
|
{
|
||||||
base.OnLoad(e);
|
base.OnLoad(e);
|
||||||
|
|
||||||
button1.Enabled = false;
|
button1.Enabled = false;
|
||||||
|
|
||||||
await InitializeAsync();
|
await InitializeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InitializeAsync()
|
private async Task InitializeAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LogMessage("Connecting to SolidWorks, this may take a minute...");
|
LogMessage("Connecting to SolidWorks, this may take a minute...");
|
||||||
|
|
||||||
await _solidWorksService.ConnectAsync();
|
await _solidWorksService.ConnectAsync();
|
||||||
_solidWorksService.ActiveDocumentChanged += OnActiveDocumentChanged;
|
_solidWorksService.ActiveDocumentChanged += OnActiveDocumentChanged;
|
||||||
|
|
||||||
LogMessage("Ready", Color.Green);
|
LogMessage("Ready", Color.Green);
|
||||||
|
|
||||||
UpdateActiveDocumentDisplay();
|
UpdateActiveDocumentDisplay();
|
||||||
button1.Enabled = true;
|
button1.Enabled = true;
|
||||||
|
// Populate equipment and (initial) drawings
|
||||||
|
await PopulateEquipmentAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -68,7 +61,58 @@ namespace ExportDXF.Forms
|
|||||||
Application.Exit();
|
Application.Exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private async Task PopulateEquipmentAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LogMessage($"Loading equipment from {_apiClient.BaseUrl} ...");
|
||||||
|
var list = await _apiClient.GetEquipmentAsync();
|
||||||
|
equipmentNoBox.DisplayMember = nameof(CutFabApiClient.ApiEquipment.EquipmentNumber);
|
||||||
|
equipmentNoBox.ValueMember = nameof(CutFabApiClient.ApiEquipment.ID);
|
||||||
|
equipmentNoBox.DataSource = list;
|
||||||
|
equipmentNoBox.SelectedIndexChanged -= equipmentNoBox_SelectedIndexChanged;
|
||||||
|
equipmentNoBox.SelectedIndexChanged += equipmentNoBox_SelectedIndexChanged;
|
||||||
|
if (list != null && list.Count > 0)
|
||||||
|
{
|
||||||
|
equipmentNoBox.SelectedIndex = 0;
|
||||||
|
await PopulateDrawingsForSelectedEquipmentAsync();
|
||||||
|
LogMessage($"Loaded {list.Count} equipment record(s)", Color.Green);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogMessage("No equipment returned by API", Color.DarkBlue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogMessage($"Failed to load equipment: {ex.Message}", Color.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async void equipmentNoBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
await PopulateDrawingsForSelectedEquipmentAsync();
|
||||||
|
}
|
||||||
|
private async Task PopulateDrawingsForSelectedEquipmentAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var selected = equipmentNoBox.SelectedItem as CutFabApiClient.ApiEquipment;
|
||||||
|
if (selected == null)
|
||||||
|
{
|
||||||
|
comboBox2.DataSource = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var drawings = await _apiClient.GetDrawingsForEquipmentAsync(selected.ID);
|
||||||
|
comboBox2.DisplayMember = nameof(CutFabApiClient.ApiDrawingSummary.DrawingNumber);
|
||||||
|
comboBox2.ValueMember = nameof(CutFabApiClient.ApiDrawingSummary.ID);
|
||||||
|
comboBox2.DataSource = drawings;
|
||||||
|
LogMessage($"Loaded {drawings.Count} drawing(s) for equipment {selected.EquipmentNumber}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogMessage($"Failed to load drawings: {ex.Message}", Color.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
private void InitializeViewFlipDeciders()
|
private void InitializeViewFlipDeciders()
|
||||||
{
|
{
|
||||||
var items = ViewFlipDeciderFactory.GetAvailableDeciders()
|
var items = ViewFlipDeciderFactory.GetAvailableDeciders()
|
||||||
@@ -78,7 +122,6 @@ namespace ExportDXF.Forms
|
|||||||
ViewFlipDecider = d
|
ViewFlipDecider = d
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// Move "Automatic" to the top if it exists
|
// Move "Automatic" to the top if it exists
|
||||||
var automatic = items.FirstOrDefault(i => i.Name == "Automatic");
|
var automatic = items.FirstOrDefault(i => i.Name == "Automatic");
|
||||||
if (automatic != null)
|
if (automatic != null)
|
||||||
@@ -86,11 +129,9 @@ namespace ExportDXF.Forms
|
|||||||
items.Remove(automatic);
|
items.Remove(automatic);
|
||||||
items.Insert(0, automatic);
|
items.Insert(0, automatic);
|
||||||
}
|
}
|
||||||
|
|
||||||
comboBox1.DataSource = items;
|
comboBox1.DataSource = items;
|
||||||
comboBox1.DisplayMember = "Name";
|
comboBox1.DisplayMember = "Name";
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void button1_Click(object sender, EventArgs e)
|
private async void button1_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (_cancellationTokenSource != null)
|
if (_cancellationTokenSource != null)
|
||||||
@@ -102,39 +143,33 @@ namespace ExportDXF.Forms
|
|||||||
await StartExportAsync();
|
await StartExportAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StartExportAsync()
|
private async Task StartExportAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_cancellationTokenSource = new CancellationTokenSource();
|
_cancellationTokenSource = new CancellationTokenSource();
|
||||||
var token = _cancellationTokenSource.Token;
|
var token = _cancellationTokenSource.Token;
|
||||||
|
|
||||||
UpdateUIForExportStart();
|
UpdateUIForExportStart();
|
||||||
|
|
||||||
var activeDoc = _solidWorksService.GetActiveDocument();
|
var activeDoc = _solidWorksService.GetActiveDocument();
|
||||||
if (activeDoc == null)
|
if (activeDoc == null)
|
||||||
{
|
{
|
||||||
LogMessage("No active document.", Color.Red);
|
LogMessage("No active document.", Color.Red);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var viewFlipDecider = GetSelectedViewFlipDecider();
|
var viewFlipDecider = GetSelectedViewFlipDecider();
|
||||||
var prefix = prefixTextBox.Text;
|
var drawingNumberText = comboBox2.Text?.Trim();
|
||||||
|
var selectedEquipment = equipmentNoBox.SelectedItem as CutFabApiClient.ApiEquipment;
|
||||||
var exportContext = new ExportContext
|
var exportContext = new ExportContext
|
||||||
{
|
{
|
||||||
ActiveDocument = activeDoc,
|
ActiveDocument = activeDoc,
|
||||||
ViewFlipDecider = viewFlipDecider,
|
ViewFlipDecider = viewFlipDecider,
|
||||||
FilePrefix = prefix,
|
FilePrefix = drawingNumberText,
|
||||||
|
EquipmentId = selectedEquipment?.ID,
|
||||||
CancellationToken = token,
|
CancellationToken = token,
|
||||||
ProgressCallback = LogMessage
|
ProgressCallback = LogMessage
|
||||||
};
|
};
|
||||||
|
|
||||||
LogMessage($"Started at {DateTime.Now:t}");
|
LogMessage($"Started at {DateTime.Now:t}");
|
||||||
|
|
||||||
await Task.Run(() => _exportService.Export(exportContext), token);
|
await Task.Run(() => _exportService.Export(exportContext), token);
|
||||||
|
|
||||||
LogMessage("Done.", Color.Green);
|
LogMessage("Done.", Color.Green);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
@@ -153,41 +188,33 @@ namespace ExportDXF.Forms
|
|||||||
_cancellationTokenSource = null;
|
_cancellationTokenSource = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CancelExport()
|
private void CancelExport()
|
||||||
{
|
{
|
||||||
button1.Enabled = false;
|
button1.Enabled = false;
|
||||||
_cancellationTokenSource?.Cancel();
|
_cancellationTokenSource?.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IViewFlipDecider GetSelectedViewFlipDecider()
|
private IViewFlipDecider GetSelectedViewFlipDecider()
|
||||||
{
|
{
|
||||||
var item = comboBox1.SelectedItem as ViewFlipDeciderComboboxItem;
|
var item = comboBox1.SelectedItem as ViewFlipDeciderComboboxItem;
|
||||||
return item?.ViewFlipDecider;
|
return item?.ViewFlipDecider;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateUIForExportStart()
|
private void UpdateUIForExportStart()
|
||||||
{
|
{
|
||||||
activeDocTitleBox.Enabled = false;
|
activeDocTitleBox.Enabled = false;
|
||||||
prefixTextBox.Enabled = false;
|
|
||||||
comboBox1.Enabled = false;
|
comboBox1.Enabled = false;
|
||||||
button1.Image = Properties.Resources.stop_alt;
|
button1.Image = Properties.Resources.stop_alt;
|
||||||
|
|
||||||
if (richTextBox1.TextLength != 0)
|
if (richTextBox1.TextLength != 0)
|
||||||
{
|
{
|
||||||
richTextBox1.AppendText("\n\n");
|
richTextBox1.AppendText("\n\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateUIForExportComplete()
|
private void UpdateUIForExportComplete()
|
||||||
{
|
{
|
||||||
activeDocTitleBox.Enabled = true;
|
activeDocTitleBox.Enabled = true;
|
||||||
prefixTextBox.Enabled = true;
|
|
||||||
comboBox1.Enabled = true;
|
comboBox1.Enabled = true;
|
||||||
button1.Image = Properties.Resources.play;
|
button1.Image = Properties.Resources.play;
|
||||||
button1.Enabled = true;
|
button1.Enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnActiveDocumentChanged(object sender, EventArgs e)
|
private void OnActiveDocumentChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (InvokeRequired)
|
if (InvokeRequired)
|
||||||
@@ -195,47 +222,36 @@ namespace ExportDXF.Forms
|
|||||||
Invoke(new Action(() => OnActiveDocumentChanged(sender, e)));
|
Invoke(new Action(() => OnActiveDocumentChanged(sender, e)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateActiveDocumentDisplay();
|
UpdateActiveDocumentDisplay();
|
||||||
UpdatePrefixFromActiveDocument();
|
UpdatePrefixFromActiveDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateActiveDocumentDisplay()
|
private void UpdateActiveDocumentDisplay()
|
||||||
{
|
{
|
||||||
var activeDoc = _solidWorksService.GetActiveDocument();
|
var activeDoc = _solidWorksService.GetActiveDocument();
|
||||||
activeDocTitleBox.Text = activeDoc?.Title ?? "<No Document Open>";
|
activeDocTitleBox.Text = activeDoc?.Title ?? "<No Document Open>";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdatePrefixFromActiveDocument()
|
private void UpdatePrefixFromActiveDocument()
|
||||||
{
|
{
|
||||||
var activeDoc = _solidWorksService.GetActiveDocument();
|
var activeDoc = _solidWorksService.GetActiveDocument();
|
||||||
|
|
||||||
if (activeDoc == null)
|
if (activeDoc == null)
|
||||||
{
|
{
|
||||||
prefixTextBox.Text = string.Empty;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeDoc.DocumentType == DocumentType.Drawing)
|
if (activeDoc.DocumentType == DocumentType.Drawing)
|
||||||
{
|
{
|
||||||
var drawingInfo = DrawingInfo.Parse(activeDoc.Title);
|
var drawingInfo = DrawingInfo.Parse(activeDoc.Title);
|
||||||
if (drawingInfo != null)
|
if (drawingInfo != null)
|
||||||
{
|
{
|
||||||
prefixTextBox.Text = $"{drawingInfo.JobNo} {drawingInfo.DrawingNo} PT";
|
|
||||||
prefixTextBox.SelectionStart = prefixTextBox.Text.Length;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
prefixTextBox.Text = string.Empty;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activeDocTitleBox_TextChanged(object sender, EventArgs e)
|
private void activeDocTitleBox_TextChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
UpdatePrefixFromActiveDocument();
|
UpdatePrefixFromActiveDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogMessage(string message, Color? color = null)
|
private void LogMessage(string message, Color? color = null)
|
||||||
{
|
{
|
||||||
if (InvokeRequired)
|
if (InvokeRequired)
|
||||||
@@ -243,7 +259,6 @@ namespace ExportDXF.Forms
|
|||||||
Invoke(new Action(() => LogMessage(message, color)));
|
Invoke(new Action(() => LogMessage(message, color)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (color.HasValue)
|
if (color.HasValue)
|
||||||
{
|
{
|
||||||
richTextBox1.AppendText(message + System.Environment.NewLine, color.Value);
|
richTextBox1.AppendText(message + System.Environment.NewLine, color.Value);
|
||||||
@@ -252,7 +267,6 @@ namespace ExportDXF.Forms
|
|||||||
{
|
{
|
||||||
richTextBox1.AppendText(message + System.Environment.NewLine);
|
richTextBox1.AppendText(message + System.Environment.NewLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
richTextBox1.ScrollToCaret();
|
richTextBox1.ScrollToCaret();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ namespace ExportDXF.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string FilePrefix { get; set; }
|
public string FilePrefix { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Selected Equipment ID for API operations (optional).
|
||||||
|
/// </summary>
|
||||||
|
public int? EquipmentId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cancellation token for canceling the export operation.
|
/// Cancellation token for canceling the export operation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using ExportDXF.Forms;
|
using ExportDXF.Forms;
|
||||||
using ExportDXF.Services;
|
using ExportDXF.Services;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Configuration;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace ExportDXF
|
namespace ExportDXF
|
||||||
@@ -39,16 +40,17 @@ namespace ExportDXF
|
|||||||
var bomExtractor = new BomExtractor();
|
var bomExtractor = new BomExtractor();
|
||||||
var partExporter = new PartExporter();
|
var partExporter = new PartExporter();
|
||||||
var drawingExporter = new DrawingExporter();
|
var drawingExporter = new DrawingExporter();
|
||||||
var bomExcelExporter = new BomExcelExporter();
|
var baseUrl = ConfigurationManager.AppSettings["CutFab.ApiBaseUrl"] ?? "http://localhost:7027";
|
||||||
|
var apiClient = new CutFabApiClient(baseUrl);
|
||||||
|
|
||||||
var exportService = new DxfExportService(
|
var exportService = new DxfExportService(
|
||||||
solidWorksService,
|
solidWorksService,
|
||||||
bomExtractor,
|
bomExtractor,
|
||||||
partExporter,
|
partExporter,
|
||||||
drawingExporter,
|
drawingExporter,
|
||||||
bomExcelExporter);
|
apiClient);
|
||||||
|
|
||||||
return new MainForm(solidWorksService, exportService);
|
return new MainForm(solidWorksService, exportService, apiClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
319
ExportDXF/Services/CutFabApiClient.cs
Normal file
319
ExportDXF/Services/CutFabApiClient.cs
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Configuration;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web.Script.Serialization;
|
||||||
|
using static ExportDXF.Services.CutFabApiClient;
|
||||||
|
|
||||||
|
namespace ExportDXF.Services
|
||||||
|
{
|
||||||
|
public interface ICutFabApiClient
|
||||||
|
{
|
||||||
|
string BaseUrl { get; }
|
||||||
|
Task<int?> ResolveDrawingIdAsync(string drawingNumber);
|
||||||
|
Task<int?> CreateDrawingAsync(int equipmentId, string drawingNumber);
|
||||||
|
Task<CutFabApiClient.ApiResponse<int?>> CreateDrawingWithInfoAsync(int equipmentId, string drawingNumber);
|
||||||
|
Task<bool> UploadDrawingPdfAsync(string drawingNumber, string pdfPath, string uploadedBy = null, string notes = null);
|
||||||
|
Task<bool> UploadDxfZipAsync(int drawingId, string zipPath);
|
||||||
|
Task<int?> CreateBomItemAsync(object upsertBomItemDto);
|
||||||
|
Task<bool> AutoLinkTemplatesAsync(int drawingId);
|
||||||
|
Task<List<ApiEquipment>> GetEquipmentAsync();
|
||||||
|
Task<List<ApiDrawingSummary>> GetDrawingsForEquipmentAsync(int equipmentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CutFabApiClient : ICutFabApiClient, IDisposable
|
||||||
|
{
|
||||||
|
private readonly HttpClient _http;
|
||||||
|
private readonly string _baseUrl;
|
||||||
|
public string BaseUrl => _baseUrl;
|
||||||
|
public class ApiResponse<T>
|
||||||
|
{
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public int StatusCode { get; set; }
|
||||||
|
public T Data { get; set; }
|
||||||
|
public string RawBody { get; set; }
|
||||||
|
public string Error { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public CutFabApiClient(string baseUrl)
|
||||||
|
{
|
||||||
|
_baseUrl = (baseUrl ?? string.Empty).TrimEnd('/');
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(_baseUrl))
|
||||||
|
{
|
||||||
|
// Default to deployed API port from deployment script
|
||||||
|
_baseUrl = "http://localhost:7027";
|
||||||
|
}
|
||||||
|
|
||||||
|
_http = new HttpClient
|
||||||
|
{
|
||||||
|
Timeout = TimeSpan.FromSeconds(100)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int?> ResolveDrawingIdAsync(string drawingNumber)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{_baseUrl}/api/Drawings/resolve?drawingNumber={Uri.EscapeDataString(drawingNumber)}";
|
||||||
|
var resp = await _http.GetAsync(url).ConfigureAwait(false);
|
||||||
|
if (!resp.IsSuccessStatusCode) return null;
|
||||||
|
var json = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||||
|
var dict = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json);
|
||||||
|
if (dict != null && dict.ContainsKey("ID"))
|
||||||
|
{
|
||||||
|
var idObj = dict["ID"]; // serializer returns int or double depending
|
||||||
|
if (idObj is int i) return i;
|
||||||
|
if (idObj is double d) return (int)d;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int?> CreateDrawingAsync(int equipmentId, string drawingNumber)
|
||||||
|
{
|
||||||
|
var payload = new { DrawingNumber = drawingNumber, Description = (string)null, Qty = 1, EquipmentID = equipmentId };
|
||||||
|
var json = new JavaScriptSerializer().Serialize(payload);
|
||||||
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||||
|
var resp = await _http.PostAsync($"{_baseUrl}/api/Drawings", content).ConfigureAwait(false);
|
||||||
|
if (!resp.IsSuccessStatusCode) return null;
|
||||||
|
var body = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dict = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(body);
|
||||||
|
if (dict != null && dict.ContainsKey("ID"))
|
||||||
|
{
|
||||||
|
var idObj = dict["ID"]; if (idObj is int i) return i; if (idObj is double d) return (int)d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse<int?>> CreateDrawingWithInfoAsync(int equipmentId, string drawingNumber)
|
||||||
|
{
|
||||||
|
var result = new ApiResponse<int?> { Success = false, StatusCode = 0, Data = null, RawBody = null, Error = null };
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var payload = new { DrawingNumber = drawingNumber, Description = (string)null, Qty = 1, EquipmentID = equipmentId };
|
||||||
|
var json = new JavaScriptSerializer().Serialize(payload);
|
||||||
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||||
|
var resp = await _http.PostAsync($"{_baseUrl}/api/Drawings", content).ConfigureAwait(false);
|
||||||
|
result.StatusCode = (int)resp.StatusCode;
|
||||||
|
result.Success = resp.IsSuccessStatusCode;
|
||||||
|
var body = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||||
|
result.RawBody = body;
|
||||||
|
if (!resp.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
result.Error = "HTTP " + ((int)resp.StatusCode) + " " + resp.ReasonPhrase;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dict = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(body);
|
||||||
|
if (dict != null)
|
||||||
|
{
|
||||||
|
object v;
|
||||||
|
if (TryGetCI(dict, new[] { "ID", "id" }, out v))
|
||||||
|
{
|
||||||
|
if (v is int i) { result.Data = i; return result; }
|
||||||
|
if (v is double d) { result.Data = (int)d; return result; }
|
||||||
|
int parsed; if (int.TryParse(Convert.ToString(v), out parsed)) { result.Data = parsed; return result; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
result.Error = ex.Message;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
result.Error = ex.Message;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> UploadDrawingPdfAsync(string drawingNumber, string pdfPath, string uploadedBy = null, string notes = null)
|
||||||
|
{
|
||||||
|
if (!File.Exists(pdfPath)) return false;
|
||||||
|
using (var form = new MultipartFormDataContent())
|
||||||
|
{
|
||||||
|
form.Add(new StringContent(drawingNumber ?? string.Empty), "drawingNumber");
|
||||||
|
if (!string.IsNullOrWhiteSpace(uploadedBy)) form.Add(new StringContent(uploadedBy), "uploadedBy");
|
||||||
|
if (!string.IsNullOrWhiteSpace(notes)) form.Add(new StringContent(notes), "notes");
|
||||||
|
|
||||||
|
var fileContent = new StreamContent(File.OpenRead(pdfPath));
|
||||||
|
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/pdf");
|
||||||
|
var fileName = Path.GetFileName(pdfPath);
|
||||||
|
form.Add(fileContent, "file", fileName);
|
||||||
|
|
||||||
|
var resp = await _http.PostAsync($"{_baseUrl}/api/DrawingRevisions/upload", form).ConfigureAwait(false);
|
||||||
|
return resp.IsSuccessStatusCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> UploadDxfZipAsync(int drawingId, string zipPath)
|
||||||
|
{
|
||||||
|
if (!File.Exists(zipPath)) return false;
|
||||||
|
using (var form = new MultipartFormDataContent())
|
||||||
|
{
|
||||||
|
var fileContent = new StreamContent(File.OpenRead(zipPath));
|
||||||
|
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/zip");
|
||||||
|
var fileName = Path.GetFileName(zipPath);
|
||||||
|
form.Add(fileContent, "file", fileName);
|
||||||
|
|
||||||
|
var resp = await _http.PostAsync($"{_baseUrl}/api/Drawings/{drawingId}/upload-dxf-templates", form).ConfigureAwait(false);
|
||||||
|
return resp.IsSuccessStatusCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int?> CreateBomItemAsync(object upsertBomItemDto)
|
||||||
|
{
|
||||||
|
var json = new JavaScriptSerializer().Serialize(upsertBomItemDto);
|
||||||
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||||
|
var resp = await _http.PostAsync($"{_baseUrl}/api/BomItems", content).ConfigureAwait(false);
|
||||||
|
if (!resp.IsSuccessStatusCode) return null;
|
||||||
|
var body = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dict = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(body);
|
||||||
|
if (dict != null)
|
||||||
|
{
|
||||||
|
object v;
|
||||||
|
if (TryGetCI(dict, new[] { "ID", "id" }, out v))
|
||||||
|
{
|
||||||
|
if (v is int i) return i;
|
||||||
|
if (v is double d) return (int)d;
|
||||||
|
int parsed; if (int.TryParse(Convert.ToString(v), out parsed)) return parsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
// Successful HTTP with empty/minimal body: treat as success
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> AutoLinkTemplatesAsync(int drawingId)
|
||||||
|
{
|
||||||
|
var url = $"{_baseUrl}/api/Drawings/{drawingId}/auto-link-templates";
|
||||||
|
var resp = await _http.PostAsync(url, new ByteArrayContent(new byte[0])).ConfigureAwait(false);
|
||||||
|
return resp.IsSuccessStatusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_http?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lightweight DTOs for UI binding
|
||||||
|
public class ApiEquipment
|
||||||
|
{
|
||||||
|
public int ID { get; set; }
|
||||||
|
public string EquipmentNumber { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public override string ToString() => EquipmentNumber ?? base.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ApiDrawingSummary
|
||||||
|
{
|
||||||
|
public int ID { get; set; }
|
||||||
|
public string DrawingNumber { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public override string ToString() => DrawingNumber ?? base.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<ApiEquipment>> GetEquipmentAsync()
|
||||||
|
{
|
||||||
|
var url = $"{_baseUrl}/api/Equipment";
|
||||||
|
var req = new HttpRequestMessage(HttpMethod.Get, url);
|
||||||
|
req.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||||
|
var resp = await _http.SendAsync(req).ConfigureAwait(false);
|
||||||
|
resp.EnsureSuccessStatusCode();
|
||||||
|
var json = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
var serializer = new JavaScriptSerializer();
|
||||||
|
var raw = serializer.DeserializeObject(json);
|
||||||
|
var result = new List<ApiEquipment>();
|
||||||
|
|
||||||
|
if (raw is System.Collections.IEnumerable enumerable && !(raw is string))
|
||||||
|
{
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
{
|
||||||
|
var dict = item as Dictionary<string, object>;
|
||||||
|
if (dict == null) continue;
|
||||||
|
var eq = new ApiEquipment();
|
||||||
|
object v;
|
||||||
|
if (TryGetCI(dict, new[] { "ID", "id" }, out v)) eq.ID = ToInt(v);
|
||||||
|
if (TryGetCI(dict, new[] { "EquipmentNumber", "equipmentNumber", "equipmentNo" }, out v)) eq.EquipmentNumber = v?.ToString();
|
||||||
|
if (TryGetCI(dict, new[] { "Description", "description" }, out v)) eq.Description = v?.ToString();
|
||||||
|
result.Add(eq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<ApiDrawingSummary>> GetDrawingsForEquipmentAsync(int equipmentId)
|
||||||
|
{
|
||||||
|
var url = $"{_baseUrl}/api/Equipment/{equipmentId}";
|
||||||
|
var resp = await _http.GetAsync(url).ConfigureAwait(false);
|
||||||
|
if (!resp.IsSuccessStatusCode) return new List<ApiDrawingSummary>();
|
||||||
|
var json = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||||
|
var serializer = new JavaScriptSerializer();
|
||||||
|
var root = serializer.DeserializeObject(json) as Dictionary<string, object>;
|
||||||
|
var results = new List<ApiDrawingSummary>();
|
||||||
|
if (root != null)
|
||||||
|
{
|
||||||
|
object dval;
|
||||||
|
if (!TryGetCI(root, new[] { "Drawings", "drawings" }, out dval)) return results;
|
||||||
|
if (dval is System.Collections.IEnumerable arr && !(dval is string))
|
||||||
|
{
|
||||||
|
foreach (var item in arr)
|
||||||
|
{
|
||||||
|
var d = item as Dictionary<string, object>;
|
||||||
|
if (d == null) continue;
|
||||||
|
var summary = new ApiDrawingSummary();
|
||||||
|
object v;
|
||||||
|
if (TryGetCI(d, new[] { "ID", "id" }, out v)) summary.ID = ToInt(v);
|
||||||
|
if (TryGetCI(d, new[] { "DrawingNumber", "drawingNumber" }, out v)) summary.DrawingNumber = v?.ToString();
|
||||||
|
if (TryGetCI(d, new[] { "Description", "description" }, out v)) summary.Description = v?.ToString();
|
||||||
|
results.Add(summary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryGetCI(Dictionary<string, object> dict, IEnumerable<string> keys, out object value)
|
||||||
|
{
|
||||||
|
foreach (var k in keys)
|
||||||
|
{
|
||||||
|
if (dict.ContainsKey(k)) { value = dict[k]; return true; }
|
||||||
|
foreach (var dk in dict.Keys)
|
||||||
|
{
|
||||||
|
if (string.Equals(dk, k, StringComparison.OrdinalIgnoreCase)) { value = dict[dk]; return true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value = null; return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int ToInt(object v)
|
||||||
|
{
|
||||||
|
if (v == null) return 0;
|
||||||
|
if (v is int i) return i;
|
||||||
|
if (v is long l) return (int)l;
|
||||||
|
if (v is double d) return (int)d;
|
||||||
|
int parsed; if (int.TryParse(v.ToString(), out parsed)) return parsed; return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,17 @@
|
|||||||
using ExportDXF.Extensions;
|
using ExportDXF.Extensions;
|
||||||
using ExportDXF.ItemExtractors;
|
using ExportDXF.ItemExtractors;
|
||||||
using ExportDXF.Models;
|
using ExportDXF.Models;
|
||||||
|
using ExportDXF;
|
||||||
using SolidWorks.Interop.sldworks;
|
using SolidWorks.Interop.sldworks;
|
||||||
using SolidWorks.Interop.swconst;
|
using SolidWorks.Interop.swconst;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using Environment = System.Environment;
|
||||||
|
using System.IO.Compression;
|
||||||
|
|
||||||
namespace ExportDXF.Services
|
namespace ExportDXF.Services
|
||||||
{
|
{
|
||||||
@@ -29,20 +33,20 @@ namespace ExportDXF.Services
|
|||||||
private readonly IBomExtractor _bomExtractor;
|
private readonly IBomExtractor _bomExtractor;
|
||||||
private readonly IPartExporter _partExporter;
|
private readonly IPartExporter _partExporter;
|
||||||
private readonly IDrawingExporter _drawingExporter;
|
private readonly IDrawingExporter _drawingExporter;
|
||||||
private readonly IBomExcelExporter _bomExcelExporter;
|
private readonly ICutFabApiClient _apiClient;
|
||||||
|
|
||||||
public DxfExportService(
|
public DxfExportService(
|
||||||
ISolidWorksService solidWorksService,
|
ISolidWorksService solidWorksService,
|
||||||
IBomExtractor bomExtractor,
|
IBomExtractor bomExtractor,
|
||||||
IPartExporter partExporter,
|
IPartExporter partExporter,
|
||||||
IDrawingExporter drawingExporter,
|
IDrawingExporter drawingExporter,
|
||||||
IBomExcelExporter bomExcelExporter)
|
ICutFabApiClient apiClient)
|
||||||
{
|
{
|
||||||
_solidWorksService = solidWorksService ?? throw new ArgumentNullException(nameof(solidWorksService));
|
_solidWorksService = solidWorksService ?? throw new ArgumentNullException(nameof(solidWorksService));
|
||||||
_bomExtractor = bomExtractor ?? throw new ArgumentNullException(nameof(bomExtractor));
|
_bomExtractor = bomExtractor ?? throw new ArgumentNullException(nameof(bomExtractor));
|
||||||
_partExporter = partExporter ?? throw new ArgumentNullException(nameof(partExporter));
|
_partExporter = partExporter ?? throw new ArgumentNullException(nameof(partExporter));
|
||||||
_drawingExporter = drawingExporter ?? throw new ArgumentNullException(nameof(drawingExporter));
|
_drawingExporter = drawingExporter ?? throw new ArgumentNullException(nameof(drawingExporter));
|
||||||
_bomExcelExporter = bomExcelExporter ?? throw new ArgumentNullException(nameof(bomExcelExporter));
|
_apiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -104,14 +108,8 @@ namespace ExportDXF.Services
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var saveDirectory = PromptUserForDirectory(context);
|
var tempDir = CreateTempWorkDir();
|
||||||
if (saveDirectory == null)
|
_partExporter.ExportSinglePart(part, tempDir, context);
|
||||||
{
|
|
||||||
LogProgress(context, "Canceled", Color.Red);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_partExporter.ExportSinglePart(part, saveDirectory, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExportAssembly(ExportContext context)
|
private void ExportAssembly(ExportContext context)
|
||||||
@@ -136,14 +134,8 @@ namespace ExportDXF.Services
|
|||||||
|
|
||||||
LogProgress(context, $"Found {items.Count} item(s).", null);
|
LogProgress(context, $"Found {items.Count} item(s).", null);
|
||||||
|
|
||||||
var saveDirectory = PromptUserForDirectory(context);
|
var tempDir = CreateTempWorkDir();
|
||||||
if (saveDirectory == null)
|
ExportItems(items, tempDir, context, drawingId: null);
|
||||||
{
|
|
||||||
LogProgress(context, "Canceled", Color.Red);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExportItems(items, saveDirectory, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExportDrawing(ExportContext context)
|
private void ExportDrawing(ExportContext context)
|
||||||
@@ -168,18 +160,120 @@ namespace ExportDXF.Services
|
|||||||
|
|
||||||
LogProgress(context, $"Found {items.Count} component(s)", null);
|
LogProgress(context, $"Found {items.Count} component(s)", null);
|
||||||
|
|
||||||
var saveDirectory = PromptUserForDirectory(context);
|
var tempDir = CreateTempWorkDir();
|
||||||
if (saveDirectory == null)
|
|
||||||
|
// Determine drawing number
|
||||||
|
var drawingNumber = ParseDrawingNumber(context);
|
||||||
|
if (string.IsNullOrWhiteSpace(drawingNumber))
|
||||||
{
|
{
|
||||||
LogProgress(context, "Canceled", Color.Red);
|
LogProgress(context, "Warning: Could not determine drawing number for API upload.", Color.DarkBlue);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export drawing to PDF first
|
// Resolve drawing ID if possible
|
||||||
_drawingExporter.ExportToPdf(drawing, saveDirectory, context);
|
int? drawingId = null;
|
||||||
|
if (!string.IsNullOrWhiteSpace(drawingNumber))
|
||||||
|
{
|
||||||
|
drawingId = _apiClient.ResolveDrawingIdAsync(drawingNumber).GetAwaiter().GetResult();
|
||||||
|
// Fallback: if resolve endpoint not available or failed, search equipment details
|
||||||
|
if (drawingId == null && context.EquipmentId.HasValue)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var drawings = _apiClient.GetDrawingsForEquipmentAsync(context.EquipmentId.Value).GetAwaiter().GetResult();
|
||||||
|
if (drawings != null)
|
||||||
|
{
|
||||||
|
// Match by exact DrawingNumber (case-insensitive, trimmed)
|
||||||
|
var match = drawings.FirstOrDefault(d => string.Equals(d.DrawingNumber?.Trim(), drawingNumber.Trim(), StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (match != null) drawingId = match.ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
if (drawingId == null)
|
||||||
|
{
|
||||||
|
// If equipment is provided, create the drawing on the API
|
||||||
|
if (context.EquipmentId.HasValue)
|
||||||
|
{
|
||||||
|
var create = _apiClient.CreateDrawingWithInfoAsync(context.EquipmentId.Value, drawingNumber).GetAwaiter().GetResult();
|
||||||
|
if (create != null && create.Success && create.Data.HasValue)
|
||||||
|
{
|
||||||
|
drawingId = create.Data;
|
||||||
|
LogProgress(context, "Created drawing '" + drawingNumber + "' (ID " + drawingId + ") for equipment " + context.EquipmentId, Color.Green);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var code = create != null ? create.StatusCode.ToString() : "?";
|
||||||
|
var err = create != null ? (create.Error ?? create.RawBody) : null;
|
||||||
|
if (!string.IsNullOrWhiteSpace(err) && err.Length > 180) err = err.Substring(0, 180) + "...";
|
||||||
|
LogProgress(context, "Warning: Could not create drawing '" + drawingNumber + "' on API (status " + code + "). " + (err ?? string.Empty), Color.DarkBlue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogProgress(context, $"Warning: Drawing '{drawingNumber}' not found in API; uploads will be skipped.", Color.DarkBlue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Then export parts to DXF
|
// Export drawing to PDF first
|
||||||
ExportItems(items, saveDirectory, context);
|
_drawingExporter.ExportToPdf(drawing, tempDir, context);
|
||||||
|
|
||||||
|
// Upload PDF if we have a drawing number
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(drawingNumber))
|
||||||
|
{
|
||||||
|
var pdfs = Directory.GetFiles(tempDir, "*.pdf");
|
||||||
|
var pdfName = pdfs.Length > 0 ? pdfs[0] : null;
|
||||||
|
if (pdfName != null)
|
||||||
|
{
|
||||||
|
var uploadedBy = Environment.UserName;
|
||||||
|
var ok = _apiClient.UploadDrawingPdfAsync(drawingNumber, pdfName, uploadedBy, null).GetAwaiter().GetResult();
|
||||||
|
LogProgress(context, ok ? $"Uploaded PDF for '{drawingNumber}'" : $"Failed to upload PDF for '{drawingNumber}'", ok ? Color.Green : Color.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogProgress(context, $"PDF upload error: {ex.Message}", Color.Red);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we still don't have an ID, resolve again after PDF upload (server may create on upload)
|
||||||
|
if (!drawingId.HasValue && !string.IsNullOrWhiteSpace(drawingNumber))
|
||||||
|
{
|
||||||
|
var resolved = _apiClient.ResolveDrawingIdAsync(drawingNumber).GetAwaiter().GetResult();
|
||||||
|
if (!resolved.HasValue && context.EquipmentId.HasValue)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var drawings = _apiClient.GetDrawingsForEquipmentAsync(context.EquipmentId.Value).GetAwaiter().GetResult();
|
||||||
|
if (drawings != null)
|
||||||
|
{
|
||||||
|
var match = drawings.FirstOrDefault(d => string.Equals(d.DrawingNumber?.Trim(), drawingNumber.Trim(), StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (match != null) resolved = match.ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
if (resolved.HasValue)
|
||||||
|
{
|
||||||
|
drawingId = resolved;
|
||||||
|
LogProgress(context, $"Resolved drawing ID after PDF upload: {drawingId}", Color.Green);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then export parts to DXF and upload per-file
|
||||||
|
ExportItems(items, tempDir, context, drawingId);
|
||||||
|
|
||||||
|
// Attempt to auto-link templates at the end
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (drawingId.HasValue)
|
||||||
|
{
|
||||||
|
_apiClient.AutoLinkTemplatesAsync(drawingId.Value).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -238,7 +332,7 @@ namespace ExportDXF.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExportItems(List<Item> items, string saveDirectory, ExportContext context)
|
private void ExportItems(List<Item> items, string saveDirectory, ExportContext context, int? drawingId)
|
||||||
{
|
{
|
||||||
LogProgress(context, "", null);
|
LogProgress(context, "", null);
|
||||||
|
|
||||||
@@ -259,9 +353,51 @@ namespace ExportDXF.Services
|
|||||||
_partExporter.ExportItem(item, saveDirectory, context);
|
_partExporter.ExportItem(item, saveDirectory, context);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(item.FileName))
|
if (!string.IsNullOrEmpty(item.FileName))
|
||||||
|
{
|
||||||
successCount++;
|
successCount++;
|
||||||
|
|
||||||
|
// If we know the drawing, upload DXF and BOM row immediately
|
||||||
|
if (drawingId.HasValue)
|
||||||
|
{
|
||||||
|
var dxfPath = Path.Combine(saveDirectory, item.FileName + ".dxf");
|
||||||
|
if (File.Exists(dxfPath))
|
||||||
|
{
|
||||||
|
// Zip just this file
|
||||||
|
string zipPath = CreateZipWithSingleFile(dxfPath);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var okZip = _apiClient.UploadDxfZipAsync(drawingId.Value, zipPath).GetAwaiter().GetResult();
|
||||||
|
LogProgress(context, okZip ? $"Uploaded DXF: {Path.GetFileName(dxfPath)}" : $"Failed to upload DXF: {Path.GetFileName(dxfPath)}", okZip ? Color.Green : Color.Red);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try { if (File.Exists(zipPath)) File.Delete(zipPath); } catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create BOM item
|
||||||
|
var dto = new
|
||||||
|
{
|
||||||
|
DrawingID = drawingId.Value,
|
||||||
|
ItemNo = item.ItemNo,
|
||||||
|
PartNo = item.FileName,
|
||||||
|
Qty = (int?)item.Quantity,
|
||||||
|
Description = string.IsNullOrWhiteSpace(item.Description) ? null : item.Description,
|
||||||
|
PartName = string.IsNullOrWhiteSpace(item.PartName) ? null : item.PartName,
|
||||||
|
ConfigurationName = string.IsNullOrWhiteSpace(item.Configuration) ? null : item.Configuration,
|
||||||
|
Material = string.IsNullOrWhiteSpace(item.Material) ? null : item.Material,
|
||||||
|
SortOrder = 0,
|
||||||
|
CutTemplateID = (int?)null,
|
||||||
|
FormProgramID = (int?)null
|
||||||
|
};
|
||||||
|
var bomId = _apiClient.CreateBomItemAsync(dto).GetAwaiter().GetResult();
|
||||||
|
LogProgress(context, bomId.HasValue ? $"Created BOM item for {item.ItemNo ?? item.PartName}" : $"Failed to create BOM item for {item.ItemNo ?? item.PartName}", bomId.HasValue ? Color.Green : Color.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
failureCount++;
|
failureCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -274,79 +410,41 @@ namespace ExportDXF.Services
|
|||||||
|
|
||||||
LogProgress(context, $"Export complete: {successCount} succeeded, {failureCount} failed",
|
LogProgress(context, $"Export complete: {successCount} succeeded, {failureCount} failed",
|
||||||
failureCount > 0 ? Color.DarkBlue : Color.Green);
|
failureCount > 0 ? Color.DarkBlue : Color.Green);
|
||||||
|
|
||||||
// Create BOM Excel file
|
|
||||||
CreateBomExcelFile(items, saveDirectory, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region BOM Excel Creation
|
#region Temp + Upload Helpers
|
||||||
|
|
||||||
private void CreateBomExcelFile(List<Item> items, string saveDirectory, ExportContext context)
|
private string CreateTempWorkDir()
|
||||||
{
|
{
|
||||||
try
|
var path = Path.Combine(Path.GetTempPath(), "ExportDXF-" + Guid.NewGuid().ToString("N"));
|
||||||
{
|
Directory.CreateDirectory(path);
|
||||||
var bomFileName = GetBomFileName(context.FilePrefix);
|
return path;
|
||||||
var bomFilePath = Path.Combine(saveDirectory, bomFileName + ".xlsx");
|
|
||||||
|
|
||||||
_bomExcelExporter.CreateBOMExcelFile(bomFilePath, items);
|
|
||||||
|
|
||||||
LogProgress(context, $"Created BOM Excel file: {bomFileName}.xlsx", Color.Green);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogProgress(context, $"Failed to create BOM Excel: {ex.Message}", Color.Red);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetBomFileName(string prefix)
|
private string ParseDrawingNumber(ExportContext context)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(prefix))
|
// Prefer prefix (e.g., "5007 A02 PT"), fallback to active document title
|
||||||
return "BOM";
|
var candidate = context?.FilePrefix;
|
||||||
|
var info = string.IsNullOrWhiteSpace(candidate) ? null : DrawingInfo.Parse(candidate);
|
||||||
var drawingInfo = DrawingInfo.Parse(prefix);
|
if (info == null)
|
||||||
|
|
||||||
if (drawingInfo != null)
|
|
||||||
{
|
{
|
||||||
return $"{drawingInfo.JobNo} {drawingInfo.DrawingNo} BOM";
|
var title = context?.ActiveDocument?.Title;
|
||||||
|
info = string.IsNullOrWhiteSpace(title) ? null : DrawingInfo.Parse(title);
|
||||||
}
|
}
|
||||||
|
return info != null ? ($"{info.EquipmentNo} {info.DrawingNo}") : null;
|
||||||
return prefix.Trim() + " BOM";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
private string CreateZipWithSingleFile(string filePath)
|
||||||
|
|
||||||
#region User Interaction
|
|
||||||
|
|
||||||
private string PromptUserForDirectory(ExportContext context)
|
|
||||||
{
|
{
|
||||||
// Check if already canceled
|
var zipPath = Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath) + ".zip");
|
||||||
if (context.CancellationToken.IsCancellationRequested)
|
if (File.Exists(zipPath)) File.Delete(zipPath);
|
||||||
return null;
|
using (var zip = System.IO.Compression.ZipFile.Open(zipPath, System.IO.Compression.ZipArchiveMode.Create))
|
||||||
|
|
||||||
string selectedPath = null;
|
|
||||||
|
|
||||||
// Must run on STA thread for FolderBrowserDialog
|
|
||||||
var thread = new System.Threading.Thread(() =>
|
|
||||||
{
|
{
|
||||||
using (var dialog = new FolderBrowserDialog())
|
zip.CreateEntryFromFile(filePath, Path.GetFileName(filePath));
|
||||||
{
|
}
|
||||||
dialog.Description = "Where do you want to save the DXF files?";
|
return zipPath;
|
||||||
dialog.ShowNewFolderButton = true;
|
|
||||||
|
|
||||||
if (dialog.ShowDialog() == DialogResult.OK)
|
|
||||||
{
|
|
||||||
selectedPath = dialog.SelectedPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
thread.SetApartmentState(System.Threading.ApartmentState.STA);
|
|
||||||
thread.Start();
|
|
||||||
thread.Join();
|
|
||||||
|
|
||||||
return selectedPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -372,3 +470,5 @@ namespace ExportDXF.Services
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -283,7 +283,11 @@ namespace ExportDXF.Services
|
|||||||
return prefix + item.PartName;
|
return prefix + item.PartName;
|
||||||
}
|
}
|
||||||
|
|
||||||
return prefix + item.ItemNo.PadLeft(2, '0');
|
var num = item.ItemNo.PadLeft(2, '0');
|
||||||
|
// Expected format: {DrawingNo} PT{ItemNo}
|
||||||
|
return string.IsNullOrWhiteSpace(prefix)
|
||||||
|
? $"PT{num}"
|
||||||
|
: $"{prefix} PT{num}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogExportFailure(Item item, ExportContext context)
|
private void LogExportFailure(Item item, ExportContext context)
|
||||||
|
|||||||
@@ -5,5 +5,7 @@
|
|||||||
</startup>
|
</startup>
|
||||||
<appSettings>
|
<appSettings>
|
||||||
<add key="MaxBendRadius" value="2.0"/>
|
<add key="MaxBendRadius" value="2.0"/>
|
||||||
|
<!-- Deployed API base URL (default port from Deploy-CutFabApi.ps1) -->
|
||||||
|
<add key="CutFab.ApiBaseUrl" value="http://localhost:7027"/>
|
||||||
</appSettings>
|
</appSettings>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
Reference in New Issue
Block a user