1. 新增AutoDotCodeConsumer自动铺码消费者,实现统一的交换机路由绑定 2. 重构RabbitMQ接收方法,支持交换机、路由键配置,添加死信队列处理 3. 重构现有JournalTaskReceiveConsumer,使用标准交换机路由配置 4. 更新JournalPageService,将打印逻辑替换为自动铺码消息发送 5. 调整枚举类型,重构任务类型命名 6. 更新实体和DTO,新增Prompt相关字段 7. 添加PrintToolV2.7配套工具和文档 8. 清理冗余的PrintJournalPageAsync接口
208 lines
7.9 KiB
C#
208 lines
7.9 KiB
C#
using Mapster;
|
|
using QYZH.InteractiveMagazine.Common.Extensions;
|
|
using QYZH.InteractiveMagazine.Infrastructure.OSS;
|
|
using QYZH.InteractiveMagazine.IService;
|
|
using QYZH.InteractiveMagazine.Models.Common;
|
|
using QYZH.InteractiveMagazine.Models.Dto.Journal;
|
|
using QYZH.InteractiveMagazine.Models.Entity;
|
|
using QYZH.InteractiveMagazine.Models.Enum;
|
|
using QYZH.InteractiveMagazine.Repository;
|
|
using SqlSugar;
|
|
using Yitter.IdGenerator;
|
|
|
|
|
|
namespace QYZH.InteractiveMagazine.Service;
|
|
|
|
public class JournalPageTaskService(BaseRepository<Journal> journalRepository, OssService ossService, BaseRepository<JournalPageTaskAnswer> answerRepository) : BaseRepository<JournalPageTask>, IJournalPageTaskService
|
|
{
|
|
public async Task<long?> InsertAsync(JournalPageTaskAddInput input)
|
|
{
|
|
var JournalStatus = await journalRepository.Queryable().Where(w => w.Id == input.JournalId).Select(s => s.Status).FirstAsync();
|
|
BusinessException.ThrowIf(JournalStatus == (int)JournalStatusEnum.Archive, "书籍已归档不能添加题目");
|
|
|
|
var map = input.Adapt<JournalPageTask>();
|
|
map.Id = YitIdHelper.NextId();
|
|
map.GroupId = map.Id;
|
|
var no = input.No.Split('-').Select(int.Parse).ToArray();
|
|
if (no.Last() >= 2)
|
|
{
|
|
var startNo = $"{no[0]}-{no[1]}-{no[2]}-1";
|
|
var groupTask = await Queryable().Where(w => w.No == startNo && w.JournalId == input.JournalId).FirstAsync();
|
|
BusinessException.ThrowIf(groupTask.IsNull(), "未找到关联跨页的第一部分");
|
|
map.GroupId = groupTask.GroupId;
|
|
map.Type = groupTask.Type;
|
|
}
|
|
|
|
await base.InsertAsync(map);
|
|
|
|
return map?.Id;
|
|
}
|
|
|
|
|
|
public async Task<bool> UpdateAsync(JournalPageTaskUpdateInput input)
|
|
{
|
|
var JournalStatus = await journalRepository.Queryable().Where(w => w.Id == input.JournalId).Select(s => s.Status).FirstAsync();
|
|
BusinessException.ThrowIf(JournalStatus == (int)JournalStatusEnum.Archive, "书籍已归档不能修改题目");
|
|
|
|
var task = await base.Queryable().Where(w => w.Id == input.Id).FirstAsync();
|
|
BusinessException.ThrowIf(task.IsNull(), "未找到关联的题号");
|
|
|
|
var sameTask = await base.Queryable().Where(w => w.No == input.No && w.JournalId == input.JournalId && w.Id != input.Id).FirstAsync();
|
|
BusinessException.ThrowIf(sameTask.IsNotEmpty(), "已经存在相同题号题目");
|
|
|
|
|
|
var key = $"journal/{task.JournalId}/{task.JournalPageId}/{task.GroupId}";
|
|
|
|
// 题目内容处理
|
|
input.Task = Deal(task.Task, input.Task, key, "task");
|
|
|
|
task.Type = input.Type;
|
|
task.Task = input.Task;
|
|
task.No = input.No;
|
|
task.Points = input.Points;
|
|
task.GrowthPoint = (int?)input.GrowthPoint;
|
|
task.Comprehension = input.Comprehension;
|
|
task.Judgment = input.Judgment;
|
|
task.Expression = input.Expression;
|
|
task.Persuasiveness = input.Persuasiveness;
|
|
task.AnswerTime = input.AnswerTime;
|
|
|
|
|
|
var no = input.No.Split('-').Select(int.Parse).ToArray();
|
|
if (no.Last() >= 2)
|
|
{
|
|
var startNo = $"{no[0]}-{no[1]}-{no[2]}-1";
|
|
var groupTask = await Queryable().Where(w => w.No == startNo && w.JournalId == input.JournalId).FirstAsync();
|
|
BusinessException.ThrowIf(groupTask.IsNull(), "未找到关联跨页的第一部分");
|
|
task.GroupId = groupTask.GroupId;
|
|
task.Type = groupTask.Type;
|
|
}
|
|
|
|
var taskResult = await base.Updateable(task).ExecuteCommandAsync() > 0;
|
|
|
|
// 答案处理:先删后插
|
|
await answerRepository.DeleteAsync(a => a.JournalPageTaskId == task.Id);
|
|
|
|
if (input.TaskAnswer != null && input.TaskAnswer.Count > 0)
|
|
{
|
|
foreach (var ansInput in input.TaskAnswer)
|
|
{
|
|
// 处理答案中的文件OSS拷贝
|
|
ansInput.Answer = Deal(null, ansInput.Answer, key, "answer");
|
|
ansInput.AnswerUrl = Deal(null, ansInput.AnswerUrl, key, "answerUrl");
|
|
|
|
var answerEntity = new JournalPageTaskAnswer
|
|
{
|
|
JournalPageTaskId = task.Id,
|
|
Answer = ansInput.Answer,
|
|
AnswerUrL = ansInput.AnswerUrl,
|
|
CreatedBy = "System",
|
|
CreatedAt = DateTime.Now,
|
|
IsDeleted = false
|
|
};
|
|
await answerRepository.InsertAsync(answerEntity);
|
|
}
|
|
}
|
|
|
|
return taskResult;
|
|
}
|
|
|
|
public async Task<JournalPageTaskOutput> DetailAsync(long id)
|
|
{
|
|
var task = await base.Queryable().Where(w => w.Id == id).FirstAsync();
|
|
if (task == null) return null;
|
|
|
|
var data = new JournalPageTaskOutput
|
|
{
|
|
Id = task.Id,
|
|
JournalId = task.JournalId,
|
|
JournalPageId = task.JournalPageId,
|
|
No = task.No,
|
|
Type = task.Type,
|
|
Task = task.Task,
|
|
Points = task.Points,
|
|
GrowthPoint = task.GrowthPoint ?? 0,
|
|
Comprehension = task.Comprehension,
|
|
Judgment = task.Judgment,
|
|
Expression = task.Expression,
|
|
Persuasiveness = task.Persuasiveness,
|
|
AnswerTime = task.AnswerTime,
|
|
};
|
|
|
|
// 查询答案列表
|
|
var answers = await answerRepository.Queryable()
|
|
.Where(a => a.JournalPageTaskId == id)
|
|
.ToListAsync();
|
|
|
|
data.Answers = answers.Select(a => new JournalTaskAnswerOutput
|
|
{
|
|
Id = a.Id,
|
|
Answer = a.Answer,
|
|
AnswerUrl = a.AnswerUrL
|
|
}).ToList();
|
|
|
|
return data;
|
|
}
|
|
|
|
public async Task<bool> DeleteAsync(long id)
|
|
{
|
|
var task = await base.Queryable().Where(w => w.Id == id).FirstAsync();
|
|
BusinessException.ThrowIf(task.IsNull(), "问题不存在");
|
|
|
|
var key = $"journal/{task.JournalId}/{task.JournalPageId}/{id}";
|
|
|
|
// 同时删除关联的答案记录
|
|
await answerRepository.DeleteAsync(a => a.JournalPageTaskId == id);
|
|
|
|
ossService.DeleteObject(key);
|
|
|
|
return await base.DeleteAsync(d => d.Id == id);
|
|
}
|
|
|
|
public async Task<bool> ComplementAsync(JournalPageTaskComplementInput input)
|
|
{
|
|
var task = await base.Queryable().Where(w => w.Id == input.Id).FirstAsync();
|
|
BusinessException.ThrowIf(task.IsNull(), "问题不存在");
|
|
|
|
if (input.AudioUrl.NotNull())
|
|
{
|
|
var key = $"journal/{task.JournalId}/{task.JournalPageId}/{task.Id}/audio.{input.AudioUrl.ToExtension()}";
|
|
ossService.CopyObject(input.AudioUrl, key);
|
|
input.AudioUrl = key;
|
|
}
|
|
if (input.PointsUrl.NotNull())
|
|
{
|
|
var key = $"journal/{task.JournalId}/{task.JournalPageId}/{task.Id}/points.json";
|
|
ossService.CopyObject(input.PointsUrl, key);
|
|
input.PointsUrl = key;
|
|
}
|
|
return await Updateable(input.Adapt<JournalPageTask>()).Where(w => w.Id == input.Id).ExecuteCommandAsync() > 0;
|
|
}
|
|
|
|
private string Deal(string oldUrls, string newUrls, string key, string type)
|
|
{
|
|
// 如果 newUrls 为空,则直接返回
|
|
if (newUrls.IsNull()) return null;
|
|
|
|
// 处理 oldUrls 为 null 的情况,将其视为空字符串
|
|
var oldTaskUrls = oldUrls.AllUrl().Distinct();
|
|
var taskUrls = newUrls.AllUrl().Distinct().Select(s => s.RemoveDomain());
|
|
|
|
// 删除不存在的(存在于旧集合但不在新集合中)
|
|
var removedUrls = oldTaskUrls.Except(taskUrls).ToList();
|
|
ossService.DeleteObjects(removedUrls);
|
|
|
|
// 添加新增的(存在于新集合但不在旧集合中)
|
|
var addedUrls = taskUrls.Except(oldTaskUrls).ToList();
|
|
foreach (var item in addedUrls)
|
|
{
|
|
var value = $"{key}/{type}/{YitIdHelper.NextId()}.{item.ToExtension()}";
|
|
ossService.CopyObject(item, value);
|
|
|
|
newUrls = newUrls.Replace(item, value);
|
|
|
|
}
|
|
return newUrls;
|
|
}
|
|
}
|