feat: update processing time property type to int and enhance app config with default values
This commit is contained in:
parent
7397df62e4
commit
8cccf513ea
@ -194,7 +194,7 @@ namespace RevitHttpControl.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 处理耗时(秒)
|
/// 处理耗时(秒)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double ProcessingTimeSeconds { get; set; }
|
public int ProcessingTimeSeconds { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -38,7 +38,7 @@ namespace RevitHttpControl.Services
|
|||||||
result.OriginalSize = FormatFileSize(originalSize);
|
result.OriginalSize = FormatFileSize(originalSize);
|
||||||
|
|
||||||
// 2. 分析模型获取删除列表
|
// 2. 分析模型获取删除列表
|
||||||
var analysis = _analyzer.AnalyzeModel(doc, mode);
|
_analyzer.AnalyzeModel(doc, mode);
|
||||||
var elementsToDelete = GetElementsToDelete(doc, mode);
|
var elementsToDelete = GetElementsToDelete(doc, mode);
|
||||||
|
|
||||||
// 3. 创建备份(如果需要)
|
// 3. 创建备份(如果需要)
|
||||||
@ -49,7 +49,8 @@ namespace RevitHttpControl.Services
|
|||||||
|
|
||||||
// 4. 执行删除操作
|
// 4. 执行删除操作
|
||||||
var deletedCount = DeleteElements(doc, elementsToDelete, mode);
|
var deletedCount = DeleteElements(doc, elementsToDelete, mode);
|
||||||
result.RemovedCount = deletedCount;
|
var purgedCount = PurgeUnusedFamilyData(doc);
|
||||||
|
result.RemovedCount = deletedCount + purgedCount;
|
||||||
|
|
||||||
// 5. 保存文档并计算优化后大小
|
// 5. 保存文档并计算优化后大小
|
||||||
SaveDocument(doc);
|
SaveDocument(doc);
|
||||||
@ -68,14 +69,14 @@ namespace RevitHttpControl.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
result.ProcessingTimeSeconds = stopwatch.Elapsed.TotalSeconds;
|
result.ProcessingTimeSeconds = (int)Math.Round(stopwatch.Elapsed.TotalSeconds, MidpointRounding.AwayFromZero);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
result.ProcessingTimeSeconds = stopwatch.Elapsed.TotalSeconds;
|
result.ProcessingTimeSeconds = (int)Math.Round(stopwatch.Elapsed.TotalSeconds, MidpointRounding.AwayFromZero);
|
||||||
|
|
||||||
// 如果有备份且操作失败,可以考虑恢复备份
|
// 如果有备份且操作失败,可以考虑恢复备份
|
||||||
throw new InvalidOperationException($"薄壳优化执行失败: {ex.Message}", ex);
|
throw new InvalidOperationException($"薄壳优化执行失败: {ex.Message}", ex);
|
||||||
@ -111,9 +112,10 @@ namespace RevitHttpControl.Services
|
|||||||
result.BackupPath = CreateBackup(doc);
|
result.BackupPath = CreateBackup(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自定义删除沿用标准安全检查逻辑(非 EnvelopeOnly)
|
// Reuse Standard safety checks for custom category deletion.
|
||||||
var deletedCount = DeleteElements(doc, elementsToDelete, ShellOptimizeMode.Standard);
|
var deletedCount = DeleteElements(doc, elementsToDelete, ShellOptimizeMode.Standard);
|
||||||
result.RemovedCount = deletedCount;
|
var purgedCount = PurgeUnusedFamilyData(doc);
|
||||||
|
result.RemovedCount = deletedCount + purgedCount;
|
||||||
|
|
||||||
SaveDocument(doc);
|
SaveDocument(doc);
|
||||||
var optimizedSize = GetDocumentFileSize(doc);
|
var optimizedSize = GetDocumentFileSize(doc);
|
||||||
@ -130,14 +132,14 @@ namespace RevitHttpControl.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
result.ProcessingTimeSeconds = stopwatch.Elapsed.TotalSeconds;
|
result.ProcessingTimeSeconds = (int)Math.Round(stopwatch.Elapsed.TotalSeconds, MidpointRounding.AwayFromZero);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
result.ProcessingTimeSeconds = stopwatch.Elapsed.TotalSeconds;
|
result.ProcessingTimeSeconds = (int)Math.Round(stopwatch.Elapsed.TotalSeconds, MidpointRounding.AwayFromZero);
|
||||||
throw new InvalidOperationException($"自定义类别删除执行失败: {ex.Message}", ex);
|
throw new InvalidOperationException($"自定义类别删除执行失败: {ex.Message}", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,6 +221,7 @@ namespace RevitHttpControl.Services
|
|||||||
using (var transaction = new Transaction(doc, "薄壳优化删除构件"))
|
using (var transaction = new Transaction(doc, "薄壳优化删除构件"))
|
||||||
{
|
{
|
||||||
transaction.Start();
|
transaction.Start();
|
||||||
|
ApplyWarningSuppression(transaction);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -404,6 +407,12 @@ namespace RevitHttpControl.Services
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prefer compact save for normal local documents to reclaim free space.
|
||||||
|
if (TryCompactSaveInPlace(doc))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
doc.Save();
|
doc.Save();
|
||||||
@ -421,6 +430,38 @@ namespace RevitHttpControl.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool TryCompactSaveInPlace(Document doc)
|
||||||
|
{
|
||||||
|
if (doc == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (doc.IsWorkshared)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var originalPath = doc.PathName;
|
||||||
|
if (string.IsNullOrWhiteSpace(originalPath))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!File.Exists(originalPath))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var options = new SaveAsOptions
|
||||||
|
{
|
||||||
|
OverwriteExistingFile = true,
|
||||||
|
Compact = true
|
||||||
|
};
|
||||||
|
|
||||||
|
doc.SaveAs(originalPath, options);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool IsReadOnlySaveError(Exception ex)
|
private bool IsReadOnlySaveError(Exception ex)
|
||||||
{
|
{
|
||||||
if (ex == null) return false;
|
if (ex == null) return false;
|
||||||
@ -453,6 +494,118 @@ namespace RevitHttpControl.Services
|
|||||||
doc.SaveAs(outputPath, saveAsOptions);
|
doc.SaveAs(outputPath, saveAsOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove unused family symbols and empty families after instance deletion.
|
||||||
|
/// </summary>
|
||||||
|
private int PurgeUnusedFamilyData(Document doc)
|
||||||
|
{
|
||||||
|
if (doc == null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var usedSymbolIds = new HashSet<int>();
|
||||||
|
var instances = new FilteredElementCollector(doc)
|
||||||
|
.OfClass(typeof(FamilyInstance))
|
||||||
|
.WhereElementIsNotElementType()
|
||||||
|
.Cast<FamilyInstance>();
|
||||||
|
|
||||||
|
foreach (var instance in instances)
|
||||||
|
{
|
||||||
|
var symbolId = instance?.Symbol?.Id?.IntegerValue;
|
||||||
|
if (symbolId.HasValue)
|
||||||
|
{
|
||||||
|
usedSymbolIds.Add(symbolId.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var unusedSymbolIds = new FilteredElementCollector(doc)
|
||||||
|
.OfClass(typeof(FamilySymbol))
|
||||||
|
.Cast<FamilySymbol>()
|
||||||
|
.Where(symbol => symbol != null && !usedSymbolIds.Contains(symbol.Id.IntegerValue))
|
||||||
|
.Select(symbol => symbol.Id)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var removedSymbolCount = DeleteElementIdsInBatches(doc, unusedSymbolIds, "清理未使用族类型");
|
||||||
|
|
||||||
|
var emptyFamilyIds = new FilteredElementCollector(doc)
|
||||||
|
.OfClass(typeof(Family))
|
||||||
|
.Cast<Family>()
|
||||||
|
.Where(family => family != null && !family.GetFamilySymbolIds().Any())
|
||||||
|
.Select(family => family.Id)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var removedFamilyCount = DeleteElementIdsInBatches(doc, emptyFamilyIds, "清理空族定义");
|
||||||
|
return removedSymbolCount + removedFamilyCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int DeleteElementIdsInBatches(Document doc, List<ElementId> elementIds, string transactionName)
|
||||||
|
{
|
||||||
|
if (doc == null || elementIds == null || elementIds.Count == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const int batchSize = 100;
|
||||||
|
int totalRemoved = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < elementIds.Count; i += batchSize)
|
||||||
|
{
|
||||||
|
var batchIds = elementIds.Skip(i).Take(batchSize).ToList();
|
||||||
|
if (batchIds.Count == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
using (var transaction = new Transaction(doc, transactionName))
|
||||||
|
{
|
||||||
|
transaction.Start();
|
||||||
|
ApplyWarningSuppression(transaction);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var deletedIds = doc.Delete(batchIds);
|
||||||
|
transaction.Commit();
|
||||||
|
totalRemoved += deletedIds.Count;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
transaction.RollBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyWarningSuppression(Transaction transaction)
|
||||||
|
{
|
||||||
|
if (transaction == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var options = transaction.GetFailureHandlingOptions();
|
||||||
|
options.SetFailuresPreprocessor(new WarningFailurePreprocessor());
|
||||||
|
options.SetClearAfterRollback(true);
|
||||||
|
transaction.SetFailureHandlingOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class WarningFailurePreprocessor : IFailuresPreprocessor
|
||||||
|
{
|
||||||
|
public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor)
|
||||||
|
{
|
||||||
|
if (failuresAccessor == null)
|
||||||
|
return FailureProcessingResult.Continue;
|
||||||
|
|
||||||
|
var failures = failuresAccessor.GetFailureMessages();
|
||||||
|
if (failures == null || failures.Count == 0)
|
||||||
|
return FailureProcessingResult.Continue;
|
||||||
|
|
||||||
|
foreach (var failure in failures)
|
||||||
|
{
|
||||||
|
if (failure != null && failure.GetSeverity() == FailureSeverity.Warning)
|
||||||
|
{
|
||||||
|
failuresAccessor.DeleteWarning(failure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FailureProcessingResult.Continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取文档文件大小
|
/// 获取文档文件大小
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<appSettings>
|
<appSettings>
|
||||||
<add key="PluginCallbackBaseUrl" value="" />
|
<add key="PluginCallbackBaseUrl" value="http://localhost:8000" />
|
||||||
<add key="PluginCallbackToken" value="" />
|
<add key="PluginCallbackToken" value="revit-callback-token" />
|
||||||
<add key="PluginSoftwareId" value="revit" />
|
<add key="PluginSoftwareId" value="revit" />
|
||||||
</appSettings>
|
</appSettings>
|
||||||
<runtime>
|
<runtime>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user