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; /// /// 证书管理服务 /// public class CertificateService : BaseService, ITransient { private readonly ISqlSugarRepository _repository; private readonly ISqlSugarRepository _eventCertRepository; private readonly IIdGenerator _idGenerator; private readonly FileService _fileService; private readonly IHttpClientFactory _httpClientFactory; public CertificateService(ISqlSugarRepository repository, ISqlSugarRepository eventCertRepository, IIdGenerator idGenerator, FileService fileService, IHttpClientFactory httpClientFactory) : base(repository) { _repository = repository; _eventCertRepository = eventCertRepository; _idGenerator = idGenerator; _fileService = fileService; _httpClientFactory = httpClientFactory; } /// /// 证书分页查询 /// [DisplayName("证书分页查询")] [HttpGet] public async Task> 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); } /// /// 添加证书 /// [DisplayName("添加证书")] [HttpPost("add")] public async Task Add(AddCertificateInput input) { var entity = input.Adapt(); entity.Id = _idGenerator.NextId(); await _repository.InsertAsync(entity); } /// /// 更新证书 /// [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); } /// /// 删除证书 /// [DisplayName("删除证书")] public async Task Delete(List ids) { if (ids == null || !ids.Any()) return; await _repository.DeleteAsync(x => ids.Contains(x.Id)); } /// /// 获取证书详情 /// [DisplayName("获取证书详情")] [HttpGet("detail")] public async Task Detail([FromQuery] long id) { return await _repository.GetByIdAsync(id); } /// /// 上传证书模板并解析 /// [DisplayName("上传证书模板")] [HttpPost("template/upload")] public async Task 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() }; } /// /// 生成证书预览 /// [DisplayName("生成证书预览")] [HttpPost("generate/preview")] public async Task 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" }; } /// /// 批量生成证书 /// [DisplayName("批量生成证书")] [HttpPost("generate/batch")] public async Task 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(); var eventCerts = new List(); 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 data, string key) { return data.ContainsKey(key) ? data[key]?.ToString() : null; } private long GetLong(Dictionary data, string key) { if (data.ContainsKey(key) && long.TryParse(data[key]?.ToString(), out long result)) { return result; } return 0; } }