Merge branch 'jingshitijiaov1_qa' into jingshitijiaov1

This commit is contained in:
tanglong 2026-01-26 18:53:01 +08:00
commit 9a25202df2

View File

@ -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<JingShiClassDto>())
// .Where(c => !string.IsNullOrWhiteSpace(c.ClassNo))
// .Select(c => c.ClassNo)
// .ToList();
//// =========================
//// 4️⃣ 查询数据库中已存在的数据(幂等)
//// =========================
//var existGrades = await _studentRepository.DbContext.Set<JS_Grade>()
// .Where(x => x.SchoolCode == schoolCode && allGradeNos.Contains(x.GradeNo))
// .ToListAsync();
//var existClasses = await _classRepository.DbContext.Set<JS_Class>()
// .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<JS_Grade>();
//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<JS_Class>()
// };
// newGrades.Add(grade);
// existGradeNoSet.Add(g.GradeNo);
// foreach (var c in grade.Classes)
// existClassNoSet.Add(c.ClassNo);
//}
//if (newGrades.Any())
// await _studentRepository.DbContext.Set<JS_Grade>().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<JS_Grade>()
// .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<Classes>()
}).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<JingShiClassDto>())
.Where(c => !string.IsNullOrWhiteSpace(c.ClassNo))
.Select(c => c.ClassNo)
.ToList();
// =========================
// 4️⃣ 查询数据库中已存在的数据(幂等)
// =========================
var existGrades = await _studentRepository.DbContext.Set<JS_Grade>()
.Where(x => x.SchoolCode == schoolCode && allGradeNos.Contains(x.GradeNo))
.ToListAsync();
var existClasses = await _classRepository.DbContext.Set<JS_Class>()
.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<JS_Grade>();
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<JS_Class>()
};
newGrades.Add(grade);
existGradeNoSet.Add(g.GradeNo);
foreach (var c in grade.Classes)
existClassNoSet.Add(c.ClassNo);
}
if (newGrades.Any())
await _studentRepository.DbContext.Set<JS_Grade>().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<JS_Grade>()
.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<Classes>()
// }).ToList()
//};
//return res;
}
public Ai_OSSInfoDto OSSInfo(Ai_Request paramDto)
{
return new Ai_OSSInfoDto()
@ -1497,108 +1498,63 @@ namespace VOL.Ai.Services
/// </summary>
/// <param name="paramDto"></param>
/// <returns></returns>
[HttpPost(nameof(ScanCodeLogin))]
[HttpPost(nameof(ScanCodeLogin))]
public async Task<Ai_TeacherFaceInfo> 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<GradeDto>();
var allGradeNos = gradeDtos.Where(g => !string.IsNullOrWhiteSpace(g.GradeNo))
.Select(g => g.GradeNo)
.ToList();
// =========================
// 3️⃣ 同步教师信息
// =========================
var existingTeacher = await _teacherRepository.DbContext.Set<JS_Teacher>()
.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<JS_Teacher>().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<JS_Teacher>()
.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<ClassDto>())
.Where(c => !string.IsNullOrWhiteSpace(c.ClassNo))
.Select(c => c.ClassNo)
.ToList();
// 3️⃣ 查询数据库已有年级和班级
var existGrades = await _studentRepository.DbContext.Set<JS_Grade>()
.Where(x => x.SchoolCode == schoolCode && allGradeNos.Contains(x.GradeNo))
.Include(g => g.Classes)
.ToListAsync();
var existClasses = await _classRepository.DbContext.Set<JS_Class>()
.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<JS_Grade>();
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<JS_Class>()
};
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<JS_Grade>().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<JS_Grade>()
.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;
}
/// <summary>
/// 登录
/// </summary>