|
@@ -1,23 +1,171 @@
|
|
|
-using Microsoft.AspNetCore.Components;
|
|
|
+using Hotline.Application.ExportExcel;
|
|
|
+using Hotline.Share.Dtos.Order;
|
|
|
+using Hotline.Share.Dtos.Snapshot;
|
|
|
+using Hotline.Share.Tools;
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
+using Microsoft.AspNetCore.Routing;
|
|
|
+using MongoDB.Bson.IO;
|
|
|
+using SqlSugar;
|
|
|
+using System.ComponentModel;
|
|
|
+using System.Reflection;
|
|
|
+using System.Text.Json;
|
|
|
+using XF.Domain.Dependency;
|
|
|
+using XF.Domain.Exceptions;
|
|
|
|
|
|
namespace Hotline.Api.Controllers.ExportData;
|
|
|
|
|
|
[ApiController]
|
|
|
-[Microsoft.AspNetCore.Mvc.Route("{*path:regex(.*export_data$)}")]
|
|
|
+[Route("{*path:regex(.*export_excel$)}")]
|
|
|
public class ExportDataController : BaseController
|
|
|
{
|
|
|
- [HttpGet]
|
|
|
- public IActionResult HandleExport()
|
|
|
+
|
|
|
+ private readonly IServiceProvider _serviceProvider;
|
|
|
+ private readonly EndpointDataSource _endpointDataSource;
|
|
|
+ private readonly IExportApplication _exportApplication;
|
|
|
+
|
|
|
+ public ExportDataController(IServiceProvider serviceProvider, EndpointDataSource endpointDataSource, IExportApplication exportApplication)
|
|
|
{
|
|
|
- // 处理 GET 请求
|
|
|
- return Ok("This is a GET export request.");
|
|
|
+ _serviceProvider = serviceProvider;
|
|
|
+ _endpointDataSource = endpointDataSource;
|
|
|
+ _exportApplication = exportApplication;
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 动态导出数据
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
[HttpPost]
|
|
|
- public IActionResult HandleExportPost()
|
|
|
+ public async Task<FileStreamResult> HandleExportPost()
|
|
|
+ {
|
|
|
+ var fullPath = HttpContext.Request.Path.Value;
|
|
|
+ var originalPath = fullPath?.Substring(0, fullPath.LastIndexOf("/export_excel")).TrimStart('/');
|
|
|
+ if (string.IsNullOrEmpty(originalPath))
|
|
|
+ throw UserFriendlyException.SameMessage("Invalid export path.");
|
|
|
+
|
|
|
+ var matchingEndpoint = _endpointDataSource.Endpoints
|
|
|
+ .OfType<RouteEndpoint>()
|
|
|
+ .FirstOrDefault(endpoint => endpoint.RoutePattern.RawText == originalPath);
|
|
|
+
|
|
|
+ if (matchingEndpoint == null)
|
|
|
+ throw UserFriendlyException.SameMessage($"No route matches '{originalPath}'.");
|
|
|
+
|
|
|
+ var controllerName = matchingEndpoint.RoutePattern.RequiredValues["controller"]?.ToString();
|
|
|
+ var actionName = matchingEndpoint.RoutePattern.RequiredValues["action"]?.ToString();
|
|
|
+
|
|
|
+ var applicationServiceType = GetApplicationServiceType(controllerName);
|
|
|
+ if (applicationServiceType == null)
|
|
|
+ throw UserFriendlyException.SameMessage($"Application service for '{controllerName}' not found.");
|
|
|
+
|
|
|
+ var method = applicationServiceType.GetMethod(actionName);
|
|
|
+ if (method == null)
|
|
|
+ {
|
|
|
+ method = applicationServiceType.GetMethod(actionName + "Async");
|
|
|
+ if (method == null)
|
|
|
+ throw UserFriendlyException.SameMessage($"Action '{actionName}' not found in Application service.");
|
|
|
+ }
|
|
|
+
|
|
|
+ var serviceInstance = _serviceProvider.GetService(applicationServiceType);
|
|
|
+ if (serviceInstance == null)
|
|
|
+ {
|
|
|
+ serviceInstance = _serviceProvider.GetService(applicationServiceType.GetInterfaces()[0]);
|
|
|
+ if (serviceInstance == null)
|
|
|
+ throw UserFriendlyException.SameMessage($"Unable to create instance of Application service '{applicationServiceType.Name}'.");
|
|
|
+ }
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var parameters = method.GetParameters();
|
|
|
+
|
|
|
+ using var reader = new StreamReader(HttpContext.Request.Body);
|
|
|
+ var body = await reader.ReadToEndAsync();
|
|
|
+ var param = parameters[0];
|
|
|
+ var genericType = typeof(ExportExcelDto<>).MakeGenericType(param.ParameterType);
|
|
|
+ var exportData = body.FromJson(genericType);
|
|
|
+ var queryDto = genericType.GetProperty("QueryDto")?.GetValue(exportData);
|
|
|
+ var isExportAll = genericType.GetProperty("IsExportAll")?.GetValue(exportData);
|
|
|
+ var pageIndex = param.ParameterType.GetProperty("PageIndex")?.GetValue(queryDto);
|
|
|
+ var pageSize = param.ParameterType.GetProperty("PageSize")?.GetValue(queryDto);
|
|
|
+ var result = method.Invoke(serviceInstance, [queryDto]);
|
|
|
+
|
|
|
+ var returnType = method.ReturnType.GetGenericArguments()[0];
|
|
|
+ var description = method.GetCustomAttribute<DescriptionAttribute>()?.Description;
|
|
|
+
|
|
|
+ return _exportApplication.GetExcelFile(returnType, genericType, exportData, ConvertToList(result, (bool)isExportAll, (int)pageIndex, (int)pageSize), description);
|
|
|
+
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ var msg = e.Message;
|
|
|
+ throw;
|
|
|
+ }
|
|
|
+ throw UserFriendlyException.SameMessage("失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ public static List<object>? ConvertToList(object? result, bool isExportAll, int pageIndex, int pageSize)
|
|
|
{
|
|
|
- // 处理 POST 请求
|
|
|
- return Ok("This is a POST export request.");
|
|
|
+ if (result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ var type = result.GetType();
|
|
|
+
|
|
|
+ if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(PostgreSQLQueryable<>))
|
|
|
+ {
|
|
|
+ throw UserFriendlyException.SameMessage("被导出方法的返回类型不是 ISugarQueryable");
|
|
|
+ }
|
|
|
+
|
|
|
+ var genericArgument = type.GetGenericArguments()[0];
|
|
|
+
|
|
|
+ if (isExportAll)
|
|
|
+ {
|
|
|
+ var toListMethod = type.GetMethods()
|
|
|
+ .Where(m => m.Name == "ToList" && m.GetParameters().Length == 0)
|
|
|
+ .First();
|
|
|
+ var list = toListMethod.Invoke(result, null) as IEnumerable<object>;
|
|
|
+ return list?.ToList();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var toListMethod = type.GetMethods()
|
|
|
+ .Where(m => m.Name == "ToPageList" && m.GetParameters().Length == 2)
|
|
|
+ .First();
|
|
|
+ var list = toListMethod.Invoke(result, [pageIndex, pageSize]) as IEnumerable<object>;
|
|
|
+ return list?.ToList();
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ private Type GetApplicationServiceType(string controllerName)
|
|
|
+ {
|
|
|
+ // 根据约定规则,将 Controller 映射到 Application 服务类
|
|
|
+ // 假设 Application 服务类命名规则为 "{ControllerName}Application"
|
|
|
+ var applicationServiceName = $"Hotline.Application.Snapshot.{controllerName}Application";
|
|
|
+ var name = controllerName + "Application";
|
|
|
+
|
|
|
+ var type = AppDomain.CurrentDomain.GetAssemblies().ToList()
|
|
|
+ .SelectMany(d => d.GetTypes())
|
|
|
+ .Where(d => d.Name == name)
|
|
|
+ .First();
|
|
|
+ return type;
|
|
|
+ }
|
|
|
+
|
|
|
+ private async Task<object[]> BindMethodParameters(System.Reflection.MethodInfo method)
|
|
|
+ {
|
|
|
+ // 动态解析方法的参数绑定
|
|
|
+ var parameters = method.GetParameters();
|
|
|
+ var result = new List<object>();
|
|
|
+
|
|
|
+ foreach (var param in parameters)
|
|
|
+ {
|
|
|
+ using var reader = new StreamReader(HttpContext.Request.Body);
|
|
|
+ var body = await reader.ReadToEndAsync();
|
|
|
+ var genericType = typeof(ExportExcelDto<>).MakeGenericType(param.ParameterType);
|
|
|
+ var deserializedObject = body.FromJson(genericType);
|
|
|
+ var queryDto = genericType.GetProperty("QueryDto")?.GetValue(deserializedObject);
|
|
|
+ result.Add(queryDto);
|
|
|
+ }
|
|
|
+
|
|
|
+ return result.ToArray();
|
|
|
+ }
|
|
|
+
|
|
|
}
|