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

news2024/11/24 13:50:21

.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.coloradmin.cn/o/1229981.html

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

相关文章

深入Ansible

1.什么是ansible ansible是新出现的自动化运维工具&#xff0c;基于Python开发&#xff0c;集合了众多运维工具&#xff08;puppet、chef、func、fabric&#xff09;的优点&#xff0c;实现了批量系统配置、批量程序部署、批量运行命令等功能。 ansible是基于 paramiko 开发的…

JavaScript 字符处理

1.删除前几个字符 使用 slice console.log(12345.slice(1))// 23452.首字母大写 var word abcconsole.log(word.charAt(0).toUpperCase() word.slice(1))// Abc3.字符为数字时可直接相乘 console.log(2*3) 4.字符串中是否包含某个子字符串 子串既可以为数字也可为字符串 /…

不必购买Mac,这款国产设计工具能轻松替代Sketch!

介绍 即时设计是新一代可以直接在浏览器中使用的设计工具&#xff0c;具有Sketch和实时协作功能。与本地Sketch相比&#xff0c;增加了实时协作功能&#xff0c;即时设计可以看作是在线Sketch&#xff0c;两个工具可以简单粗暴地总结为一个公式&#xff1a; 即时设计Sketch云…

4.9每日一题(多元抽象复合函数求二阶偏导)

注意&#xff1a;f1的一阶导数里面也有&#xff08;x,y&#xff09;&#xff0c;即存在F11、F12、F22、F21

IDEA中更换java项目JDK

我们打开IDEA 打开项目 然后选择 File 下的 Project Structure 这里 我们下拉选择自己需要的JDK Sources这里 也要设置一下JDK对应版本 然后 上面这个 Project 中 也要设置一下对应jdk的版本 保持一直 然后 我们打开 File 下的 Settings 然后 找到如下图配置 如果JKD版本看…

第94步 深度学习图像分割:DeepLabv3建模

基于WIN10的64位系统演示 一、写在前面 本期&#xff0c;我们继续学习深度学习图像分割系列的最后一个模型&#xff0c;DeepLabv3。 二、DeepLabv3简介 DeepLabv3 是 DeepLab 系列中的第三个版本&#xff0c;以其高准确性和能够在多个尺度上识别物体轮廓而著称。 以下是 De…

CRM按行业细分的重要性

很多企业和销售会诟病CRM系统不够贴合行业、功能也不够细分和实用。因为各行各业的业务千差万别&#xff0c;所以功能完备、使用满意度高的CRM一定是与不同行业业务场景高度匹配的&#xff0c;是深度行业化的。因此行业化是CRM发展的重要趋势之一&#xff0c;为什么CRM一定要走…

Linux环境搭建(tomcat,jdk,mysql下载)

是否具备环境&#xff08;前端node&#xff0c;后端环境jdk&#xff09;安装jdk,配置环境变量 JDK下载 - 编程宝库 (codebaoku.com) 进入opt目录 把下好的安装包拖到我们的工具中 把解压包解压 解压完成&#xff0c;可以删除解压包 复制解压文件的目录&#xff0c;配置环境变量…

深度学习人体语义分割在弹幕防遮挡上的实现 - python 计算机竞赛

文章目录 1 前言1 课题背景2 技术原理和方法2.1基本原理2.2 技术选型和方法 3 实例分割4 实现效果5 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习人体语义分割在弹幕防遮挡上的应用 该项目较为新颖&#xff0c;适合作为竞…

企业怎样申请SSL证书?

对于很多企业而言&#xff0c;使用SSL证书加密网站已经显得尤为重要&#xff0c;这不仅仅是关乎企业的网站安全&#xff0c;同时也关系着企业的形象以及用户的信赖。既然使用https协议已经众多企业认可&#xff0c;那么我们该如何给自己的网站申请以及安装SSL证书&#xff1f; …

4.7每日一题(复合函数求导+隐函数求导)

先对F(x , y , z)对x求偏导&#xff1b;再通过另一个方程求出Zx的值&#xff1b;代入F&#xff08;x&#xff0c;y&#xff0c;z&#xff09;中即可

代码随想录算法训练营第五十八天丨 单调栈01

739. 每日温度 思路 首先想到的当然是暴力解法&#xff0c;两层for循环&#xff0c;把至少需要等待的天数就搜出来了。时间复杂度是O(n^2) 那么接下来在来看看使用单调栈的解法。 什么时候用单调栈呢&#xff1f; 通常是一维数组&#xff0c;要寻找任一个元素的右边或者左边…

easyExcel注解详情

前言11个注解字段注解 类注解基础综合示例补充颜色总结 11个注解 ExcelProperty ColumnWith 列宽 ContentFontStyle 文本字体样式 ContentLoopMerge 文本合并 ContentRowHeight 文本行高度 ContentStyle 文本样式 HeadFontStyle 标题字体样式 HeadRowHeight 标题高度 HeadStyle…

servlet乱码问题

问题&#xff1a;中文乱码 解决&#xff1a;加框的部分

Pyside6/PyQt6如何添加右键菜单,源码示例

文章目录 📖 介绍 📖🏡 环境 🏡📒 源码分享 📒🎈 添加图标📖 介绍 📖 在UI开发中经常会使用到右键菜单,本文记录了一个添加右键菜单的示例,可以举一反三,仅供参考! 🏡 环境 🏡 本文演示环境如下 Windows11Python3.11.5PySide6📒 源码分享 📒 下面…

关系数据库理论【数据库系统概论】

1.问题的提出 1.1关系模式的表示 关系模式由五部分组成&#xff0c;是一个五元组:R&#xff08;U&#xff0c;D&#xff0c;DOM&#xff0c;F&#xff09; 元组概念R关系名R是符号化的元组语义。UU为一组属性。比如学号&#xff0c;姓名。DD为属性组U中的属性所来自的域。比…

用css实现原生form中radio单选框和input的hover已经focus的样式

一.问题描述&#xff1a;用css实现原生form中radio单选框和input的hover已经focus的样式 在实际的开发中&#xff0c;一般公司ui都会给效果图&#xff0c;比如单选按钮radio样式&#xff0c;input输入框hover的时候样式&#xff0c;以及focus的时候样式&#xff0c;等等&#…

京东API接口获取京东平台商品详情数据,SKU,价格参数及其返回值说明

做过淘客开发的一定接触过淘宝API开发。 而做京东联盟软件自然离不开京东联盟API。 京东联盟API目前上线的有很多。 参数说明 通用参数说明 url说明 https://api-gw.onebound.cn/平台/API类型/ 平台&#xff1a;淘宝&#xff0c;京东等&#xff0c; API类型:[item_search,ite…

CRM系统定制开发价格

我们都知道&#xff0c;CRM系统对企业有着很大的帮助。但是市面上大多数CRM系统都是标准化的&#xff0c;无法满足那些产品线复杂&#xff0c;或者有着特殊需求的企业。这个时候&#xff0c;就需要对CRM系统进行二次开发。那么&#xff0c;CRM系统二次开发的价格是多少&#xf…

RK3568 AD按键改成GPIO按键

authordaisy.skye的博客_CSDN博客-嵌入式,Qt,Linux领域博主 相对路径 kernel/arch/arm64/boot/dts/rockchip/ido-evb3568-v2b.dtsi 代码解析 linux,input-type <1>;//input类型 <EV_KEY>按键 即1 gpios <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>;//io脚地址…