feat: Implement scheduled tasks management and budget archiving functionality
Some checks failed
Docker Build & Deploy / Build Docker Image (push) Failing after 6s
Docker Build & Deploy / Deploy to Production (push) Has been skipped
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 2s
Docker Build & Deploy / WeChat Notification (push) Successful in 2s
Some checks failed
Docker Build & Deploy / Build Docker Image (push) Failing after 6s
Docker Build & Deploy / Deploy to Production (push) Has been skipped
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 2s
Docker Build & Deploy / WeChat Notification (push) Successful in 2s
- Added BudgetArchiveJob for monthly budget archiving. - Created BudgetArchive entity and BudgetArchiveRepository for managing archived budgets. - Introduced JobController for handling job execution, pausing, and resuming. - Developed ScheduledTasksView for displaying and managing scheduled tasks in the frontend. - Updated PeriodicBillJob to improve scope handling. - Enhanced OpenAiService with increased HTTP timeout. - Added archiveBudgets API endpoint for archiving budgets by year and month. - Refactored BudgetController to utilize new repository patterns and improved error handling. - Introduced rich-content styles for better rendering of HTML content in Vue components. - Updated various Vue components to support rich HTML content display.
This commit is contained in:
114
WebApi/Controllers/JobController.cs
Normal file
114
WebApi/Controllers/JobController.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using Quartz;
|
||||
|
||||
namespace WebApi.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]/[action]")]
|
||||
public class JobController(ISchedulerFactory schedulerFactory, ILogger<JobController> logger) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<BaseResponse<List<JobStatus>>> GetJobsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var scheduler = await schedulerFactory.GetScheduler();
|
||||
var jobKeys = await scheduler.GetJobKeys(Quartz.Impl.Matchers.GroupMatcher<JobKey>.AnyGroup());
|
||||
var jobStatuses = new List<JobStatus>();
|
||||
|
||||
foreach (var jobKey in jobKeys)
|
||||
{
|
||||
var jobDetail = await scheduler.GetJobDetail(jobKey);
|
||||
var triggers = await scheduler.GetTriggersOfJob(jobKey);
|
||||
var trigger = triggers.FirstOrDefault();
|
||||
|
||||
var status = "Unknown";
|
||||
DateTime? nextFireTime = null;
|
||||
|
||||
if (trigger != null)
|
||||
{
|
||||
var triggerState = await scheduler.GetTriggerState(trigger.Key);
|
||||
status = triggerState.ToString();
|
||||
nextFireTime = trigger.GetNextFireTimeUtc()?.ToLocalTime().DateTime;
|
||||
}
|
||||
|
||||
jobStatuses.Add(new JobStatus
|
||||
{
|
||||
Name = jobKey.Name,
|
||||
JobDescription = jobDetail?.Description ?? jobKey.Name,
|
||||
TriggerDescription = trigger?.Description ?? string.Empty,
|
||||
Status = status,
|
||||
NextRunTime = nextFireTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? "无"
|
||||
});
|
||||
}
|
||||
|
||||
return jobStatuses.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "获取任务列表失败");
|
||||
return $"获取任务列表失败: {ex.Message}".Fail<List<JobStatus>>();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<BaseResponse<bool>> ExecuteAsync([FromBody] JobRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var scheduler = await schedulerFactory.GetScheduler();
|
||||
await scheduler.TriggerJob(new JobKey(request.JobName));
|
||||
return true.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "执行任务失败: {JobName}", request.JobName);
|
||||
return $"执行任务失败: {ex.Message}".Fail<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<BaseResponse<bool>> PauseAsync([FromBody] JobRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var scheduler = await schedulerFactory.GetScheduler();
|
||||
await scheduler.PauseJob(new JobKey(request.JobName));
|
||||
return true.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "暂停任务失败: {JobName}", request.JobName);
|
||||
return $"暂停任务失败: {ex.Message}".Fail<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<BaseResponse<bool>> ResumeAsync([FromBody] JobRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var scheduler = await schedulerFactory.GetScheduler();
|
||||
await scheduler.ResumeJob(new JobKey(request.JobName));
|
||||
return true.Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "恢复任务失败: {JobName}", request.JobName);
|
||||
return $"恢复任务失败: {ex.Message}".Fail<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
public class JobStatus
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string JobDescription { get; set; } = string.Empty;
|
||||
public string TriggerDescription { get; set; } = string.Empty;
|
||||
public string Status { get; set; } = string.Empty;
|
||||
public string NextRunTime { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class JobRequest
|
||||
{
|
||||
public string JobName { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user