diff --git a/YD_Event.Application/Event/EventScoreService.cs b/YD_Event.Application/Event/EventScoreService.cs index 4dd2124..2fdf453 100644 --- a/YD_Event.Application/Event/EventScoreService.cs +++ b/YD_Event.Application/Event/EventScoreService.cs @@ -1555,42 +1555,68 @@ public class EventScoreService : BaseService, ITransient /// 导出证书 /// [DisplayName("导出证书")] - [HttpGet] - public async Task ExportCertificate([FromQuery] ScoreQueryInput input) + public async Task ExportCertificate(ScoreQueryInput input) { - var list = await _certificateRepository.AsQueryable() - .LeftJoin((c, r) => c.ResultId == r.Id) - .LeftJoin((c, r, reg) => c.RegistrationId == reg.Id) - .LeftJoin((c, r, reg, ep) => c.ProjectId == ep.Id) - .LeftJoin((c, r, reg, ep, p) => ep.ProjectId == p.Id) - .Where((c, r, reg, ep, p) => c.EventId == input.EventId) - .WhereIF(input.ProjectId.HasValue, (c, r, reg, ep, p) => c.ProjectId == input.ProjectId) - .WhereIF(!string.IsNullOrWhiteSpace(input.GroupName), (c, r, reg, ep, p) => c.GroupName == input.GroupName) - .WhereIF(!string.IsNullOrWhiteSpace(input.Name), (c, r, reg, ep, p) => c.ParticipantName.Contains(input.Name)) - .Select((c, r, reg, ep, p) => new CertificateExportDto - { - CertificateNo = c.CertificateNo, - ParticipantName = c.ParticipantName, - ProjectName = p.Name, - GroupName = c.GroupName, - UnitName = reg.TeamName, - Score = r.Score, - Rank = r.Rank, - CertificateType = c.CertificateType == 1 ? "冠军证书" : - c.CertificateType == 2 ? "亚军证书" : - c.CertificateType == 3 ? "季军证书" : - c.CertificateType == 4 ? "优胜证书" : "参与证书", - IssuedTime = c.IssuedTime + var certificates = await _certificateRepository.AsQueryable() + .Where(c => c.EventId == input.EventId && !c.DeleteMark) + .WhereIF(input.ProjectId.HasValue, c => c.ProjectId == input.ProjectId.Value) + .WhereIF(!string.IsNullOrWhiteSpace(input.GroupName), c => c.GroupName == input.GroupName) + .WhereIF(!string.IsNullOrWhiteSpace(input.Name), c => c.ParticipantName.Contains(input.Name)) + .Where(c => c.CertificateStatus >= 1 && !string.IsNullOrEmpty(c.CertificateUrl)) + .Select(c => new + { + c.Id, + c.CertificateNo, + c.ParticipantName, + c.GroupName, + c.CertificateUrl, + c.CertificateType }) .ToListAsync(); - using var stream = new MemoryStream(); - await stream.SaveAsAsync(list); - var bytes = stream.ToArray(); - - return new FileContentResult(bytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") + if (!certificates.Any()) { - FileDownloadName = $"证书列表_{DateTime.Now:yyyyMMddHHmmss}.xlsx" + throw Oops.Bah("暂无已生成的证书可导出"); + } + + using var memoryStream = new MemoryStream(); + using (var archive = new System.IO.Compression.ZipArchive(memoryStream, System.IO.Compression.ZipArchiveMode.Create, true)) + { + using var httpClient = new HttpClient(); + int successCount = 0; + int failCount = 0; + + foreach (var cert in certificates) + { + try + { + var pdfBytes = await httpClient.GetByteArrayAsync(cert.CertificateUrl); + var fileName = $"{cert.ParticipantName}_{cert.GroupName}_{cert.CertificateNo}.pdf"; + fileName = string.Join("_", fileName.Split(Path.GetInvalidFileNameChars())); + + var entry = archive.CreateEntry(fileName, System.IO.Compression.CompressionLevel.Optimal); + using var entryStream = entry.Open(); + await entryStream.WriteAsync(pdfBytes); + successCount++; + } + catch (Exception ex) + { + _logger.LogWarning(ex, "导出证书失败: CertificateId={Id}, CertificateNo={CertificateNo}", + cert.Id, cert.CertificateNo); + failCount++; + } + } + + if (successCount == 0) + { + throw Oops.Bah("所有证书导出失败"); + } + } + + memoryStream.Position = 0; + return new FileContentResult(memoryStream.ToArray(), "application/zip") + { + FileDownloadName = $"证书导出_{DateTime.Now:yyyyMMddHHmmss}.zip" }; }