ltx e049955f9c feat: 完善学生数据管理及作业批量导出
- 完善学生Excel导入的文件、行数据和重复学号校验,并返回实际导入数量
- 调整学生导出字段名称与排列顺序,移除学籍号字段
- 规范单张及ZIP批量人脸导入校验,限制格式、大小、数量和解压总量
- 批量人脸导入返回总数、成功数、失败数及详细失败原因
- 新增作业按作业、班级、完成状态等条件批量导出,每名学生一条记录
2026-07-31 14:21:04 +08:00

301 lines
12 KiB
C#

using AutoMapper;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.Extensions.DependencyInjection;
using Quartz.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VOL.Business.IRepositories;
using VOL.Business.IServices;
using VOL.Business.Repositories;
using VOL.Core.CacheManager;
using VOL.Core.Extensions;
using VOL.Core.Extensions.AutofacManager;
using VOL.Core.ManageUser;
using VOL.Core.Utilities;
using VOL.Entity.DomainModels;
using VOL.Entity.Enum;
using VOL.Model;
using VOL.Model.Ai;
using VOL.Model.HomeWork;
using VOL.Model.Norm.Request;
using VOL.Model.Norm.Response;
using VOL.System.IRepositories;
using VOL.System.Repositories;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
namespace VOL.Business.Services.Norm
{
public class S_HomeWorkService : IS_HomeWorkService, IDependency
{
#region 初始化
private readonly IMapper _mapper;
private readonly IS_HomeWorkRepository _homeWorkRepository;
private readonly IS_SubmittedAssignmentsRepository _submittedAssignmentsRepository;
private readonly S_HomeWorkStudentsRepository _homeWorkStudentsRepository;
[ActivatorUtilitiesConstructor]
public S_HomeWorkService(IMapper mapper,
IS_HomeWorkRepository homeWorkRepository, IS_SubmittedAssignmentsRepository submittedAssignmentsRepository, S_HomeWorkStudentsRepository homeWorkStudentsRepository)
{
_mapper = mapper;
_homeWorkRepository = homeWorkRepository;
_submittedAssignmentsRepository = submittedAssignmentsRepository;
_homeWorkStudentsRepository = homeWorkStudentsRepository;
}
#endregion
public async Task<PageDataDto<HomeWorkListModel>> GetHomeWorkPageList(HomeWorkPageListParam paramDto)
{
var res = new PageDataDto<HomeWorkListModel>();
var currentTime = DateTime.Now;
string schoolCode = "";
if (!string.IsNullOrWhiteSpace(paramDto.SchoolCode))
{
schoolCode = paramDto.SchoolCode;
}
else
{
schoolCode = UserContext.Current.TenantId;
}
var query = from s in _homeWorkRepository.FindAsIQueryable(x => x.SchoolCode == schoolCode)
select new HomeWorkListModel()
{
WorkId = s.Id,
TeacherId = s.TeacherId,
StudentScope = s.StudentScope,
WorkStatus = s.EndTime < currentTime ? HomeWorkStatus.Ended : (s.StartTime > currentTime ? HomeWorkStatus.NotStarted : HomeWorkStatus.Afoot),
TeacherName = s.TeacherName,
WorkName = s.WorkName,
WorkText = s.WorkText,
WorkType = s.WorkType,
WorkModeType = s.WorkModeType,
WorkModeTypeName = s.WorkModeType.GetDescription(),
StartTime = s.StartTime,
EndTime = s.EndTime,
StudentScopeStr = s.StudentScope.GetDescription(),
WorkStatusStr = s.WorkStatus.GetDescription(),
WorkTypeName = s.WorkTypeName,
GradeAndClassName = $"{s.GradeName}-{s.ClassName}"
};
if (paramDto.WorkType > 0)
{
query = query.Where(x => x.WorkType == paramDto.WorkType);
}
if (paramDto.StudentScope > 0)
{
query = query.Where(x => x.StudentScope == paramDto.StudentScope);
}
if (paramDto.WorkStatus > 0)
{
query = query.Where(x => x.WorkStatus == paramDto.WorkStatus);
}
if (!string.IsNullOrWhiteSpace(paramDto.TeacherName))
{
query = query.Where(x => x.TeacherName == paramDto.TeacherName);
}
if (paramDto.StartTime.HasValue)
{
DateTime detectionDate = paramDto.StartTime.Value.Date;
query = query.Where(x => x.StartTime.HasValue && x.StartTime.Value.Date >= detectionDate);
}
if (paramDto.EndTime.HasValue)
{
DateTime detectionDate = paramDto.EndTime.Value.Date;
query = query.Where(x => x.EndTime.HasValue && x.EndTime.Value.Date < detectionDate);
}
res.Total = await query.CountAsync();
var list = await query
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
.Take(paramDto.PageSize)
.ToListAsync();
res.Datas = list;
return res;
}
public async Task<List<HomeWorkStudentExportModel>> GetHomeWorkStudentExportList(HomeWorkExportParam paramDto)
{
const int maxExportRowCount = 100000;
var currentTime = DateTime.Now;
var schoolCode = string.IsNullOrWhiteSpace(paramDto.SchoolCode)
? UserContext.Current.TenantId
: paramDto.SchoolCode;
var homeWorkQuery = _homeWorkRepository
.FindAsIQueryable(x => x.SchoolCode == schoolCode);
if (!string.IsNullOrWhiteSpace(paramDto.HomeWorkIds))
{
var homeWorkIds = paramDto.HomeWorkIds
.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(value => int.TryParse(value.Trim(), out var id) ? id : 0)
.Where(id => id > 0)
.Distinct()
.ToList();
if (homeWorkIds.Count == 0)
throw new Exception("请选择有效的作业后再导出");
homeWorkQuery = homeWorkQuery.Where(x => homeWorkIds.Contains(x.Id));
}
if (paramDto.WorkType > 0)
homeWorkQuery = homeWorkQuery.Where(x => x.WorkType == paramDto.WorkType);
if (paramDto.StudentScope > 0)
homeWorkQuery = homeWorkQuery.Where(x => x.StudentScope == paramDto.StudentScope);
if (paramDto.WorkStatus == HomeWorkStatus.NotStarted)
homeWorkQuery = homeWorkQuery.Where(x => x.StartTime > currentTime);
else if (paramDto.WorkStatus == HomeWorkStatus.Afoot)
homeWorkQuery = homeWorkQuery.Where(x => x.StartTime <= currentTime && x.EndTime >= currentTime);
else if (paramDto.WorkStatus == HomeWorkStatus.Ended)
homeWorkQuery = homeWorkQuery.Where(x => x.EndTime < currentTime);
if (!string.IsNullOrWhiteSpace(paramDto.TeacherName))
homeWorkQuery = homeWorkQuery.Where(x => x.TeacherName == paramDto.TeacherName);
if (paramDto.StartTime.HasValue)
{
var startDate = paramDto.StartTime.Value.Date;
homeWorkQuery = homeWorkQuery.Where(x => x.StartTime.Date >= startDate);
}
if (paramDto.EndTime.HasValue)
{
var endDate = paramDto.EndTime.Value.Date;
homeWorkQuery = homeWorkQuery.Where(x => x.EndTime.Date < endDate);
}
var studentQuery = _homeWorkStudentsRepository.FindAsIQueryable(x => true);
if (paramDto.StudentWorkStatus.HasValue)
studentQuery = studentQuery.Where(x => x.WorkStatus == paramDto.StudentWorkStatus.Value);
var query =
from homeWork in homeWorkQuery
join student in studentQuery
on homeWork.Id equals student.HomeWorkId
orderby homeWork.StartTime descending, homeWork.Id descending, student.StudentNo
select new
{
homeWork.WorkTypeName,
homeWork.TeacherName,
homeWork.WorkName,
homeWork.GradeName,
homeWork.ClassName,
homeWork.StudentScope,
homeWork.WorkText,
homeWork.StartTime,
homeWork.EndTime,
homeWork.WorkModeType,
student.StudentNo,
student.StudentName,
student.Sex,
student.WorkStatus,
student.Value
};
var total = await query.CountAsync();
if (total == 0)
throw new Exception("当前筛选条件下没有可导出的作业学生数据");
if (total > maxExportRowCount)
throw new Exception($"导出数据共{total}行,单次最多导出{maxExportRowCount}行,请缩小筛选范围后重试");
var rows = await query.ToListAsync();
return rows.Select(x => new HomeWorkStudentExportModel
{
WorkTypeName = x.WorkTypeName,
TeacherName = x.TeacherName,
WorkName = x.WorkName,
GradeAndClassName = $"{x.GradeName}-{x.ClassName}",
StudentScopeName = x.StudentScope.GetDescription(),
WorkText = x.WorkText,
StartTime = x.StartTime,
EndTime = x.EndTime,
StudentNo = x.StudentNo,
StudentName = x.StudentName,
SexName = x.Sex.GetDescription(),
StudentWorkStatusName = x.WorkStatus == StudentWorkStatus.Completed ? "已完成" : "未完成",
Result = x.WorkStatus == StudentWorkStatus.Completed
? FormatWorkResult(x.Value, x.WorkModeType)
: string.Empty
}).ToList();
}
private static string FormatWorkResult(int value, WorkModeType workModeType)
{
if (workModeType != WorkModeType.CountTimer)
return value.ToString();
var seconds = Math.Max(value, 0);
var hours = seconds / 3600;
var minutes = seconds % 3600 / 60;
var remainingSeconds = seconds % 60;
return $"{hours:00}:{minutes:00}:{remainingSeconds:00}";
}
public async Task<PageDataDto<HomeWorkStudentsModel>> GetHomeWorkStudents(HomeWorkStudentsParam paramDto)
{
var res = new PageDataDto<HomeWorkStudentsModel>();
var query = from s in _homeWorkStudentsRepository.FindAsIQueryable(x => x.HomeWorkId == paramDto.HomeWorkId)
select new HomeWorkStudentsModel()
{
WorkId = s.HomeWorkId,
StudentNo = s.StudentNo,
StudentName = s.StudentName,
Photo = s.Photo,
WorkStatus = s.WorkStatus,
Value = s.Value,
WorkStatusStr = s.WorkStatus.GetDescription()
};
res.Total = await query.CountAsync();
var list = await query
.Skip((paramDto.PageIndex - 1) * paramDto.PageSize)
.Take(paramDto.PageSize)
.ToListAsync();
res.Datas = list;
return res;
}
public async Task<List<SubmittedAssignmentsModel>> GetSubmittedAssignments(int homeWorkId, string studentNo)
{
var res = await _submittedAssignmentsRepository
.FindAsIQueryable(x => x.HomeWorkId == homeWorkId &&
x.StudentNo == studentNo)
.Select(x => new SubmittedAssignmentsModel()
{
HomeWorkId = x.HomeWorkId,
StudentNo = x.StudentNo,
FileName = x.FileName,
FilePath = x.FilePath,
FileSize = x.FileSize,
FileType = x.FileType
}).ToListAsync();
return res;
}
}
}