diff --git a/QYZH.InteractiveMagazine.IService/IJournalPageService.cs b/QYZH.InteractiveMagazine.IService/IJournalPageService.cs index 654f4b8..205c86c 100644 --- a/QYZH.InteractiveMagazine.IService/IJournalPageService.cs +++ b/QYZH.InteractiveMagazine.IService/IJournalPageService.cs @@ -21,6 +21,10 @@ public interface IJournalPageService: IBaseService Task DetailAsync(long id); Task DeleteAsync(long id); - - //Task> PageNoArticleAsync(long id); + /// + /// 回调接口-自动铺码, 书页铺码后回调接口,更新书页的点阵码 + /// + /// + /// + Task CallbackPageUpdatePageNo(JournalPagePrintDto journalPagePrintDto); } diff --git a/QYZH.InteractiveMagazine.Models/Enum/PetTemplateTypeEnum.cs b/QYZH.InteractiveMagazine.Models/Enum/PetTemplateTypeEnum.cs index 2a0f4dd..a562f06 100644 --- a/QYZH.InteractiveMagazine.Models/Enum/PetTemplateTypeEnum.cs +++ b/QYZH.InteractiveMagazine.Models/Enum/PetTemplateTypeEnum.cs @@ -7,6 +7,11 @@ namespace QYZH.InteractiveMagazine.Models.Enum; /// public enum PetTemplateTypeEnum { + /// + /// 默认 + /// + [Description("默认")] + Default = 0, /// /// 普通 /// diff --git a/QYZH.InteractiveMagazine.Service/JournalPageService.cs b/QYZH.InteractiveMagazine.Service/JournalPageService.cs index cbcce20..9bd7c93 100644 --- a/QYZH.InteractiveMagazine.Service/JournalPageService.cs +++ b/QYZH.InteractiveMagazine.Service/JournalPageService.cs @@ -1,7 +1,10 @@  +using Aliyun.Acs.Core.Logging; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using QYZH.InteractiveMagazine.Common.Extensions; +using QYZH.InteractiveMagazine.Common.Helpers; using QYZH.InteractiveMagazine.Infrastructure.OSS; using QYZH.InteractiveMagazine.Infrastructure.RabbitMQ; using QYZH.InteractiveMagazine.IService; @@ -11,6 +14,7 @@ using QYZH.InteractiveMagazine.Models.Entity; using QYZH.InteractiveMagazine.Models.Enum; using QYZH.InteractiveMagazine.Repository; using System.Diagnostics; +using System.Net; using Yitter.IdGenerator; namespace QYZH.InteractiveMagazine.Service; @@ -20,6 +24,8 @@ public class JournalPageService(BaseRepository JournalRepository, IHttpClientFactory httpClientFactory, IConfiguration configuration, IRabbitMQService rabbitMqService, + ILogger logger, + BaseRepository JournalPageRepository, BaseRepository JournalPageTaskRepository, BaseRepository JournalPageTaskAnswerRepository) : BaseRepository, IJournalPageService { @@ -108,10 +114,87 @@ public class JournalPageService(BaseRepository JournalRepository, /// public async Task UpdatePageNoAsync(long JournalId) { - var msRes = await rabbitMqService.SendAsync(new RabbitMQSendParam { Exchange = "ex.journal", Queue = "mq.journal.dotcode.auto", RoutingKey = "rk.journal.dotcode.auto", Data = JournalId });//发生消息 + var journalEntity = await JournalRepository.Queryable().FirstAsync(w => w.Id == JournalId); + BusinessException.ThrowIf(journalEntity == null, "不存在此期刊"); + + //如果书籍状态不等于“已归档”,“已废弃”,“已铺码”的情况下,就更新状态为“已铺码” + BusinessException.ThrowIf((JournalStatusEnum)journalEntity.Status is JournalStatusEnum.Abandoned or JournalStatusEnum.Archive or JournalStatusEnum.Codeing, "当前【状态】不允许铺码"); + + var journalPageList = await JournalPageRepository.Queryable().Where(x => x.JournalId == JournalId).OrderBy(x => x.PageNum).ToListAsync(); + BusinessException.ThrowIf(journalPageList.Count == 0, "此期刊不存在任何书页"); + + var uploadPdfUrl = DomainHelper.OssFullUrl(journalEntity?.PdfUrl!); + BusinessException.ThrowIf(string.IsNullOrWhiteSpace(uploadPdfUrl), "此期刊上传的PDF路径错误,请检查期刊PDF文件是否上传成功"); + + logger.LogInformation("uploadPdfUrl:" + uploadPdfUrl); + //验证是否上传了PDF文件 + var response = await httpClientFactory.CreateClient().SendAsync(new HttpRequestMessage(HttpMethod.Head, uploadPdfUrl)); + BusinessException.ThrowIf(response.StatusCode != HttpStatusCode.OK, "获取期刊上传的PDF文件失败,请检查PDF文件是否上传成功"); + + journalEntity.Status = (int)JournalStatusEnum.Codeing; + + await JournalRepository.Updateable(journalEntity).UpdateColumns(x => new { x.Status, x.UpdatedAt }).ExecuteCommandAsync(); + + var data = new JournalPagePrintDto + { + JournalId = JournalId, + JournalPdfUrl = uploadPdfUrl, + PageNum = [.. journalPageList.Select(x => x.PageNum)] + }; + var msRes = await rabbitMqService.SendAsync(new RabbitMQSendParam { Exchange = "ex.journal", Queue = "mq.journal.dotcode.auto", RoutingKey = "rk.journal.dotcode.auto", Data = data });//发生消息 return msRes; } + /// + /// 回调接口-自动铺码, 书页铺码后回调接口,更新书页的点阵码 + /// + /// + /// + public async Task CallbackPageUpdatePageNo(JournalPagePrintDto request) + { + return await UseTranAsync(async () => + { + var journalEntity = await JournalRepository.Queryable().FirstAsync(w => w.Id == request.JournalId); + BusinessException.ThrowIf(journalEntity == null, "不存在此书"); + //如果书籍状态不等于“铺码中”则不允许回调接口更新点阵码 + BusinessException.ThrowIf(journalEntity.Status != (int)JournalStatusEnum.Codeing, "当前【状态】不允许修改铺码"); + + var bookPageList = await JournalPageRepository.Queryable().Where(x => x.JournalId == request.JournalId).OrderBy(x => x.PageNum).ToListAsync(); + + BusinessException.ThrowIf(bookPageList.Count == 0, "此书不存在任何书页"); + + journalEntity.Status = (int)request.Status!.Value; + journalEntity.UpdatedAt = DateTime.Now; + + //如果铺码成功了,并且之前已经有下载链接了,就删除原来的文件 + if (request.Status == JournalStatusEnum.CodeSuccess && !string.IsNullOrWhiteSpace(journalEntity.DownloadJournalPagePdfName)) + { + //删除oss上原来的文件 + ossService.DeleteObject(journalEntity.DownloadJournalPagePdfName.RemoveDomain()); + } + //如果铺码成功了,就更新下载链接,以及书页的点阵码 + if (request.Status == JournalStatusEnum.CodeSuccess) + { + journalEntity.DownloadJournalPagePdfName = request.DownloadJournalPagePdfName; + + BusinessException.ThrowIf(request.PageNo.Length != bookPageList.Count, $"点阵码条数与页码数量不匹配,点阵码条数:{request.PageNo.Length},页码数量:{bookPageList.Count}"); + + + for (var i = 0; i < bookPageList.Count; i++) + { + //让也页码和点阵码的顺序必须保持一致 + bookPageList[i].PageNo = request.PageNo[i]; + bookPageList[i].UpdatedAt = DateTime.Now; + } + + await JournalPageRepository.UpdateRangeAsync(bookPageList); + } + + await JournalRepository.Updateable(journalEntity).UpdateColumns(x => new { x.Status, x.DownloadJournalPagePdfName, x.UpdatedAt }).ExecuteCommandAsync(); + + return true; + }); + } public async Task DetailAsync(long id) { var output = await Queryable() diff --git a/QYZH.InteractiveMagazine.Service/PetService.cs b/QYZH.InteractiveMagazine.Service/PetService.cs index 07c3b41..71c1150 100644 --- a/QYZH.InteractiveMagazine.Service/PetService.cs +++ b/QYZH.InteractiveMagazine.Service/PetService.cs @@ -252,7 +252,7 @@ public class PetService( logger.LogWarning("喂养失败,宠物未激活,PetId: {PetId}, Status: {Status}", input.PetId, pet.Status); throw new BusinessException("宠物未激活,无法喂养", 400); } - FeedPetOutput result = new FeedPetOutput (); + FeedPetOutput result = new FeedPetOutput(); // 事务保证一致性 await UseTranAsync(async () => { @@ -590,6 +590,11 @@ public class PetService( if (template == null || template.IsDeleted) throw new BusinessException("宠物模板不存在", 404); + + if (template.Type == PetTemplateTypeEnum.Default) + throw new BusinessException("默认模板不允许删除", 400); + + // 校验是否有用户宠物实例关联 var hasUserPet = petRepository.Context.Queryable() .Any(p => p.TemplateId == id && !p.IsDeleted); @@ -659,9 +664,9 @@ public class PetService( var template = await petTemplateRepository.GetByIdAsync(id); if (template == null || template.IsDeleted) throw new BusinessException("宠物模板不存在", 404); - - template.Status = template.Status == (int)DefaultStatusEnum.Active - ? (int)DefaultStatusEnum.Inactive + + template.Status = template.Status == (int)DefaultStatusEnum.Active + ? (int)DefaultStatusEnum.Inactive : (int)DefaultStatusEnum.Active; template.UpdatedBy = "System"; template.UpdatedAt = DateTime.Now; diff --git a/QYZH.InteractiveMagazine.WebApi/Controllers/JournalController.cs b/QYZH.InteractiveMagazine.WebApi/Controllers/JournalController.cs index 76b03bc..2ba3b25 100644 --- a/QYZH.InteractiveMagazine.WebApi/Controllers/JournalController.cs +++ b/QYZH.InteractiveMagazine.WebApi/Controllers/JournalController.cs @@ -374,6 +374,18 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers return BaseResponse.Success(data); } + /// + /// 回调接口-自动铺码, 书页铺码后回调接口,更新书页的点阵码 + /// + /// + /// + [HttpPost, Route("page/callbackupdatepageno")] + [AllowAnonymous] + public async Task> CallbackPageUpdatePageNo([FromBody] JournalPagePrintDto journalPagePrintDto) + { + var data = await JournalPageService.CallbackPageUpdatePageNo(journalPagePrintDto); + return BaseResponse.Success(data); + } /// /// 下载书籍页码点阵码PDF文件名称 /// diff --git a/QYZH.InteractiveMagazine.WebApi/appsettings.json b/QYZH.InteractiveMagazine.WebApi/appsettings.json index dce8961..005ed1b 100644 --- a/QYZH.InteractiveMagazine.WebApi/appsettings.json +++ b/QYZH.InteractiveMagazine.WebApi/appsettings.json @@ -67,6 +67,6 @@ "DurationSeconds": 3600, //过期时间(秒) "Endpoint": "oss-cn-beijing.aliyuncs.com", "ProjectName": "InteractiveMagazine", - "Domain": "https://oss.test.qyzhjy.com/" + "Domain": "http://oss.test.qyzhjy.com/" } } diff --git a/QYZH.InteractiveMagazine.WorkService/Consumers/AutoDotCodeConsumer.cs b/QYZH.InteractiveMagazine.WorkService/Consumers/AutoDotCodeConsumer.cs index b867997..819fe15 100644 --- a/QYZH.InteractiveMagazine.WorkService/Consumers/AutoDotCodeConsumer.cs +++ b/QYZH.InteractiveMagazine.WorkService/Consumers/AutoDotCodeConsumer.cs @@ -16,6 +16,7 @@ namespace QYZH.InteractiveMagazine.WorkService.Consumers; /// public class AutoDotCodeConsumer(IConfiguration configuration, IServiceScopeFactory scopeFactory, + IWebHostEnvironment webHostEnvironment, ILogger logger, IHttpClientFactory httpClientFactory, OssService ossService @@ -78,7 +79,7 @@ public class AutoDotCodeConsumer(IConfiguration configuration, #region 调用铺码程序 // 从配置中获取点阵文件Id - var dotId = configuration.GetValue("PrintConfig:DotId", 683790963662917); + var dotId = configuration.GetValue("PrintConfig:DotId", 765837655859269); var dotfile = await dBContext.Queryable().FirstAsync(x => x.Id == dotId, cancellationToken); if (dotfile == null) @@ -87,9 +88,10 @@ public class AutoDotCodeConsumer(IConfiguration configuration, return; } - var exePath = AppDomain.CurrentDomain.BaseDirectory + "PrintToolV2.7\\PrintTool.exe"; + var printToolDirectory = Path.Combine(webHostEnvironment.ContentRootPath, "PrintToolV2.7"); + var exePath = Path.Combine(printToolDirectory, "PrintTool.exe"); - var xmlPath = AppDomain.CurrentDomain.BaseDirectory + $"PrintToolV2.7\\{dotfile.FileName}"; + var xmlPath = Path.Combine(printToolDirectory, dotfile.FileName); #region 注释说明 @@ -151,7 +153,8 @@ public class AutoDotCodeConsumer(IConfiguration configuration, // 从第一个开始执行,连续铺码N条(N为书籍页数) string pageStr = "{" + $"[{dotFileDetailList[0].PageName},{pageNumMax}]" + "}"; - var cmd = $"PrintTool.exe -sMode=Generate -sPDF={uploadFilePath} -sLIC={xmlPath} -pStart=1 -oPDF={downloadFilePath} -dPageAddr=1 -dPrint={dPrint} -dDotSize=40 -dType=0 -dOutFile=0 -dControlPageNum={pageStr}"; + var arguments = $"-sMode=Generate -sPDF=\"{uploadFilePath}\" -sLIC=\"{xmlPath}\" -pStart=1 -oPDF=\"{downloadFilePath}\" -dPageAddr=1 -dPrint={dPrint} -dDotSize=40 -dType=0 -dOutFile=0 -dControlPageNum={pageStr}"; + var cmd = $"\"{exePath}\" {arguments}"; logger.LogInformation($"执行PrintTool.exe 的命令: {cmd}"); @@ -160,9 +163,9 @@ public class AutoDotCodeConsumer(IConfiguration configuration, { p.StartInfo = new ProcessStartInfo { - WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory + "PrintToolV2.7", - FileName = "cmd.exe", - Arguments = "/c " + cmd, // /c参数表示执行后关闭 + WorkingDirectory = printToolDirectory, + FileName = exePath, + Arguments = arguments, UseShellExecute = false, //是否使用操作系统shell启动 RedirectStandardInput = true, //接受来自调用程序的输入信息 RedirectStandardOutput = true, //由调用程序获取输出信息 @@ -336,4 +339,4 @@ internal class CallbackUpdateJournalStatusResponse public bool Result { get; set; } public bool IsSuccess { get; set; } -} \ No newline at end of file +} diff --git a/QYZH.InteractiveMagazine.WorkService/PrintToolV2.7/sublic_license_1761.211.21.48_10000.xml b/QYZH.InteractiveMagazine.WorkService/PrintToolV2.7/sublic_license_1761.211.21.48_10000.xml new file mode 100644 index 0000000..1b75c8c --- /dev/null +++ b/QYZH.InteractiveMagazine.WorkService/PrintToolV2.7/sublic_license_1761.211.21.48_10000.xml @@ -0,0 +1,32 @@ + + + + + + + + + diff --git a/QYZH.InteractiveMagazine.WorkService/Program.cs b/QYZH.InteractiveMagazine.WorkService/Program.cs index 7a7fe43..bafdc3b 100644 --- a/QYZH.InteractiveMagazine.WorkService/Program.cs +++ b/QYZH.InteractiveMagazine.WorkService/Program.cs @@ -2,6 +2,8 @@ using Hangfire; using Hangfire.Dashboard; using Hangfire.MemoryStorage; using QYZH.InteractiveMagazine.Infrastructure.RabbitMQ; +using QYZH.InteractiveMagazine.Infrastructure.Redis; +using QYZH.InteractiveMagazine.Infrastructure.SDK; using QYZH.InteractiveMagazine.Models.Settings; using QYZH.InteractiveMagazine.WorkService.Consumers; using QYZH.InteractiveMagazine.WorkService.Jobs; @@ -49,6 +51,9 @@ SugarIocServices.ConfigurationSugar(db => }; }); +// 显式注册 ISqlSugarClient,供后台服务中通过 DI 解析 +builder.Services.AddScoped(_ => DbScoped.SugarScope); + // 配置Hangfire(内存存储,后续可切换Redis) builder.Services.AddHangfire(config => config .UseMemoryStorage() @@ -58,6 +63,15 @@ builder.Services.AddHangfire(config => config })); builder.Services.AddHangfireServer(); +// 配置Redis +builder.Services.AddCSRedisCacheExtension(builder.Configuration.GetSection("RedisSettings")); + +// 配置HttpClient +builder.Services.AddHttpClient(); + +// 配置OSS/SDK服务 +builder.Services.AddSDKService(builder.Configuration); + // 配置RabbitMQ builder.Services.AddRabbitMQ(builder.Configuration); diff --git a/QYZH.InteractiveMagazine.WorkService/QYZH.InteractiveMagazine.WorkService.csproj b/QYZH.InteractiveMagazine.WorkService/QYZH.InteractiveMagazine.WorkService.csproj index b931f2a..0789df2 100644 --- a/QYZH.InteractiveMagazine.WorkService/QYZH.InteractiveMagazine.WorkService.csproj +++ b/QYZH.InteractiveMagazine.WorkService/QYZH.InteractiveMagazine.WorkService.csproj @@ -22,4 +22,58 @@ + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + diff --git a/QYZH.InteractiveMagazine.WorkService/appsettings.json b/QYZH.InteractiveMagazine.WorkService/appsettings.json index 61de186..80e5596 100644 --- a/QYZH.InteractiveMagazine.WorkService/appsettings.json +++ b/QYZH.InteractiveMagazine.WorkService/appsettings.json @@ -2,6 +2,11 @@ "ConnectionStrings": { "DefaultConnection": "server=192.168.20.150;port=13306;database=InteractiveMagazine;user=user;password=n68792bu!y99r905;charset=utf8mb4;" }, + "RedisSettings": { + "ConnectionString": "192.168.20.150:16379,defaultDatabase=5", + "Sentinels": [], + "ExpireSecondRange": [ 3600, 7200 ] + }, "RabbitMq": { "HostName": "192.168.20.150", "Port": 5672, @@ -55,6 +60,14 @@ "DurationSeconds": 3600, //过期时间(秒) "Endpoint": "oss-cn-beijing.aliyuncs.com", "ProjectName": "InteractiveMagazine", - "Domain": "https://oss.test.qyzhjy.com/" + "Domain": "http://oss.test.qyzhjy.com/" + }, + "PrintConfig": { + "DPrint": 0, //打印场景,0:普通激光打印机,1:工业印刷,默认为0(可选) + "CallBackApiUrl": "http://localhost:8080/api/page/callbackupdatepageno", // 开发环境 打印成功回调API地址修改打印状态 + //"CallBackApiUrl": "http://192.168.20.150:8000/api/icr/page/callbackupdatepageno", // 测试环境 打印成功回调API地址修改打印状态 + //"CallBackApiUrl": "https://zyb.qyzhjy.com/zybback/api/icr/page/callbackupdatepageno", // 正式环境 打印成功回调API地址修改打印状态 + //这个ID执行的xml文件是:sublic_license_1761.172.8.16_1000.xml,如果想执行sublic_license_1761.211.21.48_10000.xml 换成 765837655859269 ---暂时没有导入页码 + "DotId": 765837655859269 } }