diff --git a/VOL.Ai/Services/AiAppService.cs b/VOL.Ai/Services/AiAppService.cs index eec7259..710c8d5 100644 --- a/VOL.Ai/Services/AiAppService.cs +++ b/VOL.Ai/Services/AiAppService.cs @@ -1,5 +1,6 @@ using AutoMapper; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -20,6 +21,7 @@ using VOL.Model.JingShiTiJiao; using VOL.Model.Norm.Response; using VOL.Model.Training.Response; using VOL.System.IRepositories; +using VOL.System.Repositories; namespace VOL.Ai.Services { @@ -139,173 +141,172 @@ namespace VOL.Ai.Services //if (res == null) // return new Ai_SchoolDto(); - - - - - - //var schoolCode = paramDto.Code; - - - //// ========================= - //// 2️⃣ 调用京师接口获取学校年级班级 - //// ========================= - //var schoolClass = await _jingShiTiJiaoService.GetClassBySchoolAsync(schoolCode); - - //if (schoolClass?.Grades == null || !schoolClass.Grades.Any()) - // throw new Exception("获取京师年级班级失败!"); - - //var res = new Ai_SchoolDto() - //{ - // SchoolCode = schoolCode, - // Name = schoolClass.SchoolName, - // Type = 1, - // Province = "", - // City = "" - //}; - - //var gradeDtos = schoolClass.Grades; - - //// ========================= - //// 3️⃣ 提取所有 GradeNo / ClassNo - //// ========================= - //var allGradeNos = gradeDtos - // .Where(g => !string.IsNullOrWhiteSpace(g.GradeNo)) - // .Select(g => g.GradeNo) - // .ToList(); - - //var allClassNos = gradeDtos - // .SelectMany(g => g.Classes ?? new List()) - // .Where(c => !string.IsNullOrWhiteSpace(c.ClassNo)) - // .Select(c => c.ClassNo) - // .ToList(); - - //// ========================= - //// 4️⃣ 查询数据库中已存在的数据(幂等) - //// ========================= - //var existGrades = await _studentRepository.DbContext.Set() - // .Where(x => x.SchoolCode == schoolCode && allGradeNos.Contains(x.GradeNo)) - // .ToListAsync(); - - //var existClasses = await _classRepository.DbContext.Set() - // .Where(x => x.SchoolCode == schoolCode && allClassNos.Contains(x.ClassNo)) - // .ToListAsync(); - - //var existGradeNoSet = existGrades.Select(x => x.GradeNo).ToHashSet(); - //var existClassNoSet = existClasses.Select(x => x.ClassNo).ToHashSet(); - - //// ========================= - //// 5️⃣ 构造待插入的年级 + 班级 - //// ========================= - //var newGrades = new List(); - - //foreach (var g in gradeDtos) - //{ - // if (string.IsNullOrWhiteSpace(g.GradeNo) || existGradeNoSet.Contains(g.GradeNo)) - // continue; - - // var grade = new JS_Grade - // { - // SchoolCode = schoolCode, - // Code = paramDto.Code, - // GradeNo = g.GradeNo, - // GradeName = g.GradeName, - // Classes = g.Classes? - // .Where(c => !string.IsNullOrWhiteSpace(c.ClassNo) && !existClassNoSet.Contains(c.ClassNo)) - // .Select(c => new JS_Class - // { - // SchoolCode = schoolCode, - // Code = paramDto.Code, - // GradeNo = g.GradeNo, - // GradeName = g.GradeName, - // ClassNo = c.ClassNo, - // ClassName = c.ClassName - // }).ToList() ?? new List() - // }; - - // newGrades.Add(grade); - - // existGradeNoSet.Add(g.GradeNo); - // foreach (var c in grade.Classes) - // existClassNoSet.Add(c.ClassNo); - //} - - //if (newGrades.Any()) - // await _studentRepository.DbContext.Set().AddRangeAsync(newGrades); - - //// ========================= - //// 6️⃣ 保存(并发幂等兜底) - //// ========================= - //try - //{ - // await _studentRepository.DbContext.SaveChangesAsync(); - //} - //catch (DbUpdateException ex) when (ex.InnerException?.Message.Contains("UNIQUE") == true) - //{ - // // 并发下唯一索引冲突可忽略 - //} - - //// ========================= - //// 7️⃣ 回查数据库,组装返回 DTO - //// ========================= - //var dbGrades = await _studentRepository.DbContext.Set() - // .Where(x => x.SchoolCode == schoolCode && allGradeNos.Contains(x.GradeNo)) - // .Include(g => g.Classes) - // .ToListAsync(); - - //res.Grade = dbGrades.Select(g => new Grades - //{ - // Id = (int)g.Id, - // Name = g.GradeName, - // Class = g.Classes.Select(c => new Classes - // { - // Id = (int)c.Id, - // Name = c.ClassName - // }).ToList() - //}).ToList(); - - //return res; - if (string.IsNullOrWhiteSpace(paramDto.Code)) throw new ArgumentException("学校编码不能为空", nameof(paramDto.Code)); var schoolCode = paramDto.Code; // ========================= - // 1️⃣ 调用京师接口获取学校信息及年级班级 + // 2️⃣ 调用京师接口获取学校年级班级 // ========================= var schoolClass = await _jingShiTiJiaoService.GetClassBySchoolAsync(schoolCode); if (schoolClass?.Grades == null || !schoolClass.Grades.Any()) throw new Exception("获取京师年级班级失败!"); - // ========================= - // 2️⃣ 组装返回 DTO - // ========================= var res = new Ai_SchoolDto() { SchoolCode = schoolCode, Name = schoolClass.SchoolName, - Type = 1, // 可根据业务修改 + Type = 1, Province = "", - City = "", - Grade = schoolClass.Grades.Select(g => new Grades - { - Id = 0, // 京师接口没有数据库 Id,可用占位 - Name = g.GradeName, - Class = g.Classes?.Select(c => new Classes - { - Id = 0, // 同上 - Name = c.ClassName - }).ToList() ?? new List() - }).ToList() + City = "" }; + var gradeDtos = schoolClass.Grades; + + // ========================= + // 3️⃣ 提取所有 GradeNo / ClassNo + // ========================= + var allGradeNos = gradeDtos + .Where(g => !string.IsNullOrWhiteSpace(g.GradeNo)) + .Select(g => g.GradeNo) + .ToList(); + + var allClassNos = gradeDtos + .SelectMany(g => g.Classes ?? new List()) + .Where(c => !string.IsNullOrWhiteSpace(c.ClassNo)) + .Select(c => c.ClassNo) + .ToList(); + + // ========================= + // 4️⃣ 查询数据库中已存在的数据(幂等) + // ========================= + var existGrades = await _studentRepository.DbContext.Set() + .Where(x => x.SchoolCode == schoolCode && allGradeNos.Contains(x.GradeNo)) + .ToListAsync(); + + var existClasses = await _classRepository.DbContext.Set() + .Where(x => x.SchoolCode == schoolCode && allClassNos.Contains(x.ClassNo)) + .ToListAsync(); + + var existGradeNoSet = existGrades.Select(x => x.GradeNo).ToHashSet(); + var existClassNoSet = existClasses.Select(x => x.ClassNo).ToHashSet(); + + // ========================= + // 5️⃣ 构造待插入的年级 + 班级 + // ========================= + var newGrades = new List(); + + foreach (var g in gradeDtos) + { + if (string.IsNullOrWhiteSpace(g.GradeNo) || existGradeNoSet.Contains(g.GradeNo)) + continue; + + var grade = new JS_Grade + { + SchoolCode = schoolCode, + Code = paramDto.Code, + GradeNo = g.GradeNo, + GradeName = g.GradeName, + Classes = g.Classes? + .Where(c => !string.IsNullOrWhiteSpace(c.ClassNo) && !existClassNoSet.Contains(c.ClassNo)) + .Select(c => new JS_Class + { + SchoolCode = schoolCode, + Code = paramDto.Code, + GradeNo = g.GradeNo, + GradeName = g.GradeName, + ClassNo = c.ClassNo, + ClassName = c.ClassName + }).ToList() ?? new List() + }; + + newGrades.Add(grade); + + existGradeNoSet.Add(g.GradeNo); + foreach (var c in grade.Classes) + existClassNoSet.Add(c.ClassNo); + } + + if (newGrades.Any()) + await _studentRepository.DbContext.Set().AddRangeAsync(newGrades); + + // ========================= + // 6️⃣ 保存(并发幂等兜底) + // ========================= + try + { + await _studentRepository.DbContext.SaveChangesAsync(); + } + catch (DbUpdateException ex) when (ex.InnerException?.Message.Contains("UNIQUE") == true) + { + // 并发下唯一索引冲突可忽略 + } + + // ========================= + // 7️⃣ 回查数据库,组装返回 DTO + // ========================= + var dbGrades = await _studentRepository.DbContext.Set() + .Where(x => x.SchoolCode == schoolCode && allGradeNos.Contains(x.GradeNo)) + .Include(g => g.Classes) + .ToListAsync(); + + res.Grade = dbGrades + .Where(g => g.Classes != null && g.Classes.Any()) + .Select(g => new Grades + { + Id = (int)g.Id, + Name = g.GradeName, + Class = g.Classes.Select(c => new Classes + { + Id = (int)c.Id, + Name = c.ClassName + }).ToList() + }) + .ToList(); + + return res; + + //if (string.IsNullOrWhiteSpace(paramDto.Code)) + // throw new ArgumentException("学校编码不能为空", nameof(paramDto.Code)); + + //var schoolCode = paramDto.Code; + + //// ========================= + //// 1️⃣ 调用京师接口获取学校信息及年级班级 + //// ========================= + //var schoolClass = await _jingShiTiJiaoService.GetClassBySchoolAsync(schoolCode); + + //if (schoolClass?.Grades == null || !schoolClass.Grades.Any()) + // throw new Exception("获取京师年级班级失败!"); + + //// ========================= + //// 2️⃣ 组装返回 DTO + //// ========================= + //var res = new Ai_SchoolDto() + //{ + // SchoolCode = schoolCode, + // Name = schoolClass.SchoolName, + // Type = 1, // 可根据业务修改 + // Province = "", + // City = "", + // Grade = schoolClass.Grades.Select(g => new Grades + // { + // Id = 1, // 京师接口没有数据库 Id,可用占位 + // Name = g.GradeName, + // Class = g.Classes?.Select(c => new Classes + // { + // Id = 1, // 同上 + // Name = c.ClassName + // }).ToList() ?? new List() + // }).ToList() + //}; + + //return res; } - - public Ai_OSSInfoDto OSSInfo(Ai_Request paramDto) { return new Ai_OSSInfoDto() @@ -1497,108 +1498,63 @@ namespace VOL.Ai.Services /// /// /// + [HttpPost(nameof(ScanCodeLogin))] + [HttpPost(nameof(ScanCodeLogin))] public async Task ScanCodeLogin(Ai_Request paramDto) { - // ========================= - // 1️⃣ 查询登录信息 - // ========================= + if (paramDto == null || string.IsNullOrWhiteSpace(paramDto.Code) || string.IsNullOrWhiteSpace(paramDto.SchoolCode)) + throw new ArgumentException("参数不能为空!"); + + var schoolCode = paramDto.SchoolCode; + + // 1️⃣ 查询扫码登录信息 var loginInfo = await _scanCodeLoginRepository - .FindAsIQueryable(x => x.Code == paramDto.Code && x.SchoolCode == paramDto.SchoolCode) + .FindAsIQueryable(x => x.Code == paramDto.Code && x.SchoolCode == schoolCode) .FirstOrDefaultAsync(); if (loginInfo == null) throw new Exception("未查询到登录信息!"); - // ========================= // 2️⃣ 获取京师老师信息 - // ========================= - var teacher = await _jingShiTiJiaoService - .GetClassListByTeacher(loginInfo.TeacherPhoneNo); - - if (teacher == null) + var teacher = await _jingShiTiJiaoService.GetClassListByTeacher(loginInfo.TeacherPhoneNo); + if (teacher == null || string.IsNullOrWhiteSpace(teacher.TeacherNo) || string.IsNullOrWhiteSpace(teacher.TeacherName)) throw new Exception("获取京师老师信息失败!"); - if (string.IsNullOrWhiteSpace(teacher.TeacherNo)) - throw new Exception("接口返回的教师编号为空!"); - if (string.IsNullOrWhiteSpace(teacher.TeacherName)) - throw new Exception("接口返回的教师姓名为空!"); - - var schoolCode = paramDto.SchoolCode; var gradeDtos = teacher.GradeList ?? new List(); + var allGradeNos = gradeDtos.Where(g => !string.IsNullOrWhiteSpace(g.GradeNo)) + .Select(g => g.GradeNo) + .ToList(); - // ========================= - // 3️⃣ 同步教师信息 - // ========================= - var existingTeacher = await _teacherRepository.DbContext.Set() - .FirstOrDefaultAsync(t => t.TeacherNo == teacher.TeacherNo); - - long tId; - if (existingTeacher != null) - { - tId = existingTeacher.Id; - } - else - { - var jsTeacher = new JS_Teacher - { - Code = paramDto.Code, - SchoolCode = schoolCode, - SchoolName = teacher.School ?? "", - TeacherName = teacher.TeacherName, - TeacherNo = teacher.TeacherNo - }; - - try - { - await _teacherRepository.DbContext.Set().AddAsync(jsTeacher); - await _teacherRepository.SaveChangesAsync(); - tId = jsTeacher.Id; - } - catch (DbUpdateException ex) when ( - ex.InnerException?.Message.Contains("IX_JS_Teacher_TeacherNo") == true) - { - var conflictTeacher = await _teacherRepository.DbContext.Set() - .FirstAsync(t => t.TeacherNo == teacher.TeacherNo); - tId = conflictTeacher.Id; - } - } - - if (tId == 0) - throw new Exception("教师信息同步失败!"); - - // ===================================================== - // 4️⃣ 同步【年级 + 班级】(你提供的核心逻辑) - // ===================================================== - var allGradeNos = gradeDtos - .Where(g => !string.IsNullOrWhiteSpace(g.GradeNo)) - .Select(g => g.GradeNo) - .ToList(); - - var allClassNos = gradeDtos - .SelectMany(g => g.ClassList ?? new List()) - .Where(c => !string.IsNullOrWhiteSpace(c.ClassNo)) - .Select(c => c.ClassNo) - .ToList(); - + // 3️⃣ 查询数据库已有年级和班级 var existGrades = await _studentRepository.DbContext.Set() .Where(x => x.SchoolCode == schoolCode && allGradeNos.Contains(x.GradeNo)) + .Include(g => g.Classes) .ToListAsync(); - var existClasses = await _classRepository.DbContext.Set() - .Where(x => x.SchoolCode == schoolCode && allClassNos.Contains(x.ClassNo)) - .ToListAsync(); + // 4️⃣ 更新已存在的年级老师信息(直接 UPDATE) + foreach (var grade in existGrades) + { + grade.TeacherNo = teacher.TeacherNo; + grade.TeacherName = teacher.TeacherName; - var existGradeNoSet = existGrades.Select(x => x.GradeNo).ToHashSet(); - var existClassNoSet = existClasses.Select(x => x.ClassNo).ToHashSet(); + foreach (var cls in grade.Classes) + { + cls.TeacherNo = teacher.TeacherNo; + cls.TeacherName = teacher.TeacherName; + } + } + // 5️⃣ 构造新增年级和班级 var newGrades = new List(); + var existGradeNoSet = existGrades.Select(g => g.GradeNo).ToHashSet(); + var existClassNoSet = existGrades.SelectMany(g => g.Classes).Select(c => c.ClassNo).ToHashSet(); foreach (var g in gradeDtos) { if (string.IsNullOrWhiteSpace(g.GradeNo) || existGradeNoSet.Contains(g.GradeNo)) continue; - var grade = new JS_Grade + var gradeNew = new JS_Grade { TeacherNo = teacher.TeacherNo, TeacherName = teacher.TeacherName, @@ -1607,8 +1563,7 @@ namespace VOL.Ai.Services GradeNo = g.GradeNo, GradeName = g.GradeName, Classes = g.ClassList? - .Where(c => !string.IsNullOrWhiteSpace(c.ClassNo) - && !existClassNoSet.Contains(c.ClassNo)) + .Where(c => !string.IsNullOrWhiteSpace(c.ClassNo)) .Select(c => new JS_Class { TeacherNo = teacher.TeacherNo, @@ -1621,43 +1576,34 @@ namespace VOL.Ai.Services ClassName = c.ClassName }).ToList() ?? new List() }; - - newGrades.Add(grade); - - existGradeNoSet.Add(g.GradeNo); - foreach (var c in grade.Classes) - existClassNoSet.Add(c.ClassNo); + newGrades.Add(gradeNew); } if (newGrades.Any()) await _studentRepository.DbContext.Set().AddRangeAsync(newGrades); - try - { - await _studentRepository.DbContext.SaveChangesAsync(); - } - catch (DbUpdateException ex) when (ex.InnerException?.Message.Contains("UNIQUE") == true) - { - // 并发唯一索引冲突可忽略 - } + // 6️⃣ 保存所有修改和新增 - // ========================= - // 5️⃣ 重新读取数据库,获取 Id - // ========================= + // EF Core 显式标记更新 + _studentRepository.UpdateRange(existGrades); + + // 同时更新所有班级(必须显式) + var allClasses = existGrades.SelectMany(g => g.Classes).ToList(); + _classRepository.UpdateRange(allClasses); + + await _studentRepository.DbContext.SaveChangesAsync(); + + // 7️⃣ 返回结果 var dbGrades = await _studentRepository.DbContext.Set() - .Where(x => x.SchoolCode == schoolCode && allGradeNos.Contains(x.GradeNo)) + .Where(x => x.SchoolCode == schoolCode && allGradeNos.Contains(x.GradeNo) && x.TeacherNo == teacher.TeacherNo) .Include(g => g.Classes) .ToListAsync(); - // ========================= - // 6️⃣ 组装返回 DTO - // ========================= var res = new Ai_TeacherFaceInfo { - Id = (int)tId, + Id = 0, TeacherName = teacher.TeacherName, Phone = teacher.TeacherNo, - //Photo = teacher.TeacherNo, GradeAndClassList = dbGrades .SelectMany(g => g.Classes) .Select(c => new Classes @@ -1668,15 +1614,15 @@ namespace VOL.Ai.Services .ToList() }; - // ========================= - // 7️⃣ 删除扫码记录 - // ========================= + // 8️⃣ 删除扫码记录 _scanCodeLoginRepository.Delete(loginInfo); await _scanCodeLoginRepository.SaveChangesAsync(); return res; } + + /// /// 登录 ///