|
|
@@ -0,0 +1,516 @@
|
|
|
+package com.sckw.system.service;
|
|
|
+
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.sckw.core.exception.SystemException;
|
|
|
+import com.sckw.core.model.constant.Global;
|
|
|
+import com.sckw.core.web.constant.HttpStatus;
|
|
|
+import com.sckw.core.web.context.LoginUserHolder;
|
|
|
+import com.sckw.core.web.response.result.PageDataResult;
|
|
|
+import com.sckw.system.model.TExam;
|
|
|
+import com.sckw.system.model.TQuestion;
|
|
|
+import com.sckw.system.model.TQuestionItem;
|
|
|
+import com.sckw.system.model.pojo.ExamStatusEnum;
|
|
|
+import com.sckw.system.model.pojo.QuestionTypeEnum;
|
|
|
+import com.sckw.system.model.vo.req.ExamManagePageReqVo;
|
|
|
+import com.sckw.system.model.vo.req.ExamSaveReqVo;
|
|
|
+import com.sckw.system.model.vo.req.ExamStatusReqVo;
|
|
|
+import com.sckw.system.model.vo.req.IdReqVo;
|
|
|
+import com.sckw.system.model.vo.res.ExamDetailResVo;
|
|
|
+import com.sckw.system.model.vo.res.ExamManageItemResVo;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.LinkedHashSet;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class KwsExamService {
|
|
|
+
|
|
|
+ private final TExamService tExamService;
|
|
|
+ private final TQuestionService tQuestionService;
|
|
|
+ private final TQuestionItemService tQuestionItemService;
|
|
|
+
|
|
|
+ public List<ExamManageItemResVo> listOnShelfExams() {
|
|
|
+ LambdaQueryWrapper<TExam> wrapper = new LambdaQueryWrapper<>();
|
|
|
+ wrapper.eq(TExam::getDelFlag, Global.UN_DELETED)
|
|
|
+ .eq(TExam::getStatus, 1)
|
|
|
+ .orderByDesc(TExam::getCreateTime);
|
|
|
+
|
|
|
+ Set<Long> entIds = resolveAuthorizedEntIds();
|
|
|
+ if (!entIds.isEmpty()) {
|
|
|
+ wrapper.in(TExam::getEntId, entIds);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<TExam> exams = tExamService.list(wrapper);
|
|
|
+ return exams.stream().map(this::toManageItem).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ public PageDataResult<ExamManageItemResVo> manageExamPage(ExamManagePageReqVo reqVo) {
|
|
|
+ Page<TExam> page = new Page<>(reqVo.getPageNum(), reqVo.getPageSize());
|
|
|
+ LambdaQueryWrapper<TExam> wrapper = new LambdaQueryWrapper<>();
|
|
|
+ wrapper.eq(TExam::getDelFlag, Global.UN_DELETED)
|
|
|
+ .orderByDesc(TExam::getCreateTime);
|
|
|
+
|
|
|
+ Set<Long> entIds = resolveAuthorizedEntIds();
|
|
|
+ if (!entIds.isEmpty()) {
|
|
|
+ wrapper.in(TExam::getEntId, entIds);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (StrUtil.isNotBlank(reqVo.getName())) {
|
|
|
+ wrapper.like(TExam::getName, reqVo.getName().trim());
|
|
|
+ }
|
|
|
+ if (reqVo.getStatus() != null && reqVo.getStatus() > 0) {
|
|
|
+ wrapper.eq(TExam::getStatus, reqVo.getStatus());
|
|
|
+ }
|
|
|
+
|
|
|
+ Page<TExam> examPage = tExamService.page(page, wrapper);
|
|
|
+ return PageDataResult.of(page, examPage.getRecords().stream().map(this::toManageItem).collect(Collectors.toList()));
|
|
|
+ }
|
|
|
+
|
|
|
+ public ExamDetailResVo manageExamDetail(Long examId) {
|
|
|
+ TExam exam = tExamService.getById(examId);
|
|
|
+ if (exam == null || !Objects.equals(exam.getDelFlag(), Global.UN_DELETED)) {
|
|
|
+ throw new SystemException(HttpStatus.QUERY_FAIL_CODE, "考试不存在");
|
|
|
+ }
|
|
|
+ if (!isAuthorizedEnt(exam.getEntId())) {
|
|
|
+ throw new SystemException(HttpStatus.AUTHORITY_NO_CODE, HttpStatus.ACCESS_FIAL);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<TQuestion> questions = tQuestionService.lambdaQuery()
|
|
|
+ .eq(TQuestion::getDelFlag, Global.UN_DELETED)
|
|
|
+ .eq(TQuestion::getExamId, examId)
|
|
|
+ .orderByAsc(TQuestion::getId)
|
|
|
+ .list();
|
|
|
+
|
|
|
+ Map<Long, List<TQuestionItem>> itemMap;
|
|
|
+ if (CollUtil.isNotEmpty(questions)) {
|
|
|
+ List<Long> questionIds = questions.stream().map(TQuestion::getId).filter(Objects::nonNull).toList();
|
|
|
+ List<TQuestionItem> items = tQuestionItemService.lambdaQuery()
|
|
|
+ .eq(TQuestionItem::getDelFlag, Global.UN_DELETED)
|
|
|
+ .in(TQuestionItem::getQuestionId, questionIds)
|
|
|
+ .orderByAsc(TQuestionItem::getSort)
|
|
|
+ .orderByAsc(TQuestionItem::getId)
|
|
|
+ .list();
|
|
|
+ itemMap = items.stream().collect(Collectors.groupingBy(TQuestionItem::getQuestionId));
|
|
|
+ } else {
|
|
|
+ itemMap = Collections.emptyMap();
|
|
|
+ }
|
|
|
+
|
|
|
+ ExamDetailResVo detail = toDetail(exam);
|
|
|
+ List<ExamDetailResVo.Question> questionVos = questions.stream().map(q -> {
|
|
|
+ ExamDetailResVo.Question vo = new ExamDetailResVo.Question();
|
|
|
+ vo.setId(q.getId());
|
|
|
+ vo.setName(q.getName());
|
|
|
+ vo.setType(q.getType());
|
|
|
+ vo.setTypeName(QuestionTypeEnum.getNameByCode(q.getType()));
|
|
|
+ List<TQuestionItem> items = itemMap.getOrDefault(q.getId(), Collections.emptyList());
|
|
|
+ List<ExamDetailResVo.QuestionItem> itemVos = items.stream().map(this::toQuestionItem).toList();
|
|
|
+ vo.setItems(itemVos);
|
|
|
+ return vo;
|
|
|
+ }).toList();
|
|
|
+
|
|
|
+ detail.setQuestions(questionVos);
|
|
|
+ detail.setAmount(questionVos.size());
|
|
|
+ return detail;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Long addExam(ExamSaveReqVo reqVo) {
|
|
|
+ validateSaveReq(reqVo, false);
|
|
|
+
|
|
|
+ Long entId = LoginUserHolder.getEntId();
|
|
|
+ if (entId == null) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_MISSING_CODE, "企业信息缺失");
|
|
|
+ }
|
|
|
+
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
+ Long userId = LoginUserHolder.getUserId();
|
|
|
+
|
|
|
+ List<ExamSaveReqVo.Question> questions = reqVo.getQuestions() == null ? Collections.emptyList() : reqVo.getQuestions();
|
|
|
+ int amount = questions.size();
|
|
|
+
|
|
|
+ TExam exam = new TExam();
|
|
|
+ exam.setEntId(entId);
|
|
|
+ exam.setName(reqVo.getName().trim());
|
|
|
+ exam.setExamDuration(reqVo.getExamDuration());
|
|
|
+ exam.setPassRate(reqVo.getPassRate());
|
|
|
+ exam.setAmount(amount);
|
|
|
+ exam.setDescription(normalizeNullable(reqVo.getDescription()));
|
|
|
+ exam.setStatus(reqVo.getStatus() == null ? 1 : reqVo.getStatus());
|
|
|
+ exam.setCreateBy(userId);
|
|
|
+ exam.setCreateTime(now);
|
|
|
+ exam.setUpdateBy(userId);
|
|
|
+ exam.setUpdateTime(now);
|
|
|
+ exam.setDelFlag(Global.UN_DELETED);
|
|
|
+
|
|
|
+ if (!tExamService.save(exam)) {
|
|
|
+ throw new SystemException(HttpStatus.CRUD_FAIL_CODE, "新增考试失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ saveQuestionsAndItems(exam.getId(), entId, userId, now, questions);
|
|
|
+ return exam.getId();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Boolean updateExam(ExamSaveReqVo reqVo) {
|
|
|
+ validateSaveReq(reqVo, true);
|
|
|
+
|
|
|
+ TExam exam = tExamService.getById(reqVo.getId());
|
|
|
+ if (exam == null || !Objects.equals(exam.getDelFlag(), Global.UN_DELETED)) {
|
|
|
+ throw new SystemException(HttpStatus.QUERY_FAIL_CODE, "考试不存在");
|
|
|
+ }
|
|
|
+ if (!isAuthorizedEnt(exam.getEntId())) {
|
|
|
+ throw new SystemException(HttpStatus.AUTHORITY_NO_CODE, HttpStatus.ACCESS_FIAL);
|
|
|
+ }
|
|
|
+
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
+ Long userId = LoginUserHolder.getUserId();
|
|
|
+
|
|
|
+ List<ExamSaveReqVo.Question> questions = reqVo.getQuestions() == null ? Collections.emptyList() : reqVo.getQuestions();
|
|
|
+ int amount = questions.size();
|
|
|
+
|
|
|
+ exam.setName(reqVo.getName().trim());
|
|
|
+ exam.setExamDuration(reqVo.getExamDuration());
|
|
|
+ exam.setPassRate(reqVo.getPassRate());
|
|
|
+ exam.setAmount(amount);
|
|
|
+ exam.setDescription(normalizeNullable(reqVo.getDescription()));
|
|
|
+ if (reqVo.getStatus() != null) {
|
|
|
+ exam.setStatus(reqVo.getStatus());
|
|
|
+ }
|
|
|
+ exam.setUpdateBy(userId);
|
|
|
+ exam.setUpdateTime(now);
|
|
|
+
|
|
|
+ if (!tExamService.updateById(exam)) {
|
|
|
+ throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
|
|
|
+ }
|
|
|
+
|
|
|
+ logicDeleteQuestionsAndItemsByExamId(exam.getId(), userId, now);
|
|
|
+ saveQuestionsAndItems(exam.getId(), exam.getEntId(), userId, now, questions);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Boolean updateExamStatus(ExamStatusReqVo reqVo) {
|
|
|
+ if (reqVo == null || reqVo.getId() == null) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_MISSING_CODE, HttpStatus.ID_MISSING);
|
|
|
+ }
|
|
|
+ if (reqVo.getStatus() == null || (reqVo.getStatus() != 1 && reqVo.getStatus() != 2)) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_PATTERN_ERROR_CODE, "status参数非法");
|
|
|
+ }
|
|
|
+
|
|
|
+ TExam exam = tExamService.getById(reqVo.getId());
|
|
|
+ if (exam == null || !Objects.equals(exam.getDelFlag(), Global.UN_DELETED)) {
|
|
|
+ throw new SystemException(HttpStatus.QUERY_FAIL_CODE, "考试不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
+ Long userId = LoginUserHolder.getUserId();
|
|
|
+
|
|
|
+ boolean updated = tExamService.lambdaUpdate()
|
|
|
+ .eq(TExam::getId, reqVo.getId())
|
|
|
+ .set(TExam::getStatus, reqVo.getStatus())
|
|
|
+ .set(TExam::getUpdateBy, userId)
|
|
|
+ .set(TExam::getUpdateTime, now)
|
|
|
+ .update();
|
|
|
+
|
|
|
+ if (!updated) {
|
|
|
+ throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.UPDATE_FAIL);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Boolean deleteExam(IdReqVo reqVo) {
|
|
|
+ List<Long> examIds = parseIds(reqVo == null ? null : reqVo.getIds(), reqVo == null ? null : reqVo.getId());
|
|
|
+ if (examIds.isEmpty()) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_MISSING_CODE, "ids不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ Set<Long> entIds = resolveAuthorizedEntIds();
|
|
|
+ if (!LoginUserHolder.isManager() && entIds.isEmpty()) {
|
|
|
+ throw new SystemException(HttpStatus.AUTHORITY_NO_CODE, HttpStatus.ACCESS_FIAL);
|
|
|
+ }
|
|
|
+
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
+ Long userId = LoginUserHolder.getUserId();
|
|
|
+
|
|
|
+ boolean updated = tExamService.lambdaUpdate()
|
|
|
+ .in(TExam::getId, examIds)
|
|
|
+ .eq(TExam::getDelFlag, Global.UN_DELETED)
|
|
|
+ .in(!entIds.isEmpty(), TExam::getEntId, entIds)
|
|
|
+ .set(TExam::getDelFlag, Global.DELETED)
|
|
|
+ .set(TExam::getUpdateBy, userId)
|
|
|
+ .set(TExam::getUpdateTime, now)
|
|
|
+ .update();
|
|
|
+
|
|
|
+ if (!updated) {
|
|
|
+ throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.DELETE_FAIL);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Long> questionIds = tQuestionService.lambdaQuery()
|
|
|
+ .select(TQuestion::getId)
|
|
|
+ .eq(TQuestion::getDelFlag, Global.UN_DELETED)
|
|
|
+ .in(TQuestion::getExamId, examIds)
|
|
|
+ .list()
|
|
|
+ .stream()
|
|
|
+ .map(TQuestion::getId)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .toList();
|
|
|
+
|
|
|
+ if (CollUtil.isNotEmpty(questionIds)) {
|
|
|
+ tQuestionItemService.lambdaUpdate()
|
|
|
+ .in(TQuestionItem::getQuestionId, questionIds)
|
|
|
+ .eq(TQuestionItem::getDelFlag, Global.UN_DELETED)
|
|
|
+ .set(TQuestionItem::getDelFlag, Global.DELETED)
|
|
|
+ .set(TQuestionItem::getUpdateBy, userId)
|
|
|
+ .set(TQuestionItem::getUpdateTime, now)
|
|
|
+ .update();
|
|
|
+
|
|
|
+ tQuestionService.lambdaUpdate()
|
|
|
+ .in(TQuestion::getId, questionIds)
|
|
|
+ .eq(TQuestion::getDelFlag, Global.UN_DELETED)
|
|
|
+ .set(TQuestion::getDelFlag, Global.DELETED)
|
|
|
+ .set(TQuestion::getUpdateBy, userId)
|
|
|
+ .set(TQuestion::getUpdateTime, now)
|
|
|
+ .update();
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void saveQuestionsAndItems(Long examId, Long entId, Long userId, LocalDateTime now, List<ExamSaveReqVo.Question> questions) {
|
|
|
+ if (CollUtil.isEmpty(questions)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (ExamSaveReqVo.Question q : questions) {
|
|
|
+ TQuestion question = new TQuestion();
|
|
|
+ question.setEntId(entId);
|
|
|
+ question.setExamId(examId);
|
|
|
+ question.setName(q.getName().trim());
|
|
|
+ question.setType(q.getType());
|
|
|
+ question.setCreateBy(userId);
|
|
|
+ question.setCreateTime(now);
|
|
|
+ question.setUpdateBy(userId);
|
|
|
+ question.setUpdateTime(now);
|
|
|
+ question.setDelFlag(Global.UN_DELETED);
|
|
|
+
|
|
|
+ if (!tQuestionService.save(question)) {
|
|
|
+ throw new SystemException(HttpStatus.CRUD_FAIL_CODE, "保存题目失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ List<ExamSaveReqVo.QuestionItem> items = q.getItems() == null ? Collections.emptyList() : q.getItems();
|
|
|
+ if (CollUtil.isEmpty(items)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<TQuestionItem> itemEntities = items.stream().map(item -> {
|
|
|
+ TQuestionItem entity = new TQuestionItem();
|
|
|
+ entity.setEntId(entId);
|
|
|
+ entity.setQuestionId(question.getId());
|
|
|
+ entity.setName(normalizeNullable(item.getName()));
|
|
|
+ entity.setContent(item.getContent().trim());
|
|
|
+ entity.setAnswerFlag(item.getAnswerFlag());
|
|
|
+ entity.setSort(item.getSort() == null ? 0 : item.getSort());
|
|
|
+ entity.setCreateBy(userId);
|
|
|
+ entity.setCreateTime(now);
|
|
|
+ entity.setUpdateBy(userId);
|
|
|
+ entity.setUpdateTime(now);
|
|
|
+ entity.setDelFlag(Global.UN_DELETED);
|
|
|
+ return entity;
|
|
|
+ }).toList();
|
|
|
+
|
|
|
+ if (!tQuestionItemService.saveBatch(itemEntities)) {
|
|
|
+ throw new SystemException(HttpStatus.CRUD_FAIL_CODE, "保存题目选项失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void logicDeleteQuestionsAndItemsByExamId(Long examId, Long userId, LocalDateTime now) {
|
|
|
+ List<Long> questionIds = tQuestionService.lambdaQuery()
|
|
|
+ .select(TQuestion::getId)
|
|
|
+ .eq(TQuestion::getDelFlag, Global.UN_DELETED)
|
|
|
+ .eq(TQuestion::getExamId, examId)
|
|
|
+ .list()
|
|
|
+ .stream()
|
|
|
+ .map(TQuestion::getId)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .toList();
|
|
|
+
|
|
|
+ if (CollUtil.isEmpty(questionIds)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ tQuestionItemService.lambdaUpdate()
|
|
|
+ .in(TQuestionItem::getQuestionId, questionIds)
|
|
|
+ .eq(TQuestionItem::getDelFlag, Global.UN_DELETED)
|
|
|
+ .set(TQuestionItem::getDelFlag, Global.DELETED)
|
|
|
+ .set(TQuestionItem::getUpdateBy, userId)
|
|
|
+ .set(TQuestionItem::getUpdateTime, now)
|
|
|
+ .update();
|
|
|
+
|
|
|
+ tQuestionService.lambdaUpdate()
|
|
|
+ .in(TQuestion::getId, questionIds)
|
|
|
+ .eq(TQuestion::getDelFlag, Global.UN_DELETED)
|
|
|
+ .set(TQuestion::getDelFlag, Global.DELETED)
|
|
|
+ .set(TQuestion::getUpdateBy, userId)
|
|
|
+ .set(TQuestion::getUpdateTime, now)
|
|
|
+ .update();
|
|
|
+ }
|
|
|
+
|
|
|
+ private ExamManageItemResVo toManageItem(TExam exam) {
|
|
|
+ ExamManageItemResVo vo = new ExamManageItemResVo();
|
|
|
+ vo.setId(exam.getId());
|
|
|
+ vo.setName(exam.getName());
|
|
|
+ vo.setAmount(exam.getAmount());
|
|
|
+ vo.setExamDuration(exam.getExamDuration());
|
|
|
+ vo.setPassRate(exam.getPassRate());
|
|
|
+ vo.setStatus(exam.getStatus());
|
|
|
+ vo.setStatusName(ExamStatusEnum.getNameByCode(exam.getStatus()));
|
|
|
+ vo.setCreateTime(exam.getCreateTime());
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+
|
|
|
+ private ExamDetailResVo toDetail(TExam exam) {
|
|
|
+ ExamDetailResVo vo = new ExamDetailResVo();
|
|
|
+ vo.setId(exam.getId());
|
|
|
+ vo.setName(exam.getName());
|
|
|
+ vo.setExamDuration(exam.getExamDuration());
|
|
|
+ vo.setPassRate(exam.getPassRate());
|
|
|
+ vo.setAmount(exam.getAmount());
|
|
|
+ vo.setDescription(exam.getDescription());
|
|
|
+ vo.setStatus(exam.getStatus());
|
|
|
+ vo.setStatusName(ExamStatusEnum.getNameByCode(exam.getStatus()));
|
|
|
+ vo.setCreateTime(exam.getCreateTime());
|
|
|
+ vo.setUpdateTime(exam.getUpdateTime());
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+
|
|
|
+ private ExamDetailResVo.QuestionItem toQuestionItem(TQuestionItem item) {
|
|
|
+ ExamDetailResVo.QuestionItem vo = new ExamDetailResVo.QuestionItem();
|
|
|
+ vo.setId(item.getId());
|
|
|
+ vo.setName(item.getName());
|
|
|
+ vo.setContent(item.getContent());
|
|
|
+ vo.setAnswerFlag(item.getAnswerFlag());
|
|
|
+ vo.setSort(item.getSort());
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String normalizeNullable(String value) {
|
|
|
+ if (value == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String trimmed = value.trim();
|
|
|
+ return trimmed.isEmpty() ? null : trimmed;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static List<Long> parseIds(String idsStr, Long singleId) {
|
|
|
+ if (singleId != null) {
|
|
|
+ return List.of(singleId);
|
|
|
+ }
|
|
|
+ if (StrUtil.isBlank(idsStr)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ return Arrays.stream(idsStr.split(","))
|
|
|
+ .map(String::trim)
|
|
|
+ .filter(StrUtil::isNotBlank)
|
|
|
+ .map(Long::parseLong)
|
|
|
+ .distinct()
|
|
|
+ .toList();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void validateSaveReq(ExamSaveReqVo reqVo, boolean requireId) {
|
|
|
+ if (reqVo == null) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_MISSING_CODE, "参数不能为空");
|
|
|
+ }
|
|
|
+ if (requireId && reqVo.getId() == null) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_MISSING_CODE, HttpStatus.ID_MISSING);
|
|
|
+ }
|
|
|
+ if (StrUtil.isBlank(reqVo.getName())) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_MISSING_CODE, "考试名称不能为空");
|
|
|
+ }
|
|
|
+ if (reqVo.getExamDuration() == null || reqVo.getExamDuration() <= 0) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_PATTERN_ERROR_CODE, "考试时长非法");
|
|
|
+ }
|
|
|
+ if (reqVo.getPassRate() == null || reqVo.getPassRate() < 0 || reqVo.getPassRate() > 100) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_PATTERN_ERROR_CODE, "及格率非法");
|
|
|
+ }
|
|
|
+ if (reqVo.getStatus() != null && reqVo.getStatus() != 1 && reqVo.getStatus() != 2) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_PATTERN_ERROR_CODE, "status参数非法");
|
|
|
+ }
|
|
|
+
|
|
|
+ List<ExamSaveReqVo.Question> questions = reqVo.getQuestions() == null ? Collections.emptyList() : reqVo.getQuestions();
|
|
|
+ if (questions.isEmpty()) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_MISSING_CODE, "题目不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ for (ExamSaveReqVo.Question q : questions) {
|
|
|
+ if (q == null || StrUtil.isBlank(q.getName())) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_MISSING_CODE, "题目名称不能为空");
|
|
|
+ }
|
|
|
+ if (q.getType() == null || (q.getType() != 1 && q.getType() != 2 && q.getType() != 3)) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_PATTERN_ERROR_CODE, "题目类型非法");
|
|
|
+ }
|
|
|
+
|
|
|
+ List<ExamSaveReqVo.QuestionItem> items = q.getItems() == null ? Collections.emptyList() : q.getItems();
|
|
|
+ if (q.getType() == 3) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (items.isEmpty()) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_MISSING_CODE, "题目选项不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ long answerCount = items.stream().filter(item -> item != null && Objects.equals(item.getAnswerFlag(), 1)).count();
|
|
|
+ if (q.getType() == 1 && answerCount != 1) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_PATTERN_ERROR_CODE, "单选题必须且只能有1个正确答案");
|
|
|
+ }
|
|
|
+ if (q.getType() == 2 && answerCount < 1) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_PATTERN_ERROR_CODE, "多选题至少要有1个正确答案");
|
|
|
+ }
|
|
|
+
|
|
|
+ for (ExamSaveReqVo.QuestionItem item : items) {
|
|
|
+ if (item == null || StrUtil.isBlank(item.getContent())) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_MISSING_CODE, "选项内容不能为空");
|
|
|
+ }
|
|
|
+ if (item.getAnswerFlag() == null || (item.getAnswerFlag() != 1 && item.getAnswerFlag() != 2)) {
|
|
|
+ throw new SystemException(HttpStatus.PARAMETERS_PATTERN_ERROR_CODE, "answerFlag参数非法");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Set<Long> resolveAuthorizedEntIds() {
|
|
|
+ if (LoginUserHolder.isManager()) {
|
|
|
+ return Collections.emptySet();
|
|
|
+ }
|
|
|
+ Set<Long> result = new LinkedHashSet<>();
|
|
|
+ if (LoginUserHolder.getEntId() != null) {
|
|
|
+ result.add(LoginUserHolder.getEntId());
|
|
|
+ }
|
|
|
+ result.addAll(LoginUserHolder.getChildEntList());
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static boolean isAuthorizedEnt(Long entId) {
|
|
|
+ if (LoginUserHolder.isManager()) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (entId == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Set<Long> entIds = resolveAuthorizedEntIds();
|
|
|
+ return entIds.contains(entId);
|
|
|
+ }
|
|
|
+}
|