xiatian 6 vuotta sitten
vanhempi
commit
e419713fd2

+ 49 - 0
examcloud-task-api-provider/src/main/java/cn/com/qmth/examcloud/task/api/controller/ReportsComputeController.java

@@ -0,0 +1,49 @@
+package cn.com.qmth.examcloud.task.api.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.task.dao.entity.ReportsComputeEntity;
+import cn.com.qmth.examcloud.task.service.ReportsComputeService;
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
+import io.swagger.annotations.ApiOperation;
+
+@RestController
+@RequestMapping("${$rmp.ctr.task}" + "reportsCompute")
+public class ReportsComputeController extends ControllerSupport {
+
+
+	@Autowired
+	ReportsComputeService reportsComputeService;
+
+	@ApiOperation(value = "终止计算任务")
+	@PostMapping("/stopJob")
+	public void stopJob(@RequestParam Long id){
+		if (id == null) {
+			throw new StatusException("1000001", "计算任务id不能为空");
+		}
+		User accessUser = getAccessUser();
+		Long rootOrgId = accessUser.getRootOrgId();
+		
+		ReportsComputeEntity re=reportsComputeService.findById(id);
+		
+		if (re == null) {
+			throw new StatusException("1000002", "计算任务不存在");
+		}
+		
+		if(!rootOrgId.equals(re.getRootOrgId())) {
+			throw new StatusException("1000003", "非法操作");
+		}
+		int ret=reportsComputeService.updateToStoping(re);
+		if(ret==0) {
+			throw new StatusException("1000004", "只能终止待处理和处理中的任务");
+		}
+	}
+
+
+}

+ 13 - 0
examcloud-task-dao/src/main/java/cn/com/qmth/examcloud/task/dao/ReportsComputeRepo.java

@@ -4,6 +4,7 @@ import java.util.List;
 
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.stereotype.Repository;
 
@@ -17,4 +18,16 @@ public interface ReportsComputeRepo
 	@Query(value = "SELECT t.* FROM EC_T_REPORTS_COMPUTE t "+
 			"WHERE t.id>?1 and t.status ='NONE' ORDER BY t.id limit ?2", nativeQuery = true)
 	public List<ReportsComputeEntity> findTodoData(Long startId,Integer limit);
+	
+	@Query(value = "update EC_T_REPORTS_COMPUTE t set t.status ='STOPING' where t.id=?1 and (t.status ='COMPUTING' or t.status ='NONE') ", nativeQuery = true)
+	@Modifying
+	public int updateToStoping(Long id);
+	
+	@Query(value = "update EC_T_REPORTS_COMPUTE t set t.status ='STOP' where t.status ='STOPING' ", nativeQuery = true)
+	@Modifying
+	public int initStopingJob();
+	
+	@Query(value = "update EC_T_REPORTS_COMPUTE t set t.status ='NONE' where t.status ='COMPUTING' ", nativeQuery = true)
+	@Modifying
+	public int initComputingJob();
 }

+ 13 - 1
examcloud-task-dao/src/main/java/cn/com/qmth/examcloud/task/dao/entity/ReportsComputeEntity.java

