2026-03-02 21:09:03 +08:00

267 lines
9.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using YD_Event.Application.Certificate.Dtos;
using YD_Event.Core.Entities;
using SkiaSharp;
using QuestPDF.Fluent;
using YD_Event.Core.Certificate;
using YD_Event.Application.File;
namespace YD_Event.Application.Certificate;
/// <summary>
/// 证书管理服务
/// </summary>
public class CertificateService : BaseService<YD_Event.Core.Entities.Certificate>, ITransient
{
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Certificate> _repository;
private readonly ISqlSugarRepository<EventCertificate> _eventCertRepository;
private readonly IIdGenerator _idGenerator;
private readonly FileService _fileService;
private readonly IHttpClientFactory _httpClientFactory;
public CertificateService(ISqlSugarRepository<YD_Event.Core.Entities.Certificate> repository,
ISqlSugarRepository<EventCertificate> eventCertRepository,
IIdGenerator idGenerator,
FileService fileService,
IHttpClientFactory httpClientFactory) : base(repository)
{
_repository = repository;
_eventCertRepository = eventCertRepository;
_idGenerator = idGenerator;
_fileService = fileService;
_httpClientFactory = httpClientFactory;
}
/// <summary>
/// 证书分页查询
/// </summary>
[DisplayName("证书分页查询")]
[HttpGet]
public async Task<PageResult<CertificateListOutput>> Page([FromQuery] CertificateQueryInput input)
{
return await _repository.AsQueryable()
.WhereIF(!string.IsNullOrWhiteSpace(input.Name), x => x.Name.Contains(input.Name))
.OrderBy(x => x.Sort)
.OrderByDescending(x => x.CreatedTime)
.Select(x => new CertificateListOutput
{
Id = x.Id,
Name = x.Name,
Issuer = x.Issuer,
TemplateContent = x.TemplateContent,
TemplateType = x.TemplateType,
Sort = x.Sort,
CreatedTime = x.CreatedTime
})
.ToPagedListAsync(input);
}
/// <summary>
/// 添加证书
/// </summary>
[DisplayName("添加证书")]
[HttpPost("add")]
public async Task Add(AddCertificateInput input)
{
var entity = input.Adapt<YD_Event.Core.Entities.Certificate>();
entity.Id = _idGenerator.NextId();
await _repository.InsertAsync(entity);
}
/// <summary>
/// 更新证书
/// </summary>
[DisplayName("更新证书")]
[HttpPut("edit")]
public async Task Update(UpdateCertificateInput input)
{
var entity = await _repository.GetByIdAsync(input.Id);
if (entity == null) throw Oops.Bah("证书不存在");
input.Adapt(entity);
await _repository.UpdateAsync(entity);
}
/// <summary>
/// 删除证书
/// </summary>
[DisplayName("删除证书")]
public async Task Delete(List<long> ids)
{
if (ids == null || !ids.Any()) return;
await _repository.DeleteAsync(x => ids.Contains(x.Id));
}
/// <summary>
/// 获取证书详情
/// </summary>
[DisplayName("获取证书详情")]
[HttpGet("detail")]
public async Task<YD_Event.Core.Entities.Certificate> Detail([FromQuery] long id)
{
return await _repository.GetByIdAsync(id);
}
/// <summary>
/// 上传证书模板并解析
/// </summary>
[DisplayName("上传证书模板")]
[HttpPost("template/upload")]
public async Task<object> UploadTemplate(IFormFile file)
{
// 1. 获取图片尺寸
int width = 0;
int height = 0;
try
{
using var stream = file.OpenReadStream();
using var image = SKBitmap.Decode(stream);
if (image != null)
{
width = image.Width;
height = image.Height;
}
}
catch
{
// 忽略解析错误,可能是PDF
}
// 2. 上传文件
var uploadResult = await _fileService.Upload(file);
var url = uploadResult.FirstOrDefault()?.Url;
return new
{
Url = url,
Width = width,
Height = height,
// 这里可以添加简单的OCR或表单域识别逻辑,暂留空
DetectedPlaceholders = new List<object>()
};
}
/// <summary>
/// 生成证书预览
/// </summary>
[DisplayName("生成证书预览")]
[HttpPost("generate/preview")]
public async Task<object> GeneratePreview(GenerateCertificateInput input)
{
var certificate = await _repository.GetByIdAsync(input.CertificateId);
if (certificate == null) throw Oops.Bah("证书配置不存在");
// 下载模板图片
byte[] templateBytes;
using (var client = _httpClientFactory.CreateClient())
{
templateBytes = await client.GetByteArrayAsync(certificate.TemplateContent);
}
// 生成PDF
var document = new CertificateDocument(certificate, input.Data, templateBytes);
var pdfBytes = document.GeneratePdf();
// 这里的返回方式取决于前端需求,可以返回Base64或者上传后返回URL
// 为演示方便,返回Base64
return new
{
PdfBase64 = Convert.ToBase64String(pdfBytes),
FileName = $"{certificate.Name}_{DateTime.Now:yyyyMMddHHmmss}.pdf"
};
}
/// <summary>
/// 批量生成证书
/// </summary>
[DisplayName("批量生成证书")]
[HttpPost("generate/batch")]
public async Task<object> GenerateBatch(BatchGenerateCertificateInput input)
{
var certificate = await _repository.GetByIdAsync(input.CertificateId);
if (certificate == null) throw Oops.Bah("证书配置不存在");
// 下载模板图片 (只需一次)
byte[] templateBytes;
using (var client = _httpClientFactory.CreateClient())
{
templateBytes = await client.GetByteArrayAsync(certificate.TemplateContent);
}
// 模拟批量生成,实际应放入后台任务
var batchId = _idGenerator.NextId();
var results = new List<object>();
var eventCerts = new List<EventCertificate>();
foreach (var data in input.DataList)
{
try
{
var document = new CertificateDocument(certificate, data, templateBytes);
var pdfBytes = document.GeneratePdf();
// 生成文件名
var certNo = data.ContainsKey("CertificateNo") ? data["CertificateNo"]?.ToString() : _idGenerator.NextId().ToString();
var fileName = $"{certificate.Name}_{certNo}.pdf";
// 上传到OSS
var uploadResult = await _fileService.UploadBytes(pdfBytes, fileName);
// 准备数据库实体
var eventCert = new EventCertificate
{
Id = _idGenerator.NextId(),
CertificateNo = certNo,
CertificateUrl = uploadResult?.Url,
CertificateStatus = 1, // 已生成
GeneratedTime = DateTime.Now,
CreatedTime = DateTime.Now,
DeleteMark = false,
// 尝试从Data中获取关联信息 (约定Key)
ParticipantName = GetString(data, "ParticipantName") ?? GetString(data, "Name"),
GroupName = GetString(data, "GroupName"),
EventId = GetLong(data, "EventId"),
ProjectId = GetLong(data, "ProjectId"),
RegistrationId = GetLong(data, "RegistrationId"),
ResultId = GetLong(data, "ResultId"),
ParticipationRecordId = GetLong(data, "ParticipationRecordId"),
// 其他默认值
CertificateType = 5, // 默认为参与证书,具体逻辑可根据业务调整
AwardLevel = 0
};
eventCerts.Add(eventCert);
results.Add(new { CertificateNo = certNo, Url = uploadResult?.Url, Status = "Success" });
}
catch (Exception ex)
{
results.Add(new { Status = "Failed", Error = ex.Message });
}
}
// 批量插入数据库
if (eventCerts.Any())
{
await _eventCertRepository.InsertRangeAsync(eventCerts);
}
return new { BatchId = batchId, Results = results };
}
private string GetString(Dictionary<string, object> data, string key)
{
return data.ContainsKey(key) ? data[key]?.ToString() : null;
}
private long GetLong(Dictionary<string, object> data, string key)
{
if (data.ContainsKey(key) && long.TryParse(data[key]?.ToString(), out long result))
{
return result;
}
return 0;
}
}