NPOI 实现Excel模板导出

记录一下使用NPOI实现定制的Excel导出模板,已下实现需求及主要逻辑

所需Json数据 对应参数 List<PurQuoteExportDataCrInput> listData

[
  {
    "ItemName": "电缆VV3*16+2*10",
    "Spec": "电缆VV3*16+2*10",
    "Uom": "米",
    "Quantity": 10.0,
    "MinPrice": 100.0,
    "UseOrg": null,
    "SumPrice": 3000.0,
    "Desc": "\r\n备注: \r\n1、只有*拟签数量,*拟签含税单价(元)可修改: \r\n2、底色标记的价格为该物料行的最低报价: \r\n3、若不中标,将拟签数量及价格空着即可: \r\n4、平台拟签数量最多保留4位小数点、拟签含税单价最多保留4位小数点,可能会造成平台总价计算结果与EXCEL计算略有差异,请以平台页面为准\"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n",
    "CardList": [
      {
        "Name": "供应商1",
        "Price": 100.0,
        "SumPrice": 1000.0
      },
      {
        "Name": "供应商2",
        "Price": 200.0,
        "SumPrice": 2000.0
      }
    ]
  },
  {
    "ItemName": "电缆VV3*70+1*35",
    "Spec": "电缆VV3*70+1*35",
    "Uom": "米",
    "Quantity": 10.0,
    "MinPrice": 100.0,
    "UseOrg": null,
    "SumPrice": 3000.0,
    "Desc": "\r\n备注: \r\n1、只有*拟签数量,*拟签含税单价(元)可修改: \r\n2、底色标记的价格为该物料行的最低报价: \r\n3、若不中标,将拟签数量及价格空着即可: \r\n4、平台拟签数量最多保留4位小数点、拟签含税单价最多保留4位小数点,可能会造成平台总价计算结果与EXCEL计算略有差异,请以平台页面为准\"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n",
    "CardList": [
      {
        "Name": "供应商1",
        "Price": 100.0,
        "SumPrice": 1000.0
      },
      {
        "Name": "供应商2",
        "Price": 200.0,
        "SumPrice": 2000.0
      }
    ]
  },
  {
    "ItemName": "电缆VV3*95+1*50",
    "Spec": "电缆VV3*95+1*50",
    "Uom": "米",
    "Quantity": 10.0,
    "MinPrice": 100.0,
    "UseOrg": null,
    "SumPrice": 3000.0,
    "Desc": "\r\n备注: \r\n1、只有*拟签数量,*拟签含税单价(元)可修改: \r\n2、底色标记的价格为该物料行的最低报价: \r\n3、若不中标,将拟签数量及价格空着即可: \r\n4、平台拟签数量最多保留4位小数点、拟签含税单价最多保留4位小数点,可能会造成平台总价计算结果与EXCEL计算略有差异,请以平台页面为准\"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n",
    "CardList": [
      {
        "Name": "ZH001",
        "Price": 100.0,
        "SumPrice": 1000.0
      },
      {
        "Name": "ZH002",
        "Price": 200.0,
        "SumPrice": 2000.0
      }
    ]
  },
  {
    "ItemName": "电缆VV3*120+1*70",
    "Spec": "电缆VV3*120+1*70",
    "Uom": "米",
    "Quantity": 10.0,
    "MinPrice": 0.0,
    "UseOrg": null,
    "SumPrice": 0.0,
    "Desc": "\r\n备注: \r\n1、只有*拟签数量,*拟签含税单价(元)可修改: \r\n2、底色标记的价格为该物料行的最低报价: \r\n3、若不中标,将拟签数量及价格空着即可: \r\n4、平台拟签数量最多保留4位小数点、拟签含税单价最多保留4位小数点,可能会造成平台总价计算结果与EXCEL计算略有差异,请以平台页面为准\"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n",
    "CardList": [
      {
        "Name": "ZH001",
        "Price": 0.0,
        "SumPrice": 0.0
      },
      {
        "Name": "ZH002",
        "Price": 0.0,
        "SumPrice": 0.0
      }
    ]
  }
]

调用方法