@@ -34,7 +34,11 @@ public class ReportsComputeEntity extends JpaEntity {
 	
 	@NotNull
 	private Long projectId;
-	
+	/**
+	 * 顶级机构ID
+	 */
+	@NotNull
+	private Long rootOrgId;
 	@NotNull
 	@Enumerated(EnumType.STRING)
 	private ReportsComputeStatus status;
@@ -94,6 +98,14 @@ public class ReportsComputeEntity extends JpaEntity {
 	public void setErrorDesc(String errorDesc) {
 		this.errorDesc = errorDesc;
 	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
 	
 	
 }

+ 5 - 3
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/ReportsComputeService.java

@@ -7,11 +7,13 @@ import cn.com.qmth.examcloud.task.dao.entity.ReportsComputeEntity;
 public interface ReportsComputeService {
 	
 	public List<ReportsComputeEntity> findTodoData(Long startId,Integer limit);
-	public void update(ReportsComputeEntity et);
 	public void compute(ReportsComputeEntity et);
 	public void updateToComputing(ReportsComputeEntity et);
 	public void updateToSuccess(ReportsComputeEntity et);
-	public void updateToFail(ReportsComputeEntity et);
-	public void updateToStoping(ReportsComputeEntity et);
+	public void updateToFail(ReportsComputeEntity et,String errMsg);
+	public int updateToStoping(ReportsComputeEntity et);
 	public void updateToStop(ReportsComputeEntity et);
+	public ReportsComputeEntity findById(Long id);
+	public void initReportsCompute();
+	public void clearStopingFlag(Long id);
 }

+ 7 - 2
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/consumer/ReportsComputeConsumer.java

@@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory;
 import cn.com.qmth.examcloud.task.base.multithread.Consumer;
 import cn.com.qmth.examcloud.task.dao.entity.ReportsComputeEntity;
 import cn.com.qmth.examcloud.task.service.ReportsComputeService;
+import cn.com.qmth.examcloud.task.service.exception.ReportsComputeStopException;
 import cn.com.qmth.examcloud.web.support.SpringContextHolder;
 
 public class ReportsComputeConsumer extends Consumer<ReportsComputeEntity> {
@@ -21,10 +22,14 @@ public class ReportsComputeConsumer extends Consumer<ReportsComputeEntity> {
 		try {
 			//计算报表
 			reportsComputeService.compute(et);
+		} catch (ReportsComputeStopException e) {
+			//计算终止
+			reportsComputeService.updateToStop(et);
 		} catch (Exception e) {
+			reportsComputeService.clearStopingFlag(et.getId());
 			//计算出错
-			reportsComputeService.updateToFail(et);
-			logger.info("***************************报表计算出错,projectId:"+et.getProjectId());
+			reportsComputeService.updateToFail(et,"系统错误");
+			logger.error("***************************报表计算出错,projectId:"+et.getProjectId());
 		}
 		logger.info("***************************报表计算结束,projectId:"+et.getProjectId());
 	}

+ 31 - 0
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/dto/TopicScoreDto.java

@@ -0,0 +1,31 @@
+package cn.com.qmth.examcloud.task.service.dto;
+
+public class TopicScoreDto {
+	private double total;
+	private double avg;
+	private long count;
+
+	public double getTotal() {
+		return total;
+	}
+
+	public void setTotal(double total) {
+		this.total = total;
+	}
+
+	public double getAvg() {
+		return avg;
+	}
+
+	public void setAvg(double avg) {
+		this.avg = avg;
+	}
+
+	public long getCount() {
+		return count;
+	}
+
+	public void setCount(long count) {
+		this.count = count;
+	}
+}

+ 10 - 0
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/exception/ReportsComputeStopException.java

@@ -0,0 +1,10 @@
+package cn.com.qmth.examcloud.task.service.exception;
+
+public class ReportsComputeStopException extends RuntimeException {
+
+	/**
+	 * 报表计算任务终止异常
+	 */
+	private static final long serialVersionUID = -201437314569122700L;
+
+}

+ 465 - 15
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/impl/ReportsComputeServiceImpl.java

@@ -1,29 +1,67 @@
 package cn.com.qmth.examcloud.task.service.impl;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 import javax.transaction.Transactional;
 
+import org.apache.commons.lang3.StringUtils;
+import org.examcloud.core.reports.api.ExamCourseDataReportCloudService;
+import org.examcloud.core.reports.api.ExamOrgReportCloudService;
 import org.examcloud.core.reports.api.ProjectCloudService;
+import org.examcloud.core.reports.api.bean.ExamCourseDataReportBean;
+import org.examcloud.core.reports.api.bean.ExamOrgReportBean;
+import org.examcloud.core.reports.api.bean.ProjectInfoBean;
+import org.examcloud.core.reports.api.request.DeleteExamCourseDataReportByProjectReq;
+import org.examcloud.core.reports.api.request.DeleteExamOrgReportByProjectReq;
+import org.examcloud.core.reports.api.request.GetProjectInfoBeanReq;
+import org.examcloud.core.reports.api.request.SaveExamCourseDataReportListReq;
+import org.examcloud.core.reports.api.request.SaveExamOrgReportListReq;
 import org.examcloud.core.reports.api.request.UpdateProjectStatusReq;
+import org.examcloud.core.reports.api.response.GetProjectInfoBeanResp;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import cn.com.qmth.examcloud.core.oe.admin.api.ExamStudentDataCloudService;
+import cn.com.qmth.examcloud.core.oe.admin.api.bean.ExamStudentDataBean;
+import cn.com.qmth.examcloud.core.oe.admin.api.bean.ExamStudentScoreDataBean;
+import cn.com.qmth.examcloud.core.oe.admin.api.request.GetExamStudentDataReq;
+import cn.com.qmth.examcloud.core.oe.admin.api.response.GetExamStudentDataResp;
 import cn.com.qmth.examcloud.task.dao.ReportsComputeRepo;
 import cn.com.qmth.examcloud.task.dao.entity.ReportsComputeEntity;
 import cn.com.qmth.examcloud.task.dao.enums.ReportsComputeStatus;
 import cn.com.qmth.examcloud.task.service.ReportsComputeService;
+import cn.com.qmth.examcloud.task.service.dto.TopicScoreDto;
+import cn.com.qmth.examcloud.task.service.exception.ReportsComputeStopException;
+import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 
 @Service
 public class ReportsComputeServiceImpl implements ReportsComputeService {
 
+	private final static Map<Long, Boolean> jobStopFlag = new HashMap<Long, Boolean>();
+
 	@Autowired
 	private ReportsComputeRepo reportsComputeRepo;
-	
+
 	@Autowired
 	private ProjectCloudService projectCloudService;
 
+	@Autowired
+	private ExamStudentDataCloudService examStudentDataCloudService;
+	
+	@Autowired
+	private ExamCourseDataReportCloudService examCourseDataReportCloudService;
+	
+	@Autowired
+	private ExamOrgReportCloudService examOrgReportBeanCloudService;
+
 	@Override
 	public List<ReportsComputeEntity> findTodoData(Long startId, Integer limit) {
 		return reportsComputeRepo.findTodoData(startId, limit);
@@ -31,68 +69,480 @@ public class ReportsComputeServiceImpl implements ReportsComputeService {
 
 	@Transactional
 	@Override
-	public void update(ReportsComputeEntity et) {
-		reportsComputeRepo.save(et);
+	public void initReportsCompute() {
+		reportsComputeRepo.initComputingJob();
+		reportsComputeRepo.initStopingJob();
+	}
+
+	@Override
+	public ReportsComputeEntity findById(Long id) {
+		ReportsComputeEntity re = GlobalHelper.getEntity(reportsComputeRepo, id, ReportsComputeEntity.class);
+		return re;
 	}
 
 	@Transactional
 	@Override
 	public void compute(ReportsComputeEntity et) {
-		// TODO Auto-generated method stub
+		// 判断任务终止
+		checkIsStoping(et.getId());
+		// 获取项目信息
+		GetProjectInfoBeanReq req = new GetProjectInfoBeanReq();
+		req.setProjectId(et.getProjectId());
+		GetProjectInfoBeanResp resp = projectCloudService.getProjectBean(req);
+		if (resp.getBean() == null) {
+			updateToFail(et, "未找到项目信息");
+			return;
+		}
+		ProjectInfoBean pro = resp.getBean();
+		// 只处理数据来源是同步
+		if ("SYNC".equals(pro.getDataOrigin())) {
+			computeSync(pro, et);
+		} else if ("IMPORT".equals(pro.getDataOrigin())) {
+			computeImport(pro, et);
+		} else {
+			updateToFail(et, "项目数据来源错误");
+		}
+		// 计算结束清除缓存终止标志
+		jobStopFlag.remove(et.getId());
+	}
+
+	/**
+	 * 数据来源是导入
+	 * 
+	 * @param pro
+	 * @param et
+	 */
+	private void computeImport(ProjectInfoBean pro, ReportsComputeEntity et) {
+		updateToFail(et, "不支持处理数据来源是导入的项目");
+	}
+
+	/**
+	 * 数据来源是同步
+	 * 
+	 * @param pro
+	 * @param et
+	 */
+	private void computeSync(ProjectInfoBean pro, ReportsComputeEntity et) {
+		// 判断任务终止
+		checkIsStoping(et.getId());
+		if (StringUtils.isBlank(pro.getExamIds())) {
+			updateToFail(et, "考试id为空");
+			return;
+		}
 		
+		List<Long> examIds = Arrays.asList(pro.getExamIds().split(",")).stream().map(str -> Long.parseLong(str))
+				.collect(Collectors.toList());
+		Map<String, Object> result = new HashMap<String, Object>();
+
+		// 学习中心id集合
+		Set<Long> ordIds = new HashSet<Long>();
+		result.put("ordIds", ordIds);
+
+		// 课程id集合
+		Set<Long> courseIds = new HashSet<Long>();
+		result.put("courseIds", courseIds);
+
+		// 考试-学习中心数值分析结果
+		Map<String, ExamOrgReportBean> examOrgReport = new HashMap<String, ExamOrgReportBean>();
+		result.put("examOrgReport", examOrgReport);
+		// 课程数值分析结果
+		Map<String, ExamCourseDataReportBean> examCourseDataReport = new HashMap<String, ExamCourseDataReportBean>();
+		result.put("examCourseDataReport", examCourseDataReport);
+		// 分数结果集合
+		Map<String, List<Double>> scores = new HashMap<String, List<Double>>();
+		result.put("scores", scores);
+
+		// 考试课程对应的basePaperId集合
+		Map<String, Set<String>> basePapers = new HashMap<String, Set<String>>();
+		result.put("basePapers", basePapers);
+
+		// basePaperId对应的难度系数
+		Map<String, Double> basePapersDegree = new HashMap<String, Double>();
+		result.put("basePapersDegree", basePapersDegree);
+
+		// basePaperId对应的小题平均分和满分
+		Map<String, Map<String, TopicScoreDto>> basePapersTopicScore = new HashMap<String, Map<String, TopicScoreDto>>();
+		result.put("basePapersTopicScore", basePapersTopicScore);
+
+		for (Long examId : examIds) {
+			// 根据考试id获取数据并计算结果
+			computeByExamId(result, examId, et.getId(), pro);
+		}
+		// 计算标准差
+		for (String key : examCourseDataReport.keySet()) {
+			ExamCourseDataReportBean bean = examCourseDataReport.get(key);
+			bean.setStd(std(scores.get(key), bean.getAvgScore()));
+		}
+		// 计算basePaperId对应的难度系数
+		for (String basePaperId : basePapersTopicScore.keySet()) {
+			Map<String, TopicScoreDto> temmap = basePapersTopicScore.get(basePaperId);
+			basePapersDegree.put(basePaperId, difficultyDegree(temmap));
+		}
+		// 计算平均调卷难度
+		for (String key : examCourseDataReport.keySet()) {
+			ExamCourseDataReportBean bean = examCourseDataReport.get(key);
+			String dataKey = bean.getExamId() + "-" + bean.getCourseId();
+			bean.setAvgDifficultyDegree(avgDifficultyDegree(dataKey, basePapers, basePapersDegree));
+		}
+		// 设置中心、课程、考试code和名称
+		//TODO
+		
+		// 判断任务终止
+		checkIsStoping(et.getId());
+		
+		//清除旧数据
+		DeleteExamOrgReportByProjectReq dreq1=new DeleteExamOrgReportByProjectReq();
+		dreq1.setProjectId(pro.getId());
+		dreq1.setRootOrgId(pro.getRootOrgId());
+		examOrgReportBeanCloudService.deleteExamOrgReportByProject(dreq1);
+		
+		DeleteExamCourseDataReportByProjectReq dreq2=new DeleteExamCourseDataReportByProjectReq();
+		dreq2.setProjectId(pro.getId());
+		dreq2.setRootOrgId(pro.getRootOrgId());
+		examCourseDataReportCloudService.deleteExamCourseDataReportByProject(dreq2);
+		
+		//保存计算结果
+		SaveExamOrgReportListReq req1=new SaveExamOrgReportListReq();
+		req1.setBeans(new ArrayList<ExamOrgReportBean>(examOrgReport.values()));
+		examOrgReportBeanCloudService.saveExamOrgReportList(req1);
+		
+		// 判断任务终止
+		checkIsStoping(et.getId());
+		
+		//保存计算结果
+		SaveExamCourseDataReportListReq req2=new SaveExamCourseDataReportListReq();
+		req2.setBeans(new ArrayList<ExamCourseDataReportBean>(examCourseDataReport.values()));
+		examCourseDataReportCloudService.saveExamCourseDataReportList(req2);
+	}
+
+	private Double avgDifficultyDegree(String dataKey, Map<String, Set<String>> basePapers,
+			Map<String, Double> basePapersDegree) {
+		Set<String> set = basePapers.get(dataKey);
+		if (set == null) {
+			return null;
+		}
+		double total = 0.0;
+		for (String s : set) {
+			total = total + basePapersDegree.get(s);
+		}
+		return total / set.size();
+	}
+
+	private double difficultyDegree(Map<String, TopicScoreDto> map) {
+		double totalAvg = 0.0;
+		double totalFull = 0.0;
+		for (String k : map.keySet()) {
+			TopicScoreDto dto = map.get(k);
+			totalAvg = totalAvg + dto.getAvg();
+			totalFull = totalFull + dto.getTotal();
+		}
+		return totalAvg / totalFull;
+	}
+
+	private double std(List<Double> list, Double average) {
+		if (list == null || list.size() == 0 || average == null) {
+			return 0.0;
+		}
+		double total = 0.0;
+		for (int i = 0; i < list.size(); i++) {
+			total += Math.pow((list.get(i) - average), 2);
+		}
+		double standardDeviation = Math.sqrt(total / list.size());
+		return standardDeviation;
+	}
+
+	/**
+	 * 根据考试id获取数据并计算
+	 * 
+	 * @param result
+	 * @param examId
+	 * @param jobId
+	 */
+	private void computeByExamId(Map<String, Object> result, Long examId, Long jobId, ProjectInfoBean pro) {
+		Long startId = 0l;
+		GetExamStudentDataReq req = new GetExamStudentDataReq();
+		req.setExamId(examId);
+		req.setSize(200);
+		for (;;) {
+			// 判断任务终止
+			checkIsStoping(jobId);
+			req.setStartId(startId);
+			GetExamStudentDataResp res = examStudentDataCloudService.getExamStudentData(req);
+			List<ExamStudentDataBean> list = res.getList();
+			if (list == null || list.size() == 0) {
+				break;
+			}
+			startId = list.get(list.size() - 1).getExamStudentId();
+			for (ExamStudentDataBean st : list) {
+				// 判断任务终止
+				checkIsStoping(jobId);
+				// 计算考试-学习中心数值分析表
+				computeExamOrgReport(result, st, pro);
+				// 计算课程数值分析表
+				computeExamCourseDataReport(result, st, pro);
+			}
+		}
+	}
+
+	/**
+	 * 计算考试-学习中心数值分析表
+	 * 
+	 * @param result
+	 * @param st
+	 * @param pro
+	 */
+	@SuppressWarnings("unchecked")
+	private void computeExamOrgReport(Map<String, Object> result, ExamStudentDataBean st, ProjectInfoBean pro) {
+		// 学习中心id集合
+		Set<Long> ordIds = (Set<Long>) result.get("ordIds");
+		ordIds.add(st.getOrgId());
+		Map<String, List<Double>> scores = (Map<String, List<Double>>) result.get("scores");
+		Map<String, ExamOrgReportBean> examOrgReport = (Map<String, ExamOrgReportBean>) result.get("examOrgReport");
+		String key = st.getExamId() + "-" + st.getOrgId();
+		ExamOrgReportBean bean = examOrgReport.get(key);
+		if (bean == null) {
+			bean = new ExamOrgReportBean();
+			bean.init(pro.getPartitionCount());
+			bean.setProjectId(pro.getId());
+			bean.setExamId(st.getExamId());
+			bean.setOrgId(st.getOrgId());
+			bean.setRootOrgId(pro.getRootOrgId());
+			examOrgReport.put(key, bean);
+		}
+		// 报名人数
+		bean.setSignCount(bean.getSignCount() + 1);
+		// 实考人数
+		if (!st.getAbsent()) {
+			bean.setParticipantCount(bean.getParticipantCount() + 1);
+		}
+		// 及格人数
+		if (!st.getAbsent() && st.getScore() >= pro.getPassScore()) {
+			bean.setPassCount(bean.getPassCount() + 1);
+		}
+		// 分段人数
+		if (!st.getAbsent()) {
+			addPartitionData(st.getScore(), pro, bean.getPartitionData());
+		}
+		// 分数集合
+		if (!st.getAbsent()) {
+			List<Double> list = scores.get(key);
+			if (list == null) {
+				list = new ArrayList<Double>();
+				scores.put(key, list);
+			}
+			list.add(st.getScore());
+		}
+
+	}
+
+	/**
+	 * 计算分段人数
+	 * 
+	 * @param score
+	 * @param pro
+	 * @param partitionData
+	 */
+	private void addPartitionData(Double score, ProjectInfoBean pro, List<Long> partitionData) {
+		List<Double> partitionDetails = pro.getPartitionDetails();
+		for (int i = 0; i < partitionDetails.size(); i++) {
+			if (i == 0) {
+				if (score < partitionDetails.get(i)) {
+					partitionData.set(i, partitionData.get(i) + 1);
+				}
+			} else if (i == partitionDetails.size() - 1) {
+				if (partitionDetails.get(i) <= score && score <= pro.getTotalScore()) {
+					partitionData.set(i, partitionData.get(i) + 1);
+				}
+			} else {
+				if (partitionDetails.get(i - 1) <= score && score < partitionDetails.get(i)) {
+					partitionData.set(i, partitionData.get(i) + 1);
+				}
+			}
+		}
 	}
+
+	/**
+	 * 计算课程数值分析表
+	 * 
+	 * @param result
+	 * @param st
+	 * @param pro
+	 */
+	@SuppressWarnings("unchecked")
+	private void computeExamCourseDataReport(Map<String, Object> result, ExamStudentDataBean st, ProjectInfoBean pro) {
+		// 课程id集合
+		Set<Long> courseIds = (Set<Long>) result.get("courseIds");
+		courseIds.add(st.getCourseId());
+		Map<String, ExamCourseDataReportBean> examCourseDataReport = (Map<String, ExamCourseDataReportBean>) result
+				.get("examCourseDataReport");
+		String key = st.getExamId() + "-" + st.getCourseId();
+		ExamCourseDataReportBean bean = examCourseDataReport.get(key);
+		if (bean == null) {
+			bean = new ExamCourseDataReportBean();
+			bean.init(pro.getPartitionCount());
+			bean.setProjectId(pro.getId());
+			bean.setExamId(st.getExamId());
+			bean.setCourseId(st.getCourseId());
+			bean.setRootOrgId(pro.getRootOrgId());
+			examCourseDataReport.put(key, bean);
+		}
+		// 设置满分数值
+		if (st.getTotalScore() != null) {
+			bean.setTotalScore(st.getTotalScore());
+		}
+		// 最高分
+		if (!st.getAbsent() && st.getScore() > bean.getMaxScore()) {
+			bean.setMaxScore(st.getScore());
+		}
+		// 最低分
+		if (!st.getAbsent() && (bean.getMinScore() == null || st.getScore() < bean.getMinScore())) {
+			bean.setMinScore(st.getScore());
+		}
+		// 实考人数
+		if (!st.getAbsent()) {
+			bean.setParticipantCount(bean.getParticipantCount() + 1);
+		}
+		// 满分人数
+		if (!st.getAbsent() && st.getScore() == st.getTotalScore()) {
+			bean.setFullCount(bean.getFullCount() + 1);
+		}
+		// 零分人数
+		if (!st.getAbsent() && st.getScore() == 0.0) {
+			bean.setZeroCount(bean.getZeroCount() + 1);
+		}
+		// 及格人数
+		if (!st.getAbsent() && st.getScore() >= pro.getPassScore()) {
+			bean.setPassCount(bean.getPassCount() + 1);
+		}
+		// 分段人数
+		if (!st.getAbsent()) {
+			addPartitionData(st.getScore(), pro, bean.getPartitionData());
+		}
+		// 平均分
+		if (!st.getAbsent()) {
+			Double avg = bean.getAvgScore();
+			avg += (st.getScore() - avg) / bean.getParticipantCount();
+			bean.setAvgScore(avg);
+		}
+		// 难度系数计算
+		// 考试课程对应的basePaperId集合
+		Map<String, Set<String>> basePapers = (Map<String, Set<String>>) result.get("basePapers");
+
+		// basePaperId对应的小题平均分和满分
+		Map<String, Map<String, TopicScoreDto>> basePapersTopicScore = (Map<String, Map<String, TopicScoreDto>>) result
+				.get("basePapersTopicScore");
+
+		if (!st.getAbsent()) {
+			// 考试课程对应的basePaperId集合
+			Set<String> set = basePapers.get(key);
+			if (set == null) {
+				set = new HashSet<String>();
+				basePapers.put(key, set);
+			}
+			set.add(st.getBasePaperId());
+
+			// basePaperId对应的小题平均分和满分
+			Map<String, TopicScoreDto> temmap = basePapersTopicScore.get(st.getBasePaperId());
+			if (temmap == null) {
+				temmap = new HashMap<String, TopicScoreDto>();
+				basePapersTopicScore.put(st.getBasePaperId(), temmap);
+			}
+			// 考生小题得分详情
+			List<ExamStudentScoreDataBean> scoreDetails = st.getScoreDetails();
+			// 计算每个小题的平均分
+			for (ExamStudentScoreDataBean b : scoreDetails) {
+				if (b.getScore() != null) {
+					String topicScoreKey = b.getQuestionId() + "-"
+							+ (b.getQuestionOrder() == null ? "" : b.getQuestionOrder());
+					TopicScoreDto tem = temmap.get(topicScoreKey);
+					if (tem == null) {
+						tem = new TopicScoreDto();
+						tem.setTotal(b.getTotalScore());
+						temmap.put(topicScoreKey, tem);
+					}
+					tem.setCount(tem.getCount() + 1);
+					double avg = tem.getAvg();
+					avg += (b.getScore() - avg) / tem.getCount();
+					tem.setAvg(avg);
+				}
+			}
+		}
+
+	}
+
+	@Override
+	public void clearStopingFlag(Long id) {
+		// 清除缓存终止标志
+		jobStopFlag.remove(id);
+	}
+
+	private void checkIsStoping(Long id) {
+		if (jobStopFlag.get(id) != null) {
+			// 清除缓存终止标志
+			jobStopFlag.remove(id);
+			throw new ReportsComputeStopException();
+		}
+	}
+
 	@Transactional
 	@Override
 	public void updateToComputing(ReportsComputeEntity et) {
 		et.setStatus(ReportsComputeStatus.COMPUTING);
 		et.setStartTime(new Date());
 		reportsComputeRepo.save(et);
-		UpdateProjectStatusReq req=new UpdateProjectStatusReq();
+		UpdateProjectStatusReq req = new UpdateProjectStatusReq();
 		req.setProjectId(et.getId());
 		req.setStatus(2);
 		projectCloudService.updateProjectStatus(req);
 	}
+
 	@Transactional
 	@Override
 	public void updateToSuccess(ReportsComputeEntity et) {
 		et.setStatus(ReportsComputeStatus.SUCCESS);
 		et.setEndTime(new Date());
 		reportsComputeRepo.save(et);
-		UpdateProjectStatusReq req=new UpdateProjectStatusReq();
+		UpdateProjectStatusReq req = new UpdateProjectStatusReq();
 		req.setProjectId(et.getId());
 		req.setStatus(3);
 		projectCloudService.updateProjectStatus(req);
 	}
+
 	@Transactional
 	@Override
-	public void updateToFail(ReportsComputeEntity et) {
+	public void updateToFail(ReportsComputeEntity et, String errMsg) {
 		et.setStatus(ReportsComputeStatus.FAIL);
-		et.setErrorDesc("系统错误");
+		et.setErrorDesc(errMsg);
 		et.setEndTime(new Date());
 		reportsComputeRepo.save(et);
-		UpdateProjectStatusReq req=new UpdateProjectStatusReq();
+		UpdateProjectStatusReq req = new UpdateProjectStatusReq();
 		req.setProjectId(et.getId());
 		req.setStatus(4);
 		projectCloudService.updateProjectStatus(req);
 	}
+
 	@Transactional
 	@Override
-	public void updateToStoping(ReportsComputeEntity et) {
-		et.setStatus(ReportsComputeStatus.STOPING);
-		reportsComputeRepo.save(et);
+	public int updateToStoping(ReportsComputeEntity et) {
+		int ret = reportsComputeRepo.updateToStoping(et.getId());
+		if (ret != 0) {
+			jobStopFlag.put(et.getId(), true);
+		}
+		return ret;
 	}
+
 	@Transactional
 	@Override
 	public void updateToStop(ReportsComputeEntity et) {
 		et.setStatus(ReportsComputeStatus.STOP);
 		et.setEndTime(new Date());
 		reportsComputeRepo.save(et);
-		UpdateProjectStatusReq req=new UpdateProjectStatusReq();
+		UpdateProjectStatusReq req = new UpdateProjectStatusReq();
 		req.setProjectId(et.getId());
 		req.setStatus(5);
 		projectCloudService.updateProjectStatus(req);
+		// 清除缓存终止标志
+		jobStopFlag.remove(et.getId());
 	}
 
-
-
 }

+ 1 - 1
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/ReportsComputeTask.java

@@ -22,7 +22,7 @@ public class ReportsComputeTask extends AbstractTask {
 	@Override
 	public void run(ScheduleJob scheduleJob) throws Exception {
 		ReportsComputeProducer pro=new ReportsComputeProducer();
-		pro.startDispose(ReportsComputeConsumer.class, 1, null);
+		pro.startDispose(ReportsComputeConsumer.class, 10, null);
 	}
 
 	@Override