using Laservall.Solidworks.Extension; using Laservall.Solidworks.Model; using Laservall.Solidworks.Windows; using SolidWorks.Interop.sldworks; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace Laservall.Solidworks.Server { internal sealed class SolidWorksBomDataProvider : IBomDataProvider { private readonly StaThreadMarshaller _marshaller; private static readonly HashSet StaticColumnProps = new HashSet { "零件名称", "材质", "属性", "材料" }; public SolidWorksBomDataProvider(StaThreadMarshaller marshaller) { _marshaller = marshaller ?? throw new ArgumentNullException(nameof(marshaller)); } public async Task LoadBomAsync(IProgress progress, CancellationToken ct) { return await _marshaller.InvokeAsync(async () => { ModelDoc2 model = SWUtils.SwApp.ActiveDoc as ModelDoc2; if (model == null) { return new BomLoadResult { Items = new List(), DynamicKeys = new List(), Settings = BomSettings.Load() }; } Configuration config = model.ConfigurationManager.ActiveConfiguration; var rootTree = new SwAssDocTreeModel { drawingNo = Path.GetFileNameWithoutExtension(model.GetPathName()), docPath = model.GetPathName(), configName = config?.Name ?? "", children = new List(), isAss = true, quantity = 1, props = SWUtils.GetConfig3(model.GetPathName()) }; Component2 rootComponent = config?.GetRootComponent3(true) as Component2; int totalCount = GetTotalComponentCount(model); if (HasLightweightComponents(model)) { ResolvingProgressWindow.RunWithProgress(() => { SWUtils.SetAllPartResolved(model.GetPathName()); }); } if (rootComponent != null) { IProgress swProgress = null; if (progress != null) { swProgress = new Progress(p => { progress.Report(new BomLoadProgress { Processed = p.Processed, Total = p.Total, CurrentName = p.CurrentName }); }); } var parts = await SWUtils.GetSwAssDocTreeChildrenAsync( rootComponent, true, true, totalCount, swProgress); rootTree.children.AddRange(parts); } var allItems = SWUtils.FlattenBomTree(rootTree); var propKeys = SWUtils.CollectAllPropertyKeys(allItems); var dynamicKeys = propKeys .Where(k => !StaticColumnProps.Contains(k)) .OrderBy(k => k) .ToList(); var settings = BomSettings.Load(); settings.MergeDynamicKeys(dynamicKeys); var userAddedKeys = settings.Columns .Where(c => c.IsUserAdded && !dynamicKeys.Contains(c.Name)) .Select(c => c.Name) .ToList(); dynamicKeys.AddRange(userAddedKeys); EnsurePropsKeys(allItems, dynamicKeys); return new BomLoadResult { Items = allItems, DynamicKeys = dynamicKeys, Settings = settings }; }); } public SaveResult SaveChanges(List changes) { if (changes == null || changes.Count == 0) { return new SaveResult { Success = true, SavedCount = 0 }; } return _marshaller.Invoke(() => { try { var grouped = changes .Where(c => !string.IsNullOrEmpty(c.DocPath) && !string.IsNullOrEmpty(c.Key)) .GroupBy(c => c.DocPath); int savedCount = 0; foreach (var group in grouped) { ModelDoc2 doc = SWUtils.OpenDocSilently(group.Key); if (doc == null) continue; Configuration activeConfig = doc.ConfigurationManager?.ActiveConfiguration; CustomPropertyManager configPropMgr = activeConfig?.CustomPropertyManager; CustomPropertyManager filePropMgr = null; try { filePropMgr = doc.Extension?.get_CustomPropertyManager(""); } catch { } foreach (var change in group) { bool writtenToConfig = false; if (configPropMgr != null) { var configNames = configPropMgr.GetNames() as string[]; if (configNames != null && configNames.Contains(change.Key)) { configPropMgr.Set2(change.Key, change.Value ?? ""); writtenToConfig = true; } } if (!writtenToConfig && filePropMgr != null) { filePropMgr.Set2(change.Key, change.Value ?? ""); } else if (!writtenToConfig && configPropMgr != null) { configPropMgr.Set2(change.Key, change.Value ?? ""); } } doc.Save3(0, 0, 0); savedCount++; } return new SaveResult { Success = true, SavedCount = savedCount }; } catch (Exception ex) { return new SaveResult { Success = false, Error = ex.Message }; } }); } public BomSettings GetSettings() { return BomSettings.Load(); } public void SaveSettings(BomSettings settings) { settings?.Save(); } public List GetFlatBomItems(List allItems) { return allItems .Where(i => !i.IsAssembly) .GroupBy(i => i.DrawingNo ?? "") .Select(g => { var first = g.First(); return new BomItemModel { Level = 0, LevelDisplay = "", DrawingNo = first.DrawingNo, ConfigName = first.ConfigName, PartName = first.PartName, MaterialProp = first.MaterialProp, Material = first.Material, Classification = first.Classification, Quantity = g.Sum(x => x.Quantity), IsAssembly = false, IsOutSourcing = first.IsOutSourcing, DocPath = first.DocPath, Props = first.Props, HasChildren = false, IsExpanded = false, IsVisible = true }; }) .ToList(); } private static void EnsurePropsKeys(List items, List keys) { foreach (var item in items) { if (item.Props == null) { item.Props = new Dictionary(); } foreach (var key in keys) { if (!item.Props.ContainsKey(key)) { item.Props[key] = ""; } } } } private static int GetTotalComponentCount(ModelDoc2 model) { AssemblyDoc assembly = model as AssemblyDoc; if (assembly == null) { return 1; } object[] components = assembly.GetComponents(false) as object[]; return Math.Max((components?.Length ?? 0) + 1, 1); } private static bool HasLightweightComponents(ModelDoc2 model) { AssemblyDoc assembly = model as AssemblyDoc; if (assembly == null) return false; object[] components = assembly.GetComponents(false) as object[]; if (components == null) return false; foreach (object obj in components) { Component2 comp = obj as Component2; if (comp == null) continue; int state = comp.GetSuppression(); // swComponentLightweight = 4, swComponentFullyLightweight = 8 if (state == 4 || state == 8) return true; } return false; } } }