cs 复制代码
/// <summary>
/// 导出特定模板数据.
/// </summary>
/// <param name="tempFileName">模板名称.</param>
/// <param name="listData">模板数据.</param>
/// <returns></returns>
[NonAction]
private async Task<dynamic> ExportTempExcelData(string tempFileName, List<PurQuoteExportDataCrInput> listData)
{
    //文件服务器地址
    string addPath = Path.Combine("D:\\TemporaryFile", tempFileName);

    // 创建一个新的工作簿
    HSSFWorkbook workbook = new HSSFWorkbook();
    ISheet sheet = workbook.CreateSheet("定制模版");

    // 合并列
    sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 0, 0, 5));  // 采购信息
    sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(1, 2, 0, 0));  // 序号
    sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(1, 2, 4, 4));  // 采购数量
    sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(1, 2, 5, 5));  // 最低报价

    // 设置单元格宽度
    sheet.SetColumnWidth(1, 20 * 256); // 物料名称宽度
    sheet.SetColumnWidth(2, 20 * 256); // 规格型号宽度

    // 设置主要样式
    var cellStyle = SetMainCellStyle();

    // 创建行
    var row1 = sheet.CreateRow(0);
    var row2 = sheet.CreateRow(1);
    var row3 = sheet.CreateRow(2);

    // 设置行高
    row1.Height = 30 * 30;
    row2.Height = 30 * 20;
    row3.Height = 30 * 20;

    // 采购信息标题
    var row1_cel = row1.CreateCell(0);
    row1_cel.SetCellValue("采购信息");
    row1_cel.CellStyle = cellStyle;

    // 设置边框
    row1.CreateCell(1).CellStyle = cellStyle;
    row1.CreateCell(2).CellStyle = cellStyle;
    row1.CreateCell(3).CellStyle = cellStyle;
    row1.CreateCell(4).CellStyle = cellStyle;

    // 序号标题
    var cell2 = row2.CreateCell(0);
    cell2.SetCellValue("序号");
    cell2.CellStyle = cellStyle;

    // 采购数量标题
    var row2_cel4 = row2.CreateCell(4);
    row2_cel4.SetCellValue("采购数量");
    row2_cel4.CellStyle = cellStyle;

    // 最低报价标题
    var row2_cel5 = row2.CreateCell(5);
    row2_cel5.SetCellValue("最低报价");
    row2_cel5.CellStyle = cellStyle;

    // 填充边框
    row3.CreateCell(0).CellStyle = cellStyle;

    // 物料名称标题
    var row3_cel1 = row3.CreateCell(1);
    row3_cel1.SetCellValue("物料名称");
    row3_cel1.CellStyle = cellStyle;

    // 规格型号标题
    var row3_cel2 = row3.CreateCell(2);
    row3_cel2.SetCellValue("规格型号");
    row3_cel2.CellStyle = cellStyle;

    // 计量单位标题
    var row3_cel3 = row3.CreateCell(3);
    row3_cel3.SetCellValue("计量单位");
    row3_cel3.CellStyle = cellStyle;

    // 填充边框
    row3.CreateCell(4).CellStyle = cellStyle;
    row3.CreateCell(5).CellStyle = cellStyle;

    // 从第4行开始都是动态数据
    int startRow4 = 3;

    // 记录最有一列下标
    int lastIndex = 0;

    // 拟签含税总价
    double sumAmount = 0;

    // 动态渲染数据
    for (var i = 0; i < listData.Count; i++)
    {
        ICellStyle dyCel_Style = SetMainCellStyle(false);

        var dyRow = sheet.CreateRow(startRow4);
        dyRow.Height = 30 * 20; // 设置行高

        var dyCel0 = dyRow.CreateCell(0);
        dyCel0.SetCellValue(i + 1);  // 序号值
        dyCel0.CellStyle = dyCel_Style;

        var dyCel1 = dyRow.CreateCell(1);
        dyCel1.SetCellValue(listData[i].ItemName);  // 物料名称值
        dyCel1.CellStyle = dyCel_Style;

        var dyCel2 = dyRow.CreateCell(2);
        dyCel2.SetCellValue(listData[i].ItemName);  // 型号规格值
        dyCel2.CellStyle = dyCel_Style;

        var dyCel3 = dyRow.CreateCell(3);
        dyCel3.SetCellValue(listData[i].Uom);  // 计量单位值
        dyCel3.CellStyle = dyCel_Style;

        var dyCel4 = dyRow.CreateCell(4);
        dyCel4.SetCellValue(listData[i].Quantity);  // 采购数量值
        dyCel4.CellStyle = dyCel_Style;

        var dyCel5 = dyRow.CreateCell(5);
        dyCel5.SetCellValue(listData[i].MinPrice);  // 最低报价值
        dyCel5.CellStyle = dyCel_Style;

        startRow4++;

        int startNum = 6;
        int endNum = 7;

        // 动态供应商信息从第六列开始遍历数据
        var cardList = listData[i].CardList;
        for (int k = 0; k < cardList.Count; k++)
        {
            if (i == 0)
            {
                // 合并列
                sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 0, startNum, endNum)); // 供应名称
                sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(1, 2, startNum, startNum)); // 单价
                sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(1, 2, endNum, endNum)); // 总价

                // 供应商
                ICell cell = row1.CreateCell(startNum);
                cell.SetCellValue(cardList[k].Name);
                cell.CellStyle = cellStyle;

                // 填充边框
                ICell cell1 = row1.CreateCell(endNum);
                cell1.CellStyle = cellStyle;

                // 单价标题
                var row2_cel_num = row2.CreateCell(startNum);
                row2_cel_num.SetCellValue("单价");
                row2_cel_num.CellStyle = cellStyle;

                // 总价标题
                var row2_cel_num1 = row2.CreateCell(endNum);
                row2_cel_num1.SetCellValue("总价");
                row2_cel_num1.CellStyle = cellStyle;

                // 填充边框
                row3.CreateCell(startNum).CellStyle = cellStyle;
                row3.CreateCell(endNum).CellStyle = cellStyle;
            }

            // 单价值
            var row4_cel_num = dyRow.CreateCell(startNum);
            row4_cel_num.SetCellValue(cardList[k].Price);
            row4_cel_num.CellStyle = dyCel_Style;

            // 总价值
            var row4_cel_num1 = dyRow.CreateCell(endNum);
            row4_cel_num1.SetCellValue(cardList[k].SumPrice);
            row4_cel_num1.CellStyle = dyCel_Style;

            // 供应商单价、总价突出显示
            if(listData[i].MinPrice == cardList[k].Price && listData[i].MinPrice > 0)
            {
                ICellStyle style1 = SetMainCellStyle(false);
                style1.FillForegroundColor = IndexedColors.Red.Index; // 设置背景颜色为红色
                style1.FillPattern = FillPattern.SolidForeground;     // 填充模式为纯色
                row4_cel_num.CellStyle = style1;
                row4_cel_num1.CellStyle = style1;
                sumAmount += cardList[k].SumPrice;
            }

            startNum += 2;
            endNum = startNum + 1;
            lastIndex = startNum;
        }

        // 使用单位值
        var dyCeln = dyRow.CreateCell(lastIndex);
        dyCeln.SetCellValue("使用单位" + i);
        dyCeln.CellStyle = dyCel_Style;
    }

    // 处理边框
    var row1_cel_last = row1.CreateCell(lastIndex);
    row1_cel_last.CellStyle = cellStyle;
    var row2_cel_last = row2.CreateCell(lastIndex);
    row2_cel_last.CellStyle = cellStyle;
    var row3_cel_last = row3.CreateCell(lastIndex);
    row3_cel_last.CellStyle = cellStyle;
    row3_cel_last.SetCellValue("使用单位");

    // 合并拟签含税总价
    sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(startRow4, startRow4, 0, lastIndex - 1));

    // 合并备注
    sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(startRow4 + 1, startRow4 + 1, 0, lastIndex - 1));

    // 设置合并拟签含税总价
    var row_sprice = sheet.CreateRow(startRow4);
    row_sprice.Height = 30 * 15;
    var cell_sprice = row_sprice.CreateCell(0);
    cell_sprice.SetCellValue("拟签含税总价:" + sumAmount);
    ICellStyle cell_sprice_style = SetMainCellStyle();
    cell_sprice_style.Alignment = HorizontalAlignment.Left; // 垂直靠左
    cell_sprice.CellStyle = cell_sprice_style;

    // 设置备注
    var row_desc = sheet.CreateRow(startRow4 + 1);
    row_desc.Height = 30 * 50;
    var cell_desc = row_desc.CreateCell(0);
    cell_desc.SetCellValue(listData[0].Desc);
    ICellStyle cell_desc_style = SetMainCellStyle();
    cell_desc_style.Alignment = HorizontalAlignment.Left; // 垂直靠左
    var cell_desc_style_font = workbook.CreateFont();
    cell_desc_style_font.FontName = "SimSun";
    cell_desc_style_font.FontHeightInPoints = 8; // 设置字体大小
    cell_desc_style_font.Color = HSSFColor.Red.Index; // 设置字体颜色
    cell_desc_style.SetFont(cell_desc_style_font);
    cell_desc.CellStyle = cell_desc_style;

    // 处理合并拟签含税总价样式、备注样式其余边框
    for (var i = 1; i < lastIndex + 1; i++)
    {
        ICellStyle cellStyle2 = workbook.CreateCellStyle();
        SetCellBorder(cellStyle2);
        row_sprice.CreateCell(i).CellStyle = cellStyle2;
        row_desc.CreateCell(i).CellStyle = cellStyle2;
    }

    MemoryStream fileStream = new MemoryStream();
    workbook.Write(fileStream);
    fileStream.Position = 0; // 确保流的位置重置为0
    
    //文件上传到服务器本地
    await _fileManager.UploadFileByType(fileStream, FileVariable.TemporaryFilePath, tempFileName);
    
    //返回文件下载地址前端调用下载
    return new { name = tempFileName, url = "/api/file/Download?file=" + tempFileName ) };

    // 设置单元格边框
    void SetCellBorder(ICellStyle _cellStyle)
    {
        // 设置单元格边框样式
        _cellStyle.BorderTop = BorderStyle.Thin;   // 上边框
        _cellStyle.BorderBottom = BorderStyle.Thin; // 下边框
        _cellStyle.BorderLeft = BorderStyle.Thin;   // 左边框
        _cellStyle.BorderRight = BorderStyle.Thin;  // 右边框

        // 设置边框颜色黑色
        _cellStyle.TopBorderColor = IndexedColors.Black.Index;
        _cellStyle.BottomBorderColor = IndexedColors.Black.Index;
        _cellStyle.LeftBorderColor = IndexedColors.Black.Index;
        _cellStyle.RightBorderColor = IndexedColors.Black.Index;
    }

    // 设置主要样式
    ICellStyle SetMainCellStyle(bool fontBold = true)
    {
        // 创建单元格样式
        ICellStyle cellStyle = workbook.CreateCellStyle();
        SetCellBorder(cellStyle);

        // 创建字体样式
        var font = workbook.CreateFont();
        font.IsBold = fontBold; // 设置字体加粗
        font.FontName = "SimSun"; // 设置宋体
        cellStyle.SetFont(font);

        cellStyle.Alignment = HorizontalAlignment.Center; // 水平居中
        cellStyle.VerticalAlignment = VerticalAlignment.Center; // 垂直居中
        cellStyle.WrapText = true;   // 自动换行
        return cellStyle;
    }
相关推荐
小码编匠3 小时前
C# 高性能动态获取对象属性值
后端·c#·.net
无敌最俊朗@4 小时前
c#————委托Action使用例子
java·前端·c#
stm 学习ing5 小时前
FPGA 第7讲 简单组合逻辑译码器
stm32·嵌入式硬件·学习·fpga开发·c#·学习方法·fpga
Gentle5865 小时前
labview实现导出excel表格
excel·labview
chyun20115 小时前
基于YOLO实现滑块验证码破解
python·c#
gxchai7 小时前
EXCEL延迟退休公式
excel
qtvb19878 小时前
c# 在10万条数据中判断是否存在很慢问题
开发语言·windows·c#
神奇夜光杯8 小时前
Python酷库之旅-第三方库Pandas(218)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长
eggcode9 小时前
【Revit二次开发】创建Ribbon选项卡与带图标的按钮
c#·revit