YD_YiLu.Api/YD_YiLu/Services/Impl/DeviceSyncService.cs
2026-04-02 13:53:26 +08:00

441 lines
21 KiB
C#

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
{
/// <summary>
/// 壹动站/壹体屏/活力课间屏 设备同步服务实现
/// </summary>
public class DeviceSyncService : IDeviceSyncService
{
private readonly SmartSportsContext _context;
public DeviceSyncService(SmartSportsContext context)
{
_context = context;
}
public async Task<int?> 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<DeviceSyncUserPageResponseDto> 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<S_Student>)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<DeviceSyncUserPageResponseDto> 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<List<DeviceSyncOrganizationDto>> OrganizationAsync(DeviceSyncOrganizationRequestDto dto)
{
var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial);
if (!orgId.HasValue) return new List<DeviceSyncOrganizationDto>();
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<DeviceSyncOrganizationDto>();
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<int>()
}).ToList(),
ChildrenIds = gradeClasses.Select(x => x.Id).ToList()
});
}
return result;
}
public async Task<List<DeviceSyncTrainPushResponseItem>> TrainPushAsync(List<DeviceSyncTrainPushRequestDto> list)
{
var orgId = await GetOrgIdByDeviceAsync(list.FirstOrDefault()?.DeviceSerial ?? "");
if (!orgId.HasValue) return new List<DeviceSyncTrainPushResponseItem>();
var result = new List<DeviceSyncTrainPushResponseItem>();
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<DeviceSyncTrainDetailsDto> 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<List<DeviceSyncGradeOrderItemDto>> GradeOrderAsync(DeviceSyncGradeOrderRequestDto dto)
{
var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial);
if (!orgId.HasValue) return new List<DeviceSyncGradeOrderItemDto>();
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<List<DeviceSyncRecordAppItemDto>> RecordAppAsync(DeviceSyncRecordAppRequestDto dto)
{
var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial);
if (!orgId.HasValue) return new List<DeviceSyncRecordAppItemDto>();
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<DeviceSyncMyRecordResponseDto> 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<TeacherLoginResponseDto> 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<AppVerifyResponseDto> AppVerifyAsync(AppVerifyRequestDto dto)
{
return new AppVerifyResponseDto
{
VersionNumber = dto.VersionNumber,
NeedForcedUpdating = 0,
UpdateUrl = null,
HardwareType = dto.HardwareType,
ApplyName = dto.ApplyName
};
}
public async Task<DeviceSyncUserDto> 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)
};
}
}
}