.NET6使用MiniExcel根据数据源横向导出头部标题及数据

.NET6+MiniExcel根据数据源横向导出头部标题

MiniExcel简单、高效避免OOM的.NET处理Excel查、写、填充数据工具。

特点:
低内存耗用,避免OOM、频繁 Full GC 情况
支持即时操作每行数据
兼具搭配 LINQ 延迟查询特性,能办到低消耗、快速分页等复杂查询
轻量,不需要安装 Microsoft Office、COM+,DLL小于150KB
简便操作的 API 风格

github地址: MiniExcel
gitee地址: MiniExcel

本案例实现的功能是使用Miniexcel横向导出指标编码、指标名称,医院类型及指标对应的数据值,
要求导出效果如下所示:

  1. 第一列展示医院
  2. 头部两行动态展示指标编码、指标名称,下面展示每家医院所对应指标的值
    在这里插入图片描述
  3. 安装NuGet程序包SqlSugarCore、MiniExcel、Furion

代码如下:
结合实际情况,可以适当改下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MiniExcelLibs;
using MiniExcelLibs.Attributes;
using MiniExcelLibs.OpenXml;
using SqlSugar;

namespace DJPSMS.Application.Service
{
    [AllowAnonymous]
    public class MiniexcelTest : IDynamicApiController
    {
        private readonly ISqlSugarClient _db;
        private readonly SqlSugarRepository<TDU_HOSPITALTEST> _tduHospitalRepository;

        /// <summary>
        /// 构造函数注入SqlSugar
        /// </summary>
        /// <param name="db"></param>
        public MiniexcelTest(ISqlSugarClient db, SqlSugarRepository<TDU_HOSPITALTEST> tduHospitalRepository)
        {
            _db = db;
            _tduHospitalRepository = tduHospitalRepository;
        }


