1.效果演示

2.用到的第三方类库

前端:React,Dva,Antd

后端:ASP.NET CORE,System.Linq.Dynamic.Core,EPPlus.Core

3.基本思路

  第一:EF(LINQ)解决动态列的问题,最开始的思路是直接写SQL,后来想想太Low,就放弃了。百度了下,还真有解决方案,System.Linq.Dynamic.Core

第二:.NetCore解决生成Excel文件(流),使用了EPPlus.Core。

第三:解决文件下载的问题,最开始的思路是,直接传流到前端,前端读response.blob(),然后生成文件,结果......失败,因为所有请求要先过Node层,流经过一次转发后,死活没办法变成excel文件。前端能力不强,所以放弃这个思路了。

按照后端的解决方式,就是直接把文件生成到服务端,然后返回路径给前端,前端跳转一次,就可以实现下载,尝试,成功!

4.核心代码

代码只是初版代码,实现了基础需求。仅做参考

后端部分

请求模型:

 public class ExportRequestModel<T>
{ public List<ExportRowModel> RowRequest { get; set; } /// <summary>
/// 导出人ID
/// </summary>
public string ExportUserID { get; set; } /// <summary>
/// 导出模块名称
/// </summary>
public string ModuleName { get; set; } public T Where { get; set; }
} public class ExportRowModel
{
public string RowName { get; set; } public string RowKey { get; set; } public string TableName { get; set; }
}

ExcelHelper.cs:

  public static string Export(ExportRequestModel<TWhere> THead, List<TBody> TBody, string LocalPath)
{
try
{
string sFileName = $"{THead.ExportUserID}-{Guid.NewGuid()}.xlsx";
var finallypath = LocalPath + "\\excel\\" + THead.ModuleName;
DirectoryInfo di = new DirectoryInfo(finallypath);
if (!di.Exists) { di.Create(); }
FileInfo file = new FileInfo(Path.Combine(finallypath, sFileName)); var pack = GetExcelPackage(THead.RowRequest, TBody);
pack.SaveAs(file); return ("\\excel\\" + THead.ModuleName + "\\" + sFileName).Replace("\\", "/");
}
catch (Exception)
{
throw;
} } private static ExcelPackage GetExcelPackage(List<ExportRowModel> THead, List<TBody> TBody)
{
ExcelPackage package = new ExcelPackage(); var worksheet = package.Workbook.Worksheets.Add("sheet1");
//循环生成表头
for (int i = ; i <= THead.Count; i++)
{
worksheet.Cells[, i].Value = THead[i - ].RowName;
} //循环值
for (int i = ; i <= TBody.Count; i++)
{
var body = TBody[i - ];
var bodyPro = body.GetType().GetProperties();
for (int j = ; j <= bodyPro.Length; j++)
{
if (bodyPro[j - ].Name == "Item")
{
break;
}
worksheet.Cells[i + , j].Value = bodyPro[j - ].GetValue(body, null);
}
}
return package; }
}

示例代码

            ApiResult<string> apiResult = new ApiResult<string>();
List<string> selectKey = new List<string>();
foreach (var item in request.RowRequest)
{
var tabOtherName = string.IsNullOrEmpty(item.TableName) ? item.TableName : item.TableName + ".";
selectKey.Add($"{tabOtherName}{item.RowKey} as {item.RowName}");
}
var ExportList = _studentStatuService.Query()
.Include(n => n.Payment)
.Include(n => n.Student)
.Include(n => n.Student.Department)
.Where(n => (int)n.StudentType > )
.HasWhere(request.Where.DepartMentID, n => n.Student.DepartmentID == request.Where.DepartMentID)
.HasWhere(request.Where.EduMajorID, n => n.Payment.EduMajorId == request.Where.EduMajorID)
.HasWhere(request.Where.EduSchoolID, n => n.Payment.EduSchoolId == request.Where.EduSchoolID)
.HasWhere(request.Where.Name, n => n.StudentNo.Contains(request.Where.Name))
.HasWhere(request.Where.IdCard, n => n.Student.IDCard.Contains(request.Where.IdCard))
.HasWhere(request.Where.StartTime, n => n.CreateTime>= request.Where.StartTime)
.HasWhere(request.Where.EndTime, n => n.CreateTime < request.Where.EndTime)
.Select(n => new StudentLessResponse
{
PhoneNum = n.Student.PhoneNum,
School = n.Payment.EduSchoolName,
Major = n.Payment.EduMajorName,
CreateTime = n.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"),
Guid = n.Student.Guid.ToString(),
Name = n.Student.Name,
DeptName = n.Student.Department.Name,
StudentType = (int)n.StudentType,
DiplomaType = string.Join("/", EnumHelper.GetDescription(n.DiplomaType)),
GetSeason = EnumHelper.GetDescription(n.GetSeason),
GetYear = n.GetYear,
LevelSeason = EnumHelper.GetDescription(n.LevelSeason),
LevelYear = n.LevelYear,
StudentNo = n.StudentNo,
TemporaryNo = n.TemporaryNo
})
.Select($"new ({string.Join(',', selectKey.ToArray())})")
.ToDynamicList();
var pack = ExcelHelper<dynamic, StudentPagesRequest>.Export(request, ExportList, LocalPath);

