Просмотр исходного кода

加入考试模块-补充配置

tanzy месяцев назад: 10
Родитель
Сommit
795c036a04

+ 3 - 0
ruoyi-modules/airport-exam/src/main/java/com/sundot/airport/AirportExamApplication.java

@@ -2,12 +2,15 @@ package com.sundot.airport;
2 2
 
3 3
 import com.ruoyi.common.security.annotation.EnableCustomConfig;
4 4
 import com.ruoyi.common.security.annotation.EnableRyFeignClients;
5
+import org.mybatis.spring.annotation.MapperScan;
6
+import org.mybatis.spring.annotation.MapperScans;
5 7
 import org.springframework.boot.SpringApplication;
6 8
 import org.springframework.boot.autoconfigure.SpringBootApplication;
7 9
 
8 10
 @EnableCustomConfig
9 11
 @EnableRyFeignClients
10 12
 @SpringBootApplication
13
+@MapperScan("com.sundot.airport.mapper")
11 14
 public class AirportExamApplication {
12 15
 
13 16
     public static void main(String[] args)

+ 386 - 0
ruoyi-modules/airport-exam/src/main/java/com/sundot/airport/logic/eighteen/service/impl/EighteenServiceImpl.java

@@ -0,0 +1,386 @@
1
+package com.sundot.airport.logic.eighteen.service.impl;
2
+
3
+import cn.hutool.core.bean.BeanUtil;
4
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
5
+import com.github.pagehelper.PageInfo;
6
+import com.ruoyi.common.core.context.SecurityContextHolder;
7
+import com.sundot.airport.common.*;
8
+import com.sundot.airport.common.manager.ExamRecordManager;
9
+import com.sundot.airport.common.manager.GradeManager;
10
+import com.sundot.airport.common.model.GradeResult;
11
+import com.sundot.airport.common.model.params.ExamRecPageParam;
12
+import com.sundot.airport.common.model.params.GetExamRecordParam;
13
+import com.sundot.airport.common.model.params.UserOption;
14
+import com.sundot.airport.common.model.result.ExamCountResult;
15
+import com.sundot.airport.common.model.result.GetExamRecordResult;
16
+import com.sundot.airport.common.model.result.sub.ExamRecordQuestion;
17
+import com.sundot.airport.common.service.ExamRecOptService;
18
+import com.sundot.airport.common.service.ExamRecService;
19
+import com.sundot.airport.common.service.ExamService;
20
+import com.sundot.airport.common.service.TestPaperService;
21
+import com.sundot.airport.constant.ExamConstant;
22
+import com.sundot.airport.entity.*;
23
+import com.sundot.airport.enums.CloudSchoolBizExceptionEnum;
24
+import com.sundot.airport.logic.eighteen.model.params.Get18ExamIntroParams;
25
+import com.sundot.airport.logic.eighteen.model.params.Get18ExamRecordListParams;
26
+import com.sundot.airport.logic.eighteen.model.params.Get18ExamRecordParams;
27
+import com.sundot.airport.logic.eighteen.model.params.SubmitExamParam;
28
+import com.sundot.airport.logic.eighteen.model.result.Get18ExamIntroResult;
29
+import com.sundot.airport.logic.eighteen.model.result.ItemIn18ExamRecordResult;
30
+import com.sundot.airport.logic.eighteen.model.result.SubmitExamResult;
31
+import com.sundot.airport.logic.eighteen.model.result.subresult.ItemIn18ExamRecordListResult;
32
+import com.sundot.airport.logic.eighteen.model.result.subresult.OptionIn18ExamRec;
33
+import com.sundot.airport.logic.eighteen.model.result.subresult.QuestionIn18ExamRec;
34
+import com.sundot.airport.logic.eighteen.service.EighteenService;
35
+import com.sundot.airport.mapper.DemoMapper;
36
+import org.slf4j.Logger;
37
+import org.slf4j.LoggerFactory;
38
+import org.springframework.beans.BeanUtils;
39
+import org.springframework.stereotype.Service;
40
+import org.springframework.transaction.annotation.Transactional;
41
+
42
+import javax.annotation.Resource;
43
+import java.util.*;
44
+import java.util.stream.Collectors;
45
+
46
+/**
47
+ * <b>功能名:</b>EighteenServiceImpl<br>
48
+ * <b>说明:</b> 十八大实现类 <br>
49
+ * <b>著作权:</b> Copyright (C) 2020 HUIFANEDU  CORPORATION<br>
50
+ * <b>修改履历:
51
+ *
52
+ * @author 2021-06-04 huifan
53
+ */
54
+@Service
55
+public class EighteenServiceImpl extends ServiceImpl<DemoMapper, BaseEntity> implements EighteenService {
56
+
57
+    private static final Logger log = LoggerFactory.getLogger(EighteenServiceImpl.class);
58
+    final int FINISH_RADIO = 100;
59
+    @Resource
60
+    private ExamRecService examRecService;
61
+    @Resource
62
+    private ExamService examService;
63
+    @Resource
64
+    private TestPaperService testPaperService;
65
+    @Resource
66
+    private ExamRecordManager examRecordManager;
67
+    @Resource
68
+    private GradeManager gradeManager;
69
+    @Resource
70
+    private ExamRecOptService examRecOptService;
71
+
72
+
73
+    /**
74
+     * <b>方法名: </b> getExamCountMap <br>
75
+     * <b>说明: </b> 获取考试与考试次数的映射关系 <br>
76
+     *
77
+     * @param uid        String 用户ID
78
+     * @param pcIds      List<String> 课程ID列表
79
+     * @param clientType String 客户端类型
80
+     * @return Map<String, Integer>
81
+     * <b>修改履历: </b>
82
+     * @author 2021/7/1 Mokou
83
+     */
84
+    private Map<String, Integer> getExamCountMap(String uid, List<String> pcIds, String clientType) {
85
+        log.info(String.format("EighteenServiceImpl.getExamCountMap uid=%s clientType=%s pcIds=%s", uid, clientType, pcIds.toString()));
86
+        Map<String, Integer> examCountMap = new HashMap<>((int) (pcIds.size() / 0.75) + 1);
87
+        List<ExamCountResult> examCountList = examRecService.getCountExamRec(uid, pcIds, clientType);
88
+        for (ExamCountResult countResult : examCountList) {
89
+            examCountMap.put(countResult.getPcId(), countResult.getCount());
90
+        }
91
+        return examCountMap;
92
+    }
93
+
94
+
95
+
96
+    @Override
97
+    public HttpResult<Get18ExamIntroResult> getExamIntro(Get18ExamIntroParams param) {
98
+        log.info(String.format("EighteenServiceImpl.getExamIntro param=%s", param.toString()));
99
+        Optional<Exam> examOpt = examService.get(param.getId());
100
+        CheckUtil.boolCheck(!examOpt.isPresent(), CloudSchoolBizExceptionEnum.EXAM_NOT_FOUND);
101
+
102
+        Get18ExamIntroResult res = new Get18ExamIntroResult();
103
+        // 考试基本信息
104
+        BeanUtil.copyProperties(examOpt.get(), res);
105
+
106
+        Optional<TestPaper> testPaperOpt = testPaperService.get(examOpt.get().getTpId());
107
+        CheckUtil.boolCheck(!testPaperOpt.isPresent(), CloudSchoolBizExceptionEnum.TESTPAPER_NOT_FOUND);
108
+        // 考试总分
109
+        res.setTotalScore(testPaperOpt.get().getTpTotalScore());
110
+        // 考试总题目数
111
+        res.setQuestionCount(testPaperOpt.get().getTpQuesNum());
112
+
113
+        return HttpResult.success(res);
114
+    }
115
+
116
+    @Override
117
+    public HttpResult<PageData<ItemIn18ExamRecordListResult>> getExamRecordList(Get18ExamRecordListParams param) {
118
+        log.info(String.format("EighteenServiceImpl.getExamRecordList param=%s", param.toString()));
119
+        ExamRecPageParam pageParam = new ExamRecPageParam();
120
+        BeanUtil.copyProperties(param, pageParam);
121
+
122
+        pageParam.setUsrId(SecurityContextHolder.getUserId().toString());
123
+
124
+        PageInfo<ExamRec> pageInfo = examRecService.pageList(pageParam);
125
+        // 组装分页数据
126
+        PageData<ItemIn18ExamRecordListResult> pageData = new PageData<>(pageInfo);
127
+        pageData.setList(pageInfo
128
+                .getList()
129
+                .stream()
130
+                .map(res -> new ItemIn18ExamRecordListResult() {
131
+                    {
132
+                        // 将查询结果转换为Result对象
133
+                        BeanUtils.copyProperties(res, this);
134
+                        Integer score = res.getErScore();
135
+                        Integer certTh = res.getErExCertTh();
136
+                        if (res.getErExEnableCert() && score != null && certTh != null && score >= certTh) {
137
+                            this.setGetCert(true);
138
+                        }
139
+                    }
140
+                })
141
+                .collect(Collectors.toList()));
142
+        return HttpResult.success(pageData);
143
+    }
144
+
145
+    @Override
146
+    public HttpResult<ItemIn18ExamRecordResult> getExamRecord(Get18ExamRecordParams param) {
147
+        log.info(String.format("EighteenServiceImpl.getExamRecord param=%s", param.toString()));
148
+        GetExamRecordParam commonParam = new GetExamRecordParam();
149
+        BeanUtil.copyProperties(param, commonParam);
150
+        // 查询完整的测试记录、题目、用户答案
151
+        GetExamRecordResult commonRes = examRecordManager.getExamRecord(commonParam);
152
+        ItemIn18ExamRecordResult httpRes = new ItemIn18ExamRecordResult();
153
+        BeanUtil.copyProperties(commonRes, httpRes);
154
+
155
+//        if (commonRes.getErScore() != null && commonRes.getErExCertTh() != null && commonRes.getErScore() >= commonRes.getErExCertTh()) {
156
+//            // 用户得分 与 证书门槛都有效时 返回入证书相关数据
157
+//            CertDataIn18ExamRecordResult certData = new CertDataIn18ExamRecordResult();
158
+//            BeanUtil.copyProperties(commonRes, certData);
159
+//            // 发放时间 即考试记录更新时间
160
+//            certData.setCertTime(commonRes.getUpdateTime());
161
+//            httpRes.setCertData(certData);
162
+//        }
163
+
164
+        // 将common查询结果类转换为请求返回结果类
165
+        List<ExamRecordQuestion> questionList = commonRes.getQuestion();
166
+        httpRes.setQuestion(questionList.stream().map(ques -> new QuestionIn18ExamRec() {
167
+            {
168
+                BeanUtil.copyProperties(ques, this);
169
+                this.setOption(ques.getOption().stream().map(opt -> new OptionIn18ExamRec() {
170
+                    {
171
+                        BeanUtil.copyProperties(opt, this);
172
+                    }
173
+                }).collect(Collectors.toList()));
174
+                //  将选项中的回答正确情况提出至问题
175
+                this.setEroCorrectStatus(examRecordManager.getCorrectStatusByOpts(ques.getOption()));
176
+            }
177
+        }).collect(Collectors.toList()));
178
+
179
+        httpRes.setEnableReExam(true);
180
+        // 1. 获取当前用户的信息
181
+        //CacheUserInfo cacheUserInfo = ThreadContext.get();
182
+        //checkEnableReExam(Objects.isNull(cacheUserInfo), CheckExceptionEnum.USER_ERROR, httpRes);
183
+        if (!httpRes.getEnableReExam()) {
184
+            return HttpResult.success(httpRes);
185
+        }
186
+        // 2. 检查产品课程
187
+//        Optional<ProdCourse> prodCourseOpt = prodCourseService.get(httpRes.getPcId());
188
+//        checkEnableReExam(!prodCourseOpt.isPresent(), CloudSchoolBizExceptionEnum.PROD_COURSE_NOT_FOUND, httpRes);
189
+//        if (!httpRes.getEnableReExam()) {
190
+//            return HttpResult.success(httpRes);
191
+//        }
192
+//
193
+//        Optional<Prod> prodOpt = prodService.get(prodCourseOpt.get().getPrId());
194
+//        checkEnableReExam(!prodOpt.isPresent(), CloudSchoolBizExceptionEnum.PROD_NOT_FOUND, httpRes);
195
+//        if (!httpRes.getEnableReExam()) {
196
+//            return HttpResult.success(httpRes);
197
+//        }
198
+        // 3. 检查考试信息
199
+        Optional<Exam> examOpt = examService.get(httpRes.getErExId());
200
+        checkEnableReExam(!examOpt.isPresent(), CloudSchoolBizExceptionEnum.EXAM_NOT_FOUND, httpRes);
201
+        log.info(String.format("ExamOnlineServiceImpl.applyExam:param=%s,examCount=%d",
202
+                param, examOpt.get().getExExamCount()));
203
+        if (!httpRes.getEnableReExam()) {
204
+            return HttpResult.success(httpRes);
205
+        }
206
+        // 4. 检查是否还有考试次数
207
+        if (examOpt.get().getExExamCount() > 0) {
208
+            // 统计某个课程用户的考试记录次数
209
+            long examCount = examRecService.byPcIdUsrIdEnableCount(httpRes.getPcId(), SecurityContextHolder.getUserId().toString(), true);
210
+            checkEnableReExam(examCount >= examOpt.get().getExExamCount(), CloudSchoolBizExceptionEnum.EXAM_COUNT_TO_UPPER_LIMIT, httpRes);
211
+        }
212
+        return HttpResult.success(httpRes);
213
+    }
214
+
215
+    private void checkEnableReExam(Boolean flag, AbstractBaseExceptionEnum exceptionEnum, ItemIn18ExamRecordResult httpRes) {
216
+        if (flag && httpRes.getEnableReExam()) {
217
+            httpRes.setEnableReExam(false);
218
+            httpRes.setReExamMsg(exceptionEnum.getMessage());
219
+        }
220
+    }
221
+
222
+    @Override
223
+    @Transactional(rollbackFor = Exception.class)
224
+    public HttpResult<SubmitExamResult> submitExam(SubmitExamParam param) {
225
+        log.info(String.format("EighteenServiceImpl.submitExam param=%s", param.toString()));
226
+        String clientType = param.getClientType();
227
+        String exId = param.getExId();
228
+        String erId = param.getErId();
229
+        Integer erExamTime = param.getErExamTime();
230
+
231
+        List<UserOption> options = param.getOptions().stream().map(item -> new UserOption() {
232
+            {
233
+                BeanUtil.copyProperties(item, this);
234
+            }
235
+        }).collect(Collectors.toList());
236
+
237
+        // 判卷结果
238
+        GradeResult gradeRes = gradeManager.grade(erId, options);
239
+        // 用户得分
240
+        int userScore = gradeRes.getUserScore();
241
+        // 用户答对题目数
242
+        int correctCount = gradeRes.getCorrectCount();
243
+        // 用户部分答对题目数
244
+        int partCorrectCount = gradeRes.getPartCorrectCount();
245
+        // 用户答错题目数
246
+        int incorrectCount = gradeRes.getIncorrectCount();
247
+        // 用户未作答题目数
248
+        int notFilledCount = gradeRes.getNotFilledCount();
249
+        // 题目总数
250
+        int questionCount = gradeRes.getQuestionCount();
251
+        // 需要更新的用户答案快照
252
+        List<ExamRecOpt> userOptionRecList = gradeRes.getExamRecOptList();
253
+
254
+        // 1 用erId查所属课程是否有属于系统 属于则记录考试情况
255
+        // 1.1 查询考试快照
256
+        Optional<ExamRec> examRec = examRecService.get(erId);
257
+        CheckUtil.boolCheck(!examRec.isPresent(), CloudSchoolBizExceptionEnum.EXAMREC_NOT_FOUND);
258
+
259
+//        // 1.2 通过考试快照查询考试所属课程
260
+//        Optional<ProdCourse> prodCourseOpt = prodCourseService.get(examRec.get().getPcId());
261
+//        CheckUtil.boolCheck(!prodCourseOpt.isPresent(), CloudSchoolBizExceptionEnum.PROD_COURSE_NOT_FOUND);
262
+//
263
+//        // 1.3 有父级课程则认为属于系统 需要记录系统考试情况
264
+//        if (prodCourseOpt.get().getPcParentId() != null && prodCourseOpt.get().getPcParentId().length() > 0) {
265
+//            updateUserCourseStatus(prodCourseOpt.get().getPcParentId(), clientType, userScore, examRec.get());
266
+//        }
267
+
268
+        // 2 更新用户考试快照数据
269
+        // 得分
270
+        examRec.get().setErScore(userScore);
271
+        // 正确题目数
272
+        examRec.get().setErBingoCount(correctCount);
273
+        // 正确率 小数四舍五入
274
+        examRec.get().setErCorrect(Math.round(correctCount * 100F / questionCount));
275
+        // 部分答对题目数
276
+        examRec.get().setErPartBingoCount(partCorrectCount);
277
+        // 答错题目数
278
+        examRec.get().setErIncorrectCount(incorrectCount);
279
+        // 未作答题目数
280
+        examRec.get().setErNotFilledCount(notFilledCount);
281
+        // 考试用时
282
+        examRec.get().setErExamTime(erExamTime);
283
+        // 查询并保存评语
284
+       // Optional<CertRating> certRatingOpt = certRatingService.byExIdAndScoreFindList(exId, userScore);
285
+       // certRatingOpt.ifPresent(certRating -> examRec.get().setErCrContent(certRating.getCrContent()));
286
+        // 启用本条快照
287
+        examRec.get().setEnableStatus(true);
288
+        examRecService.update(examRec.get());
289
+
290
+        // 3 更新考试管理表中的参考人数
291
+        updateExamPeopleNum(exId);
292
+
293
+        // 4 更新用户选项快照
294
+        if (userOptionRecList.size() > 0) {
295
+            userOptionRecList.forEach(orl -> examRecOptService.updateEroConnNo(orl));
296
+        }
297
+
298
+        SubmitExamResult httpRes = new SubmitExamResult();
299
+        httpRes.setErId(examRec.get().getErId());
300
+        return HttpResult.success(httpRes);
301
+    }
302
+
303
+    /**
304
+     * <b>方法名: </b> updateExamPeopleNum <br>
305
+     * <b>说明: </b> 更新考试管理表中的参考人数 <br>
306
+     *
307
+     * @param exId String 考试ID
308
+     *             <b>修改履历: </b>
309
+     * @author 2021/7/9 Mokou
310
+     */
311
+    private void updateExamPeopleNum(String exId) {
312
+        log.info(String.format("EighteenServiceImpl.updateExamPeopleNum exId=%s", exId));
313
+        long enableUserExamCount = examRecService.countExamNumEnable(SecurityContextHolder.getUserId().toString(), exId);
314
+        if (enableUserExamCount == 1) {
315
+            // 用户第一次参加该考试, 参考人数+1
316
+            Optional<Exam> examOpt = examService.get(exId);
317
+            CheckUtil.boolCheck(!examOpt.isPresent(), CloudSchoolBizExceptionEnum.EXAM_NOT_FOUND);
318
+            examOpt.get().setExPeople(examOpt.get().getExPeople() + 1);
319
+            examService.update(examOpt.get());
320
+        }
321
+    }
322
+
323
+    /**
324
+     * <b>方法名: </b> updateUserCourseStatus <br>
325
+     * <b>说明: </b> 更新用户学习系统考试状态 <br>
326
+     *
327
+     * @param parentId   String 考试所属一级课程ID
328
+     * @param clientType String 客户端类型
329
+     * @param totalScore Integer 用户得分
330
+     * @param examRec    ExamRec 考试记录快照
331
+     *                   <b>修改履历: </b>
332
+     * @author 2021/7/8 Mokou
333
+     */
334
+    private void updateUserCourseStatus(String parentId, String clientType, int totalScore, ExamRec examRec) {
335
+//        log.info(String.format(
336
+//                "EighteenServiceImpl.updateUserCourseStatus parentId=%s clientType=%s totalScore=%d examRec=%s",
337
+//                parentId, clientType, totalScore, examRec.toString())
338
+//        );
339
+//        String uid = SecurityContextHolder.getUserId().toString();
340
+//        Optional<UserCourseStatus> userCourseStatusOpt = userCourseStatusService.getByPcId(parentId, uid, clientType);
341
+//        if (userCourseStatusOpt.isPresent()) {
342
+//            // 更新考试次数
343
+//            userCourseStatusOpt.get().setUcsExamNum(userCourseStatusOpt.get().getUcsExamNum() + 1);
344
+//            // 更新最高得分 规则
345
+//            // 一、 分数高最优先
346
+//            // 二、 同分数优先取及格;
347
+//            // 三、 未开启证书按照不及格处理
348
+//
349
+//            // 原最高分
350
+//            Integer oldMaxScore = userCourseStatusOpt.get().getUcsExamMaxScore();
351
+//            oldMaxScore = oldMaxScore == null ? 0 : oldMaxScore;
352
+//
353
+//            if (oldMaxScore < totalScore) {
354
+//                // 新的分数高 优先取高 同时更新及格分数线
355
+//                userCourseStatusOpt.get().setUcsExamMaxScore(totalScore);
356
+//                userCourseStatusOpt.get().setExCertTh(examRec.getErExCertTh());
357
+//            } else if (oldMaxScore == totalScore) {
358
+//                // 同分数 优先取及格 未开启证书按照不及格处理
359
+//                // 代码逻辑 同分数时 保留最低的及格分数线
360
+//                Integer oldCertTh = userCourseStatusOpt.get().getExCertTh();
361
+//                Integer newCertTh = ExamConstant.DISABLE_CERT_TH;
362
+//                if (examRec.getErExEnableCert()) {
363
+//                    newCertTh = examRec.getErExCertTh();
364
+//                }
365
+//                if (newCertTh < oldCertTh) {
366
+//                    userCourseStatusOpt.get().setExCertTh(newCertTh);
367
+//                }
368
+//            }
369
+//            userCourseStatusService.update(userCourseStatusOpt.get());
370
+      //  } else {
371
+            // 无考试记录 初始化一条
372
+//            UserCourseStatus newStatus = new UserCourseStatus();
373
+//            newStatus.setUcsExamNum(1);
374
+//            newStatus.setUcsExamMaxScore(totalScore);
375
+//            newStatus.setUcsClientType(clientType);
376
+//            newStatus.setUsrId(uid);
377
+//            newStatus.setPcId(parentId);
378
+//            if (examRec.getErExEnableCert()) {
379
+//                newStatus.setExCertTh(examRec.getErExCertTh());
380
+//            } else {
381
+//                newStatus.setExCertTh(ExamConstant.DISABLE_CERT_TH);
382
+//            }
383
+//            userCourseStatusService.insert(newStatus);
384
+      //  }
385
+    }
386
+}

+ 1 - 0
ruoyi-modules/airport-exam/src/main/java/com/sundot/airport/mapper/QuesOptMapper.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 4
 import com.sundot.airport.entity.QuesOpt;
5 5
 import org.apache.ibatis.annotations.Mapper;
6 6
 
7
+
7 8
 /**
8 9
  * <b>功能名:</b>QuesOptMapper<br>
9 10
  * <b>说明:</b> 题目选项表 <br>

+ 20 - 0
ruoyi-modules/airport-exam/src/main/resources/bootstrap-dev.yml

@@ -0,0 +1,20 @@
1
+
2
+# Spring
3
+spring:
4
+  cloud:
5
+    nacos:
6
+      discovery:
7
+        # 服务注册地址
8
+        server-addr: 192.168.3.222:8848
9
+        username: nacos
10
+        password: nacos
11
+      config:
12
+        username: nacos
13
+        password: nacos
14
+        # 配置中心地址
15
+        server-addr: 192.168.3.222:8848
16
+        # 配置文件格式
17
+        file-extension: yml
18
+        # 共享配置
19
+        shared-configs:
20
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

+ 1 - 18
ruoyi-modules/airport-exam/src/main/resources/bootstrap.yml

@@ -9,21 +9,4 @@ spring:
9 9
     name: airport-exam
10 10
   profiles:
11 11
     # 环境配置
12
-    active: dev
13
-  cloud:
14
-    nacos:
15
-      discovery:
16
-        # 服务注册地址
17
-        server-addr: 192.168.3.222:8848
18
-        username: nacos
19
-        password: nacos
20
-      config:
21
-        username: nacos
22
-        password: nacos
23
-        # 配置中心地址
24
-        server-addr: 192.168.3.222:8848
25
-        # 配置文件格式
26
-        file-extension: yml
27
-        # 共享配置
28
-        shared-configs:
29
-          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
12
+    active: dev