feat: 添加课堂跳绳报告查询与导出接口

按课堂记录和学校权限范围查询 Ai_FastJumpRopeData,提供分页报告与 Excel 导出。

导出完整课堂数据并关闭 Excel 自动列宽,避免 GDI 依赖。
This commit is contained in:
ltx 2026-10-10 09:44:15 +08:00
parent 2759a4aa8a
commit e1fac41f8c
4 changed files with 137 additions and 0 deletions

View File

@ -169,6 +169,10 @@ namespace VOL.Business.IServices.Training
/// <returns></returns>
Task<GetClassReportDetailsModel> GetClassReportDetails(int id);
Task<PageDataDto<FastJumpRopeReportModel>> GetFastJumpRopeReport(int classRoomRecordId, int pageIndex, int pageSize);
Task<List<FastJumpRopeReportModel>> GetFastJumpRopeReportExport(int classRoomRecordId);
/// <summary>
/// 学生课堂报告详情
/// </summary>

View File

@ -1987,6 +1987,60 @@ namespace VOL.Business.Services.Training
#region 课堂报告
private IQueryable<Ai_FastJumpRopeData> FastJumpRopeReportQuery(int classRoomRecordId)
{
var schoolCode = UserContext.Current.TenantId;
var isSuperAdmin = UserContext.Current.IsSuperAdmin;
var classrooms = _teacherRepository.DbContext.Set<Ai_ClassRoomRecord>().AsNoTracking();
return _teacherRepository.DbContext.Set<Ai_FastJumpRopeData>().AsNoTracking()
.Where(row => row.ClassRoomRecordId == classRoomRecordId &&
classrooms.Any(room => room.Id == classRoomRecordId &&
room.SchoolCode == row.SchoolCode &&
(isSuperAdmin || room.SchoolCode == schoolCode)));
}
private static List<FastJumpRopeReportModel> ToFastJumpRopeReportRows(List<Ai_FastJumpRopeData> rows, int offset)
{
return rows.Select((row, index) => new FastJumpRopeReportModel
{
Index = offset + index + 1,
StudentNo = row.StudentNo,
StudentName = row.StudentName,
GradeAndClass = $"{row.GradeName}-{row.ClassName}",
ModeName = string.IsNullOrWhiteSpace(row.ModelName) ? row.ModeType.GetDescription() : row.ModelName,
JumpValue = row.JumpValue,
ErrorNumber = row.ErrorNumber,
MotionDuration = row.MotionDuration,
RankName = row.Rank.HasValue && global::System.Enum.IsDefined(typeof(AchievementRank), row.Rank.Value)
? ((AchievementRank)row.Rank.Value).GetDescription() : "-",
ScoreTime = row.ScoreTime
}).ToList();
}
public async Task<PageDataDto<FastJumpRopeReportModel>> GetFastJumpRopeReport(int classRoomRecordId, int pageIndex, int pageSize)
{
var query = FastJumpRopeReportQuery(classRoomRecordId);
var total = await query.CountAsync();
var offset = (pageIndex - 1) * pageSize;
var rows = await query.OrderByDescending(row => row.ScoreTime).ThenByDescending(row => row.Id)
.Skip(offset).Take(pageSize).ToListAsync();
return new PageDataDto<FastJumpRopeReportModel>
{
Total = total,
PageIndex = pageIndex,
PageSize = pageSize,
TotalPages = (int)Math.Ceiling(total / (double)pageSize),
Datas = ToFastJumpRopeReportRows(rows, offset)
};
}
public async Task<List<FastJumpRopeReportModel>> GetFastJumpRopeReportExport(int classRoomRecordId)
{
var rows = await FastJumpRopeReportQuery(classRoomRecordId)
.OrderByDescending(row => row.ScoreTime).ThenByDescending(row => row.Id).ToListAsync();
return ToFastJumpRopeReportRows(rows, 0);
}
/// <summary>
/// 课堂记录列表
/// </summary>

View File

@ -0,0 +1,38 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace VOL.Model
{
public class FastJumpRopeReportModel
{
[Display(Name = "序号")]
public int Index { get; set; }
[Display(Name = "学号")]
public string StudentNo { get; set; } = string.Empty;
[Display(Name = "姓名")]
public string StudentName { get; set; } = string.Empty;
[Display(Name = "年级班级")]
public string GradeAndClass { get; set; } = string.Empty;
[Display(Name = "跳绳模式")]
public string ModeName { get; set; } = string.Empty;
[Display(Name = "跳绳次数")]
public int? JumpValue { get; set; }
[Display(Name = "错误次数")]
public int? ErrorNumber { get; set; }
[Display(Name = "运动时长(秒)")]
public int? MotionDuration { get; set; }
[Display(Name = "成绩等级")]
public string RankName { get; set; } = string.Empty;
[Display(Name = "测试时间")]
public DateTime ScoreTime { get; set; }
}
}

View File

@ -365,6 +365,47 @@ namespace VOL.WebApi.Controllers.Business
return await _trainingDataService.GetClassReportDetails(id);
}
/// <summary>
/// 当前课堂的跳绳报告。
/// </summary>
[HttpGet(nameof(GetFastJumpRopeReport))]
public Task<PageDataDto<FastJumpRopeReportModel>> GetFastJumpRopeReport(
[FromQuery] int classRoomRecordId, [FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 10)
{
if (classRoomRecordId <= 0 || pageIndex <= 0 || pageSize <= 0 || pageSize > 200)
throw new ArgumentException("课堂记录、页码或每页行数不正确");
return _trainingDataService.GetFastJumpRopeReport(classRoomRecordId, pageIndex, pageSize);
}
/// <summary>
/// 导出当前课堂的全部跳绳成绩。
/// </summary>
[HttpGet(nameof(ExportFastJumpRopeReport))]
public async Task<IActionResult> ExportFastJumpRopeReport([FromQuery] int classRoomRecordId)
{
if (classRoomRecordId <= 0)
throw new ArgumentException("课堂记录不正确");
var rows = await _trainingDataService.GetFastJumpRopeReportExport(classRoomRecordId);
var columns = new List<string>
{
nameof(FastJumpRopeReportModel.Index),
nameof(FastJumpRopeReportModel.StudentNo),
nameof(FastJumpRopeReportModel.StudentName),
nameof(FastJumpRopeReportModel.GradeAndClass),
nameof(FastJumpRopeReportModel.ModeName),
nameof(FastJumpRopeReportModel.JumpValue),
nameof(FastJumpRopeReportModel.ErrorNumber),
nameof(FastJumpRopeReportModel.MotionDuration),
nameof(FastJumpRopeReportModel.RankName),
nameof(FastJumpRopeReportModel.ScoreTime)
};
var bytes = Tool.ExportToExcel(
new Dictionary<string, List<FastJumpRopeReportModel>> { ["跳绳报告"] = rows },
columns, autoFitColumns: false);
return File(bytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
$"跳绳报告{DateTime.Now:yyyyMMddHHmmss}.xlsx");
}
/// <summary>
/// 学生课堂报告详情
/// </summary>