记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的 ...
随机推荐
- Wing ide 6.0 注册 ,python 3.6环境
直接切入主题,套路如下: 1.选择手动输入license license number输入:CN123-12345-12345-12345 2.在下一步中,选择第二项,拷贝的request code ...
- 成功破解邻居的Wifi密码
// 这是一篇导入进来的旧博客,可能有时效性问题. 默认配置的路由器,8位以下密码,黑客几分钟就可以破解.以前用自己的路由器做过实验,这次真正实践成功.环境:Kali Linux工具集:aircrac ...
- Git分支-分支简介
源地址:https://git-scm.com/book/zh/ch3-1.html 几乎所有的版本控制系统都以某种形式支持分支. 使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线 ...
- vijos 1942 [AH 2005] 小岛
描述 西伯利亚北部的寒地,坐落着由 N 个小岛组成的岛屿群,我们把这些小岛依次编号为 1 到 N . 起初,岛屿之间没有任何的航线.后来随着交通的发展,逐渐出现了一些连通两座小岛的航线.例如增加一条在 ...
- [ZOJ3213] Beautiful Meadow
插头DP...网格图,有障碍,格子上有权值,求总权值最大的简单路径. 因为路径的起始点不确定..所以多开一维表示当前已经有多少个独立插头.. 只要不合并相同的联通块,并且已经用了2个独立插头,那就是一 ...
- [bzoj1223] [HNOI2002]Kathy函数
首先由题解可得TAT,f(i)=i当且仅当i在二进制下为回文串. 那么问题就变成了1~n中有多少个二进制下的回文串. 把m转成2进制后就是正常的统计了= =. f[i]表示二进制下,有多少个i位的回文 ...
- Bellman-Ford 求含负权最短路
该算法详解请看 https://www.cnblogs.com/tanky_woo/archive/2011/01/17/1937728.html 单源最短路 当图中存在负权边时 迪杰斯特拉就 ...
- hdu_2669 Romantic(扩展欧几里得)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2669 Romantic Time Limit: 2000/1000 MS (Java/Others) ...
- 分布式计算框架学习笔记--hadoop工作原理
(hadoop安装方法:http://blog.csdn.net/wangjia55/article/details/53160679这里不再累述) hadoop是针对大数据设计的一个计算架构.如果你 ...
- 番外篇--Moddule Zero安装
Moddule Zero 安装 1.2.1 从模板创建 使用ABP和module-zero开始一个新项目最简单的方式是使用启动模板.详细了解请参考启动模板文档. 1.2.2 手动安装 如果你有一个预先 ...