using PdmSwPlugin.Common.Entity.Pdm;
|
using SolidWorks.Interop.sldworks;
|
using SolidWorks.Interop.swconst;
|
using System;
|
using System.Collections.Concurrent;
|
using System.Collections.Generic;
|
using System.Collections.ObjectModel;
|
using System.IO;
|
using System.Linq;
|
using System.Threading;
|
using System.Threading.Tasks;
|
|
namespace PdmSwPlugin.Common.Util.Pdm
|
{
|
public class BomTreeReader
|
{
|
public BomTreeReader()
|
{
|
factory = LimitedConcurrencyLevelTaskSchedulerMsn.Factory;
|
}
|
|
public TaskFactory factory;
|
/// <summary>
|
/// 全部BOM的平铺List
|
/// </summary>
|
public ConcurrentQueue<PdmBom> CacheList { get; private set; } = new ConcurrentQueue<PdmBom>();
|
|
/// <summary>
|
/// 插件展示的TreeBom
|
/// </summary>
|
public ConcurrentQueue<PdmBom> TreeList { get; private set; } = new ConcurrentQueue<PdmBom>();
|
|
/// <summary>
|
/// 每次刷新时的缓存
|
/// </summary>
|
private ConcurrentDictionary<string, BomInfo> BomInfoCache { get; set; }
|
|
private CancellationTokenSource CancellationSwitch { get; set; }
|
|
public event EventHandler<PdmBom> SingleCompleted;
|
|
private int bomOrder = 0;
|
|
public ConcurrentQueue<string> needSaveList { get; set; } = new ConcurrentQueue<string>();
|
|
/// <summary>
|
/// 多线程从打开的根文档中读取BOM信息
|
/// </summary>
|
/// <returns>树型BOM列表</returns>
|
public void GetBomsFromDocAsync(ModelDoc2 sldDoc)
|
{
|
bomOrder = 0;
|
if (sldDoc == null)
|
{
|
return;
|
}
|
|
int drawingType = sldDoc.GetType();
|
Configuration activeConfiguration = sldDoc.GetActiveConfiguration() as Configuration;
|
if (activeConfiguration == null)
|
{
|
return;
|
}
|
Component2 rootComponent = activeConfiguration.GetRootComponent3(false);
|
string path = rootComponent.GetPathName();
|
|
CustomPropertyUtil.ClearAllCustomProperties(sldDoc, out bool needSave);
|
if (needSave)
|
{
|
int err = 0, warn = 0;
|
if (sldDoc.Save3((int)swSaveAsOptions_e.swSaveAsOptions_AvoidRebuildOnSave, ref err, ref warn))
|
{
|
needSaveList.Enqueue(path);
|
}
|
else
|
{
|
needSaveList.Enqueue($"{path}自动保存失败,异常代码:{err}");
|
}
|
}
|
|
BomInfo bomInfo = GetBomInfoFromDoc(rootComponent);
|
PdmBom bom = ConcatCacheBom(bomInfo, 0, null, rootComponent);
|
// ConcatBom 可能会返回null,说明这是个模拟件
|
if (bom == null)
|
{
|
return;
|
}
|
BomInfoCache[rootComponent.GetPathName()] = bomInfo;
|
CacheList.Enqueue(bom);
|
TreeList.Enqueue(bom);
|
SingleCompleted?.Invoke(this, bom);
|
bom.children = new ObservableCollection<PdmBom>();
|
// 这里放个1,多线程说不准,就扣的快了
|
CountdownEvent counter = new CountdownEvent(1);
|
// counter.Add 要在每个子任务前执行,不能放到子任务中进行!!!
|
// 防止任务数太少,来不及增加计数导致直接Wait结束
|
counter.TryAddCount();
|
|
factory.StartNew(() =>
|
{
|
GetChildrenBomAsync(bom, rootComponent, 0, bom.children, counter);
|
});
|
counter.Wait();
|
counter.Dispose();
|
}
|
|
/// <summary>
|
/// 多线程递归获取子BOM
|
/// </summary>
|
/// <param name="param"></param>
|
private void GetChildrenBomAsync(PdmBom parent,
|
Component2 parentComponent,
|
int level,
|
Collection<PdmBom> children,
|
CountdownEvent counter)
|
{
|
try
|
{
|
if (parentComponent == null)
|
{
|
parent.modules = new ObservableCollection<PdmBom>();
|
return;
|
}
|
|
object[] childrenComponents = parentComponent.GetChildren();
|
if (childrenComponents == null)
|
{
|
parent.modules = new ObservableCollection<PdmBom>();
|
return;
|
}
|
|
// 计算每个子料数量的缓存
|
Dictionary<string, PdmBom> numCache = new Dictionary<string, PdmBom>();
|
List<PdmBom> modules = new List<PdmBom>();
|
int order = -1;
|
foreach (object child in childrenComponents)
|
{
|
Component2 childComponent = child as Component2;
|
ModelDoc2 childDoc = childComponent.GetModelDoc2();
|
string childPath = childComponent.GetPathName();
|
// 清除格式不对的属性
|
CustomPropertyUtil.ClearAllCustomProperties(childDoc, out bool needSave);
|
if (needSave)
|
{
|
int err = 0, warn = 0;
|
if (childDoc.Save3((int)swSaveAsOptions_e.swSaveAsOptions_AvoidRebuildOnSave, ref err, ref warn))
|
{
|
needSaveList.Enqueue(childPath);
|
}
|
else
|
{
|
needSaveList.Enqueue($"{childPath}自动保存失败,异常代码:{err}");
|
}
|
}
|
|
PdmBom bom = null;
|
if (BomInfoCache.ContainsKey(childPath))
|
{
|
BomInfo info = BomInfoCache[childPath];
|
bom = ConcatCacheBom(info, level + 1, parent, childComponent);
|
// 就算有缓存,也要把新bom的treeId更新了,id在这里不一定唯一,tree是唯一的
|
bom.treeId = Guid.NewGuid().ToString();
|
}
|
else
|
{
|
BomInfo info = GetBomInfoFromDoc(childComponent);
|
if (info == null)
|
{
|
// 可能会返回null,说明这是个模拟件,直接跳过
|
continue;
|
}
|
BomInfoCache[childPath] = info;
|
bom = ConcatCacheBom(info, level + 1, parent, childComponent);
|
}
|
if (!bom.lost)
|
{
|
// // 如果bom没有丢失,处理子料
|
if (bom.drawingType == (int)swDocumentTypes_e.swDocASSEMBLY)
|
{
|
bom.children = new ObservableCollection<PdmBom>();
|
counter.TryAddCount();
|
factory.StartNew(() =>
|
{
|
GetChildrenBomAsync(bom, childComponent, bom.level, bom.children, counter);
|
});
|
}
|
else
|
{
|
bom.modules = new ObservableCollection<PdmBom>();
|
}
|
}
|
// 列表缓存
|
bom.order = ++order;
|
CacheList.Enqueue(bom);
|
modules.Add(bom);
|
SingleCompleted?.Invoke(this, bom);
|
|
// 丢没丢都要处理数量
|
if (numCache.ContainsKey(bom.name))
|
{
|
numCache[bom.name].quantity++;
|
}
|
else
|
{
|
numCache[bom.name] = bom;
|
children.Add(bom);
|
}
|
}
|
|
if (modules != null && modules.Count > 0)
|
{
|
parent.modules = new ObservableCollection<PdmBom>(modules.OrderBy(e => e.name).ToList());
|
return;
|
}
|
parent.modules = new ObservableCollection<PdmBom>();
|
}
|
finally
|
{
|
counter.Signal();
|
if (level == 0) counter.Signal();
|
}
|
}
|
|
public List<PdmBom> Refresh(SldWorks swApp, ModelDoc2 doc)
|
{
|
if (swApp == null || doc == null)
|
{
|
return null;
|
}
|
CacheList = new ConcurrentQueue<PdmBom>();
|
TreeList = new ConcurrentQueue<PdmBom>();
|
BomInfoCache = new ConcurrentDictionary<string, BomInfo>();
|
needSaveList = new ConcurrentQueue<string>();
|
GetBomsFromDocAsync(doc);
|
return TreeList.OrderBy(e => e.name).ToList(); ;
|
}
|
/// <summary>
|
/// 从WEB获取与Component2对应的数据库中的物料信息
|
/// </summary>
|
/// <param name="component"></param>
|
/// <returns></returns>
|
private static BomInfo GetBomInfoFromDoc(Component2 component)
|
{
|
ModelDoc2 doc = component.GetModelDoc2();
|
// 直接用文件名,以免 SolidWorks 因为有多个相同文件而把 Name2 加了 -N 的后缀名
|
string childPath = component.GetPathName();
|
string childName = System.IO.Path.GetFileNameWithoutExtension(childPath);
|
|
if (ModelUtil.Is_Mn(childName))
|
{
|
// 如果是个模拟件,直接跳过了
|
return null;
|
}
|
BomInfo bomInfo;
|
|
// id先用uuid填充
|
if (doc == null || string.IsNullOrEmpty(childPath) || !File.Exists(childPath))
|
{
|
bomInfo = new BomInfo
|
{
|
id = Guid.NewGuid().ToString(),
|
doc = doc,
|
lost = true,
|
suppressed = component.IsSuppressed(),
|
lightWeight = (component.GetSuppression2() == (int)swComponentSuppressionState_e.swComponentLightweight),
|
};
|
return bomInfo;
|
}
|
int drawingType = doc.GetType();
|
bomInfo = new BomInfo
|
{
|
id = Guid.NewGuid().ToString(),
|
doc = doc,
|
drawingType = drawingType,
|
properties = CustomPropertyUtil.GetCustomProperties2(doc, true, null, null),
|
d3FilePath = childPath,
|
};
|
return bomInfo;
|
}
|
|
/// <summary>
|
/// 拼接WEB中BomInfo信息和本地图纸中的Pdmbom信息
|
/// </summary>
|
/// <param name="info"></param>
|
/// <param name="level"></param>
|
/// <param name="parent"></param>
|
/// <returns></returns>
|
private static PdmBom ConcatCacheBom(BomInfo info, int level, PdmBom parent, Component2 component)
|
{
|
if (info == null) return null;
|
//if (component.IsHidden(true))
|
//{
|
// info.isHidden = true;
|
//}
|
PdmBom bom = new PdmBom
|
{
|
BomInfo = info,
|
treeId = info.id,
|
level = level,
|
quantity = 1,
|
parent = parent,
|
component = component,
|
isHidden = component.IsHidden(true)
|
};
|
// 封装Bom信息
|
bom.Init();
|
return bom;
|
}
|
}
|
}
|