feat: 新增期刊二维码批量生成功能及相关配套

1. 新增UserJournalQrCodeGenerateConsumer消费者处理二维码生成队列任务
2. 新增用户期刊状态枚举的生成中、失败状态
3. 新增批量生成二维码服务方法和相关DTO
4. 优化SqlSugar自动填充创建/更新人字段逻辑
5. 调整接口参数从操作人ID改为操作人名称
6. 新增获取未绑定二维码的API接口和服务方法
This commit is contained in:
glz
2026-07-02 09:46:34 +08:00
parent bfdfad14d8
commit 5700da58d9
9 changed files with 392 additions and 19 deletions

5
Directory.Build.props Normal file
View File

@ -0,0 +1,5 @@
<Project>
<PropertyGroup>
<NoWarn>$(NoWarn);CS0105;CS0108;CS0168;CS0169;CS0618;CS1570;CS1572;CS1573;CS1591;CS8600;CS8601;CS8602;CS8603;CS8604;CS8618;CS8625;CS8629;CS8634;CS8714;CS9113</NoWarn>
</PropertyGroup>
</Project>

View File

@ -35,9 +35,17 @@ public interface IUserJournalService : IBaseService<UserJournal>
/// 生成期刊二维码记录 /// 生成期刊二维码记录
/// </summary> /// </summary>
/// <param name="input">生成输入</param> /// <param name="input">生成输入</param>
/// <param name="operatorId">操作人Id</param> /// <param name="operatorName">操作人名称</param>
/// <returns>二维码记录</returns> /// <returns>二维码记录</returns>
Task<UserJournalQrCodeOutput> CreateQrCodeAsync(CreateUserJournalQrCodeInput input, long operatorId); Task<UserJournalQrCodeOutput> CreateQrCodeAsync(CreateUserJournalQrCodeInput input, string operatorName);
/// <summary>
/// 批量提交期刊二维码生成任务
/// </summary>
/// <param name="input">生成输入</param>
/// <param name="operatorName">操作人名称</param>
/// <returns>提交结果</returns>
Task<CreateUserJournalQrCodeOutput> CreateQrCodesAsync(CreateUserJournalQrCodeInput input, string operatorName);
/// <summary> /// <summary>
/// 分页查询期刊二维码记录 /// 分页查询期刊二维码记录
@ -53,11 +61,18 @@ public interface IUserJournalService : IBaseService<UserJournal>
/// <returns>二维码记录</returns> /// <returns>二维码记录</returns>
Task<UserJournalQrCodeOutput> GetQrCodeDetailAsync(long id); Task<UserJournalQrCodeOutput> GetQrCodeDetailAsync(long id);
/// <summary>
/// 根据期刊Id获取未绑定用户的二维码列表
/// </summary>
/// <param name="journalId">期刊Id</param>
/// <returns>未绑定二维码列表</returns>
Task<List<UserJournalQrCodeOutput>> GetUnboundQrCodesByJournalIdAsync(long journalId);
/// <summary> /// <summary>
/// 删除未绑定的期刊二维码记录 /// 删除未绑定的期刊二维码记录
/// </summary> /// </summary>
/// <param name="input">删除输入</param> /// <param name="input">删除输入</param>
/// <param name="operatorId">操作人Id</param> /// <param name="operatorName">操作人名称</param>
/// <returns>是否成功</returns> /// <returns>是否成功</returns>
Task<bool> DeleteQrCodeAsync(DeleteUserJournalQrCodeInput input, long operatorId); Task<bool> DeleteQrCodeAsync(DeleteUserJournalQrCodeInput input, string operatorName);
} }

View File

