feat: implement file closing and custom category deletion functionality
This commit is contained in:
parent
58d91786ea
commit
660c3bcd6f
@ -188,5 +188,66 @@ namespace RevitHttpControl.Controllers
|
||||
return Request.CreateResponse(HttpStatusCode.InternalServerError, errorResponse);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭当前打开文件
|
||||
/// </summary>
|
||||
/// <returns>关闭文件响应</returns>
|
||||
[HttpPost]
|
||||
[Route("close")]
|
||||
public HttpResponseMessage CloseFile()
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = DocumentService.CloseCurrentDocument();
|
||||
|
||||
var successResponse = new ApiResponse<CloseFileResponse>
|
||||
{
|
||||
Success = true,
|
||||
Code = 200,
|
||||
Message = "文件关闭成功",
|
||||
Data = result
|
||||
};
|
||||
|
||||
return Request.CreateResponse(HttpStatusCode.OK, successResponse);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
var conflictResponse = new ApiResponse<object>
|
||||
{
|
||||
Success = false,
|
||||
Code = 409,
|
||||
Message = ex.Message,
|
||||
Data = new { error = "NO_DOCUMENT_OPEN" }
|
||||
};
|
||||
return Request.CreateResponse(HttpStatusCode.Conflict, conflictResponse);
|
||||
}
|
||||
catch (TimeoutException ex)
|
||||
{
|
||||
var timeoutResponse = new ApiResponse<object>
|
||||
{
|
||||
Success = false,
|
||||
Code = 408,
|
||||
Message = ex.Message,
|
||||
Data = new { error = "OPERATION_TIMEOUT" }
|
||||
};
|
||||
return Request.CreateResponse(HttpStatusCode.RequestTimeout, timeoutResponse);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorResponse = new ApiResponse<object>
|
||||
{
|
||||
Success = false,
|
||||
Code = 500,
|
||||
Message = "关闭文件时发生错误",
|
||||
Data = new
|
||||
{
|
||||
error = "INTERNAL_ERROR",
|
||||
errorDescription = ex.Message
|
||||
}
|
||||
};
|
||||
return Request.CreateResponse(HttpStatusCode.InternalServerError, errorResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,6 +254,89 @@ namespace RevitHttpControl.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按类别自定义执行删除(同步)
|
||||
/// </summary>
|
||||
/// <param name="request">自定义删除请求</param>
|
||||
/// <returns>执行结果</returns>
|
||||
[HttpPost]
|
||||
[Route("execute/custom")]
|
||||
public HttpResponseMessage ExecuteShellCustom([FromBody] ShellCustomExecuteRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
return this.CreateErrorResponse(
|
||||
ErrorCodes.INVALID_REQUEST_PARAMETERS,
|
||||
"请求参数不能为空",
|
||||
HttpStatusCode.BadRequest
|
||||
);
|
||||
}
|
||||
|
||||
if (request.CategoryIds == null || request.CategoryIds.Count == 0)
|
||||
{
|
||||
return this.CreateErrorResponse(
|
||||
ErrorCodes.INVALID_REQUEST_PARAMETERS,
|
||||
"CategoryIds 不能为空,且至少包含一个类别ID",
|
||||
HttpStatusCode.BadRequest
|
||||
);
|
||||
}
|
||||
|
||||
var result = RevitService.ExecuteShellOptimizationByCategories(request.CategoryIds, request.BackupOriginal);
|
||||
return this.CreateSuccessResponse(result, "自定义类别删除执行完成");
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return this.CreateErrorResponse(
|
||||
ErrorCodes.NO_DOCUMENT_OPEN,
|
||||
ex.Message,
|
||||
HttpStatusCode.BadRequest
|
||||
);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return this.CreateErrorResponse(
|
||||
ErrorCodes.INVALID_REQUEST_PARAMETERS,
|
||||
ex.Message,
|
||||
HttpStatusCode.BadRequest
|
||||
);
|
||||
}
|
||||
catch (TimeoutException ex)
|
||||
{
|
||||
return this.CreateErrorResponse(
|
||||
ErrorCodes.OPERATION_TIMEOUT,
|
||||
ex.Message,
|
||||
HttpStatusCode.RequestTimeout
|
||||
);
|
||||
}
|
||||
catch (UnauthorizedAccessException ex)
|
||||
{
|
||||
return this.CreateErrorResponse(
|
||||
ErrorCodes.FILE_WRITE_PERMISSION_DENIED,
|
||||
"文件写入权限不足:" + ex.Message,
|
||||
HttpStatusCode.Forbidden
|
||||
);
|
||||
}
|
||||
catch (System.IO.IOException ex)
|
||||
{
|
||||
return this.CreateErrorResponse(
|
||||
ErrorCodes.FILE_IO_ERROR,
|
||||
"文件操作失败:" + ex.Message,
|
||||
HttpStatusCode.InternalServerError
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return this.CreateErrorResponse(
|
||||
ErrorCodes.REVIT_API_ERROR,
|
||||
"自定义类别删除执行失败",
|
||||
HttpStatusCode.InternalServerError,
|
||||
ex.Message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取薄壳优化预设配置
|
||||
/// </summary>
|
||||
|
||||
@ -38,4 +38,25 @@ namespace RevitHttpControl.Models
|
||||
/// </summary>
|
||||
public string FilePath { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭文件响应
|
||||
/// </summary>
|
||||
public class CloseFileResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作结果
|
||||
/// </summary>
|
||||
public string Result { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关闭前的文件名
|
||||
/// </summary>
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关闭前的文件路径
|
||||
/// </summary>
|
||||
public string FilePath { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +49,22 @@ namespace RevitHttpControl.Models
|
||||
public bool BackupOriginal { get; set; } = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按类别自定义删除请求
|
||||
/// </summary>
|
||||
public class ShellCustomExecuteRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 要删除的类别ID列表(BuiltInCategory 的 int 值)
|
||||
/// </summary>
|
||||
public List<int> CategoryIds { get; set; } = new List<int>();
|
||||
|
||||
/// <summary>
|
||||
/// 是否备份原文件
|
||||
/// </summary>
|
||||
public bool BackupOriginal { get; set; } = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 薄壳执行响应
|
||||
/// </summary>
|
||||
@ -84,6 +100,16 @@ namespace RevitHttpControl.Models
|
||||
/// 预估文件大小减少百分比
|
||||
/// </summary>
|
||||
public string EstimatedReduction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前文件大小(格式化显示)
|
||||
/// </summary>
|
||||
public string OriginalSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 预估优化后文件大小(格式化显示)
|
||||
/// </summary>
|
||||
public string EstimatedOptimizedSize { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -91,6 +117,11 @@ namespace RevitHttpControl.Models
|
||||
/// </summary>
|
||||
public class CategoryStatistics
|
||||
{
|
||||
/// <summary>
|
||||
/// 分类ID(BuiltInCategory 的 int 值)
|
||||
/// </summary>
|
||||
public int CategoryId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分类名称
|
||||
/// </summary>
|
||||
@ -205,6 +236,11 @@ namespace RevitHttpControl.Models
|
||||
/// </summary>
|
||||
public int ElementId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构件分类ID(BuiltInCategory 的 int 值)
|
||||
/// </summary>
|
||||
public int CategoryId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构件分类名称
|
||||
/// </summary>
|
||||
|
||||
@ -84,6 +84,81 @@ namespace RevitHttpControl.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭当前活动文档
|
||||
/// </summary>
|
||||
/// <returns>关闭文件响应</returns>
|
||||
public static CloseFileResponse CloseCurrentDocument()
|
||||
{
|
||||
try
|
||||
{
|
||||
var completed = false;
|
||||
Exception capturedException = null;
|
||||
CloseFileResponse response = null;
|
||||
|
||||
App.Instance.EnqueueCommand(uiApp =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var activeDoc = uiApp.ActiveUIDocument?.Document;
|
||||
if (activeDoc == null)
|
||||
{
|
||||
throw new InvalidOperationException("没有打开的文档");
|
||||
}
|
||||
|
||||
var fileName = string.IsNullOrEmpty(activeDoc.PathName)
|
||||
? activeDoc.Title
|
||||
: Path.GetFileName(activeDoc.PathName);
|
||||
var filePath = string.IsNullOrEmpty(activeDoc.PathName) ? null : activeDoc.PathName;
|
||||
|
||||
activeDoc.Close(false);
|
||||
|
||||
response = new CloseFileResponse
|
||||
{
|
||||
Result = "文件关闭成功",
|
||||
FileName = fileName,
|
||||
FilePath = filePath
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
capturedException = ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
completed = true;
|
||||
}
|
||||
});
|
||||
|
||||
// 等待命令执行完成(最多等待10秒)
|
||||
var timeout = DateTime.Now.AddSeconds(10);
|
||||
while (!completed && DateTime.Now < timeout)
|
||||
{
|
||||
System.Threading.Thread.Sleep(100);
|
||||
}
|
||||
|
||||
if (!completed)
|
||||
throw new TimeoutException("关闭文件操作超时");
|
||||
|
||||
if (capturedException != null)
|
||||
throw capturedException;
|
||||
|
||||
return response;
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"关闭文件失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步打开文档文件
|
||||
/// </summary>
|
||||
|
||||
@ -609,6 +609,61 @@ namespace RevitHttpControl.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文档文件大小(字节)
|
||||
/// </summary>
|
||||
private static long GetDocumentFileSize(Document doc)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (doc == null)
|
||||
return 0;
|
||||
|
||||
if (!string.IsNullOrEmpty(doc.PathName) && File.Exists(doc.PathName))
|
||||
return new FileInfo(doc.PathName).Length;
|
||||
|
||||
if (doc.IsWorkshared)
|
||||
{
|
||||
var centralPath = doc.GetWorksharingCentralModelPath();
|
||||
var centralPathString = centralPath?.ToString();
|
||||
if (!string.IsNullOrEmpty(centralPathString) && File.Exists(centralPathString))
|
||||
return new FileInfo(centralPathString).Length;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略文件大小获取异常,保持分析结果可用
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 基于真实文件大小和可删除比例填充动态估算信息
|
||||
/// </summary>
|
||||
private static void ApplyDynamicSizeEstimate(Document doc, ShellAnalyzeResponse response)
|
||||
{
|
||||
if (doc == null || response?.Analysis == null)
|
||||
return;
|
||||
|
||||
var summary = response.Analysis;
|
||||
var originalSize = GetDocumentFileSize(doc);
|
||||
if (originalSize <= 0)
|
||||
return;
|
||||
|
||||
var removeRatio = summary.TotalElements > 0
|
||||
? Math.Max(0.0, Math.Min(1.0, summary.RemoveElements / (double)summary.TotalElements))
|
||||
: 0.0;
|
||||
|
||||
var estimatedOptimizedBytes = (long)Math.Round(originalSize * (1.0 - removeRatio));
|
||||
if (estimatedOptimizedBytes < 0)
|
||||
estimatedOptimizedBytes = 0;
|
||||
|
||||
summary.OriginalSize = FormatFileSize(originalSize);
|
||||
summary.EstimatedOptimizedSize = FormatFileSize(estimatedOptimizedBytes);
|
||||
summary.EstimatedReduction = $"{(removeRatio * 100.0):F1}%";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分析薄壳优化方案
|
||||
/// </summary>
|
||||
@ -632,6 +687,7 @@ namespace RevitHttpControl.Services
|
||||
|
||||
var analyzer = new ShellAnalyzer();
|
||||
result = analyzer.AnalyzeModel(doc, mode);
|
||||
ApplyDynamicSizeEstimate(doc, result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -720,6 +776,59 @@ namespace RevitHttpControl.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按类别执行自定义删除(同步)
|
||||
/// </summary>
|
||||
public static ShellOptimizeResult ExecuteShellOptimizationByCategories(IEnumerable<int> categoryIds, bool backupOriginal = true)
|
||||
{
|
||||
ShellOptimizeResult result = null;
|
||||
Exception capturedException = null;
|
||||
bool completed = false;
|
||||
|
||||
try
|
||||
{
|
||||
App.Instance.EnqueueCommand(uiApp =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc = uiApp.ActiveUIDocument?.Document;
|
||||
if (doc == null)
|
||||
throw new InvalidOperationException("没有打开的Revit文档");
|
||||
|
||||
var optimizer = new ShellOptimizer();
|
||||
result = optimizer.ExecuteOptimizationByCategories(doc, categoryIds, backupOriginal);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
capturedException = ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
completed = true;
|
||||
}
|
||||
});
|
||||
|
||||
// 等待命令执行完成(最多等待5分钟)
|
||||
var timeout = DateTime.Now.AddMinutes(5);
|
||||
while (!completed && DateTime.Now < timeout)
|
||||
{
|
||||
System.Threading.Thread.Sleep(200);
|
||||
}
|
||||
|
||||
if (capturedException != null)
|
||||
throw capturedException;
|
||||
|
||||
if (!completed)
|
||||
throw new TimeoutException("自定义类别删除执行超时");
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"自定义类别删除执行失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行薄壳优化(异步)
|
||||
/// </summary>
|
||||
|
||||
@ -40,7 +40,7 @@ namespace RevitHttpControl.Services
|
||||
}
|
||||
|
||||
// 统计结果
|
||||
var summary = CreateAnalysisSummary(analysisResults, mode);
|
||||
var summary = CreateAnalysisSummary(analysisResults);
|
||||
var categories = CreateCategoryStatistics(analysisResults);
|
||||
|
||||
return new ShellAnalyzeResponse
|
||||
@ -122,6 +122,7 @@ namespace RevitHttpControl.Services
|
||||
/// </summary>
|
||||
private ElementAnalysisResult AnalyzeElement(Element element, ShellOptimizeMode mode)
|
||||
{
|
||||
var categoryId = element.Category?.Id?.IntegerValue ?? 0;
|
||||
var categoryName = element.Category?.Name ?? "未知类别";
|
||||
var action = DetermineElementAction(element, mode);
|
||||
var reason = GetActionReason(element, action, mode);
|
||||
@ -129,6 +130,7 @@ namespace RevitHttpControl.Services
|
||||
return new ElementAnalysisResult
|
||||
{
|
||||
ElementId = element.Id.IntegerValue,
|
||||
CategoryId = categoryId,
|
||||
CategoryName = categoryName,
|
||||
Action = action,
|
||||
Reason = reason
|
||||
@ -416,36 +418,24 @@ namespace RevitHttpControl.Services
|
||||
/// <summary>
|
||||
/// 创建分析摘要
|
||||
/// </summary>
|
||||
private ShellAnalysisSummary CreateAnalysisSummary(List<ElementAnalysisResult> results, ShellOptimizeMode mode)
|
||||
private ShellAnalysisSummary CreateAnalysisSummary(List<ElementAnalysisResult> results)
|
||||
{
|
||||
var total = results.Count;
|
||||
var keep = results.Count(r => r.Action == ElementAction.Keep);
|
||||
var remove = results.Count(r => r.Action == ElementAction.Remove);
|
||||
|
||||
// 根据模式估算文件大小减少百分比
|
||||
string estimatedReduction;
|
||||
switch (mode)
|
||||
{
|
||||
case ShellOptimizeMode.Conservative:
|
||||
estimatedReduction = "30%";
|
||||
break;
|
||||
case ShellOptimizeMode.Standard:
|
||||
estimatedReduction = "65%";
|
||||
break;
|
||||
case ShellOptimizeMode.Aggressive:
|
||||
estimatedReduction = "80%";
|
||||
break;
|
||||
default:
|
||||
estimatedReduction = "50%";
|
||||
break;
|
||||
}
|
||||
var estimatedReduction = total > 0
|
||||
? $"{(remove * 100.0 / total):F1}%"
|
||||
: "0%";
|
||||
|
||||
return new ShellAnalysisSummary
|
||||
{
|
||||
TotalElements = total,
|
||||
KeepElements = keep,
|
||||
RemoveElements = remove,
|
||||
EstimatedReduction = estimatedReduction
|
||||
EstimatedReduction = estimatedReduction,
|
||||
OriginalSize = "未知",
|
||||
EstimatedOptimizedSize = "未知"
|
||||
};
|
||||
}
|
||||
|
||||
@ -454,10 +444,10 @@ namespace RevitHttpControl.Services
|
||||
/// </summary>
|
||||
private List<CategoryStatistics> CreateCategoryStatistics(List<ElementAnalysisResult> results)
|
||||
{
|
||||
var categoryGroups = results.GroupBy(r => r.CategoryName);
|
||||
var categoryGroups = results.GroupBy(r => new { r.CategoryId, r.CategoryName });
|
||||
var statistics = new List<CategoryStatistics>();
|
||||
|
||||
foreach (var group in categoryGroups.OrderBy(g => g.Key))
|
||||
foreach (var group in categoryGroups.OrderBy(g => g.Key.CategoryName))
|
||||
{
|
||||
var total = group.Count();
|
||||
var keep = group.Count(r => r.Action == ElementAction.Keep);
|
||||
@ -465,7 +455,8 @@ namespace RevitHttpControl.Services
|
||||
|
||||
statistics.Add(new CategoryStatistics
|
||||
{
|
||||
Name = group.Key,
|
||||
CategoryId = group.Key.CategoryId,
|
||||
Name = group.Key.CategoryName,
|
||||
Total = total,
|
||||
Keep = keep,
|
||||
Remove = remove
|
||||
|
||||
@ -82,6 +82,66 @@ namespace RevitHttpControl.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按类别执行自定义删除
|
||||
/// </summary>
|
||||
public ShellOptimizeResult ExecuteOptimizationByCategories(Document doc, IEnumerable<int> categoryIds, bool backupOriginal = true)
|
||||
{
|
||||
if (doc == null)
|
||||
throw new ArgumentNullException(nameof(doc));
|
||||
if (categoryIds == null)
|
||||
throw new ArgumentNullException(nameof(categoryIds));
|
||||
|
||||
var categorySet = new HashSet<int>(categoryIds);
|
||||
if (categorySet.Count == 0)
|
||||
throw new ArgumentException("至少需要指定一个要删除的类别", nameof(categoryIds));
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var result = new ShellOptimizeResult();
|
||||
|
||||
try
|
||||
{
|
||||
var originalSize = GetDocumentFileSize(doc);
|
||||
result.OriginalSize = FormatFileSize(originalSize);
|
||||
|
||||
var elementsToDelete = GetElementsToDeleteByCategories(doc, categorySet);
|
||||
|
||||
if (backupOriginal)
|
||||
{
|
||||
result.BackupPath = CreateBackup(doc);
|
||||
}
|
||||
|
||||
// 自定义删除沿用标准安全检查逻辑(非 EnvelopeOnly)
|
||||
var deletedCount = DeleteElements(doc, elementsToDelete, ShellOptimizeMode.Standard);
|
||||
result.RemovedCount = deletedCount;
|
||||
|
||||
SaveDocument(doc);
|
||||
var optimizedSize = GetDocumentFileSize(doc);
|
||||
result.OptimizedSize = FormatFileSize(optimizedSize);
|
||||
|
||||
if (originalSize > 0)
|
||||
{
|
||||
var reduction = ((double)(originalSize - optimizedSize) / originalSize) * 100;
|
||||
result.Reduction = $"{reduction:F1}%";
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Reduction = "0%";
|
||||
}
|
||||
|
||||
stopwatch.Stop();
|
||||
result.ProcessingTimeSeconds = stopwatch.Elapsed.TotalSeconds;
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
stopwatch.Stop();
|
||||
result.ProcessingTimeSeconds = stopwatch.Elapsed.TotalSeconds;
|
||||
throw new InvalidOperationException($"自定义类别删除执行失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据分析结果获取需要删除的构件
|
||||
/// </summary>
|
||||
@ -106,6 +166,30 @@ namespace RevitHttpControl.Services
|
||||
return elementsToDelete;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按类别获取待删除构件
|
||||
/// </summary>
|
||||
private List<ElementId> GetElementsToDeleteByCategories(Document doc, HashSet<int> categoryIds)
|
||||
{
|
||||
var elementsToDelete = new List<ElementId>();
|
||||
|
||||
var allElements = new FilteredElementCollector(doc)
|
||||
.WhereElementIsNotElementType()
|
||||
.WhereElementIsViewIndependent()
|
||||
.ToElements();
|
||||
|
||||
foreach (var element in allElements)
|
||||
{
|
||||
var categoryId = element?.Category?.Id?.IntegerValue;
|
||||
if (categoryId.HasValue && categoryIds.Contains(categoryId.Value))
|
||||
{
|
||||
elementsToDelete.Add(element.Id);
|
||||
}
|
||||
}
|
||||
|
||||
return elementsToDelete;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量删除构件
|
||||
/// </summary>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user