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

news/2024/5/19 22:08:36 标签: .netcore

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

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


http://www.niftyadmin.cn/n/5198621.html

相关文章

IOS输入框聚焦会把内容区域顶起

前几天做了一个类似qq布局的h5的聊天界面&#xff0c;输入框固定在最底下。本来初始情况会有默认的两条聊天记录&#xff0c;但是当点击底部的输入框时&#xff0c;输入框聚焦&#xff0c;弹起键盘&#xff0c;然后整个界面就被顶上去了&#xff0c;然后那两条默认的聊天记录也…

【广州华锐互动】VR虚拟现实技术助力太空探险:穿越时空,探索宇宙奥秘

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐走进我们的生活。在教育领域&#xff0c;VR技术的应用也日益广泛&#xff0c;为学生提供了更加生动、直观的学习体验。本文将以利用VR开展太空探险学习为主题&#xff0c;探讨如何将这一先进技术…

数据分析基础之《jupyter notebook工具》

一、安装库 1、linux库 yum install python3-devel 2、python库 pip3 install -U matplotlib pip3 install -U numpy pip3 install -U pandas pip3 install -U TA-Lib pip3 install -U tables pip3 install -U notebook 3、如果TA-Lib安装不上&#xff0c;先手动安装依赖库 …

Linux:动静态库

目录 一、软硬链接 1、软链接 2、硬链接 二、动态库和静态库 编写一个库 ①静态库 使用静态库的方法 ②动态库 使用动态库的方法 库存在的意义 一、软硬链接 软硬链接的本质区别就是&#xff1a;有无独立的inode 软链接有独立的inode&#xff0c;也就意味着软链接是一…

Ubuntu18.04运行gazebo的launch文件[model-4] process has died报错

启动gazebo仿真环境报错[model-4] process has died [model-4] process has died [pid 2059, exit code 1, cmd /opt/ros/melodic/lib/gazebo_ros/spawn_model -urdf -model mycar -param robot_description __name:model __log:/root/.ros/log/8842dc14-877c-11ee-a9d9-0242a…

机器学习二元分类 二元交叉熵 二元分类例子

二元交叉熵损失函数 深度学习中的二元分类损失函数通常采用二元交叉熵&#xff08;Binary Cross-Entropy&#xff09;作为损失函数。 二元交叉熵损失函数的基本公式是&#xff1a; L(y, y_pred) -y * log(y_pred) - (1 - y) * log(1 - y_pred)其中&#xff0c;y是真实标签&…

某60区块链安全之不安全的随机数实战二学习记录

区块链安全 文章目录 区块链安全不安全的随机数实战二实验目的实验环境实验工具实验原理实验内容EXP利用 不安全的随机数实战二 实验目的 学会使用python3的web3模块 学会以太坊不安全的随机数漏洞分析及利用 实验环境 Ubuntu18.04操作机 实验工具 python3 实验原理 由…

【亚马逊云科技产品测评】活动征文|aws云服务器 + 微服务Spring Cloud Nacos 实战

文章目录 前言一、拥有一台Aws Linux服务器1.1、选择Ubuntu版本Linux系统1.2、创建新密钥对1.3、网络设置1.4、配置成功&#xff0c;启动实例1.5、回到实例区域1.6、进入具体的实例1.7、设置安全组 二、在Mac上连接Aws云服务&#xff0c;并安装配置JDK112.1、解决离奇的错误2.2…