refactor: 重构RabbitMQ消费者体系,新增自动铺码功能
1. 新增AutoDotCodeConsumer自动铺码消费者,实现统一的交换机路由绑定 2. 重构RabbitMQ接收方法,支持交换机、路由键配置,添加死信队列处理 3. 重构现有JournalTaskReceiveConsumer,使用标准交换机路由配置 4. 更新JournalPageService,将打印逻辑替换为自动铺码消息发送 5. 调整枚举类型,重构任务类型命名 6. 更新实体和DTO,新增Prompt相关字段 7. 添加PrintToolV2.7配套工具和文档 8. 清理冗余的PrintJournalPageAsync接口
This commit is contained in:
@ -18,12 +18,6 @@ public interface IJournalPageService: IBaseService<JournalPage>
|
||||
/// <returns></returns>
|
||||
Task<bool> UpdatePageNoAsync(long JournalId);
|
||||
|
||||
/// <summary>
|
||||
/// 打印书页(全部)
|
||||
/// </summary>
|
||||
/// <param name="JournalId"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> PrintJournalPageAsync(long JournalId);
|
||||
|
||||
Task<JournalPageV2Output> DetailAsync(long id);
|
||||
Task<bool> DeleteAsync(long id);
|
||||
|
||||
@ -9,6 +9,6 @@ namespace QYZH.InteractiveMagazine.Infrastructure.RabbitMQ
|
||||
|
||||
Task<bool> SendBatchAsync(IEnumerable<RabbitMQSendParam> @params, CancellationToken cancellationToken = default);
|
||||
|
||||
Task ReceiveAsync(string queueName, Func<IChannel, BasicDeliverEventArgs, Task> callback, CancellationToken cancellationToken = default);
|
||||
Task ReceiveAsync(string exchange, string queueName, string routingKey, Func<IChannel, BasicDeliverEventArgs, Task> callback, CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,18 +26,17 @@ namespace QYZH.InteractiveMagazine.Infrastructure.RabbitMQ
|
||||
{
|
||||
using var channel = await _connection.CreateChannel();
|
||||
|
||||
// 启用发布者确认
|
||||
//var channelOpts = new CreateChannelOptions
|
||||
//(
|
||||
// publisherConfirmationsEnabled: true,
|
||||
// publisherConfirmationTrackingEnabled: true,
|
||||
// outstandingPublisherConfirmationsRateLimiter: new ThrottlingRateLimiter(MAX_OUTSTANDING_CONFIRMS)
|
||||
//);
|
||||
// 声明 Exchange(持久化)
|
||||
await channel.ExchangeDeclareAsync(exchange: param.Exchange, type: "direct", durable: true, autoDelete: false, arguments: null);
|
||||
|
||||
// 声明队列(持久化)
|
||||
await channel.QueueDeclareAsync(queue: param.RoutingKey, durable: true, exclusive: false, autoDelete: false, arguments: null);
|
||||
await channel.QueueDeclareAsync(queue: param.Queue, durable: true, exclusive: false, autoDelete: false, arguments: null);
|
||||
|
||||
// 绑定队列到 Exchange
|
||||
await channel.QueueBindAsync(queue: param.Queue, exchange: param.Exchange, routingKey: param.RoutingKey, arguments: null);
|
||||
|
||||
// 清空队列
|
||||
if (param.Purge) await channel.QueuePurgeAsync(param.RoutingKey);
|
||||
if (param.Purge) await channel.QueuePurgeAsync(param.Queue);
|
||||
// 消息序列化
|
||||
var mesjson = JsonSerializer.Serialize(param.Data, options);
|
||||
|
||||
@ -128,12 +127,20 @@ namespace QYZH.InteractiveMagazine.Infrastructure.RabbitMQ
|
||||
}
|
||||
|
||||
|
||||
public async Task ReceiveAsync(string queueName, Func<IChannel, BasicDeliverEventArgs, Task> callback, CancellationToken cancellationToken = default)
|
||||
public async Task ReceiveAsync(string exchange, string queueName, string routingKey, Func<IChannel, BasicDeliverEventArgs, Task> callback, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var channel = await _connection.CreateChannel();
|
||||
//await channel.BasicQosAsync(0, 10, false); // 一次最多接收10条未确认的消息
|
||||
|
||||
// 声明 Exchange(持久化)
|
||||
await channel.ExchangeDeclareAsync(exchange: exchange, type: "direct", durable: true, autoDelete: false, arguments: null);
|
||||
|
||||
// 声明队列(持久化)
|
||||
await channel.QueueDeclareAsync(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
|
||||
|
||||
// 绑定队列到 Exchange
|
||||
await channel.QueueBindAsync(queue: queueName, exchange: exchange, routingKey: routingKey, arguments: null);
|
||||
|
||||
var consumer = new AsyncEventingBasicConsumer(channel);
|
||||
consumer.ReceivedAsync += async (model, ea) =>
|
||||
{
|
||||
|
||||
@ -71,6 +71,19 @@ namespace QYZH.InteractiveMagazine.Models.Dto.Journal
|
||||
/// 回答时间秒
|
||||
/// </summary>
|
||||
public int AnswerTime { get; set; }
|
||||
/// <summary>
|
||||
/// Desc:基础Prompt配置ID(为空则使用IsDefault=1的模板)
|
||||
/// Default:
|
||||
/// Nullable:True
|
||||
/// </summary>
|
||||
public string BasePrompt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Desc:个性化Prompt(追加到基础Prompt后面,可为空)
|
||||
/// Default:
|
||||
/// Nullable:True
|
||||
/// </summary>
|
||||
public string CustomPrompt { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -126,7 +126,7 @@ namespace QYZH.InteractiveMagazine.Models.Entity
|
||||
/// Default:
|
||||
/// Nullable:True
|
||||
/// </summary>
|
||||
public long? BasePromptId { get; set; }
|
||||
public string BasePrompt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Desc:个性化Prompt(追加到基础Prompt后面,可为空)
|
||||
|
||||
@ -7,24 +7,14 @@ namespace QYZH.InteractiveMagazine.Models.Enum;
|
||||
/// </summary>
|
||||
public enum JournalPageTaskTypeEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 单选题
|
||||
/// </summary>
|
||||
[Description("单选题")]
|
||||
SingleChoice = 1,
|
||||
/// <summary>
|
||||
/// 多选题
|
||||
/// </summary>
|
||||
[Description("多选题")]
|
||||
MultipleChoice = 2,
|
||||
/// <summary>
|
||||
/// 填空题
|
||||
/// </summary>
|
||||
[Description("填空题")]
|
||||
FillInBlank = 3,
|
||||
[Description("客观题")]
|
||||
FillInBlank = 1,
|
||||
/// <summary>
|
||||
/// 问答题
|
||||
/// </summary>
|
||||
[Description("问答题")]
|
||||
[Description("主观题")]
|
||||
TaskAnswer = 4
|
||||
}
|
||||
|
||||
@ -108,20 +108,7 @@ public class JournalPageService(BaseRepository<Journal> JournalRepository,
|
||||
/// <returns></returns>
|
||||
public async Task<bool> UpdatePageNoAsync(long JournalId)
|
||||
{
|
||||
//这里不能修改 Exchange = "icr.direct" 否则会报错
|
||||
var msRes = await rabbitMqService.SendAsync(new RabbitMQSendParam { Exchange = "icr.direct", Queue = "mq.Journal.updatePageNo.queue", RoutingKey = "mq.Journal.updatePageNo", Data = JournalId });//发生消息
|
||||
return msRes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打印书页(全部)
|
||||
/// </summary>
|
||||
/// <param name="JournalId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> PrintJournalPageAsync(long JournalId)
|
||||
{
|
||||
//这里不能修改 Exchange = "icr.direct" 否则会报错
|
||||
var msRes = await rabbitMqService.SendAsync(new RabbitMQSendParam { Exchange = "icr.direct", Queue = "mq.Journal.printJournalPage.queue", RoutingKey = "mq.Journal.printJournalPage", Data = JournalId });//发生消息
|
||||
var msRes = await rabbitMqService.SendAsync(new RabbitMQSendParam { Exchange = "ex.journal", Queue = "mq.journal.dotcode.auto", RoutingKey = "rk.journal.dotcode.auto", Data = JournalId });//发生消息
|
||||
return msRes;
|
||||
}
|
||||
|
||||
|
||||
@ -67,6 +67,7 @@ public class JournalPageTaskService(BaseRepository<Journal> journalRepository, O
|
||||
task.Persuasiveness = input.Persuasiveness;
|
||||
task.AnswerTime = input.AnswerTime;
|
||||
|
||||
|
||||
var no = input.No.Split('-').Select(int.Parse).ToArray();
|
||||
if (no.Last() >= 2)
|
||||
{
|
||||
|
||||
@ -18,6 +18,7 @@ namespace QYZH.InteractiveMagazine.Service;
|
||||
|
||||
public class JournalService(BaseRepository<JournalPage> JournalPageRepository,
|
||||
BaseRepository<JournalPageTask> JournalPageTaskRepository,
|
||||
BaseRepository<JournalCatalog> JournalCatalogRepository,
|
||||
BaseRepository<DotFile> dotFileRepository,
|
||||
BaseRepository<DotFileDetail> dotFileDetailRepository, OssService ossService, ILogger<JournalService> logger) : BaseRepository<Journal>, IJournalService
|
||||
{
|
||||
@ -208,6 +209,7 @@ public class JournalService(BaseRepository<JournalPage> JournalPageRepository,
|
||||
{
|
||||
await base.DeleteAsync(d => ids.Contains(d.Id));
|
||||
await JournalPageRepository.DeleteAsync(d => ids.Contains(d.JournalId));
|
||||
await JournalCatalogRepository.DeleteAsync(d => ids.Contains(d.JournalId));
|
||||
await JournalPageTaskRepository.DeleteAsync(d => ids.Contains(d.JournalId));
|
||||
return true;
|
||||
});
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
using System.Text;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.WorkService.Consumers;
|
||||
|
||||
/// <summary>
|
||||
/// 自动铺码消费者
|
||||
/// </summary>
|
||||
public class AutoDotCodeConsumer : IQueueConsumer
|
||||
{
|
||||
private readonly ILogger<AutoDotCodeConsumer> _logger;
|
||||
|
||||
public AutoDotCodeConsumer(ILogger<AutoDotCodeConsumer> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string Exchange => "ex.journal";
|
||||
|
||||
public string QueueName => "mq.journal.dotcode.auto";
|
||||
|
||||
public string RoutingKey => "rk.journal.dotcode.auto";
|
||||
|
||||
public async Task HandleAsync(byte[] message)
|
||||
{
|
||||
var body = Encoding.UTF8.GetString(message);
|
||||
_logger.LogInformation("收到自动铺码消息: {Message}", body);
|
||||
|
||||
// TODO: 在此编写具体的铺码处理逻辑
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnErrorAsync(byte[] message, Exception exception)
|
||||
{
|
||||
var body = Encoding.UTF8.GetString(message);
|
||||
_logger.LogError(exception, "处理自动铺码消息失败: {Message}", body);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@ -5,11 +5,21 @@ namespace QYZH.InteractiveMagazine.WorkService.Consumers;
|
||||
/// </summary>
|
||||
public interface IQueueConsumer
|
||||
{
|
||||
/// <summary>
|
||||
/// 交换机名称
|
||||
/// </summary>
|
||||
string Exchange { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 监听的队列名称
|
||||
/// </summary>
|
||||
string QueueName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 路由键
|
||||
/// </summary>
|
||||
string RoutingKey { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 处理消息
|
||||
/// </summary>
|
||||
|
||||
@ -14,7 +14,11 @@ public class JournalTaskReceiveConsumer : IQueueConsumer
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string QueueName => "mq.Journal.task.receive";
|
||||
public string Exchange => "ex.journal";
|
||||
|
||||
public string QueueName => "mq.journal.task.receive";
|
||||
|
||||
public string RoutingKey => "rk.journal.task.receive";
|
||||
|
||||
public async Task HandleAsync(byte[] message)
|
||||
{
|
||||
|
||||
@ -29,20 +29,29 @@ public class RabbitMQHostedService : BackgroundService
|
||||
|
||||
_logger.LogInformation("发现 {Count} 个队列消费者,开始启动...", consumers.Count);
|
||||
|
||||
var tasks = consumers.Select(c => StartConsumerAsync(c.QueueName, stoppingToken)).ToList();
|
||||
var tasks = consumers.Select(c => StartConsumerAsync(c, stoppingToken)).ToList();
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
private async Task StartConsumerAsync(string queueName, CancellationToken stoppingToken)
|
||||
private async Task StartConsumerAsync(IQueueConsumer queueConsumer, CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("正在启动消费者: {QueueName}", queueName);
|
||||
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(queueName, async (channel, ea) =>
|
||||
await rabbitMQService.ReceiveAsync(exchange, queueName, routingKey, async (channel, ea) =>
|
||||
{
|
||||
// 声明死信队列及绑定(幂等操作,确保DLQ存在)
|
||||
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);
|
||||
|
||||
// 每条消息创建独立 scope,确保消费者内可注入 Scoped 服务
|
||||
using var messageScope = _serviceProvider.CreateScope();
|
||||
var consumer = messageScope.ServiceProvider
|
||||
@ -57,7 +66,15 @@ public class RabbitMQHostedService : BackgroundService
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "消费者 {QueueName} 处理消息异常", queueName);
|
||||
await channel.BasicNackAsync(ea.DeliveryTag, false, true, stoppingToken);
|
||||
|
||||
// 发送到死信队列,成功则从主队列移除,失败则重新入队
|
||||
var dlqSent = await SendToDeadLetterQueueAsync(exchange, dlqName, dlqRoutingKey, ea.Body.ToArray(), stoppingToken);
|
||||
await channel.BasicNackAsync(ea.DeliveryTag, false, !dlqSent, stoppingToken);
|
||||
|
||||
if (dlqSent)
|
||||
{
|
||||
_logger.LogInformation("消息已转入死信队列 {DlqName}", dlqName);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@ -79,4 +96,32 @@ public class RabbitMQHostedService : BackgroundService
|
||||
_logger.LogError(ex, "消费者 {QueueName} 启动失败", queueName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将失败消息发送到死信队列
|
||||
/// </summary>
|
||||
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.WorkService/PrintToolV2.7/PrintTool.exe
Normal file
BIN
QYZH.InteractiveMagazine.WorkService/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>
|
||||
Binary file not shown.
BIN
QYZH.InteractiveMagazine.WorkService/PrintToolV2.7/wfdprint.dll
Normal file
BIN
QYZH.InteractiveMagazine.WorkService/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.WorkService/PrintToolV2.7/返回值说明.txt
Normal file
13
QYZH.InteractiveMagazine.WorkService/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的页数
|
||||
@ -63,6 +63,7 @@ builder.Services.AddRabbitMQ(builder.Configuration);
|
||||
|
||||
// 注册队列消费者(新增消费者只需实现 IQueueConsumer 并在此注册)
|
||||
builder.Services.AddScoped<IQueueConsumer, JournalTaskReceiveConsumer>();
|
||||
builder.Services.AddScoped<IQueueConsumer, AutoDotCodeConsumer>();
|
||||
|
||||
// 注册消费者后台服务
|
||||
builder.Services.AddHostedService<RabbitMQHostedService>();
|
||||
|
||||
Reference in New Issue
Block a user