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 { /// /// 壹动站/壹体屏/活力课间屏 设备同步服务实现 /// 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) { if (list == null || !list.Any()) return new List(); var result = new List(); // 👉 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(); 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 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(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() // 暂时为空 }; } public async Task> GradeOrderAsync(DeviceSyncGradeOrderRequestDto dto) { // 1️⃣ 获取组织ID var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial); if (!orgId.HasValue) return new List(); // 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(x.Key.CourseId) }).ToList(); } public async Task> LastGradeAsync(DeviceSyncLastGradeRequestDto dto) { if (dto?.UserSerials == null || dto.UserSerials.Count == 0) return new List(); 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 { 2, 7, 8, 9, 10, 11 }; var result = new List(); 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> RecordAppAsync(DeviceSyncRecordAppRequestDto dto) { var orgId = await GetOrgIdByDeviceAsync(dto.DeviceSerial); if (!orgId.HasValue) return new List(); // 👉 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(x.t.CourseId), // 👉 建议后面接字典表 }) .ToListAsync(); return list; } public async Task 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(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(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 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) { // 1️⃣ 查询最新版本 var latest = await _context.Set() .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 }; } /// /// 视频回放上传 /// /// /// public async Task 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().Add(entity); await _context.SaveChangesAsync(); return true; } 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) }; } 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; } } }