diff --git a/Dlhis.Jinko.Face.sln b/Dlhis.Jinko.Face.sln
index 0cf2b39a..ed3b6625 100644
--- a/Dlhis.Jinko.Face.sln
+++ b/Dlhis.Jinko.Face.sln
@@ -51,6 +51,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.Constants", "Src\Dlhi
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.Canteen.Api", "Src\Dlhis.Canteen.Api\Dlhis.Canteen.Api.csproj", "{7934BE46-9409-4D28-8B35-82A0F900DD01}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dlhis.ExcelHelper", "Src\Dlhis.ExcelHelper\Dlhis.ExcelHelper.csproj", "{F8287775-E641-479D-952B-FFE7D826E52E}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -129,6 +131,10 @@ Global
{7934BE46-9409-4D28-8B35-82A0F900DD01}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7934BE46-9409-4D28-8B35-82A0F900DD01}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7934BE46-9409-4D28-8B35-82A0F900DD01}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F8287775-E641-479D-952B-FFE7D826E52E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F8287775-E641-479D-952B-FFE7D826E52E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F8287775-E641-479D-952B-FFE7D826E52E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F8287775-E641-479D-952B-FFE7D826E52E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Src/Dlhis.Canteen/Dlhis.Canteen.csproj b/Src/Dlhis.Canteen/Dlhis.Canteen.csproj
index b3030c28..42d85d59 100644
--- a/Src/Dlhis.Canteen/Dlhis.Canteen.csproj
+++ b/Src/Dlhis.Canteen/Dlhis.Canteen.csproj
@@ -24,6 +24,7 @@
+
diff --git a/Src/Dlhis.Canteen/Dockerfile b/Src/Dlhis.Canteen/Dockerfile
index dcac8e9d..7b29619f 100644
--- a/Src/Dlhis.Canteen/Dockerfile
+++ b/Src/Dlhis.Canteen/Dockerfile
@@ -12,8 +12,10 @@ ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Src/Dlhis.Canteen/Dlhis.Canteen.csproj", "Src/Dlhis.Canteen/"]
COPY ["Src/Dlhis.Basic.Api/Dlhis.Basic.Api.csproj", "Src/Dlhis.Basic.Api/"]
+COPY ["Src/Dlhis.Constants/Dlhis.Constants.csproj", "Src/Dlhis.Constants/"]
COPY ["Src/Dlhis.Entity/Dlhis.Entity.csproj", "Src/Dlhis.Entity/"]
COPY ["Src/Dlhis.DataPermission.Model/Dlhis.DataPermission.Model.csproj", "Src/Dlhis.DataPermission.Model/"]
+COPY ["Src/Dlhis.ExcelHelper/Dlhis.ExcelHelper.csproj", "Src/Dlhis.ExcelHelper/"]
COPY ["Src/Dlhis.Sys.Api/Dlhis.Sys.Api.csproj", "Src/Dlhis.Sys.Api/"]
RUN dotnet restore "./Src/Dlhis.Canteen/Dlhis.Canteen.csproj"
COPY . .
diff --git a/Src/Dlhis.Canteen/ExcelResultAttribute.cs b/Src/Dlhis.Canteen/ExcelResultAttribute.cs
new file mode 100644
index 00000000..3f0dde87
--- /dev/null
+++ b/Src/Dlhis.Canteen/ExcelResultAttribute.cs
@@ -0,0 +1,43 @@
+using Dlhis.ExcelHelper;
+using Kurisu.AspNetCore.DataAccess.Dto;
+using Kurisu.AspNetCore.UnifyResultAndValidation.Abstractions;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+
+namespace Dlhis.Canteen;
+
+///
+/// 忽略响应.Data的自动camelCase
+///
+[AttributeUsage(AttributeTargets.Method)]
+public class ExcelResultAttribute : Attribute, IAsyncActionFilter
+{
+ private readonly string _fileName;
+
+ public ExcelResultAttribute(string fileName)
+ {
+ _fileName = fileName;
+ }
+
+ ///
+ public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
+ {
+ var r = await next();
+ var or = r.Result as ObjectResult;
+ var v = or.Value;
+ var type = or.DeclaredType.GenericTypeArguments[0];
+ if (or.DeclaredType.IsGenericType && or.DeclaredType.GetGenericTypeDefinition() == typeof(Pagination<>))
+ {
+ v = v.GetType().GetProperty("Data").GetValue(v, null);
+ }
+
+ var method = typeof(ExcelExtensions).GetMethod(nameof(ExcelExtensions.ToExcelBytesAsync));
+ var task = (Task)method.MakeGenericMethod(type).Invoke(null, new[] { v });
+ var data = await task;
+
+ r.Result = new FileContentResult(data, "application/vnd.ms-excel")
+ {
+ FileDownloadName = _fileName
+ };
+ }
+}
\ No newline at end of file
diff --git a/Src/Dlhis.Canteen/Order/Controllers/BalancesController.cs b/Src/Dlhis.Canteen/Order/Controllers/BalancesController.cs
index ee707e15..62c05f76 100644
--- a/Src/Dlhis.Canteen/Order/Controllers/BalancesController.cs
+++ b/Src/Dlhis.Canteen/Order/Controllers/BalancesController.cs
@@ -42,6 +42,7 @@ public class BalancesController : ControllerBase
///
///
[HttpGet("export")]
+ [ExcelResult("员工账务明细")]
[IgnoreTenant]
public async Task> GetPageToExportAsync([FromQuery] BalanceRecordPageRequest request)
{
diff --git a/Src/Dlhis.Canteen/Order/Response/BalanceRecordResponse.cs b/Src/Dlhis.Canteen/Order/Response/BalanceRecordResponse.cs
index ac19cb85..12bb8a1d 100644
--- a/Src/Dlhis.Canteen/Order/Response/BalanceRecordResponse.cs
+++ b/Src/Dlhis.Canteen/Order/Response/BalanceRecordResponse.cs
@@ -1,11 +1,13 @@
using Dlhis.Entity.Canteen.Enums;
+using Dlhis.ExcelHelper;
using Kurisu.AspNetCore.Utils.Converters;
using Kurisu.AspNetCore.Utils.Extensions;
using Newtonsoft.Json;
namespace Dlhis.Canteen.Order.Response;
-public class BalanceRecordResponse
+[Excel("BalanceRecords")]
+public class BalanceRecordResponse : IExcelExportable
{
public long Id { get; set; }
@@ -27,34 +29,40 @@ public class BalanceRecordResponse
///
/// 姓名
///
+ [Excel("姓名")]
public string Name { get; set; }
///
/// 学工号
///
+ [Excel("工号")]
public string UserCode { get; set; }
///
/// 部门号
///
+ [Excel("部门号")]
public string DepartmentNo { get; set; }
///
/// 部门
///
+ [Excel("部门名称")]
public string DepartmentName { get; set; }
///
/// 所属成本日期
///
+ [Excel("营业日期", "yyyy-MM-dd")]
[JsonConverter(typeof(ToDateJsonConverter))]
public DateTime CostDate { get; set; }
///
- /// 备注
+ /// 记录产生时间
///
- public string Remark { get; set; }
+ [Excel("消费时间", "yyyy-MM-dd HH:mm:ss")]
+ public DateTime CostDateTime { get; set; }
///
/// 来源
@@ -64,6 +72,7 @@ public class BalanceRecordResponse
///
/// 消费识别来源
///
+ [Excel("消费来源")]
public string SourceDesc => Source.GetDescription();
///
@@ -76,11 +85,13 @@ public class BalanceRecordResponse
///
/// 金额
///
+ [Excel("消费金额", "0.00")]
public decimal Amount { get; set; }
///
/// 营业点
///
+ [Excel("营业点")]
public string BusinessPlaceName { get; set; }
///
@@ -91,6 +102,7 @@ public class BalanceRecordResponse
///
/// 餐次
///
+ [Excel("场次")]
public string ShiftTypeDesc => ShiftType?.GetDescription();
///
@@ -103,11 +115,6 @@ public class BalanceRecordResponse
///
public string CostId { get; set; }
- ///
- /// 消费者所在基地
- ///
- public string OriginTenantId { get; set; }
-
///
/// 数据状态
///
@@ -116,20 +123,30 @@ public class BalanceRecordResponse
///
/// 数据状态描述
///
+ [Excel("数据状态")]
public string StatusDesc => Status.GetDescription();
///
- /// 记录产生时间
+ /// 消费者所在基地
///
- public DateTime CostDateTime { get; set; }
+ [Excel("在职厂区")]
+ public string OriginTenantId { get; set; }
///
/// 厂区
///
+ [Excel("消费厂区")]
public string Factory { get; set; }
///
/// 人事范围
///
+ [Excel("人事范围")]
public string Werks { get; set; }
+
+ ///
+ /// 备注
+ ///
+ [Excel("备注")]
+ public string Remark { get; set; }
}
\ No newline at end of file
diff --git a/Src/Dlhis.ExcelHelper/Dlhis.ExcelHelper.csproj b/Src/Dlhis.ExcelHelper/Dlhis.ExcelHelper.csproj
new file mode 100644
index 00000000..ef6578a3
--- /dev/null
+++ b/Src/Dlhis.ExcelHelper/Dlhis.ExcelHelper.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/Src/Dlhis.ExcelHelper/ExcelAttribute.cs b/Src/Dlhis.ExcelHelper/ExcelAttribute.cs
new file mode 100644
index 00000000..04a358c3
--- /dev/null
+++ b/Src/Dlhis.ExcelHelper/ExcelAttribute.cs
@@ -0,0 +1,19 @@
+namespace Dlhis.ExcelHelper;
+
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)]
+public class ExcelAttribute : Attribute
+{
+ public ExcelAttribute(string description) : this(description, string.Empty)
+ {
+ }
+
+ public ExcelAttribute(string description, string format)
+ {
+ Description = description;
+ Format = format;
+ }
+
+
+ public string Description { get; set; }
+ public string Format { get; set; }
+}
\ No newline at end of file
diff --git a/Src/Dlhis.ExcelHelper/ExcelExtensions.cs b/Src/Dlhis.ExcelHelper/ExcelExtensions.cs
new file mode 100644
index 00000000..8878ca80
--- /dev/null
+++ b/Src/Dlhis.ExcelHelper/ExcelExtensions.cs
@@ -0,0 +1,51 @@
+using System.Reflection;
+using OfficeOpenXml;
+
+namespace Dlhis.ExcelHelper;
+
+public static class ExcelExtensions
+{
+ public static async Task ToExcelBytesAsync(this List data) where T : IExcelExportable
+ {
+ ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
+
+ var type = typeof(T);
+ var sheetName = type.GetCustomAttribute()!.Description;
+ var excelHeaderNames = type.GetProperties().Where(x => x.IsDefined(typeof(ExcelAttribute))).ToList();
+
+ using var package = new ExcelPackage();
+ ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(sheetName);
+
+ // 写入表头
+ for (int i = 0; i < excelHeaderNames.Count; i++)
+ {
+ var cell = worksheet.Cells[1, i + 1];
+ worksheet.Column(i + 1).BestFit = true;
+ cell.Style.Font.Bold = true;
+ cell.Value = excelHeaderNames[i].GetCustomAttribute()!.Description;
+ }
+
+ int row = 2;
+ foreach (var item in data)
+ {
+ for (int col = 0; col < excelHeaderNames.Count; col++)
+ {
+ var column = excelHeaderNames[col];
+ var value = column.GetValue(item);
+
+ var cell = worksheet.Cells[row, col + 1];
+ var format = column.GetCustomAttribute()!.Format;
+ cell.Value = value;
+ if (!string.IsNullOrEmpty(format))
+ {
+ cell.Style.Numberformat.Format = format;
+ }
+ }
+
+ row++;
+ }
+
+ worksheet.Cells.AutoFitColumns();
+ return await package.GetAsByteArrayAsync();
+ }
+}
\ No newline at end of file
diff --git a/Src/Dlhis.ExcelHelper/IExcelExportable.cs b/Src/Dlhis.ExcelHelper/IExcelExportable.cs
new file mode 100644
index 00000000..b4070791
--- /dev/null
+++ b/Src/Dlhis.ExcelHelper/IExcelExportable.cs
@@ -0,0 +1,5 @@
+namespace Dlhis.ExcelHelper;
+
+public interface IExcelExportable
+{
+}
diff --git a/Src/Dlhis.ExcelHelper/Request/DataExportRequest.cs b/Src/Dlhis.ExcelHelper/Request/DataExportRequest.cs
new file mode 100644
index 00000000..40f0f536
--- /dev/null
+++ b/Src/Dlhis.ExcelHelper/Request/DataExportRequest.cs
@@ -0,0 +1,13 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Dlhis.Basic.Common.DataExport.Request
+{
+ public class DataExportRequest
+ {
+ [Required]
+ public string TableName { get; set; }
+
+ [MinLength(1)]
+ public List ColumnNames { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Src/Dlhis.ExcelHelper/Request/DataImportRequest.cs b/Src/Dlhis.ExcelHelper/Request/DataImportRequest.cs
new file mode 100644
index 00000000..cbf1b8ff
--- /dev/null
+++ b/Src/Dlhis.ExcelHelper/Request/DataImportRequest.cs
@@ -0,0 +1,9 @@
+namespace Dlhis.Basic.Common.DataExport.Request
+{
+ public class DataImportRequest
+ {
+ public string TableName { get; set; }
+
+ public string FilePath { get; set; }
+ }
+}
diff --git a/Src/Dlhis.ExcelHelper/Services/IDataExportService.cs b/Src/Dlhis.ExcelHelper/Services/IDataExportService.cs
new file mode 100644
index 00000000..972905bd
--- /dev/null
+++ b/Src/Dlhis.ExcelHelper/Services/IDataExportService.cs
@@ -0,0 +1,13 @@
+//using Dlhis.Basic.Common.DataExport.Request;
+//using Microsoft.AspNetCore.Mvc;
+
+//namespace Dlhis.Basic.Common.DataExport.Services
+//{
+// public interface IDataExportService : IScopeDependency
+// {
+// Task GetDataExportAsync(DataExportRequest request);
+
+// Task DataImportAsync(IFormFile file);
+
+// }
+//}
\ No newline at end of file
diff --git a/Src/Dlhis.ExcelHelper/Services/Implements/DataExportService.cs b/Src/Dlhis.ExcelHelper/Services/Implements/DataExportService.cs
new file mode 100644
index 00000000..174afcc7
--- /dev/null
+++ b/Src/Dlhis.ExcelHelper/Services/Implements/DataExportService.cs
@@ -0,0 +1,188 @@
+//using System.Collections;
+//using System.Reflection;
+//using Dlhis.Basic.Common.DataExport.Request;
+//using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
+//using Kurisu.AspNetCore.Utils.Extensions;
+//using Mapster;
+//using Microsoft.AspNetCore.Mvc;
+//using Newtonsoft.Json.Linq;
+//using OfficeOpenXml;
+//using SqlSugar;
+
+//namespace Dlhis.Basic.Common.DataExport.Services.Implements
+//{
+// public class DataExportService : IDataExportService
+// {
+// protected IDbContext DbContext { get; }
+
+// public DataExportService(IDbContext dbContext)
+// {
+// DbContext = dbContext;
+// ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
+// }
+
+// private readonly static MethodInfo _queryMethod = typeof(IAdo).GetMethod(nameof(IAdo.SqlQueryAsync), 1, new[] { typeof(string), typeof(object) }, null);
+// private readonly static MethodInfo _handlerTaskMethod = typeof(DataExportService).GetMethod(nameof(HandlerResult), BindingFlags.NonPublic | BindingFlags.Instance);
+
+// public async Task GetDataExportAsync(DataExportRequest request)
+// {
+// var types = Assembly.Load("Dlhis.Entity")
+// .GetTypes()
+// .Where(x => x.IsClass && x.GetCustomAttribute() != null);
+
+// var type = types.FirstOrDefault(x => x.GetCustomAttribute()?.TableName == request.TableName)!;
+// type.ThrowIfNull("该表不存在");
+
+// var columns = type.GetProperties().Where(x => request.ColumnNames.Contains(x.Name)).ToList();
+// var excelHeaderNames = columns.Select(x => x.GetCustomAttribute()?.ColumnDescription ?? x.Name)
+// .ToList();
+
+
+// using (var package = new ExcelPackage())
+// {
+// ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(request.TableName);
+
+// // 写入表头
+// for (int i = 0; i < excelHeaderNames.Count; i++)
+// {
+// worksheet.Cells[1, i + 1].Value = excelHeaderNames[i];
+// }
+
+// var tableName = type.GetCustomAttribute().TableName;
+// var fields = columns.Select(x => x.Name).Join(",");
+
+// var task = _queryMethod.MakeGenericMethod(type).Invoke(DbContext.Client.Ado, new object[] { @$"SELECT {fields} FROM {tableName}", null });
+// var data = _handlerTaskMethod.MakeGenericMethod(type).Invoke(this, new object[] { task });
+
+// int row = 2;
+// foreach (var item in data.ToJson().ToObject>())
+// {
+// for (int col = 0; col < columns.Count; col++)
+// {
+// var column = columns[col];
+// var value = item[column.Name]!.Value();
+
+// if (column.PropertyType.IsEnum)
+// {
+// value = column.PropertyType.GetFields(BindingFlags.Public | BindingFlags.Static).Where(p => (int)p.GetValue(null) == item[column.Name]!.Value()).Select(p =>
+// {
+// var e = (Enum)Enum.Parse(p.FieldType, p.GetValue(null).ToString());
+// var fd = e.GetDescription();
+
+// return fd;
+// }).First();
+// }
+
+// worksheet.Cells[row, col + 1].Value = value;
+// }
+// row++;
+// }
+
+// var ms = new MemoryStream();
+
+// await package.SaveAsAsync(ms);
+// var contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
+
+// return new FileContentResult(ms.ToArray(), contentType);
+
+// }
+// }
+// private List HandlerResult(object o)
+// {
+// var originalValue = (Task>)o;
+// if (!originalValue.IsCompleted)
+// {
+// return Task.Run(() => originalValue).GetAwaiter().GetResult();
+// }
+
+// return originalValue.Result;
+// }
+
+// public async Task DataImportAsync(IFormFile file)
+// {
+// //获取数据
+// ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
+// using (var package = new ExcelPackage(file.OpenReadStream()))
+// {
+// var worksheet = package.Workbook.Worksheets[0];
+
+// //通过表名,获取实体表类型
+// var type = GetEntityTypeByTableName(worksheet.Name);
+// var tableType = typeof(List<>).MakeGenericType(type);
+// var listGenericAddMethod = tableType.GetMethod("Add");
+// var tableTypeInstance = Activator.CreateInstance(tableType);
+
+// var headers = new List();
+// for (int col = 1; col <= worksheet.Dimension.Columns; col++)
+// {
+// headers.Add(worksheet.Cells[1, col].Value?.ToString() ?? string.Empty);
+// }
+
+// var properties = type.GetProperties();
+// for (int row = 2; row <= worksheet.Dimension.Rows; row++)
+// {
+// var item = Activator.CreateInstance(type);
+
+// for (int col = 1; col <= worksheet.Dimension.Columns; col++)
+// {
+// var header = headers[col - 1];
+// var property = properties.FirstOrDefault(p => (p.GetCustomAttribute()?.ColumnDescription ?? p.Name).Equals(header, StringComparison.OrdinalIgnoreCase));
+
+// var value = worksheet.Cells[row, col].Value.Adapt(typeof(object), property.PropertyType);
+// if (property != null)
+// {
+// if (property.PropertyType.IsEnum)
+// {
+// try
+// {
+// var enumValue = Enum.Parse(property.PropertyType, value.ToString(), true);
+// property.SetValue(item, enumValue);
+// }
+// catch (Exception ex)
+// {
+// Console.WriteLine($"无法将值 '{value}' 转换为枚举类型 '{property.PropertyType.Name}':{ex.Message}");
+// }
+// }
+// else
+// {
+// property.SetValue(item, value);
+// }
+// }
+// }
+
+// listGenericAddMethod.Invoke(tableTypeInstance, new[] { item });
+// }
+
+// //foreach (var item in list)
+// // await DbContext.Client.InsertableByObject(item).ExecuteCommandAsync();
+
+// var insertMethod = typeof(IDbContext).GetMethods(BindingFlags.Public | BindingFlags.Instance)
+// .Where(x => x.Name == nameof(DbContext.InsertAsync))
+// .Where(x =>
+// {
+// var t = x.GetParameters().First().ParameterType;
+
+// var rr = x.GetParameters().First().ParameterType.IsAssignableTo(typeof(IList)) && !t.IsArray;
+
+// return rr;
+// })
+// .First();
+
+// var task = (Task)insertMethod.MakeGenericMethod(type).Invoke(DbContext, new object[] { tableTypeInstance });
+// await task.ConfigureAwait(false);
+// }
+// }
+
+
+
+// public Type GetEntityTypeByTableName(string tableName)
+// {
+// var type = Assembly.Load("Dlhis.Entity")
+// .GetTypes()
+// .Where(x => x.IsClass && x.GetCustomAttribute() != null)
+// .FirstOrDefault(x => x.GetCustomAttribute().TableName == tableName);
+
+// return type;
+// }
+// }
+//}
\ No newline at end of file