using log4net;
|
using Microsoft.Win32;
|
using NPOI.SS.Formula.PTG;
|
using NPOI.SS.UserModel;
|
using NPOI.Util;
|
using NPOI.XSSF.UserModel;
|
using PdmSwPlugin.Commmon.Control;
|
using PdmSwPlugin.Commmon.Util.UI;
|
using PdmSwPlugin.Common;
|
using PdmSwPlugin.Common.Constants;
|
using PdmSwPlugin.Common.Control.TreeGrid;
|
using PdmSwPlugin.Common.Entity.DrawAudit;
|
using PdmSwPlugin.Common.Entity.Pdm;
|
using PdmSwPlugin.Common.Entity.System;
|
using PdmSwPlugin.Common.Interface;
|
using PdmSwPlugin.Common.Setting;
|
using PdmSwPlugin.Common.Util;
|
using PdmSwPlugin.Common.Util.Http;
|
using PdmSwPlugin.Common.Util.UI;
|
using PdmSwPlugin.PDM.Constant;
|
using PdmSwPlugin.PDM.Model;
|
using SolidWorks.Interop.sldworks;
|
using SolidWorks.Interop.swconst;
|
using System;
|
using System.Collections.Concurrent;
|
using System.Collections.Generic;
|
using System.Collections.ObjectModel;
|
using System.Diagnostics;
|
using System.IO;
|
using System.Linq;
|
using System.Net.Http;
|
using System.Threading;
|
using System.Threading.Tasks;
|
using System.Windows;
|
using System.Windows.Controls;
|
using System.Windows.Data;
|
using System.Windows.Interop;
|
using static PdmSwPlugin.PDM.Event.PdmEvent;
|
|
namespace PdmSwPlugin.PDM
|
{
|
/// <summary>
|
/// MainWindow.xaml 的交互逻辑
|
/// </summary>
|
[PdmSwPlugin(Title = "PDM")]
|
public partial class PdmControl : UserControl, IActiveDocChangeHandler
|
{
|
private static ILog Logger = LogManager.GetLogger("PDM");
|
SldWorks SwApp;
|
|
private Model.PdmControlModel model;
|
private readonly HttpClient Client;
|
private string CurrentUserName;
|
private readonly int MaxThreads;
|
private ModelDoc2 OpenDoc { get; set; }
|
private HttpClientCreator clientCreator { get; set; }
|
|
private volatile PdmStatus workStatus;
|
|
private TaskFactory taskFactory = LimitedConcurrencyLevelTaskSchedulerMsn.Factory;
|
|
SldWorks ISwAppSetter.SwApp => SwApp;
|
|
public PdmControl() : this(null)
|
{
|
}
|
|
public PdmControl(SldWorks swAddin)
|
{
|
SwApp = swAddin;
|
InitializeComponent();
|
// 滚动事件
|
// RaiseWheelEvent();
|
model = new Model.PdmControlModel();
|
model.bomTreeReader.SingleCompleted += BomTreeReader_SingleCompleted;
|
DataContext = model;
|
clientCreator = new HttpClientCreator(new HttpConfig(
|
PluginSetting.Instance.TimeOut,
|
PluginSetting.Instance.BaseAddress));
|
Client = clientCreator.GetClient();
|
CurrentUserName = System.Environment.UserName;
|
PdmBom.InBomChanged += PdmBom_InBomChanged;
|
InitDemonThread();
|
}
|
|
private void PdmBom_InBomChanged(object sender, bool e)
|
{
|
//if (e)
|
//{
|
// MaskAdorner.ShowMask(content, "请稍后...");
|
//}
|
//else {
|
// MaskAdorner.HideMask(content);
|
//}
|
|
MaskAdorner.ShowMask(content, "请稍后...");
|
|
Task.Run(() =>
|
{
|
try
|
{
|
workStatus = PdmStatus.READING;
|
PdmBom bom = sender as PdmBom;
|
bom.UpdateInBom(e);
|
RefreshBomTree();
|
}
|
finally
|
{
|
MaskAdorner.HideMask(content);
|
workStatus = PdmStatus.FREE;
|
}
|
});
|
}
|
|
private void RefreshBomTree()
|
{
|
var cache = model.BomTree;
|
model.BomTree = new ObservableCollection<PdmBom>();
|
model.BomTree = cache;
|
}
|
|
/// <summary>
|
/// 加载BOM结构时,单个BOM完成事件
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
private void BomTreeReader_SingleCompleted(object sender, PdmBom e)
|
{
|
MaskAdorner.ShowMessage(content, e.d3FilePath);
|
}
|
|
/// <summary>
|
/// 刷新BOM列表
|
/// 内部消化异常,不往外发
|
/// </summary>
|
public ObservableCollection<PdmBom> RefreshBomList(ModelDoc2 doc)
|
{
|
OpenDoc = doc;
|
try
|
{
|
if (doc == null)
|
{
|
this.Warning("请打开一张图纸");
|
return new ObservableCollection<PdmBom>();
|
}
|
//if (7 == doc.GetBlockingState())
|
//{
|
// this.Warning("请等待文档加载完毕");
|
// return new ObservableCollection<PdmBom>();
|
//}
|
|
DateTime beforeDT = DateTime.Now;
|
|
model.DoRefresh(Client, SwApp, doc);
|
|
DateTime now = DateTime.Now;
|
double times = DateTime.Now.Subtract(beforeDT).TotalMilliseconds;
|
return model.BomTree;
|
}
|
catch (Exception e)
|
{
|
// FillBomInfo(boms, bomInfos, drawInfos);
|
model.BomTree = new ObservableCollection<PdmBom>();
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, Refresh Bom List Failed.", e);
|
this.Error($"V{PdmUser.LoginUser.pluginVersion},刷新失败:{e.Message}");
|
return new ObservableCollection<PdmBom>();
|
}
|
}
|
|
public void AutoSaveAlert(List<string> msgs)
|
{
|
//Dispatcher.Invoke(() =>
|
//{
|
// MultiExWindow exWin = new MultiExWindow(this, "以下文档因删除特定配置而被保存", msgs, "文件路径");
|
// ShowExWindow(exWin);
|
//});
|
}
|
|
/// <summary>
|
/// 刷新按钮
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
private async void Refresh_Click(object sender, RoutedEventArgs e)
|
{
|
MaskAdorner.ShowMask(content, "请求中,请稍后...");
|
try
|
{
|
workStatus = PdmStatus.READING;
|
Logger.Debug("PDM插件,刷新列表...");
|
// !!! Task.Run中不能抛出异常,不然会中断程序
|
// 这里一定要用Task.Run,不然会阻塞UI线程,导致遮罩层显示不出来
|
// 垃圾WPF
|
await Task.Run(() =>
|
{
|
RefreshBomList(SwApp.IActiveDoc2);
|
if (model.bomTreeReader.needSaveList.Count > 0)
|
{
|
List<string> msgs = new List<string>(model.bomTreeReader.needSaveList);
|
AutoSaveAlert(msgs);
|
}
|
});
|
Logger.Debug("PDM插件,列表刷新完成!");
|
}
|
finally
|
{
|
workStatus = PdmStatus.FREE;
|
MaskAdorner.HideMask(content);
|
}
|
}
|
|
public void ValidateBoms(out string error)
|
{
|
error = null;
|
ObservableCollection<PdmBom> boms = model.BomTree;
|
if (boms == null || boms.Count <= 0)
|
{
|
error = string.Empty;
|
}
|
|
List<string> lostBoms = model.CacheList.Where(b => b.lost).Select(b => b.partModel).ToList();
|
if (lostBoms != null && lostBoms.Count > 0)
|
{
|
error = "[" + string.Join(",", lostBoms) + "]文件不存在!请检查";
|
}
|
}
|
|
/// <summary>
|
/// 检出操作,同步方法,不关注校验,校验放外边
|
/// </summary>
|
private object DoCheckOut()
|
{
|
ObservableCollection<PdmBom> boms = model.BomTree;
|
string bomId = boms[0].id;
|
PdmBomParam param = new PdmBomParam
|
{
|
id = bomId,
|
checkUserName = CurrentUserName
|
};
|
Result<object> res = Client.PostSyncAction<object>(param, "wpf/bom/openApi/checkOut");
|
return res.HandleResult();
|
}
|
|
/// <summary>
|
/// 检出操作,同步方法,不关注校验,校验放外边
|
/// </summary>
|
private Exception DoCheckOutAndRefresh()
|
{
|
try
|
{
|
_ = DoCheckOut();
|
RefreshBomList(SwApp.IActiveDoc2);
|
return null;
|
}
|
catch (Exception e)
|
{
|
return e;
|
}
|
}
|
|
/// <summary>
|
/// 检入操作,同步方法
|
/// </summary>
|
private object DoCheckIn()
|
{
|
Dictionary<string, object> param = new Dictionary<string, object> {
|
{ "treeList",model.BomTree },
|
{ "list",model.CacheList},
|
{ "checkInUsername",CurrentUserName}
|
};
|
Result<object> result = Client.PostSyncAction<object>(param, "wpf/bom/openApi/checkIn");
|
return result.HandleResult();
|
}
|
|
private Exception DoCheckInAndRefresh()
|
{
|
try
|
{
|
_ = DoCheckIn();
|
RefreshBomList(SwApp.IActiveDoc2);
|
return null;
|
}
|
catch (Exception e)
|
{
|
return e;
|
}
|
}
|
|
private bool SameDoc(out string message)
|
{
|
message = null;
|
ModelDoc2 currentDoc = SwApp.IActiveDoc2;
|
if (currentDoc.GetSaveFlag())
|
{
|
message = "请先保存当前文档";
|
return false;
|
}
|
// 傻逼C#,直接=赋值的对象==返回false,qnmd弱智东西
|
if (OpenDoc == currentDoc)
|
{
|
return true;
|
}
|
string sb1 = OpenDoc?.GetPathName();
|
string sb2 = currentDoc?.GetPathName();
|
if (sb1 != sb2)
|
{
|
message = "当前BOM与图纸不对应,请刷新BOM列表";
|
return false;
|
}
|
return true;
|
}
|
|
private async void CheckOut_Click(object sender, RoutedEventArgs e)
|
{
|
try
|
{
|
MaskAdorner.ShowMask(content);
|
if (!SameDoc(out string ErrMsg))
|
{
|
this.Warning(ErrMsg);
|
return;
|
}
|
|
ValidateBoms(out string message);
|
if (message != null)
|
{
|
if (message != string.Empty)
|
{
|
this.Show(message, true);
|
}
|
return;
|
}
|
Logger.Debug("PDM插件,开始检出...");
|
ObservableCollection<PdmBom> boms = model.BomTree;
|
string bomId = boms[0].id;
|
if (string.IsNullOrEmpty(bomId))
|
{
|
this.Show("该BOM并未检入!", true);
|
return;
|
}
|
// Task.Run中不能有未处理的异常,所以返回出来,放到主函数做异常处理
|
Exception error = await Task.Run(() =>
|
{
|
return DoCheckOutAndRefresh();
|
});
|
if (error != null)
|
{
|
throw error;
|
}
|
Logger.Debug("PDM插件,检出完成!");
|
this.Show("检出成功", true);
|
}
|
catch (Exception ex)
|
{
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion},Check In Bom Failed.", ex);
|
this.Error($"V{PdmUser.LoginUser.pluginVersion},检入Bom失败!{ex.Message}");
|
}
|
finally
|
{
|
MaskAdorner.HideMask(content);
|
}
|
}
|
|
private async void CheckIn_Click(object sender, RoutedEventArgs e)
|
{
|
try
|
{
|
Logger.Debug("PDM插件,开始检入...");
|
MaskAdorner.ShowMask(content);
|
if (!SameDoc(out string ErrMsg))
|
{
|
this.Warning(ErrMsg);
|
return;
|
}
|
|
ValidateBoms(out string message);
|
if (message != null)
|
{
|
if (message != string.Empty)
|
{
|
this.Show(message, true);
|
}
|
return;
|
}
|
Exception error = await Task.Run(() =>
|
{
|
return DoCheckInAndRefresh();
|
});
|
if (error != null)
|
{
|
throw error;
|
}
|
Logger.Debug("PDM插件,检入完成!");
|
this.Show("检入成功", true);
|
}
|
catch (Exception ex)
|
{
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, Check In BOM Failed.", ex);
|
this.Error($"V{PdmUser.LoginUser.pluginVersion},检入BOM失败!{ex.Message}");
|
}
|
finally
|
{
|
MaskAdorner.HideMask(content);
|
}
|
}
|
|
private async void CheckIn_Click2(object sender, RoutedEventArgs e)
|
{
|
try
|
{
|
MaskAdorner.ShowMask(content);
|
ValidateBoms(out string message);
|
if (message != null)
|
{
|
if (message != string.Empty)
|
{
|
this.Show(message, true);
|
}
|
return;
|
}
|
|
Dictionary<string, object> param = new Dictionary<string, object> {
|
{ "treeList",model.BomTree },
|
{ "list",model.CacheList},
|
{ "checkInUsername",CurrentUserName}
|
};
|
|
MultipartFormDataContent httpContent = new MultipartFormDataContent
|
{
|
{ new StringContent(JsonUtil.Serialize(param)), "sb" }
|
};
|
List<PdmBom> boms = model.GetModifiedBoms();
|
FileInfo fileInfo;
|
foreach (PdmBom bom in boms)
|
{
|
fileInfo = new FileInfo(bom.d3FilePath);
|
httpContent.Add(new ByteArrayContent(FileUtil.toByteArray(bom.d3FilePath)), bom.partModel + "_3d", fileInfo.Name);
|
if (!string.IsNullOrEmpty(bom.d2FilePath) && File.Exists(bom.d2FilePath))
|
{
|
fileInfo = new FileInfo(bom.d2FilePath);
|
httpContent.Add(new ByteArrayContent(FileUtil.toByteArray(bom.d2FilePath)), bom.partModel + "_2d", fileInfo.Name);
|
}
|
if (!string.IsNullOrEmpty(bom.pdfFilePath) && File.Exists(bom.pdfFilePath))
|
{
|
fileInfo = new FileInfo(bom.pdfFilePath);
|
httpContent.Add(new ByteArrayContent(FileUtil.toByteArray(bom.pdfFilePath)), bom.partModel + "_pdf", fileInfo.Name);
|
}
|
}
|
|
Result<object> result = await Client.PostAsyncAction<object>("wpf/bom/openApi/checkInWithFile", httpContent);
|
object res = result.HandleResult();
|
RefreshBomList(SwApp.IActiveDoc2);
|
this.Show("检入成功", true);
|
}
|
catch (Exception ex)
|
{
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, Check In Bom With File Failed.", ex);
|
this.Error($"V{PdmUser.LoginUser.pluginVersion},检入失败!{ex.Message}");
|
}
|
finally
|
{
|
MaskAdorner.HideMask(content);
|
}
|
}
|
|
private async void CheckIn_Click3(object sender, RoutedEventArgs e)
|
{
|
try
|
{
|
MaskAdorner.ShowMask(content);
|
if (!SameDoc(out string ErrMsg))
|
{
|
this.Warning(ErrMsg);
|
return;
|
}
|
|
ValidateBoms(out string message);
|
if (message != null)
|
{
|
if (message != string.Empty)
|
{
|
this.Show(message, true);
|
}
|
return;
|
}
|
Logger.Debug("PDM插件,带图纸的检入开始...");
|
// 图纸变更过的BOM,已经按照型号筛选过
|
List<PdmBom> modifiedBoms = model.GetModifiedBoms();
|
if (modifiedBoms.Count <= 0)
|
{
|
// 没有变更的图纸就直接检入,这里要用Task,否则蒙版不起作用
|
Exception err = await Task.Run(() =>
|
{
|
return DoCheckInAndRefresh();
|
});
|
if (err != null)
|
{
|
throw err;
|
}
|
this.Show("检入成功", true);
|
return;
|
}
|
|
// 多线程计数器
|
CountdownEvent counter = new CountdownEvent(modifiedBoms.Count);
|
// 异常收集
|
Dictionary<PdmBom, Exception> errors = new Dictionary<PdmBom, Exception>();
|
if (MaxThreads <= 0)
|
{
|
await Task.Run(() =>
|
{
|
SendFileToServerBatch(new object[] { modifiedBoms, counter, errors });
|
});
|
}
|
else
|
{
|
// 线程数
|
int taskCount = MaxThreads;
|
// 任务总数
|
int totalCount = modifiedBoms.Count;
|
// 每个线程处理的任务数
|
int eachCount = totalCount / taskCount;
|
// 余数
|
int otherCount = totalCount % taskCount;
|
int handledCount = 0;
|
for (int i = 0; i < taskCount; i++)
|
{
|
IEnumerable<PdmBom> boms;
|
if (i + 1 <= otherCount)
|
{
|
boms = modifiedBoms.Skip(handledCount).Take(eachCount + 1);
|
}
|
else
|
{
|
boms = modifiedBoms.Skip(handledCount).Take(eachCount);
|
}
|
handledCount += boms.Count();
|
await Task.Run(() =>
|
{
|
SendFileToServerBatch(new object[] { boms, counter, errors });
|
});
|
}
|
}
|
|
//foreach (var bom in modifiedBoms)
|
//{
|
// ThreadPool.QueueUserWorkItem(new WaitCallback(SendFileToServer), new object[] { bom, counter, errors });
|
//}
|
counter.Wait();
|
counter.Dispose();
|
if (errors.Count > 0)
|
{
|
string Msg = "";
|
foreach (PdmBom bom in errors.Keys)
|
{
|
Exception err = errors[bom];
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion},[{bom.partModel}] Upload Draw Failed.", err);
|
Msg += $"[{bom.partModel}]上传图纸错误!{err.Message}\r\n";
|
}
|
this.Show(Msg);
|
return;
|
}
|
Logger.Debug("PDM插件,带图纸的检入,图纸上传完成!正在检入...");
|
// Task.Run中不能有未处理的异常,所以返回出来,放到主函数做异常处理
|
Exception error = await Task.Run(() =>
|
{
|
return DoCheckInAndRefresh();
|
});
|
if (error != null)
|
{
|
throw error;
|
}
|
Logger.Debug("PDM插件,带图纸的检入,检入完成!");
|
this.Show("检入成功", true);
|
}
|
catch (Exception ex)
|
{
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, Check In BOM With File Failed.", ex);
|
this.Error($"V{PdmUser.LoginUser.pluginVersion},检入失败!{ex.Message}");
|
}
|
finally
|
{
|
MaskAdorner.HideMask(content);
|
}
|
}
|
|
private async void SendFileToServer(object state)
|
{
|
object[] args = (object[])state;
|
PdmBom mainBom = (PdmBom)args[0];
|
BomInfo param = new BomInfo()
|
{
|
partModel = mainBom.partModel,
|
d3FileId = mainBom.d3FileId,
|
d3FilePath = mainBom.d3FilePath,
|
|
d2FileId = mainBom.d2FileId,
|
d2FilePath = mainBom.d2FilePath,
|
|
pdfFileId = mainBom.pdfFileId,
|
pdfFilePath = mainBom.pdfFilePath,
|
|
checkUserName = CurrentUserName
|
};
|
|
CountdownEvent counter = (CountdownEvent)args[1];
|
Dictionary<PdmBom, Exception> errors = (Dictionary<PdmBom, Exception>)args[2];
|
|
try
|
{
|
FileInfo fileInfo;
|
var httpContent = new MultipartFormDataContent();
|
httpContent.Add(new StringContent(JsonUtil.Serialize(param)), "bomStr");
|
|
fileInfo = new FileInfo(param.d3FilePath);
|
httpContent.Add(new ByteArrayContent(FileUtil.toByteArray(param.d3FilePath)), param.partModel + "_3d", fileInfo.Name);
|
if (!string.IsNullOrEmpty(param.d2FilePath) && File.Exists(param.d2FilePath))
|
{
|
fileInfo = new FileInfo(param.d2FilePath);
|
httpContent.Add(new ByteArrayContent(FileUtil.toByteArray(param.d2FilePath)), param.partModel + "_2d", fileInfo.Name);
|
}
|
if (!string.IsNullOrEmpty(param.pdfFilePath) && File.Exists(param.pdfFilePath))
|
{
|
fileInfo = new FileInfo(param.pdfFilePath);
|
httpContent.Add(new ByteArrayContent(FileUtil.toByteArray(param.pdfFilePath)), param.partModel + "_pdf", fileInfo.Name);
|
}
|
|
Result<BomInfo> result = await Client.PostAsyncAction<BomInfo>("wpf/bom/openApi/updateBomFile", httpContent);
|
BomInfo res = result.HandleResult();
|
|
mainBom._drawInfo.d3Md5 = res.d3Md5;
|
mainBom._drawInfo.d2Md5 = res.d2Md5;
|
mainBom._drawInfo.pdfMd5 = res.pdfMd5;
|
|
mainBom._drawInfo.d3FileId = res.d3FileId;
|
mainBom._drawInfo.d2FileId = res.d2FileId;
|
mainBom._drawInfo.pdfFileId = res.pdfFileId;
|
|
}
|
catch (Exception e)
|
{
|
errors.Add(mainBom, e);
|
}
|
finally
|
{
|
_ = counter.Signal();
|
}
|
}
|
|
/// <summary>
|
/// 批量上传图纸到PDM服务器
|
/// </summary>
|
/// <param name="state">参数</param>
|
private void SendFileToServerBatch(object state)
|
{
|
object[] args = (object[])state;
|
IEnumerable<PdmBom> mainBoms = (IEnumerable<PdmBom>)args[0];
|
CountdownEvent counter = (CountdownEvent)args[1];
|
Dictionary<PdmBom, Exception> errors = (Dictionary<PdmBom, Exception>)args[2];
|
foreach (PdmBom mainBom in mainBoms)
|
{
|
BomInfo param = new BomInfo()
|
{
|
partModel = mainBom.partModel,
|
d3FileId = mainBom.d3FileId,
|
d3FilePath = mainBom.d3FilePath,
|
|
d2FileId = mainBom.d2FileId,
|
d2FilePath = mainBom.d2FilePath,
|
|
pdfFileId = mainBom.pdfFileId,
|
pdfFilePath = mainBom.pdfFilePath,
|
|
checkUserName = CurrentUserName
|
};
|
try
|
{
|
string d3FilePath = param.d3FilePath;
|
if (string.IsNullOrEmpty(d3FilePath) || !File.Exists(d3FilePath))
|
{
|
throw new Exception($"未找到3D图纸");
|
}
|
string d2FilePath = Path.Combine(Path.GetDirectoryName(d3FilePath), Path.GetFileNameWithoutExtension(d3FilePath) + ".SLDDRW");
|
if (string.IsNullOrEmpty(d2FilePath) || !File.Exists(d2FilePath))
|
{
|
throw new Exception($"未找到工程图文件");
|
}
|
FileInfo fileInfo;
|
MultipartFormDataContent httpContent = new MultipartFormDataContent();
|
httpContent.Add(new StringContent(JsonUtil.Serialize(param)), "bomStr");
|
fileInfo = new FileInfo(d3FilePath);
|
httpContent.Add(new ByteArrayContent(FileUtil.toByteArray(d3FilePath)), param.partModel + "_3d", fileInfo.Name);
|
fileInfo = new FileInfo(d2FilePath);
|
|
httpContent.Add(new ByteArrayContent(FileUtil.toByteArray(d2FilePath)), param.partModel + "_2d", fileInfo.Name);
|
if (!string.IsNullOrEmpty(param.pdfFilePath) && File.Exists(param.pdfFilePath))
|
{
|
fileInfo = new FileInfo(param.pdfFilePath);
|
httpContent.Add(new ByteArrayContent(FileUtil.toByteArray(param.pdfFilePath)), param.partModel + "_pdf", fileInfo.Name);
|
}
|
|
Result<BomInfo> result = Client.PostSyncAction<BomInfo>("wpf/bom/openApi/updateBomFile", httpContent);
|
BomInfo res = result.HandleResult();
|
|
mainBom._drawInfo.d3Md5 = res.d3Md5;
|
mainBom._drawInfo.d2Md5 = res.d2Md5;
|
mainBom._drawInfo.pdfMd5 = res.pdfMd5;
|
|
mainBom._drawInfo.d3FileId = res.d3FileId;
|
mainBom._drawInfo.d2FileId = res.d2FileId;
|
mainBom._drawInfo.pdfFileId = res.pdfFileId;
|
}
|
catch (Exception e)
|
{
|
errors.Add(mainBom, e);
|
}
|
finally
|
{
|
_ = counter.Signal();
|
}
|
}
|
}
|
|
/// <summary>
|
/// 为未建料的物料生成建料Excel
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
private void Excel_Click(object sender, RoutedEventArgs e)
|
{
|
if (!SameDoc(out string ErrMsg))
|
{
|
this.Warning(ErrMsg);
|
return;
|
}
|
|
List<PdmBom> nos = model.CacheList.Where(b => b.needOrdered && b.inDb != true).ToList();
|
if (nos.Count <= 0)
|
{
|
this.Show("没有需要建料的物料", true);
|
return;
|
}
|
try
|
{
|
Logger.Debug("PDM插件,正在导出新建物料...");
|
string targetPath;
|
SaveFileDialog dialog = new SaveFileDialog();
|
dialog.Filter = "文件|*.xlsx";
|
dialog.Title = "建料申请";
|
dialog.DefaultExt = "文件|*.xlsx";
|
dialog.FileName = "建料申请.xlsx";
|
if (dialog.ShowDialog() == true)
|
{
|
targetPath = dialog.FileName;
|
}
|
else
|
{
|
Logger.Debug("PDM插件,用户取消导出");
|
return;
|
}
|
|
// 从资源中获取模板
|
byte[] template = Properties.Resources.Template;
|
|
IWorkbook wb;
|
using (ByteArrayInputStream rfs = new ByteArrayInputStream(template))
|
{
|
wb = new XSSFWorkbook(rfs);
|
rfs.Close();
|
}
|
var sh = wb.GetSheetAt(0);
|
HashSet<string> models = new HashSet<string>();
|
int startRow = 6;
|
for (int i = 0; i < nos.Count; i++)
|
{
|
PdmBom bom = nos[i];
|
if (models.Contains(bom.partModel))
|
{
|
continue;
|
}
|
|
models.Add(bom.partModel);
|
sh.ShiftRows(startRow, startRow + 22, 1);
|
|
IRow row = sh.CreateRow(startRow);
|
IRow styleRow = sh.GetRow(startRow - 1);
|
row.Height = styleRow.Height;
|
|
row.CreateCell(0).SetCellValue(i + 1);
|
row.CreateCell(2).SetCellValue("pcs");
|
row.CreateCell(5).SetCellValue(bom.partModel);
|
row.CreateCell(6).SetCellValue("");
|
if (bom.jgj == true)
|
{
|
row.CreateCell(1).SetCellValue("A65");
|
string des = bom.partModel;
|
if (bom.properties.ContainsKey(PropertyName.JGJ_TYPE))
|
{
|
des += "-" + bom.properties[PropertyName.JGJ_TYPE];
|
}
|
if (bom.properties.ContainsKey(PropertyName.STUFF_TYPE))
|
{
|
des += "-" + bom.properties[PropertyName.STUFF_TYPE];
|
}
|
row.CreateCell(3).SetCellValue(des);
|
row.CreateCell(4).SetCellValue("加工件");
|
}
|
else
|
{
|
row.CreateCell(1).SetCellValue("");
|
row.CreateCell(3).SetCellValue("");
|
row.CreateCell(4).SetCellValue(bom.partBrandName);
|
}
|
for (int j = 0; j <= 6; j++)
|
{
|
row.GetCell(j).CellStyle = styleRow.GetCell(j).CellStyle;
|
}
|
|
startRow++;
|
}
|
FileStream fs = new FileStream(targetPath, FileMode.Create);
|
wb.Write(fs, false);
|
wb.Close();
|
Logger.Debug("PDM插件,新建物料导出完成!");
|
System.Diagnostics.Process.Start(targetPath);
|
}
|
catch (Exception ex)
|
{
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, Export Material Excel Failed.", ex);
|
this.Error($"V{PdmUser.LoginUser.pluginVersion},导出建料文档失败!{ex.Message}");
|
}
|
}
|
|
/// <summary>
|
/// 从服务器获取BOM信息
|
/// </summary>
|
/// <param name="topBomModel">顶层BOM型号</param>
|
/// <returns>型号-Bom字典</returns>
|
private Dictionary<string, BomInfo> GetBomsFromWeb(PdmBomParam param)
|
{
|
Result<Dictionary<string, BomInfo>> result =
|
Client.PostSyncAction<Dictionary<string, BomInfo>>(param, "wpf/bom/openApi/bomInfo");
|
Dictionary<string, BomInfo> bomInfo = result.HandleResult();
|
return bomInfo;
|
}
|
|
public void OnSwActiveDocChange(ModelDoc2 lastDoc, ModelDoc2 doc, Component2 comp)
|
{
|
//Dispatcher.Invoke(delegate
|
//{
|
// logger.Debug("PDM插件,切换文档事件触发...");
|
// Button_Click(null, null);
|
//});
|
}
|
|
public void SetSwApp(SldWorks SwApp)
|
{
|
this.SwApp = SwApp;
|
}
|
|
private void GlobalCheckBox_Checked(object sender, RoutedEventArgs e)
|
{
|
CheckBox cb = sender as CheckBox;
|
//PdmBom bom = cb.DataContext as PdmBom;
|
//bom.selected = cb.IsChecked.Value;
|
//List<PdmBom> allBoms = model.bomTreeReader.CacheList.ToList();
|
//foreach (PdmBom bom in allBoms)
|
//{
|
// if (bom.checkBoxEnabled)
|
// {
|
// bom.selected = cb.IsChecked.Value;
|
// }
|
//}
|
List<PdmBom> treeBoms = model.bomTreeReader.TreeList.ToList();
|
if (treeBoms == null || treeBoms.Count <= 0) return;
|
treeBoms[0].selected = cb.IsChecked.Value;
|
model.RefreshSelectedBomCount();
|
}
|
|
private void SingleCheckBox_Event(object sender, RoutedEventArgs e)
|
{
|
model.RefreshSelectedBomCount();
|
}
|
|
/// <summary>
|
/// SolidWorks文档保存后触发
|
/// 下面俩参数我也没搞懂有啥用
|
/// </summary>
|
/// <param name="doc">文档</param>
|
/// <param name="comp">组件</param>
|
public void OnSwActiveDocSaved(ModelDoc2 doc, Component2 comp)
|
{
|
// RefreshBomList(SwApp.IActiveDoc2);
|
}
|
|
private void treeDataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
|
{
|
TreeItemData row = e.Row.Item as TreeItemData;
|
PdmBom bom = row.Data as PdmBom;
|
// 型材子料不可选
|
// 丢失的BOM不可选
|
e.Row.IsEnabled = !(bom.xcChild == true || bom.lost);
|
}
|
|
public void OnCustomPropertyChange(string propName, string Configuration, string oldValue, string NewValue, int valueType)
|
{
|
//throw new NotImplementedException();
|
}
|
|
/// <summary>
|
/// 处理质量,保留6位小数
|
/// </summary>
|
/// <param name="number"></param>
|
/// <returns></returns>
|
public static string HandleMass(double number)
|
{
|
return Math.Round(number, 6).ToString("0.000000");
|
}
|
|
public DrawInfo GetSingleDrawInfo(PdmBom bom)
|
{
|
ModelDoc2 sldDoc = bom.doc;
|
Component2 component = bom.component;
|
Dictionary<string, string> allProperties = new Dictionary<string, string>();
|
allProperties["物料型号"] = bom.partModel;
|
DrawInfo drawInfo = bom._drawInfo;
|
drawInfo.isHidden = bom.isHidden;
|
drawInfo.allProperties = allProperties;
|
allProperties["压缩"] = bom.suppressed.ToString();
|
allProperties["轻量化"] = bom.lightWeight.ToString();
|
|
string filepath = component.GetPathName();
|
// 文件是否存在
|
allProperties["图纸是否存在"] = "true";
|
// 带后缀的全名
|
allProperties["文件全称"] = Path.GetFileName(filepath);
|
// 不带后缀的文件名
|
allProperties["文件名"] = Path.GetFileNameWithoutExtension(filepath);
|
// 文件后缀
|
allProperties["文件后缀"] = Path.GetExtension(filepath);
|
// 文件路径
|
allProperties["文件路径"] = filepath;
|
allProperties["历史图纸"] = drawInfo.HistoryData.ToString();
|
string drawFilePath = filepath.Replace(Path.GetExtension(filepath), ".slddrw");
|
bool drawExists = File.Exists(drawFilePath);
|
// 工程图一致性检查
|
allProperties["工程图是否存在"] = drawExists.ToString();
|
// 不跳过检查的加工件,如果工程图不存在,设置noDrw为true
|
if (!drawExists && !bom.skipCheck && bom.produceWay == "加工件")
|
{
|
drawInfo.noDrw = true;
|
}
|
allProperties["md5"] = bom.localD3Md5;
|
if (bom.lost || bom.BomInfo.isHidden || sldDoc == null)
|
{
|
allProperties["图纸是否存在"] = "false";
|
return drawInfo;
|
}
|
// 文件保存状态
|
allProperties["图纸保存状态"] = sldDoc.GetSaveFlag().ToString();
|
Dictionary<string, string> properties = CustomPropertyUtil.GetCustomProperties2(sldDoc, true, new HashSet<string>
|
{
|
"重量"
|
}, null);
|
// 图纸属性
|
if (properties != null)
|
{
|
foreach (string key in properties.Keys)
|
{
|
allProperties[key] = properties[key];
|
}
|
}
|
if (drawExists)
|
{
|
string[] refs = SwDMUtil.GetDrawingRef2(drawFilePath, out string err, out int[] status);
|
string refPath = "";
|
if (refs != null && refs.Length > 0)
|
{
|
foreach (var rf in refs)
|
{
|
if (string.Equals(rf, filepath, StringComparison.CurrentCultureIgnoreCase))
|
{
|
refPath = rf;
|
refPath = Path.GetFileName(refPath);
|
break;
|
}
|
}
|
}
|
else
|
{
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, [{drawFilePath}] Read slddrw Ref Path Failed.[{err}]");
|
}
|
|
//string refPath = SwDMUtil.GetDrawingRef(drawFilePath, out string errMsg);
|
//if (refPath == null)
|
//{
|
// Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, [{drawFilePath}] Read slddrw Ref Path Failed.[{errMsg}]");
|
//}
|
//else
|
//{
|
// refPath = Path.GetFileName(refPath);
|
//}
|
Logger.Debug($"V{PdmUser.LoginUser.pluginVersion},文档路径:【{filepath}】\r\n" +
|
$"工程图路径:【{drawFilePath}】\r\n" +
|
$"文件全称:【{allProperties["文件全称"]}】\r\n" +
|
$"Result:【{string.Join(",", refs ?? new string[] { })}】\r\n" +
|
$"Status:【{string.Join(",", status ?? new int[] { })}】\r\n" +
|
$"引用路径:【{refPath}】");
|
allProperties["工程图引用文件"] = refPath;
|
}
|
// 质量属性
|
try
|
{
|
// IModelDocExtension ext = sldDoc.Extension;
|
// double[] massPropertys = ext.GetMassProperties2(0, out int status, false);
|
double[] massPropertys = SwDMUtil.GetMassProperty(filepath, out string errMSg);
|
if (massPropertys == null)
|
{
|
throw new Exception(errMSg);
|
}
|
allProperties["体积"] = HandleMass(massPropertys[3]);
|
allProperties["表面积"] = HandleMass(massPropertys[4]);
|
allProperties["质量"] = HandleMass(massPropertys[5]);
|
Logger.Debug(JsonUtil.Serialize(massPropertys));
|
}
|
catch (Exception e)
|
{
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion},[{filepath}] Read Mass Properties Failed.", e);
|
}
|
allProperties["图纸类型"] = bom.produceWay;//bom.BomInfo.jgj;
|
|
bom.BomInfo.properties = allProperties;
|
return drawInfo;
|
}
|
|
public Dictionary<string, DrawInfo> GetAllPropertiesByTask(List<string> ErrMsgs)
|
{
|
ConcurrentDictionary<string, DrawInfo> result = new ConcurrentDictionary<string, DrawInfo>();
|
PdmBom topBom = model.BomTree[0];
|
CountdownEvent counter = new CountdownEvent(1);
|
GetAllByTask(new object[] { topBom, result, counter, ErrMsgs, 0 });
|
counter.Wait();
|
return new Dictionary<string, DrawInfo>(result);
|
}
|
|
public void GetAllByTask(object param)
|
{
|
object[] datas = param as object[];
|
PdmBom bom = (PdmBom)datas[0];
|
ModelDoc2 sldDoc = bom.doc;
|
Component2 component = bom.component;
|
ConcurrentDictionary<string, DrawInfo> result = (ConcurrentDictionary<string, DrawInfo>)datas[1];
|
CountdownEvent counter = (CountdownEvent)datas[2];
|
List<string> ErrMsgs = (List<string>)datas[3];
|
int level = (int)datas[4];
|
try
|
{
|
counter.AddCount();
|
string filepath = bom.partNo;
|
lock (result)
|
{
|
if (result.ContainsKey(filepath))
|
{
|
if (bom.isHidden)
|
{
|
result[filepath].isHidden = true;
|
}
|
return;
|
}
|
if (!bom.skipCheck)
|
{
|
result[filepath] = GetSingleDrawInfo(bom);
|
if (bom.BomInfo.inKeeDeeDb == true) result[filepath]._inKeeDeeDb = true;
|
|
}
|
}
|
|
ObservableCollection<PdmBom> children = bom.modules;
|
if (children != null)
|
{
|
foreach (PdmBom child in children)
|
{
|
taskFactory.StartNew(() =>
|
{
|
GetAllByTask(new object[] { child, result, counter, ErrMsgs, 1 });
|
});
|
}
|
}
|
MaskAdorner.ShowMessage(content, filepath);
|
}
|
catch (Exception e)
|
{
|
bom.drawInfo.checkRuleResult = 2;
|
bom.drawInfo.errMessages = new List<string> { e.Message };
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion},[{bom.filePath}] Read MASS Properies Failed.", e);
|
}
|
finally
|
{
|
counter.Signal();
|
if (level == 0)
|
{
|
counter.Signal();
|
}
|
}
|
}
|
|
public bool DoCheckRuleAsync(out List<string> messages)
|
{
|
var temp = new List<string>();
|
bool allSuccess = true;
|
Dictionary<string, DrawInfo> properties = GetAllPropertiesByTask(temp);
|
MaskAdorner.ShowMessage(content, "正在请求数据...");
|
// var factory = LimitedConcurrencyLevelTaskScheduler.Factory;
|
CountdownEvent counter = new CountdownEvent(properties.Count);
|
int iii = 0;
|
var start = DateTime.Now;
|
Logger.Debug("DoCheckRuleAsync Start...");
|
foreach (KeyValuePair<string, DrawInfo> property in properties)
|
{
|
/// Task.Run 这个方法最快,但不好管控,因为不知道属性字典有多大
|
/// taskFactory.StartNew 稳定一点吗?
|
taskFactory.StartNew(() =>
|
{
|
string key = property.Key;
|
iii++;
|
try
|
{
|
Logger.Debug($"{key} checking rule...");
|
DrawInfo checkResult;
|
Result<DrawInfo> result = Client.PostSyncAction<DrawInfo>(property.Value, "wpf/bom/openApi/checkRuleSingle");
|
checkResult = result.HandleResult();
|
properties[key].checkRuleResult = checkResult.checkRuleResult;
|
properties[key].errMessages = checkResult.errMessages;
|
var msgs = checkResult.errMessages;
|
if (property.Value.noDrw || property.Value.isHidden || (!properties[key].HistoryData && (!checkResult.checkRuleOk)))
|
{
|
allSuccess = false;
|
}
|
|
lock (temp)
|
{
|
if (property.Value.isHidden)
|
{
|
temp.Add($"物料【{key}】被设置为隐藏!");
|
}
|
if (property.Value.noDrw && property.Value.HistoryData)
|
{
|
temp.Add($"物料【{key}】未找到工程图!");
|
}
|
if (!properties[key].HistoryData)
|
{
|
if (msgs != null && msgs.Count > 0)
|
{
|
foreach (string msg in msgs)
|
{
|
temp.Add($"物料【{key}】未通过规则检查!{msg}");
|
}
|
}
|
}
|
}
|
MaskAdorner.ShowMessage(content, $"物料【{key}】检查完成");
|
}
|
catch (Exception ex)
|
{
|
properties[key].checkRuleResult = 2;
|
properties[key].errMessages = new List<string> { "发起检查失败,请重试" };
|
lock (temp)
|
{
|
temp.Add($"物料【{key}】发起检查失败,请重试");
|
}
|
allSuccess = false;
|
MaskAdorner.ShowMessage(content, $"物料【{key}】检查完成");
|
}
|
finally
|
{
|
counter.Signal();
|
}
|
});
|
|
//LimitedConcurrencyLevelTaskScheduler scheduler = new LimitedConcurrencyLevelTaskScheduler(int.MaxValue);
|
//Task.Factory.StartNew(() => {
|
// string key = property.Key;
|
// iii++;
|
// try
|
// {
|
// Logger.Error($"{key} checking rule...");
|
// Result<DrawInfo> result = Client.PostSyncAction<DrawInfo>(property.Value, "wpf/bom/openApi/checkRuleSingle");
|
// DrawInfo checkResult = result.HandleResult();
|
// properties[key].checkRuleResult = checkResult.checkRuleResult;
|
// properties[key].errMessages = checkResult.errMessages;
|
// var msgs = checkResult.errMessages;
|
// if (!properties[key].HistoryData && !checkResult.checkRuleOk)
|
// {
|
// allSuccess = false;
|
// }
|
|
// if (!properties[key].HistoryData && msgs != null && msgs.Count > 0)
|
// {
|
// lock (temp)
|
// {
|
// foreach (string msg in msgs)
|
// {
|
// temp.Add($"物料【{key}】未通过规则检查!{msg}");
|
// }
|
// }
|
// }
|
// MaskAdorner.ShowMessage(content, $"物料【{key}】检查完成");
|
// }
|
// catch (Exception ex)
|
// {
|
// properties[key].checkRuleResult = 2;
|
// properties[key].errMessages = new List<string> { "发起检查失败,请重试" };
|
// lock (temp)
|
// {
|
// temp.Add($"物料【{key}】发起检查失败,请重试");
|
// }
|
// allSuccess = false;
|
// MaskAdorner.ShowMessage(content, $"物料【{key}】检查完成");
|
// }
|
// finally
|
// {
|
// counter.Signal();
|
// }
|
//}, CancellationToken.None, TaskCreationOptions.None, scheduler);
|
|
|
/// 下面两个都在管控Task数量,但还是很慢
|
/*string key = property.Key;
|
_ = ThreadPool.QueueUserWorkItem(
|
(WaitCallback)delegate
|
{
|
iii++;
|
try
|
{
|
Logger.Error($"{key} checking rule...");
|
Result<DrawInfo> result = Client.PostSyncAction<DrawInfo>(property.Value, "wpf/bom/openApi/checkRuleSingle");
|
DrawInfo checkResult = result.HandleResult();
|
properties[key].checkRuleResult = checkResult.checkRuleResult;
|
properties[key].errMessages = checkResult.errMessages;
|
var msgs = checkResult.errMessages;
|
if (!properties[key].HistoryData && !checkResult.checkRuleOk)
|
{
|
allSuccess = false;
|
}
|
|
if (!properties[key].HistoryData && msgs != null && msgs.Count > 0)
|
{
|
lock (temp)
|
{
|
foreach (string msg in msgs)
|
{
|
temp.Add($"物料【{key}】未通过规则检查!{msg}");
|
}
|
}
|
}
|
MaskAdorner.ShowMessage(content, $"物料【{key}】检查完成");
|
}
|
catch (Exception ex)
|
{
|
properties[key].checkRuleResult = 2;
|
properties[key].errMessages = new List<string> { "发起检查失败,请重试" };
|
lock (temp)
|
{
|
temp.Add($"物料【{key}】发起检查失败,请重试");
|
}
|
allSuccess = false;
|
MaskAdorner.ShowMessage(content, $"物料【{key}】检查完成");
|
}
|
finally
|
{
|
counter.Signal();
|
}
|
});*/
|
|
//factory.StartNew(() =>
|
//{
|
// string key = property.Key;
|
// iii++;
|
// try
|
// {
|
// Logger.Error($"{key} checking rule...");
|
// Result<DrawInfo> result = Client.PostSyncAction<DrawInfo>(property.Value, "wpf/bom/openApi/checkRuleSingle");
|
// DrawInfo checkResult = result.HandleResult();
|
// properties[key].checkRuleResult = checkResult.checkRuleResult;
|
// properties[key].errMessages = checkResult.errMessages;
|
// var msgs = checkResult.errMessages;
|
// if (!properties[key].HistoryData && !checkResult.checkRuleOk)
|
// {
|
// allSuccess = false;
|
// }
|
|
// if (!properties[key].HistoryData && msgs != null && msgs.Count > 0)
|
// {
|
// lock (temp)
|
// {
|
// foreach (string msg in msgs)
|
// {
|
// temp.Add($"物料【{key}】未通过规则检查!{msg}");
|
// }
|
// }
|
// }
|
// MaskAdorner.ShowMessage(content, $"物料【{key}】检查完成");
|
// }
|
// catch (Exception ex)
|
// {
|
// properties[key].checkRuleResult = 2;
|
// properties[key].errMessages = new List<string> { "发起检查失败,请重试" };
|
// lock (temp)
|
// {
|
// temp.Add($"物料【{key}】发起检查失败,请重试");
|
// }
|
// allSuccess = false;
|
// MaskAdorner.ShowMessage(content, $"物料【{key}】检查完成");
|
// }
|
// finally
|
// {
|
// counter.Signal();
|
// }
|
//});
|
}
|
counter.Wait();
|
counter.Dispose();
|
messages = temp;
|
Logger.Debug($"DoCheckRuleAsync Ended in {(DateTime.Now - start).TotalMilliseconds}ms.");
|
return allSuccess;
|
}
|
|
private void ShowExWindow(MultiExWindow exWin)
|
{
|
IntPtr winformWindow = Process.GetCurrentProcess().MainWindowHandle;
|
if (winformWindow != null)
|
new WindowInteropHelper(exWin) { Owner = winformWindow };
|
exWin.ShowDialog();
|
}
|
|
/// <summary>
|
/// 规则检查按钮点击事件
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
private void CheckRule_Click(object sender, RoutedEventArgs e)
|
{
|
if (SwApp.IActiveDoc2 == null)
|
{
|
RefreshBomList(null);
|
return;
|
}
|
workStatus = PdmStatus.CHECKING;
|
MaskAdorner.ShowMask(content, "检查中,请稍后...");
|
Task.Run(() =>
|
{
|
try
|
{
|
RefreshBomList(SwApp.IActiveDoc2);
|
if (model.bomTreeReader.needSaveList.Count > 0)
|
{
|
List<string> infos = new List<string>(model.bomTreeReader.needSaveList);
|
AutoSaveAlert(infos);
|
}
|
|
if (!DoCheckRuleAsync(out List<string> msgs))
|
{
|
Dispatcher.Invoke(() =>
|
{
|
MultiExWindow exWin = new MultiExWindow(this, "检查结果", msgs);
|
ShowExWindow(exWin);
|
});
|
}
|
}
|
catch (Exception ex)
|
{
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, PDM check rule failed.", ex);
|
this.Error($"V{PdmUser.LoginUser.pluginVersion},图纸检查执行失败!{ex.Message}");
|
}
|
finally
|
{
|
workStatus = PdmStatus.FREE;
|
MaskAdorner.HideMask(content);
|
}
|
});
|
}
|
|
/// <summary>
|
/// 刷新WEB数据
|
/// </summary>
|
public void RefreshWebBomInfo()
|
{
|
model.RefreshWebInfo(Client);
|
}
|
|
/// <summary>
|
/// 发起审批按钮点击
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
public void DrawAudit_Click(object sender, RoutedEventArgs e)
|
{
|
if (SwApp.IActiveDoc2 == null)
|
{
|
RefreshBomList(null);
|
return;
|
}
|
workStatus = PdmStatus.UPLOADING;
|
MaskAdorner.ShowMask(content, "请求中,请稍等...");
|
Task.Run(() =>
|
{
|
try
|
{
|
// 对所有的BOM做规则检查
|
bool allSuccess = DoCheckRuleAsync(out _);
|
// 先获取所有的BOM
|
HashSet<string> cache = new HashSet<string>();
|
// 然后筛选选中的BOM
|
List<PdmBom> boms = model.bomTreeReader.CacheList.Where(b => b.selected).ToList();
|
if (boms == null || boms.Count <= 0)
|
{ // 如果没有选中的BOM,那就是所有BOM
|
boms = model.bomTreeReader.CacheList.ToList();
|
}
|
// 筛选有图纸的,在物料明细中,未提交的,在物料明细表中的零件体加工件进行上传
|
boms = boms.Where(b =>
|
{
|
if (!cache.Contains(b.partModel))
|
{
|
cache.Add(b.partModel);
|
return b.NeedAudit;
|
}
|
return false;
|
}).ToList();
|
|
if (boms == null || boms.Count <= 0)
|
{
|
this.Warning("只有未提交过或发生变更的加工件图纸可以进行审核");
|
return;
|
}
|
|
if (!allSuccess)
|
{
|
// 如果有未通过的图纸,需要提示
|
var err = boms.Where(b => b.noDrw || b.isHidden || (!b.IsHistoryData && (!b.checkRuleOk))).ToList();
|
if (err != null && err.Count > 0)
|
{
|
List<string> msgs = new List<string>();
|
foreach (var ee in err)
|
{
|
if (ee.noDrw && ee.IsHistoryData)
|
{
|
msgs.Add($"物料【{ee.partNo}】未通过规则检查!未找到工程图");
|
}
|
if (ee.drawInfo.isHidden)
|
{
|
msgs.Add($"物料【{ee.partNo}】未通过规则检查!被设为隐藏");
|
}
|
if (ee.drawInfo.errMessages == null)
|
{
|
msgs.Add($"物料【{ee.partNo}】未通过规则检查!");
|
continue;
|
}
|
foreach (string msg in ee.drawInfo.errMessages)
|
{
|
msgs.Add($"物料【{ee.partNo}】未通过规则检查!{msg}");
|
}
|
}
|
|
Dispatcher.Invoke(() =>
|
{
|
MultiExWindow exWin = new MultiExWindow(this, "多个待提交的图纸未通过规则检查,请确认", msgs);
|
ShowExWindow(exWin);
|
});
|
return;
|
}
|
}
|
|
// 都通过了,再进行审批
|
|
// 筛选非特殊的审核
|
boms = boms.Where(b => !b._drawInfo.isSpecial).ToList();
|
if (boms == null || boms.Count <= 0) return;
|
|
// 先申请单号
|
DrawAuditOrder daOrder = new DrawAuditOrder
|
{
|
requestUserId = PdmUser.LoginUser.id,
|
requestUser = PdmUser.LoginUser.realname
|
};
|
try
|
{
|
Result<DrawAuditOrder> res = Client.PostSyncAction<DrawAuditOrder>(daOrder, "drawAudit/order/create");
|
daOrder = res.HandleResult();
|
}
|
catch (Exception ex)
|
{
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, Request AuditOrder Code Failed.", ex);
|
this.Error($"V{PdmUser.LoginUser.pluginVersion},请求审批单号失败! {ex.Message}");
|
return;
|
}
|
|
ConcurrentQueue<string> errs = new ConcurrentQueue<string>();
|
CountdownEvent counter = new CountdownEvent(boms.Count);
|
int successCount = 0;
|
ConcurrentQueue<string> pathCache = new ConcurrentQueue<string>(boms.Select(b => b.filePath).ToList());
|
foreach (PdmBom bom in boms)
|
{
|
taskFactory.StartNew(() =>
|
{
|
try
|
{
|
MaskAdorner.ShowMessage(content, $"正在上传【{bom.partNo}】...");
|
UploadDraw(daOrder, bom, pathCache);
|
Interlocked.Increment(ref successCount);
|
}
|
catch (Exception ex)
|
{
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, [{bom.partModel}] Request Audit Failed.", ex);
|
errs.Enqueue($"物料【{bom.partModel}】发起审批失败!{ex.Message}");
|
}
|
finally
|
{
|
counter.Signal();
|
}
|
});
|
}
|
counter.Wait();
|
counter.Dispose();
|
if (successCount > 0)
|
{
|
try
|
{
|
var param = new DrawAudit
|
{
|
orderId = daOrder.id,
|
count = successCount
|
};
|
var msgRes = Client.PostSyncAction<object>(param, "drawAudit/sendToAuditor");
|
msgRes.HandleResult();
|
}
|
catch (Exception ig)
|
{
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, Send Audit Socket Failed.", ig);
|
}
|
}
|
// 刷新服务器上的BOM信息
|
RefreshWebBomInfo();
|
if (errs.Count > 0)
|
{
|
Dispatcher.Invoke(() =>
|
{
|
MultiExWindow exWindow = new MultiExWindow(this, "审批失败", errs.ToList());
|
exWindow.ShowDialog();
|
});
|
}
|
}
|
catch (Exception ex)
|
{
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, Request audit failed", ex);
|
this.Error($"V{PdmUser.LoginUser.pluginVersion},发起审批异常!{ex}");
|
}
|
finally
|
{
|
workStatus = PdmStatus.FREE;
|
MaskAdorner.HideMask(content);
|
}
|
});
|
}
|
|
/// <summary>
|
/// 上传图纸操作
|
/// </summary>
|
/// <param name="daOrder"></param>
|
/// <param name="bom"></param>
|
private void UploadDraw(DrawAuditOrder daOrder, PdmBom bom, ConcurrentQueue<string> pathCache)
|
{
|
if (bom.BomInfo.drawingType == (int)swDocumentTypes_e.swDocASSEMBLY && bom.children != null && bom.children.Count > 0)
|
{
|
foreach (PdmBom child in bom.children)
|
{
|
UploadChildDraw(daOrder, child, true, pathCache);
|
}
|
}
|
UploadSingleDraw(daOrder, bom, false);
|
}
|
|
/// <summary>
|
/// 上传子零件图纸,有递归
|
/// </summary>
|
/// <param name="daOrder"></param>
|
/// <param name="bom"></param>
|
/// <param name="justUpload"></param>
|
private void UploadChildDraw(DrawAuditOrder daOrder, PdmBom bom, bool justUpload, ConcurrentQueue<string> pathCache)
|
{
|
if (bom.BomInfo.drawingType == (int)swDocumentTypes_e.swDocASSEMBLY && bom.children != null && bom.children.Count > 0)
|
{
|
foreach (PdmBom child in bom.children)
|
{
|
UploadChildDraw(daOrder, child, justUpload, pathCache);
|
}
|
}
|
if (!pathCache.Contains(bom.filePath))
|
{
|
UploadSingleDraw(daOrder, bom, justUpload);
|
pathCache.Append(bom.filePath);
|
}
|
}
|
|
/// <summary>
|
/// 上传单张图纸
|
/// </summary>
|
/// <param name="daOrder"></param>
|
/// <param name="bom"></param>
|
/// <param name="justUpload"></param>
|
/// <exception cref="Exception"></exception>
|
private void UploadSingleDraw(DrawAuditOrder daOrder, PdmBom bom, bool justUpload)
|
{
|
try
|
{
|
string d3FilePath = bom.d3FilePath;
|
string d2FilePath = d3FilePath.Replace(Path.GetExtension(d3FilePath), ".slddrw");
|
if (string.IsNullOrEmpty(d3FilePath) || !File.Exists(d3FilePath))
|
{
|
throw new Exception($"[{bom.partModel}]未找到3D图纸");
|
}
|
// !justUpload(需要审核)要判断2D图纸存不存在
|
if (!justUpload && (string.IsNullOrEmpty(d2FilePath) || !File.Exists(d2FilePath)))
|
{
|
throw new Exception($"[{bom.partModel}]未找到工程图纸");
|
}
|
MultipartFormDataContent httpContent = new MultipartFormDataContent();
|
httpContent.Add(new StringContent(bom.partNo), "materialCode");
|
httpContent.Add(new StringContent(bom.partNo), "materialModel");
|
httpContent.Add(new StringContent(daOrder.id), "orderId");
|
httpContent.Add(new StringContent(justUpload.ToString()), "justUpload");
|
FileInfo fileInfo = new FileInfo(d3FilePath);
|
httpContent.Add(new ByteArrayContent(FileUtil.toByteArray(d3FilePath)), "d3File", fileInfo.Name);
|
// !justUpload(需要审核)要上传2D图
|
if (!justUpload)
|
{
|
FileInfo file2Info = new FileInfo(d2FilePath);
|
httpContent.Add(new ByteArrayContent(FileUtil.toByteArray(d2FilePath)), "d2File", file2Info.Name);
|
}
|
Result<DrawAudit> res = Client.PostSyncAction<DrawAudit>("drawAudit/add", httpContent);
|
DrawAudit da = res.HandleResult();
|
}
|
catch (NullReferenceException nex)
|
{
|
Logger.Error($"UploadSingleDraw NullReferenceException.", nex);
|
}
|
}
|
|
private void Exclude_Click(object sender, RoutedEventArgs e)
|
{
|
if (SwApp.IActiveDoc2 == null)
|
{
|
RefreshBomList(null);
|
return;
|
}
|
if (SwApp.SendMsgToUser2("确定将未通过的物料全部排除物料明细表吗?", (int)swMessageBoxIcon_e.swMbWarning
|
, (int)swMessageBoxBtn_e.swMbYesNo) == (int)swMessageBoxResult_e.swMbHitYes)
|
{
|
MaskAdorner.ShowMask(content, "操作中,请稍后...");
|
Task.Run(() =>
|
{
|
try
|
{
|
workStatus = PdmStatus.READING;
|
List<PdmBom> boms = model.bomTreeReader.CacheList.Where(b => b.BomInfo.status == "rejected")
|
.ToList();
|
if (boms == null || boms.Count <= 0)
|
{
|
this.Warning("没有未通过的物料");
|
return;
|
}
|
Dispatcher.Invoke(() =>
|
{
|
foreach (PdmBom bom in boms)
|
{
|
bom.UpdateInBom(true);
|
}
|
RefreshBomTree();
|
});
|
|
}
|
finally
|
{
|
workStatus = PdmStatus.FREE;
|
MaskAdorner.HideMask(content);
|
}
|
});
|
}
|
}
|
|
/// <summary>
|
/// 树数据展示过滤
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
|
{
|
if (e.Item is TreeItemData data)
|
{
|
e.Accepted = data.IsVisible;
|
}
|
}
|
|
/// <summary>
|
/// 树展开/关闭事件
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
private void treeDataGrid_ExpandedChange(object sender, bool e)
|
{
|
CollectionViewSource cvs = this.Resources["TreeGridFilter"] as CollectionViewSource;
|
cvs?.View.Refresh();
|
}
|
|
/// <summary>
|
/// 双击打开检查结果
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
private void TextBox_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
{
|
try
|
{
|
// 检查是否是双击
|
if (e.ClickCount == 2)
|
{
|
TextBlock textBlock = sender as TextBlock;
|
PdmBom bom = textBlock.DataContext as PdmBom;
|
if (bom.checkRuleResult == 0)
|
{
|
this.Warning("该图纸还未检查");
|
return;
|
}
|
|
List<string> errs = new List<string>();
|
if (bom.noDrw && bom.IsHistoryData)
|
{
|
errs.Add("工程图不存在 ");
|
}
|
if (bom.isHidden)
|
{
|
errs.Add("文档被设置为隐藏");
|
}
|
if (bom.drawInfo.errMessages != null)
|
{
|
errs.AddRange(bom.drawInfo.errMessages);
|
}
|
if (errs.Count > 0)
|
{
|
MultiExWindow exWin = new MultiExWindow(this, "检查结果", errs);
|
ShowExWindow(exWin);
|
}
|
else if (bom.checkRuleResult == 3)
|
{
|
string title = string.Empty;
|
if (bom.IsHistoryData)
|
{
|
title = "历史图纸无需检查";
|
}
|
else if (bom.ExcludeFromBOM)
|
{
|
title = "不在物料明细表中的物料无需检查";
|
}
|
else if (bom.component?.IsVirtual == true)
|
{
|
title = "虚拟件无需检查";
|
}
|
else
|
{
|
title = "无需检查";
|
}
|
this.Info(title);
|
return;
|
}
|
else if (bom.checkRuleOk && !bom.isHidden)
|
{
|
this.Show("规则检查通过");
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
Logger.Error("Double Click CheckRule Exception.", ex);
|
this.Error($"未知异常:{ex.Message}");
|
}
|
}
|
|
/// <summary>
|
/// 双击打开审核详情
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
private void AuditTextBox_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
{
|
try
|
{
|
// 检查是否是双击
|
if (e.ClickCount == 2)
|
{
|
TextBlock textBlock = sender as TextBlock;
|
PdmBom bom = textBlock.DataContext as PdmBom;
|
if (bom._drawInfo.isSpecial)
|
{
|
this.Info("无需审核");
|
return;
|
}
|
if (bom.BomInfo.inKeeDeeDb == true)
|
{
|
this.Info("已入系统");
|
return;
|
}
|
if (string.IsNullOrEmpty(bom.BomInfo.status))
|
{
|
if (bom.produceWay == "模组" || bom.produceWay == "标准件")
|
{
|
this.Info($"{bom.produceWay}无需审核");
|
return;
|
}
|
if (bom.IsHistoryData && !bom.localDocChanged)
|
{
|
this.Info("历史图纸无需审核");
|
return;
|
}
|
if (bom.IsHistoryData && bom.localDocChanged)
|
{
|
this.Info("历史图纸一致性变更,需审核");
|
return;
|
}
|
this.Warning("该图纸未审核");
|
return;
|
}
|
MaskAdorner.ShowMask(content, "请求中,请稍后...");
|
Task.Run(() =>
|
{
|
try
|
{
|
Result<List<DrawAuditHis>> res = Client.GetSyncAction<List<DrawAuditHis>>("drawAudit/listTaskHis", new DrawAudit
|
{
|
id = bom.BomInfo.id
|
});
|
var datas = res.HandleResult();
|
Dispatcher.Invoke(() =>
|
{
|
//DrawAuditHisWindow window = new DrawAuditHisWindow(this, $"【{bom.partModel}】审核详情", datas);
|
RichHisWindow window = new RichHisWindow(this, $"【{bom.partModel}】审核详情", datas);
|
|
window.ShowDialog();
|
});
|
}
|
catch (Exception ex)
|
{
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, Get draw audit history failed.", ex);
|
this.Error($"V{PdmUser.LoginUser.pluginVersion},获取审核历史失败!{ex.Message}");
|
}
|
finally
|
{
|
MaskAdorner.HideMask(content);
|
}
|
});
|
}
|
}
|
catch (Exception ex)
|
{
|
Logger.Error("Double Click Audit Status Exception.", ex);
|
this.Error($"未知异常:{ex.Message}");
|
}
|
}
|
|
|
private volatile IntPtr importPtr = IntPtr.Zero;
|
private volatile IntPtr checkInPtr = IntPtr.Zero;
|
|
private readonly object importLock = new object();
|
private readonly object checkInLock = new object();
|
|
// 捕捉到插件启动事件
|
private event PtrHandler PtrCheckHandler;
|
|
/// <summary>
|
/// 搜索是否有导入窗口,有就一直最小化,并执行规则检查
|
/// </summary>
|
/// <returns></returns>
|
private async Task ListenImportHandle()
|
{
|
IntPtr ptr = WindowIntPtrUtil.FindWindow(null, PluginSetting.Instance.ImportListenName);
|
if (ptr == IntPtr.Zero)
|
{
|
return;
|
}
|
if (ptr != importPtr)
|
{
|
WindowIntPtrUtil.ShowWindow(ptr, 6);
|
lock (importLock)
|
{
|
importPtr = ptr;
|
PtrCheckHandler += ImportHandler;
|
}
|
await PtrHandler2();
|
}
|
else if (workStatus == PdmStatus.DO_LISTENING)
|
{
|
WindowIntPtrUtil.ShowWindow(ptr, 6);
|
}
|
}
|
|
/// <summary>
|
/// 规则检查执行完之后的操作,成功就激活导入窗口,失败就关闭导入窗口
|
/// </summary>
|
/// <param name="errs"></param>
|
/// <param name="ex"></param>
|
/// <param name="success"></param>
|
private void ImportHandler(List<string> errs, Exception ex, bool success)
|
{
|
lock (importLock)
|
{
|
if (success)
|
{
|
WindowIntPtrUtil.ShowWindow(importPtr, 1);
|
}
|
else
|
{
|
WindowIntPtrUtil.KillProcessByIntPtr(importPtr);
|
importPtr = IntPtr.Zero;
|
}
|
PtrCheckHandler -= ImportHandler;
|
}
|
}
|
|
/// <summary>
|
/// 搜索是否有检入窗口,有就一直最小化,并执行规则检查
|
/// </summary>
|
/// <returns></returns>
|
private async Task ListenCheckInHandle()
|
{
|
|
IntPtr ptr = WindowIntPtrUtil.FindWindow(null, PluginSetting.Instance.CheckInListenName);
|
if (ptr == IntPtr.Zero)
|
{
|
return;
|
}
|
if (ptr != checkInPtr)
|
{
|
WindowIntPtrUtil.ShowWindow(ptr, 6);
|
lock (checkInLock)
|
{
|
checkInPtr = ptr;
|
PtrCheckHandler += CheckInWindowHandler;
|
}
|
await PtrHandler2();
|
}
|
else if (workStatus == PdmStatus.DO_LISTENING)
|
{
|
WindowIntPtrUtil.ShowWindow(ptr, 6);
|
}
|
}
|
|
/// <summary>
|
/// 规则检查执行完之后的操作,成功就激活导入窗口,失败就关闭导入窗口
|
/// </summary>
|
/// <param name="errs"></param>
|
/// <param name="ex"></param>
|
/// <param name="success"></param>
|
private void CheckInWindowHandler(List<string> errs, Exception ex, bool success)
|
{
|
lock (checkInLock)
|
{
|
if (success)
|
{
|
WindowIntPtrUtil.ShowWindow(checkInPtr, 1);
|
}
|
else
|
{
|
WindowIntPtrUtil.KillProcessByIntPtr(checkInPtr);
|
checkInPtr = IntPtr.Zero;
|
}
|
PtrCheckHandler -= CheckInWindowHandler;
|
}
|
}
|
|
private async Task PtrHandler2()
|
{
|
if (workStatus == PdmStatus.FREE)
|
{
|
workStatus = PdmStatus.DO_LISTENING;
|
MaskAdorner.ShowMask(content, "检查中,请稍后...");
|
await Task.Run(() =>
|
{
|
try
|
{
|
// 执行规则检查并获取结果
|
RefreshBomList(SwApp.IActiveDoc2);
|
if (model.bomTreeReader.CacheList.Count <= 0)
|
{
|
throw new CantCheckInException(new List<string> { "请打开一张图纸" });
|
}
|
if (model.bomTreeReader.needSaveList.Count > 0)
|
{
|
List<string> infos = new List<string>(model.bomTreeReader.needSaveList);
|
AutoSaveAlert(infos);
|
}
|
|
DoCheckRuleAsync(out _);
|
// 筛选所有在物料明细表中,不跳过检查并且检查未通过的,类型是加工件的未通过审核的,加工件审核通过的但图纸变更的
|
List<string> errs = model.bomTreeReader.CacheList.Select(b => b.NeedStopCheckIn())
|
.Where(s => s != null).ToList();
|
|
if (errs != null && errs.Count > 0)
|
{
|
throw new CantCheckInException(errs);
|
}
|
PtrCheckHandler?.Invoke(null, null, true);
|
}
|
catch (CantCheckInException cex)
|
{
|
PtrCheckHandler?.Invoke(cex.errs, null, false);
|
Dispatcher.Invoke(() =>
|
{
|
MultiExWindow exWin = new MultiExWindow(this, "检入停止", cex.errs);
|
exWin.ShowDialog();
|
});
|
}
|
catch (Exception ex)
|
{
|
PtrCheckHandler?.Invoke(null, ex, false);
|
Logger.Error($"V{PdmUser.LoginUser.pluginVersion}, PDM check rule failed.", ex);
|
this.Error($"V{PdmUser.LoginUser.pluginVersion},图纸检查执行失败:{ex.Message}");
|
}
|
finally
|
{
|
workStatus = PdmStatus.FREE;
|
MaskAdorner.HideMask(content);
|
}
|
});
|
}
|
else if (workStatus != PdmStatus.DO_LISTENING)
|
{
|
PtrCheckHandler?.Invoke(null, null, false);
|
if (workStatus == PdmStatus.CHECKING)
|
{
|
this.Info("正在进行规则检查,请勿检入");
|
}
|
else if (workStatus == PdmStatus.READING)
|
{
|
this.Info("正在加载,请勿检入");
|
}
|
else if (workStatus == PdmStatus.UPLOADING)
|
{
|
this.Info("正在上传图纸,请勿检入");
|
}
|
}
|
}
|
|
|
private Task importListenTask;
|
private Task checkInListenTask;
|
/// <summary>
|
/// 开启插件监听线程
|
/// </summary>
|
public void InitDemonThread()
|
{
|
importListenTask = Task.Run(() =>
|
{
|
while (true)
|
{
|
// 监听导入插件的启动
|
ListenImportHandle();
|
Thread.Sleep(PluginSetting.Instance.ScanInterval);
|
}
|
});
|
|
checkInListenTask = Task.Run(() =>
|
{
|
while (true)
|
{
|
// 监听检入插件的启动
|
ListenCheckInHandle();
|
Thread.Sleep(PluginSetting.Instance.ScanInterval);
|
}
|
});
|
}
|
|
public void OnDocDestroy(ModelDoc2 doc)
|
{
|
|
}
|
|
public void AfterDocDestroy()
|
{
|
|
}
|
|
public void DisabledHandler()
|
{
|
|
}
|
}
|
}
|