xiatian il y a 1 an
Parent
commit
ed84fbd50c

+ 46 - 1
src/main/java/cn/com/qmth/am/controller/AdminController.java

@@ -4,6 +4,7 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
+import java.math.BigDecimal;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -26,12 +27,14 @@ import com.qmth.boot.core.concurrent.service.ConcurrentService;
 
 import cn.com.qmth.am.config.SysProperty;
 import cn.com.qmth.am.entity.QuestionEntity;
+import cn.com.qmth.am.entity.StudentScoreEntity;
 import cn.com.qmth.am.enums.DataStatus;
 import cn.com.qmth.am.enums.ImportFileName;
 import cn.com.qmth.am.enums.LockType;
 import cn.com.qmth.am.service.QuestionService;
 import cn.com.qmth.am.service.StudentScoreService;
 import cn.com.qmth.am.service.StudentService;
+import cn.com.qmth.am.utils.Calculator;
 import io.swagger.annotations.ApiOperation;
 
 @RestController
@@ -49,6 +52,48 @@ public class AdminController {
 	@Autowired
 	private ConcurrentService concurrentService;
 
+	@ApiOperation(value = "分析数据")
+	@RequestMapping(value = "fenxi", method = RequestMethod.GET)
+	public void fenxi(HttpServletResponse response, @RequestParam Long examId) {
+		StringBuilder sb = new StringBuilder();
+		List<QuestionEntity> qs = questionService.findByExamId(examId);
+		if (CollectionUtils.isEmpty(qs)) {
+			sb.append("试题数:0");
+			returnJson(sb.toString(), response);
+			return;
+		}
+		sb.append("试题数:" + qs.size() + "\r\n");
+		for (QuestionEntity q : qs) {
+			List<StudentScoreEntity> scores = studentScoreService.findBy(examId, q.getSubjectCode(), q.getMainNumber(),
+					q.getSubNumber());
+			if (CollectionUtils.isEmpty(scores)) {
+				sb.append(q.getSubjectCode() + "|" + q.getMainNumber() + "|" + q.getSubNumber() + "| 相关系数:- \r\n");
+			} else {
+				double[] a = new double[scores.size()];
+				double[] b = new double[scores.size()];
+				int i = 0;
+				for (StudentScoreEntity s : scores) {
+					a[i] = s.getAiScore();
+					b[i] = s.getMarkingScore();
+					i++;
+				}
+				try {
+					double ret = new BigDecimal(Calculator.correlation(a, b)).setScale(2, BigDecimal.ROUND_HALF_UP)
+							.doubleValue();
+					double avg1 = new BigDecimal(Calculator.mean(a)).setScale(2, BigDecimal.ROUND_HALF_UP)
+							.doubleValue();
+					double avg2 = new BigDecimal(Calculator.mean(b)).setScale(2, BigDecimal.ROUND_HALF_UP)
+							.doubleValue();
+					sb.append(q.getSubjectCode() + "|" + q.getMainNumber() + "|" + q.getSubNumber() + "| 相关系数:" + ret
+							+ "| 人评均分:" + avg2 + "| 机评均分:" + avg1 + " \r\n");
+				} catch (Exception e) {
+					sb.append(q.getSubjectCode() + "|" + q.getMainNumber() + "|" + q.getSubNumber() + "| 相关系数:- \r\n");
+				}
+			}
+		}
+		returnJson(sb.toString(), response);
+	}
+
 	@ApiOperation(value = "进度详情")
 	@RequestMapping(value = "info", method = RequestMethod.GET)
 	public void info(HttpServletResponse response, @RequestParam Long examId) {
@@ -180,7 +225,7 @@ public class AdminController {
 		sysProperty.setMarkingTaskEnable(enable);
 		return "设置成功:" + enable;
 	}
-	
+
 	@ApiOperation(value = "ocr开关")
 	@RequestMapping(value = "ocr/status", method = RequestMethod.GET)
 	public String ocrStatus(@RequestParam Boolean enable) {

+ 2 - 0
src/main/java/cn/com/qmth/am/service/StudentScoreService.java

@@ -43,4 +43,6 @@ public interface StudentScoreService  extends IService<StudentScoreEntity> {
 
 	void removeBy(Long examId, String subjectCode);
 
+	List<StudentScoreEntity> findBy(Long examId, String subjectCode, Integer mainNumber, String subNumber);
+
 }

+ 39 - 36
src/main/java/cn/com/qmth/am/service/impl/QuestionServiceImpl.java

@@ -39,7 +39,8 @@ import cn.com.qmth.am.service.QuestionService;
 @Service
 public class QuestionServiceImpl extends ServiceImpl<QuestionDao, QuestionEntity> implements QuestionService {
 
-	private static final String[] EXCEL_HEADER = new String[] { "考试ID", "科目代码","科目名称", "大题号", "小题号", "满分", "试题内容", "试题答案","作答坐标" };
+	private static final String[] EXCEL_HEADER = new String[] { "考试ID", "科目代码", "科目名称", "大题号", "小题号", "满分", "试题内容",
+			"试题答案", "作答坐标" };
 	@Autowired
 	private SysProperty sysProperty;
 	@Autowired
@@ -186,7 +187,7 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionDao, QuestionEntity
 				msg.append("  科目代码不能超过100个字符");
 			}
 			imp.setSubjectCode(subjectCode);
-			
+
 			String subjectName = trimAndNullIfBlank(line.get(EXCEL_HEADER[2]));
 			if (StringUtils.isBlank(subjectName)) {
 				msg.append("  科目名称不能为空");
@@ -217,7 +218,7 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionDao, QuestionEntity
 				msg.append("  小题号不能为空");
 			} else if (subNum.length() > 10) {
 				msg.append("  小题号不能超过10个字符");
-			} 
+			}
 			imp.setSubNumber(subNum);
 
 			String fullScore = trimAndNullIfBlank(line.get(EXCEL_HEADER[5]));
@@ -249,17 +250,16 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionDao, QuestionEntity
 			}
 			imp.setAnswer(answer);
 
-
 			String imageSlice = trimAndNullIfBlank(line.get(EXCEL_HEADER[8]));
 			if (StringUtils.isBlank(imageSlice)) {
 				msg.append("  作答坐标不能为空");
 			} else if (imageSlice.length() > 1000) {
 				msg.append("  作答坐标不能超过1000个字符");
 			} else {
-				List<ImageSlice> val=getImageSlice(imageSlice);
-				if(val==null) {
+				List<ImageSlice> val = getImageSlice(imageSlice);
+				if (val == null) {
 					msg.append("  作答坐标格式有误");
-				}else {
+				} else {
 					imp.setImageSlice(val);
 				}
 			}
@@ -276,7 +276,7 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionDao, QuestionEntity
 			return ret;
 		}
 		try {
-			saveQuestionBatch(ret,ss);
+			saveQuestionBatch(ret, ss);
 		} catch (Exception e) {
 			failRecords.add("系统错误:" + e.getMessage());
 		}
@@ -287,25 +287,25 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionDao, QuestionEntity
 		if (StringUtils.isBlank(s)) {
 			return null;
 		}
-		s=s.trim();
+		s = s.trim();
 		if (StringUtils.isBlank(s)) {
 			return null;
 		}
 		try {
-			List<ImageSlice> list=new ArrayList<>();
-			String[] items=s.split(",");
-			for(int i=0;i<items.length;i++) {
-				String item=items[i];
-				item=item.trim();
-				String[] config=item.split(":");
-				if(config.length!=5) {
+			List<ImageSlice> list = new ArrayList<>();
+			String[] items = s.split(",");
+			for (int i = 0; i < items.length; i++) {
+				String item = items[i];
+				item = item.trim();
+				String[] config = item.split(":");
+				if (config.length != 5) {
 					return null;
 				}
-				int iVal=Integer.valueOf(config[0]);
-				int x=Integer.valueOf(config[1]);
-				int y=Integer.valueOf(config[2]);
-				int w=Integer.valueOf(config[3]);
-				int h=Integer.valueOf(config[4]);
+				int iVal = Integer.valueOf(config[0]);
+				int x = Integer.valueOf(config[1]);
+				int y = Integer.valueOf(config[2]);
+				int w = Integer.valueOf(config[3]);
+				int h = Integer.valueOf(config[4]);
 				ImageSlice ret = new ImageSlice();
 				ret.setH(h);
 				ret.setI(iVal);
@@ -313,12 +313,12 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionDao, QuestionEntity
 				ret.setX(x);
 				ret.setY(y);
 				if (ret.getH() == null || ret.getI() == null || ret.getW() == null || ret.getX() == null
-						|| ret.getY() == null||ret.getI()<0) {
+						|| ret.getY() == null || ret.getI() < 0) {
 					return null;
 				}
 				list.add(ret);
 			}
-			if(list.size()==0) {
+			if (list.size() == 0) {
 				return null;
 			}
 			list.sort(new Comparator<ImageSlice>() {
@@ -341,38 +341,39 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionDao, QuestionEntity
 		}
 	}
 
-	private void saveQuestionBatch(ImportResult ret,List<QuestionEntity> ss) {
+	private void saveQuestionBatch(ImportResult ret, List<QuestionEntity> ss) {
 		if (CollectionUtils.isEmpty(ss)) {
 			ret.setCountInfo("新增数量:0,更新数量:0");
 			return;
 		}
 		List<QuestionEntity> all = this.list();
-		Map<String,QuestionEntity> old = new HashMap<>();
-		Map<String,QuestionEntity> addMap = new HashMap<>();
+		Map<String, QuestionEntity> old = new HashMap<>();
+		Map<String, QuestionEntity> addMap = new HashMap<>();
 		if (CollectionUtils.isNotEmpty(all)) {
 			for (QuestionEntity s : all) {
-				String key = s.getExamId() + "-" + s.getSubjectCode() + "-" + s.getMainNumber()+"-"+s.getSubNumber();
-				old.put(key,s);
+				String key = s.getExamId() + "-" + s.getSubjectCode() + "-" + s.getMainNumber() + "-"
+						+ s.getSubNumber();
+				old.put(key, s);
 			}
 		}
 		List<QuestionEntity> adds = new ArrayList<>();
 		List<QuestionEntity> updates = new ArrayList<>();
 		for (QuestionEntity s : ss) {
-			String key = s.getExamId() + "-" + s.getSubjectCode() + "-" + s.getMainNumber()+"-"+s.getSubNumber();
-			if (old.get(key)==null) {
-				QuestionEntity add=addMap.get(key);
-				if(add!=null) {
+			String key = s.getExamId() + "-" + s.getSubjectCode() + "-" + s.getMainNumber() + "-" + s.getSubNumber();
+			if (old.get(key) == null) {
+				QuestionEntity add = addMap.get(key);
+				if (add != null) {
 					add.setSubjectName(s.getSubjectName());
 					add.setFullScore(s.getFullScore());
 					add.setImageSlice(s.getImageSlice());
 					add.setContent(s.getContent());
 					add.setAnswer(s.getAnswer());
-				}else {
+				} else {
 					addMap.put(key, s);
 					adds.add(s);
 				}
 			} else {
-				QuestionEntity up=old.get(key);
+				QuestionEntity up = old.get(key);
 				up.setSubjectName(s.getSubjectName());
 				up.setFullScore(s.getFullScore());
 				up.setImageSlice(s.getImageSlice());
@@ -387,7 +388,7 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionDao, QuestionEntity
 		if (CollectionUtils.isNotEmpty(updates)) {
 			updateBatchById(updates);
 		}
-		ret.setCountInfo("新增数量:"+adds.size()+",更新数量:"+updates.size());
+		ret.setCountInfo("新增数量:" + adds.size() + ",更新数量:" + updates.size());
 	}
 
 	@Override
@@ -395,6 +396,8 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionDao, QuestionEntity
 		QueryWrapper<QuestionEntity> wrapper = new QueryWrapper<>();
 		LambdaQueryWrapper<QuestionEntity> lw = wrapper.lambda();
 		lw.eq(QuestionEntity::getExamId, examId);
+		lw.orderByAsc(QuestionEntity::getSubjectCode).orderByAsc(QuestionEntity::getMainNumber)
+				.orderByAsc(QuestionEntity::getSubNumber);
 		return this.list(wrapper);
 	}
 
@@ -403,7 +406,7 @@ public class QuestionServiceImpl extends ServiceImpl<QuestionDao, QuestionEntity
 	public void removeBy(Long examId, String subjectCode) {
 		QueryWrapper<QuestionEntity> wrapper = new QueryWrapper<>();
 		LambdaQueryWrapper<QuestionEntity> lw = wrapper.lambda();
-		if(subjectCode!=null) {
+		if (subjectCode != null) {
 			lw.eq(QuestionEntity::getSubjectCode, subjectCode);
 		}
 		lw.eq(QuestionEntity::getExamId, examId);

+ 11 - 0
src/main/java/cn/com/qmth/am/service/impl/StudentScoreServiceImpl.java

@@ -731,4 +731,15 @@ public class StudentScoreServiceImpl extends ServiceImpl<StudentScoreDao, Studen
 		lw.eq(StudentScoreEntity::getExamId, examId);
 		return this.count(wrapper);
 	}
+
+	@Override
+	public List<StudentScoreEntity> findBy(Long examId, String subjectCode, Integer mainNumber, String subNumber) {
+		QueryWrapper<StudentScoreEntity> wrapper = new QueryWrapper<>();
+		LambdaQueryWrapper<StudentScoreEntity> lw = wrapper.lambda();
+		lw.eq(StudentScoreEntity::getExamId, examId);
+		lw.eq(StudentScoreEntity::getSubjectCode , subjectCode);
+		lw.eq(StudentScoreEntity::getMainNumber, mainNumber);
+		lw.eq(StudentScoreEntity::getSubNumber, subNumber);
+		return this.list(wrapper);
+	}
 }

+ 23 - 0
src/main/java/cn/com/qmth/am/utils/Calculator.java

@@ -4,6 +4,8 @@ import java.math.BigDecimal;
 import java.util.List;
 
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.math3.stat.StatUtils;
+import org.apache.commons.math3.stat.correlation.PearsonsCorrelation;
 
 import com.qmth.boot.core.exception.StatusException;
 
@@ -15,7 +17,28 @@ import com.qmth.boot.core.exception.StatusException;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 public class Calculator {
+    public static double mean(double[] values) {
+        if (values.length == 0) {
+            return 0;
+        }
+        return StatUtils.mean(values);
+    }
+    public static double correlation(double[] x, double[] y) {
+        if (x.length != y.length) {
+            throw new StatusException("两组样本数据数量大小不一致!");
+        }
 
+        if (x.length < 2) {
+            // throw new StatusException("样本数据数量过少!");
+            return 0d;
+        }
+
+        double r = new PearsonsCorrelation().correlation(x, y);
+        if (Double.isNaN(r)) {
+            return 0;
+        }
+        return r;
+    }
     /**
      * 加法 保留两位小数
      *