如果需要用到Inner Join

则需要使用SelectMany,具体语法自行百度。

前端代码

Export.js组件:

import React from 'react';
import { Popover, Button, Checkbox, Row, Col, DatePicker } from 'antd';
import PropTypes from 'prop-types';
import { setLocalStorage, getLocalStorage } from '../../utils/cookieHelper';
const { RangePicker } = DatePicker; class Export extends React.Component { state = {
visible: false,
checkedValues: getLocalStorage(this.props.moduleName),
StartTime: null,
EndTime: null
}
onChange = (checkedValues) => {
const { exportList } = this.props; this.setState({ checkedValues });
}
export = () => {
const { checkedValues, EndTime, StartTime } = this.state;
const { moduleName, onExport, exportList } = this.props; setLocalStorage(moduleName, checkedValues);
const finallyValues = exportList.filter((item, index) => {
return checkedValues.indexOf(item.RowKey) > -1;
});
const data = {
ModuleName: moduleName,
RowRequest: finallyValues,
where: {
StartTime,
EndTime
}
}
console.log(data);
if (onExport) {
onExport(data);
} } onTimeChange = (date, dateString) => {
this.setState({ StartTime: dateString[0], EndTime: dateString[1] }) }
render() {
const { exportList, moduleName } = this.props;
const ccontent = (<div> <Checkbox.Group onChange={this.onChange} style={{ width: '220px' }} value={this.state.checkedValues}>
<Row>
<div style={{ marginBottom: '12px' }}>
<div style={{ marginBottom: '5px' }}> 请选择数据产生的时间:</div>
<RangePicker onChange={this.onTimeChange} />
</div> {exportList.map((item, index) => {
return (<Col span={12}><Checkbox key={item.RowKey} value={item.RowKey}>{item.RowName}</Checkbox></Col>)
})}
</Row>
</Checkbox.Group>
<Row style={{ textAlign: 'center', marginTop: '10px' }}>
<Col span={2}></Col>
<Col span={10}> <a onClick={this.export}>确定</a></Col>
<Col span={10}> <a onClick={() => {
let visb = !this.state.visible;
this.setState({ visible: visb })
}}>取消</a></Col>
<Col span={2}></Col> </Row></div>);
return (
<Popover
content={ccontent}
title="请选择导出列"
trigger="click"
visible={this.state.visible}
placement="bottom" >
<Button type="primary" onClick={() => {
let visb = !this.state.visible;
this.setState({ visible: visb })
}} icon={'export'} style={{ marginRight: '10px' }}>导出</Button>
</Popover >
);
}
} Export.propTypes = {
onExport: PropTypes.func,
moduleName: PropTypes.string,
exportList: PropTypes.any
}; export default Export;

使用方式:

最后希望对大家有帮组!

