新增接口

This commit is contained in:
tanglong 2026-07-01 15:13:49 +08:00
parent 197948e290
commit c032d937a3
4 changed files with 203 additions and 17 deletions

View File

@ -39,4 +39,36 @@ namespace YD_YiLu.Commons.Dto.DeviceSync
public int CourseId { get; set; }
public string CourseName { get; set; }
}
public class DeviceSyncOrganizationGradeOrderItemDto
{
public string OrganizationName { get; set; }
public string SumScore { get; set; }
public string AvgScore { get; set; }
public int SumCount { get; set; }
public int CourseId { get; set; }
public string CourseName { get; set; }
}
public class DeviceSyncBestScoreRequestDto
{
public int DeviceType { get; set; }
public string DeviceSerial { get; set; }
public int CourseId { get; set; }
public int Gender { get; set; }
public string UserSerial { get; set; }
public int Range { get; set; }
}
public class DeviceSyncBestScoreDto
{
public string UserSerial { get; set; }
public string Nickname { get; set; }
public int OrganizationId { get; set; }
public string OrganizationName { get; set; }
public int Gender { get; set; }
public string Score { get; set; }
public int CourseId { get; set; }
public string CourseName { get; set; }
}
}

View File

@ -7,7 +7,7 @@ using YD_YiLu.Commons.Dto.DeviceSync;
namespace YD_YiLu.Api.Controllers
{
/// <summary>
/// 壹动站/壹体屏/活力课间屏 设备同步 HTTP 接口(小站登录与心跳见 WebSocket:<c>/ws/camera/device</c>)
/// 设备同步 HTTP 接口。
/// </summary>
[AllowAnonymous]
public class DeviceSyncController : ControllerBase
@ -22,7 +22,7 @@ namespace YD_YiLu.Api.Controllers
}
/// <summary>
/// 人员拉取(全量,与 user_page 共用服务逻辑;活力课间屏)
/// 人员全量拉取。
/// </summary>
[HttpPost]
[Route("/device/sync/user")]
@ -32,7 +32,7 @@ namespace YD_YiLu.Api.Controllers
}
/// <summary>
/// 人员分页下发(壹动站/壹体屏;弃用的 user_trace 请改用本接口)
/// 人员分页下发。
/// </summary>
[HttpPost]
[Route("/device/sync/user_page")]
@ -48,14 +48,14 @@ namespace YD_YiLu.Api.Controllers
}
/// <summary>
/// 弃用地址别名:device/sync/user_trace → 与 user_page 相同
/// user_trace 别名。
/// </summary>
[HttpPost]
[Route("/device/sync/user_trace")]
public Task<object> UserTrace([FromBody] DeviceSyncUserPageRequestDto dto) => UserPullPage(dto);
/// <summary>
/// 获取人员详情(壹动站协议)
/// 获取人员详情。
/// </summary>
[HttpGet]
[Route("/device/sync/user/detail")]
@ -65,7 +65,7 @@ namespace YD_YiLu.Api.Controllers
}
/// <summary>
/// 组织信息下发
/// 组织信息下发。
/// </summary>
[HttpPost]
[Route("/device/sync/organization")]
@ -74,9 +74,8 @@ namespace YD_YiLu.Api.Controllers
return await _deviceSyncService.OrganizationAsync(dto);
}
/// <summary>
/// 人员上次成绩(按人员序列号批量)
/// 人员上次成绩。
/// </summary>
[HttpPost]
[Route("/device/sync/grade/last_grade")]
@ -88,7 +87,7 @@ namespace YD_YiLu.Api.Controllers
}
/// <summary>
/// 成绩批量上报
/// 成绩批量上报。
/// </summary>
[HttpPost]
[Route("/device/sync/train_push")]
@ -106,7 +105,7 @@ namespace YD_YiLu.Api.Controllers
}
/// <summary>
/// 获取训练详情
/// 获取训练详情。
/// </summary>
[HttpGet]
[Route("/device/sync/train/details")]
@ -117,7 +116,7 @@ namespace YD_YiLu.Api.Controllers
}
/// <summary>
/// 个人成绩排行榜
/// 个人成绩排行榜。
/// </summary>
[HttpPost]
[Route("/device/sync/grade/order")]
@ -128,7 +127,29 @@ namespace YD_YiLu.Api.Controllers
}
/// <summary>
/// 查询运动记录
/// 组织(班级)成绩排行榜。
/// </summary>
[HttpPost]
[Route("/device/sync/organization_grade/order")]
public async Task<object> OrganizationGradeOrder([FromBody] DeviceSyncGradeOrderRequestDto dto)
{
var res = await _deviceSyncService.OrganizationGradeOrderAsync(dto);
return res;
}
/// <summary>
/// 查询挑战最好成绩。
/// </summary>
[HttpPost]
[Route("/device/sync/grade/best_score")]
public async Task<object> BestScore([FromBody] DeviceSyncBestScoreRequestDto dto)
{
var res = await _deviceSyncService.BestScoreAsync(dto);
return res;
}
/// <summary>
/// 查询运动记录。
/// </summary>
[HttpPost]
[Route("/applet/train/record_app")]
@ -139,10 +160,10 @@ namespace YD_YiLu.Api.Controllers
}
/// <summary>
/// 查询我的运动
/// 查询我的运动。
/// </summary>
[HttpPost]
[Route("/device/sync/train/my_record/ytp")]
[Route("/device/sync/grade/my_record")]
public async Task<object> MyRecord([FromBody] DeviceSyncMyRecordRequestDto dto)
{
var res = await _deviceSyncService.MyRecordAsync(dto);
@ -150,10 +171,8 @@ namespace YD_YiLu.Api.Controllers
}
/// <summary>
/// 视频回放上传
/// 视频回放上传。
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost("device/sync/video/upload")]
public async Task<bool> UploadVideo([FromForm] DeviceVideoUploadRequestDto dto)
{

View File

@ -564,6 +564,137 @@ namespace YD_YiLu.Api.Services.Impl
}).ToList();
}
public async Task<List<DeviceSyncOrganizationGradeOrderItemDto>> OrganizationGradeOrderAsync(DeviceSyncGradeOrderRequestDto dto)
{
var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial);
if (!orgId.HasValue) return new List<DeviceSyncOrganizationGradeOrderItemDto>();
string schoolCode = await _context.School
.Where(x => x.Id == orgId)
.Select(x => x.SchoolCode)
.FirstAsync();
var (start, end) = GetDateRange(dto.DateType, dto.QueryStartTime, dto.QueryEndTime);
var query = from t in _context.YL_Train
join s in _context.Student on t.UserSerial equals s.StudentNo
where s.SchoolCode == schoolCode
&& t.Score.HasValue
&& t.Score.Value > 0
select new { t, s };
if (dto.CourseId.HasValue)
query = query.Where(x => x.t.CourseId == dto.CourseId.Value);
if (dto.Gender > 0)
query = query.Where(x => x.s.Sex == dto.Gender.Value);
if (dto.OrganizeId != null && dto.OrganizeId.Count > 0 && dto.OrganizeId[0] > 0)
query = query.Where(x => dto.OrganizeId.Contains(x.s.ClassId ?? 0));
if (start.HasValue)
query = query.Where(x => x.t.StartTime >= start.Value);
if (end.HasValue)
query = query.Where(x => x.t.StartTime < end.Value.AddDays(1));
var page = dto.Page < 1 ? 1 : dto.Page;
var size = dto.Size < 1 ? 10 : dto.Size;
var grouped = await query
.GroupBy(x => new { x.s.ClassId, x.s.ClassName, x.t.CourseId })
.Select(g => new
{
g.Key.ClassName,
g.Key.CourseId,
SumScore = g.Sum(x => x.t.Score ?? 0),
AvgScore = g.Average(x => x.t.Score ?? 0),
SumCount = g.Count()
})
.OrderByDescending(x => x.SumScore)
.Skip((page - 1) * size)
.Take(size)
.ToListAsync();
return grouped.Select(x => new DeviceSyncOrganizationGradeOrderItemDto
{
OrganizationName = x.ClassName ?? "",
SumScore = Math.Round(x.SumScore).ToString("0"),
AvgScore = x.AvgScore.ToString("0.##"),
SumCount = x.SumCount,
CourseId = x.CourseId,
CourseName = Util.GetEnumDescription<CourseType>(x.CourseId)
}).ToList();
}
public async Task<DeviceSyncBestScoreDto> BestScoreAsync(DeviceSyncBestScoreRequestDto dto)
{
var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial);
if (!orgId.HasValue) return null;
string schoolCode = await _context.School
.Where(x => x.Id == orgId)
.Select(x => x.SchoolCode)
.FirstAsync();
var currentStudent = await _context.Student
.FirstOrDefaultAsync(x => x.SchoolCode == schoolCode && x.StudentNo == dto.UserSerial);
if (currentStudent == null)
return null;
var currentClass = currentStudent.ClassId.HasValue
? await _context.Class.FirstOrDefaultAsync(x => x.Id == currentStudent.ClassId.Value)
: null;
var query = from t in _context.YL_Train
join s in _context.Student on t.UserSerial equals s.StudentNo
where s.SchoolCode == schoolCode
&& t.CourseId == dto.CourseId
&& s.Sex == dto.Gender
&& t.Score.HasValue
&& t.Score.Value > 0
select new { t, s };
if (dto.Range == 1)
{
query = query.Where(x => x.s.ClassId == currentStudent.ClassId);
}
else if (dto.Range == 2 && currentClass != null)
{
var classIds = await _context.Class
.Where(x => x.SchoolCode == schoolCode && x.GradeId == currentClass.GradeId)
.Select(x => x.Id)
.ToListAsync();
query = query.Where(x => classIds.Contains(x.s.ClassId ?? 0));
}
var best = await query
.OrderByDescending(x => x.t.Score)
.ThenBy(x => x.t.StartTime)
.FirstOrDefaultAsync();
if (best == null)
return null;
var bestClass = best.s.ClassId.HasValue
? await _context.Class.FirstOrDefaultAsync(x => x.Id == best.s.ClassId.Value)
: null;
return new DeviceSyncBestScoreDto
{
UserSerial = best.s.StudentNo,
Nickname = best.s.StudentName,
OrganizationId = best.s.ClassId ?? 0,
OrganizationName = bestClass?.ClassName ?? best.s.ClassName ?? "",
Gender = best.s.Sex,
Score = best.t.Score?.ToString("0.##") ?? "0",
CourseId = best.t.CourseId,
CourseName = Util.GetEnumDescription<CourseType>(best.t.CourseId)
};
}
public async Task<List<DeviceSyncUserDto>> LastGradeAsync(DeviceSyncLastGradeRequestDto dto)
{
if (dto?.UserSerials == null || dto.UserSerials.Count == 0)

View File

@ -38,6 +38,10 @@ namespace YD_YiLu.Api.Services.Interface
/// </summary>
Task<List<DeviceSyncGradeOrderItemDto>> GradeOrderAsync(DeviceSyncGradeOrderRequestDto dto);
Task<List<DeviceSyncOrganizationGradeOrderItemDto>> OrganizationGradeOrderAsync(DeviceSyncGradeOrderRequestDto dto);
Task<DeviceSyncBestScoreDto> BestScoreAsync(DeviceSyncBestScoreRequestDto dto);
/// <summary>
/// 人员上次成绩(按人员序列号批量查询)
/// </summary>