using FoodLabeling.Application.Helpers;
using FoodLabeling.Application.Contracts.Dtos.Common;
using FoodLabeling.Application.Contracts.Dtos.Partner;
using FoodLabeling.Application.Contracts.IServices;
using FoodLabeling.Application.Services.DbModels;
using Microsoft.AspNetCore.Mvc;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using SqlSugar;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Guids;
using Volo.Abp.Uow;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace FoodLabeling.Application.Services;
///
/// 合作伙伴管理(fl_partner)
///
public class PartnerAppService : ApplicationService, IPartnerAppService
{
private const int ExportPdfMaxRows = 5000;
private readonly ISqlSugarDbContext _dbContext;
private readonly IGuidGenerator _guidGenerator;
public PartnerAppService(ISqlSugarDbContext dbContext, IGuidGenerator guidGenerator)
{
_dbContext = dbContext;
_guidGenerator = guidGenerator;
}
///
public async Task> GetListAsync(PartnerGetListInputVo input)
{
RefAsync total = 0;
var query = BuildPartnerListQuery(input);
var entities = await query.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
var items = entities.Select(MapListItem).ToList();
return BuildPagedResult(input.SkipCount, input.MaxResultCount, total, items);
}
///
public async Task GetAsync(string id)
{
var partnerId = id?.Trim();
if (string.IsNullOrWhiteSpace(partnerId))
{
throw new UserFriendlyException("合作伙伴Id不能为空");
}
var entity = await _dbContext.SqlSugarClient.Queryable()
.FirstAsync(x => !x.IsDeleted && x.Id == partnerId);
if (entity is null)
{
throw new UserFriendlyException("合作伙伴不存在");
}
return MapDetail(entity);
}
///
[UnitOfWork]
public async Task CreateAsync(PartnerCreateInputVo input)
{
var name = input.PartnerName?.Trim();
if (string.IsNullOrWhiteSpace(name))
{
throw new UserFriendlyException("合作伙伴名称不能为空");
}
var email = input.ContactEmail?.Trim();
if (!string.IsNullOrWhiteSpace(email) && !IsPlausibleEmail(email))
{
throw new UserFriendlyException("联系邮箱格式不正确");
}
var now = Clock.Now;
var entity = new FlPartnerDbEntity
{
Id = _guidGenerator.Create().ToString(),
IsDeleted = false,
PartnerName = name,
ContactEmail = string.IsNullOrWhiteSpace(email) ? null : email,
PhoneNumber = string.IsNullOrWhiteSpace(input.PhoneNumber) ? null : input.PhoneNumber.Trim(),
State = input.State,
CreationTime = now,
CreatorId = CurrentUser?.Id?.ToString(),
LastModificationTime = now,
LastModifierId = CurrentUser?.Id?.ToString()
};
await _dbContext.SqlSugarClient.Insertable(entity).ExecuteCommandAsync();
return await GetAsync(entity.Id);
}
///
[UnitOfWork]
public async Task UpdateAsync(string id, PartnerUpdateInputVo input)
{
var partnerId = id?.Trim();
if (string.IsNullOrWhiteSpace(partnerId))
{
throw new UserFriendlyException("合作伙伴Id不能为空");
}
var entity = await _dbContext.SqlSugarClient.Queryable()
.FirstAsync(x => !x.IsDeleted && x.Id == partnerId);
if (entity is null)
{
throw new UserFriendlyException("合作伙伴不存在");
}
var name = input.PartnerName?.Trim();
if (string.IsNullOrWhiteSpace(name))
{
throw new UserFriendlyException("合作伙伴名称不能为空");
}
var email = input.ContactEmail?.Trim();
if (!string.IsNullOrWhiteSpace(email) && !IsPlausibleEmail(email))
{
throw new UserFriendlyException("联系邮箱格式不正确");
}
entity.PartnerName = name;
entity.ContactEmail = string.IsNullOrWhiteSpace(email) ? null : email;
entity.PhoneNumber = string.IsNullOrWhiteSpace(input.PhoneNumber) ? null : input.PhoneNumber.Trim();
entity.State = input.State;
entity.LastModificationTime = Clock.Now;
entity.LastModifierId = CurrentUser?.Id?.ToString();
await _dbContext.SqlSugarClient.Updateable(entity).ExecuteCommandAsync();
return await GetAsync(partnerId);
}
///
[UnitOfWork]
public async Task DeleteAsync(string id)
{
var partnerId = id?.Trim();
if (string.IsNullOrWhiteSpace(partnerId))
{
throw new UserFriendlyException("合作伙伴Id不能为空");
}
var entity = await _dbContext.SqlSugarClient.Queryable()
.FirstAsync(x => !x.IsDeleted && x.Id == partnerId);
if (entity is null)
{
throw new UserFriendlyException("合作伙伴不存在");
}
entity.IsDeleted = true;
entity.LastModificationTime = Clock.Now;
entity.LastModifierId = CurrentUser?.Id?.ToString();
await _dbContext.SqlSugarClient.Updateable(entity).ExecuteCommandAsync();
}
///
public async Task ExportPdfAsync(PartnerGetListInputVo input)
{
QuestPDF.Settings.License = LicenseType.Community;
var count = await BuildPartnerListQuery(input).CountAsync();
var query = BuildPartnerListQuery(input);
if (count > ExportPdfMaxRows)
{
throw new UserFriendlyException($"导出数据超过上限 {ExportPdfMaxRows} 条,请缩小筛选范围");
}
var rows = await query.Take(ExportPdfMaxRows).ToListAsync();
var fileName = $"companies_{Clock.Now:yyyy-MM-dd_HH-mm-ss}.pdf";
var document = Document.Create(container =>
{
container.Page(page =>
{
page.Margin(28);
page.DefaultTextStyle(x => x.FontSize(10));
page.Header().Text("Companies").SemiBold().FontSize(18);
page.Content().PaddingTop(12).Table(table =>
{
table.ColumnsDefinition(c =>
{
c.RelativeColumn(2.2f);
c.RelativeColumn(2.4f);
c.RelativeColumn(1.8f);
c.RelativeColumn(1f);
c.RelativeColumn(1.6f);
});
static IContainer CellHeader(IContainer c) =>
c.Background(Colors.Grey.Lighten3).Padding(6).DefaultTextStyle(x => x.SemiBold());
table.Cell().Element(CellHeader).Text("Company");
table.Cell().Element(CellHeader).Text("Contact");
table.Cell().Element(CellHeader).Text("Phone");
table.Cell().Element(CellHeader).Text("Status");
table.Cell().Element(CellHeader).Text("Created");
foreach (var e in rows)
{
var status = e.State ? "active" : "inactive";
table.Cell().BorderBottom(0.5f).BorderColor(Colors.Grey.Lighten2).Padding(5)
.Text(e.PartnerName ?? string.Empty);
table.Cell().BorderBottom(0.5f).BorderColor(Colors.Grey.Lighten2).Padding(5)
.Text(string.IsNullOrWhiteSpace(e.ContactEmail) ? "无" : e.ContactEmail!);
table.Cell().BorderBottom(0.5f).BorderColor(Colors.Grey.Lighten2).Padding(5)
.Text(string.IsNullOrWhiteSpace(e.PhoneNumber) ? "无" : e.PhoneNumber!);
table.Cell().BorderBottom(0.5f).BorderColor(Colors.Grey.Lighten2).Padding(5).Text(status);
table.Cell().BorderBottom(0.5f).BorderColor(Colors.Grey.Lighten2).Padding(5)
.Text(e.CreationTime.ToString("yyyy-MM-dd HH:mm"));
}
});
});
});
var stream = new MemoryStream();
document.GeneratePdf(stream);
stream.Position = 0;
return new FileStreamResult(stream, "application/pdf") { FileDownloadName = fileName };
}
private ISugarQueryable BuildPartnerListQuery(PartnerGetListInputVo input)
{
var keyword = input.Keyword?.Trim();
var query = _dbContext.SqlSugarClient.Queryable()
.Where(x => !x.IsDeleted)
.WhereIF(input.State != null, x => x.State == input.State)
.WhereIF(!string.IsNullOrWhiteSpace(keyword),
x => x.PartnerName.Contains(keyword!) ||
(x.ContactEmail != null && x.ContactEmail.Contains(keyword!)) ||
(x.PhoneNumber != null && x.PhoneNumber.Contains(keyword!)));
if (!string.IsNullOrWhiteSpace(input.Sorting))
{
var sorting = input.Sorting.Trim();
if (sorting.Equals("PartnerName desc", StringComparison.OrdinalIgnoreCase))
{
query = query.OrderByDescending(x => x.PartnerName);
}
else if (sorting.Equals("PartnerName asc", StringComparison.OrdinalIgnoreCase))
{
query = query.OrderBy(x => x.PartnerName);
}
else if (sorting.Equals("CreationTime desc", StringComparison.OrdinalIgnoreCase))
{
query = query.OrderByDescending(x => x.CreationTime);
}
else if (sorting.Equals("CreationTime asc", StringComparison.OrdinalIgnoreCase))
{
query = query.OrderBy(x => x.CreationTime);
}
else if (sorting.Equals("State desc", StringComparison.OrdinalIgnoreCase))
{
query = query.OrderByDescending(x => x.State);
}
else if (sorting.Equals("State asc", StringComparison.OrdinalIgnoreCase))
{
query = query.OrderBy(x => x.State);
}
else
{
query = query.OrderByDescending(x => x.CreationTime);
}
}
else
{
query = query.OrderByDescending(x => x.CreationTime);
}
return query;
}
private static PartnerGetListOutputDto MapListItem(FlPartnerDbEntity x) => new()
{
Id = x.Id,
PartnerName = x.PartnerName,
ContactEmail = x.ContactEmail,
PhoneNumber = x.PhoneNumber,
State = x.State,
CreationTime = x.CreationTime
};
private static PartnerGetOutputDto MapDetail(FlPartnerDbEntity x) => new()
{
Id = x.Id,
PartnerName = x.PartnerName,
ContactEmail = x.ContactEmail,
PhoneNumber = x.PhoneNumber,
State = x.State,
CreationTime = x.CreationTime,
LastModificationTime = x.LastModificationTime
};
private static bool IsPlausibleEmail(string email)
{
if (email.Length > 256)
{
return false;
}
var at = email.IndexOf('@');
return at > 0 && at < email.Length - 1 && email.IndexOf('@', at + 1) < 0;
}
private static PagedResultWithPageDto BuildPagedResult(int skipCount, int maxResultCount, int total,
List items)
{
var pageSize = maxResultCount <= 0 ? items.Count : maxResultCount;
var pageIndex = pageSize <= 0 ? 1 : PagedQueryConvention.PageIndexFromSkipCount(skipCount);
var totalPages = pageSize <= 0 ? 0 : (int)Math.Ceiling(total / (double)pageSize);
return new PagedResultWithPageDto
{
PageIndex = pageIndex,
PageSize = pageSize,
TotalCount = total,
TotalPages = totalPages,
Items = items
};
}
}