        /// <summary>
        /// Miniexcel导出
        /// </summary>
        /// <param name="Chapter">章节(案例中未使用)</param>
        /// <returns></returns>
        [HttpGet("DownLoadExcel")]
        public void DownLoadExcel([FromQuery][Required] string Chapter = "1")
        {
            try
            {
                // 导出数据源总集合
                var quotaAssemble = new List<Dictionary<string, object>>();
                // 构建横向指标标题
                var quotaPairy = new Dictionary<string, object>();

                #region 构造excel模板及数据源
                Log.Information($"构造excel横向指标标题开始--------");
                // 使用SqlSugar查询数据库
                // var quotaArray = _db.Queryable<DW_QUOTATEST>()
                //    .Where(x => x.Q_CODE.StartsWith(Chapter))
                //    .GroupBy(x => new { x.Q_CODE, x.Q_NAME })
                //    .OrderBy(x => x.Q_CODE)
                //    .Select(g => new { g.Q_CODE, g.Q_NAME })
                //    .ToList();
                // 所有的指标类型
                var quotaArray = new List<DW_QUOTATEST>()
                {
                   new DW_QUOTATEST{ Q_ID = "1", Q_CODE = "1.01.01",Q_NAME ="指标1"},
                   new DW_QUOTATEST{ Q_ID = "2", Q_CODE = "1.01.02",Q_NAME ="指标2"},
                   new DW_QUOTATEST{ Q_ID = "3", Q_CODE = "1.01.03",Q_NAME ="指标3"},
                   new DW_QUOTATEST{ Q_ID = "4", Q_CODE = "1.01.04",Q_NAME ="指标4"},
                   new DW_QUOTATEST{ Q_ID = "5", Q_CODE = "1.01.05",Q_NAME ="指标5"},
                   new DW_QUOTATEST{ Q_ID = "6", Q_CODE = "1.01.06",Q_NAME ="指标6"},
                   new DW_QUOTATEST{ Q_ID = "7", Q_CODE = "1.01.07",Q_NAME ="指标7"},
                   new DW_QUOTATEST{ Q_ID = "8", Q_CODE = "1.01.08",Q_NAME ="指标8"},
                   new DW_QUOTATEST{ Q_ID = "9", Q_CODE = "1.01.09",Q_NAME ="指标9"},
                   new DW_QUOTATEST{ Q_ID = "10", Q_CODE = "1.01.10",Q_NAME ="指标10"},
                   new DW_QUOTATEST{ Q_ID = "11", Q_CODE = "1.01.11",Q_NAME ="指标11"},
                   new DW_QUOTATEST{ Q_ID = "12", Q_CODE = "1.01.12",Q_NAME ="指标12"},
                   new DW_QUOTATEST{ Q_ID = "13", Q_CODE = "1.01.13",Q_NAME ="指标13"}
                };

                // 設置列宽
                var config = new OpenXmlConfiguration
                {
                    DynamicColumns = CreateDynamicColumns(quotaArray.GroupBy(x => x.Q_CODE).Select(x => x.Key).ToList())
                };

                // 构建横向指标标题
                quotaPairy["医院名称"] = "";
                for (int i = 0; i < quotaArray.Count; i++)
                {
                    if (quotaPairy.ContainsKey(quotaArray[i].Q_CODE)) continue;
                    var propertyCode = quotaArray[i].Q_CODE;
                    var propertyName = quotaArray[i].Q_NAME;
                    quotaPairy[propertyCode] = propertyName;
                }
                quotaAssemble.Add(quotaPairy);
                Log.Information($"构造excel横向指标标题结束--------");


                // 构建第一列医院类型
                var hospitalList = new List<TDU_HOSPITALTEST>()
                {
                       new TDU_HOSPITALTEST{ FJGDM ="1",FDESC ="测试医院1" },
                       new TDU_HOSPITALTEST{ FJGDM ="2",FDESC ="测试医院2" },
                       new TDU_HOSPITALTEST{ FJGDM ="3",FDESC ="南京第一" },
                       new TDU_HOSPITALTEST{ FJGDM ="3",FDESC ="测试医院4" },
                       new TDU_HOSPITALTEST{ FJGDM ="4",FDESC ="测试医院5" },
                       new TDU_HOSPITALTEST{ FJGDM ="5",FDESC ="测试医院6" },
                       new TDU_HOSPITALTEST{ FJGDM ="6",FDESC ="测试医院7" },
                       new TDU_HOSPITALTEST{ FJGDM ="7",FDESC ="测试医院8" },
                       new TDU_HOSPITALTEST{ FJGDM ="8",FDESC ="测试医院9" },
                       new TDU_HOSPITALTEST{ FJGDM ="9",FDESC ="测试医院10" },
                       new TDU_HOSPITALTEST{ FJGDM ="10",FDESC ="测试医院11" },
                       new TDU_HOSPITALTEST{ FJGDM ="11",FDESC ="测试医院12" },
                };


                //每家医院对应的指标的值
                var quotaValuePairy = new Dictionary<string, object>();

                // 总数据源,一般来说是从数据库联表中查询的数据,这边是声明的测试数据
                List<HospitalViewCodeDetailTest> resultList = new List<HospitalViewCodeDetailTest>()
                {
                    // 测试医院1的数据
                    new HospitalViewCodeDetailTest { Code = "1.01.01", CodeName = "指标1",HospitalCode ="1",HospitalName ="测试医院1" ,QValue = "11.8"},
                    new HospitalViewCodeDetailTest { Code = "1.01.02", CodeName = "指标2",HospitalCode ="1",HospitalName ="测试医院2" ,QValue = "12.8"},
                    // 测试医院2的数据
                    new HospitalViewCodeDetailTest { Code = "1.01.01", CodeName = "指标1",HospitalCode ="2",HospitalName ="测试医院1" ,QValue = "22.6"},
                    new HospitalViewCodeDetailTest { Code = "1.01.02", CodeName = "指标2",HospitalCode ="2",HospitalName ="测试医院1" ,QValue = "23.2"} ,
                    // 测试医院3的数据
                    new HospitalViewCodeDetailTest { Code = "1.01.01", CodeName = "指标1",HospitalCode ="3",HospitalName ="测试医院3" ,QValue = "65.8"} ,
                    new HospitalViewCodeDetailTest { Code = "1.01.02", CodeName = "指标2",HospitalCode ="3",HospitalName ="测试医院4" ,QValue = "25.1"}
                };

                // 填充对应的指标值
                for (int i = 0; i < hospitalList.Count; i++)
                {
                    quotaValuePairy = new Dictionary<string, object>(); // 在每次迭代中创建新的字典对象
                    var hospitalCodeDetails = resultList.Where(x => x.HospitalCode == hospitalList[i].FJGDM)
                        .Select(x => new
                        {
                            x.Code,
                            x.QValue
                        }).ToList();
                    quotaValuePairy["医院名称"] = hospitalList[i].FDESC;

                    for (int o = 0; o < quotaArray.Count; o++)
                    {
                        if (quotaValuePairy.ContainsKey(quotaArray[o].Q_CODE)) continue;
                        quotaValuePairy[quotaArray[o].Q_CODE] = hospitalCodeDetails.FirstOrDefault(x => x.Code == quotaArray[o].Q_CODE)?.QValue; //指标值
                    }
                    quotaAssemble.Add(quotaValuePairy);
                }
                #endregion



                #region 导出excel
                if (quotaAssemble.Count > 0)
                {
                    Log.Information("正在导出......");
                    // 读取json文件中的自定义保存路径
                    // App.GetConfig官网介绍地址:http://furion.baiqian.ltd/docs/global/app?_highlight=getconfig#12-%E8%8E%B7%E5%8F%96%E9%85%8D%E7%BD%AE%E5%AF%B9%E8%B1%A1
                    //可以改成自己地址
                    string savePath = $"{App.GetConfig<string>("GenerateExcelOfHospitalFillingJobConfig:SavePath")}\\DownLoadExcel\\";
                    if (!Directory.Exists(savePath))
                    {
                        Directory.CreateDirectory(savePath);
                    }
                    string filename = $"{DateTime.Now:yyyyMMddHHmmss}.xlsx";
                    var absoluteFilePath = Path.Combine(savePath, filename);

                    // 保存
                    MiniExcel.SaveAs(absoluteFilePath, quotaAssemble.ToArray(),
                         configuration: config);

                    Log.Information($"{filename}导出成功!");
                }
                #endregion
            }
            catch (Exception ex)
            {
                // 异常处理逻辑
                Log.Error($"发生异常: {ex.Message}");
            }
        }


