NPOI 实现Excel模板导出

news2024/11/22 2:15:56

 记录一下使用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
      }
    ]
  }
]

调用方法 

/// <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;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2245034.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

凸函数与深度学习调参

问题1&#xff1a;如何区分凸问题和凹问题&#xff1f; 问题2&#xff1a;深度学习如何区分调参&#xff1f;

DBeaver MACOS 安装 并连接到docker安装的mysql

官网下载&#xff1a;Download | DBeaver Community 网盘下载&#xff1a;链接: https://pan.baidu.com/s/15fAhbflHO-AGc-uAnc3Rjw?pwdbrz9 提取码: brz9 下载驱动 连接测试 报错 null, message from server: "Host 172.17.0.1 is not allowed to connect to this M…

php:使用socket函数创建WebSocket服务

一、前言 闲来无事&#xff0c;最近捣鼓了下websocket&#xff0c;但是不希望安装第三方类库&#xff0c;所以打算用socket基础函数创建个服务。 二、构建websocket服务端 <?phpclass SocketService {// 默认的监听地址和端口private $address 0.0.0.0;private $port 8…

@RequestBody、@Data、@Validated、@Pattern(regexp=“?“)(复习)

目录 一、注解RequestBody。 二、注解Data。 三、注解Validated、Pattern(regexp"?")。 1、完成实体参数&#xff08;对象属性&#xff09;校验。 2、NotNull、NotEmpty、Email。 一、注解RequestBody。 &#xff08;如&#xff1a;JSON格式的数据——>Java对象&…

基于YOLOv8深度学习的医学影像骨折检测诊断系统研究与实现(PyQt5界面+数据集+训练代码)

本论文深入研究并实现了一种基于YOLOV8深度学习模型的医学影像骨折检测与诊断系统&#xff0c;旨在为医学影像中的骨折检测提供高效且准确的自动化解决方案。随着医疗影像技术的快速发展&#xff0c;临床医生需要从大量复杂的医学图像中精确、快速地识别病灶区域&#xff0c;特…

69.x的平方根-力扣(LeetCode)

题目&#xff1a; 解题思路&#xff1a; 解决本题主要运用的方法是二分法&#xff0c;二分法是一种在有序数组中查找某一特定元素的搜索算法。鉴于本题满足整个序列是有序的&#xff0c;并且可以通过比较来改变区间&#xff0c;满足二分法的应用条件&#xff0c;所以采用二分法…

Notepad++--在开头快速添加行号

原文网址&#xff1a;Notepad--在开头快速添加行号_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Notepad怎样在开头快速添加行号。 需求 原文件 想要的效果 方法 1.添加点号 Alt鼠标左键&#xff0c;从首行选中首列下拉&#xff0c;选中需要添加序号的所有行的首列&#xff…

新兴数据仓库设计与实践手册:从分层架构到实际应用(二)

本手册将分为三部分发布&#xff0c;以帮助读者逐步深入理解数据仓库的设计与实践。 第一部分介绍数据仓库的整体架构概述&#xff1b;第二部分深入讨论ETL在数仓中的应用理论&#xff0c;ODS层的具体实现与应用&#xff1b;第三部分将围绕DW数据仓库层、ADS层和数据仓库的整体…

java八股-SpringCloud微服务-Eureka理论

文章目录 SpringCloud架构Eureka流程Nacos和Eureka的区别是&#xff1f;CAP定理Ribbon负载均衡策略自定义负载均衡策略如何实现&#xff1f;本章小结 SpringCloud架构 Eureka流程 服务提供者向Eureka注册服务信息服务消费者向注册中心拉取服务信息服务消费者使用负载均衡算法挑…

MySQL —— explain 查看执行计划与 MySQL 优化

文章目录 explain 查看执行计划explain 的作用——查看执行计划explain 查看执行计划返回信息详解表的读取顺序&#xff08;id&#xff09;查询类型&#xff08;select_type&#xff09;数据库表名&#xff08;table&#xff09;联接类型&#xff08;type&#xff09;可用的索引…

