using dy.net.model.dto; using dy.net.service; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace dy.net.Controllers { [Route("api/tasks")] [ApiController] [Authorize] public class TasksController : ControllerBase { private readonly VideoTaskService _tasks; private readonly DouyinQuartzJobService _quartz; private readonly DouyinVideoService _videos; public TasksController(VideoTaskService tasks, DouyinQuartzJobService quartz, DouyinVideoService videos) { _tasks = tasks; _quartz = quartz; _videos = videos; } [HttpPost("sync")] public async Task StartSync([FromQuery] VideoTypeEnum? videoType = null) => await ExecuteAsync(async () => { var tasks = await _quartz.TriggerVideoJobsNowAsync(videoType); return ApiResult.Success(new { taskIds = tasks.Select(x => x.Id).ToList(), count = tasks.Count }); }); [HttpGet] public async Task List([FromQuery] VideoTaskPageRequest request) => ApiResult.Success(await _tasks.GetTasksAsync(request)); [HttpGet("summary")] public async Task Summary() => ApiResult.Success(await _tasks.GetSummaryAsync()); [HttpGet("{type}/{id}")] public async Task Detail(VideoTaskType type, string id) => await ExecuteAsync(async () => ApiResult.Success(await _tasks.GetTaskAsync(type, id))); [HttpGet("{type}/{id}/items")] public async Task Items(VideoTaskType type, string id, [FromQuery] VideoTaskItemPageRequest request) => await ExecuteAsync(async () => ApiResult.Success(await _tasks.GetItemsAsync(type, id, request))); [HttpPost("{type}/{id}/retry-failed")] public async Task RetryFailed(VideoTaskType type, string id) => await ExecuteAsync(async () => { await _tasks.RetryFailedAsync(type, id); return ApiResult.Success("重试任务已提交"); }); [HttpPost("{type}/{id}/items/{itemId}/retry")] public async Task RetryItem(VideoTaskType type, string id, string itemId) => await ExecuteAsync(async () => { await _tasks.RetryItemAsync(type, id, itemId); return ApiResult.Success("重试任务已提交"); }); [HttpPost("{type}/{id}/items/{itemId}/retry-cleanup")] public async Task RetryCleanup(VideoTaskType type, string id, string itemId) => await ExecuteAsync(async () => { if (type != VideoTaskType.Sync) throw new InvalidOperationException("仅普通同步任务支持重试旧本地文件清理。"); var deleted = await _videos.RetryTaskItemLocalCleanupAsync(id, itemId); return ApiResult.Success(new { deletedCount = deleted, message = deleted > 0 ? $"已清理 {deleted} 个旧本地文件。" : "旧本地文件已不存在或仍被共享引用,清理状态已确认。" }); }); [HttpPost("{type}/{id}/actions/{action}")] public async Task Action(VideoTaskType type, string id, string action, CancellationToken cancellationToken) => await ExecuteAsync(async () => { await _tasks.ExecuteTaskActionAsync(type, id, action, cancellationToken); return ApiResult.Success("操作已提交"); }); [HttpPost("storage-health/probe")] public async Task Probe(CancellationToken cancellationToken) { var result = await _tasks.ProbeStorageAsync(cancellationToken); return result.Success ? ApiResult.Success(new { message = result.Message }) : ApiResult.Fail(result.Message); } private static async Task ExecuteAsync(Func> action) { try { return await action(); } catch (Exception ex) when (ex is InvalidOperationException or KeyNotFoundException) { return ApiResult.Fail(ex.Message); } } } }