        /// <summary>
        /// 设置行宽
        /// </summary>
        /// <returns></returns>
        private DynamicExcelColumn[] CreateDynamicColumns(List<string> dwQuota)
        {
            var dynamicColumns = new List<DynamicExcelColumn>
            {
                new DynamicExcelColumn("医院名称") { Index = 0, Width = 30 }
            };
            dynamicColumns.AddRange(dwQuota.Select((codeTitle, codeIndex) =>
            {
                if (string.IsNullOrEmpty(codeTitle))
                {
                    // 处理空值的情况,例如使用默认列名或跳过该列
                    return null; // 返回 null 或者其他处理方式
                }
                else
                {
                    return new DynamicExcelColumn(codeTitle) { Index = codeIndex + 1, Width = 25 };
                }
            }).Where(c => c != null).ToArray());
            return dynamicColumns.ToArray();
        }


    }



    /// <summary>
    /// 指标实体
    /// </summary>
    public class DW_QUOTATEST
    {

        /// <summary>
        /// 主键guid
        /// </summary>
        [SugarColumn(ColumnDescription = "主键id", Length = 32, IsPrimaryKey = true)]
        public string Q_ID { get; set; }
        /// <summary>
        /// 编码
        /// </summary>
        public string Q_CODE { get; set; }
        /// <summary>
        /// 指标名称
        /// </summary>
        public string Q_NAME { get; set; }
    }




    /// <summary>
    /// 医院实体
    /// </summary>
    public class TDU_HOSPITALTEST
    {
        public string FJGDM { get; set; }
        public string FSEQ { get; set; }
        public string FDESC { get; set; }
    }



