# 使用 NPOI 在 aardio 中生成 Excel 文件

作为开发者，我们经常需要根据数据集生成 Excel 文件。虽然这类需求并不频繁，但每次需要时总会忘记部分实现细节。因此我决定记录一个示例并分享出来，希望能帮助到有需要的人。

## 准备工作

首先需要安装 NPOI 库。在 aardio 中可以通过 NPOP 扩展库来调用 NPOI 组件：

```aardio
import NPOI;
```

NPOI 包含多个命名空间，我们主要使用以下两个：

```aardio
// 用于操作 HSSFWorkbook、HSSFFont、HSSFCellStyle 等对象
import NPOI.HSSF.UserModel; 

// 用于定义 ISheet、IRow、ICell 等接口
import NPOI.SS.UserModel;  
```

## 基本逻辑

创建 Excel 的基本流程很简单：

1. 定义一个工作簿(Workbook)
2. 在工作簿中创建工作表(Sheet)
3. 在工作表中添加行(Row)和单元格(Cell)

## 辅助函数

为了简化单元格创建过程，我们可以先编写一个辅助函数：

```aardio
// 创建单元格的辅助函数
createCell = function(currentRow, cellIndex, value, style){
    var cell = currentRow.CreateCell(cellIndex);
    cell.SetCellValue(value);
    if(style) cell.CellStyle = style;
}
```

这样创建单元格时只需调用：

```aardio
createCell(headerRow, cellIndex, "列标题", cellStyle);
```

## 完整示例

下面是一个完整的示例，展示如何创建包含合并单元格和自动调整列宽的 Excel 文件：

```aardio
import console;
import NPOI;

// 创建工作簿
var workbook = NPOI.HSSF.UserModel.HSSFWorkbook();

// 创建字体样式
var font = workbook.CreateFont();
font.FontHeightInPoints = 11;
font.FontName = "Tahoma";

// 创建单元格的辅助函数
createCell = function(currentRow, cellIndex, value, style){
    var cell = currentRow.CreateCell(cellIndex);
    cell.SetCellValue(value);
    
    if(style) cell.CellStyle = style;
}

// 创建带边框的单元格样式
var cellStyle = workbook.CreateCellStyle();
cellStyle.SetFont(font);
cellStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Medium;
cellStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Medium; 
cellStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Medium;
cellStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Medium;
cellStyle.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.Center;

// 创建工作表
var sheet = workbook.CreateSheet("报表");

// 创建标题行
var headerRow = sheet.CreateRow(0);

// 添加表头
createCell(headerRow, 0, "批次名称", cellStyle);
createCell(headerRow, 1, "规则ID", cellStyle); 
createCell(headerRow, 2, "规则类型", cellStyle);
createCell(headerRow, 3, "代码消息类型", cellStyle);
createCell(headerRow, 4, "严重程度", cellStyle);

// 数据起始行
var rowIndex = 1;

// 模拟数据集合
var batchErrorReports = {
    {
        Name = "批次1";
        Rules = {
            {RuleID="R001", RuleType="类型A", CodeMessageType="错误", Severity="高"},
            {RuleID="R002", RuleType="类型B", CodeMessageType="警告", Severity="中"}
        }
    },
    {
        Name = "批次2"; 
        Rules = {
            {RuleID="R003", RuleType="类型C", CodeMessageType="信息", Severity="低"}
        }
    }
};

// 遍历数据集合
for i,batchErrorReport in batchErrorReports {
    // 创建当前数据行
    var currentRow = sheet.CreateRow(rowIndex);
    createCell(currentRow, 0, batchErrorReport.Name, cellStyle);
    
    // 计算需要合并的行数
    var ruleCount = #batchErrorReport.Rules;
    if(ruleCount > 1) {
        var mergeIndex = (ruleCount - 1) + rowIndex;
        
        // 合并单元格
        var mergeRange = NPOI.SS.Util.CellRangeAddress(rowIndex, mergeIndex, 0, 0);
        sheet.AddMergedRegion(mergeRange);
    }
    
    // 遍历规则集合
    for j,rule in batchErrorReport.Rules {
        if(j > 1) {
            currentRow = sheet.CreateRow(rowIndex);
        }
        createCell(currentRow, 1, rule.RuleID, cellStyle);
        createCell(currentRow, 2, rule.RuleType, cellStyle);
        createCell(currentRow, 3, rule.CodeMessageType, cellStyle); 
        createCell(currentRow, 4, rule.Severity, cellStyle);
        rowIndex++;
    }
    
    rowIndex = ruleCount >= 1 ? rowIndex : rowIndex + 1;
}

// 自动调整列宽
var lastColumn = sheet.GetRow(0).LastCellNum;
for(i=0; lastColumn;1){
    sheet.AutoSizeColumn(i);
}

// 保存 Excel 文件 
workbook.Write("/报表.xls"));

console.log("Excel 文件已生成:", filePath);
console.pause(true);
```


## 注意事项

1. aardio 中使用 NPOI 需要先安装 NPOP 扩展库
2. 合并单元格使用 `CellRangeAddress` 类，参数依次是：起始行、结束行、起始列、结束列
3. 保存文件时直接使用 `workbook.Write()` 方法，不需要像 C# 中那样使用 `FileStream`

通过这个示例，你可以快速掌握在 aardio 中使用 NPOI 生成 Excel 文件的基本方法。根据实际需求，你可以进一步扩展这个基础框架，添加更多样式和功能。