Files
QYZH.InteractiveMagazine/QYZH.InteractiveMagazine.WorkService/Consumers/UserJournalQrCodeGenerateConsumer.cs
glz 5700da58d9 feat: 新增期刊二维码批量生成功能及相关配套
1. 新增UserJournalQrCodeGenerateConsumer消费者处理二维码生成队列任务
2. 新增用户期刊状态枚举的生成中、失败状态
3. 新增批量生成二维码服务方法和相关DTO
4. 优化SqlSugar自动填充创建/更新人字段逻辑
5. 调整接口参数从操作人ID改为操作人名称
6. 新增获取未绑定二维码的API接口和服务方法
2026-07-02 09:46:34 +08:00

130 lines
5.4 KiB
C#
Raw Permalink 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 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;
/// <summary>
/// 期刊二维码生成消费者
/// </summary>
public class UserJournalQrCodeGenerateConsumer(
ILogger<UserJournalQrCodeGenerateConsumer> 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<GenerateUserJournalQrCodeMessage>(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<ISqlSugarClient>();
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<GenerateUserJournalQrCodeMessage>(Encoding.UTF8.GetString(message), new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
if (data?.RecordIds.Count > 0)
{
using var scope = scopeFactory.CreateScope();
var client = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>();
var operatorName = string.IsNullOrWhiteSpace(data.OperatorName) ? "System" : data.OperatorName;
await client.Updateable<UserJournal>()
.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<UserJournal>()
.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<UserJournal>()
.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<UserJournal>()
.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 });
}
}