|
|
|
@ -5,11 +5,9 @@ import cn.hutool.core.collection.CollectionUtil;
|
|
|
|
|
import cn.hutool.core.lang.Assert;
|
|
|
|
|
import cn.hutool.core.util.BooleanUtil;
|
|
|
|
|
import cn.hutool.core.util.ReUtil;
|
|
|
|
|
import cn.jlw.util.EnumUtil;
|
|
|
|
|
import cn.jlw.util.ToolUtils;
|
|
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
import com.ibeetl.admin.core.entity.CoreUser;
|
|
|
|
|
import com.ibeetl.admin.core.service.CoreBaseService;
|
|
|
|
|
import com.ibeetl.admin.core.util.PlatformException;
|
|
|
|
|
import com.ibeetl.admin.core.web.JsonResult;
|
|
|
|
@ -21,7 +19,6 @@ import com.ibeetl.jlw.entity.ResourcesQuestionSnapshot;
|
|
|
|
|
import com.ibeetl.jlw.entity.Student;
|
|
|
|
|
import com.ibeetl.jlw.entity.TeacherOpenCourseQuestionLog;
|
|
|
|
|
import com.ibeetl.jlw.entity.TeacherOpenCourseQuestionSetting;
|
|
|
|
|
import com.ibeetl.jlw.enums.ResourcesQuestionSnapshotFromTypeEnum;
|
|
|
|
|
import com.ibeetl.jlw.web.query.ResourcesQuestionSnapshotQuery;
|
|
|
|
|
import com.ibeetl.jlw.web.query.TeacherOpenCourseQuestionLogQuery;
|
|
|
|
|
import com.ibeetl.jlw.web.query.TeacherOpenCourseQuestionSettingQuery;
|
|
|
|
@ -42,10 +39,7 @@ import java.math.BigDecimal;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
|
|
|
|
|
import static cn.hutool.core.util.ArrayUtil.join;
|
|
|
|
|
import static com.ibeetl.admin.core.util.user.CacheUserUtil.getUser;
|
|
|
|
|
import static com.ibeetl.admin.core.util.user.CacheUserUtil.getUserId;
|
|
|
|
|
import static com.ibeetl.jlw.entity.ResourcesQuestionOptionEntity.shuffleOrderOptions;
|
|
|
|
|
import static com.ibeetl.jlw.enums.ResourcesQuestionSnapshotFromTypeEnum.CHAPTER_EXERCISE;
|
|
|
|
|
import static java.util.stream.Collectors.groupingBy;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -65,6 +59,7 @@ public class TeacherOpenCourseQuestionLogService extends CoreBaseService<Teacher
|
|
|
|
|
@Autowired @Lazy
|
|
|
|
|
private TeacherOpenCourseQuestionSettingService teacherOpenCourseQuestionSettingSettingService;
|
|
|
|
|
@Autowired private TeacherOpenCourseQuestionLogWrongService teacherOpenCourseQuestionLogWrongService;
|
|
|
|
|
@Autowired private TeacherOpenCourseQuestionSettingService teacherOpenCourseQuestionSettingService;
|
|
|
|
|
|
|
|
|
|
public PageQuery<TeacherOpenCourseQuestionLog>queryByCondition(PageQuery query){
|
|
|
|
|
PageQuery ret = teacherOpenCourseQuestionLogDao.queryByCondition(query);
|
|
|
|
@ -247,6 +242,23 @@ public class TeacherOpenCourseQuestionLogService extends CoreBaseService<Teacher
|
|
|
|
|
insertBatch(list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 教师端-手动批改一些题目的分数
|
|
|
|
|
*
|
|
|
|
|
* @param teacherOpenCourseQuestionLogIds 指定更新分数的题目日志IDs
|
|
|
|
|
* @param score
|
|
|
|
|
*/
|
|
|
|
|
public void manualModifyQuestionScores(@NotNull(message = "题目做题日志ID不能为空!") final String teacherOpenCourseQuestionLogIds, @NotEmpty final BigDecimal score) {
|
|
|
|
|
TeacherOpenCourseQuestionLogQuery teacherOpenCourseQuestionLogQuery = new TeacherOpenCourseQuestionLogQuery();
|
|
|
|
|
teacherOpenCourseQuestionLogQuery.setTeacherOpenCourseQuestionLogIdPlural(teacherOpenCourseQuestionLogIds);
|
|
|
|
|
teacherOpenCourseQuestionLogQuery.setTeacherOpenCourseQuestionLogStatus(1);
|
|
|
|
|
List<TeacherOpenCourseQuestionLog> updateList = teacherOpenCourseQuestionLogDao.getValuesByQueryNotWithPermission(teacherOpenCourseQuestionLogQuery);
|
|
|
|
|
|
|
|
|
|
// 批量更新分数
|
|
|
|
|
updateList.forEach(questionLog -> questionLog.setQuestionScore(score));
|
|
|
|
|
updateBatchTemplate(updateList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 和题目有关的做题提交方法
|
|
|
|
|
* 直接计算出学生得分情况
|
|
|
|
@ -255,15 +267,59 @@ public class TeacherOpenCourseQuestionLogService extends CoreBaseService<Teacher
|
|
|
|
|
* @param questionSettingId 题目配置ID
|
|
|
|
|
*/
|
|
|
|
|
public void insertQuestionLog(
|
|
|
|
|
@NotEmpty(message = "请上传题目快照ID和答案!") Map<Long, TreeSet<String>> questionLogMap,
|
|
|
|
|
@NotEmpty(message = "请上传题目快照ID和答案!") Map<String, TreeSet<String>> questionLogMap,
|
|
|
|
|
@NotNull(message = "开课题目配置ID不能为空!") final Long questionSettingId) {
|
|
|
|
|
|
|
|
|
|
// 查询学生身份
|
|
|
|
|
final Student student = studentDao.getByUserId(getUserId());
|
|
|
|
|
|
|
|
|
|
TeacherOpenCourseQuestionSetting info = teacherOpenCourseQuestionSettingService.getInfo(questionSettingId);
|
|
|
|
|
switch(info.getTeacherOpenCourseQuestionSettingType()) {
|
|
|
|
|
case HOMEWORK_FILE: {
|
|
|
|
|
addFileRelatedLog(join(questionLogMap.values().toArray(), ","), questionSettingId, student);
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
// 这些都和题目相关,暂时先放在一个方法
|
|
|
|
|
case CHAPTER_EXERCISE:
|
|
|
|
|
case EXAM:
|
|
|
|
|
case HOMEWORK_QUESTION:{
|
|
|
|
|
addQuestionRelatedLog(questionLogMap, questionSettingId, student);
|
|
|
|
|
} break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 跟题目相关的题目日志提交方法
|
|
|
|
|
* 附件类型的需要单独,拆分除去
|
|
|
|
|
*
|
|
|
|
|
* @param absFilePath
|
|
|
|
|
* @param questionSettingId
|
|
|
|
|
* @param student
|
|
|
|
|
*/
|
|
|
|
|
private void addFileRelatedLog(@NotBlank(message = "上传的附件不能为空!") String absFilePath, Long questionSettingId, Student student) {
|
|
|
|
|
TeacherOpenCourseQuestionLogQuery query = new TeacherOpenCourseQuestionLogQuery();
|
|
|
|
|
query.setTeacherOpenCourseQuestionLogUploadFile(absFilePath);
|
|
|
|
|
query.setTeacherOpenCourseQuestionSettingId(questionSettingId);
|
|
|
|
|
query.setTeacherOpenCourseQuestionLogStatus(1);
|
|
|
|
|
query.setOrgId(student.getOrgId());
|
|
|
|
|
query.setUserId(student.getUserId());
|
|
|
|
|
query.setStudentId(student.getStudentId());
|
|
|
|
|
add(query);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 跟题目相关的题目日志提交方法
|
|
|
|
|
* 附件类型的需要单独,拆分除去
|
|
|
|
|
*
|
|
|
|
|
* @param questionLogMap
|
|
|
|
|
* @param questionSettingId
|
|
|
|
|
* @param student
|
|
|
|
|
*/
|
|
|
|
|
private void addQuestionRelatedLog(Map<String, TreeSet<String>> questionLogMap, Long questionSettingId, Student student) {
|
|
|
|
|
// 查询符合条件的日志表
|
|
|
|
|
String questionSnapshotIds = join(questionLogMap.keySet().toArray(), ",");
|
|
|
|
|
|
|
|
|
|
// 做题思路:先从开课QuestionSetting表中生成题目日志,到开课QuestionLog中,学生这个时候提交答案,再修改日志中的结果。
|
|
|
|
|
// 查询条件
|
|
|
|
|
TeacherOpenCourseQuestionLogQuery questionLogQuery = TeacherOpenCourseQuestionLogQuery.builder()
|
|
|
|
|
.resourcesQuestionSnapshotIdPlural(questionSnapshotIds)
|
|
|
|
@ -278,110 +334,22 @@ public class TeacherOpenCourseQuestionLogService extends CoreBaseService<Teacher
|
|
|
|
|
logList.forEach(questionLog -> {
|
|
|
|
|
// 学生提交的答案
|
|
|
|
|
String answersText = join(questionLogMap.get(questionLog.getResourcesQuestionSnapshotId()).toArray(), ",");
|
|
|
|
|
// 包含/字符,代表是路径地址,是附件类型
|
|
|
|
|
if(answersText.startsWith("/")) {
|
|
|
|
|
questionLog.setTeacherOpenCourseQuestionLogUploadFile(answersText);
|
|
|
|
|
}
|
|
|
|
|
// 否则就是普通选择题的答案
|
|
|
|
|
else {
|
|
|
|
|
questionLog.setTeacherOpenCourseQuestionLogAnswer(answersText);
|
|
|
|
|
}
|
|
|
|
|
questionLog.setTeacherOpenCourseQuestionLogAnswer(answersText);
|
|
|
|
|
|
|
|
|
|
// 是否是正确答案
|
|
|
|
|
Boolean isCorrectAnswer = questionLog.getQuestionAnswer().equalsIgnoreCase(answersText);
|
|
|
|
|
|
|
|
|
|
// 计算该题目学生的得分情况
|
|
|
|
|
questionLog.setStudentScore(isCorrectAnswer ? questionLog.getQuestionScore() : BigDecimal.valueOf(0));
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 学生做的题目的答案与日志关联
|
|
|
|
|
updateBatchTemplate(logList);
|
|
|
|
|
|
|
|
|
|
// 批量插入错题集,方法内部自带判断
|
|
|
|
|
// 批量插入错题集,方法内部自带分数判断
|
|
|
|
|
teacherOpenCourseQuestionLogWrongService.insertBatchByQuestionLogList(logList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取作业
|
|
|
|
|
*
|
|
|
|
|
* @param teacherOpenCourseQuestionSettingId 开课作业ID
|
|
|
|
|
* @param fromTypeEnum
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public List<ResourcesQuestionSnapshot> questionDetail(@NotNull(message = "题目配置ID不能为空!") final Long teacherOpenCourseQuestionSettingId,
|
|
|
|
|
@NotNull(message = "类型不能为空!") ResourcesQuestionSnapshotFromTypeEnum fromTypeEnum) {
|
|
|
|
|
|
|
|
|
|
// 获取学生ID
|
|
|
|
|
CoreUser coreUser = getUser();
|
|
|
|
|
final Student student = studentDao.getByUserId(coreUser.getId());
|
|
|
|
|
|
|
|
|
|
// 常量 True的Integer表现
|
|
|
|
|
final Integer TRUE_CONST = 1;
|
|
|
|
|
List<ResourcesQuestionSnapshot> resourcesQuestionSnapshots = new ArrayList<>();
|
|
|
|
|
TeacherOpenCourseQuestionSetting homework = teacherOpenCourseQuestionSettingSettingService.getInfo(teacherOpenCourseQuestionSettingId);
|
|
|
|
|
Assert.notNull(homework, "未查询到来源ID对应的题目!");
|
|
|
|
|
|
|
|
|
|
TeacherOpenCourseQuestionSettingQuery settingQuery = new TeacherOpenCourseQuestionSettingQuery();
|
|
|
|
|
settingQuery.setTeacherOpenCourseQuestionSettingId(teacherOpenCourseQuestionSettingId);
|
|
|
|
|
TeacherOpenCourseQuestionSetting hwSetting = teacherOpenCourseQuestionSettingSettingService.getInfo(settingQuery);
|
|
|
|
|
|
|
|
|
|
ResourcesQuestionSnapshotQuery questionSnapshotQuery = new ResourcesQuestionSnapshotQuery();
|
|
|
|
|
questionSnapshotQuery.setTeacherOpenCourseQuestionSettingId(teacherOpenCourseQuestionSettingId);
|
|
|
|
|
|
|
|
|
|
// 章节练习,则跳过次数验证
|
|
|
|
|
if (!EnumUtil.contains(fromTypeEnum, CHAPTER_EXERCISE)) {
|
|
|
|
|
// 作答次数
|
|
|
|
|
Integer teacherOpenCourseQuestionSettingSettingDoCount = hwSetting.getTeacherOpenCourseQuestionSettingDoCount();
|
|
|
|
|
Assert.isTrue(teacherOpenCourseQuestionSettingSettingDoCount > 1, "作答次数设置有误,请联系管理员!");
|
|
|
|
|
// 数据库查询该学生已经做过的次数
|
|
|
|
|
TeacherOpenCourseQuestionLog teacherOpenCourseQuestionLog = new TeacherOpenCourseQuestionLog();
|
|
|
|
|
teacherOpenCourseQuestionLog.setStudentId(student.getStudentId());
|
|
|
|
|
long doCount = teacherOpenCourseQuestionLogDao.templateCount(teacherOpenCourseQuestionLog);
|
|
|
|
|
// 断言判断最大作答次数
|
|
|
|
|
Assert.isTrue(doCount < teacherOpenCourseQuestionSettingSettingDoCount, "已超过最大作答次数!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 答卷后显示答案解析
|
|
|
|
|
if (TRUE_CONST.equals(hwSetting.getTeacherOpenCourseQuestionSettingEndShowQa())) {
|
|
|
|
|
// TODO 逻辑不要在这里写
|
|
|
|
|
/** 实现 {@link TeacherOpenCourseQuestionLogService#questionAnalysis(TreeSet)} */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 答卷后显示答案对错
|
|
|
|
|
if (TRUE_CONST.equals(hwSetting.getTeacherOpenCourseQuestionSettingEndShowTrueFalse())) {
|
|
|
|
|
// TODO 逻辑不要在这里写
|
|
|
|
|
/** 实现 {@link TeacherOpenCourseQuestionLogService#questionAnalysis(TreeSet)} */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 题目乱序(同一大题内)
|
|
|
|
|
if (TRUE_CONST.equals(hwSetting.getTeacherOpenCourseQuestionSettingQuestionNoOrder())) {
|
|
|
|
|
questionSnapshotQuery.setRand(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 题目查询
|
|
|
|
|
resourcesQuestionSnapshots = resourcesQuestionSnapshotDao.getValuesByQuery(questionSnapshotQuery);
|
|
|
|
|
|
|
|
|
|
// 选项乱序(限单选、多选)
|
|
|
|
|
if (TRUE_CONST.equals(hwSetting.getTeacherOpenCourseQuestionSettingOptionNoOrder())) {
|
|
|
|
|
// 单题选项排序处理
|
|
|
|
|
resourcesQuestionSnapshots.forEach(value -> {
|
|
|
|
|
shuffleOrderOptions(value, "questionAnswer","questionOption", true);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 学生身份屏蔽答案,且记录在做题日志表中
|
|
|
|
|
if (coreUser.isStudent()) {
|
|
|
|
|
// 做题日志关联学生, 初步提交做题日志信息,不包含学生提交的答案和得分情况
|
|
|
|
|
preSubmitStudentQuestionLog(student.getStudentId(), teacherOpenCourseQuestionSettingId, resourcesQuestionSnapshots);
|
|
|
|
|
// 学生身份,需要屏蔽答案,再丢给前端
|
|
|
|
|
resourcesQuestionSnapshots.forEach(ResourcesQuestionSnapshot::hideAnswer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resourcesQuestionSnapshots;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 日志关联学生信息和配置ID信息
|
|
|
|
|
*
|
|
|
|
@ -397,6 +365,7 @@ public class TeacherOpenCourseQuestionLogService extends CoreBaseService<Teacher
|
|
|
|
|
|
|
|
|
|
// teacherOpenCourseQuestionSettingId:类似试卷ID,题目日志里会出现重复的试卷ID
|
|
|
|
|
// 逻辑删除之前的题目日志,防止学生做题统计数据异常
|
|
|
|
|
// 保证试卷是最新的
|
|
|
|
|
logicDeleteTeacherOpenCourseQuestionLogBySettingIds(String.valueOf(teacherOpenCourseQuestionSettingId));
|
|
|
|
|
|
|
|
|
|
// 断言
|
|
|
|
@ -418,16 +387,36 @@ public class TeacherOpenCourseQuestionLogService extends CoreBaseService<Teacher
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 开课相关-考试或者作业,答题提交后,获取问题解析。根据配置获取
|
|
|
|
|
* @param questionSnapshotIds
|
|
|
|
|
* 根据题目配置ID查询题目快照,并根据类型分组
|
|
|
|
|
*
|
|
|
|
|
* @param questionSettingId
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public Map<Long, List<ResourcesQuestionSnapshot>> questionAnalysis(@NotEmpty(message = "请上传题目快照ID和答案!") final TreeSet<Long> questionSnapshotIds) {
|
|
|
|
|
public Map<Integer, List<ResourcesQuestionSnapshot>> questionAnalysis(@NotNull(message = "题目配置ID不能为空!") Long questionSettingId) {
|
|
|
|
|
ResourcesQuestionSnapshotQuery resourcesQuestionSnapshotQuery = new ResourcesQuestionSnapshotQuery();
|
|
|
|
|
resourcesQuestionSnapshotQuery.setTeacherOpenCourseQuestionSettingId(questionSettingId);
|
|
|
|
|
resourcesQuestionSnapshotQuery.setQuestionStatus(1);
|
|
|
|
|
List<ResourcesQuestionSnapshot> valuesByQuery = resourcesQuestionSnapshotDao.getValuesByQuery(resourcesQuestionSnapshotQuery);
|
|
|
|
|
return questionAnalysis(valuesByQuery);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 查询题目快照列表
|
|
|
|
|
List<ResourcesQuestionSnapshot> questionSnapshots = resourcesQuestionSnapshotDao.getByIds(join(questionSnapshotIds.toArray(), ","));
|
|
|
|
|
/**
|
|
|
|
|
* 根据题目快照ID查询题目快照,并根据类型分组
|
|
|
|
|
*
|
|
|
|
|
* @param questionSnapshotIds
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public Map<Integer, List<ResourcesQuestionSnapshot>> questionAnalysis(@NotNull(message = "题目配置ID不能为空!") TreeSet<Long> questionSnapshotIds) {
|
|
|
|
|
List<ResourcesQuestionSnapshot> valuesByQuery = resourcesQuestionSnapshotDao.getByIds(join(questionSnapshotIds.toArray(), ","));
|
|
|
|
|
return questionAnalysis(valuesByQuery);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Assert.notEmpty(questionSnapshots, "未查询到题目列表!");
|
|
|
|
|
/**
|
|
|
|
|
* 开课相关-考试或者作业,答题提交后,获取问题解析。根据配置获取
|
|
|
|
|
* @param questionSnapshots
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public Map<Integer, List<ResourcesQuestionSnapshot>> questionAnalysis(@NotEmpty(message = "未查询到题目列表!") final List<ResourcesQuestionSnapshot> questionSnapshots) {
|
|
|
|
|
|
|
|
|
|
TeacherOpenCourseQuestionSettingQuery settingQuery = new TeacherOpenCourseQuestionSettingQuery();
|
|
|
|
|
settingQuery.setTeacherOpenCourseQuestionSettingId(questionSnapshots.get(0).getTeacherOpenCourseQuestionSettingId());
|
|
|
|
@ -444,7 +433,7 @@ public class TeacherOpenCourseQuestionLogService extends CoreBaseService<Teacher
|
|
|
|
|
resourcesQuestionSnapshot.setQuestionAnswer(isEndShowQa ? item.getQuestionAnswer() : "");
|
|
|
|
|
resourcesQuestionSnapshot.setQuestionAnalysis(isEndShowTrueFalse ? item.getQuestionAnalysis(): "");
|
|
|
|
|
return resourcesQuestionSnapshot;
|
|
|
|
|
}).collect(groupingBy(ResourcesQuestionSnapshot::getResourcesQuestionSnapshotId));
|
|
|
|
|
}).collect(groupingBy(ResourcesQuestionSnapshot::getQuestionType));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|