refactor: 拆分自动铺码服务为独立PrintWorker项目
1. 将原WorkService中的AutoDotCodeConsumer、RabbitMQHostedService、IQueueConsumer迁移至新的PrintWorker项目 2. 移除WorkService中冗余的PrintTool依赖文件复制配置 3. 将PrintToolV2.7相关资源移动到PrintWorker项目中统一管理 4. 从WorkService中移除AutoDotCodeConsumer的服务注册 5. 新增PrintWorker项目的完整宿主程序与配置文件
This commit is contained in:
@ -0,0 +1,338 @@
|
||||
using QYZH.InteractiveMagazine.Common.Extensions;
|
||||
using QYZH.InteractiveMagazine.Infrastructure.OSS;
|
||||
using QYZH.InteractiveMagazine.Models.Dto.Journal;
|
||||
using QYZH.InteractiveMagazine.Models.Entity;
|
||||
using QYZH.InteractiveMagazine.Models.Enum;
|
||||
using SqlSugar;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.PrintWorker.Consumers;
|
||||
|
||||
/// <summary>
|
||||
/// 自动铺码消费者。
|
||||
/// </summary>
|
||||
public class AutoDotCodeConsumer(
|
||||
IConfiguration configuration,
|
||||
IServiceScopeFactory scopeFactory,
|
||||
IHostEnvironment hostEnvironment,
|
||||
ILogger<AutoDotCodeConsumer> logger,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
OssService ossService) : IQueueConsumer
|
||||
{
|
||||
/// <summary>
|
||||
/// 交换机名称。
|
||||
/// </summary>
|
||||
public string Exchange => "ex.journal";
|
||||
|
||||
/// <summary>
|
||||
/// 队列名称。
|
||||
/// </summary>
|
||||
public string QueueName => "mq.journal.dotcode.auto";
|
||||
|
||||
/// <summary>
|
||||
/// 路由键。
|
||||
/// </summary>
|
||||
public string RoutingKey => "rk.journal.dotcode.auto";
|
||||
|
||||
/// <summary>
|
||||
/// 处理自动铺码消息。
|
||||
/// </summary>
|
||||
public async Task HandleAsync(byte[] body, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var message = Encoding.UTF8.GetString(body);
|
||||
logger.LogInformation("收到自动铺码消息: {Message}", message);
|
||||
|
||||
using var scope = scopeFactory.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>();
|
||||
|
||||
try
|
||||
{
|
||||
var request = JsonSerializer.Deserialize<JournalPagePrintDto>(message, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
});
|
||||
if (request == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var workDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "JournalPagePdf");
|
||||
var uploadDirectory = Path.Combine(workDirectory, "upload");
|
||||
var downloadDirectory = Path.Combine(workDirectory, "download");
|
||||
Directory.CreateDirectory(uploadDirectory);
|
||||
Directory.CreateDirectory(downloadDirectory);
|
||||
|
||||
var uploadFileName = $"upload_{request.JournalId}_{DateTime.Now:yyyyMMddHHmmssffffff}{Random.Shared.Next(1000, 9999)}.pdf";
|
||||
var uploadFilePath = Path.Combine(uploadDirectory, uploadFileName);
|
||||
|
||||
var journalPdfKey = request.JournalPdfUrl?.RemoveDomain();
|
||||
if (string.IsNullOrWhiteSpace(journalPdfKey))
|
||||
{
|
||||
logger.LogError("书籍上传 PDF 文件地址为空,JournalId: {JournalId}", request.JournalId);
|
||||
return;
|
||||
}
|
||||
|
||||
await using var pdfStream = ossService.GetObjectStream(journalPdfKey);
|
||||
if (pdfStream == null)
|
||||
{
|
||||
logger.LogError("获取书籍上传 PDF 文件失败,OSS Key: {OssKey}", journalPdfKey);
|
||||
return;
|
||||
}
|
||||
|
||||
await using (var fs = new FileStream(uploadFilePath, FileMode.CreateNew, FileAccess.Write))
|
||||
{
|
||||
await pdfStream.CopyToAsync(fs, cancellationToken);
|
||||
logger.LogInformation("书籍 PDF 已下载到本地,长度:{Length}", fs.Length);
|
||||
}
|
||||
|
||||
var dotId = configuration.GetValue("PrintConfig:DotId", 765837655859269);
|
||||
var dotFile = await dbContext.Queryable<DotFile>().FirstAsync(x => x.Id == dotId, cancellationToken);
|
||||
if (dotFile == null)
|
||||
{
|
||||
logger.LogError("配置打印数据错误,点阵文件不存在,DotId: {DotId}", dotId);
|
||||
return;
|
||||
}
|
||||
|
||||
var printToolDirectory = Path.Combine(hostEnvironment.ContentRootPath, "PrintToolV2.7");
|
||||
var exePath = Path.Combine(printToolDirectory, "PrintTool.exe");
|
||||
if (!File.Exists(exePath))
|
||||
{
|
||||
logger.LogError("PrintTool.exe 不存在,路径:{ExePath}", exePath);
|
||||
await ExecuteUpdateJournalStatusAsync(BuildFailResponse(request), cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
var xmlPath = Path.Combine(printToolDirectory, dotFile.FileName);
|
||||
if (!File.Exists(xmlPath))
|
||||
{
|
||||
logger.LogError("铺码授权文件不存在,路径:{XmlPath}", xmlPath);
|
||||
await ExecuteUpdateJournalStatusAsync(BuildFailResponse(request), cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
var downloadFileName = $"download_{request.JournalId}_{DateTime.Now:yyyyMMddHHmmssffffff}{Random.Shared.Next(1000, 9999)}_dot.pdf";
|
||||
var downloadFilePath = Path.Combine(downloadDirectory, downloadFileName);
|
||||
var dPrint = configuration.GetValue("PrintConfig:DPrint", 0);
|
||||
var pageNumMax = request.PageNum.Max(x => x);
|
||||
var dotFileDetailList = await dbContext.Queryable<DotFileDetail>()
|
||||
.Where(x => x.DotId == dotId && !x.IsUse)
|
||||
.OrderBy(x => x.Id)
|
||||
.Take(pageNumMax)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
if (dotFileDetailList.Count < pageNumMax)
|
||||
{
|
||||
logger.LogError("点阵页码余量不足,DotId: {DotId}, Need: {Need}, Available: {Available}", dotId, pageNumMax, dotFileDetailList.Count);
|
||||
await ExecuteUpdateJournalStatusAsync(BuildFailResponse(request), cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
var dotFileDetailPageName = dotFileDetailList.Select(x => x.PageName).OrderBy(x => x).ToArray();
|
||||
var pageStr = "{" + $"[{dotFileDetailList[0].PageName},{pageNumMax}]" + "}";
|
||||
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 printResult = await ExecutePrintToolAsync(exePath, printToolDirectory, arguments, cancellationToken);
|
||||
|
||||
if (printResult.Timeout || printResult.ExitCode != 0)
|
||||
{
|
||||
logger.LogError("执行 PrintTool.exe 失败,退出码:{ExitCode},错误信息:{ErrorMessage}", printResult.ExitCode, printResult.Error);
|
||||
await ExecuteUpdateJournalStatusAsync(BuildFailResponse(request, dotFileDetailPageName), cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
var statusModel = new JournalPagePrintDto
|
||||
{
|
||||
JournalId = request.JournalId,
|
||||
PageNo = dotFileDetailPageName
|
||||
};
|
||||
|
||||
if (!ValidatePrintOutput(printResult.Output, dotFileDetailPageName, dPrint))
|
||||
{
|
||||
statusModel.Status = JournalStatusEnum.CodeFail;
|
||||
await ExecuteUpdateJournalStatusAsync(statusModel, cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
var tempOssDownloadKey = "journal/download/" + downloadFileName;
|
||||
const int bufferSize = 1 * 1024 * 1024;
|
||||
await using var downloadFs = new FileStream(downloadFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, FileOptions.SequentialScan | FileOptions.Asynchronous);
|
||||
var downloadBookPagePdfName = ossService.PutObject(tempOssDownloadKey, downloadFs);
|
||||
var ossDomain = configuration.GetSection("AliyunOSSConfigs:Domain").Get<string>() ?? string.Empty;
|
||||
|
||||
statusModel.DownloadJournalPagePdfName = ossDomain + downloadBookPagePdfName;
|
||||
await downloadFs.DisposeAsync();
|
||||
|
||||
TryDeleteFile(uploadFilePath);
|
||||
TryDeleteFile(downloadFilePath);
|
||||
|
||||
statusModel.Status = JournalStatusEnum.CodeSuccess;
|
||||
var callbackResponse = await ExecuteUpdateJournalStatusAsync(statusModel, cancellationToken);
|
||||
if (callbackResponse.IsSuccess)
|
||||
{
|
||||
await dbContext.Ado.UseTranAsync(async () =>
|
||||
{
|
||||
foreach (var dotFileDetail in dotFileDetailList)
|
||||
{
|
||||
dotFileDetail.IsUse = true;
|
||||
dotFileDetail.UpdatedAt = DateTime.Now;
|
||||
}
|
||||
|
||||
await dbContext.Updateable(dotFileDetailList).ExecuteCommandAsync();
|
||||
await dbContext.Updateable<DotFile>()
|
||||
.SetColumns(x => x.TotalUse == x.TotalUse + dotFileDetailList.Count)
|
||||
.SetColumns(x => x.UpdatedAt == DateTime.Now)
|
||||
.Where(x => x.Id == dotId)
|
||||
.ExecuteCommandAsync();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogError("回调接口修改书籍状态失败,JournalId: {JournalId},接口返回消息:{Message}", statusModel.JournalId, callbackResponse.Message);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "自动铺码处理失败");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理消费异常。
|
||||
/// </summary>
|
||||
public Task OnErrorAsync(byte[] message, Exception exception)
|
||||
{
|
||||
var body = Encoding.UTF8.GetString(message);
|
||||
logger.LogError(exception, "处理自动铺码消息失败: {Message}", body);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task<PrintToolResult> ExecutePrintToolAsync(string exePath, string workingDirectory, string arguments, CancellationToken cancellationToken)
|
||||
{
|
||||
var printToolTimeoutSeconds = configuration.GetValue("PrintConfig:TimeoutSeconds", 300);
|
||||
var printToolTimeout = TimeSpan.FromSeconds(printToolTimeoutSeconds);
|
||||
var cmd = $"\"{exePath}\" {arguments}";
|
||||
logger.LogInformation("执行 PrintTool.exe 的命令: {Command},超时时间:{TimeoutSeconds} 秒", cmd, printToolTimeoutSeconds);
|
||||
|
||||
using var process = new Process();
|
||||
process.StartInfo = new ProcessStartInfo
|
||||
{
|
||||
WorkingDirectory = workingDirectory,
|
||||
FileName = exePath,
|
||||
Arguments = arguments,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
process.Start();
|
||||
var outputTask = process.StandardOutput.ReadToEndAsync(cancellationToken);
|
||||
var errorTask = process.StandardError.ReadToEndAsync(cancellationToken);
|
||||
var timeout = false;
|
||||
|
||||
try
|
||||
{
|
||||
await process.WaitForExitAsync(cancellationToken).WaitAsync(printToolTimeout, cancellationToken);
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
timeout = true;
|
||||
logger.LogError("执行 PrintTool.exe 超时,准备终止进程树,超时时间:{TimeoutSeconds} 秒,命令:{Command}", printToolTimeoutSeconds, cmd);
|
||||
process.Kill(entireProcessTree: true);
|
||||
await process.WaitForExitAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
var output = await outputTask;
|
||||
var error = await errorTask;
|
||||
var exitCode = process.ExitCode;
|
||||
|
||||
logger.LogInformation("执行 PrintTool.exe 后,退出码:{ExitCode},stdout:{Output}", exitCode, output);
|
||||
if (!string.IsNullOrWhiteSpace(error))
|
||||
{
|
||||
logger.LogWarning("执行 PrintTool.exe 后,stderr:{ErrorMessage}", error);
|
||||
}
|
||||
|
||||
return new PrintToolResult(output, error, exitCode, timeout);
|
||||
}
|
||||
|
||||
private bool ValidatePrintOutput(string output, string[] dotFileDetailPageName, int dPrint)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(output))
|
||||
{
|
||||
logger.LogInformation("执行铺码程序没有任何输出");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dPrint == 0)
|
||||
{
|
||||
var pageNoList = JsonSerializer.Deserialize<string[]>(output) ?? [];
|
||||
return pageNoList.OrderBy(x => x).SequenceEqual(dotFileDetailPageName.OrderBy(x => x), StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
return dotFileDetailPageName.AsParallel().Any(ip => output.Contains(ip, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private async Task<CallbackUpdateJournalStatusResponse> ExecuteUpdateJournalStatusAsync(JournalPagePrintDto request, CancellationToken cancellationToken)
|
||||
{
|
||||
var client = httpClientFactory.CreateClient();
|
||||
var callbackUrl = configuration.GetValue<string>("PrintConfig:CallBackApiUrl");
|
||||
var callbackRequest = new HttpRequestMessage(HttpMethod.Post, callbackUrl)
|
||||
{
|
||||
Content = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
var response = await client.SendAsync(callbackRequest, cancellationToken);
|
||||
if (response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
var responseContent = await response.Content.ReadAsStringAsync(cancellationToken);
|
||||
logger.LogInformation("回调接口返回内容:{ResponseContent}", responseContent);
|
||||
return JsonSerializer.Deserialize<CallbackUpdateJournalStatusResponse>(responseContent, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
}) ?? new CallbackUpdateJournalStatusResponse();
|
||||
}
|
||||
|
||||
return new CallbackUpdateJournalStatusResponse();
|
||||
}
|
||||
|
||||
private static JournalPagePrintDto BuildFailResponse(JournalPagePrintDto request, string[]? pageNo = null)
|
||||
{
|
||||
return new JournalPagePrintDto
|
||||
{
|
||||
JournalId = request.JournalId,
|
||||
PageNo = pageNo ?? [],
|
||||
Status = JournalStatusEnum.CodeFail
|
||||
};
|
||||
}
|
||||
|
||||
private void TryDeleteFile(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogWarning(ex, "删除临时文件失败,路径:{FilePath}", filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed record PrintToolResult(string Output, string Error, int ExitCode, bool Timeout);
|
||||
|
||||
internal class CallbackUpdateJournalStatusResponse
|
||||
{
|
||||
public string? Message { get; set; }
|
||||
|
||||
public string? Code { get; set; }
|
||||
|
||||
public bool Result { get; set; }
|
||||
|
||||
public bool IsSuccess { get; set; }
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
namespace QYZH.InteractiveMagazine.PrintWorker.Consumers;
|
||||
|
||||
/// <summary>
|
||||
/// 队列消费者接口。
|
||||
/// </summary>
|
||||
public interface IQueueConsumer
|
||||
{
|
||||
/// <summary>
|
||||
/// 交换机名称。
|
||||
/// </summary>
|
||||
string Exchange { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 队列名称。
|
||||
/// </summary>
|
||||
string QueueName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 路由键。
|
||||
/// </summary>
|
||||
string RoutingKey { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 处理消息。
|
||||
/// </summary>
|
||||
Task HandleAsync(byte[] message, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 处理消费异常。
|
||||
/// </summary>
|
||||
Task OnErrorAsync(byte[] message, Exception exception);
|
||||
}
|
||||
@ -0,0 +1,105 @@
|
||||
using QYZH.InteractiveMagazine.Infrastructure.RabbitMQ;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.PrintWorker.Consumers;
|
||||
|
||||
/// <summary>
|
||||
/// RabbitMQ 消费者后台服务。
|
||||
/// </summary>
|
||||
public class RabbitMQHostedService(IServiceProvider serviceProvider, ILogger<RabbitMQHostedService> logger) : BackgroundService
|
||||
{
|
||||
/// <summary>
|
||||
/// 启动所有已注册队列消费者。
|
||||
/// </summary>
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
using var scope = serviceProvider.CreateScope();
|
||||
var consumers = scope.ServiceProvider.GetServices<IQueueConsumer>().ToList();
|
||||
|
||||
if (consumers.Count == 0)
|
||||
{
|
||||
logger.LogWarning("未注册任何队列消费者");
|
||||
return;
|
||||
}
|
||||
|
||||
var tasks = consumers.Select(c => StartConsumerAsync(c, stoppingToken)).ToList();
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
private async Task StartConsumerAsync(IQueueConsumer queueConsumer, CancellationToken stoppingToken)
|
||||
{
|
||||
var queueName = queueConsumer.QueueName;
|
||||
var exchange = queueConsumer.Exchange;
|
||||
var routingKey = queueConsumer.RoutingKey;
|
||||
logger.LogInformation("正在启动消费者 {QueueName}, Exchange: {Exchange}, RoutingKey: {RoutingKey}", queueName, exchange, routingKey);
|
||||
|
||||
try
|
||||
{
|
||||
var rabbitMQService = serviceProvider.GetRequiredService<IRabbitMQService>();
|
||||
await rabbitMQService.ReceiveAsync(exchange, queueName, routingKey, async (channel, ea) =>
|
||||
{
|
||||
var dlqName = $"{queueName}.dlq";
|
||||
var dlqRoutingKey = $"{routingKey}.dlq";
|
||||
await channel.QueueDeclareAsync(queue: dlqName, durable: true, exclusive: false, autoDelete: false, arguments: null);
|
||||
await channel.QueueBindAsync(queue: dlqName, exchange: exchange, routingKey: dlqRoutingKey, arguments: null);
|
||||
|
||||
using var messageScope = serviceProvider.CreateScope();
|
||||
var consumer = messageScope.ServiceProvider
|
||||
.GetServices<IQueueConsumer>()
|
||||
.First(c => c.QueueName == queueName);
|
||||
|
||||
try
|
||||
{
|
||||
await consumer.HandleAsync(ea.Body.ToArray(), stoppingToken);
|
||||
await channel.BasicAckAsync(ea.DeliveryTag, false, stoppingToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "消费者 {QueueName} 处理消息异常", queueName);
|
||||
var dlqSent = await SendToDeadLetterQueueAsync(exchange, dlqName, dlqRoutingKey, ea.Body.ToArray(), stoppingToken);
|
||||
await channel.BasicNackAsync(ea.DeliveryTag, false, !dlqSent, stoppingToken);
|
||||
|
||||
try
|
||||
{
|
||||
await consumer.OnErrorAsync(ea.Body.ToArray(), ex);
|
||||
}
|
||||
catch (Exception errorEx)
|
||||
{
|
||||
logger.LogError(errorEx, "消费者 {QueueName} OnErrorAsync 执行异常", queueName);
|
||||
}
|
||||
}
|
||||
}, stoppingToken);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
logger.LogInformation("消费者 {QueueName} 已停止", queueName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "消费者 {QueueName} 启动失败", queueName);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> SendToDeadLetterQueueAsync(string exchange, string dlqName, string dlqRoutingKey, byte[] body, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var rabbitMQConnection = serviceProvider.GetRequiredService<IRabbitMQConnection>();
|
||||
using var channel = await rabbitMQConnection.CreateChannel();
|
||||
await channel.QueueDeclareAsync(queue: dlqName, durable: true, exclusive: false, autoDelete: false, arguments: null);
|
||||
await channel.QueueBindAsync(queue: dlqName, exchange: exchange, routingKey: dlqRoutingKey, arguments: null);
|
||||
|
||||
var properties = new RabbitMQ.Client.BasicProperties
|
||||
{
|
||||
Persistent = true
|
||||
};
|
||||
await channel.BasicPublishAsync(exchange, dlqRoutingKey, false, properties, body, cancellationToken);
|
||||
logger.LogInformation("消息已发送到死信队列: {DlqName}", dlqName);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "发送消息到死信队列 {DlqName} 失败", dlqName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
QYZH.InteractiveMagazine.PrintWorker/PrintToolV2.7/PrintTool.exe
Normal file
BIN
QYZH.InteractiveMagazine.PrintWorker/PrintToolV2.7/PrintTool.exe
Normal file
Binary file not shown.
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<licensecontainer version="1.0">
|
||||
<license level="0" name="Root license segment 1714" owner="WWZN" info="segment 1714" type="enterprise" guid="segment 1714" parentid="0">
|
||||
<page width="11720" height="11720" />
|
||||
<time expire="20320804" creation="20220804" />
|
||||
<user id="0" />
|
||||
<pattern category="enterprise">
|
||||
<pageaddress start="1714.0.0.0" stop="1714.5725.52.107" pagesnum="32775624" />
|
||||
</pattern>
|
||||
<permissions nbrof="3">
|
||||
<permission id="0" value="1" name="sublicense" />
|
||||
<permission id="1" value="1" name="deallocate" />
|
||||
<permission id="2" value="1" name="print" />
|
||||
</permissions>
|
||||
<signature value="60B9021C6ED19218AE728B101A37B6E6212D0BAF7F0D9213E936AC26885AF4A7B7BD02B4B09951A03E6EC4FFED408D55F5743DEDBBC05419FD87FC14E7119A282696CD8DD1A05F6ACC135A18903B3408C60FCF884C52737A70691828BD7E8225D595FE3BA1978CA6D4CEB8874E4BB88DBE68DDC2A3D8A25209B06C5ED35059B248B3F5E737A1A8B298802F9787600490D64BF9A634B0A018A9B9BB58CD9A33F785378F3E1DD702B8B747DD2307AE1DA578E3B4444F90686B1EFE1DD8AF25DE5CE60D986392FF9BD1417F45578A4D571AC3B43737308136E6F4C3AE1D289F0CD7FAC1BC70DF0052734D4360EC71BD575C84EAEADA6FD89AA6F5960FA59143A4C11B9FEE89DC816537232CB65F40D63A9C84C2E0181CD2D0B9FA470FB4B60DA7D5FBC610C3FA7276F56D02CC27CC805D4F7CB8E84D2BD39F277D0E402FD5B4F17449D36CB1A767452BE74E446D1D145A4646FE56325B26AE2B82AA51DAB48F8148FEB71BA61D1ED2F7260ED5A6673AF9D168FA32D5C4B2603406B98EC1B8EDBF29D0B8CA375B38036FA4348AC9B5E99CCB82D9B2A077F00889F04ADA25EA6FDCDAB18B425A51FB9E6C561DC077BBDBDF5BA15F79B56F30D0466839107C4DE5417ADA049A21657C5DD5A918EBAFF7CE31DF266486D4ADCC603125C804F7626EA5D8195A4DA1B28D5D89479C0F924052B826D658D8775A6683CB696EA3500E5963E2" />
|
||||
</license>
|
||||
<license level="3" name="license_1714.0.0.0_10" owner="WWZN" info="segment 1714" type="CommonB2B" guid="1714.0.0.0_10" parentid="1714.0.0.0_100">
|
||||
<page width="11720" height="11720" />
|
||||
<time expire="20340914" creation="20240914" />
|
||||
<user id="10" />
|
||||
<pattern category="enterprise">
|
||||
<pageaddress start="1714.0.0.0" stop="1714.0.0.9" pagesnum="10" />
|
||||
</pattern>
|
||||
<permissions nbrof="3">
|
||||
<permission id="0" value="1" name="sublicense" />
|
||||
<permission id="1" value="1" name="deallocate" />
|
||||
<permission id="2" value="1" name="print" />
|
||||
</permissions>
|
||||
<signature value="072C8A792D29FCA47FA1B73C351DD54A790D6832C70D63FBFB8BC4A71907292838C715C228AAD371F227909D387BE2F5C4609D3CAFC14B024FF65A709604DAC352AE4E595A318F69A1B828986D27B3EEEEDA4BD445E24FF386434FA8248622271148A73C49427F72C4F93C631D5195FDB3FB7066D7A2DBCA9CC67E2BA72A159C587AC35EBA22EEFEE35372DF2E2E3F889CF1E4CFF9E80E7AAB5B2FFB8D171024D210AAF47D5EB153E61491552C616F0D9D0B9E5EF9BF1AAC58498A684D9F5E38A977DE183EDAD297366AD4535D80579DA6CC31A28AE8CA26C9FEE716122F522AAA337084C06661386EB1F648698793D226CAB29FC9E3CD9FB9E24D6CDB65AF98" />
|
||||
<publickey value="MIIBCgKCAQEA0Bks5DguPRXGmTv5BuO232FipFpIGDia3tBollUILdmC7y3L/VnF6ZYl9aYyLYipZSLCJy9yRehF4TDebBIN3d6k4Tgamm2weuOqPmmzyZxALCz/aCJxW5l+8N+ie1t2uUj4srB7LGhboUqbQM3VeFlhIxM7wrMLnvlEdreC1raFSmHK+BNIlf9e9ATvV853p/qcu8S9yjrcfhrBkHjTBoOkn9CmZEm9UD/Oybrv/RKtvN0VuaNZ5+uWX3JxEDellzWU75D/QiimpCTTiLKxTzoZuBNmqLd5dAqORRzpcoggwMb0wey3gp3Cuh747DSIN3sdaUt3sO3LqMxKVzSDeQIDAQAB" />
|
||||
</license>
|
||||
</licensecontainer>
|
||||
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<licensecontainer version="1.0">
|
||||
<license level="0" name="Root license segment 1761" owner="WWZN" info="segment 1761" type="enterprise" guid="segment 1761" parentid="0">
|
||||
<page width="11720" height="11720" />
|
||||
<time expire="20340105" creation="20240105" />
|
||||
<user id="0" />
|
||||
<pattern category="enterprise">
|
||||
<pageaddress start="1761.0.0.0" stop="1761.5725.52.107" pagesnum="32775624" />
|
||||
</pattern>
|
||||
<permissions nbrof="3">
|
||||
<permission id="0" value="1" name="sublicense" />
|
||||
<permission id="1" value="1" name="deallocate" />
|
||||
<permission id="2" value="1" name="print" />
|
||||
</permissions>
|
||||
<signature value="CFB548ACD8A9ACC0FDF9BD35026E3F4F53A17EC218D4EDEFE87478862EBD45DE1A278D337640CD8C619F4044DB328E6E39CD000BEE4CB35214222C182EE457F1CA113BEFCF6F1C9770699A219CEDF878AE4CC368489BC76D949993272380F071F2E189EB42DFB4401E407F0C15972F48E9A84878E9FC8AF3DE8AA37ECCE0867C0443FE0566CAB1B8C614C9355BEF808CEC3C085ED4CC44ABED9EA131462DB21BA37EE83350493D664C5FC75B14E52391D1897351B2961610BE69FC4CF5231C315A7A55BA3EDA814DF4E1E77BE04A0413D95470EB546DAF40F590E7E75090FDA3EF1B18A15C3D36824673FA07685BD3E8993E074E5231FF8B2E7224373234AFCF98C9B2950D2F48D7F2EE4642DE08BA8D96609544E37BAD38620929E9BF16B02AD54774C5A1CFAF72B07078622AB48D2753902646A5FA54F3AE89918997C0258F5B82161083FA8CFC4A1C7A0E7DC20CABA6DC4653AEF764717616A91DF910C4A67F8BADAAA41F118FC3110110597BE6383E52CC4FF666EF883E6B49FF6B6514361EE2373DD50B21F391BEDC800B691346DCDEB63F456910528AF75E6591F17EA1DE0406E5C8693BF5D41AAB1010F8C5841468A03F0A3572B569220AE1B14CF8BD26FDCDC1FE8C013D2FF8FAEC3E8010380DABF8DC1CAFB95E21BB5DD9457AE81772DDF4ADAD35516454255BD1A1F486BB7E49BD740D5760D150087C22C7EDCACB" />
|
||||
</license>
|
||||
<license level="2" name="license_1761.172.8.16_1000" owner="TStudy" info="segment 1761" type="CommonB2B" guid="1761.172.8.16_1000" parentid="1761.0.0.0_1000000">
|
||||
<page width="8512" height="8512" />
|
||||
<time expire="20350526" creation="20250526" />
|
||||
<user id="10" />
|
||||
<pattern category="enterprise">
|
||||
<pageaddress start="1761.172.8.16" stop="1761.172.17.43" pagesnum="726" />
|
||||
</pattern>
|
||||
<permissions nbrof="3">
|
||||
<permission id="0" value="1" name="sublicense" />
|
||||
<permission id="1" value="1" name="deallocate" />
|
||||
<permission id="2" value="1" name="print" />
|
||||
</permissions>
|
||||
<signature value="D269EB10C3A3B02E1523F5DEC3B145A3BD163382891F7DC5D67122601359D9650C4F0933DFCE7BC79DCAF5213198670CCCA865554D4AAF6E6F8991016A1F3D8F0E8D002310104C4E21C7FB54A14DEEAB1663508435D66420C8FC6FDB7099EFE2FF01527AC0B88B80D64F77179C9C7A21164564CD2D9FE206BB6EEC0A4B89651E9D8CD4AAF8B02E877BB5057B35216B5B8F0AD8D170AD478405F5735F78D0AC8BE9D0C01277C6F553CFAABE165DB62ABA000990CAAE12CA87C46DEC208300DB8DE0233E8960230633BC963B4AC70882E1801FE9A645BAAEB02AF0D814690FDEB2E5BFC197F1D1D6F949E1CBB9F0E2DBEA3ECB6C2EF2A68D3B3EBE74463F2717F6" />
|
||||
<publickey value="MIIBCgKCAQEA2p7xGRjlYIzrulumRkCiH/c7ZGZj8lc6b7SUVk7y31ZmDi69VQx8Ugw59En4lrsGBIc/I2ua1n8oZYZ0RhaPaPnqZ/c/lSrVsv8ZC7I4gq8Bl/sOByh9W5+OTFT7bUpg7h/eTD9mHuucIIksgjhGt1SRpLPy8+XQqYfoetxBK9dR13K/XcFTqFvy6z0osT60VA4dcjzvCBbKnpMT4H5sufQX11gMhtFu9v5f7cVQXiMjip/mVQpn4fYOZ3BO6Qtb6McOw5JgHOK24jvYvwz4AaAiYqg5ItNGZhkZolWXY8j0ee+WX/64fL/apDJvY//2c5NsQ2GYIKX5pUDJ2McC8wIDAQAB" />
|
||||
</license>
|
||||
</licensecontainer>
|
||||
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<licensecontainer version="1.0">
|
||||
<license level="0" name="Root license segment 1761" owner="WWZN" info="segment 1761" type="enterprise" guid="segment 1761" parentid="0">
|
||||
<page width="11720" height="11720" />
|
||||
<time expire="20341025" creation="20241025" />
|
||||
<user id="0" />
|
||||
<pattern category="enterprise">
|
||||
<pageaddress start="1761.0.0.0" stop="1761.5725.52.107" pagesnum="32775624" />
|
||||
</pattern>
|
||||
<permissions nbrof="3">
|
||||
<permission id="0" value="1" name="sublicense" />
|
||||
<permission id="1" value="1" name="deallocate" />
|
||||
<permission id="2" value="1" name="print" />
|
||||
</permissions>
|
||||
<signature value="846682277F67BD118D24382FBC6DD09AF3E0A921A677F96C34B69E46C951CAC4FDD373E3652EC8FEC18FABA8CA9FAACB19E544447023DAD11CBB6EBB8389A714756395E8CA882F980FB6ED3778DFF6108C90401A43D93CD68A26B362D243FA0F160221506ADA7D031126792DC494CB4CC99C099FC8E05C19CF365D1740B2C907D7393FB73E18642236936E43F2A8FAF21E970269A5ED76BA4231F08C690D4D5D425F637AF4A38FEA4F016609696153708983F373C12EC7533D4B2CDAA496A5FA3916497FA64524D56695C58E48C71F29008EE0BD4EC5B7DBA24BCB2395FAA0D36CFEF2B63C3BC230FBDF04A56F20712FB261F5EBBF1A9E18EF3A4DF998C810248ED7F94C13F5302496914896CD3EA05D92B2B784411796D1D3B5FB00B3B2E6ADDBD68E481A9306785C05C53088DE795CE2F46E1EEAE75E80CEA8F5FF4B08B9A356C543D34B036463D699A6E4131DE9B685364A78D66455A1173823B378CA64359497E8B7E52C7E60EEAC74C1C7F991FE9F62E55DE121010820611C61E70457B5FE12AA7A0DCEEF28AE369DFE6CFB6DE4B0DDE770A4262C209C163EB31DA1150D8AF5886A792438F91A1727DB71E8AEE4247E05ECD7A5C1392260E9CFD186989B71695F308C97EC6A1F7008D90BAA1746CABB60F7A078BBF347514CC98D1AEA380946F438C0B777128E5A72FEB85FDEF16F065C93E70884BB77536CC7DEEFF01F" />
|
||||
</license>
|
||||
<license level="2" name="license_1761.211.21.48_10000" owner="CQQY" info="segment 1761" type="CommonB2B" guid="1761.211.21.48_10000" parentid="1761.174.38.0_1000000">
|
||||
<page width="8512" height="8512" />
|
||||
<time expire="20360122" creation="20260122" />
|
||||
<user id="1" />
|
||||
<pattern category="enterprise">
|
||||
<pageaddress start="1761.211.21.48" stop="1761.213.8.3" pagesnum="10000" />
|
||||
</pattern>
|
||||
<permissions nbrof="3">
|
||||
<permission id="0" value="1" name="sublicense" />
|
||||
<permission id="1" value="1" name="deallocate" />
|
||||
<permission id="2" value="1" name="print" />
|
||||
</permissions>
|
||||
<signature value="0BA47A5B9A71CF0680CE1CA41A58FF4DAAA97CD168F331494142150E8BD5A8E93F1369FD8CF026EE577F041C1F8A95D408FC4286BEE366D967DD604D2D482E2105004048C0690D637983591893CE7DC7CEBAEEC9C9569ED62955D044F21769BFE060961413818202E5BDE0216215300BF75238A08A681461DDC539ADB11DA9C3DC5F0B1E3FCDBE70A8F3E39F9FB30F74468DDC93F5D1105B8B8B99F52E13DBAC2C828DF493852037A44B7E6D22D2EAE85942A4F45ECD26F3D17E94EC63226E5A5334DF61781F20B9B65A8B7055950BA15A55D935DFE4A76A8CB4C8C9EDCF7BDDA1C03B6C64CAB8BBECC51684B7F9FD39F17F747F954A8EC3C0D90409FEE30CF5" />
|
||||
<publickey value="MIIBCgKCAQEAvKvG8GB+Q8GzBGalOEUlLKQlCQG1nmjX3n+ErjuclTUgpo7Ai0akc+77aZV3sbLgVEr1o6TuuHb+aijmJfq6raOW3W5GobAKt6i4QIGWBfzJ3V3YlpTadIWVMYcjSR2tCh4shT4mkQg4DDBT6CvuBSOLuEu8qKtBiNGAikm2Hn3kmeGM4Oy5fKam4GSO3cHEIKgWQES5AMae6KyQmcrxtlFNciFgO+/DfDGSo94QjvMURdyg+kysOAiANxXqEbH1SiDeiQEGeOCQROq2j8T6zJ96mxyYZCuaLxE2Uh5LSxYolLVKw1kq+ukeve23LXvvEV5miZmKQB5NUhRFvU6JIwIDAQAB" />
|
||||
</license>
|
||||
</licensecontainer>
|
||||
Binary file not shown.
BIN
QYZH.InteractiveMagazine.PrintWorker/PrintToolV2.7/wfdprint.dll
Normal file
BIN
QYZH.InteractiveMagazine.PrintWorker/PrintToolV2.7/wfdprint.dll
Normal file
Binary file not shown.
@ -0,0 +1,31 @@
|
||||
调用PrintTool.exe增加参数,说明如下:
|
||||
1、-sMode=Generate (必须)
|
||||
2、-sPDF=源文件pdf格式的完整路径(必须)
|
||||
3、-sLIC=铺码资源文件完整路径(必须)
|
||||
4、-oPDF=生成pdf文件的完整路径(必须)
|
||||
5、-dType=点阵形状,0:方点,1:圆点,默认为0(可选)
|
||||
6、-dPrint=打印场景,0:普通激光打印机,1:工业印刷,默认为0(可选)
|
||||
7、-pStart=数字,整数,可以制定资源文件从第几个编号开始铺码(非必须,默认0,表示从资源的剩余页码开始,每次铺码成功后点阵资源会相应减少;大于0时点阵资源不会减少,pStart=1时表示从第一页开始铺码)
|
||||
8、-dPageAddr=是否显示点阵页码地址,0:不显示,1:显示,默认为0(可选)
|
||||
9、-sPrinter=打印机名称(必须)
|
||||
10、-dPageStart=数字,设置打印起始页码,1表示从第一页开始打印,0:全部打印,默认0(可选)
|
||||
11、-dPageEnd=数字,设置打印结束页码,0:全部打印,默认0(可选)
|
||||
12、-dCopy=数字,设置打印份数,默认1(可选)
|
||||
13、-dKValue=数字,设置码点颜色深度,取值范围50-100,默认100,比如取值90表示k值为90%(可选)
|
||||
14、-dDotSize=数字,设置码点大小,取值范围30-50,默认40(可选),方点仅支持40
|
||||
15、-dOutFile=数字,0:只生成带点阵pdf文件,1:只生成纯点阵文件,2:既生成纯点阵文件也生成带点阵pdf文件,默认为0(可选)
|
||||
|
||||
16、-dControlPageNum={[页地址,连续数量],[页地址,连续数量]...} 可一个pdf有多段页码段,默认从第一页开始(可选)(最后一段若是不想数pdf剩下多少页,可直接放0默认用最后字段铺完剩下的页)
|
||||
|
||||
说明:
|
||||
当-dOutFile=2时,纯点阵文件名为输入的-oPDF参数,带点阵pdf文件名为在-oPDF参数后加上"_dp",即"D:\pdf\28_dot_dp.pdf"。
|
||||
|
||||
示例:
|
||||
制作点阵:
|
||||
-sMode=Generate -sPDF="D:\pdf\28.pdf" -sLIC="D:\Root licnese segment 70_70.0.0.0_100.xml" -oPDF="D:\pdf\28_dot.pdf" -pStart=1
|
||||
|
||||
制作纯点阵文件:
|
||||
-sMode=Generate -sPDF="D:\pdf\28.pdf" -sLIC="D:\Root licnese segment 70_70.0.0.0_100.xml" -oPDF="D:\pdf\28_dot.pdf" -dOutFile=1
|
||||
|
||||
打印:
|
||||
-sMode=Print -sPDF="D:\pdf\28_dot.pdf" -sPrinter="HP LaserJet Professional M1216nfh MFP (副本 1)" -dPageStart=2 -dPageEnd=3 -dCopy=5
|
||||
13
QYZH.InteractiveMagazine.PrintWorker/PrintToolV2.7/返回值说明.txt
Normal file
13
QYZH.InteractiveMagazine.PrintWorker/PrintToolV2.7/返回值说明.txt
Normal file
@ -0,0 +1,13 @@
|
||||
0:成功
|
||||
-1:未知错误
|
||||
-2、-105:输入参数错误
|
||||
-6:读取pdf信息失败
|
||||
-5、-7:加载授权文件失败
|
||||
-8:授权文件页码数量不够或页面尺寸不匹配
|
||||
-10:生成码点失败
|
||||
-11到-15:生成pdf失败
|
||||
-30:程序异常,触发保护机制
|
||||
-31: 传入起始页码不在资源范围内
|
||||
-32:传入起始页码+连续铺码数量大于资源文件剩余可使用页数
|
||||
-33:中间页码连续数量为0
|
||||
-34:预计铺码数量大于PDF的页数
|
||||
59
QYZH.InteractiveMagazine.PrintWorker/Program.cs
Normal file
59
QYZH.InteractiveMagazine.PrintWorker/Program.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using QYZH.InteractiveMagazine.Infrastructure.RabbitMQ;
|
||||
using QYZH.InteractiveMagazine.Infrastructure.Redis;
|
||||
using QYZH.InteractiveMagazine.Infrastructure.SDK;
|
||||
using QYZH.InteractiveMagazine.PrintWorker.Consumers;
|
||||
using Serilog;
|
||||
using SqlSugar;
|
||||
using SqlSugar.IOC;
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
var builder = Host.CreateApplicationBuilder(args);
|
||||
|
||||
builder.Configuration
|
||||
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true);
|
||||
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.ReadFrom.Configuration(builder.Configuration)
|
||||
.Enrich.FromLogContext()
|
||||
.CreateLogger();
|
||||
|
||||
builder.Services.AddSerilog();
|
||||
builder.Services.AddWindowsService(options => options.ServiceName = "QYZH InteractiveMagazine PrintWorker");
|
||||
|
||||
YitIdHelper.SetIdGenerator(new IdGeneratorOptions { WorkerId = 3 });
|
||||
|
||||
builder.Services.AddSqlSugar(new IocConfig
|
||||
{
|
||||
ConfigId = 0,
|
||||
DbType = IocDbType.MySql,
|
||||
ConnectionString = builder.Configuration.GetConnectionString("DefaultConnection"),
|
||||
IsAutoCloseConnection = true
|
||||
});
|
||||
|
||||
SugarIocServices.ConfigurationSugar(db =>
|
||||
{
|
||||
db.Aop.OnLogExecuting = (sql, pars) =>
|
||||
{
|
||||
Log.Information("[SQL] {Sql}", UtilMethods.GetSqlString((DbType)IocDbType.MySql, sql, pars));
|
||||
};
|
||||
db.Aop.OnError = ex =>
|
||||
{
|
||||
Log.Error(ex, "[SQL Error] {Message}", ex.Message);
|
||||
};
|
||||
});
|
||||
|
||||
builder.Services.AddScoped<ISqlSugarClient>(_ => DbScoped.SugarScope);
|
||||
builder.Services.AddCSRedisCacheExtension(builder.Configuration.GetSection("RedisSettings"));
|
||||
builder.Services.AddHttpClient();
|
||||
builder.Services.AddSDKService(builder.Configuration);
|
||||
builder.Services.AddRabbitMQ(builder.Configuration);
|
||||
|
||||
builder.Services.AddScoped<IQueueConsumer, AutoDotCodeConsumer>();
|
||||
builder.Services.AddHostedService<RabbitMQHostedService>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
Log.Information("PrintWorker 已启动,仅消费自动铺码队列");
|
||||
|
||||
await app.RunAsync();
|
||||
@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Worker">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\QYZH.InteractiveMagazine.Common\QYZH.InteractiveMagazine.Common.csproj" />
|
||||
<ProjectReference Include="..\QYZH.InteractiveMagazine.Models\QYZH.InteractiveMagazine.Models.csproj" />
|
||||
<ProjectReference Include="..\QYZH.InteractiveMagazine.Infrastructure\QYZH.InteractiveMagazine.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
|
||||
<PackageReference Include="MySqlConnector" Version="2.5.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
|
||||
<PackageReference Include="SqlSugar.IOC" Version="2.0.1" />
|
||||
<PackageReference Include="SqlSugarCoreNoDrive" Version="5.1.4.213" />
|
||||
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="PrintToolV2.7\**\*">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
85
QYZH.InteractiveMagazine.PrintWorker/appsettings.json
Normal file
85
QYZH.InteractiveMagazine.PrintWorker/appsettings.json
Normal file
@ -0,0 +1,85 @@
|
||||
{
|
||||
"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,
|
||||
"UserName": "smartschool",
|
||||
"Password": "@ss%&*otz%d*pq2S",
|
||||
"VirtualHost": "InteractiveMagazine"
|
||||
},
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Warning",
|
||||
"System": "Warning",
|
||||
"Hangfire": "Information"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console"
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Args": {
|
||||
"path": "logs/worker-log-.txt",
|
||||
"rollingInterval": "Day"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"HangfireJobs": {
|
||||
"_说明": "定时任务配置。新增任务只需在 Jobs 数组中追加一项。Cron格式:分 时 日 月 星期(5位)。常用:* * * * * 每分钟 | */5 * * * * 每5分钟 | 0 * * * * 每小时 | 0 9 * * * 每天9点 | 0 0 * * 1 每周一午夜",
|
||||
"Jobs": [
|
||||
{
|
||||
"Name": "sample-job",
|
||||
"JobType": "QYZH.InteractiveMagazine.WorkService.Jobs.SampleJob",
|
||||
"MethodName": "ExecuteAsync",
|
||||
"Cron": "* * * * *",
|
||||
"Enabled": false,
|
||||
"Description": "示例任务(默认关闭,仅用于验证框架运行)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"AiChat": {
|
||||
"ApiKey": "Ollama",
|
||||
"BaseUrl": "http://172.16.10.130:11434/v1/",
|
||||
"Model": "qwen2.5vl:7b",
|
||||
"TimeoutSeconds": 300,
|
||||
"MaxTokens": 2000,
|
||||
"Temperature": 0.5,
|
||||
"ScoreMaxRetryCount": 3,
|
||||
"ScoreRetryDelayMilliseconds": 1000,
|
||||
"MaxImageBytes": 10485760
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"AliyunOSSConfigs": {
|
||||
"AccessKeyID": "LTAI5tEBXGewpHSLiSxyx6Bf",
|
||||
"AccessKeySecret": "w29b8wkw6XQVL8GWXgp3ZesgYeDKvf",
|
||||
"VodBucketName": "outin-5277bbb52bec11f08dbd00163e169e2b.oss-cn-beijing.aliyuncs.com",
|
||||
"BucketName": "qyzh2025test",
|
||||
"Region": "beijing",
|
||||
"RoleArn": "acs:ram::1064745380176636:role/aliyunosstokengeneratorrole",
|
||||
"DurationSeconds": 3600, //过期时间(秒)
|
||||
"Endpoint": "oss-cn-beijing.aliyuncs.com",
|
||||
"ProjectName": "InteractiveMagazine",
|
||||
"Domain": "http://oss-test.qyzhjy.com/"
|
||||
},
|
||||
"PrintConfig": {
|
||||
"TimeoutSeconds": 300,
|
||||
"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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user