|
@@ -5,20 +5,26 @@ import com.xhkjedu.smarking.mapper.exam.MsClassStudentMapper;
|
5
|
5
|
import com.xhkjedu.smarking.mapper.exam.MsSubjectMapper;
|
6
|
6
|
import com.xhkjedu.smarking.mapper.paper.MsPaperQtypeQuestionMapper;
|
7
|
7
|
import com.xhkjedu.smarking.mapper.report.reportother.MsrReportparamMapper;
|
|
8
|
+import com.xhkjedu.smarking.mapper.stupaper.MsPaperStudentMapper;
|
8
|
9
|
import com.xhkjedu.smarking.mapper.stupaper.MsPaperStudentQuestionMapper;
|
9
|
10
|
import com.xhkjedu.smarking.model.exam.MsClassStudent;
|
10
|
11
|
import com.xhkjedu.smarking.model.paper.MsPaper;
|
11
|
12
|
import com.xhkjedu.smarking.model.paper.MsPaperQtypeQuestion;
|
12
|
13
|
import com.xhkjedu.smarking.model.report.reportclass.MsrClassQuestion;
|
|
14
|
+import com.xhkjedu.smarking.model.report.reportclass.MsrClassQuestionObj;
|
13
|
15
|
import com.xhkjedu.smarking.model.report.reportother.MsrReportparam;
|
|
16
|
+import com.xhkjedu.smarking.model.report.reportstu.MsrStudent;
|
|
17
|
+import com.xhkjedu.smarking.model.report.reportsubject.MsrSubjectSectionQuestion;
|
14
|
18
|
import com.xhkjedu.smarking.model.stupaper.MsPaperStudentQuestion;
|
15
|
19
|
import com.xhkjedu.smarking.utils.MarkingUtil;
|
16
|
20
|
import com.xhkjedu.smarking.vo.report.reportother.SzJsonVo;
|
|
21
|
+import com.xhkjedu.utils.N_Utils;
|
17
|
22
|
import org.springframework.stereotype.Service;
|
18
|
23
|
|
19
|
24
|
import javax.annotation.Resource;
|
20
|
25
|
import java.util.ArrayList;
|
21
|
26
|
import java.util.List;
|
|
27
|
+import java.util.Map;
|
22
|
28
|
import java.util.stream.Collectors;
|
23
|
29
|
|
24
|
30
|
/**
|
|
@@ -38,12 +44,15 @@ public class ReportGenerateQuestionService {
|
38
|
44
|
private MsPaperQtypeQuestionMapper msPaperQtypeQuestionMapper;
|
39
|
45
|
@Resource
|
40
|
46
|
private MsrReportparamMapper msrReportparamMapper;
|
|
47
|
+ @Resource
|
|
48
|
+ private MsPaperStudentMapper msPaperStudentMapper;
|
41
|
49
|
|
42
|
50
|
public void generateQuestion(Integer examid,Integer exammode){
|
43
|
51
|
//查询所有学生试题
|
44
|
52
|
List<MsPaperStudentQuestion> stuQuestions = msPaperStudentQuestionMapper.listAllStuQuesByExamid(examid);
|
45
|
53
|
List<MsClassStudent> classStudents = msClassStudentMapper.listStudentByExamId(examid);
|
46
|
54
|
List<MsPaper> subjects = msSubjectMapper.listReportSubject(examid, exammode);
|
|
55
|
+ List<MsrStudent> stuPapers = msPaperStudentMapper.listPaperStudentByExamId(examid, null);
|
47
|
56
|
//获取考试参数
|
48
|
57
|
List<MsrReportparam> params = msrReportparamMapper.listReportparamByRpbelong(examid,"quesummary",null);
|
49
|
58
|
|
|
@@ -56,8 +65,13 @@ public class ReportGenerateQuestionService {
|
56
|
65
|
List<MsClassStudent> subjectClassStudents = classStudents.stream().filter(classStudent -> classStudent.getSubjectid().equals(subjectid)).collect(Collectors.toList());
|
57
|
66
|
//获取试卷中所有小题基础信息包含大题信息
|
58
|
67
|
List<MsPaperQtypeQuestion> questions = msPaperQtypeQuestionMapper.listQuestionsForReport(subject.getMpid());
|
|
68
|
+ //获取科目参数
|
|
69
|
+ List<MsrReportparam> subjectParams = params.stream().filter(p -> p.getSubjectid().equals(subjectid)).collect(Collectors.toList());
|
|
70
|
+ //获取学生科目得分
|
|
71
|
+ List<MsrStudent> subjectStuPapers = stuPapers.stream().filter(p -> p.getSubjectid().equals(subjectid)).collect(Collectors.toList());
|
59
|
72
|
|
60
|
|
- List<MsrReportparam> subjectParams = params.stream().filter(p -> p.getRpbelong().equals(subjectid)).collect(Collectors.toList());
|
|
73
|
+ //处理小题
|
|
74
|
+ handleQuestion(subjectStuQuestions,subjectClassStudents,questions,subjectParams,examid,subjectid);
|
61
|
75
|
}
|
62
|
76
|
}
|
63
|
77
|
|
|
@@ -65,6 +79,7 @@ public class ReportGenerateQuestionService {
|
65
|
79
|
private void handleQuestion(List<MsPaperStudentQuestion> subjectStuQuestions, List<MsClassStudent> subjectClassStudents,List<MsPaperQtypeQuestion> questions,List<MsrReportparam> params,Integer examid,String subjectid){
|
66
|
80
|
|
67
|
81
|
List<MsrClassQuestion> saveQuestions = new ArrayList<>();//小题分析
|
|
82
|
+ List<MsrClassQuestionObj> saveQuestionObjs = new ArrayList<>();//小题-客观题选项分析
|
68
|
83
|
|
69
|
84
|
//处理小题信息
|
70
|
85
|
for(MsPaperQtypeQuestion question : questions){
|
|
@@ -72,7 +87,7 @@ public class ReportGenerateQuestionService {
|
72
|
87
|
List<MsPaperStudentQuestion> stuQuestions = subjectStuQuestions.stream().filter(q -> q.getMptqid().equals(question.getMptqid())).collect(Collectors.toList());
|
73
|
88
|
int stunum = stuQuestions.size();//学生数量
|
74
|
89
|
Double sumQScore = question.getQscore() * stunum;//小题得分
|
75
|
|
- List<Double> stuScores = stuQuestions.stream().map(q -> q.getStuscore()).collect(Collectors.toList());//所有学生得分
|
|
90
|
+ List<Double> stuScores = stuQuestions.stream().map(MsPaperStudentQuestion::getStuscore).collect(Collectors.toList());//所有学生得分
|
76
|
91
|
|
77
|
92
|
Double maxScore = stuQuestions.stream().mapToDouble(MsPaperStudentQuestion::getStuscore).max().orElse(0.0);//最高分
|
78
|
93
|
Double minScore = stuQuestions.stream().mapToDouble(MsPaperStudentQuestion::getStuscore).min().orElse(0.0);//最低分
|
|
@@ -92,19 +107,35 @@ public class ReportGenerateQuestionService {
|
92
|
107
|
saveQuestions.add(schoolQue);
|
93
|
108
|
|
94
|
109
|
//班级试题--客观题选项情况
|
|
110
|
+ MsrClassQuestionObj qobj = new MsrClassQuestionObj();
|
|
111
|
+ if(question.getQtype() == 1){
|
|
112
|
+ qobj.setExamid(examid);
|
|
113
|
+ qobj.setSubjectid(subjectid);
|
|
114
|
+ qobj.setClassid(0);
|
|
115
|
+ qobj.setMptqid(question.getMptqid());
|
|
116
|
+ List<MsrClassQuestionObj> qobjList = handleQuestionXuanxiang(stuQuestions,qobj);
|
|
117
|
+ saveQuestionObjs.addAll(qobjList);
|
|
118
|
+ }
|
95
|
119
|
|
96
|
|
-
|
97
|
|
- //处理班级情况
|
98
|
|
- for(MsClassStudent classStudent : subjectClassStudents){
|
|
120
|
+ //班级试题分析
|
|
121
|
+ //获取所有班级
|
|
122
|
+ List<Integer> classIds = subjectClassStudents.stream().map(MsClassStudent::getClassid).distinct().collect(Collectors.toList());
|
|
123
|
+ for(Integer classid : classIds){
|
99
|
124
|
//获取班级下学生id
|
100
|
|
- List<Integer> classStuIds = subjectClassStudents.stream().map(MsClassStudent::getStudentid).collect(Collectors.toList());
|
|
125
|
+ List<Integer> classStuIds = subjectClassStudents.stream().filter(c -> c.getClassid().equals(classid)).map(MsClassStudent::getStudentid).collect(Collectors.toList());
|
101
|
126
|
//获取班级下学生试题
|
102
|
127
|
List<MsPaperStudentQuestion> classStuQuestions = stuQuestions.stream().filter(q -> classStuIds.contains(q.getStudentid())).collect(Collectors.toList());
|
|
128
|
+ schoolQ.setClassid(classid);
|
103
|
129
|
MsrClassQuestion classQue = handleQuestionClass(classStuQuestions,question,params,schoolQ);
|
104
|
130
|
saveQuestions.add(classQue);
|
105
|
|
- }
|
106
|
|
-
|
107
|
131
|
|
|
132
|
+ //班级试题--客观题选项情况
|
|
133
|
+ if(question.getQtype() == 1) {
|
|
134
|
+ qobj.setClassid(classid);
|
|
135
|
+ List<MsrClassQuestionObj> qobjList = handleQuestionXuanxiang(classStuQuestions,qobj);
|
|
136
|
+ saveQuestionObjs.addAll(qobjList);
|
|
137
|
+ }
|
|
138
|
+ }
|
108
|
139
|
}
|
109
|
140
|
}
|
110
|
141
|
|
|
@@ -113,7 +144,7 @@ public class ReportGenerateQuestionService {
|
113
|
144
|
int stunum = stuQuestions.size();//学生数量
|
114
|
145
|
Double qScore = question.getQscore();//试题分值
|
115
|
146
|
Double sumQScore = question.getQscore() * stunum;//小题得分
|
116
|
|
- List<Double> stuScores = stuQuestions.stream().map(q -> q.getStuscore()).collect(Collectors.toList());//所有学生得分
|
|
147
|
+ List<Double> stuScores = stuQuestions.stream().map(MsPaperStudentQuestion::getStuscore).collect(Collectors.toList());//所有学生得分
|
117
|
148
|
Double sumStuScore = stuQuestions.stream().mapToDouble(MsPaperStudentQuestion::getStuscore).sum();//综合
|
118
|
149
|
|
119
|
150
|
Double maxScore;//最高分
|
|
@@ -156,9 +187,13 @@ public class ReportGenerateQuestionService {
|
156
|
187
|
classQ.setScorerate(stuScoreRate);
|
157
|
188
|
classQ.setScoreratec(MarkingUtil.sub(MarkingUtil.calculateRate(maxScore,qScore),MarkingUtil.calculateRate(minScore,qScore)));//得分率差=最高得分率-最低得分率
|
158
|
189
|
classQ.setNd(MarkingUtil.div(stuScoreRate,qScore));//难度
|
159
|
|
- classQ.setNdms(handleQuestionNdAndQfd(params,1,classQ.getNd()));//难度描述
|
|
190
|
+ String[] ndStr = handleQuestionNdAndQfd(params,1,classQ.getNd());
|
|
191
|
+ classQ.setNdms(ndStr[0]);//难度描述
|
|
192
|
+ classQ.setNdfw(ndStr[1]);//难度范围
|
160
|
193
|
classQ.setQfd(MarkingUtil.qfd(stuScores));//区分度
|
161
|
|
- classQ.setQfdms(handleQuestionNdAndQfd(params,2, classQ.getQfd()));//区分度描述
|
|
194
|
+ String[] qfdStr = handleQuestionNdAndQfd(params,2,classQ.getNd());
|
|
195
|
+ classQ.setQfdms(qfdStr[0]);//区分度描述
|
|
196
|
+ classQ.setQfdfw(qfdStr[1]);//区分度范围
|
162
|
197
|
classQ.setBzc(MarkingUtil.bzc(stuScores));//标准差
|
163
|
198
|
classQ.setCyxs(MarkingUtil.div(classQ.getBzc(),avgScore));//差异系数
|
164
|
199
|
classQ.setJbzs(MarkingUtil.jbzs(stuScores,stuScoreRate));//鉴别指数
|
|
@@ -169,33 +204,76 @@ public class ReportGenerateQuestionService {
|
169
|
204
|
classQ.setMfrate(MarkingUtil.div(classQ.getMfnum(), stunum));////正确率、满分人数占比
|
170
|
205
|
classQ.setMfids(mfids);
|
171
|
206
|
//获取零分学生
|
172
|
|
- List<MsPaperStudentQuestion> lfStuQuestions = stuQuestions.stream().filter(q -> q.getStuscore().equals(0)).collect(Collectors.toList());
|
|
207
|
+ List<MsPaperStudentQuestion> lfStuQuestions = stuQuestions.stream().filter(q -> q.getStuscore()==0).collect(Collectors.toList());
|
173
|
208
|
String lfids = lfStuQuestions.stream().map(p -> p.getStudentid().toString()).collect(Collectors.joining(","));//零分学生id
|
174
|
209
|
classQ.setLfnum(lfStuQuestions.size());
|
175
|
210
|
classQ.setLfrate(MarkingUtil.div(lfStuQuestions.size(),stunum));////零分人数占比
|
176
|
211
|
classQ.setLfids(lfids);
|
177
|
212
|
return classQ;
|
178
|
213
|
}
|
179
|
|
-
|
180
|
|
- private String handleQuestionNdAndQfd(List<MsrReportparam> params,Integer rptype,Double nd){
|
|
214
|
+ //处理单个试题分析-试题难度、区分度
|
|
215
|
+ private String[] handleQuestionNdAndQfd(List<MsrReportparam> params,Integer rptype,Double nd){
|
181
|
216
|
//获取难度或者区分度
|
182
|
217
|
MsrReportparam ndParam = params.stream().filter(p -> p.getRptype().equals(rptype)).findFirst().orElse(null);//难度
|
183
|
218
|
String ndms = "";
|
|
219
|
+ String ndfw = "";
|
184
|
220
|
if(ndParam!= null){
|
185
|
221
|
List<SzJsonVo> szList = JSON.parseArray(ndParam.getSzjson(), SzJsonVo.class);
|
186
|
222
|
for (SzJsonVo sz : szList) {
|
187
|
223
|
if (nd == 1 && sz.getMaxvalue() == 1) {
|
188
|
224
|
ndms = sz.getDjkey();
|
|
225
|
+ ndfw = "[" + sz.getMinvalue() + "~" + "1]";
|
189
|
226
|
break;
|
190
|
227
|
} else if (nd == 0 && sz.getMinvalue() == 0) {
|
191
|
228
|
ndms = sz.getDjkey();
|
|
229
|
+ ndfw = "[0" + "~" + sz.getMaxvalue() + ")";
|
192
|
230
|
break;
|
193
|
231
|
} else if(nd >= sz.getMinvalue() && nd < sz.getMaxvalue()) {
|
194
|
232
|
ndms = sz.getDjkey();
|
|
233
|
+ ndfw = "[" + sz.getMinvalue() + "~" + sz.getMaxvalue() + ")";
|
195
|
234
|
break;
|
196
|
235
|
}
|
197
|
236
|
}
|
198
|
237
|
}
|
199
|
|
- return ndms;
|
|
238
|
+ return new String[]{ndms,ndfw};
|
|
239
|
+ }
|
|
240
|
+ //处理单个试题分析-客观题选项情况
|
|
241
|
+ private List<MsrClassQuestionObj> handleQuestionXuanxiang(List<MsPaperStudentQuestion> stuQuestions,MsrClassQuestionObj questionObj){
|
|
242
|
+ Map<String,List<MsPaperStudentQuestion>> optionMap = stuQuestions.stream().collect(Collectors.groupingBy(MsPaperStudentQuestion::getStuanswer));
|
|
243
|
+ int totalNum = stuQuestions.size();
|
|
244
|
+ List<MsrClassQuestionObj> qobjList = new ArrayList<>();
|
|
245
|
+ for(Map.Entry<String,List<MsPaperStudentQuestion>> entry : optionMap.entrySet()){
|
|
246
|
+ String option = entry.getKey();
|
|
247
|
+ List<MsPaperStudentQuestion> optionStuQuestions = entry.getValue();
|
|
248
|
+
|
|
249
|
+ MsrClassQuestionObj qobj = new MsrClassQuestionObj();
|
|
250
|
+ qobj.setExamid(questionObj.getExamid());
|
|
251
|
+ qobj.setSubjectid(questionObj.getSubjectid());
|
|
252
|
+ qobj.setClassid(questionObj.getClassid());
|
|
253
|
+ qobj.setMptqid(questionObj.getMptqid());
|
|
254
|
+ if(N_Utils.isNotEmpty(option)){
|
|
255
|
+ qobj.setXxda(option);
|
|
256
|
+ }else{
|
|
257
|
+ qobj.setXxda("未选");
|
|
258
|
+ }
|
|
259
|
+ qobj.setXxnum(optionStuQuestions.size());
|
|
260
|
+ qobj.setXxrate(MarkingUtil.calculateRate(optionStuQuestions.size(),totalNum));
|
|
261
|
+ String stuids = optionStuQuestions.stream().map(q -> q.getStudentid().toString()).collect(Collectors.joining(","));
|
|
262
|
+ qobj.setStuids(stuids);
|
|
263
|
+ qobjList.add(qobj);
|
|
264
|
+ }
|
|
265
|
+ return qobjList;
|
|
266
|
+ }
|
|
267
|
+
|
|
268
|
+ //处理科目分段-默认5分一段为后续试题做准备
|
|
269
|
+ private void handleSubjectSectionForQuestion(List<MsrStudent> StuPapers,Double pscore){
|
|
270
|
+ //把科目总分分段,默认5分一段
|
|
271
|
+ List<int[]> fdList = MarkingUtil.fdScore(pscore,5);
|
|
272
|
+ List<MsrSubjectSectionQuestion> sections = new ArrayList<>();
|
|
273
|
+ for(int[] fd : fdList){
|
|
274
|
+ //获取学生得分在指定区间的学生
|
|
275
|
+ List<MsrStudent> fdStuPapers = StuPapers.stream().filter(s -> s.getStuscore() >= fd[0] && s.getStuscore() < fd[1]).collect(Collectors.toList());
|
|
276
|
+ //计算分段平均分
|
|
277
|
+ }
|
200
|
278
|
}
|
201
|
279
|
}
|