diff --git a/QYZH.InteractiveMagazine.IService/IAiBasePromptService.cs b/QYZH.InteractiveMagazine.IService/IAiBasePromptService.cs index 79df82c..cb06e82 100644 --- a/QYZH.InteractiveMagazine.IService/IAiBasePromptService.cs +++ b/QYZH.InteractiveMagazine.IService/IAiBasePromptService.cs @@ -42,4 +42,16 @@ public interface IAiBasePromptService : IBaseService /// 查询条件 /// 分页结果 Task> GetListAsync(AiBasePromptQueryInput input); + + /// + /// 获取全部Prompt配置(无分页) + /// + /// 全部Prompt配置列表 + Task> GetAllAsync(); + + /// + /// 切换Prompt启用/禁用状态 + /// + /// Prompt配置ID + Task ToggleStatusAsync(long id); } diff --git a/QYZH.InteractiveMagazine.IService/IJournalService.cs b/QYZH.InteractiveMagazine.IService/IJournalService.cs index eed5155..2f4cd00 100644 --- a/QYZH.InteractiveMagazine.IService/IJournalService.cs +++ b/QYZH.InteractiveMagazine.IService/IJournalService.cs @@ -24,6 +24,13 @@ public interface IJournalService : IBaseService Task> GetPageListAsync(PageQueryModel search); + /// + /// 创建杂志 + /// + /// 杂志信息 + /// 新杂志ID + Task> AddAsync(JournalAddDto input); + /// /// 编辑 /// diff --git a/QYZH.InteractiveMagazine.Models/Dto/Ai/AiBasePromptDto.cs b/QYZH.InteractiveMagazine.Models/Dto/Ai/AiBasePromptDto.cs index 016a38b..c3f9122 100644 --- a/QYZH.InteractiveMagazine.Models/Dto/Ai/AiBasePromptDto.cs +++ b/QYZH.InteractiveMagazine.Models/Dto/Ai/AiBasePromptDto.cs @@ -78,6 +78,11 @@ public class AiBasePromptOutput /// public bool IsDefault { get; set; } + /// + /// 状态(1=启用, 0=禁用) + /// + public int Status { get; set; } + /// /// 创建人 /// diff --git a/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalDto.cs b/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalDto.cs index 3fd81b2..0b14eaf 100644 --- a/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalDto.cs +++ b/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalDto.cs @@ -21,6 +21,11 @@ namespace QYZH.InteractiveMagazine.Models.Dto.Journal /// public string Name { get; set; } + /// + /// Desc:标题 + /// + public string? Title { get; set; } + /// /// Desc:总页数 /// @@ -31,7 +36,6 @@ namespace QYZH.InteractiveMagazine.Models.Dto.Journal /// public int VerifyPage { get; set; } - /// /// Desc:状态 @@ -105,41 +109,19 @@ namespace QYZH.InteractiveMagazine.Models.Dto.Journal set => _pdfPreviewUrl = value; } - /// - /// Desc:结论json - /// - public object? Conclusion { get; set; } /// - /// Desc:思路导读 + /// Desc: /// - public string? Guide { get; set; } - - /// - /// Desc:家长指导 - /// - public string? Tutelage { get; set; } - - /// - /// Desc:所属机构列表 - /// - public Dictionary? Organization { get; set; } - - //public List> Organizations => Organization.Select(c => new Dictionary() { { c.Key, c.Value } }).ToList(); - - /// - /// Desc:副标题 - /// - public string? Title { get; set; } - - /// - /// 年级 - /// - public int Grade { get; set; } + public string? Description { get; set; } /// /// Desc:下载书籍页码点阵码PDF文件名称 /// public string? DownloadJournalPagePdfName { get; set; } + + + public string CreatedBy { get; set; } + public DateTime CreatedAt { get; set; } } } diff --git a/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalEditDto.cs b/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalEditDto.cs index 3e9fb77..a06f000 100644 --- a/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalEditDto.cs +++ b/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalEditDto.cs @@ -8,28 +8,24 @@ using System.Threading.Tasks; namespace QYZH.InteractiveMagazine.Models.Dto.Journal { - public partial class JournalEditDto + public partial class JournalAddDto { - /// - /// Desc:主键id - /// - public long Id { get; set; } /// /// Desc:书籍名称 /// public string Name { get; set; } + /// + /// Desc:标题 + /// + public string? Title { get; set; } + /// /// Desc:总页数 /// public int TotalPage { get; set; } - /// - /// Desc:校验页数 - /// - public int VerifyPage { get; set; } - /// /// Desc:状态 @@ -57,10 +53,6 @@ namespace QYZH.InteractiveMagazine.Models.Dto.Journal [JsonIgnore] public int Revision { get; set; } - /// - /// Desc:审查结果(默认0 1通过 -1驳回) - /// - public int Result { get; set; } /// /// Desc:封面 @@ -75,42 +67,20 @@ namespace QYZH.InteractiveMagazine.Models.Dto.Journal /// /// Desc:pdf预览地址 /// - public string PdfPreviewUrl { get; set; } + public string? PdfPreviewUrl { get; set; } + + } + public partial class JournalEditDto: JournalAddDto + { + /// + /// Desc:主键id + /// + public long Id { get; set; } /// - /// Desc:结论json + /// Desc:状态 /// - public object Conclusion { get; set; } + public JournalStatusEnum Status { get; set; } - /// - /// Desc:思路导读 - /// - public string Guide { get; set; } - - /// - /// Desc:家长指导 - /// - [JsonIgnore] - public string Tutelage { get; set; } - - /// - /// Desc:所属机构 - /// - public long[] OrganizationIds { get; set; } - - ///// - ///// Desc:所属机构 - ///// - //public string OrganizationName { get; set; } - - /// - /// Desc:副标题 - /// - public string Title { get; set; } - - /// - /// 年级 - /// - public int Grade { get; set; } } } diff --git a/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalPageTaskAddInput.cs b/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalPageTaskAddInput.cs index 269f64b..e910085 100644 --- a/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalPageTaskAddInput.cs +++ b/QYZH.InteractiveMagazine.Models/Dto/Journal/JournalPageTaskAddInput.cs @@ -29,34 +29,5 @@ namespace QYZH.InteractiveMagazine.Models.Dto.Journal /// public TaskBankTypeEnum Type { get; set; } - /// - /// 学科Id - /// - public long SubjectId { get; set; } - - /// - /// 分数 - /// - public float Score { get; set; } - - /// - /// 回答时间(秒) - /// - public int AnswerTime { get; set; } - - /// - /// 关联的知识点ids - /// - public string KnowledgePointIds { get; set; } - - /// - /// 关键解析 - /// - public string KeywordAnalysis { get; set; } - - /// - /// 问题内容 - /// - public string Task { get; set; } } } diff --git a/QYZH.InteractiveMagazine.Models/Entity/Journal.cs b/QYZH.InteractiveMagazine.Models/Entity/Journal.cs index 38b930c..2a97b97 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/Journal.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/Journal.cs @@ -20,6 +20,13 @@ namespace QYZH.InteractiveMagazine.Models.Entity /// public string Name { get; set; } + /// + /// Desc:标题 + /// Default: + /// Nullable:True + /// + public string Title { get; set; } + /// /// Desc:总页数 /// Default: diff --git a/QYZH.InteractiveMagazine.Models/Entity/JournalPageTask.cs b/QYZH.InteractiveMagazine.Models/Entity/JournalPageTask.cs index 7907d61..3af953c 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/JournalPageTask.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/JournalPageTask.cs @@ -52,21 +52,6 @@ namespace QYZH.InteractiveMagazine.Models.Entity /// public string Task {get;set;} - /// - /// Desc:答案 - /// Default: - /// Nullable:True - /// - public string Answer {get;set;} - - /// - /// Desc:解析 - /// Default: - /// Nullable:True - /// - public string Analysis {get;set;} - - /// /// Desc:分组 /// Default: @@ -88,13 +73,6 @@ namespace QYZH.InteractiveMagazine.Models.Entity /// public string TaskUrl {get;set;} - /// - /// Desc:任务分数 - /// Default:0 - /// Nullable:False - /// - public float Score {get;set;} - /// /// Desc:选项 /// Default: @@ -102,35 +80,6 @@ namespace QYZH.InteractiveMagazine.Models.Entity /// public string Options {get;set;} - /// - /// Desc:回答时间(秒) - /// Default:0 - /// Nullable:False - /// - public int AnswerTime {get;set;} - - /// - /// Desc:关键解析json - /// Default: - /// Nullable:True - /// - public string KeywordAnalysis {get;set;} - - - /// - /// Desc:成长值设置 - /// Default:0 - /// Nullable:True - /// - public int? GrowthPoint {get;set;} - - /// - /// Desc:积分设置 - /// Default:0 - /// Nullable:True - /// - public int? Points {get;set;} - /// /// Desc:是否需要AI处理 /// Default:true @@ -152,33 +101,5 @@ namespace QYZH.InteractiveMagazine.Models.Entity /// public string CustomPrompt {get;set;} - /// - /// Desc:理解力评分 - /// Default:0 - /// Nullable:False - /// - public float Comprehension {get;set;} - - /// - /// Desc:判断力评分 - /// Default:0 - /// Nullable:False - /// - public float Judgment {get;set;} - - /// - /// Desc:表达力评分 - /// Default:0 - /// Nullable:False - /// - public float Expression {get;set;} - - /// - /// Desc:说服力评分 - /// Default:0 - /// Nullable:False - /// - public float Persuasiveness {get;set;} - } } diff --git a/QYZH.InteractiveMagazine.Models/Entity/JournalPageTaskAnswer.cs b/QYZH.InteractiveMagazine.Models/Entity/JournalPageTaskAnswer.cs new file mode 100644 index 0000000..c892f0d --- /dev/null +++ b/QYZH.InteractiveMagazine.Models/Entity/JournalPageTaskAnswer.cs @@ -0,0 +1,104 @@ +using SqlSugar; +using System; +using System.Linq; +using System.Text; + +namespace QYZH.InteractiveMagazine.Models.Entity +{ + /// + ///杂志任务答案表; + /// + [SugarTable("JournalPageTaskAnswer")] + public partial class JournalPageTaskAnswer : SqlSugarBaseEntity + { + public JournalPageTaskAnswer(){ + + + } + + /// + /// Desc:任务id + /// Default: + /// Nullable:False + /// + public long JournalPageTaskId {get;set;} + + /// + /// Desc:答案 + /// Default: + /// Nullable:True + /// + public string Answer {get;set;} + + /// + /// Desc:解析 + /// Default: + /// Nullable:True + /// + public string Analysis {get;set;} + + /// + /// Desc:回答时间(秒) + /// Default:0 + /// Nullable:False + /// + public int AnswerTime {get;set;} + + /// + /// Desc:任务分数 + /// Default:0 + /// Nullable:False + /// + public float Score {get;set;} + + /// + /// Desc:关键解析json + /// Default: + /// Nullable:True + /// + public string KeywordAnalysis {get;set;} + + /// + /// Desc:成长值设置 + /// Default:0 + /// Nullable:True + /// + public int? GrowthPoint {get;set;} + + /// + /// Desc:积分设置 + /// Default:0 + /// Nullable:True + /// + public int? Points {get;set;} + + /// + /// Desc:理解力评分 + /// Default:0 + /// Nullable:False + /// + public float Comprehension {get;set;} + + /// + /// Desc:判断力评分 + /// Default:0 + /// Nullable:False + /// + public float Judgment {get;set;} + + /// + /// Desc:表达力评分 + /// Default:0 + /// Nullable:False + /// + public float Expression {get;set;} + + /// + /// Desc:说服力评分 + /// Default:0 + /// Nullable:False + /// + public float Persuasiveness {get;set;} + + } +} diff --git a/QYZH.InteractiveMagazine.Models/Enum/MessageTypeEnum.cs b/QYZH.InteractiveMagazine.Models/Enum/MessageTypeEnum.cs index 631c931..c4c0c46 100644 --- a/QYZH.InteractiveMagazine.Models/Enum/MessageTypeEnum.cs +++ b/QYZH.InteractiveMagazine.Models/Enum/MessageTypeEnum.cs @@ -7,6 +7,11 @@ namespace QYZH.InteractiveMagazine.Models.Enum; /// public enum MessageTypeEnum { + /// + /// 消息 + /// + [Description("消息")] + Message = 0, /// /// 文章 /// diff --git a/QYZH.InteractiveMagazine.Service/AiBasePromptService.cs b/QYZH.InteractiveMagazine.Service/AiBasePromptService.cs index 8d1d68c..d9b4b94 100644 --- a/QYZH.InteractiveMagazine.Service/AiBasePromptService.cs +++ b/QYZH.InteractiveMagazine.Service/AiBasePromptService.cs @@ -78,6 +78,7 @@ public class AiBasePromptService( Description = entity.Description, Priority = entity.Priority, IsDefault = entity.IsDefault, + Status = entity.Status, CreatedBy = entity.CreatedBy, CreatedAt = entity.CreatedAt, UpdatedBy = entity.UpdatedBy, @@ -148,6 +149,7 @@ public class AiBasePromptService( Description = entity.Description, Priority = entity.Priority, IsDefault = entity.IsDefault, + Status = entity.Status, CreatedBy = entity.CreatedBy, CreatedAt = entity.CreatedAt, UpdatedBy = entity.UpdatedBy, @@ -202,6 +204,7 @@ public class AiBasePromptService( Description = entity.Description, Priority = entity.Priority, IsDefault = entity.IsDefault, + Status = entity.Status, CreatedBy = entity.CreatedBy, CreatedAt = entity.CreatedAt, UpdatedBy = entity.UpdatedBy, @@ -243,6 +246,7 @@ public class AiBasePromptService( Description = p.Description, Priority = p.Priority, IsDefault = p.IsDefault, + Status = p.Status, CreatedBy = p.CreatedBy, CreatedAt = p.CreatedAt, UpdatedBy = p.UpdatedBy, @@ -251,4 +255,61 @@ public class AiBasePromptService( return new PageListModel(result, input.PageIndex, input.PageSize, totalNumber); } + + /// + /// 获取全部Prompt配置(无分页) + /// + public async Task> GetAllAsync() + { + logger.LogInformation("正在查询全部Prompt配置"); + + var list = await promptRepository.Queryable() + .OrderBy(p => p.Priority) + .OrderByDescending(p => p.CreatedAt) + .ToListAsync(); + + return list.Select(p => new AiBasePromptOutput + { + Id = p.Id, + PromptKey = p.PromptKey, + PromptName = p.PromptName, + PromptTemplate = p.PromptTemplate, + Description = p.Description, + Priority = p.Priority, + IsDefault = p.IsDefault, + Status = p.Status, + CreatedBy = p.CreatedBy, + CreatedAt = p.CreatedAt, + UpdatedBy = p.UpdatedBy, + UpdatedAt = p.UpdatedAt + }).ToList(); + } + + /// + /// 切换Prompt启用/禁用状态 + /// + public async Task ToggleStatusAsync(long id) + { + logger.LogInformation("正在切换Prompt配置状态,ID: {Id}", id); + + var entity = await promptRepository.GetByIdAsync(id); + if (entity == null) + { + logger.LogWarning("未找到要切换状态的Prompt配置,ID: {Id}", id); + throw new BusinessException("Prompt配置不存在", 404); + } + + entity.Status = entity.Status == 1 ? 0 : 1; + entity.UpdatedBy = "System"; + entity.UpdatedAt = DateTime.Now; + + var result = await promptRepository.UpdateAsync(entity); + if (!result) + { + logger.LogError("Prompt配置状态切换失败,ID: {Id}", id); + throw new BusinessException("切换Prompt状态失败", 500); + } + + logger.LogInformation("Prompt配置状态切换成功,ID: {Id}, Status: {Status}", id, entity.Status); + } } diff --git a/QYZH.InteractiveMagazine.Service/JournalCatalogService.cs b/QYZH.InteractiveMagazine.Service/JournalCatalogService.cs index 6faf02e..5d43121 100644 --- a/QYZH.InteractiveMagazine.Service/JournalCatalogService.cs +++ b/QYZH.InteractiveMagazine.Service/JournalCatalogService.cs @@ -63,7 +63,7 @@ public class JournalCatalogService : BaseRepository, IJournalCat Sort = sort, PageNum = sort < input.Index ? 0 : sort - (input.Index - 1) }; - var key = $"Journal/{input.JournalId}/{JournalPage.Id}/page.{s.Url.ToExtension()}"; + var key = $"journal/{input.JournalId}/{JournalPage.Id}/page.{s.Url.ToExtension()}"; _ossService.CopyObject(s.Url.RemoveDomain(), key); JournalPage.Url = key; @@ -84,7 +84,7 @@ public class JournalCatalogService : BaseRepository, IJournalCat var JournalPages = result.Select(x => x.JournalPage).ToList(); await _JournalPageRepository.InsertRangeAsync(JournalPages); - var key = $"Journal/{input.JournalId}/Journal.pdf"; + var key = $"journal/{input.JournalId}/Journal.pdf"; _ossService.CopyObject(input.PdfUrl.RemoveDomain(), key); await Updateable().SetColumns(s => s.PdfUrl, key) diff --git a/QYZH.InteractiveMagazine.Service/JournalPageService.cs b/QYZH.InteractiveMagazine.Service/JournalPageService.cs index 189cc41..d170798 100644 --- a/QYZH.InteractiveMagazine.Service/JournalPageService.cs +++ b/QYZH.InteractiveMagazine.Service/JournalPageService.cs @@ -20,7 +20,8 @@ public class JournalPageService(BaseRepository JournalRepository, IHttpClientFactory httpClientFactory, IConfiguration configuration, IRabbitMQService rabbitMqService, - BaseRepository JournalPageTaskRepository) : BaseRepository, IJournalPageService + BaseRepository JournalPageTaskRepository, + BaseRepository JournalPageTaskAnswerRepository) : BaseRepository, IJournalPageService { public async Task InsertAsync(JournalAddV2Input input) @@ -91,7 +92,7 @@ public class JournalPageService(BaseRepository JournalRepository, input.TasksImages?.ForEach(it => { - var key = $"Journal/{Journal.Id}/{input.Id}/{it.TaskId}/qustion.{it.Url.ToExtension()}"; + var key = $"journal/{Journal.Id}/{input.Id}/{it.TaskId}/qustion.{it.Url.ToExtension()}"; ossService.CopyObject(it.Url.RemoveDomain(), key); JournalPageTaskRepository.Updateable().SetColumns(s => s.TaskUrl, key).Where(w => w.Id == it.TaskId).ExecuteCommand(); }); @@ -142,17 +143,18 @@ public class JournalPageService(BaseRepository JournalRepository, if (output != null) { - output.Tasks = await JournalPageTaskRepository.Queryable()//.Select() - .Where(a => a.JournalPageId == output.JournalPageId) - .Select(a => new JournalPageTaskV2Output + output.Tasks = await JournalPageTaskRepository.Queryable() + .LeftJoin((a, ans) => ans.JournalPageTaskId == a.Id) + .Where((a, ans) => a.JournalPageId == output.JournalPageId) + .Select((a, ans) => new JournalPageTaskV2Output { Id = a.Id, + GroupId = a.GroupId, No = a.No, Type = (TaskBankTypeEnum)a.Type, Options = a.Options, - Answers = a.Answer, - Analysis = a.Analysis, - //Assign = SqlFunc.Subqueryable().Where(m => a.Id == m.JournalPageTaskId).Any() + Answers = ans.Answer, + Analysis = ans.Analysis, }) .ToListAsync(); } diff --git a/QYZH.InteractiveMagazine.Service/JournalPageTaskService.cs b/QYZH.InteractiveMagazine.Service/JournalPageTaskService.cs index c6532ac..c3f228d 100644 --- a/QYZH.InteractiveMagazine.Service/JournalPageTaskService.cs +++ b/QYZH.InteractiveMagazine.Service/JournalPageTaskService.cs @@ -13,7 +13,7 @@ using Yitter.IdGenerator; namespace QYZH.InteractiveMagazine.Service; -public class JournalPageTaskService(BaseRepository journalRepository, OssService ossService) : BaseRepository, IJournalPageTaskService +public class JournalPageTaskService(BaseRepository journalRepository, OssService ossService, BaseRepository answerRepository) : BaseRepository, IJournalPageTaskService { public async Task InsertAsync(JournalPageTaskAddInput input) { @@ -30,12 +30,40 @@ public class JournalPageTaskService(BaseRepository journalRepository, O var groupTask = await Queryable().Where(w => w.No == startNo && w.JournalId == input.JournalId).FirstAsync(); BusinessException.ThrowIf(groupTask.IsNull(), "未找到关联跨页的第一部分"); map.GroupId = groupTask.GroupId; - map.Score = groupTask.Score; - map.AnswerTime = groupTask.AnswerTime; 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; } @@ -48,41 +76,18 @@ public class JournalPageTaskService(BaseRepository journalRepository, O 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).FirstAsync(); + 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}"; - //if (task.AnswerUrl != input.AnswerUrl && input.AnswerUrl.NotNull()) - //{ - // ossService.CopyObject(input.AnswerUrl.RemoveDomain(), $"{key}/answer.{input.AnswerUrl.ToExtension()}"); - // input.AnswerUrl = $"{key}/answer.{input.AnswerUrl.ToExtension()}"; - //} - //if (task.AnalysisUrl != input.AnalysisUrl && input.AnalysisUrl.NotNull()) - //{ - // ossService.CopyObject(input.AnalysisUrl.RemoveDomain(), $"{key}/analysis.{input.AnalysisUrl.ToExtension()}"); - // input.AnalysisUrl = $"{key}/analysis.{input.AnalysisUrl.ToExtension()}"; - //} - //if (task.VideoUrl != input.VideoUrl && input.VideoUrl.NotNull()) - //{ - // ossService.CopyObject(input.VideoUrl.RemoveDomain(), $"{key}/video.{input.VideoUrl.ToExtension()}"); - // input.VideoUrl = $"{key}/video.{input.VideoUrl.ToExtension()}"; - //} + var key = $"journal/{task.JournalId}/{task.JournalPageId}/{task.GroupId}"; + // 题目侧字段处理 input.Task = Deal(task.Task, input.Task, key, "task"); - input.Answer = Deal(task.Answer, input.Answer, key, "answer"); - input.Analysis = Deal(task.Analysis, input.Analysis, key, "analysis"); task.Type = input.Type; task.Task = input.Task; task.Options = input.Options; - task.Answer = input.Answer; - //task.AnswerUrl = input.AnswerUrl; - task.Analysis = input.Analysis; - //task.AnalysisUrl = input.AnalysisUrl; - task.Score = input.Score; - task.AnswerTime = input.AnswerTime; - // task.VideoUrl = input.VideoUrl; task.No = input.No; var no = input.No.Split('-').Select(int.Parse).ToArray(); if (no.Last() >= 2) @@ -91,27 +96,92 @@ public class JournalPageTaskService(BaseRepository journalRepository, O var groupTask = await Queryable().Where(w => w.No == startNo && w.JournalId == input.JournalId).FirstAsync(); BusinessException.ThrowIf(groupTask.IsNull(), "未找到关联跨页的第一部分"); task.GroupId = groupTask.GroupId; - task.Score = groupTask.Score; - task.AnswerTime = groupTask.AnswerTime; task.Type = groupTask.Type; } - //task.JournalId = input.JournalId; - //task.JournalPageId = input.JournalPageId; - // 这里不能直接用Set,因为jsonmap无法赋值 不知道为啥 - return await base.Updateable(task).ExecuteCommandAsync() > 0; + + 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) { - return await base.Updateable().SetColumns(s => s.KeywordAnalysis, input.KeywordAnalysis).Where(w => w.GroupId == input.Id).ExecuteCommandAsync() > 0; + // 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() - .Where(w => w.Id == id) - .Select(w => new JournalPageTaskOutput() - , true).FirstAsync(); + .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; } @@ -121,7 +191,10 @@ public class JournalPageTaskService(BaseRepository journalRepository, O var task = await base.Queryable().Where(w => w.Id == id).FirstAsync(); BusinessException.ThrowIf(task.IsNull(), "问题不存在"); - var key = $"Journal/{task.JournalId}/{task.JournalPageId}/{id}"; + var key = $"journal/{task.JournalId}/{task.JournalPageId}/{id}"; + + // 同时删除关联的答案记录 + await answerRepository.DeleteAsync(a => a.JournalPageTaskId == id); ossService.DeleteObject(key); @@ -135,13 +208,13 @@ public class JournalPageTaskService(BaseRepository journalRepository, O if (input.AudioUrl.NotNull()) { - var key = $"Journal/{task.JournalId}/{task.JournalPageId}/{task.Id}/audio.{input.AudioUrl.ToExtension()}"; + 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"; + var key = $"journal/{task.JournalId}/{task.JournalPageId}/{task.Id}/points.json"; ossService.CopyObject(input.PointsUrl, key); input.PointsUrl = key; } diff --git a/QYZH.InteractiveMagazine.Service/JournalService.cs b/QYZH.InteractiveMagazine.Service/JournalService.cs index fb91d4c..ca99118 100644 --- a/QYZH.InteractiveMagazine.Service/JournalService.cs +++ b/QYZH.InteractiveMagazine.Service/JournalService.cs @@ -59,6 +59,65 @@ public class JournalService(BaseRepository JournalPageRepository, return new PageListModel(dataList, search.PageIndex, search.PageSize, totalNumber); } + /// + /// 创建杂志 + /// + /// 杂志信息 + /// 新杂志ID + public async Task> AddAsync(JournalAddDto input) + { + BusinessException.ThrowIf(string.IsNullOrWhiteSpace(input.Name), "书籍名称不能为空"); + + var journal = new Journal + { + Name = input.Name.Trim(), + Title = input.Title, + TotalPage = input.TotalPage, + Status = (int)JournalStatusEnum.Created, + PdfUrl = input.PdfUrl?.RemoveDomain(), + Width = input.Width, + Height = input.Height, + Cover = input.Cover?.RemoveDomain(), + BackCover = input.BackCover?.RemoveDomain(), + PdfPreviewUrl = input.PdfPreviewUrl?.RemoveDomain(), + CreatedBy = "System", + UpdatedBy = "System", + CreatedAt = DateTime.Now, + UpdatedAt = DateTime.Now, + IsDeleted = false + }; + + // Id 已由 YitIdHelper 预生成,先搬运文件到正式目录,再一次性插入 + if (!string.IsNullOrWhiteSpace(input.Cover)) + { + var coverKey = $"journal/{journal.Id}/cover.{input.Cover.ToExtension()}"; + ossService.CopyObject(input.Cover.RemoveDomain(), coverKey); + journal.Cover = coverKey; + } + + if (!string.IsNullOrWhiteSpace(input.BackCover)) + { + var backCoverKey = $"journal/{journal.Id}/backCover.{input.BackCover.ToExtension()}"; + ossService.CopyObject(input.BackCover.RemoveDomain(), backCoverKey); + journal.BackCover = backCoverKey; + } + + if (!string.IsNullOrWhiteSpace(input.PdfUrl)) + { + var pdfKey = $"journal/{journal.Id}/Journal.{input.PdfUrl.ToExtension()}"; + ossService.CopyObject(input.PdfUrl.RemoveDomain(), pdfKey); + journal.PdfUrl = pdfKey; + } + + var res = await base.InsertAsync(journal); + if (!res) + { + new BusinessException("创建失败"); + } + logger.LogInformation("杂志创建成功,ID: {Id}, 名称: {Name}", journal.Id, input.Name); + return BaseResponse.Success(journal.Id); + } + /// /// 编辑 /// @@ -76,7 +135,7 @@ public class JournalService(BaseRepository JournalPageRepository, } else if (input.Cover.RemoveDomain() != Journal.Cover) { - var key = $"Journal/{Journal.Id}/cover.{input.Cover.ToExtension()}"; + var key = $"journal/{Journal.Id}/cover.{input.Cover.ToExtension()}"; ossService.CopyObject(input.Cover.RemoveDomain(), key); Journal.Cover = key; } @@ -87,7 +146,7 @@ public class JournalService(BaseRepository JournalPageRepository, } else if (input.BackCover.RemoveDomain() != Journal.BackCover) { - var backCoverkey = $"Journal/{Journal.Id}/backCover.{input.BackCover.ToExtension()}"; + var backCoverkey = $"journal/{Journal.Id}/backCover.{input.BackCover.ToExtension()}"; ossService.CopyObject(input.BackCover.RemoveDomain(), backCoverkey); Journal.BackCover = backCoverkey; } @@ -98,13 +157,14 @@ public class JournalService(BaseRepository JournalPageRepository, } else if (input.PdfUrl.RemoveDomain() != Journal.PdfUrl) { - var pdfUrlkey = $"Journal/{Journal.Id}/Journal.{input.PdfUrl.ToExtension()}"; + var pdfUrlkey = $"journal/{Journal.Id}/Journal.{input.PdfUrl.ToExtension()}"; ossService.CopyObject(input.PdfUrl.RemoveDomain(), pdfUrlkey); Journal.PdfUrl = pdfUrlkey; } Journal.Width = input.Width; Journal.Height = input.Height; Journal.Name = input.Name; + Journal.Title = input.Title; var res = await UseTranAsync(async () => { @@ -152,12 +212,12 @@ public class JournalService(BaseRepository JournalPageRepository, return true; }); - //删除OSS上的Journal/{JournalId}文件夹 + //删除OSS上的journal/{JournalId}文件夹 if (result) { foreach (var JournalId in ids) { - var prefix = $"Journal/{JournalId}/"; + var prefix = $"journal/{JournalId}/"; var keys = ossService.ListObjects(prefix); if (keys?.Count > 0) { @@ -219,72 +279,6 @@ public class JournalService(BaseRepository JournalPageRepository, PdfUrl = Journal.PdfUrl }; - - //铺码业务后续调整 - - //var exist = pages.All(c => c.PageNo.IsNull()); - //if (!exist) - //{ - // var dotIds = pages.Select(s => s.DotId).Distinct(); - // var dots = await dotFileRepository.Queryable().Where(w => dotIds.Contains(w.Id)).ToListAsync(); - // output.DotMatrixs = dots.Select(s => new DotMatrixMqOutput() { DotId = s.Id, FileAddress = s.FileAddress }).ToList(); - // foreach (var page in pages) - // { - // var find = output.DotMatrixs.Find(f => f.DotId == page.DotId); - // find!.Pages.Add(new DotMatrixPageDto() - // { - // PageNo = page.PageNo, - // PageNum = 1 - // }); - // } - - // var ok = await producingService.SendAsync(new RabbitMQSendParam() { Exchange = "icr.direct", RoutingKey = "mq.dotmatrix", Data = output }); - // BusinessException.ThrowIf(!ok, "消息发送失败,生成失败"); - - // await base.Updateable().SetColumns(s => s.Status, JournalStatusEnum.Codeing).Where(w => w.Id == id).ExecuteCommandAsync(); - //} - //else - //{ - // //var first = await dotFileDetailRepository.Queryable().Where(w => w.IsUse == false).GroupBy(g => g.DotId).Having(h => h.Count() >= pages.Count).FirstAsync(a => new { DotId = a.Key, Count = a.Count() }); - // var first = await dotFileDetailRepository.Queryable().Where(w => w.IsUse == false).GroupBy(g => g.DotId).Having(h => SqlFunc.AggregateCount(h.Id) >= pages.Count).Select(a => new { DotId = a.DotId, Count = SqlFunc.AggregateCount(a.Id) }).FirstAsync(); - // BusinessException.ThrowIf(first.IsNull(), "点阵页码不足,生成失败"); - // var dotFile = await dotFileRepository.Queryable().Where(w => w.Id == first.DotId).FirstAsync(); - // if (dotFile != null) - // dotFile.Details = dotFileDetailRepository.Queryable().Where(w => !w.IsUse && w.DotId == dotFile.Id).Take(pages.Count()).ToList(); - // var dotMatrix = new DotMatrixMqOutput() - // { - // DotId = dotFile.Id, - // FileAddress = dotFile.FileAddress, - // }; - // output.DotMatrixs.Add(dotMatrix); - - // foreach (var item in dotFile.Details) - // { - // var index = dotFile.Details.IndexOf(item); - // pages[index].PageNo = item.PageName; - // pages[index].DotId = dotFile.Id; - - // dotMatrix.Pages.Add(new DotMatrixPageDto() - // { - // PageNo = item.PageName, - // PageNum = 1 - // }); - // } - // await UseTranAsync(async () => - // { - // // 更新使用数量 - // //await dotFileRepository.Updateable().SetColumns(s => s.TotalUse, dotFile.TotalUse + pages.Count).Where(w => w.Id == dotFile.Id).ExecuteCommandAsync(); - // // 更新使用 - // await dotFileDetailRepository.Updateable().SetColumns(s => s.IsUse, true).Where(w => dotFile.Details.Select(s => s.Id).Contains(w.Id)).ExecuteCommandAsync(); - // // 更新页码 - // await dotMatrixPageRepository.UpdateRangeAsync(pages); - // await Updateable().SetColumns(s => s.Status, JournalStatusEnum.CodeSuccess).Where(w => w.Id == id).ExecuteCommandAsync(); - // //发送消息 - // //var ok = await producingService.SendAsync(new RabbitMQSendParam() { Exchange = "icr.direct", RoutingKey = "mq.dotmatrix", Data = output }); - // //BusinessException.ThrowIf(!ok, "消息发送失败,生成失败"); - // }); - //} - return output; } diff --git a/QYZH.InteractiveMagazine.WebApi/Controllers/AiBasePromptController.cs b/QYZH.InteractiveMagazine.WebApi/Controllers/AiBasePromptController.cs index be30d59..e34f3f3 100644 --- a/QYZH.InteractiveMagazine.WebApi/Controllers/AiBasePromptController.cs +++ b/QYZH.InteractiveMagazine.WebApi/Controllers/AiBasePromptController.cs @@ -148,4 +148,53 @@ public class AiBasePromptController : BaseController return BaseResponse>.Fail("查询Prompt配置列表失败,请稍后重试"); } } + + /// + /// 获取全部Prompt配置(无分页) + /// + /// 全部Prompt配置列表 + [HttpGet("all")] + public async Task>> GetAllAsync() + { + try + { + var result = await _aiBasePromptService.GetAllAsync(); + return Success(result); + } + catch (BusinessException ex) + { + _logger.LogWarning(ex, "查询全部Prompt配置业务异常: {Message}", ex.Message); + return BaseResponse>.Fail(ex.Message); + } + catch (Exception ex) + { + _logger.LogError(ex, "查询全部Prompt配置系统异常"); + return BaseResponse>.Fail("查询Prompt配置列表失败,请稍后重试"); + } + } + + /// + /// 切换Prompt启用/禁用状态 + /// + /// Prompt配置ID + /// 操作结果 + [HttpPut("{id}/toggle-status")] + public async Task> ToggleStatusAsync(long id) + { + try + { + await _aiBasePromptService.ToggleStatusAsync(id); + return Success(new object(), "切换Prompt状态成功"); + } + catch (BusinessException ex) + { + _logger.LogWarning(ex, "切换Prompt状态业务异常: {Message}", ex.Message); + return BaseResponse.Fail(ex.Message); + } + catch (Exception ex) + { + _logger.LogError(ex, "切换Prompt状态系统异常,ID:{Id}", id); + return BaseResponse.Fail("切换Prompt状态失败,请稍后重试"); + } + } } diff --git a/QYZH.InteractiveMagazine.WebApi/Controllers/JournalController.cs b/QYZH.InteractiveMagazine.WebApi/Controllers/JournalController.cs index 6bceea4..c4cd2ef 100644 --- a/QYZH.InteractiveMagazine.WebApi/Controllers/JournalController.cs +++ b/QYZH.InteractiveMagazine.WebApi/Controllers/JournalController.cs @@ -40,7 +40,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers /// /// /// - [HttpGet, Route("Journal/detail/{id:long}")] + [HttpGet, Route("journal/detail/{id:long}")] public async Task> GetByIdAsync([Required] long id) { var result = await JournalService.GetByExpressionAsync(c => c.Id == id); @@ -52,7 +52,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers /// /// 查询条件 /// - [HttpPost, Route("Journal/pagelist")] + [HttpPost, Route("journal/pagelist")] public async Task>> GetPageListAsync([FromBody] PageQueryModel search) { var result = await JournalService.GetPageListAsync(search); @@ -64,31 +64,31 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers /// /// /// - [HttpPost, Route("Journal/list")] + [HttpPost, Route("journal/list")] public async Task>> GetListAsync([FromQuery] JournalQueryDto dto) { var result = await JournalService.GetListAsync(dto); return BaseResponse>.Success(result); } - ///// - ///// 创建书籍 - ///// - ///// 书籍对象 - ///// - //[HttpPost, Route("Journal/add")] - //public async Task> AddAsync([FromBody] JournalEditDto dto) - //{ - // var result = await JournalService.AddAsync(dto); - // return result; - //} + /// + /// 创建杂志 + /// + /// 创建杂志 + /// + [HttpPost, Route("journal/add")] + public async Task> AddAsync([FromBody] JournalAddDto dto) + { + var result = await JournalService.AddAsync(dto); + return result; + } /// /// 编辑书籍 /// /// 书籍对象 /// - [HttpPost, Route("Journal/update")] + [HttpPost, Route("journal/update")] public async Task Edit([FromBody] JournalEditDto dto) { var result = await JournalService.EditAsync(dto); @@ -100,7 +100,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers /// /// /// - [HttpPost, Route("Journal/delete")] + [HttpPost, Route("journal/delete")] public async Task> DeleteAsync([Required][FromBody] List ids) { var result = await JournalService.DeleteAsync(ids); @@ -111,7 +111,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers /// 书籍起始页 /// /// - [HttpPost, Route("Journal/startpage")] + [HttpPost, Route("journal/startpage")] public async Task> StartPageAsync([FromQuery]long id, [FromQuery] int index) { var data = await JournalService.StartPageAsync(id, index); @@ -122,7 +122,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers /// 书籍归档 /// /// - [HttpPost, Route("Journal/rchive/{id:long}")] + [HttpPost, Route("journal/rchive/{id:long}")] public async Task> Archive(long id) { var data = await JournalService.StatusAsync(id, JournalStatusEnum.Archive); @@ -134,7 +134,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers /// /// [HttpPost] - [HttpPost, Route("Journal/abandon/{id:long}")] + [HttpPost, Route("journal/abandon/{id:long}")] public async Task> Abandon(long id) { var data = await JournalService.StatusAsync(id, JournalStatusEnum.Abandoned); @@ -145,7 +145,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers /// 书籍铺码 /// /// - [HttpPost, Route("Journal/printcode/{id:long}")] + [HttpPost, Route("journal/printcode/{id:long}")] public async Task> PrintCodeAsync(long id) { var data = await JournalService.PrintCodeAsync(id); @@ -157,12 +157,12 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers /// /// /// - [HttpPost, Route("Journal/resultreport")] + [HttpPost, Route("journal/resultreport")] public async Task> GenerateAsync([FromBody] DotMatrixNoteJournalReportInput input, [FromForm] IFormFile? file) { if (file != null) { - input.FileKey = $"Journal/{input.Id}/dotMatrixJournal.pdf"; + input.FileKey = $"journal/{input.Id}/dotMatrixJournal.pdf"; input.FileUrl = ossService.PutObject(input.FileKey, file.OpenReadStream()); } var data = await JournalService.ResultReportAsync(input); @@ -174,49 +174,13 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers /// /// /// - [HttpPost, Route("Journal/import")] + [HttpPost, Route("journal/import")] public async Task> JournalImport(JournalImportDto input) { var data = await JournalCatalogService.ImportAsync(input); return BaseResponse.Success(data); } - ///// - ///// 工单分页列表 - ///// - ///// - ///// - //[HttpPost, Route("tasklibrary/workorder/pagelist")] - //public async Task>> WorkOrderPageListAsync([FromBody] PageQueryModel search) - //{ - // var data = await JournalWorkOrderService.WorkOrderPageListAsync(search); - // return BaseResponse>.Success(data); - //} - - /// - /// 书籍发起工单 - /// - /// - /// - //[HttpPost, Route("tasklibrary/workorder/create")] - //public async Task> CreateWorkOrderAsync([FromBody] IcrWorkOrderCreateDto dto) - //{ - // var result = await JournalWorkOrderService.CreateWorkOrderAsync(dto); - // return result; - //} - - ///// - ///// 更新工单状态 - ///// - ///// - ///// - //[HttpPost, Route("tasklibrary/workorder/setstatus/{JournalId:long}")] - //public async Task> UpdateWorkOrderAsync(long JournalId) - //{ - // var result = await JournalWorkOrderService.UpdateWorkOrderAsync(JournalId); - // return BaseResponse.Success(result); - //} - /// /// 题库代理请求接口 ///