    public class HospitalViewCodeDetailTest
    {
        /// <summary>
        /// 医院编码
        /// </summary>
        public string HospitalCode { get; set; }
        /// <summary>
        /// 医院名称
        /// </summary>
        public string HospitalName { get; set; }
        /// <summary>
        /// 指标编码
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// 指标名称
        /// </summary>
        public string CodeName { get; set; }
        /// <summary>
        /// QValue指标值
        /// </summary>
        public string QValue { get; set; }
    }
}

最后效果图如下所示:
在这里插入图片描述
写的不好,如有错误还请指正

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CommonModule.dll动态链接库(DLL)文件丢失的处理方法

方法一、手动下载修复 (1)从网站下载commonmodule.dll文件到您的电脑上。 (2)将commonmodule.dll文件复制到" X:\Windows\system32 " (X代表您系统所在目录盘符&#xff0c;如&#xff1a;C:\Windows\system32)目录下。 (3)在开始菜单中找到"运行(R)" 或…

数据结构--字符串的模式匹配

案例导入概念 朴素&#xff08;暴力&#xff09;模式匹配算法 定位操作&#xff1a; 计算时间复杂度 总结

解决 Python requests 库中 SSL 错误转换为 Timeouts 问题

解决 Python requests 库中 SSL 错误转换为 Timeouts 问题&#xff1a;理解和处理 SSL 错误的关键 在使用Python的requests库进行HTTPS请求时&#xff0c;可能会遇到SSL错误&#xff0c;这些错误包括但不限于证书不匹配、SSL层出现问题等。如果在requests库中设置verifyFalse&…

ES6有何新特性?(下篇)

目录 函数参数的默认值设置 rest参数 扩展运算符 Symbol 迭代器 生成器 Promise Class 数值扩展 对象方法扩展 模块化 大家好呀&#xff01;今天这篇文章继续为大家介绍ES6的新特性&#xff0c;上上上篇文章介绍了一部分&#xff0c;这篇文章会将剩下的部分新增的特…

ElasticSearch在Windows上的下载与安装

Elasticsearch是一个开源的分布式搜索和分析引擎&#xff0c;它可以帮助我们快速地搜索、分析和处理大量数据。Elasticsearch能够快速地处理结构化和非结构化数据&#xff0c;支持全文检索、地理位置搜索、自动补全、聚合分析等功能&#xff0c;能够承载各种类型的应用&#xf…

用平板当电脑副屏(spacedesk)双端分享

文章目录 1.准备工作2.操作流程1. 打开spacedesk点击2. 勾选USB Cable Android3. 用数据线连接移动端和pc端&#xff0c;选择仅充电4. 打开安装好的spacedesk 记得在win系统中设置扩展显示器&#xff1a; 1.准备工作 下载软件spacedesk Driver Console pc端&#xff1a; 移动…

uniapp小程序定位;解决调试可以,发布不行的问题

遇见这个问题&#xff1b;一般情况就两种 1、域名配置问题&#xff1b; 2、隐私协议问题 当然&#xff0c;如果你的微信小程序定位接口没开启&#xff1b;定位也会有问题&#xff1b; 第一种&#xff0c;小程序一般是腾讯地图&#xff1b;所以一般都会用https://apis.map.qq.co…

Android studio run 手机或者模拟器安装失败,但是生成了debug.apk

错误信息如下&#xff1a;Error Installation did not succeed. The application could not be installed&#xff1a;List of apks 出现中文乱码&#xff1b; 我首先尝试了打包&#xff0c;能正常安装&#xff0c;再次尝试了debug的安装包&#xff0c;也正常安装&#xff1…

LangChain 5易速鲜花内部问答系统

展示了一个完整的问答系统的实现&#xff0c;使用了Flask来构建Web界面、langchain进行文档处理和检索&#xff0c;以及OpenAI的语言模型。代码的复杂性在于集成了多种高级技术和处理大型数据集和语言模型。 LangChain 实现给动物取名字&#xff0c;LangChain 2模块化prompt t…

AVL树你需要了解一下

AVL树介绍 AVL树是一种自平衡二叉查找树&#xff0c;它得名于发明者G.M.Adel’son-Vel’skii和E.M.Landis。AVL树的特点是任何节点的两个子树的高度最大差别为1&#xff0c;因此它也被称为高度平衡树。在AVL树中&#xff0c;每个节点的平衡因子只有-1、0、1三种&#xff0c;通…

vue3 setup展示数据

效果图 1.创建数据 content.js import { reactive } from vueconst data reactive({color:red,title: 二十四节气,subTitle: 节气&#xff0c;是干支历中表示自然节律变化以及确立“十二月建”&#xff08;月令&#xff09;的特定节令。,list: [{name: "立春",con…

hdfsClient_java对hdfs进行上传、下载、删除、移动、打印文件信息尚硅谷大海哥

Java可以通过Hadoop提供的HDFS Java API来控制HDFS。通过HDFS Java API&#xff0c;可以实现对HDFS的文件操作&#xff0c;包括文件的创建、读取、写入、删除等操作。 具体来说&#xff0c;Java可以通过HDFS Java API来创建一个HDFS文件系统对象&#xff0c;然后使用该对象来进…

基于单片机GPS轨迹定位和里程统计系统

**单片机设计介绍&#xff0c; 基于单片机GPS轨迹定位和里程统计系统 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 一个基于单片机、GPS和里程计的轨迹定位和里程统计系统可以被设计成能够在移动的交通工具中精确定位车辆的位置…

clickhouse分布式之弹性扩缩容的故事

现状 社区不支持喔&#xff0c;以后也不会有了。曾经尝试过&#xff0c;难道是是太难了&#xff0c;无法实现吗&#xff1f;因为他们企业版支持了&#xff0c;可能是利益相关吧&#xff0c;谁知道呢&#xff0c;毕竟开源也要赚钱&#xff0c;谁乐意一直付出没有回报呢。 社区…

N 字形变换

将一个给定字符串 s 根据给定的行数 numRows &#xff0c;以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 “PAYPALISHIRING” 行数为 3 时&#xff0c;排列如下&#xff1a; P A H N A P L S I I G Y I R 之后&#xff0c;你的输出需要从左往右逐行读取&#xff0…

使用树莓派学习Linux系统编程的 --- 库编程(面试重点)

在之前的Linux系统编程中&#xff0c;学习了文件的打开&#xff1b;关闭&#xff1b;读写&#xff1b;进程&#xff1b;线程等概念.... 本节补充“Linux库概念 & 相关编程”&#xff0c;这是一个面试的重点&#xff01; 分文件编程 在之前的学习中&#xff0c;面对较大的…

什么是希尔伯特空间?

照片由 丹克里斯蒂安佩杜雷什 on Unsplash 一、说明 在本文中&#xff0c;我们将探讨希尔伯特空间这个非常重要的主题。希尔伯特空间由于其特性而经常出现在物理和工程中。为了理解希尔伯特空间&#xff0c;我们从度量空间的定义开始。 二、基础概念 集合是定义明确的元素的集合…

ClickHouse的 MaterializeMySQL引擎

1 概述 MySQL 的用户群体很大&#xff0c;为了能够增强数据的实时性&#xff0c;很多解决方案会利用 binlog 将数据写入到 ClickHouse。为了能够监听 binlog 事件&#xff0c;我们需要用到类似 canal 这样的第三方中间件&#xff0c;这无疑增加了系统的复杂度。 ClickHouse 20.…

Python-----PyInstaller的简单使用

PyInstaller简介 PyInstaller是一个Python库&#xff0c;可以将Python应用程序转换为独立的可执行文件。PyInstaller支持跨平台&#xff0c;可以在Windows、Linux和MacOS上生成可执行文件。 PyInstaller会分析Python程序&#xff0c;并将程序打包成一个完整的可执行文件&…

汽车级全保护型六路半桥驱动器NCV7708FDWR2G 原理、参数及应用

NCV7708FDWR2G 是一款全保护型六路半桥驱动器&#xff0c;特别适用于汽车和工业运动控制应用。六个高压侧和低压侧驱动器可自由配置&#xff0c;也可单独控制。因此可实现高压侧、低压侧和 H 桥控制。H 桥控制提供正向、逆向、制动和高阻抗状态。驱动器通过标准 SPI 接口进行控…