记React+.NetCore API实现动态列导出
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实现动态列导出的更多相关文章
- C# 使用Epplus导出Excel [2]:导出动态列数据
C# 使用Epplus导出Excel [1]:导出固定列数据 C# 使用Epplus导出Excel [2]:导出动态列数据 C# 使用Epplus导出Excel [3]:合并列连续相同数据 C# 使用 ...
- 数据导出Excel,动态列
今天碰到一个需求,要求将用户回答的问卷及问题导出Excel表格,问卷对应的问题数量不一致,需要动态添加列表头,简单记录. 要导出Excel需要添加poi.jar包 用户-问卷实体(固定列): pack ...
- React Router API文档
React Router API文档 一.<BrowserRouter> 使用HTML5历史记录API(pushState,replaceState和popstate事件)的<Rou ...
- vue原生表格怎样实现动态列及表格数据下载
最近项目经常用到带有合并效果以及动态列的表格,而翻阅iview和element-ui官网没有找到合适的(也有可能自己的水平有限,不会改写),所以只好自己用原生表格写了一个,具体效果如下: 这个表格右侧 ...
- 原生JS实战:写了个一边玩游戏,一边记JS的API的游戏
本文是苏福的原创文章,转载请注明出处:苏福CNblog:http://www.cnblogs.com/susufufu/p/5878913.html 本程序[一边玩游戏,一边记JS的API]是本人的个 ...
- Dynamic CRM 2013学习笔记(二十六)报表设计:Reporting Service报表 动态参数、参数多选全选、动态列、动态显示行字体颜色
上次介绍过CRM里开始报表的一些注意事项:Dynamic CRM 2013学习笔记(十五)报表入门.开发工具及注意事项,本文继续介绍报表里的一些动态效果:动态显示参数,参数是从数据库里查询出来的:参数 ...
- 用JSON-server模拟REST API(二) 动态数据
用JSON-server模拟REST API(二) 动态数据 上一篇演示了如何安装并运行 json server , 在这里将使用第三方库让模拟的数据更加丰满和实用. 目录: 使用动态数据 为什么选择 ...
- extjs动态树 动态grid 动态列
由于项目需要做一个动态的extjs树.列等等,简而言之,就是一个都是动态的加载功能, 自己琢磨了半天,查各种资料,弄了将近两个星期,终于做出来了 首先,想看表结构,我的这个功能需要主从两张表来支持 代 ...
- displaytag 动态列实现
这种动态列的实现方法来自displaytag-examples-1.2.war提供的示例中,实际上下载下来的zip文件中不仅有各种jar包,还有这个包含各种例子的war包,是学习displaytag的 ...
随机推荐
- 小乔注:java关键字static
static是java中又一重要的关键字,在一定环境下使用,可以提高程序的运行性能,优化程序的结构.其主要应用有以下几方面: 1.static修饰的成员变量,称为类变量/静态变量,以实现所有对象对该成 ...
- 在虚拟机中安装metasploit官方攻防模拟器
首先我们要在windwos下载安装perl环境.下载地址: http://pan.baidu.com/s/1i3GLKAp 然后我们安装 点击next 我同意,next next next,然后他会安 ...
- (转)Docker之Compose服务编排
转自:https://www.cnblogs.com/52fhy/p/5991344.html Compose是Docker的服务编排工具,主要用来构建基于Docker的复杂应用,Compose 通过 ...
- 详解zkw算法解决最小费用流问题
网络流的一些基本概念 很多同学建立过网络流模型做题目, 也学过了各种算法, 但是对于基本的概念反而说不清楚. 虽然不同的模型在具体叫法上可能不相同, 但是不同叫法对应的思想是一致的. 下面的讨论力求规 ...
- Quick Brown Fox
The quick brown fox jumps over the lazy dog
- angular-dragon-drop.js 双向数据绑定拖拽的功能
在做公司后台物流的时候,涉及到34个省市分为两个部分,一部分为配送区域,另一部分为非配送区域,想利用拖拽的功能来实现,最好两部分的数组能自动更新. 刚好找到angular-dragon-drop.js ...
- 三 : spring-uploadify上传文件
一 : applicationContext.xml中:必须声明不然获取不到<!-- 上传文件的配置 --> <bean id="multipartResolver&quo ...
- Linux 离线安装Rubygems详解
很多时候我们会发现,真实的生成环境很多都没有外网,只有内网环境,这个时候我们又需要安装RubyGems,则不能提供yum命令进行在线安装了,这个时候我们就需要下载安装包进行离线安装.本文主要简单介绍如 ...
- c++---天梯赛---查验身份证
★题目: ★题目分析:本题要求输入一个数字n,随后n行输入n个身份证号码.之后进行进一步的判断把错误的身份证号码输出.如果全部正确输出All passed. ★思路方法: ①按题目要求输入. ②对前1 ...
- 淘淘商城学习笔记 之 上传图片到远程服务器,图片的回显出现的bug
最近在学习淘淘商城中用到的技术,感觉受益良多,遇到一个比较奇怪的bug调了好久,遂心乐之分享于诸君 bug情况是这样的:在商城的后台上传图片之后图片回显不出来,右键查看链接,发现链接被加了localh ...