using AX.FireTrainingSys.DTOs; using AX.FireTrainingSys.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; namespace AX.FireTrainingSys.Controllers { /// /// 学习记录控制器。 /// [Produces("application/json")] [Route("api/[controller]")] [ApiVersion("1.0")] [ApiController] public class StudyRecordsController : ControllerBase { private readonly DriveDbContext dbContext; public StudyRecordsController(DriveDbContext dbContext) { this.dbContext = dbContext; } /// /// 获得所有学习记录。 /// /// 查询条件 /// [Authorize(Roles = nameof(RoleType.Admin))] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status200OK)] [HttpGet] public async Task>> Get([FromQuery] StudyRecordQueryOptions options) { var rangeEnd = DateTimeOffset.Now; var rangeStart = rangeEnd.AddYears(-1); if (string.IsNullOrEmpty(options.Name)) return BadRequest($"{nameof(options.Name)} can not be empty."); if (options.StartTime != default && (options.StartTime < rangeStart || options.StartTime > rangeEnd)) return BadRequest($"{nameof(options.StartTime)} is out of range."); if (options.EndTime != default && (options.EndTime < rangeStart || options.EndTime > rangeEnd)) return BadRequest($"{nameof(options.EndTime)} is out of range."); if (options.EndTime == default) options.EndTime = rangeEnd; if (options.StartTime == default) options.StartTime = options.EndTime.Value.AddMonths(-1); if (options.PageNumber == default) options.PageNumber = 1; if (options.PageSize == default) options.PageSize = 100; var query = dbContext.StudyRecords .Include(e => e.User) .AsNoTracking(); query = query.Where(e => e.User.Name == options!.Name); query = query.Where(e => e.CreationTime >= options.StartTime!.Value.UtcDateTime); query = query.Where(e => e.CreationTime <= options.EndTime!.Value.UtcDateTime); if (!string.IsNullOrEmpty(options.PostName)) query = query.Where(e => e.PostName == options.PostName); if (!string.IsNullOrEmpty(options.Catalog)) query = query.Where(e => e.Catalog == options.Catalog); var count = await query.CountAsync(); query = query.OrderByDescending(e => e.CreationTime); if (options.PageNumber > 1) query = query.Skip((options.PageNumber.Value - 1) * options.PageSize.Value); query = query.Take(options.PageSize.Value); var items = await query.Select(e => e.ToDTO()) .ToListAsync(); var page = new Page { PageNumber = (int)options.PageNumber, PageSize = (int)options.PageSize, TotalPages = (int)Math.Ceiling((double)count / (int)options.PageSize), TotalCount = count, Items = items }; return Ok(page); } /// /// 统计学习记录。 /// /// 查询条件 /// [Authorize(Roles = nameof(RoleType.Admin))] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status200OK)] [HttpGet("[action]")] public async Task>> Statistics([FromQuery] StudyStatisticsQueryOptions options) { var rangeEnd = DateTimeOffset.Now; var rangeStart = rangeEnd.AddYears(-1); if (string.IsNullOrEmpty(options.Name)) return BadRequest($"{nameof(options.Name)} can not be empty."); if (options.StartTime != default && (options.StartTime < rangeStart || options.StartTime > rangeEnd)) return BadRequest($"{nameof(options.StartTime)} is out of range."); if (options.EndTime != default && (options.EndTime < rangeStart || options.EndTime > rangeEnd)) return BadRequest($"{nameof(options.EndTime)} is out of range."); if (options.EndTime == default) options.EndTime = rangeEnd; if (options.StartTime == default) options.StartTime = options.EndTime.Value.AddMonths(-1); var query = dbContext.StudyRecords .Include(e => e.User) .AsNoTracking(); query = query.Where(e => e.User.Name == options!.Name); query = query.Where(e => e.CreationTime >= options.StartTime!.Value.UtcDateTime); query = query.Where(e => e.CreationTime <= options.EndTime!.Value.UtcDateTime); var result = await query.GroupBy(e => new { e.PostName, e.Catalog }) .Select(g => new StudyStatisticsInfo { PostName = g.Key.PostName, Catalog = g.Key.Catalog, Count = g.Count() }) .OrderBy(e => e.PostName) .ThenBy(e => e.Catalog) .ToListAsync(); return Ok(result); } /// /// 创建学习记录。 /// /// 用户信息 /// [Authorize(Roles = "Profile")] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status201Created)] [HttpPost] public async Task> Post([FromBody] StudyRecordInfo info) { var userid = HttpContext.User.FindFirstValue(JwtClaimTypes.Subject); var model = info.ToModel(userid); dbContext.StudyRecords.Add(model); await dbContext.SaveChangesAsync(); info.Id = model.Id; info.CreationTime = model.CreationTime.ToLocalTime(); return CreatedAtAction(nameof(Post), info); } } internal static partial class Extensions { public static StudyRecord ToModel(this StudyRecordInfo info, string userid) => new StudyRecord { Operation = info.Operation, PostName = info.PostName, Catalog = info.Catalog, Target = info.Target, UserId = userid }; public static StudyRecordInfo ToDTO(this StudyRecord model) => new StudyRecordInfo { Id = model.Id, CreationTime = model.CreationTime.ToLocalTime(), Operation = model.Operation, PostName = model.PostName, Catalog = model.Catalog, Target = model.Target }; } }