using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Tiku.Api.Contracts; using Tiku.Application.Assets; using Tiku.Application.PlatformAdmin; using Tiku.Application.Security; namespace Tiku.Api.Controllers; [ApiController] [Tags("平台端-公共题库")] [Authorize(Policy = BackendPermissions.PlatformQuestionBankManage)] [Produces("application/json")] [Route("api/platform/question-banks")] public sealed class PlatformQuestionBanksController( IPlatformQuestionBankCatalogService catalogService, IPlatformQuestionBankNodeService nodeService, IPlatformQuestionAdministrationService questionService, IPlatformQuestionImportService importService, IPlatformQuestionAssetService assetService, ICurrentUser currentUser) : ControllerBase { [HttpGet] [EndpointSummary("查询平台公共题库")] public async Task>> GetBanks( [FromQuery] string? keyword, [FromQuery] string? status, CancellationToken cancellationToken) { return Ok(await catalogService.GetBanksAsync(ResolveActor(), new PlatformQuestionBankFilter(Keyword: keyword, Status: status), cancellationToken)); } [HttpPut] [EndpointSummary("新增或更新平台公共题库")] public async Task> UpsertBank( UpsertPlatformQuestionBankCommand request, CancellationToken cancellationToken) { return Ok(await catalogService.UpsertBankAsync(ResolveActor(), request, cancellationToken)); } [HttpPost("{bankId:guid}/archive")] [EndpointSummary("归档平台公共题库")] public async Task> ArchiveBank(Guid bankId, CancellationToken cancellationToken) { return Ok(await catalogService.ArchiveBankAsync(ResolveActor(), bankId, cancellationToken)); } [HttpGet("{bankId:guid}/nodes")] [EndpointSummary("查询公共题库内容结构")] public async Task>> GetNodes(Guid bankId, CancellationToken cancellationToken) { return Ok(await nodeService.GetNodesAsync(ResolveActor(), bankId, cancellationToken)); } [HttpPut("nodes")] [EndpointSummary("新增或更新公共题库内容节点")] public async Task> UpsertNode( UpsertPlatformQuestionBankNodeCommand request, CancellationToken cancellationToken) { return Ok(await nodeService.UpsertNodeAsync(ResolveActor(), request, cancellationToken)); } [HttpPost("nodes/batch")] [EndpointSummary("批量创建公共题库章节或试卷")] public async Task>> BatchCreateNodes( BatchCreatePlatformQuestionBankNodesCommand request, CancellationToken cancellationToken) { return Ok(await nodeService.BatchCreateNodesAsync(ResolveActor(), request, cancellationToken)); } [HttpPost("nodes/{nodeId:guid}/archive")] [EndpointSummary("归档公共题库内容节点")] public async Task> ArchiveNode(Guid nodeId, CancellationToken cancellationToken) { return Ok(await nodeService.ArchiveNodeAsync(ResolveActor(), nodeId, cancellationToken)); } [HttpGet("questions")] [EndpointSummary("分页查询公共题库题目")] public async Task> GetQuestions( [FromQuery] Guid questionBankId, [FromQuery] Guid? contentNodeId, [FromQuery] string? keyword, [FromQuery] string? type, [FromQuery] int? difficulty, [FromQuery] string? status, [FromQuery] int page = 1, [FromQuery] int pageSize = 20, CancellationToken cancellationToken = default) { return Ok(await questionService.GetQuestionsAsync(ResolveActor(), new PlatformQuestionBankFilter( questionBankId, contentNodeId, keyword, type, difficulty, status, page, pageSize), cancellationToken)); } [HttpPut("questions")] [EndpointSummary("新增或更新公共题库题目并保留版本")] public async Task> UpsertQuestion( UpsertPlatformQuestionCommand request, CancellationToken cancellationToken) { return Ok(await questionService.UpsertQuestionAsync(ResolveActor(), request, cancellationToken)); } [HttpPost("questions/archive")] [EndpointSummary("批量归档公共题库题目")] public async Task> ArchiveQuestions( ArchivePlatformQuestionsCommand request, CancellationToken cancellationToken) { return Ok(await questionService.ArchiveQuestionsAsync(ResolveActor(), request, cancellationToken)); } [HttpPost("imports/preview")] [EndpointSummary("预检公共题库 JSON 导入")] public async Task> PreviewImport( PlatformQuestionImportCommand request, CancellationToken cancellationToken) { return Ok(await importService.PreviewImportAsync(ResolveActor(), request, cancellationToken)); } [HttpPost("imports")] [EndpointSummary("执行公共题库 JSON 导入")] public async Task> ExecuteImport( PlatformQuestionImportCommand request, CancellationToken cancellationToken) { return Ok(await importService.ExecuteImportAsync(ResolveActor(), request, cancellationToken)); } [HttpGet("imports/{jobId:guid}")] [EndpointSummary("查询公共题库导入结果")] public async Task> GetImport(Guid jobId, CancellationToken cancellationToken) { return Ok(await importService.GetImportAsync(ResolveActor(), jobId, cancellationToken)); } [HttpPost("assets/upload-sign")] [EndpointSummary("签发公共题库图片上传地址")] public async Task> SignAssetUpload( AssetUploadSignDto request, CancellationToken cancellationToken) { return Ok(await assetService.SignQuestionAssetUploadAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpPost("assets/upload-confirm")] [EndpointSummary("确认公共题库图片上传结果")] public async Task> ConfirmAssetUpload( AssetUploadConfirmDto request, CancellationToken cancellationToken) { return Ok(await assetService.ConfirmQuestionAssetUploadAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } private PlatformAdminActor ResolveActor() { return currentUser.UserId is { } userId ? new PlatformAdminActor(userId) : throw new PlatformAdminException("无法识别当前平台员工。", "platform_access_denied"); } }