feat: 新增操作日志功能并优化定时任务配置

1.  新增OperationLogAttribute与OperationLogActionFilter,实现自动化操作日志记录
2.  新增OperationLogRecordInput输入模型,重构IOperationLogService日志接口
3.  为所有业务控制器接口添加操作日志注解
4.  调整期刊AI批改任务的执行周期与方法适配异步调用
5.  优化Hangfire定时任务注册逻辑,支持异步任务
6.  补充完善操作日志类型与目标类型枚举
This commit is contained in:
glz
2026-07-09 18:01:37 +08:00
parent 4bb03aa0df
commit 766be485d0
25 changed files with 1001 additions and 92 deletions

View File

@ -6,6 +6,7 @@ using QYZH.InteractiveMagazine.Models.Enum;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using QYZH.InteractiveMagazine.Infrastructure.Middleware;
using QYZH.InteractiveMagazine.Infrastructure.OSS;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
@ -76,6 +77,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// </summary>
/// <param name="dto">创建杂志</param>
/// <returns></returns>
[OperationLog(OperationLogActionType.Create, OperationLogTargetType.Journal)]
[HttpPost, Route("journal/add")]
public async Task<BaseResponse<long>> AddAsync([FromBody] JournalAddDto dto)
{
@ -88,6 +90,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// </summary>
/// <param name="dto">书籍对象</param>
/// <returns></returns>
[OperationLog(OperationLogActionType.Update, OperationLogTargetType.Journal, TargetIdArgumentName = "dto")]
[HttpPost, Route("journal/update")]
public async Task<BaseResponse> Edit([FromBody] JournalEditDto dto)
{
@ -100,6 +103,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
[OperationLog(OperationLogActionType.Delete, OperationLogTargetType.Journal, TargetIdRouteKey = null)]
[HttpPost, Route("journal/delete")]
public async Task<BaseResponse<bool>> DeleteAsync([Required][FromBody] List<long> ids)
{
@ -111,6 +115,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 书籍起始页
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.Update, OperationLogTargetType.Journal)]
[HttpPost, Route("journal/startpage")]
public async Task<BaseResponse<bool>> StartPageAsync([FromQuery]long id, [FromQuery] int index)
{
@ -122,6 +127,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 书籍归档
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.StatusChange, OperationLogTargetType.Journal)]
[HttpPost, Route("journal/rchive/{id:long}")]
public async Task<BaseResponse<bool>> Archive(long id)
{
@ -133,6 +139,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 书籍废弃
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.StatusChange, OperationLogTargetType.Journal)]
[HttpPost]
[HttpPost, Route("journal/abandon/{id:long}")]
public async Task<BaseResponse<bool>> Abandon(long id)
@ -145,6 +152,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 书籍发布
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.StatusChange, OperationLogTargetType.Journal)]
[HttpPost, Route("journal/publish/{id:long}")]
public async Task<BaseResponse<bool>> Publish(long id)
{
@ -156,6 +164,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 书籍铺码
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.Update, OperationLogTargetType.Journal)]
[HttpPost, Route("journal/printcode/{id:long}")]
public async Task<BaseResponse<DotMatrixOutput>> PrintCodeAsync(long id)
{
@ -168,6 +177,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// <param name="input"></param>
/// <param name="file"></param>
/// <returns></returns>
[OperationLog(OperationLogActionType.Update, OperationLogTargetType.Journal, TargetIdArgumentName = "input")]
[HttpPost, Route("journal/resultreport")]
public async Task<BaseResponse<bool>> GenerateAsync([FromBody] DotMatrixNoteJournalReportInput input, [FromForm] IFormFile? file)
{
@ -185,6 +195,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[OperationLog(OperationLogActionType.Create, OperationLogTargetType.Journal)]
[HttpPost, Route("journal/import")]
public async Task<BaseResponse<long>> JournalImport(JournalImportDto input)
{
@ -266,6 +277,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// <param name="JournalId">file</param>
/// <param name="file">file</param>
/// <returns></returns>
[OperationLog(OperationLogActionType.Create, OperationLogTargetType.JournalCatalog, TargetIdRouteKey = "JournalId")]
[HttpPost, Route("catalog/import/{JournalId}")]
public async Task<BaseResponse<bool>> ImportAsync(long JournalId, [FromForm(Name = "file")] IFormFile file)
{
@ -283,6 +295,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[OperationLog(OperationLogActionType.Create, OperationLogTargetType.JournalCatalog)]
[HttpPost, Route("catalog/add")]
public async Task<BaseResponse<long>> CatalogAdd(JournalCatalogInput input)
{
@ -294,6 +307,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[OperationLog(OperationLogActionType.Update, OperationLogTargetType.JournalCatalog, TargetIdArgumentName = "input")]
[HttpPost, Route("catalog/update")]
public async Task<BaseResponse<bool>> CatalogUpdate(JournalCatalogUpdateInput input)
{
@ -305,6 +319,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[OperationLog(OperationLogActionType.Delete, OperationLogTargetType.JournalCatalog)]
[HttpPost, Route("catalog/delete/{id:long}")]
public async Task<BaseResponse<bool>> CatalogDelete(long id)
{
@ -318,6 +333,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[OperationLog(OperationLogActionType.Update, OperationLogTargetType.JournalCatalog, TargetIdArgumentName = "input")]
[HttpPost, Route("catalog/move")]
public async Task<BaseResponse<bool>> CatalogMove(MoveInput input)
{
@ -333,6 +349,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 书页新增
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.Create, OperationLogTargetType.JournalPage)]
[HttpPost, Route("page/add")]
public async Task<BaseResponse<long>> PageAdd(JournalAddV2Input input)
{
@ -344,6 +361,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 书页修改
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.Update, OperationLogTargetType.JournalPage, TargetIdArgumentName = "input")]
[HttpPost, Route("page/update")]
public async Task<BaseResponse<bool>> PageUpdate(PageLayoutInput input)
{
@ -355,6 +373,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 自动铺码
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.Update, OperationLogTargetType.JournalPage, TargetIdRouteKey = "JournalId")]
[HttpPost, Route("page/updatepageno/{JournalId:long}")]
public async Task<BaseResponse<bool>> PageUpdatePageNo([Required(ErrorMessage = "书籍编号不允许为空")] long JournalId)
{
@ -418,6 +437,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 书页问题新增
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.Create, OperationLogTargetType.JournalPageTask)]
[HttpPost, Route("page/task/add")]
[ProducesResponseType(typeof(BaseResponse<long>), 200)]
public async Task<BaseResponse<long>> PageTaskAdd(JournalPageTaskAddInput input)
@ -430,6 +450,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 书页问题更新
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.Update, OperationLogTargetType.JournalPageTask, TargetIdArgumentName = "input")]
[HttpPost, Route("page/task/update")]
[ProducesResponseType(typeof(BaseResponse<bool>), 200)]
public async Task<BaseResponse<bool>> PageTaskUpdate(JournalPageTaskUpdateInput input)
@ -454,6 +475,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 书页问题删除
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.Delete, OperationLogTargetType.JournalPageTask)]
[HttpPost, Route("page/task/delete/{id:long}")]
public async Task<BaseResponse<bool>> PageTaskDelete(long id)
{
@ -465,6 +487,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 书页问题补充
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.Update, OperationLogTargetType.JournalPageTask, TargetIdArgumentName = "input")]
[HttpPost, Route("page/task/complement")]
public async Task<BaseResponse<bool>> ComplementAnsync(JournalPageTaskComplementInput input)
{
@ -476,6 +499,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 答案新增
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.Create, OperationLogTargetType.JournalTaskAnswer)]
[HttpPost, Route("page/task/answer/add")]
public async Task<BaseResponse<long>> AnswerAdd(JournalTaskAnswerAddInput input)
{
@ -487,6 +511,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 答案更新
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.Update, OperationLogTargetType.JournalTaskAnswer, TargetIdArgumentName = "input")]
[HttpPost, Route("page/task/answer/update")]
public async Task<BaseResponse<bool>> AnswerUpdate(JournalTaskAnswerUpdateInput input)
{
@ -498,6 +523,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers
/// 答案删除
/// </summary>
/// <returns></returns>
[OperationLog(OperationLogActionType.Delete, OperationLogTargetType.JournalTaskAnswer)]
[HttpPost, Route("page/task/answer/delete/{id:long}")]
public async Task<BaseResponse<bool>> AnswerDelete(long id)
{