记React+.NetCore API实现动态列导出的更多相关文章

  1. C# 使用Epplus导出Excel [2]:导出动态列数据

    C# 使用Epplus导出Excel [1]:导出固定列数据 C# 使用Epplus导出Excel [2]:导出动态列数据 C# 使用Epplus导出Excel [3]:合并列连续相同数据 C# 使用 ...

  2. 数据导出Excel,动态列

    今天碰到一个需求,要求将用户回答的问卷及问题导出Excel表格,问卷对应的问题数量不一致,需要动态添加列表头,简单记录. 要导出Excel需要添加poi.jar包 用户-问卷实体(固定列): pack ...

  3. React Router API文档

    React Router API文档 一.<BrowserRouter> 使用HTML5历史记录API(pushState,replaceState和popstate事件)的<Rou ...

  4. vue原生表格怎样实现动态列及表格数据下载

    最近项目经常用到带有合并效果以及动态列的表格,而翻阅iview和element-ui官网没有找到合适的(也有可能自己的水平有限,不会改写),所以只好自己用原生表格写了一个,具体效果如下: 这个表格右侧 ...

  5. 原生JS实战:写了个一边玩游戏,一边记JS的API的游戏

    本文是苏福的原创文章,转载请注明出处:苏福CNblog:http://www.cnblogs.com/susufufu/p/5878913.html 本程序[一边玩游戏,一边记JS的API]是本人的个 ...

  6. Dynamic CRM 2013学习笔记(二十六)报表设计:Reporting Service报表 动态参数、参数多选全选、动态列、动态显示行字体颜色

    上次介绍过CRM里开始报表的一些注意事项:Dynamic CRM 2013学习笔记(十五)报表入门.开发工具及注意事项,本文继续介绍报表里的一些动态效果:动态显示参数,参数是从数据库里查询出来的:参数 ...

  7. 用JSON-server模拟REST API(二) 动态数据

    用JSON-server模拟REST API(二) 动态数据 上一篇演示了如何安装并运行 json server , 在这里将使用第三方库让模拟的数据更加丰满和实用. 目录: 使用动态数据 为什么选择 ...

  8. extjs动态树 动态grid 动态列

    由于项目需要做一个动态的extjs树.列等等,简而言之,就是一个都是动态的加载功能, 自己琢磨了半天,查各种资料,弄了将近两个星期,终于做出来了 首先,想看表结构,我的这个功能需要主从两张表来支持 代 ...

  9. displaytag 动态列实现

    这种动态列的实现方法来自displaytag-examples-1.2.war提供的示例中,实际上下载下来的zip文件中不仅有各种jar包,还有这个包含各种例子的war包,是学习displaytag的 ...

随机推荐

  1. windbg关于.NET分析的扩展命令

    收到一个dump文件,运行环境的.net framework的详细版本是多少呢? dump信息与性能计数器结合分析时,想知道该dump运行的进程号是多少? dump定位到有效的堆栈信息,而对应的源码是 ...

  2. 【JavaScript 实现倒计时(天、时、分、秒)】

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  3. msfvenom向apk注入payload

    首先安装apt-get install apkinjector 这个东西,msfvenom重新组装apk的时候会自动调用 msfvenom -x /路径/apk android/meterpreter ...

  4. Codeforces 791A Bear and Big Brother(暴力枚举,模拟)

    A. Bear and Big Brother time limit per test:1 second memory limit per test:256 megabytes input:stand ...

  5. 2017ecjtu-summer training #4 UESTC 1584

    此题链接 http://acm.uestc.edu.cn/#/problem/show/1584 此题和hdu1541几乎完全一样,我们要先对坐标排序,再进行操作. hdu1541题解 http:// ...

  6. poj1258prim算法

    /*poj 1258 *题意:有若干个农场,现需要将各个农场用光纤连接起来,各个农场之间连接的光纤长度也许不同, *要求求出使得将所有农场连接起来的最短光线长度 *算法分析:使用矩阵将各个农场之间的光 ...

  7. python笔记二(mysql数据库操作)

    python2.x使用MySQLdb python3.x使用pymysql代替MySQLdb 不过我使用的是python3.5,MySQLdb还是可以在python3.5使用的. #!/usr/bin ...

  8. Kubernetes存储之Persistent Volumes简介

    简介 管理存储和管理计算有着明显的不同.PersistentVolume子系统给用户和管理员提供了一套API,从而抽象出存储是如何提供和消耗的细节.在这里,我们介绍两种新的API资源:Persiste ...

  9. [20160711][在Windows下调用neven链接库]

    相关说明 这篇文档是接前篇[20160711][neven代码移植Windows]和[20160711][VS2012配置OpenCV2.4.9]下完成,首先需要通过篇文档编译出neven动态链接库和 ...

  10. TypeScript笔记 1--环境搭建

    TypeScript是什么 Typescript是JavaScript的超集,支持ES6特性并且提供了类型系统,可以编译成Javascript.是微软开发且已经在github上开源. ES6(ES20 ...