You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
899 lines
27 KiB
899 lines
27 KiB
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Linq.Dynamic.Core;
|
|
using System.Linq.Expressions;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using AutoMapper;
|
|
using Dy_Exchange.Enums;
|
|
using Dy_Exchange.Localization;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Caching.Distributed;
|
|
using Microsoft.Extensions.Localization;
|
|
using NPOI.SS.UserModel;
|
|
using NPOI.XSSF.UserModel;
|
|
using Volo.Abp;
|
|
using Volo.Abp.Application.Dtos;
|
|
using Volo.Abp.Application.Services;
|
|
using Volo.Abp.Caching;
|
|
using Volo.Abp.Domain.Entities;
|
|
using Volo.Abp.Domain.Entities.Auditing;
|
|
using Volo.Abp.Domain.Repositories;
|
|
using WinIn.FasterZ.Inventory.AppBase;
|
|
using WinIn.FasterZ.Inventory.AppBase.Filters;
|
|
using WinIn.FasterZ.Inventory.AppBase.TableColumnTypeDto;
|
|
using WinIn.FasterZ.Wms.AppBase.Extensions;
|
|
using WinIn.FasterZ.Wms.AppBaseBusiness.ExportCustomUserSetting;
|
|
|
|
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
|
|
|
namespace WinIn.FasterZ.Wms.AppBase;
|
|
|
|
[Route("Api/[controller]")]
|
|
public class ZbxBase<TEntity, TEntityDto, TKey, TPagedAndSortedResultRequestDto, TCreateInput, TUpdateInput> :
|
|
CrudAppService<TEntity, TEntityDto, TKey,
|
|
TPagedAndSortedResultRequestDto, TCreateInput, TUpdateInput>,
|
|
IZbxBase<TEntityDto, TKey, TPagedAndSortedResultRequestDto, TCreateInput, TUpdateInput>
|
|
where TEntity : class, IEntity<TKey>
|
|
where TEntityDto : IEntityDto<TKey>
|
|
{
|
|
#region 定义
|
|
|
|
/// <summary>
|
|
/// redis缓存时间 分钟
|
|
/// </summary>
|
|
private const int CacheMinute = 30;
|
|
|
|
private readonly IRepository<TEntity, TKey> _repository;
|
|
|
|
private IMapper _mapper;
|
|
|
|
private IStringLocalizer<Dy_ExchangeResource> Localizer =>
|
|
LazyServiceProvider.LazyGetRequiredService<IStringLocalizer<Dy_ExchangeResource>>();
|
|
|
|
private ExportCustomUserSettingAppService ExportCustomUserSettingAppService =>
|
|
LazyServiceProvider.LazyGetRequiredService<ExportCustomUserSettingAppService>();
|
|
|
|
private IDistributedCache<TEntity> Cache =>
|
|
LazyServiceProvider.LazyGetRequiredService<IDistributedCache<TEntity>>();
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// 构造方法
|
|
/// </summary>
|
|
/// <param name="repository"></param>
|
|
protected ZbxBase(IRepository<TEntity, TKey> repository) : base(repository)
|
|
{
|
|
_repository = repository;
|
|
}
|
|
|
|
#region 公开接口
|
|
|
|
#region 单体操作
|
|
|
|
/// <summary>
|
|
/// 【基础】-【新增】
|
|
/// </summary>
|
|
/// <param name="input"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("Base/Create")]
|
|
[Authorize]
|
|
public override async Task<TEntityDto> CreateAsync(TCreateInput input)
|
|
{
|
|
await CheckCreatePolicyAsync().ConfigureAwait(false);
|
|
|
|
var entity = input!.ToObject<TEntity>();
|
|
|
|
//判断id是否是00000-0000 如果是则赋值
|
|
var mainId = (Guid)entity.GetType().GetProperty("Id")?.GetValue(entity)!;
|
|
if (mainId == Guid.Empty)
|
|
{
|
|
mainId = Guid.NewGuid();
|
|
entity.GetType().GetProperty("Id")?.SetValue(entity, mainId);
|
|
}
|
|
|
|
#region 给所有字表的 Id和MasterId赋值 否则默认的会是000000-000-....的id 插入时会报错
|
|
|
|
var propertyInfos = entity.GetType().GetProperties();
|
|
foreach (var propertyInfo in propertyInfos)
|
|
{
|
|
//判断是否是List集合
|
|
if (propertyInfo.Name == "Details"
|
|
&& propertyInfo.PropertyType.IsGenericType
|
|
&& propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
|
|
{
|
|
var listProperty = typeof(TEntity).GetProperty("Details");
|
|
|
|
// 获取 List 的元素类型
|
|
if (listProperty != null)
|
|
{
|
|
var listItemType = listProperty.PropertyType.GetGenericArguments()[0];
|
|
|
|
// 获取元素类型的 ID 属性
|
|
var detailIdProperty = listItemType.GetProperty("Id");
|
|
var masterIdProperty = listItemType.GetProperty("MasterId");
|
|
|
|
if (detailIdProperty != null)
|
|
{
|
|
// 获取 List 属性的值
|
|
var list = (IList)listProperty.GetValue(entity);
|
|
|
|
// 遍历 List 集合中的每个元素,给 ID 属性赋值
|
|
if (list != null)
|
|
{
|
|
foreach (var item in list)
|
|
{
|
|
if ((Guid)detailIdProperty.GetValue(item)! == Guid.Empty)
|
|
{
|
|
detailIdProperty.SetValue(item, Guid.NewGuid());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (masterIdProperty != null)
|
|
{
|
|
// 获取 List 属性的值
|
|
var list = (IList)listProperty.GetValue(entity);
|
|
|
|
// 遍历 List 集合中的每个元素,给 ID 属性赋值
|
|
if (list != null)
|
|
{
|
|
foreach (var item in list)
|
|
{
|
|
masterIdProperty.SetValue(item, mainId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
TryToSetTenantId(entity);
|
|
await Repository.InsertAsync(entity, true).ConfigureAwait(false);
|
|
|
|
return await MapToGetOutputDtoAsync(entity).ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 【基础】-【删除】
|
|
/// </summary>
|
|
/// <param name="id"></param>
|
|
/// <returns></returns>
|
|
[HttpDelete("Base/Delete")]
|
|
[Authorize]
|
|
public override async Task DeleteAsync(TKey id)
|
|
{
|
|
await CheckDeletePolicyAsync().ConfigureAwait(false);
|
|
|
|
await _repository.DeleteAsync(id, true).ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 【基础】-【修改】
|
|
/// </summary>
|
|
/// <param name="id"></param>
|
|
/// <param name="input"></param>
|
|
/// <returns></returns>
|
|
[HttpPut("Base/Update")]
|
|
[Authorize]
|
|
public override async Task<TEntityDto> UpdateAsync(TKey id, TUpdateInput input)
|
|
{
|
|
await CheckUpdatePolicyAsync().ConfigureAwait(true);
|
|
var entity = await GetEntityByIdAsync(id).ConfigureAwait(true);
|
|
|
|
//当一条库存的一部分被人修改了 数据无法提交 例如库存10个 修改了其中4个 这时乐观锁就被修改了 会抛出异常
|
|
if (entity.GetType().GetProperty("ConcurrencyStamp").GetValue(entity).ToString() !=
|
|
input.GetType().GetProperty("ConcurrencyStamp").GetValue(input).ToString())
|
|
{
|
|
throw new UserFriendlyException($"您操作的数据已经被修改:\r\n" +
|
|
$"已经由【{Newtonsoft.Json.JsonConvert.SerializeObject(entity)}】\r\n" +
|
|
$"变更为【{Newtonsoft.Json.JsonConvert.SerializeObject(input)}】\r\n");
|
|
}
|
|
|
|
Type? inputDetailDtoType = null;
|
|
Type? entityDetailType = null;
|
|
var inputDetailDtoTypeFlag = false; //input是否有子集合Details
|
|
var entityDetailTypeFlag = false; //entity是否有子集合Details
|
|
|
|
var entityProperties = entity.GetType().GetProperties();
|
|
var inputProperties = input.GetType().GetProperties();
|
|
|
|
//InputDto的
|
|
foreach (var propertyInfo in inputProperties)
|
|
{
|
|
if (propertyInfo.Name == "Details"
|
|
&& propertyInfo.PropertyType.IsGenericType
|
|
&& propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
|
|
{
|
|
var listProperty = typeof(TUpdateInput).GetProperty("Details");
|
|
if (listProperty != null)
|
|
{
|
|
inputDetailDtoType = listProperty.PropertyType.GetGenericArguments()[0];
|
|
inputDetailDtoTypeFlag = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (inputDetailDtoTypeFlag)
|
|
{
|
|
//实体的
|
|
foreach (var propertyInfo in entityProperties)
|
|
{
|
|
//判断是否是List集合
|
|
if (propertyInfo.Name == "Details"
|
|
&& propertyInfo.PropertyType.IsGenericType
|
|
&& propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
|
|
{
|
|
var listProperty = typeof(TEntity).GetProperty("Details");
|
|
// 获取 List 的元素类型
|
|
if (listProperty != null)
|
|
{
|
|
entityDetailType = listProperty.PropertyType.GetGenericArguments()[0];
|
|
entityDetailTypeFlag = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (inputDetailDtoTypeFlag && entityDetailTypeFlag)
|
|
{
|
|
var config = new MapperConfiguration(cfg =>
|
|
{
|
|
// 动态创建映射关系
|
|
cfg.CreateMap(typeof(TEntityDto), typeof(TEntity));
|
|
cfg.CreateMap(typeof(TUpdateInput), typeof(TEntity));
|
|
cfg.CreateMap(inputDetailDtoType, entityDetailType);
|
|
});
|
|
_mapper = new Mapper(config);
|
|
}
|
|
else
|
|
{
|
|
var config = new MapperConfiguration(cfg =>
|
|
{
|
|
// 动态创建映射关系
|
|
//todo 这里先要判断ID是否是000000-000000
|
|
cfg.CreateMap(typeof(TEntityDto), typeof(TEntity));
|
|
cfg.CreateMap(typeof(TUpdateInput), typeof(TEntity))
|
|
.ForMember("Id", opt => opt.Ignore())
|
|
.ForMember("ConcurrencyStamp", opt => opt.Ignore());
|
|
});
|
|
_mapper = new Mapper(config);
|
|
}
|
|
|
|
MapProperties(input, entity);
|
|
//entity.GetType().GetProperty("Id")?.SetValue(entity,id);
|
|
await ReMoveCaCheAsync(id).ConfigureAwait(false);
|
|
await _repository.UpdateAsync(entity, true).ConfigureAwait(true);
|
|
|
|
|
|
return await MapToGetOutputDtoAsync(entity).ConfigureAwait(false);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 批量操作
|
|
|
|
/// <summary>
|
|
/// 【基础】-【批量】-【新增】
|
|
/// </summary>
|
|
/// <param name="inputList"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("Base/Create-Many")]
|
|
[Authorize]
|
|
public async Task<List<TEntityDto>> CreateManyAsync(List<TCreateInput> inputList)
|
|
{
|
|
var dtoList = new List<TEntityDto>();
|
|
|
|
foreach (var input in inputList)
|
|
{
|
|
dtoList.Add(await CreateAsync(input).ConfigureAwait(false));
|
|
}
|
|
|
|
return dtoList;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 【基础】-【批量】-【删除】
|
|
/// </summary>
|
|
/// <param name="keyList"></param>
|
|
/// <returns></returns>
|
|
[HttpDelete("Base/Delete-Many")]
|
|
[Authorize]
|
|
public async Task DeleteAsync(IEnumerable<TKey> keyList)
|
|
{
|
|
await _repository.DeleteManyAsync(keyList.AsEnumerable(), true).ConfigureAwait(false);
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// 【基础】-【分页查询】【有筛选条件】
|
|
/// </summary>
|
|
/// <param name="sfsRequestInputBase"></param>
|
|
/// <param name="includeDetails"></param>
|
|
/// <param name="cancellationToken"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("Base/Get-List-Page-By-Filter")]
|
|
[Authorize]
|
|
public virtual async Task<PagedResultDto<TEntityDto>> GetPageListByFilterAsync(
|
|
SfsRequestInputBase sfsRequestInputBase,
|
|
bool includeDetails = false, CancellationToken cancellationToken = default)
|
|
{
|
|
await CheckGetListPolicyAsync();
|
|
|
|
var expression = sfsRequestInputBase.Condition.Filters?.Count > 0
|
|
? sfsRequestInputBase.Condition.Filters.ToLambda<TEntity>()
|
|
: p => true;
|
|
|
|
var resultEntities = await GetQueryListAsync(expression, sfsRequestInputBase.SkipCount,
|
|
sfsRequestInputBase.MaxResultCount,
|
|
sfsRequestInputBase.Sorting, includeDetails, cancellationToken);
|
|
|
|
var resultDtos = ObjectMapper.Map<List<TEntity>, List<TEntityDto>>(resultEntities);
|
|
|
|
//获取总数
|
|
var totalCount = await GetCountAsync(expression, cancellationToken);
|
|
|
|
return new PagedResultDto<TEntityDto>(totalCount, resultDtos);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 【基础】-【获取所有数据】
|
|
/// </summary>
|
|
/// <param name="sfsRequestInputBase"></param>
|
|
/// <param name="includeDetails"></param>
|
|
/// <param name="cancellationToken"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("Base/Get-All-List")]
|
|
[Authorize]
|
|
public virtual async Task<List<TEntityDto>> GetAllListAsync()
|
|
{
|
|
await CheckGetListPolicyAsync();
|
|
|
|
var entities = await _repository.GetListAsync();
|
|
|
|
return await MapToGetListOutputDtosAsync(entities);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 【基础】-【导出Excel】【有筛选条件】
|
|
/// </summary>
|
|
/// <param name="sfsRequestInputBase">查询条件</param>
|
|
/// <param name="isRedundance">是否冗余主表数据</param>
|
|
/// <param name="isDetailExport">是否导出子表</param>
|
|
/// <param name="userId">用户ID</param>
|
|
/// <returns></returns>
|
|
[HttpPost("Base/Export-To-Excel")]
|
|
[Authorize]
|
|
public virtual async Task<IActionResult> ExportToExcelAsync(SfsRequestInputBase sfsRequestInputBase,
|
|
bool isRedundance, Guid userId, bool isDetailExport = true)
|
|
{
|
|
var isHasDetail = false; //是否包含从表
|
|
|
|
var data = (await GetPageListByFilterAsync(sfsRequestInputBase, true)).Items;
|
|
|
|
var fileStream = new MemoryStream(); //文件流
|
|
IWorkbook workbook = new XSSFWorkbook();
|
|
var sheet = workbook.CreateSheet(Localizer[typeof(TEntity).Name]);
|
|
var splitDetailsColumnNumber = 1; //分割主表和从表的列数量
|
|
var excelDetailsCellStyle = SetExcelDetailsCellStyle(workbook); //子表单元格样式
|
|
var excelSplitCellStyle = SetSplitCellStyle(workbook); //分割单元格样式
|
|
var excelOnlyMainCellStyle = SetExcelOnlyMainCellStyle(workbook);
|
|
var excelHeadCellStyle = SetExcelHeadCellStyle(workbook);
|
|
|
|
// 获取主表的属性 创建主表 表头
|
|
var mainAllProperties = typeof(TEntityDto).GetProperties();
|
|
var mainProperties = mainAllProperties.Where(p => p.Name != "Details").ToArray(); //去除details属性否则导出时会带出来
|
|
|
|
#region 用户个性导出 主表
|
|
|
|
//获取个性导出的字段
|
|
var mainUserColumn =
|
|
await ExportCustomUserSettingAppService.GetByUserIdAndExportTableNameAsync(userId, typeof(TEntity).Name);
|
|
|
|
if (mainUserColumn.Any(p => p.CustomUserSetting == Enum_ExportCustomUserSetting.Yes))
|
|
{
|
|
var showUserColumn = mainUserColumn.Where(p => p.CustomUserSetting == Enum_ExportCustomUserSetting.Yes)
|
|
.Select(p => p.ExportColumnName?.ToLower()).Aggregate((a, b) => a + " " + b)?.Split(' ').ToList();
|
|
|
|
mainProperties = mainProperties.Where(p => showUserColumn.Contains(p.Name.ToLower())).ToArray();
|
|
}
|
|
|
|
#endregion
|
|
|
|
var headerRow = sheet.CreateRow(0); //标头列
|
|
for (var i = 0; i < mainProperties.Length; i++)
|
|
{
|
|
var englishName = mainProperties[i].Name;
|
|
//本地化
|
|
var localizerName = Localizer[typeof(TEntity).Name + englishName];
|
|
var headCell = headerRow.CreateCell(i);
|
|
headCell.SetCellValue(localizerName);
|
|
headCell.CellStyle = excelHeadCellStyle;
|
|
}
|
|
|
|
// 获取从表的属性 创建从表 表头
|
|
var detailProperties = typeof(TEntityDto).GetProperty("Details")?.PropertyType.GetGenericArguments()[0]
|
|
.GetProperties();
|
|
|
|
if (detailProperties != null)
|
|
{
|
|
isHasDetail = true;
|
|
if (!isDetailExport) //是否要导出子表
|
|
{
|
|
isHasDetail = false;
|
|
}
|
|
|
|
if (isHasDetail)
|
|
{
|
|
headerRow.CreateCell(mainProperties.Length).SetCellValue("---【分割】---");
|
|
|
|
#region 用户个性导出 从表
|
|
|
|
//获取个性导出的字段
|
|
var detailDtoName = mainAllProperties.First(p => p.Name == "Details");
|
|
var detailUserColumn = await ExportCustomUserSettingAppService.GetByUserIdAndExportTableNameAsync(
|
|
userId, detailDtoName.PropertyType.GenericTypeArguments.First().Name.Replace("Dto", ""));
|
|
var detailNotShowUserColumn = detailUserColumn
|
|
.Where(p => p.CustomUserSetting == Enum_ExportCustomUserSetting.No).Select(p => p.ExportColumnName)
|
|
.ToList();
|
|
if (detailUserColumn.Any())
|
|
{
|
|
detailProperties = detailProperties.Where(p => !detailNotShowUserColumn.Contains(p.Name)).ToArray();
|
|
}
|
|
|
|
#endregion
|
|
|
|
for (var i = 0; i < detailProperties.Length; i++)
|
|
{
|
|
headerRow.CreateCell(mainProperties.Length + splitDetailsColumnNumber + i)
|
|
.SetCellValue(detailProperties[i].Name);
|
|
var headCell = headerRow.GetCell(mainProperties.Length + splitDetailsColumnNumber + i);
|
|
headCell.CellStyle = excelHeadCellStyle;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 填充数据行
|
|
var rowIndex = 1;
|
|
foreach (var mainDto in data)
|
|
{
|
|
if (isHasDetail)
|
|
{
|
|
// 获取从表数据
|
|
var detailsIndex = mainAllProperties.FindIndex(p => p.Name == "Details");
|
|
// 子表
|
|
var detailList = (IEnumerable<object>)mainAllProperties[detailsIndex].GetValue(mainDto);
|
|
var startMainRowIndex = rowIndex;
|
|
for (var datailCount = 0; datailCount < detailList.Count(); datailCount++)
|
|
{
|
|
var dataRow = sheet.CreateRow(rowIndex);
|
|
|
|
if (isRedundance)
|
|
{
|
|
// 填充主表数据
|
|
for (var i = 0; i < mainProperties.Length; i++)
|
|
{
|
|
var value = mainProperties[i].GetValue(mainDto);
|
|
dataRow.CreateCell(i).SetCellValue(value?.ToString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (datailCount == 0)
|
|
{
|
|
// 填充主表数据
|
|
for (var i = 0; i < mainProperties.Length; i++)
|
|
{
|
|
var value = mainProperties[i].GetValue(mainDto);
|
|
dataRow.CreateCell(i).SetCellValue(value?.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
rowIndex++;
|
|
}
|
|
|
|
var overMainRowIndex = rowIndex;
|
|
foreach (var detail in detailList)
|
|
{
|
|
if (startMainRowIndex <= overMainRowIndex)
|
|
{
|
|
//填充子表数据
|
|
var detailRow = sheet.GetRow(startMainRowIndex);
|
|
|
|
var splitCell = detailRow.CreateCell(mainProperties.Length);
|
|
splitCell.CellStyle = excelSplitCellStyle;
|
|
|
|
for (var i = 0; i < detailProperties.Length; i++)
|
|
{
|
|
var value = detailProperties[i].GetValue(detail);
|
|
detailRow.CreateCell(mainProperties.Length + splitDetailsColumnNumber + i)
|
|
.SetCellValue(value?.ToString());
|
|
var detailCell = detailRow.GetCell(mainProperties.Length + splitDetailsColumnNumber + i);
|
|
detailCell.CellStyle = excelDetailsCellStyle;
|
|
}
|
|
}
|
|
|
|
startMainRowIndex++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var dataRow = sheet.CreateRow(rowIndex);
|
|
// 填充主表数据
|
|
for (var i = 0; i < mainProperties.Length; i++)
|
|
{
|
|
var value = mainProperties[i].GetValue(mainDto);
|
|
dataRow.CreateCell(i).SetCellValue(value?.ToString());
|
|
}
|
|
|
|
if (rowIndex % 2 == 0)
|
|
{
|
|
dataRow.RowStyle = excelOnlyMainCellStyle;
|
|
}
|
|
}
|
|
|
|
//添加1个空行将2条数据分割开
|
|
rowIndex++;
|
|
}
|
|
|
|
#region 自动调整列宽
|
|
|
|
// 自动调整列宽 注意:这个影响性能 会遍历所有行 并且找出宽度最大值
|
|
//sheet.AutoSizeColumn(i);
|
|
if (isHasDetail)
|
|
{
|
|
for (var i = 0; i < mainProperties.Length + splitDetailsColumnNumber + detailProperties.Length; i++)
|
|
{
|
|
var colWidth = Math.Max(sheet.GetColumnWidth(i) + 150, 265 * 15);
|
|
if (colWidth > 255 * 256) //excel列有最大宽度限制
|
|
{
|
|
colWidth = 6000;
|
|
}
|
|
|
|
sheet.SetColumnWidth(i, colWidth);
|
|
sheet.SetColumnWidth(mainProperties.Length, 3600);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (var i = 0; i < mainProperties.Length; i++)
|
|
{
|
|
var colWidth = Math.Max(sheet.GetColumnWidth(i) + 150, 265 * 15);
|
|
if (colWidth > 255 * 256) //excel列有最大宽度限制
|
|
{
|
|
colWidth = 6000;
|
|
}
|
|
|
|
sheet.SetColumnWidth(i, colWidth);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
// 保存Excel文件到MemoryStream
|
|
workbook.Write(fileStream, true);
|
|
fileStream.Position = 0;
|
|
|
|
// 创建FileContentResult返回Excel文件
|
|
var fileContentResult = new FileContentResult(fileStream.ToArray(),
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
|
{
|
|
FileDownloadName = Localizer[typeof(TEntity).Name] + ".xlsx"
|
|
};
|
|
|
|
await Task.CompletedTask;
|
|
|
|
return fileContentResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 【基础】-【获取 增 改 查基础的Dto中属性的数据类型】
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpPost("Base/Get-Dto-Column-Type")]
|
|
[Authorize]
|
|
public virtual async Task<List<AllTableColumnTypeDto>> GetDtoColumnTypeAsync()
|
|
{
|
|
var tableColumnTypeDtos = new List<AllTableColumnTypeDto>
|
|
{
|
|
GetTableColumnTypeByTable(typeof(TEntity), "S"),
|
|
GetTableColumnTypeByTable(typeof(TCreateInput), "C"),
|
|
GetTableColumnTypeByTable(typeof(TUpdateInput), "U"),
|
|
GetTableColumnTypeByTable(typeof(TEntity), "G")
|
|
};
|
|
|
|
await Task.CompletedTask;
|
|
return tableColumnTypeDtos;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 【基础】-【获取数据】-【缓存中读取】
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpPost("Base/Get-Cache-By-Id/{id}")]
|
|
[Authorize]
|
|
public virtual async Task<TEntityDto> GetCacheByIdAsync(TKey id)
|
|
{
|
|
var entity = await Cache.GetOrAddAsync(
|
|
$"{typeof(TEntityDto).Name}:{id}".ToString(),
|
|
async () => await GetEntityByIdAsync(id), GetCacheTime);
|
|
|
|
var dto = ObjectMapper.Map<TEntity, TEntityDto>(entity!);
|
|
return dto;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 【基础】-【获取数据】
|
|
/// </summary>
|
|
/// <param name="id"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("Base/Get-By-Id/{id}")]
|
|
[Authorize]
|
|
public override Task<TEntityDto> GetAsync(TKey id)
|
|
{
|
|
return base.GetAsync(id);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 【基础】-【获取数据】
|
|
/// </summary>
|
|
/// <param name="input"></param>
|
|
/// <returns></returns>
|
|
[HttpPost("Base/Get-List")]
|
|
[Authorize]
|
|
public override Task<PagedResultDto<TEntityDto>> GetListAsync(TPagedAndSortedResultRequestDto input)
|
|
{
|
|
return base.GetListAsync(input);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 私有处理
|
|
|
|
/// <summary>
|
|
/// 清除缓存
|
|
/// </summary>
|
|
/// <param name="id"></param>
|
|
/// <returns></returns>
|
|
protected async Task ReMoveCaCheAsync(TKey id)
|
|
{
|
|
await Cache.RemoveAsync(id?.ToString());
|
|
}
|
|
|
|
/// <summary>
|
|
/// 按表达式条件获取分页列表
|
|
/// </summary>
|
|
/// <param name="expression"></param>
|
|
/// <param name="skipCount"></param>
|
|
/// <param name="maxResultCount"></param>
|
|
/// <param name="sorting"></param>
|
|
/// <param name="includeDetails"></param>
|
|
/// <param name="cancellationToken"></param>
|
|
/// <returns></returns>
|
|
private async Task<List<TEntity>> GetQueryListAsync(Expression<Func<TEntity, bool>> expression,
|
|
int skipCount, int maxResultCount, string sorting,
|
|
bool includeDetails = false, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = await Repository.WithDetailsAsync();
|
|
//var query = await Repository.GetQueryableAsync();
|
|
|
|
var entities = query.Where(expression);
|
|
entities = GetSortingQueryable(entities, sorting);
|
|
var str = entities.ToQueryString();
|
|
|
|
Console.WriteLine("---------查询开始---------");
|
|
Console.WriteLine();
|
|
Console.WriteLine(str);
|
|
Console.WriteLine();
|
|
Console.WriteLine("---------查询结束---------");
|
|
|
|
var result = entities.Skip(skipCount).Take(maxResultCount).ToList();
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置排序
|
|
/// </summary>
|
|
/// <param name="entities"></param>
|
|
/// <param name="sorting"></param>
|
|
/// <returns></returns>
|
|
private IQueryable<TEntity> GetSortingQueryable(IQueryable<TEntity> entities, string sorting)
|
|
{
|
|
if (string.IsNullOrEmpty(sorting))
|
|
{
|
|
var createTimePropertyInfo = typeof(TEntity).GetProperty(nameof(AuditedEntity.CreationTime));
|
|
if (createTimePropertyInfo != null)
|
|
{
|
|
entities = entities.OrderBy(nameof(AuditedEntity.CreationTime) + " DESC");
|
|
}
|
|
else
|
|
{
|
|
entities = entities.OrderBy("Id DESC");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
entities = entities.OrderBy(sorting);
|
|
}
|
|
|
|
return entities;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取Dto的属性名字和数据类型
|
|
/// </summary>
|
|
/// <param name="dtoType"></param>
|
|
/// <param name="strDtoType"></param>
|
|
/// <returns></returns>
|
|
private AllTableColumnTypeDto GetTableColumnTypeByTable(Type dtoType, string strDtoType)
|
|
{
|
|
var gDto = new AllTableColumnTypeDto
|
|
{
|
|
DtoType = strDtoType,
|
|
DtoName = dtoType.FullName,
|
|
ColumnsTypes = new List<ColumnType>()
|
|
};
|
|
var propertyInfos = dtoType.GetProperties();
|
|
foreach (var propertyInfo in propertyInfos)
|
|
{
|
|
var columnType = new ColumnType();
|
|
columnType.IsEnum = false;
|
|
if (propertyInfo.PropertyType.GenericTypeArguments.Length > 0)
|
|
{
|
|
if (propertyInfo.PropertyType.GenericTypeArguments[0].IsEnum)
|
|
{
|
|
columnType.IsEnum = true;
|
|
}
|
|
|
|
columnType.Z_ColumnBaseType = propertyInfo.PropertyType.GenericTypeArguments[0].FullName!;
|
|
}
|
|
else
|
|
{
|
|
columnType.Z_ColumnBaseType = propertyInfo.PropertyType.FullName!;
|
|
}
|
|
|
|
columnType.Z_ColumnName = propertyInfo.Name;
|
|
columnType.Z_ColumnType = propertyInfo.PropertyType.Name;
|
|
|
|
|
|
gDto.ColumnsTypes.Add(columnType);
|
|
}
|
|
|
|
return gDto;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 【记录数量查询】【有筛选条件】
|
|
/// </summary>
|
|
/// <param name="expression"></param>
|
|
/// <param name="cancellationToken"></param>
|
|
/// <returns></returns>
|
|
private async Task<long> GetCountAsync(Expression<Func<TEntity, bool>> expression,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var count = await _repository.LongCountAsync(expression, cancellationToken);
|
|
|
|
return count;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取缓存redis时间
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private static DistributedCacheEntryOptions GetCacheTime()
|
|
{
|
|
var random = new Random();
|
|
//解决雪崩 添加随机缓存时间
|
|
var time = CacheMinute + random.Next(10, 30);
|
|
return new DistributedCacheEntryOptions
|
|
{
|
|
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(time)
|
|
};
|
|
}
|
|
|
|
|
|
#region Excel导出的样式设置
|
|
|
|
/// <summary>
|
|
/// 导出设置子表单元格样式
|
|
/// </summary>
|
|
/// <param name="workbook"></param>
|
|
/// <returns></returns>
|
|
private static ICellStyle SetExcelDetailsCellStyle(IWorkbook workbook)
|
|
{
|
|
var cellStyle = workbook.CreateCellStyle();
|
|
cellStyle.FillBackgroundColor = IndexedColors.Grey25Percent.Index;
|
|
cellStyle.FillForegroundColor = IndexedColors.Grey25Percent.Index;
|
|
cellStyle.FillPattern = FillPattern.SolidForeground;
|
|
return cellStyle;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 导出设置只有主表时的交替行 单元格样式
|
|
/// </summary>
|
|
/// <param name="workbook"></param>
|
|
/// <returns></returns>
|
|
private static ICellStyle SetExcelOnlyMainCellStyle(IWorkbook workbook)
|
|
{
|
|
var cellStyle = workbook.CreateCellStyle();
|
|
cellStyle.FillBackgroundColor = IndexedColors.Grey25Percent.Index;
|
|
cellStyle.FillForegroundColor = IndexedColors.Grey25Percent.Index;
|
|
cellStyle.FillPattern = FillPattern.SolidForeground;
|
|
return cellStyle;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置分割单元格的样式
|
|
/// </summary>
|
|
/// <param name="workbook"></param>
|
|
/// <returns></returns>
|
|
private static ICellStyle SetSplitCellStyle(IWorkbook workbook)
|
|
{
|
|
var cellStyle = workbook.CreateCellStyle();
|
|
cellStyle.BorderLeft = BorderStyle.MediumDashed;
|
|
cellStyle.BorderRight = BorderStyle.MediumDashed;
|
|
cellStyle.LeftBorderColor = IndexedColors.BrightGreen.Index;
|
|
cellStyle.RightBorderColor = IndexedColors.Grey25Percent.Index;
|
|
cellStyle.FillBackgroundColor = IndexedColors.White.Index;
|
|
cellStyle.FillForegroundColor = IndexedColors.White.Index;
|
|
cellStyle.FillPattern = FillPattern.ThickVerticalBands;
|
|
return cellStyle;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 导出设置表头单元格样式
|
|
/// </summary>
|
|
/// <param name="workbook"></param>
|
|
/// <returns></returns>
|
|
private static ICellStyle SetExcelHeadCellStyle(IWorkbook workbook)
|
|
{
|
|
var cellStyle = workbook.CreateCellStyle();
|
|
cellStyle.FillBackgroundColor = IndexedColors.LightOrange.Index;
|
|
cellStyle.FillForegroundColor = IndexedColors.LightOrange.Index;
|
|
cellStyle.FillPattern = FillPattern.SolidForeground;
|
|
return cellStyle;
|
|
}
|
|
|
|
public static void MapProperties<TSrc, TDest>(TSrc source, TDest destination)
|
|
{
|
|
if (source == null || destination == null)
|
|
{
|
|
throw new ArgumentNullException("Source and destination objects must not be null.");
|
|
}
|
|
|
|
var sourceType = typeof(TSrc);
|
|
var destType = typeof(TDest);
|
|
|
|
var sourceProperties = sourceType.GetProperties();
|
|
var destProperties = destType.GetProperties();
|
|
|
|
foreach (var sourceProperty in sourceProperties)
|
|
{
|
|
var destProperty = Array.Find(destProperties,
|
|
p => p.Name == sourceProperty.Name && p.PropertyType == sourceProperty.PropertyType);
|
|
|
|
if (destProperty != null && destProperty.CanWrite && destProperty.Name != "Id" &&
|
|
destProperty.Name != "ConcurrencyStamp")
|
|
{
|
|
var value = sourceProperty.GetValue(source);
|
|
destProperty.SetValue(destination, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|