YD_YiLu.Api/YD_YiLu/Services/Impl/DeviceSyncService.cs
2026-04-13 09:59:12 +08:00

874 lines
33 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.Entity.DomainModels.XinWei;
using YD_YiLu.Api.Context;
using YD_YiLu.Api.Services.Interface;
using YD_YiLu.Api.SmartSportsEntitys;
using YD_YiLu.Api.Utilities;
using YD_YiLu.Commons;
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)
{
if (list == null || !list.Any())
return new List<DeviceSyncTrainPushResponseItem>();
var result = new List<DeviceSyncTrainPushResponseItem>();
// 👉 1. 设备校验(可选,看你业务)
var orgId = await GetOrgIdByDeviceAsync(list.First().DeviceSerial);
if (!orgId.HasValue)
return result;
// 👉 2. 批量查已存在的 TrainSerial(防重复)
var trainSerials = list.Select(x => x.TrainSerial).ToList();
var existSerials = await _context.YL_Train
.Where(x => trainSerials.Contains(x.TrainSerial))
.Select(x => x.TrainSerial)
.ToListAsync();
var newEntities = new List<YL_Train>();
foreach (var item in list)
{
// 👉 3. 唯一校验(跳过已存在)
if (existSerials.Contains(item.TrainSerial))
continue;
var entity = new YL_Train
{
DeviceSerial = item.DeviceSerial,
DeviceType = item.DeviceType,
UserSerial = item.UserSerial,
TrainSerial = item.TrainSerial,
VideoSerial = item.VideoSerial,
TrainExam = item.TrainExam,
QuizId = item.QuizId,
StandardCounts = item.StandardCounts,
UnStandardCounts = item.UnStandardCounts,
TimeKeeping = item.TimeKeeping,
Duration = item.Duration,
Distance = item.Distance,
CourseId = item.CourseId,
StartTime = Util.ParseDateTime(item.StartTime),
EndTime = Util.ParseDateTime(item.EndTime),
// 👉 成绩计算(建议统一规则)
Score = CalculateScore(item),
IsValid = 1, // 默认有效
UploadTime = DateTime.Now,
CreateTime = DateTime.Now
};
newEntities.Add(entity);
}
// 👉 4. 批量入库(关键优化点)
if (newEntities.Any())
{
_context.YL_Train.AddRange(newEntities);
await _context.SaveChangesAsync();
}
// 👉 5. 返回结果
result = newEntities.Select(x => new DeviceSyncTrainPushResponseItem
{
TrainId = x.Id,
UserSerial = x.UserSerial
}).ToList();
return result;
}
private double? CalculateScore(DeviceSyncTrainPushRequestDto item)
{
// 👉 根据课目类型决定成绩字段
// 这里给你一个通用策略(你可以按课目细化)
// 计数类(跳绳/仰卧起坐)
if (item.StandardCounts > 0)
return item.StandardCounts;
// 计时类(悬垂)
if (item.TimeKeeping.HasValue)
return item.TimeKeeping;
// 距离类(跳远)
if (item.Distance.HasValue)
return item.Distance;
return null;
}
public async Task<DeviceSyncTrainDetailsDto> TrainDetailsAsync(int trainId)
{
// 1. 获取训练记录
var train = await _context.YL_Train.FirstOrDefaultAsync(t => t.Id == trainId);
if (train == null) return null;
// 2. 获取学生信息
var student = await _context.Student.FirstOrDefaultAsync(s => s.StudentNo == train.UserSerial);
if (student == null) return null;
// 3. 最近10次训练记录(CountList)
var recentTrains = await _context.YL_Train
.Where(t => t.UserSerial == train.UserSerial && t.CourseId == train.CourseId)
.OrderByDescending(t => t.StartTime)
.Take(10)
.Select(t => new CountListItem
{
TrainId = t.Id,
Score = (t.Score ?? 0).ToString("0"), // 先拿数值
Time = t.StartTime.ToString("yyyy-MM-dd HH:mm:ss")
})
.AsNoTracking() // 可选,提高性能
.ToListAsync();
// 在内存中格式化
var recentTrainsDto = recentTrains
.Select(t => new CountListItem
{
TrainId = t.TrainId,
Score = t.Score, // 格式化整数
Time = t.Time
})
.ToList();
// 4. 近10日最佳成绩(DailyList)
var tenDaysAgo = DateTime.Now.Date.AddDays(-10);
var dailyScores = await _context.YL_Train
.Where(t => t.UserSerial == train.UserSerial
&& t.CourseId == train.CourseId
&& t.StartTime >= tenDaysAgo)
.GroupBy(t => t.StartTime.Date)
.Select(g => new
{
Date = g.Key,
MaxScore = g.Max(t => t.Score) ?? 0
})
.OrderByDescending(g => g.Date)
.ToListAsync();
// 在内存中格式化
var dailyListDto = dailyScores
.Select(d => new DailyListItem
{
Score = d.MaxScore.ToString("0"),
Time = d.Date.ToString("yyyy-MM-dd 00:00:00")
})
.ToList();
// 5. 课程名称(枚举描述)
string courseName = Util.GetEnumDescription<CourseType>(train.CourseId);
// 6. 返回 DTO
return new DeviceSyncTrainDetailsDto
{
TrainId = train.Id,
UserSerial = train.UserSerial,
UserType = 2, // 学生
Nickname = student.StudentName,
FacePictureUrl = student.Photo ?? "",
Identity = "学生",
OrganizationId = (int)student.ClassId,
OrganizationName = student.ClassName,
Gender = student.Sex == 1 ? "男" : "女",
Score = train.Score?.ToString("0") ?? "0",
UnStandardCounts = train.UnStandardCounts,
CourseId = train.CourseId,
CourseName = courseName,
TrainType = "自由练习",
VideoUrl = train.VideoSerial,
StartTime = train.StartTime.ToString("yyyy-MM-dd HH:mm:ss"),
EndTime = train.EndTime.ToString("yyyy-MM-dd HH:mm:ss"),
CountList = recentTrains,
DailyList = dailyListDto,
KeyframeList = new List<KeyframeListItem>() // 暂时为空
};
}
public async Task<List<DeviceSyncGradeOrderItemDto>> GradeOrderAsync(DeviceSyncGradeOrderRequestDto dto)
{
// 1️⃣ 获取组织ID
var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial);
if (!orgId.HasValue) return new List<DeviceSyncGradeOrderItemDto>();
// 2️⃣ 获取学校编码
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);
// 4️⃣ 主查询(YL_Train + Student)
var query = from t in _context.YL_Train
join s in _context.Student on t.UserSerial equals s.StudentNo
where s.SchoolCode == schoolCode
select new { t, s };
// 5️⃣ 条件过滤
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));
// 6️⃣ 分组求总成绩并排序
var grouped = await query
.GroupBy(x => new { x.s.Id, x.s.StudentName, x.s.ClassId, x.s.ClassName, x.s.Sex, x.t.CourseId })
.Select(g => new
{
Key = g.Key,
Score = g.Sum(x => x.t.Score ?? 0)
})
.OrderByDescending(x => x.Score)
.Skip((dto.Page - 1) * dto.Size)
.Take(dto.Size)
.ToListAsync(); // ✅ 确保在此处完成
// 7️⃣ 返回结果
return grouped.Select(x => new DeviceSyncGradeOrderItemDto
{
UserId = x.Key.Id,
Nickname = x.Key.StudentName,
OrganizationId = x.Key.ClassId ?? 0,
OrganizationName = x.Key.ClassName ?? "",
Gender = x.Key.Sex,
Score = Math.Round(x.Score).ToString("0"),
CourseId = x.Key.CourseId,
CourseName = Util.GetEnumDescription<CourseType>(x.Key.CourseId)
}).ToList();
}
public async Task<List<DeviceSyncUserDto>> LastGradeAsync(DeviceSyncLastGradeRequestDto dto)
{
if (dto?.UserSerials == null || dto.UserSerials.Count == 0)
return new List<DeviceSyncUserDto>();
var serials = dto.UserSerials
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(x => x.Trim())
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
var students = await _context.Student
.Where(s => serials.Contains(s.StudentNo))
.ToListAsync();
var studentSerials = students.Select(s => s.StudentNo).ToList();
var trains = await _context.YL_Train
.Where(t => studentSerials.Contains(t.UserSerial))
.ToListAsync();
// 👉 人 + 课程 聚合
var trainGroup = trains
.GroupBy(t => new { t.UserSerial, t.CourseId })
.ToDictionary(
g => (g.Key.UserSerial, g.Key.CourseId),
g => new
{
Best = g.Max(x => x.Score ?? 0),
Last = g.OrderByDescending(x => x.EndTime).FirstOrDefault()?.Score ?? 0
});
// 👉 课程枚举(必须全返回)
var courseIds = new List<int> { 2, 7, 8, 9, 10, 11 };
var result = new List<DeviceSyncUserDto>();
foreach (var serial in serials)
{
var st = students.FirstOrDefault(s => s.StudentNo == serial);
var user = new DeviceSyncUserDto
{
UserId = st?.Id ?? 0,
UserType = 0, // 你自己定义
Username = st?.StudentNo ?? serial,
Nickname = st?.StudentName ?? "",
OrganizationId = st?.ClassId ?? 0,
OrganizationName = st?.ClassName ?? "",
GradeName = "", // 没有就空
FacePictureUrl = st?.Photo ?? "",
Identity = "", // 可选
Gender = st == null ? "" : (st.Sex == 1 ? "男" : "女"),
Birthday = st?.Birthday?.ToString("yyyy-MM-dd") ?? "",
UserSerial = serial
};
// 👉 构造 trainLimitValues
foreach (var cid in courseIds)
{
if (trainGroup.TryGetValue((serial, cid), out var val))
{
user.TrainLimitValues.Add(new TrainLimitValueDto
{
CourseId = cid,
BestResult = Math.Round(val.Best).ToString("0"),
LastResult = Math.Round(val.Last).ToString("0")
});
}
else
{
user.TrainLimitValues.Add(new TrainLimitValueDto
{
CourseId = cid,
BestResult = "0",
LastResult = "0"
});
}
}
result.Add(user);
}
return result;
}
public async Task<List<DeviceSyncRecordAppItemDto>> RecordAppAsync(DeviceSyncRecordAppRequestDto dto)
{
var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial);
if (!orgId.HasValue)
return new List<DeviceSyncRecordAppItemDto>();
// 👉 1. 学校编码
string schoolCode = await _context.School
.Where(x => x.Id == orgId)
.Select(x => x.SchoolCode)
.FirstAsync();
// 👉 2. 时间范围
var (start, end) = GetDateRange(dto.DateType, dto.QueryStartTime, dto.QueryEndTime);
// 👉 3. 主查询(YL_Train + Student)
var query = from t in _context.YL_Train
join s in _context.Student on t.UserSerial equals s.StudentNo
where s.SchoolCode == schoolCode
select new { t, s };
// 👉 4. 条件过滤
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 (!string.IsNullOrEmpty(dto.UserSerial))
query = query.Where(x => x.t.UserSerial == dto.UserSerial);
if (!string.IsNullOrEmpty(dto.UserName))
query = query.Where(x => x.s.StudentName.Contains(dto.UserName));
if (dto.OrganizeId != null && dto.OrganizeId.Count > 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));
// 👉 5. 分页 + 排序
var list = await query
.OrderByDescending(x => x.t.StartTime)
.Skip((dto.Page - 1) * dto.Size)
.Take(dto.Size)
.Select(x => new DeviceSyncRecordAppItemDto
{
TrainId = x.t.Id,
Nickname = x.s.StudentName,
OrganizationId = x.s.ClassId ?? 0,
OrganizationName = x.s.ClassName,
Gender = x.s.Sex,
FacePictureUrl = x.s.Photo,
Score = x.t.Score.HasValue ? x.t.Score.Value.ToString("0.##") : "0",
StartTime = x.t.StartTime.ToString("yyyy-MM-dd HH:mm:ss"),
EndTime = x.t.EndTime.ToString("yyyy-MM-dd HH:mm:ss"),
CourseId = x.t.CourseId,
CourseName = Util.GetEnumDescription<CourseType>(x.t.CourseId), // 👉 建议后面接字典表
})
.ToListAsync();
return list;
}
public async Task<DeviceSyncMyRecordResponseDto> MyRecordAsync(DeviceSyncMyRecordRequestDto dto)
{
var result = new DeviceSyncMyRecordResponseDto();
var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial);
if (!orgId.HasValue) return result;
// 👉 1. 查学生
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 result;
var c = await _context.Class.FindAsync(student.ClassId);
// 👉 2. 时间范围
var (start, end) = GetDateRange(dto.DateType, dto.QueryStartTime, dto.QueryEndTime);
var query = _context.YL_Train
.Where(x => x.UserSerial == dto.UserSerial);
if (start.HasValue)
query = query.Where(x => x.StartTime >= start.Value);
if (end.HasValue)
query = query.Where(x => x.StartTime < end.Value.AddDays(1));
if (dto.CourseType > 0)
query = query.Where(x => x.CourseId == dto.CourseType);
var trains = await query.ToListAsync();
if (!trains.Any())
return result;
// 👉 3. 统计
var trainDays = trains.Select(x => x.StartTime.Date).Distinct().Count();
var totalSeconds = trains.Sum(x => x.Duration);
var trainHours = (totalSeconds / 3600.0).ToString("0.00");
// 👉 4. gradeList(按天统计)
var gradeList = trains
.GroupBy(x => x.StartTime.Date)
.Select(g => new GradeListItem
{
Time = g.Key.ToString("yyyy-MM-dd"),
Duration = g.Sum(x => x.Duration).ToString(),
Count = g.Sum(x => x.StandardCounts).ToString()
}).ToList();
// 👉 5. graphTrainList(课目统计)
var graphList = trains
.GroupBy(x => x.CourseId)
.Select(g => new GraphTrainListItem
{
CourseId = g.Key,
CourseName = Util.GetEnumDescription<CourseType>(g.Key),
Time = g.Sum(x => x.Duration).ToString(),
Count = g.Count()
}).ToList();
// 👉 6. courseBestList(最好/平均/最差)
var courseBestList = trains
.Where(x => x.Score.HasValue)
.GroupBy(x => x.CourseId)
.Select(g => new CourseBestListItem
{
CourseId = g.Key,
CourseName = Util.GetEnumDescription<CourseType>(g.Key),
BestGrade = g.Max(x => x.Score).ToString(),
AvgGrade = g.Average(x => x.Score).ToString(),
WorstGrade = g.Min(x => x.Score).ToString()
}).ToList();
// 👉 7. 返回
result = 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,
Height = "",
Weight = ""
},
TrainCourseSum = graphList.Count,
TrainDays = trainDays,
TrainHours = trainHours,
TrainCounts = trains.Count,
GradeList = gradeList,
GraphTrainList = graphList,
//CourseBestList = courseBestList
};
return result;
}
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)
{
// 1️⃣ 查询最新版本
var latest = await _context.Set<YL_AppVersion>()
.Where(x => x.ApplyName == dto.ApplyName
&& x.DeviceType == dto.DeviceType
&& x.HardwareType == dto.HardwareType
&& x.OperatingSystem == dto.OperatingSystem
&& x.Status == 1
&& x.PublishStatus == 1)
.OrderByDescending(x => x.IsLatest)
.ThenByDescending(x => x.VersionCode)
.FirstOrDefaultAsync();
// 2️⃣ 没有配置版本 → 不更新
if (latest == null)
{
return new AppVerifyResponseDto
{
VersionNumber = dto.VersionNumber,
NeedForcedUpdating = 0,
UpdateUrl = null,
HardwareType = dto.HardwareType,
ApplyName = dto.ApplyName
};
}
// 3️⃣ 版本比较(必须用 VersionCode)
int currentVersionCode = ParseVersionCode(dto.VersionNumber);
bool needUpdate = latest.VersionCode > currentVersionCode;
if (!needUpdate)
{
return new AppVerifyResponseDto
{
VersionNumber = dto.VersionNumber,
NeedForcedUpdating = 0,
UpdateUrl = null,
HardwareType = dto.HardwareType,
ApplyName = dto.ApplyName
};
}
// 4️⃣ 是否强制升级
bool needForce = latest.NeedForcedUpdating == 1;
// 最低版本限制(强制升级)
if (!string.IsNullOrEmpty(latest.MinSupportVersion))
{
if (CompareVersion(dto.VersionNumber, latest.MinSupportVersion) < 0)
{
needForce = true;
}
}
// 5️⃣ 返回结果
return new AppVerifyResponseDto
{
VersionNumber = latest.VersionNumber,
NeedForcedUpdating = needForce ? 1 : 0,
UpdateUrl = latest.UpdateUrl,
HardwareType = latest.HardwareType,
ApplyName = latest.ApplyName
};
}
/// <summary>
/// 视频回放上传
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
public async Task<bool> DeviceVideoUploadAsync(DeviceVideoUploadRequestDto dto)
{
if (dto.File == null || dto.File.Length == 0)
return false;
// 1️⃣ 生成OSS路径(按我之前给你的规范)
var path = $"Upload/device/{dto.DeviceType}/{dto.DeviceSerial}/video/{dto.VideoSerial}/";
// 2️⃣ 上传到OSS
var url = ALiYunOss.Upload(dto.File, path, dto.VideoSerial);
if (string.IsNullOrEmpty(url))
return false;
// 3️⃣ 入库
var entity = new YL_DeviceVideo
{
DeviceSerial = dto.DeviceSerial,
DeviceType = dto.DeviceType,
VideoSerial = dto.VideoSerial,
VideoUrl = url,
Timestamp = dto.Timestamp,
CreateTime = DateTime.Now,
Status = 1
};
_context.Set<YL_DeviceVideo>().Add(entity);
await _context.SaveChangesAsync();
return true;
}
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)
};
}
private int CompareVersion(string v1, string v2)
{
if (string.IsNullOrEmpty(v1) || string.IsNullOrEmpty(v2))
return 0;
var arr1 = v1.Split('.');
var arr2 = v2.Split('.');
int len = Math.Max(arr1.Length, arr2.Length);
for (int i = 0; i < len; i++)
{
int num1 = i < arr1.Length ? int.Parse(arr1[i]) : 0;
int num2 = i < arr2.Length ? int.Parse(arr2[i]) : 0;
if (num1 > num2) return 1;
if (num1 < num2) return -1;
}
return 0;
}
private int ParseVersionCode(string version)
{
if (string.IsNullOrEmpty(version))
return 0;
var parts = version.Split('.');
int code = 0;
for (int i = 0; i < parts.Length; i++)
{
if (int.TryParse(parts[i], out int num))
{
code = code * 100 + num;
}
}
return code;
}
}
}