重构项目结构,移除Assignment相关功能,优化Submission模块
Some checks failed
TechAct / explore-gitea-actions (push) Failing after 12s
Some checks failed
TechAct / explore-gitea-actions (push) Failing after 12s
This commit is contained in:
319
TechHelper.Server/Services/Class/ClassService.cs
Normal file
319
TechHelper.Server/Services/Class/ClassService.cs
Normal file
@@ -0,0 +1,319 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Entities.DTO.Class;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Repository;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public class ClassService : IClassService
|
||||
{
|
||||
private readonly IUnitOfWork _work;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public ClassService(IUnitOfWork work, IMapper mapper)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var repository = _work.GetRepository<Class>();
|
||||
|
||||
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
var classes = await repository.GetPagedListAsync(
|
||||
predicate: c => c.ClassName.Contains(query.Search),
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var classDtosFiltered = _mapper.Map<IEnumerable<ClassDto>>(classes.Items);
|
||||
return new ApiResponse(true, classDtosFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
var classes = await repository.GetPagedListAsync(
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var classDtos = _mapper.Map<IEnumerable<ClassDto>>(classes.Items);
|
||||
return new ApiResponse(true, classDtos);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取所有班级时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var @class = await _work.GetRepository<Class>().GetFirstOrDefaultAsync(
|
||||
predicate: c => c.Id == id,
|
||||
include: i => i.Include(c => c.Grade).Include(c => c.HeadTeacher));
|
||||
|
||||
if (@class == null)
|
||||
{
|
||||
return new ApiResponse("班级未找到。");
|
||||
}
|
||||
|
||||
var classDto = _mapper.Map<ClassDto>(@class);
|
||||
return new ApiResponse(true, classDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取班级时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AddAsync(ClassDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否已存在相同年级下的同名班级
|
||||
var existingClass = await _work.GetRepository<Class>().GetFirstOrDefaultAsync(
|
||||
predicate: c => c.GradeId == model.GradeId && (c.ClassName == model.ClassName || c.Index == model.Index));
|
||||
|
||||
if (existingClass != null)
|
||||
{
|
||||
return new ApiResponse($"在当前年级下,班级 '{model.ClassName}', 序号 '{model.Index}' 已存在。 请检查你的班级名称和序号, 如有问题请联系管理员.");
|
||||
}
|
||||
|
||||
var @class = _mapper.Map<Class>(model);
|
||||
await _work.GetRepository<Class>().InsertAsync(@class);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, _mapper.Map<ClassDto>(@class));
|
||||
}
|
||||
return new ApiResponse("添加班级失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"添加班级时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UpdateAsync(ClassDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingClass = await _work.GetRepository<Class>().GetFirstOrDefaultAsync(
|
||||
predicate: c => c.Id == model.Id);
|
||||
|
||||
if (existingClass == null)
|
||||
{
|
||||
return new ApiResponse("班级未找到。");
|
||||
}
|
||||
|
||||
_mapper.Map(model, existingClass);
|
||||
_work.GetRepository<Class>().Update(existingClass);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, _mapper.Map<ClassDto>(existingClass));
|
||||
}
|
||||
return new ApiResponse("更新班级失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"更新班级时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingClass = await _work.GetRepository<Class>().GetFirstOrDefaultAsync(
|
||||
predicate: c => c.Id == id);
|
||||
|
||||
if (existingClass == null)
|
||||
{
|
||||
return new ApiResponse("班级未找到。");
|
||||
}
|
||||
|
||||
_work.GetRepository<Class>().Delete(existingClass);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, "班级删除成功。");
|
||||
}
|
||||
return new ApiResponse("删除班级失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"删除班级时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetClassStudentsAsync(Guid classId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var classEntity = await _work.GetRepository<Class>().GetFirstOrDefaultAsync(
|
||||
predicate: c => c.Id == classId);
|
||||
|
||||
if (classEntity == null)
|
||||
{
|
||||
return new ApiResponse("班级未找到。");
|
||||
}
|
||||
|
||||
var students = classEntity.Students
|
||||
.Where(u => !u.IsDeleted)
|
||||
.Select(u => u.User)
|
||||
.ToList();
|
||||
|
||||
|
||||
var StudentsDto = _mapper.Map<IEnumerable<UserListDto>>(students);
|
||||
return new ApiResponse(true, StudentsDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取班级学生时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> ValidateClassRegistration(ClassValidDto user)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 验证学校是否存在
|
||||
var schoolRepository = _work.GetRepository<School>();
|
||||
var school = await schoolRepository.GetFirstOrDefaultAsync(
|
||||
predicate: s => s.SchoolName == user.SchoolName);
|
||||
|
||||
if (school == null)
|
||||
{
|
||||
return new ApiResponse("学校未找到。");
|
||||
}
|
||||
|
||||
// 验证年级是否存在
|
||||
var gradeRepository = _work.GetRepository<Grade>();
|
||||
var grade = await gradeRepository.GetFirstOrDefaultAsync(
|
||||
predicate: g => g.SchoolId == school.Id && g.GradeLevel == user.Grade);
|
||||
|
||||
if (grade == null)
|
||||
{
|
||||
return new ApiResponse("年级未找到。");
|
||||
}
|
||||
|
||||
// 验证班级是否存在
|
||||
var classRepository = _work.GetRepository<Class>();
|
||||
var classEntity = await classRepository.GetFirstOrDefaultAsync(
|
||||
predicate: c => c.GradeId == grade.Id && c.Index == user.Class && !c.IsDeleted);
|
||||
|
||||
if (classEntity == null)
|
||||
{
|
||||
return new ApiResponse("班级未找到。");
|
||||
}
|
||||
|
||||
// 返回验证成功的班级信息
|
||||
return new ApiResponse(true, classEntity.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"验证班级信息时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UserRegister(RegisterUserToClassDto user)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 获取班级实体
|
||||
var classRepository = _work.GetRepository<Class>();
|
||||
var classEntity = await classRepository.GetFirstOrDefaultAsync(
|
||||
predicate: c => c.Id == user.ClassId);
|
||||
|
||||
if (classEntity == null)
|
||||
{
|
||||
return new ApiResponse("检查你的班级输入,没有该班级。");
|
||||
}
|
||||
|
||||
// 检查用户是否已经在该班级中
|
||||
var existingClassUser = classEntity.ClassUsers.FirstOrDefault(u => u.UserId == user.UserId);
|
||||
if (existingClassUser != null )
|
||||
{
|
||||
return new ApiResponse("用户已经在该班级中。");
|
||||
}
|
||||
|
||||
await _work.GetRepository<ClassUser>().InsertAsync(
|
||||
new ClassUser { ClassId = user.ClassId, UserId = user.UserId, EnrollmentDate = DateTime.Now });
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, "用户成功注册到班级。");
|
||||
}
|
||||
return new ApiResponse("用户注册到班级失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"用户注册到班级时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetUserInjoinedClasses(Guid user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userInfo = await _work.GetRepository<User>().GetFirstOrDefaultAsync(predicate:
|
||||
u => u.Id == user,include: i => i
|
||||
.Include(u => u.UserInjoinedClass)
|
||||
.ThenInclude(c => c.Class)
|
||||
.ThenInclude(cs => cs.Grade));
|
||||
var schoolName = userInfo.UserInjoinedClass.First().Class.Grade.School.SchoolName;
|
||||
var userClassInfo = userInfo.UserInjoinedClass.Select(c => c.Class);
|
||||
var userClassDto = userClassInfo.Select(c => new UserClassInfoDto(c.Id, c.Index, c.Grade.GradeLevel));
|
||||
var result = new UserClassDetailInfoDto(userClassDto, schoolName);
|
||||
return ApiResponse.Success(result: result);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取用户班级信息时发生错误: {ex.Message}");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public Task<ApiResponse> GetUserClassRole(Guid id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AdminAddAsync(ClassCreateDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否已存在相同年级下的同名班级
|
||||
var existingClass = await _work.GetRepository<Class>().GetFirstOrDefaultAsync(
|
||||
predicate: c => c.Grade.GradeLevel == model.Grade.GradeLevel && (c.ClassName == model.ClassName || c.Index == model.Index));
|
||||
|
||||
if (existingClass != null)
|
||||
{
|
||||
return new ApiResponse($"在当前年级下,班级 '{model.ClassName}', 序号 '{model.Index}' 已存在。 请检查你的班级名称和序号, 如有问题请联系管理员.");
|
||||
}
|
||||
|
||||
var @class = _mapper.Map<Class>(model);
|
||||
await _work.GetRepository<Class>().InsertAsync(@class);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, _mapper.Map<ClassDto>(@class));
|
||||
}
|
||||
return new ApiResponse("添加班级失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"添加班级时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
TechHelper.Server/Services/Class/IClassService.cs
Normal file
16
TechHelper.Server/Services/Class/IClassService.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Entities.DTO;
|
||||
using Entities.DTO.Class;
|
||||
using SharedDATA.Api;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public interface IClassService : IBaseService<ClassDto, Guid>
|
||||
{
|
||||
Task<ApiResponse> GetClassStudentsAsync(Guid classId);
|
||||
Task<ApiResponse> UserRegister(RegisterUserToClassDto user);
|
||||
Task<ApiResponse> ValidateClassRegistration(ClassValidDto user);
|
||||
Task<ApiResponse> GetUserInjoinedClasses(Guid user);
|
||||
Task<ApiResponse> GetUserClassRole(Guid id);
|
||||
Task<ApiResponse> AdminAddAsync(ClassCreateDto dto);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Entities.DTO.Class;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
@@ -41,7 +42,7 @@ namespace TechHelper.Services
|
||||
}
|
||||
|
||||
// 实现 IBaseService<ClassDto, int>.DeleteAsync
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id) // ID 类型现在是 int
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
196
TechHelper.Server/Services/Exam/ExamQuestionService.cs
Normal file
196
TechHelper.Server/Services/Exam/ExamQuestionService.cs
Normal file
@@ -0,0 +1,196 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Services.Beta;
|
||||
using static TechHelper.Services.Beta.IExamQuestionService;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public class ExamQuestionService : IExamQuestionService
|
||||
{
|
||||
private readonly IUnitOfWork _work;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IClassService _classService;
|
||||
|
||||
public ExamQuestionService(IUnitOfWork work, IMapper mapper, IClassService classService)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
_classService = classService;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var repository = _work.GetRepository<ExamQuestion>();
|
||||
|
||||
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
var examQuestions = await repository.GetPagedListAsync(
|
||||
predicate: eq => eq.Title.Contains(query.Search) && eq.ParentExamQuestionId == null,
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var examQuestionDtosFiltered = _mapper.Map<IEnumerable<ExamQuestionDto>>(examQuestions.Items);
|
||||
return new ApiResponse(true, examQuestionDtosFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
var examQuestions = await repository.GetPagedListAsync(
|
||||
predicate: eq => eq.ParentExamQuestionId == null,
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var examQuestionDtos = _mapper.Map<IEnumerable<ExamQuestionDto>>(examQuestions.Items);
|
||||
return new ApiResponse(true, examQuestionDtos);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取所有考试题目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var examQuestion = await _work.GetRepository<ExamQuestion>().GetFirstOrDefaultAsync(
|
||||
predicate: eq => eq.Id == id);
|
||||
|
||||
if (examQuestion == null)
|
||||
{
|
||||
return new ApiResponse("考试题目未找到。");
|
||||
}
|
||||
|
||||
var examQuestionDto = _mapper.Map<ExamQuestionDto>(examQuestion);
|
||||
return new ApiResponse(true, examQuestionDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取考试题目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AddAsync(ExamQuestionDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否已存在相同考试和题目的组合
|
||||
var existingExamQuestion = await _work.GetRepository<ExamQuestion>().GetFirstOrDefaultAsync(
|
||||
predicate: eq => eq.Id == model.Id/* && eq.QuestionId == model.Question.Id*/);
|
||||
|
||||
if (existingExamQuestion != null)
|
||||
{
|
||||
return new ApiResponse($"该题目已在此考试中存在。");
|
||||
}
|
||||
|
||||
var examQuestion = _mapper.Map<ExamQuestion>(model);
|
||||
|
||||
await _work.GetRepository<ExamQuestion>().InsertAsync(examQuestion);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, examQuestion.Id);
|
||||
}
|
||||
return new ApiResponse("添加考试题目失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"添加考试题目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UpdateAsync(ExamQuestionDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingExamQuestion = await _work.GetRepository<ExamQuestion>().GetFirstOrDefaultAsync(
|
||||
predicate: eq => eq.Id == model.Id);
|
||||
|
||||
if (existingExamQuestion == null)
|
||||
{
|
||||
return new ApiResponse("考试题目未找到。");
|
||||
}
|
||||
|
||||
// 检查是否要修改为已存在的考试题目组合(排除当前记录)
|
||||
var examQuestionWithSameCombination = await _work.GetRepository<ExamQuestion>().GetFirstOrDefaultAsync(
|
||||
predicate: eq => eq.Id == model.Id /*&& eq.QuestionId == model.QuestionId*/ && eq.Id != model.Id);
|
||||
|
||||
if (examQuestionWithSameCombination != null)
|
||||
{
|
||||
return new ApiResponse($"该题目与考试的组合已存在。");
|
||||
}
|
||||
|
||||
_mapper.Map(model, existingExamQuestion);
|
||||
_work.GetRepository<ExamQuestion>().Update(existingExamQuestion);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
var examQuestionDto = _mapper.Map<ExamQuestionDto>(existingExamQuestion);
|
||||
return new ApiResponse(true, examQuestionDto);
|
||||
}
|
||||
return new ApiResponse("更新考试题目失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"更新考试题目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingExamQuestion = await _work.GetRepository<ExamQuestion>().GetFirstOrDefaultAsync(
|
||||
predicate: eq => eq.Id == id);
|
||||
|
||||
if (existingExamQuestion == null)
|
||||
{
|
||||
return new ApiResponse("考试题目未找到。");
|
||||
}
|
||||
|
||||
_work.GetRepository<ExamQuestion>().Delete(existingExamQuestion);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, "考试题目删除成功。");
|
||||
}
|
||||
return new ApiResponse("删除考试题目失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"删除考试题目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetQuestionDependy(QuesitionDenpendceyRequst request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var classStudentsResponse = await _classService.GetClassStudentsAsync(request.ClassId);
|
||||
if (!classStudentsResponse.Status) return ApiResponse.Error(classStudentsResponse.Message);
|
||||
|
||||
var classStudents = classStudentsResponse.Result as IEnumerable<UserListDto>;
|
||||
if (classStudents == null) return ApiResponse.Error("班级学生列表为空。");
|
||||
|
||||
var submissionResult = await _work.GetRepository<SubmissionDetail>().GetAllAsync(predicate: sd => sd.ExamQuestionId == request.ExamQuestioId );
|
||||
var submission = submissionResult.Where(s => classStudents.Any(c => c.Id == s.StudentId));
|
||||
var errorStudents = submission.Select(s => s.Student);
|
||||
var scores = submission.Select(s => s.PointsAwarded);
|
||||
var lesson = submission.FirstOrDefault()?.ExamQuestion?.Question?.Lesson ?? null;
|
||||
var lessonDto = _mapper.Map<LessonDto>(lesson);
|
||||
var ErrorStudentDtro = _mapper.Map<IEnumerable<UserListDto>>(errorStudents);
|
||||
return ApiResponse.Success("获取成功", new QuestionDependecyDto(lessonDto, scores, ErrorStudentDtro));
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取考试题目密度时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
341
TechHelper.Server/Services/Exam/ExamService.cs
Normal file
341
TechHelper.Server/Services/Exam/ExamService.cs
Normal file
@@ -0,0 +1,341 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.VisualBasic;
|
||||
using SharedDATA.Api;
|
||||
using System.Linq;
|
||||
using TechHelper.Context;
|
||||
using TechHelper.Server.Repositories;
|
||||
using TechHelper.Services.Beta;
|
||||
using static TechHelper.Services.Beta.IExamService;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
|
||||
public class ExamService : IExamService
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly ISubmissionService _submissionService;
|
||||
private readonly IClassService _classService;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public ExamService(IUnitOfWork unitOfWork, IMapper mapper, IClassService classService, ISubmissionService submissionService)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_mapper = mapper;
|
||||
_classService = classService;
|
||||
_submissionService = submissionService;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> CreateExamAsync(ExamDto ExamDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
Exam newAssi = _mapper.Map<Exam>(ExamDto);
|
||||
//var context = _unitOfWork.GetDbContext<ApplicationContext>();
|
||||
|
||||
//foreach (var entry in context.ChangeTracker.Entries())
|
||||
//{
|
||||
// if (entry.State == Microsoft.EntityFrameworkCore.EntityState.Added)
|
||||
// {
|
||||
// if (entry.Entity is Question newQues)
|
||||
// {
|
||||
// newQues.CreatorId = newAssi.CreatorId;
|
||||
// }
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
if (await _unitOfWork.SaveChangesAsync() > 0)
|
||||
{
|
||||
return ApiResponse.Success();
|
||||
}
|
||||
|
||||
return ApiResponse.Error("保存失败");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var repository = _unitOfWork.GetRepository<Exam>();
|
||||
|
||||
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
var examQuestions = await repository.GetPagedListAsync(
|
||||
predicate: eq => eq.Title.Contains(query.Search),
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var examQuestionDtosFiltered = _mapper.Map<IEnumerable<ExamListDto>>(examQuestions.Items);
|
||||
return new ApiResponse(true, examQuestionDtosFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
var examQuestions = await repository.GetPagedListAsync(
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var examQuestionDtos = _mapper.Map<IEnumerable<ExamListDto>>(examQuestions.Items);
|
||||
return new ApiResponse(true, examQuestionDtos);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取所有考试题目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var assignment = await _unitOfWork.GetRepository<Exam>().GetFirstOrDefaultAsync(predicate: a => a.Id == id);
|
||||
if (assignment == null)
|
||||
{
|
||||
return ApiResponse.Error("获取失败");
|
||||
}
|
||||
var result = _mapper.Map<ExamDto>(assignment);
|
||||
return ApiResponse.Success(result: result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AddAsync(ExamDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var exam = _mapper.Map<Exam>(model);
|
||||
await _unitOfWork.GetRepository<Exam>().InsertAsync(exam);
|
||||
if (await _unitOfWork.SaveChangesAsync() > 0)
|
||||
{
|
||||
return ApiResponse.Success("创建成功", exam.Id);
|
||||
}
|
||||
return ApiResponse.Error("创建失败");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UpdateAsync(ExamDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingExam = await _unitOfWork.GetRepository<Exam>().GetFirstOrDefaultAsync(predicate: a => a.Id == model.Id);
|
||||
if (existingExam == null) return ApiResponse.Error("找不到该试卷");
|
||||
_mapper.Map(model, existingExam);
|
||||
_unitOfWork.GetRepository<Exam>().Update(existingExam);
|
||||
if (await _unitOfWork.SaveChangesAsync() > 0)
|
||||
{
|
||||
return ApiResponse.Success("更新成功");
|
||||
}
|
||||
return ApiResponse.Error("更新失败");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var assignment = await _unitOfWork.GetRepository<Exam>().GetFirstOrDefaultAsync(predicate: a => a.Id == id);
|
||||
|
||||
if (assignment == null) return ApiResponse.Error("找不到该试卷");
|
||||
_unitOfWork.GetRepository<Exam>().Delete(id);
|
||||
_unitOfWork.GetRepository<ExamQuestion>().Delete(assignment.ExamStructId);
|
||||
|
||||
|
||||
if (await _unitOfWork.SaveChangesAsync() > 0)
|
||||
{
|
||||
return ApiResponse.Success();
|
||||
}
|
||||
return ApiResponse.Error("删除失败");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"内部问题,{ex.Message}, InerException{ex.InnerException}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AssignmentToAllClassesAsync(AssigExamToClassDto examToClassDto, Guid TeacherId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _classService.GetUserInjoinedClasses(TeacherId);
|
||||
|
||||
if (result.Status == false) return ApiResponse.Error(result.Message);
|
||||
var userClass = result.Result as UserClassDetailInfoDto;
|
||||
if (userClass == null || !userClass.UserClassInfos.Any()) return ApiResponse.Error("教师没有管理任何班级");
|
||||
|
||||
|
||||
var assignment = await _unitOfWork.GetRepository<Exam>().GetFirstOrDefaultAsync(predicate: a => a.Id == examToClassDto.examId);
|
||||
if (assignment == null) return ApiResponse.Error("没有找到该试卷");
|
||||
|
||||
foreach (var classId in userClass.UserClassInfos)
|
||||
{
|
||||
await AssignmentToClassAsync(TeacherId, examToClassDto.examId, classId.Id);
|
||||
}
|
||||
|
||||
if (await _unitOfWork.SaveChangesAsync() > 0)
|
||||
{
|
||||
return ApiResponse.Success("分配成功");
|
||||
}
|
||||
return ApiResponse.Error("分配失败");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"内部错误, {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AssignmentToStudentsAsync(AssigExamToStudentsDto examToStudentsDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var assignment = await _unitOfWork.GetRepository<Exam>().GetFirstOrDefaultAsync(predicate: a => a.Id == examToStudentsDto.ExamId);
|
||||
if (assignment == null)
|
||||
{
|
||||
return ApiResponse.Error("获取失败");
|
||||
}
|
||||
if (assignment == null) return ApiResponse.Error("没有找到该试卷");
|
||||
|
||||
if (examToStudentsDto.StudentIds == null || !examToStudentsDto.StudentIds.Any())
|
||||
{
|
||||
return ApiResponse.Error("没有选择学生");
|
||||
}
|
||||
|
||||
foreach (var studentId in examToStudentsDto.StudentIds)
|
||||
{
|
||||
var subCount = await _unitOfWork.GetRepository<Submission>().GetAll(
|
||||
predicate: su => su.ExamId == examToStudentsDto.ExamId && su.StudentId == studentId
|
||||
).CountAsync();
|
||||
|
||||
var submission = assignment.ConvertToSubmission(studentId, examToStudentsDto.CreaterId, examToStudentsDto.ClassId);
|
||||
submission.AttemptNumber = (byte)(subCount + 1);
|
||||
await _unitOfWork.GetRepository<Submission>().InsertAsync(submission);
|
||||
}
|
||||
|
||||
if (await _unitOfWork.SaveChangesAsync() > 0)
|
||||
{
|
||||
return ApiResponse.Success();
|
||||
}
|
||||
return ApiResponse.Error();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"内部错误, {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AssignmentToClassAsync(Guid TeacherId, Guid examId, Guid classId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var classStudents = await _classService.GetClassStudentsAsync(classId);
|
||||
if (!classStudents.Status) return ApiResponse.Error(classStudents.Message);
|
||||
var userlist = classStudents.Result as IEnumerable<UserListDto>;
|
||||
if (userlist == null || !userlist.Any()) return ApiResponse.Error("班级没有学生");
|
||||
|
||||
var assignment = await _unitOfWork.GetRepository<Exam>().GetFirstOrDefaultAsync(predicate: a => a.Id == examId);
|
||||
if (assignment == null) return ApiResponse.Error("没有找到该试卷");
|
||||
|
||||
foreach (var student in userlist)
|
||||
{
|
||||
var subCount = await _unitOfWork.GetRepository<Submission>().GetAll(
|
||||
predicate: su => su.ExamId == examId && su.StudentId == student.Id
|
||||
).CountAsync();
|
||||
|
||||
var submission = assignment.ConvertToSubmission(student.Id, TeacherId, classId);
|
||||
submission.AttemptNumber = (byte)(subCount + 1);
|
||||
await _unitOfWork.GetRepository<Submission>().InsertAsync(submission);
|
||||
}
|
||||
|
||||
if (await _unitOfWork.SaveChangesAsync() > 0)
|
||||
{
|
||||
return ApiResponse.Success("创建成功");
|
||||
}
|
||||
return ApiResponse.Error("创建失败");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"内部错误, {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetExamSubmissionDetailInClassAsync(AssigExamToClassDto examToClassDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var submissions = await _unitOfWork.GetRepository<Submission>().GetAllAsync(predicate: s => s.ExamId == examToClassDto.examId && s.ClassId == examToClassDto.classId);
|
||||
|
||||
if (submissions == null || !submissions.Any()) return ApiResponse.Error("没有找到该试卷");
|
||||
|
||||
var result = _mapper.Map<List<SubmissionListDto>>(submissions);
|
||||
|
||||
return ApiResponse.Success(result: result);
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"内部错误, {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetExamTotalErrorDistributionInClassAsync(AssigExamToClassDto examToClassDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var submissions = await _unitOfWork.GetRepository<Submission>().
|
||||
GetAllAsync(predicate: s => s.ExamId == examToClassDto.examId && s.ClassId == examToClassDto.classId);
|
||||
|
||||
if (submissions == null || !submissions.Any()) return ApiResponse.Error("没有找到该试卷");
|
||||
|
||||
var errorTypeDistribution = submissions
|
||||
.SelectMany(s => s.SubmissionDetails)
|
||||
.Where(d => d.IsCorrect == false)
|
||||
.GroupBy(d => d.ExamQuestion.Type.Name)
|
||||
.ToDictionary(g => g.Key, g => g.Count());
|
||||
|
||||
var errorLessonDistribution = submissions
|
||||
.SelectMany(s => s.SubmissionDetails)
|
||||
.Where(d => d.IsCorrect == false)
|
||||
.Where(d => d.ExamQuestion?.Question?.Lesson?.Title != null)
|
||||
.GroupBy(d => d.ExamQuestion.Question?.Lesson?.Title)
|
||||
.ToDictionary(g => g.Key, g => g.Count());
|
||||
|
||||
|
||||
var scores = submissions.Select(s => s.OverallGrade);
|
||||
var result = new ExamDistributionDto(errorTypeDistribution, errorLessonDistribution, scores);
|
||||
|
||||
return ApiResponse.Success(result: result);
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"内部错误, {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
19
TechHelper.Server/Services/Exam/IExamQuestionService.cs
Normal file
19
TechHelper.Server/Services/Exam/IExamQuestionService.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public interface IExamQuestionService : IBaseService<ExamQuestionDto, Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF>Ҫ<EFBFBD><D2AA>֪ʶ<D6AA><CAB6>,<2C>÷<EFBFBD><C3B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֲ<EFBFBD>,<2C><><EFBFBD><EFBFBD>ѧ<EFBFBD><D1A7><EFBFBD>б<EFBFBD>
|
||||
/// </summary>
|
||||
/// <param name="ExamQuestioId"></param>
|
||||
/// <returns></returns>
|
||||
Task<ApiResponse> GetQuestionDependy(QuesitionDenpendceyRequst request);
|
||||
|
||||
public record QuesitionDenpendceyRequst(Guid ExamQuestioId, Guid ClassId);
|
||||
|
||||
public record QuestionDependecyDto (LessonDto? Lesson, IEnumerable<float?> ScoreDistribution, IEnumerable<UserListDto> ErrorStudents);
|
||||
}
|
||||
}
|
||||
66
TechHelper.Server/Services/Exam/IExamService.cs
Normal file
66
TechHelper.Server/Services/Exam/IExamService.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using Entities.DTO;
|
||||
///*
|
||||
/// 创建一个新的试卷。
|
||||
/// 删除一个试卷。
|
||||
/// 修改一个试卷。
|
||||
/// 查看试卷详情。
|
||||
///
|
||||
/// Teacher
|
||||
/// 获取指定用户的所有试卷预览。
|
||||
/// 获取试卷的所有指定
|
||||
///
|
||||
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public interface IExamService : IBaseService<ExamDto, Guid>
|
||||
{
|
||||
|
||||
///// <summary>
|
||||
///// 获取指定用户的所有试卷预览。
|
||||
///// </summary>
|
||||
//Task<ApiResponse> GetAllExamPreviewsAsync(Guid userId);
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的试卷。
|
||||
/// </summary>
|
||||
/// <returns>创建成功的试卷ID</returns>
|
||||
Task<ApiResponse> CreateExamAsync(ExamDto examDto);
|
||||
|
||||
/// <summary>
|
||||
/// 为指定的班级指派一个试卷
|
||||
/// </summary>
|
||||
/// <param name="TeacherId"> 老师ID </param>
|
||||
/// <param name="assignmentId"> 试卷ID </param>
|
||||
/// <param name="classId"> 班级ID </param>
|
||||
/// <returns></returns>
|
||||
Task<ApiResponse> AssignmentToClassAsync(Guid TeacherId , Guid assignmentId, Guid classId);
|
||||
|
||||
/// <summary>
|
||||
/// 为指定学生指派一个试卷
|
||||
/// </summary>
|
||||
/// <param name="assignementId"></param>
|
||||
/// <param name="studentId"></param>
|
||||
/// <returns></returns>
|
||||
Task<ApiResponse> AssignmentToStudentsAsync(AssigExamToStudentsDto examToStudentsDto);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取该试卷在指定班级指派了多少人
|
||||
/// </summary>
|
||||
/// <param name="examToClassDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<ApiResponse> GetExamSubmissionDetailInClassAsync(AssigExamToClassDto examToClassDto);
|
||||
|
||||
|
||||
|
||||
|
||||
Task<ApiResponse> GetExamTotalErrorDistributionInClassAsync(AssigExamToClassDto examToClassDto);
|
||||
|
||||
|
||||
public record ExamDistributionDto(Dictionary<string, int> ErrorTypeDistribution,
|
||||
Dictionary<string, int> ErrorLessonDistribution,
|
||||
IEnumerable<float> ScoreDistribution);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Entities.DTO.Class;
|
||||
using Microsoft.VisualBasic;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Context;
|
||||
@@ -32,7 +33,7 @@ namespace TechHelper.Server.Services
|
||||
try
|
||||
{
|
||||
|
||||
Assignment newAssi = _mapper.Map<Assignment>(assignmentDto);
|
||||
Exam newAssi = _mapper.Map<Exam>(assignmentDto);
|
||||
|
||||
await _examRepository.AddAsync(newAssi);
|
||||
|
||||
@@ -117,11 +118,11 @@ namespace TechHelper.Server.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
var assignment = await _unitOfWork.GetRepository<Assignment>().GetFirstOrDefaultAsync(predicate: a => a.Id == id);
|
||||
var assignment = await _unitOfWork.GetRepository<Exam>().GetFirstOrDefaultAsync(predicate: a => a.Id == id);
|
||||
|
||||
if (assignment == null) return ApiResponse.Error("找不到该试卷");
|
||||
_unitOfWork.GetRepository<Assignment>().Delete(id);
|
||||
_unitOfWork.GetRepository<AssignmentQuestion>().Delete(assignment.ExamStructId);
|
||||
_unitOfWork.GetRepository<Exam>().Delete(id);
|
||||
_unitOfWork.GetRepository<ExamQuestion>().Delete(assignment.ExamStructId);
|
||||
|
||||
|
||||
if (await _unitOfWork.SaveChangesAsync() > 0)
|
||||
@@ -170,7 +171,7 @@ namespace TechHelper.Server.Services
|
||||
var cs = cla.Result as ICollection<ClassStudent>;
|
||||
cs?.ToList().ForEach(async s =>
|
||||
{
|
||||
var subCount = _unitOfWork.GetRepository<Submission>().GetAll(predicate: su => su.AssignmentId == assignmentId && su.StudentId == s.StudentId);
|
||||
var subCount = _unitOfWork.GetRepository<Submission>().GetAll(predicate: su => su.ExamId == assignmentId && su.StudentId == s.StudentId);
|
||||
|
||||
var submission = assignment.ConvertToSubmission(s.StudentId, TeacherId);
|
||||
submission.AttemptNumber = (byte)(subCount.Count() + 1);
|
||||
@@ -199,7 +200,7 @@ namespace TechHelper.Server.Services
|
||||
|
||||
examToStudentsDto.StudentIds?.ForEach(async s =>
|
||||
{
|
||||
var subCount = _unitOfWork.GetRepository<Submission>().GetAll(predicate: su => su.AssignmentId == examToStudentsDto.AssignmentId && su.StudentId == s);
|
||||
var subCount = _unitOfWork.GetRepository<Submission>().GetAll(predicate: su => su.ExamId == examToStudentsDto.AssignmentId && su.StudentId == s);
|
||||
var submission = assignment.ConvertToSubmission(s, examToStudentsDto.CreaterId);
|
||||
submission.AttemptNumber = (byte)(subCount.Count() + 1);
|
||||
await _unitOfWork.GetRepository<Submission>().InsertAsync(submission);
|
||||
|
||||
175
TechHelper.Server/Services/ExamType/ExamTypeService.cs
Normal file
175
TechHelper.Server/Services/ExamType/ExamTypeService.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Services.Beta;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public class ExamTypeService : IExamTypeService
|
||||
{
|
||||
private readonly IUnitOfWork _work;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public ExamTypeService(IUnitOfWork work, IMapper mapper)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var repository = _work.GetRepository<ExamType>();
|
||||
|
||||
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
var examTypes = await repository.GetPagedListAsync(
|
||||
predicate: et => et.Name.Contains(query.Search) || et.Description.Contains(query.Search),
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var examTypeDtosFiltered = _mapper.Map<IEnumerable<TypeCommonDto>>(examTypes.Items);
|
||||
return new ApiResponse(true, examTypeDtosFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
var examTypes = await repository.GetPagedListAsync(
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex,
|
||||
include: i => i.Include(et => et.Exams)
|
||||
);
|
||||
var examTypeDtos = _mapper.Map<IEnumerable<TypeCommonDto>>(examTypes.Items);
|
||||
return new ApiResponse(true, examTypeDtos);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取所有考试类型时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var examType = await _work.GetRepository<ExamType>().GetFirstOrDefaultAsync(
|
||||
predicate: et => et.Id == id,
|
||||
include: i => i
|
||||
.Include(et => et.Exams));
|
||||
|
||||
if (examType == null)
|
||||
{
|
||||
return new ApiResponse("考试类型未找到。");
|
||||
}
|
||||
|
||||
var examTypeDto = _mapper.Map<ExamTypeResponseDto>(examType);
|
||||
return new ApiResponse(true, examTypeDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取考试类型时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AddAsync(ExamTypeDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否已存在同名考试类型
|
||||
var existingExamType = await _work.GetRepository<ExamType>().GetFirstOrDefaultAsync(
|
||||
predicate: et => et.Name == model.Name);
|
||||
|
||||
if (existingExamType != null)
|
||||
{
|
||||
return new ApiResponse($"考试类型 '{model.Name}' 已存在。");
|
||||
}
|
||||
|
||||
var examType = _mapper.Map<ExamType>(model);
|
||||
await _work.GetRepository<ExamType>().InsertAsync(examType);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, examType.Id);
|
||||
}
|
||||
return new ApiResponse("添加考试类型失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"添加考试类型时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UpdateAsync(ExamTypeDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingExamType = await _work.GetRepository<ExamType>().GetFirstOrDefaultAsync(
|
||||
predicate: et => et.Id == model.Id);
|
||||
|
||||
if (existingExamType == null)
|
||||
{
|
||||
return new ApiResponse("考试类型未找到。");
|
||||
}
|
||||
|
||||
// 检查是否要修改为已存在的考试类型名称(排除当前考试类型)
|
||||
var examTypeWithSameName = await _work.GetRepository<ExamType>().GetFirstOrDefaultAsync(
|
||||
predicate: et => et.Name == model.Name && et.Id != model.Id);
|
||||
|
||||
if (examTypeWithSameName != null)
|
||||
{
|
||||
return new ApiResponse($"考试类型名称 '{model.Name}' 已被其他考试类型使用。");
|
||||
}
|
||||
|
||||
_mapper.Map(model, existingExamType);
|
||||
_work.GetRepository<ExamType>().Update(existingExamType);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
var examTypeDto = _mapper.Map<ExamTypeResponseDto>(existingExamType);
|
||||
return new ApiResponse(true, examTypeDto);
|
||||
}
|
||||
return new ApiResponse("更新考试类型失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"更新考试类型时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingExamType = await _work.GetRepository<ExamType>().GetFirstOrDefaultAsync(
|
||||
predicate: et => et.Id == id,
|
||||
include: i => i.Include(et => et.Exams));
|
||||
|
||||
if (existingExamType == null)
|
||||
{
|
||||
return new ApiResponse("考试类型未找到。");
|
||||
}
|
||||
|
||||
// 检查是否有关联的考试
|
||||
if (existingExamType.Exams != null && existingExamType.Exams.Any())
|
||||
{
|
||||
return new ApiResponse("无法删除该考试类型,因为存在关联的考试。");
|
||||
}
|
||||
|
||||
_work.GetRepository<ExamType>().Delete(existingExamType);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, "考试类型删除成功。");
|
||||
}
|
||||
return new ApiResponse("删除考试类型失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"删除考试类型时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
TechHelper.Server/Services/ExamType/IExamTypeService.cs
Normal file
9
TechHelper.Server/Services/ExamType/IExamTypeService.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public interface IExamTypeService : IBaseService<ExamTypeDto, Guid>
|
||||
{
|
||||
}
|
||||
}
|
||||
155
TechHelper.Server/Services/Grade/GradeService.cs
Normal file
155
TechHelper.Server/Services/Grade/GradeService.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public class GradeService : IGradeService
|
||||
{
|
||||
private readonly IUnitOfWork _work;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public GradeService(IUnitOfWork work, IMapper mapper)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var repository = _work.GetRepository<Grade>();
|
||||
|
||||
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
var grades = await repository.GetPagedListAsync(
|
||||
predicate: g => g.GradeName.Contains(query.Search),
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var gradeDtosFiltered = _mapper.Map<IEnumerable<GradeDto>>(grades);
|
||||
return new ApiResponse(true, gradeDtosFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
var grades = await repository.GetPagedListAsync(
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var gradeDtos = _mapper.Map<IEnumerable<GradeDto>>(grades);
|
||||
return new ApiResponse(true, gradeDtos);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取所有年级时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var grade = await _work.GetRepository<Grade>().GetFirstOrDefaultAsync(
|
||||
predicate: g => g.Id == id,
|
||||
include: i => i.Include(g => g.School));
|
||||
|
||||
if (grade == null)
|
||||
{
|
||||
return new ApiResponse("年级未找到。");
|
||||
}
|
||||
|
||||
var gradeDto = _mapper.Map<GradeDto>(grade);
|
||||
return new ApiResponse(true, gradeDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取年级时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AddAsync(GradeDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否已存在相同学校下的同名年级
|
||||
var existingGrade = await _work.GetRepository<Grade>().GetFirstOrDefaultAsync(
|
||||
predicate: g => g.SchoolId == model.SchoolId && g.GradeName == model.GradeName && g.GradeLevel == model.GradeLevel);
|
||||
|
||||
if (existingGrade != null)
|
||||
{
|
||||
return new ApiResponse($"在当前学校下,年级 '{model.GradeName}' 已存在。");
|
||||
}
|
||||
|
||||
var grade = _mapper.Map<Grade>(model);
|
||||
await _work.GetRepository<Grade>().InsertAsync(grade);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, _mapper.Map<GradeDto>(grade));
|
||||
}
|
||||
return new ApiResponse("添加年级失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"添加年级时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UpdateAsync(GradeDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingGrade = await _work.GetRepository<Grade>().GetFirstOrDefaultAsync(
|
||||
predicate: g => g.Id == model.Id);
|
||||
|
||||
if (existingGrade == null)
|
||||
{
|
||||
return new ApiResponse("年级未找到。");
|
||||
}
|
||||
|
||||
_mapper.Map(model, existingGrade);
|
||||
_work.GetRepository<Grade>().Update(existingGrade);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, _mapper.Map<GradeDto>(existingGrade));
|
||||
}
|
||||
return new ApiResponse("更新年级失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"更新年级时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingGrade = await _work.GetRepository<Grade>().GetFirstOrDefaultAsync(
|
||||
predicate: g => g.Id == id);
|
||||
|
||||
if (existingGrade == null)
|
||||
{
|
||||
return new ApiResponse("年级未找到。");
|
||||
}
|
||||
|
||||
_work.GetRepository<Grade>().Delete(existingGrade);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, "年级删除成功。");
|
||||
}
|
||||
return new ApiResponse("删除年级失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"删除年级时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
TechHelper.Server/Services/Grade/IGradeService.cs
Normal file
10
TechHelper.Server/Services/Grade/IGradeService.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Entities.DTO;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public interface IGradeService : IBaseService<GradeDto, Guid>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace TechHelper.Services
|
||||
using Entities.DTO;
|
||||
|
||||
namespace TechHelper.Services
|
||||
{
|
||||
public interface IBaseService<T, TId>
|
||||
{
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Entities.DTO.Class;
|
||||
using System.Net;
|
||||
|
||||
namespace TechHelper.Services
|
||||
{
|
||||
public interface IClassService : IBaseService<ClassDto, Guid>
|
||||
{
|
||||
public Task<ApiResponse> UserRegister(UserRegistrationToClassDto user);
|
||||
public Task<ApiResponse> UserRegister(RegisterUserToClassDto user);
|
||||
public Task<ApiResponse> GetUserClass(Guid user); // List<Class>
|
||||
public Task<ApiResponse> GetUserClassRole(Guid user); // List<UserClassRoleDto>
|
||||
public Task<ApiResponse> GetClassStudents(ClassDto classDto); // Class
|
||||
public Task<ApiResponse> GetGradeClasses(byte Grade); // Class
|
||||
Task GetClassStudents(byte grade, byte id);
|
||||
public Task GetClassStudents(byte Grade, byte Class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
using Entities.DTO;
|
||||
|
||||
namespace TechHelper.Services
|
||||
{
|
||||
public interface IUserRegistrationService
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册新用户,并根据角色关联到班级。
|
||||
/// </summary>
|
||||
/// <param name="registrationDto">用户注册数据。</param>
|
||||
/// <returns>操作结果。</returns>
|
||||
Task<ApiResponse> RegisterNewUserAsync(UserForRegistrationDto registrationDto);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Entities.Contracts;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
public interface IUserSerivces : IBaseService<User, Guid>
|
||||
{
|
||||
Task<ApiResponse> GetStudentDetailInfo(Guid userId);
|
||||
Task<ApiResponse> RestoreUserRoleInformation(User user);
|
||||
Task<ApiResponse> VerifyUserInformation(Guid userId);
|
||||
}
|
||||
}
|
||||
10
TechHelper.Server/Services/KeyPoint/IKeyPointService.cs
Normal file
10
TechHelper.Server/Services/KeyPoint/IKeyPointService.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public interface IKeyPointService : IBaseService<KeyPointDto, Guid>
|
||||
{
|
||||
Task<ApiResponse> GetKeyPointsByLessonIdAsync(Guid lessonId);
|
||||
}
|
||||
}
|
||||
170
TechHelper.Server/Services/KeyPoint/KeyPointService.cs
Normal file
170
TechHelper.Server/Services/KeyPoint/KeyPointService.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public class KeyPointService : IKeyPointService
|
||||
{
|
||||
private readonly IUnitOfWork _work;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public KeyPointService(IUnitOfWork work, IMapper mapper)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var repository = _work.GetRepository<KeyPoint>();
|
||||
|
||||
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
var keyPoints = await repository.GetPagedListAsync(
|
||||
predicate: k => k.Key.Contains(query.Search),
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var keyPointDtosFiltered = _mapper.Map<IEnumerable<KeyPointDto>>(keyPoints);
|
||||
return new ApiResponse(true, keyPointDtosFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
var keyPoints = await repository.GetPagedListAsync(
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var keyPointDtos = _mapper.Map<IEnumerable<KeyPointDto>>(keyPoints);
|
||||
return new ApiResponse(true, keyPointDtos);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取所有知识点时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var keyPoint = await _work.GetRepository<KeyPoint>().GetFirstOrDefaultAsync(
|
||||
predicate: k => k.Id == id);
|
||||
|
||||
if (keyPoint == null)
|
||||
{
|
||||
return new ApiResponse("知识点未找到。");
|
||||
}
|
||||
|
||||
var keyPointDto = _mapper.Map<KeyPointResponseDto>(keyPoint);
|
||||
return new ApiResponse(true, keyPointDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取知识点时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AddAsync(KeyPointDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingKeyPoint = await _work.GetRepository<KeyPoint>().GetFirstOrDefaultAsync(
|
||||
predicate: k => k.Key == model.Key && k.LessonID == model.LessonId);
|
||||
|
||||
if (existingKeyPoint != null)
|
||||
{
|
||||
return new ApiResponse($"知识点 '{model.Key}' 在此课程中已存在。");
|
||||
}
|
||||
|
||||
var keyPoint = _mapper.Map<KeyPoint>(model);
|
||||
await _work.GetRepository<KeyPoint>().InsertAsync(keyPoint);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, _mapper.Map<KeyPointDto>(keyPoint));
|
||||
}
|
||||
return new ApiResponse("添加知识点失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"添加知识点时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UpdateAsync(KeyPointDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingKeyPoint = await _work.GetRepository<KeyPoint>().GetFirstOrDefaultAsync(
|
||||
predicate: k => k.Id == model.Id);
|
||||
|
||||
if (existingKeyPoint == null)
|
||||
{
|
||||
return new ApiResponse("知识点未找到。");
|
||||
}
|
||||
|
||||
_mapper.Map(model, existingKeyPoint);
|
||||
_work.GetRepository<KeyPoint>().Update(existingKeyPoint);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, _mapper.Map<KeyPointDto>(existingKeyPoint));
|
||||
}
|
||||
return new ApiResponse("更新知识点失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"更新知识点时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingKeyPoint = await _work.GetRepository<KeyPoint>().GetFirstOrDefaultAsync(
|
||||
predicate: k => k.Id == id);
|
||||
|
||||
if (existingKeyPoint == null)
|
||||
{
|
||||
return new ApiResponse("知识点未找到。");
|
||||
}
|
||||
|
||||
_work.GetRepository<KeyPoint>().Delete(existingKeyPoint);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, "知识点删除成功。");
|
||||
}
|
||||
return new ApiResponse("删除知识点失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"删除知识点时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetKeyPointsByLessonIdAsync(Guid lessonId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var keyPoints = await _work.GetRepository<KeyPoint>().GetAllAsync(
|
||||
predicate: k => k.LessonID == lessonId);
|
||||
|
||||
var keyPointDtos = _mapper.Map<IEnumerable<KeyPointResponseDto>>(keyPoints);
|
||||
return new ApiResponse(true, keyPointDtos);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"根据课程ID获取知识点时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
TechHelper.Server/Services/Lesson/ILessonService.cs
Normal file
11
TechHelper.Server/Services/Lesson/ILessonService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Entities.DTO;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
/// <summary>
|
||||
/// Lesson服务接口
|
||||
/// </summary>
|
||||
public interface ILessonService : IBaseService<LessonDto, Guid>
|
||||
{
|
||||
}
|
||||
}
|
||||
167
TechHelper.Server/Services/Lesson/LessonService.cs
Normal file
167
TechHelper.Server/Services/Lesson/LessonService.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using SharedDATA.Api;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
/// <summary>
|
||||
/// Lesson服务实现类
|
||||
/// </summary>
|
||||
public class LessonService : ILessonService
|
||||
{
|
||||
private readonly IUnitOfWork _work;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public LessonService(IUnitOfWork work, IMapper mapper)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var repository = _work.GetRepository<Lesson>();
|
||||
|
||||
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
var lessons = await repository.GetPagedListAsync(
|
||||
predicate: l => l.Title.Contains(query.Search),
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var lessonDtosFiltered = _mapper.Map<IEnumerable<LessonResponseDto>>(lessons.Items);
|
||||
return new ApiResponse(true, lessonDtosFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
var lessons = await repository.GetPagedListAsync(
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var lessonDtos = _mapper.Map<IEnumerable<LessonResponseDto>>(lessons.Items);
|
||||
return new ApiResponse(true, lessonDtos);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取所有课程时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var lesson = await _work.GetRepository<Lesson>().GetFirstOrDefaultAsync(
|
||||
predicate: l => l.Id == id);
|
||||
|
||||
if (lesson == null)
|
||||
{
|
||||
return new ApiResponse("课程未找到。");
|
||||
}
|
||||
|
||||
var lessonDto = _mapper.Map<LessonResponseDto>(lesson);
|
||||
return new ApiResponse(true, lessonDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取课程时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AddAsync(LessonDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否已存在同名课程
|
||||
var existingLesson = await _work.GetRepository<Lesson>().GetFirstOrDefaultAsync(
|
||||
predicate: l => l.Title == model.Title && l.TextbookID == model.TextBookId);
|
||||
|
||||
if (existingLesson != null)
|
||||
{
|
||||
return new ApiResponse($"课程 '{model.Title}' 在该教材中已存在。");
|
||||
}
|
||||
|
||||
var lesson = _mapper.Map<Lesson>(model);
|
||||
|
||||
await _work.GetRepository<Lesson>().InsertAsync(lesson);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, lesson.Id);
|
||||
}
|
||||
return new ApiResponse("添加课程失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"添加课程时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UpdateAsync(LessonDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingLesson = await _work.GetRepository<Lesson>().GetFirstOrDefaultAsync(
|
||||
predicate: l => l.Id == model.Id);
|
||||
|
||||
if (existingLesson == null)
|
||||
{
|
||||
return new ApiResponse("课程未找到。");
|
||||
}
|
||||
|
||||
// 检查是否要修改为已存在的课程名称(排除当前课程)
|
||||
var lessonWithSameName = await _work.GetRepository<Lesson>().GetFirstOrDefaultAsync(
|
||||
predicate: l => l.Title == model.Title && l.TextbookID == model.TextBookId && l.Id != model.Id);
|
||||
|
||||
if (lessonWithSameName != null)
|
||||
{
|
||||
return new ApiResponse($"课程名称 '{model.Title}' 在该教材中已被其他课程使用。");
|
||||
}
|
||||
|
||||
_mapper.Map(model, existingLesson);
|
||||
_work.GetRepository<Lesson>().Update(existingLesson);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
var lessonDto = _mapper.Map<LessonResponseDto>(existingLesson);
|
||||
return new ApiResponse(true, lessonDto);
|
||||
}
|
||||
return new ApiResponse("更新课程失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"更新课程时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingLesson = await _work.GetRepository<Lesson>().GetFirstOrDefaultAsync(
|
||||
predicate: l => l.Id == id);
|
||||
|
||||
if (existingLesson == null)
|
||||
{
|
||||
return new ApiResponse("课程未找到。");
|
||||
}
|
||||
|
||||
_work.GetRepository<Lesson>().Delete(existingLesson);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, "课程删除成功。");
|
||||
}
|
||||
return new ApiResponse("删除课程失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"删除课程时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
{
|
||||
public class QueryParameter
|
||||
{
|
||||
public int PageIndex { get; set; }
|
||||
public int PageSize { get; set; }
|
||||
public string Search { get; set; }
|
||||
public int PageIndex { get; set; } = 0;
|
||||
public int PageSize { get; set; } = 10;
|
||||
public string? Search { get; set; }
|
||||
}
|
||||
}
|
||||
11
TechHelper.Server/Services/Question/IQuestionService.cs
Normal file
11
TechHelper.Server/Services/Question/IQuestionService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public interface IQuestionService : IBaseService<QuestionDto, Guid>
|
||||
{
|
||||
Task<ApiResponse> FindByTitle(string title);
|
||||
Task<ApiResponse> CheckTitlesExistence(IEnumerable<string> titles);
|
||||
}
|
||||
}
|
||||
302
TechHelper.Server/Services/Question/QuestionService.cs
Normal file
302
TechHelper.Server/Services/Question/QuestionService.cs
Normal file
@@ -0,0 +1,302 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using SharedDATA.Api;
|
||||
using System.Linq.Expressions;
|
||||
using System.Linq;
|
||||
using Entities.DTO;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public class QuestionService : IQuestionService
|
||||
{
|
||||
private readonly IUnitOfWork _work;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IExamService _examService;
|
||||
|
||||
public QuestionService(IUnitOfWork work, IMapper mapper, IExamService examService)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
_examService = examService;
|
||||
}
|
||||
|
||||
#region CRUD Operations
|
||||
|
||||
/// <summary>
|
||||
/// 创建新题目
|
||||
/// </summary>
|
||||
/// <param name="model">题目DTO</param>
|
||||
/// <returns>API响应结果</returns>
|
||||
public async Task<ApiResponse> AddAsync(QuestionDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 业务逻辑校验:检查题目是否已存在
|
||||
var existingQuestion = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
|
||||
predicate: q => q.Title == model.Title && !q.IsDeleted
|
||||
);
|
||||
|
||||
if (existingQuestion != null)
|
||||
{
|
||||
return ApiResponse.Error($"题目 '{model.Title}' 已存在,请勿重复添加。");
|
||||
}
|
||||
|
||||
var newQuestion = _mapper.Map<Question>(model);
|
||||
|
||||
// 插入数据
|
||||
await _work.GetRepository<Question>().InsertAsync(newQuestion);
|
||||
await _work.SaveChangesAsync();
|
||||
|
||||
return ApiResponse.Success("题目添加成功。", newQuestion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"添加题目失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据ID获取题目
|
||||
/// </summary>
|
||||
/// <param name="id">题目ID</param>
|
||||
/// <returns>API响应结果</returns>
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var question = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
|
||||
predicate: q => q.Id == id && !q.IsDeleted
|
||||
);
|
||||
|
||||
if (question == null)
|
||||
{
|
||||
return ApiResponse.Error($"找不到 ID 为 {id} 的题目。");
|
||||
}
|
||||
|
||||
return ApiResponse.Success(result: question);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取题目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有题目(支持分页和搜索)
|
||||
/// </summary>
|
||||
/// <param name="query">查询参数</param>
|
||||
/// <returns>API响应结果</returns>
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var repository = _work.GetRepository<Question>();
|
||||
|
||||
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
var questions = await repository.GetPagedListAsync(
|
||||
predicate: q => q.Title.Contains(query.Search) && !q.IsDeleted,
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var questionDtosFiltered = _mapper.Map<IEnumerable<QuestionDto>>(questions.Items);
|
||||
return new ApiResponse(true, questionDtosFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
var questions = await repository.GetPagedListAsync(
|
||||
predicate: q => !q.IsDeleted,
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var questionDtos = _mapper.Map<IEnumerable<QuestionDto>>(questions.Items);
|
||||
return new ApiResponse(true, questionDtos);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取所有题目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新题目信息
|
||||
/// </summary>
|
||||
/// <param name="model">题目DTO</param>
|
||||
/// <returns>API响应结果</returns>
|
||||
public async Task<ApiResponse> UpdateAsync(QuestionDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查题目是否存在
|
||||
var existingQuestion = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
|
||||
predicate: q => q.Id == model.Id && !q.IsDeleted
|
||||
);
|
||||
|
||||
if (existingQuestion == null)
|
||||
{
|
||||
return ApiResponse.Error($"找不到 ID 为 {model.Id} 的题目,无法更新。");
|
||||
}
|
||||
|
||||
// 检查题目文本是否与其他题目重复
|
||||
var duplicateCheck = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
|
||||
predicate: q => q.Id != model.Id && q.Title == model.Title && !q.IsDeleted
|
||||
);
|
||||
|
||||
if (duplicateCheck != null)
|
||||
{
|
||||
return ApiResponse.Error($"题目文本 '{model.Title}' 已被其他题目占用,请修改。");
|
||||
}
|
||||
|
||||
// 使用mapper更新实体属性,保留系统字段
|
||||
_mapper.Map(model, existingQuestion);
|
||||
existingQuestion.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
// 更新数据
|
||||
_work.GetRepository<Question>().Update(existingQuestion);
|
||||
await _work.SaveChangesAsync();
|
||||
|
||||
return ApiResponse.Success("题目更新成功。", existingQuestion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"更新题目失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除题目(软删除)
|
||||
/// </summary>
|
||||
/// <param name="id">题目ID</param>
|
||||
/// <returns>API响应结果</returns>
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var questionToDelete = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
|
||||
predicate: q => q.Id == id && !q.IsDeleted
|
||||
);
|
||||
|
||||
if (questionToDelete == null)
|
||||
{
|
||||
return ApiResponse.Error($"找不到 ID 为 {id} 的题目,或者该题目已被删除。");
|
||||
}
|
||||
|
||||
// 软删除
|
||||
questionToDelete.IsDeleted = true;
|
||||
questionToDelete.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
_work.GetRepository<Question>().Update(questionToDelete);
|
||||
await _work.SaveChangesAsync();
|
||||
|
||||
return ApiResponse.Success($"ID 为 {id} 的题目已成功删除 (软删除)。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"删除题目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Business Logic Methods
|
||||
|
||||
/// <summary>
|
||||
/// 根据标题查找题目
|
||||
/// </summary>
|
||||
/// <param name="title">题目标题</param>
|
||||
/// <returns>API响应结果</returns>
|
||||
public async Task<ApiResponse> FindByTitle(string title)
|
||||
{
|
||||
try
|
||||
{
|
||||
var question = await _work.GetRepository<Question>().GetFirstOrDefaultAsync(
|
||||
predicate: q => q.Title == title && !q.IsDeleted
|
||||
);
|
||||
|
||||
if (question == null)
|
||||
{
|
||||
return ApiResponse.Error($"未找到题目 '{title}'。");
|
||||
}
|
||||
|
||||
return ApiResponse.Success(result: question);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"查找题目时出现问题: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量检查题目标题是否存在
|
||||
/// </summary>
|
||||
/// <param name="titles">题目标题集合</param>
|
||||
/// <returns>API响应结果</returns>
|
||||
public async Task<ApiResponse> CheckTitlesExistence(IEnumerable<string> titles)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (titles == null || !titles.Any())
|
||||
{
|
||||
return ApiResponse.Success("未指定查询的题目文本,返回空结果。", new Dictionary<string, bool>());
|
||||
}
|
||||
|
||||
var distinctTitles = titles.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
|
||||
|
||||
var existingQuestions = await _work.GetRepository<Question>().GetAllAsync(
|
||||
predicate: q => distinctTitles.Contains(q.Title) && !q.IsDeleted
|
||||
);
|
||||
|
||||
var existingQuestionTexts = new HashSet<string>(
|
||||
existingQuestions.Select(q => q.Title),
|
||||
StringComparer.OrdinalIgnoreCase
|
||||
);
|
||||
|
||||
var resultDictionary = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var title in titles)
|
||||
{
|
||||
resultDictionary[title] = existingQuestionTexts.Contains(title);
|
||||
}
|
||||
|
||||
return ApiResponse.Success(result: resultDictionary);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"批量查找题目存在性时出现问题: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表达式构建器扩展类
|
||||
/// </summary>
|
||||
public static class PredicateBuilder
|
||||
{
|
||||
public static Expression<Func<T, bool>> And<T>(
|
||||
this Expression<Func<T, bool>> first,
|
||||
Expression<Func<T, bool>> second)
|
||||
{
|
||||
var invokedExpr = Expression.Invoke(second, first.Parameters.Cast<Expression>());
|
||||
return Expression.Lambda<Func<T, bool>>(
|
||||
Expression.AndAlso(first.Body, invokedExpr),
|
||||
first.Parameters
|
||||
);
|
||||
}
|
||||
|
||||
public static Expression<Func<T, bool>> Or<T>(
|
||||
this Expression<Func<T, bool>> first,
|
||||
Expression<Func<T, bool>> second)
|
||||
{
|
||||
var invokedExpr = Expression.Invoke(second, first.Parameters.Cast<Expression>());
|
||||
return Expression.Lambda<Func<T, bool>>(
|
||||
Expression.OrElse(first.Body, invokedExpr),
|
||||
first.Parameters
|
||||
);
|
||||
}
|
||||
|
||||
public static Expression<Func<T, bool>> True<T>() => f => true;
|
||||
public static Expression<Func<T, bool>> False<T>() => f => false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public interface IQuestionTypeService : IBaseService<QuestionTypeDto, Guid>
|
||||
{
|
||||
}
|
||||
}
|
||||
202
TechHelper.Server/Services/QuestionType/QuestionTypeService.cs
Normal file
202
TechHelper.Server/Services/QuestionType/QuestionTypeService.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Services.Beta;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public class QuestionTypeService : IQuestionTypeService
|
||||
{
|
||||
private readonly IUnitOfWork _work;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public QuestionTypeService(IUnitOfWork work, IMapper mapper)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var repository = _work.GetRepository<QuestionType>();
|
||||
|
||||
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
var questionTypes = await repository.GetPagedListAsync(
|
||||
predicate: qt => qt.Name.Contains(query.Search) || qt.Description.Contains(query.Search),
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var questionTypeDtosFiltered = _mapper.Map<IEnumerable<TypeCommonDto>>(questionTypes.Items);
|
||||
return new ApiResponse(true, questionTypeDtosFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
var questionTypes = await repository.GetPagedListAsync(
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex,
|
||||
include: i => i.Include(qt => qt.Subject)
|
||||
);
|
||||
var questionTypeDtos = _mapper.Map<IEnumerable<TypeCommonDto>>(questionTypes.Items);
|
||||
return new ApiResponse(true, questionTypeDtos);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取所有题型时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var questionType = await _work.GetRepository<QuestionType>().GetFirstOrDefaultAsync(
|
||||
predicate: qt => qt.Id == id,
|
||||
include: i => i
|
||||
.Include(qt => qt.Subject)
|
||||
.Include(qt => qt.Questions));
|
||||
|
||||
if (questionType == null)
|
||||
{
|
||||
return new ApiResponse("题型未找到。");
|
||||
}
|
||||
|
||||
var questionTypeDto = _mapper.Map<QuestionTypeResponseDto>(questionType);
|
||||
return new ApiResponse(true, questionTypeDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取题型时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AddAsync(QuestionTypeDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var QuestionTypeExists = await _work.GetRepository<QuestionType>().GetFirstOrDefaultAsync(predicate: qt => qt.Id == model.Id);
|
||||
if (QuestionTypeExists != null)
|
||||
{
|
||||
if (QuestionTypeExists.Name == model.Name && QuestionTypeExists.SubjectId == model.SubjectId)
|
||||
return new ApiResponse("题型已存在。");
|
||||
else
|
||||
return new ApiResponse($"主键已被 '{QuestionTypeExists.Name}' 题型使用。");
|
||||
}
|
||||
// 检查科目是否存在
|
||||
var subjectExists = await _work.GetRepository<Subject>().GetFirstOrDefaultAsync(
|
||||
predicate: s => s.Id == model.SubjectId);
|
||||
|
||||
if (subjectExists == null)
|
||||
{
|
||||
return new ApiResponse("指定的科目不存在。");
|
||||
}
|
||||
|
||||
// 检查是否已存在相同科目下的同名题型
|
||||
var existingQuestionType = await _work.GetRepository<QuestionType>().GetFirstOrDefaultAsync(
|
||||
predicate: qt => qt.SubjectId == model.SubjectId && qt.Name == model.Name);
|
||||
|
||||
if (existingQuestionType != null)
|
||||
{
|
||||
return new ApiResponse($"在当前科目下,题型 '{model.Name}' 已存在。");
|
||||
}
|
||||
|
||||
var questionType = _mapper.Map<QuestionType>(model);
|
||||
await _work.GetRepository<QuestionType>().InsertAsync(questionType);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, questionType.Id);
|
||||
}
|
||||
return new ApiResponse("添加题型失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"添加题型时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UpdateAsync(QuestionTypeDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingQuestionType = await _work.GetRepository<QuestionType>().GetFirstOrDefaultAsync(
|
||||
predicate: qt => qt.Id == model.Id);
|
||||
|
||||
if (existingQuestionType == null)
|
||||
{
|
||||
return new ApiResponse("题型未找到。");
|
||||
}
|
||||
|
||||
// 检查科目是否存在
|
||||
var subjectExists = await _work.GetRepository<Subject>().GetFirstOrDefaultAsync(
|
||||
predicate: s => s.Id == model.SubjectId);
|
||||
|
||||
if (subjectExists == null)
|
||||
{
|
||||
return new ApiResponse("指定的科目不存在。");
|
||||
}
|
||||
|
||||
// 检查是否要修改为已存在的题型名称(排除当前题型)
|
||||
var questionTypeWithSameName = await _work.GetRepository<QuestionType>().GetFirstOrDefaultAsync(
|
||||
predicate: qt => qt.Name == model.Name && qt.Id != model.Id && qt.SubjectId == model.SubjectId);
|
||||
|
||||
if (questionTypeWithSameName != null)
|
||||
{
|
||||
return new ApiResponse($"在当前科目下,题型名称 '{model.Name}' 已被其他题型使用。");
|
||||
}
|
||||
|
||||
_mapper.Map(model, existingQuestionType);
|
||||
_work.GetRepository<QuestionType>().Update(existingQuestionType);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
var questionTypeDto = _mapper.Map<QuestionTypeResponseDto>(existingQuestionType);
|
||||
return new ApiResponse(true, questionTypeDto);
|
||||
}
|
||||
return new ApiResponse("更新题型失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"更新题型时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingQuestionType = await _work.GetRepository<QuestionType>().GetFirstOrDefaultAsync(
|
||||
predicate: qt => qt.Id == id,
|
||||
include: i => i.Include(qt => qt.Questions));
|
||||
|
||||
if (existingQuestionType == null)
|
||||
{
|
||||
return new ApiResponse("题型未找到。");
|
||||
}
|
||||
|
||||
// 检查是否有关联的题目
|
||||
if (existingQuestionType.Questions != null && existingQuestionType.Questions.Any())
|
||||
{
|
||||
return new ApiResponse("无法删除该题型,因为存在关联的题目。");
|
||||
}
|
||||
|
||||
_work.GetRepository<QuestionType>().Delete(existingQuestionType);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, "题型删除成功。");
|
||||
}
|
||||
return new ApiResponse("删除题型失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"删除题型时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
TechHelper.Server/Services/School/ISchoolService.cs
Normal file
9
TechHelper.Server/Services/School/ISchoolService.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Entities.DTO;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public interface ISchoolService : IBaseService<SchoolDto, Guid>
|
||||
{
|
||||
Task<ApiResponse> GetSchoolByNameAsync(string schoolName);
|
||||
}
|
||||
}
|
||||
179
TechHelper.Server/Services/School/SchoolService.cs
Normal file
179
TechHelper.Server/Services/School/SchoolService.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public class SchoolService : ISchoolService
|
||||
{
|
||||
private readonly IUnitOfWork _work;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public SchoolService(IUnitOfWork work, IMapper mapper)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var repository = _work.GetRepository<School>();
|
||||
|
||||
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
var schools = await repository.GetPagedListAsync(
|
||||
predicate: s => s.SchoolName.Contains(query.Search),
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var schoolDtosFiltered = _mapper.Map<IEnumerable<SchoolDto>>(schools.Items);
|
||||
return new ApiResponse(true, schoolDtosFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
var schools = await repository.GetPagedListAsync(
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var schoolDtos = _mapper.Map<IEnumerable<SchoolDto>>(schools.Items);
|
||||
return new ApiResponse(true, schoolDtos);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取所有学校时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var school = await _work.GetRepository<School>().GetFirstOrDefaultAsync(
|
||||
predicate: s => s.Id == id,
|
||||
include: i
|
||||
=> i.Include(s => s.Grades));
|
||||
|
||||
if (school == null)
|
||||
{
|
||||
return new ApiResponse("学校未找到。");
|
||||
}
|
||||
|
||||
var schoolDto = _mapper.Map<SchoolResponseDto>(school);
|
||||
return new ApiResponse(true, schoolDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取学校时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetSchoolByNameAsync(string schoolName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var school = await _work.GetRepository<School>().GetFirstOrDefaultAsync(
|
||||
predicate: s => s.SchoolName == schoolName,
|
||||
include: i
|
||||
=>i.Include(s => s.Grades));
|
||||
|
||||
if (school == null)
|
||||
{
|
||||
return new ApiResponse("学校未找到。");
|
||||
}
|
||||
|
||||
var schoolDto = _mapper.Map<SchoolResponseDto>(school);
|
||||
return new ApiResponse(true, schoolDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"根据名称获取学校时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AddAsync(SchoolDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否已存在同名学校
|
||||
var existingSchool = await _work.GetRepository<School>().GetFirstOrDefaultAsync(
|
||||
predicate: s => s.SchoolName == model.SchoolName);
|
||||
|
||||
if (existingSchool != null)
|
||||
{
|
||||
return new ApiResponse($"学校 '{model.SchoolName}' 已存在。");
|
||||
}
|
||||
|
||||
var school = _mapper.Map<School>(model);
|
||||
await _work.GetRepository<School>().InsertAsync(school);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, _mapper.Map<SchoolDto>(school));
|
||||
}
|
||||
return new ApiResponse("添加学校失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"添加学校时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UpdateAsync(SchoolDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingSchool = await _work.GetRepository<School>().GetFirstOrDefaultAsync(
|
||||
predicate: s => s.Id == model.Id);
|
||||
|
||||
if (existingSchool == null)
|
||||
{
|
||||
return new ApiResponse("学校未找到。");
|
||||
}
|
||||
|
||||
_mapper.Map(model, existingSchool);
|
||||
_work.GetRepository<School>().Update(existingSchool);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, _mapper.Map<SchoolDto>(existingSchool));
|
||||
}
|
||||
return new ApiResponse("更新学校失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"更新学校时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingSchool = await _work.GetRepository<School>().GetFirstOrDefaultAsync(
|
||||
predicate: s => s.Id == id);
|
||||
|
||||
if (existingSchool == null)
|
||||
{
|
||||
return new ApiResponse("学校未找到。");
|
||||
}
|
||||
|
||||
_work.GetRepository<School>().Delete(existingSchool);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, "学校删除成功。");
|
||||
}
|
||||
return new ApiResponse("删除学校失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"删除学校时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ namespace TechHelper.Server.Services
|
||||
// 获取submission基本信息
|
||||
var submission = await _unitOfWork.GetRepository<Submission>()
|
||||
.GetAll(s => s.Id == submissionId)
|
||||
.Include(s => s.Assignment)
|
||||
.Include(s => s.Exam)
|
||||
.ThenInclude(a => a.Creator)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace TechHelper.Server.Services
|
||||
return ApiResponse.Error("未找到指定的提交记录");
|
||||
}
|
||||
|
||||
var assignment = await examService.GetAsync(submission.AssignmentId);
|
||||
var assignment = await examService.GetAsync(submission.ExamId);
|
||||
if (assignment == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到指定的作业");
|
||||
@@ -51,7 +51,7 @@ namespace TechHelper.Server.Services
|
||||
// 获取所有提交详情
|
||||
var submissionDetails = await _unitOfWork.GetRepository<SubmissionDetail>()
|
||||
.GetAll(sd => sd.SubmissionId == submissionId)
|
||||
.Include(sd => sd.AssignmentQuestion)
|
||||
.Include(sd => sd.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question)
|
||||
.ThenInclude(q => q.Lesson)
|
||||
.ThenInclude(q => q.KeyPoints)
|
||||
@@ -59,7 +59,7 @@ namespace TechHelper.Server.Services
|
||||
|
||||
// 获取同作业的所有提交用于排名和成绩分布
|
||||
var allSubmissions = await _unitOfWork.GetRepository<Submission>()
|
||||
.GetAll(s => s.AssignmentId == submission.AssignmentId)
|
||||
.GetAll(s => s.ExamId == submission.ExamId)
|
||||
.ToListAsync();
|
||||
|
||||
// 映射基本信息
|
||||
@@ -67,11 +67,11 @@ namespace TechHelper.Server.Services
|
||||
result.Assignment = assignment.Result as AssignmentDto ?? new AssignmentDto();
|
||||
|
||||
var errorQuestion = submissionDetails
|
||||
.Where(sd => sd.IsCorrect == false && sd.AssignmentQuestion?.StructType == AssignmentStructType.Question && sd.AssignmentQuestion?.Question != null)
|
||||
.Where(sd => sd.IsCorrect == false && sd.ExamQuestion?.StructType == AssignmentStructType.Question && sd.ExamQuestion?.Question != null)
|
||||
.ToList();
|
||||
|
||||
// 计算基础统计
|
||||
result.TotalQuestions = submissionDetails.Select(x => x.AssignmentQuestion.StructType == AssignmentStructType.Question && x.AssignmentQuestion?.Question != null).Count();
|
||||
result.TotalQuestions = submissionDetails.Select(x => x.ExamQuestion.StructType == AssignmentStructType.Question && x.ExamQuestion?.Question != null).Count();
|
||||
result.ErrorCount = errorQuestion.Count;
|
||||
result.CorrectCount = result.TotalQuestions - result.ErrorCount;
|
||||
result.AccuracyRate = result.TotalQuestions > 0 ?
|
||||
@@ -79,12 +79,12 @@ namespace TechHelper.Server.Services
|
||||
|
||||
// 计算错误类型分布 - 只获取题目类型的错误
|
||||
result.ErrorTypeDistribution = errorQuestion
|
||||
.GroupBy(sd => sd.AssignmentQuestion.Question.Type.ToString())
|
||||
.GroupBy(sd => sd.ExamQuestion.Question.Type.ToString())
|
||||
.ToDictionary(g => g.Key, g => g.Count()); ;
|
||||
|
||||
// 计算错误类型成绩分布 - 只获取题目类型的错误
|
||||
result.ErrorTypeScoreDistribution = errorQuestion
|
||||
.GroupBy(sd => sd.AssignmentQuestion.Question.Type.ToString())
|
||||
.GroupBy(sd => sd.ExamQuestion.Question.Type.ToString())
|
||||
.ToDictionary(g => g.Key, g => g.Sum(sd => sd.PointsAwarded ?? 0));
|
||||
|
||||
// 计算成绩排名
|
||||
@@ -101,14 +101,14 @@ namespace TechHelper.Server.Services
|
||||
|
||||
// 计算课文错误分布
|
||||
result.LessonErrorDistribution = errorQuestion
|
||||
.Where(eq => eq.AssignmentQuestion.Question.Lesson != null)
|
||||
.GroupBy(sd => sd.AssignmentQuestion.Question.Lesson.Title)
|
||||
.Where(eq => eq.ExamQuestion.Question.Lesson != null)
|
||||
.GroupBy(sd => sd.ExamQuestion.Question.Lesson.Title)
|
||||
.ToDictionary(g => g.Key, g => g.Count());
|
||||
|
||||
// 计算关键点错误分布
|
||||
result.KeyPointErrorDistribution = errorQuestion
|
||||
.Where(eq => eq.AssignmentQuestion.Question.Lesson != null)
|
||||
.GroupBy(sd => sd.AssignmentQuestion.Question.KeyPoint.Key)
|
||||
.Where(eq => eq.ExamQuestion.Question.Lesson != null)
|
||||
.GroupBy(sd => sd.ExamQuestion.Question.KeyPoint.Key)
|
||||
.ToDictionary(g => g.Key, g => g.Count());
|
||||
|
||||
return ApiResponse.Success(result: result);
|
||||
@@ -126,9 +126,9 @@ namespace TechHelper.Server.Services
|
||||
|
||||
public void SetBCorrect(AssignmentQuestionDto assignmentQuestion, List<SubmissionDetail> submissionDetails)
|
||||
{
|
||||
var sd = submissionDetails.FirstOrDefault(x => x.AssignmentQuestionId == assignmentQuestion.Id);
|
||||
var sd = submissionDetails.FirstOrDefault(x => x.ExamQuestionId == assignmentQuestion.Id);
|
||||
if (sd != null)
|
||||
assignmentQuestion.BCorrect = sd.AssignmentQuestion.BCorrect;
|
||||
assignmentQuestion.BCorrect = sd.ExamQuestion.BCorrect;
|
||||
else
|
||||
assignmentQuestion.BCorrect = false;
|
||||
|
||||
|
||||
@@ -15,14 +15,14 @@ namespace TechHelper.Server.Services
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IRepository<Submission> _submissionRepository;
|
||||
private readonly IRepository<Assignment> _assignmentRepository;
|
||||
private readonly IRepository<Exam> _assignmentRepository;
|
||||
private readonly IRepository<User> _userRepository;
|
||||
|
||||
public StudentSubmissionService(
|
||||
IUnitOfWork unitOfWork,
|
||||
IMapper mapper,
|
||||
IRepository<Submission> submissionRepository,
|
||||
IRepository<Assignment> assignmentRepository,
|
||||
IRepository<Exam> assignmentRepository,
|
||||
IRepository<User> userRepository)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
@@ -38,7 +38,7 @@ namespace TechHelper.Server.Services
|
||||
{
|
||||
var submissions = await _submissionRepository
|
||||
.GetAll(s => s.StudentId == studentId)
|
||||
.Include(s => s.Assignment)
|
||||
.Include(s => s.Exam)
|
||||
.ThenInclude(a => a.Creator)
|
||||
.OrderByDescending(s => s.SubmissionTime)
|
||||
.ToListAsync();
|
||||
@@ -50,12 +50,12 @@ namespace TechHelper.Server.Services
|
||||
var summary = new StudentSubmissionSummaryDto
|
||||
{
|
||||
Id = submission.Id,
|
||||
AssignmentName = submission.Assignment?.Title ?? "未知作业",
|
||||
AssignmentName = submission.Exam?.Title ?? "未知作业",
|
||||
ErrorCount = await CalculateErrorCountAsync(submission.Id),
|
||||
CreatedDate = submission.SubmissionTime,
|
||||
Score = (int)submission.OverallGrade,
|
||||
TotalQuestions = submission.Assignment?.TotalQuestions ?? 0,
|
||||
StudentName = submission.Assignment?.Creator?.UserName ?? "未知老师",
|
||||
TotalQuestions = submission.Exam?.TotalQuestions ?? 0,
|
||||
StudentName = submission.Exam?.Creator?.UserName ?? "未知老师",
|
||||
Status = submission.Status.ToString()
|
||||
};
|
||||
result.Add(summary);
|
||||
@@ -79,7 +79,7 @@ namespace TechHelper.Server.Services
|
||||
|
||||
var submissions = await _submissionRepository
|
||||
.GetAll(s => s.StudentId == studentId)
|
||||
.Include(s => s.Assignment)
|
||||
.Include(s => s.Exam)
|
||||
.ThenInclude(a => a.Creator)
|
||||
.OrderByDescending(s => s.SubmissionTime)
|
||||
.Skip((pageNumber - 1) * pageSize)
|
||||
@@ -93,12 +93,12 @@ namespace TechHelper.Server.Services
|
||||
var summary = new StudentSubmissionSummaryDto
|
||||
{
|
||||
Id = submission.Id,
|
||||
AssignmentName = submission.Assignment?.Title ?? "未知作业",
|
||||
AssignmentName = submission.Exam?.Title ?? "未知作业",
|
||||
ErrorCount = await CalculateErrorCountAsync(submission.Id),
|
||||
CreatedDate = submission.SubmissionTime,
|
||||
Score = submission.OverallGrade,
|
||||
TotalQuestions = submission.Assignment?.TotalQuestions ?? 0,
|
||||
StudentName = submission.Assignment?.Creator?.UserName ?? "未知老师",
|
||||
TotalQuestions = submission.Exam?.TotalQuestions ?? 0,
|
||||
StudentName = submission.Exam?.Creator?.UserName ?? "未知老师",
|
||||
Status = submission.Status.ToString()
|
||||
};
|
||||
result.Add(summary);
|
||||
|
||||
9
TechHelper.Server/Services/Subject/ISubjectService.cs
Normal file
9
TechHelper.Server/Services/Subject/ISubjectService.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public interface ISubjectService : IBaseService<SubjectDto, Guid>
|
||||
{
|
||||
}
|
||||
}
|
||||
170
TechHelper.Server/Services/Subject/SubjectService.cs
Normal file
170
TechHelper.Server/Services/Subject/SubjectService.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Services.Beta;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public class SubjectService : ISubjectService
|
||||
{
|
||||
private readonly IUnitOfWork _work;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public SubjectService(IUnitOfWork work, IMapper mapper)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var repository = _work.GetRepository<Subject>();
|
||||
|
||||
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
var subjects = await repository.GetPagedListAsync(
|
||||
predicate: s => s.Name.Contains(query.Search),
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var subjectDtosFiltered = _mapper.Map<IEnumerable<TypeCommonDto>>(subjects.Items);
|
||||
return new ApiResponse(true, subjectDtosFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
var subjects = await repository.GetPagedListAsync(
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var subjectDtos = _mapper.Map<IEnumerable<TypeCommonDto>>(subjects.Items);
|
||||
return new ApiResponse(true, subjectDtos);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取所有科目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var subject = await _work.GetRepository<Subject>().GetFirstOrDefaultAsync(
|
||||
predicate: s => s.Id == id,
|
||||
include: i => i
|
||||
.Include(s => s.QuestionTypes)
|
||||
.Include(s => s.Questions)
|
||||
.Include(s => s.SubjectTeachers));
|
||||
|
||||
if (subject == null)
|
||||
{
|
||||
return new ApiResponse("科目未找到。");
|
||||
}
|
||||
|
||||
var subjectDto = _mapper.Map<SubjectResponseDto>(subject);
|
||||
return new ApiResponse(true, subjectDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取科目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AddAsync(SubjectDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否已存在同名科目
|
||||
var existingSubject = await _work.GetRepository<Subject>().GetFirstOrDefaultAsync(
|
||||
predicate: s => s.Name == model.Name);
|
||||
|
||||
if (existingSubject != null)
|
||||
{
|
||||
return new ApiResponse($"科目 '{model.Name}' 已存在。");
|
||||
}
|
||||
|
||||
var subject = _mapper.Map<Subject>(model);
|
||||
|
||||
await _work.GetRepository<Subject>().InsertAsync(subject);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, subject.Id);
|
||||
}
|
||||
return new ApiResponse("添加科目失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"添加科目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UpdateAsync(SubjectDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingSubject = await _work.GetRepository<Subject>().GetFirstOrDefaultAsync(
|
||||
predicate: s => s.Id == model.Id);
|
||||
|
||||
if (existingSubject == null)
|
||||
{
|
||||
return new ApiResponse("科目未找到。");
|
||||
}
|
||||
|
||||
// 检查是否要修改为已存在的科目名称(排除当前科目)
|
||||
var subjectWithSameName = await _work.GetRepository<Subject>().GetFirstOrDefaultAsync(
|
||||
predicate: s => s.Name == model.Name && s.Id != model.Id);
|
||||
|
||||
if (subjectWithSameName != null)
|
||||
{
|
||||
return new ApiResponse($"科目名称 '{model.Name}' 已被其他科目使用。");
|
||||
}
|
||||
|
||||
_mapper.Map(model, existingSubject);
|
||||
_work.GetRepository<Subject>().Update(existingSubject);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
var subjectDto = _mapper.Map<SubjectResponseDto>(existingSubject);
|
||||
return new ApiResponse(true, subjectDto);
|
||||
}
|
||||
return new ApiResponse("更新科目失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"更新科目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingSubject = await _work.GetRepository<Subject>().GetFirstOrDefaultAsync(
|
||||
predicate: s => s.Id == id);
|
||||
|
||||
if (existingSubject == null)
|
||||
{
|
||||
return new ApiResponse("科目未找到。");
|
||||
}
|
||||
|
||||
_work.GetRepository<Subject>().Delete(existingSubject);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, "科目删除成功。");
|
||||
}
|
||||
return new ApiResponse("删除科目失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"删除科目时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
/// <summary>
|
||||
/// 提交详情服务接口(Beta版本)
|
||||
/// 提供提交详情相关的业务逻辑操作
|
||||
/// </summary>
|
||||
public interface ISubmissionDetailService : IBaseService<SubmissionDetailDto, Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取提交详情列表
|
||||
/// </summary>
|
||||
/// <param name="submissionId">提交ID</param>
|
||||
/// <returns>提交详情列表</returns>
|
||||
Task<ApiResponse> GetBySubmissionIdAsync(Guid submissionId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取学生的提交详情
|
||||
/// </summary>
|
||||
/// <param name="studentId">学生ID</param>
|
||||
/// <param name="examId">考试ID</param>
|
||||
/// <returns>提交详情列表</returns>
|
||||
Task<ApiResponse> GetByStudentAndExamAsync(Guid studentId, Guid examId);
|
||||
|
||||
/// <summary>
|
||||
/// 批量创建提交详情
|
||||
/// </summary>
|
||||
/// <param name="submissionId">提交ID</param>
|
||||
/// <param name="details">提交详情列表</param>
|
||||
/// <returns>创建结果</returns>
|
||||
Task<ApiResponse> BatchCreateAsync(Guid submissionId, List<SubmissionDetailDto> details);
|
||||
|
||||
/// <summary>
|
||||
/// 批量更新提交详情
|
||||
/// </summary>
|
||||
/// <param name="details">提交详情列表</param>
|
||||
/// <returns>更新结果</returns>
|
||||
Task<ApiResponse> BatchUpdateAsync(List<SubmissionDetailDto> details);
|
||||
|
||||
/// <summary>
|
||||
/// 更新提交详情评分
|
||||
/// </summary>
|
||||
/// <param name="detailId">提交详情ID</param>
|
||||
/// <param name="points">分数</param>
|
||||
/// <param name="feedback">反馈</param>
|
||||
/// <returns>更新结果</returns>
|
||||
Task<ApiResponse> UpdateScoreAsync(Guid detailId, float? points, string? feedback);
|
||||
|
||||
/// <summary>
|
||||
/// 获取错题详情
|
||||
/// </summary>
|
||||
/// <param name="studentId">学生ID</param>
|
||||
/// <param name="examId">考试ID</param>
|
||||
/// <returns>错题详情列表</returns>
|
||||
Task<ApiResponse> GetErrorDetailsAsync(Guid studentId, Guid examId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取正确题详情
|
||||
/// </summary>
|
||||
/// <param name="studentId">学生ID</param>
|
||||
/// <param name="examId">考试ID</param>
|
||||
/// <returns>正确题详情列表</returns>
|
||||
Task<ApiResponse> GetCorrectDetailsAsync(Guid studentId, Guid examId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取未批改的提交详情
|
||||
/// </summary>
|
||||
/// <param name="teacherId">教师ID</param>
|
||||
/// <returns>未批改的提交详情列表</returns>
|
||||
Task<ApiResponse> GetUngradedDetailsAsync(Guid teacherId);
|
||||
|
||||
/// <summary>
|
||||
/// 批量更新提交详情状态
|
||||
/// </summary>
|
||||
/// <param name="submissionId">提交ID</param>
|
||||
/// <param name="status">状态</param>
|
||||
/// <returns>更新结果</returns>
|
||||
Task<ApiResponse> UpdateStatusAsync(Guid submissionId, SubmissionStatus status);
|
||||
}
|
||||
}
|
||||
86
TechHelper.Server/Services/Submission/ISubmissionService.cs
Normal file
86
TechHelper.Server/Services/Submission/ISubmissionService.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using Entities.DTO;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
/// <summary>
|
||||
/// 提交服务接口(Beta版本)
|
||||
/// 提供提交相关的业务逻辑操作
|
||||
/// </summary>
|
||||
public interface ISubmissionService : IBaseService<SubmissionDto, Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取用户的错题列表
|
||||
/// </summary>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <returns>错题列表</returns>
|
||||
Task<ApiResponse> GetAllErrorQuestionsAsync(Guid userId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定作业的错题列表
|
||||
/// </summary>
|
||||
/// <param name="assignmentId">作业ID</param>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <returns>错题列表</returns>
|
||||
Task<ApiResponse> GetAssignmentErrorQuestionsAsync(Guid assignmentId, Guid userId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取错题类型分布
|
||||
/// </summary>
|
||||
/// <param name="assignmentId">作业ID</param>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <returns>错题类型分布</returns>
|
||||
Task<ApiResponse> GetAssignmentErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有错题类型分布
|
||||
/// </summary>
|
||||
/// <param name="assignmentId">作业ID</param>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <returns>错题类型分布</returns>
|
||||
Task<ApiResponse> GetAllErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取作业中所有学生的错题情况
|
||||
/// </summary>
|
||||
/// <param name="assignmentId">作业ID</param>
|
||||
/// <param name="teacherId">教师ID</param>
|
||||
/// <returns>学生错题情况</returns>
|
||||
Task<ApiResponse> GetAssignmentAllStudentsError(Guid assignmentId, Guid teacherId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取出现错题的学生列表
|
||||
/// </summary>
|
||||
/// <param name="assignmentQuestionId">作业题目ID</param>
|
||||
/// <returns>错题学生列表</returns>
|
||||
Task<ApiResponse> GetQuestionErrorStudents(Guid assignmentQuestionId);
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否已经存在提交记录
|
||||
/// </summary>
|
||||
/// <param name="assignmentId">作业ID</param>
|
||||
/// <param name="studentId">学生ID</param>
|
||||
/// <returns>提交记录数量</returns>
|
||||
Task<byte> IsHasSubmissionAsync(Guid assignmentId, Guid studentId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取学生提交摘要
|
||||
/// </summary>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <returns>学生提交摘要列表</returns>
|
||||
Task<ApiResponse> GetStudentSubmissionSummariesAsync(Guid userId);
|
||||
|
||||
/// <summary>
|
||||
/// 获取学生提交详情
|
||||
/// </summary>
|
||||
/// <param name="submissionId">提交ID</param>
|
||||
/// <returns>学生提交详情</returns>
|
||||
Task<ApiResponse> GetStudentSubmissionDetailAsync(Guid submissionId);
|
||||
|
||||
/// <summary>
|
||||
/// 批改的试卷
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
Task<ApiResponse> GradeExam(SubmissionTeacherUpdateDto model);
|
||||
}
|
||||
}
|
||||
457
TechHelper.Server/Services/Submission/SubmissionDetailService.cs
Normal file
457
TechHelper.Server/Services/Submission/SubmissionDetailService.cs
Normal file
@@ -0,0 +1,457 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using SharedDATA.Context;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
/// <summary>
|
||||
/// 提交详情服务实现(Beta版本)
|
||||
/// 实现提交详情相关的业务逻辑操作
|
||||
/// </summary>
|
||||
public class SubmissionDetailService : ISubmissionDetailService
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IRepository<SubmissionDetail> _submissionDetailRepository;
|
||||
private readonly IRepository<Submission> _submissionRepository;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化提交详情服务
|
||||
/// </summary>
|
||||
/// <param name="mapper">AutoMapper实例</param>
|
||||
/// <param name="unitOfWork">工作单元</param>
|
||||
public SubmissionDetailService(IMapper mapper, IUnitOfWork unitOfWork)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_unitOfWork = unitOfWork;
|
||||
_submissionDetailRepository = _unitOfWork.GetRepository<SubmissionDetail>();
|
||||
_submissionRepository = _unitOfWork.GetRepository<Submission>();
|
||||
}
|
||||
|
||||
#region 基本CRUD操作
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有提交详情
|
||||
/// </summary>
|
||||
/// <param name="query">查询参数</param>
|
||||
/// <returns>提交详情列表</returns>
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var pagedDetails = await _submissionDetailRepository.GetPagedListAsync(
|
||||
pageIndex: query.PageIndex,
|
||||
pageSize: query.PageSize,
|
||||
orderBy: sd => sd.OrderByDescending(sd => sd.CreatedAt),
|
||||
predicate: sd => !sd.IsDeleted,
|
||||
include: i => i.Include(sd => sd.Student)
|
||||
.Include(sd => sd.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var detailDtos = _mapper.Map<List<SubmissionDetailDto>>(pagedDetails.Items);
|
||||
|
||||
return ApiResponse.Success("获取所有提交详情成功。", new PagedList<SubmissionDetailDto>
|
||||
{
|
||||
PageIndex = pagedDetails.PageIndex,
|
||||
PageSize = pagedDetails.PageSize,
|
||||
TotalCount = pagedDetails.TotalCount,
|
||||
TotalPages = pagedDetails.TotalPages,
|
||||
Items = detailDtos
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取所有提交详情失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据ID获取提交详情
|
||||
/// </summary>
|
||||
/// <param name="id">提交详情ID</param>
|
||||
/// <returns>提交详情详情</returns>
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var detail = await _submissionDetailRepository.GetFirstOrDefaultAsync(
|
||||
predicate: sd => sd.Id == id && !sd.IsDeleted,
|
||||
include: i => i.Include(sd => sd.Student)
|
||||
.Include(sd => sd.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
if (detail == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到提交详情。", 404);
|
||||
}
|
||||
|
||||
var detailDto = _mapper.Map<SubmissionDetailDto>(detail);
|
||||
return ApiResponse.Success("获取提交详情成功。", detailDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取提交详情失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建提交详情
|
||||
/// </summary>
|
||||
/// <param name="model">提交详情数据传输对象</param>
|
||||
/// <returns>创建结果</returns>
|
||||
public async Task<ApiResponse> AddAsync(SubmissionDetailDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(await _unitOfWork.GetRepository<SubmissionDetail>().GetFirstOrDefaultAsync(predicate: sd => sd.Id == model.Id ) != null)
|
||||
{
|
||||
return ApiResponse.Error("提交详情已存在。", 400);
|
||||
}
|
||||
|
||||
var detail = _mapper.Map<SubmissionDetail>(model);
|
||||
detail.CreatedAt = DateTime.Now;
|
||||
detail.UpdatedAt = DateTime.Now;
|
||||
detail.IsDeleted = false;
|
||||
|
||||
await _submissionDetailRepository.InsertAsync(detail);
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
|
||||
var result = _mapper.Map<SubmissionDetailDto>(detail);
|
||||
return ApiResponse.Success("创建提交详情成功。", result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"创建提交详情失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新提交详情
|
||||
/// </summary>
|
||||
/// <param name="model">提交详情数据传输对象</param>
|
||||
/// <returns>更新结果</returns>
|
||||
public async Task<ApiResponse> UpdateAsync(SubmissionDetailDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingDetail = await _submissionDetailRepository.GetFirstOrDefaultAsync(predicate: sd => sd.Id == model.Id && !sd.IsDeleted);
|
||||
if (existingDetail == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到要更新的提交详情。", 404);
|
||||
}
|
||||
|
||||
_mapper.Map(model, existingDetail);
|
||||
existingDetail.UpdatedAt = DateTime.Now;
|
||||
_submissionDetailRepository.Update(existingDetail);
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
|
||||
var result = _mapper.Map<SubmissionDetailDto>(existingDetail);
|
||||
return ApiResponse.Success("更新提交详情成功。", result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"更新提交详情失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除提交详情
|
||||
/// </summary>
|
||||
/// <param name="id">提交详情ID</param>
|
||||
/// <returns>删除结果</returns>
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var detail = await _submissionDetailRepository.GetFirstOrDefaultAsync(predicate: sd => sd.Id == id && !sd.IsDeleted);
|
||||
if (detail == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到要删除的提交详情。", 404);
|
||||
}
|
||||
|
||||
detail.IsDeleted = true;
|
||||
_submissionDetailRepository.Update(detail);
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
|
||||
return ApiResponse.Success("删除提交详情成功。", null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"删除提交详情失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 特殊操作
|
||||
|
||||
/// <summary>
|
||||
/// 获取提交详情列表
|
||||
/// </summary>
|
||||
/// <param name="submissionId">提交ID</param>
|
||||
/// <returns>提交详情列表</returns>
|
||||
public async Task<ApiResponse> GetBySubmissionIdAsync(Guid submissionId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var details = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.SubmissionId == submissionId && !sd.IsDeleted,
|
||||
include: i => i.Include(sd => sd.Student)
|
||||
.Include(sd => sd.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var detailDtos = _mapper.Map<List<SubmissionDetailDto>>(details.Items);
|
||||
return ApiResponse.Success("获取提交详情列表成功。", detailDtos);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取提交详情列表失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取学生的提交详情
|
||||
/// </summary>
|
||||
/// <param name="studentId">学生ID</param>
|
||||
/// <param name="examId">考试ID</param>
|
||||
/// <returns>提交详情列表</returns>
|
||||
public async Task<ApiResponse> GetByStudentAndExamAsync(Guid studentId, Guid examId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var details = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.StudentId == studentId &&
|
||||
sd.Submission.ExamId == examId &&
|
||||
!sd.IsDeleted,
|
||||
include: i => i.Include(sd => sd.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var detailDtos = _mapper.Map<List<SubmissionDetailDto>>(details.Items);
|
||||
return ApiResponse.Success("获取学生提交详情成功。", detailDtos);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取学生提交详情失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量创建提交详情
|
||||
/// </summary>
|
||||
/// <param name="submissionId">提交ID</param>
|
||||
/// <param name="details">提交详情列表</param>
|
||||
/// <returns>创建结果</returns>
|
||||
public async Task<ApiResponse> BatchCreateAsync(Guid submissionId, List<SubmissionDetailDto> details)
|
||||
{
|
||||
try
|
||||
{
|
||||
var detailEntities = _mapper.Map<List<SubmissionDetail>>(details);
|
||||
foreach (var detail in detailEntities)
|
||||
{
|
||||
detail.SubmissionId = submissionId;
|
||||
detail.CreatedAt = DateTime.Now;
|
||||
detail.UpdatedAt = DateTime.Now;
|
||||
detail.IsDeleted = false;
|
||||
await _submissionDetailRepository.InsertAsync(detail);
|
||||
}
|
||||
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
var result = _mapper.Map<List<SubmissionDetailDto>>(detailEntities);
|
||||
return ApiResponse.Success("批量创建提交详情成功。", result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"批量创建提交详情失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量更新提交详情
|
||||
/// </summary>
|
||||
/// <param name="details">提交详情列表</param>
|
||||
/// <returns>更新结果</returns>
|
||||
public async Task<ApiResponse> BatchUpdateAsync(List<SubmissionDetailDto> details)
|
||||
{
|
||||
try
|
||||
{
|
||||
var detailIds = details.Select(d => d.Id).ToList();
|
||||
var existingDetails = await _submissionDetailRepository.GetAllAsync(
|
||||
predicate: sd => detailIds.Contains(sd.Id) && !sd.IsDeleted);
|
||||
|
||||
foreach (var detail in details)
|
||||
{
|
||||
var existingDetail = existingDetails.FirstOrDefault(sd => sd.Id == detail.Id);
|
||||
if (existingDetail != null)
|
||||
{
|
||||
_mapper.Map(detail, existingDetail);
|
||||
existingDetail.UpdatedAt = DateTime.Now;
|
||||
_submissionDetailRepository.Update(existingDetail);
|
||||
}
|
||||
}
|
||||
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
return ApiResponse.Success("批量更新提交详情成功。", null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"批量更新提交详情失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新提交详情评分
|
||||
/// </summary>
|
||||
/// <param name="detailId">提交详情ID</param>
|
||||
/// <param name="points">分数</param>
|
||||
/// <param name="feedback">反馈</param>
|
||||
/// <returns>更新结果</returns>
|
||||
public async Task<ApiResponse> UpdateScoreAsync(Guid detailId, float? points, string? feedback)
|
||||
{
|
||||
try
|
||||
{
|
||||
var detail = await _submissionDetailRepository.GetFirstOrDefaultAsync(
|
||||
predicate: sd => sd.Id == detailId && !sd.IsDeleted);
|
||||
|
||||
if (detail == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到提交详情。", 404);
|
||||
}
|
||||
|
||||
detail.PointsAwarded = points;
|
||||
detail.TeacherFeedback = feedback;
|
||||
detail.UpdatedAt = DateTime.Now;
|
||||
|
||||
_submissionDetailRepository.Update(detail);
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
|
||||
var result = _mapper.Map<SubmissionDetailDto>(detail);
|
||||
return ApiResponse.Success("更新评分成功。", result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"更新评分失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取错题详情
|
||||
/// </summary>
|
||||
/// <param name="studentId">学生ID</param>
|
||||
/// <param name="examId">考试ID</param>
|
||||
/// <returns>错题详情列表</returns>
|
||||
public async Task<ApiResponse> GetErrorDetailsAsync(Guid studentId, Guid examId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var details = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.StudentId == studentId &&
|
||||
sd.Submission.ExamId == examId &&
|
||||
sd.IsCorrect == false &&
|
||||
!sd.IsDeleted,
|
||||
include: i => i.Include(sd => sd.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var detailDtos = _mapper.Map<List<SubmissionDetailDto>>(details.Items);
|
||||
return ApiResponse.Success("获取错题详情成功。", detailDtos);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取错题详情失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取正确题详情
|
||||
/// </summary>
|
||||
/// <param name="studentId">学生ID</param>
|
||||
/// <param name="examId">考试ID</param>
|
||||
/// <returns>正确题详情列表</returns>
|
||||
public async Task<ApiResponse> GetCorrectDetailsAsync(Guid studentId, Guid examId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var details = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.StudentId == studentId &&
|
||||
sd.Submission.ExamId == examId &&
|
||||
sd.IsCorrect == true &&
|
||||
!sd.IsDeleted,
|
||||
include: i => i.Include(sd => sd.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var detailDtos = _mapper.Map<List<SubmissionDetailDto>>(details.Items);
|
||||
return ApiResponse.Success("获取正确题详情成功。", detailDtos);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取正确题详情失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取未批改的提交详情
|
||||
/// </summary>
|
||||
/// <param name="teacherId">教师ID</param>
|
||||
/// <returns>未批改的提交详情列表</returns>
|
||||
public async Task<ApiResponse> GetUngradedDetailsAsync(Guid teacherId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var submissions = await _submissionRepository.GetPagedListAsync(
|
||||
predicate: s => s.GraderId == teacherId &&
|
||||
s.Status == SubmissionStatus.Submitted &&
|
||||
!s.IsDeleted);
|
||||
|
||||
var submissionIds = submissions.Items.Select(s => s.Id).ToList();
|
||||
|
||||
var details = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => submissionIds.Contains(sd.SubmissionId) &&
|
||||
sd.PointsAwarded == null &&
|
||||
!sd.IsDeleted,
|
||||
include: i => i.Include(sd => sd.Student)
|
||||
.Include(sd => sd.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var detailDtos = _mapper.Map<List<SubmissionDetailDto>>(details.Items);
|
||||
return ApiResponse.Success("获取未批改的提交详情成功。", detailDtos);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取未批改的提交详情失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量更新提交详情状态
|
||||
/// </summary>
|
||||
/// <param name="submissionId">提交ID</param>
|
||||
/// <param name="status">状态</param>
|
||||
/// <returns>更新结果</returns>
|
||||
public async Task<ApiResponse> UpdateStatusAsync(Guid submissionId, SubmissionStatus status)
|
||||
{
|
||||
try
|
||||
{
|
||||
var details = await _submissionDetailRepository.GetAllAsync(
|
||||
predicate: sd => sd.SubmissionId == submissionId && !sd.IsDeleted);
|
||||
|
||||
foreach (var detail in details)
|
||||
{
|
||||
detail.UpdatedAt = DateTime.Now;
|
||||
_submissionDetailRepository.Update(detail);
|
||||
}
|
||||
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
return ApiResponse.Success("批量更新状态成功。", null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"批量更新状态失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
505
TechHelper.Server/Services/Submission/SubmissionService.cs
Normal file
505
TechHelper.Server/Services/Submission/SubmissionService.cs
Normal file
@@ -0,0 +1,505 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using SharedDATA.Context;
|
||||
using TechHelper.Services.Beta;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
/// <summary>
|
||||
/// 提交服务实现(Beta版本)
|
||||
/// 实现提交相关的业务逻辑操作
|
||||
/// </summary>
|
||||
public class SubmissionService : ISubmissionService
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IRepository<Submission> _submissionRepository;
|
||||
private readonly IRepository<SubmissionDetail> _submissionDetailRepository;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化提交服务
|
||||
/// </summary>
|
||||
/// <param name="mapper">AutoMapper实例</param>
|
||||
/// <param name="unitOfWork">工作单元</param>
|
||||
public SubmissionService(IMapper mapper, IUnitOfWork unitOfWork)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_unitOfWork = unitOfWork;
|
||||
_submissionRepository = _unitOfWork.GetRepository<Submission>();
|
||||
_submissionDetailRepository = _unitOfWork.GetRepository<SubmissionDetail>();
|
||||
}
|
||||
|
||||
#region 基本CRUD操作
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有提交记录
|
||||
/// </summary>
|
||||
/// <param name="query">查询参数</param>
|
||||
/// <returns>提交记录列表</returns>
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var pagedSubmissions = await _submissionRepository.GetPagedListAsync(
|
||||
pageIndex: query.PageIndex,
|
||||
pageSize: query.PageSize,
|
||||
orderBy: s => s.OrderByDescending(s => s.SubmissionTime),
|
||||
predicate: s => !s.IsDeleted);
|
||||
|
||||
var submissionDtos = _mapper.Map<List<SubmissionListDto>>(pagedSubmissions.Items);
|
||||
|
||||
return ApiResponse.Success("获取所有提交成功。", submissionDtos);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取所有提交失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据ID获取提交记录
|
||||
/// </summary>
|
||||
/// <param name="id">提交ID</param>
|
||||
/// <returns>提交记录详情</returns>
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var submission = await _submissionRepository.GetFirstOrDefaultAsync(
|
||||
predicate: s => s.Id == id && !s.IsDeleted);
|
||||
|
||||
if (submission == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到提交记录。", 404);
|
||||
}
|
||||
|
||||
var submissionDto = _mapper.Map<SubmissionDto>(submission);
|
||||
return ApiResponse.Success("获取提交记录成功。", submissionDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取提交记录失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建提交记录
|
||||
/// </summary>
|
||||
/// <param name="model">提交数据传输对象</param>
|
||||
/// <returns>创建结果</returns>
|
||||
public async Task<ApiResponse> AddAsync(SubmissionDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var submission = _mapper.Map<Submission>(model);
|
||||
submission.SubmissionTime = DateTime.Now;
|
||||
submission.IsDeleted = false;
|
||||
|
||||
await _submissionRepository.InsertAsync(submission);
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
|
||||
var result = _mapper.Map<SubmissionDto>(submission);
|
||||
return ApiResponse.Success("提交成功。", result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"创建提交失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新提交记录
|
||||
/// </summary>
|
||||
/// <param name="model">提交数据传输对象</param>
|
||||
/// <returns>更新结果</returns>
|
||||
public async Task<ApiResponse> UpdateAsync(SubmissionDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingSubmission = await _submissionRepository.GetFirstOrDefaultAsync(predicate: s => s.Id == model.Id && !s.IsDeleted);
|
||||
if (existingSubmission == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到要更新的提交记录。", 404);
|
||||
}
|
||||
|
||||
_mapper.Map(model, existingSubmission);
|
||||
_submissionRepository.Update(existingSubmission);
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
|
||||
var result = _mapper.Map<SubmissionDto>(existingSubmission);
|
||||
return ApiResponse.Success("更新提交记录成功。", result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"更新提交记录失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除提交记录
|
||||
/// </summary>
|
||||
/// <param name="id">提交ID</param>
|
||||
/// <returns>删除结果</returns>
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var submission = await _submissionRepository.GetFirstOrDefaultAsync(predicate: s => s.Id == id && !s.IsDeleted);
|
||||
if (submission == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到要删除的提交记录。", 404);
|
||||
}
|
||||
|
||||
submission.IsDeleted = true;
|
||||
_submissionRepository.Update(submission);
|
||||
|
||||
var submissionDetails = await _submissionDetailRepository.GetPagedListAsync(predicate: sd => sd.SubmissionId == id);
|
||||
foreach (var detail in submissionDetails.Items)
|
||||
{
|
||||
detail.IsDeleted = true;
|
||||
_submissionDetailRepository.Update(detail);
|
||||
}
|
||||
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
return ApiResponse.Success("提交记录及相关详情删除成功。", null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"删除提交记录失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 错题相关操作
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户的错题列表
|
||||
/// </summary>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <returns>错题列表</returns>
|
||||
public async Task<ApiResponse> GetAllErrorQuestionsAsync(Guid userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var errorSDs = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.StudentId == userId && sd.IsCorrect == false,
|
||||
include: i => i
|
||||
.Include(s => s.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var errorQuestions = errorSDs.Items.Select(sd => sd.ExamQuestion.Question)
|
||||
.Where(q => q != null)
|
||||
.DistinctBy(q => q.Id)
|
||||
.ToList();
|
||||
|
||||
var result = _mapper.Map<List<QuestionDto>>(errorQuestions);
|
||||
return ApiResponse.Success("获取所有错题成功。", result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取所有错题失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定作业的错题列表
|
||||
/// </summary>
|
||||
/// <param name="assignmentId">作业ID</param>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <returns>错题列表</returns>
|
||||
public async Task<ApiResponse> GetAssignmentErrorQuestionsAsync(Guid assignmentId, Guid userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var errorSDs = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.Submission.ExamId == assignmentId &&
|
||||
sd.StudentId == userId &&
|
||||
sd.IsCorrect == false,
|
||||
include: i => i
|
||||
.Include(s => s.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var errorQuestions = errorSDs.Items.Select(sd => sd.ExamQuestion.Question)
|
||||
.Where(q => q != null)
|
||||
.DistinctBy(q => q.Id)
|
||||
.ToList();
|
||||
|
||||
var result = _mapper.Map<List<QuestionDto>>(errorQuestions);
|
||||
return ApiResponse.Success("获取指定作业错题成功。", result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取指定作业错题失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取错题类型分布
|
||||
/// </summary>
|
||||
/// <param name="assignmentId">作业ID</param>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <returns>错题类型分布</returns>
|
||||
public async Task<ApiResponse> GetAssignmentErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var errorSDs = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.Submission.ExamId == assignmentId &&
|
||||
sd.StudentId == userId &&
|
||||
sd.IsCorrect == false,
|
||||
include: i => i
|
||||
.Include(s => s.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var errorTypeDistribution = errorSDs.Items
|
||||
.Where(sd => sd.ExamQuestion?.Question?.QuestionType != null)
|
||||
.GroupBy(sd => sd.ExamQuestion.Question.QuestionType.Name)
|
||||
.Select(g => new
|
||||
{
|
||||
QuestionType = g.Key.ToString(),
|
||||
Count = g.Count()
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return ApiResponse.Success("获取指定作业错题类型分布成功。", errorTypeDistribution);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取指定作业错题类型分布失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有错题类型分布
|
||||
/// </summary>
|
||||
/// <param name="assignmentId">作业ID</param>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <returns>错题类型分布</returns>
|
||||
public async Task<ApiResponse> GetAllErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var errorSDs = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.Submission.ExamId == assignmentId &&
|
||||
sd.StudentId == userId &&
|
||||
sd.IsCorrect == false,
|
||||
include: i => i
|
||||
.Include(s => s.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var errorTypeDistribution = errorSDs.Items
|
||||
.Where(sd => sd.ExamQuestion?.Question?.QuestionType != null)
|
||||
.GroupBy(sd => sd.ExamQuestion.Question.QuestionType.Name)
|
||||
.Select(g => new
|
||||
{
|
||||
QuestionType = g.Key.ToString(),
|
||||
Count = g.Count()
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return ApiResponse.Success("获取错题类型分布成功。", errorTypeDistribution);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取错题类型分布失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取作业中所有学生的错题情况
|
||||
/// </summary>
|
||||
/// <param name="assignmentId">作业ID</param>
|
||||
/// <param name="teacherId">教师ID</param>
|
||||
/// <returns>学生错题情况</returns>
|
||||
public async Task<ApiResponse> GetAssignmentAllStudentsError(Guid assignmentId, Guid teacherId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var submissionDetails = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.Submission.ExamId == assignmentId &&
|
||||
sd.IsCorrect == false,
|
||||
include: i => i.Include(sd => sd.Student));
|
||||
|
||||
var studentsErrorSummary = submissionDetails.Items
|
||||
.Where(sd => sd.Student != null)
|
||||
.GroupBy(sd => new { sd.StudentId, sd.Student.UserName })
|
||||
.Select(g => new
|
||||
{
|
||||
StudentId = g.Key.StudentId,
|
||||
StudentName = g.Key.UserName,
|
||||
ErrorQuestionCount = g.Count()
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return ApiResponse.Success("获取作业中所有学生的错题情况成功。", studentsErrorSummary);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取作业中所有学生的错题情况失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取出现错题的学生列表
|
||||
/// </summary>
|
||||
/// <param name="assignmentQuestionId">作业题目ID</param>
|
||||
/// <returns>错题学生列表</returns>
|
||||
public async Task<ApiResponse> GetQuestionErrorStudents(Guid assignmentQuestionId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var errorSubmissionDetails = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.ExamQuestionId == assignmentQuestionId &&
|
||||
sd.IsCorrect == false,
|
||||
include: i => i
|
||||
.Include(sd => sd.Student)
|
||||
.Include(sd => sd.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var errorStudentsByQuestion = errorSubmissionDetails.Items
|
||||
.Where(sd => sd.ExamQuestion?.Question != null && sd.Student != null)
|
||||
.GroupBy(sd => new { sd.ExamQuestionId, sd.ExamQuestion.Question.Title })
|
||||
.Select(g => new
|
||||
{
|
||||
AssignmentQuestionId = g.Key.ExamQuestionId,
|
||||
QuestionTitle = g.Key.Title,
|
||||
ErrorStudents = g.Select(sd => new
|
||||
{
|
||||
StudentId = sd.StudentId,
|
||||
StudentName = sd.Student.UserName
|
||||
}).Distinct().ToList()
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return ApiResponse.Success("获取出现错题的学生成功。", errorStudentsByQuestion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取出现错题的学生失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 特殊操作
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否已经存在提交记录
|
||||
/// </summary>
|
||||
/// <param name="assignmentId">作业ID</param>
|
||||
/// <param name="studentId">学生ID</param>
|
||||
/// <returns>提交记录数量</returns>
|
||||
public async Task<byte> IsHasSubmissionAsync(Guid assignmentId, Guid studentId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _unitOfWork.GetRepository<Submission>().GetAllAsync(predicate: s => s.ExamId == assignmentId && s.StudentId == studentId);
|
||||
return (byte)result.Count;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取学生提交摘要
|
||||
/// </summary>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <returns>学生提交摘要列表</returns>
|
||||
public async Task<ApiResponse> GetStudentSubmissionSummariesAsync(Guid userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var submissions = await _submissionRepository.GetPagedListAsync(
|
||||
predicate: s => s.StudentId == userId && !s.IsDeleted,
|
||||
orderBy: s => s.OrderByDescending(s => s.SubmissionTime));
|
||||
|
||||
var summaries = submissions.Items.Select(s => new StudentSubmissionSummaryDto
|
||||
{
|
||||
Id = s.Id,
|
||||
AssignmentName = s.Exam?.Title ?? "未知作业",
|
||||
CreatedDate = s.SubmissionTime,
|
||||
Score = s.OverallGrade,
|
||||
StudentName = s.Student?.UserName ?? "未知学生",
|
||||
Status = s.Status.GetDisplayName()
|
||||
}).ToList();
|
||||
|
||||
return ApiResponse.Success("获取学生提交摘要成功。", new StudentSubmissionSummaryResponseDto
|
||||
{
|
||||
Submissions = summaries,
|
||||
TotalCount = submissions.TotalCount
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取学生提交摘要失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取学生提交详情
|
||||
/// </summary>
|
||||
/// <param name="submissionId">提交ID</param>
|
||||
/// <returns>学生提交详情</returns>
|
||||
public async Task<ApiResponse> GetStudentSubmissionDetailAsync(Guid submissionId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var submission = await _submissionRepository.GetFirstOrDefaultAsync(
|
||||
predicate: s => s.Id == submissionId && !s.IsDeleted);
|
||||
|
||||
if (submission == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到提交记录。", 404);
|
||||
}
|
||||
|
||||
var detail = _mapper.Map<StudentSubmissionDetailDto>(submission);
|
||||
|
||||
|
||||
return ApiResponse.Success("获取学生提交详情成功。", detail);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"获取学生提交详情失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GradeExam(SubmissionTeacherUpdateDto model)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
var existingSubmission = await _submissionRepository.GetFirstOrDefaultAsync(predicate: s => s.Id == model.Id && !s.IsDeleted);
|
||||
if (existingSubmission == null)
|
||||
{
|
||||
return ApiResponse.Error("未找到要批改的试卷记录。", 404);
|
||||
}
|
||||
|
||||
_mapper.Map(model, existingSubmission);
|
||||
|
||||
foreach (var item in existingSubmission.SubmissionDetails)
|
||||
{
|
||||
var sdd = model.SubmissionUpdateDetails.FirstOrDefault(d => d.Id == item.Id);
|
||||
if (sdd == null) continue;
|
||||
_mapper.Map(sdd, item);
|
||||
}
|
||||
_submissionRepository.Update(existingSubmission);
|
||||
await _unitOfWork.SaveChangesAsync();
|
||||
|
||||
var result = _mapper.Map<SubmissionDto>(existingSubmission);
|
||||
return ApiResponse.Success("批改试卷记录成功。", result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"批改试卷记录失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ namespace TechHelper.Server.Services
|
||||
orderBy: s => s.OrderByDescending(s => s.SubmissionTime),
|
||||
predicate: s => !s.IsDeleted,
|
||||
include: i => i.Include(s => s.Student)
|
||||
.Include(s => s.Assignment));
|
||||
.Include(s => s.Exam));
|
||||
|
||||
var submissionDtos = _mapper.Map<List<SubmissionDto>>(pagedSubmissions.Items);
|
||||
|
||||
@@ -109,10 +109,10 @@ namespace TechHelper.Server.Services
|
||||
predicate: sd => sd.StudentId == userId && sd.IsCorrect == false &&
|
||||
(sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded),
|
||||
include: i => i
|
||||
.Include(s => s.AssignmentQuestion)
|
||||
.Include(s => s.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var errorQuestions = errorSDs.Items.Select(sd => sd.AssignmentQuestion.Question)
|
||||
var errorQuestions = errorSDs.Items.Select(sd => sd.ExamQuestion.Question)
|
||||
.Where(q => q != null)
|
||||
.DistinctBy(q => q.Id)
|
||||
.ToList();
|
||||
@@ -132,18 +132,18 @@ namespace TechHelper.Server.Services
|
||||
try
|
||||
{
|
||||
var errorSDs = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.Submission.AssignmentId == assignmentId &&
|
||||
predicate: sd => sd.Submission.ExamId == assignmentId &&
|
||||
sd.StudentId == userId &&
|
||||
sd.IsCorrect == false &&
|
||||
(sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded),
|
||||
include: i => i
|
||||
.Include(s => s.AssignmentQuestion)
|
||||
.Include(s => s.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
// 对错题按类型进行分组计数
|
||||
var errorTypeDistribution = errorSDs.Items
|
||||
.Where(sd => sd.AssignmentQuestion?.Question != null)
|
||||
.GroupBy(sd => sd.AssignmentQuestion.Question.Type)
|
||||
.Where(sd => sd.ExamQuestion?.Question != null)
|
||||
.GroupBy(sd => sd.ExamQuestion.Question.Type)
|
||||
.Select(g => new
|
||||
{
|
||||
QuestionType = g.Key.ToString(),
|
||||
@@ -164,7 +164,7 @@ namespace TechHelper.Server.Services
|
||||
try
|
||||
{
|
||||
var submissionDetails = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.Submission.AssignmentId == assignmentId &&
|
||||
predicate: sd => sd.Submission.ExamId == assignmentId &&
|
||||
sd.IsCorrect == false &&
|
||||
(sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded),
|
||||
include: i => i.Include(sd => sd.Student));
|
||||
@@ -194,15 +194,15 @@ namespace TechHelper.Server.Services
|
||||
try
|
||||
{
|
||||
var errorSDs = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.Submission.AssignmentId == assignmentId &&
|
||||
predicate: sd => sd.Submission.ExamId == assignmentId &&
|
||||
sd.StudentId == userId &&
|
||||
sd.IsCorrect == false &&
|
||||
(sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded),
|
||||
include: i => i
|
||||
.Include(s => s.AssignmentQuestion)
|
||||
.Include(s => s.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var errorQuestions = errorSDs.Items.Select(sd => sd.AssignmentQuestion.Question)
|
||||
var errorQuestions = errorSDs.Items.Select(sd => sd.ExamQuestion.Question)
|
||||
.Where(q => q != null)
|
||||
.DistinctBy(q => q.Id)
|
||||
.ToList();
|
||||
@@ -221,17 +221,17 @@ namespace TechHelper.Server.Services
|
||||
try
|
||||
{
|
||||
var errorSDs = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.Submission.AssignmentId == assignmentId &&
|
||||
predicate: sd => sd.Submission.ExamId == assignmentId &&
|
||||
sd.StudentId == userId &&
|
||||
sd.IsCorrect == false &&
|
||||
(sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded),
|
||||
include: i => i
|
||||
.Include(s => s.AssignmentQuestion)
|
||||
.Include(s => s.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
var errorTypeDistribution = errorSDs.Items
|
||||
.Where(sd => sd.AssignmentQuestion?.Question != null)
|
||||
.GroupBy(sd => sd.AssignmentQuestion.Question.Type)
|
||||
.Where(sd => sd.ExamQuestion?.Question != null)
|
||||
.GroupBy(sd => sd.ExamQuestion.Question.Type)
|
||||
.Select(g => new
|
||||
{
|
||||
QuestionType = g.Key.ToString(),
|
||||
@@ -254,10 +254,10 @@ namespace TechHelper.Server.Services
|
||||
var submission = await _submissionRepository.GetFirstOrDefaultAsync(
|
||||
predicate: s => s.Id == id && !s.IsDeleted,
|
||||
include: i => i.Include(s => s.Student)
|
||||
.Include(s => s.Assignment)
|
||||
.Include(s => s.Exam)
|
||||
.Include(s => s.Grader)
|
||||
.Include(s => s.SubmissionDetails)
|
||||
.ThenInclude(sd => sd.AssignmentQuestion)
|
||||
.ThenInclude(sd => sd.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
if (submission == null)
|
||||
@@ -279,18 +279,18 @@ namespace TechHelper.Server.Services
|
||||
try
|
||||
{
|
||||
var errorSubmissionDetails = await _submissionDetailRepository.GetPagedListAsync(
|
||||
predicate: sd => sd.AssignmentQuestionId == assignmentQuestionId &&
|
||||
predicate: sd => sd.ExamQuestionId == assignmentQuestionId &&
|
||||
sd.IsCorrect == false &&
|
||||
(sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded),
|
||||
include: i => i
|
||||
.Include(sd => sd.Student)
|
||||
.Include(sd => sd.AssignmentQuestion)
|
||||
.Include(sd => sd.ExamQuestion)
|
||||
.ThenInclude(aq => aq.Question));
|
||||
|
||||
|
||||
var errorStudentsByQuestion = errorSubmissionDetails.Items
|
||||
.Where(sd => sd.AssignmentQuestion?.Question != null && sd.Student != null)
|
||||
.GroupBy(sd => new { sd.AssignmentQuestionId, sd.AssignmentQuestion.Question.Title })
|
||||
.Where(sd => sd.ExamQuestion?.Question != null && sd.Student != null)
|
||||
.GroupBy(sd => new { sd.ExamQuestionId, sd.ExamQuestion.Question.Title })
|
||||
.Select(g => new
|
||||
{
|
||||
AssignmentQuestionId = g.Key.AssignmentQuestionId,
|
||||
@@ -315,7 +315,7 @@ namespace TechHelper.Server.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _unitOfWork.GetRepository<Submission>().GetAllAsync(predicate: s => s.AssignmentId == assignment && s.StudentId == studentId);
|
||||
var result = await _unitOfWork.GetRepository<Submission>().GetAllAsync(predicate: s => s.ExamId == assignment && s.StudentId == studentId);
|
||||
return (byte)result.Count;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
12
TechHelper.Server/Services/Textbook/ITextbookService.cs
Normal file
12
TechHelper.Server/Services/Textbook/ITextbookService.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
/// <summary>
|
||||
/// 教材服务接口
|
||||
/// </summary>
|
||||
public interface ITextbookService : IBaseService<TextbookDto, Guid>
|
||||
{
|
||||
}
|
||||
}
|
||||
186
TechHelper.Server/Services/Textbook/TextbookService.cs
Normal file
186
TechHelper.Server/Services/Textbook/TextbookService.cs
Normal file
@@ -0,0 +1,186 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Services.Beta;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
/// <summary>
|
||||
/// 教材服务实现类
|
||||
/// </summary>
|
||||
public class TextbookService : ITextbookService
|
||||
{
|
||||
private readonly IUnitOfWork _work;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public TextbookService(IUnitOfWork work, IMapper mapper)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
try
|
||||
{
|
||||
var repository = _work.GetRepository<Textbook>();
|
||||
|
||||
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
var textbooks = await repository.GetPagedListAsync(
|
||||
predicate: t => t.Title.Contains(query.Search) ||
|
||||
t.Grade.ToString().Contains(query.Search) ||
|
||||
t.Publisher.ToString().Contains(query.Search) ||
|
||||
t.SubjectArea.ToString().Contains(query.Search),
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var textbookDtosFiltered = _mapper.Map<IEnumerable<TextbookResponseDto>>(textbooks.Items);
|
||||
return new ApiResponse(true, textbookDtosFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
var textbooks = await repository.GetPagedListAsync(
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var textbookDtos = _mapper.Map<IEnumerable<TextbookResponseDto>>(textbooks.Items);
|
||||
return new ApiResponse(true, textbookDtos);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取所有教材时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var textbook = await _work.GetRepository<Textbook>().GetFirstOrDefaultAsync(
|
||||
predicate: t => t.Id == id,
|
||||
include: i => i
|
||||
.Include(t => t.Lessons));
|
||||
|
||||
if (textbook == null)
|
||||
{
|
||||
return new ApiResponse("教材未找到。");
|
||||
}
|
||||
|
||||
var textbookDto = _mapper.Map<TextbookResponseDto>(textbook);
|
||||
return new ApiResponse(true, textbookDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取教材时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> AddAsync(TextbookDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否已存在同名教材(考虑年级和学科领域)
|
||||
var existingTextbook = await _work.GetRepository<Textbook>().GetFirstOrDefaultAsync(
|
||||
predicate: t => t.Title == model.Title &&
|
||||
t.Grade.ToString() == model.Grade &&
|
||||
t.SubjectArea.ToString() == model.SubjectArea);
|
||||
|
||||
if (existingTextbook != null)
|
||||
{
|
||||
return new ApiResponse($"教材 '{model.Title}' 在该年级和学科领域已存在。");
|
||||
}
|
||||
|
||||
var textbook = _mapper.Map<Textbook>(model);
|
||||
|
||||
await _work.GetRepository<Textbook>().InsertAsync(textbook);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, textbook.Id);
|
||||
}
|
||||
return new ApiResponse("添加教材失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"添加教材时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> UpdateAsync(TextbookDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingTextbook = await _work.GetRepository<Textbook>().GetFirstOrDefaultAsync(
|
||||
predicate: t => t.Id == model.Id);
|
||||
|
||||
if (existingTextbook == null)
|
||||
{
|
||||
return new ApiResponse("教材未找到。");
|
||||
}
|
||||
|
||||
// 检查是否要修改为已存在的教材名称(排除当前教材)
|
||||
var textbookWithSameName = await _work.GetRepository<Textbook>().GetFirstOrDefaultAsync(
|
||||
predicate: t => t.Title == model.Title &&
|
||||
t.Grade.ToString() == model.Grade &&
|
||||
t.SubjectArea.ToString() == model.SubjectArea &&
|
||||
t.Id != model.Id);
|
||||
|
||||
if (textbookWithSameName != null)
|
||||
{
|
||||
return new ApiResponse($"教材名称 '{model.Title}' 在该年级和学科领域已被其他教材使用。");
|
||||
}
|
||||
|
||||
_mapper.Map(model, existingTextbook);
|
||||
_work.GetRepository<Textbook>().Update(existingTextbook);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
var textbookDto = _mapper.Map<TextbookResponseDto>(existingTextbook);
|
||||
return new ApiResponse(true, textbookDto);
|
||||
}
|
||||
return new ApiResponse("更新教材失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"更新教材时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingTextbook = await _work.GetRepository<Textbook>().GetFirstOrDefaultAsync(
|
||||
predicate: t => t.Id == id);
|
||||
|
||||
if (existingTextbook == null)
|
||||
{
|
||||
return new ApiResponse("教材未找到。");
|
||||
}
|
||||
|
||||
// 检查是否有相关课程
|
||||
var hasLessons = existingTextbook.Lessons.Any();
|
||||
if (hasLessons)
|
||||
{
|
||||
return new ApiResponse("无法删除该教材,因为它包含相关课程。");
|
||||
}
|
||||
|
||||
_work.GetRepository<Textbook>().Delete(existingTextbook);
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, "教材删除成功。");
|
||||
}
|
||||
return new ApiResponse("删除教材失败。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"删除教材时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using TechHelper.Context;
|
||||
using Entities.Configuration;
|
||||
using Entities.Configuration;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
@@ -7,17 +6,24 @@ using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
|
||||
namespace TechHelper.Services
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户认证服务,实现 JWT 令牌生成、刷新令牌生成、过期令牌解析等功能。
|
||||
/// </summary>
|
||||
public class AuthenticationService : IAuthenticationService
|
||||
{
|
||||
private readonly JwtConfiguration _jwtSettings;
|
||||
private readonly JwtSecurityTokenHandler _jwtHandler;
|
||||
private readonly UserManager<User> _userManager;
|
||||
private readonly UserManager<Entities.Contracts.User> _userManager;
|
||||
private readonly IClassService _classService;
|
||||
public AuthenticationService(IOptions<JwtConfiguration> jwtSettings, UserManager<User> userManager, IClassService classService)
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数,注入 JWT 配置、用户管理器和班级服务。
|
||||
/// </summary>
|
||||
public AuthenticationService(IOptions<JwtConfiguration> jwtSettings, UserManager<Entities.Contracts.User> userManager, IClassService classService)
|
||||
{
|
||||
_jwtSettings = jwtSettings.Value;
|
||||
_jwtHandler = new JwtSecurityTokenHandler();
|
||||
@@ -25,54 +31,72 @@ namespace TechHelper.Services
|
||||
_classService = classService;
|
||||
}
|
||||
|
||||
public async Task<string> GetToken(User user)
|
||||
/// <summary>
|
||||
/// 生成指定用户的 JWT 访问令牌。
|
||||
/// </summary>
|
||||
/// <param name="user">用户实体</param>
|
||||
/// <returns>JWT 字符串</returns>
|
||||
public async Task<string> GetToken(Entities.Contracts.User user)
|
||||
{
|
||||
var signingCredentials = GetSigningCredentials();
|
||||
|
||||
var claims = await GetClaims(user);
|
||||
|
||||
var tokenOptions = GenerateTokenOptions(signingCredentials, claims);
|
||||
|
||||
return _jwtHandler.WriteToken(tokenOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 JWT 签名凭证。
|
||||
/// </summary>
|
||||
/// <returns>签名凭证</returns>
|
||||
private SigningCredentials GetSigningCredentials()
|
||||
{
|
||||
var key = Encoding.UTF8.GetBytes(_jwtSettings.SecurityKey);
|
||||
var secret = new SymmetricSecurityKey(key);
|
||||
|
||||
return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<Claim>> GetClaims(User user)
|
||||
/// <summary>
|
||||
/// 获取用户的声明信息,包括角色和班级信息。
|
||||
/// </summary>
|
||||
/// <param name="user">用户实体</param>
|
||||
/// <returns>声明集合</returns>
|
||||
private async Task<IEnumerable<Claim>> GetClaims(Entities.Contracts.User user)
|
||||
{
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.Name, user.Email)
|
||||
};
|
||||
|
||||
// 添加用户角色声明
|
||||
var roles = await _userManager.GetRolesAsync(user);
|
||||
foreach (var role in roles)
|
||||
{
|
||||
claims.Add(new Claim(ClaimTypes.Role, role));
|
||||
}
|
||||
|
||||
var classInfo = await _classService.GetUserClass(user.Id);
|
||||
#region ClassInfo
|
||||
// 添加用户班级信息声明
|
||||
var classInfo = await _classService.GetUserInjoinedClasses(user.Id);
|
||||
if (classInfo.Status)
|
||||
{
|
||||
var classs = classInfo.Result as List<Class>;
|
||||
|
||||
classs?.ForEach(c =>
|
||||
var classs = classInfo.Result as UserClassDetailInfoDto;
|
||||
if (classs == null) return claims;
|
||||
foreach (var c in classs.UserClassInfos)
|
||||
{
|
||||
|
||||
claims.Add(new Claim("Grade", c.Grade.ToString()));
|
||||
claims.Add(new Claim("Class", c.Number.ToString()));
|
||||
});
|
||||
claims.Add(new Claim("Class", c.Class.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
return claims;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成 JWT 令牌对象。
|
||||
/// </summary>
|
||||
/// <param name="signingCredentials">签名凭证</param>
|
||||
/// <param name="claims">声明集合</param>
|
||||
/// <returns>JWT 令牌对象</returns>
|
||||
private JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, IEnumerable<Claim> claims)
|
||||
{
|
||||
var tokenOptions = new JwtSecurityToken(
|
||||
@@ -86,6 +110,10 @@ namespace TechHelper.Services
|
||||
return tokenOptions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成安全的刷新令牌(Base64 字符串)。
|
||||
/// </summary>
|
||||
/// <returns>刷新令牌</returns>
|
||||
public string GenerateRefreshToken()
|
||||
{
|
||||
var randomNumber = new byte[32];
|
||||
@@ -96,6 +124,12 @@ namespace TechHelper.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从过期的 JWT 令牌中获取声明主体(不验证过期时间)。
|
||||
/// </summary>
|
||||
/// <param name="token">过期的 JWT 令牌</param>
|
||||
/// <returns>声明主体</returns>
|
||||
/// <exception cref="SecurityTokenException">令牌无效时抛出</exception>
|
||||
public ClaimsPrincipal GetPrincipalFromExpiredToken(string token)
|
||||
{
|
||||
var tokenValidationParameters = new TokenValidationParameters
|
||||
@@ -105,7 +139,7 @@ namespace TechHelper.Services
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(
|
||||
Encoding.UTF8.GetBytes(_jwtSettings.SecurityKey)),
|
||||
ValidateLifetime = false,
|
||||
ValidateLifetime = false, // 不验证过期时间
|
||||
ValidIssuer = _jwtSettings.ValidIssuer,
|
||||
ValidAudience = _jwtSettings.ValidAudience,
|
||||
};
|
||||
@@ -3,11 +3,11 @@ using Microsoft.AspNetCore.Identity;
|
||||
using System.Security.Claims;
|
||||
using Entities.Contracts;
|
||||
|
||||
namespace TechHelper.Services
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public interface IAuthenticationService
|
||||
{
|
||||
public Task<string> GetToken(User user);
|
||||
public Task<string> GetToken(Entities.Contracts.User user);
|
||||
public string GenerateRefreshToken();
|
||||
public ClaimsPrincipal GetPrincipalFromExpiredToken(string token);
|
||||
}
|
||||
20
TechHelper.Server/Services/User/IUserSerivces.cs
Normal file
20
TechHelper.Server/Services/User/IUserSerivces.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
public interface IUserSerivces : IBaseService<UserDto, Guid>
|
||||
{
|
||||
Task<ApiResponse> GetStudentDetailInfo(Guid userId);
|
||||
Task<ApiResponse> RestoreUserRoleInformation(User user);
|
||||
Task<ApiResponse> VerifyUserInformation(Guid userId);
|
||||
/// <summary>
|
||||
/// 注册新用户,并根据角色关联到班级
|
||||
/// </summary>
|
||||
/// <param name="registrationDto">用户注册数据</param>
|
||||
/// <returns>操作结果</returns>
|
||||
Task<ApiResponse> RegisterNewUserAsync(UserForRegistrationDto registrationDto);
|
||||
|
||||
Task<ApiResponse> InitAdminUser(UserForAdmin registrationDto);
|
||||
}
|
||||
}
|
||||
421
TechHelper.Server/Services/User/UserServices.cs
Normal file
421
TechHelper.Server/Services/User/UserServices.cs
Normal file
@@ -0,0 +1,421 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Features;
|
||||
|
||||
namespace TechHelper.Services.Beta
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户服务实现类
|
||||
/// 处理用户相关的业务逻辑操作
|
||||
/// </summary>
|
||||
public class UserServices : IUserSerivces
|
||||
{
|
||||
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IClassService _classService;
|
||||
private readonly UserManager<User> _userManager;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly TechHelper.Features.IEmailSender _emailSender;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化用户服务
|
||||
/// </summary>
|
||||
/// <param name="unitOfWork">工作单元实例</param>
|
||||
/// <param name="classService">班级服务实例</param>
|
||||
/// <param name="userManager">用户管理实例</param>
|
||||
/// <param name="mapper">对象映射实例</param>
|
||||
/// <param name="emailSender">邮件发送实例</param>
|
||||
public UserServices(IUnitOfWork unitOfWork, IClassService classService, UserManager<User> userManager, IMapper mapper, IEmailSender emailSender)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_classService = classService;
|
||||
_userManager = userManager;
|
||||
_mapper = mapper;
|
||||
_emailSender = emailSender;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加新用户
|
||||
/// </summary>
|
||||
/// <param name="model">用户实体对象</param>
|
||||
/// <returns>操作结果响应</returns>
|
||||
public async Task<ApiResponse> AddAsync(UserDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
//var user = _mapper.Map<User>(model);
|
||||
//user.UserName = model.Email;
|
||||
//user.EmailConfirmed = true;
|
||||
|
||||
//var result = await _userManager.CreateAsync(user, model.Password ?? "TempPassword123!");
|
||||
|
||||
//if (!result.Succeeded)
|
||||
//{
|
||||
// var errors = result.Errors.Select(e => e.Description).ToList();
|
||||
// return new ApiResponse(false, errors);
|
||||
//}
|
||||
|
||||
return new ApiResponse(true, "用户添加成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse(false, $"添加用户失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定用户
|
||||
/// </summary>
|
||||
/// <param name="id">用户唯一标识符</param>
|
||||
/// <returns>操作结果响应</returns>
|
||||
public async Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await _userManager.FindByIdAsync(id.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return new ApiResponse(false, "用户不存在");
|
||||
}
|
||||
|
||||
var result = await _userManager.DeleteAsync(user);
|
||||
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
var errors = result.Errors.Select(e => e.Description).ToList();
|
||||
return new ApiResponse(false, errors);
|
||||
}
|
||||
|
||||
return new ApiResponse(true, "用户删除成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse(false, $"删除用户失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有用户列表
|
||||
/// </summary>
|
||||
/// <param name="query">查询参数对象</param>
|
||||
/// <returns>用户列表响应</returns>
|
||||
public async Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
var repository = _unitOfWork.GetRepository<User>();
|
||||
|
||||
if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search))
|
||||
{
|
||||
var users = await repository.GetPagedListAsync(
|
||||
predicate: u => u.Email.Contains(query.Search) || u.DisplayName.Contains(query.Search),
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var userDtosFiltered = _mapper.Map<IEnumerable<UserListDto>>(users.Items);
|
||||
return new ApiResponse(true, userDtosFiltered);
|
||||
}
|
||||
else
|
||||
{
|
||||
var users = await repository.GetPagedListAsync(
|
||||
pageSize: query.PageSize,
|
||||
pageIndex: query.PageIndex
|
||||
);
|
||||
var userDtos = _mapper.Map<IEnumerable<UserListDto>>(users.Items);
|
||||
return new ApiResponse(true, userDtos);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse($"获取所有用户时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定用户信息
|
||||
/// </summary>
|
||||
/// <param name="id">用户唯一标识符</param>
|
||||
/// <returns>用户信息响应</returns>
|
||||
public async Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await _userManager.FindByIdAsync(id.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return new ApiResponse(false, "用户不存在");
|
||||
}
|
||||
|
||||
var userDto = _mapper.Map<UserDto>(user);
|
||||
return new ApiResponse(true, userDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse(false, $"获取用户信息失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取学生详细信息
|
||||
/// </summary>
|
||||
/// <param name="userId">用户唯一标识符</param>
|
||||
/// <returns>学生详细信息响应</returns>
|
||||
public async Task<ApiResponse> GetStudentDetailInfo(Guid userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await _userManager.FindByIdAsync(userId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return new ApiResponse(false, "用户不存在");
|
||||
}
|
||||
|
||||
var studentDetail = new
|
||||
{
|
||||
user.Id,
|
||||
user.Email,
|
||||
user.DisplayName,
|
||||
user.PhoneNumber,
|
||||
user.Role,
|
||||
IsEmailConfirmed = user.EmailConfirmed,
|
||||
UserStatus = user.EmailConfirmed ? "Verified" : "Pending Verification"
|
||||
};
|
||||
|
||||
return new ApiResponse(true, studentDetail);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse(false, $"获取学生详细信息失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复用户角色信息
|
||||
/// 根据用户所在班级信息恢复用户的角色权限
|
||||
/// </summary>
|
||||
/// <param name="user">用户实体对象</param>
|
||||
/// <returns>操作结果响应</returns>
|
||||
public async Task<ApiResponse> RestoreUserRoleInformation(User user)
|
||||
{
|
||||
var result = await _classService.GetUserClassRole(user.Id);
|
||||
if (result.Status)
|
||||
{
|
||||
var classRole = result.Result as string;
|
||||
if (classRole != null)
|
||||
{
|
||||
if (!await _userManager.IsInRoleAsync(user, classRole))
|
||||
{
|
||||
await _userManager.AddToRoleAsync(user, classRole);
|
||||
|
||||
return ApiResponse.Success();
|
||||
}
|
||||
}
|
||||
}
|
||||
return ApiResponse.Error();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新用户信息
|
||||
/// </summary>
|
||||
/// <param name="model">用户实体对象</param>
|
||||
/// <returns>操作结果响应</returns>
|
||||
public async Task<ApiResponse> UpdateAsync(UserDto model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await _userManager.FindByIdAsync(model.Id.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return new ApiResponse(false, "用户不存在");
|
||||
}
|
||||
|
||||
user.DisplayName = model.DisplayName;
|
||||
user.PhoneNumber = model.PhoneNumber;
|
||||
|
||||
var result = await _userManager.UpdateAsync(user);
|
||||
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
var errors = result.Errors.Select(e => e.Description).ToList();
|
||||
return new ApiResponse(false, errors);
|
||||
}
|
||||
|
||||
return new ApiResponse(true, "用户信息更新成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse(false, $"更新用户信息失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证用户信息
|
||||
/// </summary>
|
||||
/// <param name="userId">用户唯一标识符</param>
|
||||
/// <returns>验证结果响应</returns>
|
||||
public async Task<ApiResponse> VerifyUserInformation(Guid userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await _userManager.FindByIdAsync(userId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return new ApiResponse(false, "用户不存在");
|
||||
}
|
||||
|
||||
// 验证邮箱确认状态
|
||||
var isEmailConfirmed = user.EmailConfirmed;
|
||||
|
||||
// 验证用户角色
|
||||
var isInRole = await _userManager.IsInRoleAsync(user, "Student") ||
|
||||
await _userManager.IsInRoleAsync(user, "Teacher");
|
||||
|
||||
var verificationResult = new
|
||||
{
|
||||
UserId = user.Id,
|
||||
Email = user.Email,
|
||||
IsEmailConfirmed = isEmailConfirmed,
|
||||
HasValidRole = isInRole,
|
||||
DisplayName = user.DisplayName,
|
||||
Role = user.Role
|
||||
};
|
||||
|
||||
if (isEmailConfirmed && isInRole)
|
||||
{
|
||||
return new ApiResponse(true, "用户信息验证成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ApiResponse(false, "用户信息验证失败");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ApiResponse(false, $"验证用户信息失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册新用户,并根据角色关联到班级
|
||||
/// </summary>
|
||||
/// <param name="registrationDto">用户注册数据</param>
|
||||
/// <returns>操作结果</returns>
|
||||
public async Task<ApiResponse> RegisterNewUserAsync(UserForRegistrationDto registrationDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingUserByEmail = await _userManager.FindByEmailAsync(registrationDto.Email);
|
||||
if (existingUserByEmail != null)
|
||||
{
|
||||
return new ApiResponse("此电子邮件地址已被注册。");
|
||||
}
|
||||
|
||||
var user = _mapper.Map<User>(registrationDto);
|
||||
|
||||
user.UserName = registrationDto.Email;
|
||||
user.DisplayName = registrationDto.DisplayName;
|
||||
user.Role = registrationDto.Roles;
|
||||
user.EmailConfirmed = false;
|
||||
user.TeachSubjectId = registrationDto.RegisterUserToClassDto.SubjectArea;
|
||||
|
||||
var result = await _userManager.CreateAsync(user, registrationDto.Password);
|
||||
|
||||
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
var errors = result.Errors.Select(e => e.Description).ToList();
|
||||
return new ApiResponse(false, errors);
|
||||
}
|
||||
|
||||
var userResult = await _userManager.FindByEmailAsync(user.Email);
|
||||
if (userResult == null)
|
||||
return ApiResponse.Error("注册失败,请联系管理员。");
|
||||
|
||||
var roleResult = await _userManager.AddToRoleAsync(userResult, registrationDto.Roles.ToString());
|
||||
|
||||
if (!roleResult.Succeeded)
|
||||
{
|
||||
var errors = roleResult.Errors.Select(e => e.Description).ToList();
|
||||
return new ApiResponse(false, errors);
|
||||
}
|
||||
|
||||
registrationDto.RegisterUserToClassDto.UserId = userResult.Id;
|
||||
var classRegisterResult = await _classService.UserRegister(registrationDto.RegisterUserToClassDto);
|
||||
|
||||
if (!classRegisterResult.Status)
|
||||
{
|
||||
if (userResult != null)
|
||||
await _userManager.DeleteAsync(userResult);
|
||||
|
||||
return new ApiResponse(false, classRegisterResult.Message ?? "Class registration failed");
|
||||
}
|
||||
|
||||
return new ApiResponse(true, "操作成功。");
|
||||
|
||||
//var emailConfirmationToken = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
//var encodedToken = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(emailConfirmationToken));
|
||||
//var callbackUrl = QueryHelpers.AddQueryString(registrationDto.ClientURI, new Dictionary<string, string>
|
||||
//{
|
||||
// {"token", encodedToken},
|
||||
// {"email", user.Email}
|
||||
//});
|
||||
|
||||
//try
|
||||
//{
|
||||
// await _emailSender.SendEmailAsync(user.Email, "请确认您的邮箱", $"请点击此链接确认您的邮箱: {callbackUrl}");
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// Console.Error.WriteLine($"发送邮箱确认邮件失败: {ex.Message}");
|
||||
//}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var userResult = await _userManager.FindByEmailAsync(registrationDto.Email);
|
||||
if (userResult != null)
|
||||
await _userManager.DeleteAsync(userResult);
|
||||
return new ApiResponse(false, "注册过程中发生错误");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> InitAdminUser(UserForAdmin admin)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingUserByEmail = await _userManager.FindByEmailAsync(admin.Email);
|
||||
if (existingUserByEmail != null)
|
||||
{
|
||||
return new ApiResponse("此电子邮件地址已被注册。");
|
||||
}
|
||||
var user = new User { Role = UserRoles.Admin, DisplayName = admin.DisplayName, Email = admin.Email, UserName = admin.Email };
|
||||
|
||||
var result = await _userManager.CreateAsync(user, admin.Password);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
return ApiResponse.Error("管理员用户创建失败, 用户注册时失败");
|
||||
}
|
||||
|
||||
await _userManager.AddToRoleAsync(user, UserRoles.Admin.ToString());
|
||||
|
||||
await _unitOfWork.GetRepository<School>().InsertAsync(new School { SchoolName = admin.SchoolName, CreateTime = DateTime.Now, Address = admin.Address });
|
||||
|
||||
if (await _unitOfWork.SaveChangesAsync() > 0)
|
||||
{
|
||||
return ApiResponse.Success("管理员用户创建成功");
|
||||
}
|
||||
return ApiResponse.Error("管理员用户创建失败");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error($"创建失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
using AutoMapper;
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using SharedDATA.Api;
|
||||
using System.Text;
|
||||
using TechHelper.Features;
|
||||
|
||||
namespace TechHelper.Services
|
||||
{
|
||||
public class UserRegistrationService : IUserRegistrationService
|
||||
{
|
||||
private readonly IUnitOfWork _work;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly UserManager<User> _userManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
public UserRegistrationService(
|
||||
IUnitOfWork work,
|
||||
IMapper mapper,
|
||||
UserManager<User> userManager,
|
||||
IEmailSender emailSender)
|
||||
{
|
||||
_work = work;
|
||||
_mapper = mapper;
|
||||
_userManager = userManager;
|
||||
_emailSender = emailSender;
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> RegisterNewUserAsync(UserForRegistrationDto registrationDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingUserByEmail = await _userManager.FindByEmailAsync(registrationDto.Email);
|
||||
if (existingUserByEmail != null)
|
||||
{
|
||||
return new ApiResponse("此电子邮件地址已被注册。");
|
||||
}
|
||||
|
||||
var user = _mapper.Map<User>(registrationDto);
|
||||
|
||||
user.UserName = registrationDto.Email;
|
||||
user.DisplayName = registrationDto.Name;
|
||||
user.EmailConfirmed = false;
|
||||
|
||||
var result = await _userManager.CreateAsync(user, registrationDto.Password);
|
||||
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
var errors = result.Errors.Select(e => e.Description).ToList();
|
||||
return new ApiResponse(false, errors);
|
||||
}
|
||||
|
||||
var existingClass = await _work.GetRepository<Class>().GetFirstOrDefaultAsync(
|
||||
predicate: c => c.Number == registrationDto.Class && c.Grade == registrationDto.Grade);
|
||||
|
||||
if (existingClass == null)
|
||||
{
|
||||
existingClass = new Class
|
||||
{
|
||||
Number = (byte)registrationDto.Class,
|
||||
Grade = (byte)registrationDto.Grade
|
||||
};
|
||||
await _work.GetRepository<Class>().InsertAsync(existingClass);
|
||||
}
|
||||
|
||||
//if (registrationDto.Roles == UserRoles.Student)
|
||||
//{
|
||||
// var classStudent = new ClassStudent
|
||||
// {
|
||||
// ClassId = existingClass.Id,
|
||||
// StudentId = user.Id
|
||||
// };
|
||||
// await _work.GetRepository<ClassStudent>().InsertAsync(classStudent);
|
||||
|
||||
// await _userManager.AddToRoleAsync(user, UserRoles.Student.ToString());
|
||||
//}
|
||||
//else if (registrationDto.Roles == UserRoles.Teacher)
|
||||
//{
|
||||
// var classTeacher = new ClassTeacher
|
||||
// {
|
||||
// ClassId = existingClass.Id,
|
||||
// TeacherId = user.Id
|
||||
// };
|
||||
// await _work.GetRepository<ClassTeacher>().InsertAsync(classTeacher);
|
||||
|
||||
// await _userManager.AddToRoleAsync(user, UserRoles.Teacher.ToString());
|
||||
//}
|
||||
|
||||
//var emailConfirmationToken = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
//var encodedToken = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(emailConfirmationToken));
|
||||
//var callbackUrl = QueryHelpers.AddQueryString(registrationDto.ClientURI, new Dictionary<string, string>
|
||||
//{
|
||||
// {"token", encodedToken},
|
||||
// {"email", user.Email}
|
||||
// });
|
||||
|
||||
//try
|
||||
//{
|
||||
// await _emailSender.SendEmailAsync(user.Email, "请确认您的邮箱", $"请点击此链接确认您的邮箱: {callbackUrl}");
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// Console.Error.WriteLine($"发送邮箱确认邮件失败: {ex.Message}");
|
||||
//}
|
||||
|
||||
|
||||
if (await _work.SaveChangesAsync() > 0)
|
||||
{
|
||||
return new ApiResponse(true, "用户注册成功,班级关联和邮箱确认邮件已发送。");
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ApiResponse("用户注册成功但班级关联失败。");
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine($"注册过程中发生错误: {ex.Message}");
|
||||
return new ApiResponse($"注册过程中发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
using Entities.Contracts;
|
||||
using Entities.DTO;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using SharedDATA.Api;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Server.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户服务实现类
|
||||
/// 处理用户相关的业务逻辑操作
|
||||
/// </summary>
|
||||
public class UserServices : IUserSerivces
|
||||
{
|
||||
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IClassService _classService;
|
||||
private readonly UserManager<User> _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化用户服务
|
||||
/// </summary>
|
||||
/// <param name="unitOfWork">工作单元实例</param>
|
||||
/// <param name="classService">班级服务实例</param>
|
||||
/// <param name="userManager">用户管理实例</param>
|
||||
public UserServices(IUnitOfWork unitOfWork, IClassService classService, UserManager<User> userManager)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_classService = classService;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加新用户
|
||||
/// </summary>
|
||||
/// <param name="model">用户实体对象</param>
|
||||
/// <returns>操作结果响应</returns>
|
||||
public Task<ApiResponse> AddAsync(User model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定用户
|
||||
/// </summary>
|
||||
/// <param name="id">用户唯一标识符</param>
|
||||
/// <returns>操作结果响应</returns>
|
||||
public Task<ApiResponse> DeleteAsync(Guid id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有用户列表
|
||||
/// </summary>
|
||||
/// <param name="query">查询参数对象</param>
|
||||
/// <returns>用户列表响应</returns>
|
||||
public Task<ApiResponse> GetAllAsync(QueryParameter query)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定用户信息
|
||||
/// </summary>
|
||||
/// <param name="id">用户唯一标识符</param>
|
||||
/// <returns>用户信息响应</returns>
|
||||
public Task<ApiResponse> GetAsync(Guid id)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取学生详细信息
|
||||
/// </summary>
|
||||
/// <param name="userId">用户唯一标识符</param>
|
||||
/// <returns>学生详细信息响应</returns>
|
||||
public Task<ApiResponse> GetStudentDetailInfo(Guid userId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复用户角色信息
|
||||
/// 根据用户所在班级信息恢复用户的角色权限
|
||||
/// </summary>
|
||||
/// <param name="user">用户实体对象</param>
|
||||
/// <returns>操作结果响应</returns>
|
||||
public async Task<ApiResponse> RestoreUserRoleInformation(User user)
|
||||
{
|
||||
var result = await _classService.GetUserClassRole(user.Id);
|
||||
if (result.Status)
|
||||
{
|
||||
var classRole = result.Result as UserClassRoleDto;
|
||||
if (classRole != null)
|
||||
{
|
||||
if (!await _userManager.IsInRoleAsync(user, classRole.Role))
|
||||
{
|
||||
await _userManager.AddToRoleAsync(user, classRole.Role);
|
||||
|
||||
return ApiResponse.Success();
|
||||
}
|
||||
}
|
||||
}
|
||||
return ApiResponse.Error();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新用户信息
|
||||
/// </summary>
|
||||
/// <param name="model">用户实体对象</param>
|
||||
/// <returns>操作结果响应</returns>
|
||||
public Task<ApiResponse> UpdateAsync(User model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证用户信息
|
||||
/// </summary>
|
||||
/// <param name="userId">用户唯一标识符</param>
|
||||
/// <returns>验证结果响应</returns>
|
||||
public Task<ApiResponse> VerifyUserInformation(Guid userId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user