From 5700da58d966bc383a5b033aef8bd8e37d6a726e Mon Sep 17 00:00:00 2001 From: glz <694770232@qq.com> Date: Thu, 2 Jul 2026 09:46:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E6=9C=9F=E5=88=8A?= =?UTF-8?q?=E4=BA=8C=E7=BB=B4=E7=A0=81=E6=89=B9=E9=87=8F=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=8F=8A=E7=9B=B8=E5=85=B3=E9=85=8D=E5=A5=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增UserJournalQrCodeGenerateConsumer消费者处理二维码生成队列任务 2. 新增用户期刊状态枚举的生成中、失败状态 3. 新增批量生成二维码服务方法和相关DTO 4. 优化SqlSugar自动填充创建/更新人字段逻辑 5. 调整接口参数从操作人ID改为操作人名称 6. 新增获取未绑定二维码的API接口和服务方法 --- Directory.Build.props | 5 + .../IUserJournalService.cs | 23 +++- .../Dto/Journal/BindJournalDto.cs | 56 ++++++++ .../Enum/UserJournalStatusEnum.cs | 14 +- .../Core/SqlSugarExtension.cs | 50 ++++++- .../UserJournalService.cs | 113 ++++++++++++++- .../UserJournalQrCodeController.cs | 20 ++- .../UserJournalQrCodeGenerateConsumer.cs | 129 ++++++++++++++++++ .../Program.cs | 1 + 9 files changed, 392 insertions(+), 19 deletions(-) create mode 100644 Directory.Build.props create mode 100644 QYZH.InteractiveMagazine.WorkService/Consumers/UserJournalQrCodeGenerateConsumer.cs diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..97f6331 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,5 @@ + + + $(NoWarn);CS0105;CS0108;CS0168;CS0169;CS0618;CS1570;CS1572;CS1573;CS1591;CS8600;CS8601;CS8602;CS8603;CS8604;CS8618;CS8625;CS8629;CS8634;CS8714;CS9113 + + diff --git a/QYZH.InteractiveMagazine.IService/IUserJournalService.cs b/QYZH.InteractiveMagazine.IService/IUserJournalService.cs index 38102c6..0528b2f 100644 --- a/QYZH.InteractiveMagazine.IService/IUserJournalService.cs +++ b/QYZH.InteractiveMagazine.IService/IUserJournalService.cs @@ -35,9 +35,17 @@ public interface IUserJournalService : IBaseService /// 生成期刊二维码记录 /// /// 生成输入 - /// 操作人Id + /// 操作人名称 /// 二维码记录 - Task CreateQrCodeAsync(CreateUserJournalQrCodeInput input, long operatorId); + Task CreateQrCodeAsync(CreateUserJournalQrCodeInput input, string operatorName); + + /// + /// 批量提交期刊二维码生成任务 + /// + /// 生成输入 + /// 操作人名称 + /// 提交结果 + Task CreateQrCodesAsync(CreateUserJournalQrCodeInput input, string operatorName); /// /// 分页查询期刊二维码记录 @@ -53,11 +61,18 @@ public interface IUserJournalService : IBaseService /// 二维码记录 Task GetQrCodeDetailAsync(long id); + /// + /// 根据期刊Id获取未绑定用户的二维码列表 + /// + /// 期刊Id + /// 未绑定二维码列表 + Task> GetUnboundQrCodesByJournalIdAsync(long journalId); + /// /// 删除未绑定的期刊二维码记录 /// /// 删除输入 - /// 操作人Id + /// 操作人名称 /// 是否成功 - Task DeleteQrCodeAsync(DeleteUserJournalQrCodeInput input, long operatorId); + Task DeleteQrCodeAsync(DeleteUserJournalQrCodeInput input, string operatorName); } diff --git a/QYZH.InteractiveMagazine.Models/Dto/Journal/BindJournalDto.cs b/QYZH.InteractiveMagazine.Models/Dto/Journal/BindJournalDto.cs index 909874d..0907687 100644 --- a/QYZH.InteractiveMagazine.Models/Dto/Journal/BindJournalDto.cs +++ b/QYZH.InteractiveMagazine.Models/Dto/Journal/BindJournalDto.cs @@ -117,11 +117,67 @@ public class CreateUserJournalQrCodeInput /// public long JournalId { get; set; } + /// + /// 生成数量 + /// + public int Count { get; set; } = 1; +} + +/// +/// 生成期刊二维码提交结果 +/// +public class CreateUserJournalQrCodeOutput +{ + /// + /// 期刊Id + /// + public long JournalId { get; set; } + + /// + /// 请求生成数量 + /// + public int RequestedCount { get; set; } + + /// + /// 已提交生成数量 + /// + public int AcceptedCount { get; set; } + + /// + /// 二维码记录Id列表 + /// + public List RecordIds { get; set; } = []; + + /// + /// 是否后台生成 + /// + public bool IsAsync { get; set; } + + /// + /// 提示信息 + /// + public string Message { get; set; } = string.Empty; } /// /// 期刊二维码查询输入DTO /// +public class GenerateUserJournalQrCodeMessage +{ + /// + /// 二维码记录Id列表 + /// + public List RecordIds { get; set; } = []; + + /// + /// 操作人名称 + /// + public string OperatorName { get; set; } = string.Empty; +} + +/// +/// 鏈熷垔浜岀淮鐮佹煡璇㈣緭鍏TO +/// public class UserJournalQrCodeQueryInput : PageQueryModel { /// diff --git a/QYZH.InteractiveMagazine.Models/Enum/UserJournalStatusEnum.cs b/QYZH.InteractiveMagazine.Models/Enum/UserJournalStatusEnum.cs index a7c77ea..56035a0 100644 --- a/QYZH.InteractiveMagazine.Models/Enum/UserJournalStatusEnum.cs +++ b/QYZH.InteractiveMagazine.Models/Enum/UserJournalStatusEnum.cs @@ -17,5 +17,17 @@ public enum UserJournalStatusEnum /// 正常 /// [Description("正常")] - Active = 1 + Active = 1, + + /// + /// 生成中 + /// + [Description("生成中")] + Generating = 2, + + /// + /// 生成失败 + /// + [Description("生成失败")] + Failed = 3 } diff --git a/QYZH.InteractiveMagazine.Repository/Core/SqlSugarExtension.cs b/QYZH.InteractiveMagazine.Repository/Core/SqlSugarExtension.cs index 47defe5..7e94779 100644 --- a/QYZH.InteractiveMagazine.Repository/Core/SqlSugarExtension.cs +++ b/QYZH.InteractiveMagazine.Repository/Core/SqlSugarExtension.cs @@ -1,7 +1,10 @@ using QYZH.InteractiveMagazine.Models.Entity; +using Microsoft.AspNetCore.Http; +using QYZH.InteractiveMagazine.Infrastructure.Context; using SqlSugar; using System.Linq.Expressions; using System.Reflection; +using System.Security.Claims; using Yitter.IdGenerator; @@ -117,14 +120,18 @@ namespace QYZH.InteractiveMagazine.Repository.Core db.Aop.DataExecuting = (oldValue, entityInfo) => { var entityValue = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue)?.ToString(); - var currnetUserName = ""; + var currentUserName = GetCurrentUserName(); /*** inset生效 ***/ if (entityInfo.OperationType == DataFilterType.InsertByObject) { if (entityInfo.PropertyName == "CreatedAt" && (string.IsNullOrWhiteSpace(entityValue) || entityValue == DateTime.MinValue.ToString())) entityInfo.SetValue(DateTime.Now);//修改CreateTime字段 - else if (entityInfo.PropertyName == "CreatedBy" && (string.IsNullOrWhiteSpace(entityValue))) - entityInfo.SetValue(currnetUserName);//修改创建人字段 + else if (entityInfo.PropertyName == "CreatedBy" && ShouldSetOperatorName(entityValue, currentUserName)) + 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)) entityInfo.SetValue("0");//修改CreateTime字段 } @@ -134,8 +141,8 @@ namespace QYZH.InteractiveMagazine.Repository.Core { if (entityInfo.PropertyName == "UpdatedAt" && (string.IsNullOrWhiteSpace(entityValue) || entityValue == DateTime.MinValue.ToString())) entityInfo.SetValue(DateTime.Now);//修改UpdatedTime字段 - else if (entityInfo.PropertyName == "UpdatedBy" && (string.IsNullOrWhiteSpace(entityValue) || entityValue == "0")) - entityInfo.SetValue(currnetUserName);//修改更新人字段 + else if (entityInfo.PropertyName == "UpdatedBy" && ShouldSetOperatorName(entityValue, currentUserName)) + entityInfo.SetValue(currentUserName);//修改更新人字段 } }; 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; + } + + /// /// 把一个字符串转成驼峰规则的字符串 /// diff --git a/QYZH.InteractiveMagazine.Service/UserJournalService.cs b/QYZH.InteractiveMagazine.Service/UserJournalService.cs index d3d7847..e5af33c 100644 --- a/QYZH.InteractiveMagazine.Service/UserJournalService.cs +++ b/QYZH.InteractiveMagazine.Service/UserJournalService.cs @@ -29,6 +29,9 @@ public class UserJournalService( private const string JournalExchange = "ex.journal"; private const string BindJournalQueue = "mq.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; /// /// 用户绑定期刊(扫码绑定) @@ -137,7 +140,7 @@ public class UserJournalService( /// /// 生成期刊二维码记录 /// - public async Task CreateQrCodeAsync(CreateUserJournalQrCodeInput input, long operatorId) + public async Task CreateQrCodeAsync(CreateUserJournalQrCodeInput input, string operatorName) { if (input.JournalId <= 0) { @@ -162,9 +165,9 @@ public class UserJournalService( Type = 0, Status = (int)UserJournalStatusEnum.Active, IsDeleted = false, - CreatedBy = operatorId.ToString(), + CreatedBy = operatorName, CreatedAt = DateTime.Now, - UpdatedBy = operatorId.ToString(), + UpdatedBy = operatorName, UpdatedAt = DateTime.Now }; @@ -191,6 +194,88 @@ public class UserJournalService( /// /// 分页查询期刊二维码记录 /// + public async Task 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> GetQrCodePageListAsync(UserJournalQrCodeQueryInput input) { if (input.PageIndex <= 0) @@ -237,7 +322,7 @@ public class UserJournalService( /// /// 删除未绑定的期刊二维码记录 /// - public async Task DeleteQrCodeAsync(DeleteUserJournalQrCodeInput input, long operatorId) + public async Task DeleteQrCodeAsync(DeleteUserJournalQrCodeInput input, string operatorName) { if (input.Ids == null || input.Ids.Count == 0) { @@ -262,7 +347,7 @@ public class UserJournalService( var updateCount = await userJournalRepository.Updateable() .SetColumns(uj => uj.IsDeleted == true) .SetColumns(uj => uj.Status == (int)UserJournalStatusEnum.Inactive) - .SetColumns(uj => uj.UpdatedBy == operatorId.ToString()) + .SetColumns(uj => uj.UpdatedBy == operatorName) .SetColumns(uj => uj.UpdatedAt == DateTime.Now) .Where(uj => ids.Contains(uj.Id) && !uj.IsDeleted && (uj.UserId == null || uj.UserId == 0)) .ExecuteCommandAsync(); @@ -270,6 +355,24 @@ public class UserJournalService( return updateCount == ids.Count; } + public async Task> 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> BuildQrCodeOutputsAsync(List records) { if (records.Count == 0) diff --git a/QYZH.InteractiveMagazine.WebApi/Controllers/UserJournalQrCodeController.cs b/QYZH.InteractiveMagazine.WebApi/Controllers/UserJournalQrCodeController.cs index 36591f3..9115b76 100644 --- a/QYZH.InteractiveMagazine.WebApi/Controllers/UserJournalQrCodeController.cs +++ b/QYZH.InteractiveMagazine.WebApi/Controllers/UserJournalQrCodeController.cs @@ -19,10 +19,22 @@ public class UserJournalQrCodeController(IUserJournalService userJournalService) /// 生成输入 /// 二维码记录 [HttpPost("add")] - public async Task> AddAsync([FromBody] CreateUserJournalQrCodeInput input) + public async Task> AddAsync([FromBody] CreateUserJournalQrCodeInput input) { - var result = await userJournalService.CreateQrCodeAsync(input, GetCurrentUserId() ?? 0); - return BaseResponse.Success(result); + var result = await userJournalService.CreateQrCodesAsync(input, GetCurrentUserName() ?? "System"); + return BaseResponse.Success(result); + } + + /// + /// 根据期刊Id获取未绑定用户的二维码地址 + /// + /// 期刊Id + /// 未绑定二维码列表 + [HttpGet("unbound/{journalId:long}")] + public async Task>> GetUnboundByJournalIdAsync(long journalId) + { + var result = await userJournalService.GetUnboundQrCodesByJournalIdAsync(journalId); + return BaseResponse>.Success(result); } /// @@ -57,7 +69,7 @@ public class UserJournalQrCodeController(IUserJournalService userJournalService) [HttpPost("delete")] public async Task> DeleteAsync([FromBody] DeleteUserJournalQrCodeInput input) { - var result = await userJournalService.DeleteQrCodeAsync(input, GetCurrentUserId() ?? 0); + var result = await userJournalService.DeleteQrCodeAsync(input, GetCurrentUserName() ?? "System"); return BaseResponse.Success(result); } } diff --git a/QYZH.InteractiveMagazine.WorkService/Consumers/UserJournalQrCodeGenerateConsumer.cs b/QYZH.InteractiveMagazine.WorkService/Consumers/UserJournalQrCodeGenerateConsumer.cs new file mode 100644 index 0000000..02d20eb --- /dev/null +++ b/QYZH.InteractiveMagazine.WorkService/Consumers/UserJournalQrCodeGenerateConsumer.cs @@ -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; + +/// +/// 期刊二维码生成消费者 +/// +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 }); + } +} diff --git a/QYZH.InteractiveMagazine.WorkService/Program.cs b/QYZH.InteractiveMagazine.WorkService/Program.cs index 16ccff2..3df9ab6 100644 --- a/QYZH.InteractiveMagazine.WorkService/Program.cs +++ b/QYZH.InteractiveMagazine.WorkService/Program.cs @@ -77,6 +77,7 @@ builder.Services.AddRabbitMQ(builder.Configuration); // 注册队列消费者(新增消费者只需实现 IQueueConsumer 并在此注册) builder.Services.AddScoped(); +builder.Services.AddScoped(); // 注册消费者后台服务 builder.Services.AddHostedService();