zoukankan      html  css  js  c++  java
  • 记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 = 1; i <= THead.Count; i++)
                {
                    worksheet.Cells[1, i].Value = THead[i - 1].RowName;
                }
    
                //循环值
                for (int i = 1; i <= TBody.Count; i++)
                {
                    var body = TBody[i - 1];
                    var bodyPro = body.GetType().GetProperties();
                    for (int j = 1; j <= bodyPro.Length; j++)
                    {
                        if (bodyPro[j - 1].Name == "Item")
                        {
                            break;
                        }
                        worksheet.Cells[i + 1, j].Value = bodyPro[j - 1].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 > 1)
                    .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={{  '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;

    使用方式:

     最后希望对大家有帮组!

  • 相关阅读:
    下载Web微信视频
    强制删除无用old windows文件夹命令
    BitLocker 加密工具挂起和恢复命令行(windows7)
    R 统计学工具部署和使用
    Microsoft Azure 01 (Summarize)
    RocketMQ原理
    专业术语概念
    序列化-ProtoBuf
    Kafka安装与集群部署
    Redis中使用Lua脚本
  • 原文地址:https://www.cnblogs.com/Ambre/p/8422919.html
Copyright © 2011-2022 走看看