2026-07-07 17:52:21 +08:00
|
|
|
|
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()
|
|
|
|
|
|
{
|
2026-10-22 11:53:34 +08:00
|
|
|
|
{ 1, "俯卧撑" },
|
|
|
|
|
|
{ 2, "仰卧起坐" },
|
2026-07-07 17:52:21 +08:00
|
|
|
|
{ 3, "引体向上" },
|
|
|
|
|
|
{ 7, "立定跳远" },
|
|
|
|
|
|
{ 8, "跳绳" },
|
|
|
|
|
|
{ 9, "开合跳" },
|
|
|
|
|
|
{ 10, "高抬腿" },
|
|
|
|
|
|
{ 11, "深蹲" },
|
2026-10-22 11:53:34 +08:00
|
|
|
|
{ 12, "50米跑" },
|
|
|
|
|
|
{ 13, "100米跑" },
|
|
|
|
|
|
{ 14, "800米跑" },
|
|
|
|
|
|
{ 15, "1000米跑" },
|
|
|
|
|
|
{ 16, "3000米跑" },
|
|
|
|
|
|
{ 20, "50米×8" },
|
|
|
|
|
|
{ 21, "篮球绕杆" },
|
|
|
|
|
|
{ 22, "足球绕杆" },
|
2026-07-07 17:52:21 +08:00
|
|
|
|
{ 23, "坐位体前屈" },
|
|
|
|
|
|
{ 24, "单脚跳" },
|
|
|
|
|
|
{ 25, "动态臀桥" },
|
|
|
|
|
|
{ 26, "左右跳" },
|
|
|
|
|
|
{ 27, "打地鼠" },
|
|
|
|
|
|
{ 28, "七上八下" },
|
|
|
|
|
|
{ 29, "消灭蚊子" },
|
|
|
|
|
|
{ 30, "石头剪刀布" },
|
|
|
|
|
|
{ 31, "变脸" },
|
|
|
|
|
|
{ 32, "打钉子" },
|
2026-10-22 11:53:34 +08:00
|
|
|
|
{ 33, "击鼓传花" },
|
|
|
|
|
|
{ 34, "踢足球" },
|
|
|
|
|
|
{ 35, "手脚并用" },
|
|
|
|
|
|
{ 36, "踢毽子" },
|
|
|
|
|
|
{ 37, "风火轮" },
|
|
|
|
|
|
{ 38, "顺序摸数字" },
|
|
|
|
|
|
{ 39, "俄罗斯方块" },
|
|
|
|
|
|
{ 40, "诗词满腹" },
|
|
|
|
|
|
{ 41, "单词大王" },
|
|
|
|
|
|
{ 42, "数学王者" },
|
|
|
|
|
|
{ 43, "音乐大师" },
|
|
|
|
|
|
{ 44, "历史小生" },
|
|
|
|
|
|
{ 45, "科学达人" },
|
|
|
|
|
|
{ 46, "纵跳摸高" },
|
|
|
|
|
|
{ 47, "半蹲跳" },
|
|
|
|
|
|
{ 48, "深蹲跳" },
|
|
|
|
|
|
{ 49, "侧向蹲起" },
|
|
|
|
|
|
{ 50, "篮球单手运球" },
|
|
|
|
|
|
{ 51, "篮球双手交替运球" },
|
|
|
|
|
|
{ 52, "身体绕球" },
|
|
|
|
|
|
{ 53, "足球踩球" },
|
|
|
|
|
|
{ 54, "足球颠球" },
|
|
|
|
|
|
{ 55, "足球踩单车" },
|
|
|
|
|
|
{ 56, "排球垫球" },
|
|
|
|
|
|
{ 57, "排球自传挑战" },
|
|
|
|
|
|
{ 60, "实心球" },
|
|
|
|
|
|
{ 61, "阳光跑" },
|
|
|
|
|
|
{ 62, "健身长拳" },
|
|
|
|
|
|
{ 63, "200米跑" },
|
|
|
|
|
|
{ 64, "400米×4" },
|
|
|
|
|
|
{ 65, "400米跑" },
|
|
|
|
|
|
{ 66, "6分钟跑" },
|
|
|
|
|
|
{ 67, "9分钟跑" },
|
|
|
|
|
|
{ 68, "1500米跑" },
|
|
|
|
|
|
{ 69, "60米跑" },
|
2026-07-07 17:52:21 +08:00
|
|
|
|
{ 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
|
2026-10-13 14:27:08 +08:00
|
|
|
|
join school in _dbContext.Set<S_School>().AsNoTracking()
|
|
|
|
|
|
on device.OrgId equals (int?)school.Id into schoolGroup
|
|
|
|
|
|
from school in schoolGroup.DefaultIfEmpty()
|
2026-07-07 17:52:21 +08:00
|
|
|
|
join student in _dbContext.Set<S_Student>().AsNoTracking()
|
2026-10-13 14:27:08 +08:00
|
|
|
|
on new { StudentNo = train.UserSerial, SchoolCode = school.SchoolCode }
|
|
|
|
|
|
equals new { student.StudentNo, student.SchoolCode } into studentGroup
|
2026-07-07 17:52:21 +08:00
|
|
|
|
from student in studentGroup.DefaultIfEmpty()
|
2026-10-13 14:27:08 +08:00
|
|
|
|
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()
|
2026-07-07 17:52:21 +08:00
|
|
|
|
select new
|
|
|
|
|
|
{
|
|
|
|
|
|
train.Id,
|
|
|
|
|
|
device.OrgId,
|
2026-10-13 14:27:08 +08:00
|
|
|
|
DeviceSchoolCode = school.SchoolCode,
|
2026-07-07 17:52:21 +08:00
|
|
|
|
train.CourseId,
|
|
|
|
|
|
train.StartTime,
|
|
|
|
|
|
train.EndTime,
|
2026-10-13 14:27:08 +08:00
|
|
|
|
train.Score,
|
2026-10-22 11:32:30 +08:00
|
|
|
|
// Cast in SQL so int and float columns both materialize as the original int type.
|
|
|
|
|
|
StandardCounts = Convert.ToInt32(Convert.ToDouble(train.StandardCounts)),
|
2026-10-13 14:27:08 +08:00
|
|
|
|
train.UnStandardCounts,
|
|
|
|
|
|
train.TimeKeeping,
|
|
|
|
|
|
train.Duration,
|
|
|
|
|
|
train.Distance,
|
2026-07-07 17:52:21 +08:00
|
|
|
|
train.UserSerial,
|
|
|
|
|
|
StudentName = student == null ? train.UserSerial : student.StudentName,
|
|
|
|
|
|
Sex = student == null ? (SexType?)null : student.Sex,
|
|
|
|
|
|
ClassId = student == null ? 0 : student.ClassId,
|
2026-10-13 14:27:08 +08:00
|
|
|
|
ClassName = studentClass == null || studentClass.ClassName == null || studentClass.ClassName == ""
|
|
|
|
|
|
? (student == null ? string.Empty : student.ClassName)
|
|
|
|
|
|
: (studentClass.GradeName ?? string.Empty) + studentClass.ClassName
|
2026-07-07 17:52:21 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (!isAdmin)
|
|
|
|
|
|
{
|
|
|
|
|
|
var currentSchoolId = schoolId.GetValueOrDefault();
|
2026-10-13 14:27:08 +08:00
|
|
|
|
query = query.Where(x => x.OrgId == currentSchoolId && x.DeviceSchoolCode == schoolCode);
|
2026-07-07 17:52:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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))
|
2026-10-22 11:53:34 +08:00
|
|
|
|
rows = rows.Where(x => GetCourseName(x.CourseId) == projectName).ToList();
|
2026-07-07 17:52:21 +08:00
|
|
|
|
|
|
|
|
|
|
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),
|
2026-10-13 14:27:08 +08:00
|
|
|
|
ClassName = string.IsNullOrWhiteSpace(x.ClassName) ? "未匹配班级" : x.ClassName,
|
2026-07-07 17:52:21 +08:00
|
|
|
|
ProjectName = GetCourseName(x.CourseId),
|
2026-10-13 14:27:08 +08:00
|
|
|
|
CourseId = x.CourseId,
|
|
|
|
|
|
Score = x.Score,
|
|
|
|
|
|
StandardCounts = x.StandardCounts,
|
|
|
|
|
|
UnStandardCounts = x.UnStandardCounts,
|
|
|
|
|
|
TimeKeeping = x.TimeKeeping,
|
|
|
|
|
|
Duration = x.Duration,
|
|
|
|
|
|
Distance = x.Distance,
|
2026-07-07 17:52:21 +08:00
|
|
|
|
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)
|
|
|
|
|
|
{
|
2026-10-13 14:27:08 +08:00
|
|
|
|
return CourseNames.TryGetValue(courseId, out var name) ? name : $"待确认课目(编号{courseId})";
|
2026-07-07 17:52:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 ? "男" : "女";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|