@ -117,11 +117,67 @@ public class CreateUserJournalQrCodeInput
/// </summary> /// </summary>
public long JournalId { get; set; } public long JournalId { get; set; }
/// <summary>
/// 生成数量
/// </summary>
public int Count { get; set; } = 1;
}
/// <summary>
/// 生成期刊二维码提交结果
/// </summary>
public class CreateUserJournalQrCodeOutput
{
/// <summary>
/// 期刊Id
/// </summary>
public long JournalId { get; set; }
/// <summary>
/// 请求生成数量
/// </summary>
public int RequestedCount { get; set; }
/// <summary>
/// 已提交生成数量
/// </summary>
public int AcceptedCount { get; set; }
/// <summary>
/// 二维码记录Id列表
/// </summary>
public List<long> RecordIds { get; set; } = [];
/// <summary>
/// 是否后台生成
/// </summary>
public bool IsAsync { get; set; }
/// <summary>
/// 提示信息
/// </summary>
public string Message { get; set; } = string.Empty;
} }
/// <summary> /// <summary>
/// 期刊二维码查询输入DTO /// 期刊二维码查询输入DTO
/// </summary> /// </summary>
public class GenerateUserJournalQrCodeMessage
{
/// <summary>
/// 二维码记录Id列表
/// </summary>
public List<long> RecordIds { get; set; } = [];
/// <summary>
/// 操作人名称
/// </summary>
public string OperatorName { get; set; } = string.Empty;
}
/// <summary>
/// 鏈熷垔浜岀淮鐮佹煡璇㈣緭鍏TO
/// </summary>
public class UserJournalQrCodeQueryInput : PageQueryModel public class UserJournalQrCodeQueryInput : PageQueryModel
{ {
/// <summary> /// <summary>

View File

@ -17,5 +17,17 @@ public enum UserJournalStatusEnum
/// 正常 /// 正常
/// </summary> /// </summary>
[Description("正常")] [Description("正常")]
Active = 1 Active = 1,
/// <summary>
/// 生成中
/// </summary>
[Description("生成中")]
Generating = 2,
/// <summary>
/// 生成失败
/// </summary>
[Description("生成失败")]
Failed = 3
} }

View File

@ -1,7 +1,10 @@
using QYZH.InteractiveMagazine.Models.Entity; using QYZH.InteractiveMagazine.Models.Entity;
using Microsoft.AspNetCore.Http;
using QYZH.InteractiveMagazine.Infrastructure.Context;
using SqlSugar; using SqlSugar;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using System.Security.Claims;
using Yitter.IdGenerator; using Yitter.IdGenerator;
@ -117,14 +120,18 @@ namespace QYZH.InteractiveMagazine.Repository.Core
db.Aop.DataExecuting = (oldValue, entityInfo) => db.Aop.DataExecuting = (oldValue, entityInfo) =>
{ {
var entityValue = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue)?.ToString(); var entityValue = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue)?.ToString();
var currnetUserName = ""; var currentUserName = GetCurrentUserName();
/*** inset生效 ***/ /*** inset生效 ***/
if (entityInfo.OperationType == DataFilterType.InsertByObject) if (entityInfo.OperationType == DataFilterType.InsertByObject)
{ {
if (entityInfo.PropertyName == "CreatedAt" && (string.IsNullOrWhiteSpace(entityValue) || entityValue == DateTime.MinValue.ToString())) if (entityInfo.PropertyName == "CreatedAt" && (string.IsNullOrWhiteSpace(entityValue) || entityValue == DateTime.MinValue.ToString()))
entityInfo.SetValue(DateTime.Now);//修改CreateTime字段 entityInfo.SetValue(DateTime.Now);//修改CreateTime字段
else if (entityInfo.PropertyName == "CreatedBy" && (string.IsNullOrWhiteSpace(entityValue))) else if (entityInfo.PropertyName == "CreatedBy" && ShouldSetOperatorName(entityValue, currentUserName))
entityInfo.SetValue(currnetUserName);//修改创建人字段 entityInfo.SetValue(currentUserName);//修改创建人字段
else if (entityInfo.PropertyName == "UpdatedAt" && (string.IsNullOrWhiteSpace(entityValue) || entityValue == DateTime.MinValue.ToString()))
entityInfo.SetValue(DateTime.Now);//修改UpdatedTime字段
else if (entityInfo.PropertyName == "UpdatedBy" && ShouldSetOperatorName(entityValue, currentUserName))
entityInfo.SetValue(currentUserName);//修改更新人字段
else if (entityInfo.PropertyName == "IsDeleted" && string.IsNullOrWhiteSpace(entityValue)) else if (entityInfo.PropertyName == "IsDeleted" && string.IsNullOrWhiteSpace(entityValue))
entityInfo.SetValue("0");//修改CreateTime字段 entityInfo.SetValue("0");//修改CreateTime字段
} }
@ -134,8 +141,8 @@ namespace QYZH.InteractiveMagazine.Repository.Core
{ {
if (entityInfo.PropertyName == "UpdatedAt" && (string.IsNullOrWhiteSpace(entityValue) || entityValue == DateTime.MinValue.ToString())) if (entityInfo.PropertyName == "UpdatedAt" && (string.IsNullOrWhiteSpace(entityValue) || entityValue == DateTime.MinValue.ToString()))
entityInfo.SetValue(DateTime.Now);//修改UpdatedTime字段 entityInfo.SetValue(DateTime.Now);//修改UpdatedTime字段
else if (entityInfo.PropertyName == "UpdatedBy" && (string.IsNullOrWhiteSpace(entityValue) || entityValue == "0")) else if (entityInfo.PropertyName == "UpdatedBy" && ShouldSetOperatorName(entityValue, currentUserName))
entityInfo.SetValue(currnetUserName);//修改更新人字段 entityInfo.SetValue(currentUserName);//修改更新人字段
} }
}; };
return db; return db;
@ -143,6 +150,39 @@ namespace QYZH.InteractiveMagazine.Repository.Core
} }
private static string GetCurrentUserName()
{
try
{
var httpContextAccessor = ServiceContext.ServiceProvider?.GetService(typeof(IHttpContextAccessor)) as IHttpContextAccessor;
var user = httpContextAccessor?.HttpContext?.User;
var userName = user?.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value
?? user?.Identity?.Name;
return string.IsNullOrWhiteSpace(userName) ? "System" : userName;
}
catch
{
return "System";
}
}
private static bool ShouldSetOperatorName(string? entityValue, string currentUserName)
{
if (string.IsNullOrWhiteSpace(entityValue) || entityValue == "0")
{
return true;
}
if (currentUserName != "System" && long.TryParse(entityValue, out _))
{
return true;
}
return false;
}
/// <summary> /// <summary>
/// 把一个字符串转成驼峰规则的字符串 /// 把一个字符串转成驼峰规则的字符串
/// </summary> /// </summary>

