From e22a28ec92f7971c5d35481cdddefd2ad32f2faf Mon Sep 17 00:00:00 2001 From: xiaochanghai Date: Tue, 21 May 2024 10:08:24 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=96=B0=E5=A2=9E=E9=80=9A=E7=94=A8=E5=AF=BC?= =?UTF-8?q?=E5=87=BAexcel=E6=8E=A5=E5=8F=A3=EF=BC=8C=E4=B8=8E=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E7=BC=96=E8=BE=91=E9=A1=B5=E6=95=B0=E6=8D=AE=E5=85=B3?= =?UTF-8?q?=E8=81=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/CommonController.cs | 13 ++ Tiobon.Core.Api/Tiobon.Core.xml | 7 + Tiobon.Core.Common/Attribute/QueryFilter.cs | 64 +++++- .../Extensions/IQueryableExtensions.cs | 206 ++++++++++++------ Tiobon.Core.DataAccess/ReportHelper.cs | 33 +++ Tiobon.Core.IServices/ICommonServices.cs | 3 + .../ViewModels/Extend/CommonSelectItem.cs | 8 + Tiobon.Core.Services/BASE/BaseServices.cs | 20 ++ Tiobon.Core.Services/CommonServices.cs | 89 ++++++++ 9 files changed, 373 insertions(+), 70 deletions(-) create mode 100644 Tiobon.Core.Model/ViewModels/Extend/CommonSelectItem.cs diff --git a/Tiobon.Core.Api/Controllers/CommonController.cs b/Tiobon.Core.Api/Controllers/CommonController.cs index 72d26edc..6e06de00 100644 --- a/Tiobon.Core.Api/Controllers/CommonController.cs +++ b/Tiobon.Core.Api/Controllers/CommonController.cs @@ -61,4 +61,17 @@ public class CommonController : BaseApiController return await _commonServices.GetSelectAsync(type); } #endregion + + #region 导出Excel + /// + /// 导出Excel + /// + /// + /// + [HttpPost, Route("ExportExcel")] + public async Task> ExportExcelAsync([FromBody] QueryExport param) + { + return await _commonServices.ExportExcelAsync(param); + } + #endregion } \ No newline at end of file diff --git a/Tiobon.Core.Api/Tiobon.Core.xml b/Tiobon.Core.Api/Tiobon.Core.xml index fbce25c4..65010133 100644 --- a/Tiobon.Core.Api/Tiobon.Core.xml +++ b/Tiobon.Core.Api/Tiobon.Core.xml @@ -258,6 +258,13 @@ + + + 导出Excel + + + + 构造函数 diff --git a/Tiobon.Core.Common/Attribute/QueryFilter.cs b/Tiobon.Core.Common/Attribute/QueryFilter.cs index adc510cc..5fcddc66 100644 --- a/Tiobon.Core.Common/Attribute/QueryFilter.cs +++ b/Tiobon.Core.Common/Attribute/QueryFilter.cs @@ -1,5 +1,6 @@ using System.ComponentModel.DataAnnotations; using Newtonsoft.Json.Linq; +using Tiobon.Core.Model; namespace Tiobon.Core.Common; @@ -117,9 +118,6 @@ public class QueryForm public string timestamp { get; set; } public string userId { get; set; } private JObject _jsonParam; - /// - /// 查询条件( 例如:id = 1 and name = 小明) - /// public JObject jsonParam { get { return _jsonParam; } @@ -129,4 +127,64 @@ public class QueryForm } } +} + +public class QueryExportField +{ + public List ExFields { get; set; } + public string IsTitle { get; set; } + public string TitleName { get; set; } + +} + +/// +/// 动态查询条件 +/// +public class QueryExport +{ + public string commonType { get; set; } + public QueryExportField exportSet { get; set; } + + public string getDataType { get; set; } + private JObject _jsonParam; + public int langId { get; set; } + public string menuName { get; set; } + public string orderBy { get; set; } + public int pageNum { get; set; } + public int pageSize { get; set; } + public string token { get; set; } + public string procName { get; set; } + public string timestamp { get; set; } + public string userId { get; set; } + + public JObject jsonParam + { + get { return _jsonParam; } + set + { + _jsonParam = value; + } + } + +} +public class QueryExportColumn +{ + public int sortNum { get; set; } + public string label { get; set; } + public string field { get; set; } + public string dataSource { get; set; } + public string required { get; set; } + + public string dataType { get; set; } + + public string elementType { get; set; } +} + +public class QueryExportReturn +{ + public JM_PageControlT1 JM_PageControlT1 { get; set; } = new JM_PageControlT1(); + public JM_TableColumnT1 JM_TableColumnT1 { get; set; } = new JM_TableColumnT1(); + public List DT_PageMutiMsg { get; set; } + + public DT_Procedure DT_Procedure { get; set; } = new DT_Procedure(); } \ No newline at end of file diff --git a/Tiobon.Core.Common/Extensions/IQueryableExtensions.cs b/Tiobon.Core.Common/Extensions/IQueryableExtensions.cs index 1abf731e..7319f767 100644 --- a/Tiobon.Core.Common/Extensions/IQueryableExtensions.cs +++ b/Tiobon.Core.Common/Extensions/IQueryableExtensions.cs @@ -1,5 +1,7 @@ using System.Collections; +using System.Collections.Generic; using System.ComponentModel; +using System.Data; using System.Reflection; using OfficeOpenXml; using OfficeOpenXml.Style; @@ -169,6 +171,143 @@ public static class IQueryableExtensions } LoggerHelper.SendLog("生成文件 " + fname + " 完毕 " + dbCount + " 耗时 " + (int)(DateTime.Now - dt_start).TotalSeconds); } + public static void IntoFileFromLinqExcel(this DataTable db, string fname, string splitstr, Dictionary fieldDescs, List exportFieldsWidth, string headText = "", string totalText = "", bool isNeedItemNo = false) + { + if (db.IsNull()) + return; + //查询文件状态 + if (File.Exists(fname)) + { + LoggerHelper.SendLog("文件已生成 " + fname); + return; + } + LoggerHelper.SendLog("正在生成文件 " + fname); + DateTime dt_start = DateTime.Now; + if (!File.Exists(fname)) + File.Create(fname).Close(); + //获取需要导出的字段 + int dbCount = db.Rows.Count; + + //列名排序,返回有序列表 + var (fields, colunms) = Sort(fieldDescs, null); + using (FileStream stream = File.Create(fname)) + { + using (ExcelPackage package = new ExcelPackage(stream)) + { + ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("sheet1"); + + + var colunmsCount = colunms.Count; + + var startCol = 0; + var startRow = 1; // 初始行数 + if (isNeedItemNo) + startCol = 1; + + + if (!string.IsNullOrEmpty(headText)) + { + worksheet.Cells[startRow, 1].Value = headText; + worksheet.Cells[startRow, 1, 1, colunmsCount + startCol].Merge = true; + worksheet.Cells[startRow, 1, 1, colunmsCount + startCol].Style.Font.Bold = true; + worksheet.Cells[startRow, 1, 1, colunmsCount + startCol].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; // Alignment is center + worksheet.Cells[startRow, 1, 1, colunmsCount + startCol].Style.Font.Size = 14; + startRow++; + } + + if (isNeedItemNo) + { + worksheet.Cells[startRow, 1].Value = "序号"; + worksheet.Cells[startRow, 1, startRow, 1].Style.Font.Bold = true; + worksheet.Cells[startRow, 1, startRow, 1].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center; + worksheet.Cells[startRow, 1, startRow, 1].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; + } + + //写入列名 + for (int i = 0; i < fields.Count; ++i) + { + worksheet.Cells[startRow, i + 1 + startCol].Value = fields[i]; + worksheet.Cells[startRow, i + 1 + startCol, startRow, i + 1 + startCol].Style.Font.Bold = true; + worksheet.Cells[startRow, i + 1 + startCol, startRow, i + 1 + startCol].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center; + worksheet.Cells[startRow, i + 1 + startCol, startRow, i + 1 + startCol].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; + } + startRow++; + + for (int row = 0; row < dbCount; ++row) + { + if (isNeedItemNo) + { + worksheet.Cells[row + startRow, 1].Value = row + 1; + worksheet.Cells[row + startRow, 1, row + startRow, 1].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center; + worksheet.Cells[row + startRow, 1, row + startRow, 1].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; + } + //遍历需要写入文件的字段 + for (int i = 0; i < colunms.Count; ++i) + { + worksheet.Cells[row + startRow, i + 1 + startCol].Value = db.Rows[row][colunms[i]].ToString(); + worksheet.Cells[row + startRow, i + 1 + startCol, row + startRow, i + 1 + startCol].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center; + worksheet.Cells[row + startRow, i + 1 + startCol, row + startRow, i + 1 + startCol].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; + } + } + + if (!string.IsNullOrEmpty(totalText)) + { + worksheet.Cells[dbCount + startRow, 1].Value = "总计:"; + worksheet.Cells[dbCount + startRow, 1, dbCount + startRow, 1].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center; + worksheet.Cells[dbCount + startRow, 1, dbCount + startRow, 1].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; + + worksheet.Cells[dbCount + startRow, 2, dbCount + startRow, colunms.Count + startCol].Value = totalText; + worksheet.Cells[dbCount + startRow, 2, dbCount + startRow, colunms.Count + startCol].Merge = true; + startRow++; + } + + using (ExcelRange r = worksheet.Cells[1, 1, dbCount + startRow - 1, fields.Count + startCol]) + { + r.Style.Border.Top.Style = ExcelBorderStyle.Thin; + r.Style.Border.Left.Style = ExcelBorderStyle.Thin; + r.Style.Border.Right.Style = ExcelBorderStyle.Thin; + r.Style.Border.Bottom.Style = ExcelBorderStyle.Thin; + + r.Style.Border.Top.Color.SetColor(Color.Black); + r.Style.Border.Left.Color.SetColor(Color.Black); + r.Style.Border.Right.Color.SetColor(Color.Black); + r.Style.Border.Bottom.Color.SetColor(Color.Black); + } + if (isNeedItemNo) + { + worksheet.Column(1).Width = 20;//设置列宽为默认值 + } + //设置列宽 + if (exportFieldsWidth == null || exportFieldsWidth.Count < fields.Count) + { + for (int i = 0; i < fields.Count; ++i) + { + worksheet.Column(i + 1 + startCol).Width = 20;//设置列宽为默认值 + } + } + else + { + for (int i = 0; i < fields.Count; ++i) + { + worksheet.Column(i + 1 + startCol).Width = exportFieldsWidth[i];//设置列宽为前段配置的值 + } + } + + package.Workbook.Properties.Title = "数据导出"; + package.Workbook.Properties.Author = "SUZHOUEU"; + package.Workbook.Properties.Comments = "苏州一优信息技术有限公司提供技术支持!"; + + package.Workbook.Properties.Company = "苏州一优信息技术有限公司"; + + package.Workbook.Properties.SetCustomPropertyValue("Checked by", "SimonHsiao"); + package.Workbook.Properties.SetCustomPropertyValue("AssemblyName", "SUZHOUEU"); + + package.Save(); + + } + } + LoggerHelper.SendLog("生成文件 " + fname + " 完毕 " + dbCount + " 耗时 " + (int)(DateTime.Now - dt_start).TotalSeconds); + } private static string ConvertData2String(T t, string field) where T : class { if (t.FieldTypeIsDateTime(field)) @@ -225,73 +364,6 @@ public static class IQueryableExtensions return (fields, colunms); } - /// - /// 获取数据 - /// - /// 对象 - /// - /// - public static List GetPropertyData(T obj, List colunms) where T : class - { - List data = new List(); - //声明obj的类型 - Type type = obj.GetType(); - // 获取obj类型的所有属性信息 - System.Reflection.PropertyInfo[] PropertyList = type.GetProperties(); - //循环每一个属性 - foreach (var item in PropertyList) - { - // 获取自定义特性 - object[] export = item.GetCustomAttributes(typeof(ExportDatatAttribute), true); - object[] descript = item.GetCustomAttributes(typeof(DescriptionAttribute), true); - //判断是否需要导出 - if (export.Length > 0) - { - //取值 - var exdesc = ((ExportDatatAttribute)export[0]); - // 是否嵌套 - if (exdesc != null) - { - //是否是序列 - if (exdesc.ExportDataFlag == "1") - { - var tmp = item.GetValue(obj) as IEnumerable; //List - if (tmp != null) - { - foreach (var o in tmp) - { - data.AddRange(GetPropertyData(o, colunms)); - } - } - } - // 如果是嵌套model - else if (exdesc.ExportDataFlag == "2") - { - var tmp = item.GetValue(obj); - if (tmp != null) - { - data.AddRange(GetPropertyData(tmp, colunms)); - } - } - else if (exdesc.ExportDataFlag == "3") - { - if (colunms.Contains(item.Name)) - { - data.Add(item.GetValue(obj).ToString()); - } - } - } - } - else if (descript.Length > 0) - { - if (colunms.Contains(item.Name)) - { - data.Add(item.GetValue(obj).ToString()); - } - } - } - return data; - } #region 获取字段描述 /// diff --git a/Tiobon.Core.DataAccess/ReportHelper.cs b/Tiobon.Core.DataAccess/ReportHelper.cs index ac14bf2e..34dca1a3 100644 --- a/Tiobon.Core.DataAccess/ReportHelper.cs +++ b/Tiobon.Core.DataAccess/ReportHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data; using System.IO; using System.Linq; using System.Linq.Dynamic.Core; @@ -63,6 +64,38 @@ public static class ReportHelper await _context.SaveChangesAsync(); return fid; } + + public static async Task SendFile (DataTable list, string modelName, Dictionary fieldDescs, List exportFieldsWidth, string sort = null, string headText = "", string totalText = "", bool isNeedItemNo = false) + { + + if (list == null) + throw new Exception("生成文件失败"); + //生成文件至文件服务器 + var fid = SnowFlakeSingle.Instance.NextId(); + var path = $"{$"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}wwwroot{Path.DirectorySeparatorChar}files{Path.DirectorySeparatorChar}export{Path.DirectorySeparatorChar}{fid}{Path.DirectorySeparatorChar}"}"; + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + var fname = $"{modelName}.xlsx"; + + list.IntoFileFromLinqExcel(path + fname, ",", fieldDescs, exportFieldsWidth, headText, totalText, isNeedItemNo); + + using var _context = ContextFactory.CreateContext(); + + Ghre_Attachment fileAttachment = new Ghre_Attachment(); + fileAttachment.Id = fid; + fileAttachment.AttachFileName = fname; + fileAttachment.CreateBy = App.User.ID; + fileAttachment.CreateTime = DateTime.Now; + fileAttachment.AttachmentName = fname; + fileAttachment.AttachFileExtension = "xlsx"; + fileAttachment.AttachFileSize = 0; + fileAttachment.PhysicsPath = $"/files/export/{fid}/" + fname; + fileAttachment.AttachmentType = "xlsx"; + + await _context.Ghre_Attachment.AddAsync(fileAttachment); + await _context.SaveChangesAsync(); + return fid; + } #endregion } \ No newline at end of file diff --git a/Tiobon.Core.IServices/ICommonServices.cs b/Tiobon.Core.IServices/ICommonServices.cs index 01f76720..533a704b 100644 --- a/Tiobon.Core.IServices/ICommonServices.cs +++ b/Tiobon.Core.IServices/ICommonServices.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using Tiobon.Core.Common; using Tiobon.Core.IServices.BASE; using Tiobon.Core.Model; @@ -21,4 +22,6 @@ public interface ICommonServices : IBaseServices> Task> GetModuleInfoAsync([FromBody] ModuleParam param); Task> GetSelectAsync(string type); + + Task> ExportExcelAsync(QueryExport param); } diff --git a/Tiobon.Core.Model/ViewModels/Extend/CommonSelectItem.cs b/Tiobon.Core.Model/ViewModels/Extend/CommonSelectItem.cs new file mode 100644 index 00000000..fac67a34 --- /dev/null +++ b/Tiobon.Core.Model/ViewModels/Extend/CommonSelectItem.cs @@ -0,0 +1,8 @@ +namespace Tiobon.Core.Model; + +public class CommonSelectItem +{ + public string value { get; set; } + public string label { get; set; } + +} \ No newline at end of file diff --git a/Tiobon.Core.Services/BASE/BaseServices.cs b/Tiobon.Core.Services/BASE/BaseServices.cs index af22b714..c5a53f4a 100644 --- a/Tiobon.Core.Services/BASE/BaseServices.cs +++ b/Tiobon.Core.Services/BASE/BaseServices.cs @@ -686,6 +686,26 @@ public class BaseServices : IBaseServ } public async Task> Export(QueryBody body) { + //sql = @$"SELECT field, + // [dbo].[FLangKeyToValue] (mkey, {body.langId}, label) + // label, + // required, + // editable, + // rowNum, + // colNum, + // elementType, + // dbo.FS_GetdataSourceBySet + // (dataSource, APIDataSourceType, Ghrs_PageSettingEdit.APIDataSourceID) + // dataSource, + // defaultHidden, + // isPrimaryKey, + // isSingleColumn + // FROM Ghrs_PageSettingEdit + // WHERE IsEnable = 1 + // AND pageNo = '{body.menuName}' + // AND elementType NOT IN ('FnKey', 'PageGroup');"; + //dt = await Db.Ado.GetDataTableAsync(sql); + var data = await BaseDal.QueryFilterPage(body); var fileId = await ReportHelper.SendFile(data.result.DT_TableDataT1.AsQueryable(), $"测试测试", null, null, null, null); return ServiceResult.OprateSuccess("导出成功", fileId); diff --git a/Tiobon.Core.Services/CommonServices.cs b/Tiobon.Core.Services/CommonServices.cs index ff5b4c90..33d2ec10 100644 --- a/Tiobon.Core.Services/CommonServices.cs +++ b/Tiobon.Core.Services/CommonServices.cs @@ -9,6 +9,7 @@ using Newtonsoft.Json.Linq; using SqlSugar; using Tiobon.Core.Common; using Tiobon.Core.Common.DB.Dapper; +using Tiobon.Core.DataAccess; using Tiobon.Core.IServices; using Tiobon.Core.Model; using Tiobon.Core.Services.BASE; @@ -1138,4 +1139,92 @@ public partial class CommonServices : BaseServices>, ICommon } #endregion + #region Export + public async Task> ExportExcelAsync(QueryExport param) + { + var result = new QueryExportReturn(); + + var tableNmae = string.Empty; + string sql = "select QueryProcedure, EditProcedure, IUDProcedure from Ghrs_Menu where MenuNo='{0}'"; + sql = string.Format(sql, param.menuName); + var dt = await Db.Ado.GetDataTableAsync(sql); + if (dt.Rows.Count > 0) + { + string queryProcedure = dt.Rows[0]["QueryProcedure"].ToString(); + + string[] aaa = queryProcedure.Split('/'); + tableNmae = aaa[1]; + } + + sql = $@"SELECT Row_Number () + OVER (ORDER BY CONVERT (INT, rowNum), CONVERT (INT, colNum)) + sortNum, + field, + [dbo].[FLangKeyToValue] (mkey, 1, label) + label, + dbo.FS_GetdataSourceBySet + (dataSource, APIDataSourceType, Ghrs_PageSettingEdit.APIDataSourceID) + dataSource, + required, + dataType, + CONVERT (NVARCHAR (1000), '') + commentText -- StaffWith + , + elementType + + CASE WHEN multipleSelect = 'true' THEN '_multiple' ELSE '' END + elementType -- 增加多选判断 + FROM Ghrs_PageSettingEdit + WHERE IsEnable = 1 + AND elementType NOT IN ('FnKey', 'PageGroup') + AND pageNo = 'F_Training_Course' + --and editable = 'true' + AND defaultHidden ! = 'true' + AND elementType ! = 'FileUpload' + AND dataType ! = ''"; + + var columns = await Db.Ado.SqlQueryAsync(sql); + + + columns = columns.WhereIF(param.exportSet.ExFields.Any(), x => param.exportSet.ExFields.Contains(x.field)).ToList(); + + dt = await Db.Ado.GetDataTableAsync("SELECT * FROM " + tableNmae + " WHERE IsEnable=1"); + + // 获取所有列名 + var dtColumns = dt.Columns; + + var convertColumns = columns.Where(x => !string.IsNullOrEmpty(x.dataSource) && !string.IsNullOrEmpty(x.elementType)).ToList(); + for (int i = 0; i < convertColumns.Count; i++) + { + dt.Columns.Add(convertColumns[i].field + "1", typeof(string)); + //var values = dt.AsEnumerable().Select(row => row.Field(column.field)).Distinct().ToList(); + sql = $@"SELECT SelectSql from Ghrs_ListCommonSql WHERE ListCommonSqlNo=REPLACE('{convertColumns[i].dataSource}','CommonList_','') and IsEnable=1 "; + + sql = await Db.Ado.GetScalarAsync(sql) as string; + sql = sql.Replace("{@KeyWords}", null); + var dtSelect = await Db.Ado.SqlQueryAsync(sql); + + foreach (DataColumn column in dtColumns) + { + if (column.ColumnName == convertColumns[i].field) + { + //column.DataType = typeof(string); + //dt.AcceptChanges(); + for (int j = 0; j < dt.Rows.Count; j++) + { + dt.Rows[j][column.ColumnName + "1"] = dtSelect.FirstOrDefault(x => x.value == dt.Rows[j][column.ColumnName].ToString())?.label; + } + } + + } + + } + var fieldDescs = columns.ToDictionary(item => item.label, item => convertColumns.Any(x => x.field == item.field) ? item.field + "1" : item.field); + + + var fileId = await ReportHelper.SendFile(dt, $"测试测试", fieldDescs, null, null, null); + + return new ServiceResult() { Success = true, Message = "查询成功", Data = result, }; + } + #endregion + }