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 journalRepository, OssService ossService, BaseRepository answerRepository) : BaseRepository, IJournalPageTaskService { public async Task 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(); 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; } var data = await base.InsertAsync(map); // 创建默认答案记录 var answer = new JournalPageTaskAnswer { JournalPageTaskId = map.Id, CreatedBy = "System", UpdatedBy = "System", CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now, IsDeleted = false }; // 如果是关联跨页题目,从第一部分的 Answer 复制 Score 和 AnswerTime if (no.Last() >= 2) { var startNo = $"{no[0]}-{no[1]}-{no[2]}-1"; var firstTask = await Queryable().Where(w => w.No == startNo && w.JournalId == input.JournalId).FirstAsync(); if (firstTask != null) { var firstAnswer = await answerRepository.Queryable().Where(a => a.JournalPageTaskId == firstTask.Id).FirstAsync(); if (firstAnswer != null) { answer.Score = firstAnswer.Score; answer.AnswerTime = firstAnswer.AnswerTime; } } } await answerRepository.InsertAsync(answer); return map?.Id; } public async Task 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.Options = input.Options; task.No = input.No; 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; // 答案侧字段处理 var answer = await answerRepository.Queryable().Where(a => a.JournalPageTaskId == task.Id).FirstAsync(); if (answer == null) { // 兼容旧数据:如果 Answer 记录不存在则创建 answer = new JournalPageTaskAnswer { JournalPageTaskId = task.Id, CreatedBy = "System", CreatedAt = DateTime.Now, IsDeleted = false }; } // 答案/解析内容处理 answer.Answer = Deal(answer.Answer, input.Answer, key, "answer"); answer.Analysis = Deal(answer.Analysis, input.Analysis, key, "analysis"); answer.Score = input.Score; answer.AnswerTime = input.AnswerTime; answer.UpdatedBy = "System"; answer.UpdatedAt = DateTime.Now; if (no.Last() >= 2) { var startNo = $"{no[0]}-{no[1]}-{no[2]}-1"; var firstTask = await Queryable().Where(w => w.No == startNo && w.JournalId == input.JournalId).FirstAsync(); if (firstTask != null) { var firstAnswer = await answerRepository.Queryable().Where(a => a.JournalPageTaskId == firstTask.Id).FirstAsync(); if (firstAnswer != null) { answer.Score = firstAnswer.Score; answer.AnswerTime = firstAnswer.AnswerTime; } } } if (answer.Id == 0) { await answerRepository.InsertAsync(answer); } else { await answerRepository.UpdateAsync(answer); } return taskResult; } public async Task KeywordAnalysisAsync(JournalPageTaskKeywordAnalysis input) { // KeywordAnalysis 已移至 Answer 表,通过 GroupId 关联的 Task 找到对应的 Answer 记录进行更新 var taskIds = await Queryable().Where(w => w.GroupId == input.Id).Select(w => w.Id).ToListAsync(); if (taskIds.Count == 0) return false; return await answerRepository.Updateable() .SetColumns(s => s.KeywordAnalysis, input.KeywordAnalysis) .Where(a => taskIds.Contains(a.JournalPageTaskId)) .ExecuteCommandAsync() > 0; } public async Task DetailAsync(long id) { var data = await base.Queryable() .InnerJoin((w, a) => a.JournalPageTaskId == w.Id) .Where((w, a) => w.Id == id) .Select((w, a) => new JournalPageTaskOutput() { Id = w.Id, JournalId = w.JournalId, JournalPageId = w.JournalPageId, No = w.No, Type = (TaskBankTypeEnum)w.Type, Task = w.Task, Options = w.Options, Answer = a.Answer, Analysis = a.Analysis, Score = a.Score, AnswerTime = a.AnswerTime, KeywordAnalysis = a.KeywordAnalysis }, true).FirstAsync(); return data; } public async Task 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 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()).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; } }