View File

@ -29,6 +29,9 @@ public class UserJournalService(
private const string JournalExchange = "ex.journal"; private const string JournalExchange = "ex.journal";
private const string BindJournalQueue = "mq.journal.bindUser"; private const string BindJournalQueue = "mq.journal.bindUser";
private const string BindJournalRoutingKey = "rk.journal.bindUser"; private const string BindJournalRoutingKey = "rk.journal.bindUser";
private const string QrCodeGenerateQueue = "mq.journal.qrcode.generate";
private const string QrCodeGenerateRoutingKey = "rk.journal.qrcode.generate";
private const int MaxBatchQrCodeCount = 500;
/// <summary> /// <summary>
/// 用户绑定期刊(扫码绑定) /// 用户绑定期刊(扫码绑定)
@ -137,7 +140,7 @@ public class UserJournalService(
/// <summary> /// <summary>
/// 生成期刊二维码记录 /// 生成期刊二维码记录
/// </summary> /// </summary>
public async Task<UserJournalQrCodeOutput> CreateQrCodeAsync(CreateUserJournalQrCodeInput input, long operatorId) public async Task<UserJournalQrCodeOutput> CreateQrCodeAsync(CreateUserJournalQrCodeInput input, string operatorName)
{ {
if (input.JournalId <= 0) if (input.JournalId <= 0)
{ {
@ -162,9 +165,9 @@ public class UserJournalService(
Type = 0, Type = 0,
Status = (int)UserJournalStatusEnum.Active, Status = (int)UserJournalStatusEnum.Active,
IsDeleted = false, IsDeleted = false,
CreatedBy = operatorId.ToString(), CreatedBy = operatorName,
CreatedAt = DateTime.Now, CreatedAt = DateTime.Now,
UpdatedBy = operatorId.ToString(), UpdatedBy = operatorName,
UpdatedAt = DateTime.Now UpdatedAt = DateTime.Now
}; };
@ -191,6 +194,88 @@ public class UserJournalService(
/// <summary> /// <summary>
/// 分页查询期刊二维码记录 /// 分页查询期刊二维码记录
/// </summary> /// </summary>
public async Task<CreateUserJournalQrCodeOutput> CreateQrCodesAsync(CreateUserJournalQrCodeInput input, string operatorName)
{
if (input.JournalId <= 0)
{
throw new BusinessException("期刊Id不能为空", ResultCode.BAD_REQUEST);
}
if (input.Count <= 0 || input.Count > MaxBatchQrCodeCount)
{
throw new BusinessException($"生成数量必须在1-{MaxBatchQrCodeCount}之间", ResultCode.BAD_REQUEST);
}
var journal = await journalRepository.GetByIdAsync(input.JournalId);
if (journal == null || journal.IsDeleted)
{
throw new BusinessException("期刊不存在", ResultCode.NOT_FOUND);
}
if (journal.Status != (int)JournalStatusEnum.Published)
{
throw new BusinessException("该期刊暂未发布,无法生成二维码", ResultCode.UNPROCESSABLE_ENTITY);
}
var now = DateTime.Now;
var records = Enumerable.Range(0, input.Count)
.Select(_ => new UserJournal
{
UserId = null,
JournalId = input.JournalId,
Type = 0,
Status = (int)UserJournalStatusEnum.Generating,
IsDeleted = false,
CreatedBy = operatorName,
CreatedAt = now,
UpdatedBy = operatorName,
UpdatedAt = now
})
.ToList();
var insertCount = await userJournalRepository.Context.Insertable(records).ExecuteCommandAsync();
if (insertCount <= 0)
{
throw new BusinessException("提交二维码生成任务失败,请稍后重试", ResultCode.GLOBAL_ERROR);
}
var recordIds = records.Select(r => r.Id).ToList();
var messageSent = await rabbitMqService.SendAsync(new RabbitMQSendParam
{
Exchange = JournalExchange,
Queue = QrCodeGenerateQueue,
RoutingKey = QrCodeGenerateRoutingKey,
Data = new GenerateUserJournalQrCodeMessage
{
RecordIds = recordIds,
OperatorName = operatorName
}
});
if (!messageSent)
{
await userJournalRepository.Updateable()
.SetColumns(uj => uj.Status == (int)UserJournalStatusEnum.Failed)
.SetColumns(uj => uj.UpdatedBy == operatorName)
.SetColumns(uj => uj.UpdatedAt == DateTime.Now)
.Where(uj => recordIds.Contains(uj.Id) && !uj.IsDeleted && uj.Status == (int)UserJournalStatusEnum.Generating)
.ExecuteCommandAsync();
logger.LogError("发送期刊二维码生成消息失败RecordIds: {RecordIds}", string.Join(",", recordIds));
throw new BusinessException("二维码生成任务提交失败,请稍后重试", ResultCode.GLOBAL_ERROR);
}
return new CreateUserJournalQrCodeOutput
{
JournalId = input.JournalId,
RequestedCount = input.Count,
AcceptedCount = insertCount,
RecordIds = recordIds,
IsAsync = true,
Message = "二维码生成任务已提交,请稍后查询未绑定二维码列表"
};
}
public async Task<PageListModel<UserJournalQrCodeOutput>> GetQrCodePageListAsync(UserJournalQrCodeQueryInput input) public async Task<PageListModel<UserJournalQrCodeOutput>> GetQrCodePageListAsync(UserJournalQrCodeQueryInput input)
{ {
if (input.PageIndex <= 0) if (input.PageIndex <= 0)
@ -237,7 +322,7 @@ public class UserJournalService(
/// <summary> /// <summary>
/// 删除未绑定的期刊二维码记录 /// 删除未绑定的期刊二维码记录
/// </summary> /// </summary>
public async Task<bool> DeleteQrCodeAsync(DeleteUserJournalQrCodeInput input, long operatorId) public async Task<bool> DeleteQrCodeAsync(DeleteUserJournalQrCodeInput input, string operatorName)
{ {
if (input.Ids == null || input.Ids.Count == 0) if (input.Ids == null || input.Ids.Count == 0)
{ {
@ -262,7 +347,7 @@ public class UserJournalService(
var updateCount = await userJournalRepository.Updateable() var updateCount = await userJournalRepository.Updateable()
.SetColumns(uj => uj.IsDeleted == true) .SetColumns(uj => uj.IsDeleted == true)
.SetColumns(uj => uj.Status == (int)UserJournalStatusEnum.Inactive) .SetColumns(uj => uj.Status == (int)UserJournalStatusEnum.Inactive)
.SetColumns(uj => uj.UpdatedBy == operatorId.ToString()) .SetColumns(uj => uj.UpdatedBy == operatorName)
.SetColumns(uj => uj.UpdatedAt == DateTime.Now) .SetColumns(uj => uj.UpdatedAt == DateTime.Now)
.Where(uj => ids.Contains(uj.Id) && !uj.IsDeleted && (uj.UserId == null || uj.UserId == 0)) .Where(uj => ids.Contains(uj.Id) && !uj.IsDeleted && (uj.UserId == null || uj.UserId == 0))
.ExecuteCommandAsync(); .ExecuteCommandAsync();
@ -270,6 +355,24 @@ public class UserJournalService(
return updateCount == ids.Count; return updateCount == ids.Count;
} }
public async Task<List<UserJournalQrCodeOutput>> GetUnboundQrCodesByJournalIdAsync(long journalId)
{
if (journalId <= 0)
{
throw new BusinessException("期刊Id不能为空", ResultCode.BAD_REQUEST);
}
var records = await userJournalRepository.Queryable()
.Where(uj => uj.JournalId == journalId && !uj.IsDeleted)
.Where(uj => uj.UserId == null || uj.UserId == 0)
.Where(uj => uj.Status == (int)UserJournalStatusEnum.Active)
.Where(uj => !string.IsNullOrEmpty(uj.QrCodeUrl))
.OrderByDescending(uj => uj.CreatedAt)
.ToListAsync();
return await BuildQrCodeOutputsAsync(records);
}
private async Task<List<UserJournalQrCodeOutput>> BuildQrCodeOutputsAsync(List<UserJournal> records) private async Task<List<UserJournalQrCodeOutput>> BuildQrCodeOutputsAsync(List<UserJournal> records)
{ {
if (records.Count == 0) if (records.Count == 0)

View File

@ -19,10 +19,22 @@ public class UserJournalQrCodeController(IUserJournalService userJournalService)
/// <param name="input">生成输入</param> /// <param name="input">生成输入</param>
/// <returns>二维码记录</returns> /// <returns>二维码记录</returns>
[HttpPost("add")] [HttpPost("add")]
public async Task<BaseResponse<UserJournalQrCodeOutput>> AddAsync([FromBody] CreateUserJournalQrCodeInput input) public async Task<BaseResponse<CreateUserJournalQrCodeOutput>> AddAsync([FromBody] CreateUserJournalQrCodeInput input)
{ {
var result = await userJournalService.CreateQrCodeAsync(input, GetCurrentUserId() ?? 0); var result = await userJournalService.CreateQrCodesAsync(input, GetCurrentUserName() ?? "System");
return BaseResponse<UserJournalQrCodeOutput>.Success(result); return BaseResponse<CreateUserJournalQrCodeOutput>.Success(result);
}
/// <summary>
/// 根据期刊Id获取未绑定用户的二维码地址
/// </summary>
/// <param name="journalId">期刊Id</param>
/// <returns>未绑定二维码列表</returns>
[HttpGet("unbound/{journalId:long}")]
public async Task<BaseResponse<List<UserJournalQrCodeOutput>>> GetUnboundByJournalIdAsync(long journalId)
{
var result = await userJournalService.GetUnboundQrCodesByJournalIdAsync(journalId);
return BaseResponse<List<UserJournalQrCodeOutput>>.Success(result);
} }
/// <summary> /// <summary>
@ -57,7 +69,7 @@ public class UserJournalQrCodeController(IUserJournalService userJournalService)
[HttpPost("delete")] [HttpPost("delete")]
public async Task<BaseResponse<bool>> DeleteAsync([FromBody] DeleteUserJournalQrCodeInput input) public async Task<BaseResponse<bool>> DeleteAsync([FromBody] DeleteUserJournalQrCodeInput input)
{ {
var result = await userJournalService.DeleteQrCodeAsync(input, GetCurrentUserId() ?? 0); var result = await userJournalService.DeleteQrCodeAsync(input, GetCurrentUserName() ?? "System");
return BaseResponse<bool>.Success(result); return BaseResponse<bool>.Success(result);
} }
} }

View File

@ -0,0 +1,129 @@
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 });
}
}

View File

@ -77,6 +77,7 @@ builder.Services.AddRabbitMQ(builder.Configuration);
// 注册队列消费者(新增消费者只需实现 IQueueConsumer 并在此注册) // 注册队列消费者(新增消费者只需实现 IQueueConsumer 并在此注册)
builder.Services.AddScoped<IQueueConsumer, JournalTaskReceiveConsumer>(); builder.Services.AddScoped<IQueueConsumer, JournalTaskReceiveConsumer>();
builder.Services.AddScoped<IQueueConsumer, UserJournalQrCodeGenerateConsumer>();
// 注册消费者后台服务 // 注册消费者后台服务
builder.Services.AddHostedService<RabbitMQHostedService>(); builder.Services.AddHostedService<RabbitMQHostedService>();