From 6985a4af42504411e613ce4b477e500a66d3867e Mon Sep 17 00:00:00 2001 From: glz <694770232@qq.com> Date: Tue, 30 Jun 2026 11:03:39 +0800 Subject: [PATCH] feat(journal): add journal publish feature 1. add PublishAsync method to IJournalService and implement it in JournalService 2. add publish start/end time fields to Journal entity, DTOs and edit form 3. add journal publish API endpoint 4. add rabbitMQ message sending for book and page publish events 5. clean up some commented-out old controller methods --- .../IJournalService.cs | 2 + .../Dto/Journal/JournalDto.cs | 25 +++++++ .../Dto/Journal/JournalEditDto.cs | 10 +++ .../Entity/Journal.cs | 14 ++++ .../JournalService.cs | 73 ++++++++++++++++++- .../Controllers/JournalController.cs | 69 +++--------------- 6 files changed, 133 insertions(+), 60 deletions(-) diff --git a/QYZH.InteractiveMagazine.IService/IJournalService.cs b/QYZH.InteractiveMagazine.IService/IJournalService.cs index 1f16412..153e7db 100644 --- a/QYZH.InteractiveMagazine.IService/IJournalService.cs +++ b/QYZH.InteractiveMagazine.IService/IJournalService.cs @@ -49,6 +49,8 @@ public interface IJournalService : IBaseService Task StatusAsync(long id, JournalStatusEnum status); + Task PublishAsync(long id); + Task PrintCodeAsync(long id); Task ResultReportAsync(DotMatrixNoteJournalReportInput input); diff --git a/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalDto.cs b/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalDto.cs index 0b14eaf..31329c7 100644 --- a/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalDto.cs +++ b/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalDto.cs @@ -120,8 +120,33 @@ namespace QYZH.InteractiveMagazine.Models.Dto.Journal /// public string? DownloadJournalPagePdfName { get; set; } + /// + /// 发布开始时间 + /// + public DateTime? StartTime { get; set; } + + /// + /// 发布结束时间 + /// + public DateTime? EndTime { get; set; } + public string CreatedBy { get; set; } public DateTime CreatedAt { get; set; } } + + public class JournalPublishBookMessage + { + public long BookId { get; set; } + public DateTime StartTime { get; set; } + public DateTime EndTime { get; set; } + } + + public class JournalPublishBookPageMessage + { + public long BookId { get; set; } + public long PageId { get; set; } + public string? PageNo { get; set; } + public string? Layout { get; set; } + } } diff --git a/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalEditDto.cs b/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalEditDto.cs index a06f000..7a57d4c 100644 --- a/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalEditDto.cs +++ b/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalEditDto.cs @@ -69,6 +69,16 @@ namespace QYZH.InteractiveMagazine.Models.Dto.Journal /// public string? PdfPreviewUrl { get; set; } + /// + /// Desc:发布开始时间 + /// + public DateTime? StartTime { get; set; } + + /// + /// Desc:发布结束时间 + /// + public DateTime? EndTime { get; set; } + } public partial class JournalEditDto: JournalAddDto { diff --git a/QYZH.InteractiveMagazine.Models/Entity/Journal.cs b/QYZH.InteractiveMagazine.Models/Entity/Journal.cs index 2a97b97..4e1cb8b 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/Journal.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/Journal.cs @@ -106,6 +106,20 @@ namespace QYZH.InteractiveMagazine.Models.Entity /// public string DownloadJournalPagePdfName { get; set; } + /// + /// Desc:发布日期开始时间 + /// Default: + /// Nullable:True + /// + public DateTime? StartTime { get; set; } + + /// + /// Desc:发布日期结束时间 + /// Default: + /// Nullable:True + /// + public DateTime? EndTime { get; set; } + /// /// Desc:书籍描述/简介 diff --git a/QYZH.InteractiveMagazine.Service/JournalService.cs b/QYZH.InteractiveMagazine.Service/JournalService.cs index ce5e227..6194492 100644 --- a/QYZH.InteractiveMagazine.Service/JournalService.cs +++ b/QYZH.InteractiveMagazine.Service/JournalService.cs @@ -21,8 +21,17 @@ public class JournalService(BaseRepository JournalPageRepository, BaseRepository JournalPageTaskAnswerRepository, BaseRepository JournalCatalogRepository, BaseRepository dotFileRepository, - BaseRepository dotFileDetailRepository, OssService ossService, ILogger logger) : BaseRepository, IJournalService + BaseRepository dotFileDetailRepository, + OssService ossService, + IRabbitMQService rabbitMqService, + ILogger logger) : BaseRepository, IJournalService { + private const string JournalExchange = "ex.journal"; + private const string PublishBookQueue = "mq.journal.publish.book"; + private const string PublishBookRoutingKey = "rk.journal.publish.book"; + private const string PublishBookPageQueue = "mq.journal.publish.bookpage"; + private const string PublishBookPageRoutingKey = "rk.journal.publish.bookpage"; + /// /// 查询List /// @@ -82,6 +91,8 @@ public class JournalService(BaseRepository JournalPageRepository, Cover = input.Cover?.RemoveDomain(), BackCover = input.BackCover?.RemoveDomain(), PdfPreviewUrl = input.PdfPreviewUrl?.RemoveDomain(), + StartTime = input.StartTime, + EndTime = input.EndTime, CreatedBy = "System", UpdatedBy = "System", CreatedAt = DateTime.Now, @@ -167,6 +178,9 @@ public class JournalService(BaseRepository JournalPageRepository, Journal.Height = input.Height; Journal.Name = input.Name; Journal.Title = input.Title; + Journal.StartTime = input.StartTime; + Journal.EndTime = input.EndTime; + Journal.UpdatedAt = DateTime.Now; var res = await UseTranAsync(async () => { @@ -320,4 +334,59 @@ public class JournalService(BaseRepository JournalPageRepository, var res = await base.Updateable().SetColumns(s => s.Status, status).Where(w => w.Id == id).ExecuteCommandAsync() > 0; return res; } -} \ No newline at end of file + + public async Task PublishAsync(long id) + { + var book = await base.GetByIdAsync(id); + BusinessException.ThrowIf(book == null || book.IsDeleted, "杂志不存在", ResultCode.NOT_FOUND); + + var pages = await JournalPageRepository.Queryable() + .Where(x => x.JournalId == id && !x.IsDeleted) + .OrderBy(x => x.PageNum) + .OrderBy(x => x.Sort) + .ToListAsync(); + BusinessException.ThrowIf(pages.Count == 0, "书籍未添加任何书页,无法发布", ResultCode.UNPROCESSABLE_ENTITY); + + BusinessException.ThrowIf(!book.StartTime.HasValue, "发布开始时间不能为空", ResultCode.UNPROCESSABLE_ENTITY); + BusinessException.ThrowIf(!book.EndTime.HasValue, "发布结束时间不能为空", ResultCode.UNPROCESSABLE_ENTITY); + BusinessException.ThrowIf(book.EndTime < book.StartTime, "发布结束时间不能早于开始时间", ResultCode.UNPROCESSABLE_ENTITY); + + var bookMessageSent = await rabbitMqService.SendAsync(new RabbitMQSendParam + { + Exchange = JournalExchange, + Queue = PublishBookQueue, + RoutingKey = PublishBookRoutingKey, + Data = new JournalPublishBookMessage + { + BookId = id, + StartTime = book.StartTime.Value, + EndTime = book.EndTime.Value + } + }); + BusinessException.ThrowIf(!bookMessageSent, "发布书籍消息发送失败", ResultCode.GLOBAL_ERROR); + + foreach (var page in pages) + { + var pageMessageSent = await rabbitMqService.SendAsync(new RabbitMQSendParam + { + Exchange = JournalExchange, + Queue = PublishBookPageQueue, + RoutingKey = PublishBookPageRoutingKey, + Data = new JournalPublishBookPageMessage + { + BookId = id, + PageId = page.Id, + PageNo = page.PageNo, + Layout = page.Layout + } + }); + BusinessException.ThrowIf(!pageMessageSent, $"发布书页消息发送失败,PageId: {page.Id}", ResultCode.GLOBAL_ERROR); + } + + return await base.Updateable() + .SetColumns(s => s.Status, JournalStatusEnum.Published) + .SetColumns(s => s.UpdatedAt, DateTime.Now) + .Where(w => w.Id == id) + .ExecuteCommandAsync() > 0; + } +} diff --git a/QYZH.InteractiveMagazine.WebApi/Controllers/JournalController.cs b/QYZH.InteractiveMagazine.WebApi/Controllers/JournalController.cs index 8d2b452..89255f1 100644 --- a/QYZH.InteractiveMagazine.WebApi/Controllers/JournalController.cs +++ b/QYZH.InteractiveMagazine.WebApi/Controllers/JournalController.cs @@ -141,6 +141,17 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers return BaseResponse.Success(data); } + /// + /// 书籍发布 + /// + /// + [HttpPost, Route("journal/publish/{id:long}")] + public async Task> Publish(long id) + { + var data = await JournalService.PublishAsync(id); + return BaseResponse.Success(data); + } + /// /// 书籍铺码 /// @@ -200,17 +211,6 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers #region 书籍目录 - ///// - ///// 书籍目录详情 - ///// - ///// - //[HttpGet, Route("catalog/tree/{JournalId:long}")] - //public async Task>> CatalogDetailAsync(long JournalId) - //{ - // var data = await _JournalCatalogService.DetailAsync(JournalId); - // return BaseResponse>.Success(data); - //} - /// /// 书籍目录详情 /// @@ -312,18 +312,6 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers return BaseResponse.Success(data); } - ///// - ///// 书籍目录复制 - ///// - ///// - ///// - //[HttpPost, Route("catalog/copy")] - //[ProducesResponseType(typeof(BaseResponse), 200)] - //public async Task CatalogCopy(CopyInput input) - //{ - // var data = await _JournalCatalogServices.CopyAsync(input); - // return ApiResult(data, "书籍目录删除失败!"); - //} /// /// 书籍目录移动 @@ -411,30 +399,6 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers } - ///// - ///// 打印书页(全部) 暂时废弃这个方,直接使用 Adobe Reader X 软件打印就可以了 - ///// - ///// - //[HttpPost, Route("page/printJournalPage/{JournalId:long}")] - //public async Task> PrintJournalPage([Required(ErrorMessage = "书籍编号不允许为空")] long JournalId) - //{ - // var data = await JournalPageService.PrintJournalPageAsync(JournalId); - // return BaseResponse.Success(data); - //} - - - ///// - ///// 书页删除 - ///// - ///// - //[HttpPost, Route("page/delete/{id:long}")] - //[ProducesResponseType(typeof(BaseResponse), 200)] - //public async Task PageDelete(long id) - //{ - // var data = await _JournalPageServices.DeleteAsync(id); - // return ApiResult(data, "更新书页失败!"); - //} - /// /// 书页详情 /// @@ -446,17 +410,6 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers return BaseResponse.Success(data); } - ///// - ///// 不包含有文章的书页 - ///// - ///// - //[HttpGet, Route("page/no-article/{JournalId:long}")] - //[ProducesResponseType(typeof(BaseResponse>), 200)] - //public async Task PageNoArticleAsync(long JournalId) - //{ - // var data = await _JournalPageService.PageNoArticleAsync(JournalId); - // return BaseResponse>(data, "查询书页失败!"); - //} #endregion