YD_SmartSports.Api/VOL.Ai/Services/AiSportsStationService.cs
ltx c4b01d2f53 feat: 完善运动记录与体测数据接口
AI运动站:按设备学校和学生学号关联学生、班级,返回课目编号与成绩值,并修正壹路训练有效次数的数值类型。

AI阳光跑:在分页查询与导出共用条件中排除零有效里程、零有效次数记录。

体测数据记录:补全年级与课目编号、姓名和测试时间,新增按当前筛选条件导出完整记录的 Excel 接口;800/1000 米成绩格式化为分秒。
2026-10-13 14:27:08 +08:00

203 lines
7.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.EntityFrameworkCore;
using VOL.Ai.IServices;
using VOL.Core.EFDbContext;
using VOL.Core.Extensions.AutofacManager;
using VOL.Core.ManageUser;
using VOL.Entity.DomainModels;
using VOL.Entity.DomainModels.YiLu;
using VOL.Entity.Enum;
using VOL.Model;
using VOL.Model.Ai.Request;
using VOL.Model.Ai.Response;
namespace VOL.Ai.Services
{
public class AiSportsStationService : IAiSportsStationService, IDependency
{
private readonly VOLContext _dbContext;
private static readonly Dictionary<int, string> CourseNames = new()
{
{ 3, "引体向上" },
{ 7, "立定跳远" },
{ 8, "跳绳" },
{ 9, "开合跳" },
{ 10, "高抬腿" },
{ 11, "深蹲" },
{ 23, "坐位体前屈" },
{ 24, "单脚跳" },
{ 25, "动态臀桥" },
{ 26, "左右跳" },
{ 27, "打地鼠" },
{ 28, "七上八下" },
{ 29, "消灭蚊子" },
{ 30, "石头剪刀布" },
{ 31, "变脸" },
{ 32, "打钉子" },
{ 1001, "体重系数(BMI)" },
{ 1002, "肺活量" }
};
public AiSportsStationService(VOLContext dbContext)
{
_dbContext = dbContext;
}
public async Task<PageDataDto<AiSportsStationDto>> GetAiSportsStationList(AiSportsStationListRequest paramDto)
{
paramDto.PageIndex = paramDto.PageIndex <= 0 ? 1 : paramDto.PageIndex;
paramDto.PageSize = paramDto.PageSize <= 0 ? 10 : paramDto.PageSize;
var currentUser = UserContext.Current;
var isAdmin = currentUser?.IsSuperAdmin == true
|| string.Equals(currentUser?.UserName, "admin", StringComparison.OrdinalIgnoreCase);
var schoolCode = currentUser?.TenantId;
int? schoolId = null;
if (!isAdmin)
{
schoolId = await _dbContext.Set<S_School>()
.Where(x => x.SchoolCode == schoolCode)
.Select(x => (int?)x.Id)
.FirstOrDefaultAsync();
if (schoolId == null)
{
return new PageDataDto<AiSportsStationDto>
{
Total = 0,
TotalPages = 0,
PageIndex = paramDto.PageIndex,
PageSize = paramDto.PageSize,
Datas = new List<AiSportsStationDto>()
};
}
}
var studentName = paramDto.StudentName?.Trim();
var projectName = paramDto.ProjectName?.Trim();
var sex = GetSexType(paramDto.Sex);
var query =
from train in _dbContext.Set<YL_Train>().AsNoTracking()
join device in _dbContext.Set<YL_Device>().AsNoTracking()
on train.DeviceSerial equals device.SerialNumber
join school in _dbContext.Set<S_School>().AsNoTracking()
on device.OrgId equals (int?)school.Id into schoolGroup
from school in schoolGroup.DefaultIfEmpty()
join student in _dbContext.Set<S_Student>().AsNoTracking()
on new { StudentNo = train.UserSerial, SchoolCode = school.SchoolCode }
equals new { student.StudentNo, student.SchoolCode } into studentGroup
from student in studentGroup.DefaultIfEmpty()
join studentClass in _dbContext.Set<S_Class>().AsNoTracking()
on new { Id = student.ClassId, student.SchoolCode }
equals new { studentClass.Id, studentClass.SchoolCode } into classGroup
from studentClass in classGroup.DefaultIfEmpty()
select new
{
train.Id,
device.OrgId,
DeviceSchoolCode = school.SchoolCode,
train.CourseId,
train.StartTime,
train.EndTime,
train.Score,
train.StandardCounts,
train.UnStandardCounts,
train.TimeKeeping,
train.Duration,
train.Distance,
train.UserSerial,
StudentName = student == null ? train.UserSerial : student.StudentName,
Sex = student == null ? (SexType?)null : student.Sex,
ClassId = student == null ? 0 : student.ClassId,
ClassName = studentClass == null || studentClass.ClassName == null || studentClass.ClassName == ""
? (student == null ? string.Empty : student.ClassName)
: (studentClass.GradeName ?? string.Empty) + studentClass.ClassName
};
if (!isAdmin)
{
var currentSchoolId = schoolId.GetValueOrDefault();
query = query.Where(x => x.OrgId == currentSchoolId && x.DeviceSchoolCode == schoolCode);
}
if (!string.IsNullOrWhiteSpace(studentName))
query = query.Where(x => x.StudentName.Contains(studentName));
if (sex.HasValue)
query = query.Where(x => x.Sex == sex.Value);
if (paramDto.ClassId > 0)
query = query.Where(x => x.ClassId == paramDto.ClassId);
if (paramDto.StartTime.HasValue)
query = query.Where(x => x.StartTime >= paramDto.StartTime.Value);
if (paramDto.EndTime.HasValue)
query = query.Where(x => x.StartTime <= paramDto.EndTime.Value);
var rows = await query
.OrderByDescending(x => x.StartTime)
.ThenByDescending(x => x.Id)
.ToListAsync();
if (!string.IsNullOrWhiteSpace(projectName))
rows = rows.Where(x => GetCourseName(x.CourseId).Contains(projectName)).ToList();
var total = rows.Count;
var datas = rows
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
.Take(paramDto.PageSize)
.Select((x, index) => new AiSportsStationDto
{
Ind = (paramDto.PageIndex - 1) * paramDto.PageSize + index + 1,
StudentName = x.StudentName,
Sex = GetSexName(x.Sex),
ClassName = string.IsNullOrWhiteSpace(x.ClassName) ? "未匹配班级" : x.ClassName,
ProjectName = GetCourseName(x.CourseId),
CourseId = x.CourseId,
Score = x.Score,
StandardCounts = x.StandardCounts,
UnStandardCounts = x.UnStandardCounts,
TimeKeeping = x.TimeKeeping,
Duration = x.Duration,
Distance = x.Distance,
StartTime = x.StartTime,
EndTime = x.EndTime
})
.ToList();
return new PageDataDto<AiSportsStationDto>
{
Total = total,
TotalPages = (int)Math.Ceiling(total / (double)paramDto.PageSize),
PageIndex = paramDto.PageIndex,
PageSize = paramDto.PageSize,
Datas = datas
};
}
private static string GetCourseName(int courseId)
{
return CourseNames.TryGetValue(courseId, out var name) ? name : $"待确认课目(编号{courseId})";
}
private static SexType? GetSexType(string sex)
{
return sex switch
{
"男" => SexType.Male,
"女" => SexType.Female,
_ => null
};
}
private static string GetSexName(SexType? sex)
{
if (sex == null) return string.Empty;
return sex == SexType.Male ? "男" : "女";
}
}
}