using Microsoft.EntityFrameworkCore; using VOL.Entity.DomainModels.XinWei; using YD_YiLu.Api.Context; using YD_YiLu.Api.Services.Interface; using YD_YiLu.Api.SmartSportsEntitys; using YD_YiLu.Commons.Dto.DeviceSync; using YD_YiLu.Commons.Utils; namespace YD_YiLu.Api.Services.Impl { /// /// 壹动站/壹体屏/活力课间屏 设备同步服务实现 /// public class DeviceSyncService : IDeviceSyncService { private readonly SmartSportsContext _context; public DeviceSyncService(SmartSportsContext context) { _context = context; } public async Task GetOrgIdByDeviceAsync(string deviceSerial) { var device = await _context.YL_Device.FirstOrDefaultAsync(x => x.SerialNumber == deviceSerial); if (device?.OrgId != null) return device.OrgId; else return 0; } public async Task UserPageAsync(DeviceSyncUserPageRequestDto dto) { var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial); if (!orgId.HasValue) return new DeviceSyncUserPageResponseDto(); string schoolCode = await _context.School.Where(x => x.Id == orgId).Select(x => x.SchoolCode).FirstAsync(); var query = _context.Student.Where(x => x.SchoolCode == schoolCode); //if (dto.UserType == 1) query = query.Where(x => false); //else if (dto.UserType == 2) { } //else if (dto.UserType == 3) query = query.Where(x => false); var total = await query.CountAsync(); var pageIndex = dto.PageIndex < 1 ? 1 : dto.PageIndex; var fullSync = dto.FullSync || dto.PageSize <= 0; var pageSize = fullSync ? total : (dto.PageSize <= 0 ? 10 : dto.PageSize); var listQuery = query.OrderBy(x => x.Id); if (!fullSync) listQuery = (IOrderedQueryable)listQuery.Skip((pageIndex - 1) * pageSize).Take(pageSize); var list = await listQuery .Select(s => new DeviceSyncUserDto { UserId = s.Id, UserType = 2, Username = s.StudentNo, Nickname = s.StudentName, GradeName = "", OrganizationId = s.Id, OrganizationName = s.ClassName ?? "", FacePictureUrl = s.Photo ?? "", Identity = "学生", Gender = s.Sex == 1 ? "男" : "女", Birthday = s.Birthday.HasValue ? s.Birthday.Value.ToString("yyyy-MM-dd") : "", UserSerial = s.StudentNo, }) .ToListAsync(); foreach (var u in list) { var c = await _context.Class.FindAsync(u.OrganizationId); if (c != null) { u.OrganizationName = c.ClassName ?? ""; u.GradeName = c.GradeName ?? ""; } } return new DeviceSyncUserPageResponseDto { SyncId = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), Current = fullSync ? 1 : pageIndex, Pages = fullSync ? 1 : (total == 0 ? 0 : (int)Math.Ceiling(total / (double)Math.Max(pageSize, 1))), Total = total, UserList = list }; } public async Task UserSyncAsync(string deviceSerial, int deviceType, int userType) { return await UserPageAsync(new DeviceSyncUserPageRequestDto { DeviceSerial = deviceSerial, DeviceType = deviceType, UserType = userType, PageIndex = 1, FullSync = true, PageSize = 0 }); } public async Task> OrganizationAsync(DeviceSyncOrganizationRequestDto dto) { var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial); if (!orgId.HasValue) return new List(); string schoolCode = await _context.School.Where(x => x.Id == orgId).Select(x => x.SchoolCode).FirstAsync(); var grades = await _context.Grade.Where(x => x.SchoolCode == schoolCode).OrderBy(x => x.Id).ToListAsync(); var classes = await _context.Class.Where(x => x.SchoolCode == schoolCode).ToListAsync(); var result = new List(); foreach (var g in grades) { var gradeClasses = classes.Where(x => x.GradeId == g.Id).ToList(); result.Add(new DeviceSyncOrganizationDto { OrganizationId = g.Id, ParentId = 0, ParentName = null, OrganizationName = g.GradeName, OrganizationType = "年级", Children = gradeClasses.Select(c => new DeviceSyncOrganizationDto { OrganizationId = c.Id, ParentId = g.Id, ParentName = g.GradeName, OrganizationName = c.ClassName ?? "", OrganizationType = "班级", ChildrenIds = new List() }).ToList(), ChildrenIds = gradeClasses.Select(x => x.Id).ToList() }); } return result; } public async Task> TrainPushAsync(List list) { var orgId = await GetOrgIdByDeviceAsync(list.FirstOrDefault()?.DeviceSerial ?? ""); if (!orgId.HasValue) return new List(); var result = new List(); var projects = await _context.XW_TestingProject.ToListAsync(); string schoolCode = await _context.School.Where(x => x.Id == orgId).Select(x => x.SchoolCode).FirstAsync(); foreach (var item in list) { var student = await _context.Student.FirstOrDefaultAsync(x => x.SchoolCode == schoolCode && x.StudentNo == item.UserSerial); if (student == null) continue; var project = projects.FirstOrDefault(x => x.ProjectId == item.CourseId) ?? projects.FirstOrDefault(); var trainData = new XW_SportsTestData { OrgId = orgId, ProjectId = item.CourseId, ProjectName = project?.ProjectName ?? $"课目{item.CourseId}", StartTime = item.StartTime, EndTime = item.EndTime, CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }; _context.XW_SportsTestData.Add(trainData); await _context.SaveChangesAsync(); var c = await _context.Class.FindAsync(student.ClassId); var trainStudent = new XW_TrainStudents { XW_SportsTestDataId = trainData.Id, StudentId = student.Id, StudentName = student.StudentName, StudentNo = student.StudentNo, Sex = student.Sex, GradeId = c?.GradeId ?? 0, GradeName = c?.GradeName ?? "", ClassId = student.ClassId ?? 0, ClassName = student.ClassName ?? c?.ClassName ?? "", Achievement = item.StandardCounts, ErrorCount = item.UnStandardCounts, CreateTime = item.StartTime }; _context.XW_TrainStudents.Add(trainStudent); await _context.SaveChangesAsync(); result.Add(new DeviceSyncTrainPushResponseItem { TrainId = trainData.Id, UserSerial = item.UserSerial }); } return result; } public async Task TrainDetailsAsync(int trainId) { var train = await _context.XW_SportsTestData.FindAsync(trainId); if (train == null) return null; var ts = await _context.XW_TrainStudents .FirstOrDefaultAsync(x => x.XW_SportsTestDataId == trainId); if (ts == null) return null; var student = await _context.Student.FindAsync(ts.StudentId); var recentTrains = await (from t in _context.XW_TrainStudents join td in _context.XW_SportsTestData on t.XW_SportsTestDataId equals td.Id where t.StudentId == ts.StudentId && td.ProjectId == train.ProjectId orderby t.CreateTime descending select new CountListItem { TrainId = td.Id, Score = t.Achievement.ToString(), Time = t.CreateTime ?? "" }) .Take(10) .ToListAsync(); return new DeviceSyncTrainDetailsDto { TrainId = trainId, UserSerial = student?.StudentNo ?? "", UserType = 2, Nickname = ts.StudentName, FacePictureUrl = student?.Photo ?? "", Identity = "学生", OrganizationId = ts.ClassId, OrganizationName = ts.ClassName, Gender = ts.Sex == 1 ? "男" : "女", Score = ts.Achievement?.ToString() ?? "0", UnStandardCounts = ts.ErrorCount ?? 0, CourseId = train.ProjectId ?? 0, CourseName = train.ProjectName ?? "", TrainType = "自由练习", VideoUrl = ts.VideoRecord, StartTime = train.StartTime, EndTime = train.EndTime, CountList = recentTrains }; } public async Task> GradeOrderAsync(DeviceSyncGradeOrderRequestDto dto) { var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial); if (!orgId.HasValue) return new List(); var (start, end) = GetDateRange(dto.DateType, dto.QueryStartTime, dto.QueryEndTime); string schoolCode = await _context.School.Where(x => x.Id == orgId).Select(x => x.SchoolCode).FirstAsync(); var query = from ts in _context.XW_TrainStudents join td in _context.XW_SportsTestData on ts.XW_SportsTestDataId equals td.Id join s in _context.Student on ts.StudentId equals s.Id where s.SchoolCode == schoolCode && td.ProjectId == (dto.CourseId ?? td.ProjectId) select new { ts, td, s }; if (dto.Gender.HasValue) query = query.Where(x => x.s.Sex == dto.Gender); if (dto.OrganizeId?.Count > 0) query = query.Where(x => dto.OrganizeId.Contains(x.ts.ClassId)); if (start.HasValue) query = query.Where(x => x.ts.CreateTime != null && string.Compare(x.ts.CreateTime, start.Value.ToString("yyyy-MM-dd")) >= 0); if (end.HasValue) query = query.Where(x => x.ts.CreateTime != null && string.Compare(x.ts.CreateTime, end.Value.AddDays(1).ToString("yyyy-MM-dd")) < 0); var grouped = await query .GroupBy(x => new { x.s.Id, x.s.StudentName, x.ts.ClassId, x.ts.ClassName, x.s.Sex, x.td.ProjectId, x.td.ProjectName }) .Select(g => new { g.Key, Score = g.Sum(x => x.ts.Achievement ?? 0) }) .OrderByDescending(x => x.Score) .Skip((dto.Page - 1) * dto.Size) .Take(dto.Size) .ToListAsync(); return grouped.Select((x, i) => new DeviceSyncGradeOrderItemDto { UserId = x.Key.Id, Nickname = x.Key.StudentName, OrganizationId = x.Key.ClassId, OrganizationName = x.Key.ClassName ?? "", Gender = x.Key.Sex, Score = x.Score.ToString(), CourseId = x.Key.ProjectId ?? 0, CourseName = x.Key.ProjectName ?? "" }).ToList(); } public async Task> RecordAppAsync(DeviceSyncRecordAppRequestDto dto) { var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial); if (!orgId.HasValue) return new List(); var (start, end) = GetDateRange(dto.DateType, dto.QueryStartTime, dto.QueryEndTime); string schoolCode = await _context.School.Where(x => x.Id == orgId).Select(x => x.SchoolCode).FirstAsync(); var query = from ts in _context.XW_TrainStudents join td in _context.XW_SportsTestData on ts.XW_SportsTestDataId equals td.Id join s in _context.Student on ts.StudentId equals s.Id where s.SchoolCode == schoolCode select new { ts, td, s }; if (dto.CourseId.HasValue) query = query.Where(x => x.td.ProjectId == dto.CourseId); if (dto.Gender.HasValue) query = query.Where(x => x.s.Sex == dto.Gender); if (!string.IsNullOrEmpty(dto.UserSerial)) query = query.Where(x => x.s.StudentNo == dto.UserSerial); if (!string.IsNullOrEmpty(dto.UserName)) query = query.Where(x => x.s.StudentName.Contains(dto.UserName)); if (dto.OrganizeId?.Count > 0) query = query.Where(x => dto.OrganizeId.Contains(x.ts.ClassId)); if (start.HasValue) query = query.Where(x => x.ts.CreateTime != null && string.Compare(x.ts.CreateTime, start.Value.ToString("yyyy-MM-dd")) >= 0); if (end.HasValue) query = query.Where(x => x.ts.CreateTime != null && string.Compare(x.ts.CreateTime, end.Value.AddDays(1).ToString("yyyy-MM-dd")) < 0); return await query .OrderByDescending(x => x.ts.CreateTime) .Skip((dto.Page - 1) * dto.Size) .Take(dto.Size) .Select(x => new DeviceSyncRecordAppItemDto { TrainId = x.td.Id, Nickname = x.ts.StudentName, OrganizationId = x.ts.ClassId, OrganizationName = x.ts.ClassName, Gender = x.ts.Sex, FacePictureUrl = x.s.Photo, Score = x.ts.Achievement.ToString(), StartTime = x.td.StartTime, EndTime = x.td.EndTime, CourseId = x.td.ProjectId ?? 0, CourseName = x.td.ProjectName }) .ToListAsync(); } public async Task MyRecordAsync(DeviceSyncMyRecordRequestDto dto) { var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial); if (!orgId.HasValue) return new DeviceSyncMyRecordResponseDto(); string schoolCode = await _context.School.Where(x => x.Id == orgId).Select(x => x.SchoolCode).FirstAsync(); var student = await _context.Student.FirstOrDefaultAsync(x => x.SchoolCode == schoolCode && x.StudentNo == dto.UserSerial); if (student == null) return new DeviceSyncMyRecordResponseDto(); var (start, end) = GetDateRange(dto.DateType, dto.QueryStartTime, dto.QueryEndTime); var trainQuery = _context.XW_TrainStudents.Where(x => x.StudentId == student.Id); if (start.HasValue) trainQuery = trainQuery.Where(x => x.CreateTime != null && string.Compare(x.CreateTime, start.Value.ToString("yyyy-MM-dd")) >= 0); if (end.HasValue) trainQuery = trainQuery.Where(x => x.CreateTime != null && string.Compare(x.CreateTime, end.Value.AddDays(1).ToString("yyyy-MM-dd")) < 0); var trains = await trainQuery.Include(x => x.XW_SportsTestData).ToListAsync(); var graphList = trains.Where(x => x.XW_SportsTestData != null).GroupBy(x => x.XW_SportsTestData.ProjectId ?? 0).Select(g => new GraphTrainListItem { CourseId = g.Key, CourseName = g.First().XW_SportsTestData?.ProjectName ?? "", Time = g.Count().ToString(), Count = g.Count() }).ToList(); var c = await _context.Class.FindAsync(student.ClassId); return new DeviceSyncMyRecordResponseDto { UserSync = new UserSyncDto { UserId = student.Id, UserType = 2, Nickname = student.StudentName, OrganizationId = student.ClassId ?? 0, OrganizationName = c?.ClassName ?? "", FacePictureUrl = student.Photo, Identity = "学生", Gender = student.Sex == 1 ? "男" : "女", Birthday = student.Birthday?.ToString("yyyy-MM-dd") ?? "", UserSerial = student.StudentNo }, TrainCourseSum = graphList.Count, TrainDays = trains.Select(x => x.CreateTime?.Substring(0, 10)).Distinct().Count(), TrainHours = "0", TrainCounts = trains.Count, GraphTrainList = graphList }; } public async Task TeacherLoginAsync(TeacherLoginRequestDto dto) { var pwdHash = MD5Helper.MD5Encrypt32(dto.Password); var user = await _context.Sys_User.FirstOrDefaultAsync(x => x.UserName == dto.Username && x.UserPwd == pwdHash); if (user == null) return null; var school = await _context.School.FirstOrDefaultAsync(x => x.SchoolCode == user.SchoolCode); return new TeacherLoginResponseDto { UserId = user.User_Id, Nickname = user.UserTrueName ?? user.UserName, Username = user.UserName, OrganizationId = school?.Id ?? 0, OrganizationName = school?.SchoolName ?? user.SchoolName ?? "", SerialNumber = user.UserName, Classification = 1, Gender = user.Gender }; } public async Task AppVerifyAsync(AppVerifyRequestDto dto) { return new AppVerifyResponseDto { VersionNumber = dto.VersionNumber, NeedForcedUpdating = 0, UpdateUrl = null, HardwareType = dto.HardwareType, ApplyName = dto.ApplyName }; } public async Task GetUserDetailAsync(string deviceSerial, int userId) { var orgId = await GetOrgIdByDeviceAsync(deviceSerial); if (!orgId.HasValue) return null; string schoolCode = await _context.School.Where(x => x.Id == orgId).Select(x => x.SchoolCode).FirstAsync(); var s = await _context.Student.FirstOrDefaultAsync(x => x.Id == userId && x.SchoolCode == schoolCode); if (s == null) return null; var dto = new DeviceSyncUserDto { UserId = s.Id, UserType = 2, Username = s.StudentNo, Nickname = s.StudentName, OrganizationId = s.ClassId ?? 0, OrganizationName = s.ClassName ?? "", GradeName = "", FacePictureUrl = s.Photo ?? "", Identity = "学生", Gender = s.Sex == 1 ? "男" : "女", Birthday = s.Birthday.HasValue ? s.Birthday.Value.ToString("yyyy-MM-dd") : "", UserSerial = s.StudentNo }; var c = await _context.Class.FindAsync(dto.OrganizationId); if (c != null) { dto.OrganizationName = c.ClassName ?? ""; dto.GradeName = c.GradeName ?? ""; } return dto; } private static (DateTime? start, DateTime? end) GetDateRange(int dateType, string queryStart, string queryEnd) { var now = DateTime.Now; return dateType switch { 1 => (now.Date, now.Date), 2 => (now.AddDays(-(int)now.DayOfWeek + 1).Date, now.Date), 3 => (new DateTime(now.Year, now.Month, 1), now.Date), 4 => (now.Month >= 9 ? new DateTime(now.Year, 9, 1) : new DateTime(now.Year - 1, 9, 1), now.Date), 5 => (DateTime.TryParse(queryStart, out var s) ? s : (DateTime?)null, DateTime.TryParse(queryEnd, out var e) ? e : (DateTime?)null), _ => (null, null) }; } } }