input file结合vue3和vant实现上传图片效果,并显示上传进度百分比%

这里写自定义目录标题 采用的dom结构是input file&#xff0c;label事件绑定&#xff0c;一下为代码传入参数为uploadNum实现效果如图上传中&#xff0c;图片1上传成功&#xff0c;图片2 采用的dom结构是input file&#xff0c;label事件绑定&#xff0c;一下为代码 传入参数为…

CSS优化file控件样式

<div class"file-box"><input type"button" class"btn" value"选择文件" /><inputtype"file"class"file"id"upimg"change"previewFiles"multiple/></div><!-- Vu…

AJAX笔记 (速通精华版)

AJAX&#xff08;Asynchronous Javascript And Xml&#xff09; 此笔记来自于动力节点最美老杜 传统请求及缺点 传统的请求都有哪些&#xff1f; 直接在浏览器地址栏上输入URL。点击超链接提交 form 表单使用 JS 代码发送请求 window.open(url)document.location.href urlwi…

某校园网登录界面前端加密绕过

前言 尝试对学校校园网登录框进行爆破&#xff0c;发现密码在前端被加密了 Burp抓包 抓包信息 DDDDD2022***&upass3d5c84b6fb1dc75987884f39c05b0e6a123456782&R10&R21&para00&0MKKey123456&v6ip From表单提交上来的文本这些参数&#xff0c;DDDD是…

《生成式 AI》课程 第3講 CODE TASK执行文章摘要的机器人

课程 《生成式 AI》课程 第3講&#xff1a;訓練不了人工智慧嗎&#xff1f;你可以訓練你自己-CSDN博客 任务1:总结 1.我们希望你创建一个可以执行文章摘要的机器人。 2.设计一个提示符&#xff0c;使语言模型能够对文章进行总结。 model: gpt-4o-mini,#gpt-3.5-turbo, import…

Github客户端工具github-desktop使用教程

文章目录 1.客户端工具的介绍2.客户端工具使用感受3.仓库的创建4.初步尝试5.本地文件和仓库路径5.1原理说明5.2修改文件5.3版本号的说明5.4结合码云解释5.5版本号的查找 6.分支管理6.1分支的引入6.2分支合并6.3创建测试仓库6.4创建测试分支6.5合并分支6.6合并效果查看6.7分支冲…

python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具

python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具 文章目录 python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具项目背景技术栈用户界面核心功能实现结果展示完整代码总结 在现代软件开发中&#xff0c;测试接口的有效性与响应情况变得尤为重要。本文将指导…

JavaScript的类型转换

类型转换 &#xff1a; 隐式转换和显示转换 一般的&#xff0c;默认单选框和多选框传过来的值都是字符串 JavaScript是弱数据类型&#xff1a;JavaScript不知道变量属于哪种类型&#xff0c;需要赋值了才清楚。 缺点&#xff1a;使用表单、prompt获取过来的数据默认是字符串类…

Spring Boot中使用AOP和反射机制设计一个基于redis的幂等注解,简单易懂教程

由于对于一些非查询操作&#xff0c;有时候需要保证该操作是幂等的&#xff0c;该帖子设计幂等注解的原理是使用AOP和反射机制获取方法的类、方法和参数&#xff0c;然后拼接形成一个幂等键&#xff0c;当下一次有重复操作过来的时候&#xff0c;判断该幂等键是否存放&#xff…

一文详细深入总结服务器选型

1. 题记&#xff1a; 服务器选型工作是项目规划检讨的一项非常重要的工作&#xff0c;本文详细深入总结服务器选型。 2. 服务器基础知识概览 2.1 服务器的定义与功能 2.1 .1 定义 服务器是一种高性能计算机&#xff0c;其设计目的是在网络中提供服务。它可以处理来自多个客…