2025-04-24 20:56:44 +08:00
|
|
|
|
using System.IO;
|
2026-02-21 16:31:24 +08:00
|
|
|
|
using System.Windows;
|
2025-02-10 20:53:40 +08:00
|
|
|
|
using Autodesk.Revit.DB;
|
2026-02-21 16:31:24 +08:00
|
|
|
|
|
2026-02-20 16:47:26 +08:00
|
|
|
|
using Melskin.Controls;
|
2026-02-21 16:31:24 +08:00
|
|
|
|
|
|
|
|
|
|
using MiniExcelLibs;
|
|
|
|
|
|
|
2025-02-10 20:53:40 +08:00
|
|
|
|
using Nice3point.Revit.Toolkit.External;
|
2026-02-21 16:31:24 +08:00
|
|
|
|
|
|
|
|
|
|
using ShrlAlgoToolkit.RevitAddins.Common.Assists;
|
2025-02-10 20:53:40 +08:00
|
|
|
|
|
2026-02-22 20:03:42 +08:00
|
|
|
|
namespace ShrlAlgoToolkit.RevitAddins.DrawSheet;
|
2025-02-10 20:53:40 +08:00
|
|
|
|
|
|
|
|
|
|
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
|
|
|
|
|
|
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
|
|
|
|
|
|
public class ExportSchedulesCmd : ExternalCommand
|
|
|
|
|
|
{
|
|
|
|
|
|
public override void Execute()
|
|
|
|
|
|
{
|
|
|
|
|
|
var list = Document.OfCollector().OfClass(typeof(ViewSchedule)).OfCategory(BuiltInCategory.OST_Schedules).Cast<ViewSchedule>().ToList();
|
|
|
|
|
|
if (!list.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
ErrorMessage = "当前项目不存在明细表";
|
|
|
|
|
|
Result = Result.Failed;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
var browserWindow = new VistaFolderBrowserDialog();
|
|
|
|
|
|
browserWindow.ShowDialog();
|
|
|
|
|
|
var selectedPath = browserWindow.SelectedPath;
|
|
|
|
|
|
if (selectedPath == null || !Directory.Exists(selectedPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
//var manager = new NotificationMessageManager();
|
2025-07-11 09:20:23 +08:00
|
|
|
|
//manager.CreateMessage().Primary("#1751C3").Background("#333").HasBadge("净高").HasMessage("未选择文件夹").Queue();
|
2025-02-10 20:53:40 +08:00
|
|
|
|
Result = Result.Cancelled;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var path = $"{selectedPath}\\导出的明细表.xlsx";
|
2026-02-21 16:31:24 +08:00
|
|
|
|
ExportScheduleToExcel(list, path);
|
2026-02-24 11:34:18 +08:00
|
|
|
|
WinDialogAssist.OpenFolderAndSelectFile(path);
|
2026-02-21 16:31:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void ExportScheduleToExcel(List<ViewSchedule> list,string path)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
var allSheetsData = new Dictionary<string, object>();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var viewSchedule in list)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 过滤掉无法分配类型的明细表(如修订云线明细表等特殊情况)
|
|
|
|
|
|
if (!viewSchedule.CanHaveTypeAssigned()) continue;
|
|
|
|
|
|
|
|
|
|
|
|
var td = viewSchedule.GetTableData();
|
|
|
|
|
|
var tdd = td.GetSectionData(SectionType.Body);
|
|
|
|
|
|
var nColumns = tdd.NumberOfColumns;
|
|
|
|
|
|
var nRows = tdd.NumberOfRows;
|
|
|
|
|
|
|
|
|
|
|
|
// 如果明细表连标题行都没有,直接跳过
|
|
|
|
|
|
if (nRows == 0) continue;
|
2025-02-10 20:53:40 +08:00
|
|
|
|
|
2026-02-21 16:31:24 +08:00
|
|
|
|
// 1. 获取第 0 行作为 Excel 的标题 (Headers)
|
|
|
|
|
|
var headers = new List<string>();
|
|
|
|
|
|
for (int j = 0; j < nColumns; j++)
|
2025-02-10 20:53:40 +08:00
|
|
|
|
{
|
2026-02-21 16:31:24 +08:00
|
|
|
|
string headerName = viewSchedule.GetCellText(SectionType.Body, 0, j);
|
|
|
|
|
|
|
|
|
|
|
|
// 容错处理:如果列名为空,给个默认名;如果列名重复,加后缀(MiniExcel要求Key唯一)
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(headerName)) headerName = $"Column_{j + 1}";
|
|
|
|
|
|
string uniqueName = headerName;
|
|
|
|
|
|
int counter = 1;
|
|
|
|
|
|
while (headers.Contains(uniqueName))
|
2025-02-10 20:53:40 +08:00
|
|
|
|
{
|
2026-02-21 16:31:24 +08:00
|
|
|
|
uniqueName = $"{headerName}_{counter++}";
|
2025-02-10 20:53:40 +08:00
|
|
|
|
}
|
2026-02-21 16:31:24 +08:00
|
|
|
|
headers.Add(uniqueName);
|
2025-02-10 20:53:40 +08:00
|
|
|
|
}
|
2026-02-21 16:31:24 +08:00
|
|
|
|
|
|
|
|
|
|
// 2. 构造数据行(从第 1 行开始循环)
|
|
|
|
|
|
var rowsData = new List<Dictionary<string, object>>();
|
|
|
|
|
|
for (int i = 1; i < nRows; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var row = new Dictionary<string, object>();
|
|
|
|
|
|
for (int j = 0; j < nColumns; j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 使用上面取到的 headers[j] 作为 Key
|
|
|
|
|
|
row[headers[j]] = viewSchedule.GetCellText(SectionType.Body, i, j);
|
|
|
|
|
|
}
|
|
|
|
|
|
rowsData.Add(row);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 处理 Sheet 名称非法字符 (Excel 不允许 \ / ? * [ ] : )
|
|
|
|
|
|
string safeSheetName = viewSchedule.Name;
|
|
|
|
|
|
char[] invalidChars = { '\\', '/', '?', '*', '[', ']', ':' };
|
|
|
|
|
|
foreach (var c in invalidChars) safeSheetName = safeSheetName.Replace(c, '_');
|
|
|
|
|
|
if (safeSheetName.Length > 31) safeSheetName = safeSheetName.Substring(0, 31);
|
|
|
|
|
|
|
|
|
|
|
|
allSheetsData.Add(safeSheetName, rowsData);
|
|
|
|
|
|
}
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
MiniExcel.SaveAs(path, allSheetsData, overwriteFile: true);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (IOException)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 提示文件被占用
|
|
|
|
|
|
MessageBox.Show("请先关闭已打开的 Excel 文件后再尝试保存。");
|
|
|
|
|
|
}
|
2025-02-10 20:53:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|