using QYZH.InteractiveMagazine.Common.Helpers; using QYZH.InteractiveMagazine.Infrastructure.OSS; using QYZH.InteractiveMagazine.Models.Common; using QYZH.InteractiveMagazine.Models.Dto; using QYZH.InteractiveMagazine.Models.Entity; using QYZH.InteractiveMagazine.Models.Enum; using SqlSugar; using System.Text; using System.Text.Json; namespace QYZH.InteractiveMagazine.WorkService.Consumers; /// /// 期刊二维码生成消费者 /// public class UserJournalQrCodeGenerateConsumer( ILogger logger, IServiceScopeFactory scopeFactory, OssService ossService) : IQueueConsumer { public string Exchange => "ex.journal"; public string QueueName => "mq.journal.qrcode.generate"; public string RoutingKey => "rk.journal.qrcode.generate"; public async Task HandleAsync(byte[] message, CancellationToken cancellationToken = default) { var content = Encoding.UTF8.GetString(message); logger.LogInformation("收到期刊二维码生成消息: {Message}", content); var data = JsonSerializer.Deserialize(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) ?? throw new InvalidOperationException("期刊二维码生成消息为空"); if (data.RecordIds.Count == 0) { logger.LogWarning("期刊二维码生成消息缺少记录Id"); return; } using var scope = scopeFactory.CreateScope(); var client = scope.ServiceProvider.GetRequiredService(); var operatorName = string.IsNullOrWhiteSpace(data.OperatorName) ? "System" : data.OperatorName; foreach (var recordId in data.RecordIds.Distinct()) { await GenerateQrCodeImageAsync(client, recordId, operatorName, cancellationToken); } } public async Task OnErrorAsync(byte[] message, Exception exception) { logger.LogError(exception, "处理期刊二维码生成消息失败: {Message}", Encoding.UTF8.GetString(message)); try { var data = JsonSerializer.Deserialize(Encoding.UTF8.GetString(message), new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); if (data?.RecordIds.Count > 0) { using var scope = scopeFactory.CreateScope(); var client = scope.ServiceProvider.GetRequiredService(); var operatorName = string.IsNullOrWhiteSpace(data.OperatorName) ? "System" : data.OperatorName; await client.Updateable() .SetColumns(uj => uj.Status == (int)UserJournalStatusEnum.Failed) .SetColumns(uj => uj.UpdatedBy == operatorName) .SetColumns(uj => uj.UpdatedAt == DateTime.Now) .Where(uj => data.RecordIds.Contains(uj.Id) && !uj.IsDeleted && uj.Status == (int)UserJournalStatusEnum.Generating) .ExecuteCommandAsync(); } } catch (Exception ex) { logger.LogError(ex, "标记期刊二维码生成失败状态异常"); } } private async Task GenerateQrCodeImageAsync(ISqlSugarClient client, long recordId, string operatorName, CancellationToken cancellationToken) { try { var record = await client.Queryable() .Where(uj => uj.Id == recordId && !uj.IsDeleted) .FirstAsync(cancellationToken); if (record == null || record.Status != (int)UserJournalStatusEnum.Generating) { return; } var qrCodeContent = BuildQrCodeContent(record.JournalId, record.Id); var qrCodeKey = $"journal/qrcode/{record.JournalId}/{record.Id}.png"; using var qrCodeStream = new MemoryStream(QrCodeHelper.GeneratePng(qrCodeContent)); var uploadedKey = ossService.PutObject(qrCodeKey, qrCodeStream); if (string.IsNullOrWhiteSpace(uploadedKey)) { throw new BusinessException("二维码图片上传失败", ResultCode.GLOBAL_ERROR); } await client.Updateable() .SetColumns(uj => uj.QrCodeUrl == uploadedKey) .SetColumns(uj => uj.Status == (int)UserJournalStatusEnum.Active) .SetColumns(uj => uj.UpdatedBy == operatorName) .SetColumns(uj => uj.UpdatedAt == DateTime.Now) .Where(uj => uj.Id == recordId && !uj.IsDeleted && uj.Status == (int)UserJournalStatusEnum.Generating) .ExecuteCommandAsync(cancellationToken); } catch (Exception ex) { logger.LogError(ex, "生成期刊二维码失败,RecordId: {RecordId}", recordId); await client.Updateable() .SetColumns(uj => uj.Status == (int)UserJournalStatusEnum.Failed) .SetColumns(uj => uj.UpdatedBy == operatorName) .SetColumns(uj => uj.UpdatedAt == DateTime.Now) .Where(uj => uj.Id == recordId && !uj.IsDeleted && uj.Status == (int)UserJournalStatusEnum.Generating) .ExecuteCommandAsync(cancellationToken); } } private static string BuildQrCodeContent(long journalId, long id) { return JsonSerializer.Serialize(new { JournalId = journalId, Id = id }); } }