Files
QYZH.InteractiveMagazine/QYZH.InteractiveMagazine.Service/JournalPageTaskService.cs
glz eb4f09e391 feat: 新增打印任务相关功能并完善服务配置
1. 调整回调响应的Code字段类型为object以兼容更多返回值
2. 为JournalDto新增Url和QuestionNo属性
3. 为JournalPageTaskOutput新增Task字段并完善注释
4. 新增打印工作服务的发布、安装卸载脚本与README文档
5. 调整项目配置,添加运行时标识与资源拷贝配置
6. 优化程序启动逻辑,修复工作目录与日志路径问题
7. 简化日志配置,移除多余的Hangfire与AI配置项
8. 完善期刊删除逻辑,关联删除相关子数据
9. 新增期刊发布时的书页任务排序与回调地址补全逻辑
2026-07-01 10:56:18 +08:00

244 lines
9.7 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;
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, "书籍已归档不能添加题目", ResultCode.CONFLICT);
var map = input.Adapt<JournalPageTask>();
map.Id = YitIdHelper.NextId();
map.GroupId = map.Id;
map.NeedAiProcess = input.NeedAiProcess;
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(), "未找到关联跨页的第一部分", ResultCode.NOT_FOUND);
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, "书籍已归档不能修改题目", ResultCode.CONFLICT);
var task = await base.Queryable().Where(w => w.Id == input.Id).FirstAsync();
BusinessException.ThrowIf(task.IsNull(), "未找到关联的题号", ResultCode.NOT_FOUND);
var sameTask = await base.Queryable().Where(w => w.No == input.No && w.JournalId == input.JournalId && w.Id != input.Id).FirstAsync();
BusinessException.ThrowIf(sameTask.IsNotEmpty(), "已经存在相同题号题目", ResultCode.CONFLICT);
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.Points = input.Points;
task.GrowthPoint = input.GrowthPoint;
task.Comprehension = input.Comprehension;
task.Judgment = input.Judgment;
task.Expression = input.Expression;
task.Persuasiveness = input.Persuasiveness;
task.AnswerTime = input.AnswerTime;
task.Prompt = input.Prompt;
task.NeedAiProcess = input.NeedAiProcess;
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(), "未找到关联跨页的第一部分", ResultCode.NOT_FOUND);
task.GroupId = groupTask.GroupId;
task.Type = groupTask.Type;
}
var taskResult = await base.Updateable(task).ExecuteCommandAsync() > 0;
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,
Task =task.Task,
Type = task.Type,
Points = task.Points,
GrowthPoint = task.GrowthPoint,
Comprehension = task.Comprehension,
Judgment = task.Judgment,
Expression = task.Expression,
Persuasiveness = task.Persuasiveness,
AnswerTime = task.AnswerTime,
Prompt = task.Prompt,
NeedAiProcess = task.NeedAiProcess
};
// 查询答案列表
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(), "问题不存在", ResultCode.NOT_FOUND);
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(), "问题不存在", ResultCode.NOT_FOUND);
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;
}
public async Task<long> AddAnswerAsync(JournalTaskAnswerAddInput input)
{
var task = await base.Queryable().Where(w => w.Id == input.JournalPageTaskId).FirstAsync();
BusinessException.ThrowIf(task.IsNull(), "问题不存在", ResultCode.NOT_FOUND);
var key = $"journal/{task.JournalId}/{task.JournalPageId}/{task.GroupId}";
input.Answer = Deal(null, input.Answer, key, "answer");
input.AnswerUrl = Deal(null, input.AnswerUrl, key, "answerUrl");
var entity = new JournalPageTaskAnswer
{
JournalPageTaskId = input.JournalPageTaskId,
Answer = input.Answer,
AnswerUrL = input.AnswerUrl,
CreatedBy = "System",
CreatedAt = DateTime.Now,
IsDeleted = false
};
await answerRepository.InsertAsync(entity);
return entity.Id;
}
public async Task<bool> UpdateAnswerAsync(JournalTaskAnswerUpdateInput input)
{
var answer = await answerRepository.Queryable().Where(a => a.Id == input.Id).FirstAsync();
BusinessException.ThrowIf(answer.IsNull(), "答案不存在", ResultCode.NOT_FOUND);
var task = await base.Queryable().Where(w => w.Id == answer.JournalPageTaskId).FirstAsync();
var key = $"journal/{task.JournalId}/{task.JournalPageId}/{task.GroupId}";
input.Answer = Deal(answer.Answer, input.Answer, key, "answer");
input.AnswerUrl = Deal(answer.AnswerUrL, input.AnswerUrl, key, "answerUrl");
return await answerRepository.Updateable()
.SetColumns(a => a.Answer == input.Answer)
.SetColumns(a => a.AnswerUrL == input.AnswerUrl)
.Where(a => a.Id == input.Id)
.ExecuteCommandAsync() > 0;
}
public async Task<bool> DeleteAnswerAsync(long id)
{
var answer = await answerRepository.Queryable().Where(a => a.Id == id).FirstAsync();
BusinessException.ThrowIf(answer.IsNull(), "答案不存在", ResultCode.NOT_FOUND);
var task = await base.Queryable().Where(w => w.Id == answer.JournalPageTaskId).FirstAsync();
var key = $"journal/{task.JournalId}/{task.JournalPageId}/{task.GroupId}";
// 清理OSS文件
Deal(answer.Answer, "", key, "answer");
Deal(answer.AnswerUrL, "", key, "answerUrl");
return await answerRepository.DeleteAsync(a => a.Id == id);
}
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;
}
}